sheleg-design-skill 1.9.0 → 1.10.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 +108 -0
- package/README.md +34 -17
- package/bin/cli.js +10 -5
- package/cursor/rules/sheleg-design.mdc +36 -1
- package/kits/atrium/src/styles.css +1 -2
- package/kits/blueprint/src/styles.css +2 -2
- package/kits/editorial-luxury/src/styles.css +5 -2
- package/kits/field-notes/src/styles.css +6 -0
- package/kits/instrument-console/src/styles.css +4 -1
- package/kits/maquette/src/styles.css +1 -1
- package/kits/orchard/src/styles.css +6 -1
- package/kits/showroom/src/styles.css +2 -2
- package/kits/workbench/src/styles.css +1 -1
- package/package.json +3 -3
- package/plugins/sheleg-design/.claude-plugin/plugin.json +2 -2
- package/plugins/sheleg-design/commands/sheleg-design.md +24 -8
- package/plugins/sheleg-design/skills/sheleg-design/DESIGN_SYNC_BRIDGE.md +4 -3
- package/plugins/sheleg-design/skills/sheleg-design/MOTION_DOCTRINE.md +10 -2
- package/plugins/sheleg-design/skills/sheleg-design/SHELEG_DESIGN.md +16 -7
- package/plugins/sheleg-design/skills/sheleg-design/SKILL.md +62 -21
- package/plugins/sheleg-design/skills/sheleg-design/styles/STYLE_PACK_TEMPLATE.md +5 -0
- package/plugins/sheleg-design/skills/sheleg-design/styles/atrium.md +36 -4
- package/plugins/sheleg-design/skills/sheleg-design/styles/blueprint.md +21 -12
- package/plugins/sheleg-design/skills/sheleg-design/styles/briefing-room.md +16 -6
- package/plugins/sheleg-design/skills/sheleg-design/styles/cyclorama.md +2 -0
- package/plugins/sheleg-design/skills/sheleg-design/styles/editorial-luxury.md +18 -7
- package/plugins/sheleg-design/skills/sheleg-design/styles/field-notes.md +13 -5
- package/plugins/sheleg-design/skills/sheleg-design/styles/instrument-console.md +10 -0
- package/plugins/sheleg-design/skills/sheleg-design/styles/maquette.md +4 -2
- package/plugins/sheleg-design/skills/sheleg-design/styles/orchard.md +20 -6
- package/plugins/sheleg-design/skills/sheleg-design/styles/prism.md +9 -5
- package/plugins/sheleg-design/skills/sheleg-design/styles/showroom.md +12 -7
- package/plugins/sheleg-design/skills/sheleg-design/styles/tokens/atrium.css +1 -1
- package/plugins/sheleg-design/skills/sheleg-design/styles/tokens/blueprint.css +2 -2
- package/plugins/sheleg-design/skills/sheleg-design/styles/tokens/editorial-luxury.css +5 -1
- package/plugins/sheleg-design/skills/sheleg-design/styles/tokens/field-notes.css +6 -0
- package/plugins/sheleg-design/skills/sheleg-design/styles/tokens/instrument-console.css +4 -0
- package/plugins/sheleg-design/skills/sheleg-design/styles/tokens/maquette.css +1 -1
- package/plugins/sheleg-design/skills/sheleg-design/styles/tokens/orchard.css +6 -0
- package/plugins/sheleg-design/skills/sheleg-design/styles/tokens/showroom.css +2 -2
- package/plugins/sheleg-design/skills/sheleg-design/styles/tokens/workbench.css +1 -1
- package/plugins/sheleg-design/skills/sheleg-design/styles/workbench.md +28 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,114 @@ 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.10.0] - 2026-08-10
|
|
8
|
+
|
|
9
|
+
A fresh-eyes audit of the whole skill, and the finding is the green: at 1.9.0 all
|
|
10
|
+
three gates passed — 1270 / 412 / 224 — while the skill told a reading agent
|
|
11
|
+
there were six style packs, handed the chart layer a token ramp no pack defines,
|
|
12
|
+
and stated thirteen contrast ratios that are wrong.
|
|
13
|
+
|
|
14
|
+
Full report with every `file:line`, and the reproductions:
|
|
15
|
+
[`docs/audit/2026-08-10-skill-audit.md`](./docs/audit/2026-08-10-skill-audit.md).
|
|
16
|
+
|
|
17
|
+
### Fixed — what an agent was told that was not true
|
|
18
|
+
|
|
19
|
+
- **The `dataviz` handoff named tokens no pack defines.** `SKILL.md` promised a
|
|
20
|
+
ramp `--accent-tint … --accent-deep`: `--accent-tint` exists in **one** pack of
|
|
21
|
+
twelve, `--accent-deep` in three, and **no pack has both**. It promised a
|
|
22
|
+
status set of `--good` / `--warning` / `--danger` that seven packs lack and
|
|
23
|
+
two have no version of at all. An undefined custom property does not error —
|
|
24
|
+
the declaration goes invalid at computed-value time and the property silently
|
|
25
|
+
inherits — so the agent follows the instruction exactly and the page is wrong.
|
|
26
|
+
The table is now written by role, and the non-uniform mappings are named.
|
|
27
|
+
- **Thirteen stated contrast ratios, recomputed and corrected.** `blueprint`'s
|
|
28
|
+
ratio column is headed ``On `--bg` `` and every number in it was computed
|
|
29
|
+
against pure white (`--ink` 17.74 → **17.15**, `--accent` 7.53 → **7.28**,
|
|
30
|
+
pure black 21 → **20.31**). `prism` claimed ink "≥18:1 over all four stops"
|
|
31
|
+
three times; it is **15.85–16.82** — 18.95 is ink on plain white, carried onto
|
|
32
|
+
the wash. Also `showroom` 15.9 → **15.35** and 7.7 → **7.08**, `maquette` 5.0 →
|
|
33
|
+
**5.62** and 13.9 → **13.57**, `editorial-luxury` 6.1 → **6.93**, `workbench`
|
|
34
|
+
5.0 → **4.57**. None crossed a floor; all were presented as measured.
|
|
35
|
+
- **Two packs justified one accent by a "symmetry" that is a mathematical
|
|
36
|
+
identity.** WCAG contrast is symmetric for every pair by definition. In
|
|
37
|
+
`showroom`, whose field is white, the sentence stated one measurement twice; in
|
|
38
|
+
`blueprint`, whose field is not, the two directions genuinely differ and the
|
|
39
|
+
pack asserted one number for both.
|
|
40
|
+
- **`atrium` prescribed `transition: padding-top .2s` on a sticky header** — a
|
|
41
|
+
layout property, transitioned, on scroll: the exact form `MOTION_DOCTRINE.md`
|
|
42
|
+
forbids, shipped inside the bundle that ships the ban.
|
|
43
|
+
- **`field-notes`' radius rule, its worked example and its token layer were three
|
|
44
|
+
different systems.** "Subtract the padding … `12 - 12 ≈ 7.2`" — subtraction
|
|
45
|
+
gives 0; the token layer uses `calc(var(--radius) * 0.6)`.
|
|
46
|
+
- **`blueprint`'s Components and Hero instructed the violation its own Signature
|
|
47
|
+
element section names** (registration marks on both CTAs). `test/scenarios.md`
|
|
48
|
+
recorded this as "fixed in the same run"; only half of it had landed.
|
|
49
|
+
- **`atrium` said three shadows exist**; its token layer defines four.
|
|
50
|
+
- **The colour-blindness ban was copy-pasted into six packs**, asserting a
|
|
51
|
+
measurement across "several pairs" in packs owning one status colour or none —
|
|
52
|
+
and naming four states as if the pack supplied them, which is an invitation to
|
|
53
|
+
invent a hue. Rewritten for `orchard`, `editorial-luxury` and `briefing-room`.
|
|
54
|
+
- **`MOTION_DOCTRINE.md` §5 over-banned**, forbidding everything outside four
|
|
55
|
+
properties while §2 prescribes an ease for colour changes. The ban is on
|
|
56
|
+
layout, which is what its own rationale says.
|
|
57
|
+
- **ADR-0001 named a pack that never existed** (`lecture-hall`; the pack that
|
|
58
|
+
shipped from graphify.com is `field-notes`). The decision stands; the example
|
|
59
|
+
was written on a branch that never merged.
|
|
60
|
+
|
|
61
|
+
### Added — the half-library nobody declared
|
|
62
|
+
|
|
63
|
+
Six of twelve packs carry `## Components`, `## Hero`, `## Responsive` and
|
|
64
|
+
`## Signature element`; six do not, and nothing said which. Every pack now
|
|
65
|
+
declares **`Contract: core` or `Contract: widened`** above its Register, a core
|
|
66
|
+
pack states what it leaves the reader to decide, the `SKILL.md` routing table
|
|
67
|
+
marks it, and a check enforces the declaration against the headings present.
|
|
68
|
+
|
|
69
|
+
### Added — six checks, each watched failing on a planted defect
|
|
70
|
+
|
|
71
|
+
Counted claims (whitespace-normalised: the README's "six locked style packs" was
|
|
72
|
+
split across a line break) · exhaustive pack enumerations in both manifests, the
|
|
73
|
+
slash command, the CLI, the README and the Cursor rule · one name for the pack
|
|
74
|
+
contract · the `Contract:` declaration · the core role vocabulary (`--bg`,
|
|
75
|
+
`--ink`, and an accent role every pack resolves) · and **every stated contrast
|
|
76
|
+
ratio, recomputed from the token layer**.
|
|
77
|
+
|
|
78
|
+
The ratio check is scoped to claims whose base the document declares — a column
|
|
79
|
+
headed ``On `--bg` ``, an `on/over --token` phrase, or an `--on-X` name. A first
|
|
80
|
+
draft that inferred the partner produced 22 false positives out of 40.
|
|
81
|
+
|
|
82
|
+
### Fixed — three gates that could not fail
|
|
83
|
+
|
|
84
|
+
- **Deleting requirements made two gates quieter, and green.** Stripping a pack's
|
|
85
|
+
four widened headings took `validate.py` 1270 → 1269 and `sloplint.py` 224 →
|
|
86
|
+
223, both exit 0. **Ratchet floors** now live in `test/floors.json` and are
|
|
87
|
+
enforced by all three.
|
|
88
|
+
- **One decoy comment disabled a slop-lint ban for a whole file, permanently.**
|
|
89
|
+
The check took the first match only and `continue`d past a nearby negation
|
|
90
|
+
word, so the counter fell and later occurrences went unexamined. Suppression is
|
|
91
|
+
now per occurrence, and ban-quoting sections are exempted by heading.
|
|
92
|
+
- **`validate.py --self-test` printed OK for a self-test that did not exist** —
|
|
93
|
+
the same defect the 2026-08-05 retrospective recorded in `validate_palette.py`.
|
|
94
|
+
All three scripts now exit 2 on an unknown argument, and `validate.py` has a
|
|
95
|
+
real self-test: six planted defects, run against a copy of the tree.
|
|
96
|
+
- **The slop lint read only fenced code blocks**, and no style pack contains one —
|
|
97
|
+
so all twelve packs, `SKILL.md`, both bridges and the AI patterns were never
|
|
98
|
+
linted. It now reads the inline CSS the packs prescribe in prose.
|
|
99
|
+
- **`npm test` and both workflows now run every gate and every self-test.** The
|
|
100
|
+
release path was gated on one of three.
|
|
101
|
+
|
|
102
|
+
### Fixed — stale counts and reach
|
|
103
|
+
|
|
104
|
+
"six locked style packs" and "all six kits" (twelve), "T1–T7" (T1–T19), "Three
|
|
105
|
+
packs extracted" (eight), the pack contract called nine / ten / thirteen in five
|
|
106
|
+
places at once — one of which told an author to ship nine headings, which the
|
|
107
|
+
gate then passed. `plugin.json`, `marketplace.json` and the `/sheleg-design`
|
|
108
|
+
command named three packs of twelve, so nine could not be asked for by name.
|
|
109
|
+
`MOTION_DOCTRINE.md`, marked REQUIRED, appeared on no install surface: it is now
|
|
110
|
+
in the README table, the CLI help and banner, the slash command, and the Cursor
|
|
111
|
+
rule — which gains the whole doctrine in condensed form.
|
|
112
|
+
|
|
113
|
+
Gates: **1364 / 469 / 320**, from 1270 / 412 / 224.
|
|
114
|
+
|
|
7
115
|
## [1.9.0] - 2026-08-09
|
|
8
116
|
|
|
9
117
|
Four style packs, taking the library from eight to twelve — and a fix to the
|
package/README.md
CHANGED
|
@@ -10,7 +10,8 @@ nothing. Ask it for a dashboard and you get a different flavor of the same
|
|
|
10
10
|
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
|
-
methodology** for cinematic, scroll-driven pages
|
|
13
|
+
methodology** for cinematic, scroll-driven pages, **a motion doctrine** that
|
|
14
|
+
decides whether to animate before it decides how, and **twelve locked style
|
|
14
15
|
packs** with ready-made design tokens, so what it builds reads as one system
|
|
15
16
|
instead of a pile of effects.
|
|
16
17
|
|
|
@@ -34,11 +35,13 @@ and collectively cinematic. One scroll "clock" feeds a WebGL particle field, a
|
|
|
34
35
|
rail — each an independent, degrade-to-calm layer. Nothing crossfades; things
|
|
35
36
|
*redeploy*.
|
|
36
37
|
|
|
37
|
-
**Style packs** — the visual identity, pluggable per project.
|
|
38
|
-
meant to be used **standalone
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
38
|
+
**Style packs** — the visual identity, pluggable per project. Three of them are
|
|
39
|
+
meant to be used **standalone**: `workbench` (quiet light/dark product UI for
|
|
40
|
+
dashboards, admin panels, internal and dev tools) and `briefing-room` (a dark
|
|
41
|
+
16:9 presentation deck, where the presenter's voice is the timeline and slides
|
|
42
|
+
therefore never animate) take none of the motion layer at all; `field-notes` is
|
|
43
|
+
standalone by default — its reference carries no motion library — but may opt
|
|
44
|
+
into the cinematic layer, and says so in its own *Motion flavor* section.
|
|
42
45
|
|
|
43
46
|
| Pack | Look | Choose for |
|
|
44
47
|
|---|---|---|
|
|
@@ -123,11 +126,12 @@ skills.
|
|
|
123
126
|
|---|---|
|
|
124
127
|
| `SKILL.md` | The agent-facing skill: discovery triggers, the principles, how to apply them, quick-reference rules, common mistakes |
|
|
125
128
|
| `SHELEG_DESIGN.md` | The full reference: architecture, layer-by-layer mechanics with code, the exact morph math, the DOM↔WebGL projection bridge, a build-from-scratch recipe, and why each piece works |
|
|
129
|
+
| `MOTION_DOCTRINE.md` | Whether to animate at all, before how: the frequency table that kills motion on high-repetition paths, the easing tree and the `ease-in` ban, the duration ceiling, the forbidden forms, and the reduced-motion contract. `SKILL.md` marks it required before any animation |
|
|
126
130
|
| `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 |
|
|
127
131
|
| `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 |
|
|
128
132
|
| `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 |
|
|
129
133
|
| `styles/*.md` | The twelve style packs — palette, type, texture, motion tokens, motifs, bans, and the traps each one carries |
|
|
130
|
-
| `styles/tokens/*.css` | The ready-made token layer per pack, copied verbatim instead of transcribed (workbench
|
|
134
|
+
| `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) |
|
|
131
135
|
| `styles/STYLE_PACK_TEMPLATE.md` | The pack contract as a skeleton, so a new style is authored against the same headings rather than improvised |
|
|
132
136
|
|
|
133
137
|
## What you get out of it
|
|
@@ -197,7 +201,7 @@ cd ./ds-workbench && npm install && npm run build
|
|
|
197
201
|
then `/design-sync` in that directory, from Claude Code. Three layers cross: the
|
|
198
202
|
pack's **bans** as the design system's own README, `styles.css` built from
|
|
199
203
|
`tokens/<pack>.css` verbatim, and the components — a six-name spine that is
|
|
200
|
-
identical in all
|
|
204
|
+
identical in all twelve kits, so switching packs swaps identity rather than API,
|
|
201
205
|
plus each pack's signature parts. **Motion does not cross**, exactly as it does
|
|
202
206
|
not cross into Figma: a kit is the static half of a pack, and saying so is what
|
|
203
207
|
stops an agent inventing motion to fill the silence.
|
|
@@ -224,16 +228,29 @@ repo. Entirely optional; without it the skill works from the pack alone.
|
|
|
224
228
|
python3 test/validate.py # or: npm test
|
|
225
229
|
```
|
|
226
230
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
the full style-pack section contract, pack ↔ `SKILL.md` ↔ CLI-help agreement,
|
|
230
|
-
the bundled template against `templates/`, both installers' file lists, the
|
|
231
|
-
entire `.cursor/` mirror against the plugin copy, and every relative link. CI
|
|
232
|
-
runs it on each push and PR alongside a negative self-test (the validator must
|
|
233
|
-
fail on a corrupted version) and installs the bundle through **both** installers,
|
|
234
|
-
diffing the result against the source.
|
|
231
|
+
`npm test` is **four gates**, not one, and `validate.py` alone is about a third
|
|
232
|
+
of the contract:
|
|
235
233
|
|
|
236
|
-
|
|
234
|
+
| Gate | What it decides |
|
|
235
|
+
|---|---|
|
|
236
|
+
| `test/validate.py` | manifests and four-way version sync · skill/command/rule front-matter and the description canon · the pack section contract (nine always, the widened four all-or-nothing) and each pack's `Contract:` declaration · the core role vocabulary (`--bg`, `--ink`, and a resolvable accent) in every token layer · every counted claim (packs, kits, scenarios, headings) · exhaustive pack enumerations in the manifests, the command, the CLI, the README and the rule · one name for the pack contract · fork reciprocity · the eleven kit checks · `install.sh`'s file list, both directions · the whole `.cursor/` mirror · every relative link |
|
|
237
|
+
| `test/validate_palette.py` | contrast floors and semantic separation per theme, including three simulated dichromacies · AI-default-cluster provenance · **every contrast ratio the docs state, recomputed from the token layer** |
|
|
238
|
+
| `test/sloplint.py` | the bundle obeying its own bans, in token layers, fenced examples **and the inline CSS the packs prescribe in prose** · doctrine completeness · pack origin addressability |
|
|
239
|
+
| `node --check bin/cli.js` | the installer parses |
|
|
240
|
+
|
|
241
|
+
Each gate ships a `--self-test` that plants a defect it must catch (`npm run
|
|
242
|
+
selftest`), rejects an unknown argument instead of silently running the normal
|
|
243
|
+
pass, and enforces a **ratchet floor** from `test/floors.json` — a check count
|
|
244
|
+
that falls means a requirement stopped being required, which is how stripping
|
|
245
|
+
a pack's four widened sections used to make two gates *quieter* and still green.
|
|
246
|
+
|
|
247
|
+
One honest limit: the npx installer is checked by asserting its runtime bundle
|
|
248
|
+
walker exists, not by reading a file list — it has none by design. What proves
|
|
249
|
+
it ships the right files is CI, which installs the bundle through **both**
|
|
250
|
+
installers and `diff -r`s the result against the source, then builds all twelve
|
|
251
|
+
kits.
|
|
252
|
+
|
|
253
|
+
`test/scenarios.md` (T1–T19) is the behavioral harness: fresh subagents given a
|
|
237
254
|
task, checking that the skill is discovered, applied and quoted correctly.
|
|
238
255
|
Re-run the affected scenarios after any edit to `SKILL.md`, a pack or the
|
|
239
256
|
reference.
|
package/bin/cli.js
CHANGED
|
@@ -228,7 +228,11 @@ ${c("bold", "Default")}
|
|
|
228
228
|
${c("bold", "What it installs")}
|
|
229
229
|
SKILL.md the agent-facing skill (discovery + principles)
|
|
230
230
|
SHELEG_DESIGN.md the full reference (architecture, recipes, why it works)
|
|
231
|
+
MOTION_DOCTRINE.md whether to animate at all — frequency, easing, duration,
|
|
232
|
+
forbidden forms, the reduced-motion contract
|
|
231
233
|
FIGMA_BRIDGE.md the design↔code contract (tokens ⇄ Figma variables)
|
|
234
|
+
DESIGN_SYNC_BRIDGE.md the Claude Design contract (what a pack sends, and
|
|
235
|
+
what does not cross)
|
|
232
236
|
AI_PRODUCT_PATTERNS.md chat / agent / streaming surfaces (honest state)
|
|
233
237
|
styles/ twelve style packs — instrument-console (dark console),
|
|
234
238
|
editorial-luxury (warm editorial), workbench (light/dark
|
|
@@ -317,12 +321,13 @@ function main() {
|
|
|
317
321
|
const rel = path.relative(cwd, targetDir) || ".";
|
|
318
322
|
console.log(
|
|
319
323
|
`\n${c("green", "✓")} ${c("bold", "SHELEG Design")} installed to ${c("blue", rel + "/")}\n` +
|
|
320
|
-
` ${c("dim", "SKILL.md")}
|
|
321
|
-
` ${c("dim", "SHELEG_DESIGN.md")}
|
|
322
|
-
` ${c("dim", "
|
|
324
|
+
` ${c("dim", "SKILL.md")} the agent skill\n` +
|
|
325
|
+
` ${c("dim", "SHELEG_DESIGN.md")} the full reference\n` +
|
|
326
|
+
` ${c("dim", "MOTION_DOCTRINE.md")} whether to animate at all — read before any animation\n` +
|
|
327
|
+
` ${c("dim", "styles/")} style packs + token CSS (instrument-console / editorial-luxury / workbench / briefing-room / atrium / orchard / field-notes / cyclorama / showroom / blueprint / prism / maquette)\n\n` +
|
|
323
328
|
`Your Cursor / Claude agent can now discover the skill and build\n` +
|
|
324
|
-
`cinematic, scroll-driven pages — or style product UI (dashboards,\n` +
|
|
325
|
-
`
|
|
329
|
+
`cinematic, scroll-driven pages — or style product UI (dashboards, admin,\n` +
|
|
330
|
+
`internal tools) from a standalone pack — on its principles.\n\n` +
|
|
326
331
|
`${c("dim", "Docs: " + pkg.homepage)}\n`,
|
|
327
332
|
);
|
|
328
333
|
}
|
|
@@ -9,7 +9,8 @@ A page feels cinematic from a **single source of truth** (measured scroll
|
|
|
9
9
|
position) driving **many cheap, layered, independently-degradable responses** —
|
|
10
10
|
not from many animations. If the project has the full skill installed
|
|
11
11
|
(`.cursor/skills/sheleg-design/`), read its `SKILL.md`, `SHELEG_DESIGN.md`,
|
|
12
|
-
and the chosen style pack in
|
|
12
|
+
`MOTION_DOCTRINE.md` (before any animation) and the chosen style pack in
|
|
13
|
+
`styles/` first (instrument-console — dark
|
|
13
14
|
console; editorial-luxury — warm editorial; workbench — quiet light/dark
|
|
14
15
|
product UI for dashboards and tools, used standalone without the cinematic
|
|
15
16
|
motion layer; briefing-room — dark 16:9 presentation deck, standalone, slides
|
|
@@ -29,6 +30,40 @@ static iridescent wash over mono body copy; maquette — enterprise data
|
|
|
29
30
|
infrastructure as a cream axonometric model on a near-black table);
|
|
30
31
|
otherwise follow the contract below (self-contained on purpose).
|
|
31
32
|
|
|
33
|
+
## Whether to animate at all — before how
|
|
34
|
+
|
|
35
|
+
Frequency decides before taste gets a vote. (Full doctrine:
|
|
36
|
+
`MOTION_DOCTRINE.md` in the installed skill.)
|
|
37
|
+
|
|
38
|
+
- Seen 100+ times a day — command palette, keyboard shortcut, tab switch:
|
|
39
|
+
**no animation, ever.** Never animate a keyboard-initiated action; it turns
|
|
40
|
+
instant into laggy and disconnects the result from the keypress.
|
|
41
|
+
- Tens of times a day — hover, list navigation, inline toggles: remove it or
|
|
42
|
+
cut it to the floor. Occasional (modals, drawers, toasts): standard. Rare or
|
|
43
|
+
first-time (onboarding, empty-to-filled): delight is allowed.
|
|
44
|
+
- Every animation answers "why does this move?" in one sentence — spatial
|
|
45
|
+
consistency, state indication, feedback, explanation, or preventing a jarring
|
|
46
|
+
cut. "It looked cool" is not an answer; if you cannot write the sentence,
|
|
47
|
+
delete the animation.
|
|
48
|
+
- **`ease-in` is banned in UI.** It starts slow, in the exact moment the user is
|
|
49
|
+
watching hardest. Entering or leaving → `ease-out`; moving or morphing on
|
|
50
|
+
screen → `ease-in-out`; hover or colour change → `ease`; constant motion →
|
|
51
|
+
`linear`. Curves: `--ease-out: cubic-bezier(.23,1,.32,1)`,
|
|
52
|
+
`--ease-in-out: cubic-bezier(.77,0,.175,1)`,
|
|
53
|
+
`--ease-drawer: cubic-bezier(.32,.72,0,1)`.
|
|
54
|
+
- **UI motion stays under 300 ms.** Button press 100–160ms · tooltip 125–200ms ·
|
|
55
|
+
dropdown 150–250ms · modal/drawer 200–500ms. Marketing and scrollytelling are
|
|
56
|
+
deliberately longer.
|
|
57
|
+
- Never animate a property that triggers layout (`width`, `height`, `top`,
|
|
58
|
+
`left`, `padding`, `margin`, `gap`, `font-size`). Never a bare scroll
|
|
59
|
+
listener, never `requestAnimationFrame` writing component state, never
|
|
60
|
+
`backdrop-filter` or grain on a scrolling container, never a left-behind
|
|
61
|
+
`will-change`, never two marquees.
|
|
62
|
+
- **Reduced motion is a contract, not a feature.** Anything beyond a colour
|
|
63
|
+
change honours `prefers-reduced-motion: reduce`; loops, parallax and springs
|
|
64
|
+
collapse to static or instant, never to "slower". Shipping an animation
|
|
65
|
+
without that branch is a bug, not a polish item.
|
|
66
|
+
|
|
32
67
|
## Five principles, in order
|
|
33
68
|
|
|
34
69
|
1. **One clock.** All motion derives from one measured scroll state in one
|
|
@@ -119,7 +119,7 @@
|
|
|
119
119
|
--track-mono: 0.1em;
|
|
120
120
|
--track-mono-sm: 0.07em;
|
|
121
121
|
|
|
122
|
-
/* ---- Elevation:
|
|
122
|
+
/* ---- Elevation: four shadows, one job each --------------------------- */
|
|
123
123
|
--shadow-panel: 12px 32px 80px 0 rgba(42, 43, 47, 0.1); /* the hero panel */
|
|
124
124
|
--shadow-lift: 0 4px 30px 0 rgba(0, 0, 0, 0.1); /* a card pulled forward */
|
|
125
125
|
--shadow-cta: 0 2px 12px 0 rgba(0, 0, 0, 0.1); /* a button on photography */
|
|
@@ -175,7 +175,6 @@
|
|
|
175
175
|
--marquee-cycle: 0s;
|
|
176
176
|
}
|
|
177
177
|
}
|
|
178
|
-
|
|
179
178
|
/* ── components ── */
|
|
180
179
|
|
|
181
180
|
/* Everything below consumes var(--…) only. Colour never appears as a literal:
|
|
@@ -32,8 +32,8 @@
|
|
|
32
32
|
quietly changes a value it claims to have measured is worse than one that
|
|
33
33
|
changes it and says so. Pure black is 21:1 on the sheet; this is 17.74:1,
|
|
34
34
|
and both are far above any floor that matters. */
|
|
35
|
-
--ink: #111827; /* 17.
|
|
36
|
-
--ink-soft: #4b5563; /* 7.
|
|
35
|
+
--ink: #111827; /* 17.15:1 on --bg */
|
|
36
|
+
--ink-soft: #4b5563; /* 7.31:1 on --bg — secondary copy, safe as body */
|
|
37
37
|
--ink-faint: #9ca3af; /* 2.5:1 — RULES AND MARKS ONLY, never text */
|
|
38
38
|
--on-ink: #ffffff;
|
|
39
39
|
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
--accent-deep: #2f5e47;
|
|
16
16
|
--accent-weak: rgba(63, 125, 95, 0.12); /* tint fill (badges, wash) */
|
|
17
17
|
--accent-med: rgba(63, 125, 95, 0.34); /* hairline / border tint */
|
|
18
|
-
--accent-ink: #fbf6ec; /* text ON the accent — 6.
|
|
18
|
+
--accent-ink: #fbf6ec; /* text ON the accent — 6.93:1 on --accent-deep; 4.52:1 on --accent, AA by 0.02, so large text only there */
|
|
19
19
|
--accent-on-dark: #9fd9bc;
|
|
20
20
|
--terra: #b5623f;
|
|
21
21
|
--red: #a83a2b;
|
|
@@ -51,8 +51,11 @@
|
|
|
51
51
|
background-color: var(--paper);
|
|
52
52
|
color: var(--ink);
|
|
53
53
|
color-scheme: light;
|
|
54
|
-
}
|
|
55
54
|
|
|
55
|
+
/* Core role vocabulary — every pack resolves --bg, --ink and --accent, so a
|
|
56
|
+
cross-pack document can name them truthfully. Alias, never a new colour. */
|
|
57
|
+
--bg: var(--paper); /* role alias -> --paper, this pack's field */
|
|
58
|
+
}
|
|
56
59
|
/* ── components ── */
|
|
57
60
|
|
|
58
61
|
/* Everything below consumes var(--…) only. The token block above is the whole
|
|
@@ -231,6 +231,12 @@
|
|
|
231
231
|
|
|
232
232
|
background-color: var(--bg);
|
|
233
233
|
color: var(--ink);
|
|
234
|
+
|
|
235
|
+
/* Core role vocabulary — every pack resolves --bg, --ink and --accent, so a
|
|
236
|
+
cross-pack document can name them truthfully. Alias, never a new colour. */
|
|
237
|
+
/* @role accent: --brand — this pack's ONE functional accent. It is not
|
|
238
|
+
aliased to --accent because that would make it a status peer, and the
|
|
239
|
+
palette gate measures it 5.5 from --danger (hard floor 10). */
|
|
234
240
|
}
|
|
235
241
|
|
|
236
242
|
/* The dark twin. Warm, one family, and clean on contrast throughout —
|
|
@@ -41,8 +41,11 @@
|
|
|
41
41
|
background-color: var(--base);
|
|
42
42
|
color: var(--ink);
|
|
43
43
|
color-scheme: dark;
|
|
44
|
-
}
|
|
45
44
|
|
|
45
|
+
/* Core role vocabulary — every pack resolves --bg, --ink and --accent, so a
|
|
46
|
+
cross-pack document can name them truthfully. Alias, never a new colour. */
|
|
47
|
+
--bg: var(--base); /* role alias -> --base, this pack's field */
|
|
48
|
+
}
|
|
46
49
|
/* ── components ── */
|
|
47
50
|
|
|
48
51
|
/* Everything below consumes var(--…) only. Colour never appears as a literal.
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
warm object on a cold page. */
|
|
31
31
|
--ink: #fff9f4; /* 17.49:1 on --bg */
|
|
32
32
|
--ink-soft: #b3b5c1; /* 8.95:1 — secondary copy, comfortably AA */
|
|
33
|
-
--ink-faint: #8a8f98; /* 5.
|
|
33
|
+
--ink-faint: #8a8f98; /* 5.62:1 on --bg — captions and leader lines */
|
|
34
34
|
--on-ink: #151515;
|
|
35
35
|
|
|
36
36
|
/* ---- Lines ------------------------------------------------------------ */
|
|
@@ -107,6 +107,12 @@
|
|
|
107
107
|
background-color: var(--bg);
|
|
108
108
|
color: var(--ink);
|
|
109
109
|
color-scheme: light;
|
|
110
|
+
|
|
111
|
+
/* Core role vocabulary — every pack resolves --bg, --ink and --accent, so a
|
|
112
|
+
cross-pack document can name them truthfully. Alias, never a new colour. */
|
|
113
|
+
/* @role accent: --cta — this pack's ONE functional accent. It is not
|
|
114
|
+
aliased to --accent because that would make it a status peer, and the
|
|
115
|
+
palette gate measures it 5.5 from --danger (hard floor 10). */
|
|
110
116
|
}
|
|
111
117
|
|
|
112
118
|
/* The reference ships NO reduced-motion branch at all. This one is mandatory:
|
|
@@ -120,7 +126,6 @@
|
|
|
120
126
|
--reveal-floor: 1;
|
|
121
127
|
}
|
|
122
128
|
}
|
|
123
|
-
|
|
124
129
|
/* ── components ── */
|
|
125
130
|
|
|
126
131
|
/* Everything below consumes var(--…) only. Colour never appears as a literal:
|
|
@@ -25,8 +25,8 @@
|
|
|
25
25
|
|
|
26
26
|
/* ---- Ink -------------------------------------------------------------- */
|
|
27
27
|
--ink: #1c1d1f; /* 16.87:1 on --bg */
|
|
28
|
-
--ink-2: #232529; /* 15.
|
|
29
|
-
--ink-soft: #505967; /* 7.
|
|
28
|
+
--ink-2: #232529; /* 15.35:1 on --bg — secondary headings */
|
|
29
|
+
--ink-soft: #505967; /* 7.08:1 on --bg — captions that must actually be read */
|
|
30
30
|
--on-ink: #ffffff;
|
|
31
31
|
|
|
32
32
|
/* [CORRECTION] The reference names #a4adba "caption-foreground" and it
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
--border-strong: #d7dce4;
|
|
12
12
|
--accent: #2f6feb;
|
|
13
13
|
--accent-weak: #eaf0fe;
|
|
14
|
-
--accent-ink: #ffffff; /* text ON the accent —
|
|
14
|
+
--accent-ink: #ffffff; /* text ON the accent — 4.57:1 on --accent */
|
|
15
15
|
--ok: #1a7f37;
|
|
16
16
|
--ok-weak: #e6f4ea;
|
|
17
17
|
--warn: #9a6700;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sheleg-design-skill",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.10.0",
|
|
4
4
|
"description": "Design taste as an installable agent skill. Cinematic scroll-driven landing pages built on one scroll clock and layered degrade-to-calm motion, a motion doctrine that decides whether to animate before it decides how, three calibration dials, and twelve locked style packs with ready-made design tokens — instrument-console, editorial-luxury, workbench, briefing-room, atrium, orchard, field-notes, cyclorama, showroom, blueprint, prism and maquette. Colour, slop and fork-reciprocity gates run as scripts, not opinions. Works with Cursor, Claude Code and any agent that reads a SKILL.md.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"sheleg-design-skill": "bin/cli.js"
|
|
@@ -19,12 +19,12 @@
|
|
|
19
19
|
"node": ">=16"
|
|
20
20
|
},
|
|
21
21
|
"scripts": {
|
|
22
|
-
"test": "python3 test/validate.py && python3 test/validate_palette.py && python3 test/sloplint.py && node --check bin/cli.js",
|
|
22
|
+
"test": "python3 test/validate.py && python3 test/validate_palette.py && python3 test/sloplint.py && node --check bin/cli.js && npm run selftest",
|
|
23
23
|
"validate": "python3 test/validate.py && python3 test/validate_palette.py && python3 test/sloplint.py",
|
|
24
24
|
"smoke": "node bin/cli.js --help",
|
|
25
25
|
"palette": "python3 test/validate_palette.py",
|
|
26
26
|
"sloplint": "python3 test/sloplint.py",
|
|
27
|
-
"selftest": "python3 test/validate_palette.py --self-test && python3 test/sloplint.py --self-test"
|
|
27
|
+
"selftest": "python3 test/validate.py --self-test && python3 test/validate_palette.py --self-test && python3 test/sloplint.py --self-test"
|
|
28
28
|
},
|
|
29
29
|
"keywords": [
|
|
30
30
|
"skill",
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sheleg-design",
|
|
3
3
|
"displayName": "SHELEG Design",
|
|
4
|
-
"description": "SHELEG Design methodology: cinematic scroll-driven landing pages (single scroll clock, layered degrade-to-calm motion, WebGL particle formations)
|
|
5
|
-
"version": "1.
|
|
4
|
+
"description": "SHELEG Design methodology: cinematic scroll-driven landing pages (single scroll clock, layered degrade-to-calm motion, WebGL particle formations), a motion doctrine that decides whether to animate before it decides how, and twelve pluggable visual style packs — instrument-console (dark console), editorial-luxury (warm editorial), workbench (light/dark product UI for dashboards and tools), briefing-room (dark 16:9 deck), atrium (warm consumer health), orchard (friendly consumer biotech), field-notes (warm paper for dev tools sold on auditability), cyclorama (a pastel field on a 32s cycle), showroom (the product as the exhibit), blueprint (a drawing sheet, zero radius), prism (one iridescent wash over mono body), maquette (cream axonometric models on a dark table). Ships the sheleg-design skill, the architecture reference, the motion doctrine, the Figma and Claude Design bridges, AI-surface patterns, style packs with ready-made token CSS, and the /sheleg-design command.",
|
|
5
|
+
"version": "1.10.0",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "ssheleg",
|
|
8
8
|
"url": "https://x.com/sshlg93"
|
|
@@ -5,14 +5,30 @@ argument-hint: "[what to build or upgrade]"
|
|
|
5
5
|
|
|
6
6
|
Invoke the `sheleg-design` skill and apply it to the current request.
|
|
7
7
|
|
|
8
|
-
- Read the skill's SKILL.md, then
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
a
|
|
13
|
-
|
|
8
|
+
- Read the skill's `SKILL.md` first, then — **before designing anything** — its
|
|
9
|
+
full reference `SHELEG_DESIGN.md` and, **before any animation**,
|
|
10
|
+
`MOTION_DOCTRINE.md` (same directory). `SHELEG_DESIGN.md` says how motion is
|
|
11
|
+
built; the doctrine says whether to build it at all. Skipping the second is
|
|
12
|
+
how a keyboard path ends up animated.
|
|
13
|
+
- Task: $ARGUMENTS — if empty, ask what page or section to build/upgrade.
|
|
14
|
+
- **If the arguments name a style pack, use that pack without re-asking.** The
|
|
15
|
+
twelve are `instrument-console`, `editorial-luxury`, `workbench`,
|
|
16
|
+
`briefing-room`, `atrium`, `orchard`, `field-notes`, `cyclorama`, `showroom`,
|
|
17
|
+
`blueprint`, `prism`, `maquette`. Otherwise pick per the `SKILL.md` table,
|
|
18
|
+
and say which pack you picked and why before you build.
|
|
19
|
+
- **Set the three dials out loud before any layout exists** — `DESIGN_VARIANCE`,
|
|
20
|
+
`MOTION_INTENSITY`, `VISUAL_DENSITY`, with one line of reasoning. The
|
|
21
|
+
`SKILL.md` "Reading them off the brief" table gives the starting values;
|
|
22
|
+
baseline is `7 / 5 / 4`. Announcing them and then drifting is the failure this
|
|
23
|
+
step exists to prevent.
|
|
24
|
+
- Then proceed per the skill's "How to Apply" order.
|
|
14
25
|
- Product UI (dashboard, admin, internal/dev tool, design tokens, theming):
|
|
15
|
-
apply
|
|
16
|
-
|
|
26
|
+
apply a **standalone** pack and its token CSS — no scroll clock, no particle
|
|
27
|
+
field, no cinematic motion. `workbench` is the default; `field-notes` is the
|
|
28
|
+
fork for a developer product sold on auditability, and `briefing-room` for a
|
|
29
|
+
deck published as a page. The packs state the distinction; read it rather than
|
|
30
|
+
defaulting.
|
|
31
|
+
- AI surfaces (chat, agent runs, streaming, generated content): read
|
|
32
|
+
`AI_PRODUCT_PATTERNS.md` as well.
|
|
17
33
|
- Follow the skill's non-negotiables (Quick Reference table) and ship every
|
|
18
34
|
layer's reduced-motion/fallback branch in the same commit.
|
|
@@ -91,12 +91,13 @@ hierarchy, content order. It never answers what it looks like.
|
|
|
91
91
|
|
|
92
92
|
## 5. Live-site extraction — the pack first, the sync second
|
|
93
93
|
|
|
94
|
-
|
|
94
|
+
Most packs in this skill were extracted from production sites by reading their live
|
|
95
95
|
computed styles. That is a legitimate way to *make a pack* and never a way to make a
|
|
96
96
|
kit.
|
|
97
97
|
|
|
98
|
-
**The order is the rule:** extraction lands in a pack first —
|
|
99
|
-
|
|
98
|
+
**The order is the rule:** extraction lands in a pack first — **the full thirteen
|
|
99
|
+
headings** (plus `## Motion flavor` if it is cinematic) and a `tokens/<pack>.css` —
|
|
100
|
+
and only a pack syncs. A site's raw values never reach
|
|
100
101
|
claude.ai/design, because a kit assembled straight from a scrape carries that site's
|
|
101
102
|
accidents, its dead ends and its one-off hexes, and the design agent will treat every
|
|
102
103
|
one of them as a decision.
|
|
@@ -156,8 +156,16 @@ These are not stylistic preferences. Each one is a defect with a known failure.
|
|
|
156
156
|
- **State for continuous input** — pointer position, scroll progress, magnetic
|
|
157
157
|
hover, physics. Storing these in `useState` re-renders the tree on every
|
|
158
158
|
movement and collapses on mobile.
|
|
159
|
-
- **Animating
|
|
160
|
-
`
|
|
159
|
+
- **Animating a property that triggers layout** — `top`, `left`, `width`,
|
|
160
|
+
`height`, `padding`, `margin`, `gap`, `font-size`. These re-lay-out the
|
|
161
|
+
document on every frame. Animate `transform` and `opacity`, which the
|
|
162
|
+
compositor handles alone; `filter` and `clip-path` are also safe. Paint-only
|
|
163
|
+
changes (`background-color`, `border-color`, `color`, `box-shadow`) are
|
|
164
|
+
cheaper than layout and are permitted — §2 gives them an ease and §9 treats a
|
|
165
|
+
colour change as the baseline everything else is measured against. The ban is
|
|
166
|
+
on **layout**, not on everything outside a list of four; an earlier wording
|
|
167
|
+
said "anything but `transform`, `opacity`, `filter`, `clip-path`", which
|
|
168
|
+
contradicted both of those sections.
|
|
161
169
|
- **`backdrop-filter` on a scrolling container** — continuous GPU repaint. Blur
|
|
162
170
|
belongs on fixed or sticky elements.
|
|
163
171
|
- **Grain and noise on a scrolling container** — same reason. Put them on a
|
|
@@ -15,6 +15,15 @@ build new sites on the same principles and understand *why* each piece works.
|
|
|
15
15
|
> Where a pack's motion tokens differ from the defaults in §10, **the pack
|
|
16
16
|
> wins** — it is the visual contract.
|
|
17
17
|
|
|
18
|
+
> **Every `**Reference file:**` path below belongs to the reference
|
|
19
|
+
> implementation, not to your project.** `src/lib/motion/scroll-progress.ts` and
|
|
20
|
+
> its siblings do not exist until you write them, and none of them ships with
|
|
21
|
+
> this skill — nothing here is importable. Read the paths as *one file per idea*
|
|
22
|
+
> (the split is the lesson; §13 is the full map) and name them however your
|
|
23
|
+
> framework does. An agent that imports from these paths because the heading
|
|
24
|
+
> looked authoritative will get a build error at best and a silently missing
|
|
25
|
+
> module at worst.
|
|
26
|
+
|
|
18
27
|
---
|
|
19
28
|
|
|
20
29
|
## 0. The one-paragraph thesis
|
|
@@ -81,7 +90,7 @@ file with one responsibility, reading the same clock.
|
|
|
81
90
|
|
|
82
91
|
## 2. Layer 1 — The scroll store (the single clock)
|
|
83
92
|
|
|
84
|
-
**
|
|
93
|
+
**Reference file:** `src/lib/motion/scroll-progress.ts`
|
|
85
94
|
|
|
86
95
|
This is the heart of the system. One `requestAnimationFrame` loop (scheduled on
|
|
87
96
|
the native `scroll` event) measures the page and writes a plain `state` object.
|
|
@@ -161,7 +170,7 @@ to you" signal.
|
|
|
161
170
|
|
|
162
171
|
## 3. Layer 2 — Smooth scroll (one position per frame)
|
|
163
172
|
|
|
164
|
-
**
|
|
173
|
+
**Reference file:** `src/components/motion/SmoothScroll.tsx`
|
|
165
174
|
|
|
166
175
|
Lenis provides inertial scrolling, but the important move is **driving Lenis
|
|
167
176
|
from the GSAP ticker** rather than its own rAF:
|
|
@@ -186,7 +195,7 @@ and keep native scroll. The store still runs, so the rail and nav stay in sync.
|
|
|
186
195
|
|
|
187
196
|
## 4. Layer 3 — The particle field (the scene-formation engine)
|
|
188
197
|
|
|
189
|
-
**
|
|
198
|
+
**Reference file:** `src/components/webgl/SignalField.tsx`
|
|
190
199
|
|
|
191
200
|
This is the showpiece: 936 points (a `24 × 13` grid × 3 depth layers — a count,
|
|
192
201
|
not a scene index) that narrate the page section by section. It is a single `THREE.Points` cloud whose target positions change
|
|
@@ -195,7 +204,7 @@ with the brand accent.
|
|
|
195
204
|
|
|
196
205
|
### 4.1 The scene registry
|
|
197
206
|
|
|
198
|
-
**
|
|
207
|
+
**Reference file:** `src/lib/motion/scenes.ts`
|
|
199
208
|
|
|
200
209
|
Each section "owns" a scene; a scene is a `{ anchor, formation, focusX, energy }`
|
|
201
210
|
record. The registry is the single place that maps DOM sections to particle
|
|
@@ -329,7 +338,7 @@ scrubbed scalar, scrolling back up rewinds the whole explosion frame-for-frame.
|
|
|
329
338
|
|
|
330
339
|
## 5. Layer 4 — The 2D fallback (SignalMesh)
|
|
331
340
|
|
|
332
|
-
**
|
|
341
|
+
**Reference file:** `src/components/atmosphere/SignalMesh.tsx`
|
|
333
342
|
|
|
334
343
|
Touch and no-WebGL clients get a canvas mesh: two depth layers of grid nodes
|
|
335
344
|
with hairline links and traveling pulses, plus **stroke overlays** that fade in
|
|
@@ -346,7 +355,7 @@ fidelity. Only `prefers-reduced-motion` gets a single static frame.
|
|
|
346
355
|
|
|
347
356
|
## 6. Layer 5 — The projection bridge (fusing DOM and WebGL)
|
|
348
357
|
|
|
349
|
-
**
|
|
358
|
+
**Reference file:** `src/lib/motion/field-sync.ts`
|
|
350
359
|
|
|
351
360
|
The hardest problem in mixing WebGL particles with DOM labels: the camera moves,
|
|
352
361
|
so you cannot hard-code where a cluster appears on screen. The bridge solves it
|
|
@@ -423,7 +432,7 @@ React renders. Act markers deep-link to their anchor sections and use the coarse
|
|
|
423
432
|
|
|
424
433
|
## 8. Layer 7 — Reveal primitives (act-themed entrances)
|
|
425
434
|
|
|
426
|
-
**
|
|
435
|
+
**Reference file:** `src/components/design/Reveal.tsx`
|
|
427
436
|
|
|
428
437
|
Entrances are not generic. Each narrative act has a reveal whose *physics* match
|
|
429
438
|
its meaning — this is Disney's "staging" applied to a scroll page:
|