角色与台词着色

声明角色之后,台词行按说话人着色——两种标注写法、自动配色、简称,以及只要颜色不要名字的开关。

对话多了,读者会分不清谁在说话。在项目根放一份 characters.json 声明角色,正文里在台词行开头标出说话人,阅读时那一行就按角色着色。

{
  "克里斯托弗": {},
  "阿黎娅": { "color": "#7fb3d5" }
}
=== 序章 ===
雾散了,港口露出轮廓。

<克里斯托弗> 我今天出门了。
阿黎娅:外面在下雨。
<克里斯托弗> 那我带伞。

他们没再说话。

三句台词各按说话人着色,两句旁白是正文色。

两种标注写法

写法 例子
尖括号 <克里斯托弗> 我今天出门了。
冒号 阿黎娅:外面在下雨。(半角 : 同样认)

两种形状完全不同、识别时互不干扰,同一个作品里随便混用

几条边界:

  • 只有声明过的名字才触发。 正文里的「他说:」「时间:三点二十」一概是普通正文——冒号没有获得任何新含义,也不需要新的转义规则。
  • 标注只在行首生效,且尖括号必须紧包名字:< 名字><名字 > 都不算。
  • 多个角色名有前缀包含关系时(同时声明了「林」和「林然」),冒号写法取最长匹配
  • 匹配成功时整行着色(包括标记本身);你自己写的 <color=…> 优先,不会被角色色盖掉。
  • 着色作用于正文、选项文本、@panel 固定区域三处——对话式的选项 <克里斯托弗> 那我跟你走 同样着色。

和内置标签的边界

<名字>内联富文本标签同形。解析器遇到不认识的标签名按字面输出、也不报诊断,所以角色名的尖括号安全地留在正文里。

唯一的冲突面是角色名恰好等于内置标签名

名字 <名字> 台词 的后果
br / pause(自闭合标签) 被解析成那个标签,该行不着色;无诊断,作品照常读
b / i / u / s(成对标签) 被解析成一个未闭合的标签:该行不着色,且校验期报 error

两种情况的冒号写法都正常着色。编辑器对这几个名字会给提示。

角色表的形状

有两种合法写法,判据是顶层有没有 characters

只声明角色时用扁平映射(上面那份就是)。需要作品级选项时分两层:

{
  "options": { "showNames": false },
  "characters": {
    "大虎":   { "color": "red", "abbr": "DH" },
    "阿黎娅": { "color": "#7fb3d5" }
  }
}

因此 charactersoptions保留名,不能拿来当角色名——一个叫「characters」的角色会把整份文件判成两层形状。

角色的键是角色名,值是对象,两个可选字段:

字段 说明
color 任意 CSS 颜色;不写就自动分配(见下)
abbr 简称,与全名完全等价地参与匹配(见下)

作品级选项目前只有一个:

字段 默认 说明
showNames true 台词行首的说话人标记是否呈现给读者

名字有两条限制:不能含 < > : 与换行;不能是纯数字。后者是 JSON 本身的性质——整数形态的键在对象里一律排到最前、按数值升序,「键的先后就是声明顺序」这条约定在它们身上不成立,自动配色的槽位也就跟着乱。要给编号角色命名,写成「7 号」「机器人 7」这类即可。

颜色

不写 color 的角色由播放层自动分配:明度取自当前主题的正文色、色相取八个固定槽位之一,按声明顺序取槽,第九个角色起循环复用。

这样换主题(含作者自定义底色)时每个角色的颜色都自动保持可读,而加一个角色不会让已有角色全部改色——只有调整声明顺序才会。角色超过八个又想要更多区分,给超出的那些显式写 color

简称

声明了 abbr 的角色,正文里用简称标注与用全名完全等价。显示时归一到全名——作者少打字,读者读到的始终是角色的正式名字:

原文 读者看到(showNames: true
<DH> 喵呜呜~ <大虎> 喵呜呜~
DH:喵呜呜~ 大虎:喵呜呜~

冲突怎么判:某个串既是甲的全名、又是乙的简称时判给甲;两个角色撞同一个简称时,声明顺序靠前的那个生效(编辑器会提示)。

简称越短越容易与普通正文撞上。 DH: 出现在正文里的概率远高于「大虎:」,选串时自己掂量。上面那张「与内置标签冲突」的名单同样适用于简称,而 ASCII 简称正好写成 b / i / u / s / br / pause 的概率,比中文全名高得多。

只要颜色,不要名字

showNames 为假时,匹配成功的那一行整个标记连同其后至多一个空格一并不呈现,读者只看到彩色的台词本身:

原文 showNames: true showNames: false
<大虎> 喵呜呜~ <大虎> 喵呜呜~ 喵呜呜~
大虎:喵呜呜~ 大虎:喵呜呜~ 喵呜呜~

吃掉那一个空格是必要的——不吃的话每行台词都会平白缩进一格。标记后没有空格时不多吃,未匹配的行一字不动。

showNames: false 下误匹配的代价比着色大得多。 隐藏同样作用于正文、选项、面板三处:面板里写 林:3、而作品恰好有个叫「林」的角色时,读者看到的是 3。这是选名字与选简称时要掂量的事。

写坏了会怎样

  • 文件缺失 = 没有角色声明,全部正文色。
  • 文件不是合法 JSON、或某一条的值形状不对 → 该文件(或该条)当作没有,作品照常读
  • options 不是对象、或 showNames 不是布尔 → 该选项当作没写、回落默认。

着色是锦上添花,任何情况下都不该让作品打不开。

着色、标记隐藏与简称归一都是呈现层的派生物,不进存档——存档里始终是你写的原文。用不用这些功能,存档都同样可读。

在编辑器里改

不用手写 JSON:文件 → 作品角色… 可以增删角色、调整配色。

接下来

最后一篇语言文档讲整个阅读页的外观——作品外观