From da7bd9940e87ddfb7c1ea7e20f31adccc64ae16e Mon Sep 17 00:00:00 2001 From: LucaP Date: Sat, 10 Oct 2026 19:06:29 +0300 Subject: [PATCH] docs: record round 3 route concept and decisions --- docs/redesign/round3.md | 129 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 docs/redesign/round3.md diff --git a/docs/redesign/round3.md b/docs/redesign/round3.md new file mode 100644 index 0000000..4e7733f --- /dev/null +++ b/docs/redesign/round3.md @@ -0,0 +1,129 @@ +# Round 3: The Route + +## Concept + +Round 2 gave the page one sign language. It still read as one page: eight +identical glass cards laid over a world that never changed. Round 3 makes the +drive a route, with places along it. + +- **The world changes per chapter.** A Blender-authored kit of roadside + districts rises out of the ground for each chapter and sinks again behind + you. +- **The page changes its form.** Each chapter opens with its exit tab and a + large heading standing over the road, then a reading panel, then a "next + exit" sign. Open road separates chapters, so the districts can be seen. +- **Navigation is a map of the route.** You can see where you are, which exits + you have passed, and where you stopped last time. + +## Changes + +### World + +- **Roadside districts** (`assets/blender/districts/`, `src/scene/world/districts.ts`). + - Eight original pieces, 5,424 triangles in total. The GLB is 84 KB raw, or + 13 KB with brotli. + - The kit is authored by a headless script, `author-districts.py`. It writes + `nightdrive-districts.blend` with its own "Roadside Districts" scene. + - `export-districts.py` writes the GLB and the provenance file. + - Which pieces rise in which chapter: + + | Pieces | Chapters | + |---|---| + | Gantries | Profile to Toolkit | + | Billboards | Profile, Career | + | Server rows and radio masts | Infra | + | Workshop and cranes | Builds | + | Container yard | More work | + | Destination arch | Contact | + + - Pieces are instanced and wrapped by the same distance shader as the + expressway. Flat normals are derived per fragment, so the GLB carries + positions only. + - Lights take the chapter accent, catch with a neon stutter, and dim close to + the camera. + - Pieces at rest are hidden, so they cost no draw calls. + - The low tier halves the instance counts. + - Shaders compile at the on-ramp, not mid-drive. + +### Page + +- **Reading stage** (fixed in `71959f7`, before this round's UI work). + - Sticky failed because the viewport used `overflow: clip`. + - The viewport is now a script-scrolled `overflow: hidden` container. + - Browser-initiated inner scrolls (find-in-page, focus) are forwarded to the + document. + - Navigation re-lands before focus if the stage switches on or off mid-journey. +- **Chapter openers** (`PortfolioSection.vue`, `route.css`). + - Each chapter starts with a `clamp(54px, 7.2vw, 124px)` heading over the + road, with a dark halo instead of a plate and an accent bar. + - The panel chrome moves to a new `.chapter-body`. + - Each chapter ends with a `NEXT EXIT 04 / Infrastructure →` sign. + - Phones get the same opener, scaled to the column. +- **Case studies** (≥1100 px). + - Evidence sits beside a sticky media column. This was impossible before the + stage fix. + - Evidence reads as spec rows: a lettered stop, then the text. +- **Destination.** + - A 168 px heading and larger copy and CTA. + - The avatar stands beside the heading. + - The plate reads `END OF ROUTE · 7 OF 8 EXITS · 3 MIN ON THE ROAD`. This + comes from the real visit and is rendered as CSS generated content. +- **Route-map navigation.** + - A road line under the exits fills up to the current one. It changes on + chapter change only, never per scroll. + - Nodes are hollow ahead, filled once passed, and shown as a car marker where + you are. + - On phones the closed bar reads `EXIT 05 · Builds`, and the open list is a + vertical route. +- **Persisted progress** (`useRouteMemory.ts`). + - Exits passed and the last stop are kept in localStorage. + - Storage is read only after mount, and failures are silent. + - A returning visitor gets a "Resume · Exit 05 · Builds →" chip in the hero. + The chip has an aria-label and a CSS label, so the hydrated text is + identical to the server document. +- **Keyboard.** Alt+↓ and Alt+↑ go to the next and previous exit. + +## Decisions + +| Brief item | Decision | Why | +|---|---|---| +| Per-chapter Blender props and districts | Adopted | The biggest missing piece: the world now tells you which chapter you are in. | +| Gantries | Adopted | They are part of the district kit, and their height clears the chase camera. | +| Better sign geometry | Adapted | Round 2's sign faces read well at 1280, 1440 and 1920. The budget went to the districts instead. | +| Atmosphere and time progression | Kept | The chapter palettes already run from deep night to pre-dawn. District accents now follow them. | +| Rain or wet road | Rejected | A new full-screen pass plus reflections costs a GPU tier, and it fights the synthwave identity. | +| Better hero car lighting | Deferred | The car GLB was not touched this round (see the Blender note below). | +| Draco or meshopt | Rejected | The districts are 13 KB brotli, and the decoder would cost more than it saves. | +| Reading panels and typography | Adopted | Chapter openers, `.chapter-body` panels and next-exit signs. | +| Case studies | Adapted | Sticky two-column at ≥1100 px. Long galleries stay in normal flow when taller than the window. | +| Route map or minimap | Adopted | The navigation itself is the map. No extra widget, and no per-scroll work. | +| Scroll choreography | Adapted | Rising districts and the exit-tab strike carry it. The view-timeline reveals stay off inside the live stage to avoid fighting the reading mask. | +| Mobile first-class | Adapted | Openers, the route bar and the vertical route list on phones. No horizontal scroll at 320 or 390 px. | +| Contact as a destination and a strong ending | Adopted | The arch district, the giant heading and the trip log. | +| Sticky layout | Fixed | See "Reading stage" above. | +| Keyboard journey | Adapted | Alt+arrows, not digits or `[` `]`: single-character shortcuts fail WCAG 2.1.4 without a way to turn them off. | +| Deep links | Kept | Hash links already land correctly and are now more robust. | +| Persisted progress | Adopted | localStorage, client-only. | +| Honest loading states | Kept | Districts stream in silently. A failed fetch leaves the old road. | +| Sound coupling | Deferred | Round 2's music pulse already couples the world to the soundtrack. A pass-by on exit arrival needed audio design time this round did not have. | +| Stylesheet consolidation | Deferred | `route.css` is one new file. Merging the eleven existing files safely needs a cascade-order audit, and its risk is out of proportion to its value. | + +## Blender note + +An early attempt drove the user's live Blender session through MCP. Calling +`bpy.data.libraries.write` with a scene crashed that Blender. The open file +reported no unsaved changes beforehand. The crash log is at +`/tmp/nightdrive-grand-tourer.crash.txt`. + +All later work ran headless (`blender -b --factory-startup`). The author script +refuses to run anywhere else. + +## Run + +```sh +source ~/.nvm/nvm.sh && nvm use 22.22.1 +npm run build:preview # budgets: "violations": [] +python3 -m http.server 5175 -d dist +blender -b --factory-startup --python assets/blender/districts/author-districts.py +blender -b assets/blender/districts/nightdrive-districts.blend --python assets/blender/districts/export-districts.py +```