Creator docs
Beautify Spec
This is the mechanics reference for Foreverse chat beautify: what a single message can contain (HTML / fv-card / stickers), how the full-card beautify rendering pipeline works, and where the regex engine stops. Every entry matches real app behavior, so cards written against this spec render immediately after import.
Quick start
Fastest path: send the prompt below to any AI, ask it to generate beautify code for you, then place the result in a character card greeting or message to test the render.
请生成一段用于聊天气泡的自包含 HTML + 内联 <style>。
需求:紫色渐变主题的状态栏卡片,白色描边,圆角,顶部一行标题。
约束:不要引用外部资源(图片/字体/JS 库都不行);不要用 min-height: 100vh;
所有样式写在一个 <style> 里;宽度自适应容器。Put the full generated result inside a ```html fence when sending it. Foreverse will render that message with the built-in WebView using your styles. "Don't reference external resources" is not a suggestion; it's a sandbox rule. See below.
Single-message syntax
An AI reply is split into segments in order, and each segment is rendered by the syntax it matches:
| Syntax | Rendered as | Notes |
|---|---|---|
```html … ``` | Rich WebView render | Full HTML/CSS renders as the author intended; each fence gets an isolated iframe scope and reports its height automatically |
| Bare HTML block | Rich WebView render | Without a fence, paired <div> / <section> / <style> / <table> / <svg> / <details> / <center> tags also go through WebView |
```fv-card … ``` | Native mini card | The fence contains JSON. It doesn't use WebView; the app renders it natively. Fields are listed below |
[[sticker:name]] | Sticker image | Name length <= 40 characters; loads the same-name image from this companion's stickers/ folder and falls back to a text badge if missing |
| Other text | Plain bubble | Rendered with basic markdown syntax |
fv-card fields (v1 · three types)
| Field | Type | Notes |
|---|---|---|
type | string | note (small note) / countdown (countdown date) / mood (mood card); unknown values render as note for forward compatibility |
title | string | Card title; title or body must have at least one non-empty value, or the card won't render |
body | string | Body text, optional |
date | string | Used by countdown, yyyy-MM-dd; the app calculates "N days left / today / N days ago" automatically |
emoji | string | Used by mood cards |
accent | string | Accent color #RRGGBB; when empty, the current character accent color is used |
```fv-card
{ "type": "countdown", "title": "见面纪念日", "date": "2026-08-14", "accent": "#8b5cf6" }
```Full-card beautify pipeline (status bars / chain of thought / clickable options)
To make the model output themed status bars, collapsible chain-of-thought blocks, or clickable options every turn, use the same three-stage pipeline as desktop Tavern:
模型输出纯文本 marker → 卡内美化正则替换成主题化 HTML → WebView 渲染Three hard rules. Break any one and it won't render:
- Markers must be plain text symbols (such as
:::think,[状态|…],:::scene,:::note,:::opt). Don't use<tag>as a marker. Import-time cleanup strips raw HTML from card text fields. HTML is only allowed in the regexreplaceString. - Beautify regex rules should set
placement: [2](AI output) andmarkdownOnly: true(run only at display time, without polluting the history sent back to the model). - When a card includes an HTML beautify regex, import automatically turns on rich rendering for that card. Users don't need to set it manually.
Regex rules
| Feature | Support |
|---|---|
| Capture group references | $1–$99, $<name>, {{match}} |
| Variable-length loops / recursive replacement | Not supported. Components such as status bars need a fixed number of fields (demo cards use 4 fixed fields) |
| Scope | placement controls whether it applies to user input / AI output; markdownOnly controls display-only replacement without rewriting history sent back to the model |
| Safety fallback | If a regex replaces content with empty text, the original text is shown instead. No blank screen |
WebView features and limits
Rich-render WebView matches desktop Tavern rendering semantics while running inside a mobile sandbox. Capability list:
| Item | Behavior |
|---|---|
| Inline CSS / JS | Supported; each html fence gets its own isolated iframe scope |
| Height | Automatically reports scrollHeight to expand the bubble; don't use viewport-filling styles such as min-height: 100vh |
| External resources | Blocked: file / content access is disabled, remote JS libraries such as jQuery CDN are unavailable; external-link taps are handed to the system browser |
| TavernHelper host API | Supports triggerSlash (/setinput, /send, /trigger, and so on), getChatMessages, getCurrentMessageId, getWorldbook; generate() / generateRaw() can trigger real second-pass generation |
| Clickable options | Options / buttons / links disable text selection while body text can still be selected. Tapping an option won't accidentally select text |
| Sensitive information | Content shaped like token: value is redacted to *** before entering model context |
The goal is for beautified cards tuned on desktop to behave the same on phone. If you hit a rendering difference, send the card and screenshots to [email protected], and we'll treat it as P1.