# Scene JSON 完整字段参考 ## 顶层结构 ```json { "assetBase": "", "locales": { "path": "locales/", "languages": ["zh", "en"] }, "startScene": "intro", "variables": { "trust": 50, "courage": 0 }, "introVideo": "__intro__/logo.mp4", "menuVideo": "__intro__/menu_bg.mp4", "scenes": { ... }, "chapters": [ ... ], "achievements": [ ... ], "endings": [ ... ] } ``` | 字段 | 类型 | 必需 | 说明 | |------|------|------|------| | `assetBase` | string | 否 | 所有资源路径前缀,默认 `""`。设 `"demo/"` 后 `videoUrl: "intro/video.mp4"` 自动拼成 `demo/intro/video.mp4`。改 CDN 只需改这一行 | | `locales` | object | 否 | 多语言配置。`path` 为 locale 文件目录(相对于 `assetBase`),`languages` 为支持的语言列表 | | `startScene` | string | 是 | 开始场景的 ID | | `variables` | object | 否 | 全局变量初始值 | | `introVideo` | string | 否 | 开场视频路径 | | `menuVideo` | string | 否 | 主菜单背景视频路径(自动循环播放) | | `scenes` | object | 是 | 所有场景的集合,key 为场景 ID | | `chapters` | array | 否 | 章节列表 | | `achievements` | array | 否 | 成就列表 | | `endings` | array | 否 | 结局列表 | --- ## SceneNode ```typescript interface SceneNode { id: string type?: 'video' | 'image' videoUrl: string streamingUrl?: Record imageUrl?: string thumbnail?: string contentSize?: { w: number; h: number } 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 } ``` | 字段 | 类型 | 说明 | |------|------|------| | `id` | string | 场景唯一标识 | | `type` | string | `"video"` (默认) 或 `"image"`。image 类型展示图片+热点,不播放视频 | | `videoUrl` | string | 视频文件路径(本地 MP4,桌面版使用)。image 场景可为空 | | `streamingUrl` | object | Web 版使用的 CDN 流媒体路径。三档画质:`{ "超清 (1080P)": "...", "高清 (720P)": "...", "标清 (480P)": "..." }`。引擎根据 `getVideoMode()` 自动选择环境 | | `imageUrl` | string | 图片场景的图片路径 | | `thumbnail` | string | 场景缩略图路径 | | `contentSize` | object | 内容基准分辨率 `{ w: 1280, h: 720 }`,Hotspot 坐标基于此计算。用于 object-fit: contain 的偏移补偿 | | `subtitleUrl` | string | 回退字幕路径。优先使用 `subtitles` | | `subtitles` | object | 多语言字幕 `{ "zh": "...", "en": "..." }`。语言切换时自动选择 | | `choices` | Choice[] | 选项列表 | | `hotspots` | Hotspot[] | 可点击热点区域 | | `qte` | QTEDefinition | QTE 定义 | | `nextScene` | string | 无选项时的默认跳转场景 | | `onEnter` | Effect[] | 进入场景时触发的效果 | | `loopStart` | number | 循环起始时间(秒) | | `loopEnd` | number | 循环结束时间(秒)。视频播放到 loopEnd 时跳回 loopStart | | `bgmUrl` | string | 背景音乐路径 | | `bgmVolume` | number | 背景音乐音量(0-1),默认 0.8 | | `bgmCrossFade` | number | 背景音乐交叉淡化时长(秒),默认 2.0 | | `bgmDuckLevel` | number | BGM Duck 压低比例(0-1),默认 0.35 | | `bgmDuckFade` | number | BGM Duck 过渡时长(秒),默认 0.5 | | `videoMuted` | boolean | 视频静音(配合独立 BGM 使用) | | `skippable` | boolean | `false` = 禁止跳过(用于 QTE 等关键场景) | --- ## Choice ```typescript interface Choice { text: string textKey?: string prompt?: string promptKey?: string targetScene: string conditions?: Condition[] effects?: Effect[] timeLimit?: number } ``` | 字段 | 说明 | |------|------| | `text` | 选项文本(回退值) | | `textKey` | i18n key,优先于 `text`。如 `"intro.choice.left_door"` | | `prompt` | 选择后浮现的提示文字(回退值) | | `promptKey` | prompt 的 i18n key。如 `"left_door.prompt.handshake"`。优先于 `prompt` | | `promptKey` | prompt 的 i18n key。如 `"left_door.prompt.handshake"` | | `targetScene` | 目标场景 ID | | `conditions` | 显示条件,不满足的选项隐藏 | | `effects` | 选择后触发的效果 | | `timeLimit` | 限时秒数,0=不限时 | --- ## Hotspot ```typescript 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 } ``` | 字段 | 说明 | |------|------| | `id` | 热点唯一标识 | | `label` | 显示标签(回退值) | | `labelKey` | i18n key | | `x, y` | 左上角坐标(像素,基于 contentSize) | | `width, height` | 尺寸(像素) | | `showAt` | 视频时间(秒),此时间后显示。不设则始终可见 | | `hideAt` | 视频时间(秒),此时间后隐藏 | | `targetScene` | 点击后跳转的场景 | | `conditions` | 显示条件 | | `effects` | 点击后触发的效果 | | `timeLimit` | 限时热点(秒),超时后热点消失 | --- ## QTEDefinition ```typescript interface QTEDefinition { triggerTime: number prompt: string promptKey?: string keys: string[] timeLimit: number successScene: string failScene: string effects?: { success: Effect[] fail: Effect[] } } ``` | 字段 | 说明 | |------|------| | `triggerTime` | 触发时间(秒),视频播放到此时间弹出 QTE | | `prompt` | 提示文字(回退值) | | `promptKey` | i18n key。如 `"right_door.qte.dodge"`。优先于 `prompt` | | `promptKey` | i18n key。如 `"right_door.qte.dodge"` | | `keys` | 有效按键列表,如 `["ArrowLeft", "ArrowRight", "a", "d"]` | | `timeLimit` | 限时秒数 | | `successScene` | 成功跳转场景 | | `failScene` | 失败/超时跳转场景 | | `effects` | 成功/失败分别触发效果 | --- ## 其他类型 ### Condition ```typescript interface Condition { variable: string op: '>' | '<' | '>=' | '<=' | '==' | '!=' value: number | string | boolean } ``` ### Effect ```typescript interface Effect { type: 'set' | 'add' target: string value?: number | string | boolean } ``` - `set` — 设置变量值 - `add` — 变量增加/减少 ### ChapterInfo ```typescript interface ChapterInfo { id: string label: string labelKey?: string startScene: string thumbnail?: string defaultVariables?: Record } ``` | 字段 | 说明 | |------|------| | `id` | 章节 ID | | `label` | 章节名称(回退值) | | `labelKey` | i18n key,优先于 `label` | | `startScene` | 起始场景 ID。玩家到达此场景时章节自动解锁 | | `thumbnail` | 缩略图路径 | | `defaultVariables` | 从章节选择界面进入时的默认变量值。未设时 fallback 到全局 `variables` | ### AchievementDef ```typescript interface AchievementDef { id: string title: string titleKey?: string description: string descKey?: string icon?: string hidden?: boolean condition: Condition } ``` | 字段 | 说明 | |------|------| | `id` | 成就唯一 ID | | `title` | 成就标题(回退值) | | `titleKey` | i18n key,优先于 `title` | | `description` | 成就描述(回退值) | | `descKey` | i18n key,优先于 `description` | | `icon` | 图标路径 | | `hidden` | `true` 时未解锁不显示标题和描述(显示 ???) | | `condition` | 解锁条件。变量满足时自动解锁并弹出 toast | ### EndingDef ```typescript interface EndingDef { id: string label: string labelKey?: string sceneId: string chapterId?: string thumbnail?: string } ``` | 字段 | 说明 | |------|------| | `id` | 结局唯一 ID | | `label` | 结局名称(回退值) | | `labelKey` | i18n key,优先于 `label` | | `sceneId` | 结局场景 ID。玩家到达此场景时结局自动标记已解锁 | | `chapterId` | 结局归属章节 ID(可选,BFS 自动推导) | | `thumbnail` | 缩略图路径 | ### LocalesConfig ```typescript interface LocalesConfig { path: string languages: string[] } ``` | 字段 | 说明 | |------|------| | `path` | 语言文件目录(相对于 `assetBase`),如 `"locales/"` | | `languages` | 支持的语言列表,如 `["zh", "en", "ja"]` |