Spanning playback: one background-prepared path, no fallbacks
For a block that overflows onto the next spread, the plan is now prepared spanning-aware during the background lookahead — the start spread's reveal timing is derived across both preview spreads, and the continuation spread's plan is prepared and cached at the same time. playback then follows a single path: - activate reuses the prepared start plan (removed the synchronous forceRebuild rebuild). - revealContinuationSpread reuses the prepared continuation plan (removed the redraw fallback); a missing plan is surfaced as a problem, not silently redrawn. This removes the parallel/immediate prepare distinction and the two fallbacks, leaving one intended path, and moves the spanning draw work off the critical path. Verified live on a real spanning block: right line reveals at its area share (~3.3s), the flip fires, and the continuation appears ~0.3s after the flip (was ~2.7s) and animates progressively across the next spread over the full TTS — no pop-in, no fast-forward, no timeline-reveal-continuation-missing. Static suite passes (165). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -893,10 +893,9 @@ class BookTextureRendererModule extends BaseModule {
|
||||
wordTimingCount: wordTimings.length,
|
||||
phase
|
||||
});
|
||||
// forceRebuild: the cached plan was built before the block's continuation was
|
||||
// committed (it would be right-only). Discard it and redraw from current spreads.
|
||||
if (options.forceRebuild === true) this.pageCache?.takePreparedRevealPlan?.(id);
|
||||
if (phase === 'activate' && options.forceRebuild !== true && this.pageCache?.hasPreparedRevealPlan?.(id)) {
|
||||
// At activate, reuse the plan prepared during lookahead (it is spanning-aware when the
|
||||
// block overflows). Building only happens when no plan was prepared yet.
|
||||
if (phase === 'activate' && this.pageCache?.hasPreparedRevealPlan?.(id)) {
|
||||
const cached = this.pageCache.takePreparedRevealPlan(id);
|
||||
this.activeAnimations.set(id, this.createAnimationState(blockId, wordTimings, detail));
|
||||
this.publishPreparedReveal(cached, options);
|
||||
@@ -918,8 +917,7 @@ class BookTextureRendererModule extends BaseModule {
|
||||
const sides = ['left', 'right'];
|
||||
// When the caller supplies the (not-yet-committed) preview spreads for a spanning
|
||||
// block, derive this spread's reveal timing across all of them so the cached plan
|
||||
// already spans both pages. activate can then reuse it instead of forcing a
|
||||
// synchronous rebuild on the critical path.
|
||||
// already spans both pages, letting activate reuse it directly.
|
||||
const spanningPreview = Array.isArray(detail.previewSpreads) && detail.previewSpreads.length > 1;
|
||||
const previousOverride = this.revealSpreadSourceOverride;
|
||||
if (spanningPreview) this.revealSpreadSourceOverride = detail.previewSpreads;
|
||||
@@ -938,8 +936,7 @@ class BookTextureRendererModule extends BaseModule {
|
||||
...published,
|
||||
blockId,
|
||||
wordTimings,
|
||||
totalDuration: detail.totalDuration || 0,
|
||||
spanningTimingPrepared: spanningPreview === true
|
||||
totalDuration: detail.totalDuration || 0
|
||||
});
|
||||
}
|
||||
this.markPipelineTiming('prepareRevealBlock:end', {
|
||||
|
||||
Reference in New Issue
Block a user