@struq/skill 0.5.1 → 0.5.3

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 (65) hide show
  1. package/README.md +137 -100
  2. package/package.json +5 -3
  3. package/skills/struq/SKILL.md +168 -165
  4. package/skills/struq/blocks/CATALOG.md +49 -46
  5. package/skills/struq/blocks/backgrounds/background-aurora.tsx +2 -1
  6. package/skills/struq/blocks/backgrounds/background-facets.tsx +5 -3
  7. package/skills/struq/blocks/backgrounds/background-silk.tsx +6 -2
  8. package/skills/struq/blocks/catalog.json +50 -5
  9. package/skills/struq/blocks/film.json +11 -7
  10. package/skills/struq/blocks/footers/footer-contact.tsx +8 -78
  11. package/skills/struq/blocks/headers/header-bar.tsx +144 -29
  12. package/skills/struq/blocks/headers/menu-curtain.tsx +36 -19
  13. package/skills/struq/blocks/heroes/hero-poster.tsx +36 -10
  14. package/skills/struq/blocks/kit/HeroCanvas.tsx +6 -2
  15. package/skills/struq/blocks/kit/SplitHeadline.tsx +2 -1
  16. package/skills/struq/blocks/kit/accent.ts +29 -3
  17. package/skills/struq/blocks/kit/blocks.css +530 -6
  18. package/skills/struq/blocks/kit/feel.ts +183 -0
  19. package/skills/struq/blocks/kit/gsap.ts +9 -6
  20. package/skills/struq/blocks/kit/middle/PlaceHours.tsx +254 -0
  21. package/skills/struq/blocks/kit/middle/ProcessStrip.tsx +428 -0
  22. package/skills/struq/blocks/kit/middle/ServicesList.tsx +496 -0
  23. package/skills/struq/blocks/kit/middle/entrance.ts +98 -0
  24. package/skills/struq/blocks/kit/middle/hours.ts +154 -0
  25. package/skills/struq/blocks/kit/middle/index.ts +14 -0
  26. package/skills/struq/blocks/kit/motion/HoverLink.tsx +33 -0
  27. package/skills/struq/blocks/kit/motion/ImageCurtain.tsx +79 -0
  28. package/skills/struq/blocks/kit/motion/MaskWipe.tsx +91 -0
  29. package/skills/struq/blocks/kit/motion/Pressable.tsx +58 -0
  30. package/skills/struq/blocks/kit/motion/RevealText.tsx +103 -0
  31. package/skills/struq/blocks/kit/motion/Rise.tsx +77 -0
  32. package/skills/struq/blocks/kit/motion/ScrubLine.tsx +108 -0
  33. package/skills/struq/blocks/kit/motion/index.ts +11 -0
  34. package/skills/struq/blocks/kit/quiet/Close.tsx +178 -52
  35. package/skills/struq/blocks/kit/quiet/Statement.tsx +3 -2
  36. package/skills/struq/blocks/kit/subject/AppScreen.tsx +388 -0
  37. package/skills/struq/blocks/kit/subject/Document.tsx +742 -0
  38. package/skills/struq/blocks/kit/subject/Mark.tsx +44 -0
  39. package/skills/struq/blocks/kit/subject/PatternPaper.tsx +410 -0
  40. package/skills/struq/blocks/kit/subject/SectionDrawing.tsx +349 -0
  41. package/skills/struq/blocks/kit/subject/Ticket.tsx +354 -0
  42. package/skills/struq/blocks/kit/subject/build.ts +66 -0
  43. package/skills/struq/blocks/kit/subject/draw.ts +196 -0
  44. package/skills/struq/blocks/kit/subject/drawings.ts +373 -0
  45. package/skills/struq/blocks/kit/subject/format.ts +122 -0
  46. package/skills/struq/blocks/kit/subject/index.ts +11 -0
  47. package/skills/struq/blocks/kit/subject/patterns.ts +204 -0
  48. package/skills/struq/blocks/preloaders/preloader-stack.tsx +75 -22
  49. package/skills/struq/blocks/showpieces/hero-opener.tsx +55 -7
  50. package/skills/struq/blocks/showpieces/image-to-fullbleed.tsx +64 -6
  51. package/skills/struq/blocks/showpieces/manifesto-scrub.tsx +56 -3
  52. package/skills/struq/blocks/showpieces/panel-wipe.tsx +93 -11
  53. package/skills/struq/blocks/showpieces/wordmark-finale.tsx +38 -5
  54. package/skills/struq/canon/canon.json +1 -1
  55. package/skills/struq/references/art-direction.md +51 -0
  56. package/skills/struq/scripts/blocks.mjs +56 -20
  57. package/skills/struq/scripts/canon.mjs +36 -7
  58. package/skills/struq/scripts/check.mjs +417 -11
  59. package/skills/struq/scripts/draw.mjs +49 -0
  60. package/skills/struq/scripts/film-check.mjs +28 -4
  61. package/skills/struq/scripts/gate.mjs +13 -3
  62. package/skills/struq/scripts/hand.mjs +222 -0
  63. package/skills/struq/scripts/images.mjs +12 -3
  64. package/skills/struq/scripts/look.mjs +1184 -0
  65. package/skills/struq/scripts/stamp.mjs +47 -0
@@ -6,51 +6,58 @@ argument-hint: "[brief] | redesign <path> | audit <path-or-url> | direct <brief>
6
6
 
7
7
  # Struq
8
8
 
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).
9
+ You are the director. Struq gives you a catalogue of studio-grade blocks ([blocks/CATALOG.md](blocks/CATALOG.md)),
10
+ a canon of palettes and pairings, a photo library and a self-check. They are a toolbox, not a menu: the site should
11
+ look like it could only belong to this one client, and like nothing Struq built before. `<skill-dir>` is this file's
12
+ folder. Worked treatments: [references/film.md](references/film.md); craft: [references/craft.md](references/craft.md).
13
13
 
14
14
  | Invocation | Mode |
15
15
  |---|---|
16
- | `/struq <brief>` | **Build**: the checklist below, start to finish. |
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. |
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. |
19
- | `/struq direct <brief>` | One continuous WebGL experience across chapters: steps 1 to 4, then [cinematic/README.md](cinematic/README.md). |
16
+ | `/struq <brief>` | **Build**: the checklist below. |
17
+ | `/struq redesign <path>` | Keep brand, copy and components ([references/triage.md](references/triage.md)); write the treatment of the page as it will be, stop once, then swap in blocks where it is weakest and run the checklist from step 3. |
18
+ | `/struq audit <path-or-url>` | Change nothing. Run `check.mjs` (or `struq_controle`), report every FAIL and WARN and the three fixes with the most payoff. Never a score. |
19
+ | `/struq direct <brief>` | One continuous WebGL experience: steps 1 to 4, then [cinematic/README.md](cinematic/README.md). |
20
20
 
21
- For a dashboard or product UI keep the tokens, faces and tells; drop the preloader, Lenis and the pinned pieces.
22
-
23
- ## Three rules that never bend
21
+ ## Rules that never bend
24
22
 
25
23
  1. **Never an empty frame.** Every image slot holds a real photo: the client's, else the beeldbank pack (free, CC0,
26
- no permission needed). A photo shows the world around the client, never their own room, team or product unless it
27
- is theirs; captions are written from the alt.
28
- 2. **Never invent facts.** No testimonials, logos, stats, awards, prices, addresses, hours, bios or quotes the brief
29
- did not give. Leave them out and list them under Assumptions in STRUQ.md.
24
+ no permission needed). Pack photos are mood: the world around the client, never their own room, team, work or
25
+ product. So never set one under a first-person claim ("our oven", "every piece we make", "my plates"), and where
26
+ the work is the product (a portfolio, a shop, a collection) build the frame for their work and ask for it at the
27
+ stop. A caption is copy you write for this client, never the alt read back.
28
+ 2. **Never invent, never stand in.** No testimonials, logos, stats, awards, prices, addresses, hours, bios, quotes,
29
+ product features, programme, process, equipment (a wood oven) or name the brief did not give. A missing fact
30
+ leaves no trace: no "to follow", "to be announced", "Your Name", example.com, and no button for an action with no
31
+ real destination (shop, booking, contact, sign-up), no "come by" without the address. Drop the line, the field or
32
+ the button and list it under
33
+ Assumptions in STRUQ.md. With no door (no address, phone, mail, booking or shop link from the brief or the stop) the
34
+ site ends on the idea, never on an invitation: no "Schuif aan", "Pick up a mug", "Book a class" or "Shop the
35
+ collection", and Assumptions names the door the client must add. With no name in the brief the header shows no
36
+ wordmark and the opener and the close carry none (or ask for the name at the one stop); the trade word ("Yoga",
37
+ "Bakery") is never a name. The self-check fails stand-ins, links to anchors that do not exist, calls with no door
38
+ and a trade word as the name.
30
39
  3. **Never the tells** ([references/tells.md](references/tells.md)): no eyebrows, pills, gradients or gradient text,
31
40
  glow, mono on marketing, Inter or the other generator faces, default purple or blue, numbered steps, icon grids,
32
41
  stat banners, generic CTAs, em or en dashes.
42
+ 4. **Copy in the client's market language**, which may differ from the brief's (a plumber in Utrecht reads Dutch).
43
+ Say which on the Brief line and under Assumptions. Write it as a native copywriter would, never a translation.
33
44
 
34
- ## The MCP, or the skill's own copy
35
-
36
- Same blocks, same derivation: use the MCP tool when it is connected, else the offline column from the skill's copy.
45
+ ## Tools: the MCP, or the skill's own copy
37
46
 
38
47
  | Need | MCP connected | Offline |
39
48
  |---|---|---|
40
- | 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` |
41
- | What blocks exist | `struq_blokken(kind?, query?)` | `blocks.mjs list [kind]`, [blocks/CATALOG.md](blocks/CATALOG.md) |
49
+ | Palette, pairing, photo pack as tokens and fonts | `struq_richting(brief)` | `canon.mjs draw` (this site's hand), `canon.mjs palette <id>`, `canon.mjs type <id>`; `images.mjs --brief` |
50
+ | What blocks exist | `struq_blokken(kind?, query?)` | `blocks.mjs list [kind]` |
42
51
  | A block as files | `struq_blok(slug, variant?)` | `blocks.mjs add <slug>` |
43
- | The tell check | `struq_controle()`: run its detectors on your own files | `check.mjs` |
52
+ | The self-check | `struq_controle()` | `check.mjs` |
44
53
 
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:
47
- `node <skill-dir>/scripts/log.mjs mcp <tool> --note "<what you took>"`. Run `check.mjs` either way.
54
+ Log each MCP call: `node <skill-dir>/scripts/log.mjs mcp <tool> --note "<what you took>"`.
48
55
 
49
56
  ## Build checklist
50
57
 
51
- Copy this into `STRUQ.md` under the plan and tick each line as you finish it. Keep `STRUQ-LOG.md` from the first
52
- step: append only, one entry per step (`node <skill-dir>/scripts/log.mjs "Step N Name" "what" "why"`; the scripts log
53
- their own). `check.mjs` fails while a line is open or a ticked step has no entry.
58
+ Copy this into `STRUQ.md` under the plan and tick each line when done. Log every step in `STRUQ-LOG.md`
59
+ (`node <skill-dir>/scripts/log.mjs "Step N Name" "what" "why"`); `check.mjs` fails while a line is open or a ticked
60
+ step has no entry.
54
61
 
55
62
  ```
56
63
  ## Build checklist
@@ -60,170 +67,166 @@ their own). `check.mjs` fails while a line is open or a ticked step has no entry
60
67
  - [ ] 4 Images: images.mjs --brief printed OK; only photos whose alt fits the client
61
68
  - [ ] 5 Scenes: frames and the centerpiece installed, every other scene built as the storyboard says, composed in app/page.tsx with real copy
62
69
  - [ ] 6 Build: npm run build passes
63
- - [ ] 7 Look: 390 and 1440 screenshots and one full scroll, fixes made (or "Verify: not seen, no browser")
70
+ - [ ] 7 Look: LOOK: PASS on the served build, its screenshots read; a fresh subagent's asks in .struq/art-direction.md each answered Built: or Refused:, then LOOK: PASS again
64
71
  - [ ] 8 Check: check.mjs prints RESULT: PASS
65
72
  ```
66
73
 
67
- **1 Project.** Empty folder: `npx create-next-app@latest . --ts --tailwind --app --eslint --yes`, then
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):
74
+ **1 Project.** `npx create-next-app@latest . --ts --tailwind --app --eslint --yes`, then
75
+ `node <skill-dir>/scripts/blocks.mjs init` (the kit, layout, tokens, fonts, gsap and lenis; it never overwrites your
76
+ files, merge from `recipes/app/`).
77
+
78
+ **2 Treatment, then stop once.** Think like a studio pitching this client. First run
79
+ `node <skill-dir>/scripts/canon.mjs draw`: it deals this site a hand, two languages, two type pairings, two
80
+ palettes (one light, one dark) and three lenses, the way a creative director hands a team its constraints. Every site gets a different hand,
81
+ so no two start from the same place; your craft is choosing well within it. Write three ideas, one from each lens
82
+ (each a point of view on this client, not a description), take the one a rival studio would least expect that still
83
+ fits this client, and note the other two as Passed over. Name the Subject: what the brief is about
84
+ that a visitor must see (the app, the event, the garment, the cup, the bread); the site shows it (step 5). Then
85
+ the Unlike line: the site any agent would build, and Struq's own reflexes, which you must also avoid (a framed photo
86
+ with the name small beside it; one italic word in every headline; a middle of one-word rows, a sentence with a small
87
+ photo and a photo beside text; an echo close over a full-width wordmark). Pick the language from the hand, run
88
+ `node <skill-dir>/scripts/blocks.mjs arc <language>`, and cast every line of the storyboard it prints, each pick with
89
+ its reason after "because": the Opening and the Centerpiece from the five each it deals (look at the photos first,
90
+ step 4), the middle scenes named and designed for this client, the close ending where the idea ends. Invent own scenes wherever the
91
+ idea wants a moment no block gives. Outside the hand only what the client gave: their brand colours or faces, marked
92
+ `(brand)`, or a block they named, marked `(named)`.
81
93
 
82
94
  ```
83
95
  # STRUQ.md: <name>
84
- Brief: <one line: what, for whom, where>
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>)
96
+ Brief: <one line: what, for whom, where, in which language>
97
+ Hand: <the id canon.mjs draw printed>
98
+ Idea: <lens>: <a point of view in one sentence: what a visitor believes when they leave>
99
+ Passed over: <your two other ideas, one line>
100
+ Subject: <what the visitor must see> -> <shown by: the client's photo, a pack photo that shows it, or drawn in code>
101
+ Unlike: <the likeliest site, and Struq's reflexes> -> <what this one does instead>
102
+ Language: <weight | cut | curtain> (<the tempo the idea needs>; not <each of the other two>, because <why not>; temperament: <the language's default, or its neighbour and why>)
87
103
  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>
104
+ Lexicon: <three to five working words of the trade; every label and caption uses them>
89
105
  Palette: <id> (<mood>)
90
- Type: <pairing id>: <display> + <body>
106
+ Type: <pairing id>: <display> + <body> (not <the pairing you passed over>, because <why>)
91
107
  Images: pack <slug> (or the client's photos, then pack <slug>)
92
108
  Centerpiece: <block>: <why this is this site's one moment>
93
109
  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>
100
- Assumptions: <every drafted line and every fact left out>
110
+ Storyboard: <as blocks.mjs arc printed it, every line cast>
111
+ Assumptions: <every drafted line, every fact left out, the copy language>
101
112
  Verify: <filled in at step 7>
102
113
  ```
103
114
 
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`.
115
+ Run `node <skill-dir>/scripts/check.mjs --plan` until `PLAN: PASS` with no `quiet-is-quiet`, `loud-adjacent` or
116
+ `quiet-share` warning. Then stop once, in the user's language: the treatment in plain words (never slugs), the
117
+ storyboard as one sentence per scene, palette, type and pack on one line, and ask for what only the client has and
118
+ the page needs: their name if the brief gave none, how visitors reach them (address, phone or mail; the shop, booking
119
+ or sign-up link), their own photos when the work is the product. End with "Akkoord?" or "Approve?". The build request
120
+ is not the approval. Log the reply word for word: `log.mjs "Step 2 Approval" "Asked: ..." "Reply: \"<their words>\""`.
121
+ Any yes builds it; what they send replaces the matching pick; whatever stays unanswered is left out. Never ask twice.
122
+
123
+ **3 Canon.** `canon.mjs palette <id>` and `canon.mjs type <id>` write the one STRUQ TOKENS block and `app/fonts.ts`.
124
+
125
+ **4 Images, done before you cast the Opening.** In step 2, before the storyboard, run
126
+ `node <skill-dir>/scripts/images.mjs --brief "<the user's words>"` and open the hero photos it wrote
127
+ (`public/images/hero-*.webp`) with your image reader. A photo opens the site only if it shows this client's own
128
+ subject: a tap or a bathroom for a plumber, a mug for a mug shop, a city lot for a city garden. A photo that only
129
+ sets a mood (paper for a conference, cloth for a label, a room for a studio you have never seen) never opens a site.
130
+ If none shows the subject, run it again with `--no-hero`, and the Opening is type-led or WebGL (the hand always holds
131
+ one). Never widen the brief to
132
+ make a pack fit; the other photos serve the middle only where they show this client's world, never under a
133
+ first-person claim.
134
+
135
+ **5 Scenes.** Install the frames, the opening, the centerpiece and the footer (`blocks.mjs add <slug>:<variant>`):
136
+ these are the signatures, hardened blocks. The middle is yours. Compose each middle scene for this client from the
137
+ primitives (`SplitHeadline` for fitted type, `Reveal`, `MediaFrame`, the grid and the tokens), from what only this
138
+ trade has: a price board for a bakery, a tide table for a guesthouse, a joint drawn to scale for a plumber, a menu set
139
+ like a chalkboard for a restaurant. No two middle scenes share a layout, and none is a one-word list, a big sentence
140
+ with a small photo, or a photo beside text unless the idea truly asks for it.
141
+
142
+ When no photo shows the Subject, design it in code as a scene of its own, often the centerpiece's neighbour: the
143
+ app's real screen or document (the invoice of an invoicing app) built in HTML with the tokens, the event's identity (a
144
+ poster system, a badge, a programme grid with only the slots the brief gives), the label's lookbook frame, a menu
145
+ board. Sample content inside it reads as an example of the trade (an invoice for "Studio Noord, identity, round 2"),
146
+ never as a fact about the client: no customer names, no figures they would quote, no feature the brief did not give.
147
+ Start from the kit's designed pieces in `@/components/struq/kit/subject` before drawing your own: `Document` (an
148
+ invoice, quote, receipt, menu or label), `AppScreen` (a window or phone with the app's real screen), `Ticket` (a
149
+ ticket, badge or poster), `PatternPaper` (a sewing pattern) and `SectionDrawing` (a technical section). Fill them with
150
+ this client's content and palette; read each file header for its props and its scroll motion.
151
+
152
+ Own scenes may move. Give at least two of them a motion of their own, tied to the scroll and reversing (a line that
153
+ draws as you read, a document that assembles, a grid that sorts itself), never a pin over one screen; mark the root
154
+ `data-scene="<name>" data-energy="2"`, tag it (loud) in the storyboard, and keep the budgets. Compose them from
155
+ `@/components/struq/kit/motion` first (`RevealText`, `MaskWipe`, `ImageCurtain`, `ScrubLine`, `HoverLink`,
156
+ `Pressable`); write `gsap` from `@/components/struq/kit/gsap` only for what they cannot do, timed by `feel()` from
157
+ `@/components/struq/kit/feel`, never a literal ease or duration. A still own scene is `data-scene="<name>"` alone.
158
+ The kit's `Statement`, `PhotoText` and `Rows` (`@/components/struq/kit/quiet`) remain for a plain moment, at most one
159
+ per page. Build the close with `Close`: shape `idea` (the idea's last line and the motif drawn), `echo` (the opening
160
+ returns smaller) or `door` (the brief's real address, phone, mail or booking link, set large). The name at full width
161
+ is never the close; a wordmark there stays at text size. Read each file header for its props. Wrap ink or field scenes in
162
+ `scene-inverse` or `scene-field`. Every section, the hero too, says its ground with `data-bar-tone` ("photo" only
163
+ where the bar sits over the photo); the bar never repeats a name the hero sets at poster scale.
164
+
165
+ **6 to 8.** `npm run build` passes (fix your code; never delete a block for green). Serve it with
166
+ `npx next start -p 4321` (or a free port when that one is taken, then `look.mjs --url http://localhost:<port>`),
167
+ leave it running, and run `node <skill-dir>/scripts/look.mjs` (the first run installs Playwright into the project).
168
+ Never stop a server you did not start. It scrolls the page at 390 and 1440 with motion on, saves every step to
169
+ `.struq/look/`, and fails on text under the header, the site name twice on the first screen, letters cut by a mask
170
+ or the screen edge, a page wider than the screen, low contrast on a solid ground or measured over a photo, a blank
171
+ screen, a number broken across lines, a font that never loaded, and console or image errors; it warns on a
172
+ screen-high empty stretch. Open the screenshots and crops it names and read
173
+ them as a studio's art director would: the preloader lands, every pin engages and lets go, the first screen is bold
174
+ enough to stop a visitor. Fix, rebuild, restart the server and run it again until `LOOK: PASS`.
175
+
176
+ **Art direction.** Then hand the site to a fresh pair of eyes: start a subagent (the Agent tool in Claude Code, or your
177
+ host's equivalent) and give it only the brief, the Idea line, the paths of the stills in `.struq/look/` and
178
+ [references/art-direction.md](references/art-direction.md), never your plan or your reasoning. Save its answer to
179
+ `.struq/art-direction.md` as numbered asks, and write an answer line under each: `Built: <what changed>` or
180
+ `Refused: <reason>`. The asks are binding. Build every one. When an ask needs another order, opening or centerpiece,
181
+ rewrite the storyboard in STRUQ.md and swap the blocks (the storyboard serves the site); when it breaks a budget, keep
182
+ the budget by dropping something else. Refuse only an ask that breaks a rule that never bends or a fact of the brief
183
+ (a price, an address, a programme nobody gave), and say which. A refusal that cites the storyboard, the plan, a budget
184
+ or a block is no refusal: `check.mjs` fails it, and fails an ask with no answer. Rebuild, run `look.mjs` again, and ask
185
+ a new subagent once more; two rounds at most, each logged with `log.mjs`. A host without subagents: reread only the
186
+ brief, then read the stills against that file yourself. Then `check.mjs` to
187
+ `RESULT: PASS`; it fails while `.struq/look.json` is missing, failing or older than app/ and components/. A FAIL you
188
+ are sure is false goes in the final report with the reason, never worked around. Stop the server when done.
130
189
 
131
190
  ## The film
132
191
 
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.
192
+ One film, not a showreel: one language, one motif (seen at the arrival, the opening, the centerpiece and the close),
193
+ one centerpiece. A loud scene moves with the scroll; a quiet scene enters once and sits still.
194
+
195
+ | Language | Feel | Temperament | Frames: preloader, page transition, menu |
196
+ |---|---|---|---|
197
+ | weight | slow and settled; a print grows into place; long holds | weighted | `preloader-stack`, `page-transition-stack`, `menu-curtain:stack` |
198
+ | cut | sharp and decisive; hard cuts, short masks, no fades | crisp | `preloader-slices`, `page-transition-slices`, `menu-curtain:slices` |
199
+ | curtain | held, then revealed; panels part after a long hold | slow | `preloader-gate` or `preloader-wordmark:split`, `page-transition-gate`, `menu-curtain:gate` |
200
+
201
+ Set the temperament once, as `data-temperament` on `<body>` beside `data-blocks`: the language's default, or its
202
+ neighbour (weighted beside crisp or slow) with the reason on the Language line. Every primitive and `feel()` read it.
203
+
204
+ Pick by the tempo the idea needs, never by trade; calm and the held reveal are both reflexes. The Opening and the
205
+ Centerpiece may come from anywhere in the catalogue: choose the pair that could only be this client's.
206
+
207
+ Budgets the plan check enforces: exactly one centerpiece and nothing pinned after it; never two loud scenes side by
208
+ side; at least four in ten scenes quiet; pins together about 4.5 screens; every frame from the language; at most two
209
+ full-bleed photo reveals, one marquee, one custom cursor, one accent device (an italic word, a weight shift, a
210
+ coloured word, a jump in scale, or none); two or three type moments at poster scale; no eyebrows, mono, uppercase
211
+ labels or numbered steps.
208
212
 
209
213
  ## What makes it feel high end
210
214
 
211
215
  The blocks hold this already; your glue must too. Detail in [references/craft.md](references/craft.md).
212
216
 
213
- - Reveals clip from numbers, never scale a box; whole pixels; photos decoded before they show, cut or swap.
214
- - Scroll effects are scroll-tied and reverse when the visitor scrolls back; key frames hold.
215
- - The gate: `sq-js` on `<html>` before paint hides only what will animate, and shows it anyway after 3 s.
216
- - Type on a photo sits on the measured calm side over the lightest flat veil that reaches 3:1.
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.
220
- - Tokens only, mixes in oklab, a surface step and a hairline instead of a shadow, one accent.
221
- - Icons: Struq Icons (`@struq/icons`), functional only ([references/iconography.md](references/iconography.md)).
217
+ - Reveals clip from numbers, never scale a box; whole pixels; photos decoded before they show.
218
+ - Scroll effects are scroll-tied and reverse; key frames hold.
219
+ - `sq-js` on `<html>` before paint hides only what will animate, and shows it anyway after 3 s.
220
+ - Type on a photo sits on its calm side over the lightest veil that reaches 3:1.
221
+ - Display runs light unless the pairing says otherwise; fitted lines measured after `document.fonts.ready`.
222
+ - Never clip a descender; never `overflow-hidden` on a heading of your own.
223
+ - Tokens only, a surface step and a hairline instead of a shadow, one accent colour.
224
+ - Icons: `@struq/icons`, functional only ([references/iconography.md](references/iconography.md)).
222
225
 
223
226
  ## When something goes wrong
224
227
 
225
228
  - **Nothing scrolls:** an overlay called `getLenis()?.stop()` without `start()`, or `SmoothScroll` is not mounted.
226
229
  - **Content stays invisible for 3 s:** the block never set `data-ready`; usually it threw. Read the console.
227
230
  - **Wrong colours or faces:** `data-blocks` is missing on `<body>`, or STRUQ TOKENS sits before the kit import.
228
- - **A fitted line overflows or jumps:** the face did not load (check `app/fonts.ts` and the links in the layout).
231
+ - **A fitted line overflows or jumps:** the face did not load (check `app/fonts.ts` and the layout links).
229
232
  - **Vite:** [references/stack-targets.md](references/stack-targets.md).