@pikku/skills 0.12.32 → 0.12.34
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/skills.gen.js +1 -1
- package/package.json +1 -1
- package/skills/pikku-architect/SKILL.md +23 -16
- package/skills/pikku-build/SKILL.md +21 -17
- package/skills/pikku-build/references/app.md +61 -30
- package/skills/pikku-build/references/design.md +218 -0
- package/skills/pikku-build/references/theming.md +122 -0
- package/skills/pikku-knowledge/SKILL.md +2 -2
|
@@ -53,6 +53,128 @@ Then **write the direction into `knowledge/decisions/design/`** — the words th
|
|
|
53
53
|
user gave you, what you chose, and what it rules out. The JSON records what the
|
|
54
54
|
theme is; only the note records why.
|
|
55
55
|
|
|
56
|
+
## The colours the theme has no field for
|
|
57
|
+
|
|
58
|
+
`brand` is the product's accent. It is not the only colour a screen needs, and
|
|
59
|
+
the missing ones are why "don't hardcode colours per component" gets broken by
|
|
60
|
+
the same agent that wrote it down.
|
|
61
|
+
|
|
62
|
+
A screen has to say *covered* and *still open*, *fine* and *needs attention* —
|
|
63
|
+
and those are not the accent. Using the accent for them is worse than a stray
|
|
64
|
+
hex: the brand colour stops meaning "this product" and starts meaning "good", so
|
|
65
|
+
it means nothing. But there is no `brand.covered` field, so the value lands
|
|
66
|
+
inline as `#3f7d5c`, once per component, slightly different each time.
|
|
67
|
+
|
|
68
|
+
Give them a home. A small stylesheet of custom properties, imported once beside
|
|
69
|
+
the Mantine styles, is enough:
|
|
70
|
+
|
|
71
|
+
```css
|
|
72
|
+
:root:root:root {
|
|
73
|
+
--app-covered: #3f7d5c; --app-covered-bg: #e6f1ea;
|
|
74
|
+
--app-open: #a8701a; --app-open-bg: #fbeedb;
|
|
75
|
+
--app-sunk: #fdf7f4; /* a recessed surface, for forms and asides */
|
|
76
|
+
--app-hairline: #ecdfd9; /* NOT var(--mantine-color-gray-2) — see below */
|
|
77
|
+
}
|
|
78
|
+
:root:root[data-mantine-color-scheme='dark'] {
|
|
79
|
+
--app-covered: #7fc09a; --app-covered-bg: #1e2f26;
|
|
80
|
+
--app-open: #e0ab5c; --app-open-bg: #33271a;
|
|
81
|
+
--app-sunk: #241b18;
|
|
82
|
+
--app-hairline: #392b26;
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Those values are one app's warm direction, not a palette to copy — derive your
|
|
87
|
+
own from yours.
|
|
88
|
+
|
|
89
|
+
## Choose the neutrals; do not inherit them
|
|
90
|
+
|
|
91
|
+
The two details in that snippet that look like typos are the two things most
|
|
92
|
+
likely to make your app look like every other app.
|
|
93
|
+
|
|
94
|
+
**The hairline is a literal, not `var(--mantine-color-gray-2)`.** Mantine's grey
|
|
95
|
+
ramp is blue-biased — `#f8f9fa`, `#dee2e6`, `#868e96` are all cool — and it is
|
|
96
|
+
what draws card borders, dividers, the shell's edges and every disabled control.
|
|
97
|
+
The theme JSON has `brand` and `structure` and **no neutral field at all**, so
|
|
98
|
+
unless you choose otherwise, every app built from this skill runs its accent on
|
|
99
|
+
somebody else's greys.
|
|
100
|
+
|
|
101
|
+
If the accent is not itself blue, that mismatch lands on every screen at once:
|
|
102
|
+
warm content ruled off in cold lines, off everywhere and wrong nowhere in
|
|
103
|
+
particular, which is the hardest kind of wrong to find. It survives a careful
|
|
104
|
+
critique because no single screen is broken.
|
|
105
|
+
|
|
106
|
+
So bias the whole ramp toward the accent — not just the tokens with obvious
|
|
107
|
+
names. Keep Mantine's lightness steps so contrast behaviour and every component
|
|
108
|
+
that picks a step by number are unchanged; move only the hue:
|
|
109
|
+
|
|
110
|
+
```css
|
|
111
|
+
/* The ramps: hue only. Mantine picks a step by number in either scheme, so
|
|
112
|
+
these are scheme-independent and belong in the unscoped block. */
|
|
113
|
+
:root:root:root {
|
|
114
|
+
--mantine-color-gray-0: #faf7f5; --mantine-color-gray-5: #b8a49d;
|
|
115
|
+
--mantine-color-gray-1: #f5efec; --mantine-color-gray-6: #93807a;
|
|
116
|
+
--mantine-color-gray-2: #efe6e2; --mantine-color-gray-7: #574a45;
|
|
117
|
+
--mantine-color-gray-3: #e6dad5; --mantine-color-gray-8: #3d332f;
|
|
118
|
+
--mantine-color-gray-4: #d8c8c2; --mantine-color-gray-9: #2a1f1b;
|
|
119
|
+
--mantine-color-dark-0: #f3e9e4; --mantine-color-dark-5: #4a3a34;
|
|
120
|
+
--mantine-color-dark-1: #cdbdb6; --mantine-color-dark-6: #392b26;
|
|
121
|
+
--mantine-color-dark-2: #a8938c; --mantine-color-dark-7: #241b18;
|
|
122
|
+
--mantine-color-dark-3: #7a655e; --mantine-color-dark-8: #1b1512;
|
|
123
|
+
--mantine-color-dark-4: #5c4a44; --mantine-color-dark-9: #120d0b;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/* Ground, text and border are a different colour in each scheme, so each one
|
|
127
|
+
is set in the scheme it belongs to. A scheme-dependent token left in the
|
|
128
|
+
block above is the classic unreadable-in-dark bug. */
|
|
129
|
+
:root:root:root[data-mantine-color-scheme='light'] {
|
|
130
|
+
--mantine-color-body: #fdfaf8;
|
|
131
|
+
--mantine-color-text: #2a1f1b;
|
|
132
|
+
--mantine-color-default-border: #ecdfd9;
|
|
133
|
+
--mantine-color-dimmed: #7a625c; /* keep AA: ~5.4:1 on the body above */
|
|
134
|
+
--mantine-color-placeholder: #826a64; /* ~4.8:1 */
|
|
135
|
+
}
|
|
136
|
+
:root:root:root[data-mantine-color-scheme='dark'] {
|
|
137
|
+
--mantine-color-body: #1b1512;
|
|
138
|
+
--mantine-color-text: #f3e9e4;
|
|
139
|
+
--mantine-color-default-border: #392b26;
|
|
140
|
+
--mantine-color-dimmed: #a8938c; /* ~5.6:1 on the body above */
|
|
141
|
+
--mantine-color-placeholder: #8c7a74; /* ~4.7:1 */
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Check the four text tokens against your own grounds rather than copying these —
|
|
146
|
+
`dimmed` is the most-used text colour in the app and the easiest to drop below
|
|
147
|
+
4.5:1 while making it prettier, and it has to clear the bar on *both* grounds.
|
|
148
|
+
|
|
149
|
+
**The selector is tripled on purpose.** Mantine's `cssVariablesResolver` injects
|
|
150
|
+
its own `:root` block into `<head>` at runtime, which lands *after* your
|
|
151
|
+
stylesheet and wins on source order at equal specificity. A plain `:root` here is
|
|
152
|
+
silently reverted: the file reads correct, the app renders Mantine's defaults,
|
|
153
|
+
and nothing errors. Repeating the pseudo-class raises specificity without adding
|
|
154
|
+
an element to the selector.
|
|
155
|
+
|
|
156
|
+
This one costs a whole pass if you meet it without knowing: you diagnose the
|
|
157
|
+
colours correctly, write the right values, reload, and see no change — so you
|
|
158
|
+
assume the diagnosis was wrong. **The only thing that catches it is looking at a
|
|
159
|
+
screenshot and disbelieving the CSS.**
|
|
160
|
+
|
|
161
|
+
Name them for what they *mean* in this product, never for the colour — `covered`,
|
|
162
|
+
not `green`. The name is the whole value: it survives a change of palette, and it
|
|
163
|
+
is the thing that makes the second use agree with the first. Define both colour
|
|
164
|
+
schemes at once; a token defined only in light is the classic unreadable-in-dark
|
|
165
|
+
bug, and Mantine will happily render it.
|
|
166
|
+
|
|
167
|
+
The same file is where a couple of other things belong that the theme JSON has no
|
|
168
|
+
field for and every screen otherwise re-invents: the hairline that separates rows
|
|
169
|
+
in a list, the recessed surface a form sits on so it does not carry the same
|
|
170
|
+
weight as the content it adds to, and the one animation the product is allowed
|
|
171
|
+
(behind `prefers-reduced-motion`). Two or three rules, not a framework.
|
|
172
|
+
|
|
173
|
+
If the app ships template screens you did not write — the error and not-found
|
|
174
|
+
pages usually — read them before you call the palette done. They arrive with the
|
|
175
|
+
scaffold's colours hardcoded, and a stock blue accent on an app whose direction
|
|
176
|
+
says warm is the single loudest contradiction in the build.
|
|
177
|
+
|
|
56
178
|
**Set the theme once, don't hardcode colours per component.** A screen full of
|
|
57
179
|
inline `color="blue"` and one-off hex values is why apps look templated. Change
|
|
58
180
|
the theme, not the components — and keep it theme-aware for light and dark.
|
|
@@ -266,7 +266,7 @@ Two things about the output matter if you are driving it:
|
|
|
266
266
|
`options` is empty when the answer is free text, and an empty list means offer free
|
|
267
267
|
text — never invent choices to fill it.
|
|
268
268
|
|
|
269
|
-
`hold` means a profile's own gate is holding the milestone and
|
|
269
|
+
`hold` means a profile's own gate is holding the milestone and nothing this loop knows
|
|
270
270
|
about can clear it. It names the hold and the notes it is about; what to do then
|
|
271
271
|
belongs to that profile, not here.
|
|
272
272
|
|
|
@@ -282,7 +282,7 @@ pikku knowledge plan progress <milestone> # what it still owes, read fr
|
|
|
282
282
|
pikku knowledge plan defer <milestone> <item> -r "<why>"
|
|
283
283
|
```
|
|
284
284
|
|
|
285
|
-
`progress` reconciles the plan against pikku's generated meta — set membership, never anyone's status — and exits non-zero while the first pass is short, or while anything already built contradicts the plan. Unbuilt work in a later pass is reported, not blocked; a function that shipped wide open against a planned permission rule blocks from any pass, because that is a hole rather than a backlog.
|
|
285
|
+
`progress` reconciles the plan against pikku's generated meta — set membership, never anyone's status — and exits non-zero while the first pass is short, or while anything already built contradicts the plan. Unbuilt work in a later pass is reported, not blocked; a function that shipped wide open against a planned permission rule blocks from any pass, because that is a hole rather than a backlog. How a plan is written is `pikku-architect`; building against one, and the order plan-then-build, is `pikku-build`.
|
|
286
286
|
|
|
287
287
|
### A finished milestone is a tombstone
|
|
288
288
|
|