- 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
42 lines
862 B
Vue
42 lines
862 B
Vue
<script setup lang="ts">
|
|
import { ref, onMounted } from 'vue'
|
|
|
|
const emit = defineEmits<{
|
|
videoReady: [elA: HTMLVideoElement, elB: HTMLVideoElement]
|
|
}>()
|
|
|
|
const videoARef = ref<HTMLVideoElement | null>(null)
|
|
const videoBRef = ref<HTMLVideoElement | null>(null)
|
|
|
|
onMounted(() => {
|
|
if (videoARef.value && videoBRef.value) {
|
|
emit('videoReady', videoARef.value, videoBRef.value)
|
|
}
|
|
})
|
|
|
|
defineExpose({ videoARef, videoBRef })
|
|
</script>
|
|
|
|
<template>
|
|
<div class="game-player">
|
|
<video ref="videoARef" class="player-video" preload="auto"></video>
|
|
<video ref="videoBRef" class="player-video" preload="auto"></video>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.game-player {
|
|
position: relative;
|
|
width: 100%;
|
|
height: 100%;
|
|
background: #000;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.player-video {
|
|
max-width: 100%;
|
|
max-height: 100%;
|
|
will-change: opacity;
|
|
}
|
|
</style>
|