feat: P2 - QTE system, subtitles, save thumbnails
- QTESystem: trigger detection via timeupdate, multi-key matching, timeout handling - QTEOverlay: SVG countdown ring + key prompts + success/fail animation - Engine: integrate QTE (timeupdate check, conditional branching, effect application) - Subtitles: WebVTT parsing + synchronized subtitle rendering - GamePlayer: overlay QTE and subtitle components - SaveSystem: DB v2 with thumbnail field, canvas snapshot at 320x180 JPEG - SaveLoadMenu: thumbnail preview for save slots - VideoManager: getActiveVideoElement() for canvas capture - App.vue: QTE/subtitle integration, thumbnail capture on save - stores: QTE state management, save list with thumbnails - demo.json: QTE scene (right_door), subtitles, new event types - ROADMAP: mark P2 as completed
This commit is contained in:
@@ -9,6 +9,7 @@ interface SaveRecord {
|
||||
variables: string
|
||||
flags: string
|
||||
history: string
|
||||
thumbnail?: string
|
||||
}
|
||||
|
||||
class SaveDB extends Dexie {
|
||||
@@ -16,7 +17,7 @@ class SaveDB extends Dexie {
|
||||
|
||||
constructor() {
|
||||
super('MovieGameSaves')
|
||||
this.version(1).stores({
|
||||
this.version(2).stores({
|
||||
saves: '++id, slot',
|
||||
})
|
||||
}
|
||||
@@ -25,14 +26,15 @@ class SaveDB extends Dexie {
|
||||
const db = new SaveDB()
|
||||
|
||||
export class SaveSystem {
|
||||
async save(slot: number, data: Omit<SaveData, 'slot' | 'thumbnail'>): Promise<void> {
|
||||
async save(slot: number, data: Omit<SaveData, 'slot'>): Promise<void> {
|
||||
const record: SaveRecord = {
|
||||
slot,
|
||||
timestamp: Date.now(),
|
||||
timestamp: data.timestamp || Date.now(),
|
||||
currentScene: data.currentScene,
|
||||
variables: JSON.stringify(data.variables),
|
||||
flags: JSON.stringify(data.flags),
|
||||
history: JSON.stringify(data.history),
|
||||
thumbnail: data.thumbnail,
|
||||
}
|
||||
|
||||
const existing = await db.saves.where('slot').equals(slot).first()
|
||||
@@ -54,15 +56,17 @@ export class SaveSystem {
|
||||
variables: JSON.parse(record.variables),
|
||||
flags: JSON.parse(record.flags),
|
||||
history: JSON.parse(record.history),
|
||||
thumbnail: record.thumbnail,
|
||||
}
|
||||
}
|
||||
|
||||
async listSlots(): Promise<{ slot: number; timestamp: number; sceneLabel: string }[]> {
|
||||
async listSlots(): Promise<{ slot: number; timestamp: number; sceneLabel: string; thumbnail?: string }[]> {
|
||||
const records = await db.saves.orderBy('slot').toArray()
|
||||
return records.map((r) => ({
|
||||
slot: r.slot,
|
||||
timestamp: r.timestamp,
|
||||
sceneLabel: r.currentScene,
|
||||
thumbnail: r.thumbnail,
|
||||
}))
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user