export interface SceneNode { id: string type?: 'video' | 'image' videoUrl: string imageUrl?: string subtitleUrl?: string subtitles?: Record choices?: Choice[] hotspots?: Hotspot[] qte?: QTEDefinition nextScene?: string onEnter?: Effect[] loopStart?: number loopEnd?: number bgmUrl?: string bgmVolume?: number bgmCrossFade?: number bgmDuckLevel?: number bgmDuckFade?: number videoMuted?: boolean skippable?: boolean } export interface Choice { text: string textKey?: string textEn?: string targetScene: string conditions?: Condition[] effects?: Effect[] timeLimit?: number } export interface Hotspot { id: string label: string targetScene: string x: number y: number width: number height: number showAt?: number hideAt?: number conditions?: Condition[] effects?: Effect[] timeLimit?: number } export interface Condition { variable: string op: '>' | '<' | '>=' | '<=' | '==' | '!=' | 'hasFlag' value: number | string | boolean } export interface Effect { type: 'set' | 'add' | 'toggleFlag' | 'triggerEvent' target: string value?: number | string | boolean } export interface QTEDefinition { triggerTime: number prompt: string keys: string[] timeLimit: number successScene: string failScene: string effects?: { success: Effect[] fail: Effect[] } } export interface ChapterInfo { id: string label: string startScene: string thumbnail?: string defaultVariables?: Record } export interface GameData { scenes: Record startScene: string variables: Record chapters?: ChapterInfo[] } export interface ChoiceRecord { sceneId: string choiceIndex: number choiceText: string } export interface SaveData { slot: number timestamp: number currentScene: string variables: Record flags: string[] history: ChoiceRecord[] thumbnail?: string } export type EngineEvent = | 'sceneChange' | 'choiceRequest' | 'choiceTimer' | 'gameEnd' | 'qteTrigger' | 'qteTimer' | 'qteResult' | 'videoEnd' | 'choiceTimeout' | 'hotspotRequest' | 'hotspotUpdate' | 'chapterUnlock'