@radicool/throughline 0.24.0 → 0.26.0

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.
Files changed (62) hide show
  1. package/README.md +8 -4
  2. package/adapters/codex/AGENTS.md +2 -0
  3. package/adapters/codex/prompts/check-figma.md +41 -0
  4. package/adapters/codex/prompts/component-builder.md +5 -3
  5. package/adapters/codex/prompts/compose-figma.md +59 -0
  6. package/adapters/codex/prompts/document-component.md +3 -2
  7. package/adapters/cursor/.cursor/commands/check-figma.md +41 -0
  8. package/adapters/cursor/.cursor/commands/compose-figma.md +59 -0
  9. package/adapters/cursor/.cursor/commands/document-component.md +3 -2
  10. package/adapters/cursor/.cursor/rules/component-builder.mdc +5 -3
  11. package/adapters/generic/AGENTS.md +2 -0
  12. package/adapters/generic/commands/check-figma.md +41 -0
  13. package/adapters/generic/commands/compose-figma.md +59 -0
  14. package/adapters/generic/commands/document-component.md +3 -2
  15. package/adapters/generic/skills/component-builder/SKILL.md +5 -3
  16. package/package.json +1 -1
  17. package/references/doc-card-builder.md +62 -15
  18. package/references/figma-adherence.md +463 -0
  19. package/references/figma-checks.md +106 -43
  20. package/references/figma-compose.md +896 -0
  21. package/scripts/README.md +8 -2
  22. package/scripts/build-doc-card-builder.mjs +16 -0
  23. package/scripts/build-figma-checks.mjs +208 -23
  24. package/scripts/doc-card-payload.mjs +115 -0
  25. package/scripts/install.mjs +7 -1
  26. package/scripts/lib/doc-card-plan.mjs +37 -0
  27. package/scripts/lib/doc-card-render.figma.js +9 -15
  28. package/scripts/lib/figma-adherence-read.figma.js +228 -0
  29. package/scripts/lib/figma-adherence.mjs +146 -0
  30. package/scripts/lib/figma-checks-read.figma.js +43 -43
  31. package/scripts/lib/figma-checks.mjs +16 -5
  32. package/scripts/lib/figma-compose.figma.js +326 -0
  33. package/scripts/lib/figma-compose.mjs +317 -0
  34. package/scripts/lib/figma-variables-read.figma.js +39 -0
  35. package/scripts/lib/fixtures/figma-adherence/clean.json +90 -0
  36. package/scripts/lib/fixtures/figma-adherence/detached-library.json +116 -0
  37. package/scripts/lib/fixtures/figma-adherence/ds01-gaps.json +84 -0
  38. package/scripts/lib/fixtures/figma-adherence/inert-all.json +45 -0
  39. package/scripts/lib/fixtures/figma-adherence/mixed-text.json +61 -0
  40. package/scripts/lib/fixtures/figma-adherence/nothing-scanned.json +49 -0
  41. package/scripts/lib/fixtures/figma-adherence/off-scale-gap.json +65 -0
  42. package/scripts/lib/fixtures/figma-adherence/override-raw.json +72 -0
  43. package/scripts/lib/fixtures/figma-adherence/padding-raw.json +74 -0
  44. package/scripts/lib/fixtures/figma-adherence/raw-colour-token.json +70 -0
  45. package/scripts/lib/fixtures/figma-adherence/root-radius.json +88 -0
  46. package/scripts/lib/fixtures/figma-adherence/skip-colour.json +86 -0
  47. package/scripts/lib/fixtures/figma-adherence/zygarden-override-bound.json +85 -0
  48. package/scripts/lib/fixtures/figma-adherence/zygarden-text-raw.json +208 -0
  49. package/scripts/lib/fixtures/figma-compose/casing-and-suffix.json +8 -0
  50. package/scripts/lib/fixtures/figma-compose/fill-in-unlaid-slot.json +7 -0
  51. package/scripts/lib/fixtures/figma-compose/hug-on-fixed-component.json +34 -0
  52. package/scripts/lib/fixtures/figma-compose/inventory.json +295 -0
  53. package/scripts/lib/fixtures/figma-compose/many-errors.json +8 -0
  54. package/scripts/lib/fixtures/figma-compose/missing-component.json +7 -0
  55. package/scripts/lib/fixtures/figma-compose/name-taken.json +6 -0
  56. package/scripts/lib/fixtures/figma-compose/padding-sides.json +23 -0
  57. package/scripts/lib/fixtures/figma-compose/radius-kind.json +27 -0
  58. package/scripts/lib/fixtures/figma-compose/raw-number.json +5 -0
  59. package/scripts/lib/fixtures/figma-compose/sign-in-ok.json +16 -0
  60. package/scripts/lib/fixtures/figma-compose/slot-ok.json +9 -0
  61. package/scripts/lib/fixtures/figma-compose/unknown-prop-and-option.json +7 -0
  62. package/scripts/lib/fixtures/figma-compose/wrong-kind.json +5 -0
@@ -0,0 +1,70 @@
1
+ {
2
+ "covers": "an unbound fill whose colour a token has fails, naming the token",
3
+ "snapshot": {
4
+ "fileKey": "FILE",
5
+ "screens": [
6
+ {
7
+ "id": "0:1",
8
+ "name": "Screen"
9
+ }
10
+ ],
11
+ "nodes": [
12
+ {
13
+ "id": "1:1",
14
+ "path": "Templates / Screen / Node",
15
+ "isRoot": false,
16
+ "inInstance": false,
17
+ "overridden": [],
18
+ "paints": [
19
+ {
20
+ "kind": "fill",
21
+ "hex": "#ffffff",
22
+ "bound": false,
23
+ "styled": false
24
+ }
25
+ ],
26
+ "mixedPaints": false,
27
+ "gap": null,
28
+ "padding": [],
29
+ "radius": [],
30
+ "detached": null
31
+ }
32
+ ],
33
+ "tokens": {
34
+ "colours": {
35
+ "#ffffff": [
36
+ "color/bg/canvas"
37
+ ],
38
+ "#111827": [
39
+ "color/text/primary"
40
+ ]
41
+ },
42
+ "gap": {
43
+ "8": [
44
+ "spacing/2"
45
+ ],
46
+ "12": [
47
+ "spacing/3"
48
+ ],
49
+ "16": [
50
+ "spacing/4"
51
+ ]
52
+ },
53
+ "radius": {
54
+ "8": [
55
+ "radius/md"
56
+ ],
57
+ "32": [
58
+ "radius/xl"
59
+ ]
60
+ }
61
+ }
62
+ },
63
+ "expected": {
64
+ "pass": false,
65
+ "failures": [
66
+ "raw-colour"
67
+ ],
68
+ "advisories": 0
69
+ }
70
+ }
@@ -0,0 +1,88 @@
1
+ {
2
+ "covers": "Zygarden 2026-10-13: the screen root radius 32 is skipped; the same radius on a child fails",
3
+ "snapshot": {
4
+ "fileKey": "FILE",
5
+ "screens": [
6
+ {
7
+ "id": "0:1",
8
+ "name": "Screen"
9
+ }
10
+ ],
11
+ "nodes": [
12
+ {
13
+ "id": "3:1",
14
+ "path": "Templates / Example 1",
15
+ "isRoot": true,
16
+ "inInstance": false,
17
+ "overridden": [],
18
+ "paints": [],
19
+ "mixedPaints": false,
20
+ "gap": null,
21
+ "padding": [],
22
+ "radius": [
23
+ {
24
+ "corner": "all",
25
+ "value": 32,
26
+ "bound": false
27
+ }
28
+ ],
29
+ "detached": null
30
+ },
31
+ {
32
+ "id": "3:2",
33
+ "path": "Templates / Example 1 / Card",
34
+ "isRoot": false,
35
+ "inInstance": false,
36
+ "overridden": [],
37
+ "paints": [],
38
+ "mixedPaints": false,
39
+ "gap": null,
40
+ "padding": [],
41
+ "radius": [
42
+ {
43
+ "corner": "all",
44
+ "value": 32,
45
+ "bound": false
46
+ }
47
+ ],
48
+ "detached": null
49
+ }
50
+ ],
51
+ "tokens": {
52
+ "colours": {
53
+ "#ffffff": [
54
+ "color/bg/canvas"
55
+ ],
56
+ "#111827": [
57
+ "color/text/primary"
58
+ ]
59
+ },
60
+ "gap": {
61
+ "8": [
62
+ "spacing/2"
63
+ ],
64
+ "12": [
65
+ "spacing/3"
66
+ ],
67
+ "16": [
68
+ "spacing/4"
69
+ ]
70
+ },
71
+ "radius": {
72
+ "8": [
73
+ "radius/md"
74
+ ],
75
+ "32": [
76
+ "radius/xl"
77
+ ]
78
+ }
79
+ }
80
+ },
81
+ "expected": {
82
+ "pass": false,
83
+ "failures": [
84
+ "raw-dimension"
85
+ ],
86
+ "advisories": 0
87
+ }
88
+ }
@@ -0,0 +1,86 @@
1
+ {
2
+ "covers": "a skipped rule runs nothing and its inert check does not fire",
3
+ "skip": [
4
+ "raw-colour"
5
+ ],
6
+ "tokens": {
7
+ "colours": {},
8
+ "gap": {
9
+ "8": [
10
+ "spacing/2"
11
+ ],
12
+ "12": [
13
+ "spacing/3"
14
+ ],
15
+ "16": [
16
+ "spacing/4"
17
+ ]
18
+ },
19
+ "radius": {
20
+ "8": [
21
+ "radius/md"
22
+ ],
23
+ "32": [
24
+ "radius/xl"
25
+ ]
26
+ }
27
+ },
28
+ "snapshot": {
29
+ "fileKey": "FILE",
30
+ "screens": [
31
+ {
32
+ "id": "0:1",
33
+ "name": "Screen"
34
+ }
35
+ ],
36
+ "nodes": [
37
+ {
38
+ "id": "1:1",
39
+ "path": "Templates / Screen / Node",
40
+ "isRoot": false,
41
+ "inInstance": false,
42
+ "overridden": [],
43
+ "paints": [
44
+ {
45
+ "kind": "fill",
46
+ "hex": "#ffffff",
47
+ "bound": false,
48
+ "styled": false
49
+ }
50
+ ],
51
+ "mixedPaints": false,
52
+ "gap": null,
53
+ "padding": [],
54
+ "radius": [],
55
+ "detached": null
56
+ }
57
+ ],
58
+ "tokens": {
59
+ "colours": {},
60
+ "gap": {
61
+ "8": [
62
+ "spacing/2"
63
+ ],
64
+ "12": [
65
+ "spacing/3"
66
+ ],
67
+ "16": [
68
+ "spacing/4"
69
+ ]
70
+ },
71
+ "radius": {
72
+ "8": [
73
+ "radius/md"
74
+ ],
75
+ "32": [
76
+ "radius/xl"
77
+ ]
78
+ }
79
+ }
80
+ },
81
+ "expected": {
82
+ "pass": true,
83
+ "failures": [],
84
+ "advisories": 0
85
+ }
86
+ }
@@ -0,0 +1,85 @@
1
+ {
2
+ "covers": "Zygarden 2026-10-13: overridden fills that are bound pass",
3
+ "snapshot": {
4
+ "fileKey": "FILE",
5
+ "screens": [
6
+ {
7
+ "id": "0:1",
8
+ "name": "Screen"
9
+ }
10
+ ],
11
+ "nodes": [
12
+ {
13
+ "id": "1:1",
14
+ "path": "Templates / Screen / Node",
15
+ "isRoot": false,
16
+ "inInstance": true,
17
+ "overridden": [
18
+ "fills"
19
+ ],
20
+ "paints": [
21
+ {
22
+ "kind": "fill",
23
+ "hex": "#111827",
24
+ "bound": true,
25
+ "styled": false
26
+ }
27
+ ],
28
+ "mixedPaints": false,
29
+ "gap": null,
30
+ "padding": [],
31
+ "radius": [],
32
+ "detached": null
33
+ },
34
+ {
35
+ "id": "1:2",
36
+ "path": "Templates / Screen / Node",
37
+ "isRoot": false,
38
+ "inInstance": true,
39
+ "overridden": [
40
+ "fills"
41
+ ],
42
+ "paints": [],
43
+ "mixedPaints": false,
44
+ "gap": null,
45
+ "padding": [],
46
+ "radius": [],
47
+ "detached": null
48
+ }
49
+ ],
50
+ "tokens": {
51
+ "colours": {
52
+ "#ffffff": [
53
+ "color/bg/canvas"
54
+ ],
55
+ "#111827": [
56
+ "color/text/primary"
57
+ ]
58
+ },
59
+ "gap": {
60
+ "8": [
61
+ "spacing/2"
62
+ ],
63
+ "12": [
64
+ "spacing/3"
65
+ ],
66
+ "16": [
67
+ "spacing/4"
68
+ ]
69
+ },
70
+ "radius": {
71
+ "8": [
72
+ "radius/md"
73
+ ],
74
+ "32": [
75
+ "radius/xl"
76
+ ]
77
+ }
78
+ }
79
+ },
80
+ "expected": {
81
+ "pass": true,
82
+ "failures": [],
83
+ "advisories": 0
84
+ }
85
+ }
@@ -0,0 +1,208 @@
1
+ {
2
+ "covers": "Zygarden 2026-10-13: 8 text fills #e8e7e7, which no token has: advisories, not failures",
3
+ "snapshot": {
4
+ "fileKey": "FILE",
5
+ "screens": [
6
+ {
7
+ "id": "0:1",
8
+ "name": "Screen"
9
+ }
10
+ ],
11
+ "nodes": [
12
+ {
13
+ "id": "10:1",
14
+ "path": "Templates / Example 1 / My tournaments",
15
+ "isRoot": false,
16
+ "inInstance": false,
17
+ "overridden": [],
18
+ "paints": [
19
+ {
20
+ "kind": "fill",
21
+ "hex": "#e8e7e7",
22
+ "bound": false,
23
+ "styled": false
24
+ }
25
+ ],
26
+ "mixedPaints": false,
27
+ "gap": null,
28
+ "padding": [],
29
+ "radius": [],
30
+ "detached": null
31
+ },
32
+ {
33
+ "id": "10:2",
34
+ "path": "Templates / Example 2 / My tournaments",
35
+ "isRoot": false,
36
+ "inInstance": false,
37
+ "overridden": [],
38
+ "paints": [
39
+ {
40
+ "kind": "fill",
41
+ "hex": "#e8e7e7",
42
+ "bound": false,
43
+ "styled": false
44
+ }
45
+ ],
46
+ "mixedPaints": false,
47
+ "gap": null,
48
+ "padding": [],
49
+ "radius": [],
50
+ "detached": null
51
+ },
52
+ {
53
+ "id": "10:3",
54
+ "path": "Templates / Example 3 / My tournaments",
55
+ "isRoot": false,
56
+ "inInstance": false,
57
+ "overridden": [],
58
+ "paints": [
59
+ {
60
+ "kind": "fill",
61
+ "hex": "#e8e7e7",
62
+ "bound": false,
63
+ "styled": false
64
+ }
65
+ ],
66
+ "mixedPaints": false,
67
+ "gap": null,
68
+ "padding": [],
69
+ "radius": [],
70
+ "detached": null
71
+ },
72
+ {
73
+ "id": "10:4",
74
+ "path": "Templates / Example 4 / My tournaments",
75
+ "isRoot": false,
76
+ "inInstance": false,
77
+ "overridden": [],
78
+ "paints": [
79
+ {
80
+ "kind": "fill",
81
+ "hex": "#e8e7e7",
82
+ "bound": false,
83
+ "styled": false
84
+ }
85
+ ],
86
+ "mixedPaints": false,
87
+ "gap": null,
88
+ "padding": [],
89
+ "radius": [],
90
+ "detached": null
91
+ },
92
+ {
93
+ "id": "10:5",
94
+ "path": "Templates / Example 5 / My tournaments",
95
+ "isRoot": false,
96
+ "inInstance": false,
97
+ "overridden": [],
98
+ "paints": [
99
+ {
100
+ "kind": "fill",
101
+ "hex": "#e8e7e7",
102
+ "bound": false,
103
+ "styled": false
104
+ }
105
+ ],
106
+ "mixedPaints": false,
107
+ "gap": null,
108
+ "padding": [],
109
+ "radius": [],
110
+ "detached": null
111
+ },
112
+ {
113
+ "id": "10:6",
114
+ "path": "Templates / Example 6 / My tournaments",
115
+ "isRoot": false,
116
+ "inInstance": false,
117
+ "overridden": [],
118
+ "paints": [
119
+ {
120
+ "kind": "fill",
121
+ "hex": "#e8e7e7",
122
+ "bound": false,
123
+ "styled": false
124
+ }
125
+ ],
126
+ "mixedPaints": false,
127
+ "gap": null,
128
+ "padding": [],
129
+ "radius": [],
130
+ "detached": null
131
+ },
132
+ {
133
+ "id": "10:7",
134
+ "path": "Templates / Example 7 / My tournaments",
135
+ "isRoot": false,
136
+ "inInstance": false,
137
+ "overridden": [],
138
+ "paints": [
139
+ {
140
+ "kind": "fill",
141
+ "hex": "#e8e7e7",
142
+ "bound": false,
143
+ "styled": false
144
+ }
145
+ ],
146
+ "mixedPaints": false,
147
+ "gap": null,
148
+ "padding": [],
149
+ "radius": [],
150
+ "detached": null
151
+ },
152
+ {
153
+ "id": "10:8",
154
+ "path": "Templates / Example 8 / My tournaments",
155
+ "isRoot": false,
156
+ "inInstance": false,
157
+ "overridden": [],
158
+ "paints": [
159
+ {
160
+ "kind": "fill",
161
+ "hex": "#e8e7e7",
162
+ "bound": false,
163
+ "styled": false
164
+ }
165
+ ],
166
+ "mixedPaints": false,
167
+ "gap": null,
168
+ "padding": [],
169
+ "radius": [],
170
+ "detached": null
171
+ }
172
+ ],
173
+ "tokens": {
174
+ "colours": {
175
+ "#ffffff": [
176
+ "color/bg/canvas"
177
+ ],
178
+ "#111827": [
179
+ "color/text/primary"
180
+ ]
181
+ },
182
+ "gap": {
183
+ "8": [
184
+ "spacing/2"
185
+ ],
186
+ "12": [
187
+ "spacing/3"
188
+ ],
189
+ "16": [
190
+ "spacing/4"
191
+ ]
192
+ },
193
+ "radius": {
194
+ "8": [
195
+ "radius/md"
196
+ ],
197
+ "32": [
198
+ "radius/xl"
199
+ ]
200
+ }
201
+ }
202
+ },
203
+ "expected": {
204
+ "pass": true,
205
+ "failures": [],
206
+ "advisories": 8
207
+ }
208
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "covers": "set, prop and option names match case-folded and without the #id suffix",
3
+ "description": { "screen": "Menu", "page": "Screens", "width": 390, "root": { "layout": "vertical", "children": [
4
+ { "component": "select menu item", "props": { "state": "SELECTED", "label": "One" } },
5
+ { "component": "BUTTON", "props": { "State": "default", "LABEL": "Go" } }
6
+ ] } },
7
+ "expected": { "ok": true, "errors": [] }
8
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "covers": "fill inside a slot with no auto layout would throw in Figma, so it is rejected first",
3
+ "description": { "screen": "X", "page": "Screens", "width": 390, "root": { "layout": "vertical", "children": [
4
+ { "component": "Sheet", "slots": { "Content": [ { "layout": "vertical", "sizing": { "horizontal": "fill" } } ] } }
5
+ ] } },
6
+ "expected": { "ok": false, "errors": ["invalid"] }
7
+ }
@@ -0,0 +1,34 @@
1
+ {
2
+ "covers": "hug on a component without auto layout would throw in Figma, so it is rejected; fill is fine",
3
+ "description": {
4
+ "screen": "X",
5
+ "page": "Screens",
6
+ "width": 390,
7
+ "root": {
8
+ "layout": "vertical",
9
+ "children": [
10
+ {
11
+ "component": "Spinner",
12
+ "sizing": {
13
+ "horizontal": "hug"
14
+ }
15
+ },
16
+ {
17
+ "component": "Spinner",
18
+ "sizing": {
19
+ "horizontal": "fill"
20
+ }
21
+ },
22
+ {
23
+ "component": "Spinner"
24
+ }
25
+ ]
26
+ }
27
+ },
28
+ "expected": {
29
+ "ok": false,
30
+ "errors": [
31
+ "invalid"
32
+ ]
33
+ }
34
+ }