mirror of
https://github.com/nexu-io/open-design.git
synced 2026-07-09 16:35:54 +08:00
* fix(bake): classify deck-vs-scroll by viewport, real-wheel pan, motion config
Systematic audit of all 126 baked previews surfaced three capture bugs:
- 2 vertical pages misread as decks (the input probe wheel-scrolled them and the
scroll-driven animation looked like a slide change), so they got walked
sideways. Classify by viewport height instead: a fixed-viewport page is a deck,
a vertically-scrollable page is a landing page (pan it) even with a horizontal
marquee/carousel sub-component.
- 9 scroll-hijack landing pages (custom/transform scroll) that window.scrollTo
can't move, so the pan was static. Pan those with REAL wheel events
(page.mouse.wheel), which drive the page's own scroll handler.
- single-screen pages now hold (static) instead of being forced down a deck path.
Plus an opt-in override: authors can declare od.preview.motion ('scroll' | 'deck'
| 'static') and the bake honors it, auto-detecting only when it's absent. Schema
+ plugins-spec document the field. (Also strips a stray NUL byte from the hash
line that made the file read as binary.) BAKE_VERSION -> 4 re-bakes everything.
* perf(plugins-home): only decode visible gallery clips + stream first frame
Two cheap wins for the baked gallery videos:
- Decouple mount from play. The tile mounts the <video> across the wider inView
margin (so scroll-in/hover never remounts + reloads), but only PLAYS while
truly visible — off-screen tiles in the mount margin hold their poster frame
paused instead of all running a simultaneous decode. Adds a 0-margin visible
observer in PreviewSurface alongside the existing near one.
- preload=metadata instead of auto: paints the first frame off the +faststart
header instead of eagerly buffering the whole clip up front, so tiles show fast
and don't saturate the network. The idle hold buffers the pan before hover.
* perf(plugins-home): keep baked clips mounted across a scroll window
Scrolling a tile out of view and back re-showed a load even though the clip
bytes are HTTP-cached (R2 immutable): the <video> unmounted at the tight 120px
margin, so scroll-back remounted a fresh element that re-fetches metadata and
re-decodes the first frame. Add a wide keep-mounted observer (~1500/1800px) so a
clip stays mounted for a few screens — instant scroll-back — while iframes keep
the tight margin and play stays gated to the truly-visible zone (paused, not
unmounted, off screen).
* fix(bake,contracts): probe scroll mechanism before recording; validate motion
Address review:
- Move the window.scrollTo probe before Page.startScreencast so its scrollTo
160 -> 0 jump isn't baked into the head of the pan as a visible lurch.
- Type od.preview.motion in the Zod PluginManifestSchema (enum scroll|deck|
static) so an invalid value fails doctor/install instead of silently parsing
via passthrough and being ignored by the bake; add contract test coverage.
* fix(bake): auto-detect single-screen fixed pages as static, not deck
A fixed-viewport page is only a deck if an input actually advances it; probe the
driver during auto-detect and fall back to 'static' (default viewport + a hold)
when nothing moves it, instead of routing every non-scrollable page through the
deck path where walkSlides(null) just held at the deck-sized capture. Extracted
the arrow/wheel probe into probeDeckDriver(). Verified: a waitlist page now bakes
a 2.5s static hold, guizang still walks, acreage still pans.
---------
Co-authored-by: audit <a@b.c>