@struq/skill 0.4.3 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/README.md +1 -1
  2. package/package.json +2 -2
  3. package/skills/struq/SKILL.md +145 -89
  4. package/skills/struq/blocks/CATALOG.md +74 -22
  5. package/skills/struq/blocks/backgrounds/background-aurora.tsx +34 -12
  6. package/skills/struq/blocks/backgrounds/background-facets.tsx +14 -6
  7. package/skills/struq/blocks/backgrounds/background-silk.tsx +40 -15
  8. package/skills/struq/blocks/catalog.json +697 -16
  9. package/skills/struq/blocks/film.json +426 -0
  10. package/skills/struq/blocks/footers/footer-contact.tsx +81 -55
  11. package/skills/struq/blocks/footers/footer-reveal.tsx +1 -1
  12. package/skills/struq/blocks/headers/header-bar.tsx +24 -13
  13. package/skills/struq/blocks/headers/menu-curtain.tsx +24 -11
  14. package/skills/struq/blocks/heroes/hero-framed.tsx +33 -20
  15. package/skills/struq/blocks/heroes/hero-index.tsx +32 -11
  16. package/skills/struq/blocks/heroes/hero-poster.tsx +68 -35
  17. package/skills/struq/blocks/heroes/hero-split.tsx +22 -9
  18. package/skills/struq/blocks/heroes/hero-still.tsx +80 -74
  19. package/skills/struq/blocks/kit/accent.ts +82 -0
  20. package/skills/struq/blocks/kit/blocks.css +78 -35
  21. package/skills/struq/blocks/kit/quiet/Close.tsx +73 -0
  22. package/skills/struq/blocks/kit/quiet/PhotoText.tsx +79 -0
  23. package/skills/struq/blocks/kit/quiet/Rows.tsx +81 -0
  24. package/skills/struq/blocks/kit/quiet/Statement.tsx +157 -0
  25. package/skills/struq/blocks/kit/quiet/index.ts +7 -0
  26. package/skills/struq/blocks/kit/quiet/sheet.ts +12 -0
  27. package/skills/struq/blocks/page-transitions/page-transition-gate.tsx +87 -36
  28. package/skills/struq/blocks/preloaders/preloader-gate.tsx +116 -46
  29. package/skills/struq/blocks/preloaders/preloader-stack.tsx +10 -7
  30. package/skills/struq/blocks/sections/contact-form.tsx +1 -1
  31. package/skills/struq/blocks/sections/cta-closing.tsx +3 -2
  32. package/skills/struq/blocks/sections/fanned-cards.tsx +14 -10
  33. package/skills/struq/blocks/sections/film-strip.tsx +18 -14
  34. package/skills/struq/blocks/sections/grid-assembly.tsx +16 -11
  35. package/skills/struq/blocks/sections/manifesto.tsx +3 -2
  36. package/skills/struq/blocks/sections/panel-accordion.tsx +3 -2
  37. package/skills/struq/blocks/sections/split-pair.tsx +4 -3
  38. package/skills/struq/blocks/showpieces/hero-opener.tsx +76 -17
  39. package/skills/struq/blocks/showpieces/wordmark-finale.tsx +3 -1
  40. package/skills/struq/blocks/transitions/zoom-through.tsx +9 -10
  41. package/skills/struq/canon/canon.json +1 -1
  42. package/skills/struq/references/craft.md +4 -0
  43. package/skills/struq/references/film.md +158 -0
  44. package/skills/struq/references/triage.md +3 -0
  45. package/skills/struq/scripts/blocks.mjs +89 -7
  46. package/skills/struq/scripts/canon.mjs +8 -1
  47. package/skills/struq/scripts/check.mjs +94 -11
  48. package/skills/struq/scripts/film-check.mjs +997 -0
  49. package/skills/struq/scripts/gate.mjs +146 -0
  50. package/skills/struq/scripts/packs.mjs +73 -12
@@ -1,12 +1,13 @@
1
1
  # Block catalogue
2
2
 
3
- Generated by scripts/release-blocks.mjs from Struq origin/main at a2b7d56. Do not edit: run the release script again.
3
+ Generated by scripts/release-blocks.mjs from Struq origin/main at 95e54a2. Do not edit: run the release script again.
4
4
  44 admitted blocks. Install one with `node <skill-dir>/scripts/blocks.mjs add <slug>`; read its file for the props.
5
5
  Every block works light and dark; a variant is a different composition of the same idea, passed as `variant`.
6
6
 
7
7
  ## Preloaders
8
8
 
9
9
  ### preloader-wordmark
10
+ film: role frame · home curtain · motif word · energy 2 · pins 0 · none
10
11
 
11
12
  Preloader: the wordmark. The first paint is the page's ground with the studio's name set huge across the screen in the display face at a light weight, fitted to the width with the loaded face; each letter fills through a rising mask, a faint tone first and the ink rising inside it, driven by real progress between a floor and a cap; then the name opens as a curtain onto the hero (split along its middle, dropped letter by letter, or settled into the header's wordmark) within 2.4 seconds of the first paint, once per session (helper: preloaders/preloader-slices-uncovered.ts).
12
13
 
@@ -19,29 +20,33 @@ Exports: `PreloaderWordmark`. Packages: @gsap/react, gsap.
19
20
  Files: `kit/blocks.css`, `kit/gsap.ts`, `preloaders/preloader-slices-uncovered.ts`, `preloaders/preloader-wordmark.tsx`.
20
21
 
21
22
  ### preloader-stack
23
+ film: role frame · home weight · motif frame · energy 2 · pins 0 · counter
22
24
 
23
- Preloader: the stack. The first paint is the page's ground with the client's name, a quiet count and the first print in a small portrait frame; five or six prints cut inside that frame, each held shorter than the last, ending on the hero's own photo, and the frame then grows to the hero image's exact place and crop (the page marks it data-stack-target) so the cover becomes the hero with no seam, within 2.4 seconds of the first paint, once per session (helper: preloaders/preloader-slices-uncovered.ts).
25
+ Preloader: the stack. The first paint is the page's ground with the client's name, a quiet count and the first print in a small portrait frame; five or six prints cut inside that frame, each held shorter than the last, ending on the hero's own photo, and the frame then grows to the hero image's exact place and crop (the page marks it data-stack-target) so the cover becomes the hero with no seam, within 2.4 seconds of the first paint, once per session.
24
26
 
25
27
  Exports: `PreloaderStack`. Packages: @gsap/react, gsap.
26
28
  Files: `kit/blocks.css`, `kit/gsap.ts`, `kit/images.ts`, `preloaders/preloader-slices-uncovered.ts`, `preloaders/preloader-stack.tsx`.
27
29
 
28
30
  ### preloader-slices
31
+ film: role frame · home cut · motif cut · energy 2 · pins 0 · counter
29
32
 
30
- Preloader: the slices. The first paint is a dark cover cut into four vertical slices (three on phones), already composed: the client's name large, a caption, a hairline and the count at 000; the count runs to 100 in one move, then the slices drop away left to right, each carrying its strip of the name and count down and off behind a 5px accent edge, uncovering the page from the top onto its own entrance, within 2.4 seconds of the first paint, once per session (helper: preloaders/preloader-slices-uncovered.ts).
33
+ Preloader: the slices. The first paint is a dark cover cut into four vertical slices (three on phones), already composed: the client's name large, a caption, a hairline and the count at 000; the count runs to 100 in one move, then the slices drop away left to right, each carrying its strip of the name and count down and off behind a 5px accent edge, uncovering the page from the top onto its own entrance, within 2.4 seconds of the first paint, once per session.
31
34
 
32
35
  Exports: `PreloaderSlices`. Packages: @gsap/react, gsap.
33
36
  Files: `kit/blocks.css`, `kit/gsap.ts`, `preloaders/preloader-slices-uncovered.ts`, `preloaders/preloader-slices.tsx`.
34
37
 
35
38
  ### preloader-gate
39
+ film: role frame · home curtain · motif aperture · energy 2 · pins 0 · counter
36
40
 
37
- Preloader: the gate. The first paint is a shut gate with a whole film-leader dial and one figure; only the sweep moves, counting 3, 2, 1 on an eased count that waits for the fonts and the hero image, then the line through the middle lights and the two bars open top and bottom onto the hero, by 2.4 seconds from the first paint, once per session.
41
+ Preloader: the gate. The first paint is a shut gate with a hairline ring on its middle line; an accent arc fills the ring on an eased count that waits for the fonts and the hero image (cutting through the client's own marks, one per beat, when given), then the line through the middle lights and the two bars open top and bottom onto the hero, by 2.4 seconds from the first paint, once per session (helper: preloaders/preloader-slices-uncovered.ts).
38
42
 
39
43
  Exports: `PreloaderGate`. Packages: @gsap/react, gsap.
40
- Files: `kit/blocks.css`, `kit/gsap.ts`, `preloaders/preloader-gate.tsx`.
44
+ Files: `kit/blocks.css`, `kit/gsap.ts`, `preloaders/preloader-gate.tsx`, `preloaders/preloader-slices-uncovered.ts`.
41
45
 
42
46
  ## Page transitions
43
47
 
44
48
  ### page-transition-stack
49
+ film: role frame · home weight · motif frame · energy 2 · pins 0 · none
45
50
 
46
51
  Page transition: the stack. On every link click and on back and forward, a small portrait print of the destination's own hero photo appears where the pointer is (centred for keys and history) and grows to fill the screen while the route loads under it, then settles into the new page's hero at its exact place and crop, so arriving is the preloader's own landing, under 0.9 seconds door to door; a print not decoded in time becomes the destination's name on the page ground and the cover lifts away instead (helper: preloaders/preloader-slices-uncovered.ts).
47
52
 
@@ -49,6 +54,7 @@ Exports: `PageTransitionStack`. Packages: @gsap/react, gsap, lenis.
49
54
  Files: `kit/SmoothScroll.tsx`, `kit/blocks.css`, `kit/gsap.ts`, `page-transitions/page-transition-stack.tsx`, `preloaders/preloader-slices-uncovered.ts`.
50
55
 
51
56
  ### page-transition-slices
57
+ film: role frame · home cut · motif cut · energy 2 · pins 0 · none
52
58
 
53
59
  Page transition: the slices. On every link click and on back and forward, the slices of preloader-slices come in from above and close over the page with the destination's name and a running hairline, the route loads under them, and they carry on down and off, uncovering the new page from the top onto its entrance, about 0.65 seconds door to door, with focus, hashes and scroll restored (helper: preloaders/preloader-slices-uncovered.ts).
54
60
 
@@ -56,29 +62,33 @@ Exports: `PageTransitionSlices`. Packages: @gsap/react, gsap, lenis.
56
62
  Files: `kit/SmoothScroll.tsx`, `kit/blocks.css`, `kit/gsap.ts`, `page-transitions/page-transition-slices.tsx`, `preloaders/preloader-slices-uncovered.ts`.
57
63
 
58
64
  ### page-transition-gate
65
+ film: role frame · home curtain · motif aperture · energy 2 · pins 0 · none
59
66
 
60
- Page transition: the gate. On every navigation, back button included, the preloader's bars close carrying the two halves of a slate (the dial and the destination's name), lock into one frame as the line and the dial light, hold while the route changes, then split the name and open onto the finished page, 0.9 seconds door to door.
67
+ Page transition: the gate. On every navigation, back button included, the preloader's bars close carrying the two halves of a frame (a hairline ring and the destination's name), lock into one as the line and the ring light, hold while the route changes, then split the name and open onto the finished page, 0.9 seconds door to door (helper: preloaders/preloader-slices-uncovered.ts).
61
68
 
62
69
  Exports: `GateLink`, `GateStage`, `PageTransitionGate`. Packages: @gsap/react, gsap, lenis.
63
- Files: `kit/SmoothScroll.tsx`, `kit/blocks.css`, `kit/gsap.ts`, `page-transitions/page-transition-gate.tsx`.
70
+ Files: `kit/SmoothScroll.tsx`, `kit/blocks.css`, `kit/gsap.ts`, `page-transitions/page-transition-gate.tsx`, `preloaders/preloader-slices-uncovered.ts`.
64
71
 
65
72
  ## Headers
66
73
 
67
74
  ### header-bar
75
+ film: role frame · home none · motif neutral · energy 1 · pins 0 · hover · clock by prop clock
76
+ film variants: settle energy 2
68
77
 
69
- Header: the bar. A fixed bar with the wordmark Noord, four links and one quiet text action, its ink changing per pixel at the edges of the sections under it, taking the ground once the page scrolls and keeping the hero's type clear; it hides and returns with the scroll and rolls each label, lands a large hero wordmark in the bar, or carries centred links, Rotterdam's live time and a progress rule; on phones it collapses to the wordmark and one Menu link.
78
+ Header: the bar. A fixed bar with the wordmark Noord, four links and one quiet text action, its ink changing per pixel at the edges of the sections under it, taking the ground once the page scrolls and keeping the hero's type clear; it hides and returns with the scroll and rolls each label, lands a large hero wordmark in the bar, or carries centred links, the studio's place (its live time only with clock) and a progress rule; on phones it collapses to the wordmark and one Menu link.
70
79
 
71
80
  Variants (`variant`, the first is the default):
72
81
  - `quiet`: Wordmark left, links right, each label rolling letter by letter on hover; the bar hides as the page scrolls down and returns on scroll up, a hairline under it once scrolled.
73
82
  - `settle`: The wordmark is set large across the hero and shrinks into its place in the bar as the page scrolls, the links fading in as it lands.
74
- - `split`: Wordmark left, links centred with a line gliding under the hovered one, Rotterdam's live time and the action right, and a thin rule filling with the page's progress.
83
+ - `split`: Wordmark left, links centred with a line gliding under the hovered one, the studio's place (its live time only with clock) and the action right, and a thin rule filling with the page's progress.
75
84
 
76
85
  Exports: `HeaderBar`. Packages: @gsap/react, gsap.
77
86
  Files: `headers/header-bar.tsx`, `kit/blocks.css`, `kit/gsap.ts`.
78
87
 
79
88
  ### menu-curtain
89
+ film: role frame · home curtain · motif aperture · energy 1 · pins 0 · clock, hover · clock by prop clock
80
90
 
81
- Menu: the curtain. A minimal bar (wordmark Noord, one button that rolls Menu to Sluiten) whose ink changes exactly at the edge of the section under it, opening a full-screen menu as a curtain in the gate, slices or stack language: five large links rise through masks, the hovered or focused link shows its decoded photo on the calm side, and a foot line carries the contact address and Rotterdam local time; it closes the same way reversed, a close overtaken by an open turns round, and the page under it is held still and inert while it is open.
91
+ Menu: the curtain. A minimal bar (wordmark Noord, one button that rolls Menu to Sluiten) whose ink changes exactly at the edge of the section under it, opening a full-screen menu as a curtain in the gate, slices or stack language: five large links rise through masks, the hovered or focused link shows its decoded photo on the calm side, and a foot line carries the contact address and the place of the studio (its live local time only with clock); it closes the same way reversed, a close overtaken by an open turns round, and the page under it is held still and inert while it is open.
82
92
 
83
93
  Variants (`variant`, the first is the default):
84
94
  - `gate`: An accent line draws from the middle of the screen and the menu opens from it as two edges part; the photo opens from its own middle line on hover.
@@ -91,6 +101,7 @@ Files: `headers/menu-curtain.tsx`, `kit/SmoothScroll.tsx`, `kit/blocks.css`, `ki
91
101
  ## Heroes
92
102
 
93
103
  ### hero-framed
104
+ film: role opening · home none · motif frame · energy 3 · pins 1.5 · none
94
105
 
95
106
  Hero: the frame. One photograph hung on the page ground like a framed print, with four registration marks, a museum label and a caption, in three hangs: a small print at the centre you walk up to on the first scroll, the name set large on the wall with a tall print at the edge that opens over it, or a print that nearly fills the screen in a thin mat and steps back to a small portrait with the line beside it; pin 150%, the line on the photo's measured calm side or on the wall.
96
107
 
@@ -100,9 +111,11 @@ Variants (`variant`, the first is the default):
100
111
  - `passe`: A print that nearly fills the screen inside a thin mat; the first scroll steps back to a small portrait at the left with the line on the wall beside it.
101
112
 
102
113
  Exports: `HeroFramed`. Packages: @gsap/react, gsap.
103
- Files: `heroes/hero-framed.tsx`, `kit/blocks.css`, `kit/gsap.ts`, `kit/images.ts`, `kit/photo-read.ts`, `preloaders/preloader-slices-uncovered.ts`.
114
+ Files: `heroes/hero-framed.tsx`, `kit/accent.ts`, `kit/blocks.css`, `kit/gsap.ts`, `kit/images.ts`, `kit/photo-read.ts`, `preloaders/preloader-slices-uncovered.ts`.
104
115
 
105
116
  ### hero-split
117
+ film: role opening · home none · motif cut · energy 1 · pins 0 · none
118
+ film variants: opening energy 2 pins 0.9
106
119
 
107
120
  Hero: split. One headline set twice across a seam, in the ground's ink and the photo's ink, with a cycling discipline and its photograph: the seam stands upright, lies flat with the word rising through it, or opens with the first scroll from a strip at the edge to the split.
108
121
 
@@ -112,9 +125,11 @@ Variants (`variant`, the first is the default):
112
125
  - `opening`: At rest the ground fills the screen and the photo is a strip at the edge; the first scroll opens it to the split while the headline turns to the photo ink as the edge passes.
113
126
 
114
127
  Exports: `HeroSplit`. Packages: @gsap/react, gsap.
115
- Files: `heroes/hero-split.tsx`, `kit/blocks.css`, `kit/gsap.ts`, `kit/images.ts`, `kit/photo-read.ts`, `preloaders/preloader-slices-uncovered.ts`.
128
+ Files: `heroes/hero-split.tsx`, `kit/accent.ts`, `kit/blocks.css`, `kit/gsap.ts`, `kit/images.ts`, `kit/photo-read.ts`, `preloaders/preloader-slices-uncovered.ts`.
116
129
 
117
130
  ### hero-index
131
+ film: role opening · home none · motif neutral · energy 1 · pins 0 · hover
132
+ film variants: doorlopen energy 3 pins 2.4
118
133
 
119
134
  Hero: the index. The studio's list of work as the first screen, each name calling up its project's photograph: full screen behind the list on hover, in a window beside the list on the ground, or walked one by one by the first scroll while the hero holds.
120
135
 
@@ -124,11 +139,13 @@ Variants (`variant`, the first is the default):
124
139
  - `doorlopen`: The list centred over the photograph while the hero holds; each stretch of the first scroll raises the next project and steps its name forward.
125
140
 
126
141
  Exports: `HeroIndex`. Packages: @gsap/react, gsap.
127
- Files: `heroes/hero-index.tsx`, `kit/blocks.css`, `kit/gsap.ts`, `kit/images.ts`, `kit/photo-read.ts`, `preloaders/preloader-slices-uncovered.ts`.
142
+ Files: `heroes/hero-index.tsx`, `kit/accent.ts`, `kit/blocks.css`, `kit/gsap.ts`, `kit/images.ts`, `kit/photo-read.ts`, `preloaders/preloader-slices-uncovered.ts`.
128
143
 
129
144
  ### hero-still
145
+ film: role opening · home none · motif neutral · energy 1 · pins 0 · clock · clock by prop clock
146
+ film variants: frame energy 2 pins 1
130
147
 
131
- Hero: full-bleed still. One photograph with a title in three compositions: full bleed with a slow push-in and the headline on its measured calm side, held in a frame of page ground opening to full bleed by registration on the first scroll, or the headline split across the photo's horizon; the caption strip with place, live time and one link under all three, and preloaders land on its photo box.
148
+ Hero: full-bleed still. One photograph with a title in three compositions: full bleed with a slow push-in and the headline on its measured calm side, held in a frame of page ground opening to full bleed by registration on the first scroll, or the headline split across the photo's horizon; a caption strip with the place, one fact in the client's words (or, with clock, the live time) and one link under all three, and preloaders land on its photo box.
132
149
 
133
150
  Variants (`variant`, the first is the default):
134
151
  - `still`: Full bleed with a slow push-in and the headline on the photo's measured calm side.
@@ -136,9 +153,10 @@ Variants (`variant`, the first is the default):
136
153
  - `horizon`: The headline split at the photo's horizon, each half in the ink its side measures for, the halves closing on the horizon.
137
154
 
138
155
  Exports: `HeroStill`. Packages: @gsap/react, gsap.
139
- Files: `heroes/hero-still.tsx`, `kit/blocks.css`, `kit/gsap.ts`, `kit/images.ts`, `kit/photo-read.ts`, `preloaders/preloader-slices-uncovered.ts`.
156
+ Files: `heroes/hero-still.tsx`, `kit/accent.ts`, `kit/blocks.css`, `kit/gsap.ts`, `kit/images.ts`, `kit/photo-read.ts`, `preloaders/preloader-slices-uncovered.ts`.
140
157
 
141
158
  ### hero-poster
159
+ film: role opening · home none · motif aperture · energy 3 · pins 1.5 · none
142
160
 
143
161
  Hero: poster type. The first screen as a poster in three compositions: two fitted lines with a letterbox window between them, a narrow slit cutting through the type in the photo's measured ink, or one word per row with a window of a different crop between each pair; on the first scroll (pin 150%) the type parts while the windows open by registration into the full-bleed photo; phones keep the composition with the entrance only.
144
162
 
@@ -148,11 +166,12 @@ Variants (`variant`, the first is the default):
148
166
  - `stack`: One word per row with a window of a different crop between each pair; on scroll the rows part and the crops slide into one photograph.
149
167
 
150
168
  Exports: `HeroPoster`. Packages: @gsap/react, gsap.
151
- Files: `heroes/hero-poster.tsx`, `heroes/hero-still.tsx`, `kit/blocks.css`, `kit/gsap.ts`, `kit/images.ts`, `kit/photo-read.ts`, `preloaders/preloader-slices-uncovered.ts`.
169
+ Files: `heroes/hero-poster.tsx`, `heroes/hero-still.tsx`, `kit/accent.ts`, `kit/blocks.css`, `kit/gsap.ts`, `kit/images.ts`, `kit/photo-read.ts`, `preloaders/preloader-slices-uncovered.ts`.
152
170
 
153
171
  ## Backgrounds
154
172
 
155
173
  ### background-aurora
174
+ film: role opening · home none · motif field · energy 2 · pins 0 · none
156
175
 
157
176
  Background: Noorderlicht. A full-screen hero on a live field of northern light: slow curtains hang from folding hems with long drifting rays, in the palette's accent over its ground, so it is soft ink on paper in light palettes and real light in dark ones.
158
177
 
@@ -162,9 +181,10 @@ Variants (`variant`, the first is the default):
162
181
  - `drift`: Curtains across the upper half, drifting slowly sideways and bending away from the pointer.
163
182
 
164
183
  Exports: `BackgroundAurora`. Packages: @gsap/react, gsap.
165
- Files: `backgrounds/background-aurora.tsx`, `kit/blocks.css`, `kit/gsap.ts`.
184
+ Files: `backgrounds/background-aurora.tsx`, `kit/accent.ts`, `kit/blocks.css`, `kit/gsap.ts`, `preloaders/preloader-slices-uncovered.ts`.
166
185
 
167
186
  ### background-silk
187
+ film: role opening · home none · motif field · energy 2 · pins 0 · cursor
168
188
 
169
189
  Background: Zijde. A sheet of silk in raking light behind the headline: long soft folds, the cloth one step off the page ground, and a sheen in the accent that travels slowly over the crests.
170
190
 
@@ -174,9 +194,10 @@ Variants (`variant`, the first is the default):
174
194
  - `drape`: The cloth hangs from the top edge in rounded pleats down to a wavy hem; scrolling the hero away draws the hem down and stretches the pleats.
175
195
 
176
196
  Exports: `BackgroundSilk`. Packages: @gsap/react, gsap.
177
- Files: `backgrounds/background-silk.tsx`, `kit/blocks.css`, `kit/gsap.ts`.
197
+ Files: `backgrounds/background-silk.tsx`, `kit/accent.ts`, `kit/blocks.css`, `kit/gsap.ts`, `preloaders/preloader-slices-uncovered.ts`.
178
198
 
179
199
  ### background-facets
200
+ film: role opening · home none · motif field · energy 2 · pins 0 · none
180
201
 
181
202
  Background: Facetten. A full-screen surface of cut planes on a triangle lattice, every crease a crisp hairline where two planes really fold, each plane catching a slow travelling light in the palette's accent, with the type on the flat ground of the calm side.
182
203
 
@@ -186,18 +207,20 @@ Variants (`variant`, the first is the default):
186
207
  - `turn`: Diagonal pleats in the upper left cut into planes; the light turns across them as the hero scrolls away and leans toward the pointer.
187
208
 
188
209
  Exports: `BackgroundFacets`. Packages: @gsap/react, gsap.
189
- Files: `backgrounds/background-facets.tsx`, `kit/blocks.css`, `kit/gsap.ts`, `preloaders/preloader-slices-uncovered.ts`.
210
+ Files: `backgrounds/background-facets.tsx`, `kit/accent.ts`, `kit/blocks.css`, `kit/gsap.ts`, `preloaders/preloader-slices-uncovered.ts`.
190
211
 
191
212
  ## Showpieces
192
213
 
193
214
  ### hero-opener
215
+ film: role opening · home none · motif word · energy 2 · pins 1 · magnetic
194
216
 
195
217
  Hero opener. A full-bleed photo (or the WebGL scene over it) with the display line at 14 to 20vw across it; on scroll it pins, scales down and darkens while the next section slides over.
196
218
 
197
219
  Exports: `HeroOpener`. Packages: @gsap/react, @types/three, gsap, three.
198
- Files: `kit/HeroCanvas.tsx`, `kit/MagneticButton.tsx`, `kit/SplitHeadline.tsx`, `kit/blocks.css`, `kit/gsap.ts`, `kit/images.ts`, `kit/scenes/contours.ts`, `kit/scenes/dots.ts`, `kit/scenes/ripple.ts`, `kit/scenes/types.ts`, `showpieces/hero-opener.tsx`.
220
+ Files: `kit/HeroCanvas.tsx`, `kit/MagneticButton.tsx`, `kit/accent.ts`, `kit/blocks.css`, `kit/gsap.ts`, `kit/images.ts`, `kit/scenes/contours.ts`, `kit/scenes/dots.ts`, `kit/scenes/ripple.ts`, `kit/scenes/types.ts`, `preloaders/preloader-slices-uncovered.ts`, `showpieces/hero-opener.tsx`.
199
221
 
200
222
  ### image-to-fullbleed
223
+ film: role centerpiece · home none · motif frame · energy 3 · pins 2.2 · none
201
224
 
202
225
  Image to full bleed. A small image between the two halves of a name unclips to the full screen as the words travel off the edges.
203
226
 
@@ -205,6 +228,7 @@ Exports: `ImageToFullbleed`. Packages: @gsap/react, gsap.
205
228
  Files: `kit/blocks.css`, `kit/gsap.ts`, `kit/images.ts`, `showpieces/image-to-fullbleed.tsx`.
206
229
 
207
230
  ### panel-wipe
231
+ film: role centerpiece · home none · motif aperture · energy 3 · pins 1.7 · none
208
232
 
209
233
  Panel wipe. Two panels carrying one word each slide apart to reveal a photo, and close again.
210
234
 
@@ -212,6 +236,7 @@ Exports: `PanelWipe`. Packages: @gsap/react, gsap.
212
236
  Files: `kit/blocks.css`, `kit/gsap.ts`, `kit/images.ts`, `showpieces/panel-wipe.tsx`.
213
237
 
214
238
  ### scrub-connector
239
+ film: role centerpiece · home none · motif line · energy 3 · pins 3 · none
215
240
 
216
241
  Scrub connector. Two words far apart with a tall slab of ink between them; the slab swings into one thick slash through both words (their letters knocked out where it crosses), then carries the words in on its two ends, turning to the accent as it travels, and seats long and rising between them; the joined pair holds and scrolls away whole.
217
242
 
@@ -219,6 +244,7 @@ Exports: `ScrubConnector`. Packages: @gsap/react, gsap.
219
244
  Files: `kit/blocks.css`, `kit/gsap.ts`, `showpieces/scrub-connector.tsx`.
220
245
 
221
246
  ### project-stack
247
+ film: role centerpiece · home none · motif neutral · energy 3 · pins 3.3 · none
222
248
 
223
249
  Project stack. One project per screen; each slides up full bleed over the last while the one beneath recedes.
224
250
 
@@ -226,6 +252,7 @@ Exports: `ProjectStack`. Packages: @gsap/react, gsap.
226
252
  Files: `kit/blocks.css`, `kit/gsap.ts`, `kit/images.ts`, `showpieces/project-stack.tsx`.
227
253
 
228
254
  ### manifesto-scrub
255
+ film: role centerpiece · home none · motif word · energy 3 · pins 2 · none
229
256
 
230
257
  Manifesto scrub. One large statement that fills word by word, from a faint ink to full ink, as it scrolls through the screen.
231
258
 
@@ -233,6 +260,7 @@ Exports: `ManifestoScrub`. Packages: @gsap/react, gsap.
233
260
  Files: `kit/blocks.css`, `kit/gsap.ts`, `showpieces/manifesto-scrub.tsx`.
234
261
 
235
262
  ### fill-rows
263
+ film: role pattern · home none · motif neutral · energy 1 · pins 0 · hover
236
264
 
237
265
  Fill rows. Large hairline rows; on hover or focus a row floods with the accent from below and its detail slides in.
238
266
 
@@ -240,6 +268,7 @@ Exports: `FillRows`. Packages: @gsap/react, gsap.
240
268
  Files: `kit/blocks.css`, `kit/gsap.ts`, `showpieces/fill-rows.tsx`.
241
269
 
242
270
  ### pixel-resolve
271
+ film: role pattern · home none · motif neutral · energy 1 · pins 0 · none
243
272
 
244
273
  Pixel resolve. A photo that arrives as coarse pixels and resolves to full sharpness.
245
274
 
@@ -247,6 +276,7 @@ Exports: `PixelResolve`. Packages: @gsap/react, gsap.
247
276
  Files: `kit/blocks.css`, `kit/images.ts`, `showpieces/pixel-resolve.tsx`.
248
277
 
249
278
  ### wordmark-finale
279
+ film: role frame · home none · motif word · energy 1 · pins 0 · clock · clock by prop timeZone
250
280
 
251
281
  Wordmark finale. The footer as a finale: the name fitted edge to edge, rising out of a mask, with a closing line and a live local clock.
252
282
 
@@ -256,6 +286,7 @@ Files: `kit/blocks.css`, `kit/gsap.ts`, `showpieces/wordmark-finale.tsx`.
256
286
  ## Scene transitions
257
287
 
258
288
  ### zoom-through
289
+ film: role centerpiece · home none · motif aperture · energy 3 · pins 3 · none
259
290
 
260
291
  Zoom-through. A pinned composed frame (the display line and a lead on the ground, the photo in an upright window with its caption and corner marks) holds; then the camera pushes into the window: the type, nearer the lens, scales away past the edges, the window opens until all four edges leave the screen together, and the photo, deeper than the window, settles out of its push-in to full bleed with its subject held in place; a strip of the ground rises from the bottom edge with the line and caption, and the next section's heading, at the display size of the frame it left, rises out of masks in the photo where its pixels allow a light or dark ink at 4.5:1 (the calm side first, then the window's side), or on bands of ground stepped up from the strip where they do not (or cannot be read), holds, and the pin lets go with the photo drifting slower than the page.
261
292
 
@@ -265,6 +296,8 @@ Files: `kit/blocks.css`, `kit/gsap.ts`, `kit/images.ts`, `kit/photo-read.ts`, `t
265
296
  ## Sections
266
297
 
267
298
  ### about-studio
299
+ film: role pattern · home none · motif frame · energy 2 · pins 0 · none
300
+ film variants: doorkijk energy 3 pins 1.3
268
301
 
269
302
  About the studio. Who the studio is (a statement, a paragraph, honest facts and the place given real space), as a plate that opens out of the margins, a walk past two columns of photographs beside sticky type, or a slit of photograph that opens and pushes the statement's halves apart.
270
303
 
@@ -277,6 +310,8 @@ Exports: `AboutStudio`. Packages: @gsap/react, gsap.
277
310
  Files: `kit/blocks.css`, `kit/gsap.ts`, `kit/images.ts`, `sections/about-studio.tsx`.
278
311
 
279
312
  ### approach
313
+ film: role pattern · home none · motif line · energy 2 · pins 0 · none
314
+ film variants: zin energy 3 pins 2.4; schuif energy 1
280
315
 
281
316
  Approach. How the studio works from first conversation to handover, told without numbers: a line that draws down the page with the stages hanging off it, one pinned sentence whose clauses come to ink in turn, or an index you scrub by drag, click or arrow keys while the photographs wipe across in register.
282
317
 
@@ -289,6 +324,8 @@ Exports: `Approach`. Packages: @gsap/react, gsap.
289
324
  Files: `kit/blocks.css`, `kit/gsap.ts`, `kit/images.ts`, `sections/approach.tsx`.
290
325
 
291
326
  ### manifesto
327
+ film: role pattern · home none · motif line · energy 3 · pins 2 · none
328
+ film variants: quote energy 2 pins 0; split pins 1.5
292
329
 
293
330
  Manifesto. The studio's statement as the page's moment of conviction: written in line by line behind a caret, set as a pull quote over a drifting photograph on its measured calm side, or split across a short pin where the second half arrives sentence by sentence until the whole statement stands.
294
331
 
@@ -301,6 +338,7 @@ Exports: `Manifesto`. Packages: @gsap/react, gsap.
301
338
  Files: `kit/blocks.css`, `kit/gsap.ts`, `kit/images.ts`, `kit/photo-read.ts`, `sections/manifesto.tsx`.
302
339
 
303
340
  ### contact-form
341
+ film: role pattern · home none · motif line · energy 1 · pins 0 · none
304
342
 
305
343
  Contact form. The one place the site asks for input: name, e-mail, a short subject and an optional choice, as fields that are only a drawing rule with lifting labels, as a sentence the reader completes inline at display size, or one question at a time, with every state designed from invalid to a travelling-arrow send, a thank-you in the form's own place and a kept-text retry.
306
344
 
@@ -313,6 +351,8 @@ Exports: `ContactForm`. Packages: none.
313
351
  Files: `kit/blocks.css`, `sections/contact-form.tsx`.
314
352
 
315
353
  ### cta-closing
354
+ film: role pattern · home none · motif aperture · energy 2 · pins 0 · none
355
+ film variants: pointer energy 1
316
356
 
317
357
  Closing call to action. The page's last screen before the footer, one light display line and one large text link with an arrow and a drawing line, arriving on a short scroll-scrubbed stretch that runs backwards on the way back: a photograph opening by registration behind the line on its measured calm side, the line as a slow scroll-nudged band behind a still link, or a still line whose link brings a project frame that follows the pointer.
318
358
 
@@ -325,6 +365,7 @@ Exports: `CtaClosing`. Packages: @gsap/react, gsap.
325
365
  Files: `kit/blocks.css`, `kit/gsap.ts`, `kit/images.ts`, `kit/photo-read.ts`, `sections/cta-closing.tsx`.
326
366
 
327
367
  ### reveals
368
+ film: role pattern · home none · motif neutral · energy 1 · pins 0 · none
328
369
 
329
370
  Reveals. A plain editorial section (statement, paragraph, one photo, one text link) that enters on a short scroll-scrubbed stretch in one of three ways: lines rising through masks with the photo opening from its bottom edge, the photo opening from a thin slit with the type rising beside it, or the whole section laid over the previous one like a card, which dims and falls behind; scrolling back runs every entrance backwards.
330
371
 
@@ -337,6 +378,7 @@ Exports: `Reveals`. Packages: @gsap/react, gsap.
337
378
  Files: `kit/blocks.css`, `kit/gsap.ts`, `kit/images.ts`, `sections/reveals.tsx`.
338
379
 
339
380
  ### image-trail
381
+ film: role pattern · home none · motif neutral · energy 1 · pins 0 · cursor, hover
340
382
 
341
383
  Image trail. A list of work at display size; moving the pointer over a row deals that project's photograph at the pointer each time it has travelled a set distance, turned a little with the hand and settling as it lands, while older prints hold, shrink and fade behind it, six at most; a fast hand leaves a longer, wider trail and a still one leaves nothing new; keyboard focus and reduced motion show one print beside the row, and touch and phones show each photograph inline.
342
384
 
@@ -344,6 +386,7 @@ Exports: `ImageTrail`. Packages: @gsap/react, gsap.
344
386
  Files: `kit/blocks.css`, `kit/gsap.ts`, `kit/images.ts`, `sections/image-trail.tsx`.
345
387
 
346
388
  ### panel-accordion
389
+ film: role pattern · home none · motif aperture · energy 1 · pins 0 · hover
347
390
 
348
391
  Panel accordion. A full-height row of five tall photo panels like gallery shutters: hover or focus opens one wide while the others narrow, the photograph already full size behind a widening window, its name rising in through a mask; on scroll into view the panels rise from their bottom edge one after another and the first opens on its own; phones stack them as rows that open on tap.
349
392
 
@@ -351,6 +394,7 @@ Exports: `PanelAccordion`. Packages: @gsap/react, gsap.
351
394
  Files: `kit/blocks.css`, `kit/gsap.ts`, `kit/images.ts`, `sections/panel-accordion.tsx`.
352
395
 
353
396
  ### grid-assembly
397
+ film: role centerpiece · home none · motif frame · energy 3 · pins 2.5 · none
354
398
 
355
399
  Grid assembly. A pinned section (250%) opens on nine photos lying at angles in a composed pile, a few past the screen edges, that travel one after another into an editorial grid with exact gaps as the section's line rises in its type cell; the grid holds, then the hero print, a window onto its photo at full size, opens to the full screen while the others are pushed out, the photo never changing scale, and the next line rises on the photo's calmer side, holds, and the photo drifts slower than the page as the pin lets go. Phones open the grid tile by tile; reduced motion and pages without scripts show the grid, then the full-bleed photo with its line.
356
400
 
@@ -358,6 +402,7 @@ Exports: `GridAssembly`. Packages: @gsap/react, gsap.
358
402
  Files: `kit/blocks.css`, `kit/gsap.ts`, `kit/images.ts`, `kit/photo-read.ts`, `sections/grid-assembly.tsx`.
359
403
 
360
404
  ### velocity-type
405
+ film: role pattern · home none · motif word · energy 2 · pins 0 · marquee
361
406
 
362
407
  Velocity type. Two lines of display type at 15vw run sideways in opposite directions as you scroll, run ahead with its speed, lean back and stretch slightly as if dragged, and settle upright within about 0.4 seconds of stopping, with small photographs sitting between the phrases as their own frames; the belt loops without a seam, and reduced motion and pages without scripts leave the lines at rest.
363
408
 
@@ -365,6 +410,7 @@ Exports: `VelocityType`. Packages: @gsap/react, gsap.
365
410
  Files: `kit/blocks.css`, `kit/gsap.ts`, `kit/images.ts`, `sections/velocity-type.tsx`.
366
411
 
367
412
  ### sticky-chapters
413
+ film: role pattern · home none · motif neutral · energy 2 · pins 0 · none
368
414
 
369
415
  Sticky chapters. A process or story in chapters: one large photograph holds still on the left (plain position sticky) while the chapters scroll past on the right; as each reaches the middle its photograph rises over the last from the bottom edge (from the top when scrolling back) out of a push-in, that chapter comes forward while the others step back, and a hairline beside the frame fills as you read; phones and pages without scripts show each photograph inline, reduced motion keeps the frame with hard cuts.
370
416
 
@@ -372,6 +418,7 @@ Exports: `StickyChapters`. Packages: @gsap/react, gsap.
372
418
  Files: `kit/blocks.css`, `kit/gsap.ts`, `kit/images.ts`, `sections/sticky-chapters.tsx`.
373
419
 
374
420
  ### film-strip
421
+ film: role centerpiece · home none · motif frame · energy 3 · pins 3 · none
375
422
 
376
423
  Film strip. A pinned reel between two rows of sprocket holes opens on the section's display line beside the first project in the gate; the scroll advances it one frame at a time, portrait frames high and landscape low, each seating at the gate as its photo settles out of a push-in while the title swaps through its mask and a hairline progress line fills; the last stop is the closing frame with the call to action, and on release the strip runs on to the left. Phones swipe a snap row between sprocket rows with titles under the frames; reduced motion and pages without scripts get the same still row.
377
424
 
@@ -379,6 +426,7 @@ Exports: `FilmStrip`. Packages: @gsap/react, gsap.
379
426
  Files: `kit/blocks.css`, `kit/gsap.ts`, `kit/images.ts`, `sections/film-strip.tsx`.
380
427
 
381
428
  ### hover-list
429
+ film: role pattern · home none · motif neutral · energy 1 · pins 0 · cursor, hover
382
430
 
383
431
  Hover reveal list. A list of work at display size, each name with a quiet line of place and year; hovering a row shows its photograph in an upright frame that follows the pointer closely and leans with its speed while the other rows step back, row to row the photograph wipes in the way the pointer travels, and leaving the list folds the frame shut; keyboard focus and reduced motion stand the frame beside the row, and touch and phones show each photograph inline.
384
432
 
@@ -386,6 +434,7 @@ Exports: `HoverList`. Packages: @gsap/react, gsap.
386
434
  Files: `kit/blocks.css`, `kit/gsap.ts`, `kit/images.ts`, `sections/hover-list.tsx`.
387
435
 
388
436
  ### split-pair
437
+ film: role centerpiece · home none · motif cut · energy 3 · pins 3 · none
389
438
 
390
439
  Split pair. A pinned pair of tall photos that meet at a hard seam: the word stands whole in ink on the ground with the seam through it; the first photo rises in on the left, turning its half of the letters to the photo's own ink, and holds half and half; the second comes down on the right against it and the pair holds whole, the two photos running against each other at different speeds the whole time, and on release the halves leave at their own speeds so the word shears along the seam.
391
440
 
@@ -393,6 +442,7 @@ Exports: `SplitPair`. Packages: @gsap/react, gsap.
393
442
  Files: `kit/blocks.css`, `kit/gsap.ts`, `kit/images.ts`, `kit/photo-read.ts`, `sections/split-pair.tsx`.
394
443
 
395
444
  ### fanned-cards
445
+ film: role centerpiece · home none · motif neutral · energy 3 · pins 3 · hover
396
446
 
397
447
  Fanned cards. Services or cases as a hand of photographs played onto the table: a poster heading set on the diagonal, the hand rising into the frame and fanning open large in 3D between its two lines; it holds, then the hand is played from the back, each card flying along an arc toward the lens and turning as it goes, and laid down at its own scale into a spread (the lead card large in front, each card behind it smaller and partly under the one before, all crossing the first line), each title rising from its mask as its card lands; the spread holds, and on release the cards are picked up off the table at their own speeds. Phones get the hand as a still fan; reduced motion gets the spread. Cards lift slightly on hover.
398
448
 
@@ -402,6 +452,7 @@ Files: `kit/blocks.css`, `kit/gsap.ts`, `kit/images.ts`, `sections/fanned-cards.
402
452
  ## Footers
403
453
 
404
454
  ### footer-reveal
455
+ film: role frame · home none · motif neutral · energy 2 · pins 0 · none
405
456
 
406
457
  Footer: revealed from under the page. The page's last section lifts away like a sheet and uncovers the footer already waiting beneath it (the name large at a light weight, a closing line, the contact address, a few plain links), scrubbed to the scroll and laid down again on the way back.
407
458
 
@@ -414,12 +465,13 @@ Exports: `FooterReveal`. Packages: @gsap/react, gsap, lenis.
414
465
  Files: `footers/footer-reveal.tsx`, `kit/SmoothScroll.tsx`, `kit/blocks.css`, `kit/gsap.ts`.
415
466
 
416
467
  ### footer-contact
468
+ film: role frame · home none · motif word · energy 1 · pins 0 · clock, hover · clock by prop clock
417
469
 
418
- Footer: contact. The page ends on the way to reach the studio: the mail address as a real link at display size (or a live clock, or a quiet three-column grid), the city's local time with an honest open marker computed from it, a phone line, the address and a few plain links, entering scrubbed to the scroll.
470
+ Footer: contact. The page ends on the way to reach the studio: the mail address as a real link at display size (or the city at display size, or a quiet three-column grid), the city and its opening hours, a phone line, the address and a few plain links, entering scrubbed to the scroll; with clock the city keeps its live local time with an honest open marker computed from it.
419
471
 
420
472
  Variants (`variant`, the first is the default):
421
473
  - `address`: The mail address heads the footer as a fitted headline whose characters roll up into their slots from blank as you scroll in, then roll again from the pointer's side on hover; the details close it under a ruled line.
422
- - `clock`: A live Rotterdam clock at display size is the centre, its colon breathing once a second; mail, phone, address and hours stand around it like a timetable.
474
+ - `clock`: The city at display size is the centre (with clock, a live clock whose colon breathes once a second); mail, phone, address and hours stand around it like a timetable.
423
475
  - `columns`: A closing line at display size, then three columns (Contact, Studio, Volg ons) with links whose underline draws from the pointer's side.
424
476
 
425
477
  Exports: `FooterContact`. Packages: @gsap/react, gsap.
@@ -7,7 +7,11 @@
7
7
  // shade of the accent at its thin edges. The headline (light display weight), one lead sentence and one text link
8
8
  // stand on the calm side, clear of the curtains.
9
9
  //
10
- // <BackgroundAurora variant="veil" lines={["Ruimte voor", "het licht."]} lead="..." link={{ href: "/werk", label: "Bekijk het werk" }} />
10
+ // <BackgroundAurora variant="veil" lines={["Ruimte voor", "het licht."]} accent="licht" lead="..." link={{ href: "/werk", label: "Bekijk het werk" }} />
11
+ //
12
+ // `accent` (optional) is the site's one accent word: where it first stands in the headline it is set in the pairing's
13
+ // italic accent face, inside its line's mask, and the contrast ceiling is measured once that face is in. The Statement
14
+ // and the Close carry the same word. Left out, or not in the headline, the hero is exactly as it was.
11
15
  //
12
16
  // Three variants, three compositions of the same field:
13
17
  // veil one tall curtain standing in the right third, two pleats crossing as it sways; the type on the calm left.
@@ -27,13 +31,16 @@
27
31
  // the same colour math the shader uses. The compositions keep the curtains clear of the type, so the ceiling only
28
32
  // catches a stray ray, and it meets the field softly: faint light runs on behind the text, no veil and no cutout.
29
33
  //
30
- // Entrance: the canvas stays hidden until its first frame is drawn, then fades in while the light dawns; the type
31
- // rises through masks once its face is in (capped). Reduced motion: one rendered still frame, held, type in place. No
34
+ // Entrance: the canvas stays hidden until its first frame is drawn, then fades in; the light dawns and the type rises
35
+ // through masks once its face is in (capped) and nothing covers the page (whenUncovered: a preloader or page
36
+ // transition has started to leave, or there is none). Reduced motion: one rendered still frame, held, type in place. No
32
37
  // WebGL: the same field drawn once, small, on a 2D canvas. No scripts: the composed hero on the plain ground; with
33
38
  // scripts the type waits below its masks and is released by the CSS after 3 seconds if the script never runs
34
39
  // (blocks.css, "--- background-aurora ---").
35
40
  import { useEffect, useRef } from "react";
41
+ import { accentFaceReady, accentLines } from "../kit/accent";
36
42
  import { ScrollTrigger, gsap, useGSAP } from "../kit/gsap";
43
+ import { whenUncovered } from "../preloaders/preloader-slices-uncovered";
37
44
 
38
45
  export type AuroraVariant = "veil" | "horizon" | "drift";
39
46
 
@@ -48,6 +55,9 @@ type Props = {
48
55
  variant?: AuroraVariant;
49
56
  /** The headline, one entry per line. Two short lines read best. */
50
57
  lines: string[];
58
+ /** The site's one accent word: where it first stands in the headline it is set in the pairing's italic accent face
59
+ * (--face-accent), as the Statement and the Close set it. A word the headline does not hold changes nothing. */
60
+ accent?: string;
51
61
  /** One lead sentence. */
52
62
  lead: string;
53
63
  /** One text link. */
@@ -419,7 +429,7 @@ function build(gl: WebGL2RenderingContext): Gl | null {
419
429
 
420
430
  // ---------------------------------------------------------------------------------------------------------------
421
431
 
422
- export function BackgroundAurora({ variant = "veil", lines, lead, link, className = "" }: Props) {
432
+ export function BackgroundAurora({ variant = "veil", lines, accent, lead, link, className = "" }: Props) {
423
433
  const root = useRef<HTMLElement>(null);
424
434
  const canvasRef = useRef<HTMLCanvasElement>(null);
425
435
 
@@ -442,6 +452,7 @@ export function BackgroundAurora({ variant = "veil", lines, lead, link, classNam
442
452
  let last = 0;
443
453
  let clock = 0;
444
454
  let introClock = 0;
455
+ let dawning = false;
445
456
  const leave = { now: 0, target: 0 };
446
457
  const ptr = { x: 0.5, y: 0.5, z: 0, tx: 0.5, ty: 0.5, tz: 0 };
447
458
 
@@ -570,7 +581,8 @@ export function BackgroundAurora({ variant = "veil", lines, lead, link, classNam
570
581
  const dt = last ? Math.min(0.1, (now - last) / 1000) : 0;
571
582
  last = now;
572
583
  clock += dt;
573
- introClock += dt;
584
+ // The dawn holds at its start while a cover is over the page.
585
+ if (dawning) introClock += dt;
574
586
  // The pointer eases in over about 0.18 s; the scroll settles like a camera, about 0.4 s.
575
587
  const kp = 1 - Math.exp(-dt / 0.06);
576
588
  ptr.x += (ptr.tx - ptr.x) * kp;
@@ -615,7 +627,8 @@ export function BackgroundAurora({ variant = "veil", lines, lead, link, classNam
615
627
  let fontsId = 0;
616
628
  const refit = () => {
617
629
  const id = ++fontsId;
618
- document.fonts?.ready.then(() => {
630
+ // The accent face too, when a word is marked: the text boxes are measured as they will stand.
631
+ document.fonts?.ready.then(() => accentFaceReady(el)).then(() => {
619
632
  if (gone || id !== fontsId) return;
620
633
  measure();
621
634
  if (gl && prog) draw();
@@ -698,9 +711,13 @@ export function BackgroundAurora({ variant = "veil", lines, lead, link, classNam
698
711
  }
699
712
 
700
713
  wake();
714
+ const stopDawn = whenUncovered(() => {
715
+ dawning = true;
716
+ });
701
717
 
702
718
  return () => {
703
719
  gone = true;
720
+ stopDawn();
704
721
  if (raf) cancelAnimationFrame(raf);
705
722
  sized.disconnect();
706
723
  themed.disconnect();
@@ -752,17 +769,22 @@ export function BackgroundAurora({ variant = "veil", lines, lead, link, classNam
752
769
  if (gone) return;
753
770
  gsap.to(rise, { yPercent: 0, duration: 1.2, ease: "expo.out", stagger: 0.09, delay: 0.15 });
754
771
  });
772
+ // Once the face is in, and once nothing covers the page (a preloader or page transition starting to leave).
773
+ let stop = () => {};
755
774
  const fonts = document.fonts?.ready ?? Promise.resolve();
756
- Promise.race([fonts, new Promise((r) => setTimeout(r, 1200))]).then(play);
775
+ Promise.race([fonts, new Promise((r) => setTimeout(r, 1200))]).then(() => {
776
+ if (!gone) stop = whenUncovered(play);
777
+ });
757
778
  return () => {
758
779
  gone = true;
780
+ stop();
759
781
  };
760
782
  },
761
783
  { scope: root, dependencies: [variant] },
762
784
  );
763
785
 
764
786
  const mask = (child: React.ReactNode, key?: number) => (
765
- <span key={key} className="struq-line-mask block overflow-hidden">
787
+ <span key={key} className="struq-line-mask block">
766
788
  <span data-rise="" className="block">
767
789
  {child}
768
790
  </span>
@@ -786,24 +808,24 @@ export function BackgroundAurora({ variant = "veil", lines, lead, link, classNam
786
808
  className={`relative isolate flex h-svh min-h-[34rem] overflow-hidden bg-surface-0 text-ink ${className}`}
787
809
  >
788
810
  <canvas ref={canvasRef} data-field="" aria-hidden="true" className="absolute inset-0 block h-full w-full" />
789
- <div className={`relative z-10 flex w-full px-6 md:px-[4vw] ${place}`}>
811
+ <div className={`relative z-10 flex w-full px-sheet-margin ${place}`}>
790
812
  <div className={variant === "veil" ? "md:max-w-[52%]" : "max-w-[min(100%,52rem)]"}>
791
813
  <h1
792
814
  data-quiet="display"
793
815
  className="w-fit font-display text-[clamp(2.9rem,12.5vw,4.5rem)] leading-[0.95] tracking-[-0.03em] md:text-[clamp(3.5rem,7vw,8rem)]"
794
816
  >
795
- {lines.map((line, i) => mask(line, i))}
817
+ {accentLines(lines, accent).map((line, i) => mask(line, i))}
796
818
  </h1>
797
819
  {/* The spacing sits on plain wrappers: the line mask's own negative margins would cancel it. */}
798
820
  <div className="mt-7 md:mt-10">
799
- <div data-quiet="small" className="struq-line-mask max-w-[34ch] overflow-hidden text-ink-muted">
821
+ <div data-quiet="small" className="struq-line-mask max-w-[34ch] text-ink-muted">
800
822
  <p data-rise="" className="text-lead m-0">
801
823
  {lead}
802
824
  </p>
803
825
  </div>
804
826
  </div>
805
827
  <div className="mt-5 md:mt-6">
806
- <div data-quiet="small" className="struq-line-mask w-fit overflow-hidden">
828
+ <div data-quiet="small" className="struq-line-mask w-fit">
807
829
  <span data-rise="" className="block">
808
830
  <a href={link.href} className="text-body underline decoration-1 underline-offset-[0.3em]">
809
831
  {link.label}