# 礼物特效
[English](./gift-effects.md) | [中文](./gift-effects.zh-CN.md)
礼物特效:把礼物动画叠在对话区上,并飘出一条送礼提示弹幕。总开关默认关闭,**素材入库即可用**——不需要先绑定任何礼物。
## 总览
礼物特效由三层组成:
- **素材库**——本地素材库(SVG / SVGA / 图片),带文件夹、权重与 manifest,落在 `$DSH_HOME/danmaku-gifts/`。
- **礼物目录**——B 站礼物清单(名称 / ID / 价格 / 图标),用于左列选择;内置一份离线目录,也可用你自己的房间号提取合并。
- **特效位置**——把「礼物」对应到一张素材卡,设置落点;触发时播放动画并叠加一条提示弹幕。
礼物特效与弹幕渲染共用同一覆盖层:特效在独立的 `.dsh-gift-layer` 上播放,不拦截鼠标事件;提示弹幕走普通弹幕轨道。
新装首次启动会播种 **3 张默认礼物卡**(礼物目录随包内置、离线可用;但导入每张卡的动画素材需要联网,离线时会跳过 —— 即 0 卡,可稍后手动重试):
| 礼物 | ID | 卡权重(= 触发概率系数) |
|---|---|---|
| 牛哇牛哇 | 31225 | 0.7 |
| 人气票 | 34391 | 1 |
| 干杯 | 31116 | 0.2 |
## 入口
设置 → 插件 → 插件配置 →「弹幕 Live Chat」卡片,滚到 **礼物** 区段:
- **启用礼物特效**(`giftEnabled`)——礼物模块**自身**的总开关,**默认关闭**;插件总开关(`enabled`)关闭时礼物模块同样停摆。
- **打开礼物配置…**——唯一的入口按钮,打开大模态(左礼物库 + 中素材库 + 右配置)。
也可在设置左侧导航点「礼物」Tab(紧跟在「弹幕库」之后)。大模态 `min(1280px, 96vw)` × `min(760px, 88vh)`,横向三栏:
- **左栏(礼物库)**——顶部一行:**搜索框在左**、**单个分类下拉在右**(点开一个浮窗,父级 bilibili / 自定义与 bilibili 的金瓜子 / 银瓜子子级同在其中);下方是清单;bilibili 行是「+」/红色「×」,自定义行只有红色「×」(删除素材)(248px 起,200–400)。
- **中栏(素材库)**——本地素材面板,顶部一行工具条,下方是自适应素材网格。
- **右栏(配置)**——特效位置 / 基础 / 测试三段(300px 起,240–420)。
两条栏间分界线**可以拖动**改宽窄;宽度写入本地存储(键 `dsh-gift-pane-layout-v1`),**刷新页面、重开窗口、重启 dsh 后都保持**。没有右侧锚点导航条,也不再是单页四段。
## 素材库(中栏面板)
中栏是本地素材库主界面,顶部一行工具条,下方是素材网格:
- **工具条**——房间号输入框(**无标签**,仅占位符提示)+「提取」|「导入文件…」+「▾」|「图标大小」|「新建文件夹」|「清空素材」。
- **导入文件…**——选择文件导入(走 file input)。
- **▾ 下拉菜单**——三项:粘贴 SVG 代码 / GitHub 导入… / 导入 zip…。「粘贴 SVG 代码」与「GitHub 导入…」点击后弹出**居中文本输入框模态**(确定即导入):SVG 是多行文本框,GitHub 是仓库地址 + 导入上限(0 = 不限)。
- **图标大小**——点击在按钮下方展开浮窗(滑块 + 数字输入框,0.6–1.6,默认 1),实时缩放素材网格里**文件夹卡与素材卡**的尺寸(列宽与卡片高度按倍率计算);点击浮窗外部即收起,倍率写入本地存储(键 `dsh-gift-icon-scale-v1`),刷新/重启后保持。
- **卡片密度自适应**——素材以网格卡片铺开,每行数量随中栏宽度自动增减(窄屏更少、宽屏更多),卡片填满格宽。
- **循环缩略图**——SVG 缩略图每个共享 tick(3 秒)重挂一次,让一次性 CSS 动画循环重播、不再停在空白;动图(gif/apng/webp)本身就会循环,保持静态 `
`(不再周期性重解码);png/jpg 保持静态,SVGA 用类型徽标 + 悬停预览。
- **卡权重 = 触发概率**——每张卡的「权重」(0–100)就是它在加权抽签里的概率系数;权重 0 表示永不触发。
支持的扩展名:`.svg`、`.svga`、`.gif`、`.apng`、`.webp`、`.png`、`.jpg`。单文件大小上限 `giftMaxAssetMB`(默认 8 MB,可调 1–64)。导入是**任务制**:上传接口返回任务对象,前端轮询 `/api/danmaku/gift/assets/import/status` 显示进度。素材文件落在 `$DSH_HOME/danmaku-gifts/files/`,清单为同目录 `manifest.json`;服务走 `GET /api/danmaku/gift/file?id=`(支持 Range / ETag / immutable 缓存)。
> [!NOTE]
> 礼物素材是**用户资产**:卸载插件时不会自动删除;「清空素材」按钮需二次确认。
左列礼物行的状态**只由素材库派生**:某礼物存在 `source === 'gift:'` 的素材卡时显示**红色「×」**,否则显示**「+」**。点「+」→ Host 走白名单抓取(`importGift`)导入该礼物动画为一张卡,成功即变「×」;点「×」删除对应素材卡,该行**回落为「+」**(无二次确认)。没有素材卡的礼物在**库外不会触发**——抽签只从**素材库**里「有卡且有正权重」的素材中选。
## 礼物目录与房间号提取
礼物清单默认读 `$DSH_HOME/danmaku-gifts/catalog.json`;不存在时从包内 `assets/gift-catalog.json` 播种一份(离线可用)。
要**用自己的房间**礼物清单合并进目录:
1. 在中栏工具条的房间号输入框填号——**房间号由你本人填写**,仓库与文档里一律用占位符,例如 `<你的房间号>`。
2. 点「提取」。空输入 → 只弹提示、**不发任何请求**。
行为约定:
- 提取 = **合并去重**:把实时礼物配置映射后**并入当前目录**(保留已有条目,新增缺失的),而非整体替换;响应回 `{added, skipped}`,二次点击同一房间号 `added` 为 0。
- 提取成功 → 弹「新增 X / 跳过 Y」并刷新左列;失败 → 只弹 toast,**不写文件**、不回显房间号。
- 映射只读白名单字段,原始响应里的房间标识(`room_id` / `uid` 等)**不会**进入清单,也不会进日志(日志只打印数量摘要)。
## 礼物库:搜索 + 单分类下拉
左栏顶部一行是两个控件:**搜索框在左**(按名称 / ID 过滤,占满剩余宽度),**分类下拉在右**。下拉按钮显示当前选择 + 「▾」(如 `bilibili ▾` / `金瓜子 ▾` / `自定义 ▾`),点击展开**同一个浮窗**,父子两级都在里面:
- **bilibili**——顶层项,代表整个 bilibili 来源;其下按目录中首次出现顺序列出瓜子类型(金瓜子 / 银瓜子),点某一子项只显示该瓜子类型。
- **自定义**——叶子项,没有子级;列出素材库里非礼物来源的素材。
选中任一项后浮窗关闭、列表立即刷新(翻页回到第一页);点击浮窗外部也会收起。浮窗向下展开、右对齐到下拉控件,不会横出左栏。不再有悬停展开的子菜单,也没有 `