Fix WebGL timeline startup ordering

This commit is contained in:
2026-06-10 10:04:06 +02:00
parent ce8147b5b1
commit 623b42caf9
4 changed files with 79 additions and 6 deletions
+46 -5
View File
@@ -8,12 +8,11 @@ import { BaseModule } from './base-module.js';
class BookPlaybackTimelineModule extends BaseModule {
constructor() {
super('book-playback-timeline', 'Book Playback Timeline');
this.dependencies = ['book-pagination', 'book-texture-renderer', 'webgl-page-cache', 'playback-coordinator', 'sentence-queue'];
this.dependencies = ['book-pagination', 'book-texture-renderer', 'webgl-page-cache', 'playback-coordinator'];
this.pagination = null;
this.textureRenderer = null;
this.pageCache = null;
this.playbackCoordinator = null;
this.sentenceQueue = null;
this.activeSegment = null;
this.preparedSegments = new Map();
this.timelineDiagnostics = [];
@@ -26,6 +25,7 @@ class BookPlaybackTimelineModule extends BaseModule {
'prepareSentence',
'activatePreparedSegment',
'ensureAnimationTimings',
'calculateAnimationTiming',
'createPreparedSegment',
'createRevealDetail',
'applyTexturePlan',
@@ -55,7 +55,6 @@ class BookPlaybackTimelineModule extends BaseModule {
this.textureRenderer = this.getModule('book-texture-renderer');
this.pageCache = this.getModule('webgl-page-cache');
this.playbackCoordinator = this.getModule('playback-coordinator');
this.sentenceQueue = this.getModule('sentence-queue');
this.addEventListener(document, 'webgl-book:page-reveal-start', (event) => {
this.markBenchmark('reveal-start', {
blockId: event.detail?.blockId ?? null
@@ -210,8 +209,50 @@ class BookPlaybackTimelineModule extends BaseModule {
ensureAnimationTimings(sentence = {}) {
if (Array.isArray(sentence.animation?.wordTimings) && sentence.animation.wordTimings.length > 0) return;
const words = String(sentence.layoutText || sentence.text || '').match(/\S+/g) || [];
sentence.animation = this.sentenceQueue?.calculateAnimationTiming?.(words, sentence.tts?.duration || 0, sentence.cueMarkers || [])
|| { wordTimings: [], cueTimings: [], totalDuration: 0 };
sentence.animation = this.calculateAnimationTiming(words, sentence.tts?.duration || 0, sentence.cueMarkers || []);
}
calculateAnimationTiming(words = [], totalDuration = 0, cueMarkers = []) {
if (!Array.isArray(words) || words.length === 0) {
return {
wordTimings: [],
cueTimings: [],
totalDuration: 0
};
}
const totalChars = words.reduce((sum, word) => sum + String(word || '').length, 0);
if (totalChars === 0) {
return {
wordTimings: words.map(word => ({ word, delay: 0, duration: 0 })),
cueTimings: [],
totalDuration: 0
};
}
const msPerChar = Number(totalDuration || 0) / totalChars;
let currentDelay = 0;
const wordTimings = words.map(word => {
const duration = String(word || '').length * msPerChar;
const timing = {
word,
delay: currentDelay,
duration
};
currentDelay += duration;
return timing;
});
const cueTimings = (cueMarkers || []).map(cue => {
const wordIndex = Math.max(0, Math.min(cue.wordIndex || 0, wordTimings.length - 1));
const timing = wordTimings[wordIndex] || { delay: currentDelay };
return {
...cue,
delay: timing.delay
};
});
return {
wordTimings,
cueTimings,
totalDuration: Math.round(currentDelay)
};
}
createRevealDetail(sentence = {}, spread = null, phase = 'activate') {