sheleg-design-skill 1.29.0 → 1.32.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.
- package/CHANGELOG.md +224 -0
- package/README.md +5 -4
- package/bin/cli.js +5 -2
- package/cursor/rules/sheleg-design.mdc +5 -1
- package/kits/paperclip/.design-sync/config.json +14 -0
- package/kits/paperclip/.design-sync/conventions.md +62 -0
- package/kits/paperclip/README.md +46 -0
- package/kits/paperclip/package.json +29 -0
- package/kits/paperclip/src/Button.md +23 -0
- package/kits/paperclip/src/Button.tsx +33 -0
- package/kits/paperclip/src/CapsuleCurtain.md +32 -0
- package/kits/paperclip/src/CapsuleCurtain.tsx +109 -0
- package/kits/paperclip/src/Card.md +22 -0
- package/kits/paperclip/src/Card.tsx +24 -0
- package/kits/paperclip/src/Chip.md +21 -0
- package/kits/paperclip/src/Chip.tsx +25 -0
- package/kits/paperclip/src/HairlineGrid.md +34 -0
- package/kits/paperclip/src/HairlineGrid.tsx +23 -0
- package/kits/paperclip/src/Heading.md +21 -0
- package/kits/paperclip/src/Heading.tsx +19 -0
- package/kits/paperclip/src/LedgerRow.md +31 -0
- package/kits/paperclip/src/LedgerRow.tsx +54 -0
- package/kits/paperclip/src/OrgNode.md +27 -0
- package/kits/paperclip/src/OrgNode.tsx +42 -0
- package/kits/paperclip/src/Rule.md +20 -0
- package/kits/paperclip/src/Rule.tsx +18 -0
- package/kits/paperclip/src/ScheduleLane.md +31 -0
- package/kits/paperclip/src/ScheduleLane.tsx +58 -0
- package/kits/paperclip/src/SectionBadge.md +23 -0
- package/kits/paperclip/src/SectionBadge.tsx +21 -0
- package/kits/paperclip/src/Stat.md +18 -0
- package/kits/paperclip/src/Stat.tsx +17 -0
- package/kits/paperclip/src/Terminal.md +34 -0
- package/kits/paperclip/src/Terminal.tsx +67 -0
- package/kits/paperclip/src/index.ts +29 -0
- package/kits/paperclip/src/styles.css +962 -0
- package/kits/paperclip/tsconfig.json +15 -0
- package/kits/tenor/src/styles.css +61 -9
- package/package.json +2 -2
- package/plugins/sheleg-design/.claude-plugin/plugin.json +2 -2
- package/plugins/sheleg-design/commands/sheleg-design.md +2 -2
- package/plugins/sheleg-design/skills/sheleg-design/DESIGN_SYNC_BRIDGE.md +1 -1
- package/plugins/sheleg-design/skills/sheleg-design/MOBILE_SURFACES.md +1 -1
- package/plugins/sheleg-design/skills/sheleg-design/SKILL.md +12 -8
- package/plugins/sheleg-design/skills/sheleg-design/SURFACE_COMPOSITION.md +4 -4
- package/plugins/sheleg-design/skills/sheleg-design/styles/instrument-console.md +10 -0
- package/plugins/sheleg-design/skills/sheleg-design/styles/ora.md +13 -0
- package/plugins/sheleg-design/skills/sheleg-design/styles/orchard.md +9 -0
- package/plugins/sheleg-design/skills/sheleg-design/styles/paperclip.md +775 -0
- package/plugins/sheleg-design/skills/sheleg-design/styles/tenor.md +115 -23
- package/plugins/sheleg-design/skills/sheleg-design/styles/tokens/paperclip.css +294 -0
- package/plugins/sheleg-design/skills/sheleg-design/styles/tokens/tenor.css +61 -9
- package/plugins/sheleg-design/skills/sheleg-design/styles/workbench.md +10 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,230 @@ All notable changes to this project are documented in this file. The format
|
|
|
4
4
|
follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versions
|
|
5
5
|
follow [SemVer](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## [1.32.0] - 2026-08-15
|
|
8
|
+
|
|
9
|
+
**The pack met a product surface, and three of its own measurements did not survive
|
|
10
|
+
the meeting.** `tenor` was mounted on a populated twenty-route dashboard behind a
|
|
11
|
+
`?pack=` switch — the "mount them, don't imagine them" procedure `SKILL.md` prescribes
|
|
12
|
+
— and every finding below came from a screen with real data on it rather than from a
|
|
13
|
+
re-read. Each is reproduced by a number the token layer now carries and
|
|
14
|
+
`validate_stated_ratios` now checks.
|
|
15
|
+
|
|
16
|
+
### Fixed — in `tenor`
|
|
17
|
+
|
|
18
|
+
- **The reference puts the wrong label on its own accent, and the pack copied the
|
|
19
|
+
workaround instead of the fix.** Gotcha 3 measured `--paper` on the orange at 3.02:1,
|
|
20
|
+
correctly, and concluded that a control whose label is its only statement must keep
|
|
21
|
+
its ink fill and move its *border* to the accent. It never measured the other
|
|
22
|
+
direction: `--coal` on the same orange is **5.84:1**. `--accent-ink` is the coal now,
|
|
23
|
+
declared once and deliberately not overridden on the dark band — the orange does not
|
|
24
|
+
change between fields, so neither does the only label readable on it. The hover fill,
|
|
25
|
+
which is this pack's most recognisable interaction, is legal after all.
|
|
26
|
+
- **Gotcha 1's remedy was short on the pack's own second field.** It said to darken
|
|
27
|
+
`--ink-soft` "to at least `#6f6f6b`", which clears 4.67:1 on `--bg` and only **4.27:1**
|
|
28
|
+
on `--bg-deep` — a field the pack spends on a whole section. A remedy nobody
|
|
29
|
+
re-measures is a defect with a citation attached. **New `--ink-soft-aa` `#6b6b67`**:
|
|
30
|
+
4.95:1 and 4.53:1, the smallest step that holds on both. `--ink-soft` keeps the
|
|
31
|
+
reference's value and is now marked for the tracked mono labels, not for prose.
|
|
32
|
+
- **`--warn` is the accent, and a product surface sets warn as a word.** At 3.02:1 the
|
|
33
|
+
orange cannot carry one. **New `--warn-ink` `#94400f`** — the same hue on the value
|
|
34
|
+
axis, 6.47:1 on `--bg` and 5.93:1 on `--bg-deep`. `--warn` stays the mark (the dot,
|
|
35
|
+
the edge rule, the fill); the two are one severity in two roles, which is the split
|
|
36
|
+
`--sev-ask`/`--sev-limit`/`--sev-never` already models. On the dark band the orange
|
|
37
|
+
clears AA unaided, so `--warn-ink` remaps back to the accent there.
|
|
38
|
+
- **The dark band's `--bg-deep` resolved to the field it sits on.** Correct for a band,
|
|
39
|
+
which has no hover and no resting chip; a rule that silently does nothing on a product
|
|
40
|
+
surface, which has both. Derived to `#222221` — paper at 8% over the coal, 1.20:1
|
|
41
|
+
against `--bg`, and `--ink` 14.73:1 / `--ink-soft` 6.31:1 / `--good` 7.07:1 on it.
|
|
42
|
+
|
|
43
|
+
### Added — in `tenor`
|
|
44
|
+
|
|
45
|
+
- **`--coal`**, beside `--paper`. The pack has two materials and named only one, which is
|
|
46
|
+
why the dark band restated `#f7f6f2` as a literal that then had to agree with the light
|
|
47
|
+
block by hand. `--ink` is `var(--coal)` on the paper and `var(--paper)` on the band.
|
|
48
|
+
- **`### On a product surface`**, inside `## Components`. Five things a marketing page
|
|
49
|
+
never exercises, each derived and each found on the dashboard: no dark theme exists and
|
|
50
|
+
a product with a toggle has to pick one of three answers; ranking by value costs the
|
|
51
|
+
link its affordance, and the pack's own flipped-origin rule is the fix (static
|
|
52
|
+
underline in a table — fifty animated rules is the marquee ban in another costume); a
|
|
53
|
+
rail's selected row is the lattice cell's inversion held open; **a column of chips is
|
|
54
|
+
where the single hairline stops separating**, which makes the Register's "not for dense
|
|
55
|
+
operator chrome" specific rather than a blanket refusal; and prose sits on two fields
|
|
56
|
+
at once. What does not change: the spacing scale and the type ramp, which are page
|
|
57
|
+
values.
|
|
58
|
+
|
|
59
|
+
### Note
|
|
60
|
+
|
|
61
|
+
`--bg-deep` on the dark band was written into this changelog's draft as 1.41:1 against
|
|
62
|
+
`--bg` and is **1.20:1**. The number was asserted rather than computed, and
|
|
63
|
+
`validate_stated_ratios` caught it before the commit — the check earning its keep on the
|
|
64
|
+
run that extended it.
|
|
65
|
+
|
|
66
|
+
## [1.31.0] - 2026-08-14
|
|
67
|
+
|
|
68
|
+
**T29 ran, and the pack it was written for did not survive it intact.** Both branches
|
|
69
|
+
green — the routing worked — and the pair returned forty-one findings, twenty-six of them
|
|
70
|
+
against `paperclip`, a pack that had passed all three gates three times. Every one was
|
|
71
|
+
reproduced before an edit; every one is fixed here.
|
|
72
|
+
|
|
73
|
+
### Fixed — in `paperclip`, found by T29a
|
|
74
|
+
|
|
75
|
+
- **`--cream` was prescribed and never declared.** The dark primary button's hover was
|
|
76
|
+
specified to keep its label and border at `--cream`, a token this pack does not ship. It
|
|
77
|
+
means `--accent`, and now says so.
|
|
78
|
+
- **The dark card hover was a no-op.** A card rests at `--surface` and the hover was
|
|
79
|
+
written as `--surface`. A card and a grid cell are now separated: the cell rests at
|
|
80
|
+
`--bg` and hovers one step toward the card's fill; the card does not hover at all.
|
|
81
|
+
- **`--terminal-dim` at 2.92:1 was the label of a tab a reader has to click.** Repaired to
|
|
82
|
+
`--terminal-mid` (5.64:1). `--terminal-dim` survives for the prompt glyph, which is
|
|
83
|
+
`aria-hidden` punctuation, and now carries an `@role non-text:` note saying so.
|
|
84
|
+
- **`--shadow-alert` was a second resting shadow in a pack that claimed one** — and it
|
|
85
|
+
hardcoded the reference's **light**-theme amber into a value only ever painted on the
|
|
86
|
+
dark field. Derived from `--warn` with `color-mix()`, and the Texture section now names
|
|
87
|
+
both shadows.
|
|
88
|
+
- **All three stagger formulas hardcoded `.14s`.** Zeroing `--stagger` under reduced
|
|
89
|
+
motion would have left every one of them running. They spend `var(--stagger)` now, and
|
|
90
|
+
the pack says why in the sentence that used to say "change it in one place".
|
|
91
|
+
- **The reduced-motion blanket had no mechanism for half of what it promised.** The
|
|
92
|
+
marquee and the two 1.5s trace loops are literals inside `animation` shorthands, which no
|
|
93
|
+
token can zero. The pack now ships the rule block beside the token list.
|
|
94
|
+
- **The signature element's generation rule did not reproduce its own artwork.** The
|
|
95
|
+
bottom stop was stated at −10.3°/step and does not land on the last capsule; the value
|
|
96
|
+
implied by the anchors is **−10.45°**. "Near-constant saturation and lightness" was true
|
|
97
|
+
of the top ramp (S 96→84, L 56→48) and false of the bottom (S 96→69, L 56→33) — the
|
|
98
|
+
bottom stop darkens as it turns, which is what keeps the curtain's lower edge off the
|
|
99
|
+
field. Both ramps are now stated separately, and "forty-five gradients" no longer sits
|
|
100
|
+
two sentences from "every capsule is filled with its own": a column carries twelve and
|
|
101
|
+
the eight columns reuse the ramps, four of them in reverse.
|
|
102
|
+
- **The concentric-radius rule was arithmetically wrong about a nest that does not exist.**
|
|
103
|
+
`8 − 2 ≈ 4.8` is 6, and the reference's tab group sits inside a header with no radius.
|
|
104
|
+
The rule is now declared as the pack's own decision, with a worked example that computes,
|
|
105
|
+
and the reference's actual behaviour — pick by element size, no arithmetic — recorded.
|
|
106
|
+
- **`--radius-lg` was called "never spent" and is spent five times**, on the three large
|
|
107
|
+
mock panels. `--radius-md` is the rung that is never spent.
|
|
108
|
+
- Smaller, and all reproduced: the artwork called 1200px *tall* where 1200 is its frame's
|
|
109
|
+
width (it is a 560 × 630 curtain in a 1200 × 675 frame); "nothing in this pack overlaps"
|
|
110
|
+
in a pack whose hero is an overlap; a 1.5 line-height floor claimed against a display
|
|
111
|
+
ramp that runs 0.98; `--font-serif` and `--font-sans` named as if the layer declared
|
|
112
|
+
them; an icon range of 14–16px that excluded the pack's own 11px nav glyph; a mono ramp
|
|
113
|
+
called width-invariant beside an axis mark that steps at 768px; a Gotchas count of seven
|
|
114
|
+
where eight are defects; the grain's 512-unit filter in a 256px tile, which is the
|
|
115
|
+
reference's own arrangement and doubles the effective frequency to ~5.9 — now stated with
|
|
116
|
+
its consequence rather than repaired; weight 450 prescribed in a pack that documents 450
|
|
117
|
+
as unrenderable; and an invented "roughly 22 characters per line", replaced by the two
|
|
118
|
+
lines the reference actually sets.
|
|
119
|
+
|
|
120
|
+
### Fixed — in neighbours, found by the same run
|
|
121
|
+
|
|
122
|
+
- **`ora`'s merge-time fork clause called this pack "three grotesques and a monospace".**
|
|
123
|
+
It is two grotesques and a monospace; the pack's own Bans cap it at three families.
|
|
124
|
+
- **`SKILL.md` marked three packs `(standalone)` and its ceiling paragraph named four.**
|
|
125
|
+
`ora`, `tenor` and `paperclip` all declare standalone in their own Registers and all
|
|
126
|
+
three pin a ceiling — 4, 4 and 5 — that the paragraph never mentioned. An agent choosing
|
|
127
|
+
any of them off the table alone would have taken `MOTION_INTENSITY` 7 from the marketing
|
|
128
|
+
row. All three are marked and all three ceilings enumerated.
|
|
129
|
+
|
|
130
|
+
### Added
|
|
131
|
+
|
|
132
|
+
- **`--terminal-dot`, `--mark-rest`, `--scrim`** — three colours the pack spent as literals
|
|
133
|
+
in its Components section. `--scrim` is `#0a0a0a8c` in **both** themes, because the
|
|
134
|
+
reference veils a light modal in coal too, and it stays a literal because the palette gate
|
|
135
|
+
cannot compute a `color-mix()` into `transparent` — and an unparseable token is a failure
|
|
136
|
+
there, not a skip.
|
|
137
|
+
- **`--t-hero-art` and `--t-hero-copy` in the Motion tokens table**, which shipped in the
|
|
138
|
+
token layer and appeared only as prose. The table is now the whole set.
|
|
139
|
+
- **B-038 … B-043** — fifteen findings against `instrument-console` from T29b, filed rather
|
|
140
|
+
than fixed because they belong to a shipped pack this run does not own. Four reproduced
|
|
141
|
+
first: zero `--danger`/`--info` tokens against Bans that legislate for four statuses; a
|
|
142
|
+
pressed primary label at **3.06:1**; one of only two token layers with no
|
|
143
|
+
`prefers-reduced-motion` branch, in the pack that mandates a particle field; and a Bans
|
|
144
|
+
line that forbids coloured shadows "besides `--accent-glow`", which is a colour.
|
|
145
|
+
|
|
146
|
+
## [1.30.0] - 2026-08-14
|
|
147
|
+
|
|
148
|
+
A twentieth pack, **`paperclip`**, extracted from a live reference rather than composed:
|
|
149
|
+
<https://paperclip.ing>, read from the two shipped stylesheets
|
|
150
|
+
(`/_next/static/chunks/0sw-z-v7xc9dd.css`, 622 rules; `/_next/static/chunks/19xj4kovk13jy.css`,
|
|
151
|
+
712 rules), the hero's inline SVG and the `@font-face` block. It is the first pack whose
|
|
152
|
+
thesis is that **colour is ornament**: there is no functional colour anywhere in the
|
|
153
|
+
interface, and the whole chromatic budget is spent on two things a reader cannot click.
|
|
154
|
+
|
|
155
|
+
Authored on `feat/paperclip-pack` in a dedicated worktree while another run held the
|
|
156
|
+
`PACK-TENOR` lease on the shared checkout, per `docs/DOCMAP.md`. That run landed `ora` and
|
|
157
|
+
`tenor` as 1.29.0 while this branch was open — including the version this branch had
|
|
158
|
+
already taken — so the merge moved it to 1.30.0 and recounted every site from eighteen to
|
|
159
|
+
twenty. Nothing was lost in either direction; the counted-claims gate named all eleven
|
|
160
|
+
sites that needed moving.
|
|
161
|
+
|
|
162
|
+
### Added
|
|
163
|
+
|
|
164
|
+
- **`styles/paperclip.md` + `styles/tokens/paperclip.css` — widened contract, all thirteen
|
|
165
|
+
headings.** A neutral coal field (`#0a0a0a`) with `#fafafa` ink at 18.97:1, and a light
|
|
166
|
+
twin on pure white at 19.80:1 that has **no elevation step at all**: the reference sets
|
|
167
|
+
`--background` and `--card` to the same white and separates a card from the page with a
|
|
168
|
+
1px rule and nothing else.
|
|
169
|
+
- **The accent is the inverted field, and colour is ornament.** Every control is
|
|
170
|
+
monochrome — `.navbar-cta`, `.hero-btn-primary`, `.sim-submit` and `.cta-btn` are one
|
|
171
|
+
component wearing four names — and the pack's central rule is one sentence: a gradient
|
|
172
|
+
that can be clicked, hovered or focused has left the pack. The corollary is what makes
|
|
173
|
+
the four status hues land: because colour is spent entirely on things that do nothing,
|
|
174
|
+
anything coloured reads as scenery.
|
|
175
|
+
- **The capsule curtain as the signature element.** 96 capsules in 8 columns on a 70px
|
|
176
|
+
pitch, each 70 × 170 at `rx: 35`, stepped 34.5px so every capsule covers all but a
|
|
177
|
+
34.5px band of the one above it. The 45 gradients filling them are **generated, not
|
|
178
|
+
chosen**: the top stop rotates forward around the hue wheel by ~12.4° per capsule and
|
|
179
|
+
the bottom stop backward by ~10.3°, at near-constant saturation and lightness — so the
|
|
180
|
+
stops stay near-complementary and each column inverts its own gradient between its first
|
|
181
|
+
capsule and its last. Measured across all 45 gradients and 89 distinct stops.
|
|
182
|
+
- **One noise recipe, on every saturated surface and nowhere else.** `fractalNoise`,
|
|
183
|
+
`baseFrequency 2.95`, 5 octaves, seed 9, tiled at 256px under `isolation: isolate` with
|
|
184
|
+
`mix-blend-mode: overlay` — 12% on a section badge, 86% over the artwork through an
|
|
185
|
+
alpha mask of the capsules themselves. The same seed on both, which is why a
|
|
186
|
+
twelve-gradient page does not band.
|
|
187
|
+
- **Twelve section-badge gradients, each with its own hand-picked label ink** — white on
|
|
188
|
+
six, and `#2a1530` / `#3d3010` / `#1a2a40` / `#2a2340` / `#1a3a38` on the five light
|
|
189
|
+
ramps, because a 90° gradient has two ends and one label has to clear both.
|
|
190
|
+
- **`kits/paperclip/` — the React reference kit**, the six-name spine plus seven signature
|
|
191
|
+
components: `CapsuleCurtain`, `SectionBadge`, `HairlineGrid`, `OrgNode`, `LedgerRow`,
|
|
192
|
+
`ScheduleLane`, `Terminal`. `src/styles.css` opens with the token layer byte for byte,
|
|
193
|
+
and four of the seven carry `container-type: inline-size`, so no component in the kit is
|
|
194
|
+
sized by the screen.
|
|
195
|
+
- **`T29` in `test/scenarios.md`** — the operator register and its fork against the
|
|
196
|
+
console, with the negative branch, and a second rejected pack because `ora` now sits
|
|
197
|
+
inside the same silhouette. **Written and not yet run**, and the scenario says so in its
|
|
198
|
+
own Result line rather than in a footnote.
|
|
199
|
+
|
|
200
|
+
### Fixed — in the pack, against its own reference
|
|
201
|
+
|
|
202
|
+
- **`--info` is derived and marked derived.** The reference's dark block overrides five
|
|
203
|
+
status *icon* colours and leaves the four base status colours at their light values, so
|
|
204
|
+
`--status-task-in_progress` renders at **3.83:1** on the coal field and is set as text
|
|
205
|
+
(`● 1 live`). The pack ships `#60a5fa`, the 400 step of the same ramp, at 7.79:1.
|
|
206
|
+
- **The focus ring is kept.** The reference's one text input sets `outline: none` on focus
|
|
207
|
+
and replaces the ring with a 1px border colour change.
|
|
208
|
+
- **Two 1.5s infinite loops are stopped under `prefers-reduced-motion`.** `dotPulse` and
|
|
209
|
+
`statusBlink` survive the reference's own reduced-motion blocks, which do calm the hero,
|
|
210
|
+
the parallax, the marquee tracks and the modal.
|
|
211
|
+
- **The budget bar animates `transform: scaleX()`**, not `width` for 1.2s per bar with six
|
|
212
|
+
bars in view.
|
|
213
|
+
|
|
214
|
+
### Changed
|
|
215
|
+
|
|
216
|
+
- **Four reciprocal fork clauses.** `instrument-console`, `workbench` and `orchard` each
|
|
217
|
+
gain one against `paperclip`; `ora` and `paperclip` gain the pair in both directions,
|
|
218
|
+
which is the one edge no gate could have asked for — neither pack existed in the other's
|
|
219
|
+
tree, so `validate_fork_reciprocity()` had nothing to check. The two are the closest in
|
|
220
|
+
the library: both dark by default, both refusing a brand hue, both spending the accent as
|
|
221
|
+
the inverted field. Three tests separate them, and both packs now carry all three.
|
|
222
|
+
- Counts moved from nineteen to twenty in the README, `bin/cli.js`, the three manifests,
|
|
223
|
+
`SURFACE_COMPOSITION.md`, `MOBILE_SURFACES.md` and `DESIGN_SYNC_BRIDGE.md`; the
|
|
224
|
+
`@role non-text:` tally is recomputed (fourteen of twenty, from thirteen of nineteen) and
|
|
225
|
+
the accent tally with it (eighteen, from seventeen).
|
|
226
|
+
- `/sheleg-design`'s by-name fast path said "the fourteen are" over a list of nineteen —
|
|
227
|
+
a count no gate reads, because it has no counted noun after it. It now says twenty and
|
|
228
|
+
lists them.
|
|
229
|
+
- `SKILL.md`'s core-contract paragraph: six of the twenty, the other fourteen.
|
|
230
|
+
|
|
7
231
|
## [1.29.0] - 2026-08-14
|
|
8
232
|
|
|
9
233
|
A nineteenth pack, **`tenor`**, and the first one in the library extracted from a
|
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@ problem — invented colors, six accent hues, dark mode retrofitted later.
|
|
|
11
11
|
|
|
12
12
|
This skill is the taste layer. It gives a coding agent **one motion
|
|
13
13
|
methodology** for cinematic, scroll-driven pages, **a motion doctrine** that
|
|
14
|
-
decides whether to animate before it decides how, and **
|
|
14
|
+
decides whether to animate before it decides how, and **twenty locked style
|
|
15
15
|
packs** with ready-made design tokens, so what it builds reads as one system
|
|
16
16
|
instead of a pile of effects.
|
|
17
17
|
|
|
@@ -64,6 +64,7 @@ into the cinematic layer, and says so in its own *Motion flavor* section.
|
|
|
64
64
|
| `roster` | a white field in a faint grid of squares, hairlines instead of shadows, a display set in the **body** face while the section heads take another, and one orange that may never carry a word | products whose argument is **who already carries them** — AI-search and GEO visibility, SEO and content platforms, agencies, marketplaces, integration-led tooling |
|
|
65
65
|
| `ora` | a warm coal field with cream ink and **no third hue** — the accent is the inverted field, so the one solid object on a page is the one meant to be pressed — a serif doing the sans job over a monospace that carries every machine fact, a terminal surface cut *below* the page plane, a six-step verdict ramp, and dark as the default theme rather than the option | products whose output is **a machine's verdict about the reader** — agent-readiness and crawlability scores, SEO and answer-engine audits, agent-run traces, MCP and protocol surfaces, bot observability |
|
|
66
66
|
| `tenor` | warm paper with **zero radius and zero shadow anywhere**, a single hairline weight assembling every lattice, and one orange that exists only on hover and on focus — so the page screenshots with no colour in it at all — a sans held at weight 400 and tracked negative against a mono tracked positive, display at a line-height below one in an eight-to-twelve-character measure, and proof delivered as silent looping video in a 1px rectangle | products arguing a **management thesis** — that a new kind of thing has to be run like an existing organisation: AI-workforce and agent-operations platforms, autonomous back-office, revenue and sales operations, sold to the director who will have to manage it |
|
|
67
|
+
| `paperclip` | neutral coal with **no functional colour at all** — every control monochrome, elevation made of hairlines, and the whole chromatic budget spent on a curtain of 96 gradient capsules and twelve gradient section badges that cannot be clicked — a tight grotesque over a plain one over a monospace, and the capsule as the shape of everything from a button to a 10 × 20 schedule tick | products that ask a person to **run something that runs itself** — agent teams and orchestrators, autonomous back-office, schedulers, job runners, budget-governed compute |
|
|
67
68
|
|
|
68
69
|
Each pack locks palette, type, texture, motion tokens, signature motifs and
|
|
69
70
|
bans — and ships a `tokens/<pack>.css` to copy verbatim, so the agent never
|
|
@@ -138,7 +139,7 @@ skills.
|
|
|
138
139
|
| `DESIGN_SYNC_BRIDGE.md` | The Claude Design contract: what a pack sends to claude.ai/design and in what shape, the rule for each of the four reference types, and the border motion does not cross |
|
|
139
140
|
| `FIGMA_BRIDGE.md` | The design↔code contract: how a pack's tokens map onto Figma variable collections and modes, how to implement a design without importing raw values, and what cannot cross the border |
|
|
140
141
|
| `AI_PRODUCT_PATTERNS.md` | The surfaces a model drives: the five states of a call, streaming instead of spinners, latency, provenance and uncertainty, agent confirmations, and the bans that keep it honest |
|
|
141
|
-
| `styles/*.md` | The
|
|
142
|
+
| `styles/*.md` | The twenty style packs — palette, type, texture, motion tokens, motifs, bans, and the traps each one carries |
|
|
142
143
|
| `styles/tokens/*.css` | The ready-made token layer per pack, copied verbatim instead of transcribed (`workbench` and `field-notes` each ship a light `:root` plus a `data-theme="dark"` twin) |
|
|
143
144
|
| `styles/STYLE_PACK_TEMPLATE.md` | The pack contract as a skeleton, so a new style is authored against the same headings rather than improvised |
|
|
144
145
|
|
|
@@ -209,7 +210,7 @@ cd ./ds-workbench && npm install && npm run build
|
|
|
209
210
|
then `/design-sync` in that directory, from Claude Code. Three layers cross: the
|
|
210
211
|
pack's **bans** as the design system's own README, `styles.css` built from
|
|
211
212
|
`tokens/<pack>.css` verbatim, and the components — a six-name spine that is
|
|
212
|
-
identical in all
|
|
213
|
+
identical in all twenty kits, so switching packs swaps identity rather than API,
|
|
213
214
|
plus each pack's signature parts. **Motion does not cross**, exactly as it does
|
|
214
215
|
not cross into Figma: a kit is the static half of a pack, and saying so is what
|
|
215
216
|
stops an agent inventing motion to fill the silence.
|
|
@@ -255,7 +256,7 @@ a pack's four widened sections used to make two gates *quieter* and still green.
|
|
|
255
256
|
One honest limit: the npx installer is checked by asserting its runtime bundle
|
|
256
257
|
walker exists, not by reading a file list — it has none by design. What proves
|
|
257
258
|
it ships the right files is CI, which installs the bundle through **both**
|
|
258
|
-
installers and `diff -r`s the result against the source, then builds all
|
|
259
|
+
installers and `diff -r`s the result against the source, then builds all twenty
|
|
259
260
|
kits.
|
|
260
261
|
|
|
261
262
|
`test/scenarios.md` (T1–T19) is the behavioral harness: fresh subagents given a
|
package/bin/cli.js
CHANGED
|
@@ -234,7 +234,7 @@ ${c("bold", "What it installs")}
|
|
|
234
234
|
DESIGN_SYNC_BRIDGE.md the Claude Design contract (what a pack sends, and
|
|
235
235
|
what does not cross)
|
|
236
236
|
AI_PRODUCT_PATTERNS.md chat / agent / streaming surfaces (honest state)
|
|
237
|
-
styles/
|
|
237
|
+
styles/ twenty style packs — instrument-console (dark console),
|
|
238
238
|
editorial-luxury (warm editorial), workbench (light/dark
|
|
239
239
|
product UI), briefing-room (dark 16:9 presentation deck),
|
|
240
240
|
atrium (warm cream consumer health), orchard (friendly
|
|
@@ -255,7 +255,10 @@ ${c("bold", "What it installs")}
|
|
|
255
255
|
whose accent is the inverted field, a serif over mono,
|
|
256
256
|
and a terminal cut below the page), tenor (warm paper at
|
|
257
257
|
zero radius and zero shadow, one orange that exists only
|
|
258
|
-
on hover, and proof delivered as silent looping video)
|
|
258
|
+
on hover, and proof delivered as silent looping video),
|
|
259
|
+
paperclip (neutral coal with no functional colour at all
|
|
260
|
+
and one curtain of gradient capsules that cannot be
|
|
261
|
+
clicked, for products that run themselves) —
|
|
259
262
|
plus a ready-made token CSS per pack and
|
|
260
263
|
STYLE_PACK_TEMPLATE.md for authoring more
|
|
261
264
|
`);
|
|
@@ -52,7 +52,11 @@ exists only on hover and on focus, a sans at weight 400 tracked negative
|
|
|
52
52
|
against a mono tracked positive, display at a line-height below one in an
|
|
53
53
|
eight-to-twelve-character measure, and proof delivered as silent looping
|
|
54
54
|
video, for products arguing that a new kind of thing must be managed like an
|
|
55
|
-
existing organisation
|
|
55
|
+
existing organisation; paperclip — neutral coal with no functional colour
|
|
56
|
+
anywhere, every control monochrome and elevation made of hairlines, the whole
|
|
57
|
+
chromatic budget spent on a curtain of gradient capsules and a row of gradient
|
|
58
|
+
section badges that cannot be clicked, for products that ask a person to run
|
|
59
|
+
something that runs itself);
|
|
56
60
|
otherwise follow the contract below (self-contained on purpose).
|
|
57
61
|
|
|
58
62
|
## Whether to animate at all — before how
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"pkg": "@sheleg-design/paperclip",
|
|
3
|
+
"globalName": "ShelegPaperclip",
|
|
4
|
+
"shape": "package",
|
|
5
|
+
"buildCmd": "npm run build",
|
|
6
|
+
"srcDir": "src",
|
|
7
|
+
"tsconfig": "tsconfig.json",
|
|
8
|
+
"cssEntry": "src/styles.css",
|
|
9
|
+
"docsDir": "src",
|
|
10
|
+
"readmeHeader": ".design-sync/conventions.md",
|
|
11
|
+
"guidelinesGlob": [
|
|
12
|
+
"guidelines/*.md"
|
|
13
|
+
]
|
|
14
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Paperclip — the design contract
|
|
2
|
+
|
|
3
|
+
The reference is <https://paperclip.ing>, measured 2026-08-14 from the two shipped
|
|
4
|
+
stylesheets (`/_next/static/chunks/0sw-z-v7xc9dd.css`, 622 rules, and
|
|
5
|
+
`/_next/static/chunks/19xj4kovk13jy.css`, 712 rules), the hero's inline SVG and the
|
|
6
|
+
`@font-face` block. Both themes read. The full pack is `styles/paperclip.md`; this file
|
|
7
|
+
is what a design agent must not get wrong.
|
|
8
|
+
|
|
9
|
+
## The one thing this pack is
|
|
10
|
+
|
|
11
|
+
**No functional colour, and one loud object that does nothing.** A neutral coal field,
|
|
12
|
+
every control monochrome, elevation made of hairlines — and the entire chromatic budget
|
|
13
|
+
spent on a curtain of gradient capsules behind the headline and a row of gradient section
|
|
14
|
+
badges, neither of which can be clicked. Delete every colour from this page and it loses
|
|
15
|
+
its poster, not its meaning.
|
|
16
|
+
|
|
17
|
+
## Non-negotiable
|
|
18
|
+
|
|
19
|
+
- **The accent is the inverted field.** Solid `--accent`, label in `--accent-ink`, capsule
|
|
20
|
+
radius, one per viewport. A brand hue has nowhere to live here.
|
|
21
|
+
- **A coloured thing is never interactive.** No gradient button, no gradient link, no
|
|
22
|
+
hover on a badge. This is the rule the whole composition rests on.
|
|
23
|
+
- **Status is never by colour alone.** `--good` and `--warn` separate by 6.2 under
|
|
24
|
+
protanopia and `--good` and `--info` by 6.7 under tritanopia — both below the 8.0
|
|
25
|
+
floor — and in the light theme `--good` (2.28:1) and `--warn` (2.15:1) are below the
|
|
26
|
+
3:1 non-text floor on paper. Every dot, ring, tint and bar carries its word.
|
|
27
|
+
- **The capsule is the shape.** `--r-pill` on the button, the badge, the org node and the
|
|
28
|
+
10 × 20 schedule mark alike. A circle is a point; a capsule is a paperclip's end. The
|
|
29
|
+
avatar is the single circle in the system, and the data bar's flat 4px the single
|
|
30
|
+
square-ended form.
|
|
31
|
+
- **Elevation is a hairline.** One resting shadow exists in the whole pack and it belongs
|
|
32
|
+
to the modal. No card floats, and the sticky nav gains nothing on scroll.
|
|
33
|
+
- **In light there is no surface step.** `--bg` and `--surface` are the same white. A grey
|
|
34
|
+
card fill turns this pack into a generic dashboard in one commit.
|
|
35
|
+
- **The tracking closes as the size opens** — −0.01em at 16px through −0.045em at 44px.
|
|
36
|
+
A 60px headline at the default 0em is the fastest way to lose the pack.
|
|
37
|
+
- **One noise recipe, on saturated surfaces only.** `fractalNoise`, `baseFrequency 2.95`,
|
|
38
|
+
5 octaves, seed 9, tiled at 256px, `mix-blend-mode: overlay` under `isolation: isolate`
|
|
39
|
+
— 12% on a badge, 86% on the artwork. The field itself stays flat colour.
|
|
40
|
+
- **One stagger, 140ms, everywhere.** The org tree, the swimlanes, the goal cascade and
|
|
41
|
+
the card reveals share it. Change it in one place or not at all.
|
|
42
|
+
- **Hover is colour, border and fill. Never geometry.** Nothing lifts, scales or shifts.
|
|
43
|
+
|
|
44
|
+
## What the reference gets wrong, and this kit does not
|
|
45
|
+
|
|
46
|
+
- `--status-task-in_progress` stays at its light value on the dark field — **3.83:1**,
|
|
47
|
+
set as text. The kit ships `#60a5fa` at 7.79:1 and marks it derived.
|
|
48
|
+
- The one text input sets `outline: none` on focus and replaces the ring with a 1px border
|
|
49
|
+
colour change. Keep the ring.
|
|
50
|
+
- Two 1.5s infinite loops (`dotPulse`, `statusBlink`) survive `prefers-reduced-motion`.
|
|
51
|
+
Stop them; their meaning is already in the word beside them.
|
|
52
|
+
- The budget bar transitions `width` for 1.2s, per bar, six bars in view. Never that —
|
|
53
|
+
`transform: scaleX()` from a left origin.
|
|
54
|
+
- There is no `@media (hover: hover)` anywhere, so every hover state fires on first touch.
|
|
55
|
+
- `font-weight: 450` is asked for and only 400 and 500 are loaded, as static instances.
|
|
56
|
+
|
|
57
|
+
## Container, not viewport
|
|
58
|
+
|
|
59
|
+
Four components size against their own box and carry `container-type: inline-size`:
|
|
60
|
+
`HairlineGrid`, `OrgNode`, `LedgerRow`, `ScheduleLane`. The page's own breakpoints — the
|
|
61
|
+
nav, the hero padding, the artwork offset, the section rhythm — stay on the viewport,
|
|
62
|
+
because the page is not inside anybody's container.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# @sheleg-design/paperclip
|
|
2
|
+
|
|
3
|
+
The React reference kit for the SHELEG **Paperclip** style pack — a neutral coal field
|
|
4
|
+
with no functional colour at all, every control monochrome, elevation made of hairlines,
|
|
5
|
+
and the whole chromatic budget spent on one curtain of gradient capsules that cannot be
|
|
6
|
+
clicked.
|
|
7
|
+
|
|
8
|
+
It is generated from the pack, not authored beside it: `src/styles.css` opens with
|
|
9
|
+
`styles/tokens/paperclip.css` byte for byte, and the rules the design agent must obey are
|
|
10
|
+
in [`.design-sync/conventions.md`](./.design-sync/conventions.md).
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm install && npm run build
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Then run `/design-sync` in Claude Code from this directory to push it to
|
|
17
|
+
claude.ai/design.
|
|
18
|
+
|
|
19
|
+
## The spine, and this pack's seven
|
|
20
|
+
|
|
21
|
+
`Button`, `Card`, `Chip`, `Stat`, `Heading` and `Rule` are identical in name, props and
|
|
22
|
+
types across every SHELEG kit — switching packs swaps identity, not API.
|
|
23
|
+
|
|
24
|
+
| Component | What it is |
|
|
25
|
+
|---|---|
|
|
26
|
+
| `CapsuleCurtain` | 96 gradient capsules from one hue-rotation rule, under a noise mask — the **signature element** |
|
|
27
|
+
| `SectionBadge` | a mono uppercase label on one of twelve ramps, each with its own hand-picked ink |
|
|
28
|
+
| `HairlineGrid` | the gap *is* the rule: 1px over a border-coloured background, clipped by the container's radius |
|
|
29
|
+
| `OrgNode` | a capsule node at 1.5px, whose live state is a word and not only a ring |
|
|
30
|
+
| `LedgerRow` | a spend row in tabular figures whose bar is white and animates `scaleX`, never `width` |
|
|
31
|
+
| `ScheduleLane` | a swimlane whose ticks are 10 × 20 capsules and whose active tick says what it is doing |
|
|
32
|
+
| `Terminal` | the only warm surface in the pack, with a concentric tab group machined into its bar |
|
|
33
|
+
|
|
34
|
+
## Container queries, not viewport queries
|
|
35
|
+
|
|
36
|
+
`HairlineGrid`, `OrgNode`, `LedgerRow` and `ScheduleLane` each take
|
|
37
|
+
`container-type: inline-size` and collapse against **their own width**. A three-across
|
|
38
|
+
grid dropped into a 320px sidebar on a 1440px screen keeps its columns and overflows
|
|
39
|
+
otherwise — which is the bug a kit's viewport query always becomes.
|
|
40
|
+
|
|
41
|
+
## Two themes, one token layer
|
|
42
|
+
|
|
43
|
+
Dark is the default; `data-theme="light"` is the twin. The dark border token is *alpha*
|
|
44
|
+
(`#ffffff1a`), so the same hairline reads correctly over the field, over `--surface` and
|
|
45
|
+
over the warm terminal without being restated. In light there is no surface step at all —
|
|
46
|
+
`--bg` and `--surface` are the same white — and that is the theme's whole idea.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@sheleg-design/paperclip",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"default": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist",
|
|
17
|
+
"src"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "tsc -p tsconfig.json"
|
|
21
|
+
},
|
|
22
|
+
"peerDependencies": {
|
|
23
|
+
"react": ">=18"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"typescript": "^5.6.0",
|
|
27
|
+
"@types/react": "^18.3.0"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
---
|
|
2
|
+
category: Actions
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
`primary` is the inverted field: solid `--accent`, label in `--accent-ink`, and the
|
|
6
|
+
capsule radius the whole pack is built from. **Its hover is theme-dependent and that is
|
|
7
|
+
deliberate** — on paper the fill goes whiter, on coal it goes away and leaves an outline.
|
|
8
|
+
Copying one gesture into both themes makes the button vanish in one of them, because on
|
|
9
|
+
paper there is nowhere brighter to go and on coal there is nowhere darker.
|
|
10
|
+
|
|
11
|
+
`secondary` is the pack's single exception to the capsule: `--r-md`, a hairline border,
|
|
12
|
+
a `--muted` label. It exists for the path that is not being recommended — the reference
|
|
13
|
+
spends it once, on `or install the local version` under the hero.
|
|
14
|
+
|
|
15
|
+
`ghost` is a text button; the label carries the whole affordance.
|
|
16
|
+
|
|
17
|
+
Nothing presses. There is no `:active` transform anywhere in this pack — hover is
|
|
18
|
+
colour, border and fill only.
|
|
19
|
+
|
|
20
|
+
```tsx
|
|
21
|
+
<Button>Join the waitlist</Button>
|
|
22
|
+
<Button variant="secondary">or install the local version</Button>
|
|
23
|
+
```
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
export interface ButtonProps {
|
|
4
|
+
/** `primary` is the inverted field — at most one per viewport. */
|
|
5
|
+
variant?: 'primary' | 'secondary' | 'ghost';
|
|
6
|
+
size?: 'sm' | 'md' | 'lg';
|
|
7
|
+
disabled?: boolean;
|
|
8
|
+
onClick?: () => void;
|
|
9
|
+
children: ReactNode;
|
|
10
|
+
className?: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function Button({
|
|
14
|
+
variant = 'primary',
|
|
15
|
+
size = 'md',
|
|
16
|
+
disabled = false,
|
|
17
|
+
onClick,
|
|
18
|
+
children,
|
|
19
|
+
className,
|
|
20
|
+
}: ButtonProps) {
|
|
21
|
+
return (
|
|
22
|
+
<button
|
|
23
|
+
type="button"
|
|
24
|
+
className={['pc-btn', `pc-btn--${variant}`, `pc-btn--${size}`, className]
|
|
25
|
+
.filter(Boolean)
|
|
26
|
+
.join(' ')}
|
|
27
|
+
disabled={disabled}
|
|
28
|
+
onClick={onClick}
|
|
29
|
+
>
|
|
30
|
+
{children}
|
|
31
|
+
</button>
|
|
32
|
+
);
|
|
33
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
category: Signature
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
**The signature element.** Eight columns on a 70px pitch, twelve 70 × 170 capsules each
|
|
6
|
+
at `rx: 35`, stepped 34.5px apart so every capsule covers all but a 34.5px band of the one
|
|
7
|
+
above it — a stack of overlapping paperclip ends falling from the top of the page.
|
|
8
|
+
|
|
9
|
+
The fills are **generated, not chosen**. The top stop rotates forward around the hue wheel
|
|
10
|
+
by ~12.4° per capsule and the bottom stop rotates backward by ~10.3°, at near-constant
|
|
11
|
+
saturation and lightness, so the two stops stay near-complementary and the column inverts
|
|
12
|
+
its own gradient between its first capsule and its last. The reference ships 45 gradients
|
|
13
|
+
and 89 distinct stops from that one rule.
|
|
14
|
+
|
|
15
|
+
Over all of it, the pack's single noise recipe — `fractalNoise`, `baseFrequency 2.95`,
|
|
16
|
+
5 octaves, seed 9 — masked by the capsules themselves and composited `overlay`. Without
|
|
17
|
+
it a twelve-gradient artwork bands on any 8-bit panel.
|
|
18
|
+
|
|
19
|
+
**It is decoration and it must stay decoration.** `aria-hidden`, no pointer events, no
|
|
20
|
+
information. The composition only works when the copy sits *on top of it*: the reference
|
|
21
|
+
pushes the artwork up by `translateY(-310px)` so only its lower half is in frame and gives
|
|
22
|
+
the headline `margin-top: 124px` to land in the curtain's lower third. A hero that puts
|
|
23
|
+
the art beside the copy is a different pack.
|
|
24
|
+
|
|
25
|
+
Entrance and parallax belong to the page, not to this component — 1.1s rise on
|
|
26
|
+
`--ease-hero`, then a native `animation-timeline: view-timeline` inside `@supports`.
|
|
27
|
+
|
|
28
|
+
```tsx
|
|
29
|
+
<div className="pc-hero__art" aria-hidden>
|
|
30
|
+
<CapsuleCurtain />
|
|
31
|
+
</div>
|
|
32
|
+
```
|