@struq/skill 0.4.3 → 0.5.1

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 (53) hide show
  1. package/README.md +27 -27
  2. package/cli/struq.mjs +2 -2
  3. package/package.json +6 -6
  4. package/skills/struq/SKILL.md +145 -89
  5. package/skills/struq/blocks/CATALOG.md +74 -22
  6. package/skills/struq/blocks/backgrounds/background-aurora.tsx +34 -12
  7. package/skills/struq/blocks/backgrounds/background-facets.tsx +14 -6
  8. package/skills/struq/blocks/backgrounds/background-silk.tsx +40 -15
  9. package/skills/struq/blocks/catalog.json +697 -16
  10. package/skills/struq/blocks/film.json +426 -0
  11. package/skills/struq/blocks/footers/footer-contact.tsx +81 -55
  12. package/skills/struq/blocks/footers/footer-reveal.tsx +1 -1
  13. package/skills/struq/blocks/headers/header-bar.tsx +24 -13
  14. package/skills/struq/blocks/headers/menu-curtain.tsx +24 -11
  15. package/skills/struq/blocks/heroes/hero-framed.tsx +33 -20
  16. package/skills/struq/blocks/heroes/hero-index.tsx +32 -11
  17. package/skills/struq/blocks/heroes/hero-poster.tsx +68 -35
  18. package/skills/struq/blocks/heroes/hero-split.tsx +22 -9
  19. package/skills/struq/blocks/heroes/hero-still.tsx +80 -74
  20. package/skills/struq/blocks/kit/accent.ts +82 -0
  21. package/skills/struq/blocks/kit/blocks.css +78 -35
  22. package/skills/struq/blocks/kit/quiet/Close.tsx +73 -0
  23. package/skills/struq/blocks/kit/quiet/PhotoText.tsx +79 -0
  24. package/skills/struq/blocks/kit/quiet/Rows.tsx +81 -0
  25. package/skills/struq/blocks/kit/quiet/Statement.tsx +157 -0
  26. package/skills/struq/blocks/kit/quiet/index.ts +7 -0
  27. package/skills/struq/blocks/kit/quiet/sheet.ts +12 -0
  28. package/skills/struq/blocks/page-transitions/page-transition-gate.tsx +87 -36
  29. package/skills/struq/blocks/preloaders/preloader-gate.tsx +116 -46
  30. package/skills/struq/blocks/preloaders/preloader-stack.tsx +10 -7
  31. package/skills/struq/blocks/sections/contact-form.tsx +1 -1
  32. package/skills/struq/blocks/sections/cta-closing.tsx +3 -2
  33. package/skills/struq/blocks/sections/fanned-cards.tsx +14 -10
  34. package/skills/struq/blocks/sections/film-strip.tsx +18 -14
  35. package/skills/struq/blocks/sections/grid-assembly.tsx +16 -11
  36. package/skills/struq/blocks/sections/manifesto.tsx +3 -2
  37. package/skills/struq/blocks/sections/panel-accordion.tsx +3 -2
  38. package/skills/struq/blocks/sections/split-pair.tsx +4 -3
  39. package/skills/struq/blocks/showpieces/hero-opener.tsx +76 -17
  40. package/skills/struq/blocks/showpieces/wordmark-finale.tsx +3 -1
  41. package/skills/struq/blocks/transitions/zoom-through.tsx +9 -10
  42. package/skills/struq/canon/canon.json +1 -1
  43. package/skills/struq/references/craft.md +4 -0
  44. package/skills/struq/references/film.md +158 -0
  45. package/skills/struq/references/iconography.md +1 -1
  46. package/skills/struq/references/triage.md +3 -0
  47. package/skills/struq/scripts/blocks.mjs +89 -7
  48. package/skills/struq/scripts/canon.mjs +8 -1
  49. package/skills/struq/scripts/check.mjs +99 -15
  50. package/skills/struq/scripts/film-check.mjs +997 -0
  51. package/skills/struq/scripts/gate.mjs +146 -0
  52. package/skills/struq/scripts/images.mjs +64 -37
  53. package/skills/struq/scripts/packs.mjs +73 -12
package/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  <h1 align="center">
2
- <a href="https://struq.nl/skill">
2
+ <a href="https://struq.app/skill">
3
3
  <picture>
4
- <source media="(prefers-color-scheme: dark)" srcset="https://cdn.jsdelivr.net/gh/struqnl/struq-design@main/assets/readme/banner-dark.svg">
5
- <img alt="Struq skill: studio-grade sites from the AI you already use." src="https://cdn.jsdelivr.net/gh/struqnl/struq-design@main/assets/readme/banner-light.svg" width="100%">
4
+ <source media="(prefers-color-scheme: dark)" srcset="https://cdn.jsdelivr.net/gh/struqapp/struq-design@main/assets/readme/banner-dark.svg">
5
+ <img alt="Struq skill: studio-grade sites from the AI you already use." src="https://cdn.jsdelivr.net/gh/struqapp/struq-design@main/assets/readme/banner-light.svg" width="100%">
6
6
  </picture>
7
7
  </a>
8
8
  </h1>
@@ -12,13 +12,13 @@
12
12
  </p>
13
13
 
14
14
  <p align="center">
15
- <a href="https://struq.nl/skill">Website</a>
15
+ <a href="https://struq.app/skill">Website</a>
16
16
  &nbsp;&middot;&nbsp;
17
17
  <a href="https://www.npmjs.com/package/@struq/skill">npm</a>
18
18
  &nbsp;&middot;&nbsp;
19
19
  <a href="skills/struq/blocks/CATALOG.md">The blocks</a>
20
20
  &nbsp;&middot;&nbsp;
21
- <a href="https://struq.nl/iconen">Struq Icons</a>
21
+ <a href="https://struq.app/icons">Struq Icons</a>
22
22
  &nbsp;&middot;&nbsp;
23
23
  <a href="CHANGELOG.md">Changelog</a>
24
24
  </p>
@@ -45,7 +45,7 @@ It plans the site, stops once to show you the plan, and builds only after you sa
45
45
 
46
46
  <br>
47
47
 
48
- ## <picture><source media="(prefers-color-scheme: dark)" srcset="https://cdn.jsdelivr.net/gh/struqnl/struq-design@main/assets/readme/h/agents-dark.svg"><img src="https://cdn.jsdelivr.net/gh/struqnl/struq-design@main/assets/readme/h/agents-light.svg" width="26" height="26" alt=""></picture> Same brief, two agents
48
+ ## <picture><source media="(prefers-color-scheme: dark)" srcset="https://cdn.jsdelivr.net/gh/struqapp/struq-design@main/assets/readme/h/agents-dark.svg"><img src="https://cdn.jsdelivr.net/gh/struqapp/struq-design@main/assets/readme/h/agents-light.svg" width="26" height="26" alt=""></picture> Same brief, two agents
49
49
 
50
50
  Three briefs, each built twice by the same model with the same materials: once as a plain coding agent, once with `/struq`. Look at the left column first.
51
51
 
@@ -53,7 +53,7 @@ Three briefs, each built twice by the same model with the same materials: once a
53
53
 
54
54
  | Plain agent | With the Struq skill |
55
55
  |---|---|
56
- | ![Tidewater, built by a plain agent](https://cdn.jsdelivr.net/gh/struqnl/struq-design@main/docs/compare/saas-plain.webp) | ![Tidewater, built with the Struq skill](https://cdn.jsdelivr.net/gh/struqnl/struq-design@main/docs/compare/saas-struq.webp) |
56
+ | ![Tidewater, built by a plain agent](https://cdn.jsdelivr.net/gh/struqapp/struq-design@main/docs/compare/saas-plain.webp) | ![Tidewater, built with the Struq skill](https://cdn.jsdelivr.net/gh/struqapp/struq-design@main/docs/compare/saas-struq.webp) |
57
57
 
58
58
  <details>
59
59
  <summary><b>Seen the left one before?</b></summary>
@@ -67,7 +67,7 @@ You have. It is the dark developer-tool template, item for item: the green glow,
67
67
 
68
68
  | Plain agent | With the Struq skill |
69
69
  |---|---|
70
- | ![Ana Ferreira, built by a plain agent](https://cdn.jsdelivr.net/gh/struqnl/struq-design@main/docs/compare/ceramics-plain.webp) | ![Ana Ferreira, built with the Struq skill](https://cdn.jsdelivr.net/gh/struqnl/struq-design@main/docs/compare/ceramics-struq.webp) |
70
+ | ![Ana Ferreira, built by a plain agent](https://cdn.jsdelivr.net/gh/struqapp/struq-design@main/docs/compare/ceramics-plain.webp) | ![Ana Ferreira, built with the Struq skill](https://cdn.jsdelivr.net/gh/struqapp/struq-design@main/docs/compare/ceramics-struq.webp) |
71
71
 
72
72
  <details>
73
73
  <summary><b>Where did "12 restaurants" come from?</b></summary>
@@ -81,7 +81,7 @@ Nowhere. The brief gave no figures, no quote and no bio, and the plain agent wro
81
81
 
82
82
  | Plain agent | With the Struq skill |
83
83
  |---|---|
84
- | ![Vela Mono, built by a plain agent](https://cdn.jsdelivr.net/gh/struqnl/struq-design@main/docs/compare/ebike-plain.webp) | ![Vela Mono, built with the Struq skill](https://cdn.jsdelivr.net/gh/struqnl/struq-design@main/docs/compare/ebike-struq.webp) |
84
+ | ![Vela Mono, built by a plain agent](https://cdn.jsdelivr.net/gh/struqapp/struq-design@main/docs/compare/ebike-plain.webp) | ![Vela Mono, built with the Struq skill](https://cdn.jsdelivr.net/gh/struqapp/struq-design@main/docs/compare/ebike-struq.webp) |
85
85
 
86
86
  <details>
87
87
  <summary><b>Both built a pinned 3D bike. So what is the difference?</b></summary>
@@ -95,13 +95,13 @@ Where the Struq skill still loses: craft. The plain builds aim lower and break l
95
95
 
96
96
  <br>
97
97
 
98
- ## <picture><source media="(prefers-color-scheme: dark)" srcset="https://cdn.jsdelivr.net/gh/struqnl/struq-design@main/assets/readme/h/layers-dark.svg"><img src="https://cdn.jsdelivr.net/gh/struqnl/struq-design@main/assets/readme/h/layers-light.svg" width="26" height="26" alt=""></picture> The blocks carry the motion
98
+ ## <picture><source media="(prefers-color-scheme: dark)" srcset="https://cdn.jsdelivr.net/gh/struqapp/struq-design@main/assets/readme/h/layers-dark.svg"><img src="https://cdn.jsdelivr.net/gh/struqapp/struq-design@main/assets/readme/h/layers-light.svg" width="26" height="26" alt=""></picture> The blocks carry the motion
99
99
 
100
100
  Your agent picks the direction, sets the order and writes the copy. The motion comes from Struq's own catalogue: 44 admitted blocks, each a real React file with three variants, working in light and dark.
101
101
 
102
102
  <picture>
103
- <source media="(prefers-color-scheme: dark)" srcset="https://cdn.jsdelivr.net/gh/struqnl/struq-design@main/assets/readme/blocks-dark.webp">
104
- <img alt="Six Struq blocks playing at once: a preloader, a hero, a page transition, a manifesto scrub, an image growing to full bleed and a WebGL background." src="https://cdn.jsdelivr.net/gh/struqnl/struq-design@main/assets/readme/blocks-light.webp" width="100%">
103
+ <source media="(prefers-color-scheme: dark)" srcset="https://cdn.jsdelivr.net/gh/struqapp/struq-design@main/assets/readme/blocks-dark.webp">
104
+ <img alt="Six Struq blocks playing at once: a preloader, a hero, a page transition, a manifesto scrub, an image growing to full bleed and a WebGL background." src="https://cdn.jsdelivr.net/gh/struqapp/struq-design@main/assets/readme/blocks-light.webp" width="100%">
105
105
  </picture>
106
106
 
107
107
  <details>
@@ -126,11 +126,11 @@ Each one with its files, packages, props and variants: [the catalogue](skills/st
126
126
 
127
127
  <br>
128
128
 
129
- ## <picture><source media="(prefers-color-scheme: dark)" srcset="https://cdn.jsdelivr.net/gh/struqnl/struq-design@main/assets/readme/h/brush-dark.svg"><img src="https://cdn.jsdelivr.net/gh/struqnl/struq-design@main/assets/readme/h/brush-light.svg" width="26" height="26" alt=""></picture> What is in the skill
129
+ ## <picture><source media="(prefers-color-scheme: dark)" srcset="https://cdn.jsdelivr.net/gh/struqapp/struq-design@main/assets/readme/h/brush-dark.svg"><img src="https://cdn.jsdelivr.net/gh/struqapp/struq-design@main/assets/readme/h/brush-light.svg" width="26" height="26" alt=""></picture> What is in the skill
130
130
 
131
131
  <picture>
132
- <source media="(prefers-color-scheme: dark)" srcset="https://cdn.jsdelivr.net/gh/struqnl/struq-design@main/assets/readme/kit-dark.svg">
133
- <img alt="Six parts: blocks, direction, photos, craft, a check, and the Struq MCP." src="https://cdn.jsdelivr.net/gh/struqnl/struq-design@main/assets/readme/kit-light.svg" width="100%">
132
+ <source media="(prefers-color-scheme: dark)" srcset="https://cdn.jsdelivr.net/gh/struqapp/struq-design@main/assets/readme/kit-dark.svg">
133
+ <img alt="Six parts: blocks, direction, photos, craft, a check, and the Struq MCP." src="https://cdn.jsdelivr.net/gh/struqapp/struq-design@main/assets/readme/kit-light.svg" width="100%">
134
134
  </picture>
135
135
 
136
136
  <details>
@@ -152,9 +152,9 @@ Stack: Next.js App Router and Tailwind v4 (Vite by hand, see `references/stack-t
152
152
 
153
153
  <br>
154
154
 
155
- ## <picture><source media="(prefers-color-scheme: dark)" srcset="https://cdn.jsdelivr.net/gh/struqnl/struq-design@main/assets/readme/h/compass-dark.svg"><img src="https://cdn.jsdelivr.net/gh/struqnl/struq-design@main/assets/readme/h/compass-light.svg" width="26" height="26" alt=""></picture> How a build runs
155
+ ## <picture><source media="(prefers-color-scheme: dark)" srcset="https://cdn.jsdelivr.net/gh/struqapp/struq-design@main/assets/readme/h/compass-dark.svg"><img src="https://cdn.jsdelivr.net/gh/struqapp/struq-design@main/assets/readme/h/compass-light.svg" width="26" height="26" alt=""></picture> How a build runs
156
156
 
157
- - **Direction.** A palette, a type pairing and a photo pack from Struq's canon, and the order of the site from the catalogue: arrival, header, hero, manifesto, about, approach, work, closing call to action, footer. All of it in one `STRUQ.md`.
157
+ - **Direction.** The site is planned as one film: a motion language (weight, cut or curtain), one idea, one motif, and a storyboard of scenes with the handovers between them. Then a palette, a type pairing and a photo pack from Struq's canon. All of it in one `STRUQ.md`, and no block goes in until that plan passes its own check.
158
158
  - **One stop.** It shows you that plan and asks once: approve it, and send a logo, photos or real numbers if you have them. It does not ask again.
159
159
  - **Blocks.** It installs each block with everything it imports, writes the tokens and fonts, and composes the page with your real copy.
160
160
  - **Check.** `check.mjs` runs until the page passes. With a browser tool it also looks at the page at phone and desktop width and fixes what it sees.
@@ -170,7 +170,7 @@ In Codex the command is `$struq`; as a Claude Code plugin it is `/struq:struq`.
170
170
 
171
171
  <br>
172
172
 
173
- ## <picture><source media="(prefers-color-scheme: dark)" srcset="https://cdn.jsdelivr.net/gh/struqnl/struq-design@main/assets/readme/h/download-dark.svg"><img src="https://cdn.jsdelivr.net/gh/struqnl/struq-design@main/assets/readme/h/download-light.svg" width="26" height="26" alt=""></picture> Install
173
+ ## <picture><source media="(prefers-color-scheme: dark)" srcset="https://cdn.jsdelivr.net/gh/struqapp/struq-design@main/assets/readme/h/download-dark.svg"><img src="https://cdn.jsdelivr.net/gh/struqapp/struq-design@main/assets/readme/h/download-light.svg" width="26" height="26" alt=""></picture> Install
174
174
 
175
175
  ```bash
176
176
  npx @struq/skill@latest
@@ -188,13 +188,13 @@ npx @struq/skill@latest --claude
188
188
  npx @struq/skill@latest --project
189
189
 
190
190
  # with the open skills CLI, which knows 70+ agents
191
- npx skills add struqnl/struq-design -g
191
+ npx skills add struqapp/struq-design -g
192
192
  ```
193
193
 
194
194
  As a Claude Code plugin (the command is then `/struq:struq`):
195
195
 
196
196
  ```text
197
- /plugin marketplace add struqnl/struq-design
197
+ /plugin marketplace add struqapp/struq-design
198
198
  /plugin install struq@struq
199
199
  ```
200
200
 
@@ -204,11 +204,11 @@ The screenshot step uses whatever browser tool your agent has (Playwright or sim
204
204
 
205
205
  <br>
206
206
 
207
- ## <picture><source media="(prefers-color-scheme: dark)" srcset="https://cdn.jsdelivr.net/gh/struqnl/struq-design@main/assets/readme/h/palette-dark.svg"><img src="https://cdn.jsdelivr.net/gh/struqnl/struq-design@main/assets/readme/h/palette-light.svg" width="26" height="26" alt=""></picture> The icons it reaches for
207
+ ## <picture><source media="(prefers-color-scheme: dark)" srcset="https://cdn.jsdelivr.net/gh/struqapp/struq-design@main/assets/readme/h/palette-dark.svg"><img src="https://cdn.jsdelivr.net/gh/struqapp/struq-design@main/assets/readme/h/palette-light.svg" width="26" height="26" alt=""></picture> The icons it reaches for
208
208
 
209
- Struq builds use [Struq Icons](https://struq.nl/iconen) by default: 182 icons in two tones, and each of the 118 full icons makes one small move under the cursor that says what it does. Every icon on this page is one of them.
209
+ Struq builds use [Struq Icons](https://struq.app/icons) by default: 182 icons in two tones, and each of the 118 full icons makes one small move under the cursor that says what it does. Every icon on this page is one of them.
210
210
 
211
- <a href="https://struq.nl/iconen">
211
+ <a href="https://struq.app/icons">
212
212
  <picture>
213
213
  <source media="(prefers-color-scheme: dark)" srcset="https://cdn.jsdelivr.net/npm/@struq/icons@1/readme/motion-dark.svg">
214
214
  <img alt="Eight Struq icons playing their hover motion: lock, delete, settings, mail, history, sound, hint, bug." src="https://cdn.jsdelivr.net/npm/@struq/icons@1/readme/motion-light.svg" width="100%">
@@ -221,18 +221,18 @@ npm install @struq/icons
221
221
 
222
222
  <br>
223
223
 
224
- ## <picture><source media="(prefers-color-scheme: dark)" srcset="https://cdn.jsdelivr.net/gh/struqnl/struq-design@main/assets/readme/h/shield-dark.svg"><img src="https://cdn.jsdelivr.net/gh/struqnl/struq-design@main/assets/readme/h/shield-light.svg" width="26" height="26" alt=""></picture> What it fetches and sends
224
+ ## <picture><source media="(prefers-color-scheme: dark)" srcset="https://cdn.jsdelivr.net/gh/struqapp/struq-design@main/assets/readme/h/shield-dark.svg"><img src="https://cdn.jsdelivr.net/gh/struqapp/struq-design@main/assets/readme/h/shield-light.svg" width="26" height="26" alt=""></picture> What it fetches and sends
225
225
 
226
226
  The Struq skill is instructions, the block files and five small Node scripts (`blocks.mjs`, `canon.mjs`, `images.mjs`, `check.mjs`, `log.mjs`) that your agent runs in your project. They read and write files there, including a build log, `STRUQ-LOG.md`.
227
227
 
228
228
  - **Blocks and canon** ship inside the skill. Nothing is fetched to install a block or write the tokens.
229
229
  - **Fonts** load from Google Fonts (or Fontshare, for a face that lives there) in the visitor's browser, as on any site with web fonts.
230
- - **Photos**, for every slot your own photos do not fill: `images.mjs` reads the public pack list at `https://struq.nl/api/media/packs` and downloads the chosen images from `https://struq.nl/media/packs/`. Offline it writes plates graded to your palette instead.
231
- - **The MCP**, if you connect it: your agent calls Struq's tools with your brief. Nothing else leaves your machine.
230
+ - **Photos**, for every slot your own photos do not fill: `images.mjs` reads the public pack list at `https://struq.app/api/media/packs` and downloads the chosen images from `https://struq.app/media/packs/`, or from the same paths on the old domain when struq.app does not answer. Offline it writes plates graded to your palette instead.
231
+ - **The MCP** (`https://struq.app/api/mcp`), if you connect it: your agent calls Struq's tools with your brief. Nothing else leaves your machine.
232
232
  - **The installer** downloads the package from npm, looks for your AI tools' folders in your home folder and copies the skill into them. It sends nothing.
233
233
 
234
234
  <br>
235
235
 
236
236
  ## License
237
237
 
238
- MIT. Made by [Struq](https://struq.nl).
238
+ MIT. Made by [Struq](https://struq.app).
package/cli/struq.mjs CHANGED
@@ -34,7 +34,7 @@ Usage
34
34
  npx @struq/skill@latest remove remove the skill again (takes the same flags)
35
35
  npx @struq/skill@latest --help show this
36
36
 
37
- Run it again at any time to update. More: https://struq.nl/skill
37
+ Run it again at any time to update. More: https://struq.app/skill
38
38
  `;
39
39
 
40
40
  function parse(argv) {
@@ -119,7 +119,7 @@ function run(argv) {
119
119
  for (const tool of new Map(list.map(({ tool }) => [tool.label, tool])).values()) {
120
120
  out.push(` ${tool.label.padEnd(15)}${tool.use}`);
121
121
  }
122
- out.push('', 'Run this again at any time to update. More: https://struq.nl/skill');
122
+ out.push('', 'Run this again at any time to update. More: https://struq.app/skill');
123
123
  }
124
124
  process.stdout.write(`${out.join('\n')}\n`);
125
125
  }
package/package.json CHANGED
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "name": "@struq/skill",
3
- "version": "0.4.3",
3
+ "version": "0.5.1",
4
4
  "description": "Install the free Struq skill into Claude Code, Cursor, Codex and other AI coding tools: websites at the level of a design studio, built by your own AI.",
5
5
  "license": "MIT",
6
- "author": "Struq (https://struq.nl)",
7
- "homepage": "https://struq.nl/skill",
6
+ "author": "Struq (https://struq.app)",
7
+ "homepage": "https://struq.app/skill",
8
8
  "repository": {
9
9
  "type": "git",
10
- "url": "git+https://github.com/struqnl/struq-design.git"
10
+ "url": "git+https://github.com/struqapp/struq-design.git"
11
11
  },
12
- "bugs": "https://github.com/struqnl/struq-design/issues",
12
+ "bugs": "https://github.com/struqapp/struq-design/issues",
13
13
  "keywords": [
14
14
  "agent-skill",
15
15
  "skills",
@@ -35,7 +35,7 @@
35
35
  "node": ">=18"
36
36
  },
37
37
  "scripts": {
38
- "test": "node --test test/install.test.mjs test/check.test.mjs test/packs.test.mjs test/tokens.test.mjs test/blocks.test.mjs test/plugin.test.mjs",
38
+ "test": "node --test test/install.test.mjs test/check.test.mjs test/packs.test.mjs test/tokens.test.mjs test/blocks.test.mjs test/gate.test.mjs test/arc.test.mjs test/plugin.test.mjs",
39
39
  "release:blocks": "node scripts/release-blocks.mjs",
40
40
  "release:plugin": "node scripts/build-plugin.mjs"
41
41
  },
@@ -1,23 +1,20 @@
1
1
  ---
2
2
  name: struq
3
- description: "Award-tier studio websites for coding agents, built from Struq's catalogue of admitted blocks: preloaders, page transitions, headers, heroes, WebGL backgrounds, showpieces, sections and footers, each with three real variants, judged at FWA level and shipped as files. Struq's palettes and type pairings as one token block, art-directed CC0 photos from the Struq beeldbank, Lenis on one GSAP clock, and a self-check against the AI tells. Works offline from its own copy; uses the Struq MCP (struq_richting, struq_blokken, struq_blok, struq_controle) when connected. Use when designing, building, redesigning, animating or auditing a marketing, studio, agency or portfolio site that must feel cinematic and custom instead of templated. Stack: Next.js App Router + Tailwind v4."
3
+ description: "Award-tier studio websites for coding agents, built from Struq's catalogue of admitted blocks and directed as one film: one idea, one motion language, one motif and one centerpiece, cast into a storyboard before a block is installed. Preloaders, page transitions, headers, heroes, WebGL backgrounds, showpieces, sections and footers, each with real variants, judged at FWA level and shipped as files. Struq's palettes and type pairings as one token block, art-directed CC0 photos from the Struq beeldbank, Lenis on one GSAP clock, and a self-check against the AI tells. Works offline from its own copy; uses the Struq MCP (struq_richting, struq_blokken, struq_blok, struq_controle) when connected. Use when designing, building, redesigning, animating or auditing a marketing, studio, agency or portfolio site that must feel cinematic and custom instead of templated. Stack: Next.js App Router + Tailwind v4."
4
4
  argument-hint: "[brief] | redesign <path> | audit <path-or-url> | direct <brief>"
5
5
  ---
6
6
 
7
7
  # Struq
8
8
 
9
- A site looks like a template because every choice in it is the likeliest one. Struq replaces those choices with
10
- blocks a studio would ship: each one built, reviewed against a named award-tier reference and admitted by hand. Your
11
- job is the direction, the order, the copy and the seams between blocks. Do not rebuild what a block already does.
12
-
13
- `<skill-dir>` is the folder this file is in. The catalogue is [blocks/CATALOG.md](blocks/CATALOG.md); the craft that
14
- makes the blocks feel high end is [references/craft.md](references/craft.md); the tell list is
15
- [references/tells.md](references/tells.md).
9
+ A site looks like a template when every choice is the likeliest one, and like a showreel when every slot gets the
10
+ loudest block. Struq casts studio blocks into one film; your job is the treatment, the copy and the seams, never a
11
+ rebuild of what a block does. `<skill-dir>` is this file's folder; the catalogue is [blocks/CATALOG.md](blocks/CATALOG.md),
12
+ a worked treatment per language [references/film.md](references/film.md), the craft [references/craft.md](references/craft.md).
16
13
 
17
14
  | Invocation | Mode |
18
15
  |---|---|
19
16
  | `/struq <brief>` | **Build**: the checklist below, start to finish. |
20
- | `/struq redesign <path>` | Keep the brand, copy and components ([references/triage.md](references/triage.md)); swap in blocks where the page is weakest, then run the checklist from step 3. |
17
+ | `/struq redesign <path>` | Keep the brand, copy and components ([references/triage.md](references/triage.md)); write a treatment of the page as it will be (kept sections as own scenes) and stop once as in step 2, then swap in blocks where the page is weakest and run the checklist from step 3. |
21
18
  | `/struq audit <path-or-url>` | Change nothing. Run `check.mjs` (and `struq_controle` when connected), report every FAIL and WARN and the three fixes with the most visual payoff. Never a numeric score. |
22
19
  | `/struq direct <brief>` | One continuous WebGL experience across chapters: steps 1 to 4, then [cinematic/README.md](cinematic/README.md). |
23
20
 
@@ -36,8 +33,7 @@ For a dashboard or product UI keep the tokens, faces and tells; drop the preload
36
33
 
37
34
  ## The MCP, or the skill's own copy
38
35
 
39
- The Struq MCP and this skill serve the same blocks and the same derivation. Use the tool when it is connected; the
40
- offline column does the same from the skill's copy.
36
+ Same blocks, same derivation: use the MCP tool when it is connected, else the offline column from the skill's copy.
41
37
 
42
38
  | Need | MCP connected | Offline |
43
39
  |---|---|---|
@@ -46,8 +42,8 @@ offline column does the same from the skill's copy.
46
42
  | A block as files | `struq_blok(slug, variant?)` | `blocks.mjs add <slug>` |
47
43
  | The tell check | `struq_controle()`: run its detectors on your own files | `check.mjs` |
48
44
 
49
- Put `struq_richting`'s token block in `app/globals.css` in place of the STRUQ TOKENS block and its font URLs in
50
- `app/fonts.ts`; drop `struq_blok`'s files into `components/struq/` at the paths it gives. Log each tool call:
45
+ `struq_richting`'s token block replaces STRUQ TOKENS in `app/globals.css`, its font URLs go in `app/fonts.ts`;
46
+ `struq_blok`'s files go into `components/struq/` at their paths. Log each call:
51
47
  `node <skill-dir>/scripts/log.mjs mcp <tool> --note "<what you took>"`. Run `check.mjs` either way.
52
48
 
53
49
  ## Build checklist
@@ -59,107 +55,168 @@ their own). `check.mjs` fails while a line is open or a ticked step has no entry
59
55
  ```
60
56
  ## Build checklist
61
57
  - [ ] 1 Project: Next.js App Router + Tailwind v4; blocks.mjs init printed OK
62
- - [ ] 2 Direction and approval: palette, pairing, pack and the block order in STRUQ.md; the one stop sent and answered
58
+ - [ ] 2 Treatment and approval: the treatment in STRUQ.md, the plan check at PLAN: PASS; the one stop sent and answered
63
59
  - [ ] 3 Canon: the token block and fonts written (canon.mjs palette and type, or struq_richting)
64
60
  - [ ] 4 Images: images.mjs --brief printed OK; only photos whose alt fits the client
65
- - [ ] 5 Blocks: every block on the order installed and composed in app/page.tsx with real copy
61
+ - [ ] 5 Scenes: frames and the centerpiece installed, every other scene built as the storyboard says, composed in app/page.tsx with real copy
66
62
  - [ ] 6 Build: npm run build passes
67
63
  - [ ] 7 Look: 390 and 1440 screenshots and one full scroll, fixes made (or "Verify: not seen, no browser")
68
64
  - [ ] 8 Check: check.mjs prints RESULT: PASS
69
65
  ```
70
66
 
71
67
  **1 Project.** Empty folder: `npx create-next-app@latest . --ts --tailwind --app --eslint --yes`, then
72
- `node <skill-dir>/scripts/blocks.mjs init`. It copies the kit to `components/struq/kit/`, writes the layout (the
73
- `sq-js` script before paint, the font links, `data-blocks` on `<body>`, `SmoothScroll`), `globals.css` (the kit
74
- import, the theme names, the STRUQ TOKENS block) and `fonts.ts` over a starter, and installs gsap, @gsap/react and
75
- lenis. Your own layout or stylesheet is never overwritten: merge from `recipes/app/`.
76
-
77
- **2 Direction and the one stop.** Pick from the canon, never invent a palette or pairing while one fits. Palette by
78
- the brief's mood, then its sector; a palette marked "kept out" (blue, purple, teal) only for a brand that is that
79
- colour, declared as `Cool hue: declared because <brand colour>`. The brand's own colours and faces beat the canon:
80
- write them into the same token names. Pairing by temperament: Fraunces (serif-editorial) warm and premium, Newsreader
81
- literate, Sora calm and architectural, Urbanist soft and current, Bodoni Moda for fashion, Big Shoulders
82
- (condensed-poster) for a campaign at poster scale, Unbounded for a wide agency voice. Then choose the order (below)
83
- and write the top of STRUQ.md:
68
+ `node <skill-dir>/scripts/blocks.mjs init`: the kit in `components/struq/kit/`, the layout (`sq-js` before paint,
69
+ font links, `data-blocks` on `<body>`, `SmoothScroll`), `globals.css` (kit import, theme names, STRUQ TOKENS),
70
+ `fonts.ts`, gsap, @gsap/react and lenis. It never overwrites your layout or stylesheet: merge from `recipes/app/`.
71
+
72
+ **2 Treatment and the one stop.** Pick from the canon, never invent a palette or pairing while one fits: palette by
73
+ mood, then sector; a "kept out" palette (blue, purple, teal) only for a brand of that colour, declared as `Cool hue:
74
+ declared because <brand colour>`; the brand's own colours and faces beat the canon, in the same token names. Pairing
75
+ by temperament: Fraunces (serif-editorial) warm and premium, Newsreader literate, Sora calm and architectural,
76
+ Urbanist soft and current, Bodoni Moda for fashion, Big Shoulders (condensed-poster) for a campaign at poster scale,
77
+ Unbounded for a wide agency voice. Pick the language (The film, below), then run
78
+ `node <skill-dir>/scripts/blocks.mjs arc <language>` and paste the Tone arc and Storyboard it prints into the
79
+ treatment at the top of STRUQ.md. Fill every `<...>`, one pick per line (`or:` lists what else fits; swap at most one
80
+ scene; a block the user names goes in first):
84
81
 
85
82
  ```
86
83
  # STRUQ.md: <name>
87
84
  Brief: <one line: what, for whom, where>
88
- Idea: <the one idea the site is about>
85
+ Idea: <a point of view in one sentence, never a description of the client: what a visitor believes when they leave>
86
+ Language: <weight | cut | curtain> (<the client's sector, or the brief's own words for another feel>)
87
+ Motif: <line | frame | aperture | cut | word | field>: <what it is in this client's world and how it changes down the page>
88
+ Lexicon: <three to five working words of the client's trade (a material, a part, a tool, a unit), never the brief repeated; every label, counter and caption uses these, no film or studio jargon the client does not own>
89
89
  Palette: <id> (<mood>)
90
90
  Type: <pairing id>: <display> + <body>
91
91
  Images: pack <slug> (or the client's photos, then pack <slug>)
92
- Order: <block slug:variant>, <block slug:variant>, ...
92
+ Centerpiece: <block>: <why this is this site's one moment>
93
+ Tone arc: <as blocks.mjs arc printed it>
94
+ Storyboard:
95
+ 1. Arrival (frame) <preloader of the language> | lands on: <what>
96
+ 2. Opening (loud) <block:variant> | on screen: <...> | enters: <...> | hands over: <...>
97
+ 3. <scene> (quiet) <block:variant or kit scene> | on screen: <...> | enters: <...> | hands over: <...>
98
+ ...
99
+ N. Close (quiet) <block or kit scene> | echoes the opening: <how> | footer: <block>
93
100
  Assumptions: <every drafted line and every fact left out>
94
101
  Verify: <filled in at step 7>
95
102
  ```
96
103
 
97
- Then **stop once**, in the user's language: the plan in five lines (idea, palette, type, pack, order) and
98
- "Akkoord? Heb je een logo, foto's of echte cijfers, stuur ze nu." (English: "Approve? If you have a logo, photos or
99
- real numbers, send them now."). The build request is not the approval. Log the reply word for word:
100
- `log.mjs "Step 2 Approval" "Asked: ..." "Reply: \"<their words>\""`. Any yes builds the plan; what they send replaces
101
- the matching pick; a veto changes only what it names. Never ask a second time. When no pack shows the client's own
102
- product, add: "Ik heb geen foto's van je <product>: stuur ze, dan komen ze in de hero."
103
-
104
- **3 Canon.** `canon.mjs palette <id>` and `canon.mjs type <id>` rewrite the one STRUQ TOKENS block and `app/fonts.ts`:
105
- the surface ladder, the field and inverse roles, `--photo-ground`, the accent's ink, the pairing's display weight and
106
- faces, and each Google face asked for its real weights. It is the block Struq's lab judged every block in.
107
-
108
- **4 Images.** `node <skill-dir>/scripts/images.mjs --brief "<the brief, in the user's words>"` picks the pack, keeps
109
- only the photos whose alt fits the client, downloads and verifies them to `public/images/` and writes
110
- `lib/struq-images.ts` (`images.hero`, `.band`, `.card`, `.column`, `.detail`, `.backdrop`, `imageCredit`, `imageFit`).
111
- `images.mjs --list` shows every pack. Read the alts before you place a photo; with `imageFit` "none" use no photos and
112
- let a background block carry the hero. Offline it writes plates graded to the palette. Set the title, description and
113
- `lang` in the layout.
114
-
115
- **5 Blocks.** Install the order with `blocks.mjs add <slug> ...` (or `struq_blok`), read each block's file header for
116
- its props, variants and how it mounts, and compose `app/page.tsx` with the brief's real copy. Glue between blocks uses
117
- the kit (`Reveal`, `MediaFrame`, `SplitHeadline`, `MagneticButton`) and the craft rules, never a fresh motion system.
118
-
119
- **6 to 8.** `npm run build` passes (fix your code, never delete a block to get green). Look at the production build
120
- (`npx next start -p 4321`) at 390 and 1440 and scroll it once: the preloader lands on the hero, every frame fills, each
121
- pin engages and releases without a jump, nothing overflows at 390, scrolling back reverses. Never claim you saw what
122
- you did not. Then `check.mjs` until `RESULT: PASS`.
123
-
124
- ## The order of a studio site
125
-
126
- Read top to bottom; each line is a slot with the blocks that fill it. Seven to nine slots, not all of them every time.
127
-
128
- 1. **Arrival, once:** a preloader on the first visit (`preloader-wordmark`, `-slices`, `-gate`, `-stack`) and the
129
- page transition of the same language on every navigation (`page-transition-slices`, `-gate`, `-stack`; mount it in
130
- the layout). Slices with slices, gate with gate, stack with stack: they share one handover.
131
- 2. **Header:** `header-bar` (quiet, settle, split) or `menu-curtain` for a full-screen menu. Sections under it say
132
- their ground with `data-bar-tone`.
133
- 3. **Hero:** `hero-still` (one photo, calm side measured), `hero-framed` (the print on the wall), `hero-split` (a
134
- seam), `hero-index` (the work list as the first screen), `hero-poster` (type as poster), `hero-opener` (full bleed
135
- with the WebGL layer), or a background block (`background-aurora`, `-silk`, `-facets`) when the hero is type on a
136
- live field.
137
- 4. **Manifesto:** `manifesto`, `manifesto-scrub`, `velocity-type` or `reveals`: the one statement, given a screen.
138
- 5. **About:** `about-studio` or `split-pair`.
139
- 6. **Approach:** `approach`, `sticky-chapters`, `panel-accordion` or `fill-rows`. Never numbered steps.
140
- 7. **Work:** `project-stack`, `hover-list`, `image-trail`, `film-strip`, `grid-assembly`, `fanned-cards`, or a scene
141
- move (`image-to-fullbleed`, `panel-wipe`, `zoom-through`, `scrub-connector`, `pixel-resolve`) between two slots.
142
- 8. **Closing call to action:** `cta-closing`, with `contact-form` when the site asks for input.
143
- 9. **Footer:** `footer-reveal`, `footer-contact` or `wordmark-finale`.
144
-
145
- **Picking.** One lead move per page, the hero or a work piece, and the rest quieter around it. Never two pinned
146
- pieces back to back: a plain slot breathes between them. One contrast scene, at most two: wrap a slot in
147
- `scene-inverse` or `scene-field`. Choose the variant by the brief and the photos, not by novelty: a variant is a
148
- different composition of the same idea, and every variant works light and dark. Name a block the user asks for first.
149
- A studio with real project photos leads with work (`hero-index`, `project-stack`); a studio without them leads with
150
- type and one photo (`hero-poster`, `hero-still`, `manifesto`).
104
+ Run `node <skill-dir>/scripts/check.mjs --plan` and fix every FAIL and every `quiet-is-quiet`, `loud-adjacent` and
105
+ `quiet-share` warning until it prints `PLAN: PASS` without them. `canon.mjs` and `blocks.mjs add` refuse until the
106
+ plan passes and the reply is logged. Then **stop once**, in the user's language, and show the treatment, never block
107
+ slugs: idea, language, motif and centerpiece in plain words; the storyboard as numbered lines, one sentence each of
108
+ what the visitor sees; palette, type and pack on one line; then "Akkoord? Heb je een logo, foto's of echte cijfers,
109
+ stuur ze nu." (English: "Approve? If you have a logo, photos or real numbers, send them now."). The build request is
110
+ not the approval. Log the reply word for word: `log.mjs "Step 2 Approval" "Asked: ..." "Reply: \"<their words>\""`.
111
+ Any yes builds the treatment; what they send replaces the matching pick; a veto changes only what it names. Never
112
+ ask twice. No pack shows the client's product? Add: "Ik heb geen foto's van je <product>: stuur ze, dan komen ze in de hero."
113
+
114
+ **3 Canon.** `canon.mjs palette <id>` and `canon.mjs type <id>` rewrite the one STRUQ TOKENS block and `app/fonts.ts`.
115
+
116
+ **4 Images.** `node <skill-dir>/scripts/images.mjs --brief "<the brief, in the user's words>"` keeps only the pack's
117
+ photos whose alt fits the client, verifies them into `public/images/` and writes `lib/struq-images.ts` (`images.hero`,
118
+ `.band`, `.card`, `.column`, `.detail`, `.backdrop`, `imageCredit`, `imageFit`). Read the alts before you place a
119
+ photo; with `imageFit` "none" a background block carries the hero. Title and `lang` go in the layout.
120
+
121
+ **5 Scenes.** Install the frames and the centerpiece first (`blocks.mjs add <slug>:<variant>` or `struq_blok`), then
122
+ each scene as its storyboard line says, the quiet ones with the kit's four (The film, below). Read each file header
123
+ for its props and how it mounts; fill every label, counter and caption from the lexicon; wrap the tone arc's ink or
124
+ field scenes in `scene-inverse` or `scene-field` (a kit scene takes it as `className`). Glue and an own scene use
125
+ `Reveal`, `MediaFrame` and `SplitHeadline`, and an own scene's root carries `data-scene="<name>"`.
126
+
127
+ **6 to 8.** `npm run build` passes (fix your code; never delete a block for green). View `npx next start -p 4321` at
128
+ 390 and 1440, scroll once: the preloader lands on the hero, every frame fills, each pin engages and lets go without a
129
+ jump, nothing overflows, scrolling back reverses. Never claim what you did not see. Then `check.mjs` to `RESULT: PASS`.
130
+
131
+ ## The film
132
+
133
+ One film, not a showreel: every frame from one language, one arc, one centerpiece, one motif seen at the arrival,
134
+ the opening, the centerpiece and the close. A loud scene moves with the scroll (a pin, a scrub, a reveal to full
135
+ bleed); a quiet scene is type and a photo that enter once and sit still. Two tags only: `(loud)` when the block's
136
+ energy in the catalogue is 2 or more, `(quiet)` at 1 or less, for a kit scene or for an own scene.
137
+
138
+ | Language | For | Feel | Frames: preloader, page transition, menu | Motif |
139
+ |---|---|---|---|---|
140
+ | weight | architecture, hotels, craft, interiors | photographic and slow; a print grows into place; long holds | `preloader-stack`, `page-transition-stack`, `menu-curtain:stack` | frame |
141
+ | cut | fashion, agencies, portfolios, music | hard cuts, short masks, no fades, short holds | `preloader-slices`, `page-transition-slices`, `menu-curtain:slices` | cut or word |
142
+ | curtain | campaigns, launches, events, culture | a light line, panels part, a long hold before the reveal | `preloader-gate` or `preloader-wordmark:split`, `page-transition-gate`, `menu-curtain:gate` | line or aperture |
143
+
144
+ Pick the language by the client's sector in the For column. Another language only when the brief asks for that feel
145
+ in its own words; then quote those words on the `Language:` line. The idea may pick another motif of the six.
146
+ `preloader-gate` and `page-transition-gate` show a neutral hairline ring; the film leader (a dial counting 3, 2, 1)
147
+ only for a film client, through `dial="leader"` and `marks`. The header is `header-bar:quiet` or `:settle`; sections
148
+ say their ground with `data-bar-tone`. Each arc is loud only at the opening, the centerpiece and at most one gentle
149
+ scene with a quiet scene on each side. The arcs below are the printed arcs in short; the first pick is the default.
150
+
151
+ **Quiet scenes** are the kit's four, imported from `@/components/struq/kit/quiet` (props in each file's header):
152
+ - `Statement`: the one sentence and the page's first type moment, with an `accent` word and a margin `label` or a
153
+ small `image`, so it is composed, never a lone line.
154
+ - `PhotoText`: a photo and a short text side by side on the grid.
155
+ - `Rows`: three to six hairline rows, a term and one sentence each, never numbered.
156
+ - `Close`: the closing line and its one link, echoing the opening; `frame` when the motif is the frame.
157
+ - An own scene only when none of the four fits: your type beside a photo with `SplitHeadline`, `MediaFrame` and
158
+ `Reveal`, entering once, its root marked `data-scene="<name>"` (the check warns `own-scene-unmarked` without it).
159
+
160
+ **weight.** Paper throughout, ink at the centerpiece.
161
+ 1. Arrival (frame): `preloader-stack`; the print lands on the hero photo.
162
+ 2. Opening (loud, short hold): `hero-framed:wand`, `hero-framed:portret` or `hero-still:frame`; calmer, `hero-still:still` (quiet).
163
+ 3. Statement (quiet): `Statement`.
164
+ 4. About (loud, the gentle one): `about-studio:wandeling` or `about-studio:plaat` (a full-bleed reveal); quiet, `PhotoText`.
165
+ 5. Approach (quiet): `approach:schuif` or `Rows`.
166
+ 6. Centerpiece (loud, ink): `image-to-fullbleed`, `grid-assembly`, `zoom-through` or `project-stack` (real projects).
167
+ 7. Release (quiet): `PhotoText`.
168
+ 8. Close (quiet): `Close`, type only after a full-bleed centerpiece. Footer: `wordmark-finale`.
169
+
170
+ **cut.** Paper and ink in hard alternation, never a fade.
171
+ 1. Arrival (frame): `preloader-slices`, its caption from the lexicon.
172
+ 2. Opening (loud): `hero-poster`; quiet, `hero-index:lijst`, `hero-index:venster`, `hero-split:naad` or `hero-split:liggend`.
173
+ 3. Work (quiet): `hover-list` or `image-trail`; after `hero-index`, already a list, `reveals:clip`.
174
+ 4. Statement (quiet): `Statement`.
175
+ 5. Centerpiece (loud, ink): `split-pair`, `panel-wipe`, `project-stack`, `fanned-cards` or `film-strip` (film clients).
176
+ 6. Release (quiet): `fill-rows` or `Rows`.
177
+ 7. Close (quiet): `Close`, type only, or `cta-closing:pointer`. Footer: `footer-contact`.
178
+
179
+ **curtain.** Field or ink at the opening, paper between, ink at the centerpiece.
180
+ 1. Arrival (frame): `preloader-gate`, the ring fills and the gate parts; or `preloader-wordmark:split`.
181
+ 2. Opening (loud): `hero-opener`, `background-aurora`, `background-silk` or `background-facets`, the line at poster scale; calmer, `hero-still:horizon` (quiet).
182
+ 3. Statement (quiet): `Statement`.
183
+ 4. Details (loud, the gentle one): `sticky-chapters`, or quiet `panel-accordion`: the programme, places and dates given.
184
+ 5. Build (quiet): `PhotoText`, who makes it.
185
+ 6. Centerpiece (loud, ink): `scrub-connector`, `zoom-through`, `manifesto-scrub` or `panel-wipe`.
186
+ 7. Release (quiet): `PhotoText`.
187
+ 8. Close (quiet): `cta-closing:pointer`, the line returning. Footer: `footer-reveal`, the curtain closing.
188
+
189
+ **Budgets.** Hard rules: a storyboard that breaks one is rewritten before the stop.
190
+ - Exactly one centerpiece; nothing pins after it. The opening holds at most 1.5 screens, all pins together about 4.5.
191
+ Screens pinned: `hero-opener` 1, `hero-framed` and `hero-poster` 1.5, `manifesto-scrub` 2, `image-to-fullbleed`
192
+ 2.2, `grid-assembly` 2.5, `panel-wipe` 1.7 (2.6 when it closes), `film-strip` up to 3, `fanned-cards`, `split-pair`,
193
+ `zoom-through` and `scrub-connector` 3, `project-stack` 1.1 per project after the first. Pinned in one variant, so
194
+ never quiet: `hero-still:frame`, `hero-split:opening`, `hero-index:doorlopen`, `about-studio:doorkijk`,
195
+ `approach:zin`, `manifesto:writes` and `:split`.
196
+ - Never two loud scenes side by side. At least four in ten scenes are quiet.
197
+ - Every frame from the site's language. A page transition only when the site has more than one route.
198
+ - Install only what the storyboard names, plus the header and the language's menu.
199
+ - One motif on the page. At most two full-bleed photo reveals, built the same way: `hero-framed:wand` and `:portret`,
200
+ `hero-poster`, `hero-still:frame`, `image-to-fullbleed`, `zoom-through`, `grid-assembly`, `about-studio:plaat` and
201
+ `cta-closing:photo` each count one.
202
+ - At most one marquee (`cta-closing:marquee`, `velocity-type`) and one custom cursor. One accent word, set in the
203
+ accent face through the `accent` prop: in the opening's headline, in `Statement` and again in `Close`.
204
+ - No clock unless the lexicon is about time; then one, turned on by its prop (`clock`, `timeZone` on `wordmark-finale`).
205
+ - Two or three type moments at poster scale (12 to 20vw) on the page; everything else from the scale.
206
+ - Labels: no eyebrows above headings, no mono, no uppercase labels, no numbered steps. A small sentence-case label in
207
+ the body face may sit beside a headline in the margin column or under a photo, in words from the lexicon.
151
208
 
152
209
  ## What makes it feel high end
153
210
 
154
211
  The blocks hold this already; your glue must too. Detail in [references/craft.md](references/craft.md).
155
212
 
156
- - Reveals clip from numbers (inset values tweened as numbers), never scale a box; positions in whole pixels.
157
- - Photos are decoded before they show, cut or swap.
213
+ - Reveals clip from numbers, never scale a box; whole pixels; photos decoded before they show, cut or swap.
158
214
  - Scroll effects are scroll-tied and reverse when the visitor scrolls back; key frames hold.
159
215
  - The gate: `sq-js` on `<html>` before paint hides only what will animate, and shows it anyway after 3 s.
160
216
  - Type on a photo sits on the measured calm side over the lightest flat veil that reaches 3:1.
161
- - Display faces run light (300, or the poster pairing's own weight); fitted lines are measured with the real face
162
- after `document.fonts.ready`.
217
+ - Display runs light (300, or the poster pairing's weight); fitted lines measured after `document.fonts.ready`.
218
+ - Never clip a descender: the kit's masks already keep them; never `overflow-hidden` on a heading of your own, and
219
+ look at a line with a g and a j before calling type done.
163
220
  - Tokens only, mixes in oklab, a surface step and a hairline instead of a shadow, one accent.
164
221
  - Icons: Struq Icons (`@struq/icons`), functional only ([references/iconography.md](references/iconography.md)).
165
222
 
@@ -167,7 +224,6 @@ The blocks hold this already; your glue must too. Detail in [references/craft.md
167
224
 
168
225
  - **Nothing scrolls:** an overlay called `getLenis()?.stop()` without `start()`, or `SmoothScroll` is not mounted.
169
226
  - **Content stays invisible for 3 s:** the block never set `data-ready`; usually it threw. Read the console.
170
- - **Blocks render in the wrong colours or faces:** `data-blocks` is missing on `<body>`, or the STRUQ TOKENS block
171
- sits before the kit import in `globals.css`.
227
+ - **Wrong colours or faces:** `data-blocks` is missing on `<body>`, or STRUQ TOKENS sits before the kit import.
172
228
  - **A fitted line overflows or jumps:** the face did not load (check `app/fonts.ts` and the links in the layout).
173
229
  - **Vite:** [references/stack-targets.md](references/stack-targets.md).