cozyclay 2.1.1 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (585) hide show
  1. package/CHANGELOG.md +88 -0
  2. package/README.md +12 -30
  3. package/bin/agent/agent-routes.mjs +43 -116
  4. package/bin/agent/agent-runner.mjs +14 -15
  5. package/bin/agent/cliproxy-provider.mjs +135 -0
  6. package/bin/agent/credential-store.mjs +30 -7
  7. package/bin/agent/pi-tools.mjs +4 -1
  8. package/bin/agent/provider-keys.mjs +32 -0
  9. package/bin/agent/provider-login.mjs +110 -0
  10. package/bin/agent/provider-routes.mjs +99 -0
  11. package/bin/agent/providers.mjs +19 -97
  12. package/bin/agent/script-tool.mjs +17 -4
  13. package/bin/agent/session-store.mjs +2 -2
  14. package/bin/agent/studio-context-budget.mjs +93 -0
  15. package/bin/agent/studio-motion-reference.mjs +23 -0
  16. package/bin/agent/studio-prompt.mjs +1 -1
  17. package/bin/agent/studio-rebase-text.mjs +32 -0
  18. package/bin/agent/studio-rebase.mjs +26 -39
  19. package/bin/agent/studio-tools.mjs +9 -28
  20. package/bin/agent/tool-arguments.mjs +49 -0
  21. package/bin/agent/turn-frames.mjs +66 -0
  22. package/bin/codex-auth.mjs +9 -2
  23. package/bin/cozyclay.mjs +10 -116
  24. package/bin/live/cli.mjs +3 -3
  25. package/bin/mcp-runtime.mjs +2 -12
  26. package/bin/package-signature.mjs +0 -4
  27. package/dist/app/index.html +7 -6
  28. package/dist/assets/EXRLoader-CvVIvGVE.js +1 -0
  29. package/dist/assets/analytics-BWCqdgWA.js +1 -0
  30. package/dist/assets/app-DfTCxaKk.js +5087 -0
  31. package/dist/assets/app-f-fkV5uP.css +1 -0
  32. package/dist/assets/compile-worker-BxKXh07s.js +5 -0
  33. package/dist/assets/fflate.module-KbGj5-H6.js +5 -0
  34. package/dist/assets/{first-shot-handoff-msLI71g1.js → first-shot-handoff-DNO8kv_N.js} +1 -1
  35. package/dist/assets/{landing-ChUvB_zL.js → landing-yfZaJkWc.js} +1 -1
  36. package/dist/assets/scene-asset-sync-U3kS2rvK.js +20 -0
  37. package/dist/assets/scene-asset-sync-_S8NQl5B.css +1 -0
  38. package/dist/assets/workflow-D78eiKTa.js +179 -0
  39. package/dist/cozyclay-package.json +1 -1
  40. package/dist/index.html +3 -3
  41. package/dist/sw.js +3 -6
  42. package/dist/workflow/index.html +5 -4
  43. package/mcp/LIVE-PROTOCOL.md +7 -47
  44. package/mcp/README.md +16 -26
  45. package/mcp/live-hub.mjs +6 -10
  46. package/mcp/package.json +1 -3
  47. package/mcp/tool-handlers.mjs +4 -168
  48. package/package.json +3 -22
  49. package/src/App.jsx +151 -2625
  50. package/src/agent-progress.js +80 -0
  51. package/src/agent-turn-mark.js +30 -0
  52. package/src/analytics.js +1 -19
  53. package/src/app-context.js +12 -2
  54. package/src/app-stage.jsx +2 -34
  55. package/src/asset-pane.jsx +6 -5
  56. package/src/camera-block.js +21 -0
  57. package/src/camera-direction.js +120 -0
  58. package/src/character-kind.js +3 -9
  59. package/src/command-bus.js +10 -8
  60. package/src/commands/cast.js +5 -34
  61. package/src/commands/elements/character.js +1 -1
  62. package/src/commands/elements/motion.js +1 -6
  63. package/src/commands/elements/object.js +6 -2
  64. package/src/commands/elements/shot.js +4 -1
  65. package/src/commands/elements.js +38 -14
  66. package/src/commands/index.js +3 -1
  67. package/src/commands/kits.js +37 -0
  68. package/src/commands/motion-timing.js +57 -0
  69. package/src/commands/motion.js +9 -152
  70. package/src/commands/motion3-compile.js +65 -0
  71. package/src/commands/motion3.js +214 -0
  72. package/src/commands/objects.js +6 -4
  73. package/src/commands/shot.js +55 -13
  74. package/src/commands/stage.js +14 -1
  75. package/src/commands/view.js +4 -1
  76. package/src/document-mirrors.js +42 -0
  77. package/src/document-store.js +4 -0
  78. package/src/domains/cast.js +19 -194
  79. package/src/domains/motion/motion-range-pin-rules.js +1 -1
  80. package/src/domains/motion/take-source.js +53 -0
  81. package/src/domains/motion.js +60 -1838
  82. package/src/domains/scenes.js +12 -55
  83. package/src/domains/shots.js +2 -2
  84. package/src/domains/stage.js +4 -2
  85. package/src/draft-ghost.js +47 -0
  86. package/src/draft-ghost.jsx +129 -0
  87. package/src/dualview.jsx +4 -3
  88. package/src/effects/EffectsLayer.jsx +112 -0
  89. package/src/effects/effect-meshes.js +232 -0
  90. package/src/effects/effect-record.js +103 -0
  91. package/src/effects/emitter.js +59 -0
  92. package/src/effects/simulate.js +261 -0
  93. package/src/effects/state.js +59 -0
  94. package/src/execution-telemetry.js +2 -3
  95. package/src/first-success-guide.jsx +5 -5
  96. package/src/ghost-set.js +257 -0
  97. package/src/held-object-edit.jsx +113 -0
  98. package/src/held-object-pose.js +175 -0
  99. package/src/hierarchy-model.js +1 -1
  100. package/src/hierarchy-panel.jsx +1 -1
  101. package/src/imported-mesh.jsx +103 -0
  102. package/src/kits/held.js +84 -0
  103. package/src/kits/index.js +70 -0
  104. package/src/kits/smoking.js +57 -0
  105. package/src/light-blockers.js +93 -0
  106. package/src/motion/beat-board-model.js +84 -0
  107. package/src/motion/beat-board.css +124 -0
  108. package/src/motion/beat-board.jsx +60 -0
  109. package/src/motion/center-of-mass.js +66 -0
  110. package/src/motion/fix-collisions.js +850 -0
  111. package/src/motion/physics-review.js +118 -0
  112. package/src/{ardy → motion}/physics-support.js +1 -76
  113. package/src/motion/rig-snapshot.js +22 -0
  114. package/src/motion/take-segments.jsx +140 -0
  115. package/src/{ardy → motion}/timeline-coordinates.js +0 -21
  116. package/src/{ardy → motion}/timeline.css +1 -2
  117. package/src/{ardy → motion}/timeline.jsx +42 -413
  118. package/src/motion/waypoints.js +76 -0
  119. package/src/motion3/beats.js +83 -0
  120. package/src/motion3/body.js +158 -0
  121. package/src/motion3/bones.js +47 -0
  122. package/src/motion3/carried.js +47 -0
  123. package/src/motion3/compile-job.js +79 -0
  124. package/src/motion3/compile-worker.js +10 -0
  125. package/src/motion3/compiler/anchors.js +113 -0
  126. package/src/motion3/compiler/arm-orient.js +128 -0
  127. package/src/motion3/compiler/channels.js +125 -0
  128. package/src/motion3/compiler/compile.js +205 -0
  129. package/src/motion3/compiler/gait-rhythm.js +97 -0
  130. package/src/motion3/compiler/grip.js +171 -0
  131. package/src/motion3/compiler/head-steady.js +48 -0
  132. package/src/motion3/compiler/hold.js +134 -0
  133. package/src/motion3/compiler/idle.js +113 -0
  134. package/src/motion3/compiler/limbs.js +197 -0
  135. package/src/motion3/compiler/math.js +72 -0
  136. package/src/motion3/compiler/pose.js +177 -0
  137. package/src/motion3/compiler/quat.js +49 -0
  138. package/src/motion3/compiler/skeleton.js +74 -0
  139. package/src/motion3/compiler/validate-common.js +32 -0
  140. package/src/motion3/compiler/validate-goals.js +118 -0
  141. package/src/motion3/compiler/validate-objects.js +144 -0
  142. package/src/motion3/compiler/validate-parts.js +118 -0
  143. package/src/motion3/compiler/validate.js +122 -0
  144. package/src/motion3/compiler/vocab.js +74 -0
  145. package/src/motion3/compiler/walk-pelvis.js +275 -0
  146. package/src/motion3/compiler/walk.js +207 -0
  147. package/src/motion3/compiler/wrist-clamp.js +32 -0
  148. package/src/motion3/delta.js +47 -0
  149. package/src/motion3/describe.js +177 -0
  150. package/src/motion3/docs.js +27 -0
  151. package/src/motion3/edit-carry.js +21 -0
  152. package/src/motion3/fix/ease.js +16 -0
  153. package/src/motion3/fix/ground.js +37 -0
  154. package/src/motion3/fix/index.js +52 -0
  155. package/src/motion3/fix/push.js +71 -0
  156. package/src/motion3/fix/reach.js +46 -0
  157. package/src/motion3/fix/retime.js +79 -0
  158. package/src/motion3/fix/self.js +211 -0
  159. package/src/motion3/fix/slide.js +70 -0
  160. package/src/motion3/fix/turn.js +51 -0
  161. package/src/motion3/follow.js +39 -0
  162. package/src/motion3/free-motion.js +204 -0
  163. package/src/motion3/grip-choice.js +130 -0
  164. package/src/motion3/hold-plan.js +157 -0
  165. package/src/motion3/json-patch.js +77 -0
  166. package/src/motion3/key-aim.js +105 -0
  167. package/src/motion3/key-edit.js +82 -0
  168. package/src/motion3/lenient.js +127 -0
  169. package/src/motion3/object-keys.js +236 -0
  170. package/src/motion3/object-pose.js +182 -0
  171. package/src/motion3/object-tracks.js +12 -0
  172. package/src/motion3/people.js +82 -0
  173. package/src/motion3/pipeline.js +102 -0
  174. package/src/motion3/playback.js +51 -0
  175. package/src/motion3/probes.js +91 -0
  176. package/src/motion3/qa/body-checks.js +34 -0
  177. package/src/motion3/qa/check-names.js +14 -0
  178. package/src/motion3/qa/checks.js +125 -0
  179. package/src/motion3/qa/contact-checks.js +51 -0
  180. package/src/motion3/qa/explain.js +80 -0
  181. package/src/motion3/qa/fmt.js +5 -0
  182. package/src/motion3/qa/foot-checks.js +72 -0
  183. package/src/motion3/qa/geometry.js +77 -0
  184. package/src/motion3/qa/goals.js +191 -0
  185. package/src/motion3/qa/ground.js +60 -0
  186. package/src/motion3/qa/hints-contact.js +195 -0
  187. package/src/motion3/qa/hints-goal.js +160 -0
  188. package/src/motion3/qa/hints-knee.js +24 -0
  189. package/src/motion3/qa/hints-motion.js +209 -0
  190. package/src/motion3/qa/hints-object.js +91 -0
  191. package/src/motion3/qa/index.js +44 -0
  192. package/src/motion3/qa/key-checks.js +82 -0
  193. package/src/motion3/qa/near.js +96 -0
  194. package/src/motion3/qa/object-checks.js +135 -0
  195. package/src/motion3/qa/patch.js +161 -0
  196. package/src/motion3/qa/people-checks.js +37 -0
  197. package/src/motion3/qa/severity.js +38 -0
  198. package/src/motion3/qa/spec-checks.js +65 -0
  199. package/src/motion3/qa/style.js +228 -0
  200. package/src/motion3/qa/wrist-checks.js +69 -0
  201. package/src/motion3/qa/wrist-obs.js +60 -0
  202. package/src/motion3/refs.js +129 -0
  203. package/src/motion3/repair-tune.js +121 -0
  204. package/src/motion3/repair.js +83 -0
  205. package/src/motion3/report.js +67 -0
  206. package/src/motion3/rigs/index.js +14 -0
  207. package/src/motion3/rigs/x-bot-tpose-body.json +1 -0
  208. package/src/motion3/rigs/x-bot-tpose.json +1 -0
  209. package/src/motion3/rigs/y-bot-tpose-body.json +1 -0
  210. package/src/motion3/rigs/y-bot-tpose.json +1 -0
  211. package/src/motion3/scene.js +60 -0
  212. package/src/motion3/schema/brief.js +89 -0
  213. package/src/motion3/schema/fields.js +44 -0
  214. package/src/motion3/schema/spec-examples.js +46 -0
  215. package/src/motion3/schema/topics.js +113 -0
  216. package/src/motion3/schema/types.js +149 -0
  217. package/src/motion3/search.js +117 -0
  218. package/src/motion3/second-hand.js +112 -0
  219. package/src/motion3/settle.js +136 -0
  220. package/src/motion3/skills/basic.js +83 -0
  221. package/src/motion3/skills/book.js +76 -0
  222. package/src/motion3/skills/car.js +145 -0
  223. package/src/motion3/skills/flip.js +200 -0
  224. package/src/motion3/skills/frames-auto.js +29 -0
  225. package/src/motion3/skills/impact.js +109 -0
  226. package/src/motion3/skills/index.js +85 -0
  227. package/src/motion3/skills/info.js +80 -0
  228. package/src/motion3/skills/smoke-kit.js +109 -0
  229. package/src/motion3/skills/smoke.js +160 -0
  230. package/src/motion3/spec-store.js +59 -0
  231. package/src/motion3/take-edit.js +155 -0
  232. package/src/motion3/take.js +63 -0
  233. package/src/motion3/timeline.js +127 -0
  234. package/src/motion3/views.js +121 -0
  235. package/src/motion3/walk-plan.js +119 -0
  236. package/src/object-catalog.jsx +7 -1
  237. package/src/object-colors.js +98 -0
  238. package/src/object-gizmo-parts.js +115 -0
  239. package/src/object-gizmo.jsx +37 -122
  240. package/src/object-glow.js +139 -0
  241. package/src/object-hidden.js +33 -0
  242. package/src/object-look.js +196 -0
  243. package/src/object-size.js +10 -0
  244. package/src/object-travel.js +71 -6
  245. package/src/panels/CameraPanel.jsx +7 -7
  246. package/src/panels/HdrEnvironmentControls.jsx +59 -0
  247. package/src/panels/LightPanel.jsx +25 -4
  248. package/src/panels/ObjectLookPanel.jsx +88 -0
  249. package/src/panels/PosePanel.jsx +2 -17
  250. package/src/panels/RigControlPanel.jsx +5 -53
  251. package/src/panels/SubjectBox.jsx +4 -1
  252. package/src/panels/details.css +14 -0
  253. package/src/posestudio.jsx +4 -27
  254. package/src/project-browser.jsx +3 -4
  255. package/src/project-resources.js +18 -31
  256. package/src/project.js +13 -104
  257. package/src/props.jsx +25 -280
  258. package/src/qa-label.js +25 -0
  259. package/src/rail-dot-drag.js +23 -0
  260. package/src/render-passes.js +10 -0
  261. package/src/resource-status.jsx +1 -0
  262. package/src/result-modal.jsx +4 -19
  263. package/src/room.jsx +20 -12
  264. package/src/scene-assets.js +8 -6
  265. package/src/scene-light-place.js +72 -0
  266. package/src/scene-lights.jsx +148 -0
  267. package/src/scene-objects.js +31 -139
  268. package/src/scenes.js +15 -105
  269. package/src/semantic-edit.js +2 -5
  270. package/src/set-pieces.jsx +183 -0
  271. package/src/settings-menu.jsx +3 -11
  272. package/src/shell/BottomDock.jsx +9 -51
  273. package/src/shell/DetailsSlot.jsx +16 -200
  274. package/src/shell/GhostsMenuGroup.jsx +74 -0
  275. package/src/shell/LibrarySlot.jsx +1 -3
  276. package/src/shell/MenuBar.jsx +3 -3
  277. package/src/shell/PreferencesDialog.jsx +15 -264
  278. package/src/shell/PreferencesSlot.jsx +2 -8
  279. package/src/shell/TopBar.jsx +5 -84
  280. package/src/shell/ViewportToolbar.jsx +10 -70
  281. package/src/shell/agent-glass.css +19 -6
  282. package/src/shell/details-selection.js +42 -0
  283. package/src/shell/ghosts-menu.css +22 -0
  284. package/src/shell/glass-regions.css +29 -3
  285. package/src/shell/preferences.css +6 -1
  286. package/src/shot-authoring.js +4 -7
  287. package/src/soft-shadows.js +37 -0
  288. package/src/stage-attach-frames.js +12 -12
  289. package/src/stage-canvas-rigs.jsx +3 -3
  290. package/src/stage-capture.jsx +42 -8
  291. package/src/stage-characters.jsx +22 -216
  292. package/src/stage-editor-gizmos.jsx +6 -6
  293. package/src/stage-environment.js +93 -0
  294. package/src/stage-hdr-builtins.js +107 -0
  295. package/src/stage-hdr-image.js +116 -0
  296. package/src/stage-hdr-library.js +70 -0
  297. package/src/stage-hdr-map.js +94 -0
  298. package/src/stage-hdr.js +130 -0
  299. package/src/stage-lighting.js +149 -0
  300. package/src/stage-occlusion.js +210 -0
  301. package/src/stage-sky.jsx +159 -0
  302. package/src/stage-startup-defaults.js +5 -9
  303. package/src/studio-actions.js +16 -14
  304. package/src/studio-agent-commands.js +19 -16
  305. package/src/studio-agent-motion.js +9 -9
  306. package/src/studio-agent-protocol.js +47 -77
  307. package/src/studio-app-binding.js +27 -47
  308. package/src/studio-asset-list.js +17 -0
  309. package/src/studio-contact-sheet.js +37 -5
  310. package/src/studio-elements.js +27 -7
  311. package/src/studio-entity-bounds.js +18 -0
  312. package/src/studio-error-codes.js +15 -0
  313. package/src/studio-export-framing.js +152 -0
  314. package/src/studio-lighting-check.js +103 -0
  315. package/src/studio-motion-visual.js +150 -0
  316. package/src/studio-schema-errors.js +80 -0
  317. package/src/studio-support-gap.js +74 -0
  318. package/src/styles.css +1 -19
  319. package/src/timeline-defaults.js +5 -0
  320. package/src/timeline-extent.js +8 -20
  321. package/src/tutorial-walk.js +17 -0
  322. package/src/ui-scrub.js +1 -1
  323. package/src/use-shot-camera-tracks.js +12 -0
  324. package/src/view-ghosts.js +97 -0
  325. package/src/view-ghosts.jsx +49 -0
  326. package/src/workflow/AgentPanel.jsx +47 -166
  327. package/src/workflow/AgentProgressCard.jsx +109 -0
  328. package/src/workflow/AgentReplyText.jsx +37 -0
  329. package/src/workflow/AgentTurnSteps.jsx +84 -0
  330. package/src/workflow/LoginPanel.jsx +140 -0
  331. package/src/workflow/WorkflowBuilder.jsx +7 -23
  332. package/src/workflow/agent-client.js +54 -51
  333. package/src/workflow/agent-panel.css +71 -1
  334. package/src/workflow/agent-progress-card.css +167 -0
  335. package/src/workflow/agent-progress-view.js +47 -0
  336. package/src/workflow/agent-turn-steps.css +113 -0
  337. package/src/workflow/agent-turn.js +191 -0
  338. package/src/workflow/login-client.js +34 -0
  339. package/src/workflow/motion-input.js +18 -31
  340. package/src/workflow/node-schema.js +1 -1
  341. package/src/workflow/reply-markdown.js +69 -0
  342. package/src/workflow/scene-asset-sync.js +8 -8
  343. package/tools/agent-session-stats.mjs +61 -0
  344. package/tools/dev-full.mjs +5 -56
  345. package/tools/eslint-baseline.json +12 -13
  346. package/tools/knip-baseline.json +0 -179
  347. package/tools/loc-baseline.json +31 -81
  348. package/tools/motion3/extract-body.mjs +103 -0
  349. package/tools/motion3/extract-rig.mjs +85 -0
  350. package/tools/process-supervisor.mjs +0 -88
  351. package/tools/run-tests.mjs +9 -125
  352. package/bin/agent/motion-runtime.mjs +0 -76
  353. package/dist/ardy/cskel27-rest.json +0 -557
  354. package/dist/assets/analytics-C9pMpW7s.js +0 -1
  355. package/dist/assets/app-B_2XB9rw.css +0 -1
  356. package/dist/assets/app-DAuvKPP8.js +0 -4920
  357. package/dist/assets/config-Bx7pYsD9.js +0 -1
  358. package/dist/assets/config-DeoFTYzb.css +0 -1
  359. package/dist/assets/demo-CvKuBgy5.js +0 -1
  360. package/dist/assets/scene-asset-sync-DKkpjKBV.js +0 -19
  361. package/dist/assets/scene-asset-sync-DjJ_cJ2R.css +0 -1
  362. package/dist/assets/ticket-BPk2Ni95.js +0 -1
  363. package/dist/assets/workflow-jJRBR94Z.js +0 -179
  364. package/dist/demo/walk-then-stop.npz +0 -0
  365. package/mcp/ardy-prompts.mjs +0 -218
  366. package/src/ardy/auto-fix-panel.css +0 -108
  367. package/src/ardy/auto-physics.js +0 -1194
  368. package/src/ardy/client.js +0 -153
  369. package/src/ardy/convert.js +0 -313
  370. package/src/ardy/cskel27-neutral.js +0 -39
  371. package/src/ardy/cskel27.js +0 -77
  372. package/src/ardy/export.js +0 -165
  373. package/src/ardy/fix-collisions.js +0 -2257
  374. package/src/ardy/foot-lock.js +0 -230
  375. package/src/ardy/motion-calibration.js +0 -118
  376. package/src/ardy/motion-edit.js +0 -213
  377. package/src/ardy/motion-url.js +0 -55
  378. package/src/ardy/mp4-duration.js +0 -102
  379. package/src/ardy/npz.js +0 -595
  380. package/src/ardy/physics-panel.css +0 -21
  381. package/src/ardy/physics-panel.jsx +0 -89
  382. package/src/ardy/physics-refine.js +0 -111
  383. package/src/ardy/physics-review.js +0 -567
  384. package/src/ardy/physics-temporal.js +0 -54
  385. package/src/ardy/platform-fit-panel.css +0 -64
  386. package/src/ardy/platform-fit-panel.jsx +0 -41
  387. package/src/ardy/platform-fit.js +0 -326
  388. package/src/ardy/playback.js +0 -711
  389. package/src/ardy/pose-pin.js +0 -97
  390. package/src/ardy/prompt-clips.js +0 -30
  391. package/src/ardy/retime.js +0 -211
  392. package/src/ardy/root-drop.js +0 -369
  393. package/src/ardy/timeline-resize.js +0 -13
  394. package/src/ardy/to-cskel27.js +0 -225
  395. package/src/ardy/trim.js +0 -33
  396. package/src/ardy/waypoints.js +0 -369
  397. package/src/ardy-bridge-contract.js +0 -281
  398. package/src/domains/motion/motion-video-capture.js +0 -664
  399. package/src/i2v-motion-client.js +0 -77
  400. package/src/i2v-motion-studio.jsx +0 -180
  401. package/src/line-edit.js +0 -1348
  402. package/src/motion/generation.js +0 -105
  403. package/src/motion-readiness-ui.jsx +0 -67
  404. package/src/motion-readiness.js +0 -40
  405. package/src/motion-resources.js +0 -177
  406. package/src/motion-store.js +0 -65
  407. package/src/motion-trail.js +0 -601
  408. package/src/multimodel-ingest.js +0 -394
  409. package/src/panels/PromptBlocksPanel.jsx +0 -444
  410. package/src/panels/VideoCapturePanel.jsx +0 -181
  411. package/src/pose-extract/browser.js +0 -42
  412. package/src/pose-extract/detector.js +0 -100
  413. package/src/pose-extract/fit.js +0 -227
  414. package/src/pose-extract/image-frame.js +0 -51
  415. package/src/pose-extract/index.js +0 -58
  416. package/src/pose-extract/keyframes.js +0 -74
  417. package/src/pose-extract/landmarks.js +0 -162
  418. package/src/pose-extract/mirror.js +0 -153
  419. package/src/pose-extract/take.js +0 -131
  420. package/src/pose-extract/video-frames.js +0 -91
  421. package/src/take-recipe.js +0 -165
  422. package/src/trail-key-conflicts.js +0 -39
  423. package/src/trail-pick.js +0 -59
  424. package/src/use-i2v-capture-modal.js +0 -15
  425. package/tools/ardy/BRIDGE.md +0 -37
  426. package/tools/ardy/GVHMR-NPZ.md +0 -68
  427. package/tools/ardy/README.md +0 -124
  428. package/tools/ardy/__pycache__/cclay_gvhmr_worker.cpython-313.pyc +0 -0
  429. package/tools/ardy/artifacts.mjs +0 -34
  430. package/tools/ardy/bridge.mjs +0 -1732
  431. package/tools/ardy/bvh-cskel27.mjs +0 -1265
  432. package/tools/ardy/cclay_constrained_generate.py +0 -561
  433. package/tools/ardy/cclay_gvhmr_worker.py +0 -264
  434. package/tools/ardy/cclay_motion_edit.py +0 -510
  435. package/tools/ardy/cclay_sequence_generate.py +0 -705
  436. package/tools/ardy/cclay_worker.py +0 -304
  437. package/tools/ardy/dump-npz.py +0 -205
  438. package/tools/ardy/extract-rest.mjs +0 -299
  439. package/tools/ardy/extract.mjs +0 -507
  440. package/tools/ardy/footage.mjs +0 -467
  441. package/tools/ardy/gvhmr-floor.mjs +0 -102
  442. package/tools/ardy/gvhmr-to-cskel27.mjs +0 -21
  443. package/tools/ardy/gvhmr_fastpath.py +0 -168
  444. package/tools/ardy/gvhmr_trajectory.py +0 -240
  445. package/tools/ardy/merge-text-encoder.py +0 -160
  446. package/tools/ardy/mocap-metrics.mjs +0 -200
  447. package/tools/ardy/mocap-quality-gate.mjs +0 -110
  448. package/tools/ardy/motion-stabilize.mjs +0 -348
  449. package/tools/ardy/npz.mjs +0 -414
  450. package/tools/ardy/pose-to-npz.mjs +0 -106
  451. package/tools/ardy/prompt-limits.mjs +0 -5
  452. package/tools/ardy/run-edit-on-box.sh +0 -73
  453. package/tools/ardy/run-local.mjs +0 -233
  454. package/tools/ardy/run-on-box.sh +0 -593
  455. package/tools/ardy/run-sequence-on-box.sh +0 -177
  456. package/tools/ardy/runners/gvhmr-worker.mjs +0 -206
  457. package/tools/ardy/runners/index.mjs +0 -18
  458. package/tools/ardy/runners/local.mjs +0 -455
  459. package/tools/ardy/runners/proc.mjs +0 -125
  460. package/tools/ardy/runners/remote.mjs +0 -252
  461. package/tools/ardy/setup-local.mjs +0 -189
  462. package/tools/ardy/setup-text-encoder-on-box.sh +0 -93
  463. package/tools/ardy/setup-text-encoder.py +0 -306
  464. package/tools/ardy/smpl-cskel27.mjs +0 -178
  465. package/tools/ardy/visual-qa.mjs +0 -196
  466. package/tools/ardy/vq-car.mjs +0 -52
  467. package/tools/bench/EXP3.md +0 -61
  468. package/tools/bench/cclay_bench_extract_incam.py +0 -125
  469. package/tools/bench/cclay_bench_extract_obs.py +0 -204
  470. package/tools/bench/cclay_bench_runner.py +0 -42
  471. package/tools/bench/cube-contact.mjs +0 -162
  472. package/tools/bench/exp3.mjs +0 -152
  473. package/tools/bench/extract-bench-lib.mjs +0 -216
  474. package/tools/bench/extract-bench.mjs +0 -302
  475. package/tools/bench/fal-generate.mjs +0 -88
  476. package/tools/bench/fit/README.md +0 -189
  477. package/tools/bench/fit/camera.mjs +0 -59
  478. package/tools/bench/fit/contact.mjs +0 -419
  479. package/tools/bench/fit/footlock.mjs +0 -234
  480. package/tools/bench/fit/motion.mjs +0 -85
  481. package/tools/bench/fit/pin.mjs +0 -27
  482. package/tools/bench/fit/remote.mjs +0 -105
  483. package/tools/bench/fit-bench.mjs +0 -126
  484. package/tools/bench/fit-sanity.mjs +0 -45
  485. package/tools/bench/metrics.mjs +0 -313
  486. package/tools/bench/obs/depth.mjs +0 -258
  487. package/tools/bench/obs/extrinsics.mjs +0 -175
  488. package/tools/bench/obs/fit_mannequin_betas.py +0 -340
  489. package/tools/bench/obs/ground.mjs +0 -294
  490. package/tools/bench/obs/heading.mjs +0 -151
  491. package/tools/bench/obs/ladder.mjs +0 -555
  492. package/tools/bench/obs/mannequin-betas.json +0 -124
  493. package/tools/bench/obs/remote.mjs +0 -83
  494. package/tools/bench/obs/rest_joints.py +0 -52
  495. package/tools/bench/obs/ybot-targets.mjs +0 -49
  496. package/tools/bench/obs-bench.mjs +0 -520
  497. package/tools/bench/score.mjs +0 -343
  498. package/tools/bench/summarize.mjs +0 -86
  499. package/tools/demo-worker/README.md +0 -137
  500. package/tools/demo-worker/api-client.mjs +0 -233
  501. package/tools/demo-worker/generate.mjs +0 -301
  502. package/tools/demo-worker/index.mjs +0 -466
  503. package/tools/demo-worker/sign-core.mjs +0 -112
  504. package/tools/demo-worker/sign.mjs +0 -161
  505. package/tools/gt-render/browser.mjs +0 -182
  506. package/tools/gt-render/camera-math.mjs +0 -276
  507. package/tools/gt-render/page.mjs +0 -267
  508. package/tools/gt-render/render.mjs +0 -514
  509. package/tools/gt-render/scene-box.mjs +0 -31
  510. package/tools/gt-render/take-transform.mjs +0 -87
  511. package/tools/kimodo/compare-seam.mjs +0 -108
  512. package/tools/kimodo/constraints.mjs +0 -244
  513. package/tools/kimodo/edit.mjs +0 -259
  514. package/tools/kimodo/effector-constraints.mjs +0 -200
  515. package/tools/kimodo/generate.mjs +0 -646
  516. package/tools/kimodo/local-output.mjs +0 -265
  517. package/tools/kimodo/measure-pose.mjs +0 -65
  518. package/tools/kimodo/measure-preserve.mjs +0 -899
  519. package/tools/kimodo/measure-waypoints.mjs +0 -55
  520. package/tools/kimodo/mlx-generate.py +0 -111
  521. package/tools/kimodo/pose-constraints.mjs +0 -248
  522. package/tools/kimodo/preserve-mask.mjs +0 -543
  523. package/tools/kimodo/read-npz.mjs +0 -189
  524. package/tools/kimodo/run-edit-on-box.mjs +0 -155
  525. package/tools/kimodo/run-sequence-on-box.mjs +0 -178
  526. package/tools/kimodo/runner.mjs +0 -284
  527. package/tools/kimodo/seam-batch.mjs +0 -77
  528. package/tools/kimodo/setup-local.mjs +0 -30
  529. package/tools/kimodo/setup-on-box.sh +0 -339
  530. package/tools/kimodo/soma77-to-cskel27.mjs +0 -305
  531. package/tools/morphgs/assets/gen_truth.py +0 -39
  532. package/tools/morphgs/assets/mesh_ori_rig.txt +0 -27
  533. package/tools/morphgs/assets/playback-check.mjs +0 -30
  534. package/tools/morphgs/demo-gate.sh +0 -26
  535. package/tools/morphgs/fbx2morphgs.mjs +0 -68
  536. package/tools/morphgs/morphgs-to-cskel27.mjs +0 -105
  537. package/tools/morphgs/patches/preprocess_src-none-mode.patch +0 -76
  538. package/tools/morphgs/setup-on-cluster.sh +0 -126
  539. package/tools/projflow/driver.py +0 -1069
  540. package/tools/projflow/generate.mjs +0 -805
  541. package/tools/projflow/hml22-to-cskel27.mjs +0 -735
  542. package/tools/projflow/line-edit-job.mjs +0 -547
  543. package/tools/projflow/replay.mjs +0 -452
  544. package/tools/projflow/runner.mjs +0 -269
  545. package/tools/projflow/service.mjs +0 -742
  546. package/tools/track/DESIGN.md +0 -513
  547. package/tools/track/backfill-provenance.mjs +0 -116
  548. package/tools/track/budget.mjs +0 -8
  549. package/tools/track/check-rig.mjs +0 -209
  550. package/tools/track/diagnostics.schema.json +0 -60
  551. package/tools/track/export-rig.mjs +0 -256
  552. package/tools/track/fallback.mjs +0 -7
  553. package/tools/track/fk-parity-fixture.mjs +0 -161
  554. package/tools/track/gate.mjs +0 -349
  555. package/tools/track/masks.mjs +0 -318
  556. package/tools/track/metrics.mjs +0 -201
  557. package/tools/track/publish-obs.mjs +0 -108
  558. package/tools/track/py/check_env.py +0 -61
  559. package/tools/track/py/eval_lr.py +0 -229
  560. package/tools/track/py/lr_viterbi.py +0 -294
  561. package/tools/track/py/masks.py +0 -405
  562. package/tools/track/py/objective.py +0 -382
  563. package/tools/track/py/rig.py +0 -508
  564. package/tools/track/py/scene.py +0 -326
  565. package/tools/track/py/test_joint_indices.py +0 -123
  566. package/tools/track/py/test_lr_viterbi.py +0 -195
  567. package/tools/track/py/test_masks.py +0 -229
  568. package/tools/track/py/test_rig.py +0 -288
  569. package/tools/track/py/test_scene.py +0 -354
  570. package/tools/track/py/test_track.py +0 -328
  571. package/tools/track/py/track.py +0 -411
  572. package/tools/track/remote.mjs +0 -140
  573. package/tools/track/rig-dump.mjs +0 -227
  574. package/tools/track/run-box-tests.mjs +0 -14
  575. package/tools/track/run-box.mjs +0 -168
  576. package/tools/track/setup-box.sh +0 -59
  577. package/tools/track/study-2d.mjs +0 -728
  578. /package/src/{ardy → motion}/collision-blockers.js +0 -0
  579. /package/src/{ardy → motion}/ground.js +0 -0
  580. /package/src/{ardy → motion}/ik-drag.js +0 -0
  581. /package/src/{ardy → motion}/ik-key-json.js +0 -0
  582. /package/src/{ardy → motion}/ik.js +0 -0
  583. /package/src/{ardy → motion}/physics-surface.js +0 -0
  584. /package/src/{ardy → motion}/playback-clock.js +0 -0
  585. /package/src/{ardy → motion}/range-pin.js +0 -0
@@ -1,735 +0,0 @@
1
- /**
2
- * hml22-to-cskel27.mjs — ProjFlow's HumanML3D 22-joint POSITION stream → the
3
- * exact motion arrays the cclay npz encoder consumes ({ frames, fps, rotMats,
4
- * rootPos, posedJoints }), i.e. the same shape tools/kimodo/soma77-to-cskel27.mjs
5
- * and tools/ardy/bvh-cskel27.mjs produce. Everything downstream — the npz
6
- * writer, measure-preserve, playback, the splice — is written against that
7
- * shape, so this file's whole job is to end at it.
8
- *
9
- * WHY POSITIONS AND NOT ROTATIONS (the one structural difference from Kimodo).
10
- * The checkpoint we target is `ACMDM_Raw_Flow_S_PatchSize22`. ACMDM's "Raw"
11
- * family generates ABSOLUTE JOINT COORDINATES — the model's output tensor is
12
- * [T, 22, 3] metres at 20 fps with no rotation channel at all (that is the
13
- * backbone paper's thesis: "Absolute Coordinates Make Motion Generation Easy").
14
- * soma77ToCskel27Motion is handed `global_rot_mats` and only has to re-express
15
- * them; here the rotations DO NOT EXIST YET and must be lifted from positions.
16
- * Plan C8 amendment (2026-08-29) froze that: input is positions, the converter
17
- * lifts.
18
- *
19
- * THREE MOVES, deliberately the same three as soma77-to-cskel27.mjs:
20
- * 1. NAME MAPPING with an explicit null for every cskel27 joint the source
21
- * cannot author (CSKEL27_FROM_HML22).
22
- * 2. NEAREST-MAPPED-ANCESTOR rule for those nulls: an unauthored joint borrows
23
- * its nearest mapped ancestor's GLOBAL rotation, so its LOCAL comes out
24
- * identity — the same "not authored" convention poseToCskel27 and
25
- * bvhToCskel27Motion use.
26
- * 3. EVERYTHING THROUGH GLOBAL SPACE. cskel27 and hml22 do not share a spine
27
- * segmentation (cskel27 runs Hips→Spine→Spine1→Spine2→Spine3, four links
28
- * before the shoulder carrier; hml22 runs pelvis→spine1→spine2→spine3,
29
- * three), so a cskel27 local is only well defined as
30
- * parentGlobalᵀ · global. Anything between two mapped joints is absorbed
31
- * into the child's local and no rotation is lost.
32
- *
33
- * THE NEW MOVE: POSITIONS → GLOBALS ("aim + inherited twist").
34
- * For every mapped cskel27 joint we know a rest bone vector (from the canonical
35
- * cskel27 skeleton) and the observed direction to the same descendant in the
36
- * hml22 frame. The global rotation is then
37
- *
38
- * G_j = swing( G_parent · restDir_j → obsDir_j ) · G_parent
39
- *
40
- * i.e. start from the parent's orientation, then apply the MINIMAL rotation that
41
- * puts the bone on the observed direction. Twist is INHERITED from the parent
42
- * rather than invented, which is the physically right default (the forearm's
43
- * roll follows the upper arm unless something says otherwise) and — the reason
44
- * it is the right ENGINEERING default too — it is a continuous function of the
45
- * parent, so a smooth input clip produces a smooth output clip. Two joints get
46
- * better than that: Hips and Spine3 each see TWO independent directions (the hip
47
- * axis, the shoulder axis), so their full orientation including twist is
48
- * recovered exactly by orthonormalising a two-vector frame. Those two carry the
49
- * whole body's heading, which is why they are the ones worth pinning.
50
- *
51
- * TEMPORAL CONTINUITY IS PART OF THE CONTRACT, not a nicety. A twist flip
52
- * between two frames reads as a limb snapping through 180° and would survive
53
- * every positional gate, because positions are invariant to it. The lift is
54
- * continuous everywhere except at two measure-zero branch points — an
55
- * antiparallel swing (bone reversed exactly through its parent's rest aim) and a
56
- * two-vector frame whose secondary collapses onto its primary. At both, this
57
- * converter resolves the branch by continuing the PREVIOUS FRAME (`carry`),
58
- * never by an arbitrary seed. See liftHml22PoseGlobals.
59
- *
60
- * WHAT THIS CANNOT RECOVER, by construction, from positions alone:
61
- * - axial TWIST of any single-child bone (forearm pronation, humerus roll,
62
- * shin roll, the head's roll about the neck axis). A joint chain's positions
63
- * are invariant to twist of the parent bone about its own axis. Measured on
64
- * real takes this is 26–55° on the arms. Positions are sub-millimetre;
65
- * rotations are approximate. Plan GP4 carve-out: measure and report, do not
66
- * gate on it in v1.
67
- * - the 5 cskel27 joints hml22 has no source for (Spine2, L/R HandEnd,
68
- * L/R HandThumb1) — filled with identity locals, 4.7–6.1 cm positional
69
- * error, accepted losses per GP4. None of them is a line-edit target that
70
- * hml22 can author.
71
- * Neither loss moves a MAPPED joint's position, which is what a line edit is
72
- * scored on.
73
- *
74
- * PITFALL THIS FILE EXISTS TO DOCUMENT (the hml22 analogue of the soma77 leg
75
- * shift): hml22 uses SMPL naming, where `left_collar` is the CLAVICLE and
76
- * `left_shoulder` is the UPPER-ARM root. cskel27 calls those `LeftShoulder` and
77
- * `LeftArm`. Mapping by matching name text would put the shoulder's rotation on
78
- * the clavicle and shear the whole arm. Likewise hml22's `left_foot` (joint 10)
79
- * is the TOE BASE — the ankle is `left_ankle` (7).
80
- *
81
- * FPS: the output keeps the source rate (20 fps, ACMDM's own). Retiming onto the
82
- * 24 fps app timeline happens DOWNSTREAM, exactly as it does for Kimodo takes —
83
- * this file must not retime, or the retimer would run twice.
84
- */
85
-
86
- import { CSKEL27_JOINTS, CSKEL27_PARENTS } from "../../src/ardy/cskel27.js";
87
- import { deriveBoneOffsets, forwardKinematics, matMul, matTranspose } from "../../src/ardy/convert.js";
88
- import { canonicalCskel27Reference } from "../../src/ardy/to-cskel27.js";
89
-
90
- /**
91
- * The HumanML3D / t2m 22-joint skeleton, in npz index order.
92
- *
93
- * SOURCE OF TRUTH, two independent confirmations (S2, 2026-08-29):
94
- * 1. github.com/EricGuo5513/HumanML3D `paramUtil.py` → `t2m_kinematic_chain`
95
- * = [[0,2,5,8,11], [0,1,4,7,10], [0,3,6,9,12,15], [9,14,17,19,21],
96
- * [9,13,16,18,20]]. That fixes the TOPOLOGY and the left/right ordering
97
- * exactly: index 1 is the LEFT hip (it heads the chain that also contains
98
- * 4,7,10) and index 2 the right.
99
- * 2. The names are SMPL's, because HumanML3D's 22 joints are SMPL body joints
100
- * 0..21 verbatim: github.com/vchoutas/smplx `smplx/joint_names.py`.
101
- * The two agree on every entry: joint 9 (`spine3`) is the parent of 12/13/14,
102
- * which is precisely the "carries the neck and both clavicles" role.
103
- */
104
- export const HML22_JOINTS = [
105
- "pelvis", // 0
106
- "left_hip", // 1
107
- "right_hip", // 2
108
- "spine1", // 3
109
- "left_knee", // 4
110
- "right_knee", // 5
111
- "spine2", // 6
112
- "left_ankle", // 7
113
- "right_ankle", // 8
114
- "spine3", // 9
115
- "left_foot", // 10 ← TOE BASE, not the ankle
116
- "right_foot", // 11 ← TOE BASE, not the ankle
117
- "neck", // 12
118
- "left_collar", // 13 ← CLAVICLE (cskel27 "LeftShoulder")
119
- "right_collar", // 14
120
- "head", // 15
121
- "left_shoulder", // 16 ← UPPER ARM (cskel27 "LeftArm")
122
- "right_shoulder", // 17
123
- "left_elbow", // 18
124
- "right_elbow", // 19
125
- "left_wrist", // 20
126
- "right_wrist", // 21
127
- ];
128
-
129
- /** Parent index per hml22 joint, expanded from t2m_kinematic_chain. */
130
- export const HML22_PARENTS = [
131
- null, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9, 12, 13, 14, 16, 17, 18, 19,
132
- ];
133
-
134
- /**
135
- * cskel27 joint name → the hml22 joint that drives it, or null for "this joint
136
- * is not authored by the source".
137
- *
138
- * TORSO ANCHORING is structural, not cosmetic, exactly as in the soma77 case.
139
- * Hips↔pelvis is the root in both. cskel27's Spine3 carries the neck AND both
140
- * clavicles; hml22's `spine3` (9) carries `neck` (12) and both collars (13,14).
141
- * So Spine3↔spine3 is FORCED. That leaves three cskel27 links (Spine, Spine1,
142
- * Spine2) spanning the two hml22 links (spine1, spine2) between the anchors, so
143
- * exactly one cskel27 spine joint must go unauthored. Spine2 is the one chosen,
144
- * for the same reason soma77-to-cskel27 chose it: mapping bottom-up keeps the
145
- * lower spine — where the large trunk rotation lives — driven by real data and
146
- * pushes the identity link to the top of the chain, where the residual
147
- * Spine2→Spine3 rotation is absorbed into Spine3's local anyway.
148
- *
149
- * The hand ends and thumbs stay unauthored: hml22 stops at the wrist. Borrowing
150
- * anything would invent finger articulation the model never generated.
151
- */
152
- export const CSKEL27_FROM_HML22 = {
153
- Hips: "pelvis",
154
- Spine: "spine1",
155
- Spine1: "spine2",
156
- Spine2: null,
157
- Spine3: "spine3",
158
- Neck: "neck",
159
- Head: "head",
160
-
161
- RightShoulder: "right_collar",
162
- RightArm: "right_shoulder",
163
- RightForeArm: "right_elbow",
164
- RightHand: "right_wrist",
165
- RightHandEnd: null,
166
- RightHandThumb1: null,
167
-
168
- LeftShoulder: "left_collar",
169
- LeftArm: "left_shoulder",
170
- LeftForeArm: "left_elbow",
171
- LeftHand: "left_wrist",
172
- LeftHandEnd: null,
173
- LeftHandThumb1: null,
174
-
175
- RightUpLeg: "right_hip",
176
- RightLeg: "right_knee",
177
- RightFoot: "right_ankle",
178
- RightToeBase: "right_foot",
179
-
180
- LeftUpLeg: "left_hip",
181
- LeftLeg: "left_knee",
182
- LeftFoot: "left_ankle",
183
- LeftToeBase: "left_foot",
184
- };
185
-
186
- /**
187
- * Per mapped cskel27 joint, the DESCENDANT whose bone direction determines this
188
- * joint's global rotation, plus (where a second independent direction exists)
189
- * the pair whose difference pins the twist.
190
- *
191
- * `aim` names a cskel27 joint, but the direction is measured between the two
192
- * joints' HML22 SOURCES — which is why Spine1 aims at Spine3 and not Spine2:
193
- * Spine2 is unauthored, so in the reconstructed skeleton G_Spine2 === G_Spine1
194
- * and the EFFECTIVE bone leaving Spine1 is Spine1→Spine3.
195
- *
196
- * A null entry is a joint whose own orientation positions cannot observe (no
197
- * mapped child below it): Head, both Hands, both ToeBases. They inherit their
198
- * parent's global, so their local is identity — and their POSITION is still
199
- * exact, because it is produced by the parent's aim.
200
- */
201
- const AIM = {
202
- Hips: { aim: "Spine", twistRef: ["LeftUpLeg", "RightUpLeg"] },
203
- Spine: { aim: "Spine1" },
204
- Spine1: { aim: "Spine3" },
205
- Spine2: null,
206
- Spine3: { aim: "Neck", twistRef: ["LeftShoulder", "RightShoulder"] },
207
- Neck: { aim: "Head" },
208
- Head: null,
209
-
210
- LeftShoulder: { aim: "LeftArm" },
211
- LeftArm: { aim: "LeftForeArm" },
212
- LeftForeArm: { aim: "LeftHand" },
213
- LeftHand: null,
214
- LeftHandEnd: null,
215
- LeftHandThumb1: null,
216
-
217
- RightShoulder: { aim: "RightArm" },
218
- RightArm: { aim: "RightForeArm" },
219
- RightForeArm: { aim: "RightHand" },
220
- RightHand: null,
221
- RightHandEnd: null,
222
- RightHandThumb1: null,
223
-
224
- LeftUpLeg: { aim: "LeftLeg" },
225
- LeftLeg: { aim: "LeftFoot" },
226
- LeftFoot: { aim: "LeftToeBase" },
227
- LeftToeBase: null,
228
-
229
- RightUpLeg: { aim: "RightLeg" },
230
- RightLeg: { aim: "RightFoot" },
231
- RightFoot: { aim: "RightToeBase" },
232
- RightToeBase: null,
233
- };
234
-
235
- const IDENTITY = [
236
- [1, 0, 0],
237
- [0, 1, 0],
238
- [0, 0, 1],
239
- ];
240
-
241
- /** cskel27 joints whose Y decides where the floor is (same set as soma77). */
242
- const GROUND_JOINTS = ["LeftFoot", "LeftToeBase", "RightFoot", "RightToeBase"];
243
-
244
- const CSKEL_INDEX = new Map(CSKEL27_JOINTS.map((name, index) => [name, index]));
245
- const HML_INDEX = new Map(HML22_JOINTS.map((name, index) => [name, index]));
246
-
247
- /** cskel27 index → hml22 index, or -1 when unauthored. */
248
- export const CSKEL27_TO_HML22_INDEX = CSKEL27_JOINTS.map((name) => {
249
- const source = CSKEL27_FROM_HML22[name];
250
- return source === null || source === undefined ? -1 : HML_INDEX.get(source);
251
- });
252
-
253
- /** hml22 index → cskel27 index. Total: every hml22 joint has exactly one target. */
254
- export const HML22_TO_CSKEL27_INDEX = HML22_JOINTS.map((name) => {
255
- const target = CSKEL27_JOINTS.findIndex((joint) => CSKEL27_FROM_HML22[joint] === name);
256
- if (target < 0) {
257
- throw new Error(`hml22-to-cskel27: hml22 joint ${name} has no cskel27 target`);
258
- }
259
- return target;
260
- });
261
-
262
- /**
263
- * Per cskel27 joint, the hml22 index whose orientation it takes. An unmapped
264
- * joint walks up the cskel27 parent chain to the nearest mapped ancestor, which
265
- * is what makes its local come out identity. Verbatim the soma77 rule.
266
- */
267
- export function resolveSourceIndices() {
268
- const resolved = new Array(CSKEL27_JOINTS.length);
269
- for (let index = 0; index < CSKEL27_JOINTS.length; index += 1) {
270
- let cursor = index;
271
- let source = CSKEL27_FROM_HML22[CSKEL27_JOINTS[cursor]];
272
- while (source == null) {
273
- cursor = CSKEL27_PARENTS[cursor];
274
- if (cursor === null) {
275
- throw new Error(
276
- `hml22ToCskel27Motion: ${CSKEL27_JOINTS[index]} has no mapped ancestor`
277
- );
278
- }
279
- source = CSKEL27_FROM_HML22[CSKEL27_JOINTS[cursor]];
280
- }
281
- resolved[index] = HML_INDEX.get(source);
282
- }
283
- return resolved;
284
- }
285
-
286
- // ---------------------------------------------------------------------------
287
- // small vector helpers (convert.js exports matrix maths but no matVec)
288
- // ---------------------------------------------------------------------------
289
-
290
- const sub = (a, b) => [a[0] - b[0], a[1] - b[1], a[2] - b[2]];
291
- const dot = (a, b) => a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
292
- const cross = (a, b) => [
293
- a[1] * b[2] - a[2] * b[1],
294
- a[2] * b[0] - a[0] * b[2],
295
- a[0] * b[1] - a[1] * b[0],
296
- ];
297
- const norm = (a) => Math.hypot(a[0], a[1], a[2]);
298
-
299
- function unit(a, label) {
300
- const length = norm(a);
301
- if (!(length > 1e-9)) {
302
- throw new Error(`hml22ToCskel27Motion: degenerate direction for ${label}`);
303
- }
304
- return [a[0] / length, a[1] / length, a[2] / length];
305
- }
306
-
307
- function matVec(m, v) {
308
- return [
309
- m[0][0] * v[0] + m[0][1] * v[1] + m[0][2] * v[2],
310
- m[1][0] * v[0] + m[1][1] * v[1] + m[1][2] * v[2],
311
- m[2][0] * v[0] + m[2][1] * v[1] + m[2][2] * v[2],
312
- ];
313
- }
314
-
315
- /** Component of `v` perpendicular to unit vector `axis`, or null if it vanishes. */
316
- function rejectFrom(v, axis) {
317
- if (!v) return null;
318
- const k = dot(v, axis);
319
- const out = [v[0] - axis[0] * k, v[1] - axis[1] * k, v[2] - axis[2] * k];
320
- return norm(out) > 1e-6 ? out : null;
321
- }
322
-
323
- /**
324
- * Minimal ("swing") rotation taking unit vector `from` onto unit vector `to`,
325
- * returned together with the axis it turned about.
326
- *
327
- * THE BRANCH POINT. When `from` and `to` are antiparallel every axis
328
- * perpendicular to `from` is a valid 180° rotation, and picking a fixed seed
329
- * (say +X) makes the choice jump the moment the bone crosses that
330
- * configuration — a visible 180° limb flip between two adjacent frames. `hint`
331
- * is the axis this same joint turned about on the PREVIOUS frame; continuing it
332
- * is the branch nearest the previous frame, which is exactly the continuity
333
- * rule this converter promises. The fixed seed survives only as the
334
- * first-frame fallback, where there is no previous frame to be near.
335
- */
336
- function swingWithAxis(from, to, hint, label) {
337
- const cosine = Math.max(-1, Math.min(1, dot(from, to)));
338
- if (cosine > 1 - 1e-12) {
339
- // Already aligned: identity, and the previous axis stays the live hint so
340
- // a momentary alignment does not erase the branch we have been following.
341
- return { matrix: IDENTITY.map((row) => row.slice()), axis: hint ?? null };
342
- }
343
- let axis;
344
- if (cosine < -1 + 1e-9) {
345
- const continued = rejectFrom(hint, from);
346
- const seed = continued ?? (Math.abs(from[0]) < 0.9 ? [1, 0, 0] : [0, 1, 0]);
347
- axis = continued
348
- ? unit(continued, `${label} antiparallel continuation`)
349
- : unit(cross(from, seed), `${label} antiparallel swing`);
350
- } else {
351
- axis = unit(cross(from, to), `${label} swing`);
352
- }
353
- const sine = Math.sqrt(Math.max(0, 1 - cosine * cosine));
354
- const t = 1 - cosine;
355
- const [x, y, z] = axis;
356
- return {
357
- matrix: [
358
- [t * x * x + cosine, t * x * y - sine * z, t * x * z + sine * y],
359
- [t * x * y + sine * z, t * y * y + cosine, t * y * z - sine * x],
360
- [t * x * z - sine * y, t * y * z + sine * x, t * z * z + cosine],
361
- ],
362
- axis,
363
- };
364
- }
365
-
366
- /**
367
- * Orthonormal frame (as a rotation matrix, columns e1/e2/e3) from two vectors.
368
- * `hint` is the previous frame's e2 for this joint: it only comes into play when
369
- * the secondary collapses onto the primary (a body folded so the hip axis lies
370
- * along the spine), which is the other branch point, resolved the same way.
371
- */
372
- function frameOf(primary, secondary, label, hint) {
373
- const e1 = unit(primary, `${label} primary`);
374
- let projected = rejectFrom(secondary, e1);
375
- if (!projected) projected = rejectFrom(hint, e1);
376
- if (!projected) {
377
- throw new Error(`hml22ToCskel27Motion: ${label} secondary is parallel to its primary`);
378
- }
379
- const e2 = unit(projected, `${label} secondary`);
380
- const e3 = cross(e1, e2);
381
- return [
382
- [e1[0], e2[0], e3[0]],
383
- [e1[1], e2[1], e3[1]],
384
- [e1[2], e2[2], e3[2]],
385
- ];
386
- }
387
-
388
- // ---------------------------------------------------------------------------
389
- // 27 → 22 (downsample). Positions only.
390
- //
391
- // This is the direction the BOX is fed: ProjFlow's preservation rows are the
392
- // source take's own frames expressed in hml22 space, so the driver needs the
393
- // inverse of this file. It is also what the verify harness uses to manufacture
394
- // an hml22 fixture out of a real cclay take without a HumanML3D download.
395
- // Pure index gather — lossless by construction, since every hml22 joint has a
396
- // cskel27 counterpart.
397
- // ---------------------------------------------------------------------------
398
-
399
- /**
400
- * @param {{frames?:number, posedJoints:ArrayLike<number>}} input cskel27 [T,27,3]
401
- * @returns {Float32Array} hml22 positions, [T,22,3]
402
- */
403
- export function cskel27ToHml22Positions({ frames, posedJoints }) {
404
- if (!(ArrayBuffer.isView(posedJoints) || Array.isArray(posedJoints))) {
405
- throw new Error("cskel27ToHml22Positions: posedJoints must be an array of numbers");
406
- }
407
- const count = frames ?? posedJoints.length / (27 * 3);
408
- if (!Number.isInteger(count) || count < 1) {
409
- throw new Error(
410
- `cskel27ToHml22Positions: posedJoints length ${posedJoints.length} is not a whole number of 27-joint frames`
411
- );
412
- }
413
- if (posedJoints.length !== count * 27 * 3) {
414
- throw new Error(
415
- `cskel27ToHml22Positions: posedJoints must be ${count * 27 * 3} long, got ${posedJoints.length}`
416
- );
417
- }
418
- const out = new Float32Array(count * 22 * 3);
419
- for (let frame = 0; frame < count; frame += 1) {
420
- const src = frame * 27 * 3;
421
- const dst = frame * 22 * 3;
422
- for (let joint = 0; joint < 22; joint += 1) {
423
- const source = HML22_TO_CSKEL27_INDEX[joint];
424
- out[dst + joint * 3] = posedJoints[src + source * 3];
425
- out[dst + joint * 3 + 1] = posedJoints[src + source * 3 + 1];
426
- out[dst + joint * 3 + 2] = posedJoints[src + source * 3 + 2];
427
- }
428
- }
429
- return out;
430
- }
431
-
432
- // ---------------------------------------------------------------------------
433
- // 22 → 27, pose level. These are the building blocks the motion loop composes;
434
- // they are exported so a test can pin one frame's behaviour (and one frame's
435
- // continuity carry) without going through the whole clip.
436
- // ---------------------------------------------------------------------------
437
-
438
- /**
439
- * The canonical cskel27 rest body re-expressed at hml22 indices — the rest
440
- * directions every aim is measured against.
441
- * @param {{posed_joints:number[][]}} reference
442
- * @returns {number[][]} 22 rest positions
443
- */
444
- export function restPositionsHml22(reference) {
445
- const rest = new Array(22);
446
- for (let joint = 0; joint < 22; joint += 1) {
447
- rest[joint] = reference.posed_joints[HML22_TO_CSKEL27_INDEX[joint]].slice();
448
- }
449
- return rest;
450
- }
451
-
452
- /**
453
- * One frame of hml22 positions → 27 GLOBAL rotation matrices.
454
- *
455
- * @param {number[][]} observed 22 world positions for this frame
456
- * @param {object} options
457
- * @param {number[][]} options.rest 22 rest positions (restPositionsHml22)
458
- * @param {{swingAxis:Array, frameSecondary:Array}} [options.carry]
459
- * the previous frame's branch state; pass the returned `carry` straight
460
- * back in on the next frame to keep the clip continuous.
461
- * @param {number} [options.frame] frame index, for error messages only
462
- * @returns {{globals:number[][][], carry:{swingAxis:Array, frameSecondary:Array}}}
463
- */
464
- export function liftHml22PoseGlobals(observed, { rest, carry = null, frame = 0 } = {}) {
465
- if (!Array.isArray(observed) || observed.length !== 22) {
466
- throw new Error("liftHml22PoseGlobals: observed must be 22 [x,y,z] positions");
467
- }
468
- if (!Array.isArray(rest) || rest.length !== 22) {
469
- throw new Error("liftHml22PoseGlobals: rest must be 22 [x,y,z] positions");
470
- }
471
- const globals = new Array(27);
472
- const swingAxis = new Array(27).fill(null);
473
- const frameSecondary = new Array(27).fill(null);
474
-
475
- // cskel27 indices are topologically ordered (parent < child) — asserted in
476
- // the verify file — so one ascending pass suffices.
477
- for (let joint = 0; joint < 27; joint += 1) {
478
- const name = CSKEL27_JOINTS[joint];
479
- const parent = CSKEL27_PARENTS[joint];
480
- const spec = AIM[name];
481
- const parentGlobal = parent === null ? IDENTITY : globals[parent];
482
-
483
- if (!spec) {
484
- // Unauthored joint, or a mapped joint with no mapped child: borrow the
485
- // nearest mapped ancestor's global ⇒ identity local.
486
- globals[joint] = parentGlobal.map((row) => row.slice());
487
- continue;
488
- }
489
-
490
- const label = `${name} (frame ${frame})`;
491
- const self = CSKEL27_TO_HML22_INDEX[joint];
492
- const aim = CSKEL27_TO_HML22_INDEX[CSKEL_INDEX.get(spec.aim)];
493
- const restDir = unit(sub(rest[aim], rest[self]), `${label} rest bone`);
494
- const observedDir = unit(sub(observed[aim], observed[self]), `${label} observed bone`);
495
-
496
- if (spec.twistRef) {
497
- // Two independent directions ⇒ the full orientation, twist and all.
498
- const [first, second] = spec.twistRef;
499
- const a = CSKEL27_TO_HML22_INDEX[CSKEL_INDEX.get(first)];
500
- const b = CSKEL27_TO_HML22_INDEX[CSKEL_INDEX.get(second)];
501
- const restFrame = frameOf(restDir, sub(rest[a], rest[b]), `${label} rest frame`);
502
- const observedFrame = frameOf(
503
- observedDir,
504
- sub(observed[a], observed[b]),
505
- `${label} observed frame`,
506
- carry?.frameSecondary?.[joint]
507
- );
508
- frameSecondary[joint] = [observedFrame[0][1], observedFrame[1][1], observedFrame[2][1]];
509
- globals[joint] = matMul(observedFrame, matTranspose(restFrame));
510
- } else {
511
- // Aim + inherited twist.
512
- const aimed = unit(matVec(parentGlobal, restDir), `${label} aimed rest bone`);
513
- const swung = swingWithAxis(aimed, observedDir, carry?.swingAxis?.[joint], label);
514
- swingAxis[joint] = swung.axis;
515
- globals[joint] = matMul(swung.matrix, parentGlobal);
516
- }
517
- }
518
- return { globals, carry: { swingAxis, frameSecondary } };
519
- }
520
-
521
- /**
522
- * 27 global rotations → 27 LOCAL rotations. The soma77 rule, unchanged: whatever
523
- * sits between two mapped joints composes into the child's local, and an
524
- * unauthored joint (which borrowed its parent's global) comes out identity.
525
- * @param {number[][][]} globals
526
- * @returns {number[][][]}
527
- */
528
- export function globalsToCskel27Locals(globals) {
529
- const locals = new Array(27);
530
- for (let joint = 0; joint < 27; joint += 1) {
531
- const parent = CSKEL27_PARENTS[joint];
532
- locals[joint] =
533
- parent === null
534
- ? globals[joint].map((row) => row.slice())
535
- : matMul(matTranspose(globals[parent]), globals[joint]);
536
- }
537
- return locals;
538
- }
539
-
540
- /**
541
- * Full single-frame convert: hml22 positions → cskel27 rotations + posed joints.
542
- * The motion path calls exactly this per frame; a test can call it on one pose.
543
- *
544
- * @param {number[][]} observed 22 world positions
545
- * @param {object} options
546
- * @param {number[][]} options.rest
547
- * @param {number[][]} options.boneOffsets canonical cskel27 bone offsets
548
- * @param {number} [options.rootScale=1]
549
- * @param {object} [options.carry]
550
- * @param {number} [options.frame]
551
- * @returns {{globals, locals, root:number[], posed:number[][], carry:object}}
552
- */
553
- export function hml22PoseToCskel27(observed, { rest, boneOffsets, rootScale = 1, carry = null, frame = 0 }) {
554
- const lifted = liftHml22PoseGlobals(observed, { rest, carry, frame });
555
- const locals = globalsToCskel27Locals(lifted.globals);
556
- const pelvis = observed[HML_INDEX.get("pelvis")];
557
- const root = [pelvis[0] * rootScale, pelvis[1] * rootScale, pelvis[2] * rootScale];
558
- // FK on OUR body, never the source's bone lengths: the take has to move
559
- // CozyClay's figure, not drag HumanML3D's average proportions into the scene.
560
- const posed = forwardKinematics(locals, boneOffsets, root);
561
- return { globals: lifted.globals, locals, root, posed, carry: lifted.carry };
562
- }
563
-
564
- // ---------------------------------------------------------------------------
565
- // 22 → 27, motion level. THE C8 ENTRY POINT.
566
- // ---------------------------------------------------------------------------
567
-
568
- function chainLengthHml(positions, names) {
569
- let total = 0;
570
- for (let step = 1; step < names.length; step += 1) {
571
- total += norm(sub(positions[HML_INDEX.get(names[step])], positions[HML_INDEX.get(names[step - 1])]));
572
- }
573
- return total;
574
- }
575
-
576
- function chainLengthCskel(positions, names) {
577
- let total = 0;
578
- for (let step = 1; step < names.length; step += 1) {
579
- total += norm(sub(positions[CSKEL_INDEX.get(names[step])], positions[CSKEL_INDEX.get(names[step - 1])]));
580
- }
581
- return total;
582
- }
583
-
584
- /**
585
- * ProjFlow motion → the cclay motion arrays.
586
- *
587
- * @param {object} raw
588
- * @param {Float32Array|number[]} raw.positions hml22 joint positions, [T,22,3]
589
- * flattened, world metres, Y-up. ACMDM's own output tensor.
590
- * @param {number} [raw.fps=20] source rate. NOT retimed here (see header).
591
- * @param {number} [raw.frames] optional; derived from `positions` when absent,
592
- * cross-checked against it when present.
593
- * @param {object} [raw.reference] {local_rot_mats, posed_joints} cskel27 rest
594
- * (default: canonicalCskel27Reference())
595
- * @param {boolean} [raw.scaleRoot=true] scale the root trajectory by the
596
- * leg-length ratio so stride survives reproportioning (soma77's rule)
597
- * @param {boolean} [raw.ground=true] one rigid floor shift for the clip
598
- * (soma77's rule; see the note at the bottom of this function)
599
- * @returns {{frames:number, fps:number, rotMats:Float32Array, rootPos:Float32Array, posedJoints:Float32Array}}
600
- * rotMats are LOCAL rotations, [T,27,3,3] flattened row-major — the exact
601
- * five fields soma77ToCskel27Motion returns, nothing more.
602
- */
603
- export function hml22ToCskel27Motion(raw) {
604
- if (!raw || typeof raw !== "object") {
605
- throw new Error("hml22ToCskel27Motion: expected an object { positions, fps }");
606
- }
607
- const {
608
- positions,
609
- fps = 20,
610
- frames: declaredFrames,
611
- reference = canonicalCskel27Reference(),
612
- scaleRoot = true,
613
- ground = true,
614
- } = raw;
615
-
616
- // `ArrayBuffer.isView || Array.isArray` and not a duck-typed `.length` check:
617
- // a string has a length too, and would sail past the shape check to die
618
- // later as a NaN with a misleading joint name.
619
- if (!(ArrayBuffer.isView(positions) || Array.isArray(positions))) {
620
- throw new Error(
621
- "hml22ToCskel27Motion: positions must be a Float32Array or number[] of [T,22,3] world metres"
622
- );
623
- }
624
- if (positions.length === 0 || positions.length % (22 * 3) !== 0) {
625
- throw new Error(
626
- `hml22ToCskel27Motion: positions length ${positions.length} is not a whole number of 22-joint frames (multiple of 66)`
627
- );
628
- }
629
- const frames = positions.length / (22 * 3);
630
- if (declaredFrames !== undefined && declaredFrames !== frames) {
631
- throw new Error(
632
- `hml22ToCskel27Motion: frames says ${declaredFrames} but positions holds ${frames} frames`
633
- );
634
- }
635
- if (!Number.isInteger(fps) || fps < 1) {
636
- throw new Error(`hml22ToCskel27Motion: fps must be a positive integer, got ${fps}`);
637
- }
638
- // Scan once up front rather than letting a NaN propagate into a rotation
639
- // matrix, where it would surface a thousand lines downstream as an empty
640
- // viewport instead of as "frame 61 left_wrist z is NaN".
641
- for (let index = 0; index < positions.length; index += 1) {
642
- if (!Number.isFinite(positions[index])) {
643
- const frame = Math.floor(index / (22 * 3));
644
- const joint = Math.floor((index % (22 * 3)) / 3);
645
- throw new Error(
646
- `hml22ToCskel27Motion: positions[${index}] is ${positions[index]} ` +
647
- `(frame ${frame}, joint ${joint} ${HML22_JOINTS[joint]}, axis ${"xyz"[index % 3]})`
648
- );
649
- }
650
- }
651
-
652
- const boneOffsets = deriveBoneOffsets(reference.posed_joints, reference.local_rot_mats);
653
- const rest = restPositionsHml22(reference);
654
-
655
- // Leg-length ratio, measured on the source's own first frame against the
656
- // reference body, so a stride generated for HumanML3D's average body covers
657
- // the same fraction of a step on ours. Same rule as soma77ToCskel27Motion.
658
- const firstFrame = [];
659
- for (let joint = 0; joint < 22; joint += 1) {
660
- firstFrame.push([positions[joint * 3], positions[joint * 3 + 1], positions[joint * 3 + 2]]);
661
- }
662
- const sourceLeg = chainLengthHml(firstFrame, ["left_hip", "left_knee", "left_ankle"]);
663
- const referenceLeg = chainLengthCskel(reference.posed_joints, ["LeftUpLeg", "LeftLeg", "LeftFoot"]);
664
- if (!(sourceLeg > 0)) {
665
- throw new Error("hml22ToCskel27Motion: source leg length measured as zero");
666
- }
667
- const rootScale = scaleRoot ? referenceLeg / sourceLeg : 1;
668
-
669
- const rotMats = new Float32Array(frames * 27 * 9);
670
- const rootPos = new Float32Array(frames * 3);
671
- const outPosed = new Float32Array(frames * 27 * 3);
672
- let floorY = Infinity;
673
- let carry = null;
674
-
675
- for (let frame = 0; frame < frames; frame += 1) {
676
- const base = frame * 22 * 3;
677
- const observed = new Array(22);
678
- for (let joint = 0; joint < 22; joint += 1) {
679
- observed[joint] = [
680
- positions[base + joint * 3],
681
- positions[base + joint * 3 + 1],
682
- positions[base + joint * 3 + 2],
683
- ];
684
- }
685
-
686
- // `carry` threads the previous frame's branch choices in and this frame's
687
- // out — the whole of the temporal-continuity guarantee lives on this line.
688
- const pose = hml22PoseToCskel27(observed, { rest, boneOffsets, rootScale, carry, frame });
689
- carry = pose.carry;
690
-
691
- for (const name of GROUND_JOINTS) {
692
- const y = pose.posed[CSKEL_INDEX.get(name)][1];
693
- if (y < floorY) floorY = y;
694
- }
695
-
696
- const rotBase = frame * 27 * 9;
697
- for (let joint = 0; joint < 27; joint += 1) {
698
- const m = pose.locals[joint];
699
- for (let row = 0; row < 3; row += 1) {
700
- for (let col = 0; col < 3; col += 1) {
701
- rotMats[rotBase + joint * 9 + row * 3 + col] = m[row][col];
702
- }
703
- }
704
- }
705
- rootPos[frame * 3] = pose.root[0];
706
- rootPos[frame * 3 + 1] = pose.root[1];
707
- rootPos[frame * 3 + 2] = pose.root[2];
708
- const posBase = frame * 27 * 3;
709
- for (let joint = 0; joint < 27; joint += 1) {
710
- outPosed[posBase + joint * 3] = pose.posed[joint][0];
711
- outPosed[posBase + joint * 3 + 1] = pose.posed[joint][1];
712
- outPosed[posBase + joint * 3 + 2] = pose.posed[joint][2];
713
- }
714
- }
715
-
716
- // ONE RIGID FLOOR SHIFT for the whole clip, so the lowest foot sample of the
717
- // clip touches Y=0. This is soma77ToCskel27Motion's convention copied
718
- // deliberately and it is a SPLICING requirement, not a cosmetic one: a
719
- // ProjFlow line edit gets spliced back into a Kimodo/ARDY take, and if the two
720
- // converters grounded differently the figure would step up or down at the
721
- // seam. Per-frame grounding is the wrong answer for the same reason it is
722
- // there: it would flatten the arc of a jump, which is exactly the motion this
723
- // pipeline exists to stage.
724
- if (ground && Number.isFinite(floorY) && floorY !== 0) {
725
- for (let frame = 0; frame < frames; frame += 1) {
726
- rootPos[frame * 3 + 1] -= floorY;
727
- const posBase = frame * 27 * 3;
728
- for (let joint = 0; joint < 27; joint += 1) outPosed[posBase + joint * 3 + 1] -= floorY;
729
- }
730
- }
731
-
732
- return { frames, fps, rotMats, rootPos, posedJoints: outPosed };
733
- }
734
-
735
- export { IDENTITY as CSKEL27_IDENTITY };