@struq/skill 0.5.2 → 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.
- package/README.md +27 -27
- package/package.json +2 -2
- package/skills/struq/SKILL.md +168 -165
- package/skills/struq/blocks/CATALOG.md +49 -46
- package/skills/struq/blocks/backgrounds/background-aurora.tsx +2 -1
- package/skills/struq/blocks/backgrounds/background-facets.tsx +5 -3
- package/skills/struq/blocks/backgrounds/background-silk.tsx +6 -2
- package/skills/struq/blocks/catalog.json +50 -5
- package/skills/struq/blocks/film.json +11 -7
- package/skills/struq/blocks/footers/footer-contact.tsx +8 -78
- package/skills/struq/blocks/headers/header-bar.tsx +144 -29
- package/skills/struq/blocks/headers/menu-curtain.tsx +36 -19
- package/skills/struq/blocks/heroes/hero-poster.tsx +36 -10
- package/skills/struq/blocks/kit/HeroCanvas.tsx +6 -2
- package/skills/struq/blocks/kit/SplitHeadline.tsx +2 -1
- package/skills/struq/blocks/kit/accent.ts +29 -3
- package/skills/struq/blocks/kit/blocks.css +530 -6
- package/skills/struq/blocks/kit/feel.ts +183 -0
- package/skills/struq/blocks/kit/gsap.ts +9 -6
- package/skills/struq/blocks/kit/middle/PlaceHours.tsx +254 -0
- package/skills/struq/blocks/kit/middle/ProcessStrip.tsx +428 -0
- package/skills/struq/blocks/kit/middle/ServicesList.tsx +496 -0
- package/skills/struq/blocks/kit/middle/entrance.ts +98 -0
- package/skills/struq/blocks/kit/middle/hours.ts +154 -0
- package/skills/struq/blocks/kit/middle/index.ts +14 -0
- package/skills/struq/blocks/kit/motion/HoverLink.tsx +33 -0
- package/skills/struq/blocks/kit/motion/ImageCurtain.tsx +79 -0
- package/skills/struq/blocks/kit/motion/MaskWipe.tsx +91 -0
- package/skills/struq/blocks/kit/motion/Pressable.tsx +58 -0
- package/skills/struq/blocks/kit/motion/RevealText.tsx +103 -0
- package/skills/struq/blocks/kit/motion/Rise.tsx +77 -0
- package/skills/struq/blocks/kit/motion/ScrubLine.tsx +108 -0
- package/skills/struq/blocks/kit/motion/index.ts +11 -0
- package/skills/struq/blocks/kit/quiet/Close.tsx +178 -52
- package/skills/struq/blocks/kit/quiet/Statement.tsx +3 -2
- package/skills/struq/blocks/kit/subject/AppScreen.tsx +388 -0
- package/skills/struq/blocks/kit/subject/Document.tsx +742 -0
- package/skills/struq/blocks/kit/subject/Mark.tsx +44 -0
- package/skills/struq/blocks/kit/subject/PatternPaper.tsx +410 -0
- package/skills/struq/blocks/kit/subject/SectionDrawing.tsx +349 -0
- package/skills/struq/blocks/kit/subject/Ticket.tsx +354 -0
- package/skills/struq/blocks/kit/subject/build.ts +66 -0
- package/skills/struq/blocks/kit/subject/draw.ts +196 -0
- package/skills/struq/blocks/kit/subject/drawings.ts +373 -0
- package/skills/struq/blocks/kit/subject/format.ts +122 -0
- package/skills/struq/blocks/kit/subject/index.ts +11 -0
- package/skills/struq/blocks/kit/subject/patterns.ts +204 -0
- package/skills/struq/blocks/preloaders/preloader-stack.tsx +75 -22
- package/skills/struq/blocks/showpieces/hero-opener.tsx +55 -7
- package/skills/struq/blocks/showpieces/image-to-fullbleed.tsx +64 -6
- package/skills/struq/blocks/showpieces/manifesto-scrub.tsx +56 -3
- package/skills/struq/blocks/showpieces/panel-wipe.tsx +93 -11
- package/skills/struq/blocks/showpieces/wordmark-finale.tsx +38 -5
- package/skills/struq/canon/canon.json +1 -1
- package/skills/struq/references/art-direction.md +51 -0
- package/skills/struq/scripts/blocks.mjs +56 -20
- package/skills/struq/scripts/canon.mjs +36 -7
- package/skills/struq/scripts/check.mjs +417 -11
- package/skills/struq/scripts/draw.mjs +49 -0
- package/skills/struq/scripts/film-check.mjs +28 -4
- package/skills/struq/scripts/gate.mjs +13 -3
- package/skills/struq/scripts/hand.mjs +222 -0
- package/skills/struq/scripts/images.mjs +12 -3
- package/skills/struq/scripts/look.mjs +1184 -0
- package/skills/struq/scripts/stamp.mjs +47 -0
package/skills/struq/SKILL.md
CHANGED
|
@@ -6,51 +6,58 @@ argument-hint: "[brief] | redesign <path> | audit <path-or-url> | direct <brief>
|
|
|
6
6
|
|
|
7
7
|
# Struq
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
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
|
|
17
|
-
| `/struq redesign <path>` | Keep
|
|
18
|
-
| `/struq audit <path-or-url>` | Change nothing. Run `check.mjs` (
|
|
19
|
-
| `/struq direct <brief>` | One continuous WebGL experience
|
|
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
|
-
|
|
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).
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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
|
-
##
|
|
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
|
-
|
|
|
41
|
-
| What blocks exist | `struq_blokken(kind?, query?)` | `blocks.mjs list [kind]
|
|
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
|
|
52
|
+
| The self-check | `struq_controle()` | `check.mjs` |
|
|
44
53
|
|
|
45
|
-
|
|
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
|
|
52
|
-
|
|
53
|
-
|
|
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:
|
|
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.**
|
|
68
|
-
`node <skill-dir>/scripts/blocks.mjs init
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
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
|
-
|
|
86
|
-
|
|
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
|
|
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
|
-
|
|
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`
|
|
105
|
-
`quiet-share` warning
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
**
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
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:
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
|
139
|
-
|
|
140
|
-
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
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
|
|
214
|
-
- Scroll effects are scroll-tied and reverse
|
|
215
|
-
-
|
|
216
|
-
- Type on a photo sits on
|
|
217
|
-
- Display runs light
|
|
218
|
-
- Never clip a descender
|
|
219
|
-
|
|
220
|
-
-
|
|
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
|
|
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).
|