#321 · The first frame of a zoom animation moves the view
- timeline-app
- pull request
Closes #319. **What profiling found.** I profiled keyboard zoom (`bench/ui.mjs` keyboard-zoom: 1,000 moments, a 4× slowed CPU, `+` on the focused stage) with CDP CPU profiles and per-tick logging. The zoom animation (`animateView`, 220 ms, cubic ease) took its progress from the frame timestamp `now`. Input is handled at the start of a frame, after that frame's timestamp, so on a busy page the first tick often saw `now − started ≤ 0` (−4 ms and −16 ms in two of three throttled runs): progress 0. It redrew the **unchanged** view at full cost. With the CPU slowed, the next frame then arrived after the whole 220 ms animation and jumped to the end. So keyboard zoom paid two full renders before anything moved, while wheel zoom, which doesn't animate, pays one. That fits CI's 246–262 ms for keyboard zoom against about 150 ms for wheel zoom. **The fix** (`src/app.ts`, one line): the first frame advances at least one frame interval (`max(now − started, 1000/60)`), so it already shows about a fifth of the zoom. Every caller of `animateView` benefits: the zoom keys and buttons, Fit all, Fit in view and following the latest moments. Nothing else changes visibly; it removes a dead frame. **CI with the fix** (the UI capacity job on this branch, 4× CPU, 1,000 moments): | Run | keyboard-zoom | wheel-zoom | | --- | --- | --- | | Before (five failing runs, main and PRs) | 246–262 ms | 143–164 ms | | This branch, PR run | 157 ms | 94 ms | | This branch, push run | 105 ms | 115 ms | Both are within the usual gate (1.5 × 150 = 225 ms), so the second commit removes keyboard zoom's `gateTolerance: 2` from #320. The `gateTolerance` option stays for future exceptions. `docs/benchmarks.md` records the finding. **Test:** `test/zoom-help-browser.mjs` shifts frame timestamps 50 ms back, forcing the case, presses `+` and `−` five times, and requires the first painted frame after each key to show a new view. - **Without the fix:** fails 3 of 3 runs in Chromium and Firefox, and 1 of 3 in WebKit. - **With it:** passes 3 of 3 in Chromium, Firefox, WebKit and Chromium at 4×. - **Suites:** the full `test/browser.mjs` passes in Firefox, and `npm test` passes 325 of 325.
Sources
Open #321 · The first frame of a zoom animation moves the view in the timeline