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 };
|
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 => ({
|
const browserRuntime = (): NavigationRuntime => ({
|
||||||
getHash: () => window.location.hash,
|
getHash: () => window.location.hash,
|
||||||
pushHash: (hash) => window.history.pushState(window.history.state, "", hash),
|
pushHash: (hash) => window.history.pushState(window.history.state, "", hash),
|
||||||
@@ -107,10 +136,10 @@ const browserRuntime = (): NavigationRuntime => ({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const margin = parseFloat(getComputedStyle(target).scrollMarginTop) || 0;
|
const margin = parseFloat(getComputedStyle(target).scrollMarginTop) || 0;
|
||||||
window.scrollTo({
|
const delta = target.getBoundingClientRect().top - margin;
|
||||||
top: window.scrollY + target.getBoundingClientRect().top - margin,
|
if (behavior === "smooth" && Math.abs(delta) > window.innerHeight * 0.6)
|
||||||
behavior,
|
preArmInterlude();
|
||||||
});
|
window.scrollTo({ top: window.scrollY + delta, behavior });
|
||||||
},
|
},
|
||||||
focusHeading: (target) => {
|
focusHeading: (target) => {
|
||||||
// The live reading stage can start or stop while a long journey is still
|
// The live reading stage can start or stop while a long journey is still
|
||||||
|
|||||||
@@ -590,6 +590,8 @@ export async function createProceduralSceneGeneration(
|
|||||||
interludeOn = interlude;
|
interludeOn = interlude;
|
||||||
riseUntil = interlude ? 0 : now + INTERLUDE_RISE_MS;
|
riseUntil = interlude ? 0 : now + INTERLUDE_RISE_MS;
|
||||||
document.documentElement.dataset.interlude = interlude ? 'on' : 'rise';
|
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) {
|
} else if (riseUntil > 0 && now > riseUntil) {
|
||||||
riseUntil = 0;
|
riseUntil = 0;
|
||||||
delete document.documentElement.dataset.interlude;
|
delete document.documentElement.dataset.interlude;
|
||||||
@@ -630,6 +632,7 @@ export async function createProceduralSceneGeneration(
|
|||||||
disposed = true;
|
disposed = true;
|
||||||
delete document.documentElement.dataset.gantry;
|
delete document.documentElement.dataset.gantry;
|
||||||
delete document.documentElement.dataset.interlude;
|
delete document.documentElement.dataset.interlude;
|
||||||
|
delete document.documentElement.dataset.interludeArmed;
|
||||||
// Quality changes reuse the canvas context. Leave texture upload flags at
|
// Quality changes reuse the canvas context. Leave texture upload flags at
|
||||||
// defaults before the next renderer creates its empty array textures.
|
// defaults before the next renderer creates its empty array textures.
|
||||||
const gl = renderer.getContext();
|
const gl = renderer.getContext();
|
||||||
|
|||||||
Reference in New Issue
Block a user