LetsGal Studio 的剧本以 JSON 文件保存在工程目录里。本页先定义章节、Fragment、Block 的磁盘结构,再给出指令全参考。这里描述的是 Studio 工程源文件,不是编译后的运行时 OP 数据,也不是 Studio 内置 AI 的流式协议。
想让 AI 帮你写剧本?先看下面的最小示例,再把本页和工程实体对照表一起交给 AI。生成后按页尾检查清单核对结构、类型和引用;缺少资源信息时,让 AI 报告缺项,不要猜 id。
工程里的剧本文件
一个 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 整理章节树后,展开顺序会同步到 chapterOrder;不要生成互相矛盾的排序。
先复制这个最小章节
以下是一个完整、合法、不依赖角色、场景、音频或变量的章节文件。保存为 chapters/最小示例.json;复制多份时请替换章节和片段 id,避免重复。
{
"id": "ch-example-minimal",
"name": "最小示例",
"fragments": [
{
"id": "frag-example-main",
"name": "main",
"blocks": [
{
"type": "narration",
"props": { "keepDialogue": false },
"content": [
{ "type": "text", "text": "故事从这里开始。", "styles": {} }
]
},
{ "type": "endChapter", "props": {} }
]
}
]
}
在已有工程的 project.json 中,把 最小示例 加入原有的 chapterOrder,保留入口章节和其他配置。下面只是索引片段,不能作为完整的 project.json 覆盖工程配置:
{ "chapterOrder": ["开始", "最小示例"] }
这个示例会显示一句旁白,然后结束本章。只需要空章节骨架时,把 blocks 改为 [] 即可;不需要用 paragraph 占位。独立 Fragment 或 Block 对象都不能直接替代整个章节文件。
章节文件的结构
每个 chapters/*.json 的顶层结构:
{
"id": "ch-1755500000000-1",
"name": "第一章",
"fragments": [
{ "id": "frag-1755500000000-2", "name": "main", "blocks": [] }
]
}
| 字段 | JSON 类型 | 生成时必填 | 默认值 / 缺省行为 | 约束 |
|---|
id | string | 是 | 无;生成器必须提供 | 非空、全工程唯一。Studio 新建时使用 ch-<毫秒时间戳>-<序号>;这是生成习惯,不是必须匹配的正则,也可使用 UUID。修改现有章节时保留原 id |
name | string | 是 | 无 | 非空,与文件名去掉 .json 后完全一致;避免文件系统不允许的字符。工程内章节名不能重复 |
fragments | Fragment[] | 是 | 无;新建章节会创建一个 main 片段 | 至少一个元素,第一项名称必须为 main;不要输出空数组或 null |
disabled | boolean | 否 | 缺省视为 false | true 停用章节;入口章节不应停用。不是字符串 "true" |
kind | string | 否 | 省略表示普通章节 | 仅特殊前处理章节使用 "schedule-preprocessing";没有 "normal" 等其他约定值。普通剧情生成时省略 |
kind 属于高级章节调度。不要为了“补齐默认值”给普通章节添加此字段,也不要用 null 表示普通章节。
剧情片段
剧情片段在编辑器里叫 Fragment,是章节内的执行单元:
{
"id": "frag-1755500000000-2",
"name": "main",
"blocks": []
}
| 字段 | JSON 类型 | 生成时必填 | 默认值 / 缺省行为 | 约束 |
|---|
id | string | 是 | 无;生成器必须提供 | 非空、全工程唯一。Studio 新建时使用 frag-<毫秒时间戳>-<序号>,也可使用其他唯一字符串;引用填写 id,不是片段名 |
name | string | 是 | 无 | 第一项固定为 main;其他片段使用非空名称,不要再命名为 main |
blocks | Block[] | 是 | 新建片段为 [];生成时显式填写 | 指令按数组顺序执行;空数组合法。不能改成对象、字符串或 null |
metadata | object | 否 | 无片段级附加配置 | 非执行元数据。普通片段省略;修改已有片段时保留原配置。这里是真对象,不是 JSON 字符串 |
片段没有通用 disabled、next、nextFragmentId、chapterId 或 type 字段,不要自行添加这些字段控制执行。停用单条指令用 block.props.disabled,停用整章用 chapter.disabled。
普通线性剧情不需要 metadata。蓝图中的扩展调度策略可以使用 metadata.scheduleEvent:
| 字段 | JSON 类型 | 必填 | 默认值 / 约束 |
|---|
metadata.scheduleEvent | object | 否 | 省略表示没有在此处配置调度事件 |
scheduleEvent.strategyTarget | string | 配置事件时必填 | 无默认值;必须是工程实际使用的调度策略全局 id |
scheduleEvent.enabled | boolean | 否 | 缺省视为 true;false 保留配置但不加入调度事件池,不是片段通用停用开关 |
scheduleEvent.config | object | 配置事件时必填 | 字段由该调度扩展的 schema 定义,无通用默认结构,不能由 AI 猜测 |
metadata 还允许扩展附加配置。保留已有未知配置;需要新增时,先取得对应扩展的字段规范。
执行模型:默认线性链
以下描述基础线性调度;启用蓝图调度时,章节选取还受工程调度配置控制:
- 章节从
main 片段的第一个 Block 开始,顺序执行;一个章节执行完,进入 chapterOrder 里的下一章。
- 跳出线性流的手段只有三种指令:
branch(玩家选项)、if(条件跳转)、callFragment(直接调用片段)。它们的目标都是同一章节内的非 main 片段。
- 跳转到的片段执行完毕后,回到原跳转点之后继续(汇流回主线),类似函数调用。片段之间不要循环引用。
指令的通用结构
生成内置剧本指令时,使用以下通用字段:
{
"id": "66d4d76d-ddec-4f99-836a-50beac4f6f90",
"type": "dialogue",
"props": { "disabled": false, "characterId": "b8e3efe5-…" },
"content": [
{ "type": "text", "text": "台词正文。", "styles": {} }
]
}
| 字段 | JSON 类型 | 生成时必填 | 默认值 / 缺省行为 | 约束 |
|---|
id | string | 否 | BlockNote 编辑器加载该片段时可自动生成 | 新建 Block 可省略;修改已有 Block 时保留。自行提供时保证唯一;片段跳转不引用 Block id |
type | string | 是 | 无可供生成器依赖的默认值 | 大小写敏感,使用下文指令全参考中的类型;不要用 text、say、jump 替代指令类型 |
props | object | 是 | 各指令有不同参数默认值 | 无参数也写 {};不是数组或 JSON 字符串。仅写该类型支持的属性 |
props.disabled | boolean | 否 | false | 所有内置剧本指令共用;必须放在 props 内,不是 Block 顶层 |
content | InlineContent[] | 有正文时填写 | 无正文可省略;空正文可写 [] | 正文类型为 dialogue、narration、storyParagraph、comment、floatingText;生成时统一使用下节的文本数组 |
children | Block[] | 否 | 普通指令不需要 | BlockNote 保存结果可能带 children: [];普通剧情用片段的 blocks 顺序表达,不要把条件或分支剧情嵌在这里 |
这里的“生成时必填”是生成可用剧本的约定,不代表读取器会在缺字段时自动报错。原始数据接口为兼容旧工程和扩展允许更宽的形态,不应据此省略 type 或猜测新字段。
最小无正文 Block(等待默认的 1000 毫秒):
{ "type": "wait", "props": {} }
显式写出默认参数的等价版本:
{
"type": "wait",
"props": { "disabled": false, "duration": 1000, "waitForInput": false }
}
参数存储的三条约定
编辑器底层只能在 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。
- 区分 schema 默认值和可执行所需值。下文默认列主要表示编辑器
propSchema 的初始值;例如 characterId: "" 只是尚未选择角色,不表示空 id 能显示角色。生成时仍需填齐功能必需参数。编辑器加载 Block 时可补默认参数,但读取章节文件本身不等于遍历并补全所有 Block;若绕过编辑器直接交给脚本工具或编译器,应显式写出影响行为的参数。
省略字段、空字符串、null 不是一回事。只有字段表明确说明时,"" 才表示“使用默认”或“清除”;不要给缺省字段批量填 null。JSON 不允许注释、尾逗号、undefined 或省略号。
正文的结构
正文是一个内联片段数组,最常用的形态:
{ "content": [ { "type": "text", "text": "这是一句话。", "styles": {} } ] }
上面只是 content 字段示意,不是完整 Block。每个纯文本内联项的约定如下:
| 字段 | JSON 类型 | 生成时必填 | 约束 |
|---|
type | string | 是 | 固定 "text";这是内联项类型,不是 Block 类型 |
text | string | 是 | 正文;空字符串表示空文本,换行在 JSON 中写 \n |
styles | object | 是 | 无格式写 {};加粗可写 {"bold":true},文字颜色可写 {"textColor":"#ff0000"} |
一条正文可以拆成多段不同样式的 text 片段。纯文本生成统一使用上面的数组结构,不要把台词放进 props.text、Block 顶层 text,也不要把整个 content 数组序列化成字符串。
引用规则
这是 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": "+"
}
]
}
]
| 字段 | JSON 类型 | 生成时必填 | 默认值 / 约束 |
|---|
mode | string | 是 | "jump" 或 "vars";旧数据缺省可兼容为 jump,新生成时显式填写 |
text | string | 是 | 无可用默认文案;填写玩家看到的选项文字 |
fragmentId | string | jump 模式必填 | 非空时指向同章非 main 片段;"" 表示选中后直接继续当前片段 |
varOps | object[] | vars 模式必填 | 每项与下文 setver 运算字段同构;[] 表示不修改变量。这里是数组,整个 choices 才序列化成字符串 |
visibleIf | string | 否 | 省略或空字符串表示不附加显示条件;可填写变量表达式,为真才显示。编辑器也会保存结构化条件的 JSON 字符串,修改现有数据时保留其格式 |
isDefault | boolean | 否 | 缺省不标记默认项;true 标为预览快进的默认选项,全组最多一个。不要写成 "true" |
新建空白分支的 choices 默认值是字符串 "[]",但这不构成有意义的玩家选项。生成可用分支时至少提供一个有文字的选项。
写入 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"
}
]
| 字段 | JSON 类型 | 生成时必填 | 默认值 / 约束 |
|---|
sourceKind | string | 否 | 缺省为 "variable";扩展方法条件为 "extension-method" |
left | string | 变量条件必填 | 变量 key;编辑器占位值 "" 不是有效变量引用。custom 或扩展方法条件可写 "" |
op | string | 是 | 新建条件初值 "==";可用 == != > >= < <= contains notContains startsWith endsWith isEmpty isNotEmpty exists notExists custom |
rightKind | string | 是 | 新建条件初值 "literal";"literal" 用字面量,"variable" 用变量 |
rightLiteral | string | 字面量比较 / custom 时必填 | 新建初值 "";数字如 "50",布尔如 "true",字符串如 "你好";custom 时是表达式文本 |
rightRef | string | 变量比较时必填 | 无有效默认引用;填另一个真实变量 key |
extensionMethod | string | 扩展方法条件必填 | 真实方法全局 id,不能编造 |
extensionParams | object | 按方法声明 | 使用该方法声明的参数,值为 {"kind":"lit","value":5} 或 {"kind":"var","ref":"score"};此处是真对象 |
extensionReturnType | string | 否 | 编辑器记录的返回类型,运行时以扩展声明为准;没有声明时不要猜测 |
一元算子(isEmpty / isNotEmpty / exists / notExists)不需要右值。条件为真跳 thenFragmentId(必填),为假跳 elseFragmentId(可空,空则继续当前片段)。
变量赋值的运算字段
setver 把「A 运算」拆成了几个标量字段,branch 选项里的 varOps 与它同构:
| 字段 | JSON 类型 | 默认值 | 约束 |
|---|
key | string | "" | 必须填写已声明的目标变量 key;空值不是可执行默认 |
op | string | "=" | = += -= *= /=;生成时显式填写所需操作 |
aKind | string | "lit" | lit(字面量)或 var(变量) |
aLit | string | "" | aKind=lit 时提供有效字面量 |
aVar | string | "" | aKind=var 时填写真实变量 key |
bKind | string | "none" | none / lit / var |
bLit | string | "" | bKind=lit 时提供有效字面量 |
bVar | string | "" | bKind=var 时填写真实变量 key |
binOp | string | "+" | 双操作数之间的 + - * / |
两条组合规则:op 不是 = 时 bKind 必须是 none(即 好感度 += 5 这种形态);要用双操作数(金钱 = 基础 + 奖金)时 op 必须是 =。字面量写法:true、123、"你好"(字符串带引号)。
指令全参考
以下覆盖当前 43 种内置剧本 Block 类型,其中 animateSprite、hideStageMask 仅供读取旧工程,41 种可用于新剧本。各节列出用途与参数;扩展自定义 Block 还需要对应扩展的 schema,不能自行编造。图形界面用法见各节「手册」链接。
场景与演出
场景、镜头、粒子与浮动文字 · 12 种
界面与扩展
消息框、链接、Steam 与扩展方法 · 7 种
四条阅读约定
- 所有指令的
props 都支持 "disabled": true(这条指令不执行),字段表里不再重复。
- 类型列就是磁盘存储类型:标
"true"/"false" 的是字符串布尔,标 boolean 的才是真布尔;标「JSON 字符串」的字段要把整个结构序列化成字符串存入。
- 默认值与功能必填值不同:默认
"" 的资源引用仍需填写真实 id。精简示例面向编辑器加载;自动化直编时显式填写关键参数。
- 每节末尾「生成时勿填」列出的字段由编辑器自动维护,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 |
| 玻璃碎裂 | mirrorShatterIntensity(碎裂程度)/ mirrorShatterCenterX / mirrorShatterCenterY(撞击位置) |
| 雾 | 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: "stageMask"
显示、更新或移除舞台蒙层。覆盖蒙层用于聚光、挖洞和氛围效果;对象裁剪用于裁剪场景与立绘。见手册:蒙层。
{
"type": "stageMask",
"props": {
"action": "show",
"maskId": "spotlight",
"mode": "overlay",
"plane": "bottom",
"shape": "ellipse",
"visibility": "inside",
"centerX": 50,
"centerY": 45,
"width": 36,
"height": 60,
"feather": 24,
"opacity": 85,
"color": "#000000",
"enterDuration": 1000
}
}
操作与目标
| 字段 | 类型 | 必填 | 默认 | 说明 |
|---|
action | string | | "show" | show(显示或更新)/ remove(移除) |
maskId | string | | "mask" | 稳定 ID;show 使用相同 ID 会更新已有蒙层;remove 时留空表示移除当前剧情创建的全部蒙层 |
mode | string | | "overlay" | overlay(覆盖蒙层)/ clip(对象裁剪) |
plane | string | | "bottom" | 覆盖层级:behind-scene / bottom / top / topmost;仅 overlay 使用 |
scope | string | | "stage" | 裁剪范围:scene / characters / stage / selected;仅 clip 使用 |
targetsJson | JSON 字符串 | | "" | selected 的目标数组;元素为场景、场景图层或角色引用 |
形状与变换
| 字段 | 类型 | 必填 | 默认 | 说明 |
|---|
shape | string | | "rect" | rect / rounded-rect / ellipse / image |
image | string | | "" | image 形状使用的 PNG / WebP 素材路径 |
imageChannel | string | | "alpha" | alpha(透明度)/ luma(亮度) |
imageFit | string | | "stretch" | stretch / cover / contain |
centerX / centerY | number | | 50 / 50 | 中心位置,占设计画布百分比 |
width / height | number | | 50 / 50 | 宽高,占设计画布百分比 |
rotation | number | | 0 | 旋转角度 |
radius | number | | 24 | 圆角矩形的圆角半径(像素) |
visibility | string | | "inside" | inside(保留形状内部)/ outside(保留形状外部) |
coordinateSpace | string | | "screen" | 坐标空间;当前统一使用 screen,target 仅为旧数据兼容 |
feather | number | | 0 | 边缘羽化(像素) |
覆盖填充与效果
以下字段只影响 overlay;clip 只使用上面的形状和羽化设置。
| 字段 | 类型 | 必填 | 默认 | 说明 |
|---|
opacity | number | | 100 | 覆盖强度百分比 |
color | string | | "#000000" | 纯色填充颜色 |
fillMode | string | | "solid" | solid / gradient / texture |
gradientStart / gradientEnd | string | | "#000000" / "#243247" | 渐变起始色 / 结束色 |
gradientDirection | number | | 0 | 渐变方向角度;0 为上到下,90 为左到右 |
texture | string | | "" | 纹理素材路径 |
textureFit | string | | "cover" | cover / contain / tile |
textureBlend | string | | "normal" | normal / multiply / screen / overlay |
textureScale / textureOpacity | number | | 100 / 100 | 纹理缩放 / 透明度百分比 |
blurEnabled / blurAmount | boolean / number | | false / 8 | 启用模糊 / 模糊强度(像素) |
vignetteEnabled / vignetteAmount / vignetteSize | boolean / number / number | | false / 35 / 55 | 启用暗角 / 强度 / 中心范围 |
noiseEnabled / noiseAmount / noiseSize | boolean / number / number | | false / 12 / 45 | 启用噪点 / 强度 / 颗粒尺寸 |
colorAdjustmentEnabled | boolean | | false | 是否启用调色 |
colorHue / colorSaturation / colorBrightness | number | | 0 / 100 / 100 | 色相角度 / 饱和度 / 亮度 |
enterDuration / exitDuration | number | | 1000 / 1000 | 淡入 / 淡出时长(毫秒);范围 0~60000 |
隐藏蒙层(遗留)
type: "hideStageMask"
此类型只用于读取旧工程。新剧本请使用 stageMask,把 action 设为 remove。
| 字段 | 类型 | 必填 | 默认 | 说明 |
|---|
maskId | string | | "" | 要移除的蒙层 ID;留空表示移除当前剧情创建的全部蒙层 |
exitDuration | number | | 1000 | 淡出时长(毫秒),0 表示立即移除 |
粒子效果
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: "loadingStrategy"
提前准备后续剧情资源,支持图片、序列帧、差分立绘、Spine 和 Live2D。策略持续到下一条加载策略或当前脚本运行周期结束。
| 字段 | 类型 | 默认 | 说明 |
|---|
mode | string | "auto" | auto 自动预测;manual 加载资源清单 |
lookahead | number | 20 | 自动模式检查后续 OP 数量,1–500。按运行时 OP 计数,不是编辑器 Block 数量;只扫描当前队列,不提前执行分支或跳转 |
execution | string | "background" | background 继续剧情并后台加载;wait 暂停脚本推进,等待加载完成 |
delayMs | number | 2000 | 等待模式显示加载界面前的延迟,0–60000 毫秒;0 表示立即显示 |
resourcesJson | string | "[]" | 手动资源清单的 JSON 数组字符串,格式如下 |
手动清单选择角色表情时使用 { "kind": "character", "characterId": "真实角色id", "expression": "真实表情名" },可加 skin 指定皮肤;选择场景使用 { "kind": "scene", "sceneId": "真实场景id" }。引用必须来自当前工程。角色表情会自动解析对应的静态或动态立绘资源及依赖,不需要手填模型文件路径。
{ "type": "loadingStrategy", "props": { "mode": "auto", "lookahead": 20, "execution": "wait", "delayMs": 2000, "resourcesJson": "[]" } }
等待从执行本 Block 时开始;2 秒是显示界面的阈值,不是放弃加载的超时。资源在阈值内准备好就直接继续,超出后显示默认游戏壳的 loading-screen,完成后关闭并继续。可以通过 internal.system.loading 系统槽位替换该界面。
默认界面使用“正在加载资源…”和“加载进度”智能组件;组件自动绑定只读系统变量 加载百分比(0–100)。普通文字也可写 {{加载百分比}}%。
进度按当前窗口去重后的已完成资源数统计,Spine / Live2D 在模型与依赖准备完成后计为完成,不代表下载字节比例或剩余时间;单个资源可能从 0% 直接到 100%。预测窗口变化时重新计算,停止后归零,不写入存档。
编辑画布可调整“预览百分比”检查外观,此示例值不会影响游戏运行。
后台失败会记录警告;等待模式失败会进入脚本错误处理。读档恢复不会重新等待已经跳过的手动预加载 Block。
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 | | "" | 说明文字 |
label | string | | "玩家姓名" | 文本输入框左侧标签 |
showLabel | boolean | | true | 是否显示文本输入框左侧标签 |
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: "openExternalUrl"
{ "type": "openExternalUrl", "props": { "url": "https://example.com" } }
| 字段 | 类型 | 必填 | 默认 | 说明 |
|---|
url | string | ✅ | "" | 完整 HTTP/HTTPS 地址;生成时换成实际目标网址 |
在外部浏览器打开网页;读档、跳转回放和快进不会打开。编辑器预览先显示提示,由作者点击打开;Debug 使用真实打开行为。
解锁 Steam 成就
type: "unlockSteamAchievement"
{ "type": "unlockSteamAchievement", "props": { "apiName": "ACH_FIRST_CHAPTER" } }
| 字段 | 类型 | 必填 | 默认 | 说明 |
|---|
apiName | string | ✅ | "" | Steamworks 已发布的成就 API 名称,区分大小写;示例名称必须换成实际配置 |
只在启用 Steam 的桌面导出游戏中生效;编辑器预览和读档重放不会解锁。它与本地成就扩展相互独立。
Steam 操作
type: "steamAction"
{
"type": "steamAction",
"props": { "action": "stat.add", "name": "CHAPTERS_READ", "value": "1" }
}
| 字段 | 类型 | 必填 | 默认 | 说明 |
|---|
action | string | ✅ | "presence.set" | presence.set / presence.clear / stat.set / stat.add / stat.get / achievement.progress / dlc.get / overlay.open / screenshot |
name | string | 按 action | "steam_display" | 状态键、统计 / 成就 API 名、DLC App ID;浮层使用 friends / community / achievements / store |
value | string | 按 action | "" | 状态值、统计数值、当前进度、商店 App ID 或截图说明 |
maximum | string | 进度操作 | "100" | 成就进度上限;当前进度必须小于上限,显示进度不会解锁成就 |
resultVariable | string | 查询操作 | "" | stat.get / dlc.get 写入的已声明变量;不可用时分别写入 0 / false |
仅导出的 Steam 桌面游戏生效,读档重放不提交。统计必须是 Steamworks 已发布的 INT 统计,DLC 查询同时检查拥有和安装状态。示例中的统计名需要替换成真实配置。
type: "comment"
正文放 content,只在编辑器里可见,不参与游戏编译,用于给剧本留备注。见手册:注释。
以上为当前内置剧本类型;animateSprite、hideStageMask 仅兼容旧数据。paragraph 是编辑器内部保留类型,cmdDraft 是纯文本模式临时输入态,两者都不要作为新剧本指令生成。扩展类型必须以工程已安装扩展的声明为准。
最小片段调用示例
保存为 chapters/片段调用示例.json,并在已有工程索引中登记同名章节。此例没有资源占位符:先执行“问候”片段,结束后回到 main 的下一条指令。目标写的是 frag-example-greeting,不能写片段名“问候”。
{
"id": "ch-example-call",
"name": "片段调用示例",
"fragments": [
{
"id": "frag-example-call-main",
"name": "main",
"blocks": [
{
"type": "callFragment",
"props": {
"fragmentId": "frag-example-greeting"
}
},
{
"type": "narration",
"props": {
"keepDialogue": false
},
"content": [
{
"type": "text",
"text": "已回到主片段,继续故事。",
"styles": {}
}
]
},
{
"type": "endChapter",
"props": {}
}
]
},
{
"id": "frag-example-greeting",
"name": "问候",
"blocks": [
{
"type": "narration",
"props": {
"keepDialogue": false
},
"content": [
{
"type": "text",
"text": "这是被调用片段中的旁白。",
"styles": {}
}
]
}
]
}
]
}
完整示例章节
一个小而全的章节文件,覆盖场景、音乐、对白、选项与片段跳转(片段 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 几条硬规则(也可以直接把下面这段一起复制过去):
- 只使用本页可创作的内置
type;禁止生成 animateSprite、hideStageMask、paragraph、cmdDraft。镜头使用 camera / stageAnimation,移除遮罩使用 stageMask 的 action: "remove"。
- 不要生成编辑器自动维护的字段:
voiceHash、isFirst、isLast、prevExpression、prevNameVariantId。
fragments[0] 必须命名为 main;branch / if / callFragment 的非空片段引用必须在同一章节里真实存在,且不能指向 main 或形成循环。字段明确允许空引用时,空字符串表示继续当前片段。
- 新建章节 id、片段 id 必须在工程内唯一;新建 Block 可省略
id。修改已有内容时保留原 id、元数据和未涉及的工程配置。
- 对白一句一个
dialogue,正文放 content,不要塞进 props。
- 对白自带立绘显示(
showCharacter 默认 true),不要在 dialogue 前额外加 showCharacter(那是重复调用);只有角色不说话就要登场时才用「角色登场」。
- 一段对话结束、后面不再有对白时(尤其接镜头动画、场景切换等演出),把最后一句
dialogue / narration 的 keepDialogue 设为 false,自动隐藏对话框。
生成的文件放进工程 chapters/ 目录(文件名 = 章节名),再把章节名加进 project.json 的 chapterOrder 数组,重新打开工程即可在 Studio 里看到并继续编辑。也可以只让 AI 生成 fragments 里的 blocks 内容,粘贴合并进现有章节文件,这样可以完全不碰 id 和索引。
生成后检查清单
- 整个输出能被
JSON.parse 解析;一个章节文件只有一个顶层对象,没有 Markdown 围栏、注释、尾逗号或省略号。
- 章节有
id、name、非空 fragments;每个 Fragment 有 id、name、数组 blocks,第一项名为 main。
- Block 的
type 大小写正确,props 是对象;台词使用 content 文本数组。无参数指令也写 props: {}。
- 真布尔 / 数字与字符串布尔 / 数字按字段表分别处理;
choices、conditions 等 JSON 字符串还要再解析一遍,确认内部结构正确。
- 所有非空片段引用在同章存在,目标不是
main,没有循环调用;所有资源、变量、扩展引用均来自提供的实体清单。
- 区分示例 id 与资源占位符:新章节 / 片段可以生成唯一 id;角色、场景、素材和扩展 id 不能编造。缺少信息时列出缺项,不输出假装能运行的占位引用。
- 文件名与章节名一致,登记
chapterOrder 并保持章节树排序一致;保留入口章节、原有 id 和其他工程配置。不要把索引片段覆盖为完整 project.json。
字段规范核对来源
本文按仓库中的以下定义核对。维护文档或编写生成器时,应同时核对结构、编辑器默认值和运行时读取逻辑,不能只根据旧示例推测:
src/studio/types/types.ts:磁盘 ChapterFile / FragmentData。
src/studio/types/project.ts、src/studio/shared/project-context.tsx:章节、片段结构及新建行为。
src/sdk/types/schema.ts:StoryBlock、片段元数据和调度事件配置边界。
src/studio/components/blocks/schema.ts、各指令组件的 propSchema:内置类型、可创作类型及默认参数。
src/studio/components/branch/branch-choice.ts、src/studio/components/blocks/if-condition.ts:选项、赋值与条件结构。
src/studio/components/preview/blocks-to-ops.ts:实际编译语义及缺省参数处理。
2.5.0:调整音量
type: "adjustVolume"。见调整音量。
| 字段 | 类型 | 默认 | 说明 |
|---|
scope | string | "track" | track 指定音轨;type 整类声音 |
soundType | string | "BGM" | BGM / SE / VOCAL |
soundId | string | "" | 指定音轨时与播放块 ID 一致;空值使用默认音轨 |
volume | string | "100" | 0~100 百分比;0 静音但不停止 |
fadeDuration | string | "0" | 渐变毫秒数,0~600000;剧情不等待渐变 |
{"type":"adjustVolume","props":{"scope":"type","soundType":"BGM","volume":"30","fadeDuration":"1000"}}
分类音量是当前及后续音轨的比例;指定音轨只调整该音轨当前播放。它们还会叠加项目与玩家音量。