@struq/skill 0.3.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -36
- package/package.json +4 -2
- package/skills/struq/SKILL.md +139 -307
- package/skills/struq/blocks/CATALOG.md +426 -0
- package/skills/struq/blocks/backgrounds/background-aurora.tsx +818 -0
- package/skills/struq/blocks/backgrounds/background-facets.tsx +1283 -0
- package/skills/struq/blocks/backgrounds/background-silk.tsx +906 -0
- package/skills/struq/blocks/catalog.json +1302 -0
- package/skills/struq/blocks/footers/footer-contact.tsx +789 -0
- package/skills/struq/blocks/footers/footer-reveal.tsx +313 -0
- package/skills/struq/blocks/headers/header-bar.tsx +652 -0
- package/skills/struq/blocks/headers/menu-curtain.tsx +790 -0
- package/skills/struq/blocks/heroes/hero-framed.tsx +627 -0
- package/skills/struq/blocks/heroes/hero-index.tsx +855 -0
- package/skills/struq/blocks/heroes/hero-poster.tsx +1086 -0
- package/skills/struq/blocks/heroes/hero-split.tsx +685 -0
- package/skills/struq/blocks/heroes/hero-still.tsx +862 -0
- package/skills/struq/{recipes/components/struq → blocks/kit}/Cursor.tsx +1 -1
- package/skills/struq/{recipes/components/struq → blocks/kit}/HeroCanvas.tsx +4 -4
- package/skills/struq/{recipes/components/struq → blocks/kit}/HorizontalGallery.tsx +2 -2
- package/skills/struq/{recipes/components/struq → blocks/kit}/MagneticButton.tsx +1 -1
- package/skills/struq/{recipes/components/struq → blocks/kit}/MediaFrame.tsx +2 -2
- package/skills/struq/{recipes/components/struq → blocks/kit}/PinnedZoom.tsx +14 -4
- package/skills/struq/{recipes/components/struq → blocks/kit}/Reveal.tsx +1 -1
- package/skills/struq/{recipes/components/struq → blocks/kit}/SmoothScroll.tsx +1 -1
- package/skills/struq/{recipes/components/struq → blocks/kit}/SplitHeadline.tsx +1 -1
- package/skills/struq/blocks/kit/blocks.css +2102 -0
- package/skills/struq/blocks/kit/images.ts +17 -0
- package/skills/struq/blocks/kit/photo-read.ts +102 -0
- package/skills/struq/blocks/page-transitions/page-transition-gate.tsx +706 -0
- package/skills/struq/blocks/page-transitions/page-transition-slices.tsx +469 -0
- package/skills/struq/blocks/page-transitions/page-transition-stack.tsx +583 -0
- package/skills/struq/blocks/preloaders/preloader-gate.tsx +358 -0
- package/skills/struq/blocks/preloaders/preloader-slices-uncovered.ts +50 -0
- package/skills/struq/blocks/preloaders/preloader-slices.tsx +289 -0
- package/skills/struq/blocks/preloaders/preloader-stack.tsx +367 -0
- package/skills/struq/blocks/preloaders/preloader-wordmark.tsx +568 -0
- package/skills/struq/blocks/sections/about-studio.tsx +436 -0
- package/skills/struq/blocks/sections/approach.tsx +661 -0
- package/skills/struq/blocks/sections/contact-form.tsx +664 -0
- package/skills/struq/blocks/sections/cta-closing.tsx +763 -0
- package/skills/struq/blocks/sections/fanned-cards.tsx +547 -0
- package/skills/struq/blocks/sections/film-strip.tsx +385 -0
- package/skills/struq/blocks/sections/grid-assembly.tsx +616 -0
- package/skills/struq/blocks/sections/hover-list.tsx +467 -0
- package/skills/struq/blocks/sections/image-trail.tsx +432 -0
- package/skills/struq/blocks/sections/manifesto.tsx +691 -0
- package/skills/struq/blocks/sections/panel-accordion.tsx +380 -0
- package/skills/struq/blocks/sections/reveals.tsx +416 -0
- package/skills/struq/blocks/sections/split-pair.tsx +670 -0
- package/skills/struq/blocks/sections/sticky-chapters.tsx +256 -0
- package/skills/struq/blocks/sections/velocity-type.tsx +269 -0
- package/skills/struq/{cinematic/showpieces/toonstuk-fill-rows.tsx → blocks/showpieces/fill-rows.tsx} +1 -1
- package/skills/struq/{cinematic/showpieces/toonstuk-hero-opener.tsx → blocks/showpieces/hero-opener.tsx} +5 -5
- package/skills/struq/{cinematic/showpieces/toonstuk-image-to-fullbleed.tsx → blocks/showpieces/image-to-fullbleed.tsx} +16 -5
- package/skills/struq/blocks/showpieces/manifesto-scrub.tsx +48 -0
- package/skills/struq/{cinematic/showpieces/toonstuk-panel-wipe.tsx → blocks/showpieces/panel-wipe.tsx} +2 -2
- package/skills/struq/{cinematic/showpieces/toonstuk-pixel-resolve.tsx → blocks/showpieces/pixel-resolve.tsx} +1 -1
- package/skills/struq/{cinematic/showpieces/toonstuk-project-stack.tsx → blocks/showpieces/project-stack.tsx} +2 -2
- package/skills/struq/blocks/showpieces/scrub-connector.tsx +307 -0
- package/skills/struq/{cinematic/showpieces/toonstuk-wordmark-finale.tsx → blocks/showpieces/wordmark-finale.tsx} +1 -1
- package/skills/struq/blocks/transitions/zoom-through.tsx +613 -0
- package/skills/struq/canon/canon.json +627 -0
- package/skills/struq/cinematic/README.md +7 -18
- package/skills/struq/cinematic/examples/code/nextjs/app/components/LenisRoot.tsx +1 -1
- package/skills/struq/cinematic/examples/code/shared/styles.css +1 -1
- package/skills/struq/cinematic/examples/code/vite/src/LenisRoot.tsx +1 -1
- package/skills/struq/cinematic/references/01-core-mental-model.md +1 -1
- package/skills/struq/cinematic/references/02-vocabulary.md +1 -1
- package/skills/struq/cinematic/references/07-stack-integration.md +2 -2
- package/skills/struq/recipes/app/fonts.ts +12 -22
- package/skills/struq/recipes/app/globals.css +34 -177
- package/skills/struq/recipes/app/layout.tsx +13 -11
- package/skills/struq/references/craft.md +77 -0
- package/skills/struq/references/iconography.md +28 -230
- package/skills/struq/references/stack-targets.md +23 -74
- package/skills/struq/references/tells.md +52 -0
- package/skills/struq/references/triage.md +6 -7
- package/skills/struq/scripts/blocks.mjs +156 -0
- package/skills/struq/scripts/canon.mjs +106 -281
- package/skills/struq/scripts/check.mjs +92 -126
- package/skills/struq/scripts/images.mjs +2 -2
- package/skills/struq/scripts/log.mjs +6 -23
- package/skills/struq/scripts/tokens.mjs +222 -0
- package/skills/struq/cinematic/showpieces/README.md +0 -18
- package/skills/struq/cinematic/showpieces/toonstuk-manifesto-scrub.tsx +0 -81
- package/skills/struq/cinematic/showpieces/toonstuk-scrub-connector.tsx +0 -78
- package/skills/struq/references/anti-patterns.md +0 -330
- package/skills/struq/references/baseline-prompt.md +0 -122
- package/skills/struq/references/brand.md +0 -143
- package/skills/struq/references/brief-router.md +0 -218
- package/skills/struq/references/composition.md +0 -190
- package/skills/struq/references/depth-parallax.md +0 -235
- package/skills/struq/references/direction.md +0 -188
- package/skills/struq/references/feel-layer.md +0 -107
- package/skills/struq/references/gsap-api.md +0 -293
- package/skills/struq/references/hero-scenes.md +0 -107
- package/skills/struq/references/imagery.md +0 -125
- package/skills/struq/references/loaders.md +0 -287
- package/skills/struq/references/micro-interactions.md +0 -270
- package/skills/struq/references/mobile-composition.md +0 -70
- package/skills/struq/references/nav-header.md +0 -296
- package/skills/struq/references/niche-packets.md +0 -338
- package/skills/struq/references/page-architecture.md +0 -134
- package/skills/struq/references/page-entrances.md +0 -198
- package/skills/struq/references/performance.md +0 -235
- package/skills/struq/references/pinning-scrub.md +0 -340
- package/skills/struq/references/pitfalls.md +0 -290
- package/skills/struq/references/route-transitions.md +0 -281
- package/skills/struq/references/scaling.md +0 -151
- package/skills/struq/references/scroll-reveals.md +0 -279
- package/skills/struq/references/sections.md +0 -141
- package/skills/struq/references/seo.md +0 -219
- package/skills/struq/references/setup.md +0 -397
- package/skills/struq/references/showcase.md +0 -87
- package/skills/struq/references/struq-imagery.md +0 -107
- package/skills/struq/references/svg-motion.md +0 -390
- package/skills/struq/references/transitions.md +0 -160
- package/skills/struq/references/typography.md +0 -720
- package/skills/struq/references/vibe-presets.md +0 -287
- package/skills/struq/references/webgl-r3f.md +0 -274
- package/skills/struq/references/webgl-scenes.md +0 -593
- package/skills/struq/scripts/font-names.mjs +0 -40
- package/skills/struq/scripts/recipes.mjs +0 -135
- /package/skills/struq/{recipes/lib → blocks/kit}/gsap.ts +0 -0
- /package/skills/struq/{recipes/components/struq → blocks/kit}/scenes/contours.ts +0 -0
- /package/skills/struq/{recipes/components/struq → blocks/kit}/scenes/dots.ts +0 -0
- /package/skills/struq/{recipes/components/struq → blocks/kit}/scenes/ripple.ts +0 -0
- /package/skills/struq/{recipes/components/struq → blocks/kit}/scenes/types.ts +0 -0
package/skills/struq/SKILL.md
CHANGED
|
@@ -1,341 +1,173 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: struq
|
|
3
|
-
description: "Award-tier
|
|
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
|
-
A site looks like a template because every choice in it is the likeliest one. Struq replaces those choices with
|
|
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
|
-
`<skill-dir>`
|
|
12
|
-
|
|
13
|
-
|
|
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).
|
|
14
16
|
|
|
15
17
|
| Invocation | Mode |
|
|
16
18
|
|---|---|
|
|
17
|
-
| `/struq <brief>` | **Build**: the
|
|
18
|
-
| `/struq redesign <path>` |
|
|
19
|
-
| `/struq audit <path-or-url>` |
|
|
20
|
-
| `/struq direct <brief>` |
|
|
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). |
|
|
21
23
|
|
|
22
|
-
|
|
24
|
+
For a dashboard or product UI keep the tokens, faces and tells; drop the preloader, Lenis and the pinned pieces.
|
|
23
25
|
|
|
24
26
|
## Three rules that never bend
|
|
25
27
|
|
|
26
|
-
1. **Never an empty frame.** Every image slot holds a real
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
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.
|
|
33
36
|
|
|
34
|
-
## The
|
|
37
|
+
## The MCP, or the skill's own copy
|
|
35
38
|
|
|
36
|
-
|
|
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.
|
|
37
41
|
|
|
38
|
-
|
|
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` |
|
|
39
48
|
|
|
40
|
-
|
|
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.
|
|
41
52
|
|
|
42
|
-
```
|
|
43
53
|
## Build checklist
|
|
44
|
-
Rule: keep STRUQ-LOG.md at every step: node <skill-dir>/scripts/log.mjs "Step N Name" "what" "why" (canon, images, recipes and check log themselves)
|
|
45
|
-
- [ ] 1 Project: Next.js App Router + Tailwind v4 in place (scaffolded if the folder was empty)
|
|
46
|
-
- [ ] 2 Plan and approval: palette, pairing, design system and pack picked from the canon (canon.mjs list); STRUQ.md written; the one stop for approval sent and answered
|
|
47
|
-
- [ ] 3 Recipes: node <skill-dir>/scripts/recipes.mjs printed "OK recipes ready"
|
|
48
|
-
- [ ] 4 Canon: canon.mjs palette and canon.mjs type wrote the tokens and the fonts of the approved picks
|
|
49
|
-
- [ ] 5 Images: images.mjs --brief printed "OK"; only photos whose alt fits the client are used, captions written from the alts; title and lang set in app/layout.tsx
|
|
50
|
-
- [ ] 6 Hero: the full-bleed HeroOpener (photo edge to edge, line at 14 to 20vw, lead, large CTA, header with the data-wordmark name), or a hand-built hero under the same rules
|
|
51
|
-
- [ ] 7 Sections: 5 to 7 sections on the arc, every image in a MediaFrame, text groups in Reveal, two grid breaks; one contrast scene (scene-inverse or scene-field), at most two
|
|
52
|
-
- [ ] 8 Showpieces: the lead toonstuk from the picker (or the one the user named) and at most one supporting move
|
|
53
|
-
- [ ] 9 Footer: toonstuk-wordmark-finale, with the image credit
|
|
54
|
-
- [ ] 10 Build: npm run build passes
|
|
55
|
-
- [ ] 11 Look: screenshots at 390 and 1440 and one full scroll, fixes made (or "not seen: no browser" written under Verify)
|
|
56
|
-
- [ ] 12 Check: node <skill-dir>/scripts/check.mjs prints RESULT: PASS
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
### Step 1: Project
|
|
60
|
-
|
|
61
|
-
Empty folder: `npx create-next-app@latest . --ts --tailwind --app --eslint --yes`. Existing project: read `package.json`; when the installed version's types disagree with a recipe, the installed version wins (adapt the recipe, keep its intent). Vite: translate each step through [references/stack-targets.md](references/stack-targets.md).
|
|
62
|
-
|
|
63
|
-
### Step 2: Plan, then the one stop for approval
|
|
64
|
-
|
|
65
|
-
Run `node <skill-dir>/scripts/canon.mjs list` (it reads the canon and changes nothing) and pick the palette, the pairing, the design system and the beeldbank pack as step 4 and step 5 describe. Then write this at the top of `STRUQ.md`, with the checklist under it:
|
|
66
|
-
|
|
67
|
-
```
|
|
68
|
-
# STRUQ.md: <name>
|
|
69
|
-
Brief: <one line: what it is, for whom, where>
|
|
70
|
-
Idea: <the one idea the site is about, and the one visual motif that carries it>
|
|
71
|
-
Palette: <canon palette slug> (<its mood>)
|
|
72
|
-
Type: <canon pairing slug>: <display face> + <text face>
|
|
73
|
-
System: <canon design system slug> (<its section order>)
|
|
74
|
-
Images: pack <slug> (or: the client's photos, then pack <slug>)
|
|
75
|
-
Hero: <contours | ripple | dots | the MCP background>
|
|
76
|
-
Showpiece: <HorizontalGallery | PinnedZoom>, after section <n>
|
|
77
|
-
Arc: 1 hero, 2 <...>, 3 <...>, 4 showpiece, 5 <...>, 6 invite, footer
|
|
78
|
-
Assumptions: <every drafted line and every fact left out>
|
|
79
|
-
Verify: <filled in at step 11>
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
Then **stop, once**: send the plan in five lines (idea, palette, type, pack, arc with the showpiece) and the materials request, in the user's language:
|
|
83
|
-
|
|
84
|
-
> Akkoord? Heb je een logo, foto's of echte cijfers, stuur ze nu.
|
|
85
|
-
|
|
86
|
-
(English: "Approve? If you have a logo, photos or real numbers, send them now.") Wait for the answer. Any yes, or "bouw maar" with nothing attached, builds with the canon picks as planned; what the user sends replaces the matching pick or pack images; a veto changes only what it names. **This is the only stop: never ask a second time**, not for permission to download the images (they are free and CC0) and not to confirm a build step. Only a brief that does not say what the business is gets one question before the plan, instead of this stop.
|
|
87
|
-
|
|
88
|
-
**No photos that pretend.** When the brief's own sector words point at no pack (a product launch: an e-bike, a device, a drink), no beeldbank photo shows the client's product. Then add this line to the stop: "Ik heb geen foto's van je <product>: stuur ze, dan komen ze in de hero." (English: "I have no photos of your <product>: send them and they go in the hero.")
|
|
89
|
-
|
|
90
|
-
**The build request is not the approval.** "Build me a site for ..." is the brief; the approval is the user's answer to this stop, and nothing else counts as one. Log it word for word, then go on: `node <skill-dir>/scripts/log.mjs "Step 2 Approval" "Asked: Akkoord? Heb je een logo, foto's of echte cijfers, stuur ze nu." "Reply: \"<the user's own words>\""`. `check.mjs` fails without that entry and its Reply line.
|
|
91
|
-
|
|
92
|
-
### Step 3: Recipes
|
|
93
|
-
|
|
94
|
-
```bash
|
|
95
|
-
node <skill-dir>/scripts/recipes.mjs
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
Copies the tested components into the project and installs `gsap @gsap/react lenis three @types/three`. On a fresh scaffold it also writes `app/globals.css`, `app/layout.tsx` and `app/fonts.ts`; on your own files it prints what to merge. The components (all in `components/struq/`):
|
|
99
|
-
|
|
100
|
-
| Component | What it gives the page |
|
|
101
|
-
|---|---|
|
|
102
|
-
| `SmoothScroll` | Lenis on `gsap.ticker`, one clock for the whole page. Already in the layout. `getLenis()?.stop()` / `.start()` for menus. |
|
|
103
|
-
| `SplitHeadline` | SplitText line-mask rise. `as="h1"` for the hero, `on="scroll"` for a statement further down. Plain text children. |
|
|
104
|
-
| `Reveal` | Staggered rise of its direct children on scroll (`on="load"` in the hero). |
|
|
105
|
-
| `MediaFrame` | The only way an image goes on the page: curtain reveal, photo settle, scrubbed parallax. Props `image`, `ratio`, `sizes`, `priority` (the hero image only), `reveal`. |
|
|
106
|
-
| `HeroCanvas` | The WebGL hero layer: `scene="contours"`, `"ripple"` (needs `image`) or `"dots"`. Lazy three.js chunk, poster first, DPR cap, pixel budget, pause offscreen, still frame under reduced motion, colours read from the tokens. |
|
|
107
|
-
| `HorizontalGallery` | Showpiece: pinned section, a track of photos sliding sideways, each photo panning. Native swipe row on phones. |
|
|
108
|
-
| `PinnedZoom` | Showpiece: a small framed photo opens to full bleed while the statement lifts away. |
|
|
109
|
-
| `MagneticButton` | The primary CTA: leans to the pointer, ink fill rises on hover. `variant="line"` for the secondary. |
|
|
110
|
-
| `Cursor` | Dot and trailing ring, inverted against the page. Already in the layout; delete it for a booking tool or a dense shop. |
|
|
111
|
-
|
|
112
|
-
### Step 4: Canon (Struq's own palette, type and system, every build)
|
|
113
|
-
|
|
114
|
-
A generic AI falls back on its standard palette and fonts. A Struq build starts from Struq's canon: curated palettes, pairings and design systems, public, no account. **Never invent a palette or a pairing while the canon has a fit.**
|
|
115
|
-
|
|
116
|
-
```bash
|
|
117
|
-
node <skill-dir>/scripts/canon.mjs list # every palette (slug, mood, light or dark), pairing, system, pack
|
|
118
|
-
node <skill-dir>/scripts/canon.mjs palette <slug> # writes the STRUQ TOKENS block in app/globals.css
|
|
119
|
-
node <skill-dir>/scripts/canon.mjs type <slug> # writes app/fonts.ts (Google via next/font, Fontshare as local woff2)
|
|
120
|
-
node <skill-dir>/scripts/canon.mjs system <slug> # prints the section order
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
Each command prints the line to paste into STRUQ.md (`Palette:`, `Type:`, `System:`). The raw API, if you want to read it yourself:
|
|
124
|
-
|
|
125
|
-
| Endpoint | Read |
|
|
126
|
-
|---|---|
|
|
127
|
-
| `curl -s "https://struq.nl/api/assets?filter=palette"` | `items[].slug`, `items[].data.mood`, `items[].data.colors` with `background`, `surface`, `text`, `accent`, `accentAlt` (OKLCH or hex), `items[].tags` (`sfeer:licht`, `sfeer:donker`, `sfeer:warm`, `sfeer:koel`, `sfeer:redactioneel`, `sfeer:rustig`, `sfeer:gedurfd`, `sfeer:technisch`) |
|
|
128
|
-
| `curl -s "https://struq.nl/api/assets?filter=typography"` | `items[].slug`, `items[].data.display.name`, `items[].data.body.name`, their `stack`, `items[].data.intent` |
|
|
129
|
-
| `curl -s "https://struq.nl/api/assets?filter=design_system"` | `items[].slug`, `items[].data.silhouette.sectionOrder`, `items[].data.paletteRef`, `items[].data.typographyRef` |
|
|
130
|
-
| `curl -s "https://struq.nl/api/media/packs"` | `packs[].slug`, `packs[].description` (step 5) |
|
|
131
|
-
|
|
132
|
-
Testing only: `STRUQ_API_BASE=https://staging.struq.nl` points `canon.mjs` and `images.mjs` (API and image downloads) at another Struq environment. Users never set it.
|
|
133
|
-
|
|
134
|
-
**How to pick.** Palette by the brief's mood first (`data.mood` and the `sfeer:` tags), then by sector: a restaurant by a wood fire reads `frontier-olea-flour-terracotta` or `frontier-lumen-firelit-flour`; an architect `graphite-ivory` or `midnight-brass`; a mobility launch `frontier-aperture-technical-dark` or `frontier-velar-graphite-scarlet`; care `frontier-thuispost-oat-petrol` or `frontier-stillwater-oat-sage`; fashion `frontier-seve-bone-oxblood`. A palette whose accent is blue or purple (`canon.mjs list` marks it) only when the brand is that colour, declared in STRUQ.md as `Cool hue: declared because <the brand colour>`. The brand's own colours, when the brief gives them, beat the canon: write them into the same token names.
|
|
135
|
-
|
|
136
|
-
Pairing by temperament: `serif-editorial` (Fraunces, warm and premium), `newsreader-classic` (Newsreader, literate, long-form), `editorial-sans-precision` (Sora, architectural, calm), `geometric-modern` (Manrope, self-assured), `display-drama` (Syne, expressive campaigns). `canon.mjs type` applies Struq's overrides for you: Inter is replaced (Fraunces gets Urbanist), a commercial face gets its free stand-in (Neue Haas Grotesk Text becomes General Sans from Fontshare), and `grotesk-workhorse` (Space Grotesk + Inter) is refused. When no canon pairing fits the temperament (quiet luxury, a fashion house, a poster voice), use the Signature set in [references/typography.md](references/typography.md) §3.1 through `canon.mjs type --display "Cormorant Garamond" --body "Jost"`.
|
|
137
|
-
|
|
138
|
-
Design system by the business: `gallery-first` when the work is visual (restaurant, architecture, shop), `proof-forward` when the brief has real facts to show, `story-led` for founder-led and care, `loud-campaign` for a launch, `editorial-restrained` for professional services. Use its section order for the arc; drop any section that would need invented content (`proof` and `story-proof` only with real facts, `faq` only with answers the brief gives), and add the Struq floor: the hero canvas, one showpiece at the act break, the designed footer.
|
|
139
54
|
|
|
140
|
-
|
|
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.
|
|
141
58
|
|
|
142
|
-
No network: keep the `Paper` tokens the recipe ships, set `Palette: offline default (paper)` in STRUQ.md, and run `canon.mjs` again when struq.nl answers.
|
|
143
|
-
|
|
144
|
-
### Step 5: Images (automatic, every build)
|
|
145
|
-
|
|
146
|
-
```bash
|
|
147
|
-
node <skill-dir>/scripts/images.mjs --brief "<the brief, in the user's words>"
|
|
148
|
-
node <skill-dir>/scripts/images.mjs <pack-slug> --brief "<the brief>" # when you picked the pack yourself
|
|
149
59
|
```
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
| Architect, real estate, makelaar, property, interiors studio | `datum` | concrete, glass and timber, corrected verticals, no people |
|
|
160
|
-
| Construction, trades, installation, renovation | `mortar` | scaffold, timber frame, tools, backs and hands |
|
|
161
|
-
| Hotel, holiday home, travel, terrace, pool | `portico` | limewash, shutters, still water, late warm light |
|
|
162
|
-
| Law, accountancy, consultancy, finance, notary | `ledger` | oak desks, closed volumes, brass |
|
|
163
|
-
| Design studio, agency, print, illustration, writer | `quire` | studio desk mid-project, paper, ink, swatches |
|
|
164
|
-
| Software, SaaS, AI, anything with nothing to photograph | `halide` | glass, machined metal and light in darkness |
|
|
165
|
-
| Electronics, hardware, devices, engineering, deep tech | `circuit` | copper, solder and connectors at macro range |
|
|
166
|
-
| Logistics, freight, distribution, warehousing (vracht, distributie, magazijn) | `transit` | depots, wet road, containers under sodium light |
|
|
167
|
-
| A product launch with no sector of its own: an e-bike, a cargo bike, a device, a drink | `vitrine` | the product's world on stone under one light; the hero scene carries the product |
|
|
168
|
-
| Sport, gym, running, coaching for performance | `cadence` | training spaces after dark, chalk and steel |
|
|
169
|
-
| Yoga, physio, spa, wellness, movement | `vessel` | studio floor, still water, linen, sand tones |
|
|
170
|
-
| Care, therapy, coaching, psychology, a small B&B | `linen` | calm rooms, linen, quiet hands |
|
|
171
|
-
| Hair salon, beauty, barber, nails | `sable` | salon light in taupe and brass |
|
|
172
|
-
| Fashion, textile, tailoring, clothing | `bolt` | cloth, rails, folds and seams, no bodies |
|
|
173
|
-
| Farm, growers, farm shop, food provenance | `loam` | soil, crops, greenhouse in low morning light |
|
|
174
|
-
| Nature, outdoor, coast, landscape, sustainability | `brume` | Atlantic coast under overcast, fog, stone |
|
|
175
|
-
| Crafts, metalwork, furniture making, workshop | `forge` | hot steel, worn tools, warm darkness |
|
|
176
|
-
| School, childcare, education | `primer` | empty rooms at child height, birch and felt |
|
|
177
|
-
| Events, venues, theatre, conferences | `assembly` | the room before it fills, chairs and stage light |
|
|
178
|
-
|
|
179
|
-
The table reads the photos, never the API's `sector` field: production still carries old labels that do not match the pictures (`vessel` is wellness, not kitchen; `datum` is architecture, not data), so the skill never chooses by that field. Nothing fits closely: take the pack whose light matches the palette (warm and light `linen`, warm and dark `forge`, cool and dark `halide`, cool and light `datum`). Never skip images. One pack per site. Translate the alts in `lib/struq-images.ts` when the site is not Dutch. Then set the title, description and `lang` in `app/layout.tsx`.
|
|
180
|
-
|
|
181
|
-
### Step 6: The hero: a full-bleed cinematic opener
|
|
182
|
-
|
|
183
|
-
The first screen is the photo, edge to edge, with giant type set across it. Not a text block beside a picture. Use `toonstuk-hero-opener` (copied to `components/struq/showpieces/`):
|
|
184
|
-
|
|
185
|
-
```tsx
|
|
186
|
-
<HeroOpener
|
|
187
|
-
image={images.hero[0]}
|
|
188
|
-
title="Koken op"
|
|
189
|
-
accent="vuur."
|
|
190
|
-
lead="Een houtoven, een wijnbar en een zaal aan het water."
|
|
191
|
-
cta={{ href: "#reserveren", label: "Reserveer een tafel" }}
|
|
192
|
-
header={<SiteHeader />}
|
|
193
|
-
/>
|
|
194
|
-
// or the name split to both edges with the photo between:
|
|
195
|
-
<HeroOpener image={images.hero[0]} split={["Vuur", "Noord"]} lead="..." cta={{ href: "#reserveren", label: "Reserveer een tafel" }} header={<SiteHeader />} />
|
|
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
|
|
196
69
|
```
|
|
197
70
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
- **The handover is a move:** on scroll the opener pins, scales down and darkens while the next section slides up over it. The section after it needs nothing extra: globals.css gives it a ground and the layer above.
|
|
204
|
-
- **The header** with the wordmark (`data-wordmark`) goes in the `header` prop, set over the photo in `text-on-photo`.
|
|
205
|
-
- **Never model the client's product from primitives:** a launch uses the `vitrine` product photography in the opener. For a portfolio brief ("laat ons werk zien"), the opener photo is a real project of the client.
|
|
206
|
-
- Phones and reduced motion get the composed still: the same full-bleed photo and line, no pin.
|
|
207
|
-
|
|
208
|
-
A hand-built hero is allowed when the brief needs something the opener does not do, under the same rules: a pack photo in the hero (`check.mjs` fails one without), the copy marked `data-quiet` (the `SplitHeadline` h1 marks itself), the line at 10vw or more, a header with the wordmark.
|
|
209
|
-
|
|
210
|
-
**One contrast scene.** Every site has one dark or full-colour scene, at most two, so the page does not stay on one ground: wrap one section in `scene-inverse` (the palette's dark ground with light type) or `scene-field` (a full-strength colour field). The tokens turn inside, so any recipe in it follows. Good places: the agency's scrub connector, the services rows, the project stack, the invitation. `canon.mjs palette` writes the `inverse` and `field` roles from the canon palette when it has them, and swaps text and ground when it does not. `check.mjs` fails a site with none, or with more than two.
|
|
211
|
-
|
|
212
|
-
### Step 7: Sections on the arc
|
|
213
|
-
|
|
214
|
-
Five to seven sections after the hero, in this order of beats: **orient** (what it is, one statement beside a big image), **prove** (the real specifics: the menu, the services, the projects, typeset), the **showpiece**, **deepen** (detail photos and short text), **invite** (the one CTA again). Then the footer. Patterns with code: [references/sections.md](references/sections.md).
|
|
215
|
-
|
|
216
|
-
- Every image in a `MediaFrame` from `lib/struq-images.ts`, declared ratios only (16/9, 3/2, 4/5, 1/1, 21/9), never the same photo twice.
|
|
217
|
-
- Text groups in `<Reveal>`: a heading and its paragraph rise together.
|
|
218
|
-
- Break the grid at least twice: an image bleeding off the viewport edge, an image overlapping the next section (`-mb-[12vh] relative z-10`), oversized type running off the canvas.
|
|
219
|
-
- Vary the layouts: after a 5/7 split comes a full-bleed band or hairline rows, never three equal cards.
|
|
220
|
-
- Section padding varies by role: dense 6 to 8rem, breathers 12 to 20rem. One section should feel too empty by SaaS standards.
|
|
221
|
-
- Wayfinding without eyebrows: the heading itself, a hairline rule (`border-t border-line`), a change of surface step, a jump in scale.
|
|
222
|
-
- **Captions on media are allowed:** a metadata line directly under or on an image or frame, describing it ("Klant · Woningbouw · 2025"), may be small and tracked. Set it as `<figcaption>` or mark it `data-caption`. A label above a section heading stays an eyebrow and stays banned, and so do numbered steps.
|
|
223
|
-
- **A display heading never sits under or behind an image box,** and never inside an `overflow-hidden` box that would clip its letters: give it its own grid cell beside the image. `check.mjs` fails a clipped display heading and an image reference past what the pack holds (`images.card[5]` when the pack kept four), which renders as an empty swatch. The inline photos of `toonstuk-manifesto-scrub` are a word's size: give them a subject (card, column or hero photos), never a texture (detail, backdrop), which reads as a grey swatch.
|
|
224
|
-
|
|
225
|
-
### Step 8: The showpieces (toonstuk)
|
|
226
|
-
|
|
227
|
-
Struq builds impressive agency, brand, product and company sites, not simple conversion pages. The showpieces are what make them so: directed, pinned, scroll-scrubbed scenes on the one clock. `recipes.mjs` copies them to `components/struq/showpieces/`, one file per stable slug; each has a composed still for phones and reduced motion built in.
|
|
228
|
-
|
|
229
|
-
**Pick one lead showpiece and at most one supporting move,** from this table, by the kind of client. Do not improvise a third. When the user names one in the brief ("met de project-stack", "with the panel wipe"), use that one as the lead, whatever the table says.
|
|
230
|
-
|
|
231
|
-
| The client is | Lead showpiece | Supporting move (at most one) |
|
|
232
|
-
|---|---|---|
|
|
233
|
-
| Architect, studio or portfolio with real project photos | `toonstuk-project-stack` | `toonstuk-image-to-fullbleed` |
|
|
234
|
-
| Architect, studio or portfolio without project photos | `toonstuk-image-to-fullbleed` | `toonstuk-manifesto-scrub` |
|
|
235
|
-
| Product launch | `toonstuk-image-to-fullbleed`, with the hero scene carrying the product | `toonstuk-pixel-resolve` in the hero |
|
|
236
|
-
| Restaurant, hospitality, hotel | `toonstuk-panel-wipe` | `toonstuk-manifesto-scrub` |
|
|
237
|
-
| Agency or creative brand | `toonstuk-scrub-connector` | `toonstuk-fill-rows` for the services |
|
|
238
|
-
| Editorial, a writer, a publication | `toonstuk-manifesto-scrub` | `toonstuk-image-to-fullbleed` |
|
|
239
|
-
| Anything else | `toonstuk-image-to-fullbleed` | none |
|
|
240
|
-
|
|
241
|
-
Every site closes with `toonstuk-wordmark-finale` as its footer; it does not count as the supporting move.
|
|
242
|
-
|
|
243
|
-
| Slug | Component | What it does |
|
|
244
|
-
|---|---|---|
|
|
245
|
-
| `toonstuk-image-to-fullbleed` | `ImageToFullbleed` | A small centred photo unclips to the full viewport while pinned, the name split to either side and travelling off the edges, one line rising over the open photo. |
|
|
246
|
-
| `toonstuk-panel-wipe` | `PanelWipe` | Two ground-colour panels, each carrying one word, part to reveal a full-bleed photo and close again over it, carrying the headline into the next scene. |
|
|
247
|
-
| `toonstuk-scrub-connector` | `ScrubConnector` | One accent bar rotates, stretches and travels across a pinned stretch until it lands as a level line between two words. |
|
|
248
|
-
| `toonstuk-project-stack` | `ProjectStack` | Pinned full-bleed project cards slide over each other, the one beneath receding; the cursor becomes a round "Bekijk" label over them. Only with the client's own project photos. |
|
|
249
|
-
| `toonstuk-manifesto-scrub` | `ManifestoScrub` | One large statement fills word by word on scroll, with small photos opening inside the line (`{0}`, `{1}` in the text). |
|
|
250
|
-
| `toonstuk-fill-rows` | `FillRows` | Large hairline rows of services or chapters; on hover and focus a row floods with the accent and its detail slides in. |
|
|
251
|
-
| `toonstuk-wordmark-finale` | `WordmarkFinale` | The footer: the name fitted edge to edge, letters rising out of a mask, one closing line and a live local clock. |
|
|
252
|
-
| `toonstuk-pixel-resolve` | `PixelResolve` | The hero photo arrives as coarse pixels and resolves to sharp in held steps, then the plain image stays. |
|
|
253
|
-
|
|
254
|
-
**The direction these showpieces need** (they look cheap without it):
|
|
255
|
-
- Two or three colours from the canon palette, at full strength: the ground, the ink, the accent. No tints.
|
|
256
|
-
- Display type at 12 to 20vw against small body copy. The display type is the composition, not a heading above it.
|
|
257
|
-
- One italic serif accent at most, on one word.
|
|
258
|
-
- Full-bleed beeldbank photography (or the client's own), never framed small in a box when a scene can carry it.
|
|
259
|
-
- One idea per screen. Hold on it.
|
|
260
|
-
- Transitions are scale, mask and clip moves between full-bleed scenes, never fades between boxes.
|
|
261
|
-
- SplitText on display lines, long eases, holds on every key frame; nothing bounces.
|
|
262
|
-
- Struq's rules still win over any reference: no eyebrow or dot labels, no pills (the round cursor label is not a pill), no stat rows ("20+", "51+"), no three identical cards, no numbered sections, no mono flavour, no Inter, no dashes, no blue or purple by default, and never a reference's layout, copy or images.
|
|
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/`.
|
|
263
76
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
- `npm run build` must pass. Fix type errors in your own code; never delete a recipe to get green.
|
|
273
|
-
- **Look**, when you have a browser tool: serve the production build (`npx next start -p 4321`), screenshot 390 and 1440, scroll the page once top to bottom. Check: the headline reads, no frame is blank after its reveal, the showpiece engages and releases without a jump, nothing overflows sideways at 390. No browser tool: write `Verify: not seen, no browser` in STRUQ.md. Never claim you saw what you did not.
|
|
274
|
-
- **Check**: `node <skill-dir>/scripts/check.mjs`. Fix every FAIL at its file and line, run it again, and repeat until `RESULT: PASS`. Then tick line 12 and report.
|
|
275
|
-
|
|
276
|
-
## With the Struq MCP (Pro): the build line
|
|
277
|
-
|
|
278
|
-
When the `struq_*` tools are connected, the build runs on Struq's build line, and this checklist replaces steps 2, 4 and 7 of the Build checklist (the others stay). Every call is logged with `log.mjs mcp`; `check.mjs` fails a build whose log shows a bouwplan but fewer sectiespec calls than the plan's arc rows, and an approval stop that is not between the bouwplan and the projectschil.
|
|
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:
|
|
279
84
|
|
|
280
85
|
```
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
node <skill-dir>/scripts/log.mjs mcp struq_motion --token <planToken>
|
|
291
|
-
- [ ] M5 struq_achtergrond: build the background it returns as the hero scene (below)
|
|
292
|
-
node <skill-dir>/scripts/log.mjs mcp struq_achtergrond --token <planToken>
|
|
293
|
-
- [ ] M6 For EVERY arc row, in order: struq_sectiespec with the planToken and the row, then write
|
|
294
|
-
that row's code from the spec, then log it. Never write a row without its spec.
|
|
295
|
-
node <skill-dir>/scripts/log.mjs mcp struq_sectiespec --row <n> --id <arc id> --token <planToken>
|
|
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>
|
|
296
95
|
```
|
|
297
96
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
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)).
|
|
330
165
|
|
|
331
166
|
## When something goes wrong
|
|
332
167
|
|
|
333
|
-
- **
|
|
334
|
-
- **
|
|
335
|
-
- **
|
|
336
|
-
|
|
337
|
-
- **
|
|
338
|
-
|
|
339
|
-
## Depth, when a step needs it
|
|
340
|
-
|
|
341
|
-
Per client type (tension, type, palette fallback, motion, arc, the niche tells, the pack) [niche-packets.md](references/niche-packets.md) · Typography [typography.md](references/typography.md) · palettes and presets [vibe-presets.md](references/vibe-presets.md) · page arc and footer [page-architecture.md](references/page-architecture.md) · composition [composition.md](references/composition.md), on phones [mobile-composition.md](references/mobile-composition.md) · imagery and grading [imagery.md](references/imagery.md), the beeldbank [struq-imagery.md](references/struq-imagery.md) · reveals [scroll-reveals.md](references/scroll-reveals.md) · more showpieces [showcase.md](references/showcase.md), [pinning-scrub.md](references/pinning-scrub.md) · the feel layer [feel-layer.md](references/feel-layer.md) · nav and menus [nav-header.md](references/nav-header.md) · route transitions [route-transitions.md](references/route-transitions.md), loaders [loaders.md](references/loaders.md) · SVG motion [svg-motion.md](references/svg-motion.md) · pointer [micro-interactions.md](references/micro-interactions.md) · WebGL beyond the hero [webgl-r3f.md](references/webgl-r3f.md), [webgl-scenes.md](references/webgl-scenes.md), hero scenes [hero-scenes.md](references/hero-scenes.md) · brand from nothing [brand.md](references/brand.md) · SEO [seo.md](references/seo.md) · performance [performance.md](references/performance.md) · a long, interactive planning session [direction.md](references/direction.md).
|
|
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).
|