角色与台词着色
声明角色之后,台词行按说话人着色——两种标注写法、自动配色、简称,以及只要颜色不要名字的开关。
对话多了,读者会分不清谁在说话。在项目根放一份 characters.json 声明角色,正文里在台词行开头标出说话人,阅读时那一行就按角色着色。
{
"克里斯托弗": {},
"阿黎娅": { "color": "#7fb3d5" }
}
=== 序章 ===
雾散了,港口露出轮廓。
<克里斯托弗> 我今天出门了。
阿黎娅:外面在下雨。
<克里斯托弗> 那我带伞。
他们没再说话。
三句台词各按说话人着色,两句旁白是正文色。
两种标注写法
| 写法 | 例子 |
|---|---|
| 尖括号 | <克里斯托弗> 我今天出门了。 |
| 冒号 | 阿黎娅:外面在下雨。(半角 : 同样认) |
两种形状完全不同、识别时互不干扰,同一个作品里随便混用。
几条边界:
- 只有声明过的名字才触发。 正文里的「他说:」「时间:三点二十」一概是普通正文——冒号没有获得任何新含义,也不需要新的转义规则。
- 标注只在行首生效,且尖括号必须紧包名字:
< 名字>和<名字 >都不算。 - 多个角色名有前缀包含关系时(同时声明了「林」和「林然」),冒号写法取最长匹配。
- 匹配成功时整行着色(包括标记本身);你自己写的
<color=…>优先,不会被角色色盖掉。 - 着色作用于正文、选项文本、
@panel固定区域三处——对话式的选项<克里斯托弗> 那我跟你走同样着色。
和内置标签的边界
<名字> 与内联富文本标签同形。解析器遇到不认识的标签名按字面输出、也不报诊断,所以角色名的尖括号安全地留在正文里。
唯一的冲突面是角色名恰好等于内置标签名:
| 名字 | 写 <名字> 台词 的后果 |
|---|---|
br / pause(自闭合标签) |
被解析成那个标签,该行不着色;无诊断,作品照常读 |
b / i / u / s(成对标签) |
被解析成一个未闭合的标签:该行不着色,且校验期报 error |
两种情况的冒号写法都正常着色。编辑器对这几个名字会给提示。
角色表的形状
有两种合法写法,判据是顶层有没有 characters 键。
只声明角色时用扁平映射(上面那份就是)。需要作品级选项时分两层:
{
"options": { "showNames": false },
"characters": {
"大虎": { "color": "red", "abbr": "DH" },
"阿黎娅": { "color": "#7fb3d5" }
}
}
因此 characters 与 options 是保留名,不能拿来当角色名——一个叫「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:文件 → 作品角色… 可以增删角色、调整配色。
接下来
最后一篇语言文档讲整个阅读页的外观——作品外观。