diff --git a/src/journey/navigation-controller.ts b/src/journey/navigation-controller.ts index b4b94e7..462dd2f 100644 --- a/src/journey/navigation-controller.ts +++ b/src/journey/navigation-controller.ts @@ -113,6 +113,13 @@ const browserRuntime = (): NavigationRuntime => ({ }); }, focusHeading: (target) => { + // The live reading stage can start or stop while a long journey is still + // in flight (the scene boots lazily and steps down on slow GPUs), which + // shifts layout under the scroll. Re-land once, instantly, before focus. + const margin = parseFloat(getComputedStyle(target).scrollMarginTop) || 0; + const delta = target.getBoundingClientRect().top - margin; + if (Math.abs(delta) > 2) + window.scrollTo({ top: window.scrollY + delta, behavior: "instant" }); target .querySelector('h1[tabindex="-1"], h2[tabindex="-1"]') ?.focus({ preventScroll: true });