Files
opendance-web/tasks/013-bone-rebinding.md
T
zijunchiang 3738bd91b9 release(v0.7.1): 契约 websocket-keypoints 0.2.0 + 补齐场景规格与任务文档
契约变更(T-WEB-016,与 Android T-AND-011「两端一起改」配套)
- websocket-keypoints 0.1.0 -> 0.2.0,均为向后兼容(子协议名与二进制帧
  version 均不变,只新增可选控制字段与一种新控制类型):
  1.1 保活:接收端必须声明 silentTimeoutMs 与 heartbeatIntervalMs,且心跳必须
      小于静默超时的一半。根因是客户端只能用 OkHttp 的协议层 ping,而它由
      底层库自动应答、**不暴露给应用层**,接收端根本看不到,无法续命;
  3.1 hello.deviceId(该安装实例的稳定标识,不使用任何硬件序列号);
  3.2/3.3 welcome/config 携带保活字段;
  3.6 应用层 ping/pong(回显 sentAtMs,pong 另带 serverAtMs 供算 RTT);
  5   设备去重:同一 deviceId 只保留最新连接,旧连接以 1000 关闭
      (刻意用 1000:对端据 §7 不会重连,否则形成"挤掉-重连-再挤掉"循环);
  7   关闭码与重连策略:1000/1001/1002 与主动停止不重连,其余重连;
  7.1 退避参数冻结:min(500ms*2^(n-1), 15000ms) + ±20% 抖动;
  8   连接状态机(两端同名,日志可直接对照)。
- contracts/VERSION 与 src/config/contract-versions.ts 同步到 0.2.0。

补齐 rest-api.yaml 漏写的场景结构(只补规格,不改线格式,版本号不变)
- CatalogBundle 增加 scenes[](标注 0.5.0 起下发);
- 新增 Scene / SceneConfig / Vec3 schemas。catalog/export 自 v0.7.0 起就返回
  scenes[],data-models 7 也已冻结,但规格漏写会让两端对字段边界
  (如 0~1、±200)的理解不一致。

deploy/proxy/README.md 新增第九节:Gitea 站点的附件上传上限
- 与一~五节的 Web 服务反代是**两个不同站点**;实测 30.5 MB / 40 MB 上传返回
  HTTP 413,根因是 IIS 默认 maxAllowedContentLength = 30,000,000 字节;
- 给出放宽到 256 MB 的 IIS / ARR / Gitea app.ini / nginx 四处配置与复验命令;
- 这解释了 Windows 端 v0.1.0 为何被拆成 zip.part0/1/2(交付缺陷)。

文档与脚本
- 补齐 tasks/011~016 与 project.yaml 条目(T-WEB-011~015 此前已在代码中落地
  却缺任务说明书);project.yaml 的 contracts_version 由单个 0.4.0 改为六项字典;
- scripts/package-release.sh 的版本号改为从 web-server/package.json 读取
  (与 GET /health 的 version、管理端左下角展示同源),并与 project.yaml 交叉校验;
  同时补上 SHA256SUMS 与自校验(此前是手工生成的)。

验证:npm run verify 通过(contracts:check 六项一致 + 35 条路由一致、
typecheck、246 项测试、nest build);产物 opendance-web-v0.7.1.tar.gz
sha256 27f92cfb125bbcf29077d4ad90c44720cbca46d23ddef12cd7826d73bd8865e2。
2026-09-17 01:30:41 +08:00

43 lines
1.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# T-WEB-013 动作内部标准与模型骨骼重绑定
- **状态**: done
- **依赖**: T-WEB-006 / T-WEB-012
- **文档**: v1.6 §4.10
- **契约**: `skeleton-topology 0.2.0`、`data-models 0.7.0`
## 目标
1. **动作内部标准**:所有动作(BVH / VMD / FBX / glTF)统一预处理成
MediaPipe 33 点关键点序列(`mediapipe33@0.1.0`),客户端只认这一种;
2. **模型骨骼重绑定**:任意命名风格的模型都能被关键点驱动 —— 按**名字**映射到
canonical humanoid 骨骼,而不是要求模型符合某一种命名规范。
## 方案
### 动作内部标准
`preprocess.service.ts` 按扩展名分派解析器,统一产出 NDJSON 关键点序列 +
9 个关节角特征(108 维),与 Android 端推流结构完全同构 —— 因此客户端
DTW 的两侧输入是同一套特征。
### 骨骼重绑定
| 项 | 做法 |
|--|--|
| 归一化 | `normalizeBoneName()`:保留 CJK 与假名(**不能再只留 `a-z0-9`**),全角 ASCII 折叠(`足IK` → `足ik`) |
| 候选表 | `HUMANOID_CANDIDATES` 覆盖 VRM/VRoid、Mixamo、MMD 日文名、中文常见名 |
| 生成而非手写 | Godot 端 `src/model/humanoid_map.gd` 的 CANDIDATES **由服务端表生成**,并有跨端一致性测试 |
| 覆盖度 | `coverage()` / `missing_bones()` 暴露给审核界面与客户端 |
> **踩坑记录**:第一版 `normalizeBoneName()` 只保留 `[a-z0-9]`,把 CJK 名字
> 整个抹成空串,导致 MMD 模型 humanoid 覆盖 **0/22**。修复后实测
> 奥黛塔 **21/22**、初音未来 **19/22**,两者 `drivable = true` 且 VRM 正常产出。
## 验收
| 验收项 | 结果 |
|--|--|
| MMD(日文骨骼名)模型可驱动 | ✅ 实测 21/22、19/22 覆盖;客户端可正常驱动 |
| Godot 端候选表与服务端一致 | ✅ 一致性测试(跨仓库生成 + 校验) |
| 动作统一为 33 点 | ✅ `keypoint_format = mediapipe33@0.1.0`;Android 端推流同构 |