Checkpoint current UI and ink integration state
This commit is contained in:
@@ -22,6 +22,7 @@ class PlaybackCoordinatorModule extends BaseModule {
|
||||
'animateWords',
|
||||
'waitForAudioStart',
|
||||
'completeSentenceVisual',
|
||||
'accelerateActiveWordAnimations',
|
||||
'fastForward',
|
||||
'stop'
|
||||
]);
|
||||
@@ -92,15 +93,47 @@ class PlaybackCoordinatorModule extends BaseModule {
|
||||
if (!sentence?.element) return;
|
||||
sentence.element.dataset.playbackComplete = 'true';
|
||||
sentence.element.querySelectorAll('.word').forEach(word => {
|
||||
word.onanimationend = null;
|
||||
word.style.transition = 'none';
|
||||
word.style.animation = 'none';
|
||||
word.style.visibility = 'visible';
|
||||
word.style.opacity = '1';
|
||||
word.style.transform = 'translateY(0)';
|
||||
word.style.clipPath = 'inset(0 0 0 0)';
|
||||
word.style.clipPath = 'none';
|
||||
});
|
||||
}
|
||||
|
||||
accelerateActiveWordAnimations(sentence) {
|
||||
if (!sentence?.element) return;
|
||||
sentence.element.querySelectorAll('.word').forEach(word => {
|
||||
if (typeof word.getAnimations !== 'function') return;
|
||||
word.getAnimations()
|
||||
.filter(animation => animation.playState === 'running' || animation.playState === 'pending')
|
||||
.forEach(animation => {
|
||||
try {
|
||||
if (animation.effect && typeof animation.effect.getTiming === 'function' && typeof animation.effect.updateTiming === 'function') {
|
||||
const timing = animation.effect.getTiming();
|
||||
const elapsed = Number(animation.currentTime || 0);
|
||||
const duration = Math.max(1, Number(timing.duration || 1));
|
||||
const remaining = Math.max(0, duration - elapsed);
|
||||
const targetRemaining = 24;
|
||||
if (remaining > targetRemaining) {
|
||||
const playbackRate = Math.min(80, Math.max(1, remaining / targetRemaining));
|
||||
if (typeof animation.updatePlaybackRate === 'function') {
|
||||
animation.updatePlaybackRate(playbackRate);
|
||||
} else {
|
||||
animation.playbackRate = playbackRate;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('PlaybackCoordinator: Could not accelerate active word animation', error);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Play TTS audio for a sentence
|
||||
* @param {Object} sentence - Sentence object with TTS data
|
||||
@@ -217,13 +250,19 @@ class PlaybackCoordinatorModule extends BaseModule {
|
||||
if (i < wordElements.length) {
|
||||
animQueue.schedule(() => {
|
||||
const word = wordElements[i];
|
||||
const duration = Math.max(0, timing.duration || 0);
|
||||
const duration = animQueue.isFastForwarding && animQueue.isFastForwarding()
|
||||
? Math.min(24, Math.max(8, Math.round((timing.duration || 0) * 0.035)))
|
||||
: Math.max(0, timing.duration || 0);
|
||||
word.style.transition = 'none';
|
||||
word.style.animation = 'none';
|
||||
word.style.visibility = 'visible';
|
||||
word.style.opacity = '1';
|
||||
word.style.transform = 'translateY(0)';
|
||||
word.style.clipPath = 'inset(0 100% 0 0)';
|
||||
word.onanimationend = () => {
|
||||
word.style.clipPath = 'none';
|
||||
word.onanimationend = null;
|
||||
};
|
||||
word.style.animation = `wordReveal ${duration}ms linear forwards`;
|
||||
}, timing.delay);
|
||||
}
|
||||
@@ -303,10 +342,15 @@ class PlaybackCoordinatorModule extends BaseModule {
|
||||
}
|
||||
|
||||
console.log('PlaybackCoordinator: Fast forwarding');
|
||||
this.accelerateActiveWordAnimations(this.currentSentence);
|
||||
|
||||
const animQueue = this.getModule('animation-queue');
|
||||
if (animQueue) {
|
||||
animQueue.fastForward();
|
||||
if (typeof animQueue.fastForwardSequential === 'function') {
|
||||
animQueue.fastForwardSequential(320);
|
||||
} else {
|
||||
animQueue.fastForward();
|
||||
}
|
||||
}
|
||||
|
||||
const ttsFactory = this.getModule('tts-factory');
|
||||
@@ -321,8 +365,9 @@ class PlaybackCoordinatorModule extends BaseModule {
|
||||
});
|
||||
}
|
||||
|
||||
// Complete all word animations immediately
|
||||
this.completeSentenceVisual(this.currentSentence);
|
||||
if (!animQueue || typeof animQueue.fastForwardSequential !== 'function') {
|
||||
this.completeSentenceVisual(this.currentSentence);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user