export interface SceneNode { id: string type?: 'video' | 'image' videoUrl: string imageUrl?: string thumbnail?: string contentSize?: { w: number; h: number } subtitleUrl?: string subtitles?: Record choices?: Choice[] hotspots?: Hotspot[] qte?: QTEDefinition nextScene?: string | Choice[] onEnter?: Effect[] loopStart?: number loopEnd?: number bgmUrl?: string bgmVolume?: number bgmCrossFade?: number bgmDuckLevel?: number bgmDuckFade?: number videoMuted?: boolean skippable?: boolean streamingUrl?: Record keyMoment?: boolean battleHUD?: BattleHUDEntry[] battleResult?: BattleResultDef } export interface Choice { text: string textKey?: string prompt?: string promptKey?: string targetScene: string conditions?: Condition[] effects?: Effect[] timeLimit?: number } export interface Hotspot { id: string label: string labelKey?: 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' // @deprecated hasFlag will be removed value: number | string | boolean } export interface Effect { type: 'set' | 'add' | 'toggleFlag' | 'triggerEvent' // @deprecated toggleFlag will be removed target: string value?: number | string | boolean } export interface QTEDefinition { triggerTime: number prompt: string promptKey?: string keys: string[] timeLimit: number successScene: string failScene: string effects?: { success: Effect[] fail: Effect[] } } export interface ChapterInfo { id: string label: string labelKey?: string startScene: string thumbnail?: string defaultVariables?: Record } export interface AchievementDef { id: string title: string titleKey?: string description: string descKey?: string icon?: string hidden?: boolean condition: Condition } export interface EndingDef { id: string label: string labelKey?: string sceneId: string chapterId?: string thumbnail?: string } export interface LocalesConfig { path: string languages: string[] } export interface GameData { scenes: Record startScene: string variables: Record assetBase?: string locales?: LocalesConfig chapters?: ChapterInfo[] achievements?: AchievementDef[] endings?: EndingDef[] introVideo?: string menuVideo?: string } 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' | 'achievementUnlock' | 'battleResultRequest' export interface PlayerTreeNode { sceneId: string label: string visited: boolean locked: boolean lockHint?: string children: PlayerTreeNode[] isGateway?: boolean gatewayChapterId?: string } export interface BattleHUDStat { variable: string label: string labelKey?: string max?: number style?: 'bar' | 'number' } export interface BattleHUDEntry { label: string labelKey?: string portrait?: string stats: BattleHUDStat[] } export interface BattleResultStat { label: string labelKey?: string variable: string max?: number } export interface BattleResultDef { title: string titleKey?: string stats: BattleResultStat[] }