• v0.2.5 e0ba4ea833

    zijunchiang released this 2026-09-18 02:47:05 +08:00 | 3 commits to main since this release

    OpenDance Studio -- Windows 客户端 v0.2.5

    修复:config 被当成心跳周期性广播(每 2 秒一条);
    新增:契约「可选/兜底」语义的定向验收(v0.1.0 风格对端 / 缺 deviceId / 不发 hello)。

    契约快照不变: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-web / opendance-android 逐字节一致)。

    一、缺陷:config 被当成心跳

    _maybe_push_config() 原来每 CONFIG_PUSH_INTERVAL_MS(2 秒)无条件广播一次 config。
    契约 §3.3 的语义是「运行中调整时下发」,不是心跳:

    • 一次 30 分钟推流 = 900 条没有任何信息量的消息;
    • 更糟的是它让「收到 config」无法被当作「配置变了」的信号 —— 发送端想据此做点什么
      就无从判断。

    修复:抽出 config_payload() 作为唯一载荷与指纹来源;hello 应答顺序固定为
    先 welcome、再 config(若靠周期 tick 补发,新对端第一条消息可能变成 config,
    只认握手应答的实现会困惑);之后仅当载荷真的变化才广播,并用同一常量做去抖
    (连续拖动滑块不会每个中间值都发一条);显式 broadcast_config()(UI 改设置)也同步
    更新指纹,避免下一 tick 重发。

    实测:17 秒内 config 9 条 → 1 条。

    二、新增:契约「可选/兜底」语义的定向验收

    上一轮 Android 侧的教训是「契约里可选的字段必须用不提供它的对端来测,
    否则等于没测」(自家两端总是互相迎合)。本版把它用到接收端:

    场景 契约 断言
    v0.1.0 风格对端:只发二进制帧(每 500 ms 一帧)、从不发 ping/stats、hello 不带 deviceId,持续 17 秒(> 静默超时 15 秒) §1.1 明确「仅实现 v0.1.0 的一端仍可正常互通(它不发 ping,但每帧已足够保活)」 连接保持打开;服务端没有把它静默超时踢掉
    两条都不带 deviceId 的连接同时在线 §5「deviceId 缺失或为空 → 不做去重,按连接计数」 两条都保持打开;device_replaced 只应有那次真正重复 deviceId 的事件
    完全不发 hello、只发 5 帧的对端 契约未规定(不该崩、不该断) 不断开、不崩、帧仍计入

    WebSocket 验收断言:30 → 40 项,40 通过 / 0 失败。

    三、顺带修掉验收脚本自身两处误判

    1. 把「跨连接的 frame_id 回退」当缺陷:frame_id 是每条连接各自从 0 递增,
      新连接重新从 0 开始完全合规 —— 指标用错了。已改名并标注「仅参考」;
      真正相关的判据是逐连接的 frames_dropped == 3。
    2. 把「静默超时次数」当固定值:套件里本来就有"完全不发数据"的对端,空闲的连接也会
      被正常超时。已改为定向断言:由 hello 记录建立 client_id → device 映射
      (探针新增 hellos[]),只检查 v0.1.0 风格对端没被误踢。

    测试客户端也改为顺序无关(nextOfType(type))—— 契约没规定消息顺序,
    "第一条消息就是 welcome" 的假设在 welcome 后紧跟 config 时立刻暴露。

    四、附件与解压(重要)

    资产 说明
    opendance-windows-v0.2.5.zip 单个完整包,不分卷:OpenDance.exe + OpenDance.pck(必须同目录)+ THIRD_PARTY.md + README.txt + README.md + contracts/
    SHA256SUMS 裸文件名,sha256sum -c SHA256SUMS 直接校验

    解压需要 7-Zip / WinRAR / PeaZip:本包用 LZMA 压缩(26,634,144 B)以绕过本站
    前置 IIS 的 maxAllowedContentLength = 30,000,000 字节上限
    (同内容 deflate 包约 38 MB,会 HTTP 413)。Windows 10 资源管理器不支持
    LZMA(method 14) 的 zip
    ,双击会报错。

    五、发布前自检(本版实测,四条全绿)

    $ bash build/accept-release.sh <zip>
      ✓ PE 版本资源 0.2.5 / pck 启动 180 帧无错 / pck 无开发残留 / 运行时探针全过
    $ bash build/accept-ws.sh <zip>
      == 结果:40 通过 / 0 失败 ==(客户端)+ 服务端侧全部事实
    $ bash build/accept-frame-vectors.sh <zip>
      ✓ 解码 12/12、396 点 0 差异 / ✓ 编码器字节与参考实现完全一致(0 项差异)
    $ bash build/verify.sh
      == 结果:785 通过 / 0 失败,6 跳过 ==
    

    六、未在本环境验证(诚实声明)

    • 本仓库在 Linux 上导出 Windows 产物,没有 Windows 机器与真机 30 分钟联调;
    • 跨端集成验收(accept-integration.sh)需要已部署的 Web 服务端。
    Downloads
  • v0.2.4 6ea2c93d66

    zijunchiang released this 2026-09-17 05:59:59 +08:00 | 5 commits to main since this release

    ⚠️ 本版已被 v0.2.5 取代(建议直接用 v0.2.5):
    v0.2.5 把 config 从「每 2 秒无条件广播」改为变更驱动(契约 §3.3 的语义是
    「运行中调整时下发」),并新增契约「可选/兜底」语义的定向验收
    (v0.1.0 风格对端只发帧不发 ping 也必须保住、缺 deviceId 不做去重、不发 hello 不崩)。

    OpenDance Studio -- Windows 客户端 v0.2.4

    两个缺陷修复:编码取整与契约参考实现对齐;发布包不再夹带测试夹具。
    建议所有用户改用本版。

    契约快照不变: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-web / opendance-android 逐字节一致)。

    一、编码取整与契约参考实现不一致

    KeypointFrame.encode() 用的是 GDScript 的 roundi(半数远离零),
    而契约参考实现(opendance-web 的 keypoint-codec.ts)与生产发送方 Android
    (Kotlin Math.round)都是「半数朝 +∞」:

    -2.5 2.5 -0.5
    JS / Kotlin Math.round(参考 + 生产发送方) -2 3 0
    GDScript roundi(本端旧实现) -3 3 -1

    跨实现向量实测:12 个用例里有 1 例 33 字节不同。

    影响:本端是接收方,encode() 只用于自测与协议回归,对产品无影响;
    但它让「跨实现一致性」只能停留在宽松口径("差异仅限取整边界"),
    而宽松口径会退化成永远没人看的"已知差异"。修复:_round_like_js(v) = floor(v + 0.5),
    用于 4 处取整;验收口径收紧为「编码差异必须为 0」。

    二、发布包内夹带了开发/验收工具

    export_filter="all_resources" 且 exclude_filter 里没有 build/*,于是每次新增
    构建/验收脚本都被编译进产物 —— 包括故意不合规的坏服务端夹具
    (probe-ws-bad.gd)与向量文件:

    res://build/probe-release.gdc
    res://build/integration/probe-integration.gdc
    res://build/integration/probe-ws.gdc
    res://build/integration/probe-ws-bad.gdc      ← 故意违反协议的夹具
    res://build/integration/probe-frame-vectors.gdc
    res://build/integration/frame-vectors.json
    

    体积:OpenDance.pck 315,464 B → 145,400 B(54% 的 pck 是测试夹具)。
    已发布的 v0.2.3 同样带着这些残留。修复:exclude_filter 增加 build/*;
    并新增产物级防线 build/integration/list-pck.gd(遍历包内条目、标出
    res://build/、res://tests/、res://_scratch/、res://dist-release/、*.md 残留),
    接进 accept-release.sh 断言「无开发残留」—— 否则下次加个新工具目录又会重演。

    三、附件与解压(重要)

    资产 说明
    opendance-windows-v0.2.4.zip 单个完整包,不分卷:OpenDance.exe + OpenDance.pck(必须同目录)+ THIRD_PARTY.md + README.txt + README.md + contracts/
    SHA256SUMS 裸文件名,下载目录内直接 sha256sum -c SHA256SUMS

    解压需要 7-Zip / WinRAR / PeaZip:本包用 LZMA 压缩(26,632,886 B)以绕过本站
    前置 IIS 的 maxAllowedContentLength = 30,000,000 字节上限
    (同内容 deflate 包约 38 MB,会 HTTP 413)。Windows 10 资源管理器不支持
    LZMA(method 14) 的 zip
    ,双击会报错。

    四、发布前自检(本版实测)

    $ bash build/accept-release.sh dist-release/opendance-windows-v0.2.4.zip
      ✓ PE 版本资源一致:FileVersion 0.2.4.0 / 资源字符串 0.2.4
      ✓ 包内 pck 启动 180 帧无错误(退出码 0)
      ✓ pck 共 58 项,无开发残留(build/ tests/ _scratch/ *.md)
      ✓ 包内 version=0.2.4 / AboutScreen.app_version()=0.2.4 / 15 项关键资源可加载
      ✓ pck 内契约表与包内 contracts/VERSION 快照一致
    $ bash build/accept-ws.sh <zip>
      == 结果:30 通过 / 0 失败 ==(客户端)+ 服务端侧 16 项事实
    $ bash build/accept-frame-vectors.sh <zip>
      ✓ 解码用例 12/12,逐点比对 396 个,解码差异 0 项
      ✓ 编码器字节与参考实现完全一致(0 项差异)
    $ bash build/verify.sh
      == 结果:785 通过 / 0 失败,6 跳过 ==
    

    五、未在本环境验证(诚实声明)

    • 本仓库在 Linux 上导出 Windows 产物,没有 Windows 机器与真机 30 分钟联调:
      运行行为仍以「无头 785 项断言 + 包内 pck 启动 + 三条产物级验收」为证据;
    • 跨端集成验收(accept-integration.sh)需要一个已部署的 Web 服务端。
    Downloads
  • v0.2.3 a78a536476

    zijunchiang released this 2026-09-17 05:18:08 +08:00 | 10 commits to main since this release

    ⚠️ 本版已被 v0.2.4 取代(建议直接用 v0.2.4):
    v0.2.4 把编码取整与契约参考实现对齐(-2.5 的取整口径差异),
    并修掉了「发布包内夹带开发/验收工具」——本版 OpenDance.pck 里含有
    构建探针与一个故意违反协议的测试夹具(res://build/integration/*.gdc),
    体积占 pck 的 54%(315,464 B → v0.2.4 的 145,400 B)。
    功能不受影响,但不该被用户拿到。

    OpenDance Studio -- Windows 客户端 v0.2.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
    (与 opendance-web / opendance-android 逐字节一致)。

    一、新增:跨端集成验收(拿发布包里的客户端打真实服务端)

    本仓单测用的是假 HTTP 夹具,Web 端测试只验自己那一侧 —— 两端各自绿灯,
    不代表契约字段真的对得上(字段名、嵌套、null、单位、范围都可能一侧对一侧错)。
    所以本版加了 build/accept-integration.sh:用 --main-pack 加载包内 pck,
    打真实 Web 服务端,逐项断言:

    [integration] Windows 包内客户端 × 真实 Web 服务端:http://127.0.0.1:3100
      ✓ GET /health 200(服务端版本 0.7.4);契约 6 项全部一致
      ✓ 目录指纹非空;目录四类资源齐备:songs=… motions=… models=… scenes=…
      ✓ defaultModelId 解析为默认模型
      ✓ 重力 y=-3.50;基础风 (2.0,0.0,-1.0);阵风 4.0 m/s @ 0.50 Hz;风坐标系 world
      ✓ 地面摩擦/坡度 0.80/30°;碰撞体 mesh;出生点 yaw 90°;相机 orbit/6.0/2.0
      ✓ 环境光 2.0/雾 0.20;风采样 t=0 等于基础风;场景 GLB 可下载且魔数正确
      ✓ 动作内部标准 mediapipe33@0.1.0;客户端解析 2901 帧 == 服务端 2901 帧
      ✓ 无解析失败行;首帧 33 点;每帧带服务端关节角;30.00 fps;96.67 s
      ✓ 动作缩略图可下载且为 PNG;模型 vrm/默认模型/文件可下载
    [integration] ✓ 跨端集成探针全部通过
    

    播种用的是真实素材(示例文件/ 下的真 VMD → 内部标准 33 点;真 PMX → VRM)。

    二、探针首次运行就抓到的两个真实缺陷

    1. Motion.thumbnailUrl 被客户端丢掉 —— 服务端 catalog/export 从
    data-models 0.6.0 起一直在发该字段(同一文件的 Model / Scene 都有解析),
    客户端类型里却没有。已补字段与解析(缺失时为 "",兼容旧服务端),
    并新增 tests/test_catalog_types.gd(4 项 / 20 条断言)用服务端真实报文形状锁住;
    同时显式记录一处刻意不消费的差异:Model.usable / unusableReason
    (目录只下发可用模型,恒为 true,不可用模型的可见性由 Web 管理端负责)。

    2. 二进制响应白做 UTF-8 解码 —— ApiClient._request() 对所有响应无条件
    raw.get_string_from_utf8()。数据本身没错(二进制路径返回原始字节),但:

    • 每下载一个文件都会打印一条
      Unicode parsing error … Invalid UTF-8 leading byte (N) 噪声(探针里第一次注意到);
    • 白白把整个文件(模型可达数十 MB)解码成一份 String 拷贝后丢弃。

    已改为只在需要文本时解码。

    顺带修掉测试里写死的契约版本:tests/test_api_integration.gd 断言三项契约均为
    0.1.0。该用例只在服务端可达时才跑、平时一直 skip,所以契约升到 0.5.0 后没有任何
    地方发现它。现改为从仓库 contracts/VERSION 读期望值并与 /health 比对。

    三、附件与解压(重要)

    资产 说明
    opendance-windows-v0.2.3.zip 单个完整包,不分卷:OpenDance.exe + OpenDance.pck(必须同目录)+ THIRD_PARTY.md + README.txt + README.md + contracts/
    SHA256SUMS 裸文件名,下载目录内直接 sha256sum -c SHA256SUMS

    解压需要 7-Zip / WinRAR / PeaZip:本包用 LZMA 压缩(26,644,121 B)以绕过本站
    前置 IIS 的 maxAllowedContentLength = 30,000,000 字节上限
    (同内容 deflate 包约 38 MB,会 HTTP 413)。Windows 10 资源管理器不支持
    LZMA(method 14) 的 zip
    ,双击会报错。上限放开后可用
    ZIP_METHOD=deflate bash build/package-release.sh 0.2.3 重打包为可直接双击解压的包。

    四、发布前自检(本版实测)

    $ bash build/check-version.sh 0.2.3
      ✓ 版本一致:v0.2.3(project.godot = project.yaml = export_presets.cfg = 期望值)
    $ bash build/check-pe-version.sh <exe> 0.2.3
      ✓ PE 版本资源一致:FileVersion 0.2.3.0 / 资源字符串 0.2.3
    $ GODOT_BIN=... bash build/accept-release.sh dist-release/opendance-windows-v0.2.3.zip
      ✓ 包内 application/config/version = 0.2.3 / AboutScreen.app_version() = 0.2.3
      ✓ 主场景 / autoload / 15 项关键资源 / pck 内契约表与快照一致
     发布包级验收全部通过
    $ bash build/verify.sh
      == 结果:820 通过 / 0 失败,5 跳过 ==
    

    五、未在本环境验证的部分(诚实声明)

    • 本仓库在 Linux 上导出 Windows 产物,没有 Windows 机器与真机 30 分钟联调:
      运行行为仍以「无头断言 + 包内 pck 启动 + 包内探针」为证据;
    • 跨端集成验收需要已部署的 Web 服务端(本项目不部署它,契约边界如此)。
    Downloads
  • v0.2.2 ba988f6ca6

    zijunchiang released this 2026-09-17 04:23:00 +08:00 | 12 commits to main since this release

    ⚠️ 本版已被 v0.2.3 取代(建议直接用 v0.2.3):
    v0.2.3 由跨端集成验收抓出并修掉了两个真实缺陷 ——
    CatalogTypes.Motion 未解析服务端一直在发的 thumbnailUrl;
    ApiClient 对所有响应(含模型/GLB/PNG)无条件做 UTF-8 解码,既刷噪声日志又白做一份
    String 拷贝。另修掉测试里写死的契约版本(0.1.0)。

    OpenDance Studio -- Windows 客户端 v0.2.2

    修复:发布包 OpenDance.exe 的版本元数据(Windows「右键 → 属性 → 详细信息」里显示的
    文件版本 / 产品版本)。建议所有用户改用本版;v0.2.1 的包解开后属性页显示的是 0.1.0。

    契约快照不变: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-web / opendance-android 逐字节一致)。

    一、缺陷(v0.2.1 实测)

    opendance-windows-v0.2.1.zip → OpenDance.exe → 属性 → 详细信息
        文件版本    0.1.0
        产品版本    0.1.0
    

    产物名、Git tag、README 全都是 v0.2.1 —— 属于不可核对的发布。

    根因:export_presets.cfg 的 application/file_version /
    application/product_version 被硬编码在 0.1.0,而这两个键不会跟随
    project.godot 的 application/config/version 自动更新。
    build/check-version.sh 当时只比 project.godot ↔ project.yaml(两处一致),
    所以静态校验全绿、产物却是错的 —— 漂移发生在没人看的第三个位置。

    证据:

    $ strings -a -el OpenDance.exe | sed -n '3147,3151p'
    FileVersion
    0.1.0
    ProductVersion
    0.1.0
    
    $ VS_FIXEDFILEINFO @0x67b976c
    FileVersion=0.1.0.0  ProductVersion=0.0.0.0
    

    对照:官方模板 windows_release_x86_64.exe 的 FileVersion = 4.7.2,
    说明本机 rcedit 改写是生效的,问题纯粹出在预设的值本身。

    二、修复

    环节 做法
    同步 build/sync-export-version.sh(新增):导出前把版本号写进导出预设,幂等、拒绝非 X.Y.Z
    静态防线 build/check-version.sh:新增对导出预设两个键的校验
    产物防线 build/check-pe-version.sh(新增):直接读 exe 的 PE 版本资源 —— VS_FIXEDFILEINFO(签名 0xFEEF04BD 后 16 字节)+ StringFileInfo(strings -el,属性页显示的就是这两项)。两处都查:实测固定信息里的 ProductVersion 恒为 0.0.0.0
    打包 build/package-release.sh:打包前校验源 exe,解包后再校验包内 exe
    一键验证 build/verify.sh:新增步骤 1/5「产物 PE 版本资源」
    单元测试 tests/test_about.gd:预设两个键必须等于版本号唯一来源

    反向验证:把预设 file_version 改回 0.1.0 → check-version.sh 退出码 1;
    无头测试 753 通过 / 1 失败,失败项正是「导出预设的 file_version 与版本号唯一来源一致」。

    实测 v0.2.2 产物:PE FileVersion 0.2.2.0、StringFileInfo 0.2.2 ——
    版本号在 project.godot / project.yaml / export_presets.cfg / exe 元数据 /
    产物名 / Git tag 六处一致。build/verify.sh 全绿(754 通过 / 0 失败 / 5 跳过)。

    三、附件与解压(重要)

    资产 说明
    opendance-windows-v0.2.2.zip 单个完整包,不分卷:OpenDance.exe + OpenDance.pck(必须同目录)+ THIRD_PARTY.md + README.txt + README.md + contracts/
    SHA256SUMS 裸文件名,下载目录内直接 sha256sum -c SHA256SUMS
    97942f033cdd47ce4efe37b7b98921001bc00e531fae0be7bf6bc6cefcc33232  ← v0.2.2 首次打包(已作废)
    cfd7d675b2ebbb20b7db3e836a41dc7467ac33c856e31b3cfc8436df054e2332  opendance-windows-v0.2.2.zip
    

    解压需要 7-Zip / WinRAR / PeaZip:本包用 LZMA 压缩(26,628,529 B)以绕过
    本站前置 IIS 的 maxAllowedContentLength = 30,000,000 字节上限
    (同内容 deflate 包为 38,248,818 B,会 HTTP 413)。
    Windows 10 资源管理器不支持 LZMA(method 14) 的 zip,双击会报错。
    若该上限已放开、或包改由别处分发,可改用资源管理器直接双击解压的 deflate 包:
    ZIP_METHOD=deflate bash build/package-release.sh 0.2.2。

    四、发布前自检(本版实测输出)

    $ bash build/check-version.sh 0.2.2
      ✓ 版本一致:v0.2.2(project.godot = project.yaml = export_presets.cfg = 期望值)
    
    $ bash build/check-pe-version.sh build/windows/OpenDance.exe 0.2.2
        VS_FIXEDFILEINFO  FileVersion    = 0.2.2.0
        StringFileInfo    FileVersion    = 0.2.2
        StringFileInfo    ProductVersion = 0.2.2
      ✓ PE 版本资源一致:FileVersion 0.2.2.0 / 资源字符串 0.2.2
    

    五、未在本环境验证的部分(诚实声明)

    • 本仓库在 Linux 上导出 Windows 产物,没有 Windows 机器与真机 30 分钟联调:
      包的运行行为仍以「无头 754 项断言 + 180 帧启动检查」为证据;
    • build/export-windows.ps1(Windows 兜底导出路径)未在真实 Windows 上执行过。
    Downloads
  • v0.2.1 14ee5f7ec9

    zijunchiang released this 2026-09-17 03:59:30 +08:00 | 13 commits to main since this release

    ⚠️ 本版已被 v0.2.2 取代(建议直接用 v0.2.2):
    本版的 OpenDance.exe 在 Windows「右键 → 属性 → 详细信息」里显示的
    文件版本 / 产品版本是 0.1.0,而产物名与 tag 是 v0.2.1 —— 元数据不可核对。
    根因是 export_presets.cfg 的 application/file_version /
    application/product_version 被硬编码成 0.1.0 后无人更新;
    v0.2.2 起由 sync-export-version.sh 在导出前同步、由 check-pe-version.sh
    直接读产物 exe 的 PE 版本资源复核。

    OpenDance Studio -- Windows 客户端 v0.2.1

    场景包围盒修复 + 21 项"真机等价"无头测试 + 版本号一致性强制校验。
    本版取代 v0.2.0(v0.2.0 存在下述缺陷)。

    契约快照不变:rest-api 0.5.0 / websocket-keypoints 0.2.0 / data-models 0.7.0 /
    database 0.4.0(与 opendance-web / opendance-android 逐字节一致)。

    一、修复:场景包围盒在"未入树"时用 global_transform

    SceneRuntime._compute_aabb() 原先用 MeshInstance3D.global_transform 计算包围盒,
    而它在 _assemble() 里被调用 —— 那时运行时节点还没被加入场景树:

    • Godot 会打一行错误日志(真机每次载入场景都刷一条,与"日志里不应出现 ERROR"的
      排查约定冲突):

      ERROR: Condition "!is_inside_tree()" is true. Returning: Transform3D()
      
    • 树外的 global_transform 返回单位变换,于是算出来的只是各网格的局部 AABB。
      包围盒用于①重力/风 Area3D 的碰撞盒尺寸与位置 ②兜底地面的尺寸与位置 ——
      对于把网格摆在非原点位置的场景(导出 GLB 的常见情况),区域会偏小或偏位,
      风力/重力可能作用不到物体上。

    修复:改为从根节点往下累乘 Node3D.transform,不依赖是否入树;
    运行时挂在单位变换的父节点下时,结果与旧语义一致。

    二、新增 21 项无头"真机等价"测试(不需要设备)

    场景(tests/test_scene_config.gd)

    在代码里手写一个合法 GLB(三角形:POSITION 3×VEC3 + indices 3×u16 + BIN chunk)
    落盘后真实加载,核对:

    • 真实 GLB 加载 warnings 为空、不使用兜底地面;
    • colliders 三种取值:mesh → 按网格生成;auto 命中 *_col → 生成;
      auto 未命中 → 兜底地面并标记;none → 不生成也不兜底;
    • 重力 Area3D 的 gravity / gravity_direction 与服务端配置一致,
      且用 SPACE_OVERRIDE_REPLACE(不改全局 ProjectSettings);
    • 风力按基础风向量生效(与 WIND_FORCE_SCALE 对齐),describe() 摘要可核对;
    • 带位移网格(节点 translation [10,0,0])时,重力区域碰撞盒与兜底地面
      都跟着位移(x≈10)—— 即上述缺陷的回归测试。

    保活的时间维度(tests/test_pose_server.gd)

    用真实的 15 秒静默超时跑一次对照:

    • 只发应用层 ping、不发任何关键点帧的客户端,17 秒后仍保持连接
      —— 这正是"画面里没人就掉线、然后疯狂重连"的根因对照(契约 §1.1 的应用层心跳);
    • 连上后什么都不发的客户端被 close(1001, "timeout") 断开(超时机制仍有效,
      且按契约 §7 对端不会重连)。

    三、新增版本号一致性强制校验

    build/check-version.sh:强制 project.godot 的 application/config/version
    (「关于」清单与导出 .pck 的唯一来源)与 project.yaml、发布版本号三者一致;
    已接入 build/package-release.sh(打包前)与 build/verify.sh(第 0/4 步),
    并做过反向验证(把 project.godot 改错后校验立刻失败)。
    此前没有任何机制保证这两个文件同步 —— 界面显示的版本可能与产物名不一致。

    本版三者一致为 0.2.1,并已用 strings 核对导出 .pck 内的版本号同为 0.2.1。

    校验

    • build/verify.sh 四步全通过:版本一致性 → 脚本编译 → 751 项断言(原 720)→
      180 帧启动无运行时错误;
    • 导出 OpenDance.exe 106,605 KiB(PE 头 MZ)+ OpenDance.pck 141 KiB;
    • 整包 7z t 完整性测试通过、解压后 OpenDance.exe + OpenDance.pck 同目录。

    交付物与校验和

    opendance-windows-v0.2.1.zip     26,627,191 字节(LZMA 压缩,单个完整包)
      ├── OpenDance.exe
      ├── OpenDance.pck
      ├── THIRD_PARTY.md
      ├── README.txt / README.md
      └── contracts/                 契约快照(与另两端逐字节一致)
    SHA256SUMS                       裸文件名,下载目录内 sha256sum -c 直接可用
    

    opendance-windows-v0.2.1.zip sha256:
    d49885327047f5a52de6c732431ea080cd1a030ae1c581a8bc0ec0d99bfb792c

    ⚠️ 解压要求:本包用 LZMA 压缩(发布时 Gitea 站点 IIS 的
    maxAllowedContentLength 仍是默认的 30,000,000 字节,37 MB 的 deflate 整包会返回
    HTTP 413)。Windows 10 的资源管理器不支持 LZMA(method 14) 的 zip,请用
    7-Zip / WinRAR / PeaZip 解压
    ;解压后 OpenDance.exe 与 OpenDance.pck
    必须在同一目录。若运维已把 IIS 上限放开到 256 MB,可用
    bash build/package-release.sh 0.2.1 得到可双击解压的 deflate 包。

    下载与安装

    sha256sum -c SHA256SUMS
    7z x opendance-windows-v0.2.1.zip
    # 进入目录后双击 OpenDance.exe
    
    Downloads
  • v0.2.0 86e5decd10

    zijunchiang released this 2026-09-17 03:42:06 +08:00 | 14 commits to main since this release

    ⚠️ 本版已被 v0.2.1 取代(建议直接用 v0.2.1):
    v0.2.0 存在场景包围盒缺陷 —— SceneRuntime._compute_aabb() 在节点入树前调用
    global_transform,会打一行 !is_inside_tree() 的 ERROR,且对把网格摆在非原点
    位置的场景算出的范围偏小/偏位(风力可能作用不到物体上)。
    v0.2.1 已修复,并新增 21 项"真机等价"无头测试与版本号一致性强制校验。

    OpenDance Studio -- Windows 客户端 v0.2.0

    场景选择与物理落地(《DSH 开发文档 v1.6》5.6 / T-WIN-013)、
    「关于」清单版本号(11.2 / T-WIN-012)、发布必须是单个完整包(5.7 / T-WIN-014)、
    连接保活与设备去重(6.5 / T-WIN-015)。

    契约快照同步到 rest-api 0.5.0、websocket-keypoints 0.2.0、data-models 0.7.0、
    database 0.4.0(与 opendance-web / opendance-android 逐字节一致)。

    ✅ 发布资产已就位:opendance-windows-v0.2.0.zip(26,625,705 B)+ SHA256SUMS。

    本包使用 LZMA 压缩:发布时 Gitea 站点 IIS 的
    maxAllowedContentLength 仍是默认的 30,000,000 字节,37 MB 的 deflate 整包
    上传固定返回 HTTP 413(16.4 MB 通过、30.5 MB / 37 MB / 40 MB 全部 413)。
    为了不再拆分卷,改为 ZIP_METHOD=lzma 打包:37 MB → 26 MB,得以正常上传。

    ⚠️ 解压要求:Windows 10 的资源管理器不支持 LZMA(method 14) 的 zip,
    请用 7-Zip / WinRAR / PeaZip 解压(Win11 24H2+ 起资源管理器原生支持 7z 等格式,
    但本项目未在 Windows 上实测)。解压后目录内必须是
    OpenDance.exe + OpenDance.pck 同目录,双击 OpenDance.exe 运行。

    若运维已把 IIS 上限放开到 256 MB,可用默认方式重新打包得到可双击解压的 deflate 包:
    bash build/package-release.sh 0.2.0(约 38 MB)。

    sha256sum -c SHA256SUMS     # 期望 OK
    7z x opendance-windows-v0.2.0.zip
    

    【排查更正】 此前我把另一个现象(HTTP 500 {"message":"","url":"…/api/swagger"},
    空消息)判成"Gitea 宿主机磁盘写满"——那是误判:该接口 multipart 字段名是
    attachment,用 file= 才会得到这个空消息 500。Gitea 附件接口本身完全正常
    (同一 1 KB 文件:-F "attachment=@…" → 201、--data-binary @…?name= → 201、
    -F "file=@…" → 500)。正确写法记在 deploy/proxy/README.md 第九节。

    连接保活与设备去重(T-WIN-015,本次一并交付)

    与 Android 端 v0.2.0 的 T-AND-011「两端一起改」,契约 websocket-keypoints 提升到 0.2.0:

    • welcome / config 声明 silentTimeoutMs = 15000 与 heartbeatIntervalMs = 5000
      (心跳 < 静默超时的一半);新增应用层 ping / pong。
      原 5 秒静默超时 + 客户端只有协议层 ping(底层库自动应答,本端应用层看不到)
      是"画面里没人就掉线、然后疯狂重连"的根因;
    • 按 hello.deviceId 去重:同一设备的新连接替换旧连接(旧连接以 1000 关闭,
      对端不会重连),界面显示去重后的设备数;
    • 逐客户端维护与 Android 端同名的连接状态
      (connecting → handshaking → streaming → degraded,终态 stopped),
      并记录 close code / 协商子协议 / 连接·握手·首帧时间;「查看接收状态」可逐台查看。

    无头测试 720 通过 / 0 失败(test_pose_server.gd 新增 7 项),
    build/verify.sh 三步全通过。

    校验

    检查 结果
    无头测试 720 通过 / 0 失败(test_pose_server.gd 新增 7 项;场景相关 12 项)
    build/verify.sh 三步全通过(脚本编译 / 无头测试 / 180 帧启动无运行时错误)
    Windows 导出 OpenDance.exe 106,605 KiB(PE 头 MZ 校验通过)+ OpenDance.pck 141 KiB
    整包完整性自检 解压后 OpenDance.exe + OpenDance.pck 同目录同名、PE 头 MZ、pck 魔数 GDPC
    包内文档与 tag 树一致 README.txt / README.md / THIRD_PARTY.md / contracts/* 共 11 个文件 md5 逐字节一致
    版本号 project.godot 与导出 .pck 均为 0.2.0;「关于」清单展示 v0.2.0

    交付物与校验和

    opendance-windows-v0.2.0.zip     26,625,705 字节(LZMA 压缩,单个完整包;解压后约 104 MB)
      ├── OpenDance.exe
      ├── OpenDance.pck
      ├── THIRD_PARTY.md
      ├── README.txt / README.md
      └── contracts/                 契约快照(与另两端逐字节一致)
    SHA256SUMS                       裸文件名,下载目录内 sha256sum -c 直接可用
    

    opendance-windows-v0.2.0.zip sha256:
    e45398bcf4a50e6ddd6f4d475f3e8f19dc7c33177663fa447980a771bc869e03

    关于本次重新打包(域名占位符修正)

    交付文档里原有的「Gitea 地址 / 属主」占位符已补齐为真实值
    (gitea.kasugano.cn / 属主 zijunchiang)—— 域名与仓库属主属于「部署必需且
    非隐私」的信息,文档中直接写明
    ;口令、访问令牌等真正的秘密项仍是占位符。

    因为本整包还没有上传成功(见上),所以直接按修正后的文档重新打包,
    避免发布出一个域名仍是占位符的包;因此 sha256 由
    e45398bcf4a50e6ddd6f4d475f3e8f19dc7c33177663fa447980a771bc869e03
    更新为 e45398bcf4a50e6ddd6f4d475f3e8f19dc7c33177663fa447980a771bc869e03,
    并把 v0.2.0 标签移到含修正文档的提交上。

    下载后

    sha256sum -c SHA256SUMS
    unzip opendance-windows-v0.2.0.zip
    # 进入目录后双击 OpenDance.exe(OpenDance.pck 必须与它同目录)
    
    Downloads
  • v0.1.0 aef5f88083

    zijunchiang released this 2026-09-14 20:05:51 +08:00 | 35 commits to main since this release

    ⚠️ 本版已废弃,请直接使用 v0.2.2

    不要再按下面的分卷说明操作。 下面那套「先 cat 合并 3 个分卷」的流程
    是本项目早期受 Gitea 前置 IIS 上传上限所迫的临时方案,现已作废:
    发布规则改为只上传单个完整包,不再提供任何 .partN 分卷。

    为什么不建议再用本版(contracts/VERSION 实测,取出包内快照比对):

    契约项 v0.1.0 包内 当前服务端
    rest-api 0.1.0 0.5.0
    websocket-keypoints 0.1.0 0.2.0
    data-models 0.1.0 0.7.0
    skeleton-topology 0.1.0 0.2.0
    model-formats 0.1.0 0.5.0
    database 0.1.0 0.4.0

    契约差 4 个大版本:本版不认服务端 0.5.0 目录里的 scenes[](没有场景选择),
    也没有 0.2.0 的连接保活 / 设备去重 / 状态机,「关于」页面同样不显示版本号。
    也就是说:即使你成功合并并解压,跑起来也对不上当前服务端。

    本版的分卷资产保留(已核验:三个分卷的 sha256 与 SHA256SUMS.txt 一致、
    合并后 unzip -t 无错、包内 OpenDance.exe 的 PE 头为 MZ、OpenDance.pck 存在),
    仅作历史存档,不再作为可用发布推荐。


    OpenDance Studio — Windows 客户端 v0.1.0

    阶段二交付物:Godot 4 客户端,接收 Android 辅助 App 的 33 点骨骼关键点,
    驱动 VRM 角色并 DTW 实时评分。只接收关键点,不接收、不存储视频画面。

    关于附件(历史存档,已作废)

    发布包 36.4 MB,超过本 Gitea 实例反向代理的单次上传上限(实测 20 MB 可通过、
    30 MB 被拒),因此拆分为 3 个分卷。请先合并:

    cat opendance-windows-v0.1.0.zip.part* > opendance-windows-v0.1.0.zip
    sha256sum -c SHA256SUMS.txt
    

    合并结果的 sha256 为
    87edb67242c0fcd596bbb79fb2484a6af1401813d33be3dbc61207fbd967f4e2(已验证一致)。

    治本做法是在反向代理上放开限制:client_max_body_size 100m;(Gitea 自身限制为 100 MB)。
    也可直接从源码打包:bash build/export-windows.sh release && bash build/package-release.sh 0.1.0

    交付内容

    文件 说明
    OpenDance.exe 主程序(Windows x86_64,PE 头校验通过,104 MB)
    OpenDance.pck 资源包(必须与 exe 同目录,107 KB)
    THIRD_PARTY.md 第三方开源项目声明(15 项)
    README.txt 使用说明(含防火墙、评分规则、FAQ)
    contracts/ opendance-web v0.1.0 契约快照

    任务完成情况

    T-WIN-001 → T-WIN-011 全部完成,project.yaml 中状态均为 done。

    验收结果

    脚本编译        ✓ 全部通过(无 SCRIPT ERROR)
    无头测试        ✓ 580 / 580 通过(8 个测试套件)
    应用启动        ✓ 180 帧无运行时错误
    Windows 导出    ✓ OpenDance.exe 104 MB + OpenDance.pck,PE(MZ) 校验通过
    真实 VRM        ✓ 154 骨骼 VRoid 模型,humanoid 覆盖率 100%
    骨骼重定向      ✓ 关键点方向与骨骼实际指向点积 1.0000
    跨实现交叉校验  ✓ 关节角与 Web 服务端 TypeScript 实现逐帧一致
    

    关键验证说明

    跨实现交叉校验:本端 GDScript 从服务端下发的关键点重新计算 9 个关节角,
    与服务端 TypeScript 实现写在同一份 NDJSON 里的 angles 逐帧比对,最大偏差 < 1e-3。
    这证明两端对冻结契约的理解完全一致。

    骨骼重定向功能性验证:不是「函数被调用了」,而是给定一组关键点后,
    读出 VRM 骨骼在世界空间的实际指向,与关键点方向做点积 —— 结果为 1.0000。
    这个合成公式是在真实 VRM 上暴力枚举 5 种候选后实测标定的(误差 1.9e-8)。

    测试框架自身的可靠性:发现测试运行器会把「静默失败的方法」记成通过
    (脚本编译失败、协程被主循环截断等),已加固为:未执行任何断言的测试方法一律计为失败、
    编译失败的测试文件硬失败、带 await 的异步测试可跨帧正常完成。
    加固过程中因此暴露并修复了 3 个真实缺陷,其中一个导致 VRoid 模型骨骼覆盖率为 0%。

    使用

    解压后先启动 Web 管理服务端,再运行 OpenDance.exe(需放行 TCP 8765 入站)。
    详见 README.txt。

    已知事项

    • Godot 的 WebSocketPeer 不暴露握手路径,无法校验 /pose,仅校验子协议
    • 文档原选型 godot-vrm 不发布预编译产物,改用 Godot 内置 glTF 导入器 + 自实现骨骼名映射
    • export-windows.ps1 未在真实 Windows 上执行(本次环境无 Windows)
    • 真实 VRM 样例因版权未入库,测试找不到时显式跳过
    Downloads