@pixerate/editor 0.223.7 → 0.223.9

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.
@@ -0,0 +1,148 @@
1
+ {
2
+ "prompt": "Apply our brand palette to this layout: the background is #f1faee, the big panel is primary #1d3557, and the small badge is accent #e63946.",
3
+ "fixture": {
4
+ "editor": "vector",
5
+ "width": 200,
6
+ "height": 120,
7
+ "colorTools": true,
8
+ "setup": [
9
+ {
10
+ "id": "vector.addShape",
11
+ "params": {
12
+ "kind": "rect",
13
+ "x": 0,
14
+ "y": 0,
15
+ "width": 200,
16
+ "height": 120,
17
+ "name": "Background",
18
+ "fill": "#ffffff",
19
+ "stroke": null
20
+ }
21
+ },
22
+ {
23
+ "id": "vector.addShape",
24
+ "params": {
25
+ "kind": "rect",
26
+ "x": 20,
27
+ "y": 20,
28
+ "width": 160,
29
+ "height": 80,
30
+ "name": "Panel",
31
+ "fill": "#334455",
32
+ "stroke": null
33
+ }
34
+ },
35
+ {
36
+ "id": "vector.addShape",
37
+ "params": {
38
+ "kind": "ellipse",
39
+ "x": 150,
40
+ "y": 10,
41
+ "width": 30,
42
+ "height": 30,
43
+ "name": "Badge",
44
+ "fill": "#ff6600",
45
+ "stroke": null
46
+ }
47
+ }
48
+ ]
49
+ },
50
+ "checks": [
51
+ {
52
+ "why": "each part in its brand colour",
53
+ "tool": "run_command",
54
+ "args": {
55
+ "id": "vector.list"
56
+ },
57
+ "expect": {
58
+ "result": {
59
+ "nodes": {
60
+ "$expr": "(() => { const f = (n) => (v.find((x) => x.name === n).fill || '').toLowerCase(); return f('Background') === '#f1faee' && f('Panel') === '#1d3557' && f('Badge') === '#e63946'; })()"
61
+ }
62
+ }
63
+ }
64
+ },
65
+ {
66
+ "why": "nothing moved",
67
+ "tool": "run_command",
68
+ "args": {
69
+ "id": "vector.list"
70
+ },
71
+ "expect": {
72
+ "result": {
73
+ "nodes": {
74
+ "$some": {
75
+ "name": "Badge",
76
+ "bounds": {
77
+ "x": 150,
78
+ "y": 10,
79
+ "width": 30,
80
+ "height": 30
81
+ }
82
+ }
83
+ }
84
+ }
85
+ }
86
+ }
87
+ ],
88
+ "solution": [
89
+ {
90
+ "tool": "run_command",
91
+ "args": {
92
+ "id": "vector.list"
93
+ }
94
+ },
95
+ {
96
+ "tool": "run_commands",
97
+ "args": {
98
+ "steps": [
99
+ {
100
+ "id": "vector.setStyle",
101
+ "params": {
102
+ "ids": [
103
+ {
104
+ "$read": "run_command",
105
+ "args": {
106
+ "id": "vector.list"
107
+ },
108
+ "path": "result.nodes.0.id"
109
+ }
110
+ ],
111
+ "fill": "#f1faee"
112
+ }
113
+ },
114
+ {
115
+ "id": "vector.setStyle",
116
+ "params": {
117
+ "ids": [
118
+ {
119
+ "$read": "run_command",
120
+ "args": {
121
+ "id": "vector.list"
122
+ },
123
+ "path": "result.nodes.1.id"
124
+ }
125
+ ],
126
+ "fill": "#1d3557"
127
+ }
128
+ },
129
+ {
130
+ "id": "vector.setStyle",
131
+ "params": {
132
+ "ids": [
133
+ {
134
+ "$read": "run_command",
135
+ "args": {
136
+ "id": "vector.list"
137
+ },
138
+ "path": "result.nodes.2.id"
139
+ }
140
+ ],
141
+ "fill": "#e63946"
142
+ }
143
+ }
144
+ ]
145
+ }
146
+ }
147
+ ]
148
+ }
@@ -0,0 +1,104 @@
1
+ {
2
+ "prompt": "The white text on our light-blue badge fails contrast. Fix it using a colour from our palette (#1d3557, #457b9d, #a8dadc, #f1faee, #e63946), keeping the badge light blue.",
3
+ "fixture": {
4
+ "editor": "vector",
5
+ "width": 120,
6
+ "height": 60,
7
+ "colorTools": true,
8
+ "setup": [
9
+ {
10
+ "id": "vector.addShape",
11
+ "params": {
12
+ "kind": "rect",
13
+ "x": 10,
14
+ "y": 10,
15
+ "width": 100,
16
+ "height": 40,
17
+ "name": "Badge",
18
+ "fill": "#a8dadc",
19
+ "stroke": null
20
+ }
21
+ },
22
+ {
23
+ "id": "vector.addShape",
24
+ "params": {
25
+ "kind": "rect",
26
+ "x": 30,
27
+ "y": 24,
28
+ "width": 60,
29
+ "height": 12,
30
+ "name": "Text",
31
+ "fill": "#ffffff",
32
+ "stroke": null
33
+ }
34
+ }
35
+ ]
36
+ },
37
+ "checks": [
38
+ {
39
+ "why": "the text uses a palette colour that reads on the badge at 4.5:1 or more",
40
+ "tool": "run_command",
41
+ "args": {
42
+ "id": "vector.list"
43
+ },
44
+ "expect": {
45
+ "result": {
46
+ "nodes": {
47
+ "$expr": "(() => { const L = (h) => { const c = [1, 3, 5].map((i) => parseInt(h.replace('#', '').padEnd(6, '0').slice(i - 1, i + 1), 16) / 255).map((x) => (x <= 0.04045 ? x / 12.92 : ((x + 0.055) / 1.055) ** 2.4)); return 0.2126 * c[0] + 0.7152 * c[1] + 0.0722 * c[2]; }; const cr = (a, b) => { const [x, y] = [L(a), L(b)].sort((p, q) => q - p); return (x + 0.05) / (y + 0.05); }; const t = v.find((n) => n.name === 'Text').fill.toLowerCase(); return ['#1d3557', '#457b9d', '#a8dadc', '#f1faee', '#e63946'].includes(t) && cr(t, v.find((n) => n.name === 'Badge').fill) >= 4.5; })()"
48
+ }
49
+ }
50
+ }
51
+ },
52
+ {
53
+ "why": "the badge stays light blue",
54
+ "tool": "run_command",
55
+ "args": {
56
+ "id": "vector.list"
57
+ },
58
+ "expect": {
59
+ "result": {
60
+ "nodes": {
61
+ "$some": {
62
+ "name": "Badge",
63
+ "fill": "#a8dadc"
64
+ }
65
+ }
66
+ }
67
+ }
68
+ }
69
+ ],
70
+ "solution": [
71
+ {
72
+ "tool": "check_color_contrast",
73
+ "args": {
74
+ "foreground": "#ffffff",
75
+ "background": "#a8dadc"
76
+ }
77
+ },
78
+ {
79
+ "tool": "check_color_contrast",
80
+ "args": {
81
+ "foreground": "#1d3557",
82
+ "background": "#a8dadc"
83
+ }
84
+ },
85
+ {
86
+ "tool": "run_command",
87
+ "args": {
88
+ "id": "vector.setStyle",
89
+ "params": {
90
+ "ids": [
91
+ {
92
+ "$read": "run_command",
93
+ "args": {
94
+ "id": "vector.list"
95
+ },
96
+ "path": "result.nodes.1.id"
97
+ }
98
+ ],
99
+ "fill": "#1d3557"
100
+ }
101
+ }
102
+ }
103
+ ]
104
+ }
@@ -0,0 +1,148 @@
1
+ {
2
+ "prompt": "These colours are almost our brand colours but not exact. Snap each shape to the nearest colour in the palette: #1d3557, #457b9d, #a8dadc, #e63946.",
3
+ "fixture": {
4
+ "editor": "vector",
5
+ "width": 160,
6
+ "height": 40,
7
+ "colorTools": true,
8
+ "setup": [
9
+ {
10
+ "id": "vector.addShape",
11
+ "params": {
12
+ "kind": "rect",
13
+ "x": 0,
14
+ "y": 0,
15
+ "width": 40,
16
+ "height": 40,
17
+ "name": "A",
18
+ "fill": "#1f3759",
19
+ "stroke": null
20
+ }
21
+ },
22
+ {
23
+ "id": "vector.addShape",
24
+ "params": {
25
+ "kind": "rect",
26
+ "x": 40,
27
+ "y": 0,
28
+ "width": 40,
29
+ "height": 40,
30
+ "name": "B",
31
+ "fill": "#4a7fa0",
32
+ "stroke": null
33
+ }
34
+ },
35
+ {
36
+ "id": "vector.addShape",
37
+ "params": {
38
+ "kind": "rect",
39
+ "x": 80,
40
+ "y": 0,
41
+ "width": 40,
42
+ "height": 40,
43
+ "name": "C",
44
+ "fill": "#aadcde",
45
+ "stroke": null
46
+ }
47
+ },
48
+ {
49
+ "id": "vector.addShape",
50
+ "params": {
51
+ "kind": "rect",
52
+ "x": 120,
53
+ "y": 0,
54
+ "width": 40,
55
+ "height": 40,
56
+ "name": "D",
57
+ "fill": "#e43b48",
58
+ "stroke": null
59
+ }
60
+ }
61
+ ]
62
+ },
63
+ "checks": [
64
+ {
65
+ "why": "each shape in its nearest brand colour",
66
+ "tool": "run_command",
67
+ "args": {
68
+ "id": "vector.list"
69
+ },
70
+ "expect": {
71
+ "result": {
72
+ "nodes": {
73
+ "$expr": "v.map((n) => (n.fill || '').toLowerCase()).join() === '#1d3557,#457b9d,#a8dadc,#e63946'"
74
+ }
75
+ }
76
+ }
77
+ }
78
+ ],
79
+ "solution": [
80
+ {
81
+ "tool": "run_commands",
82
+ "args": {
83
+ "steps": [
84
+ {
85
+ "id": "vector.setStyle",
86
+ "params": {
87
+ "ids": [
88
+ {
89
+ "$read": "run_command",
90
+ "args": {
91
+ "id": "vector.list"
92
+ },
93
+ "path": "result.nodes.0.id"
94
+ }
95
+ ],
96
+ "fill": "#1d3557"
97
+ }
98
+ },
99
+ {
100
+ "id": "vector.setStyle",
101
+ "params": {
102
+ "ids": [
103
+ {
104
+ "$read": "run_command",
105
+ "args": {
106
+ "id": "vector.list"
107
+ },
108
+ "path": "result.nodes.1.id"
109
+ }
110
+ ],
111
+ "fill": "#457b9d"
112
+ }
113
+ },
114
+ {
115
+ "id": "vector.setStyle",
116
+ "params": {
117
+ "ids": [
118
+ {
119
+ "$read": "run_command",
120
+ "args": {
121
+ "id": "vector.list"
122
+ },
123
+ "path": "result.nodes.2.id"
124
+ }
125
+ ],
126
+ "fill": "#a8dadc"
127
+ }
128
+ },
129
+ {
130
+ "id": "vector.setStyle",
131
+ "params": {
132
+ "ids": [
133
+ {
134
+ "$read": "run_command",
135
+ "args": {
136
+ "id": "vector.list"
137
+ },
138
+ "path": "result.nodes.3.id"
139
+ }
140
+ ],
141
+ "fill": "#e63946"
142
+ }
143
+ }
144
+ ]
145
+ }
146
+ }
147
+ ]
148
+ }
@@ -25,6 +25,14 @@ from `get_editor_state`; component and set ids from `list_components`. Tools tha
25
25
  just selected with `canvas_select`. See `pixerate-agent-tools` for namespacing, `run_commands`
26
26
  batching and error codes.
27
27
 
28
+ ## Workflow skills
29
+
30
+ For these jobs, load the workflow skill too: it has the method, the checks between steps and
31
+ the pitfalls, and uses the tools below.
32
+
33
+ - `pixerate-canvas-design-system-components`: components, instances, variant sets and overrides.
34
+ - `pixerate-canvas-layout`: align, distribute, order and lock.
35
+
28
36
  ## Working method
29
37
 
30
38
  1. **Read.** `get_editor_state` with `includeDocument: false` returns `canvas.nodes` and
@@ -0,0 +1,103 @@
1
+ ---
2
+ name: pixerate-canvas-design-system-components
3
+ description: The design system components workflow in the Pixerate canvas - turning repeated design into main components, placing instances instead of copies, combining versions into a component set with named variant properties and values, adding variants, keeping instances linked, swapping, resetting and pushing overrides, and keeping the library tidy and named. Use when asked to build or tidy a design system, component library or UI kit, make a component, instance, variant or component set, add a state (hover, disabled) or size, rename variant properties, or replace copies with instances, or when create_component, combine_as_variants, add_variant or create_instance are available. Load with pixerate-canvas, which lists every tool.
4
+ metadata:
5
+ kind: workflow
6
+ reference: pixerate-canvas
7
+ ---
8
+
9
+ # Building design system components
10
+
11
+ A design system replaces copies with components. A main component holds the design; instances
12
+ show it elsewhere and update when it changes, with per-instance overrides where they differ.
13
+ Versions of one thing (styles, states, sizes) become variants in a component set, described by
14
+ properties ("Style=Primary, State=Disabled") a person or agent can switch between. Names and
15
+ properties are the interface: keep them clear and consistent.
16
+
17
+ This skill is the method. `pixerate-canvas` has the full tool reference.
18
+
19
+ ## Goal and quality bar
20
+
21
+ - Anything used more than once is a main component; its uses are linked instances
22
+ (`inspect_instance` `status: "linked"`), not copies.
23
+ - Versions of one element are variants in one component set, with named properties (Style,
24
+ State, Size) and named values (Primary, Disabled, Large), never "Property 1" and "Variant2".
25
+ - Every combination of property values is unique; the default variant is the most common one.
26
+ - Instances keep their link; detach only when one must diverge for good.
27
+ - Components are named by what they are ("Button", "Card"), sets list their options clearly.
28
+
29
+ ## Inputs to confirm
30
+
31
+ - **What becomes a component**, and which existing copies should become its instances.
32
+ - **Properties and values** for variants (Style: Primary / Secondary; State: Default / Hover /
33
+ Disabled; Size: Small / Medium / Large).
34
+ - **Naming conventions** of the team's library.
35
+
36
+ ## Working method
37
+
38
+ 1. **Read.** `list_components` (components, sets, their variants and options) and
39
+ `get_canvas_document` for the nodes.
40
+ **Check:** you know which nodes are already components and which are copies.
41
+ 2. **Make components.** `create_component` with the frame's id(s).
42
+ **Check:** `list_components` lists it with its name.
43
+ 3. **Replace copies with instances.** `create_instance` with `componentId`, `x`, `y`; remove the
44
+ copies once instances stand in their place.
45
+ **Check:** `get_canvas_document` shows instance nodes where the copies were.
46
+ 4. **Combine versions into variants.** `create_component` each version, then
47
+ `combine_as_variants` with their ids; the set gets generic names ("Property 1", "Default",
48
+ "Variant2"). Rename at once: `rename_variant_property` (`name`, `newName`, `setId`) and
49
+ `rename_variant_value` (`property`, `value`, `newValue`, `setId`).
50
+ **Check:** `list_components` `sets[].options` shows the real names; each variant's `variant`
51
+ map is right.
52
+ 5. **Add variants.** `add_variant` with `setId` and the new `variant` values (it duplicates the
53
+ default, or `from`); `set_variant_properties` to change a variant's values.
54
+ **Check:** the set lists every combination once.
55
+ 6. **Maintain instances.** `swap_instance` to another component or variant, `reset_overrides` to
56
+ go back to the main, `push_overrides` to promote an instance's change to the main,
57
+ `go_to_main_component` to edit the source.
58
+
59
+ ## Decision table
60
+
61
+ | Situation | Tool |
62
+ | --- | --- |
63
+ | The same element appears several times | `create_component`, then `create_instance` for each use |
64
+ | Versions of one element (styles, states, sizes) | `combine_as_variants`, then rename properties and values |
65
+ | A new state or size | `add_variant` with `variant` values |
66
+ | An instance should look like another variant | `set_instance_properties` or `swap_instance` |
67
+ | An instance's change belongs in the main | `push_overrides` |
68
+ | An instance drifted by accident | `reset_overrides` |
69
+ | One copy must diverge permanently | `detach_instance` (last resort) |
70
+
71
+ ## Recipes
72
+
73
+ **Card component with two instances.** `create_component` `{ ids: ["card"] }` →
74
+ `create_instance` `{ componentId: "card", x: 0, y: 150 }` and `{ componentId: "card", x: 240,
75
+ y: 150 }`.
76
+
77
+ **Primary and Secondary variants.** `create_component` each button → `combine_as_variants`
78
+ `{ ids }` → `rename_variant_property` `{ name: "Property 1", newName: "Style", setId }` →
79
+ `rename_variant_value` `Default` → `Primary`, `Variant2` → `Secondary`.
80
+
81
+ **A Disabled variant.** `add_variant` `{ setId, variant: { Style: "Disabled" } }`.
82
+
83
+ ## Pitfalls
84
+
85
+ - **Copies instead of instances** drift apart and cannot be updated together.
86
+ - **Generic variant names** ("Property 1", "Variant2") left after combining make the set unusable;
87
+ rename right away.
88
+ - **The rename and add tools need the set** (`setId` from `list_components`) when nothing is
89
+ selected.
90
+ - **Duplicate combinations** are refused; every variant needs a unique set of values.
91
+ - **Detaching to make a small change** loses future updates; override instead.
92
+ - **Combining unrelated components** into one set; a set is one element's versions.
93
+
94
+ ## Tools used
95
+
96
+ - `list_components`, `inspect_instance`: components, sets, variants and instance status
97
+ - `get_canvas_document`: the nodes, to check placement
98
+ - `create_component`, `create_instance`: components and their instances
99
+ - `combine_as_variants`, `add_variant`, `remove_variant`, `set_variant_properties`: component sets
100
+ - `rename_variant_property`, `rename_variant_value`: clear property and value names
101
+ - `set_instance_properties`, `swap_instance`, `reset_overrides`, `push_overrides`: instances and overrides
102
+ - `detach_instance`, `go_to_main_component`, `restore_main_component`: break links, edit or restore mains
103
+ - `undo_canvas`: take back a step
@@ -0,0 +1,172 @@
1
+ {
2
+ "prompt": "Add a Disabled style to the button component set, as a third variant of its Style property.",
3
+ "fixture": {
4
+ "editor": "canvas",
5
+ "nodes": [
6
+ {
7
+ "id": "primary",
8
+ "type": "group",
9
+ "position": {
10
+ "x": 0,
11
+ "y": 0
12
+ },
13
+ "width": 120,
14
+ "height": 40,
15
+ "data": {
16
+ "label": "Button / Primary"
17
+ }
18
+ },
19
+ {
20
+ "id": "pbg",
21
+ "type": "shape",
22
+ "parentId": "primary",
23
+ "position": {
24
+ "x": 0,
25
+ "y": 0
26
+ },
27
+ "width": 120,
28
+ "height": 40,
29
+ "data": {
30
+ "label": "Bg",
31
+ "shape": {
32
+ "kind": "rect",
33
+ "fill": "#1d3557"
34
+ }
35
+ }
36
+ },
37
+ {
38
+ "id": "secondary",
39
+ "type": "group",
40
+ "position": {
41
+ "x": 0,
42
+ "y": 60
43
+ },
44
+ "width": 120,
45
+ "height": 40,
46
+ "data": {
47
+ "label": "Button / Secondary"
48
+ }
49
+ },
50
+ {
51
+ "id": "sbg",
52
+ "type": "shape",
53
+ "parentId": "secondary",
54
+ "position": {
55
+ "x": 0,
56
+ "y": 0
57
+ },
58
+ "width": 120,
59
+ "height": 40,
60
+ "data": {
61
+ "label": "Bg",
62
+ "shape": {
63
+ "kind": "rect",
64
+ "fill": "#ffffff"
65
+ }
66
+ }
67
+ }
68
+ ],
69
+ "setup": [
70
+ {
71
+ "tool": "create_component",
72
+ "args": {
73
+ "ids": [
74
+ "primary"
75
+ ]
76
+ }
77
+ },
78
+ {
79
+ "tool": "create_component",
80
+ "args": {
81
+ "ids": [
82
+ "secondary"
83
+ ]
84
+ }
85
+ },
86
+ {
87
+ "tool": "combine_as_variants",
88
+ "args": {
89
+ "ids": [
90
+ "primary",
91
+ "secondary"
92
+ ]
93
+ }
94
+ },
95
+ {
96
+ "tool": "rename_variant_property",
97
+ "args": {
98
+ "name": "Property 1",
99
+ "newName": "Style",
100
+ "setId": {
101
+ "$read": "list_components",
102
+ "path": "sets.0.id"
103
+ }
104
+ }
105
+ },
106
+ {
107
+ "tool": "rename_variant_value",
108
+ "args": {
109
+ "property": "Style",
110
+ "value": "Default",
111
+ "newValue": "Primary",
112
+ "setId": {
113
+ "$read": "list_components",
114
+ "path": "sets.0.id"
115
+ }
116
+ }
117
+ },
118
+ {
119
+ "tool": "rename_variant_value",
120
+ "args": {
121
+ "property": "Style",
122
+ "value": "Variant2",
123
+ "newValue": "Secondary",
124
+ "setId": {
125
+ "$read": "list_components",
126
+ "path": "sets.0.id"
127
+ }
128
+ }
129
+ }
130
+ ]
131
+ },
132
+ "checks": [
133
+ {
134
+ "why": "three variants: Primary, Secondary and Disabled",
135
+ "tool": "list_components",
136
+ "expect": {
137
+ "sets": [
138
+ {
139
+ "variants": {
140
+ "$length": 3
141
+ },
142
+ "options": [
143
+ {
144
+ "name": "Style",
145
+ "values": {
146
+ "$expr": "[...v].sort().join() === 'Disabled,Primary,Secondary'"
147
+ }
148
+ }
149
+ ]
150
+ }
151
+ ]
152
+ }
153
+ }
154
+ ],
155
+ "solution": [
156
+ {
157
+ "tool": "list_components"
158
+ },
159
+ {
160
+ "tool": "add_variant",
161
+ "args": {
162
+ "setId": {
163
+ "$read": "list_components",
164
+ "path": "sets.0.id"
165
+ },
166
+ "variant": {
167
+ "Style": "Disabled"
168
+ }
169
+ }
170
+ }
171
+ ]
172
+ }