LetsGal Studio 的剧本以 JSON 文件保存在工程目录里,结构完全公开。本页前半部分讲整体结构与引用规则,后半部分的指令全参考逐一列出全部 38 种指令的字段。
想让 AI 帮你写剧本?把本页整页复制给 AI,再附上你工程里的角色、场景、变量的 id 对照表(见页尾「让 AI 生成剧本」一节),AI 就能直接产出可以放进工程的章节 JSON。
工程里的剧本文件
一个 Studio 工程的根目录下,与剧本相关的文件如下:
| 路径 | 内容 |
|---|
project.json | 工程配置与章节索引(章节顺序、目录结构) |
chapters/*.json | 剧本正文。每个章节一个文件,文件名就是章节名(如 chapters/序章.json) |
characters.json | 角色定义:id、名字、表情、皮肤、属性模板 |
scenes.json | 场景定义:id、名字、图层 |
project.variables.json | 全局变量表:id、名字、类型、默认值 |
assets/ | 素材文件,按分类分子目录(bgm/、se/、video/ 等) |
几条基本规则:
- 改章节名时,章节文件也会跟着改名;文件名与 JSON 里的
name 字段始终一致。
project.json 的 chapterOrder 是一个章节名数组,决定章节的运行顺序;新章节文件必须登记进去才会被工程识别。
chapterOrder 的第一项是入口章节(工程模板里叫「开始」),不可删除。
project.json 里还有 chapterFolders(编辑器里的虚拟目录)和 chapterTreeOrder(章节树根层排序),只影响 Studio 里的展示,不影响运行顺序。
章节文件的结构
每个 chapters/*.json 的顶层结构:
{
"id": "ch-1755500000000-1",
"name": "第一章",
"fragments": [
{ "id": "frag-1755500000000-2", "name": "main", "blocks": [] }
]
}
| 字段 | 类型 | 必填 | 说明 |
|---|
id | string | ✅ | 章节唯一标识。Studio 生成的格式是 ch-<毫秒时间戳>-<序号>,也接受 UUID;全工程内不可重复 |
name | string | ✅ | 章节名,必须与文件名一致 |
fragments | 数组 | ✅ | 剧情片段列表,见下节 |
disabled | boolean | | 章节停用开关,省略视为 false |
剧情片段
剧情片段在编辑器里叫 Fragment,是章节内的执行单元:
{
"id": "frag-1755500000000-2",
"name": "main",
"blocks": [ ... ]
}
| 字段 | 类型 | 必填 | 说明 |
|---|
id | string | ✅ | 片段唯一标识,格式 frag-<毫秒时间戳>-<序号>。分支、条件、调用片段都靠它引用,必须唯一且真实存在 |
name | string | ✅ | 片段名。fragments[0] 必须叫 main,是章节正文;其余片段自由命名(如「去图书馆」) |
blocks | 数组 | ✅ | 指令序列,顺序执行 |
执行模型:默认线性链
理解剧本流转只需要三句话:
- 章节从
main 片段的第一个 Block 开始,顺序执行;一个章节执行完,进入 chapterOrder 里的下一章。
- 跳出线性流的手段只有三种指令:
branch(玩家选项)、if(条件跳转)、callFragment(直接调用片段)。它们的目标都是同一章节内的非 main 片段。
- 跳转到的片段执行完毕后,回到原跳转点之后继续(汇流回主线),类似函数调用。片段之间不要循环引用。
指令的通用结构
剧本里的每条指令(Block)最多只有 4 个字段:
{
"id": "66d4d76d-ddec-4f99-836a-50beac4f6f90",
"type": "dialogue",
"props": { "disabled": false, "characterId": "b8e3efe5-…" },
"content": [
{ "type": "text", "text": "台词正文。", "styles": {} }
]
}
| 字段 | 必填 | 说明 |
|---|
id | | Block 的编辑器内部 id(UUID)。可以省略,Studio 打开工程时会自动补生成;剧情跳转不依赖它 |
type | ✅ | 指令类型,合法值共 38 种,全表见下文指令全参考 |
props | ✅ | 该指令的全部参数。所有指令都支持 "disabled": true 把这条指令临时停用 |
content | 视类型 | 只有携带正文的指令才有(dialogue、narration、storyParagraph、comment、floatingText),存放文字内容 |
参数存储的三条约定
编辑器底层只能在 props 里保存标量(字符串、数字、布尔),因此磁盘 JSON 有几个乍看奇怪、实则一致的约定:
- 不少布尔与数值以字符串保存。例如
sound 的 "loop": "true"、"volume": "80",scene 的 "waitForComplete": "false"。每个字段的实际存储类型以指令参考页的标注为准,不要自行改成真布尔/真数字。
- 复杂结构一律是「JSON 字符串」,即把整个 JSON 数组或对象序列化成一个字符串再存入 props。涉及的字段:
branch.choices、if.conditions、stageAnimation.clipJson、callExtensionFunction.paramsJson、particle.optionsJson、camera.objectTargetsJson。
- 省略即默认。Studio 自己落盘时会写全所有字段(包括默认值),但手写或 AI 生成时只需给出必填字段和想改的字段,其余省略,打开工程时会按默认值自动补齐。
正文的结构
正文是一个内联片段数组,最常用的形态:
"content": [ { "type": "text", "text": "这是一句话。", "styles": {} } ]
styles 支持 bold、textColor、backgroundColor 等富文本样式;一条正文可以拆成多段不同样式的 text 片段。纯文本剧本让 styles 保持 {} 即可。
引用规则
这是 AI 生成剧本最容易出错的地方:所有 id 引用都必须指向工程里真实存在的实体,不能凭空编造。
| 引用 | 格式 | 来源 |
|---|
角色 characterId | UUID | characters.json 里 characters[].id |
场景 sceneId | UUID | scenes.json 里 scenes[].id |
音频 soundId | UUID | 资源库中音频素材的 id |
片段 fragmentId | frag-… | 同一章节内 fragments[].id |
素材 uri | 相对路径 | assets/ 下的路径,如 bgm/主题曲.mp3、video/intro.mp4 |
表情 expression / 皮肤 skin | 名字字符串 | 该角色在 characters.json 里配置过的表情名 / 皮肤名 |
变量的 key 有三种命名空间:
| 变量种类 | key 写法 | 例子 |
|---|
| 全局 / 系统变量 | 裸名字 | alice_affection |
| 角色属性变量 | 角色UUID.属性名 | b8e3efe5-….好感度 |
| 扩展存档变量 | 扩展id.键名 | avg.official.affection.total |
其他通用格式:
- 坐标与尺寸:写成
"(x,y)" / "(宽,高)" 的字符串,支持像素、百分比和 center / left / right / top / bottom 关键字,如 "(center,center)"、"(50%,200)"。
- 颜色:CSS 色值字符串,如
"#000000"。
- 站位 / 距离:
position 内置 left / center-left / center / center-right / right,distance 内置 far / middle / near;空字符串表示用工程默认,也可以填工程里自定义预设的 id。
三个复杂结构详解
分支的选项列表
branch 指令的 props.choices 是一个 JSON 字符串,反序列化后是选项数组。选项有两种模式:
[
{ "mode": "jump", "text": "去图书馆", "fragmentId": "frag-3" },
{
"mode": "vars",
"text": "回家休息",
"varOps": [
{
"key": "b8e3efe5-….好感度",
"op": "+=",
"aKind": "lit",
"aLit": "5",
"bKind": "none",
"binOp": "+"
}
]
}
]
| 字段 | 说明 |
|---|
mode | jump = 跳转到片段;vars = 不跳转,只修改变量 |
text | 玩家看到的选项文字 |
fragmentId | 仅 jump:目标片段 id,空字符串表示选中后什么都不做、继续主线 |
varOps | 仅 vars:变量操作数组,每一项与 setver 指令的 props 同构(见下) |
visibleIf | 可选:变量条件表达式,为真才显示该选项 |
isDefault | 可选:标记为默认选项(预览快进时自动选它),全组最多一个 |
写入 props 时记得把整个数组序列化成字符串:
"choices":
"[{\"mode\":\"jump\",\"text\":\"去图书馆\",\"fragmentId\":\"f3\"}]"
条件的结构
if 指令的 props.conditions 也是 JSON 字符串,反序列化后是条件数组,多条之间用 props.logicOp(and / or)连接:
[
{
"left": "alice_affection",
"op": ">=",
"rightKind": "literal",
"rightLiteral": "50"
},
{
"left": "route_flag",
"op": "==",
"rightKind": "variable",
"rightRef": "target_route"
}
]
| 字段 | 说明 |
|---|
left | 左值:变量 key |
op | 比较算子,全集:== != > >= < <= contains notContains startsWith endsWith isEmpty isNotEmpty exists notExists custom |
rightKind | 右值类型:literal(字面量)或 variable(另一个变量) |
rightLiteral | 右值字面量原始字符串(数字直接写 "50",不用补引号);op 为 custom 时这里是一段自由 JS 表达式 |
rightRef | 右值变量 key(rightKind 为 variable 时用) |
一元算子(isEmpty / isNotEmpty / exists / notExists)不需要右值。条件为真跳 thenFragmentId(必填),为假跳 elseFragmentId(可空,空则继续当前片段)。
变量赋值的运算字段
setver 把「A 运算」拆成了几个标量字段,branch 选项里的 varOps 与它同构:
| 字段 | 说明 |
|---|
key | 要写入的变量 key(必填) |
op | 赋值算子:= += -= *= /=(必填) |
aKind | 第一操作数类型:lit(字面量)或 var(变量) |
aLit / aVar | 按 aKind 二选一填写,另一个留空字符串 |
bKind | 第二操作数类型:none / lit / var |
bLit / bVar | 按 bKind 填写 |
binOp | 两个操作数之间的运算:+ - * / |
两条组合规则:op 不是 = 时 bKind 必须是 none(即 好感度 += 5 这种形态);要用双操作数(金钱 = 基础 + 奖金)时 op 必须是 =。字面量写法:true、123、"你好"(字符串带引号)。
指令全参考
以下是全部 38 种指令的字段字典:每种指令给出一句话用途、可抄的 JSON 示例和完整字段表;想学习在编辑器里怎么用某个指令,点各小节里的「手册」链接。
场景与演出
场景、镜头、粒子与浮动文字 · 10 种
界面与扩展
消息框、自定义界面与扩展方法 · 4 种
四条阅读约定
- 所有指令的
props 都支持 "disabled": true(这条指令不执行),字段表里不再重复。
- 类型列就是磁盘存储类型:标
"true"/"false" 的是字符串布尔,标 boolean 的才是真布尔;标「JSON 字符串」的字段要把整个结构序列化成字符串存入。
- 省略非必填字段即取默认值,示例里只写了常用字段。
- 每节末尾「生成时勿填」列出的字段由编辑器自动维护,AI 生成剧本时不要输出。
文本与角色
写故事最常用的一组:说话、叙述,以及立绘和文字样式的控制。
type: "dialogue"
角色说一句话,一句一个 Block,正文放 content。图形界面用法见手册:对白。
{
"type": "dialogue",
"props": {
"characterId": "<角色UUID>",
"characterName": "小雪",
"expression": "微笑",
"position": "center"
},
"content": [
{ "type": "text", "text": "今天想去哪里?", "styles": {} }
]
}
| 字段 | 类型 | 必填 | 默认 | 说明 |
|---|
characterId | UUID | ✅ | "" | 说话角色,引用 characters.json |
characterName | string | | "" | 角色显示名(冗余字段,与角色同名即可) |
nameVariantId | string | | "" | 角色的名字变体 id,空 = 主名称 |
expression | string | | "" | 该角色配置过的表情名 |
skin | string | | "" | 立绘皮肤名,空 = 自动 |
distance | string | | "" | far / middle / near 或自定义距离预设 id,空 = 默认 |
position | string | | "" | left / center-left / center / center-right / right 或自定义站位预设 id |
showCharacter | boolean | | true | 说话时是否同时显示立绘 |
dialoguePortraitOnly | boolean | | false | 只显示对话框头像,不上舞台立绘 |
keepCharacter | boolean | | true | 这组对白结束后是否保留立绘 |
keepDialogue | boolean | | true | 结束后是否保留对话框 |
两个常见的 AI 生成坏习惯,请避免:
- 不要在对白前多加「角色登场」。对白自带立绘显示(
showCharacter 默认 true),说话时角色会自动登场;前面再加一个 showCharacter 指令就是重复调用。只有角色不说话就要先站上舞台时,才单独使用「角色登场」。
- 对话收尾要放下对话框。一段对话结束、后面不再有对白时(尤其接镜头动画、场景切换等演出),把最后一句
dialogue 或 narration 的 keepDialogue 设为 false,对话框会自动隐藏,演出画面才干净。
生成时勿填:isFirst、isLast、prevExpression、prevNameVariantId、voiceHash、entryMotion* / exitMotion* 系列。
type: "narration"
无角色的叙述文字,显示在对话框里。图形界面用法见手册:旁白。
{
"type": "narration",
"props": {},
"content": [
{
"type": "text",
"text": "放学后的教室,只剩下我们两个人。",
"styles": {}
}
]
}
| 字段 | 类型 | 必填 | 默认 | 说明 |
|---|
keepDialogue | boolean | | true | 结束后是否保留对话框 |
生成时勿填:voiceHash。
type: "storyParagraph"
整屏长文(小说式演出),相邻的段落 Block 会合并成一屏。见手册:段落。
| 字段 | 类型 | 必填 | 默认 | 说明 |
|---|
speed | number | | 0 | 文字速度(字/秒),0 = 跟随全局设置 |
生成时勿填:isFirst。
角色登场
type: "showCharacter"
让角色立绘出现在舞台上(不说话)。注意:对白会自动显示立绘,本指令只用于角色不说话就登场的场合,不要作为对白的前置步骤。见手册:角色。
{
"type": "showCharacter",
"props": {
"characterId": "<角色UUID>",
"expression": "微笑",
"position": "left"
}
}
| 字段 | 类型 | 必填 | 默认 | 说明 |
|---|
characterId | UUID | ✅ | "" | 角色引用 |
characterName | string | | "" | 显示名冗余字段 |
expression | string | | "" | 空 = 角色的第一个表情 |
skin | string | | "" | 立绘皮肤 |
distance / position | string | | "" | 同「对白」 |
cameraBound | boolean | | false | 立绘是否参与镜头位移 / 震动 / 景深 |
cameraDistance | number | | 1 | 镜头深度距离,越小越靠近镜头 |
生成时勿填:animated 与 motion* 系列。
更新立绘
type: "updateCharacter"
修改已在场角色的表情、皮肤或站位。见手册:更新立绘。
| 字段 | 类型 | 必填 | 默认 | 说明 |
|---|
characterId | UUID | ✅ | "" | 角色引用 |
characterName | string | | "" | 显示名冗余字段 |
expression / skin / distance / position | string | | "" | 同「对白」,空 = 不变 |
placementTransitionEnabled | boolean | | true | 换位时是否播放平移动画 |
placementTransitionDuration | number | | 350 | 换位动画时长(毫秒) |
placementTransitionEasing | string | | "outCubic" | linear / inOutQuad / outCubic |
placementTransitionBlocking | boolean | | false | 是否阻塞后续指令 |
移除立绘
type: "removeCharacter"
见手册:移除立绘。
| 字段 | 类型 | 必填 | 默认 | 说明 |
|---|
characterId | UUID | ✅ | "" | 要移除的角色 |
characterName | string | | "" | 显示名冗余字段 |
生成时勿填:motion* 系列。
设置对话参数
type: "switchDialogueStyle"
切换对话框样式或微调打字机参数,数值参数以 -1 表示「不覆盖」。见手册:设置对话参数。
| 字段 | 类型 | 必填 | 默认 | 说明 |
|---|
source | string | | "" | 样式来源:preset / user / system / extension,空 = 只改参数不换样式 |
targetId | string | | "" | 对应来源下的样式 id |
extensionId | string | | "" | source 为 extension 时的扩展 id |
textSpeed | number | | -1 | 每字间隔毫秒(0–200) |
charFadeIn | number | | -1 | 单字淡入时长(0–300) |
waitForIconDelay | number | | -1 | 等待图标出现延迟(0–2000) |
showWaitForIcon | string | | "" | 三态:""(不变)/ "true" / "false" |
设置段落参数
type: "switchParagraphStyle"
切换段落样式与文字浮现效果,数值参数以 -1 表示「不覆盖」。见手册:设置段落参数。
| 字段 | 类型 | 必填 | 默认 | 说明 |
|---|
source | string | | "" | preset / user / extension,空 = 只改参数 |
targetId / extensionId | string | | "" | 同上 |
textSpeed | number | | -1 | 每字间隔毫秒 |
charFadeIn | number | | -1 | 单字淡入时长 |
revealEffect | string | | "" | 浮现效果:smooth-rise / classic / instant / smooth-drop / slide-left / slide-right / pop / flip / swing / blur,空 = 不变 |
revealDistance | number | | -1 | 浮现位移距离(0–48 像素) |
revealScale | number | | -1 | 起始缩放(30–100,百分比) |
revealRotation | number | | -1 | 起始旋转角度(0–180) |
revealBlur | number | | -1 | 起始模糊(0–12 像素) |
readMode | string | | "" | 已读段落:dim(变暗)/ keep(保留)/ hide(隐藏),空 = 不变 |
historyLimit | number | | -1 | 保留的历史段落数,0 = 不限 |
设置立绘发言状态
type: "portraitStyleRule"
一条「规则」指令:设定之后所有对白的立绘进退场动效、发言高亮和空间聚焦。字段较多,按组列出,全部为标量直存。见手册:设置立绘发言状态。
总开关与版本
| 字段 | 类型 | 默认 | 说明 |
|---|
enabled | boolean | true | 规则总开关 |
portraitMotionSemanticsVersion | number | 0 | 新建规则写 2;0 是旧工程兼容语义 |
进场动效 entryMotion* 与退场动效 exitMotion*(两组字段同构,仅前缀不同)
| 字段(以 entry 为例) | 类型 | 默认 | 说明 |
|---|
entryMotionEnabled | boolean | true | 是否启用 |
entryMotionPreset | string | "classic" | classic / fade / slide / rise / pop / swoop / drop / zoom / float / wipe / dissolve / none |
entryMotionDuration | number | 300 | 时长(毫秒) |
entryMotionIntensity | number | 1 | 强度,建议 0.25–2 |
entryMotionDirection | string | "auto" | auto / left / right / up / down |
entryMotionTiming | string | "preset" | preset / smooth / snappy / bounce / linear |
entryMotionFadeEnabled | boolean | true | 是否叠加淡入淡出 |
entryMotionDistanceMode | string | "offset" | offset(固定位移)/ offscreen(从屏幕外) |
entryMotionEdgeSoftness | number | -1 | wipe / dissolve 边缘柔化(0–0.25),-1 = 按预设默认 |
entryMotionGrainSize | number | -1 | dissolve 颗粒大小(2–64),-1 = 按预设默认 |
entryMotionWait | boolean | entry false / exit true | 是否等动效播完再继续 |
发言状态
| 字段 | 类型 | 默认 | 说明 |
|---|
speakingStateEnabled | boolean | true | 发言高亮总开关 |
othersState | string | "inactive" | 其他角色的状态:listening / inactive |
narrationState | string | "listening" | 旁白时全体状态:listening / inactive / keep |
transitionEnabled | boolean | true | 状态切换是否渐变 |
transitionDuration | number | 180 | 渐变时长(毫秒) |
transitionEasing | string | "outQuad" | linear / outQuad / inOutQuad / outCubic / outBack |
transitionBlocking | boolean | false | 渐变是否阻塞下一句台词 |
三态视觉参数 —— speaking / listening / inactive 三组前缀 × 六个参数(Scale / Brightness / Saturation / Contrast / Blur / Alpha),共 18 个 number 字段,如 speakingScale、inactiveBrightness。默认值:
| 前缀 | Scale | Brightness | Saturation | Contrast | Blur | Alpha |
|---|
speaking | 1.04 | 1.08 | 1 | 1 | 0 | 1 |
listening | 1 | 0.88 | 0.82 | 1 | 0 | 1 |
inactive | 1 | 0.8 | 0.42 | 1 | 0 | 1 |
空间聚焦 focusMotion*(发言角色向镜头前聚焦的电影感效果)
| 字段 | 类型 | 默认 | 说明 |
|---|
focusMotionEnabled | boolean | false | 总开关 |
focusMotionStrength | number | 0.16 | 聚焦位移强度 |
focusMotionDistance | number | 0.75 | 发言者的镜头距离 |
focusMotionDefocusDistance | number | 1 | 非发言者的镜头距离 |
focusMotionCameraZoom | number | 1 | 发言时镜头缩放 |
focusMotionNarrationCamera | string | "keep" | 旁白时镜头:center / keep |
focusMotionNarrationCameraZoom | number | 1 | 旁白时镜头缩放 |
focusMotionScale | number | 1.02 | 发言者额外缩放 |
focusMotionBackgroundMode | string | "fixed" | 背景:fixed / follow |
focusMotionCharacterZoomMode | string | "fixed" | 立绘缩放:fixed / follow |
focusMotionCenterMode | string | "position" | 聚焦中心:position / anchor |
focusMotionCenterPositionId | string | "" | 中心站位 id |
focusMotionEntryMode | string | "direct" | 入场衔接:direct / afterEnter |
focusMotionWaitPreviousExit | boolean | false | 是否等上一位退场 |
focusMotionTransitionEnabled | boolean | true | 聚焦切换是否渐变 |
focusMotionDuration | number | 180 | 渐变时长(毫秒) |
focusMotionEasing | string | "outQuad" | 同发言状态的枚举 |
focusMotionBlocking | boolean | false | 是否阻塞 |
生成时勿填:placementTransition* 四个字段(换位动画已迁移到「更新立绘」)。
场景与演出
背景、镜头与视觉演出。
场景切换
type: "scene"
切换背景场景,带 22 种转场效果。见手册:场景。
{
"type": "scene",
"props": {
"sceneId": "<场景UUID>",
"sceneName": "教室",
"transitionMode": "crossfade",
"transitionDuration": "500"
}
}
核心字段
| 字段 | 类型 | 必填 | 默认 | 说明 |
|---|
sceneId | UUID | ✅ | "" | 场景引用,来自 scenes.json |
sceneName | string | | "" | 显示名冗余字段 |
transitionMode | string | | "cover" | 转场方式,见下表 |
transitionDuration | string | | "500" | 转场时长(毫秒) |
waitForComplete | "true"/"false" | | "false" | 是否等转场播完再继续 |
resetCamera | "true"/"false" | | "false" | 切换时是否复位镜头 |
displayType | string | | "cover" | 铺放方式:cover / contain / by_width / by_height / stretch / center |
position | string | | "(center,center)" | 位置,"(x,y)" 格式 |
anchor | string | | "center" | 锚点九宫格:top-left / top-center / top-right / center-left / center / center-right / bottom-left / bottom-center / bottom-right |
size | string | | "" | "(宽,高)",空 = 按 displayType |
autoAddToGallery | "true"/"false" | | "true" | 展示成功后自动加入鉴赏(CG 收集) |
uri / galleryMethodTarget | string | | | 由资源系统 / 默认壳维护,一般不用填 |
22 种转场方式(transitionMode)
| 值 | 效果 | 值 | 效果 |
|---|
cover | 覆盖(默认) | rule | 规则图(配 transitionRuleUri) |
crossfade | 交叉淡化 | radial-wipe | 放射扫除 |
fade-to-black | 黑场过渡 | barn-door | 对开门 |
fade-to-white | 白场过渡 | diagonal-wipe | 斜切 |
cut | 瞬切 | zoom-fade | 缩放淡化 |
wipe | 方向擦除 | blur-dissolve | 模糊溶解 |
slide | 滑入 | mosaic | 马赛克 |
blinds | 百叶窗 | glitch | 故障闪烁 |
rotate | 旋转缩放 | page-turn | 翻页 |
iris | 圆形展开 | checkerboard | 棋盘格 |
pixel-dissolve | 像素溶解 | random-dissolve | 随机溶解 |
转场微调参数(只在对应模式下生效)
| 字段 | 默认 | 说明 |
|---|
transitionDirection | "" | 方向。擦除/滑入:left-to-right / right-to-left / top-to-bottom / bottom-to-top;百叶窗/对开门:vertical / horizontal;旋转/放射:clockwise / counterclockwise;斜切:top-left-to-bottom-right 等四角方向。空 = 各模式默认 |
transitionStrips | "12" | 百叶窗叶片数(2–64) |
transitionRuleUri | "" | rule 模式的灰度规则图路径,如 transitions/ink-wash.png |
transitionCenterX / transitionCenterY | "50" | 转场中心(百分比 0–100),用于 iris / radial-wipe / barn-door |
transitionSoftness | "" | 边缘柔化(0–20%);空时 rule 默认 5.5 |
transitionZoomScale | "1.14" | zoom-fade 缩放(1–2) |
transitionBlurStrength | "16" | blur-dissolve 模糊(0–32) |
transitionMosaicSize | "52" | mosaic 块大小(2–128) |
transitionGlitchStrength / ColorShift / Scanlines | "100" / "4.5" / "17" | glitch 专用 |
transitionPagePerspective / transitionPageShadow | "50" / "38" | page-turn 专用(百分比) |
mouseParallaxEnabled | "false" | 是否让当前场景跟随鼠标移动 |
mouseParallaxAmplitude | "4" | 鼠标位于画布边缘时的最大移动幅度(画布百分比,0–100) |
mouseParallaxEdgeEase | "0" | 接近画布边缘时的跟随减速程度(0–100);0 为线性跟随 |
mouseParallaxReturnOnLeave | "true" | 鼠标移出游戏画布时是否平滑回到中心 |
mouseParallaxScaleMode | "auto" | auto 根据幅度和最近图层距离防露边;custom 使用指定倍率 |
mouseParallaxScale | "1.08" | 自定义缩放倍率(1–5),仅 custom 模式生效 |
销毁场景
type: "destroyScene"
见手册:销毁场景。
| 字段 | 类型 | 必填 | 默认 | 说明 |
|---|
sceneId | string | ✅ | "all" | 场景 UUID;"all" = 销毁全部 |
sceneName | string | | "" | 显示名冗余字段 |
animated | "true"/"false" | | "true" | 是否播放淡出 |
waitForComplete | "true"/"false" | | "false" | 是否等待完成 |
type: "curtain"
拉上 / 拉开一层纯色幕布,常用于转场和黑屏演出。见手册:帷幕。
{
"type": "curtain",
"props": { "op": "close", "duration": "800" }
}
| 字段 | 类型 | 必填 | 默认 | 说明 |
|---|
op | string | ✅ | "close" | close(拉上)/ open(拉开) |
duration | string | | "1000" | 动画时长(毫秒) |
color | string | | "#000000" | 幕布颜色(CSS 色值) |
mode | string | | "full-screen" | full-screen(全屏)/ letterbox(上下黑边)/ pillarbox(左右黑边)/ windowbox(四边) |
curtainSize | string | | "100" | 黑边占比(0–100) |
生成时勿填:effect(旧数据兼容)。
镜头特效
type: "camera"
控制镜头位移、缩放、对焦、震动与全部滤镜。见手册:镜头特效。
所有数值字段都是字符串,空字符串 = 该参数保持不变。 只填想改的参数即可,比如推近镜头只需要 zoom 和 duration 两个字段。
{
"type": "camera",
"props": {
"zoom": "1.4",
"offsetY": "-60",
"colorToneMode": "sepia",
"colorToneIntensity": "0.6",
"duration": "800",
"easing": "easeInOut"
}
}
基础与补间
| 字段 | 默认 | 说明 |
|---|
offsetX / offsetY | "" | 镜头位移(像素),建议 ±300 / ±200 |
zoom | "" | 缩放,建议 0.8–2.5 |
focalDistance | "" | 对焦距离(0–1) |
blurStrength | "" | 景深模糊强度 |
duration | "0" | 补间时长(毫秒),"0" = 立即生效 |
easing | "linear" | linear / easeInOut |
waitForComplete | "true" | 是否等补间播完 |
targets | "scene,characters" | 作用范围:场景、立绘或两者 |
tweenFields | 内置默认 | 逗号分隔的字段名,只有列出的字段参与补间;一般省略 |
objectTargetsJson | "" | JSON 字符串,精确指定作用对象;空 = 按 targets 全局范围 |
震动
| 字段 | 默认 | 说明 |
|---|
shakeAmplitude | "" | 振幅(4–30 像素),非空即触发震动 |
shakeFrequency | "" | 频率(4–20 Hz) |
shakeAmplitudeRandomness / shakeFrequencyRandomness | "0" | 随机度(0–100) |
shakeFalloff | "linear" | 衰减:linear / expo |
shakeAxis | "both" | 方向:both / x / y |
色彩与基础滤镜(默认均为 "" = 不变)
| 字段 | 说明 |
|---|
colorToneMode | 色调:none / grayscale(黑白)/ sepia(怀旧),默认 "none" |
colorToneIntensity | 色调强度(0–1) |
colorExposure | 曝光(-2–2) |
colorBrightness / colorContrast | 亮度 / 对比度(-1–1) |
colorSaturation | 饱和度(0–2) |
colorTemperature | 色温(-1–1) |
lutPreset / lutIntensity | LUT 调色预设与强度 |
distortionStrength | 镜头畸变(-1–1) |
vignetteIntensity / vignetteSize | 暗角强度 / 范围(0–1) |
blurAmount | 全屏模糊(0–20) |
sharpenStrength | 锐化(-1–1) |
bloomIntensity | 泛光 |
chromaticAberration | 色差(-20–20) |
pixelateSize | 像素化块大小(1–64) |
glitchIntensity | 故障艺术强度 |
crtIntensity | CRT 扫描线 |
oldFilmIntensity | 老电影颗粒 |
shockIntensity | 冲击波 |
体积光 Godray
| 字段 | 说明 |
|---|
godrayIntensity | 强度,非空即启用 |
godrayAngle / godrayGain / godrayLacunarity / godraySpeed | 角度 / 增益 / 细节 / 流动速度 |
godrayParallel | 光源模式:"" / true(平行光)/ false(点光)/ spotlight(聚光) |
godrayCenterX / godrayCenterY | 光源位置 |
godrayConeAngle / godrayConeSoftness / godrayDistance | 聚光锥角 / 边缘柔化 / 距离 |
方向模糊
| 字段 | 说明 |
|---|
radialBlurStrength / radialBlurCenterX / radialBlurCenterY | 放射模糊:强度与中心 |
motionBlurStrength / motionBlurAngle | 运动模糊:强度与角度 |
zoomBlurStrength / zoomBlurCenterX / zoomBlurCenterY | 缩放模糊:强度与中心 |
氛围叠加
| 效果 | 字段 |
|---|
| 漏光 | lightLeakIntensity / lightLeakAngle |
| 镜头光斑 | lensFlareIntensity / lensFlareCenterX / lensFlareCenterY |
| 胶片颗粒 | filmGrainIntensity / filmGrainSize |
| 热浪 | heatHazeIntensity / heatHazeSpeed / heatHazeScale |
| 水波 | waterRippleIntensity / waterRippleFrequency / waterRippleSpeed / waterRippleCenterX / waterRippleCenterY |
| 雾 | fogIntensity / fogSpeed / fogScale |
| VHS 录像带 | vhsIntensity / vhsJitter / vhsNoise |
| 半调网点 | halftoneIntensity / halftoneScale / halftoneAngle |
| 抖动色阶 | ditherIntensity / ditherLevels |
| 描边 | outlineIntensity / outlineThickness |
速度线
| 字段 | 说明 |
|---|
speedLinesIntensity | 强度,非空即启用 |
speedLinesMode | radial(放射,默认)/ directional(定向) |
speedLinesDensity / speedLinesAngle / speedLinesSpeed | 密度 / 角度 / 速度 |
speedLinesFlicker / speedLinesIrregularity | 闪烁 / 不规则度 |
speedLinesLength / speedLinesThickness / speedLinesThicknessVariation | 长度 / 粗细 / 粗细变化 |
speedLinesTone / speedLinesFocus | 明暗 / 聚焦范围 |
speedLinesCenterX / speedLinesCenterY | 中心位置 |
泼墨 / 烟雾 / 眼睑
| 效果 | 字段 |
|---|
| 泼墨 | inkSplashIntensity、inkSplashVariant(cluster / burst / slash,默认 "cluster")、inkSplashScale、inkSplashRotation、inkSplashTone、inkSplashCenterX / inkSplashCenterY |
| 烟雾 | smokeOverlayIntensity、smokeOverlayVariant(left / right / full,默认 "full")、smokeOverlayStyle(warm / soft / dark,默认 "warm")、smokeOverlayTone、smokeOverlayScale、smokeOverlaySpeed |
| 眼睑(睁眼/闭眼演出) | eyelidOpenness(睁开程度)、eyelidWidth、eyelidCurvature、eyelidSoftness、eyelidCenterX / eyelidCenterY;仅作用于场景层 |
生成时勿填:shakeDuration(旧兼容,震动时长走顶部 duration)、presetId、targetSelectionPending。
复位镜头
type: "resetCamera"
清除所有镜头位移与滤镜,恢复默认视角。见手册:复位镜头。
| 字段 | 类型 | 必填 | 默认 | 说明 |
|---|
resetMode | string | | "instant" | instant(立即)/ animated(动画过渡) |
duration | string | | "500" | animated 时的过渡时长(毫秒) |
easing | string | | "easeInOut" | linear / easeInOut |
waitForComplete | "true"/"false" | | "true" | 是否等待完成 |
镜头动画
type: "stageAnimation"
多轨时间轴演出,在 Studio 的演出设计视图编辑。AI 生成剧本时一般只放一个占位,由创作者在 Studio 里编排。见手册:镜头动画。
| 字段 | 类型 | 必填 | 默认 | 说明 |
|---|
name | string | | "镜头段" | 演出段名称 |
clipJson | JSON 字符串 | | 空轨道 | 轨道数据,默认 {"version":1,"duration":3000,"tracks":[],"events":[]} |
loop | string | | "0" | 循环次数,"0" = 不循环 |
playbackRate | string | | "1" | 播放速率 |
waitForComplete | "true"/"false" | | "true" | 是否等待播完 |
粒子效果
type: "particle"
下雪、下雨、萤火虫等全屏粒子。见手册:粒子效果。
{
"type": "particle",
"props": { "mode": "show", "preset": "LIGHT_SNOW" }
}
| 字段 | 类型 | 必填 | 默认 | 说明 |
|---|
mode | string | ✅ | "show" | show(显示)/ hide(销毁) |
effectId | string | | "" | 粒子实例 id;show 时定义、hide 时引用,hide 留空 = 销毁全部 |
preset | string | | "LIGHT_SNOW" | LIGHT_SNOW / MODERATE_SNOW / HEAVY_SNOW(小/中/大雪)、LIGHT_RAIN / MODERATE_RAIN / HEAVY_RAIN(小/中/大雨)、FIREFLY(萤火虫)、FALLEN_LEAVES(落叶)、custom |
textureUri | string | | "" | 自定义粒子贴图路径 |
optionsJson | JSON 字符串 | | "" | 完整粒子参数,空 = 用预设 |
fadeInDuration / fadeOutDuration | string | | "500" | 淡入 / 淡出时长(毫秒) |
浮动文字
type: "floatingText"
在画面任意位置显示一段可动画的文字(标题、地点提示、内心独白等)。正文放 content,支持 [color=red]…[/color]、[b]、[i]、[size=32] 样式标记。见手册:浮动文字。
{
"type": "floatingText",
"props": {
"position": "(center,20%)",
"anchor": "top-center",
"fontSize": "42",
"animIn": "fade,slide"
},
"content": [
{ "type": "text", "text": "——三年后。", "styles": {} }
]
}
| 字段 | 类型 | 必填 | 默认 | 说明 |
|---|
floatingTextId | string | | "" | 实例 id,空 = 自动生成;常驻文字需自取 id 供后续隐藏 |
blocking | "true"/"false" | | "true" | 是否阻塞剧情推进 |
recordHistory | "true"/"false" | | "false" | 是否进入历史记录 |
position | string | | "(0,0)" | 位置 "(x,y)" |
anchor | string | | "top-left" | 锚点九宫格(同「场景切换」) |
size | string | | "" | "(宽,高)",空 = 自适应 |
color | string | | "#ffffff" | 文字颜色 |
fontFamily / fontSize / lineHeight / letterSpacing / textShadow | string | | "" | 文字样式,空 = 默认 |
fontWeight / fontStyle | string | | "normal" | 字重 / 斜体 |
textAlign | string | | "left" | 对齐 |
duration | string | | "2000" | 显示时长(毫秒) |
infinite | "true"/"false" | | "false" | "true" = 不自动消失,需「隐藏浮动文字」手动隐藏 |
animIn / animOut | string | | "fade" | 入 / 出场动画,可逗号叠加:fade / slide / scale / blur |
inDuration / outDuration | string | | "300" | 入 / 出场动画时长 |
slideFrom | string | | "top" | slide 方向 |
slideDistance | string | | "40" | slide 距离(像素) |
scaleFrom / scaleTo | string | | "0.8" | scale 起止缩放 |
blurRadius | string | | "8" | blur 动画模糊半径 |
隐藏浮动文字
type: "hideFloatingText"
| 字段 | 类型 | 必填 | 默认 | 说明 |
|---|
floatingTextId | string | | "" | 要隐藏的实例 id,空 = 隐藏全部 |
精灵动画(遗留)
type: "animateSprite"
遗留类型,仅用于读取旧工程,AI 与新剧本都不要使用。移动镜头请用「镜头特效 camera」,编排演出请用「镜头动画 stageAnimation」。
音视频
播放声音
type: "sound"
见手册:声音。
{
"type": "sound",
"props": {
"soundType": "BGM",
"soundId": "<音频UUID>",
"uri": "bgm/日常.mp3",
"loop": "true",
"volume": "80"
}
}
| 字段 | 类型 | 必填 | 默认 | 说明 |
|---|
soundType | string | ✅ | "BGM" | BGM(背景音乐)/ SE(音效)/ VOCAL(语音) |
soundId | UUID | ✅ | "" | 音频资源引用 |
uri | string | | "" | 资源相对路径,如 bgm/主题曲.mp3 |
volume | string | | "100" | 音量(0–100) |
loop | "true"/"false" | | "false" | 是否循环(BGM 通常填 "true") |
fadeDuration | string | | "" | 淡入时长(毫秒),空 = 立即 |
停止声音
type: "stopSound"
见手册:停止声音。
| 字段 | 类型 | 必填 | 默认 | 说明 |
|---|
soundType | string | ✅ | "BGM" | 要停止的声音类型 |
soundId | string | | "" | 指定音轨 id,空 = 停止该类型的默认音轨 |
fadeDuration | string | | "" | 淡出时长(毫秒),空 = 立即 |
播放视频
type: "video"
见手册:视频。
| 字段 | 类型 | 必填 | 默认 | 说明 |
|---|
uri | string | ✅ | "" | 视频路径,如 video/intro.mp4 |
videoId | string | | "video" | 视频实例 id |
loop | "true"/"false" | | "true" | 是否循环 |
muted | "true"/"false" | | "true" | 是否静音 |
alpha | string | | "100" | 不透明度(0–100) |
waitForFinished | "true"/"false" | | "false" | 是否等播完再继续 |
mode | string | | "normal" | normal / mixed(叠加发光混合,适合特效视频) |
停止视频
type: "stopVideo"
| 字段 | 类型 | 必填 | 默认 | 说明 |
|---|
videoId | string | | "" | 要停止的实例 id,空 = 停止全部 |
fadeOutDuration | string | | "" | 淡出时长(毫秒) |
逻辑流程
分支、条件、变量与章节流转——剧本的骨架。
选项分支
type: "branch"
向玩家展示选项。choices 的内部结构详见上文分支的选项列表。见手册:分支。
{
"type": "branch",
"props": {
"title": "去哪里",
"choices":
"[{\"mode\":\"jump\",\"text\":\"出发\",\"fragmentId\":\"f3\"}]"
}
}
| 字段 | 类型 | 必填 | 默认 | 说明 |
|---|
choices | JSON 字符串 | ✅ | "[]" | 选项数组 |
title | string | | "" | 编辑器内的分支标题,不显示给玩家 |
branchId | UUID | | "" | 叙事地图用的稳定身份,可省略(自动补) |
type: "if"
按变量条件跳转片段。conditions 的内部结构详见上文条件的结构。见手册:条件。
| 字段 | 类型 | 必填 | 默认 | 说明 |
|---|
conditions | JSON 字符串 | ✅ | "" | 条件数组 |
logicOp | string | | "and" | 多条件连接:and / or |
thenFragmentId | string | ✅ | "" | 条件为真跳转的片段(同章节、非 main) |
elseFragmentId | string | | "" | 条件为假跳转的片段,空 = 继续当前片段 |
生成时勿填:expression(由编辑器从 conditions 派生)。
变量赋值
type: "setver"
修改变量的值。字段与组合规则详见上文变量赋值的运算字段。见手册:赋值。
{
"type": "setver",
"props": {
"key": "<角色UUID>.好感度",
"op": "+=",
"aKind": "lit",
"aLit": "5",
"bKind": "none",
"binOp": "+"
}
}
核心字段:key(必填)、op(= += -= *= /=)、aKind / aLit / aVar、bKind / bLit / bVar、binOp。
调用片段
type: "callFragment"
跳去执行另一个片段,执行完回到此处继续(嵌套上限 30 层)。见手册:调用片段。
| 字段 | 类型 | 必填 | 默认 | 说明 |
|---|
fragmentId | string | ✅ | "" | 目标片段 id(同章节) |
type: "wait"
见手册:等待。
| 字段 | 类型 | 必填 | 默认 | 说明 |
|---|
duration | number | ✅ | 1000 | 等待时长(毫秒)。注意是真数字,不是字符串 |
waitForInput | boolean | | false | true = 改为等玩家点击,忽略 duration |
玩家输入
type: "playerInput"
弹出输入框,把玩家输入写进变量(起名字等场景)。
| 字段 | 类型 | 必填 | 默认 | 说明 |
|---|
variable | string | ✅ | "" | 结果写入的变量 key |
valueType | string | ✅ | "string" | string / number / bool |
title | string | ✅ | "请输入" | 输入框标题 |
description | string | | "" | 说明文字 |
placeholder | string | | "请输入…" | 占位提示 |
confirmText | string | | "确认" | 确认按钮文字 |
required | boolean | | true | 是否必填 |
requiredText | string | | "请填写后再继续" | 必填提示 |
minLength / maxLength | number | | 0 / 20 | 字符串长度限制,0 = 不限 |
minValue / maxValue | number | | 不限 | 数字范围(valueType 为 number) |
step | number | | 1 | 数字步进 |
trueText / falseText | string | | "是" / "否" | 布尔选项文字(valueType 为 bool) |
终止章节
type: "endChapter"
无参数。立即结束当前章节,进入 chapterOrder 的下一章。见手册:终止章节。
返回入口章节
type: "returnToEntry"
无参数。跳回工程的入口章节(常用于「回到标题」类流程)。见手册:返回入口章节。
进入 / 退出自动播放
type: "enterAutoPlay" / "exitAutoPlay"
成对使用,让剧情像放映一样自动推进。见手册:自动播放。
| 字段 | 类型 | 必填 | 默认 | 说明 |
|---|
allowInterrupt | "true"/"false" | | "true" | 仅 enterAutoPlay:"false" = 玩家不能打断(强制必看段) |
exitAutoPlay 无参数。
界面与扩展
标准消息框
type: "systemMessage"
弹出提示或确认对话框。见手册:标准消息框。
{
"type": "systemMessage",
"props": {
"mode": "confirm",
"title": "确认",
"message": "要保存进度吗?",
"resultVariable": "save_confirmed"
}
}
| 字段 | 类型 | 必填 | 默认 | 说明 |
|---|
mode | string | ✅ | "alert" | alert(仅确认)/ confirm(确认 + 取消) |
title | string | ✅ | "提示" | 标题 |
message | string | ✅ | "" | 正文 |
confirmText | string | | "知道了" | 确认按钮文字 |
cancelText | string | | "取消" | 取消按钮文字(仅 confirm) |
tone | string | | "info" | info / success / warning / danger |
resultVariable | string | | "" | 仅 confirm:把结果(布尔)写入的变量 key |
显示界面
type: "showExtensionUI"
打开扩展或可视化 UI 编辑器制作的界面。见手册:显示界面。
| 字段 | 类型 | 必填 | 默认 | 说明 |
|---|
target | string | ✅ | "" | 三种写法:扩展id/界面id、ui:界面名(可视化 UI 编辑器的界面)、slot:槽位id |
modal | boolean | | false | true = 模态阻塞,关闭后剧情才继续 |
layer | string | | "topmost" | 层级:topmost / top / bottom / behind-scene |
seekBehavior | string | | "skip-if-seeking" | 快进 / 读档时的行为:skip-if-seeking / always-open(modal 为 true 时忽略) |
interactable | string | | "" | 三态:""(默认)/ "true" / "false",是否接收点击 |
size / position | string | | "" | 覆盖尺寸 / 位置,空 = 界面自身设定 |
隐藏界面
type: "hideExtensionUI"
| 字段 | 类型 | 必填 | 默认 | 说明 |
|---|
target | string | ✅ | "" | 与显示时的写法一致 |
调用扩展方法
type: "callExtensionFunction"
调用扩展提供的方法(解锁成就、加好感度等)。见手册:调用扩展方法。
{
"type": "callExtensionFunction",
"props": {
"target": "avg.official.affection/add",
"paramsJson": "{\"amount\":{\"kind\":\"lit\",\"value\":5}}"
}
}
| 字段 | 类型 | 必填 | 默认 | 说明 |
|---|
target | string | ✅ | "" | 扩展id/方法id |
paramsJson | JSON 字符串 | | "{}" | 参数表;每个值形如 {"kind":"lit","value":…}(字面量)或 {"kind":"var","ref":"变量key"}(变量) |
type: "comment"
正文放 content,只在编辑器里可见,不参与游戏编译,用于给剧本留备注。见手册:注释。
以上 38 种是 type 字段的全部合法值。剧本文件里偶尔还会见到 paragraph(编辑器内部保留类型)——它不是剧本指令,生成剧本时不要使用。
完整示例章节
一个小而全的章节文件,覆盖场景、音乐、对白、选项与片段跳转(片段 id 用了缩写示意,实际生成时保持全工程唯一即可):
{
"id": "ch-1755500000000-1",
"name": "第一章",
"fragments": [
{
"id": "f2",
"name": "main",
"blocks": [
{
"type": "scene",
"props": {
"sceneId": "<场景UUID>",
"sceneName": "教室",
"transitionMode": "crossfade",
"transitionDuration": "500"
}
},
{
"type": "sound",
"props": {
"soundType": "BGM",
"soundId": "<音频UUID>",
"uri": "bgm/日常.mp3",
"loop": "true",
"volume": "80"
}
},
{
"type": "narration",
"props": {},
"content": [
{
"type": "text",
"text": "放学后的教室,只剩下我们两个人。",
"styles": {}
}
]
},
{
"type": "dialogue",
"props": {
"characterId": "<角色UUID>",
"characterName": "小雪",
"expression": "微笑",
"position": "center"
},
"content": [
{ "type": "text", "text": "今天想去哪里?", "styles": {} }
]
},
{
"type": "branch",
"props": {
"title": "去哪里",
"choices":
"[{\"mode\":\"jump\",\"text\":\"出发\",\"fragmentId\":\"f3\"}]"
}
},
{
"type": "narration",
"props": {},
"content": [
{
"type": "text",
"text": "无论选了哪边,故事都会回到这里继续。",
"styles": {}
}
]
},
{ "type": "endChapter", "props": {} }
]
},
{
"id": "f3",
"name": "去图书馆",
"blocks": [
{
"type": "dialogue",
"props": {
"characterId": "<角色UUID>",
"characterName": "小雪",
"expression": "开心"
},
"content": [
{ "type": "text", "text": "那就走吧!", "styles": {} }
]
}
]
}
]
}
示例里的 <…UUID> 占位符必须替换成你工程里真实存在的 id,否则对应指令不会生效。角色 id 在 characters.json,场景 id 在 scenes.json。
让 AI 生成剧本
把资料喂给 AI 时,建议这样组织:
- 复制本页全文:结构规则和指令字段明细都在这一页。
- 附上工程实体对照表:从
characters.json、scenes.json、project.variables.json 里整理出「名字 → id」清单,以及每个角色可用的表情名。AI 只能引用这份清单里的 id,不能编造。
- 说明你要的剧情:章节名、片段规划(哪些分支、汇流到哪)、想要的演出效果。
再叮嘱 AI 几条硬规则(也可以直接把下面这段一起复制过去):
- 只使用本页「指令全参考」列出的 38 种
type;animateSprite 是遗留类型,禁止生成,动镜头用 camera、动演出用 stageAnimation。
- 不要生成编辑器自动维护的字段:
voiceHash、isFirst、isLast、prevExpression、prevNameVariantId。
fragments[0] 必须命名为 main;branch / if / callFragment 引用的 fragmentId 必须在同一章节里真实存在。
- 章节 id、片段 id 在工程内唯一;Block 的
id 可以整个省略。
- 对白一句一个
dialogue,正文放 content,不要塞进 props。
- 对白自带立绘显示(
showCharacter 默认 true),不要在 dialogue 前额外加 showCharacter(那是重复调用);只有角色不说话就要登场时才用「角色登场」。
- 一段对话结束、后面不再有对白时(尤其接镜头动画、场景切换等演出),把最后一句
dialogue / narration 的 keepDialogue 设为 false,自动隐藏对话框。
生成的文件放进工程 chapters/ 目录(文件名 = 章节名),再把章节名加进 project.json 的 chapterOrder 数组,重新打开工程即可在 Studio 里看到并继续编辑。也可以只让 AI 生成 fragments 里的 blocks 内容,粘贴合并进现有章节文件,这样可以完全不碰 id 和索引。