-
released this
2026-09-18 03:03:50 +08:00 | 1 commits to main since this releaseOpenDance Studio Web 服务端 v0.7.5
两个真实缺陷修复(都由跨端边界验收暴露)+ 跨端边界验收新增两类场景。
契约快照不变:
rest-api 0.5.0/websocket-keypoints 0.2.0/data-models 0.7.0/
skeleton-topology 0.2.0/model-formats 0.5.0/database 0.4.0
(与 opendance-windows / opendance-android 逐字节一致)。一、上传落盘:去重命中时删掉了唯一副本
persistTempFile(动作 / 模型 / 场景上传走的通路)在 sha256 去重命中时
直接删掉刚上传的临时文件并返回旧记录。若旧记录指向的路径已不存在
(换过STORAGE_DIR、只恢复了数据库、手工删过文件),上传仍返回 201,
但后续全部失败:ERROR [PreprocessService] 动作 #7 预处理失败:ENOENT ... /storage/motion/2026/09/a8/<sha>.vmd实测就是在本机的验收环境上撞到的(换过存储目录后动作预处理直接 500)。
persistBuffer(内存通路:关键点序列 / 缩略图 / 转换产物)早已有「文件缺失则按
原路径补写」的兜底,这条通路漏了。修复:去重命中时先确认文件存在;缺失则按记录里的原路径
rename
(跨设备退化为copyFile)补写,只有确认目标存在才删临时文件。新增
test/storage-persist.spec.ts(5 项)。反向验证:临时还原修复后,
「去重命中但文件已丢失」这条立刻失败;恢复后 5 项全过。二、不可用模型的原因归因不准确
unusableReason()原来只要stats里有 humanoid 数字就归因于 humanoid,于是
一个直接上传的.glb(骨架完全合规、drivable = true、只是没有 VRM 容器)
会被写成「humanoid 不达标(19/22)」—— 审核界面据此会把修复方向引到
「重新绑定骨骼」,而实际要做的是「以 VRM 交付」。用真实素材实测(PMX → Assimp → GLB,886 KB):
原因文案 修复前 humanoid 不达标(19/22),未产出 VRM修复后 未产出 VRM(格式为 GLB;humanoid 覆盖 19/22 已达标),需重新以 VRM 交付才能进入客户端目录现在按
drivable区分:不满足 16 根必需骨才归因 humanoid;达标但没有 VRM 容器
则明确说明"已达标"。新增 2 项单测(model-usability5 → 7 项)。三、跨端边界验收(Windows 客户端 × 本服务端)
accept-integration.sh新增两类场景,两端都断言:- 不可用模型:真实 PMX 用 Assimp 转 GLB 后入库(等价"管线只产出 GLB")→
usable=false、原因准确、不进入catalog/export、defaultModelId不受影响;
包内客户端的bundle.models里没有任何非 VRM 模型; - 场景
config只给最少字段({physics:{gravity:{y:-9.8}}})→ 服务端补齐默认
(碰撞体auto、地面0.6 / 45°、静风、相机follow、环境光1、出生点 1 条),
客户端解析后逐项一致。
四、发布前自检(本版实测)
$ npm run verify ✓ 契约 6 项 / 35 条路由 / 版本一致(0.7.5) ✓ 27 个文件 309 项测试(原 26 / 304) ✓ 产物级实体注册核对(dist/entities 6 项含 Scene)/启动冒烟 $ bash web-server/scripts/accept-release.sh <tar.gz> # 对发布包本身的验收 ✓ /health v0.7.5 / scenes.available=true / 包内 smoke 全过 $ 跨端集成验收(Windows v0.2.5 包内客户端 × 本服务端) ✓ 目录四类资源 / 场景物理参数逐项 / 关键点 2901 帧 / 不可用模型不进目录 / 最简配置补默认包内全部 356 个文件已逐字节核对:179 个源码/文档与 tag
v0.7.5一致,
177 个构建产物与工作树构建一致(0 处不一致 / 0 处多余 / 0 处缺失)。五、部署提示
- 本次不涉及表结构变更(迁移仍为 6 个),可直接替换程序文件后重启;
- 如果你换过
STORAGE_DIR或只恢复过数据库:v0.7.5 起,命中去重时会自动按记录中的
路径把文件补写回去;此前的版本会出现「上传成功但预处理/下载 500」。
Downloads
- 不可用模型:真实 PMX 用 Assimp 转 GLB 后入库(等价"管线只产出 GLB")→
-
released this
2026-09-17 03:52:34 +08:00 | 5 commits to main since this releaseOpenDance Studio -- Web 管理服务端 v0.7.4
场景功能的真正根因修复:
Scene实体没有被注册进ENTITIES
(v0.7.3 的降级修复 + 本版的实体注册修复,两者缺一不可)。契约无变更(
rest-api 0.5.0/websocket-keypoints 0.2.0/data-models 0.7.0/
skeleton-topology 0.2.0/model-formats 0.5.0/database 0.4.0)。根因:
No metadata for "Scene" was found.部署 v0.7.3 后,
/health的scenes.error给出了决定性线索:"scenes": { "available": false, "error": "No metadata for \"Scene\" was found." }src/entities/index.ts一直是:export const ENTITIES = [Asset, Song, Motion, CharacterModel, ReviewRecord]; // ← 少了 SceneTypeORM 的 DataSource 只按
ENTITIES注册 metadata。漏注册的后果非常隐蔽:环节 表现 启动 完全正常(DI 图可解析、 /health正常、migrationsPending 0)迁移 正常 —— AddScenes已执行,scenes表其实是建好的第一次查该实体 抛 No metadata for "Scene" was found.连带影响 /api/scenes、/api/catalog/export、/api/catalog/version、/api/reviews?status=pending全部 500 → 客户端拉不到任何目录、管理端待审列表打不开也就是说:此前"数据库缺 scenes 表"的判断是错的(那是我的误判)。
v0.7.3 的降级修复与诊断脚本因此仍然必要 —— 它们把"场景坏了"限制成"场景不可用",
而不是让整站不可用(部署 v0.7.3 后catalog/export与待审列表已恢复 200)。修复
ENTITIES加入Scene并导出。新增静态防线:
test/entities-registry.spec.ts(4 项)- 扫描
src/entities/*.entity.ts里所有@Entity()类,逐一与ENTITIES对账
(漏一个即失败;已做反向验证:把Scene从ENTITIES移除,测试立刻失败); - 检查
ENTITIES无重复、无多余项; - 核对
AddScenes迁移文件确实存在(迁移文件缺失时showMigrations()仍会显示
"0 个待执行",这是另一个隐蔽的静默不一致)。
这类"漏注册"既过得了
tsc,也过得了启动冒烟(应用能启动),只能靠静态核对兜住。校验
npm run verify通过:contracts:check(六项一致 + 35 条路由一致 + 版本一致)、
tsc --noEmit、23 文件 / 285 项测试、nest build、启动冒烟;- 发布产物解压后
npm ci --omit=dev+node dist/main.js实测打印「应用版本 v0.7.4」。
部署与部署后自检
curl -fLO https://gitea.kasugano.cn/zijunchiang/opendance-web/releases/download/v0.7.4/opendance-web-v0.7.4.tar.gz curl -fLO https://gitea.kasugano.cn/zijunchiang/opendance-web/releases/download/v0.7.4/SHA256SUMS sha256sum -c SHA256SUMS tar -xzf opendance-web-v0.7.4.tar.gz && cd opendance-web-v0.7.4 sudo bash deploy/install.sh # 1) 版本可核对 curl -s http://<服务器地址>:3000/health | grep -o '"version":"[^"]*"' # 期望 0.7.4 # 2) 场景子系统应恢复可用(不再有 No metadata) curl -s http://<服务器地址>:3000/health | python3 -m json.tool | grep -A3 '"scenes"' # 期望 available: true # 3) 场景接口不再 500 curl -s -o /dev/null -w '%{http_code}\n' http://<服务器地址>:3000/api/scenes # 期望 200 # 4) 表/列实际状态(默认只读) cd <APP_DIR>/web-server && set -a && . ../deploy/.env && set +a node scripts/diagnose-scenes.mjs # 5) 数据库端到端验收(歌曲 → 动作 → 预处理 → 模型 → 审核 → 场景 → 目录导出) API_BASE=http://<服务器地址>:3000 node web-server/test/smoke.mjs<服务器地址>是你们自己部署的服务端地址(部署方决定),不是被脱敏的域名。交付物校验和(可核对)
e03e28f3ab483291c4b030a428ace9100bddcd1ab5d40010ab29a4a9500d1987 opendance-web-v0.7.4.tar.gz下载后:
curl -fLO https://gitea.kasugano.cn/zijunchiang/opendance-web/releases/download/v0.7.4/SHA256SUMS curl -fLO https://gitea.kasugano.cn/zijunchiang/opendance-web/releases/download/v0.7.4/opendance-web-v0.7.4.tar.gz sha256sum -c SHA256SUMS # 期望 OKDownloads
- 扫描
-
released this
2026-09-17 03:39:36 +08:00 | 7 commits to main since this releaseOpenDance Studio -- Web 管理服务端 v0.7.3
两个真实缺陷修复(均在生产部署上复现并定位)。
契约无变更(仍为
rest-api 0.5.0/websocket-keypoints 0.2.0/data-models 0.7.0/
skeleton-topology 0.2.0/model-formats 0.5.0/database 0.4.0)。一、场景根本传不上来:diskStorage 却按内存存储判断
现象:
POST /api/scenes一律 400「上传场景必须带 file 字段(.glb 为主…)」,
而同一份 multipart 请求打/api/models返回 201(已用 curl 对照验证)。根因:上传中间件在
storage.module.ts里用的是 multer 的diskStorage
(先落${STORAGE_DIR}/tmp,避免 512 MiB 级 VRM 打爆进程内存),落盘后的文件对象
只有path、没有buffer;而ScenesService.create()当初按内存存储写:if (!file || !file.buffer || file.buffer.length === 0) { /* 400 */ }file.buffer恒为undefined→ 任何场景都传不上来。修复:与 models / motions 统一到同一套上传处理:
requireUploadedFile(file)—— 校验确实落盘,并修正 busboy 按 latin1 解出的中文/日文文件名;- 直接导入(
.glb/.gltf)→storage.persistTempFile(AssetKind.Scene, upload.path, …)
—— 归档并顺带清理临时文件; - 需转换(
.zip/.pmx/.fbx)→readFile(upload.path)取 buffer 后转换 →persistBuffer,
并在finally中unlink(upload.path); - 体积上限用
upload.size判断(UPLOAD_MAX_BYTES),超限 400 且不落盘。
全局排查过同类写法:除注释外,代码里已无按
file.buffer处理上传的地方。二、场景表不可用会拖垮整站
现象(生产):数据库缺
scenes表,于是请求 结果 /api/songs、/api/motions、/api/models200 /api/scenes、/api/scenes/:id500 /api/catalog/export、/api/catalog/version500 ← 客户端拉不到任何目录 /api/reviews?status=pending500 ← 管理端待审列表打不开 而
/health显示database.connected true、migrationsPending 0—— 因为
DataSource.showMigrations()只比较代码里加载到的迁移;部署的dist/migrations/
若缺AddScenes.js,它根本不在比较集合里,于是"没有待执行迁移"但表并不存在。契约与文档都写明场景是可选资源(没有可用场景时客户端回退内置空场景),
因此改为降级而不是 500:ScenesService.queryScenes():数据库层面失败 → 返回空结果、只记一次日志、
原因写入diagnostics();下一次查询成功即自动复位;ReviewsService.listByStatus():场景查询单独catch,待审列表照常返回其它资源;/health新增scenes: { available, error }—— 降级但绝不静默。
三、新增诊断脚本
web-server/scripts/diagnose-scenes.mjs(默认只读)打印运行期真实连的库、表清单、
typeorm_migrations记录、代码实际加载的迁移、
scenes实际列 vs 实体期望列的逐列 diff;--fix仅在缺表时用迁移里同一份 DDL
幂等补表。cd <APP_DIR>/web-server set -a; . ../deploy/.env; set +a node scripts/diagnose-scenes.mjs # 只读诊断 node scripts/diagnose-scenes.mjs --fix # 仅在缺表时补表(幂等)四、顺带修正
models.controller.ts的误导性注释:模型上传不接受isPrimary/status
(契约:上传一律pending,默认模型由审核通过时带setPrimary=true或
POST /api/models/{id}/primary设定);test/smoke.mjs此前按错误预期断言「isPrimary 已置位」,已改为契约流程
(上传断言pending+isPrimary=false→ 审核带setPrimary=true→ 断言isPrimary=true);
另给目录导出/指纹等检查补上失败细节(HTTP 状态 + 响应体),并把待审列表查询的
pageSize放大到 200(避免库里待审项多时新条目被挤出第一页);deploy/proxy/README.md第九节更正一次误判:Gitea 附件接口本身是好的 ——
它的 multipart 字段名是attachment,用file=会得到
HTTP 500 {"message":"","url":"…/api/swagger"}(空消息,极易误判成"服务器磁盘写满")。
本节同时记录了两种正确的上传写法与复验命令。
⚠️ 仍然存在、需要运维处理的唯一上传限制:IIS 的
maxAllowedContentLength
还是默认的 30,000,000 字节,37 MB 的 Windows 整包上传仍返回 HTTP 413。
请按deploy/proxy/README.md9.2 放开到 256 MB。校验
npm run verify通过:contracts:check(六项一致 + 35 条路由一致 + 版本一致)、
tsc --noEmit、22 文件 / 281 项测试、nest build、启动冒烟;- 新增
test/scene-upload.spec.ts(5 项,修复前必失败)与
test/scenes-degradation.spec.ts(6 项); - 发布产物解压后
npm ci --omit=dev+node dist/main.js实测打印
应用版本 v0.7.3(与/health、管理端左下角同源)。
部署与部署后自检
curl -fLO https://gitea.kasugano.cn/zijunchiang/opendance-web/releases/download/v0.7.3/opendance-web-v0.7.3.tar.gz curl -fLO https://gitea.kasugano.cn/zijunchiang/opendance-web/releases/download/v0.7.3/SHA256SUMS sha256sum -c SHA256SUMS tar -xzf opendance-web-v0.7.3.tar.gz && cd opendance-web-v0.7.3 sudo bash deploy/install.sh # 部署后必须「可核对」: curl -s http://<服务器地址>:3000/health | grep -o '"version":"[^"]*"' # 必须输出 0.7.3 # 场景子系统可用性(降级时也会如实显示原因,而不是把整站带崩): curl -s http://<服务器地址>:3000/health | python3 -m json.tool | grep -A3 '"scenes"' # 若 scenes 不可用,先诊断再决定是否补表: cd <APP_DIR>/web-server && set -a && . ../deploy/.env && set +a node scripts/diagnose-scenes.mjs数据库端到端验收(歌曲 → 动作 → 预处理 → 模型 → 审核 → 场景 → 目录导出):
API_BASE=http://<服务器地址>:3000 node web-server/test/smoke.mjs<服务器地址>是你们自己部署的服务端地址(部署方决定),不是被脱敏的域名。交付物校验和(可核对)
5d0f90ec6a1b58ad0beec92928c99467bc159c2720e3b058da7e588fdddda519 opendance-web-v0.7.3.tar.gz下载后:
curl -fLO https://gitea.kasugano.cn/zijunchiang/opendance-web/releases/download/v0.7.3/SHA256SUMS curl -fLO https://gitea.kasugano.cn/zijunchiang/opendance-web/releases/download/v0.7.3/opendance-web-v0.7.3.tar.gz sha256sum -c SHA256SUMS # 期望 OKDownloads
-
released this
2026-09-17 01:49:53 +08:00 | 13 commits to main since this releaseOpenDance Studio -- Web 管理服务端 v0.7.2
⚠️ 请务必升级到本版:v0.7.0 / v0.7.1 的产物启动不起来(详见第一条)。
本版同时修正/health在正式部署下报错版本号的问题。本版不含契约变更(仍为
rest-api 0.5.0/websocket-keypoints 0.2.0/data-models 0.7.0/
skeleton-topology 0.2.0/model-formats 0.5.0/database 0.4.0)与接口行为变更。一、【致命】
CatalogModule漏 importScenesModule:产物「装得上、起不来」CatalogService因为catalog/export要下发scenes[]而注入了ScenesService,
但CatalogModule的imports里只列了SongsModule / MotionsModule / ModelsModule。
Nest 的 DI 是按模块解析的,于是:UnknownDependenciesException: Nest can't resolve dependencies of the CatalogService (SongRepository, MotionRepository, CharacterModelRepository, SongsService, MotionsService, ModelsService, ?, AppConfig). Please make sure that the argument ScenesService at index [6] is available in the CatalogModule module.node dist/main.js在 bootstrap 阶段就退出,服务完全起不来。为什么之前三层检查全绿却没发现:
检查 为什么没抓到 nest build/tsc --noEmit模块 import 缺失是运行时 DI 问题,类型系统看不出来 258 项单元测试 直接 new 服务或测纯函数,从不编译 AppModule打包脚本的产物完整性校验 只校验文件清单与压缩包结构,不启动服务 修复:
CatalogModule.imports补上ScenesModule。新增防线(同时挂进
npm run verify与打包脚本):scripts/check-bootstrap.mjs:以正式部署方式(ExecStart=node dist/main.js、
不带任何 npm 环境变量、不需要数据库)拉起真实产物,断言
①日志里没有依赖解析类错误②启动日志里的应用版本等于package.json
③启动确实推进到数据库连接阶段。
已做反向验证:把ScenesModule删除后该检查立刻失败。
二、
/health的version在正式部署下永远是0.1.0原实现:
process.env.npm_package_version ?? '0.1.0'。该变量只在通过 npm 脚本启动时才存在,而本项目的正式部署方式是原生服务
(systemd / OpenRC / initd,ExecStart=node dist/main.js)—— npm 不参与,
于是它恒为undefined,/health就回退到硬编码的0.1.0。
这与「管理端左下角展示 vX.Y.Z,且必须与GET /health的version一致」
(文档 §11.2 第 4 条)直接冲突。修复:
- 新增
src/config/app-version.ts作为版本号的运行时唯一解析点,按优先级尝试
APP_VERSION环境变量 → 运行入口旁的package.json→ 工作目录的
package.json→npm_package_version,每一步都做包名校验
(必须是opendance-web-server,避免读到上层仓库的package.json);
全都拿不到时返回显式的0.0.0,绝不伪装成某个具体版本; /health改为version: resolveAppVersion();main.ts启动首行也打印应用版本 vX.Y.Z,即使数据库连不上、进程退出,
日志里也一定能看到本次运行的版本号。
新增防线:
scripts/check-version.mjs(并入npm run contracts:check)校验
web-server/package.json=admin/package.json=project.yaml,并用正则
禁止health.controller.ts再出现硬编码版本回退;管理端已构建时还会断言
产物 JS 内确实含vX.Y.Z;test/app-version.spec.ts12 项,其中一项显式模拟无 npm 环境变量的原生部署。
校验(全部通过)
检查 结果 npm run contracts:check契约六项版本一致 + 35 条路由一致 + 版本一致性一致 npx tsc --noEmit通过 npx vitest run19 文件 / 258 项全通过 nest build通过 启动冒烟 npm run bootstrap:check通过(见上) 对发布产物解压后的实测 解压 tarball → npm ci --omit=dev(与install.sh同一步骤)→env -u npm_package_version node dist/main.js:打印应用版本 v0.7.2,全部模块dependencies initialized,随后因本机没有 MySQL 而止于ECONNREFUSED(预期)opendance-web-v0.7.2.tar.gzsha256:f04ecc85d17517ec00754238616eb1237cdb2fe17440af6dce731827c0922b26部署与部署后自检
curl -fLO https://gitea.kasugano.cn/zijunchiang/opendance-web/releases/download/v0.7.2/opendance-web-v0.7.2.tar.gz curl -fLO https://gitea.kasugano.cn/zijunchiang/opendance-web/releases/download/v0.7.2/SHA256SUMS sha256sum -c SHA256SUMS tar -xzf opendance-web-v0.7.2.tar.gz && cd opendance-web-v0.7.2 bash deploy/install.sh # 部署后必须做到「可核对」: curl -s http://<服务器地址>:3000/health | grep -o '"version":"[^"]*"' # 必须输出 0.7.2管理端页面左下角显示的版本号必须与上面这条完全一致(都来自
web-server/package.json)。数据库端到端验收(歌曲 CRUD → 动作上传 → 预处理 → 模型上传 → 审核 → 场景 → 目录导出)
可在部署完成后执行:API_BASE=http://<服务器地址>:3000 node web-server/test/smoke.mjs说明:
<服务器地址>是你们自己部署的服务端地址(部署方决定),不是被脱敏的域名;
本文档只对 Gitea 域名这类「部署必需且非隐私」的信息直接写出真实值
(gitea.kasugano.cn/ 属主zijunchiang)。Downloads
-
released this
2026-09-17 01:30:42 +08:00 | 15 commits to main since this releaseOpenDance Studio -- Web 管理服务端 v0.7.1
契约补齐 + 文档补齐(《DSH 开发文档 v1.6》7.2)。本版不含运行时行为变更,
GET /health的version由web-server/package.json同源驱动,管理端左下角同步显示v0.7.1。一、契约
websocket-keypoints0.1.0 → 0.2.0(T-WEB-016)与 Android 端
T-AND-011「连接状态异常、频繁重连」的两端一起改配套。
按文档 §7.2,契约先在 Web 端修改并提升版本,再向另两端建迁移任务。完全向后兼容:子协议名
opendance.pose.v1与二进制帧version = 0x01均不变,
只新增可选控制字段与一种新控制类型;仅实现 v0.1.0 的一端仍可互通。章节 新增 为什么必须写进契约 1.1 保活 接收端必须声明 silentTimeoutMs与heartbeatIntervalMs,且心跳必须小于静默超时的一半客户端原先只能用 OkHttp 的协议层 ping,而它由底层库自动应答、不暴露给应用层,接收端根本看不到,无法续命 —— 这是"画面里没人就掉线、然后疯狂重连"的根因 3.1 hello.deviceId(该安装实例的稳定标识,不使用任何硬件序列号)没有它,一次闪断重连会被接收端显示成两台设备 3.2 / 3.3 welcome/config携带上述保活字段让客户端按服务端节奏保活,而不是各写一套魔数 3.6 应用层 ping/pong(回显sentAtMs,pong另带serverAtMs供算 RTT)协议层 ping 对应用层不可见,必须自定义 5 设备去重:同一 deviceId只保留最新连接,旧连接以1000关闭用 1000是刻意的:对端据 §7 不会重连,否则会形成"挤掉-重连-再挤掉"的循环7 关闭码与重连策略: 1000/1001/1002与主动停止不重连,其余重连原实现"只要能重连就重连",服务端重启或协议不匹配时也会疯狂重连 7.1 退避参数冻结: min(500ms × 2^(n-1), 15000ms)+ ±20% 抖动避免同网段多台设备同时重连打尖峰 8 连接状态机 idle → resolving → connecting → handshaking → streaming → degraded → reconnecting → stopped两端同名,日志可直接对照 contracts/VERSION与web-server/src/config/contract-versions.ts同步到0.2.0
(npm run contracts:check强制两者一致)。二、补齐
rest-api.yaml里漏写的场景结构catalog/export自 v0.7.0 起就返回scenes[],data-models.md§7 也已冻结,
但CatalogBundle漏了这个字段、components里也没有Scene/SceneConfig定义 ——
属于"实现已发布、规格漏写"。只补规格,不改线格式,六个契约版本号均不变:CatalogBundle增加scenes[](标注 0.5.0 起下发);- 新增
Scene/SceneConfig/Vec3schemas(重力 ±200、风 0100 / 0.015Hz、
摩擦 01、坡度 089°、出生点 ≤16、相机follow|fixed|orbit等边界全部写明)。
规格缺失会让两端对字段边界的理解不一致(Windows 端
T-WIN-013正是照这份结构生成的
GDScript 类型)。三、
deploy/proxy/README.md新增第九节:Gitea 站点的附件上传上限与前八节的 Web 服务反代是两个不同站点 —— 托管 Gitea(源码 + Release 附件)的
IIS 站点必须单独放开:上传体积 实测结果 14 MB 通过(HTTP 201) 30.5 MB 失败 HTTP 413 40 MB 失败 HTTP 413 根因是 IIS 默认的
maxAllowedContentLength = 30,000,000字节(≈28.6 MiB)。
这正是 Windows 客户端 v0.1.0 被拆成zip.part0/1/2(用户拿到无法直接解压的碎片)的根因。文档给出放宽到 256 MB 的四处配置(IIS
requestLimits+uploadReadAheadSize、
ARRmaxRequestBytes、Giteaapp.ini的[attachment] MAX_SIZE、前置 nginx 的
client_max_body_size)与curl复验命令。四、文档与脚本
- 补齐
tasks/011~tasks/016与project.yaml条目:此前 T-WEB-011~015
已在代码中落地却缺任务说明书(011 版本号展示 / 012 VRM 优先 / 013 动作标准与骨骼
重绑定 / 014 动作预览 / 015 场景管理 / 016 本契约变更); 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 条路由一致)、tsc --noEmit、
18 文件 / 246 项测试、nest build全部通过;opendance-web-v0.7.1.tar.gzsha256:27f92cfb125bbcf29077d4ad90c44720cbca46d23ddef12cd7826d73bd8865e2
部署
curl -fLO https://gitea.kasugano.cn/zijunchiang/opendance-web/releases/download/v0.7.1/opendance-web-v0.7.1.tar.gz curl -fLO https://gitea.kasugano.cn/zijunchiang/opendance-web/releases/download/v0.7.1/SHA256SUMS sha256sum -c SHA256SUMS tar -xzf opendance-web-v0.7.1.tar.gz && cd opendance-web-v0.7.1 bash deploy/install.sh本版不需要重新部署也能继续使用:运行时行为未变,只是
/health报出的
websocket-keypoints契约版本从 0.1.0 变为 0.2.0,以及contracts/快照更新。
若要让/health与新快照一致,重新部署本版即可。Downloads
-
released this
2026-09-17 00:32:05 +08:00 | 17 commits to main since this releaseOpenDance Studio -- Web 管理服务端 v0.7.0
补齐场景管理前端(《DSH 开发文档 v1.6》4.12 / T-WEB-015)。
契约保持rest-api -> 0.5.0、data-models -> 0.7.0、database -> 0.4.0(三端一致,本次无契约变更)。本次改动
- 新增管理端「场景管理」页(左侧导航 → 场景管理,路由
/scenes):- 场景列表:审核状态、格式、可用性、GLB 体积、更新时间;
- 上传:拖拽
.glb/.gltf/.zip/.pmx/.fbx(zip 自动解包、非 GLB 由服务端 Assimp 转 GLB); - 审核操作:通过 / 驳回(上传一律先落
pending,复用/api/reviews/scene/:id/...); - 删除:同时清理对象存储中的源文件、GLB 与缩略图。
- 物理参数可视化编辑(对应
SceneConfig,冻结在 data-models 7.1):- 重力向量(
(0,-9.8,0)默认,各分量 ±200)、质量无关的常量加速度; - 风:基础风向量 + 阵风(幅度 0
100、频率 0.015Hz、方向、world/local); - 地面:摩擦 0
1、弹性 01、坡度上限 0~89 度;碰撞体auto/mesh/none; - 环境:环境光颜色与强度、雾浓度;出生点(≤16)与相机(
follow/fixed/orbit)。 - 编辑期即做与后端相同的夹紧/回退(
admin/src/lib/scene-physics.ts,与scene-config.ts同规则),
保存前不会产生非法枚举;服务端仍会再收敛一次,服务端只存参数、不跑物理。
- 重力向量(
- 3D 预览:预审场景可展开惰性加载的 GLB 预览(与模型预览共用加载器),便于确认坐标系与尺寸。
- 版本号:管理端左下角显示当前版本(构建期由
web-server/package.json注入),本次显示v0.7.0。
校验
- 类型检查通过;
vitest245 项全绿(新增test/scene-config.spec.ts边界用例); contracts:check通过、check-routes35 条路由一致;- 管理端生产构建通过;
opendance-web-v0.7.0.tar.gzsha256:6ed1b0fd63697f38f5b4e40e25923d53d693d0742e4ef4c4093282e3c0942eab
部署
curl -fLO https://gitea.kasugano.cn/zijunchiang/opendance-web/releases/download/v0.7.0/opendance-web-v0.7.0.tar.gz curl -fLO https://gitea.kasugano.cn/zijunchiang/opendance-web/releases/download/v0.7.0/SHA256SUMS sha256sum -c SHA256SUMS tar -xzf opendance-web-v0.7.0.tar.gz && cd opendance-web-v0.7.0 bash deploy/install.sh下一步(同一目标内继续)
- Windows 端场景选择与物理落地(T-WIN-013)、发布整包(T-WIN-014);
- Android 端重连与 MediaPipe 修复(T-AND-011/012)。
Downloads
- 新增管理端「场景管理」页(左侧导航 → 场景管理,路由
-
released this
2026-09-17 00:27:08 +08:00 | 18 commits to main since this releaseOpenDance Studio -- Web 管理服务端 v0.6.0
新增场景管理(《DSH 开发文档 v1.6》4.12 / T-WEB-015)。
契约rest-api -> 0.5.0、data-models -> 0.7.0、database -> 0.4.0(三端已同步)。本次改动
- 场景以 GLB 为主:
.glb/.gltf直接导入(不重编码);.zip/.pmx/.fbx
由服务端转 GLB。场景不做 humanoid 重绑定、不转 VRM(与模型区分)。 - 物理参数(
SceneConfig,冻结在 data-models 7.1):gravity重力向量(默认(0,-9.8,0),各分量 ±200);wind风向动态:基础风向量 + 阵风(幅度 0100、频率 0.015Hz、方向、world/local 坐标系);ground:摩擦 01、弹性 01、坡度上限 0~89 度;colliders:auto/mesh/none;environment:环境光颜色/强度、雾浓度;spawnPoints(≤16)、camera(follow/fixed/orbit)。
服务端只存参数、不跑物理 —— 仿真在客户端(Windows 端用 Godot 内置物理)。
- 入库即收敛:越界夹紧、非法枚举回退默认值,保证客户端拿到的参数一定可解释;
config/stats用 MEDIUMTEXT(TEXT 的 64KB 上限在models.stats上踩过坑)。 - 端点(
check-routes35 条一致):GET/POST /api/scenes、GET/PATCH/DELETE /api/scenes/<built-in function id>;
审核复用/api/reviews/scene/:id/approve|reject(上传一律pending);
catalog/export增加scenes[],目录指纹纳入场景变更。 - 缩略图复用模型光栅化器、分析复用模型检查器。
下一步(同一目标内继续)
- 管理端「场景管理」页:GLB 预览 + 重力/风向等参数可视化编辑;
- Windows 端场景选择与物理落地(T-WIN-013)、发布整包(T-WIN-014);
- Android 端重连与 MediaPipe 修复(T-AND-011/012)。
校验
opendance-web-v0.6.0.tar.gzsha256:223d2b0d059bbffcfda6d873f13eea911a39619ad4de301be96b3e124f105eadDownloads
- 场景以 GLB 为主:
-
released this
2026-09-17 00:21:09 +08:00 | 19 commits to main since this releaseOpenDance Studio -- Web 管理服务端 v0.5.0
动作预览(《DSH 开发文档 v1.6》4.11 / T-WEB-014)。契约
data-models-> 0.6.0。本次改动
服务端
- 抽出公共 PNG 编码器
common/png.ts(模型缩略图改为复用;零原生依赖不变); - 新增
motions/motion-thumbnail.ts:关键点序列 -> 正视图骨架 PNG
(复用 33 点父表连线,包围盒按整段计算,低置信度点不画); motions.thumbnail_asset_id(迁移AddMotionThumbnail)+AssetKind.MotionThumbnail;/api/motions/:id/preprocess生成缩略图并落库,失败只记 warning,不影响预处理;MotionDto.thumbnailUrl(契约 data-models 0.6.0)。
管理端(重点)
6. 新增MotionPreview3D 回放:懒加载GET /api/motions/:id/keypoints(NDJSON)→
骨架线框 + 关节球体,支持 播放/暂停、上一帧/下一帧、时间轴拖动、0.25x-2x 变速、循环,
叠加「第 N/M 帧 · 当前时间 · 总时长」,按整段包围盒自动取景;
7. 动作管理列表新增 40px 骨架缩略图列(点击即开预览)与「预览 / 收起预览」按钮 + 内联预览面板;
8. three.js 单独分包(lazy+Suspense):主包 241 kB 不涨(three 568 kB 独立 chunk)。已有动作请重新预处理
缩略图在
/preprocess时生成,已有动作需要重跑一次预处理才会出现缩略图:# 管理端「动作管理」逐条点「预处理」,或对每个动作调用: curl -X POST http://127.0.0.1:3000/api/motions/<id>/preprocess预览功能本身不需要缩略图,只要动作处于
done状态即可播放。校验
opendance-web-v0.5.0.tar.gzsha256:67afe31e51e192b0d766fff219381577b3a9c4e326c256093b5219d4b58d21c3Downloads
- 抽出公共 PNG 编码器
-
released this
2026-09-17 00:10:07 +08:00 | 20 commits to main since this releaseOpenDance Studio -- Web 管理服务端 v0.4.0
骨骼重绑定:让「一律转 VRM」真正可用(契约
skeleton-topology-> 0.2.0)。
对应《DSH 开发文档 v1.6》4.10(T-WEB-013)。根因:MMD 模型 humanoid 恒为 0/22
normalizeBoneName()原先只保留a-z0-9,中文/日文字符被整个丢掉:
上半身/左ひじ/首归一化后都是空串,MMD 骨名必然失配 ->
humanoidMapped=0/22-> 不可驱动 -> 只能回退交付 GLB 并标记usable=false。本次改动
- 归一化修复:保留 CJK / 平假名 / 片假名 / 长音符 /
々,并把全角 ASCII 折成半角
(MMD 常写足IK/つま先IK);精确匹配保证左足IK不会抢占左足。 - 候选表补齐四类命名(22 根 × 8-13 个候选):VRoid、Mixamo、MMD 标准骨架
(下半身/上半身/上半身2/首/頭/左肩/左腕/左ひじ/左手首/左足/左ひざ/左足首/左つま先)、
常见中文名(臀部/头/脖子/左大臂/左小臂/左大腿/左脚…)。 - 服务端与 Windows 客户端逐字一致:
humanoid_map.gd的CANDIDATES由服务端表生成写入,
normalize()同步改造;parity 测试断言键顺序与候选顺序完全一致。 - 契约
skeleton-topology-> 0.2.0:新增 §6「内部动作标准与模型骨骼重绑定」
(三层标准:33 点关键点 / MMD 标准骨架 / 22 根 humanoid;22 与 16 根骨清单;
归一化与匹配规则;实测记录)。 - 测试规模 17 文件 / 229 项。
实测(重绑定后)
样本 之前 现在 【奥黛塔】_by_原神.zip(PMX 日文骨名)0/22,不可驱动,回退 GLB、 usable=false21/22,drivable=true,交付 VRM 模型_初音未来…zip(PMX)0/22,不可驱动 19/22,drivable=true,交付 VRM 未命中的 1-3 根均为非必需骨(
upperChest/leftToes等),不影响驱动与评分。升级后请重新导入模型
材质/骨骼重绑定都在转换时生效:把 MMD 模型(
.zip/.pmx)重新上传即可,
此前标记「不可用」的模型重新导入后会变成可用并进入客户端目录;
reanalyze-models.mjs只刷新分析与缩略图,不会重转。校验
opendance-web-v0.4.0.tar.gzsha256:2c913c39a5feda918bdf144ffac773284d7bdb768a2da50877647ae63ceb40bfDownloads
- 归一化修复:保留 CJK / 平假名 / 片假名 / 长音符 /
-
released this
2026-09-17 00:05:02 +08:00 | 21 commits to main since this releaseOpenDance Studio -- Web 管理服务端 v0.3.0
模型主力格式全面转为 VRM(契约
data-models/model-formats-> 0.5.0)。
按《DSH 开发文档 v1.6》4.9 与第十一章实现的第一步(Web 端)。本次改动
- 所有上传的模型一律转 VRM:
MODEL_CONVERT_FORMAT默认改为vrm
(.pmx/.fbx走assimp -> GLB -> VRM 1.0;.glb/.gltf导入后包装为 VRM)。
支持库:自研vrm-writer/vrm-inspector+ 外部assimp(可选@gltf-transform/core校验)。 - humanoid 硬门槛 + 可用性标记(按你的选择「入库但标记不可用,不进入已发布目录」):
- 必需骨齐全 -> 交付 VRM,
usable=true,可发布可选用; - 不达标(如 MMD 日文骨名
0/22)-> 回退交付 GLB、usable=false,
可入库、可审核,但不进入catalog/export(/api/catalog/version指纹同步过滤),
resolveDefaultModelId也不会选中它; - 管理端模型列表与审核面板显示「不可用」及原因
(如humanoid 不达标(0/22),未产出 VRM);待骨骼按skeleton-topology
标准重绑定后重新导入即转为可用(下一步 T-WEB-013)。
- 必需骨齐全 -> 交付 VRM,
- 管理端左下角展示当前版本号(v1.5 文档第十一章):构建期从
web-server/package.json注入,与GET /health的version同源;
顺带修掉了侧栏里写死的「契约 rest-api 0.1.0」。 - 契约:
data-models/model-formats-> 0.5.0(三端契约文件逐字节一致,
已同步 opendance-windows / opendance-android 仓库)。 - 测试规模 16 文件 / 225 项。
升级注意
- 升级后新上传/重新导入的模型才会走 VRM 管线;存量 GLB 模型会显示为「不可用」,
不再出现在客户端目录里 —— 这是本次策略变更的预期结果。 - 想保留旧行为可显式设置
MODEL_CONVERT_FORMAT=glb(不推荐,与 0.5.0 契约不符)。
校验
opendance-web-v0.3.0.tar.gzsha256:46c19e8f51a38f083bfc41e190fc45548dd0b248bd9a0932fdeaddd9988feb81Downloads
- 所有上传的模型一律转 VRM: