状态栏、思维链、可点选项:美化这门手艺,搬进手机
美化是中文酒馆社区最有生命力的手艺:状态栏、可折叠思维链、主题化聊天皮肤,全靠正则和 HTML 搭出来。但这套生态默认长在桌面浏览器里。这封信写给美化创作者:你的卡在 Foreverse 手机端怎么渲染、marker→正则→WebView 三段链路各自的规矩、哪些桌面习惯会翻车、以及美化代码为什么不吃你的 token。

写这封信的起因,是测试期一位美化作者发来的问题:「我的状态栏在桌面酒馆是活的,到你们这变成一坨源代码,为什么?」排查完发现是 marker 写成了 HTML 标签的形状,导入净化把它剥了。问题本身五分钟解决,但它暴露了一件事:美化这门手艺的全部隐性知识都长在桌面浏览器的土壤里,搬进手机,规矩得重新讲一遍。这篇就是那份规矩,写给做美化包的你。
先对齐一个共识:美化为什么值得认真对待
美化不是装饰。一张带状态栏的卡,把好感度、时间、地点这些隐性状态显性化,玩家不用在脑子里维护游戏状态;可折叠的思维链让长回复有了目录;主题化皮肤让一张卡有自己的视觉人格。中文社区把这门手艺卷出了惊人的高度,小红书上一套精致的美化包能拿几千赞。这些创作理应在手机上被完整渲染,而不是降级成纯文本。
三段链路,各自的规矩
整卡美化在 Foreverse 里走的链路和桌面同构:
| 环节 | 发生了什么 | 规矩 |
|---|---|---|
| 模型输出 marker | 每轮回复带纯文本标记,如 [状态|开心|85] 或 :::think | marker 必须是纯文本符号,不能长成 <tag>(导入净化会剥生 HTML) |
| 正则替换 | 卡内美化正则把 marker 替换成主题化 HTML | 设 placement 作用于 AI 输出 + markdownOnly 只在显示期跑,不污染回喂历史 |
| WebView 渲染 | 替换产物进沙箱 WebView,按作者样式渲染 | 自包含 HTML+CSS;每个围栏独立作用域;高度自动回报撑开气泡 |
第二行的 markdownOnly 值得单独强调:它是「美化代码不吃 token」的开关。模型看到的历史永远是干净的 marker,你的几百行 HTML 只活在显示层。同样一张卡,把 HTML 直接写进开场白的做法(社区早期常见)每轮都在烧上下文,走正则链路则一个 token 都不多花。
移动沙箱:哪些桌面习惯会翻车
WebView 的能力清单里,最重要的是三条禁令和一条兜底。禁外部资源:CDN 上的 jQuery、远程字体、外链图片统统加载不出来,所有资源必须内联。禁撑满视口: min-height: 100vh 这类样式在自动高度回报机制下会把气泡撑到荒谬的高度。禁访问本地文件系统。兜底是:正则把内容替换成空的时候回退显示原文,不会白屏——你的 bug 最多让美化失效,不会吞掉正文。
能力侧也交代清楚:内联 CSS 和 JS 都跑;宿主 API 支持常用子集(triggerSlash、getChatMessages、getWorldbook、 generate() 真实触发二次生成),可点选项和按钮菜单能做;每个 html 围栏一个独立作用域,两个组件的样式互不打架。
不想写正则的人,有一条现成的路
除了整卡美化链路,还有两个低门槛协议:一个是 fv-card 原生小卡(围栏里放 JSON,App 原生渲染小纸条、倒数日、心情卡三型,连 WebView 都不过);一个是 [[sticker:名字]] 贴纸协议,从角色目录取同名图片。给伴侣做表情包、给卡做纪念日提醒,这两个协议五分钟上手。
写在最后
美化生态的价值在创作者手里,平台的本分是把渲染语义做稳、把规矩写清楚。这篇覆盖了日常创作会撞到的 90%;剩下的 10%(正则捕获组的边界、宏展开时机、TavernHelper API 的完整清单)在美化规范文档里逐条列了表。你调好的卡在手机上渲染不对,把卡和截图发到 [email protected],我们按 P1 排查——这不是客套话,渲染一致性就是这条产品线的验收标准。
常见问题
桌面酒馆调好的美化卡,在手机上能直接用吗?
目标是行为一致:卡带 HTML 美化正则时,导入会自动打开这张卡的富渲染开关,marker→正则→HTML 的链路和桌面同构。会翻车的主要是两类桌面习惯:引用外部资源(CDN 上的 jQuery、远程字体、外链图片)在移动沙箱里一律加载不出来;依赖整页浏览器环境的脚本(操作父页面 DOM)没有对应物。自包含的 HTML+CSS 卡基本无痛。
美化代码会吃掉我的上下文 token 吗?
不会,这是链路设计的关键点。模型每轮输出的只是纯文本 marker(比如 [状态|心情|好感]这样的短标记),几十个 token;几百行的 HTML 模板放在正则的替换串里,只在显示期生效。配合 markdownOnly 设置,替换结果不会写回喂给模型的历史——模型永远只看到干净的 marker,你的 HTML 一个 token 都不占。
为什么我的 marker 不能写成 HTML 标签的样子?
因为导入净化。角色卡文本字段里的生 HTML 标签会在导入期被剥掉(这是对不可信卡内容的安全处理),marker 如果长成 <status> 这样就活不到渲染那一步。规矩是:marker 用纯文本符号(:::think、[状态|…] 这类),HTML 只出现在正则的替换串里。
手机上能做可点击的交互美化吗?
能。WebView 里支持宿主 API 的常用子集:triggerSlash 可以执行 /setinput、/send、/trigger 这类命令,getChatMessages 能读消息,generate() 能真实触发二次生成——可点选项、按钮菜单这类交互组件都能落地。细节按钮和链接默认禁用文本选择,点选项不会误选中文字。
有想法或问题?来 Discord 聊聊 →