v0.3.0
tagged this
17 May 19:44
Opt-in viewer mode tuned for long-scroll reading content (manhwa,
manga, comics, document viewers) where the user pans continuously
and rarely zooms. By default OSD repaints the canvas via
ctx.drawImage(tile) every pan frame — fine on desktop, painfully
slow on iOS Safari even on recent hardware. The new
`:pan_optimized` attr swaps that per-frame redraw for a GPU-
composited `transform: translate3d` glide during the gesture,
dropping per-frame cost from ~10-20ms to <1ms.
Mechanism (JS hook):
- On pan-start, the hook saves OSD's drawer.draw, replaces it with
a no-op, and emits `fast-pan {phase:"start"}` through the
existing handle.on subscriber list (via a new `handle._emit`
internal method).
- Per pan tick, computes the screen-pixel delta of the original
viewport center using `viewport.pixelFromPoint(startCenter,true)`
and applies `transform: translate3d(dx, dy, 0)` to the canvas.
Emits `fast-pan {phase:"delta", x:dx, y:dy}`.
- On animation-finish (or zoom-change / overscan bail), restores
drawer.draw, clears the canvas transform, triggers one immediate
repaint at the committed position, and emits
`fast-pan {phase:"end"}`.
The fast path bails to OSD's normal redraw on zoom mid-pan, when
cumulative delta crosses 50% of viewport height (overscan), or
when `:rotate` is active (rotation invalidates simple translate
math).
A new `fast-pan` event in the handle.on channel lets overlay
extensions transform in lockstep. Etcher >= 0.2.8 listens
automatically — its SVG overlay wrapper picks up the same
translate3d so annotations stay anchored. Older Etcher paired
with :pan_optimized would see annotations drift visibly during
the pan window (documented in the new README section + CHANGELOG
notes).
Bumped to minor because the release adds a new public attr and
a new synthetic event channel that creates a coordination
contract with overlay libraries. No breaking changes; default off
for `:pan_optimized` means existing viewers see no behavior change.
- `lib/fresco/viewer.ex`: new `:pan_optimized` attr (defaults
false), plumbed to `data-pan-optimized` on the host.
- `priv/static/fresco.js`: new `installFastPan` module + new
`handle._emit` internal method; module header updated with the
fast-pan event description.
- `test/fresco_test.exs`: 2 new render-assertion tests (default
off, opt-in true).
- `README.md`: new "Optimized pan for long-scroll content" section
with the consumer API and the overlay-coordination contract.
- `CHANGELOG.md`: 0.3.0 entry.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>