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.
- package/CHANGELOG.md +154 -0
- package/README.md +6 -4
- package/bin/cli.js +6 -2
- package/cursor/rules/sheleg-design.mdc +10 -1
- package/kits/ora/.design-sync/config.json +14 -0
- package/kits/ora/.design-sync/conventions.md +61 -0
- package/kits/ora/README.md +43 -0
- package/kits/ora/package.json +29 -0
- package/kits/ora/src/Button.md +21 -0
- package/kits/ora/src/Button.tsx +33 -0
- package/kits/ora/src/Card.md +19 -0
- package/kits/ora/src/Card.tsx +24 -0
- package/kits/ora/src/Chip.md +16 -0
- package/kits/ora/src/Chip.tsx +25 -0
- package/kits/ora/src/Heading.md +15 -0
- package/kits/ora/src/Heading.tsx +19 -0
- package/kits/ora/src/LayerBar.md +26 -0
- package/kits/ora/src/LayerBar.tsx +57 -0
- package/kits/ora/src/Rule.md +15 -0
- package/kits/ora/src/Rule.tsx +18 -0
- package/kits/ora/src/SectionRule.md +18 -0
- package/kits/ora/src/SectionRule.tsx +37 -0
- package/kits/ora/src/Stat.md +15 -0
- package/kits/ora/src/Stat.tsx +17 -0
- package/kits/ora/src/StatusDot.md +16 -0
- package/kits/ora/src/StatusDot.tsx +21 -0
- package/kits/ora/src/StepLog.md +22 -0
- package/kits/ora/src/StepLog.tsx +39 -0
- package/kits/ora/src/Terminal.md +18 -0
- package/kits/ora/src/Terminal.tsx +27 -0
- package/kits/ora/src/Verdict.md +21 -0
- package/kits/ora/src/Verdict.tsx +47 -0
- package/kits/ora/src/index.ts +27 -0
- package/kits/ora/src/styles.css +669 -0
- package/kits/ora/tsconfig.json +15 -0
- package/kits/tenor/.design-sync/config.json +14 -0
- package/kits/tenor/.design-sync/conventions.md +70 -0
- package/kits/tenor/README.md +43 -0
- package/kits/tenor/package.json +29 -0
- package/kits/tenor/src/Button.md +21 -0
- package/kits/tenor/src/Button.tsx +33 -0
- package/kits/tenor/src/Card.md +18 -0
- package/kits/tenor/src/Card.tsx +24 -0
- package/kits/tenor/src/Chip.md +15 -0
- package/kits/tenor/src/Chip.tsx +25 -0
- package/kits/tenor/src/Eyebrow.md +13 -0
- package/kits/tenor/src/Eyebrow.tsx +22 -0
- package/kits/tenor/src/FilmFrame.md +18 -0
- package/kits/tenor/src/FilmFrame.tsx +40 -0
- package/kits/tenor/src/Guardrail.md +20 -0
- package/kits/tenor/src/Guardrail.tsx +27 -0
- package/kits/tenor/src/Heading.md +17 -0
- package/kits/tenor/src/Heading.tsx +19 -0
- package/kits/tenor/src/Lattice.md +19 -0
- package/kits/tenor/src/Lattice.tsx +23 -0
- package/kits/tenor/src/LatticeCell.md +20 -0
- package/kits/tenor/src/LatticeCell.tsx +37 -0
- package/kits/tenor/src/Rule.md +13 -0
- package/kits/tenor/src/Rule.tsx +18 -0
- package/kits/tenor/src/SplitHeadline.md +22 -0
- package/kits/tenor/src/SplitHeadline.tsx +30 -0
- package/kits/tenor/src/Staircase.md +25 -0
- package/kits/tenor/src/Staircase.tsx +33 -0
- package/kits/tenor/src/Stat.md +14 -0
- package/kits/tenor/src/Stat.tsx +17 -0
- package/kits/tenor/src/index.ts +29 -0
- package/kits/tenor/src/styles.css +646 -0
- package/kits/tenor/tsconfig.json +15 -0
- package/package.json +2 -2
- package/plugins/sheleg-design/.claude-plugin/plugin.json +2 -2
- package/plugins/sheleg-design/commands/sheleg-design.md +1 -1
- 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 +6 -4
- package/plugins/sheleg-design/skills/sheleg-design/SURFACE_COMPOSITION.md +4 -4
- package/plugins/sheleg-design/skills/sheleg-design/styles/blueprint.md +4 -0
- package/plugins/sheleg-design/skills/sheleg-design/styles/datasheet.md +5 -1
- package/plugins/sheleg-design/skills/sheleg-design/styles/manpage.md +5 -1
- package/plugins/sheleg-design/skills/sheleg-design/styles/ora.md +523 -0
- package/plugins/sheleg-design/skills/sheleg-design/styles/roster.md +5 -1
- package/plugins/sheleg-design/skills/sheleg-design/styles/tenor.md +470 -0
- package/plugins/sheleg-design/skills/sheleg-design/styles/tokens/ora.css +219 -0
- 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 **
|
|
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
|
|
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
|
|
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
|
|
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/
|
|
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
|
+
```
|