语言指南 · Story DSL v1
把故事写成可读的源码
Lattice 是 TypeApe 的声明式故事语言。它同时记录可读正文与正文周围的精确结构,因此同一个项目既能编辑,也能校验和体验。
故事身份与项目元数据
段落一个可阅读的叙事单元
文本写在花括号里的正文
流转显式连接,绝不依赖文件顺序
使用完整语法参考
本页负责建立语言心智模型。需要查精确声明形态、允许值、所有权规则或错误修复方式时,使用以下四章:
- 源码文件与声明——导入、注释、分隔符、标识符、字符串、正文、元数据、Story 字段、实体和 Scene。
- Block 与线性流转——所有 Block 字段与 purpose、叙述、Dialogue 展示、连续性批注、终结语句和完整线性约束。
- CYOA 语法参考——选择、Predicate 模式、落地 State、Group、初始 State、Guard、Pool、Module、Effect 和穷举运行时规则。
- 校验与诊断——parse 与 validate 的区别、错误恢复、引用错误、软锁、运行时循环、警告,以及校验能做什么、不能做什么。
TypeApe 当前读写 Story DSL v1。规则不成立时,诊断会指向相关源码,并说明需要修复什么。
文件、导入与值
配置的入口文件是项目根。使用带引号的相对路径拆分项目:
# main.la
use "./story/characters.la";
use "./story/opening.la";载入所有导入后,项目只能有一个 story 声明。导入必须留在项目内,不能形成循环,也不能重复载入同一个文件。
Lattice 只使用少数几种值:
| 形式 | 示例 | 含义 |
|---|---|---|
| 标识符 | opening、ch_mara | 稳定 ID 与引用 |
| 字符串 | "zh-CN" | 精确的带引号文本 |
| 正文 | { 一束光苏醒。 } | 可包含换行的叙事文本 |
| 列表 | [opening, resolution] | 有序元数据值 |
| 布尔值 / 数字 | true、3 | 扩展或事件允许的字面量 |
注释以 # 开始。导入、没有主体的声明、内容条目和流转语句都以分号结束。元数据属性用逗号分隔。自定义元数据键必须以 x_ 开始;它会被保留,但不会改变内置行为。
Story、实体与场景
Story 声明确定阅读入口和项目格式:
story main (
title: "信号花园",
language: "zh-CN",
format: novel,
entry: opening,
prose_unit: non_whitespace_graphemes,
prose_scope: authored_body,
prose_minimum: 4500,
prose_target: 5000,
prose_maximum: 5500,
beat_order: [opening, midpoint, resolution]
);title、带引号的 language、format 和 entry 为必填项。initial_state 只适用于 CYOA。
可选的正文目标用于持久记录创作要求。prose_unit、prose_scope 和 prose_target 必须一起声明。word_like 统计类单词单元;中文“字数”请求适合使用 non_whitespace_graphemes。可选的最小值和最大值必须包含目标值。
实体为角色、地点和物品提供稳定身份:
entity character ch_mara (
name: "玛拉",
role: protagonist,
traits: [observant, stubborn]
);
entity location loc_garden (name: "信号花园");
entity item it_key (name: "信号钥匙");场景组织叙事语境。pov 必须引用角色,location 必须引用地点:
scene garden (
title: "花园",
beat: opening,
pov: ch_mara,
location: loc_garden,
prose_target: 1200
) {
# Block 写在这里。
}Block、正文与对白
Block 是流转能直接寻址的最小段落。达到发布就绪时,它需要全局唯一 ID、标题、叙事目的、可见内容,以及恰好一个结束流转。在大纲阶段,正文可以暂时为空,同时检查稳定 ID、摘要、流转和可选的正文预算。
block opening (
title: "警告",
purpose: setup,
summary: { 玛拉找到了信号源。 },
prose_target: 500,
setup: [signal_arc]
) {
text: {
一束光从花园地下苏醒。
};
dialogue ch_mara (
mode: whisper,
emotion: cautious,
stage_direction: { 她俯身贴近土壤。 }
): { 别再来了。 };
next -> answer;
}对白说话者必须是已经声明的角色。mode 可以是 speech、thought、whisper 或 shout;位置、情绪、表情、姿势和舞台提示都是可选的展示元数据。
叙事连续性批注
setup、requires 和 resolves 标记轻量的叙事承诺。它们帮助校验铺垫与回收,但不会创建路径,也不会改变 CYOA State。
结构化事件可以留下更丰富的创作证据:
foreshadowing fs_signal: event {
subject: ch_mara,
object: it_key,
predicate: notices
};
reveals rv_signal resolves fs_signal: event {
subject: ch_mara,
object: it_key,
predicate: understands
};线性故事流转
每个线性 Block 都以一次自动继续或一个结局结束:
next -> target_block;end;配置的入口必须沿一条无分支、无环的链到达唯一结局。线性故事会拒绝选择、合流、孤立 Block、循环、State、Pool 和 Module。
CYOA 选择与结局
CYOA 可以分支,也可以合流。普通选择至少有两个选项:
choice {
option inspect_key: { 检查钥匙 } -> inspect;
option leave_garden: { 离开花园 } -> departure;
}选项标签描述读者能理解的意图。选择会改变路径拓扑,但不会自动记住读者选了什么。后续规则如果依赖这个决定,应把它建模为已经声明的有限 State。
有限 State
CYOA State 有意保持有限和封闭:没有脚本、变量、计数器、随机数或任意表达式。
先声明 Predicate 模式,再声明一个完全落地的 State:
predicate knows (subject: character, object: item);
state st_knows_signal (title: "已经理解信号"): event {
subject: ch_mara,
object: it_key,
predicate: knows
};不属于组的 State 是永久标记,用 add 激活。State Group 是互斥插槽,用 set 切换成员:
state group location (
members: [st_location_gate, st_location_garden]
);Guard 使用 State ID 列表:
requires:列出的 State 必须全部激活。requires_any:至少有一个列出的 State 激活。forbids:列出的 State 必须全部未激活。
Pool 与 Floating Module
Pool 会暂停主路径,并展示符合条件、只能完成一次的 Module。只有退出 Guard 成立后,主路径才会继续。
pool investigation (
title: "调查花园",
exit_requires: [st_knows_signal]
);
scene garden (title: "花园") {
block arrival (title: "抵达", purpose: setup) {
text: { 埋藏的钥匙在玛拉手下搏动。 };
enter investigation -> departure;
}
}Module 只属于一个 Pool,不能跳到主故事或其他 Module:
module md_decode (
title: "解读钥匙",
pool: investigation,
entry: decode,
forbids: [st_knows_signal]
) {
scene decoding (title: "埋藏的编码") {
block decode (title: "解读", purpose: development) {
text: { 光芒逐渐显现为一串耐心的序列。 };
complete (add: [st_knows_signal]);
}
}
}进入 Pool 以及每次完成 Module 后,TypeApe 都会先检查退出条件,再展示仍符合条件的未完成 Module。如果退出为假且没有 Module 可用,故事会发生软锁,校验也会失败。
解析、检查、校验、体验
每完成一组连贯源码修改,都按相同顺序检查:
- 解析配置的入口。
先修复语法与导入诊断,再解释后续阶段。 - 校验并检查大纲。
正文尚未完成时,检查结构、创作契约、精确正文进度和最大的局部缺口。 - 按发布标准校验。
恢复可见内容要求,修复所有错误,并根据预期体验判断每一条警告。 - 阅读受影响的路径。
一张有效的图仍然可能偏离创作意图。
除非身份本身必须改变,否则应保留稳定 ID。TypeApe 报错时,应修复真正的源码问题,而不是用 x_ 元数据隐藏错误。
下一篇:阅读完整的源码与声明参考。
