@struq/skill 0.2.2 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. package/README.md +23 -35
  2. package/package.json +3 -2
  3. package/skills/struq/SKILL.md +148 -212
  4. package/skills/struq/blocks/CATALOG.md +426 -0
  5. package/skills/struq/blocks/backgrounds/background-aurora.tsx +818 -0
  6. package/skills/struq/blocks/backgrounds/background-facets.tsx +1283 -0
  7. package/skills/struq/blocks/backgrounds/background-silk.tsx +906 -0
  8. package/skills/struq/blocks/catalog.json +1302 -0
  9. package/skills/struq/blocks/footers/footer-contact.tsx +789 -0
  10. package/skills/struq/blocks/footers/footer-reveal.tsx +313 -0
  11. package/skills/struq/blocks/headers/header-bar.tsx +652 -0
  12. package/skills/struq/blocks/headers/menu-curtain.tsx +790 -0
  13. package/skills/struq/blocks/heroes/hero-framed.tsx +627 -0
  14. package/skills/struq/blocks/heroes/hero-index.tsx +855 -0
  15. package/skills/struq/blocks/heroes/hero-poster.tsx +1086 -0
  16. package/skills/struq/blocks/heroes/hero-split.tsx +685 -0
  17. package/skills/struq/blocks/heroes/hero-still.tsx +862 -0
  18. package/skills/struq/blocks/kit/Cursor.tsx +117 -0
  19. package/skills/struq/blocks/kit/HeroCanvas.tsx +278 -0
  20. package/skills/struq/blocks/kit/HorizontalGallery.tsx +106 -0
  21. package/skills/struq/blocks/kit/MagneticButton.tsx +92 -0
  22. package/skills/struq/blocks/kit/MediaFrame.tsx +96 -0
  23. package/skills/struq/blocks/kit/PinnedZoom.tsx +89 -0
  24. package/skills/struq/blocks/kit/Reveal.tsx +64 -0
  25. package/skills/struq/blocks/kit/SmoothScroll.tsx +57 -0
  26. package/skills/struq/blocks/kit/SplitHeadline.tsx +68 -0
  27. package/skills/struq/blocks/kit/blocks.css +2102 -0
  28. package/skills/struq/blocks/kit/gsap.ts +21 -0
  29. package/skills/struq/blocks/kit/images.ts +17 -0
  30. package/skills/struq/blocks/kit/photo-read.ts +102 -0
  31. package/skills/struq/blocks/kit/scenes/contours.ts +161 -0
  32. package/skills/struq/blocks/kit/scenes/dots.ts +110 -0
  33. package/skills/struq/blocks/kit/scenes/ripple.ts +99 -0
  34. package/skills/struq/blocks/kit/scenes/types.ts +114 -0
  35. package/skills/struq/blocks/page-transitions/page-transition-gate.tsx +706 -0
  36. package/skills/struq/blocks/page-transitions/page-transition-slices.tsx +469 -0
  37. package/skills/struq/blocks/page-transitions/page-transition-stack.tsx +583 -0
  38. package/skills/struq/blocks/preloaders/preloader-gate.tsx +358 -0
  39. package/skills/struq/blocks/preloaders/preloader-slices-uncovered.ts +50 -0
  40. package/skills/struq/blocks/preloaders/preloader-slices.tsx +289 -0
  41. package/skills/struq/blocks/preloaders/preloader-stack.tsx +367 -0
  42. package/skills/struq/blocks/preloaders/preloader-wordmark.tsx +568 -0
  43. package/skills/struq/blocks/sections/about-studio.tsx +436 -0
  44. package/skills/struq/blocks/sections/approach.tsx +661 -0
  45. package/skills/struq/blocks/sections/contact-form.tsx +664 -0
  46. package/skills/struq/blocks/sections/cta-closing.tsx +763 -0
  47. package/skills/struq/blocks/sections/fanned-cards.tsx +547 -0
  48. package/skills/struq/blocks/sections/film-strip.tsx +385 -0
  49. package/skills/struq/blocks/sections/grid-assembly.tsx +616 -0
  50. package/skills/struq/blocks/sections/hover-list.tsx +467 -0
  51. package/skills/struq/blocks/sections/image-trail.tsx +432 -0
  52. package/skills/struq/blocks/sections/manifesto.tsx +691 -0
  53. package/skills/struq/blocks/sections/panel-accordion.tsx +380 -0
  54. package/skills/struq/blocks/sections/reveals.tsx +416 -0
  55. package/skills/struq/blocks/sections/split-pair.tsx +670 -0
  56. package/skills/struq/blocks/sections/sticky-chapters.tsx +256 -0
  57. package/skills/struq/blocks/sections/velocity-type.tsx +269 -0
  58. package/skills/struq/blocks/showpieces/fill-rows.tsx +74 -0
  59. package/skills/struq/blocks/showpieces/hero-opener.tsx +128 -0
  60. package/skills/struq/blocks/showpieces/image-to-fullbleed.tsx +89 -0
  61. package/skills/struq/blocks/showpieces/manifesto-scrub.tsx +48 -0
  62. package/skills/struq/blocks/showpieces/panel-wipe.tsx +89 -0
  63. package/skills/struq/blocks/showpieces/pixel-resolve.tsx +107 -0
  64. package/skills/struq/blocks/showpieces/project-stack.tsx +86 -0
  65. package/skills/struq/blocks/showpieces/scrub-connector.tsx +307 -0
  66. package/skills/struq/blocks/showpieces/wordmark-finale.tsx +105 -0
  67. package/skills/struq/blocks/transitions/zoom-through.tsx +613 -0
  68. package/skills/struq/canon/canon.json +627 -0
  69. package/skills/struq/cinematic/README.md +7 -18
  70. package/skills/struq/cinematic/examples/code/nextjs/app/components/LenisRoot.tsx +1 -1
  71. package/skills/struq/cinematic/examples/code/shared/styles.css +1 -1
  72. package/skills/struq/cinematic/examples/code/vite/src/LenisRoot.tsx +1 -1
  73. package/skills/struq/cinematic/references/01-core-mental-model.md +1 -1
  74. package/skills/struq/cinematic/references/02-vocabulary.md +1 -1
  75. package/skills/struq/cinematic/references/07-stack-integration.md +2 -2
  76. package/skills/struq/recipes/app/fonts.ts +12 -0
  77. package/skills/struq/recipes/app/globals.css +42 -0
  78. package/skills/struq/recipes/app/layout.tsx +30 -0
  79. package/skills/struq/references/craft.md +77 -0
  80. package/skills/struq/references/iconography.md +28 -230
  81. package/skills/struq/references/stack-targets.md +23 -74
  82. package/skills/struq/references/tells.md +52 -0
  83. package/skills/struq/references/triage.md +6 -7
  84. package/skills/struq/scripts/blocks.mjs +156 -0
  85. package/skills/struq/scripts/canon.mjs +134 -0
  86. package/skills/struq/scripts/check.mjs +513 -0
  87. package/skills/struq/scripts/images.mjs +360 -0
  88. package/skills/struq/scripts/log.mjs +75 -0
  89. package/skills/struq/scripts/packs.mjs +156 -0
  90. package/skills/struq/scripts/tokens.mjs +222 -0
  91. package/skills/struq/references/anti-patterns.md +0 -265
  92. package/skills/struq/references/baseline-prompt.md +0 -118
  93. package/skills/struq/references/brand.md +0 -143
  94. package/skills/struq/references/brief-router.md +0 -219
  95. package/skills/struq/references/composition.md +0 -191
  96. package/skills/struq/references/depth-parallax.md +0 -235
  97. package/skills/struq/references/direction.md +0 -188
  98. package/skills/struq/references/feel-layer.md +0 -107
  99. package/skills/struq/references/gsap-api.md +0 -293
  100. package/skills/struq/references/imagery.md +0 -144
  101. package/skills/struq/references/loaders.md +0 -287
  102. package/skills/struq/references/micro-interactions.md +0 -270
  103. package/skills/struq/references/mobile-composition.md +0 -70
  104. package/skills/struq/references/nav-header.md +0 -296
  105. package/skills/struq/references/page-architecture.md +0 -134
  106. package/skills/struq/references/page-entrances.md +0 -198
  107. package/skills/struq/references/performance.md +0 -235
  108. package/skills/struq/references/pinning-scrub.md +0 -341
  109. package/skills/struq/references/pitfalls.md +0 -290
  110. package/skills/struq/references/route-transitions.md +0 -281
  111. package/skills/struq/references/scaling.md +0 -151
  112. package/skills/struq/references/scroll-reveals.md +0 -280
  113. package/skills/struq/references/seo.md +0 -219
  114. package/skills/struq/references/setup.md +0 -397
  115. package/skills/struq/references/showcase.md +0 -87
  116. package/skills/struq/references/struq-imagery.md +0 -107
  117. package/skills/struq/references/svg-motion.md +0 -390
  118. package/skills/struq/references/transitions.md +0 -160
  119. package/skills/struq/references/typography.md +0 -720
  120. package/skills/struq/references/vibe-presets.md +0 -287
  121. package/skills/struq/references/webgl-r3f.md +0 -274
  122. package/skills/struq/references/webgl-scenes.md +0 -593
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  **Award-tier web design for your coding agent.**
4
4
 
5
- Struq is a design skill for Claude Code, Codex, Cursor and OpenCode. Give it a brief and it builds a cinematic, agency-grade site: the kind with large light type, a restrained palette, smooth scroll, masked reveals, a pinned showpiece, full-screen page transitions and, where it earns its place, a 3D moment. It ships the decisions an award-winning studio makes, in the order they make them, on the stack they use.
5
+ Struq is a design skill for Claude Code, Codex, Cursor and OpenCode. Give it a brief and it builds a studio-grade site from Struq's catalogue of admitted blocks: preloaders, page transitions, headers, heroes, WebGL backgrounds, showpieces, sections and footers, each judged against an award-tier reference and shipped as real files with three variants. Your agent picks the direction and the order, writes the copy and joins the blocks; the blocks carry the motion.
6
6
 
7
7
  The icon set the skill uses by default, Struq Icons, is browsable at [struq.nl/iconen](https://struq.nl/iconen).
8
8
 
@@ -26,16 +26,7 @@ It finds the AI tools on your machine and installs the skill into each of them.
26
26
 
27
27
  ## Same brief, with and without Struq
28
28
 
29
- Three briefs, each built twice by the same model with the same materials: once as a plain coding agent, once with `/struq`. An independent reviewer then scored all six sites **blind**, from screenshots only, without knowing which side used the skill.
30
-
31
- | Brief | Without | With Struq | Invented facts (without / with) | Template tells (without / with) |
32
- |---|---|---|---|---|
33
- | Ceramicist portfolio, no logo, no photos | 56 | **79** | 14 / 5 | 6 / 3 |
34
- | E-bike launch, existing brand, wants 3D | 66 | **76** | 11 / 3 | 6 / 3 |
35
- | Open-source dev-tool landing page | 50 | **76** | 11 / 2 | 10 / 2 |
36
- | **Average** | **57** | **77** | **36 / 10** | **22 / 8** |
37
-
38
- Scored out of 100 on typography, composition, color, concept, motion, content honesty, craft and distinctiveness. "Invented facts" counts claims the brief never gave: quotes, bios, stats, specs, API names.
29
+ Three briefs, each built twice by the same model with the same materials: once as a plain coding agent, once with `/struq`.
39
30
 
40
31
  **Dev-tool landing page.** Without: the dark developer-tool template, item for item. With: a light page built around a trace waterfall that assembles as you scroll.
41
32
 
@@ -59,39 +50,34 @@ Where Struq lost points: craft. The plain builds are less ambitious and break le
59
50
 
60
51
  ## What you get
61
52
 
62
- **One recipe, fixed on purpose.** The expensive feel comes from these pieces sharing one animation clock, not from any single effect.
63
-
64
- | Layer | Tooling |
53
+ | Part | What it is |
65
54
  |---|---|
66
- | Typography | Two faces from the Signature pairing set, set through role tokens. Display runs large and light (300 to 400). A fluid scale, one typographic signature move per site, SplitText choreography. |
67
- | Palette | Temperature-shifted neutrals, one accent, light and dark surface ladders |
68
- | Scroll | Lenis on the GSAP ticker, ScrollTrigger scrub, masked reveals, never opacity-only fades |
69
- | Showpieces | 23 named recipes, each tagged showpiece or system: pinned scrub timelines, horizontal galleries, sticky stacks, path journeys, manifesto fills |
70
- | SVG | DrawSVG and MorphSVG: self-drawing marks, logo morphs, scroll-drawn paths |
71
- | Pointer | Magnetic buttons, cursor followers, hover scenes, image distortion |
72
- | Page flow | Full-screen cover, swap and reveal route transitions, session-gated loaders, Radix overlay menus |
73
- | 3D | Three.js, React Three Fiber, Drei and postprocessing as lazy islands with poster fallbacks |
74
- | Direction | A directed mode for full WebGL experiences: chapters, camera shots, handoffs, ownership |
75
-
76
- Stack: Next.js App Router and Tailwind by default, Vite supported. It reads the versions your project has installed and adapts to them; nothing is pinned. Every GSAP plugin used is free on npm. Icons: [Struq Icons](https://struq.nl/iconen) (`@struq/icons`, MIT) by default.
55
+ | Blocks | 44 admitted blocks in `skills/struq/blocks/` ([catalogue](skills/struq/blocks/CATALOG.md)): 4 preloaders, 3 page transitions, 2 headers, 5 heroes, 3 WebGL backgrounds, 9 showpieces, a scene transition, 15 sections and 2 footers, with the kit they stand on. A copy of Struq's own set, refreshed at every release. |
56
+ | Direction | Struq's palettes and type pairings, written as the one token block the blocks read (surface ladder, contrast scenes, the accent's ink) with each face loaded at its real weights. Offline, no account. |
57
+ | Photos | Art-directed CC0 packs from the Struq beeldbank, picked by the brief and filtered to what fits the client. |
58
+ | Craft | The rules that make the blocks feel high end, for the code between them: clips from numbers, whole pixels, decode before show, scroll-tied and reversing, a gate with a 3 s fallback, type on the measured calm side of a photo. |
59
+ | Check | `check.mjs`: the tell list (eyebrows, pills, gradients, glow, mono, Inter, default purple, numbered steps, icon grids, dashes) and what a page owes its blocks. |
60
+ | MCP | With the Struq MCP connected, the same four jobs come from `struq_richting`, `struq_blokken`, `struq_blok` and `struq_controle`. Without it the skill works from its own copy. |
61
+
62
+ Stack: Next.js App Router and Tailwind v4 (Vite by hand, see `references/stack-targets.md`). Every GSAP plugin used is free on npm. Icons: [Struq Icons](https://struq.nl/iconen) (`@struq/icons`, MIT) by default.
77
63
 
78
64
  ## Commands
79
65
 
80
66
  | Command | What it does |
81
67
  |---|---|
82
- | `/struq <brief>` | Plans the site into one `STRUQ.md`, stops once for your veto, builds it, then screenshots it at 390, 768, 1440 and 1920 and fixes what it sees |
83
- | `/struq redesign <path>` | Keeps your brand, copy and components; rebuilds the execution |
84
- | `/struq audit <path-or-url>` | Changes nothing. Returns a score out of 100, every tell with its fix, and the three highest-payoff changes |
68
+ | `/struq <brief>` | Plans the site into one `STRUQ.md`, stops once for your approval, builds it, then runs its own check and, with a browser tool, screenshots it and fixes what it sees |
69
+ | `/struq redesign <path>` | Keeps your brand, copy and components; swaps in blocks where the page is weakest |
70
+ | `/struq audit <path-or-url>` | Changes nothing. Returns every tell with its fix and the three highest-payoff changes |
85
71
  | `/struq direct <brief>` | Directed mode for one continuous 3D experience across chapters |
86
72
 
87
73
  In Codex, use `$struq` instead of `/struq`; as a Claude Code plugin the command is `/struq:struq`.
88
74
 
89
75
  ## How a build runs
90
76
 
91
- 1. **Plan.** It reads your brief and writes one `STRUQ.md`: brand, concept, the two typefaces, palette tokens, icon family, page arc, which showcase recipes go where, the transition system, and whether 3D is warranted. It never invents testimonials or stats.
92
- 2. **One stop.** It shows the summary and asks once: veto anything, and send a logo, photos or real numbers if you have them. Only an empty or vague brief gets a short wizard first.
93
- 3. **Build.** Static layout to the baseline first, at desktop and mobile at once. Motion goes on in layers: reveals, composition, showpieces, text and SVG, pointer, then 3D.
94
- 4. **Look.** Screenshots at four widths, a tell scan, a feel audit and one full scroll. Then it fixes and re-shoots.
77
+ 1. **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 in one `STRUQ.md`. It never invents testimonials or stats.
78
+ 2. **One stop.** It shows the plan and asks once: approve, and send a logo, photos or real numbers if you have them.
79
+ 3. **Blocks.** It installs each block with everything it imports, writes the tokens and fonts, and composes the page with your real copy.
80
+ 4. **Check.** `check.mjs` runs until it passes; with a browser tool it also looks at the page at phone and desktop width and fixes what it sees.
95
81
 
96
82
  ## Install options
97
83
 
@@ -131,10 +117,12 @@ npm install @struq/icons
131
117
 
132
118
  ## What it fetches and sends
133
119
 
134
- Struq is instructions and reference files. It runs no code of its own and collects or sends nothing about you or your project.
120
+ Struq 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 in your project, including a build log (`STRUQ-LOG.md`).
135
121
 
136
- - **Photos, only when your brief has none.** The skill has your agent read the public pack list at `https://struq.nl/api/media/packs` and download the chosen images from `https://struq.nl/media/packs/` into your project. These are plain public requests: no account, no key, and nothing from your project goes with them. The images are CC0.
137
- - **Checks.** The screenshot and performance checks run against your own local dev server, with your agent's own browser tool.
122
+ - **Blocks and canon.** Shipped inside the skill. Nothing is fetched to install a block or write the tokens.
123
+ - **Fonts.** The site links Google Fonts (or Fontshare for a face that lives there) from the visitor's browser, as any site with web fonts does.
124
+ - **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/` into your project. Offline it writes plates graded to your palette instead.
125
+ - **The MCP, if you connect it.** Your agent calls Struq's tools with your brief; nothing else leaves your machine.
138
126
  - **The installer.** `npx @struq/skill@latest` downloads the package from npm, looks for the AI tools' folders in your home folder and copies the skill into them. It sends nothing.
139
127
 
140
128
  ## License
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@struq/skill",
3
- "version": "0.2.2",
3
+ "version": "0.4.0",
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
6
  "author": "Struq (https://struq.nl)",
@@ -35,7 +35,8 @@
35
35
  "node": ">=18"
36
36
  },
37
37
  "scripts": {
38
- "test": "node --test test/install.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",
39
+ "release:blocks": "node scripts/release-blocks.mjs"
39
40
  },
40
41
  "publishConfig": {
41
42
  "access": "public"
@@ -1,237 +1,173 @@
1
1
  ---
2
2
  name: struq
3
- description: "Award-tier web design for coding agents. Builds cinematic, agency-grade marketing sites, landing pages and portfolios at FWA / Awwwards level: two-face typography with light display weights, curated palettes, Lenis smooth scroll on one GSAP clock, SplitText, DrawSVG and MorphSVG, masked reveals, pinned and horizontal showpieces, hover choreography, full-screen route transitions, Radix overlays, and Three.js / R3F / Drei / postprocessing moments. Use when designing, building, redesigning, animating or auditing a marketing or narrative site, or when a page must feel premium, custom, cinematic or award-winning instead of templated. Stack: Next.js App Router + Tailwind v4 or later (Vite supported), versions detected from the project."
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."
4
4
  argument-hint: "[brief] | redesign <path> | audit <path-or-url> | direct <brief>"
5
5
  ---
6
6
 
7
7
  # Struq
8
8
 
9
- The gap between "looks like a template" and "looks like an award-winning agency build" is not talent. It is a finite set of decisions, made in the right order, executed on the right stack. Struq is those decisions. Apply the baseline to **every** build and load reference files only for the techniques the page actually uses.
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.
10
12
 
11
- **Register check.** Struq is for marketing, landing, portfolio and narrative sites: the cinematic, scroll-driven, agency register. For dashboards and product UI, keep the type and surface rules from the baseline, drop Lenis, cinematic durations and showpieces. Density and native scroll win there.
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).
12
16
 
13
- ## Modes
14
-
15
- Read the argument and pick one. State the mode in one line, then work.
17
+ | Invocation | Mode |
18
+ |---|---|
19
+ | `/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. |
21
+ | `/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
+ | `/struq direct <brief>` | One continuous WebGL experience across chapters: steps 1 to 4, then [cinematic/README.md](cinematic/README.md). |
16
23
 
17
- | Invocation | Mode | What happens |
18
- |---|---|---|
19
- | `/struq <brief>` (or no argument) | **Build** | Run the Direction phases into `STRUQ.md`, stop once for a veto, build, verify. |
20
- | `/struq redesign <path>` | **Redesign** | Audit assets and performance, triage the current site ([references/triage.md](references/triage.md)), then Direction with the brand kept, then build. |
21
- | `/struq audit <path-or-url>` | **Audit** | No code changes. Screenshot, run the tell scan and feel audit, return a scored report (see Audit below). |
22
- | `/struq direct <brief>` | **Directed** | One continuous WebGL experience across chapters (persistent stage, camera shots, handoffs). Run Direction phases 0 to 3 into `STRUQ.md`, then enter [cinematic/README.md](cinematic/README.md), which appends its direction to the same file. Use only when the brief is genuinely an "experience", not a site with a 3D hero. |
24
+ For a dashboard or product UI keep the tokens, faces and tells; drop the preloader, Lenis and the pinned pieces.
23
25
 
24
- **Plan everything before the first component.** Build and Redesign always start with [references/direction.md](references/direction.md): intake, brand (name, SVG logo and mark, when there is none), concept (the one idea and its motif), system (two typefaces, palette, icon family, imagery, motion), and the site plan (pages, arc, showpieces, transitions, SEO). It all goes into one file, `STRUQ.md` in the project root, which is the only plan artifact and the contract for the rest of the build. Stop once, at the gate, then build.
26
+ ## Three rules that never bend
25
27
 
26
- **Ask for materials, never invent them.** Use the logo, copy, photos and numbers that exist. With a usable brief, do not stop to ask first: plan with what is there, and put the materials request inside the one gate message ("Veto anything? If you have a logo, photos or real numbers, send them now."). Where something is still missing, write real, specific running copy for the brief and plan imagery from one Struq beeldbank pack ([references/struq-imagery.md](references/struq-imagery.md)) or as graded placeholders ([references/imagery.md](references/imagery.md) §4b). Never lorem, never "Acme", never invented testimonials, logos or stats. Never write in a real person's or brand's voice: no invented bio, process claims, quotes or catalogue facts; anything the layout needs before the real copy arrives is a labelled draft listed under ASSUMPTIONS ([references/direction.md](references/direction.md) §1).
28
+ 1. **Never an empty frame.** Every image slot holds a real photo: the client's, else the beeldbank pack (free, CC0,
29
+ no permission needed). A photo shows the world around the client, never their own room, team or product unless it
30
+ is theirs; captions are written from the alt.
31
+ 2. **Never invent facts.** No testimonials, logos, stats, awards, prices, addresses, hours, bios or quotes the brief
32
+ did not give. Leave them out and list them under Assumptions in STRUQ.md.
33
+ 3. **Never the tells** ([references/tells.md](references/tells.md)): no eyebrows, pills, gradients or gradient text,
34
+ glow, mono on marketing, Inter or the other generator faces, default purple or blue, numbered steps, icon grids,
35
+ stat banners, generic CTAs, em or en dashes.
27
36
 
28
- ## The recipe
37
+ ## The MCP, or the skill's own copy
29
38
 
30
- This is the stack and the layer each tool owns. It is fixed on purpose: the "weighted, expensive" feel comes from these pieces sharing one clock, not from any single effect.
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.
31
41
 
32
- | Layer | Tool | Rule of thumb | Reference |
33
- |---|---|---|---|
34
- | Brand | Name, SVG wordmark and mark, favicon set | Positioning before name; the wordmark is drawn from the display face | [brand.md](references/brand.md) |
35
- | Typography | Signature first: one pairing id (S1 to S7), one display face and one text face, set through role tokens | Display runs **large and light (300 to 400)**. Hierarchy from scale contrast, not weight. One signature move per site. | [typography.md](references/typography.md) |
36
- | Palette | Tokens on `:root` via Tailwind `@theme` (v4 or later) | Temperature-shifted neutrals do 95% of the work, one accent | [vibe-presets.md](references/vibe-presets.md) |
37
- | Scale | One fluid root-rem knob | Everything in rem; breakpoints change layout, never size | [scaling.md](references/scaling.md) |
38
- | Smooth scroll | Lenis, driven by `gsap.ticker` | One requestAnimationFrame for the whole page | [setup.md](references/setup.md), [feel-layer.md](references/feel-layer.md) |
39
- | Scroll motion | GSAP + ScrollTrigger | Scrub for scroll-tied values; masked reveals over fades | [scroll-reveals.md](references/scroll-reveals.md) |
40
- | Text motion | SplitText | Masked line rise, char stagger, scroll color fill | [typography.md](references/typography.md) |
41
- | SVG motion | DrawSVG, MorphSVG, MotionPath | Draw-on-scroll paths, logo morphs, signature marks | [svg-motion.md](references/svg-motion.md) |
42
- | Showpieces | Pinned scrub, horizontal galleries, sticky stacks | One or two per site, placed at act breaks | [showcase.md](references/showcase.md), [pinning-scrub.md](references/pinning-scrub.md) |
43
- | Icons | Struq Icons (`@struq/icons`) by default, after the brand's own set; else Phosphor (light), else Iconoir or Tabler | One icon family per site, never mixed, never Lucide by reflex | [iconography.md](references/iconography.md) |
44
- | Hover and pointer | GSAP `quickTo` (magnetic, cursor), CSS + GSAP hover scenes | Garnish, applied last | [micro-interactions.md](references/micro-interactions.md) |
45
- | React lifecycle | Motion (`motion/react`) | Mount/unmount, `layoutId`, gesture state | GSAP vs Motion below |
46
- | Overlays | Radix primitives (Dialog for menus and modals) | Focus trap, Escape, scroll lock paired with `lenis.stop()` | [nav-header.md](references/nav-header.md) |
47
- | Page flow | Full-screen cover, swap, reveal transitions; session-gated loader | Every route change is a designed moment | [route-transitions.md](references/route-transitions.md), [loaders.md](references/loaders.md) |
48
- | 3D moments | Three.js, R3F, Drei, postprocessing | Lazy island, poster fallback, driven from the same ticker | [webgl-r3f.md](references/webgl-r3f.md), [webgl-scenes.md](references/webgl-scenes.md) |
49
- | Findability | Metadata API, an OG image per route, sitemap, robots, JSON-LD | One h1 per page; loaders and reveals never hide content from the HTML | [seo.md](references/seo.md) |
50
- | Performance | ffmpeg, next/image, gltf-transform, next/font | Assets first: budgets per role, posters always, WebGL never in the first-load bundle | [performance.md](references/performance.md) |
42
+ | Need | MCP connected | Offline |
43
+ |---|---|---|
44
+ | A direction: palette, pairing, photo pack as tokens and fonts | `struq_richting(brief)` (or with `palette`, `type` ids) | `canon.mjs list`, then `canon.mjs palette <id>` and `canon.mjs type <id>`; `images.mjs --brief` |
45
+ | What blocks exist | `struq_blokken(kind?, query?)` | `blocks.mjs list [kind]`, [blocks/CATALOG.md](blocks/CATALOG.md) |
46
+ | A block as files | `struq_blok(slug, variant?)` | `blocks.mjs add <slug>` |
47
+ | The tell check | `struq_controle()`: run its detectors on your own files | `check.mjs` |
51
48
 
52
- Install line and provider wiring: [references/setup.md](references/setup.md). All GSAP plugins are free on npm from GSAP 3.13 on (the minimum version); no token, no club. No other version is assumed: the installed project decides ([references/setup.md](references/setup.md) §0).
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:
51
+ `node <skill-dir>/scripts/log.mjs mcp <tool> --note "<what you took>"`. Run `check.mjs` either way.
53
52
 
54
- ## The baseline (applies to everything)
53
+ ## Build checklist
55
54
 
56
- <!-- CANONICAL: this is the single source of the baseline block. references/baseline-prompt.md carries a standalone copy for pasting into other agents; after editing here, re-copy the block there. -->
55
+ Copy this into `STRUQ.md` under the plan and tick each line as you finish it. Keep `STRUQ-LOG.md` from the first
56
+ step: append only, one entry per step (`node <skill-dir>/scripts/log.mjs "Step N Name" "what" "why"`; the scripts log
57
+ their own). `check.mjs` fails while a line is open or a ticked step has no entry.
57
58
 
58
59
  ```
59
- STRUQ BASELINE: NON-NEGOTIABLES
60
-
61
- TYPE: Signature first: one pairing id from typography.md §3.1 (S1 to S7;
62
- Extended E1 to E6 only when no Signature temperament fits), two faces max.
63
- Never Inter, Roboto, Open Sans, Poppins, Montserrat or Lato; never Space
64
- Grotesk or Geist as a reflex. Scale 1.333 with skipped steps (body 1, lead
65
- 1.25, h3 1.78, h2 3.16, display 7 to 8). Hero h1 = text-display,
66
- clamp(2.875rem, 1.2rem + 6.86vw, 8rem), leading 0.92 to 1.0; S4 and S5 set
67
- larger, S7 smaller (typography.md §3.1). Display runs LIGHT (300 to 400);
68
- heavy display only as a declared genre (the Brutalist appendix), never a
69
- reflex. Tracking per face, never one tracking-tight on every size: sans
70
- display about -0.025 to -0.03em, serif display about -0.01 to -0.025em, h2
71
- about half that. Body 1rem to 1.0625rem at 400, leading 1.6+, 55 to 75ch;
72
- emphasis 500, never 700. Hierarchy from scale contrast, not medium sizes.
73
- ROLES: every string takes a role token, never text-xs, text-lg or text-5xl:
74
- font-display text-display, font-display text-h2, type-h3 text-h3,
75
- text-lead, text-body, text-small, eyebrow text-eyebrow, font-ui text-ui,
76
- stat text-stat, and font-display text-statement for the one Orient line
77
- or manifesto. Eyebrows: uppercase 0.75rem (the 12px floor), tracked 0.12
78
- to 0.18em per face, ink-muted, one per section, never ink-faint.
79
- FLOOR: body at least 1rem, muted at least 0.875rem, nothing under 12px.
80
- CONTRAST: body at least 4.5:1, large text at least 3:1. ink-faint is never
81
- text: hairlines and disabled states only.
82
- SIGNATURE: every STRUQ.md declares one typographic signature move
83
- (typography.md §5: weight-in, soft-scrub, type-mask-media,
84
- fit-width-wordmark, a cropped display). The masked line rise is a
85
- technique, not the default hero. Mono only for literal code. Headings get
86
- text-wrap: balance; body gets text-wrap: pretty.
87
-
88
- SPACING: Base-8 rhythm with deliberate asymmetry. Section padding varies by
89
- role: hero 12 to 20rem, dense content 6 to 8rem, breathers 16 to 24rem. NEVER
90
- uniform py-16 on every section. Whitespace is a material: at least one section
91
- should feel "too empty" by SaaS standards.
92
-
93
- SCALING: One fluid root-rem knob, not per-breakpoint size ladders:
94
- html { font-size: clamp(1rem, 0.92rem + 0.2vw, 1.125rem); }
95
- 16px at 390, about 17.6px at 1440, frozen at 18px from about 1640. Every
96
- clamp() keeps a rem term in its middle so zoom works; a vw-only middle is a
97
- bug. Author everything in rem; px only for 1px hairlines. Breakpoints change
98
- LAYOUT (columns, stack or row), never size. Display roles carry their own
99
- clamp() on top.
100
-
101
- SURFACE: Elevation is a tonal step, not a drop shadow. Dark mode: each layer
102
- steps LIGHTER (#0A0A0B, #111113, #19191C, #232328). Light mode: pick one
103
- direction and keep it (panels a shade deeper than a toned page, or white lifted
104
- off a toned page). Hairline borders about 8 to 12% off the surface; in light
105
- mode a border is the ink at low alpha (rgb(<ink> / 0.08 to 0.14)), never a
106
- flat gray hex. Shadows only for true floating elements, then large, soft and faint
107
- (0 24px 80px -12px rgb(0 0 0 / 0.4)). Never shadow-md or shadow-lg.
108
-
109
- COLOR: One accent, used sparingly (links, the key CTA, one highlight per
110
- viewport). Neutrals are temperature-shifted (warm cream and off-black, or cool
111
- charcoal), never pure #FFF and #000 with gray-500 text. A second accent is a
112
- declared genre choice with its own token and the same budget. No blue to
113
- purple gradients, no gradient text, no glassmorphism cards.
114
-
115
- MOTION: Lenis smooth scroll (lerp 0.09 to 0.11) on one gsap.ticker clock,
116
- unless the genre calls for native scroll. Every entrance animates opacity AND
117
- transform (y 24 to 80px, or a clip or overflow mask). Opacity-only fades are
118
- forbidden. Stagger siblings 0.06 to 0.1s. Durations: micro 0.2 to 0.3s,
119
- standard UI 0.3 to 0.6s, reveals 0.6 to 1.0s, hero and cinematic 1.0 to 1.6s;
120
- exits run about 60% of their entrance. Eases: entrances expo-out
121
- cubic-bezier(0.16, 1, 0.3, 1) (expo.out); exits power2.in; position swaps
122
- quart-in-out cubic-bezier(0.76, 0, 0.24, 1) (power3.inOut); curtains and
123
- panels quint-in-out cubic-bezier(0.83, 0, 0.17, 1) (power4.inOut). Never
124
- default ease-in-out everywhere.
125
- Scroll-tied effects scrub; they do not fire time-based tweens at a threshold.
126
- prefers-reduced-motion: gate transforms, keep opacity.
127
-
128
- COMPOSITION: Break the grid at least twice per page: an image bleeding off
129
- the viewport, an element overlapping two sections, oversized type running off
130
- canvas, a sticky element. No three identical icon cards in a row. Vary section
131
- layout: after a 50/50 split comes full-bleed or an asymmetric 1/3 and 2/3.
132
- Icons: ONE coherent family chosen for the brand, one stroke and size,
133
- ink-colored. Never emoji, never the AI-cliche icons (Sparkles, Rocket, Zap),
134
- never icons in colored chips. Animated icons run under 500ms on click and
135
- never loop in standard UI.
136
-
137
- DETAILS THAT SELL IT: Real running copy. Tracked uppercase eyebrows as
138
- wayfinding, not 01/02/03 stamped on every section (one deliberate oversized
139
- numeral is fine). The footer is designed as hard as the hero. Custom
140
- ::selection color. Visible, designed focus-visible states. Every route change
141
- is a designed transition, not a hard cut.
60
+ ## Build checklist
61
+ - [ ] 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
63
+ - [ ] 3 Canon: the token block and fonts written (canon.mjs palette and type, or struq_richting)
64
+ - [ ] 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
66
+ - [ ] 6 Build: npm run build passes
67
+ - [ ] 7 Look: 390 and 1440 screenshots and one full scroll, fixes made (or "Verify: not seen, no browser")
68
+ - [ ] 8 Check: check.mjs prints RESULT: PASS
142
69
  ```
143
70
 
144
- Why each rule earns its place: [references/baseline-prompt.md](references/baseline-prompt.md).
145
-
146
- ## Leverage ranking: spend effort in this order
147
-
148
- Ordered by visual payoff divided by implementation cost. Do 1 to 7 on every build; 8 to 13 when the page calls for them.
149
-
150
- 1. **Page architecture.** Which sections exist, in what order, and where the showpiece sits. Free, and it decides everything downstream. A perfect section inside a template arc still reads as a template. [references/page-architecture.md](references/page-architecture.md)
151
- 2. **Typography.** The Signature pairing, the light display weight, the role tokens, the eyebrow system, the one signature move. This is 70% of "looks designed". Set the root-rem knob ([references/scaling.md](references/scaling.md)) first, then the type system ([references/typography.md](references/typography.md)).
152
- 3. **Palette and surfaces.** Kills the "Tailwind default" look instantly. [references/vibe-presets.md](references/vibe-presets.md)
153
- 4. **Masked, staggered scroll reveals.** The single highest-payoff motion technique, including the curtain section reveal. [references/scroll-reveals.md](references/scroll-reveals.md)
154
- 5. **The feel layer.** Lenis lerp, scrub smoothing, ease selection. Wrong values make good techniques feel cheap. [references/feel-layer.md](references/feel-layer.md)
155
- 6. **Nav and header.** On screen for the whole session; the fullscreen menu is often the most art-directed moment on the site. [references/nav-header.md](references/nav-header.md)
156
- 7. **Imagery and art direction.** One grade, declared ratios, treated assets. Ungraded mixed stock undoes everything above it. [references/imagery.md](references/imagery.md). No photos of their own? Struq's beeldbank comes before stock: [references/struq-imagery.md](references/struq-imagery.md)
157
- 8. **Composition: overlap, bleed, z-choreography.** [references/composition.md](references/composition.md), and how each technique translates at 360 to 430px: [references/mobile-composition.md](references/mobile-composition.md)
158
- 9. **Showpieces.** Pinned scrub timelines, horizontal galleries, sticky stacks, path journeys. High cost; one or two per site at act breaks. Pick by id from [references/showcase.md](references/showcase.md).
159
- 10. **Page flow.** Full-screen route transitions ([references/route-transitions.md](references/route-transitions.md)), a session-gated first-load loader ([references/loaders.md](references/loaders.md)), per-zone entrances ([references/page-entrances.md](references/page-entrances.md)), section curtains and match cuts ([references/transitions.md](references/transitions.md)). Loader invariant: the pre-paint revisit gate and the live animation phase are separate state machines. A persistent `seen` flag must never hide a curtain that is still playing.
160
- 11. **Text and SVG choreography.** SplitText beyond the line reveal, DrawSVG, MorphSVG. [references/typography.md](references/typography.md), [references/svg-motion.md](references/svg-motion.md)
161
- 12. **Hover and pointer.** Magnetic buttons, cursor followers, hover scenes. Garnish, not the meal. [references/micro-interactions.md](references/micro-interactions.md)
162
- 13. **WebGL moments.** Highest cost of all; only when a section genuinely calls for it. Integration first ([references/webgl-r3f.md](references/webgl-r3f.md)), then Drei, postprocessing and interaction ([references/webgl-scenes.md](references/webgl-scenes.md)). If the whole page is one 3D experience, switch to Directed mode.
163
-
164
- Before and after pairs for every category, the cheap reflex against the agency version: [references/anti-patterns.md](references/anti-patterns.md). **If output drifts generic, read that file first.**
71
+ **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/`.
165
76
 
166
- **Something looks wrong in motion?** Read [references/pitfalls.md](references/pitfalls.md) first, before changing any code: the symptom-first bug clinic for the bugs that recur on every GSAP build: clipped descenders, jarring or jumping pins, content stuck invisible after a reveal, utilities that vanish on animated elements, entrances that fire before the image paints. Each entry gives the cause, the fix and the check.
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:
167
84
 
168
- **The page will not scroll at all?** It is one of exactly two bugs. Either nothing drives `lenis.raf()` because the ticker wiring lost a race with the `<ReactLenis>` ref, or an overlay left an unbalanced `lenis.stop()`. Check the `<html>` class list for `lenis-stopped` first; that one glance tells you which. Both fixes are in [references/setup.md](references/setup.md) §2 and §2b. Do not start "fixing" CSS overflow. A pinned section that jerks on engage is almost always `anticipatePin` with smooth scroll: [references/pinning-scrub.md](references/pinning-scrub.md) §2.
169
-
170
- ## AI-default blocklist
171
-
172
- These scream "generated". Never ship them:
173
-
174
- - A three-column grid of identical `rounded-xl border shadow-sm` cards with a centered icon, an h3 and two lines of gray text
175
- - Blue to purple (or teal to violet) gradients on backgrounds, buttons or `bg-clip-text` headlines
176
- - Uniform `py-16` or `py-24` on every section, where every section is a centered h2, a subhead and a grid
177
- - Off-list faces: Inter, Roboto, Open Sans, Poppins or Montserrat (or Lato, or the system stack) for everything, or Space Grotesk or Geist as the reflex "technical" face, instead of a Signature pairing
178
- - Bold 700 display headlines, five medium heading sizes, one `tracking-tight` on every size, ad-hoc `text-xs uppercase tracking-[...]` eyebrows instead of the role tokens
179
- - `text-ink-faint` on any text
180
- - `shadow-md` or `shadow-lg` as the elevation system on gray-50 cards
181
- - Opacity-only fade-ins, all fired at once, with default `ease-in-out` and `duration-300`
182
- - `bg-white` page, `text-gray-500` body, `border-gray-200` everywhere
183
- - Emoji as icons, the cliche trio (Sparkles, Rocket, Zap) as decoration, icons in colored circles
184
- - Monospace as decoration on eyebrows, labels, stats or badges
185
- - `01 / 02 / 03` stamped on every section or row
186
- - Hero = centered h1, subhead, two buttons and a dashboard screenshot in browser chrome
187
- - Untreated mixed-grade stock at random ratios, glossy AI-render blobs, floating purple spheres
188
- - `backdrop-blur` glass cards on a mesh-gradient background
189
- - Hard cuts between routes on a multi-page site
190
- - Lorem ipsum, "John Doe", "Acme Inc.", "Your journey starts here"
191
-
192
- ## GSAP vs Motion: the decision rule
193
-
194
- Both are installed. Never animate the same property on the same element with both, and never with GSAP and a CSS `transition` either: one owner per property per element ([references/pitfalls.md](references/pitfalls.md) §3). **GSAP owns everything that runs every frame or is tied to scroll; Motion owns React lifecycle, layout and gesture state.** The reason is the single clock: the whole build runs on one requestAnimationFrame (Lenis driven by `gsap.ticker`, [references/setup.md](references/setup.md) §2). High-frequency pointer work belongs on that same ticker via `quickTo`. Pushing it onto a competing spring loop is exactly what makes good motion feel subtly off.
85
+ ```
86
+ # STRUQ.md: <name>
87
+ Brief: <one line: what, for whom, where>
88
+ Idea: <the one idea the site is about>
89
+ Palette: <id> (<mood>)
90
+ Type: <pairing id>: <display> + <body>
91
+ Images: pack <slug> (or the client's photos, then pack <slug>)
92
+ Order: <block slug:variant>, <block slug:variant>, ...
93
+ Assumptions: <every drafted line and every fact left out>
94
+ Verify: <filled in at step 7>
95
+ ```
195
96
 
196
- | GSAP + ScrollTrigger | Motion |
197
- |---|---|
198
- | Anything scroll-tied: scrub, pins, parallax, reveals | Mount and unmount (`AnimatePresence`) |
199
- | Multi-step timelines and orchestration | Layout and shared-element swaps from React state (`layout`, `layoutId`) |
200
- | SplitText, DrawSVG, MorphSVG, MotionPath | `whileHover`, `whileTap`, one-off `whileInView` |
201
- | Flip morphs that coordinate with scroll or a timeline | Press and toggle micro-feedback |
202
- | Magnetic buttons, custom cursor (`quickTo`) | Local stateful overlays that are not part of a timeline |
203
- | Horizontal scroll, sticky stacks, R3F uniforms from scroll | |
204
-
205
- **Before writing any Flip,** read [references/gsap-api.md](references/gsap-api.md) §7.1 to 7.4. Flip has four failure modes that compound and that no typecheck catches. Flip is verified by watching it, never by a green build.
206
-
207
- ## Workflow (Build and Redesign)
208
-
209
- These step names are the one numbering scheme; [references/brief-router.md](references/brief-router.md) §4 keys its load manifest to them.
210
-
211
- 0. **Detect versions.** Scaffold with `@latest` if the folder is empty, then read the installed `package.json` and record the majors on the `Stack:` line. When unsure of an API, check the installed package's types, `npm view <pkg> version` and the official docs for that major. **When the skill's code disagrees with the installed version's types or docs, the installed version wins:** adapt the code and log the adaptation under LOG in STRUQ.md. Strip the scaffold's starter fonts, page and CSS. The known shifts and how to tell which side a project is on: [references/setup.md](references/setup.md) §0.
212
- 1. **Direction.** Run [references/direction.md](references/direction.md) phases 0 to 4: intake (the brief extracted silently, stack detected and recorded as `Stack:`), brand ([references/brand.md](references/brand.md) when there is none), concept, system, and the site plan via [references/brief-router.md](references/brief-router.md) §2. No usable brief? The router's wizard asks at most three plain-language rounds; that is the only early stop. Write `STRUQ.md`, then send the one gate message: summary, materials request, "Veto anything?" Vite? Every later step translates through [references/stack-targets.md](references/stack-targets.md). Redesigning? First run the asset audit in [references/performance.md](references/performance.md) §2 and read [references/triage.md](references/triage.md).
213
- 2. **Brand files and tokens.** Write the logo, mark and favicon set ([references/brand.md](references/brand.md) §5). Set the root-rem knob, the type system ([references/typography.md](references/typography.md)) and the palette tokens exactly as STRUQ.md records them.
214
- 3. **Structure and SEO.** Routes, metadata, sitemap, robots and JSON-LD from the PLAN's page list ([references/seo.md](references/seo.md)), before any section is styled. Then, with the routes in place, the OG image per shared route ([references/seo.md](references/seo.md) §3).
215
- 4. **Wire providers.** Lenis on the GSAP ticker with the reduced-motion guard ([references/setup.md](references/setup.md)). For multi-page sites, the transition provider ([references/route-transitions.md](references/route-transitions.md)) and optionally a loader ([references/loaders.md](references/loaders.md)).
216
- 5. **Static layout.** Authored in rem, designed at 1440 and 390 at the same time, and checked at 768 wherever a breakpoint changes the column count ([references/mobile-composition.md](references/mobile-composition.md) §4). Type, spacing and surfaces right **before any motion**; motion cannot rescue a flat layout. Nav per [references/nav-header.md](references/nav-header.md), icons per [references/iconography.md](references/iconography.md).
217
- 6. **Motion in layers.** Reveals, then composition, then the one or two showpieces, then text and SVG choreography, then hover and pointer. WebGL last, as a lazy island with a poster. Read [references/pitfalls.md](references/pitfalls.md) before the first tween.
218
- 7. **Optimize and sweep.** Every asset through the budgets in [references/performance.md](references/performance.md); then [references/anti-patterns.md](references/anti-patterns.md) as a checklist and the [references/seo.md](references/seo.md) checklist.
219
- 8. **Verify.** Against a production server only: `next build && next start` (or `vite build && vite preview`), never the dev server, and confirm the port you shoot is owned by that production process (a leftover dev server on the same port answers silently). Then:
220
- - **Layout:** screenshot at **390, 768, 1440 and 1920** with whatever browser tool the harness has (Playwright or similar). Full-page shots do not show a fixed footer-reveal (the viewport becomes the document height); verify the close from the scroll pass.
221
- - **Scans:** the 30-second tell scan ([references/anti-patterns.md](references/anti-patterns.md)) and the 60-second feel audit ([references/feel-layer.md](references/feel-layer.md) §5) against the screenshots, not the code.
222
- - **Motion:** scroll the page end to end with motion on: no dead wheel, no flash on route change, and **every pinned section** engaged and released at a slow and a fast scroll with no jump or snap. Run the descender test ("Gyp, jq." in every masked component at 390 and 1440) and the pin checks in [references/pitfalls.md](references/pitfalls.md) §1 and §2.
223
- - **No empty regions:** ambitious motion loses to plain pages when a reveal leaves a region blank. Capture a full page with reduced motion, a full page with JavaScript off, and the scroll sequence after each reveal settles; any blank footer, frame, CTA or row that should hold content fails verify ([references/pitfalls.md](references/pitfalls.md) §3.6, §3.7).
224
- - **Timing:** static PNGs cannot show timing bugs. Take a frame trace of the first 3 seconds (a screenshot every 200 to 250ms from navigation) and confirm each entrance does what its recipe says: the hold frame of a match cut is the photo, a split hero is never shown unsplit, nothing stays at opacity 0.
225
- - **Vitals:** LCP (with the element it names) and CLS from an in-page `PerformanceObserver` probe under 4x CPU and a throttled network, plus INP from field data or a manual interaction trace, and the first-load JS measured from the served HTML (Turbopack prints no table). Port check, probe, trace and first-load scripts: [references/performance.md](references/performance.md) §8.
226
- Fix, re-shoot, and write the score under VERIFY in STRUQ.md.
227
-
228
- ## Audit
229
-
230
- `/struq audit` changes nothing. It returns:
231
-
232
- 1. **Score out of 100**, starting at 100: minus 5 per blocklist tell found, minus 3 per baseline violation (type, spacing, surface, color, motion, composition), minus 10 if the page fails to scroll smoothly or a pin jerks, minus 10 if there is no designed mobile layout, minus 5 per asset over budget ([references/performance.md](references/performance.md) §1, capped at minus 15), minus 5 if social images, the sitemap or page metadata are missing ([references/seo.md](references/seo.md)).
233
- 2. **The tells**, grouped by category, each with the file and line (or screenshot region) and the one-line fix.
234
- 3. **Feel audit** result from [references/feel-layer.md](references/feel-layer.md) §5.
235
- 4. **The three changes with the most visual payoff**, ordered by the leverage ranking above.
236
-
237
- Keep the score honest. An award-tier page lands at 90+; a typical AI-generated page lands under 50.
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`).
151
+
152
+ ## What makes it feel high end
153
+
154
+ The blocks hold this already; your glue must too. Detail in [references/craft.md](references/craft.md).
155
+
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.
158
+ - Scroll effects are scroll-tied and reverse when the visitor scrolls back; key frames hold.
159
+ - The gate: `sq-js` on `<html>` before paint hides only what will animate, and shows it anyway after 3 s.
160
+ - 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`.
163
+ - Tokens only, mixes in oklab, a surface step and a hairline instead of a shadow, one accent.
164
+ - Icons: Struq Icons (`@struq/icons`), functional only ([references/iconography.md](references/iconography.md)).
165
+
166
+ ## When something goes wrong
167
+
168
+ - **Nothing scrolls:** an overlay called `getLenis()?.stop()` without `start()`, or `SmoothScroll` is not mounted.
169
+ - **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`.
172
+ - **A fitted line overflows or jumps:** the face did not load (check `app/fonts.ts` and the links in the layout).
173
+ - **Vite:** [references/stack-targets.md](references/stack-targets.md).