diff --git a/docs/overnight/LOG.md b/docs/overnight/LOG.md index cfa4a6e..e2b8e88 100644 --- a/docs/overnight/LOG.md +++ b/docs/overnight/LOG.md @@ -15,3 +15,11 @@ Run: `npm run build:preview` then serve `dist` (dev server shows a blank page). - **Known weakness:** the reading panel covers the scene during p 0.1-0.75, so district power-down, packets and offsite are barely visible; relight uses the normal accent so the payoff reads as "back to normal". Audio rain bed skipped. Do not revisit before round 5. - Screenshots: docs/overnight/round1/ (before-* vs p*-1440/390). +## Round 2: High Beam (hero, road, plates) +- **What:** the cursor steers the headlights. Fine-pointer hero name first paints as an outline, a 1.6 s sweep lights it, then a pointer-following halo lights the letters, plate edges and sparks; in the world the road cones yaw, terrain/districts catch the light, a warm SpotLight rakes the truss (high/medium), and a haze cone shows in the gaps between chapters. Click hero/gantry window flashes (rate-limited). Idle 4 s returns to centre. Touch/low tier: slow sway and tap flash only. Reduced motion: no effect, name stays lit. +- **Why:** first thing a juror does is move the mouse; the hero had no pointer response and the scene none at all (direction.md signature moment 3, never built). Lives where round 1 said drama should: hero, gaps, panel edges. +- **Build:** src/journey/headlight-beam.ts, useHeadlightBeam.ts, scene/world/headlights.ts, styles/headlight.css; beam terms in road, districts, terrain shaders. Initial JS +1.3 KB gz (113.0), 732 tests green. +- **Verdict: KEEP with fixes.** Fable found the DOM half dead on delivery (NaN sentinel), fixed it, removed a drop-shadow rectangle artefact, raised the resting level. Frame times unchanged (p95 16.7 ms on hardware GL). +- **Known weaknesses:** the outline-to-lit sweep beat is short (~300 ms visible); haze cone slightly flat/white; spark boost barely perceptible. +- Screenshots: docs/overnight/round2/. + diff --git a/docs/overnight/round2/beam-centre.webp b/docs/overnight/round2/beam-centre.webp new file mode 100644 index 0000000..016127f Binary files /dev/null and b/docs/overnight/round2/beam-centre.webp differ diff --git a/docs/overnight/round2/beam-left.webp b/docs/overnight/round2/beam-left.webp new file mode 100644 index 0000000..7a28aef Binary files /dev/null and b/docs/overnight/round2/beam-left.webp differ diff --git a/docs/overnight/round2/beam-right.webp b/docs/overnight/round2/beam-right.webp new file mode 100644 index 0000000..05da7c6 Binary files /dev/null and b/docs/overnight/round2/beam-right.webp differ diff --git a/docs/overnight/round2/before-fix-dim-name-1440.webp b/docs/overnight/round2/before-fix-dim-name-1440.webp new file mode 100644 index 0000000..4e850d8 Binary files /dev/null and b/docs/overnight/round2/before-fix-dim-name-1440.webp differ diff --git a/docs/overnight/round2/before-hero-1440.webp b/docs/overnight/round2/before-hero-1440.webp new file mode 100644 index 0000000..d42c522 Binary files /dev/null and b/docs/overnight/round2/before-hero-1440.webp differ diff --git a/docs/overnight/round2/builds-1440.webp b/docs/overnight/round2/builds-1440.webp new file mode 100644 index 0000000..d790b74 Binary files /dev/null and b/docs/overnight/round2/builds-1440.webp differ diff --git a/docs/overnight/round2/contact-1440.webp b/docs/overnight/round2/contact-1440.webp new file mode 100644 index 0000000..042564d Binary files /dev/null and b/docs/overnight/round2/contact-1440.webp differ diff --git a/docs/overnight/round2/flash.webp b/docs/overnight/round2/flash.webp new file mode 100644 index 0000000..7a6ff46 Binary files /dev/null and b/docs/overnight/round2/flash.webp differ diff --git a/docs/overnight/round2/gap-1440.webp b/docs/overnight/round2/gap-1440.webp new file mode 100644 index 0000000..1e5deb3 Binary files /dev/null and b/docs/overnight/round2/gap-1440.webp differ diff --git a/docs/overnight/round2/gap-right-1440.webp b/docs/overnight/round2/gap-right-1440.webp new file mode 100644 index 0000000..75d0d57 Binary files /dev/null and b/docs/overnight/round2/gap-right-1440.webp differ diff --git a/docs/overnight/round2/idle-return.webp b/docs/overnight/round2/idle-return.webp new file mode 100644 index 0000000..8f7784c Binary files /dev/null and b/docs/overnight/round2/idle-return.webp differ diff --git a/docs/overnight/round2/mobile-390.webp b/docs/overnight/round2/mobile-390.webp new file mode 100644 index 0000000..34e3c59 Binary files /dev/null and b/docs/overnight/round2/mobile-390.webp differ diff --git a/docs/overnight/round2/plate-edge-1440.webp b/docs/overnight/round2/plate-edge-1440.webp new file mode 100644 index 0000000..b137e60 Binary files /dev/null and b/docs/overnight/round2/plate-edge-1440.webp differ diff --git a/docs/overnight/round2/reduced-motion-1440.webp b/docs/overnight/round2/reduced-motion-1440.webp new file mode 100644 index 0000000..4237fae Binary files /dev/null and b/docs/overnight/round2/reduced-motion-1440.webp differ diff --git a/docs/overnight/round2/road-left.webp b/docs/overnight/round2/road-left.webp new file mode 100644 index 0000000..4371f2d Binary files /dev/null and b/docs/overnight/round2/road-left.webp differ diff --git a/docs/overnight/round2/road-right.webp b/docs/overnight/round2/road-right.webp new file mode 100644 index 0000000..04656c3 Binary files /dev/null and b/docs/overnight/round2/road-right.webp differ diff --git a/docs/overnight/round2/t100-hero.webp b/docs/overnight/round2/t100-hero.webp new file mode 100644 index 0000000..07cefd9 Binary files /dev/null and b/docs/overnight/round2/t100-hero.webp differ diff --git a/docs/overnight/round2/t1800-hero.webp b/docs/overnight/round2/t1800-hero.webp new file mode 100644 index 0000000..7aa24b8 Binary files /dev/null and b/docs/overnight/round2/t1800-hero.webp differ diff --git a/docs/overnight/round2/t3500-hero-settled.webp b/docs/overnight/round2/t3500-hero-settled.webp new file mode 100644 index 0000000..0e80469 Binary files /dev/null and b/docs/overnight/round2/t3500-hero-settled.webp differ diff --git a/docs/overnight/round2/t800-hero.webp b/docs/overnight/round2/t800-hero.webp new file mode 100644 index 0000000..c3a9657 Binary files /dev/null and b/docs/overnight/round2/t800-hero.webp differ diff --git a/src/App.vue b/src/App.vue index 8e593ff..332d1e2 100644 --- a/src/App.vue +++ b/src/App.vue @@ -16,6 +16,7 @@ import './styles/gantry.css'; import './styles/cards.css'; import './styles/maintenance.css'; import './styles/print.css'; +import './styles/headlight.css'; defineProps<{ inputs: Readonly }>(); diff --git a/src/components/AppShell.vue b/src/components/AppShell.vue index b30df84..9e9c1fd 100644 --- a/src/components/AppShell.vue +++ b/src/components/AppShell.vue @@ -16,6 +16,7 @@ import { useAdaptiveQuality } from '@/composables/useAdaptiveQuality'; import { useAudioEngine } from '@/composables/useAudioEngine'; import { useAudioIntent } from '@/composables/useAudioIntent'; import { useCardEntrances } from '@/composables/useCardEntrances'; +import { useHeadlightBeam } from '@/composables/useHeadlightBeam'; import { useJourneySections } from '@/composables/useJourneySections'; import { useKeyboardNavigation } from '@/composables/useKeyboardNavigation'; import { useMaintenanceWindow } from '@/composables/useMaintenanceWindow'; @@ -140,6 +141,12 @@ const pinnedPerformanceTier = requestedPerformanceTier === 'high' || requestedPe ? requestedPerformanceTier : null; const actualQuality = computed(() => pinnedPerformanceTier ?? adaptive.snapshot.value.actual); +/* HIGH BEAM: the cursor is the car's headlights, in the scene and on the page. */ +const headlight = useHeadlightBeam({ + motionAllowed: computed(() => motion.policy.value.allowSceneRequest && pageLifecycle.value === 'active'), + quality: actualQuality, + activeSectionId: () => journey.value.activeSectionId, +}); const activeSectionLabel = computed(() => sectionLabel(journey.value.activeSectionId)); const serverDefaultPolicy: MotionPolicy = { allowSceneRequest: false, @@ -152,6 +159,7 @@ const displayedSceneState = computed(() => controlsReady.value ? sceneState.valu let removePageListeners = (): void => {}; const sampleSceneFrame = (start: number, end: number): void => { + headlight.sceneFrame(); if (pinnedPerformanceTier === null) adaptive.sampleFrame(start, end); if (TEST_BUILD) window.__PORTFOLIO_PERFORMANCE__?.recordSceneFrame(start, end); }; @@ -253,6 +261,7 @@ onUnmounted(() => removePageListeners()); :scene-description="content.sceneDescription" :credit="`${content.identity.name} · ${content.identity.role} · ${content.identity.location.city}, ${content.identity.location.country}`" :sample-frame="sampleSceneFrame" + :sample-beam="headlight.sampleBeam" @state-change="updateSceneState" />
-

{{ identity.name }}

+

{{ identity.name }}

{{ identity.role }}

{{ identity.valueProposition }}

{{ identity.availability }}

diff --git a/src/components/NameParticles.vue b/src/components/NameParticles.vue index b889421..f69ebbb 100644 --- a/src/components/NameParticles.vue +++ b/src/components/NameParticles.vue @@ -1,5 +1,6 @@