Repository navigation
Conversation
The desk stayed hidden until document.fonts.ready, so on a slow connection the home seal (the page's largest image) had already loaded and then waited about 1.7 s to paint. Items are re-measured by the ResizeObserver as fonts swap in, and the intro's final framing is computed when it is used.
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars.
|
|
Reviewed the diff ( |
Without the fonts.ready wait, the instant (and reduced-motion) opening fit was computed from fallback-font sizes and never revisited. If the visitor hasn't moved yet, the desk is framed again from the real sizes. Raised in Claude review on #7.
| // Once the fonts have swapped in, frame the desk again from the real sizes, unless the visitor | ||
| // has already moved, a site is open, or the intro is still about to compute it anyway. | ||
| document.fonts.ready.then(() => { | ||
| if (!html.classList.contains("desk") || !untouched || introTimer || liveFrom) return; |
There was a problem hiding this comment.
introTimer is never reset when the timeout fires (line 567 only assigns it; only cancelIntro zeroes it). Once the 650 ms pull-back has run, introTimer stays truthy, so || introTimer here returns early for good. If the fonts arrive after 650 ms (slow network, the case this PR is for), the re-frame is skipped. The intro already computed overview() from the pre-font sizes, so the desk stays mis-framed.
Reset it inside the timeout callback:
introTimer = window.setTimeout(() => { introTimer = 0; go(overview(), { stiffness: 2.2 }); }, 650);untouched already covers input. Also, halt() calls cancelIntro(), so a desk→list→desk toggle sets untouched = false without any camera input. That is harmless, but the flag then means "halted or touched", not "untouched".
A fired timer stayed truthy, so the post-font re-frame was skipped whenever the fonts arrived after the intro, which is the slow-network case it exists for. Raised in Claude review on #7.
| // has already moved, a site is open, or the intro is still about to compute it anyway. | ||
| document.fonts.ready.then(() => { | ||
| if (!html.classList.contains("desk") || !untouched || introTimer || liveFrom) return; | ||
| go(openingView(), { stiffness: 2.2 }); |
There was a problem hiding this comment.
openingView() reads boxes, vw and vh, which are only refreshed by measure() or by the ResizeObserver (~line 604). document.fonts.ready resolves as a microtask when the font load finishes, which is before the next rendering step. ResizeObserver callbacks are delivered in that rendering step, after layout. So this handler can run while boxes still holds the pre-swap sizes. It would then re-frame from the same stale data and the fix would do nothing, depending on timing.
Suggested fix: re-measure here before framing, so it doesn't depend on observer ordering:
document.fonts.ready.then(() => {
if (!html.classList.contains("desk") || !untouched || introTimer || liveFrom) return;
measure();
go(openingView(), { stiffness: 2.2 });
});(measure() rebuilds the whole boxes map from offsetWidth/offsetHeight, which forces a synchronous layout and so picks up the swapped fonts.) The same applies to the intro timer callback at ~line 567: it runs 650ms after setMode, so it is probably fine there. Still, if you want the framing correct, measure() before overview() is cheap.
Minor: with the intro running, a font swap that lands after the timer has fired (introTimer === 0, untouched still true) re-targets the pull-back mid-flight. That is harmless, but it is a second animated move the visitor did not ask for. It is instant under reduced motion, because go honours it.
There was a problem hiding this comment.
Fixed in 9fcc82c: measure() and the minimap run before the re-frame.
The ResizeObserver might not have run yet when fonts.ready resolves. Raised in Claude review on #7.
Without the fonts.ready wait, the instant (and reduced-motion) opening fit was computed from fallback-font sizes and never revisited. If the visitor hasn't moved yet, the desk is framed again from the real sizes. Raised in Claude review on #7.
A fired timer stayed truthy, so the post-font re-frame was skipped whenever the fonts arrived after the intro, which is the slow-network case it exists for. Raised in Claude review on #7.
The ResizeObserver might not have run yet when fonts.ready resolves. Raised in Claude review on #7.
Production Lighthouse (mobile) put LCP at 4.5 s, and 1.7 s of that was element render delay: the home seal had loaded but the desk stayed hidden until
document.fonts.ready. The desk now shows as soon as the script runs. The ResizeObserver from #5 re-measures items as the fonts swap in, and the intro's final framing is computed when it is used instead of up front.Locally, with applied (devtools) throttling, mobile scores 98 with LCP 2.2 s. Local fonts arrive almost at once, so the gain shows on the network rather than here. e2e: 43 passed.