Enforce explicit WebGL book playback timeline

This commit is contained in:
2026-06-10 09:35:00 +02:00
parent 5a84923884
commit ce8147b5b1
7 changed files with 199 additions and 185 deletions
+15 -62
View File
@@ -899,39 +899,9 @@ class SentenceQueueModule extends BaseModule {
const blockId = sentence.blockId ?? sentence.metadata?.blockId ?? null;
if (blockId == null) return null;
const bookPlaybackTimeline = this.getModule('book-playback-timeline');
if (bookPlaybackTimeline && typeof bookPlaybackTimeline.prepareSentence === 'function') {
if (!options.immediate) {
await new Promise(resolve => {
const scheduler = window.requestIdleCallback || ((callback) => window.setTimeout(callback, 1));
scheduler(() => resolve(), { timeout: 80 });
});
}
if (options.queueGeneration !== undefined && options.queueGeneration !== this.queueGeneration) return null;
const segment = await bookPlaybackTimeline.prepareSentence(sentence, {
immediate: options.immediate === true
});
if (!segment) return null;
sentence.webglBookPresentation = {
prepared: true,
blockId,
spread: segment.previewSpread || segment.activeSpread || null,
timelineSegment: segment
};
return sentence.webglBookPresentation.spread;
if (!bookPlaybackTimeline || typeof bookPlaybackTimeline.prepareSentence !== 'function') {
throw new Error('SentenceQueue: 3D book presentation requires the book playback timeline');
}
const bookPagination = this.getModule('book-pagination');
const bookTextureRenderer = this.getModule('book-texture-renderer');
if (!bookPagination || !bookTextureRenderer) return null;
if (this.isWebGLBookPresentationPrepared(sentence)) {
return sentence.webglBookPresentation?.spread || null;
}
if (!Array.isArray(sentence.animation?.wordTimings) || sentence.animation.wordTimings.length === 0) {
const words = String(sentence.layoutText || sentence.text || '').match(/\S+/g) || [];
sentence.animation = this.calculateAnimationTiming(words, sentence.tts?.duration || 0, sentence.cueMarkers || []);
}
if (!options.immediate) {
await new Promise(resolve => {
const scheduler = window.requestIdleCallback || ((callback) => window.setTimeout(callback, 1));
@@ -939,42 +909,25 @@ class SentenceQueueModule extends BaseModule {
});
}
if (options.queueGeneration !== undefined && options.queueGeneration !== this.queueGeneration) return null;
const spread = typeof bookPagination.preparePendingBlock === 'function'
? await bookPagination.preparePendingBlock(sentence, {
activate: false,
publish: false,
includeUnrenderedHistory: true
})
: null;
if (!spread) return null;
if (options.queueGeneration !== undefined && options.queueGeneration !== this.queueGeneration) return null;
if (typeof bookTextureRenderer.prepareRevealBlock === 'function') {
bookTextureRenderer.prepareRevealBlock({
id: sentence.id,
blockId,
wordTimings: sentence.animation?.wordTimings || [],
cueTimings: sentence.animation?.cueTimings || [],
totalDuration: sentence.animation?.totalDuration || 0,
spread,
phase: 'prepare'
}, { phase: 'prepare' });
sentence.webglBookPresentation = {
prepared: true,
blockId,
spread
};
}
return spread;
const segment = await bookPlaybackTimeline.prepareSentence(sentence, {
immediate: options.immediate === true
});
if (!segment) return null;
sentence.webglBookPresentation = {
prepared: true,
blockId,
spread: segment.previewSpread || segment.activeSpread || null,
timelineSegment: segment
};
return sentence.webglBookPresentation.spread;
}
isWebGLBookPresentationPrepared(sentence) {
const blockId = sentence?.blockId ?? sentence?.metadata?.blockId ?? null;
if (blockId == null) return false;
if (sentence?.webglBookPresentation?.prepared === true) return true;
const bookTextureRenderer = this.getModule('book-texture-renderer');
return Boolean(bookTextureRenderer?.hasPreparedRevealBlock?.(blockId));
const bookPlaybackTimeline = this.getModule('book-playback-timeline');
return Boolean(bookPlaybackTimeline?.preparedSegments?.has?.(`${sentence.gameId || sentence.metadata?.gameId || 'game'}:${blockId}`));
}
isCurrentQueueItem(item, queueGeneration = this.queueGeneration) {