Checkpoint current UI and ink integration state

This commit is contained in:
2026-05-18 02:46:02 +02:00
parent 2c54498ee2
commit d7bb175167
384 changed files with 922883 additions and 764 deletions
+50 -5
View File
@@ -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);
}
}
/**