@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.
- package/dist/tools/skill-evals.d.cts +10 -1
- package/dist/tools/skill-evals.d.ts +10 -1
- package/package.json +1 -1
- package/skills/README.md +7 -2
- package/skills/pixerate-accessibility-audit/SKILL.md +98 -0
- package/skills/pixerate-accessibility-audit/evals/button-label-contrast.json +97 -0
- package/skills/pixerate-accessibility-audit/evals/distinct-for-cvd.json +160 -0
- package/skills/pixerate-accessibility-audit/evals/icon-non-text-contrast.json +109 -0
- package/skills/pixerate-brand-application/SKILL.md +99 -0
- package/skills/pixerate-brand-application/evals/apply-palette.json +148 -0
- package/skills/pixerate-brand-application/evals/readable-on-brand.json +104 -0
- package/skills/pixerate-brand-application/evals/snap-to-palette.json +148 -0
- package/skills/pixerate-canvas/SKILL.md +8 -0
- package/skills/pixerate-canvas-design-system-components/SKILL.md +103 -0
- package/skills/pixerate-canvas-design-system-components/evals/add-variant.json +172 -0
- package/skills/pixerate-canvas-design-system-components/evals/combine-variants.json +172 -0
- package/skills/pixerate-canvas-design-system-components/evals/make-component.json +103 -0
- package/skills/pixerate-canvas-layout/SKILL.md +95 -0
- package/skills/pixerate-canvas-layout/evals/align-tops.json +98 -0
- package/skills/pixerate-canvas-layout/evals/distribute-evenly.json +98 -0
- package/skills/pixerate-canvas-layout/evals/order-and-lock.json +110 -0
- package/skills/pixerate-color/SKILL.md +8 -0
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
{
|
|
2
|
+
"prompt": "These two buttons are versions of one button. Combine them into a single component with a 'Style' property whose values are Primary and Secondary.",
|
|
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
|
+
"position": {
|
|
23
|
+
"x": 0,
|
|
24
|
+
"y": 0
|
|
25
|
+
},
|
|
26
|
+
"width": 120,
|
|
27
|
+
"height": 40,
|
|
28
|
+
"data": {
|
|
29
|
+
"label": "Bg",
|
|
30
|
+
"shape": {
|
|
31
|
+
"kind": "rect",
|
|
32
|
+
"fill": "#1d3557"
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"parentId": "primary"
|
|
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
|
+
"position": {
|
|
54
|
+
"x": 0,
|
|
55
|
+
"y": 0
|
|
56
|
+
},
|
|
57
|
+
"width": 120,
|
|
58
|
+
"height": 40,
|
|
59
|
+
"data": {
|
|
60
|
+
"label": "Bg",
|
|
61
|
+
"shape": {
|
|
62
|
+
"kind": "rect",
|
|
63
|
+
"fill": "#ffffff"
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
"parentId": "secondary"
|
|
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
|
+
},
|
|
88
|
+
"checks": [
|
|
89
|
+
{
|
|
90
|
+
"why": "one component set with a Style property whose values are Primary and Secondary",
|
|
91
|
+
"tool": "list_components",
|
|
92
|
+
"expect": {
|
|
93
|
+
"sets": {
|
|
94
|
+
"$length": 1,
|
|
95
|
+
"$some": {
|
|
96
|
+
"options": [
|
|
97
|
+
{
|
|
98
|
+
"name": "Style",
|
|
99
|
+
"values": {
|
|
100
|
+
"$expr": "[...v].sort().join() === 'Primary,Secondary'"
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
]
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
"why": "the primary button is the Primary variant",
|
|
110
|
+
"tool": "list_components",
|
|
111
|
+
"expect": {
|
|
112
|
+
"components": {
|
|
113
|
+
"$some": {
|
|
114
|
+
"id": "primary",
|
|
115
|
+
"variant": {
|
|
116
|
+
"Style": "Primary"
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
],
|
|
123
|
+
"solution": [
|
|
124
|
+
{
|
|
125
|
+
"tool": "combine_as_variants",
|
|
126
|
+
"args": {
|
|
127
|
+
"ids": [
|
|
128
|
+
"primary",
|
|
129
|
+
"secondary"
|
|
130
|
+
]
|
|
131
|
+
}
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
"tool": "list_components"
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
"tool": "rename_variant_property",
|
|
138
|
+
"args": {
|
|
139
|
+
"name": "Property 1",
|
|
140
|
+
"newName": "Style",
|
|
141
|
+
"setId": {
|
|
142
|
+
"$read": "list_components",
|
|
143
|
+
"path": "sets.0.id"
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
"tool": "rename_variant_value",
|
|
149
|
+
"args": {
|
|
150
|
+
"property": "Style",
|
|
151
|
+
"value": "Default",
|
|
152
|
+
"newValue": "Primary",
|
|
153
|
+
"setId": {
|
|
154
|
+
"$read": "list_components",
|
|
155
|
+
"path": "sets.0.id"
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
"tool": "rename_variant_value",
|
|
161
|
+
"args": {
|
|
162
|
+
"property": "Style",
|
|
163
|
+
"value": "Variant2",
|
|
164
|
+
"newValue": "Secondary",
|
|
165
|
+
"setId": {
|
|
166
|
+
"$read": "list_components",
|
|
167
|
+
"path": "sets.0.id"
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
]
|
|
172
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
{
|
|
2
|
+
"prompt": "Turn the card into a reusable component and place two instances of it below the original, side by side.",
|
|
3
|
+
"fixture": {
|
|
4
|
+
"editor": "canvas",
|
|
5
|
+
"nodes": [
|
|
6
|
+
{
|
|
7
|
+
"id": "card",
|
|
8
|
+
"type": "group",
|
|
9
|
+
"position": {
|
|
10
|
+
"x": 0,
|
|
11
|
+
"y": 0
|
|
12
|
+
},
|
|
13
|
+
"width": 200,
|
|
14
|
+
"height": 100,
|
|
15
|
+
"data": {
|
|
16
|
+
"label": "Card"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"id": "bg",
|
|
21
|
+
"type": "shape",
|
|
22
|
+
"position": {
|
|
23
|
+
"x": 0,
|
|
24
|
+
"y": 0
|
|
25
|
+
},
|
|
26
|
+
"width": 200,
|
|
27
|
+
"height": 100,
|
|
28
|
+
"data": {
|
|
29
|
+
"label": "Bg",
|
|
30
|
+
"shape": {
|
|
31
|
+
"kind": "rect",
|
|
32
|
+
"fill": "#eeeeee"
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"parentId": "card"
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"id": "title",
|
|
39
|
+
"type": "text",
|
|
40
|
+
"parentId": "card",
|
|
41
|
+
"position": {
|
|
42
|
+
"x": 10,
|
|
43
|
+
"y": 10
|
|
44
|
+
},
|
|
45
|
+
"data": {
|
|
46
|
+
"label": "Hello",
|
|
47
|
+
"name": "Title"
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
]
|
|
51
|
+
},
|
|
52
|
+
"checks": [
|
|
53
|
+
{
|
|
54
|
+
"why": "one component, made from the card",
|
|
55
|
+
"tool": "list_components",
|
|
56
|
+
"expect": {
|
|
57
|
+
"components": {
|
|
58
|
+
"$length": 1,
|
|
59
|
+
"$some": {
|
|
60
|
+
"id": "card"
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"why": "two instances below the card",
|
|
67
|
+
"tool": "get_canvas_document",
|
|
68
|
+
"expect": {
|
|
69
|
+
"document": {
|
|
70
|
+
"nodes": {
|
|
71
|
+
"$expr": "v.filter((n) => n.data && n.data.instance && n.position.y >= 100).length === 2"
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
],
|
|
77
|
+
"solution": [
|
|
78
|
+
{
|
|
79
|
+
"tool": "create_component",
|
|
80
|
+
"args": {
|
|
81
|
+
"ids": [
|
|
82
|
+
"card"
|
|
83
|
+
]
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
"tool": "create_instance",
|
|
88
|
+
"args": {
|
|
89
|
+
"componentId": "card",
|
|
90
|
+
"x": 0,
|
|
91
|
+
"y": 150
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
"tool": "create_instance",
|
|
96
|
+
"args": {
|
|
97
|
+
"componentId": "card",
|
|
98
|
+
"x": 240,
|
|
99
|
+
"y": 150
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
]
|
|
103
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pixerate-canvas-layout
|
|
3
|
+
description: The layout workflow in the Pixerate canvas - tidying a board or screen by aligning edges and centres, distributing elements evenly, keeping consistent spacing on a grid, ordering layers so the right things are on top, grouping related elements, locking backgrounds and guides, and checking the result. Use when asked to align, line up, centre, distribute, space evenly, tidy, clean up or lay out elements on a canvas, board, screen, slide or wireframe, bring something to the front or send it back, or lock a layer, or when canvas.alignLeft, canvas.distributeHorizontal, canvas.bringToFront or canvas.lock are available. Load with pixerate-canvas, which lists every tool.
|
|
4
|
+
metadata:
|
|
5
|
+
kind: workflow
|
|
6
|
+
reference: pixerate-canvas
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Laying out a canvas
|
|
10
|
+
|
|
11
|
+
A tidy layout comes from a few relations applied deliberately: shared edges and centres,
|
|
12
|
+
equal gaps, a consistent spacing scale, and a stacking order where what matters is on top.
|
|
13
|
+
Use the arrange commands rather than moving nodes by hand: they act on exact geometry, keep
|
|
14
|
+
other axes untouched, and are one undo step each.
|
|
15
|
+
|
|
16
|
+
This skill is the method. `pixerate-canvas` has the full tool reference; run the `canvas.*`
|
|
17
|
+
commands with `run_command` (`params: { ids }`) or several in one `run_commands` batch.
|
|
18
|
+
|
|
19
|
+
## Goal and quality bar
|
|
20
|
+
|
|
21
|
+
- Elements in a row share a top, centre or bottom; elements in a column share a left, centre or
|
|
22
|
+
right edge.
|
|
23
|
+
- Gaps between repeated elements are equal, on the spacing scale (multiples of 4 or 8).
|
|
24
|
+
- The stacking order matches meaning: backgrounds at the back, content above, badges, overlays
|
|
25
|
+
and annotations on top.
|
|
26
|
+
- Backgrounds, guides and finished areas are locked so they cannot be moved by accident.
|
|
27
|
+
- Only the intended axis changes: aligning tops does not move anything sideways.
|
|
28
|
+
|
|
29
|
+
## Inputs to confirm
|
|
30
|
+
|
|
31
|
+
- **Which elements** belong together (a row of cards, a form column) and the anchor (the first
|
|
32
|
+
element, the container, the canvas).
|
|
33
|
+
- **Spacing:** equal distribution between fixed ends, or a set gap.
|
|
34
|
+
- **What must stay put**, and what to lock.
|
|
35
|
+
|
|
36
|
+
## Working method
|
|
37
|
+
|
|
38
|
+
1. **Read.** `get_canvas_document` for node ids, positions, sizes, parents and z-order.
|
|
39
|
+
**Check:** you know the rows, columns and stacking you want.
|
|
40
|
+
2. **Align** rows and columns: `canvas.alignTop`, `canvas.alignMiddle`, `canvas.alignBottom`,
|
|
41
|
+
`canvas.alignLeft`, `canvas.alignCenter`, `canvas.alignRight` with the group's `ids`.
|
|
42
|
+
**Check:** the shared coordinate is equal; the other axis is unchanged.
|
|
43
|
+
3. **Distribute** repeated elements: `canvas.distributeHorizontal` or `canvas.distributeVertical`
|
|
44
|
+
(the outer elements stay, the gaps between them become equal).
|
|
45
|
+
**Check:** the gaps are equal within a pixel.
|
|
46
|
+
4. **Order layers.** `canvas.bringToFront`, `canvas.bringForward`, `canvas.sendBackward`,
|
|
47
|
+
`canvas.sendToBack`; order is by `zIndex`, then document order.
|
|
48
|
+
**Check:** what must be on top has the highest effective order.
|
|
49
|
+
5. **Lock** backgrounds and finished parts: `canvas.lock` (`canvas.unlock` to edit again).
|
|
50
|
+
**Check:** locked nodes are no longer draggable in `get_canvas_document`.
|
|
51
|
+
6. **Look** with the host's view (`capture_view`, `view_editor`) when available.
|
|
52
|
+
|
|
53
|
+
## Decision table
|
|
54
|
+
|
|
55
|
+
| Want | Command |
|
|
56
|
+
| --- | --- |
|
|
57
|
+
| A row lined up | `canvas.alignTop` (or `canvas.alignMiddle` for mixed heights) |
|
|
58
|
+
| A column lined up | `canvas.alignLeft` (or `canvas.alignCenter`) |
|
|
59
|
+
| Even gaps between fixed ends | `canvas.distributeHorizontal` / `canvas.distributeVertical` |
|
|
60
|
+
| Something hidden behind | `canvas.bringToFront` |
|
|
61
|
+
| A background covering content | `canvas.sendToBack` |
|
|
62
|
+
| One step up or down | `canvas.bringForward` / `canvas.sendBackward` |
|
|
63
|
+
| Protect a background or guide | `canvas.lock` |
|
|
64
|
+
|
|
65
|
+
## Recipes
|
|
66
|
+
|
|
67
|
+
**Line up a row of cards.** `run_command` `{ id: "canvas.alignTop", params: { ids: ["a", "b",
|
|
68
|
+
"c"] } }`.
|
|
69
|
+
|
|
70
|
+
**Even spacing.** `run_command` `{ id: "canvas.distributeHorizontal", params: { ids } }`; the
|
|
71
|
+
leftmost and rightmost stay where they are.
|
|
72
|
+
|
|
73
|
+
**Badge on top, background locked.** `run_commands` with `canvas.bringToFront` `{ ids: ["badge"]
|
|
74
|
+
}` and `canvas.lock` `{ ids: ["backdrop"] }`.
|
|
75
|
+
|
|
76
|
+
## Pitfalls
|
|
77
|
+
|
|
78
|
+
- **Moving by hand** with rounded numbers drifts; align and distribute act on exact geometry.
|
|
79
|
+
- **Distributing two elements** does nothing; it needs at least three.
|
|
80
|
+
- **Aligning across different parents** aligns in each parent's own space; group or reparent
|
|
81
|
+
first.
|
|
82
|
+
- **Stacking by array order only**: `zIndex` wins over order; read the effective order.
|
|
83
|
+
- **Locked nodes** refuse moves; unlock, change, lock again.
|
|
84
|
+
- **Aligning everything to one edge** of the canvas when the group should align to itself.
|
|
85
|
+
|
|
86
|
+
## Tools used
|
|
87
|
+
|
|
88
|
+
- `get_canvas_document`: node positions, sizes, parents, z-order and locks
|
|
89
|
+
- `canvas.alignLeft`, `canvas.alignCenter`, `canvas.alignRight`: column alignment
|
|
90
|
+
- `canvas.alignTop`, `canvas.alignMiddle`, `canvas.alignBottom`: row alignment
|
|
91
|
+
- `canvas.distributeHorizontal`, `canvas.distributeVertical`: even gaps
|
|
92
|
+
- `canvas.bringToFront`, `canvas.bringForward`, `canvas.sendBackward`, `canvas.sendToBack`: stacking order
|
|
93
|
+
- `canvas.lock`, `canvas.unlock`: protect backgrounds and finished parts
|
|
94
|
+
- `capture_view`, `view_editor`: look at the result
|
|
95
|
+
- `undo_canvas`: take back a step
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
{
|
|
2
|
+
"prompt": "Line up the tops of the three cards.",
|
|
3
|
+
"fixture": {
|
|
4
|
+
"editor": "canvas",
|
|
5
|
+
"nodes": [
|
|
6
|
+
{
|
|
7
|
+
"id": "a",
|
|
8
|
+
"type": "shape",
|
|
9
|
+
"position": {
|
|
10
|
+
"x": 0,
|
|
11
|
+
"y": 10
|
|
12
|
+
},
|
|
13
|
+
"width": 100,
|
|
14
|
+
"height": 80,
|
|
15
|
+
"data": {
|
|
16
|
+
"label": "Card A",
|
|
17
|
+
"shape": {
|
|
18
|
+
"kind": "rect",
|
|
19
|
+
"fill": "#eeeeee"
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"id": "b",
|
|
25
|
+
"type": "shape",
|
|
26
|
+
"position": {
|
|
27
|
+
"x": 130,
|
|
28
|
+
"y": 30
|
|
29
|
+
},
|
|
30
|
+
"width": 100,
|
|
31
|
+
"height": 80,
|
|
32
|
+
"data": {
|
|
33
|
+
"label": "Card B",
|
|
34
|
+
"shape": {
|
|
35
|
+
"kind": "rect",
|
|
36
|
+
"fill": "#eeeeee"
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"id": "c",
|
|
42
|
+
"type": "shape",
|
|
43
|
+
"position": {
|
|
44
|
+
"x": 300,
|
|
45
|
+
"y": 0
|
|
46
|
+
},
|
|
47
|
+
"width": 100,
|
|
48
|
+
"height": 80,
|
|
49
|
+
"data": {
|
|
50
|
+
"label": "Card C",
|
|
51
|
+
"shape": {
|
|
52
|
+
"kind": "rect",
|
|
53
|
+
"fill": "#eeeeee"
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
]
|
|
58
|
+
},
|
|
59
|
+
"checks": [
|
|
60
|
+
{
|
|
61
|
+
"why": "all three tops at the same y",
|
|
62
|
+
"tool": "get_canvas_document",
|
|
63
|
+
"expect": {
|
|
64
|
+
"document": {
|
|
65
|
+
"nodes": {
|
|
66
|
+
"$expr": "new Set(v.map((n) => n.position.y)).size === 1"
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
"why": "the horizontal positions are unchanged",
|
|
73
|
+
"tool": "get_canvas_document",
|
|
74
|
+
"expect": {
|
|
75
|
+
"document": {
|
|
76
|
+
"nodes": {
|
|
77
|
+
"$expr": "v.map((n) => n.position.x).join() === '0,130,300'"
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
],
|
|
83
|
+
"solution": [
|
|
84
|
+
{
|
|
85
|
+
"tool": "run_command",
|
|
86
|
+
"args": {
|
|
87
|
+
"id": "canvas.alignTop",
|
|
88
|
+
"params": {
|
|
89
|
+
"ids": [
|
|
90
|
+
"a",
|
|
91
|
+
"b",
|
|
92
|
+
"c"
|
|
93
|
+
]
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
]
|
|
98
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
{
|
|
2
|
+
"prompt": "Space the three cards evenly across, keeping the first and last where they are.",
|
|
3
|
+
"fixture": {
|
|
4
|
+
"editor": "canvas",
|
|
5
|
+
"nodes": [
|
|
6
|
+
{
|
|
7
|
+
"id": "a",
|
|
8
|
+
"type": "shape",
|
|
9
|
+
"position": {
|
|
10
|
+
"x": 0,
|
|
11
|
+
"y": 0
|
|
12
|
+
},
|
|
13
|
+
"width": 100,
|
|
14
|
+
"height": 80,
|
|
15
|
+
"data": {
|
|
16
|
+
"label": "Card A",
|
|
17
|
+
"shape": {
|
|
18
|
+
"kind": "rect",
|
|
19
|
+
"fill": "#eeeeee"
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"id": "b",
|
|
25
|
+
"type": "shape",
|
|
26
|
+
"position": {
|
|
27
|
+
"x": 120,
|
|
28
|
+
"y": 0
|
|
29
|
+
},
|
|
30
|
+
"width": 100,
|
|
31
|
+
"height": 80,
|
|
32
|
+
"data": {
|
|
33
|
+
"label": "Card B",
|
|
34
|
+
"shape": {
|
|
35
|
+
"kind": "rect",
|
|
36
|
+
"fill": "#eeeeee"
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"id": "c",
|
|
42
|
+
"type": "shape",
|
|
43
|
+
"position": {
|
|
44
|
+
"x": 300,
|
|
45
|
+
"y": 0
|
|
46
|
+
},
|
|
47
|
+
"width": 100,
|
|
48
|
+
"height": 80,
|
|
49
|
+
"data": {
|
|
50
|
+
"label": "Card C",
|
|
51
|
+
"shape": {
|
|
52
|
+
"kind": "rect",
|
|
53
|
+
"fill": "#eeeeee"
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
]
|
|
58
|
+
},
|
|
59
|
+
"checks": [
|
|
60
|
+
{
|
|
61
|
+
"why": "equal gaps between the cards",
|
|
62
|
+
"tool": "get_canvas_document",
|
|
63
|
+
"expect": {
|
|
64
|
+
"document": {
|
|
65
|
+
"nodes": {
|
|
66
|
+
"$expr": "(() => { const xs = v.map((n) => n.position.x).sort((p, q) => p - q); return Math.abs((xs[1] - xs[0]) - (xs[2] - xs[1])) <= 1; })()"
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
"why": "the outer cards stay put",
|
|
73
|
+
"tool": "get_canvas_document",
|
|
74
|
+
"expect": {
|
|
75
|
+
"document": {
|
|
76
|
+
"nodes": {
|
|
77
|
+
"$expr": "v.find((n) => n.id === 'a').position.x === 0 && v.find((n) => n.id === 'c').position.x === 300"
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
],
|
|
83
|
+
"solution": [
|
|
84
|
+
{
|
|
85
|
+
"tool": "run_command",
|
|
86
|
+
"args": {
|
|
87
|
+
"id": "canvas.distributeHorizontal",
|
|
88
|
+
"params": {
|
|
89
|
+
"ids": [
|
|
90
|
+
"a",
|
|
91
|
+
"b",
|
|
92
|
+
"c"
|
|
93
|
+
]
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
]
|
|
98
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
{
|
|
2
|
+
"prompt": "The badge is hidden behind the card: bring it to the front, and lock the background so it can't be moved by accident.",
|
|
3
|
+
"fixture": {
|
|
4
|
+
"editor": "canvas",
|
|
5
|
+
"nodes": [
|
|
6
|
+
{
|
|
7
|
+
"id": "backdrop",
|
|
8
|
+
"type": "shape",
|
|
9
|
+
"position": {
|
|
10
|
+
"x": 0,
|
|
11
|
+
"y": 0
|
|
12
|
+
},
|
|
13
|
+
"width": 400,
|
|
14
|
+
"height": 300,
|
|
15
|
+
"data": {
|
|
16
|
+
"label": "Background",
|
|
17
|
+
"shape": {
|
|
18
|
+
"kind": "rect",
|
|
19
|
+
"fill": "#f1faee"
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"id": "badge",
|
|
25
|
+
"type": "shape",
|
|
26
|
+
"position": {
|
|
27
|
+
"x": 280,
|
|
28
|
+
"y": 20
|
|
29
|
+
},
|
|
30
|
+
"width": 40,
|
|
31
|
+
"height": 40,
|
|
32
|
+
"data": {
|
|
33
|
+
"label": "Badge",
|
|
34
|
+
"shape": {
|
|
35
|
+
"kind": "rect",
|
|
36
|
+
"fill": "#e63946"
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"id": "card",
|
|
42
|
+
"type": "shape",
|
|
43
|
+
"position": {
|
|
44
|
+
"x": 40,
|
|
45
|
+
"y": 20
|
|
46
|
+
},
|
|
47
|
+
"width": 300,
|
|
48
|
+
"height": 200,
|
|
49
|
+
"data": {
|
|
50
|
+
"label": "Card",
|
|
51
|
+
"shape": {
|
|
52
|
+
"kind": "rect",
|
|
53
|
+
"fill": "#ffffff"
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
]
|
|
58
|
+
},
|
|
59
|
+
"checks": [
|
|
60
|
+
{
|
|
61
|
+
"why": "the badge is drawn last (on top)",
|
|
62
|
+
"tool": "get_canvas_document",
|
|
63
|
+
"expect": {
|
|
64
|
+
"document": {
|
|
65
|
+
"nodes": {
|
|
66
|
+
"$expr": "(() => { const z = (n) => (typeof n.zIndex === 'number' ? n.zIndex : 0); const order = v.map((n, i) => ({ id: n.id, z: z(n), i })).sort((a, b) => a.z - b.z || a.i - b.i); return order[order.length - 1].id === 'badge'; })()"
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
"why": "the background is locked",
|
|
73
|
+
"tool": "get_canvas_document",
|
|
74
|
+
"expect": {
|
|
75
|
+
"document": {
|
|
76
|
+
"nodes": {
|
|
77
|
+
"$some": {
|
|
78
|
+
"id": "backdrop",
|
|
79
|
+
"$expr": "v.draggable === false || (v.data && v.data.locked === true) || v.locked === true"
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
],
|
|
86
|
+
"solution": [
|
|
87
|
+
{
|
|
88
|
+
"tool": "run_command",
|
|
89
|
+
"args": {
|
|
90
|
+
"id": "canvas.bringToFront",
|
|
91
|
+
"params": {
|
|
92
|
+
"ids": [
|
|
93
|
+
"badge"
|
|
94
|
+
]
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
"tool": "run_command",
|
|
100
|
+
"args": {
|
|
101
|
+
"id": "canvas.lock",
|
|
102
|
+
"params": {
|
|
103
|
+
"ids": [
|
|
104
|
+
"backdrop"
|
|
105
|
+
]
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
]
|
|
110
|
+
}
|
|
@@ -7,6 +7,14 @@ description: How to inspect colours, check and optimize WCAG contrast and access
|
|
|
7
7
|
|
|
8
8
|
The colour module provides DOM-free colour tools for inspection, WCAG accessibility validation, colour-vision deficiency simulation, palette audits, colour harmony suggestions, and perceptual blending.
|
|
9
9
|
|
|
10
|
+
## Workflow skills
|
|
11
|
+
|
|
12
|
+
For these jobs, load the workflow skill too: it has the method, the checks between steps and
|
|
13
|
+
the pitfalls, and uses the tools below.
|
|
14
|
+
|
|
15
|
+
- `pixerate-accessibility-audit`: contrast, colour-blind-safe meaning, both modes, fixes and a report.
|
|
16
|
+
- `pixerate-brand-application`: brand roles, exact palette values, readable text, derivatives.
|
|
17
|
+
|
|
10
18
|
## Working method
|
|
11
19
|
|
|
12
20
|
1. **Inspect and convert.** Run `inspect_color` to parse any hex, `rgb()`, `hsl()`, `oklch()`, or CSS named colour into standard formats (hex, rgb, hsl, oklch) and relative luminance, and to check if it fits within the sRGB gamut.
|