Rework WebGL book playback to single ownership and fix flip/reveal pipeline
Establish book-playback-timeline as the sole playback owner driving the scene through formal webgl-book:* events (not the BookLabDebug surface), with a single reveal clock in the scene render loop and webgl-page-cache as the only texture cache. Remove the legacy dual playback path and the ownsPageFlipCommit gating. Fixes: - Flip page detached/folded at the spine: restore the raw page-cap line for flip geometry (matches the prototype/pre-regression), removing normalizeFlipLineToVisiblePage which moved the pivot off the spine arc. - Flip textures: distance-based UVs (no horizontal compression), direction-aware face material (source on the camera-facing side), source meta derived from the visible spread (manual flips), prewarm shape fix. - Reveal: flash removed on the static page and the flip back surface; spanning blocks rebuild the reveal plan at activate and continue the reveal on the next spread after the fill flip. - Cache staleness is contentVersion-primary; nav clamps to spreadCount. Docs updated to describe the intended single-owner architecture. Regression checks updated to match. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+72
-22
@@ -52,40 +52,90 @@ This section records the current state after the procedural book integration wor
|
||||
- The custom book material shader includes a small local indirect/bounce-light term for book surfaces. This is not emissive; it is multiplied by material albedo so paper, leather, and head/end-band colors remain distinct while shadowed side faces stay readable.
|
||||
- Temporary screenshots and generated debug images are not product assets unless explicitly promoted.
|
||||
|
||||
## Current Page-Flow Architecture
|
||||
## Page-Flow Architecture
|
||||
|
||||
The 3D book pipeline is module-owned. No page content should be generated by ad hoc scene code.
|
||||
The 3D book is the primary display. A secondary 2D DOM view may be driven from the same content,
|
||||
but it is never the source of truth and must not own playback decisions. No page content is
|
||||
generated by ad hoc scene code.
|
||||
|
||||
- `ui-display-handler` owns the live 3D prepare -> optional page flip -> activate sequence for story text.
|
||||
- `sentence-queue` may prepare future page presentations during lookahead using the same pagination and texture renderer modules.
|
||||
- `book-pagination` owns page/spread construction, page metadata, widows/orphans/hyphenation decisions, image placement decisions, and explicit blank/title/body page records.
|
||||
- `book-texture-renderer` owns drawing final page canvases, reveal-region coordinates, reveal timing metadata, and publishing explicit `webgl-book:page-texture-records`.
|
||||
- `webgl-page-cache` owns persistent page canvases, memory canvases, prepared reveal plans, prepared GPU textures, resident VRAM textures, blank page texture, and visible texture bindings.
|
||||
- `webgl-book-lab` owns the Three.js scene, materials, geometry, pointer projection, page flip meshes, and consuming page texture records. It must not become a second page cache.
|
||||
### Single ownership
|
||||
|
||||
Problem states must be surfaced instead of hidden:
|
||||
There is exactly one playback owner: `book-playback-timeline`. It owns the complete content
|
||||
lifecycle for story text and is the only module allowed to sequence it:
|
||||
|
||||
```
|
||||
prepare (pagination + textures + prewarm)
|
||||
-> activate (make the target spread the visible spread)
|
||||
-> reveal (animate the new block's text in)
|
||||
-> flip (turn the page when a spread boundary is crossed)
|
||||
```
|
||||
|
||||
- `ui-display-handler` and `sentence-queue` are clients of the owner. They call
|
||||
`book-playback-timeline.playSentence` (live) and `prepareSentence` (lookahead). They contain no
|
||||
flip, reveal, or spread-transition logic of their own.
|
||||
- `book-pagination` owns page/spread construction, page metadata, widows/orphans/hyphenation,
|
||||
image placement, and explicit blank/title/body page records. It does not decide playback timing.
|
||||
- `book-texture-renderer` owns drawing final page canvases and computing reveal-region coordinates
|
||||
and per-region timing metadata. It is a pure renderer: it does **not** run a playback clock, does
|
||||
**not** decide when reveals start/finish, and does **not** trigger flips. Reactive redraws keyed
|
||||
off pagination events are forbidden; the owner asks it to draw.
|
||||
- `webgl-page-cache` is the single texture/canvas cache: persistent canvases, memory canvases,
|
||||
prepared reveal plans, prepared GPU textures, resident VRAM textures, the blank texture, and
|
||||
visible texture bindings. No other module may keep a parallel cache.
|
||||
- `webgl-book-scene` (implemented in `webgl-book-lab.js`) owns the Three.js scene, materials,
|
||||
geometry, pointer projection, page-flip meshes, the single reveal clock, and consuming page
|
||||
texture records. It must not become a second page cache and must not decide playback order.
|
||||
|
||||
### Single reveal clock
|
||||
|
||||
Reveal timing has exactly one authority: the scene render loop. It advances reveal progress,
|
||||
freezes it during a physical flip, and emits `webgl-book:reveal-committed` when a side's reveal
|
||||
finishes. No module runs a second `setTimeout`/`requestAnimationFrame` reveal clock in parallel.
|
||||
The texture renderer supplies region timings; it does not measure their elapsed time.
|
||||
|
||||
### Owner-to-scene command channel
|
||||
|
||||
The owner drives the scene through the registered scene command interface obtained from the module
|
||||
registry (`webgl-book-scene`), or through the formal `webgl-book:*` events listed below. The owner
|
||||
must never reach into `window.BookLabDebug` — that object is a debug/inspection surface only and is
|
||||
not part of any production control path. Production code must not throw because a debug global is
|
||||
missing.
|
||||
|
||||
### Problem states are surfaced, never hidden
|
||||
|
||||
- A missing persistent page canvas during prewarm is a `db-cache-miss`.
|
||||
- A missing source or required back texture before a page flip is a `flip-source-texture-missing` or `flip-back-texture-missing`.
|
||||
- These problem states must appear in `webglPageCacheProblems` and must not be silently fixed by borrowing unrelated visible stack textures.
|
||||
- A missing source or required back texture before a page flip is a `flip-source-texture-missing`
|
||||
or `flip-back-texture-missing`.
|
||||
- These appear in `webglPageCacheProblems` and must not be silently fixed by borrowing unrelated
|
||||
visible stack textures. Surfacing a problem must not abort live reading: a transient miss degrades
|
||||
(blank/last-good texture) and is logged, rather than throwing out of the playback path.
|
||||
|
||||
## Event Surface
|
||||
|
||||
The preferred 3D book content path is direct module calls through `ui-display-handler` for live playback and `sentence-queue` for lookahead preparation.
|
||||
The owner controls the scene through the scene command interface (preferred for direct,
|
||||
ordered calls) and through these formal events. Each event has one producer and stable meaning:
|
||||
|
||||
The following events remain formal integration events and must keep their meaning stable while they exist:
|
||||
- `webgl-book:page-texture-records` (owner/renderer -> scene): publishes explicit page texture
|
||||
records for a spread, carrying `phase` (`prepare`|`activate`) and per-side `visibility`.
|
||||
- `webgl-book:page-reveal-start` (owner -> scene): starts the scene reveal clock for a block.
|
||||
- `webgl-book:page-reveal-fast-forward` (owner -> scene): accelerates reveal timing without
|
||||
replacing the page pipeline.
|
||||
- `webgl-book:reveal-committed` (scene -> owner): a page-side reveal completed. The owner — not the
|
||||
scene — decides whether a flip follows.
|
||||
- `webgl-book:request-page-flip` (owner -> scene): requests a physical page flip.
|
||||
- `webgl-book:page-flip-started`, `webgl-book:page-flip-near-end`, `webgl-book:page-flip-finished`
|
||||
(scene -> owner): the physical flip lifecycle, each carrying the resolved `targetSpread`.
|
||||
|
||||
- `webgl-book:page-texture-records` publishes explicit page texture records from `book-texture-renderer` to the WebGL scene.
|
||||
- `webgl-book:page-reveal-start` starts shader reveal timing for the prepared block.
|
||||
- `webgl-book:page-reveal-fast-forward` accelerates reveal timing without replacing the page pipeline.
|
||||
- `webgl-book:reveal-committed` reports that a page-side reveal completed; if `pageFlipAfterReveal` is true, the WebGL scene may arm a page flip.
|
||||
- `webgl-book:request-page-flip` requests a physical page flip through the WebGL scene.
|
||||
- `webgl-book:page-flip-started`, `webgl-book:page-flip-near-end`, and `webgl-book:page-flip-finished` describe the physical flip lifecycle.
|
||||
The scene reacts to these events; it does not originate flip decisions from `reveal-committed`.
|
||||
|
||||
Deprecated or forbidden event contracts:
|
||||
Deprecated or forbidden contracts:
|
||||
|
||||
- `webgl-book:page-canvases` is obsolete. New code must use `webgl-book:page-texture-records`.
|
||||
- `preloadOnly` and `allowFutureUnrendered` are obsolete boolean flags. New code must use explicit `phase` and `visibility` values.
|
||||
- `webgl-book:page-canvases` is obsolete; use `webgl-book:page-texture-records`.
|
||||
- `preloadOnly` and `allowFutureUnrendered` boolean flags are obsolete; use explicit `phase` and
|
||||
`visibility` values.
|
||||
- The legacy `ownsPageFlipCommit` toggle and the `book-pagination:spread-updated`-driven reveal/flip
|
||||
path in `book-texture-renderer` and the scene are removed. There is no second playback path to
|
||||
gate, so no gating flag exists.
|
||||
|
||||
## Non-Negotiable Workflow Rules
|
||||
|
||||
|
||||
Reference in New Issue
Block a user