This System Requirements Document defines ultra-do, the project codename for Vanguard & Stone, a cinematic, scroll-driven marketing website for a premium architectural developer. The site presents the "River District" development as one continuous, scroll-driven experience where a raw construction site transforms into a glowing living city, rendered in real time by a persistent Three.js world behind fixed HTML overlays.
The document captures the required capabilities, architecture, data, visual language, interaction model, motion direction, and technical stack as specified by the source material. The product scope is a single-page, scroll-narrative marketing experience — not an application with accounts, dashboards, or administrative surfaces. The explicit user directive is to build the described experience but with improved 3D, better transformations, better movement, and better scroll.
Vanguard & Stone is a single-page experience built on a 600vh scroll track. As the visitor scrolls, a fixed, full-viewport Three.js canvas (rendered behind all content) grows a procedural city from a raw construction site into a completed glowing living city. Fixed-position HTML overlays — one per narrative section — mount and unmount at discrete scroll boundaries, presenting copy, controls, data cards, forms, and a floor-plan modal.
Core structural ideas:
useSyncExternalStore) holds discrete state: current section, time preference, blueprint mode, exploded view, active project/pin/floor, saved homes, modal, hover tooltip, quality tier, and scene-ready flag.Sections and global progress ranges:
| Section | Range | Nav Label |
|---|---|---|
| hero | 0.00–0.10 | Overview |
| build | 0.10–0.46 | The Rise |
| residences | 0.46–0.62 | Residences |
| district | 0.62–0.76 | District |
| record | 0.76–0.88 | Record |
| contact | 0.88–1.00 | Inquire |
Build-phase sub-ranges inside build: DATUM 0.10–0.18 · RISE 0.18–0.27 · FAÇADE 0.27–0.36 · REALM 0.36–0.42 · LIFE 0.42–0.46.
prefers-reduced-motion setting.scrollEngine that owns the only requestAnimationFrame loop so that all per-frame work is centralized.onFrame(progress, dt, time) so that the 3D world updates every frame without React involvement.onSectionChange notifications so that discrete UI state updates only at section boundaries.useSyncExternalStore (no external state library) so that UI state is shared predictably.section so that the active overlay and camera behavior can be derived.timePreference ('auto' | 'day' | 'golden' | 'night') so that time-of-day can be controlled by the user or the scroll story.blueprint (boolean) so that blueprint X-ray mode can be toggled.exploded (boolean) so that the exploded tower view can be toggled.activeProjectId so that the active residence tower is tracked.activePinId so that the active district pin is tracked.selectedFloor (number | null) so that the selected floor is tracked.savedHomes: string[] so that saved homes are available across overlays.savedHomes persisted to localStorage under key vs-saved-homes-v1, with entries formatted as projectId:floorNumber, so that saves persist between visits.modalFloor: {projectId, floorNumber} | null so that the floor-plan modal can be opened/closed.hoverTip: {x, y, label, sub} | null so that 3D hover tooltips can be displayed.quality: 'high' | 'medium' | 'low' so that render quality tier is tracked.sceneReady so that the scene-ready state is available to the UI.section === 'hero' && <HeroOverlay />) so that overlays appear in the correct narrative window.fixed inset-0 z-20 with pointer-events-none on the root and pointer-events-auto on interactive children so that overlays don't block canvas interaction.@ → repo root in vite.config.ts so that imports are consistent.SceneEngine built on WebGLRenderer and an EffectComposer (RenderPass → UnrealBloomPass → ShaderPass → OutputPass from three/addons) so that the world renders with bloom and post-processing.onQualityChange) so that the experience stays smooth on weaker devices.hoverTip so that I know what I'm hovering.dragAz/dragPol) so that I can rotate the view.parX/parY) so that the scene feels alive and responsive to my cursor.cityBuilder that generates a procedural city from seeded lots (x, z, w, d, h, minH, stagger, bucket, variant) so that the district is reproducible and varied.mergeGeometries for performance so that large building counts render efficiently.cityBuilder.update(buildT, dt, time) to grow the construction as I scroll through the build section so that the city literally builds itself.setDusk(dusk) to lerp city lighting so that the district changes with time of day.setConstructionFxVisible so that construction effects appear during the build narrative.glowMaterials exposed for bloom so that glowing elements participate in post-processing.focus (the construction point for the camera) exposed so that the camera can target the active construction area.setExplode(0..1) for an exploded axonometric view so that I can see a tower's structure separated.setGrowth(0..1) so that towers grow along the scroll narrative.setHighlightFloor(floorNumber | null) so that the selected floor is highlighted in 3D.pick(raycaster) → { projectId, floorNumber, listed, label, price, point } so that hovering/clicking a tower yields structured unit data.setDusk on hero towers so that towers respond to time of day.[0,-16], Skybridge [-34,2]) and midY exposed so that the camera can orbit/frame each tower.skyRig gradient sky dome shader that transitions day → golden hour → night (with stars) so that the sky matches the story.dusk 0..1 to blend sky palettes driven by timePreference so that sky transitions are continuous.cameraDirector with section-aware analytic camera goals (position/lookAt/fov) and heavy exponential damping so that camera movement is smooth and cinematic.textures module generating 2D-canvas facade/window patterns via makeFacade, scaleBoxUVs, and reseed so that facades are procedurally varied.makeCloudTexture and makeGlowSprite so that clouds and glow sprites are available to the scene.BUILD_PHASES data (01 DATUM Foundations +0m · 02 RISE Superstructure +85m · 03 FAÇADE Glass & bronze +140m · 04 REALM Parks & canal +165m · 05 LIFE First residents 2027) so that the build narrative has precise phases.RESIDENCE_PROJECTS with three projects — The Spire (36 storeys · river glass tower, highrise, 165 m, 36 floors, from €890K, 8 left, Q3 2027, "Full-height solar glass, corner loggias, skyline forever."), Skybridge One (Twin towers · pool in the sky, 110 m, 28 floors, from €740K, 6 left, Q1 2027, "Two slender towers joined at level 20 by a glass sky club."), and River Terraces (Stepped villas · private pools, from €1.45M, 3 left, Q4 2026) — so that all residences are presented accurately.€4.85M, features: Private lift foyer / 65 m² sky terrace / Plunge pool; rooms: Grand Salon 75.5 m² Silver Travertine, Primary Suite 33.5 Oak & Linen, Kitchen 21.8 Calacatta & Bronze, Sky Terrace 39.5 Ash Decking · Floor 22 Corner River Home, 3-bed, 178 m², SE waterfront, €2.15M · Floor 8 Parkside Loft, 1-bed loft, 72 m², Park & canal, €890K) so that unit detail is complete.€2.49M) so that its flagship unit is shown.floorNumber, name, type, areaSqm, bedrooms, bathrooms, orientation, price, priceEUR, status, features[], rooms[] so that unit data is structured.{ id, name, areaSqm, finish, at: [x,z], size: [w,d] } so that they are SVG-ready floor-plan geometry (at/size → rects).NEIGHBORHOOD_PINS data with four pins — Express Metro (transit, 3 min, [-40,-15.5]) · Central River Park (nature, 2 min, [-8,-34]) · Marina Promenade (water, 1 min, [16,25]) · Avenue Roastery (culinary, 2 min, [22,-13]) — so that amenities are accurate and placed.RECORD_STATS data — EST. 2004 / 22 / Years · DELIVERED / 1240+ / Homes · MASTERPLAN / 485k m² / Built realm · PROTOCOL / 99.4% / On time — so that the record section shows real credibility figures.onComplete — so that the experience loads deliberately.fixed top-0 left-0 right-0 z-40 flex items-center justify-between gap-3 px-4 md:px-6 py-3 bg-white/75 backdrop-blur-md border-b border-stone-900/8) so that global controls are always available.Vanguard<span>&</span>Stone (text-base md:text-lg font-serif font-semibold tracking-tight, hover → #E65100) plus a hidden lg:inline text-[9px] font-mono uppercase tracking-[0.2em] text-stone-400 "River District" label, so that brand identity is persistent.hidden md:flex, container p-0.5 rounded-full bg-stone-900/5) for Overview / The Rise / Residences / District / Record / Inquire, with active state bg-stone-900 text-white shadow-sm and inactive text-stone-500 hover:text-stone-900, so that I can navigate sections.Sparkles auto / Sun day / Sunset golden / Moon night; active bg-[#E65100] text-white) so that I can control the sky.DraftingCompass, active bg-[#0b3aa8] text-white, tooltip "Blueprint X-Ray (B)") so that I can switch to blueprint X-ray view.Heart) button with a count so that I can open/review saved homes.Volume2/VolumeX) so that I can enable/disable the ambient soundscape.51.9225° N · 4.4792° E, the current section, and scroll progress so that I have orientation.utils/audio.ts) as an opt-in ambient soundscape whose soundscape.updateScroll(p) is fed from the frame loop (no React state) so that sound responds to scroll without causing re-renders.Hero Overlay
w-1.5 h-1.5 rounded-full bg-[#E65100] animate-pulse) plus "River District" (text-[10px] font-mono tracking-[0.25em] uppercase) so that the district is introduced.text-5xl sm:text-7xl md:text-8xl font-serif text-stone-900 leading-[0.95] tracking-tight mb-6) so that the brand statement lands.3 towers · 165 m · 2027 so that key facts are immediate.group flex items-center gap-2.5 px-6 py-3.5 bg-[#E65100] hover:bg-[#D84300] text-white text-xs font-bold uppercase tracking-widest transition-all shadow-lg shadow-orange-900/20 + Lucide ArrowRight with group-hover:translate-x-1) so that I can jump to residences.px-6 py-3.5 bg-white/85 hover:bg-white backdrop-blur-sm border border-stone-900/10 text-stone-800 text-xs font-bold uppercase tracking-widest) so that I can watch construction.hidden sm:flex, absolute bottom-6 right-6 md:right-12) with a MousePointer2 icon and text-[10px] font-mono uppercase tracking-widest text-stone-500 "Scroll — the city builds itself" so that I know to scroll.absolute bottom-0 left-0 right-0 h-[2px] with bg-gradient-to-r from-[#E65100] to-transparent opacity-60) so that hero progress is visible.Build Overlay
text-[10px] font-mono font-bold tracking-[0.3em] text-[#E65100] uppercase, e.g. "02 / RISE") so that the current phase is labeled.text-4xl md:text-6xl font-serif text-stone-900 leading-none tracking-tight) plus elevation (text-lg md:text-2xl font-mono text-stone-400 tabular-nums, e.g. +85m) so that phase and height are shown.mt-5 h-[3px] w-64 max-w-full bg-stone-900/10 overflow-hidden with inner h-full w-full bg-[#E65100] origin-left scaled by phase progress) so that phase completion is visible.Residences Overlay
pointer-events-auto flex items-center gap-1 p-1 bg-white/85 backdrop-blur-md border border-stone-900/10 shadow-lg; tab px-3 md:px-4 py-2 text-[11px] font-bold uppercase tracking-wider, active bg-[#E65100] text-white shadow-sm, inactive text-stone-600 hover:text-stone-900 hover:bg-stone-100) so that I can switch between the three projects.Layers icon + "Exploded"/"Assembled", active bg-stone-900 text-white border-stone-900, inactive bg-white/85 backdrop-blur-md text-stone-700 border-stone-900/10, text-[10px] font-mono uppercase tracking-widest) so that I can switch tower views.pointer-events-auto w-full max-w-sm bg-white/88 backdrop-blur-md border border-stone-900/10 shadow-2xl) with a header row (tagline text-[9px] font-mono uppercase tracking-[0.25em] text-[#E65100] font-bold, serif name, right-aligned from {price} + availability in text-emerald-700 font-bold) so that project pricing is clear.District Overlay
flex items-center gap-3 px-4 py-2 bg-white/85 backdrop-blur-md border border-stone-900/10 shadow-xl) with MapPin w-3.5 h-3.5 text-[#E65100], name (text-xs font-semibold text-stone-900), and walk time (text-[10px] font-mono text-emerald-700 font-bold) so that I see pin details.flex flex-wrap justify-center items-center gap-1.5 p-1.5 bg-white/85 backdrop-blur-md border border-stone-900/10 shadow-xl max-w-[94vw], chips text-[11px] font-bold uppercase tracking-wider) so that I can filter amenities.Record Overlay
text-[10px] font-mono font-bold tracking-[0.3em] text-[#E65100] uppercase) and a serif headline (text-4xl md:text-6xl ... leading-[0.95] mb-7 drop-shadow-sm) so that the credibility section is introduced.pointer-events-auto grid grid-cols-2 md:grid-cols-4 gap-2.5 md:gap-3) with cards (bg-white/80 backdrop-blur-md border border-stone-900/10 shadow-xl px-4 py-4 md:px-6 md:py-5), kicker (text-[9px] font-mono font-bold tracking-[0.25em] text-[#E65100] uppercase), value (text-3xl md:text-5xl font-mono font-bold text-stone-900 tabular-nums leading-tight), and label (text-[11px] font-medium text-stone-500) so that the four record stats read clearly.Contact Overlay
pointer-events-auto grid grid-cols-1 lg:grid-cols-12 gap-4 w-full max-w-4xl) with a form card (lg:col-span-7 bg-white/88 backdrop-blur-md border border-stone-900/10 shadow-2xl p-6 md:p-8) so that the inquiry form is presented cleanly.text-[10px] font-mono font-bold tracking-[0.3em] text-[#E65100] uppercase mb-1) and H2 "The keys are waiting<span>.</span>" (text-3xl md:text-4xl font-serif text-stone-900 tracking-tight mb-5) so that the closing message lands.w-full px-4 py-3 text-sm bg-white/70 border border-stone-900/15 focus:border-[#E65100] focus:outline-none transition-colors) so that I can submit an inquiry.w-full flex items-center justify-center gap-2 py-3.5 bg-[#E65100] hover:bg-[#D84300] text-white text-xs font-bold uppercase tracking-[0.2em] transition-all shadow-lg shadow-orange-900/20, with ArrowRight nudge; label "Sending…" while submitting) so that I can request contact.w-11 h-11 rounded-full bg-emerald-100 + Check w-5 h-5 text-emerald-700, "Received — an advisor replies within 24h.", and a "Send another" link) so that I know my inquiry was received.savedHomes) and an address block "14 Quai de Saint-Jude" with MapPin so that my saved units and the address are visible.Floor Plan Modal
FloorPlanModal that draws an SVG floor plan from floor.rooms (at/size → rects) so that I can see the unit layout.{room.name} — {room.finish} (otherwise "Hover rooms for finishes") so that I can inspect finishes.{areaSqm} m² · {bedrooms} bed · {bathrooms} bath so that unit specs are summarized.ArrowDown/ArrowRight to advance to the next section and ArrowUp/ArrowLeft to go to the previous section in order (hero, build, residences, district, record, contact) so that I can navigate without a mouse.B to toggle blueprint X-ray so that I can switch views from the keyboard.hoverTip) so that I know what I'm hovering.FloorPlanModal so that I can inspect the unit.activePinId so that I can inspect that amenity.#0b3aa8) so that I can view structures as blueprints.localStorage and surface in the contact overlay so that my saves carry through the experience and across visits.setExplode on the active tower so that I can separate/reassemble a tower..vs-range in index.css) with a 3px track rgba(28,25,23,0.12) and a square orange thumb #e65100 with white border and orange glow that rotates 45° and scales on hover (mortgage/payment calculator styling) so that sliders feel on-brand.body::after, fixed, low opacity, pointer-events-none) so that the site has a subtle cinematic texture.p-4 md:p-8 / p-6 md:p-12) so that content fits small screens.text-5xl sm:text-7xl md:text-8xl) so that the hero headline is legible.grid-cols-2 md:grid-cols-4 so that stats stack appropriately.grid-cols-1 lg:grid-cols-12 so that the form is usable on small screens.hidden md:flex and the hero scroll hint hidden sm:flex so that small screens aren't cluttered.flex-wrap, max-w-[94vw] on district chips) so that controls remain accessible.#E65100, stone neutrals, #0b3aa8, white/85–90 glass) so that the visual identity is consistent.prefers-reduced-motion: reduce who loads the site and needs Lenis and heavy motion disabled while content and overlays remain reachable. Their successful outcome is that the narrative sections, controls, and inquiry flow stay usable without heavy motion.System Actors (not product personas):
localStorage.External Recipients:
Flow 1 — Arrival & Narrative Scroll (Prospective Resident)
onComplete, the Hero Overlay appears over the persistent 3D world with the pulsing "River District" kicker, the "Live above the river." headline, the 3 towers · 165 m · 2027 sub-line, and the scroll hint.Flow 2 — Exploring Residences (Prospective Resident)
from {price}, and availability.setExplode) to see the axonometric separation.hoverTip tooltip appears; clicks a slab → floor is selected, highlighted in 3D, and FloorPlanModal opens.rooms; hovering a room updates the footer to {room.name} — {room.finish}; footer stats show area, bed, bath.localStorage under vs-saved-homes-v1 as projectId:floorNumber).Flow 3 — Exploring the District (Prospective Resident)
activePinId is set and the active pin card shows name, MapPin, and walk time.Flow 4 — Setting Atmosphere & View (Prospective Resident)
timePreference updates and the sky rig crossfades palettes (with fog/light and water shimmer) via the dusk blend.DraftingCompass button or the B key; materials switch to #0b3aa8 blueprint style.soundscape.updateScroll(p) is fed from the frame loop.Flow 5 — Record & Inquiry (Prospective Resident → External Recipient)
RECORD_STATS cards (Years, Homes, Built realm, On time) appear.savedHomes) and the address block "14 Quai de Saint-Jude" with MapPin. The inquiry is delivered to a Sales Advisor as an external recipient.Flow 6 — Reduced Motion (Motion-Sensitive Visitor)
prefers-reduced-motion: reduce loads the site; Lenis and heavy motion are disabled while content and overlays remain reachable.Brand & Typography (exact): Single Google Fonts link loading Fraunces, JetBrains Mono, and Plus Jakarta Sans. Tailwind v4 @theme in src/index.css:
--font-serif: 'Fraunces', Georgia, serif--font-sans: 'Plus Jakarta Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif--font-mono: 'JetBrains Mono', monospaceBody: bg-[#f4f2ec] antialiased overflow-x-hidden. App root: bg-[#eef1f2] text-stone-900 selection:bg-[#E65100] selection:text-white.
Palette (exact):
#E65100 (hover #D84300, shadow shadow-orange-900/20)stone-900; muted stone-400 / 500 / 600; hairlines border-stone-900/8 and /10; chips bg-stone-900/5#0b3aa8emerald-700 on emerald-100bg-white/85 or bg-white/88 + backdrop-blur-md + border border-stone-900/10 + shadow-lg / shadow-xl / shadow-2xl#eef1f2 (app) over #f4f2ec (body)Sky Palettes (shader): day zen #6fa8d8 / mid #bfd9ec / hor #f2ede2; golden zen #5b7fb4 / mid #e8a878 / hor #ffd9a0; night zen #04060e / mid #0a1428 / hor #1c2c46; fog day #dce7ee.
Theme Character: Warm-neutral stone canvas, glass panels over a living 3D world, a single hot orange accent for action and emphasis, blueprint blue reserved for X-ray mode, emerald for success/availability. Editorial serif display type against mono labels and sans body text. A subtle fixed architectural film-grain overlay (body::after) adds cinematic texture.
The signature concept is "the city builds itself as you scroll." A single 600vh scroll track transforms a raw construction site into a glowing living city, with a persistent Three.js world behind fixed HTML overlays. The 3D scene is the hero — the HTML is a restrained glass-and-stone editorial layer floating above it. Scroll is the primary input; the camera is a director operating through six composed sections (Overview → The Rise → Residences → District → Record → Inquire), and the construction narrative advances through five explicit phases (DATUM → RISE → FAÇADE → REALM → LIFE) with matching elevation readouts. Motion is intentional and limited, with no floating badges, marquees, or gratuitous animation.
Interaction Model:
ArrowDown/ArrowRight next section, ArrowUp/ArrowLeft previous section, B toggles blueprint X-ray (ignored while typing in inputs).localStorage (vs-saved-homes-v1) and surface in the contact overlay.Motion Direction (only intentional motion):
prefers-reduced-motion disables Lenis and heavy motion.requestAnimationFrame loop owned by scrollEngine; React components never re-render per frame (state changes only at discrete section boundaries); city geometries merged via mergeGeometries; FPS-based auto quality degradation (high → medium → low).EffectComposer with RenderPass → UnrealBloomPass → ShaderPass → OutputPass; bloom driven by exposed glowMaterials.prefers-reduced-motion: reduce disables Lenis and heavy motion; full keyboard section navigation and B blueprint toggle; keyboard shortcuts ignored during input entry.p-4 md:p-8 / p-6 md:p-12; hero type text-5xl sm:text-7xl md:text-8xl; record stats grid-cols-2 md:grid-cols-4; contact grid-cols-1 lg:grid-cols-12; header pills hidden md:flex; hero scroll hint hidden sm:flex; tabs wrap (flex-wrap, max-w-[94vw] district chips).localStorage under vs-saved-homes-v1 as projectId:floorNumber entries.#E65100, stone neutrals, #0b3aa8, white/85–88 glass), and exact copy strings preserved.useSyncExternalStore; no external state library.@ → repo root in vite.config.ts)@tailwindcss/vite, @import "tailwindcss" + @theme in CSS — no tailwind.config)three/addons: EffectComposer, RenderPass, UnrealBloomPass, ShaderPass, OutputPass, mergeGeometries)useSyncExternalStore + localStorage (vs-saved-homes-v1)File tree to produce:
index.html (fonts, title, body classes)
src/main.tsx · src/App.tsx · src/index.css
src/lib/scrollEngine.ts (Lenis + single rAF loop + section map)
src/state/store.ts (useSyncExternalStore UI store)
src/data/residences.ts (phases, projects+floors+rooms, pins, stats)
src/types/index.ts
src/utils/audio.ts
src/three/SceneEngine.ts · cameraDirector.ts · cityBuilder.ts · heroTowers.ts · skyRig.ts · textures.ts
src/components/Preloader.tsx · Header.tsx · ElevationGauge.tsx · StatusBar.tsx · CustomCursor.tsx
src/components/HeroOverlay.tsx · BuildOverlay.tsx · ResidencesOverlay.tsx · DistrictOverlay.tsx · RecordOverlay.tsx · ContactOverlay.tsx · FloorPlanModal.tsx · ThreeScene.tsx
tailwind.config; theme defined via @theme in CSS.scrollEngine may own a requestAnimationFrame loop; React must not re-render per frame.vs-saved-homes-v1 with projectId:floorNumber entries.prefers-reduced-motion: reduce.h-[600vh]) that drives the entire narrative.requestAnimationFrame loop, driving Lenis, computing global progress, and fanning out frame/section events.RenderPass → UnrealBloomPass → ShaderPass → OutputPass).#0b3aa8, toggled by control or B key.setExplode(0..1).localStorage.'auto' | 'day' | 'golden' | 'night') controlling the sky rig.rooms geometry.
Raising the towers, the canal edge and the recorder’s ledger.
Five stamped phases carry the site through the build. The needle below tracks the scroll track from datum excavation to the first residents arriving on site.
Phase 01 of 05 — Foundations on the River District build.
0.62–0.76District
04 / District
Four anchors define the River District — transit, green, water and table. The elevated survey frames each one from the masterplan datum.
Delivered towers, masterplans and river frontages — measured, ruled and on record.
Send a private inquiry and a sales advisor responds directly. The final frame of the city is composed behind this panel — the development is complete, and the last residences remain open.
No homes saved yet.Heart a residence to add it here

Raising the towers, the canal edge and the recorder’s ledger.
Five stamped phases carry the site through the build. The needle below tracks the scroll track from datum excavation to the first residents arriving on site.
Phase 01 of 05 — Foundations on the River District build.
0.62–0.76District
04 / District
Four anchors define the River District — transit, green, water and table. The elevated survey frames each one from the masterplan datum.
Delivered towers, masterplans and river frontages — measured, ruled and on record.
Send a private inquiry and a sales advisor responds directly. The final frame of the city is composed behind this panel — the development is complete, and the last residences remain open.
No homes saved yet.Heart a residence to add it here
No comments yet. Be the first!