Lattice 语法参考 · 第 2 章,共 4 章
Block、内容与线性流转
Block 是流转能直接指向的最小段落。它把创作元数据、可见内容、可选连续性批注和恰好一个流转终结语句组合在一起。
Block 声明
block opening (
title: "警告",
purpose: setup,
summary: { 玛拉找到了信号源。 },
setup: [signal_arc],
tags: [opening]
) {
text: { 一束光从花园地下苏醒。 };
next -> answer;
}每个 Block 必须同时满足以下规则:
- ID 在所有导入文件中保持唯一;
- 必须有
title和purpose; - 至少包含一条可见的
text或dialogue; - 内容条目写在终结语句之前;
- 恰好有一个终结语句,并且所选故事类型与当前位置允许它;
- 所有目标都存在,并留在主故事或当前 Module 内。
Block 元数据
| 字段 | 必填 | 接受的值 | 含义 |
|---|---|---|---|
title | 是 | 文本 | 面向读者/作者的段落标题 |
purpose | 是 | 目的标识符 | Block 的叙事功能 |
summary | 否 | 文本 | 简短的作者侧摘要 |
prose_target | 否 | 正整数 | 可重新分配的局部创作预算 |
setup | 否 | 标记 ID 列表 | 引入叙事承诺 |
requires | 否 | 标记 ID 列表 | 期待此前已有铺垫 |
resolves | 否 | 标记 ID 列表 | 回收此前的铺垫 |
tags | 否 | 文本或列表 | 创作分类 |
prose_target 要求 Story 已经声明完整的正文目标。它用于引导渐进创作,但不会独立决定 Block 是否有效。
purpose 接受以下值:
| 值 | 常见用途 |
|---|---|
setup | 建立角色、处境、问题或承诺 |
exposition | 提供读者需要的背景 |
development | 推进已经建立的线索 |
transition | 在地点、时间或阶段之间移动 |
turn | 改变事件方向或意义 |
climax | 通过决定性行动解决核心压力 |
resolution | 展示核心冲突之后的结果 |
payoff | 兑现此前承诺的揭示、后果或情感回报 |
这些值服务于校验和创作工具,但不会创建流转。
叙述
叙述由 text、冒号、正文值和分号组成:
text: {
车站时钟始终分秒不差。
玛拉看着秒针越过午夜。
};一个 Block 可以按阅读顺序包含多条叙述与 Dialogue。
text: { 铁轨开始低鸣。 };
dialogue ch_mara: { 那列车早到了一天。 };
text: { 站台上没有人回头回答。 };text 是可见内容。发布校验会拒绝只有批注或流转、没有正文和对白的 Block。大纲校验会暂时允许这种结构,以便在创作正文前检查最终 Block 图、摘要、预算和连续性关系。预览和导出绝不会用作者侧摘要代替缺失的读者正文。
Dialogue 对白
声明形态是 dialogue <character-id> (<metadata>): <prose>;。
dialogue ch_mara (
mode: whisper,
emotion: cautious,
expression: focused,
pose: listening,
position: left,
stage_direction: { 她俯身贴近土壤。 }
): { 别再来了。 };说话者必须引用已声明的 character。所有 Dialogue 元数据都是可选项。
| 字段 | 接受的值 | 含义 |
|---|---|---|
mode | speech、thought、whisper、shout | 说话方式 |
position | left、center、right | 阅读器中的展示位置 |
emotion | 标识符 | 面向素材的情绪状态 |
expression | 标识符 | 面向素材的面部表情 |
pose | 标识符 | 面向素材的身体姿势 |
stage_direction | 文本 | 独立动作或舞台提示 |
展示字段会保留到预览/导出,但不会改变 Block 流转、Guard 或运行时 State。缺少素材也不会创建故事分支。
轻量连续性标记
Block 元数据可以描述铺垫和回收,而不增加运行时逻辑:
block warning (
title: "警告",
purpose: setup,
setup: [signal_arc]
) {
text: { 每当玛拉朝向北方,钥匙就会搏动。 };
next -> crossing;
}
block crossing (
title: "穿越",
purpose: development,
requires: [signal_arc]
) {
text: { 她相信那阵搏动,踏进雾里。 };
next -> answer;
}
block answer (
title: "答案",
purpose: payoff,
resolves: [signal_arc]
) {
text: { 搏动拼出了她自己的名字。 };
end;
}setup引入一个标记。requires表示这个 Block 期待标记此前已经出现。resolves表示这个 Block 回收该标记。
标记 ID 是创作事实,不是声明的 State。它不能让 Module 变得可用、满足 Pool 退出条件,也不能记住普通玩家选择。
结构化连续性事件
结构化批注写在叙述和 Dialogue 之间:
foreshadowing fs_signal: event {
subject: ch_mara,
object: it_key,
predicate: notices,
time: "黎明之前"
};
reveals rv_signal resolves fs_signal: event {
subject: ch_mara,
object: it_key,
predicate: understands,
time: "午夜"
};foreshadowing 有自己的 ID。reveals 也有自己的 ID,并指出它回收哪条 foreshadowing。
事件必须包含 subject 和 predicate;object、place、time 为可选字段。事件值可以是标识符、字符串、数字或布尔值。这些批注只描述叙事证据。即使它的元组形态与 CYOA State 相似,也绝不会激活或移除 State。
流转终结语句
每个 Block 恰好以以下一种形态结束:
| 终结语句 | 形态 | 可以使用的位置 |
|---|---|---|
| 自动继续 | next -> target; | 线性与 CYOA;同故事或 Module |
| 结局 | end; | 线性与 CYOA;结束整个故事 |
| 玩家选择 | choice { option ... } | CYOA;同故事或 Module |
| 进入 Pool | enter pool_id -> resume; | 仅 CYOA 主故事 |
| 完成 Module | complete (...); | 仅 CYOA Module |
不存在隐式顺序执行。文件或 Scene 里的下一个 Block 不会自动运行,除非终结语句明确指向它。
线性故事规则
线性故事只允许 next 和 end:
next -> answer;end;它会拒绝 choice、enter、complete、predicate、state、state group、pool、module 和 story.initial_state,即使这些声明本身能通过语法解析。
Story 入口必须开始一条有限链:
entry -> block -> block -> ... -> 唯一结局完整校验会拒绝:
- 指向入口的边;
- 没有恰好一条入边的非入口 Block;
- 分叉或合流;
- 不可达/孤立 Block;
- 循环;
- 没有结局或存在多个结局。
完整线性示例
story main (
title: "信号花园",
language: "zh-CN",
format: novel,
entry: opening,
beat_order: [opening, resolution]
);
entity character ch_mara (name: "玛拉", role: protagonist);
entity location loc_garden (name: "信号花园");
scene garden (
title: "花园",
beat: opening,
pov: ch_mara,
location: loc_garden
) {
block opening (
title: "警告",
purpose: setup,
setup: [signal_arc]
) {
text: { 一束光从花园地下苏醒。 };
dialogue ch_mara (
mode: whisper,
emotion: cautious
): { 别再来了。 };
next -> answer;
}
block answer (
title: "答案",
purpose: resolution,
resolves: [signal_arc]
) {
text: { 她循着光回到家。 };
end;
}
}声明顺序让源码便于浏览,但只有 entry、next 和 end 定义阅读顺序。新增 Block 却没有把它连接进链,会产生不可达 Block。
Beat 顺序不是 Block 流转
story.beat_order 为 Scene beat 元数据提供预期顺序。在受支持的校验路径中,它能诊断缺失、未知或乱序的 beat,但绝不会连接 Block。把线性故事拆到多个文件时,既要保留预期节拍顺序,也要保留显式 Block 目标。
