sheleg-design-skill 1.27.0 → 1.29.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 (83) hide show
  1. package/CHANGELOG.md +154 -0
  2. package/README.md +6 -4
  3. package/bin/cli.js +6 -2
  4. package/cursor/rules/sheleg-design.mdc +10 -1
  5. package/kits/ora/.design-sync/config.json +14 -0
  6. package/kits/ora/.design-sync/conventions.md +61 -0
  7. package/kits/ora/README.md +43 -0
  8. package/kits/ora/package.json +29 -0
  9. package/kits/ora/src/Button.md +21 -0
  10. package/kits/ora/src/Button.tsx +33 -0
  11. package/kits/ora/src/Card.md +19 -0
  12. package/kits/ora/src/Card.tsx +24 -0
  13. package/kits/ora/src/Chip.md +16 -0
  14. package/kits/ora/src/Chip.tsx +25 -0
  15. package/kits/ora/src/Heading.md +15 -0
  16. package/kits/ora/src/Heading.tsx +19 -0
  17. package/kits/ora/src/LayerBar.md +26 -0
  18. package/kits/ora/src/LayerBar.tsx +57 -0
  19. package/kits/ora/src/Rule.md +15 -0
  20. package/kits/ora/src/Rule.tsx +18 -0
  21. package/kits/ora/src/SectionRule.md +18 -0
  22. package/kits/ora/src/SectionRule.tsx +37 -0
  23. package/kits/ora/src/Stat.md +15 -0
  24. package/kits/ora/src/Stat.tsx +17 -0
  25. package/kits/ora/src/StatusDot.md +16 -0
  26. package/kits/ora/src/StatusDot.tsx +21 -0
  27. package/kits/ora/src/StepLog.md +22 -0
  28. package/kits/ora/src/StepLog.tsx +39 -0
  29. package/kits/ora/src/Terminal.md +18 -0
  30. package/kits/ora/src/Terminal.tsx +27 -0
  31. package/kits/ora/src/Verdict.md +21 -0
  32. package/kits/ora/src/Verdict.tsx +47 -0
  33. package/kits/ora/src/index.ts +27 -0
  34. package/kits/ora/src/styles.css +669 -0
  35. package/kits/ora/tsconfig.json +15 -0
  36. package/kits/tenor/.design-sync/config.json +14 -0
  37. package/kits/tenor/.design-sync/conventions.md +70 -0
  38. package/kits/tenor/README.md +43 -0
  39. package/kits/tenor/package.json +29 -0
  40. package/kits/tenor/src/Button.md +21 -0
  41. package/kits/tenor/src/Button.tsx +33 -0
  42. package/kits/tenor/src/Card.md +18 -0
  43. package/kits/tenor/src/Card.tsx +24 -0
  44. package/kits/tenor/src/Chip.md +15 -0
  45. package/kits/tenor/src/Chip.tsx +25 -0
  46. package/kits/tenor/src/Eyebrow.md +13 -0
  47. package/kits/tenor/src/Eyebrow.tsx +22 -0
  48. package/kits/tenor/src/FilmFrame.md +18 -0
  49. package/kits/tenor/src/FilmFrame.tsx +40 -0
  50. package/kits/tenor/src/Guardrail.md +20 -0
  51. package/kits/tenor/src/Guardrail.tsx +27 -0
  52. package/kits/tenor/src/Heading.md +17 -0
  53. package/kits/tenor/src/Heading.tsx +19 -0
  54. package/kits/tenor/src/Lattice.md +19 -0
  55. package/kits/tenor/src/Lattice.tsx +23 -0
  56. package/kits/tenor/src/LatticeCell.md +20 -0
  57. package/kits/tenor/src/LatticeCell.tsx +37 -0
  58. package/kits/tenor/src/Rule.md +13 -0
  59. package/kits/tenor/src/Rule.tsx +18 -0
  60. package/kits/tenor/src/SplitHeadline.md +22 -0
  61. package/kits/tenor/src/SplitHeadline.tsx +30 -0
  62. package/kits/tenor/src/Staircase.md +25 -0
  63. package/kits/tenor/src/Staircase.tsx +33 -0
  64. package/kits/tenor/src/Stat.md +14 -0
  65. package/kits/tenor/src/Stat.tsx +17 -0
  66. package/kits/tenor/src/index.ts +29 -0
  67. package/kits/tenor/src/styles.css +646 -0
  68. package/kits/tenor/tsconfig.json +15 -0
  69. package/package.json +2 -2
  70. package/plugins/sheleg-design/.claude-plugin/plugin.json +2 -2
  71. package/plugins/sheleg-design/commands/sheleg-design.md +1 -1
  72. package/plugins/sheleg-design/skills/sheleg-design/DESIGN_SYNC_BRIDGE.md +1 -1
  73. package/plugins/sheleg-design/skills/sheleg-design/MOBILE_SURFACES.md +1 -1
  74. package/plugins/sheleg-design/skills/sheleg-design/SKILL.md +6 -4
  75. package/plugins/sheleg-design/skills/sheleg-design/SURFACE_COMPOSITION.md +4 -4
  76. package/plugins/sheleg-design/skills/sheleg-design/styles/blueprint.md +4 -0
  77. package/plugins/sheleg-design/skills/sheleg-design/styles/datasheet.md +5 -1
  78. package/plugins/sheleg-design/skills/sheleg-design/styles/manpage.md +5 -1
  79. package/plugins/sheleg-design/skills/sheleg-design/styles/ora.md +523 -0
  80. package/plugins/sheleg-design/skills/sheleg-design/styles/roster.md +5 -1
  81. package/plugins/sheleg-design/skills/sheleg-design/styles/tenor.md +470 -0
  82. package/plugins/sheleg-design/skills/sheleg-design/styles/tokens/ora.css +219 -0
  83. package/plugins/sheleg-design/skills/sheleg-design/styles/tokens/tenor.css +207 -0
package/CHANGELOG.md CHANGED
@@ -4,6 +4,160 @@ 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.29.0] - 2026-08-14
8
+
9
+ A nineteenth pack, **`tenor`**, and the first one in the library extracted from a
10
+ **hand-authored stylesheet** rather than a compiled bundle: <https://heytenor.com> ships
11
+ 33,822 bytes of CSS somebody wrote, so the token names, the ratios between them and the
12
+ reasons they exist were all legible in the source instead of having to be reconstructed.
13
+
14
+ ### Added
15
+
16
+ - **`styles/tenor.md` + `styles/tokens/tenor.css` — widened contract, all thirteen
17
+ headings.** Warm paper `#f7f6f2` under near-black ink at 17.61:1, **zero `border-radius`
18
+ and zero `box-shadow` in the entire reference**, and one border weight for the whole
19
+ system. The colour argument is the pack: at rest the page carries a single 25px orange
20
+ square, and every other appearance of the accent is a hover fill or the focus ring — a
21
+ page in this pack screenshots with no colour in it at all.
22
+ - **Severity as value rather than hue.** The reference's guardrail chips settle it in one
23
+ row: ALWAYS ASK is the orange, LIMIT is a grey, NEVER is the ink, and the *word* carries
24
+ the meaning in all three. The pack ships `--sev-ask` / `--sev-limit` / `--sev-never` as
25
+ the primary system; `--warn` is the accent and `--danger` is the ink, so `--good`
26
+ `#296b46` is the only value in the pack the reference does not contain, and it is marked
27
+ DERIVED at its declaration.
28
+ - **Type: two families, two weights, and tracking that runs both ways.** The sans is held
29
+ at weight 400 and tracks negative, tightening to `-0.065em` on the hero; the mono is 500
30
+ and tracks positive, opening to `0.12em` on the smallest label. Display line-height goes
31
+ **below one** — 0.91 at a `12ch` measure — which is what turns every heading into a
32
+ three- or four-line stack.
33
+ - **`kits/tenor/` — the React reference kit**, the six-name spine plus seven signature
34
+ components: `Staircase` (the signature element, typed as a **four-tuple** so the value
35
+ ramp cannot grow a fifth rung), `SplitHeadline`, `Lattice` + `LatticeCell`, `FilmFrame`,
36
+ `Guardrail` and `Eyebrow`. Every breakpoint in `src/styles.css` is a `@container` query;
37
+ `FilmFrame` deliberately does not call `play()`, because the page owns the motion policy
38
+ and a kit is the static half of a pack.
39
+
40
+ ### Changed
41
+
42
+ - **The library is nineteen packs**, and every counted claim moved with it: `SKILL.md`
43
+ (the routing table, the core-contract split — six of the nineteen, the other thirteen —
44
+ and the token-vocabulary note), `README.md`, `bin/cli.js`, `install.sh`, the three
45
+ manifests, the Cursor rule, the slash command, `MOBILE_SURFACES.md`,
46
+ `SURFACE_COMPOSITION.md` (`--accent` in seventeen packs, `@role non-text:` in thirteen of
47
+ the nineteen) and `DESIGN_SYNC_BRIDGE.md` (nineteen kits).
48
+ - **`blueprint` and `roster` fork against it, reciprocally.** `blueprint` also refuses
49
+ radius outright and also builds from hairlines — the tell is the marks, since it draws
50
+ registration marks over a visible grid and `tenor` has neither. `roster` also spends one
51
+ orange on a light field and also forbids it from carrying a word — it argues *who
52
+ already uses you*, where `tenor` argues *how the work is organised*.
53
+ - **`bin/cli.js` now names `ora` as well.** The enumeration gate had passed it since
54
+ 1.28.0 because `ora` is a substring of `cyclorama` — the under-reporting the machine's
55
+ own notes warn about, found by the same check failing honestly on `tenor`.
56
+ - **Ratchet floors raised** to 2294 / 1156 / 478, purely additive; all three self-tests
57
+ still catch every planted defect.
58
+
59
+ ### Six defects in the reference, recorded in the pack rather than copied
60
+
61
+ - **`--ink-soft` is 4.16:1** on the paper and carries every lead paragraph at 16px, which
62
+ is not large text — short of AA by a margin no one notices and every audit finds.
63
+ - **`--ink-faint` is 2.36:1** and carries the grey half of the hero headline at 40.8px to
64
+ 74.4px, below even the 3:1 that large text is allowed.
65
+ - **The accent clears its non-text floor by 0.02**, and contrast is symmetric — so a paper
66
+ label on an orange fill is the same 3.02:1. Both of the reference's orange-filled
67
+ elements put a label below the large-text threshold on it, including **every CTA at the
68
+ moment it is hovered**, where the label falls from 17.61:1 to 3.02:1.
69
+ - **A variable font is loaded across two axes and used at one point**: Instrument Sans is
70
+ requested as `wdth,wght@75..100,400..600` against zero `font-stretch` declarations, zero
71
+ `font-variation-settings` and exactly one weight in 33,822 bytes.
72
+ - **The mobile panel ships the pre-`dvh` viewport unit as its base** with a `@supports`
73
+ upgrade, so it jumps on every browser that lacks the upgrade.
74
+ - **Seven display selectors carry hand-written `<br>` tags** whose visibility is then
75
+ managed at 620px, and one of them appears in both the hide rule and the re-show rule.
76
+
77
+ ## [1.28.0] - 2026-08-14
78
+
79
+ > Authored and gated on its own, **released inside `v1.29.0`**: the `tenor` pack followed
80
+ > it in the same session before a tag was cut, and splitting the two after the fact would
81
+ > have produced an intermediate commit whose ratchet floors no longer matched its own
82
+ > tree. There is no `v1.28.0` tag; this section is the record of what it added.
83
+
84
+ An eighteenth pack, **`ora`**, extracted from a live reference rather than composed:
85
+ <https://ora.ai> and <https://journey.ora.ai>, read from the shipped stylesheet
86
+ `/_next/static/chunks/feb8eaf5618096ba.css` and the route bundles beside it. It is the
87
+ first pack in the library whose **default theme is dark** — because that is the
88
+ reference's own arrangement, which paints its dark values on
89
+ `:root:not([data-theme=light])`, so an unattributed root is dark.
90
+
91
+ ### Added
92
+
93
+ - **`styles/ora.md` + `styles/tokens/ora.css` — widened contract, all thirteen
94
+ headings.** A warm coal field, cream ink, and **no third hue**: the accent is the
95
+ inverted field, which the reference names out loud as
96
+ `--accent-signature` / `--accent-signature-foreground` and spends as
97
+ `bg-foreground text-background` on its one primary action. Both themes ship: coal
98
+ `#141210` with cream `#f7f2e5` at 16.72:1, paper `#f9f7f2` with `#1a1a1a` at 16.26:1.
99
+ - **Two families and one of them is a serif doing the sans job.** `--font-sans`,
100
+ `--font-serif` and `--default-font-family` all resolve to Lora, so there is no sans
101
+ anywhere in the system; Space Mono carries every machine fact. The rule the pair
102
+ encodes — a serif means a person said it, mono means a machine reported it — is what
103
+ the whole page is read through, and the pack bans adding a sans for that reason.
104
+ - **`kits/ora/` — the React reference kit**, the six-name spine plus six signature
105
+ components: `Verdict` (the signature element), `LayerBar`, `Terminal`, `StepLog`,
106
+ `SectionRule`, `StatusDot`. `src/styles.css` opens with the token layer byte for byte;
107
+ every breakpoint in it is a `@container` query, so no component is sized by the screen.
108
+ - **The verdict numeral as the signature element.** One number in the display serif in
109
+ its grade colour, a hairline `/ 100` at half its size, and the letter plus the word
110
+ beneath. `grade` and `label` are **required props** on the component, which is the
111
+ palette rule made into an API: under deuteranopia `--good` and `--danger` separate by
112
+ 6.5 in dark and 7.4 in light, below the 8.0 CVD floor, so the letter and the word are
113
+ what make the verdict legible.
114
+
115
+ ### Changed
116
+
117
+ - **The library is eighteen packs**, and every counted claim moved with it: `SKILL.md`
118
+ (the routing table, the core-contract split — six of the eighteen, the other twelve —
119
+ and the token-vocabulary note), `README.md`, `bin/cli.js`, `install.sh`, the three
120
+ manifests, the Cursor rule, the slash command, `MOBILE_SURFACES.md`,
121
+ `SURFACE_COMPOSITION.md` (`--accent` in sixteen packs, `@role non-text:` in twelve of
122
+ the eighteen) and `DESIGN_SYNC_BRIDGE.md` (eighteen kits).
123
+ - **`datasheet` and `manpage` fork against it, reciprocally.** Both are verdict-shaped
124
+ and both refuse a second family, so an agent reaching either first now learns the
125
+ distinction: `datasheet` when the artefact is a row of cells, `manpage` when the page
126
+ is documentation, `ora` when the artefact is a number with a grade and the reader must
127
+ be shown the raw response a machine received.
128
+ - **Ratchet floors raised** to 2179 / 1095 / 464, purely additive; all three self-tests
129
+ still catch every planted defect.
130
+
131
+ ### Six defects in the reference, recorded in the pack rather than copied
132
+
133
+ Named in `## Gotchas` because a pack extracted from a live site inherits its accidents
134
+ unless someone reads them:
135
+
136
+ - `--border-strong` is declared once in the light `:root` and never re-declared for
137
+ dark, so the reference paints a paper-coloured hairline at **12.02:1** on the coal
138
+ field. This pack ships a dark value of its own and marks it derived at the declaration.
139
+ - `--shadow-pop` is a complete shadow in the app scope and a bare **colour** in the
140
+ journey scope. Copying the wrong one produces an invalid declaration, so the shadow
141
+ disappears silently rather than erroring.
142
+ - The shadcn `--accent` is a raised **surface**, not an accent — an agent reading token
143
+ names alone concludes the pack has none.
144
+ - Two dark greys in one product: warm coal `#141210` against neutral `#151515`, each
145
+ with its own ladder and its own accent.
146
+ - Two radius systems: the proportional ladder off `--radius: .5rem`, and
147
+ `rounded-[7px]` / `rounded-[9px]` literals that sit on no ladder.
148
+ - Four webfont families are loaded on `<html>` and two are referenced in the stylesheet;
149
+ the progress fill is animated with `transition-all`, which animates `width` and lays
150
+ out every frame.
151
+
152
+ ## [1.27.1] - 2026-08-13
153
+
154
+ This project's own pipeline paperwork moved from `docs/superpowers/` to
155
+ `docs/evidence/`, following `task-pipeline` v1.53.0, which renamed the default and made
156
+ the root resolvable. **A patch, deliberately: nothing a consumer of this skill can see
157
+ changed.** The directory, this repository's own validator paths and its CI plants moved
158
+ together; the records inside the directory were NOT rewritten — a brief describes where
159
+ things were when it was written.
160
+
7
161
  ## [1.27.0] - 2026-08-13
8
162
 
9
163
  A ban that said "no side-stripe accent borders" was measured against a real consumer for
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 **seventeen locked style
14
+ decides whether to animate before it decides how, and **nineteen 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
 
@@ -62,6 +62,8 @@ into the cinematic layer, and says so in its own *Motion flavor* section.
62
62
  | `manpage` | cream paper under the reader's own system monospace — zero webfont bytes for the display face — a 48px display that never grows louder, a 576px argument column, coral label chips that are real `<h2>`s, `└` tree glyphs in their own grid column, and one dark code frame as the focal point | developer products whose buyer reads code — APIs, SDKs, CLIs, MCP servers, developer infrastructure, where the honest hero is the call itself |
63
63
  | `pigeonhole` | a white field ruled by hairlines, a display face that never passes weight 400 with exactly one italic word, and **nine categories in which a hue is the category**, drawn from an eleven-ramp pastel system — each rendered as a two-layer chip, 8px outside and 7px inside, whose label word is mandatory because the hue cannot carry the meaning alone | products whose job is to sort the reader's incoming mess into named categories — email triage, ticket routing, notification digests, file organisers, CRM inboxes |
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
+ | `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
+ | `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 |
65
67
 
66
68
  Each pack locks palette, type, texture, motion tokens, signature motifs and
67
69
  bans — and ships a `tokens/<pack>.css` to copy verbatim, so the agent never
@@ -136,7 +138,7 @@ skills.
136
138
  | `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 |
137
139
  | `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 |
138
140
  | `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 |
139
- | `styles/*.md` | The seventeen style packs — palette, type, texture, motion tokens, motifs, bans, and the traps each one carries |
141
+ | `styles/*.md` | The nineteen style packs — palette, type, texture, motion tokens, motifs, bans, and the traps each one carries |
140
142
  | `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) |
141
143
  | `styles/STYLE_PACK_TEMPLATE.md` | The pack contract as a skeleton, so a new style is authored against the same headings rather than improvised |
142
144
 
@@ -207,7 +209,7 @@ cd ./ds-workbench && npm install && npm run build
207
209
  then `/design-sync` in that directory, from Claude Code. Three layers cross: the
208
210
  pack's **bans** as the design system's own README, `styles.css` built from
209
211
  `tokens/<pack>.css` verbatim, and the components — a six-name spine that is
210
- identical in all seventeen kits, so switching packs swaps identity rather than API,
212
+ identical in all nineteen kits, so switching packs swaps identity rather than API,
211
213
  plus each pack's signature parts. **Motion does not cross**, exactly as it does
212
214
  not cross into Figma: a kit is the static half of a pack, and saying so is what
213
215
  stops an agent inventing motion to fill the silence.
@@ -253,7 +255,7 @@ a pack's four widened sections used to make two gates *quieter* and still green.
253
255
  One honest limit: the npx installer is checked by asserting its runtime bundle
254
256
  walker exists, not by reading a file list — it has none by design. What proves
255
257
  it ships the right files is CI, which installs the bundle through **both**
256
- installers and `diff -r`s the result against the source, then builds all seventeen
258
+ installers and `diff -r`s the result against the source, then builds all nineteen
257
259
  kits.
258
260
 
259
261
  `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/ seventeen style packs — instrument-console (dark console),
237
+ styles/ nineteen 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
@@ -251,7 +251,11 @@ ${c("bold", "What it installs")}
251
251
  pigeonhole (a white sorting wall whose nine pastel
252
252
  categories are a filing scheme, one hue each),
253
253
  roster (a white wall of other people's marks: the proof
254
- is a name rather than a number) —
254
+ is a name rather than a number), ora (a warm coal field
255
+ whose accent is the inverted field, a serif over mono,
256
+ and a terminal cut below the page), tenor (warm paper at
257
+ zero radius and zero shadow, one orange that exists only
258
+ on hover, and proof delivered as silent looping video) —
255
259
  plus a ready-made token CSS per pack and
256
260
  STYLE_PACK_TEMPLATE.md for authoring more
257
261
  `);
@@ -43,7 +43,16 @@ that file the reader's incoming mess into named categories; roster — a white
43
43
  field in a faint grid of squares whose whole argument is other people's
44
44
  marks, with client logotypes in pill-labelled industry columns and an
45
45
  engine's wordmark inside the headline, for products sold on who already
46
- carries them);
46
+ carries them; ora — a warm coal field with cream ink and no third hue, where
47
+ the accent is the inverted field, a serif carries every human sentence and a
48
+ monospace every machine fact, and a terminal surface is cut below the page,
49
+ for products whose output is a machine's verdict about the reader; tenor — warm
50
+ paper with zero radius and zero shadow, one hairline weight, an orange that
51
+ exists only on hover and on focus, a sans at weight 400 tracked negative
52
+ against a mono tracked positive, display at a line-height below one in an
53
+ eight-to-twelve-character measure, and proof delivered as silent looping
54
+ video, for products arguing that a new kind of thing must be managed like an
55
+ existing organisation);
47
56
  otherwise follow the contract below (self-contained on purpose).
48
57
 
49
58
  ## Whether to animate at all — before how
@@ -0,0 +1,14 @@
1
+ {
2
+ "pkg": "@sheleg-design/ora",
3
+ "globalName": "ShelegOra",
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,61 @@
1
+ # Ora — the design contract
2
+
3
+ The reference is <https://ora.ai> and <https://journey.ora.ai> (era labs), read
4
+ 2026-08-14 from the shipped stylesheet `/_next/static/chunks/feb8eaf5618096ba.css` and
5
+ the route bundles beside it. The full pack is `styles/ora.md`; this file is what a
6
+ design agent must not get wrong.
7
+
8
+ ## The one thing this pack is
9
+
10
+ **A page that tells a person what a machine concluded about them.** A warm coal field,
11
+ cream ink, and no third hue — the accent is the inverted field. A serif carries every
12
+ human sentence and a monospace every machine fact. The only surface that leaves the
13
+ page plane goes *down*, into a terminal block cut below the field.
14
+
15
+ ## Non-negotiable
16
+
17
+ - **There is no brand colour.** `--accent` is the ink: cream on coal, near-black on
18
+ paper, 16.72:1 and 16.90:1 on their own fields. One filled element per view. A second
19
+ filled button is a design error, not a variant.
20
+ - **No sans-serif.** `--font-sans`, `--font-serif` and the default family all resolve to
21
+ Lora in the reference. Adding a real sans dismantles the rule the whole page is read
22
+ through: a serif means a person said it, mono means a machine reported it.
23
+ - **Status is never by colour alone.** Every dot, bar and number in a status colour
24
+ carries its word; the six-step grade ramp carries its letter. Under deuteranopia
25
+ `--good` and `--danger` separate by 6.5 in dark and 7.4 in light, and under protanopia
26
+ `--good` and `--warn` by 6.4 in light. In the light theme `--good` (2.13:1) and
27
+ `--warn` (2.01:1) are below the non-text floor on paper and may not set text at all.
28
+ - **Elevation is a hairline.** `--border` at 1.15:1 is a seam. Shadows exist for things
29
+ that float over the page — overlays, popovers, tooltips — and a card does not float.
30
+ - **The terminal is darker than the page**, in both themes, and never carries a shadow.
31
+ - **One radius root.** `--radius: 0.5rem`, and every other radius is a ratio of it:
32
+ chip ×0.5, control ×1, card ×1.5, plus the pill. Do not add a step.
33
+ - **A layer that does not apply is hatched and reads `N/A`.** Never an empty bar — an
34
+ empty bar reads as zero, which is a different verdict about the same product.
35
+ - **Motion is entrance, hover and two ambient loops.** No scroll-jacking, no parallax,
36
+ no `animation-timeline`, no scroll library — zero occurrences of any of them in the
37
+ reference's shipped bundles. Scroll drives two things only: the sticky nav's 1px
38
+ hairline shadow and one pinned two-panel comparison. Hover changes colour, border and
39
+ opacity and never geometry. Under reduced motion every duration token collapses to
40
+ zero and the page keeps every value it was showing.
41
+ - **Numbers are `tabular-nums`, always.** A count that changes while the reader watches
42
+ must not reflow.
43
+
44
+ ## What this kit is not
45
+
46
+ It is the **static half** of the pack. The hero's breathing glows, the drifting agent
47
+ marks and the scroll-pinned comparison section are page-level motion and do not cross
48
+ into a component library. Nothing here invents motion to fill that silence.
49
+
50
+ ## The traps the reference itself carries
51
+
52
+ Four of them, so a design agent does not reproduce them from a screenshot:
53
+
54
+ 1. `--border-strong` is never re-declared for dark, so the reference paints a
55
+ paper-coloured hairline at 12.02:1 on coal. This kit ships a dark value of its own.
56
+ 2. `--shadow-pop` is a complete shadow in one scope and a bare colour in the other.
57
+ Here it is always complete.
58
+ 3. The reference's shadcn `--accent` is a raised *surface*, not an accent. The real one
59
+ is `--accent-signature`, which points at the foreground.
60
+ 4. The progress fill is animated with `transition-all`, which animates `width` and lays
61
+ out every frame. Here it is `transform: scaleX()` from a left origin.
@@ -0,0 +1,43 @@
1
+ # @sheleg-design/ora
2
+
3
+ The React reference kit for the SHELEG **Ora** style pack — a warm coal field with cream
4
+ ink and no third hue, where the accent is the inverted field, a serif carries every human
5
+ sentence and a monospace every machine fact, and the only surface that leaves the page
6
+ plane goes down, into a terminal block cut below the field.
7
+
8
+ It is generated from the pack, not authored beside it: `src/styles.css` opens with
9
+ `styles/tokens/ora.css` byte for byte, and the rules the design agent must obey are in
10
+ [`.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 six
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
+ | `Verdict` | one number in the display serif, in its grade colour, with the letter and the word beneath — the **signature element** |
27
+ | `LayerBar` | the weighted score bar, where a layer that does not apply is hatched and reads `N/A` rather than empty |
28
+ | `Terminal` | the surface below the page plane: raw machine output, `white-space: pre`, and never a shadow |
29
+ | `StepLog` | the loading idiom — one mono line per step, appended as it happens, the caret on the running line |
30
+ | `SectionRule` | the band between sections: a squiggle through a hairline strip with a numbered label knocked out over it |
31
+ | `StatusDot` | a 6px dot and its word, where the word is a required prop |
32
+
33
+ ## Theme
34
+
35
+ Dark is the default, because it is the default in the reference. Set
36
+ `data-theme="light"` on `:root` for the twin; both are declared in the token block at the
37
+ top of `src/styles.css`.
38
+
39
+ ## What is not here
40
+
41
+ The hero's breathing glows, the drifting agent marks and the scroll-pinned comparison
42
+ section are page-level motion. A kit is the static half of a pack, and inventing motion
43
+ to fill that silence is the failure this note exists to prevent.
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "@sheleg-design/ora",
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,21 @@
1
+ ---
2
+ category: Actions
3
+ ---
4
+
5
+ `primary` is the **inverted field**: `--accent` is the ink, so the button is a solid
6
+ cream slab on coal and a solid near-black slab on paper, and the label takes
7
+ `--accent-ink`. At 16.72:1 in dark and 16.90:1 in light it is the highest-contrast
8
+ object on the page, which is why the pack allows **one per view**.
9
+
10
+ Hover is the reference's own: the fill drops to 90% opacity. Nothing translates,
11
+ scales or lifts — this pack does not press.
12
+
13
+ `secondary` is a hairline over `--surface-raised`; its hover moves the **border** to
14
+ `--border-strong` and leaves the fill where it is. `ghost` is mono, `--muted`, and
15
+ gains `--ink` on hover.
16
+
17
+ ```tsx
18
+ <Button>Run</Button>
19
+ <Button variant="secondary">Rescan</Button>
20
+ <Button variant="ghost">View logs</Button>
21
+ ```
@@ -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={['ora-btn', `ora-btn--${variant}`, `ora-btn--${size}`, className]
25
+ .filter(Boolean)
26
+ .join(' ')}
27
+ disabled={disabled}
28
+ onClick={onClick}
29
+ >
30
+ {children}
31
+ </button>
32
+ );
33
+ }
@@ -0,0 +1,19 @@
1
+ ---
2
+ category: Surfaces
3
+ ---
4
+
5
+ `--surface` inside a 1px `--border`, at `--radius-card`. The border is 1.15:1 against
6
+ the field: a seam, not a line. There is no shadow, because a card does not float —
7
+ `--shadow-pop` exists for overlays and nothing else.
8
+
9
+ A row of facts inside a card is separated by a top border and padding, never by a
10
+ nested card. Three equal blocks share **one** card with internal dividers.
11
+
12
+ The head sizes against its **container** (`container-type: inline-size`), so a card in a
13
+ narrow column wraps its title and meta instead of overflowing.
14
+
15
+ ```tsx
16
+ <Card title="Can an agent discover and trust you?" meta="5/100">
17
+ …
18
+ </Card>
19
+ ```
@@ -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={['ora-card', className].filter(Boolean).join(' ')}>
15
+ {head && (
16
+ <div className="ora-card__head">
17
+ {title !== undefined && <h3 className="ora-card__title">{title}</h3>}
18
+ {meta !== undefined && <span className="ora-card__meta">{meta}</span>}
19
+ </div>
20
+ )}
21
+ <div className="ora-card__body">{children}</div>
22
+ </section>
23
+ );
24
+ }
@@ -0,0 +1,16 @@
1
+ ---
2
+ category: Data
3
+ ---
4
+
5
+ `--radius-chip` (4px, the root radius halved), a 1px border and mono at 11px in
6
+ `--muted`. Hover moves the border and the text toward `--accent`; `selected` completes
7
+ the move.
8
+
9
+ A chip that reports a status carries a `StatusDot` **and** the word. A chip is never a
10
+ button: if it triggers something, it is a `Button` with `variant="ghost"`.
11
+
12
+ ```tsx
13
+ <Chip>find pricing</Chip>
14
+ <Chip selected>create an account</Chip>
15
+ <Chip tone="accent">MCP</Chip>
16
+ ```
@@ -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
+ 'ora-chip',
15
+ `ora-chip--${tone}`,
16
+ selected ? 'ora-chip--selected' : undefined,
17
+ className,
18
+ ]
19
+ .filter(Boolean)
20
+ .join(' ')}
21
+ >
22
+ {children}
23
+ </span>
24
+ );
25
+ }
@@ -0,0 +1,15 @@
1
+ ---
2
+ category: Foundations
3
+ ---
4
+
5
+ The display face is **Lora, a serif doing the sans job** — `--font-sans` and
6
+ `--font-serif` resolve to the same family in the reference, so there is no sans in this
7
+ pack. Every heading is weight 400; the prose ramp never leaves regular.
8
+
9
+ Level 1 is the display step and takes the fluid clamp; 2 and 3 are fixed. A heading is
10
+ never set in mono: mono means a machine reported it.
11
+
12
+ ```tsx
13
+ <Heading level={1}>Watch top agents use your site</Heading>
14
+ <Heading level={2}>Quick answers</Heading>
15
+ ```
@@ -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={['ora-heading', `ora-heading--${level}`, className].filter(Boolean).join(' ')}
15
+ >
16
+ {children}
17
+ </Tag>
18
+ );
19
+ }
@@ -0,0 +1,26 @@
1
+ ---
2
+ category: Signature
3
+ ---
4
+
5
+ The weighted score bar: one segment per scoring layer, each sized by the points it can
6
+ contribute, each carrying its own tone, its name and its raw fraction.
7
+
8
+ **A layer that does not apply is hatched and reads `N/A`.** It is never drawn as an
9
+ empty track, because an empty track reads as zero — a different verdict about the same
10
+ product, and the one failure this component exists to prevent.
11
+
12
+ The fill animates with `transform: scaleX()` from a left origin. Do not animate its
13
+ width; the reference does, with `transition-all`, and lays out every frame.
14
+
15
+ The legend sizes against its **container** and stacks below 380px.
16
+
17
+ ```tsx
18
+ <LayerBar
19
+ segments={[
20
+ { label: 'Discovery', score: 2, outOf: 20, tone: 'bad' },
21
+ { label: 'Access', score: 23, outOf: 30, tone: 'good' },
22
+ { label: 'Usability', score: 29, outOf: 40, tone: 'warn' },
23
+ { label: 'Payments', score: null, outOf: 10, tone: 'na' },
24
+ ]}
25
+ />
26
+ ```