fix: step the reading plates aside at click time on long navigator jumps
This commit is contained in:
@@ -94,6 +94,35 @@ export function validateSectionAnchor(
|
||||
return heading === null ? null : { id, target };
|
||||
}
|
||||
|
||||
/** How long a pre-armed interlude waits for the scene loop to take over. */
|
||||
const PRE_ARM_TIMEOUT_MS = 1400;
|
||||
/** Matches INTERLUDE_RISE_MS in the environment loop. */
|
||||
const PRE_ARM_RISE_MS = 1100;
|
||||
|
||||
/**
|
||||
* A long navigator scroll passes the chapters in between. While the scene runs
|
||||
* (the loop has set data-gantry), the reading plates step aside at click time
|
||||
* instead of when the sign starts its approach, so those chapters do not flash
|
||||
* past. The loop takes the attribute over as soon as the sign's interlude
|
||||
* starts; if no interlude follows, the plates rise again after a timeout.
|
||||
*/
|
||||
const preArmInterlude = (): void => {
|
||||
const root = document.documentElement;
|
||||
if (root.dataset.gantry === undefined || root.dataset.interlude === "on") return;
|
||||
root.dataset.interlude = "on";
|
||||
root.dataset.interludeArmed = "nav";
|
||||
window.setTimeout(() => {
|
||||
if (root.dataset.interludeArmed !== "nav") return;
|
||||
root.dataset.interlude = "rise";
|
||||
root.dataset.interludeArmed = "rise";
|
||||
window.setTimeout(() => {
|
||||
if (root.dataset.interludeArmed !== "rise") return;
|
||||
delete root.dataset.interlude;
|
||||
delete root.dataset.interludeArmed;
|
||||
}, PRE_ARM_RISE_MS);
|
||||
}, PRE_ARM_TIMEOUT_MS);
|
||||
};
|
||||
|
||||
const browserRuntime = (): NavigationRuntime => ({
|
||||
getHash: () => window.location.hash,
|
||||
pushHash: (hash) => window.history.pushState(window.history.state, "", hash),
|
||||
@@ -107,10 +136,10 @@ const browserRuntime = (): NavigationRuntime => ({
|
||||
return;
|
||||
}
|
||||
const margin = parseFloat(getComputedStyle(target).scrollMarginTop) || 0;
|
||||
window.scrollTo({
|
||||
top: window.scrollY + target.getBoundingClientRect().top - margin,
|
||||
behavior,
|
||||
});
|
||||
const delta = target.getBoundingClientRect().top - margin;
|
||||
if (behavior === "smooth" && Math.abs(delta) > window.innerHeight * 0.6)
|
||||
preArmInterlude();
|
||||
window.scrollTo({ top: window.scrollY + delta, behavior });
|
||||
},
|
||||
focusHeading: (target) => {
|
||||
// The live reading stage can start or stop while a long journey is still
|
||||
|
||||
@@ -590,6 +590,8 @@ export async function createProceduralSceneGeneration(
|
||||
interludeOn = interlude;
|
||||
riseUntil = interlude ? 0 : now + INTERLUDE_RISE_MS;
|
||||
document.documentElement.dataset.interlude = interlude ? 'on' : 'rise';
|
||||
// A navigator click may have pre-armed the interlude; the loop owns it now.
|
||||
delete document.documentElement.dataset.interludeArmed;
|
||||
} else if (riseUntil > 0 && now > riseUntil) {
|
||||
riseUntil = 0;
|
||||
delete document.documentElement.dataset.interlude;
|
||||
@@ -630,6 +632,7 @@ export async function createProceduralSceneGeneration(
|
||||
disposed = true;
|
||||
delete document.documentElement.dataset.gantry;
|
||||
delete document.documentElement.dataset.interlude;
|
||||
delete document.documentElement.dataset.interludeArmed;
|
||||
// Quality changes reuse the canvas context. Leave texture upload flags at
|
||||
// defaults before the next renderer creates its empty array textures.
|
||||
const gl = renderer.getContext();
|
||||
|
||||
Reference in New Issue
Block a user