docs: reorganize docs into guide/ and electron/, add 6 new guide docs, update README
This commit is contained in:
255
docs/guide/SCENE_JSON_SPEC.md
Normal file
255
docs/guide/SCENE_JSON_SPEC.md
Normal file
@@ -0,0 +1,255 @@
|
||||
# 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
|
||||
imageUrl?: string
|
||||
contentSize?: { w: number; h: number }
|
||||
subtitleUrl?: string
|
||||
subtitles?: Record<string, string>
|
||||
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 | 视频文件路径。image 场景可为空 |
|
||||
| `imageUrl` | 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"` |
|
||||
| `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[]
|
||||
}
|
||||
```
|
||||
|
||||
| 字段 | 说明 |
|
||||
|------|------|
|
||||
| `id` | 热点唯一标识 |
|
||||
| `label` | 显示标签(回退值) |
|
||||
| `labelKey` | i18n key |
|
||||
| `x, y` | 左上角坐标(像素,基于 contentSize) |
|
||||
| `width, height` | 尺寸(像素) |
|
||||
| `showAt` | 视频时间(秒),此时间后显示。不设则始终可见 |
|
||||
| `hideAt` | 视频时间(秒),此时间后隐藏 |
|
||||
| `targetScene` | 点击后跳转的场景 |
|
||||
| `conditions` | 显示条件 |
|
||||
| `effects` | 点击后触发的效果 |
|
||||
|
||||
---
|
||||
|
||||
## 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"` |
|
||||
| `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<string, number>
|
||||
}
|
||||
```
|
||||
|
||||
### AchievementDef
|
||||
|
||||
```typescript
|
||||
interface AchievementDef {
|
||||
id: string
|
||||
title: string
|
||||
titleKey?: string
|
||||
description: string
|
||||
descKey?: string
|
||||
icon?: string
|
||||
hidden?: boolean
|
||||
condition: Condition
|
||||
}
|
||||
```
|
||||
|
||||
### EndingDef
|
||||
|
||||
```typescript
|
||||
interface EndingDef {
|
||||
id: string
|
||||
label: string
|
||||
labelKey?: string
|
||||
sceneId: string
|
||||
chapterId?: string
|
||||
thumbnail?: string
|
||||
}
|
||||
```
|
||||
|
||||
### LocalesConfig
|
||||
|
||||
```typescript
|
||||
interface LocalesConfig {
|
||||
path: string
|
||||
languages: string[]
|
||||
}
|
||||
```
|
||||
Reference in New Issue
Block a user