更新点歌和弹幕微调

This commit is contained in:
2026-08-19 12:30:30 -07:00
parent a36d511d39
commit 845b0f5900
43 changed files with 1903 additions and 766 deletions
+1 -1
View File
@@ -51,7 +51,7 @@ flowchart LR
| 组件实例与设置 | PostgreSQL | `InMemoryComponentStore` | 写入成功后刷新热路径缓存 |
| 礼物/表情目录 | Bilibili API | provider catalog | 刷新失败保留最近成功快照 |
| 实时消息 | provider | `EventHub` 有界广播 | 不作为业务持久化机制 |
| 点歌队列和评分 | PostgreSQL | OBS revision snapshot | handler 事务写入、RLS 隔离 |
| 点歌队列与历史 | PostgreSQL | OBS revision snapshot | handler 事务写入、RLS 隔离 |
| 账户语言偏好 | PostgreSQL | React/OBS runtime | TOML 目录验证、RLS 隔离 |
| PWA 静态壳层 | Docker 镜像 | Cache Storage | 不包含 API 或用户数据 |
+4 -3
View File
@@ -1,7 +1,8 @@
# 组件开发指南
组件是“消费所属账户事件流的独立功能实例”。当前内建 `danmaku_overlay`、`song_request`、 `gift_effect`
与 `gift_menu`,未来礼物墙或统计组件也应使用同一套契约。
组件是“消费所属账户事件流的独立功能实例”。当前内建
`danmaku_overlay`、`song_request`、`gift_effect`、 `guard_effect` 与
`gift_menu`,未来礼物墙或统计组件也应使用同一套契约。
账户注册时会为每种内建 kind 创建一个初始实例。控制台可以为同一 kind 再创建多个命名实例;每个实例都有独立 settings、OBS
token、`publicId` 与 `EventHub`
@@ -63,4 +64,4 @@ Handler 面向“业务事实”。例如点歌请求、礼物累计或审计写
当前组件的具体行为见 [`danmaku-overlay.md`](danmaku-overlay.md) 与
[`song-request.md`](song-request.md)、[`gift-effect.md`](gift-effect.md) 与
[`gift-menu.md`](gift-menu.md)。
[`guard-effect.md`](guard-effect.md)、[`gift-menu.md`](gift-menu.md)。
+3 -1
View File
@@ -22,6 +22,7 @@
| `fontScale` | 50–300% | 展开与收缩字号的统一比例 |
| `decorationLineWeight` | 50–300% | 边框、分隔线与古风边缘粗细 |
| `maxVisible` | 1–12 | 同时保留的消息卡数量 |
| `expandNewDanmaku` | boolean | 新弹幕是否先展开并在超时后收缩 |
| `collapseAfterSeconds` | 2–120 秒 | 最新卡从展开态切换到紧凑态 |
| `unfoldDurationMs` | 200–5000 ms | 横向卷轴展开动画时间 |
| `motionIntensity` | 0–100% | 卡片、流光与焦点动画强度 |
@@ -54,7 +55,8 @@ WenKai 与漓雨手书。颜色覆盖同样只接受六位十六进制颜色;
## 卡片生命周期
1. 新事件追加在可视区域底部,以卷轴动画横向展开;旧事件被向上顶出并裁切。
1. 新事件追加在可视区域底部;启用 `expandNewDanmaku`
时,普通弹幕以卷轴动画横向展开,否则直接使用紧凑态。旧事件被向上顶出并裁切。
2. 用户名与内容在展开态分行显示,长内容完整换行。
3. 新事件到达或超时后,旧卡变成紧凑态;内容不会隐藏。
4. 紧凑态缩小字号并尽量压缩布局,但仍允许换行避免截断。
+7 -9
View File
@@ -1,9 +1,9 @@
# 全屏礼物特效组件
`gift_effect`
在账户注册时创建一个初始实例,并允许为不同 OBS 场景添加多个独立样式实例。每个实例消费账户级直播源中的
`live.gift` 和 `live.guard.buy`,使用自己的只读 token 作为透明 OBS 浏览器源;不订阅
`live.gift.combo`,避免一次连击重复触发完整特效。
在账户注册时创建一个初始实例,并允许为不同 OBS 场景添加多个独立样式实例。每个实例只消费账户级直播源中的
`live.gift`,使用自己的只读 token 作为透明 OBS 浏览器源;不订阅 `live.guard.buy` 或
`live.gift.combo`。大航海事件由独立的 [`guard_effect`](guard-effect.md) 组件处理。
## 展示行为
@@ -12,11 +12,10 @@
`highValueThreshold` 和 `featuredValueThreshold`
分为普通、高价、特别高价三档,每档分别设置流星数量、基准尺寸和飞行速度。图片加载失败时使用内置星光图形,不依赖外部主题素材。
舰长、提督或总督使用同一个 `live.guard.buy`
路径,临时显示不透明星河、闪耀粒子、身份和用户昵称。多个普通礼物可并发;大航海展示选择最新事件。
实时礼物进入浏览器内存中的有界 FIFO。画布始终只播放队首的一笔礼物,当前流星组、短笺或月下清供动画结束后才取出下一笔,因此密集投喂不会叠加特效或同时放大粒子负载。队列按事件到达顺序排列并去重,容量可在控制台设置;达到上限时保留正在播放及已等待的事件,忽略新到达事件。该视觉队列不写入数据库,OBS 断线重连后只接收新事件。
`moonlit-water`(“静夜曲水”)则采用“月下清供”:价值低于 50 元(原始
`totalPrice < 50000`)的礼物以右侧水纹短笺展示图标、用户、名称和价格;50 元及以上礼物在整张浏览器源上展开月轮、水纹、礼物图标和文字。舰长、提督、总督也使用全屏月夜祝贺。该主题的全屏动效仍不绘制不透明底色,OBS 场景始终可见。
`moonlit-water`(“静夜曲水”)采用“月下清供”:价值低于 50 元(原始
`totalPrice < 50000`)的礼物以右侧水纹短笺展示图标、用户、名称和价格;50 元及以上礼物在整张浏览器源上展开月轮、水纹、礼物图标和文字。该主题的全屏动效不绘制不透明底色,OBS 场景始终可见。
## 尺寸与性能
@@ -24,8 +23,7 @@ OBS 建议从 `1920×1080` 开始,但渲染器没有固定画布。`ResizeObse
按浏览器源实际宽高缩放流星,宽屏、竖屏或自定义分辨率都保持全视口透明。控制台可调整:
- 三档数量、尺寸和速度;
- 拖尾强度和最大并发特效数;
- 大航海星数和全屏持续时间;
- 拖尾强度和最大等待礼物数;
- 中文字体与文字亮度;
- 低性能模式(限制粒子和流星数量)。
+25
View File
@@ -0,0 +1,25 @@
# 大航海特效组件
`guard_effect`
是与礼物星雨完全独立的组件类型。账户注册或升级时创建一个初始实例,同一账户可以继续添加多个实例;每个实例分别拥有 settings、只读 OBS
token、`publicId` 和 WebSocket 广播通道。它只订阅 `live.guard.buy`,不接收普通礼物或连击事件。
从旧版本升级且账户尚无大航海组件时,服务会从最早的礼物特效实例复制主题、字体、星数、时长、性能模式及感谢文案作为初始设置。此后两个组件的设置互不关联。
## 青玉星落
舰长、提督或总督分别选择 `captain.webm`、`admiral.webm` 或 `general.webm`
全屏播放。视频约 8 秒,首尾各淡入/淡出 0.5 秒;第 4 秒开始在中央横向展开行书卷轴,依次显示可编辑的等级标题、开通或续费用户 UID,以及可编辑的收尾文字。标题模板可使用
`{guard}` 插入规范化的“舰长/提督/总督”,默认三行为“{guard}启航”、UID、“相伴前行”。
大航海事件进入浏览器内存中的有界 FIFO,当前约八秒的视频或月夜庆祝完整结束后才播放下一项,不会覆盖正在播放的用户。队列按事件到达顺序排列并去重,容量可在控制台设置;达到上限时保留正在播放及已等待的事件,忽略新到达事件。该视觉队列不持久化,OBS 断线重连后只接收新事件。
感谢文字固定使用 Rust 静态服务同域提供的鸿雷行书简体 WOFF2,不读取 OBS 机器的系统字体。该字体随源文件提供的说明不包含开放再分发许可,公开或商业部署前需由部署者确认相应的 Web 嵌入和再分发授权。
## 静夜曲水
静夜主题使用透明月轮、水纹、身份、观众昵称与星光庆祝。控制台可以调整中文字体、文字亮度、星光数量、全屏持续时间和低性能模式。它不会绘制不透明的全场底色。
## OBS 与预览
组件适配任意浏览器源尺寸,控制台提供舰长、提督和总督三个独立预览入口。OBS 地址与礼物星雨完全不同;场景需要两种特效时,应分别添加两个浏览器源。
+6 -6
View File
@@ -1,13 +1,13 @@
# `song_request` 点歌姬
每个账户自动拥有一个初始 `song_request`
实例,也可以再创建同类型的命名实例。每个实例拥有独立设置、OBS 地址、队列、评分和 revision,但共享账户的固定直播监听;删除实例会同时删除该实例的队列历史。组件只订阅规范化的
实例,也可以再创建同类型的命名实例。每个实例拥有独立设置、OBS 地址、队列、历史和 revision,但共享账户的固定直播监听;删除实例会同时删除该实例的队列历史。组件只订阅规范化的
`live.danmaku`;业务状态由 PostgreSQL 保存,不依赖 OBS 是否在线。
## 弹幕命令
- `点歌 <歌名>`:合并首尾和连续空白,接受 1–80 字自由文本。当前或待唱队列中已有大小写不敏感的同名歌曲时忽略。
- `打分 <1-5>`:对事务执行时的当前歌曲评分。同一 Bilibili UID 只有一票,重复评分会覆盖旧分数。
- `点歌<歌名>` 或
`点歌 <歌名>`:命令与歌名之间的空格可有可无;合并首尾和连续空白,接受 1–80 字自由文本。当前或待唱队列中已有大小写不敏感的同名歌曲时忽略。
首首点歌立即成为当前歌曲。完成或取消当前歌曲时,队首自动接替;置顶待唱项只把它移动为下一首,不打断当前歌曲。完成或取消后的歌名可以再次点播。
@@ -17,11 +17,11 @@
和 `edgePauseSeconds` 控制 OBS 外观与往返滚动。`maxQueueSize`、`maxRequestsPerViewer` 与
`requestCooldownSeconds` 是可选防刷限制;值 `0` 表示不限制。
`moonlit-water`(“静夜曲水”)与弹幕姬共享主题 ID:当前歌曲使用圆形音符、演唱状态、大号歌名、紧凑评分和弱化音频柱,待唱区按“点歌用户、歌名”两行显示。它不绘制卡片或面板背景,只用米金文字、青色微光、共享的上下古风细边和一条弱分隔线建立层级。用户和歌名颜色均可覆盖主题默认值。
`moonlit-water`(“静夜曲水”)与弹幕姬共享主题 ID:当前歌曲使用圆形音符、演唱状态、大号歌名和弱化音频柱,待唱区按“点歌用户、歌名”两行显示。它不绘制卡片或面板背景,只用米金文字、青色微光、共享的上下古风细边和一条弱分隔线建立层级。用户和歌名颜色均可覆盖主题默认值。
## OBS 与管理
OBS 顶部固定显示当前歌曲、点歌用户、平均分和评分人数,下面保存全部待唱横条。列表超过实际浏览器源高度时从顶部滚到底部,再返回顶部;布局不假设固定分辨率。
OBS 顶部固定显示当前歌曲和点歌用户,下面保存全部待唱横条。列表超过实际浏览器源高度时从顶部滚到底部,再返回顶部;布局不假设固定分辨率。
控制台的“打开点歌统计”进入会话保护页面。它每两秒刷新完整活动队列和近期历史;页面隐藏时停止轮询。管理者可以置顶或取消待唱项,也可以完成、取消当前歌曲,或在确认后一次性将全部活动歌曲标记为已取消。清空操作保留历史与评分,并以一个 revision 原子广播。所有 REST 查询都从会话取得 owner,并由 PostgreSQL
控制台的“打开点歌统计”进入会话保护页面。它每两秒刷新完整活动队列和近期历史;页面隐藏时停止轮询。管理者可以置顶或取消待唱项,也可以完成、取消当前歌曲,或在确认后一次性将全部活动歌曲标记为已取消。清空操作保留历史,并以一个 revision 原子广播。所有 REST 查询都从会话取得 owner,并由 PostgreSQL
RLS 再次限制组件归属。
+11 -4
View File
@@ -50,7 +50,8 @@ close 结束连接。
`component.language.updated`,payload 为 `{ "language": "en-US" }`;新连接以认证帧为准。
设置快照中的 `themeId` 是稳定的主题标识。弹幕姬与点歌姬支持 `jade-scroll` 和
`moonlit-water`;礼物特效支持 `jade-starfall` 和 `moonlit-water`;礼物菜单支持 `jade-banquet` 和
`moonlit-water`;礼物特效与大航海特效分别支持 `jade-starfall` 和 `moonlit-water`;礼物菜单支持
`jade-banquet` 和
`moonlit-water`。消费者应把未知主题降级为自身默认主题,不能因主题发布顺序不同而中断实时消息。
## 版本化事件信封
@@ -105,8 +106,8 @@ close 结束连接。
3. `song.queue.snapshot.end`:提交该快照。
后续 `song.queue.changed` 携带连续 revision,`operation` 为 `added`、`promoted`、
`completed`、`cancelled`、`cleared` 或
`rating-updated`。客户端发现 revision 缺口必须重连取得新快照,不能猜测缺失队列状态。 `cleared`
`completed`、`cancelled` 或
`cleared`。客户端发现 revision 缺口必须重连取得新快照,不能猜测缺失队列状态。 `cleared`
表示当前歌曲与全部待唱项已在同一事务中取消,客户端必须立即清空活动投影。
礼物目录价格的原始单位是人民币的千分之一。`gift.totalPrice` 保留该整数单位,`gift.priceCny`
@@ -115,11 +116,17 @@ close 结束连接。
`live.gift` 与 `live.gift.combo` 不是两笔礼物。需要持久化计数的组件通常只消费
`live.gift`;连击事件用于更新同一张视觉卡片。
`gift_effect` 只订阅 `live.gift` 与 `live.guard.buy`。礼物档位由 sanitized settings 中的
`gift_effect` 只订阅 `live.gift`,不会收到 `live.guard.buy`。礼物档位由 sanitized settings 中的
`highValueThreshold` 和 `featuredValueThreshold` 决定;浏览器使用 `gift.imageUrl` 或
`gift.animationUrl`
作为流星主体,图片失效时必须使用本地星光占位。该组件不维护状态快照,重连后只展示新到达的实时事件。
`guard_effect` 只订阅
`live.guard.buy`。舰长、提督和总督事件进入该组件独立的广播通道;它不接收普通礼物或礼物连击,也不维护状态快照。
`gift_effect` 与 `guard_effect`
的浏览器渲染器分别维护有界 FIFO,并且每次只播放一个 active 特效。动画完成后按到达顺序推进下一项;这个队列仅用于 OBS 视觉节流,不是可靠业务队列,也不会在重连后恢复。
`gift_menu` 同样只消费一次性 `live.gift` 与 `live.guard.buy`。命中配置后投影为
`gift-menu.triggered`,payload 包含 `itemIds`、`viewer` 和
`sourceEventId`。一个特定礼物和一个同价电池规则可以同时命中多个菜单项;客户端应全部高亮,并滚动到第一个匹配项。未命中的投喂不会进入该组件通道。