0.10.3: preloader + multi-scene export parity, jumpToScene rewinds

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
thandClaude Opus 4.7 committed 2026-04-22 17:43:44 +02:00
1 parent 87de1344c4
commit fcb8edbb88
6 files changed
+461 -102

No files matched your search

+60 -5
View File
@@ -1018,6 +1018,48 @@ export function registerAllTests(): void {
expect(r).toContain('ctx.scale(isx2,isy2)')
})
test('runtime embeds a preloader (spinner + Promise.all) before starting the frame loop', () => {
// Loading big images, video metadata and audio `canplaythrough`
// must settle before the rAF kicks off — otherwise the first few
// frames stutter while the browser decodes. Structural pins:
// - A spinner <style> is injected.
// - A preloader overlay is appended.
// - Image/audio/video promises are awaited together.
// - canplaythrough is the event we wait on for audio.
const r = generateRuntimeScript()
expect(r).toContain('ruwio-spinner-style')
expect(r).toContain('ruwio-preloader')
expect(r).toContain('Promise.all')
expect(r).toContain('canplaythrough')
expect(r).toContain('preloadAudioClips')
expect(r).toContain('preloadBgVideos')
})
test('runtime honours separated position / rotation keyframes', () => {
// Parity regression: the editor samples separated position and
// rotation tracks via `sampleLayer()` when `layer.separated`;
// the runtime used to only look at the main keyframes array.
// Animations set up with Separate-toggled layers played flat
// in exports. Pin the helper and the per-branch merge.
const r = generateRuntimeScript()
expect(r).toContain('sampleKeyframeSet')
expect(r).toContain('layer.separated')
expect(r).toContain('layer.positionKeyframes')
expect(r).toContain('layer.rotationKeyframes')
})
test('runtime supports multi-scene switching (jumpToScene + applySceneSwitch)', () => {
// Exported bundles now carry the whole Project and handle
// jumpToScene internally. The runtime must expose a scene-
// switch helper and NOT fall through to the "unsupported"
// warning message anymore.
const r = generateRuntimeScript()
expect(r).toContain('applySceneSwitch')
expect(r).toContain('project.scenes')
expect(r).toContain('currentSceneId')
expect(r.indexOf('does not support multi-scene')).toBe(-1)
})
test('runtime rangeOut falls back to scene.duration (not last keyframe)', () => {
// Regression: the runtime used to fall back to `effectiveEnd(scene)`
// — the time of the last keyframe — when scene.outTime was unset.
@@ -1356,6 +1398,19 @@ export function registerAllTests(): void {
expect(s.project.activeSceneId).toBe(two.id)
})
test('switchScene with resetPlayhead: true rewinds to the in-point', () => {
// Script and button jumps should restart the target scene at
// its in-point — otherwise chapter-like transitions play from
// wherever the previous scene was paused.
const s = makeFreshStore()
s.setDuration(10)
const two = s.addScene('Two')
s.setPlayhead(4.5)
expect(s.playhead).toBe(4.5)
s.switchScene(two.id, { resetPlayhead: true })
expect(s.playhead).toBe(0)
})
test('switchScene leaves playback state alone — editor navigation does not force play', () => {
// The editor treats scene-switch as a navigation gesture. The
// fullscreen preview is the one that auto-plays on switch (via
@@ -6381,11 +6436,10 @@ export function registerAllTests(): void {
await tick()
})
test('a scripted jumpToScene switches the active scene and keeps playing', async () => {
// User-facing contract: a script track fires a scene-switch in the
// middle of a running timeline — the active scene flips and the
// timeline keeps running on the new page. All pages share
// duration/fps, so the playhead stays put and continues onward.
test('a scripted jumpToScene switches the scene, keeps playing, and rewinds to the in-point', async () => {
// Chapter-transition semantics: the incoming scene starts at
// the project's in-point no matter where the outgoing scene was
// paused. Keeps playback running across the switch.
const s = makeFreshStore()
s.setDuration(10)
const aId = s.project.activeSceneId
@@ -6397,6 +6451,7 @@ export function registerAllTests(): void {
s.tick(3)
expect(s.project.activeSceneId).toBe(bId)
expect(s.playing).toBe(true)
expect(s.playhead).toBe(s.playbackIn)
await tick()
})