@nnao45/figma-use 0.1.3 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/README.md +9 -0
- package/SKILL.md +147 -121
- package/dist/cli/index.js +433 -230
- package/package.json +5 -1
- package/packages/cli/src/render/components.tsx +5 -0
- package/packages/plugin/src/main.ts +45 -41
- package/packages/plugin/src/rpc.ts +58 -59
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nnao45/figma-use",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "Control Figma from the command line. Full read/write access for AI agents.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -63,9 +63,11 @@
|
|
|
63
63
|
"agentfmt": "^0.1.3",
|
|
64
64
|
"citty": "^0.1.6",
|
|
65
65
|
"consola": "^3.4.2",
|
|
66
|
+
"d3": "^7.9.0",
|
|
66
67
|
"diff": "^8.0.3",
|
|
67
68
|
"esbuild": "^0.25.4",
|
|
68
69
|
"fontoxpath": "^3.34.0",
|
|
70
|
+
"jsdom": "^27.0.1",
|
|
69
71
|
"postcss": "^8.5.6",
|
|
70
72
|
"svgpath": "^2.6.0",
|
|
71
73
|
"typescript": "^5.8.3",
|
|
@@ -78,6 +80,8 @@
|
|
|
78
80
|
"@iconify/types": "^2.0.0",
|
|
79
81
|
"@iconify/utils": "^3.1.0",
|
|
80
82
|
"@types/bun": "^1.3.6",
|
|
83
|
+
"@types/d3": "^7.4.3",
|
|
84
|
+
"@types/jsdom": "^27.0.0",
|
|
81
85
|
"@types/pngjs": "^6.0.5",
|
|
82
86
|
"@types/react": "^19.2.9",
|
|
83
87
|
"@types/ws": "^8.18.1",
|
|
@@ -28,6 +28,10 @@ export function Line(props: BaseProps): TreeNode {
|
|
|
28
28
|
return node('line', props)
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
export function Arrow(props: BaseProps): TreeNode {
|
|
32
|
+
return node('arrow', props)
|
|
33
|
+
}
|
|
34
|
+
|
|
31
35
|
export function Image(props: BaseProps & { src: string }): TreeNode {
|
|
32
36
|
return node('image', props)
|
|
33
37
|
}
|
|
@@ -70,6 +74,7 @@ export const INTRINSIC_ELEMENTS = [
|
|
|
70
74
|
'rectangle',
|
|
71
75
|
'ellipse',
|
|
72
76
|
'line',
|
|
77
|
+
'arrow',
|
|
73
78
|
'image',
|
|
74
79
|
'svg',
|
|
75
80
|
'star',
|
|
@@ -625,6 +625,29 @@ async function handleCommand(command: string, args?: unknown): Promise<unknown>
|
|
|
625
625
|
}
|
|
626
626
|
|
|
627
627
|
case 'create-line': {
|
|
628
|
+
const { x, y, length, rotation, name, parentId, stroke, strokeWeight } = args as {
|
|
629
|
+
x: number
|
|
630
|
+
y: number
|
|
631
|
+
length: number
|
|
632
|
+
rotation?: number
|
|
633
|
+
name?: string
|
|
634
|
+
parentId?: string
|
|
635
|
+
stroke?: string
|
|
636
|
+
strokeWeight?: number
|
|
637
|
+
}
|
|
638
|
+
const line = figma.createLine()
|
|
639
|
+
line.x = x
|
|
640
|
+
line.y = y
|
|
641
|
+
line.resize(length, 0)
|
|
642
|
+
if (rotation) line.rotation = rotation
|
|
643
|
+
if (name) line.name = name
|
|
644
|
+
if (stroke) line.strokes = [await createSolidPaint(stroke)]
|
|
645
|
+
if (strokeWeight !== undefined) line.strokeWeight = strokeWeight
|
|
646
|
+
await appendToParent(line, parentId)
|
|
647
|
+
return serializeNode(line)
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
case 'create-arrow': {
|
|
628
651
|
const { x, y, length, rotation, name, parentId, stroke, strokeWeight, startCap, endCap } =
|
|
629
652
|
args as {
|
|
630
653
|
x: number
|
|
@@ -638,47 +661,28 @@ async function handleCommand(command: string, args?: unknown): Promise<unknown>
|
|
|
638
661
|
startCap?: string
|
|
639
662
|
endCap?: string
|
|
640
663
|
}
|
|
641
|
-
const startCapValue = normalizeLineCap(startCap)
|
|
642
|
-
const endCapValue = normalizeLineCap(endCap)
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
if (stroke) vector.strokes = [await createSolidPaint(stroke)]
|
|
664
|
-
if (strokeWeight !== undefined) vector.strokeWeight = strokeWeight
|
|
665
|
-
if (rotation) vector.rotation = rotation
|
|
666
|
-
if (name) vector.name = name
|
|
667
|
-
await appendToParent(vector, parentId)
|
|
668
|
-
return serializeNode(vector)
|
|
669
|
-
}
|
|
670
|
-
|
|
671
|
-
// No caps specified - use simple Line
|
|
672
|
-
const line = figma.createLine()
|
|
673
|
-
line.x = x
|
|
674
|
-
line.y = y
|
|
675
|
-
line.resize(length, 0)
|
|
676
|
-
if (rotation) line.rotation = rotation
|
|
677
|
-
if (name) line.name = name
|
|
678
|
-
if (stroke) line.strokes = [await createSolidPaint(stroke)]
|
|
679
|
-
if (strokeWeight !== undefined) line.strokeWeight = strokeWeight
|
|
680
|
-
await appendToParent(line, parentId)
|
|
681
|
-
return serializeNode(line)
|
|
664
|
+
const startCapValue = normalizeLineCap(startCap) ?? 'NONE'
|
|
665
|
+
const endCapValue = normalizeLineCap(endCap) ?? 'ARROW_LINES'
|
|
666
|
+
|
|
667
|
+
const vector = figma.createVector()
|
|
668
|
+
vector.x = x
|
|
669
|
+
vector.y = y
|
|
670
|
+
vector.name = name || 'Arrow'
|
|
671
|
+
|
|
672
|
+
vector.vectorNetwork = {
|
|
673
|
+
vertices: [
|
|
674
|
+
{ x: 0, y: 0, strokeCap: startCapValue },
|
|
675
|
+
{ x: length, y: 0, strokeCap: endCapValue }
|
|
676
|
+
],
|
|
677
|
+
segments: [{ start: 0, end: 1, tangentStart: { x: 0, y: 0 }, tangentEnd: { x: 0, y: 0 } }],
|
|
678
|
+
regions: []
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
if (stroke) vector.strokes = [await createSolidPaint(stroke)]
|
|
682
|
+
if (strokeWeight !== undefined) vector.strokeWeight = strokeWeight
|
|
683
|
+
if (rotation) vector.rotation = rotation
|
|
684
|
+
await appendToParent(vector, parentId)
|
|
685
|
+
return serializeNode(vector)
|
|
682
686
|
}
|
|
683
687
|
|
|
684
688
|
case 'create-polygon': {
|
|
@@ -899,6 +899,29 @@ async function handleCommand(command: string, args?: unknown): Promise<unknown>
|
|
|
899
899
|
}
|
|
900
900
|
|
|
901
901
|
case 'create-line': {
|
|
902
|
+
const { x, y, length, rotation, name, parentId, stroke, strokeWeight } = args as {
|
|
903
|
+
x: number
|
|
904
|
+
y: number
|
|
905
|
+
length: number
|
|
906
|
+
rotation?: number
|
|
907
|
+
name?: string
|
|
908
|
+
parentId?: string
|
|
909
|
+
stroke?: string
|
|
910
|
+
strokeWeight?: number
|
|
911
|
+
}
|
|
912
|
+
const line = figma.createLine()
|
|
913
|
+
line.x = x
|
|
914
|
+
line.y = y
|
|
915
|
+
line.resize(length, 0)
|
|
916
|
+
if (rotation) line.rotation = rotation
|
|
917
|
+
if (name) line.name = name
|
|
918
|
+
if (stroke) line.strokes = [await createSolidPaint(stroke)]
|
|
919
|
+
if (strokeWeight !== undefined) line.strokeWeight = strokeWeight
|
|
920
|
+
await appendToParent(line, parentId)
|
|
921
|
+
return serializeNode(line)
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
case 'create-arrow': {
|
|
902
925
|
const { x, y, length, rotation, name, parentId, stroke, strokeWeight, startCap, endCap } =
|
|
903
926
|
args as {
|
|
904
927
|
x: number
|
|
@@ -912,47 +935,28 @@ async function handleCommand(command: string, args?: unknown): Promise<unknown>
|
|
|
912
935
|
startCap?: string
|
|
913
936
|
endCap?: string
|
|
914
937
|
}
|
|
915
|
-
const startCapValue = normalizeLineCap(startCap)
|
|
916
|
-
const endCapValue = normalizeLineCap(endCap)
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
if (stroke) vector.strokes = [await createSolidPaint(stroke)]
|
|
938
|
-
if (strokeWeight !== undefined) vector.strokeWeight = strokeWeight
|
|
939
|
-
if (rotation) vector.rotation = rotation
|
|
940
|
-
if (name) vector.name = name
|
|
941
|
-
await appendToParent(vector, parentId)
|
|
942
|
-
return serializeNode(vector)
|
|
943
|
-
}
|
|
944
|
-
|
|
945
|
-
// No caps specified - use simple Line
|
|
946
|
-
const line = figma.createLine()
|
|
947
|
-
line.x = x
|
|
948
|
-
line.y = y
|
|
949
|
-
line.resize(length, 0)
|
|
950
|
-
if (rotation) line.rotation = rotation
|
|
951
|
-
if (name) line.name = name
|
|
952
|
-
if (stroke) line.strokes = [await createSolidPaint(stroke)]
|
|
953
|
-
if (strokeWeight !== undefined) line.strokeWeight = strokeWeight
|
|
954
|
-
await appendToParent(line, parentId)
|
|
955
|
-
return serializeNode(line)
|
|
938
|
+
const startCapValue = normalizeLineCap(startCap) ?? 'NONE'
|
|
939
|
+
const endCapValue = normalizeLineCap(endCap) ?? 'ARROW_LINES'
|
|
940
|
+
|
|
941
|
+
const vector = figma.createVector()
|
|
942
|
+
vector.x = x
|
|
943
|
+
vector.y = y
|
|
944
|
+
vector.name = name || 'Arrow'
|
|
945
|
+
|
|
946
|
+
vector.vectorNetwork = {
|
|
947
|
+
vertices: [
|
|
948
|
+
{ x: 0, y: 0, strokeCap: startCapValue },
|
|
949
|
+
{ x: length, y: 0, strokeCap: endCapValue }
|
|
950
|
+
],
|
|
951
|
+
segments: [{ start: 0, end: 1, tangentStart: { x: 0, y: 0 }, tangentEnd: { x: 0, y: 0 } }],
|
|
952
|
+
regions: []
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
if (stroke) vector.strokes = [await createSolidPaint(stroke)]
|
|
956
|
+
if (strokeWeight !== undefined) vector.strokeWeight = strokeWeight
|
|
957
|
+
if (rotation) vector.rotation = rotation
|
|
958
|
+
await appendToParent(vector, parentId)
|
|
959
|
+
return serializeNode(vector)
|
|
956
960
|
}
|
|
957
961
|
|
|
958
962
|
case 'create-polygon': {
|
|
@@ -2631,30 +2635,25 @@ async function handleCommand(command: string, args?: unknown): Promise<unknown>
|
|
|
2631
2635
|
const isText = type === 'text'
|
|
2632
2636
|
const processed = processProps(props || {}, isText)
|
|
2633
2637
|
|
|
2634
|
-
// Handle <
|
|
2635
|
-
if (type === '
|
|
2636
|
-
const startCapValue = normalizeLineCap(props.startCap as string | undefined)
|
|
2637
|
-
const endCapValue = normalizeLineCap(props.endCap as string | undefined)
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
stroke: processed.stroke as string | undefined,
|
|
2647
|
-
strokeWidth: processed.strokeWidth as number | undefined
|
|
2648
|
-
})
|
|
2649
|
-
}
|
|
2638
|
+
// Handle <arrow> - mark for VectorNetwork with caps
|
|
2639
|
+
if (type === 'arrow') {
|
|
2640
|
+
const startCapValue = normalizeLineCap(props.startCap as string | undefined) ?? 'NONE'
|
|
2641
|
+
const endCapValue = normalizeLineCap(props.endCap as string | undefined) ?? 'ARROW_LINES'
|
|
2642
|
+
|
|
2643
|
+
lineCapNodes.push({
|
|
2644
|
+
path: [...path],
|
|
2645
|
+
startCap: startCapValue,
|
|
2646
|
+
endCap: endCapValue,
|
|
2647
|
+
stroke: processed.stroke as string | undefined,
|
|
2648
|
+
strokeWidth: processed.strokeWidth as number | undefined
|
|
2649
|
+
})
|
|
2650
2650
|
|
|
2651
|
-
//
|
|
2651
|
+
// Create normal Line as placeholder (will be replaced)
|
|
2652
2652
|
const cleanProps = { ...processed }
|
|
2653
2653
|
delete cleanProps.startCap
|
|
2654
2654
|
delete cleanProps.endCap
|
|
2655
2655
|
delete cleanProps.__startCap
|
|
2656
2656
|
delete cleanProps.__endCap
|
|
2657
|
-
// Create normal Line as placeholder
|
|
2658
2657
|
return h(Line, cleanProps)
|
|
2659
2658
|
}
|
|
2660
2659
|
|