style: trim the interlude to about 1.5 s
This commit is contained in:
@@ -97,7 +97,7 @@ export function validateSectionAnchor(
|
|||||||
/** How long a pre-armed interlude waits for the scene loop to take over. */
|
/** How long a pre-armed interlude waits for the scene loop to take over. */
|
||||||
const PRE_ARM_TIMEOUT_MS = 1400;
|
const PRE_ARM_TIMEOUT_MS = 1400;
|
||||||
/** Matches INTERLUDE_RISE_MS in the environment loop. */
|
/** Matches INTERLUDE_RISE_MS in the environment loop. */
|
||||||
const PRE_ARM_RISE_MS = 1100;
|
const PRE_ARM_RISE_MS = 800;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A long navigator scroll passes the chapters in between. While the scene runs
|
* A long navigator scroll passes the chapters in between. While the scene runs
|
||||||
|
|||||||
@@ -649,7 +649,7 @@ const OUTRO_RETURN_SECONDS = 1.6;
|
|||||||
const OUTRO_REACH = 0.62;
|
const OUTRO_REACH = 0.62;
|
||||||
const ENGINE_OFF_NIGHT = new THREE.Color(0x000000);
|
const ENGINE_OFF_NIGHT = new THREE.Color(0x000000);
|
||||||
/** Plates rise back over 720 ms with up to three 90 ms staggers. */
|
/** Plates rise back over 720 ms with up to three 90 ms staggers. */
|
||||||
const INTERLUDE_RISE_MS = 1100;
|
const INTERLUDE_RISE_MS = 800;
|
||||||
|
|
||||||
function easeInOutCubic(t: number): number {
|
function easeInOutCubic(t: number): number {
|
||||||
return t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2;
|
return t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2;
|
||||||
|
|||||||
@@ -47,8 +47,12 @@ const TILT_RADIANS = 0.07;
|
|||||||
const HANDOFF_MS = 200;
|
const HANDOFF_MS = 200;
|
||||||
/** Above this scroll drive speed a passive crossing skips the interlude. */
|
/** Above this scroll drive speed a passive crossing skips the interlude. */
|
||||||
const BRISK_DRIVE_SPEED = 0.5;
|
const BRISK_DRIVE_SPEED = 0.5;
|
||||||
/** Share of the approach spent on the truss before the arc into the window. */
|
/** Share of the approach spent on the truss before the arc into the window.
|
||||||
const ON_TRUSS = 0.7;
|
* Round 6 trimmed the hold so the arc carries more of the approach. */
|
||||||
|
const ON_TRUSS = 0.62;
|
||||||
|
/** The reading plates start to rise about 180 ms (of a 900 ms approach)
|
||||||
|
* before the sign docks, so the interlude closes in about 1.5 s. */
|
||||||
|
const PLATE_RISE_PROGRESS = 0.8;
|
||||||
|
|
||||||
const SIGN_MARKER_FONT =
|
const SIGN_MARKER_FONT =
|
||||||
'600 60px "Geist Mono Variable", ui-monospace, monospace';
|
'600 60px "Geist Mono Variable", ui-monospace, monospace';
|
||||||
@@ -524,7 +528,8 @@ export function createSign(
|
|||||||
return state;
|
return state;
|
||||||
},
|
},
|
||||||
interlude() {
|
interlude() {
|
||||||
return !brisk && state === 'incoming';
|
if (brisk || state !== 'incoming') return false;
|
||||||
|
return !(snapshot?.phase === 'approach' && snapshot.progress >= PLATE_RISE_PROGRESS);
|
||||||
},
|
},
|
||||||
compose(camera, width, height, dock, now, tilt = REST_TILT) {
|
compose(camera, width, height, dock, now, tilt = REST_TILT) {
|
||||||
const dt = Math.min(0.05, Math.max(0, (now - previousNow) / 1000));
|
const dt = Math.min(0.05, Math.max(0, (now - previousNow) / 1000));
|
||||||
|
|||||||
@@ -708,45 +708,47 @@ html .drive-controls__audio-status {
|
|||||||
|
|
||||||
/* ---------- The interlude under the gantry ---------- */
|
/* ---------- The interlude under the gantry ---------- */
|
||||||
/* While a sign approaches (environment.ts sets data-interlude='on'), the
|
/* While a sign approaches (environment.ts sets data-interlude='on'), the
|
||||||
reading plates step up and out in 260 ms, so the road and the sign have
|
reading plates step up and out in 180 ms, so the road and the sign have
|
||||||
the frame to themselves; then ('rise') they come back up from below in
|
the frame to themselves; the headings follow once the plates are gone, so
|
||||||
sequence. Headings only fade: journey and audio measure them. */
|
a departing plate never ghosts over an arriving title. Then ('rise', about
|
||||||
|
180 ms before the sign docks) they come back up from below in sequence.
|
||||||
|
Headings only fade: journey and audio measure them. */
|
||||||
@media (prefers-reduced-motion: no-preference) {
|
@media (prefers-reduced-motion: no-preference) {
|
||||||
html[data-interlude='on'] .reading-stage .portfolio-main > * > * {
|
html[data-interlude='on'] .reading-stage .portfolio-main > * > * {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transition: opacity 260ms cubic-bezier(0.5, 0, 0.75, 0);
|
transition: opacity 200ms cubic-bezier(0.5, 0, 0.75, 0) 160ms;
|
||||||
}
|
}
|
||||||
html[data-interlude='on'] .reading-stage .portfolio-main > * > :not(h1, h2, :has(h1, h2)) {
|
html[data-interlude='on'] .reading-stage .portfolio-main > * > :not(h1, h2, :has(h1, h2)) {
|
||||||
transform: translateY(-24px);
|
transform: translateY(-24px);
|
||||||
transition:
|
transition:
|
||||||
opacity 260ms cubic-bezier(0.5, 0, 0.75, 0),
|
opacity 180ms cubic-bezier(0.5, 0, 0.75, 0),
|
||||||
transform 260ms cubic-bezier(0.5, 0, 0.75, 0);
|
transform 180ms cubic-bezier(0.5, 0, 0.75, 0);
|
||||||
}
|
}
|
||||||
/* The exit tag's strike-on animation restarts as the plates return. */
|
/* The exit tag's strike-on animation restarts as the plates return. */
|
||||||
html[data-interlude='on'] .reading-stage .portfolio-section::before,
|
html[data-interlude='on'] .reading-stage .portfolio-section::before,
|
||||||
html[data-interlude='on'] .reading-stage .portfolio-section[data-exit='08']::after {
|
html[data-interlude='on'] .reading-stage .portfolio-section[data-exit='08']::after {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
animation: none;
|
animation: none;
|
||||||
transition: opacity 260ms cubic-bezier(0.5, 0, 0.75, 0);
|
transition: opacity 180ms cubic-bezier(0.5, 0, 0.75, 0);
|
||||||
}
|
}
|
||||||
html[data-interlude='rise'] .reading-stage .portfolio-section[data-exit='08']::after,
|
html[data-interlude='rise'] .reading-stage .portfolio-section[data-exit='08']::after,
|
||||||
html[data-interlude='rise'] .reading-stage .portfolio-main > .portfolio-section > *,
|
html[data-interlude='rise'] .reading-stage .portfolio-main > .portfolio-section > *,
|
||||||
html[data-interlude='rise'] .reading-stage .portfolio-main > .hero-journey > * {
|
html[data-interlude='rise'] .reading-stage .portfolio-main > .hero-journey > * {
|
||||||
animation: plate-fade 720ms cubic-bezier(0.22, 1, 0.36, 1) both;
|
animation: plate-fade 400ms cubic-bezier(0.22, 1, 0.36, 1) both;
|
||||||
}
|
}
|
||||||
html[data-interlude='rise'] .reading-stage .portfolio-main > .portfolio-section > :not(h1, h2, :has(h1, h2)),
|
html[data-interlude='rise'] .reading-stage .portfolio-main > .portfolio-section > :not(h1, h2, :has(h1, h2)),
|
||||||
html[data-interlude='rise'] .reading-stage .portfolio-main > .hero-journey > :not(h1, h2, :has(h1, h2)) {
|
html[data-interlude='rise'] .reading-stage .portfolio-main > .hero-journey > :not(h1, h2, :has(h1, h2)) {
|
||||||
animation: plate-rise 720ms cubic-bezier(0.22, 1, 0.36, 1) both;
|
animation: plate-rise 400ms cubic-bezier(0.22, 1, 0.36, 1) both;
|
||||||
}
|
}
|
||||||
/* The chapter body keeps its light-edge sweep alongside the rise. */
|
/* The chapter body keeps its light-edge sweep alongside the rise. */
|
||||||
html[data-interlude='rise'] .reading-stage .portfolio-main > .portfolio-section[data-current] > .chapter-body {
|
html[data-interlude='rise'] .reading-stage .portfolio-main > .portfolio-section[data-current] > .chapter-body {
|
||||||
animation:
|
animation:
|
||||||
plate-rise 720ms cubic-bezier(0.22, 1, 0.36, 1) both,
|
plate-rise 400ms cubic-bezier(0.22, 1, 0.36, 1) both,
|
||||||
exit-panel-light 1.6s cubic-bezier(0.2, 0.75, 0.2, 1) both;
|
exit-panel-light 1.6s cubic-bezier(0.2, 0.75, 0.2, 1) both;
|
||||||
}
|
}
|
||||||
html[data-interlude='rise'] .reading-stage .portfolio-main > * > :nth-child(2) { animation-delay: 90ms; }
|
html[data-interlude='rise'] .reading-stage .portfolio-main > * > :nth-child(2) { animation-delay: 40ms; }
|
||||||
html[data-interlude='rise'] .reading-stage .portfolio-main > * > :nth-child(3) { animation-delay: 180ms; }
|
html[data-interlude='rise'] .reading-stage .portfolio-main > * > :nth-child(3) { animation-delay: 80ms; }
|
||||||
html[data-interlude='rise'] .reading-stage .portfolio-main > * > :nth-child(n + 4) { animation-delay: 270ms; }
|
html[data-interlude='rise'] .reading-stage .portfolio-main > * > :nth-child(n + 4) { animation-delay: 120ms; }
|
||||||
}
|
}
|
||||||
@keyframes plate-rise {
|
@keyframes plate-rise {
|
||||||
from { opacity: 0; transform: translateY(28px); }
|
from { opacity: 0; transform: translateY(28px); }
|
||||||
|
|||||||
@@ -164,7 +164,7 @@ describe('composed route signs', () => {
|
|||||||
const h = setup();
|
const h = setup();
|
||||||
h.render({ ...profile, phase: 'approach', progress: 0, opacity: 1 }, 30);
|
h.render({ ...profile, phase: 'approach', progress: 0, opacity: 1 }, 30);
|
||||||
const early = h.render({ ...profile, phase: 'approach', progress: 0.2, opacity: 1 })!.bounds;
|
const early = h.render({ ...profile, phase: 'approach', progress: 0.2, opacity: 1 })!.bounds;
|
||||||
const big = h.render({ ...profile, phase: 'approach', progress: 0.69, opacity: 1 })!.bounds;
|
const big = h.render({ ...profile, phase: 'approach', progress: 0.61, opacity: 1 })!.bounds;
|
||||||
const arcing = h.render({ ...profile, phase: 'approach', progress: 0.85, opacity: 1 })!.bounds;
|
const arcing = h.render({ ...profile, phase: 'approach', progress: 0.85, opacity: 1 })!.bounds;
|
||||||
const docked = h.render(profile)!.bounds;
|
const docked = h.render(profile)!.bounds;
|
||||||
expect(h.sign.dockState()).toBe('docked');
|
expect(h.sign.dockState()).toBe('docked');
|
||||||
|
|||||||
Reference in New Issue
Block a user