Previously goToScene added a new checkQTE closure to onTimeUpdate on
every scene transition, accumulating stale closures that re-triggered
old QTE. Now checkQTE is an arrow property registered once in the
constructor, reading this.currentScene directly — no closure, no stale
references, no guard condition needed.
Since onTimeUpdate callbacks are now additive (Set), goToScene closures
for old scenes persist. Add currentScene?.id !== scene.id check to
prevent QTE from re-triggering for past scenes after scene transitions.
- VideoManager: A/B dual-buffered video with crossfade transitions and candidate preloading
- Engine: condition-based choice filtering, ChoiceSystem timer, resumeScene for save/load
- SceneManager: getCandidateUrls for preloading next scenes
- SaveSystem: Dexie.js IndexedDB multi-slot save/load
- ChoiceSystem: timed choices with countdown and auto-default on timeout
- GamePlayer: dual video elements with crossfade CSS
- ChoicePanel: timer progress bar and countdown text
- SaveLoadMenu: save/load UI component
- App.vue: menu trigger, dual video refs, save/load integration
- gameStore: timer state, saves list
- demo.json: conditional choice example (secret ending, requires trust >= 80)
- ROADMAP: mark P1 as completed
- Reorder onEnd callback before play() in Engine.goToScene to prevent
missed ended event if video ends synchronously
- Wait for loadedmetadata event in VideoManager.play() before seeking
to ensure currentTime reset works correctly on new video sources