dreative 0.4.0 → 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.
@@ -1,223 +1,223 @@
1
- # Dreative Specialist Skill — Immersive Worlds & Spatial Transitions
2
-
3
- Load this file when `plan.skills` includes `immersive`, or the brief/prompt asks
4
- for an "award-site" feel, a site that behaves like a world/scene/space, spatial or
5
- 3D page transitions, "sites like epic.net / Awwwards winners", scroll-as-journey,
6
- or "make it feel like an experience, not a webpage". This is the genre young
7
- studios and portfolios use to signal craft: the page is a continuous SPACE the
8
- visitor travels through, not a stack of sections.
9
-
10
- It EXTENDS DESIGN.md (register, type, color still apply) and STACKS with
11
- `motion.md` (timing vocabulary) and `3d.md` (WebGL craft) — read those too when
12
- listed. This file is about the architecture and choreography that makes a site
13
- read as one continuous world. It is universal: apply it to any codebase or
14
- framework directly; the Dreative editor is never required.
15
-
16
- ## 0. Commit to the genre or don't enter it
17
-
18
- Immersive is a REGISTER, not a garnish. A normal marketing page with one fancy
19
- transition reads as broken; a world with one static utility page reads as
20
- intentional. Decide up front:
21
-
22
- - **Earns it**: portfolios, studios/agencies, campaign and launch sites, brand
23
- storytelling, exhibitions, games/entertainment — anywhere the site IS the proof
24
- of craft and visitors expect to explore.
25
- - **Doesn't**: dashboards, docs, e-commerce checkout, anything task-first.
26
- Product register (DESIGN.md §1) hard-caps this genre to a hero moment.
27
- - The genre demands a **spatial metaphor** named in one sentence before any code:
28
- "each project is a room off a corridor", "scroll descends through a tower",
29
- "the cursor is a flashlight over an archive", "works float in a void you orbit".
30
- No metaphor = you'll produce disconnected effects. The metaphor decides what
31
- transitions, camera moves, and layout make sense — everything below serves it.
32
- - Immersive sites still need an **escape hatch**: visible menu with plain links,
33
- working back button, deep-linkable routes — all held to ux.md's working-page
34
- contract (the menu closes, links resolve, back plays reverse, nothing
35
- invisible eats clicks: run ux.md §7 on the world too). Lost visitors close tabs. On touch
36
- devices the escape hatch becomes the PRIMARY route (DESIGN.md §13): drag/
37
- spatial navigation conflicts with native scroll, so mobile gets the index-list
38
- world view or a swipe carousel, with the full world behind an explicit tap-in.
39
-
40
- ## 1. Architecture: one persistent stage
41
-
42
- The defining trait of this genre is that navigation doesn't feel like page loads
43
- — the world persists and the camera/content moves. Structure the app accordingly:
44
-
45
- - **App shell + stage**: one persistent layer (WebGL canvas, fixed background
46
- scene, or shared layout chrome) mounted OUTSIDE the router's swap point. Routes
47
- change the DOM content layer; the stage transitions continuously underneath.
48
- React: canvas in the root layout, never inside a page component. Vanilla/MPA:
49
- use cross-document View Transitions (`@view-transition { navigation: auto; }`)
50
- or an SPA-ify layer (barba.js/Taxi.js-style: fetch next page, swap `<main>`,
51
- play the transition yourself).
52
- - **Scene manager**: each route/section maps to a named scene state (camera pose,
53
- palette, fog, active objects). Transitions tween BETWEEN states — never unmount
54
- scene A and mount scene B. Keep one source of truth
55
- (`{ route → { cameraPos, lookAt, theme } }`) so transitions are data, not
56
- scattered code.
57
- - **State machine for choreography**: preloading → intro → idle → transitioning.
58
- Input is locked during `transitioning` (ignore clicks, queue at most one). Every
59
- award-site jank bug is two transitions running at once.
60
- - URLs stay honest: every "place" in the world has a route; refresh lands you
61
- there with the scene in the right state (read route on boot, snap camera, skip
62
- the travel animation).
63
-
64
- ## 2. The preloader (the genre's front door)
65
-
66
- Heavy worlds need loading; the genre turns it into the first brand moment.
67
-
68
- - Show a preloader ONLY if real assets need it (fonts+models+textures > ~1s).
69
- Faking a 3-second counter on a light page is user-hostile — banned.
70
- - Real progress: count bytes/items from an asset manifest (`THREE.LoadingManager`
71
- `onProgress`, or Promise.allSettled over fetches), display as an oversized
72
- number (tabular-nums) or a filling wordmark — not a spinner.
73
- - Exit is a choreographed REVEAL, not a fade: counter completes → beat (~200ms) →
74
- curtain wipe (clip-path/transform panel slide) or mask expansion reveals the
75
- hero mid-motion (world already idling underneath). The hero entrance and the
76
- preloader exit are ONE timeline.
77
- - Cache the visit (`sessionStorage`): returning visitors within a session skip to
78
- a ≤400ms version. Preloader shows once, not per navigation.
79
-
80
- ## 3. Spatial transitions (route ↔ route)
81
-
82
- The signature move: leaving a page feels like traveling, not swapping.
83
-
84
- Pick per the metaphor — every route pair uses the SAME transition language:
85
-
86
- - **Camera travel** (persistent WebGL): tween camera along a path to the next
87
- scene anchor while DOM content of page A exits (fast fade + small offset) and
88
- page B's content enters after arrival. Travel 600–1200ms; longer feels like a
89
- loading screen.
90
- - **Shared-element morph**: the clicked card/image IS the next page's hero.
91
- Same-doc: Motion `layoutId` or FLIP the element to its new bounds. MPA/simple
92
- SPA: `view-transition-name` on the pair. This is the highest-value transition
93
- per line of code — prefer it for list → detail (work index → project page).
94
- - **Mask/wipe**: full-viewport panel or clip-path (`inset()`/`circle()` from the
95
- click point) sweeps over A, next route mounts underneath, sweep continues off.
96
- Two-phase with a color/texture beat at full-cover (~150ms hold) reads as
97
- premium; a plain crossfade reads as a slideshow.
98
- - **WebGL texture transition**: page A screenshot/render and page B as two
99
- textures on a fullscreen plane, shader-blended with a noise/displacement mask
100
- (see 3d.md §4). For image-heavy portfolios.
101
-
102
- Rules: exits ≤ 40% of the total; something from A must persist through the
103
- transition (the stage, a morphing element, the nav) or it's just a fancy reload;
104
- browser back plays the REVERSE direction (remember last direction); first paint
105
- on a cold URL never plays a transition.
106
-
107
- ## 4. Scroll as travel (the world's main axis)
108
-
109
- In this genre scroll is displacement through space, not document reading:
110
-
111
- - Map document scroll to world motion: a tall scroll container
112
- (`height: N * 100vh`) drives camera position along a `CatmullRomCurve3` (or
113
- layered 2D transforms for a DOM-only world) via damped progress — Lenis +
114
- ScrollTrigger scrub, or `useScroll` + `useTransform`. The page height IS the
115
- journey length; native scrollbar, momentum, and a11y keep working. This is how
116
- you get the "flying through the site" feel WITHOUT scroll-jacking — wheel
117
- hijacking stays banned (motion.md §3).
118
- - **Chapters**: divide the journey into named stops (sections). Each chapter owns
119
- a camera pose + palette shift + one content group. Snap gently
120
- (`scroll-snap-type: y proximity`, never `mandatory` on long chapters). Expose a
121
- progress rail / chapter index (dots or numerals, current chapter labeled) —
122
- spatial sites without one feel endless.
123
- - Depth cues sell the space: atmospheric fade (fog / opacity by depth), scale +
124
- blur on far layers, parallax speed ordered by depth (bg slowest), a subtle
125
- camera sway on idle (≤ 2°, damped). 3–5 depth layers; more reads as soup.
126
- - Horizontal chapters: translate a wide track from vertical scroll progress
127
- inside a pinned section (sticky wrapper) — one per page, ≤ 4 viewport-widths.
128
- - DOM content floats IN the world: copy blocks fade/rise at their chapter,
129
- anchored to scene positions (drei `<Html>`, or absolutely-positioned blocks
130
- keyed to progress ranges). Text always real DOM — never baked into textures.
131
-
132
- ## 5. The dressing: what makes it read "award site"
133
-
134
- The genre's supporting cast — apply 3–4, not all (checklist-complete = template):
135
-
136
- - **Oversized display type** as an object in the space: 10–20vw headlines that
137
- clip, sit behind/in front of the 3D subject (z-sandwiching via two text layers
138
- or `occlude`), or run off-canvas. Line-mask reveals on arrival (motion.md §4).
139
- The full-commitment version (unseen.co's hero) puts the headline INSIDE the
140
- scene as reflective 3D type — chrome material, mirrored in the environment,
141
- revealed by dragging/panning the world; pair a keep-real-DOM copy underneath
142
- for a11y/SEO.
143
- - **Custom cursor**: small dot + trailing ring (damped follow, ~0.15 lerp),
144
- morphs over interactives (scales up with a label: "View", "Drag", "Play").
145
- Hide only the visual cursor layer via CSS on fine pointers; touch devices get
146
- none of it and lose nothing. Magnetic pull on nav/CTAs (interaction.md).
147
- - **HUD chrome**: fixed corners used as an instrument panel — wordmark top-left,
148
- menu top-right, chapter index + local time / coordinates bottom corners, mono
149
- small-caps microtype. The frame stays put while the world moves — it's what
150
- makes the motion legible.
151
- - **Fullscreen menu** as a scene: menu button flips a full-viewport overlay with
152
- oversized nav links (staggered line-mask entrance), hover previews (image or
153
- scene tint per link). The overlay is part of the world (same palette/texture),
154
- not a white sheet.
155
- - **Textural grain**: one fullscreen noise/grain layer (CSS `mask` over an SVG
156
- turbulence tile or a tiny shader) at 3–6% opacity unifies WebGL and DOM into
157
- one photographic surface. Cheap, high-impact.
158
- - **Easter eggs** (epic.net's signature): 1–3 hidden delights — a konami code, a
159
- clickable mascot, an idle-timeout animation. Never gate content behind them.
160
-
161
- ## 6. Performance & accessibility (the genre's hard mode)
162
-
163
- Everything in motion.md §6 and 3d.md §7 applies, plus genre-specific:
164
-
165
- - Budget the WHOLE experience: ≤ 4–5MB initial including models/fonts; stage
166
- code lazy-loaded behind the preloader; route content prefetched on hover so
167
- spatial transitions never wait on network mid-flight.
168
- - One rAF loop owns the world (scene + cursor + scroll damping share it). Two
169
- competing loops = the micro-stutter that separates good from great here.
170
- - `prefers-reduced-motion` gets a REAL alternative, not a broken world: static
171
- scene per chapter, instant route swaps (crossfade ≤ 200ms), scroll returns to
172
- plain document reading. Decide this layout up front — retrofitting it is why
173
- most immersive sites fail the audit.
174
- - Keyboard path through the world: chapter index and nav focusable, focus moved
175
- to incoming page's `<h1>`/main after a route transition, skip-link to content
176
- over the intro. Announce route changes (`aria-live="polite"` region).
177
- - Low-power fallback ("flat mode"): detect weak GPU/`navigator.deviceMemory`/
178
- first dropped-frame burst → swap stage for poster art + gradients, keep ALL
179
- content and transitions-lite. Content is never hostage to the world. Offer the
180
- same switch as a visible toggle if the brief allows.
181
- - SEO/no-JS: every route server-renders its real copy; the world enhances it.
182
-
183
- ## 7. Recipes
184
-
185
- - **Scroll-dolly index (verified on unseen.co)**: one scroll axis dollies the
186
- camera from the hero space directly into the works gallery — a bright hall
187
- whose section heading and filter pills are DOM floating in front of the
188
- scene, work cards as gently-warped paper planes hovering in depth. The route
189
- updates mid-journey while the world persists. One continuous shot, zero page
190
- loads.
191
- - **Chapter theme inversion (verified on bdsn.club)**: an editorial case-study
192
- page where each full-viewport project chapter flips the ENTIRE page theme
193
- (white → black → brand indigo…) as it scrolls in, with an oversized grotesk
194
- project title and one product render per chapter; HUD (local time top-left,
195
- CTA top-right, awards rail on the edge) stays fixed through every inversion.
196
- DOM-only, no WebGL — the spatial feel comes purely from theme travel + scale.
197
- - **World portfolio**: persistent canvas; works as textured planes arranged in
198
- depth (DOM-synced media planes per media.md §3 — real images underneath);
199
- scroll flies the camera past them; hover tilts a plane + cursor says
200
- "View"; click = camera dives to the plane which morphs into the project hero
201
- (shared-element). Back = reverse flight.
202
- - **Scene-hopping studio site (epic-style)**: stylized environment as stage;
203
- each route = a location; nav travels the camera between locations with a
204
- velocity blur beat; DOM copy floats per location; playful idle animations +
205
- 1–2 easter eggs; HUD chrome + fullscreen menu.
206
- - **One-page descent**: 6–8 chapter tall-scroll journey down one axis (tower,
207
- ocean, timeline); palette darkens/shifts per chapter; progress rail with
208
- chapter names; ends on a contact "floor" that snaps.
209
- - **DOM-only spatial site (no WebGL)**: layered `translateZ`-style parallax with
210
- scale/blur depth cues, View Transitions for shared-element route morphs,
211
- clip-path wipes, grain overlay, custom cursor, oversized type. 80% of the feel
212
- at 5% of the cost — the right call below motion dial 8 or without 3D subject
213
- matter.
214
-
215
- ## 8. Changing an existing site into this
216
-
217
- An existing conventional site cannot become immersive through CSS — this genre
218
- requires the app-shell/stage architecture (§1), which means restructuring markup,
219
- routing, and component boundaries. Follow DESIGN.md §11's transformation-depth
220
- ladder: present the depth options, and on user confirmation restructure for real
221
- — move the router swap point, introduce the stage layer, rebuild sections as
222
- chapters. Never simulate the genre by decorating the old structure; a restyled
223
- static page with a custom cursor is the uncanny valley of this genre.
1
+ # Dreative Specialist Skill — Immersive Worlds & Spatial Transitions
2
+
3
+ Load this file when `plan.skills` includes `immersive`, or the brief/prompt asks
4
+ for an "award-site" feel, a site that behaves like a world/scene/space, spatial or
5
+ 3D page transitions, "sites like epic.net / Awwwards winners", scroll-as-journey,
6
+ or "make it feel like an experience, not a webpage". This is the genre young
7
+ studios and portfolios use to signal craft: the page is a continuous SPACE the
8
+ visitor travels through, not a stack of sections.
9
+
10
+ It EXTENDS DESIGN.md (register, type, color still apply) and STACKS with
11
+ `motion.md` (timing vocabulary) and `3d.md` (WebGL craft) — read those too when
12
+ listed. This file is about the architecture and choreography that makes a site
13
+ read as one continuous world. It is universal: apply it to any codebase or
14
+ framework directly; the Dreative editor is never required.
15
+
16
+ ## 0. Commit to the genre or don't enter it
17
+
18
+ Immersive is a REGISTER, not a garnish. A normal marketing page with one fancy
19
+ transition reads as broken; a world with one static utility page reads as
20
+ intentional. Decide up front:
21
+
22
+ - **Earns it**: portfolios, studios/agencies, campaign and launch sites, brand
23
+ storytelling, exhibitions, games/entertainment — anywhere the site IS the proof
24
+ of craft and visitors expect to explore.
25
+ - **Doesn't**: dashboards, docs, e-commerce checkout, anything task-first.
26
+ Product register (DESIGN.md §1) hard-caps this genre to a hero moment.
27
+ - The genre demands a **spatial metaphor** named in one sentence before any code:
28
+ "each project is a room off a corridor", "scroll descends through a tower",
29
+ "the cursor is a flashlight over an archive", "works float in a void you orbit".
30
+ No metaphor = you'll produce disconnected effects. The metaphor decides what
31
+ transitions, camera moves, and layout make sense — everything below serves it.
32
+ - Immersive sites still need an **escape hatch**: visible menu with plain links,
33
+ working back button, deep-linkable routes — all held to ux.md's working-page
34
+ contract (the menu closes, links resolve, back plays reverse, nothing
35
+ invisible eats clicks: run ux.md §7 on the world too). Lost visitors close tabs. On touch
36
+ devices the escape hatch becomes the PRIMARY route (DESIGN.md §13): drag/
37
+ spatial navigation conflicts with native scroll, so mobile gets the index-list
38
+ world view or a swipe carousel, with the full world behind an explicit tap-in.
39
+
40
+ ## 1. Architecture: one persistent stage
41
+
42
+ The defining trait of this genre is that navigation doesn't feel like page loads
43
+ — the world persists and the camera/content moves. Structure the app accordingly:
44
+
45
+ - **App shell + stage**: one persistent layer (WebGL canvas, fixed background
46
+ scene, or shared layout chrome) mounted OUTSIDE the router's swap point. Routes
47
+ change the DOM content layer; the stage transitions continuously underneath.
48
+ React: canvas in the root layout, never inside a page component. Vanilla/MPA:
49
+ use cross-document View Transitions (`@view-transition { navigation: auto; }`)
50
+ or an SPA-ify layer (barba.js/Taxi.js-style: fetch next page, swap `<main>`,
51
+ play the transition yourself).
52
+ - **Scene manager**: each route/section maps to a named scene state (camera pose,
53
+ palette, fog, active objects). Transitions tween BETWEEN states — never unmount
54
+ scene A and mount scene B. Keep one source of truth
55
+ (`{ route → { cameraPos, lookAt, theme } }`) so transitions are data, not
56
+ scattered code.
57
+ - **State machine for choreography**: preloading → intro → idle → transitioning.
58
+ Input is locked during `transitioning` (ignore clicks, queue at most one). Every
59
+ award-site jank bug is two transitions running at once.
60
+ - URLs stay honest: every "place" in the world has a route; refresh lands you
61
+ there with the scene in the right state (read route on boot, snap camera, skip
62
+ the travel animation).
63
+
64
+ ## 2. The preloader (the genre's front door)
65
+
66
+ Heavy worlds need loading; the genre turns it into the first brand moment.
67
+
68
+ - Show a preloader ONLY if real assets need it (fonts+models+textures > ~1s).
69
+ Faking a 3-second counter on a light page is user-hostile — banned.
70
+ - Real progress: count bytes/items from an asset manifest (`THREE.LoadingManager`
71
+ `onProgress`, or Promise.allSettled over fetches), display as an oversized
72
+ number (tabular-nums) or a filling wordmark — not a spinner.
73
+ - Exit is a choreographed REVEAL, not a fade: counter completes → beat (~200ms) →
74
+ curtain wipe (clip-path/transform panel slide) or mask expansion reveals the
75
+ hero mid-motion (world already idling underneath). The hero entrance and the
76
+ preloader exit are ONE timeline.
77
+ - Cache the visit (`sessionStorage`): returning visitors within a session skip to
78
+ a ≤400ms version. Preloader shows once, not per navigation.
79
+
80
+ ## 3. Spatial transitions (route ↔ route)
81
+
82
+ The signature move: leaving a page feels like traveling, not swapping.
83
+
84
+ Pick per the metaphor — every route pair uses the SAME transition language:
85
+
86
+ - **Camera travel** (persistent WebGL): tween camera along a path to the next
87
+ scene anchor while DOM content of page A exits (fast fade + small offset) and
88
+ page B's content enters after arrival. Travel 600–1200ms; longer feels like a
89
+ loading screen.
90
+ - **Shared-element morph**: the clicked card/image IS the next page's hero.
91
+ Same-doc: Motion `layoutId` or FLIP the element to its new bounds. MPA/simple
92
+ SPA: `view-transition-name` on the pair. This is the highest-value transition
93
+ per line of code — prefer it for list → detail (work index → project page).
94
+ - **Mask/wipe**: full-viewport panel or clip-path (`inset()`/`circle()` from the
95
+ click point) sweeps over A, next route mounts underneath, sweep continues off.
96
+ Two-phase with a color/texture beat at full-cover (~150ms hold) reads as
97
+ premium; a plain crossfade reads as a slideshow.
98
+ - **WebGL texture transition**: page A screenshot/render and page B as two
99
+ textures on a fullscreen plane, shader-blended with a noise/displacement mask
100
+ (see 3d.md §4). For image-heavy portfolios.
101
+
102
+ Rules: exits ≤ 40% of the total; something from A must persist through the
103
+ transition (the stage, a morphing element, the nav) or it's just a fancy reload;
104
+ browser back plays the REVERSE direction (remember last direction); first paint
105
+ on a cold URL never plays a transition.
106
+
107
+ ## 4. Scroll as travel (the world's main axis)
108
+
109
+ In this genre scroll is displacement through space, not document reading:
110
+
111
+ - Map document scroll to world motion: a tall scroll container
112
+ (`height: N * 100vh`) drives camera position along a `CatmullRomCurve3` (or
113
+ layered 2D transforms for a DOM-only world) via damped progress — Lenis +
114
+ ScrollTrigger scrub, or `useScroll` + `useTransform`. The page height IS the
115
+ journey length; native scrollbar, momentum, and a11y keep working. This is how
116
+ you get the "flying through the site" feel WITHOUT scroll-jacking — wheel
117
+ hijacking stays banned (motion.md §3).
118
+ - **Chapters**: divide the journey into named stops (sections). Each chapter owns
119
+ a camera pose + palette shift + one content group. Snap gently
120
+ (`scroll-snap-type: y proximity`, never `mandatory` on long chapters). Expose a
121
+ progress rail / chapter index (dots or numerals, current chapter labeled) —
122
+ spatial sites without one feel endless.
123
+ - Depth cues sell the space: atmospheric fade (fog / opacity by depth), scale +
124
+ blur on far layers, parallax speed ordered by depth (bg slowest), a subtle
125
+ camera sway on idle (≤ 2°, damped). 3–5 depth layers; more reads as soup.
126
+ - Horizontal chapters: translate a wide track from vertical scroll progress
127
+ inside a pinned section (sticky wrapper) — one per page, ≤ 4 viewport-widths.
128
+ - DOM content floats IN the world: copy blocks fade/rise at their chapter,
129
+ anchored to scene positions (drei `<Html>`, or absolutely-positioned blocks
130
+ keyed to progress ranges). Text always real DOM — never baked into textures.
131
+
132
+ ## 5. The dressing: what makes it read "award site"
133
+
134
+ The genre's supporting cast — apply 3–4, not all (checklist-complete = template):
135
+
136
+ - **Oversized display type** as an object in the space: 10–20vw headlines that
137
+ clip, sit behind/in front of the 3D subject (z-sandwiching via two text layers
138
+ or `occlude`), or run off-canvas. Line-mask reveals on arrival (motion.md §4).
139
+ The full-commitment version (unseen.co's hero) puts the headline INSIDE the
140
+ scene as reflective 3D type — chrome material, mirrored in the environment,
141
+ revealed by dragging/panning the world; pair a keep-real-DOM copy underneath
142
+ for a11y/SEO.
143
+ - **Custom cursor**: small dot + trailing ring (damped follow, ~0.15 lerp),
144
+ morphs over interactives (scales up with a label: "View", "Drag", "Play").
145
+ Hide only the visual cursor layer via CSS on fine pointers; touch devices get
146
+ none of it and lose nothing. Magnetic pull on nav/CTAs (interaction.md).
147
+ - **HUD chrome**: fixed corners used as an instrument panel — wordmark top-left,
148
+ menu top-right, chapter index + local time / coordinates bottom corners, mono
149
+ small-caps microtype. The frame stays put while the world moves — it's what
150
+ makes the motion legible.
151
+ - **Fullscreen menu** as a scene: menu button flips a full-viewport overlay with
152
+ oversized nav links (staggered line-mask entrance), hover previews (image or
153
+ scene tint per link). The overlay is part of the world (same palette/texture),
154
+ not a white sheet.
155
+ - **Textural grain**: one fullscreen noise/grain layer (CSS `mask` over an SVG
156
+ turbulence tile or a tiny shader) at 3–6% opacity unifies WebGL and DOM into
157
+ one photographic surface. Cheap, high-impact.
158
+ - **Easter eggs** (epic.net's signature): 1–3 hidden delights — a konami code, a
159
+ clickable mascot, an idle-timeout animation. Never gate content behind them.
160
+
161
+ ## 6. Performance & accessibility (the genre's hard mode)
162
+
163
+ Everything in motion.md §6 and 3d.md §7 applies, plus genre-specific:
164
+
165
+ - Budget the WHOLE experience: ≤ 4–5MB initial including models/fonts; stage
166
+ code lazy-loaded behind the preloader; route content prefetched on hover so
167
+ spatial transitions never wait on network mid-flight.
168
+ - One rAF loop owns the world (scene + cursor + scroll damping share it). Two
169
+ competing loops = the micro-stutter that separates good from great here.
170
+ - `prefers-reduced-motion` gets a REAL alternative, not a broken world: static
171
+ scene per chapter, instant route swaps (crossfade ≤ 200ms), scroll returns to
172
+ plain document reading. Decide this layout up front — retrofitting it is why
173
+ most immersive sites fail the audit.
174
+ - Keyboard path through the world: chapter index and nav focusable, focus moved
175
+ to incoming page's `<h1>`/main after a route transition, skip-link to content
176
+ over the intro. Announce route changes (`aria-live="polite"` region).
177
+ - Low-power fallback ("flat mode"): detect weak GPU/`navigator.deviceMemory`/
178
+ first dropped-frame burst → swap stage for poster art + gradients, keep ALL
179
+ content and transitions-lite. Content is never hostage to the world. Offer the
180
+ same switch as a visible toggle if the brief allows.
181
+ - SEO/no-JS: every route server-renders its real copy; the world enhances it.
182
+
183
+ ## 7. Recipes
184
+
185
+ - **Scroll-dolly index (verified on unseen.co)**: one scroll axis dollies the
186
+ camera from the hero space directly into the works gallery — a bright hall
187
+ whose section heading and filter pills are DOM floating in front of the
188
+ scene, work cards as gently-warped paper planes hovering in depth. The route
189
+ updates mid-journey while the world persists. One continuous shot, zero page
190
+ loads.
191
+ - **Chapter theme inversion (verified on bdsn.club)**: an editorial case-study
192
+ page where each full-viewport project chapter flips the ENTIRE page theme
193
+ (white → black → brand indigo…) as it scrolls in, with an oversized grotesk
194
+ project title and one product render per chapter; HUD (local time top-left,
195
+ CTA top-right, awards rail on the edge) stays fixed through every inversion.
196
+ DOM-only, no WebGL — the spatial feel comes purely from theme travel + scale.
197
+ - **World portfolio**: persistent canvas; works as textured planes arranged in
198
+ depth (DOM-synced media planes per media.md §3 — real images underneath);
199
+ scroll flies the camera past them; hover tilts a plane + cursor says
200
+ "View"; click = camera dives to the plane which morphs into the project hero
201
+ (shared-element). Back = reverse flight.
202
+ - **Scene-hopping studio site (epic-style)**: stylized environment as stage;
203
+ each route = a location; nav travels the camera between locations with a
204
+ velocity blur beat; DOM copy floats per location; playful idle animations +
205
+ 1–2 easter eggs; HUD chrome + fullscreen menu.
206
+ - **One-page descent**: 6–8 chapter tall-scroll journey down one axis (tower,
207
+ ocean, timeline); palette darkens/shifts per chapter; progress rail with
208
+ chapter names; ends on a contact "floor" that snaps.
209
+ - **DOM-only spatial site (no WebGL)**: layered `translateZ`-style parallax with
210
+ scale/blur depth cues, View Transitions for shared-element route morphs,
211
+ clip-path wipes, grain overlay, custom cursor, oversized type. 80% of the feel
212
+ at 5% of the cost — the right call below motion dial 8 or without 3D subject
213
+ matter.
214
+
215
+ ## 8. Changing an existing site into this
216
+
217
+ An existing conventional site cannot become immersive through CSS — this genre
218
+ requires the app-shell/stage architecture (§1), which means restructuring markup,
219
+ routing, and component boundaries. Follow DESIGN.md §11's transformation-depth
220
+ ladder: present the depth options, and on user confirmation restructure for real
221
+ — move the router swap point, introduce the stage layer, rebuild sections as
222
+ chapters. Never simulate the genre by decorating the old structure; a restyled
223
+ static page with a custom cursor is the uncanny valley of this genre.