For the complete documentation index, see llms.txt. This page is also available as Markdown.

RUN_DESIGN 文本格式指南

本指南描述一种简洁、便于人手编辑的交互故事文本格式(RUN_DESIGN)

RUN_DESIGN 文本格式指南

本指南描述一种简洁、便于人手编辑的交互故事文本格式(RUN_DESIGN)。同时支持可逆转换:JSON → RUN_DESIGN → JSON,在支持的字段范围内不会有语义流失。

目标

  • 简单、可读、利于版本控管的文本格式

  • 能编译成 JSON 的故事结构

  • 能将 JSON 无语义差异地导出回文本

文件编码

  • UTF-8

空白与注解(Whitespace & Comments)

  • 允许空白行。

  • // 开头的单行为注解,编译时会被忽略。请另开新行。

顶层元数据(Metadata)

  • [meta] title "<Title>" 设置故事标题

  • [meta] author "<Author>" 设置作者(必填;导入/更新时若缺少会被拒绝)

  • [intro] <text> 追加一行故事导言(可重复多行),在剧本开始时会显示。

显示行为:

  • .st list 中:

    • 指定 alias 时,会完整显示该故事的导言(若有)。

    • 列出所有可启动剧本时,会在每列标题下显示导言第一行的预览(最多 80 字)。

  • .st mylist 中:

    • 每项剧本会显示导言第一行的预览(最多 80 字)。

  • 在启动游戏后且玩家变量尚未完成设置时:

    • 角色设置提示前会先显示【简介】区块,内容为导言全文。

范例:

玩家变量(Player Variables)

  • [player_var] <key> "<prompt>" ["<placeholder>"]

    • key:识别字,例如 cat_name

    • prompt:显示给玩家的提问

    • placeholder:可选的提示文本

范例:

游戏属性(Game Stats)

  • [stat_def] <key> <min> <max> ["<label>"]

  • 初始化:未被明确设置时,首次开始时以 min~max 随机整数初始化。

  • 锁定:若该属性曾被内容内的 [set] 明确指定,之后将不再被随机初始化覆写。

范例:

变量(Variables)

  • [var_def] <key> <min> <max> ["<label>"]

范例:

页面(Pages)

故事由多个页面组成。

  • 定义页面标签(ID):[label] <id>

    • 限制:页面 ID 只能使用数字(如 0, 1, 2, 10 等)

    • 开点页面[label] 0 为故事的起始页面,游戏开始时会自动加载此页面

    • 其他页面可使用任意数字作为 ID,建议使用连续数字以保持可读性

  • 可选页面标题:[title] <text>

  • 页面内容(不限行数):

    • [text] <content>

    • [text|if=<expr>] <content> 条件显示

    • [text|else] <content> 与前一或多个连续的 [text|if=...] 形成条件链,只会显示第一个符合条件的项目;若皆不符合则显示 else。也支持于结局区块中使用。

    • [text|ifs=<expr>] <content> 独立条件显示:只要命中就显示,不会与上下邻近的 [text|if=...]/[text|else] 形成条件链。

    • [text|speaker=<key>] <content> 指定说话者

    • [text|speaker=<key>,if=<expr>] <content> 指定说话者且具条件

    • [random] <percent>% 仅影响「下一行」的 [text](例如 30%),percent 为 0~100 的整数。

    • [set] <key>=<expr> 在渲染时设置值:若 key 属于已定义的 stat_def,则写入 stats;否则写入 variables<expr> 支持基本表达式(见下文)。

      • 任一属性一旦被 [set] 明确设置,之后将不再由随机初始化覆写。

    • 文本内可直接掷骰:{xDy} 会在显示时掷骰并以总和取代,例如 {1D100}{2d20}{3d6}

  • 结局标记:

    • [ending] 之后的 [text] 行视为结局文本,会使用第一个符合条件的结局

    • 支持条件链:可使用多行 [text|if=...] 后接一行 [text|else] 作为后备

    • 要求:一个有效的 RUN_DESIGN 必须至少包含一个带有 [ending] 标记的页面;若未定义结局,上传/更新将被拒绝。

  • 选项区块:

    • [choice] 开始定义选项列表

    • -> <text> | <页面代号> [| if=<expr>] [| stat=a+1,b-2]

      • <页面代号> 必须为数字页面 ID,或使用带字母尾码的变体(例如 2a2b2c);或特殊值 END

      • 新功能:支持 2a, 2b, 2c 等格式,其中数字部分(如 2)为实际跳转的页面,字母部分(如 a, b, c)仅用于区分不同的加成或描述变体(实际跳转到 2)。

      • <页面代号>END 时,接口会提供「.st end」按钮以结束游戏。

      • stat= 仅支持整数加减,并在成功前往该选项之目标页面时套用(例:Cuteness+1,Energy-2)。

新功能:多选项同页面跳转

使用 2a, 2b, 2c 等格式可以让多个选项都跳转到同一个页面(如页面 2),但每个选项可以有不同的加成效果:

当玩家使用 .st goto 2a.st goto 2b.st goto 2c 时:

  • 都会跳转到页面 2

  • 但会分别获得不同的加成:淘气度+1、萌度+1、活力+1

表达式(Expressions)

  • 条件以小型、类 JS 的子集合为语法,运行于 scope(variables + stats + playerVariables

  • 支持操作符:&& || ! < <= > >= == === != !== + - * / % ()

  • 安全限制:不允许任何函数调用;不可访问 globalThisglobalprocessthisFunctionconstructorrequire 等识别字。

    • 范例:if=Cuteness>=8 && Energy>3

  • 支持一元否定 !expr(可搭配括号以控制优先级)。

    • 范例:if=(Strength>5) && !(Agility>5)

掷骰(Dice)

  • 在条件与赋值表达式中,可直接使用 xDy 字面量,会在运算前掷骰并以总和值替换,例如:

    • if=2d20>25

    • [set] luck=3d6+2

    • 允许的范围:x 1100、y 110000;超出将被夹在此范围内。

条件赋值(Conditional Set)

  • 支持在 [set] 上使用条件选项:[set|if=<expr>] key=<expr>

  • 结合掷骰,可实作常见的检定流程。

范例:

范例页面(Example Page)

结局页(Ending Page)

占位符(Placeholders)

  • [text] 内使用 {key} 会依序从 playerVariablesstatsvariables 取值并套入(优先级如前,后者可覆盖前者)。

  • 若找不到对应键,将保留原样(例如 {unknown_key} 会原样输出)。

注:兼容性与限制补充

  • 目前不支持以纯字符串作为页面 ID;请使用数字页面 ID(例如 0, 1, 2)。

  • [set] 行允许在值的后方加上行尾 // 注解,导入时该注解会被忽略,不影响赋值内容。

往返转换(Round Trip)

  • 导入文本(于 Discord 夹带文件):发送 .st import <alias> [title] 并附上 .txt(RUN_DESIGN)或 .json 文件

  • 更新既有剧本:.st update <alias> [title] 并附上新文件

  • 导出文本:.st exportfile <alias>(机器人将以私讯发送文本档)

  • 验证可逆:.st verify <alias>

范式(Normalization)

  • 编译器会将紧邻的 [random] 与其后的第一行 [text] 合并解释为「几率显示」。

  • 导出时,若页面是结局页,[ending] 会紧跟在该页 [label] 之下,以维持可逆性。

惯例(Conventions)

  • 开点页面[label] 0 为故事的起始页面,游戏开始时会自动加载此页面。若需要可在编译后的 JSON 再行设置。

  • 页面 ID 限制:只能使用数字作为页面 ID。

  • 说话者为可选;示例采用纯文本。

  • 若需在内文中加入随机性,请于欲影响的 [text] 之前「紧贴」放置 [random] <percent>%(percent 为整数)。

  • 若需在选项上改变属性值,使用 stat=a+1,b-2(仅支持整数加减)。

  • 若需多个选项跳转到同一页面但有不同的加成效果,使用 2a, 2b, 2c 等格式。

最佳实务(Best Practices)

  • 为可读性建议使用数字且连续的 ID

  • 条件判断尽量简单并以已定义的键为基础

  • 避免过长的行;可拆分成多个 [text]

  • 确保每个结局页面都提供重新开始或结束的选项

  • 善用 2a, 2b, 2c 格式来创建有不同加成的选项

限制(Limits)

  • 最多页数:400

  • 每段文本(每一行 [text],包含结局文本)最长 500 字

  • 至少需包含一个带有 [ending] 的页面

  • 导入/更新之附件大小上限:约 1 MB

  • 页面 ID 只能使用数字

更多范例(More Examples)

说话者(Speakers)与条件链

说话者为可选字段,渲染时仅作为数据字段保存,不影响文本输出。

随机显示(Random)

[random] <percent>% 仅作用于其后第一行 [text],编译器在导出时会保持可逆性。

内嵌掷骰(Dice)与条件检定

在表达式中可使用 xDy 字面量;在文本中可用 {xDy} 直接内嵌掷骰,显示总和。

条件赋值(Conditional Set)与字符串值

RHS 以引号包装时会被视为字符串常值;否则会尝试以表达式求值。

多个选项同页面跳转(带加成)

玩家输入 .st goto 2a/2b/2c 皆会抵达页面 2,但各自套用不同的加成。

独立条件显示(ifs)

使用 ifs[text] 不会与相邻的 if/else 形成条件链,命中就显示,可同时出现多行。

结局区块的条件链

结局的多行 [text|if=...] 与一行 [text|else] 形成条件链,仅显示第一个符合条件者;可在其上方书写无条件前言文本。

占位符的优先级与嵌套

{key} 查找顺序为 playerVariablesstatsvariables。字符串值内若再包含 {...},会进行一次嵌套展开。

最后更新于