sheleg-design-skill 1.49.0 → 1.50.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/CHANGELOG.md +78 -0
  2. package/README.md +18 -4
  3. package/bin/cli.js +5 -2
  4. package/cursor/rules/sheleg-design.mdc +6 -1
  5. package/kits/almanac/src/styles.css +3 -3
  6. package/kits/daylight/src/styles.css +3 -3
  7. package/kits/notation/src/styles.css +3 -3
  8. package/kits/onionskin/.design-sync/config.json +14 -0
  9. package/kits/onionskin/.design-sync/conventions.md +63 -0
  10. package/kits/onionskin/README.md +37 -0
  11. package/kits/onionskin/package.json +29 -0
  12. package/kits/onionskin/src/Button.md +16 -0
  13. package/kits/onionskin/src/Button.tsx +33 -0
  14. package/kits/onionskin/src/Card.md +13 -0
  15. package/kits/onionskin/src/Card.tsx +24 -0
  16. package/kits/onionskin/src/Chip.md +14 -0
  17. package/kits/onionskin/src/Chip.tsx +25 -0
  18. package/kits/onionskin/src/Data.md +16 -0
  19. package/kits/onionskin/src/Data.tsx +16 -0
  20. package/kits/onionskin/src/Grid.md +14 -0
  21. package/kits/onionskin/src/Grid.tsx +15 -0
  22. package/kits/onionskin/src/Heading.md +14 -0
  23. package/kits/onionskin/src/Heading.tsx +19 -0
  24. package/kits/onionskin/src/Micro.md +17 -0
  25. package/kits/onionskin/src/Micro.tsx +17 -0
  26. package/kits/onionskin/src/Panel.md +21 -0
  27. package/kits/onionskin/src/Panel.tsx +25 -0
  28. package/kits/onionskin/src/Rule.md +14 -0
  29. package/kits/onionskin/src/Rule.tsx +18 -0
  30. package/kits/onionskin/src/Stat.md +11 -0
  31. package/kits/onionskin/src/Stat.tsx +17 -0
  32. package/kits/onionskin/src/index.ts +23 -0
  33. package/kits/onionskin/src/styles.css +532 -0
  34. package/kits/onionskin/tsconfig.json +15 -0
  35. package/kits/vitrine/src/styles.css +3 -3
  36. package/package.json +2 -2
  37. package/plugins/sheleg-design/.claude-plugin/plugin.json +2 -2
  38. package/plugins/sheleg-design/commands/sheleg-design.md +2 -2
  39. package/plugins/sheleg-design/skills/sheleg-design/DESIGN_SYNC_BRIDGE.md +1 -1
  40. package/plugins/sheleg-design/skills/sheleg-design/FIGMA_BRIDGE.md +1 -1
  41. package/plugins/sheleg-design/skills/sheleg-design/MOBILE_SURFACES.md +1 -1
  42. package/plugins/sheleg-design/skills/sheleg-design/SKILL.md +4 -3
  43. package/plugins/sheleg-design/skills/sheleg-design/SURFACE_COMPOSITION.md +3 -3
  44. package/plugins/sheleg-design/skills/sheleg-design/styles/STYLE_PACK_TEMPLATE.md +1 -1
  45. package/plugins/sheleg-design/skills/sheleg-design/styles/blueprint.md +1 -0
  46. package/plugins/sheleg-design/skills/sheleg-design/styles/onionskin.md +329 -0
  47. package/plugins/sheleg-design/skills/sheleg-design/styles/tenor.md +1 -1
  48. package/plugins/sheleg-design/skills/sheleg-design/styles/tokens/onionskin.css +271 -0
package/CHANGELOG.md CHANGED
@@ -6,6 +6,84 @@ follow [SemVer](https://semver.org/spec/v2.0.0.html).
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [1.50.0] - 2026-08-25
10
+
11
+ ### Onionskin, the thirty-fifth pack — two bases, and everything quiet is an alpha
12
+
13
+ Extracted from `supermemory.ai`, the front page of a memory and context engine for AI
14
+ applications. The site is Astro: two stylesheets totalling 154,143 bytes declaring 151
15
+ custom properties. Every value was read off **computed styles on the live page** through
16
+ CDP at 1440×900 — 1,469 visible of 1,653 elements on a 14,437px page — and at a
17
+ device-emulated 390×844.
18
+
19
+ **The principle is measurable and it is the pack.** 199 of the 631 colour-carrying
20
+ values on the page carry an alpha, drawn from exactly **two** bases: 97 from a navy used
21
+ for every rule and panel edge and never for a word, and 83 from the ink, used only for
22
+ words. Text dims through the ink; structure dims through the navy. **There is no grey
23
+ ramp in this pack**, because the reference has none — which is what separates it from
24
+ every other near-white technical sheet in the library.
25
+
26
+ At **96.5% zero radius** — 1,418 of 1,469 rendered elements — it is the squarest page
27
+ here by a margin. Three faces with one job each (a grotesque displays, a sans carries
28
+ sentences, a mono carries every number and key), a dot grid at 0.8px, dashed hairlines
29
+ for a provisional boundary, and a **working size of 11px**, which is the most frequent
30
+ size on the page at every width.
31
+
32
+ **An alpha composites in sRGB, not in linear light, and the first pass of this pack got
33
+ that wrong.** Mixed in linear space, the ink at 60% computes 2.32:1 and reads as a
34
+ failure that would have forced every tier to be redrawn; composited the way a browser
35
+ does it, the same value is **4.98:1** and passes. The correction is recorded at the top
36
+ of the token layer, because a pack whose central mechanism is alpha cannot afford the
37
+ next reader to repeat it.
38
+
39
+ **Four corrections travel with the pack.** A grey that fails on every field it is used
40
+ on — `#888e94` on 48 text nodes, 3.31:1 on white, 3.17:1 on the panel, 2.97:1 on the
41
+ tint. The lowest ink tier, which composites to 3.08:1 and carries six live text nodes,
42
+ demoted to non-text. The rules, at 1.21:1 and 1.10:1, declared as rules rather than
43
+ marks — with a ban requiring a second separator rather than a darker hairline. And 88 of
44
+ 123 interactive elements at 1440 under 44px, 73 of 106 at 390.
45
+
46
+ **The accent needed none, which is rare here:** `#0562ef` is 5.25:1 on white *and*
47
+ 5.25:1 under white, so one token carries the fill and the word with no derived twin.
48
+
49
+ **The fork against `blueprint` is the closest call in the library** and is written from
50
+ both ends. Both are near-white technical sheets, both spend one blue that writes and
51
+ fills, both are zero-radius, and `blueprint`'s Register describes this reference too.
52
+ The separation is mechanical: `blueprint` builds its quiet layer from solid greys and
53
+ rules with a solid line; this one has no greys at all. Body 16px against 11px, two
54
+ families against three, a ruled field with ticks against a dot field.
55
+
56
+ **The gate caught five of my own numbers.** Every stated ratio in the dark block was
57
+ computed by hand and five were wrong; the gate supplied the right ones and they are what
58
+ shipped. It also refused a `color-mix` with `transparent` inside it as uncomputable, and
59
+ refused three tight status pairs in a dark set I had picked rather than searched — the
60
+ searched set clears all ten pairs.
61
+
62
+ **Rendering the kit found nothing**, for the first time in four releases. Worth saying
63
+ because the step is not decoration: both classes it caught before — a control following
64
+ its field into the dark act, and a box that grew by its own padding — were pre-empted
65
+ here, `box-sizing` from the first line and a dark block with no light twin to invert.
66
+
67
+ `MOTION_INTENSITY` is pinned at **2**: 1,290 of 1,469 elements compute
68
+ `transition-duration: 0s` and `animation-timeline` appears zero times in 154,143 bytes.
69
+
70
+ `ADR-0001` gains a further application, with `quadrille`, `tracing` and `vellum` weighed
71
+ and rejected on its own criteria.
72
+
73
+ Gates: 4754 → **4882**, 2784 → **2875**, 706 → **720**. Both palette ceilings held for
74
+ the third consecutive release; `computed_at_least` rises 600 → 628.
75
+
76
+ ## [1.49.1] - 2026-08-25
77
+
78
+ ### Fixed
79
+
80
+ The README told a reader to run commands the published package cannot run: it ships no
81
+ `test/` directory, so `python3 test/validate.py` resolves in a clone and nowhere else. Measured against the
82
+ published tarball on 2026-08-25. Shipping the suite does not fix it — the plants live in
83
+ `.github/workflows/`, which no packaging npm can express puts in a tarball — so the document
84
+ now names where the command runs instead of claiming it, beside a marker the umbrella's
85
+ validator reads. Naming a dead command is this family's own rule; claiming one is the defect.
86
+
9
87
  ## [1.49.0] - 2026-08-24
10
88
 
11
89
  ### Rimlight, the thirty-fourth pack — elevation made of light
package/README.md CHANGED
@@ -3,6 +3,15 @@
3
3
  [![npm version](https://img.shields.io/npm/v/sheleg-design-skill)](https://www.npmjs.com/package/sheleg-design-skill)
4
4
  [![CI](https://github.com/ssheleg/sheleg-design-skill/actions/workflows/validate.yml/badge.svg)](https://github.com/ssheleg/sheleg-design-skill/actions/workflows/validate.yml)
5
5
  [![license: MIT](https://img.shields.io/badge/license-MIT-blue)](./LICENSE)
6
+ [![site](https://img.shields.io/badge/docs-skills.sshlg.me-8ab0ff)](https://skills.sshlg.me/skills/sheleg-design/)
7
+
8
+ **[Docs, and every skill →](https://skills.sshlg.me/)** · [this skill's page](https://skills.sshlg.me/skills/sheleg-design/) · [follow @sshlg93 on X](https://x.com/intent/follow?screen_name=sshlg93)
9
+
10
+ Loads in **DeepSeek Harness** (`dsh`) with **no plugin to write**: it reads the
11
+ Agent Skills standard directly, scanning `~/.agents/skills` — where `npx skills
12
+ add` puts this pack — at rank 500.
13
+
14
+ **[Browse every style pack →](https://ssheleg.github.io/sheleg-design-skill/)** — every card rendered in its own token layer, plus the collection audit. The site each pack was measured from stays in the pack; the published pages name none of them.
6
15
 
7
16
  An agent can generate a landing page in under a minute, and it will look like
8
17
  every other generated landing page: three cards, a gradient, a hero that does
@@ -11,7 +20,7 @@ problem — invented colors, six accent hues, dark mode retrofitted later.
11
20
 
12
21
  This skill is the taste layer. It gives a coding agent **one motion
13
22
  methodology** for cinematic, scroll-driven pages, **a motion doctrine** that
14
- decides whether to animate before it decides how, and **thirty-four locked style
23
+ decides whether to animate before it decides how, and **thirty-five locked style
15
24
  packs** with ready-made design tokens, so what it builds reads as one system
16
25
  instead of a pile of effects.
17
26
 
@@ -54,6 +63,7 @@ into the cinematic layer, and says so in its own *Motion flavor* section.
54
63
  | `patchbay` | near-black under a faint 40px grid, one mint-cyan doing every functional job, elevation made of 8% hairlines with no shadow anywhere, and a live architecture diagram whose cords carry SMIL particles | engines, message buses, pipelines, schedulers and open-source front doors — anything whose argument is an architecture rather than a promise |
55
64
  | `nameplate` | a cool near-white slab under a page that is **square on 87% of its elements** — 1,091 of 1,251 measured — where the one round shape is reserved for a white 1px-bordered pill carrying somebody else's publication name **as type rather than as a logo**, one family with the body at **weight 500**, and two uppercase registers tracked 0.06em and 0.175em | **pages whose argument is that named third parties will vouch for you** — press and media placement, PR distribution, trust marks and badges, certification, review aggregation and "as featured in" surfaces (standalone) |
56
65
  | `rimlight` | a white field with a cool grey act separator and one near-black act, a grotesque for every sentence and a **monospace for every piece of chrome**, square on 84% of its elements, tracked negative at every size and with **no bold anywhere** — and an elevation made of **coloured light**: a sixteen-layer rig, six layers lit and ten held at alpha 0, thrown from below-left onto one control per viewport | **a studio's own front door and the pages that sell what it makes** — design and engineering agencies, product studios, service and case-study pages (standalone) |
66
+ | `onionskin` | a white technical sheet at **96.5% zero radius** — the squarest page in the library — where **two bases do all the work and everything quiet is one of them at an alpha**: text dims through the ink, structure through a navy that is never a word, so there is no grey ramp at all. A dot grid, dashed hairlines, three faces with one job each, and an **11px working size** | **developer and AI infrastructure whose front page is a working document** — memory and context engines, retrieval services, agent runtimes, evaluation and observability surfaces (standalone) |
57
67
  | `outrank` | white field with one violet that carries text in both directions, a 5px light ring standing in for a button shadow, and two type families split by how long a thing is read | SEO and growth SaaS, agent-run back-office — the pack for a product that ships a landing and a dashboard at once |
58
68
  | `orchard` | warm oat field of rounded slabs, sage brand + one candy-orange action, rounded geometric display, soft-3D pills built from inset light | friendly consumer biotech, DTC wellness, testing kits & supplements |
59
69
  | `field-notes` | warm green-cast paper ruled by hairlines, one rust accent, a hero that dissolves into the page instead of ending, numbered mono eyebrows, crop marks, colour that encodes how a claim is known | open-source & developer tools sold on auditability — code intelligence, provenance, evals, agent memory |
@@ -154,7 +164,7 @@ skills.
154
164
  | `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 |
155
165
  | `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 |
156
166
  | `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 |
157
- | `styles/*.md` | The thirty-four style packs — palette, type, texture, motion tokens, motifs, bans, and the traps each one carries |
167
+ | `styles/*.md` | The thirty-five style packs — palette, type, texture, motion tokens, motifs, bans, and the traps each one carries |
158
168
  | `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) |
159
169
  | `styles/STYLE_PACK_TEMPLATE.md` | The pack contract as a skeleton, so a new style is authored against the same headings rather than improvised |
160
170
 
@@ -225,7 +235,7 @@ cd ./ds-workbench && npm install && npm run build
225
235
  then `/design-sync` in that directory, from Claude Code. Three layers cross: the
226
236
  pack's **bans** as the design system's own README, `styles.css` built from
227
237
  `tokens/<pack>.css` verbatim, and the components — a six-name spine that is
228
- identical in all thirty-four kits, so switching packs swaps identity rather than API,
238
+ identical in all thirty-five kits, so switching packs swaps identity rather than API,
229
239
  plus each pack's signature parts. **Motion does not cross**, exactly as it does
230
240
  not cross into Figma: a kit is the static half of a pack, and saying so is what
231
241
  stops an agent inventing motion to fill the silence.
@@ -248,6 +258,10 @@ repo. Entirely optional; without it the skill works from the pack alone.
248
258
 
249
259
  ## Development
250
260
 
261
+ <!-- commands-run-in: a clone -->
262
+ These run **in a clone of this repository**. The published npm package ships no
263
+ `test/` directory, so from an install they are names, not commands.
264
+
251
265
  ```bash
252
266
  python3 test/validate.py # or: npm test
253
267
  ```
@@ -271,7 +285,7 @@ a pack's four widened sections used to make two gates *quieter* and still green.
271
285
  One honest limit: the npx installer is checked by asserting its runtime bundle
272
286
  walker exists, not by reading a file list — it has none by design. What proves
273
287
  it ships the right files is CI, which installs the bundle through **both**
274
- installers and `diff -r`s the result against the source, then builds all thirty-four
288
+ installers and `diff -r`s the result against the source, then builds all thirty-five
275
289
  kits.
276
290
 
277
291
  `test/scenarios.md` (T1–T30) 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/ thirty-four style packs — instrument-console (dark console),
237
+ styles/ thirty-five 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), patchbay (dark live
@@ -244,7 +244,10 @@ ${c("bold", "What it installs")}
244
244
  as type), rimlight (a white field and one near-black
245
245
  act, a monospace carrying every label and button, and
246
246
  an elevation made of coloured light rather than a
247
- shadow), babylove (white +
247
+ shadow), onionskin (a white technical sheet at 96.5%
248
+ zero radius where every quiet value is the ink or a
249
+ navy at an alpha, over a dot grid, at an 11px working
250
+ size), babylove (white +
248
251
  one orange, seven tokens over Tailwind defaults),
249
252
  outrank (white +
250
253
  one violet, a landing and a dashboard in one brand),
@@ -112,7 +112,12 @@ rimlight — a white field with a cool grey act separator and one near-black act
112
112
  grotesque for every sentence and a monospace for every piece of chrome, square on 84%
113
113
  of its elements, tracked negative at every size and with no bold anywhere, whose only
114
114
  elevation is a sixteen-layer coloured light rig thrown from below-left onto one
115
- control per viewport, for a studio's front door and its service and case-study pages);
115
+ control per viewport, for a studio's front door and its service and case-study pages;
116
+ onionskin — a white technical sheet at 96.5% zero radius where two bases do all the
117
+ work and everything quiet is one of them at an alpha: text dims through the ink,
118
+ structure through a navy that is never a word, over a dot grid with dashed hairlines,
119
+ three faces with one job each and an 11px working size, for developer and AI
120
+ infrastructure whose front page is a working document);
116
121
  otherwise follow the contract below (self-contained on purpose).
117
122
 
118
123
  ## Whether to animate at all — before how
@@ -404,7 +404,7 @@
404
404
  }
405
405
 
406
406
  .al-status--ok .al-status__dot {
407
- background: var(--ok-mark);
407
+ background: var(--ok);
408
408
  }
409
409
 
410
410
  .al-status--warn {
@@ -413,7 +413,7 @@
413
413
  }
414
414
 
415
415
  .al-status--warn .al-status__dot {
416
- background: var(--warn-mark);
416
+ background: var(--warn);
417
417
  }
418
418
 
419
419
  .al-status--danger {
@@ -422,7 +422,7 @@
422
422
  }
423
423
 
424
424
  .al-status--danger .al-status__dot {
425
- background: var(--danger-mark);
425
+ background: var(--danger);
426
426
  }
427
427
 
428
428
  .al-status--neutral {
@@ -398,7 +398,7 @@
398
398
  }
399
399
 
400
400
  .dy-status--ok .dy-status__dot {
401
- background: var(--ok-mark);
401
+ background: var(--ok);
402
402
  }
403
403
 
404
404
  .dy-status--warn {
@@ -407,7 +407,7 @@
407
407
  }
408
408
 
409
409
  .dy-status--warn .dy-status__dot {
410
- background: var(--warn-mark);
410
+ background: var(--warn);
411
411
  }
412
412
 
413
413
  .dy-status--danger {
@@ -416,7 +416,7 @@
416
416
  }
417
417
 
418
418
  .dy-status--danger .dy-status__dot {
419
- background: var(--danger-mark);
419
+ background: var(--danger);
420
420
  }
421
421
 
422
422
  .dy-status--neutral {
@@ -396,7 +396,7 @@ strong, b { font-weight: var(--w-bold); }
396
396
  }
397
397
 
398
398
  .nt-status--ok .nt-status__dot {
399
- background: var(--ok-mark);
399
+ background: var(--ok);
400
400
  }
401
401
 
402
402
  .nt-status--warn {
@@ -405,7 +405,7 @@ strong, b { font-weight: var(--w-bold); }
405
405
  }
406
406
 
407
407
  .nt-status--warn .nt-status__dot {
408
- background: var(--warn-mark);
408
+ background: var(--warn);
409
409
  }
410
410
 
411
411
  .nt-status--danger {
@@ -414,7 +414,7 @@ strong, b { font-weight: var(--w-bold); }
414
414
  }
415
415
 
416
416
  .nt-status--danger .nt-status__dot {
417
- background: var(--danger-mark);
417
+ background: var(--danger);
418
418
  }
419
419
 
420
420
  .nt-status--neutral {
@@ -0,0 +1,14 @@
1
+ {
2
+ "pkg": "@sheleg-design/onionskin",
3
+ "globalName": "ShelegOnionskin",
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,63 @@
1
+ # Onionskin — the contract this design system ships under
2
+
3
+ **Register.** Choose Onionskin for **developer and AI infrastructure whose front page is
4
+ a working document**: memory and context engines, retrieval and embedding services,
5
+ agent runtimes, evaluation and observability surfaces. A white technical sheet at 96.5%
6
+ zero radius, ruled by hairlines, over a dot grid. Build every screen against `var(--…)`
7
+ and never a literal.
8
+
9
+ **Two bases, and everything quiet is one of them at an alpha.** Text dims through
10
+ `--ink`; structure dims through a navy that is never a word. There is **no grey ramp in
11
+ this pack** — introducing `#6b7280` here introduces a third base and dissolves the whole
12
+ construction. 199 of the reference's 631 colour-carrying values carry an alpha, from
13
+ exactly two bases.
14
+
15
+ **An alpha composites in sRGB, not in linear light.** `--ink` at 60% is 4.98:1 and
16
+ passes; computed in linear space the same value reads 2.32:1 and looks like a failure.
17
+ Every ratio in the token layer was computed the way a browser composites.
18
+
19
+ **The navy is never a word.** At its working alpha it is 1.21:1. It rules and it edges.
20
+
21
+ **A rule is never the only separator.** At 1.21:1 a hairline is below every floor there
22
+ is, so the region it bounds must ALSO change field, gain a label, or gain space. This is
23
+ a ban, not a preference.
24
+
25
+ **Elevation is an edge.** `--edge-lit` — the accent at 28%, inset on the left and right
26
+ — marks the one panel per section that is the subject. `--shadow-lift` appears once on
27
+ the reference and should appear once on your page. A panel never floats.
28
+
29
+ **The working size is 11px.** It is the most frequent size on the reference at every
30
+ width, and it carries labels, keys, annotations and mono data. Setting it at 13px "for
31
+ readability" turns this into a different pack; the density is the argument.
32
+
33
+ **Tracking is two-sided.** `--track-micro` (+0.18em) on the uppercase label,
34
+ `--track-display` (−0.05em) on the display. Collapsing them loses the page's texture.
35
+
36
+ **Three faces, one job each.** Space Grotesk displays, DM Sans carries every sentence,
37
+ DM Mono carries every number, key and identifier. Nothing crosses: a number in the sans
38
+ or a sentence in the mono and the page stops reading as a document.
39
+
40
+ **No bold.** 500 is the ceiling at scale — 205 nodes against 400's 175, with 600 on
41
+ seven elements and 700 on four.
42
+
43
+ **No radius above 5px.** 1,418 of 1,469 rendered elements are square.
44
+
45
+ **The dot grid is a field.** Under a section, never inside a panel, never a border, and
46
+ its 24px step does not rescale at narrow widths.
47
+
48
+ **The accent needed no correction.** `#0562ef` is 5.25:1 on white and 5.25:1 under
49
+ white — one token for the fill and the word.
50
+
51
+ **Status is never by colour alone**, on either field, and the dark band carries its own
52
+ four because the light set measures 1.4–2.6:1 there.
53
+
54
+ **`[data-surface="dark"]` is one section, never the document.** Its rules invert base
55
+ rather than alpha — white at 14% instead of navy at 10% — because a navy at 10% over
56
+ near-black is nothing at all.
57
+
58
+ **Every control clears `--tap-min` (44px).** A correction: 88 of the reference's 123
59
+ interactive elements at 1440 are shorter, and 73 of 106 at 390.
60
+
61
+ **Nothing travels in space.** No parallax, no scrub, no `animation-timeline`, no press
62
+ translation. `MOTION_INTENSITY` above 2 has nothing legal to buy, and reduced motion
63
+ collapses every duration to zero.
@@ -0,0 +1,37 @@
1
+ # @sheleg-design/onionskin
2
+
3
+ The React reference kit for the SHELEG **Onionskin** style pack — a white technical
4
+ sheet at 96.5% zero radius where two bases do all the work and everything quiet is one
5
+ of them at an alpha.
6
+
7
+ It is generated from the pack, not authored beside it: `src/styles.css` opens with
8
+ `styles/tokens/onionskin.css` byte for byte, and the rules the design agent must obey
9
+ are in [`.design-sync/conventions.md`](./.design-sync/conventions.md).
10
+
11
+ ```bash
12
+ npm install && npm run build
13
+ ```
14
+
15
+ ## The spine
16
+
17
+ `Button`, `Card`, `Chip`, `Stat`, `Heading`, `Rule` — identical names, props and types
18
+ in every SHELEG kit, so switching packs swaps identity rather than API. On this pack
19
+ `Card` exists for parity only: reach for `Panel`.
20
+
21
+ ## This pack's own
22
+
23
+ `Panel` (the signature — a ruled region of the sheet, with a provisional dashed variant
24
+ and a lit-edge subject variant), `Micro` (11px uppercase tracked open, the most repeated
25
+ object on the page), `Data` (the monospace, which owns every number) and `Grid` (the dot
26
+ field, which goes under a section and nowhere else).
27
+
28
+ ## The three rules that carry the kit
29
+
30
+ 1. **There is no grey.** Every quiet value is `--ink` or the navy at an alpha. The
31
+ moment a third base appears, the system reads as an ordinary light UI.
32
+ 2. **Nothing floats.** Elevation is a 1px rule and, once per section, an inset lit edge.
33
+ 3. **The three faces do not cross.** Display, sentences, numbers — one family each.
34
+
35
+ **Motion does not cross into a design tool.** A kit is the static half of a pack, and
36
+ this one is nearly all static by measurement: 1,290 of the reference's 1,469 visible
37
+ elements do not transition at all.
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "@sheleg-design/onionskin",
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,16 @@
1
+ ---
2
+ category: Actions
3
+ ---
4
+
5
+ `primary` fills with `--accent` and takes `--on-accent` — 5.25:1, and the same number
6
+ in both directions, which is why this pack needs no derived accent twin. `secondary` is
7
+ `--surface` with a 1px `--rule` and an `--ink` label; hover moves the border to
8
+ `--accent-rule` and never adds a fill.
9
+
10
+ `--r-sm` (4px), and every size clears `--tap-min` (44px). The reference's own controls
11
+ are 36px — that is the one geometry this pack corrects rather than copies.
12
+
13
+ ```tsx
14
+ <Button>Get an API key</Button>
15
+ <Button variant="secondary">Read the docs</Button>
16
+ ```
@@ -0,0 +1,33 @@
1
+ import type { ReactNode } from 'react';
2
+
3
+ export interface ButtonProps {
4
+ /** `primary` is the accent fill — at most one per view. */
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={['ok-btn', `ok-btn--${variant}`, `ok-btn--${size}`, className]
25
+ .filter(Boolean)
26
+ .join(' ')}
27
+ disabled={disabled}
28
+ onClick={onClick}
29
+ >
30
+ {children}
31
+ </button>
32
+ );
33
+ }
@@ -0,0 +1,13 @@
1
+ ---
2
+ category: Surfaces
3
+ ---
4
+
5
+ Present for spine parity. **On this pack, reach for `Panel` instead** — the reference
6
+ has no rounded card, and `Card` here is a `Panel` with a title row: zero radius, a 1px
7
+ `--rule`, no shadow.
8
+
9
+ If a design calls for something that floats, it is not this pack.
10
+
11
+ ```tsx
12
+ <Card title="Throughput" meta="p95">…</Card>
13
+ ```
@@ -0,0 +1,24 @@
1
+ import type { ReactNode } from 'react';
2
+
3
+ export interface CardProps {
4
+ title?: string;
5
+ /** Right-aligned metadata on the title row: a count, an id, a timestamp. */
6
+ meta?: string;
7
+ children: ReactNode;
8
+ className?: string;
9
+ }
10
+
11
+ export function Card({ title, meta, children, className }: CardProps) {
12
+ const head = title !== undefined || meta !== undefined;
13
+ return (
14
+ <section className={['ok-card', className].filter(Boolean).join(' ')}>
15
+ {head && (
16
+ <div className="ok-card__head">
17
+ {title !== undefined && <h3 className="ok-card__title">{title}</h3>}
18
+ {meta !== undefined && <span className="ok-card__meta">{meta}</span>}
19
+ </div>
20
+ )}
21
+ <div className="ok-card__body">{children}</div>
22
+ </section>
23
+ );
24
+ }
@@ -0,0 +1,14 @@
1
+ ---
2
+ category: Foundations
3
+ ---
4
+
5
+ A tag at `--r-xs` (2px) with a 1px `--rule` and a `--t-micro` label. `accent` tints with
6
+ `--accent-wash`, which is `--tint` — the reference's called-out block colour doing double
7
+ duty.
8
+
9
+ `selected` fills `--accent` with `--on-accent`.
10
+
11
+ ```tsx
12
+ <Chip>embeddings</Chip>
13
+ <Chip tone="accent" selected>vector</Chip>
14
+ ```
@@ -0,0 +1,25 @@
1
+ import type { ReactNode } from 'react';
2
+
3
+ export interface ChipProps {
4
+ children: ReactNode;
5
+ selected?: boolean;
6
+ tone?: 'neutral' | 'accent';
7
+ className?: string;
8
+ }
9
+
10
+ export function Chip({ children, selected = false, tone = 'neutral', className }: ChipProps) {
11
+ return (
12
+ <span
13
+ className={[
14
+ 'ok-chip',
15
+ `ok-chip--${tone}`,
16
+ selected ? 'ok-chip--selected' : undefined,
17
+ className,
18
+ ]
19
+ .filter(Boolean)
20
+ .join(' ')}
21
+ >
22
+ {children}
23
+ </span>
24
+ );
25
+ }
@@ -0,0 +1,16 @@
1
+ ---
2
+ category: Data
3
+ ---
4
+
5
+ Every number, key and identifier on the page, in `--font-mono` at `--t-micro` or
6
+ `--t-xs`. The figure takes `--ink`; its unit takes `--ink-soft`, which is the ink at
7
+ 60% rather than a grey.
8
+
9
+ **Nothing crosses the three families.** A number in the sans, or a sentence in the mono,
10
+ and the page stops reading as a document — that is the whole reason the pack carries
11
+ three faces instead of two.
12
+
13
+ ```tsx
14
+ <Data value="42" unit="ms" />
15
+ <Data value="sk_live_…" />
16
+ ```
@@ -0,0 +1,16 @@
1
+ export interface DataProps {
2
+ /** The figure. Always the monospace — a number in the sans breaks the document. */
3
+ value: string;
4
+ /** Its unit or suffix, one tier quieter. */
5
+ unit?: string;
6
+ className?: string;
7
+ }
8
+
9
+ export function Data({ value, unit, className }: DataProps) {
10
+ return (
11
+ <span className={['ok-data', className].filter(Boolean).join(' ')}>
12
+ <span className="ok-data__value">{value}</span>
13
+ {unit !== undefined && <span className="ok-data__unit">{unit}</span>}
14
+ </span>
15
+ );
16
+ }
@@ -0,0 +1,14 @@
1
+ ---
2
+ category: Surfaces
3
+ ---
4
+
5
+ The page's only texture: a `radial-gradient` dot of `--grid-color` at `--grid-dot`
6
+ (0.8px) repeated every `--grid-step` (24px).
7
+
8
+ It is a **field**. It belongs under a section, and it is never a border and never
9
+ inside a panel. The step does not rescale at narrow widths — a field that rescales
10
+ stops reading as paper.
11
+
12
+ ```tsx
13
+ <Grid><section>…</section></Grid>
14
+ ```
@@ -0,0 +1,15 @@
1
+ import type { ReactNode } from 'react';
2
+
3
+ export interface GridProps {
4
+ children: ReactNode;
5
+ className?: string;
6
+ }
7
+
8
+ /** The dot field. It goes UNDER a section — never inside a panel, never as a border. */
9
+ export function Grid({ children, className }: GridProps) {
10
+ return (
11
+ <div className={['ok-grid', className].filter(Boolean).join(' ')} data-grid="">
12
+ {children}
13
+ </div>
14
+ );
15
+ }
@@ -0,0 +1,14 @@
1
+ ---
2
+ category: Foundations
3
+ ---
4
+
5
+ Three levels in `--font-display` (Space Grotesk) at `--weight-medium` (500) with
6
+ `--track-display` (−0.05em): 1 is `--t-display` (56px, 34px at ≤768), 2 is `--t-h2`
7
+ (40px), 3 is `--t-h3` (28px).
8
+
9
+ **No bold.** 500 is the ceiling at scale on this pack; a headline is loud because it is
10
+ 56px and tracked in hard.
11
+
12
+ ```tsx
13
+ <Heading level={1}>Memory for your agents</Heading>
14
+ ```
@@ -0,0 +1,19 @@
1
+ import type { ReactNode } from 'react';
2
+
3
+ export interface HeadingProps {
4
+ /** 1 = page title (28px), 2 = section (20px), 3 = card title (15px). */
5
+ level?: 1 | 2 | 3;
6
+ children: ReactNode;
7
+ className?: string;
8
+ }
9
+
10
+ export function Heading({ level = 2, children, className }: HeadingProps) {
11
+ const Tag = `h${level}` as 'h1' | 'h2' | 'h3';
12
+ return (
13
+ <Tag
14
+ className={['ok-heading', `ok-heading--${level}`, className].filter(Boolean).join(' ')}
15
+ >
16
+ {children}
17
+ </Tag>
18
+ );
19
+ }