Prepare spanning-block continuation spread in background (kill post-flip redraw)
For a paragraph that overflows onto the next spread, the continuation page was redrawn synchronously after the flip (drawSpread on the main thread), so the next page stayed blank for ~2.7s and then the carried-over lines popped in already ~24% revealed instead of animating from the start. Move that work off the critical path: during lookahead, prepare and cache the continuation spread's reveal plan using the not-yet-committed preview spreads (so per-line timing is computed across both spreads), then reuse it after the flip instead of redrawing. - pagination: expose the preview spread layout on the returned preview spread so the owner can detect the continuation spread (race-free; each call owns its preparedSpreads). - renderer: revealSpreadSourceOverride lets region collection use preview spreads during lookahead; prepareContinuationRevealPlan draws+caches the continuation plan (publishEvent off); takeContinuationRevealPlan reuses it, re-stamped as an activate-phase publish. - timeline: prepare the continuation plan during background (non-immediate) prepares; revealContinuationSpread reuses it, falling back to the redraw when none was prepared. Verified live on a spanning block: continuation now appears ~0.25s after the flip (was ~2.7s) at ve~3471 = the right line's duration, i.e. it animates from the start (no pop-in), runs to ~full over the TTS, no fast-forward, no continuation-missing problems. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -233,17 +233,24 @@ class BookPaginationModule extends BaseModule {
|
||||
if (targetSpread) this.currentSpreadIndex = targetSpread.index;
|
||||
}
|
||||
if (options.publish !== false) this.publish({ reason: options.activate === false ? 'prepare-preload' : 'prepare-activate' });
|
||||
const resultSpread = targetSpread || (options.activate === false ? preparedSpreads[0] : this.getCurrentSpread());
|
||||
// Expose the full preview layout on the returned (preview) spread so the playback owner
|
||||
// can detect a spanning block and prepare its continuation spread in the background,
|
||||
// off the critical path. Each call returns its own preparedSpreads, so this is race-free.
|
||||
if (options.activate === false && resultSpread) {
|
||||
resultSpread.previewSpreads = preparedSpreads;
|
||||
}
|
||||
document.dispatchEvent(new CustomEvent('book-pagination:block-prepared', {
|
||||
detail: {
|
||||
blockId: pendingBlockId,
|
||||
spread: targetSpread || (options.activate === false ? preparedSpreads[0] : this.getCurrentSpread()),
|
||||
spread: resultSpread,
|
||||
spreadIndex: targetSpread?.index ?? this.currentSpreadIndex,
|
||||
latestBlockId: pendingBlockId,
|
||||
latestRenderedBlockId,
|
||||
phase: options.activate === false ? 'prepare' : 'activate'
|
||||
}
|
||||
}));
|
||||
return targetSpread || (options.activate === false ? preparedSpreads[0] : this.getCurrentSpread());
|
||||
return resultSpread;
|
||||
}
|
||||
|
||||
getPreparedBlockCacheKey(gameId, blockId, historyEndBlockId, latestRenderedBlockId, options = {}) {
|
||||
|
||||
Reference in New Issue
Block a user