界面包格式
这是界面包的参考。界面包是世界、故事或你的角色扮演目录中的 ui/<包>/ 文件夹。
包文件夹
文件夹名就是包的 id:字母、数字、- 和 _,以字母或数字开头,最长 60 个字符。文件夹中必须有 pack.json。
| 限制 | 值 |
|---|---|
| 一个包的文件数 | 200 |
| 一个包的大小 | 5 MB |
| 单个文件大小 | 1 MB |
| 文件夹深度 | 4 |
| 文件和文件夹名 | 字母、数字、-、_ 和 .,不能以点开头 |
| 文件类型 | html、css、js、json、txt、png、jpg、jpeg、webp、gif、avif、svg、woff、woff2、ttf、otf、mp3、ogg、wav |
符号链接、其他文件类型以及不符合上述规则的名称都算问题。有任何问题的包不会被使用,每个问题都会指出所在文件。
pack.json
{
"name": "Atlas",
"version": "0.1",
"description": "状态条和地图标签页。",
"api": 1,
"theme": { "--dsw-alias-brand-primary": { "light": "#8a3b12", "dark": "#e0a36b" } },
"skin": "skin.css",
"actions": ["say", "fill", "choose"],
"surfaces": {
"hud": { "file": "hud.html", "height": 48 },
"tab": { "file": "map.html", "title": "Atlas" }
}
}
| 字段 | 含义 |
|---|---|
name | 设置中显示的名称。缺省为文件夹名。 |
version、description | 写给人看的自由文本。 |
api | 包所针对的桥接版本。只有 1;其他数字算问题。 |
theme | 要替换的颜色令牌。名称必须以 --dsw-alias- 开头,每个值给出 light 和 dark 两个普通 CSS 颜色(不含 url(、var(、;、{、} 或 @import,最长 120 个字符)。 |
skin | 包内的一个 .css 文件。见皮肤。 |
actions | 包的页面可以执行的操作:say、fill、choose(为玩家执行)和 open(显示包自己的标签页或侧栏页面)。未列出的会被拒绝。默认没有。 |
surfaces | 按位置列出的页面:hud、dock、opening、backdrop、tab、sidebar。未知位置算问题。 |
页面写作 { "file": "page.html", "title": "...", "height": 48 }。file 必须是包内的 .html 文件。title 是 tab 页面的无障碍名称,也是 sidebar 页面在引导入口和细栏中的名称,缺省为包名;标签页本身在 DSH 的标签栏中始终显示为 界面。height 是条带的初始高度(像素)。
页面位置
| 页面 | 显示位置 | 高度 |
|---|---|---|
hud | 回合操作、建议行动和输入框上方的一条。 | 24–320 px,默认 56 |
dock | 紧靠输入框上方、建议行动下方的一条。 | 24–320 px,默认 48 |
opening | 在条带位置显示的卡片,只在第一个回合播放之前、且没有回合正在运行时显示。回退到开头后会再次出现。 | 120–640 px,默认 320 |
backdrop | 聊天中文字后面的一层。它不接收点击。其下部会被 DSH 输入框上方自带的渐隐遮住。 | 聊天区域 |
tab | 聊天旁的标签页,标签显示为 界面。 | 标签页 |
sidebar | 右侧栏中的页面,从其引导页进入,上方有带返回按钮的细栏。隐藏时仍保持运行。 | 侧栏的其余部分 |
只要世界、故事或你的角色扮演目录中有包声明了标签页 ,就会提供该标签页;新增的标签页需要刷新页面才会被发现。条带和开场卡片用 rp.resize 申请别的高度,超出范围的高度会被调整到范围内。如果聊天的结构不是背景所期望的(例如 DSH 升级之后),背景会被跳过,并在浏览器控制台留下一条说明;其他部分不受影响。
皮肤
皮肤改变故事自身元素的样式。包被使用期间它应用于页面,并随包一起移除。
元素
data-rp | 元素 |
|---|---|
narration | 一个已送达的回合 |
prose | 一段叙述 |
utterance | 一句台词 |
avatar、speaker、words | 台词的各部分 |
ooc | 一条游戏外说明 |
suggestions、suggestion | 建议行动条及其中一条 |
turns | 回合操作:重新生成、回退、分支 |
hud、dock、opening、backdrop、tab、sidebar | 容纳包自身页面的框架 |
规则
- 顶层只允许样式规则、
@media、@supports、@keyframes和@font-face(最后一个只能在顶层)。其他一切,如@import、@namespace、@container和@page,都会被拒绝。 - 每个选择器的每一部分都必须用
[data-rp="..."]指明上述元素之一。body、:root、单独的类选择器或元素选择器、:not([data-rp])和嵌套都会被拒绝。 url()只能用相对路径指向包内文件。带协议的地址、绝对路径、data:地址、image-set()和expression()都会被拒绝。字符串之外的反斜杠转义会被拒绝。- 有任何问题的皮肤会整体被拒绝,问题会带有行号。
属性不受过滤:皮肤可以隐藏或移动它所指明的元素。
框架
每个页面都显示在一个没有自己来源的框架里。它的脚本会运行,并且:
- 它无法访问 DSH 页面、你的登录状态、Cookie 或存储,也不能打开窗口、提交表单或让页面跳转。
- 它只能加载和获取自己那个包的文件:样式表、脚本、图片、字体、声音、数据文件、worker。对其他任何地方(包括 DSH 服务器自己的 API)的普通
fetch和资源加载都会失败。 - 在这些限制之内,它不受约束。canvas、WebGL、WebAudio、worker(包括来自 blob 的)、WebAssembly 和
eval都可用,所以包可以带上自己的库,绘制或计算任何它想要的东西。 - 框架仍可自行跳转到别的地址。浏览器没有已支持的 CSP 指令能阻止自行跳转,因此恶意界面包可以把故事数据放进该地址。界面包属于受信任的输入:启用之前请检查其代码和来源。
宿主随每个包文件发送的策略是 sandbox allow-scripts,加上 default-src 'none'; script-src 'self' 'unsafe-inline' 'unsafe-eval' 'wasm-unsafe-eval'; worker-src 'self' blob:; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; font-src 'self' data:; media-src 'self' data: blob:; connect-src 'self'; frame-src 'self'; form-action 'none'; base-uri 'self'。隔离来自缺失的来源、资源加载指令和狭窄的桥接接口;它不会让恶意的界面包代码变得安全。
脚本运行之前,宿主会先把 rp 对象放进页面。框架加载的内容(<script src>、<link>、图片、fetch)按相对地址从包自己的文件夹提供。
DSH 的颜色以 CSS 变量提供给框架,框架的根元素带有 data-rp-scheme="light" 或 "dark":
--dsw-alias-bg-base、--dsw-alias-bg-layer-1、--dsw-alias-bg-layer-2、--dsw-alias-bg-overlay、--dsw-alias-border-l1 到 -l4、--dsw-alias-brand-primary、--dsw-alias-label-primary、--dsw-alias-label-secondary、--dsw-alias-label-tertiary、--dsw-alias-link、--dsw-alias-state-business-primary、--dsw-alias-state-error-primary、--dsw-alias-state-idle-primary、--dsw-alias-state-success-primary、--dsw-alias-state-warn-primary、--dsw-radius-sm。