cozyclay 2.1.1 → 3.0.0

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 (577) hide show
  1. package/CHANGELOG.md +60 -0
  2. package/README.md +12 -30
  3. package/bin/agent/agent-routes.mjs +40 -113
  4. package/bin/agent/agent-runner.mjs +9 -10
  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/studio-motion-reference.mjs +23 -0
  14. package/bin/agent/studio-prompt.mjs +1 -1
  15. package/bin/agent/studio-rebase-text.mjs +32 -0
  16. package/bin/agent/studio-rebase.mjs +26 -39
  17. package/bin/agent/studio-tools.mjs +9 -28
  18. package/bin/agent/tool-arguments.mjs +49 -0
  19. package/bin/agent/turn-frames.mjs +66 -0
  20. package/bin/codex-auth.mjs +9 -2
  21. package/bin/cozyclay.mjs +10 -116
  22. package/bin/live/cli.mjs +3 -3
  23. package/bin/mcp-runtime.mjs +2 -12
  24. package/bin/package-signature.mjs +0 -4
  25. package/dist/app/index.html +7 -6
  26. package/dist/assets/EXRLoader-CvVIvGVE.js +1 -0
  27. package/dist/assets/analytics-C9sUnndd.js +1 -0
  28. package/dist/assets/app-CCh--1Hc.js +5087 -0
  29. package/dist/assets/app-f-fkV5uP.css +1 -0
  30. package/dist/assets/compile-worker-CkxiD6lH.js +5 -0
  31. package/dist/assets/fflate.module-KbGj5-H6.js +5 -0
  32. package/dist/assets/{first-shot-handoff-msLI71g1.js → first-shot-handoff-CC4xe4HM.js} +1 -1
  33. package/dist/assets/{landing-ChUvB_zL.js → landing-DjHD8u7k.js} +1 -1
  34. package/dist/assets/scene-asset-sync-Hx_FzdOH.js +20 -0
  35. package/dist/assets/scene-asset-sync-_S8NQl5B.css +1 -0
  36. package/dist/assets/workflow-C4yKH1p4.js +179 -0
  37. package/dist/cozyclay-package.json +1 -1
  38. package/dist/index.html +3 -3
  39. package/dist/sw.js +3 -6
  40. package/dist/workflow/index.html +5 -4
  41. package/mcp/LIVE-PROTOCOL.md +7 -47
  42. package/mcp/README.md +16 -26
  43. package/mcp/live-hub.mjs +6 -10
  44. package/mcp/package.json +1 -3
  45. package/mcp/tool-handlers.mjs +4 -168
  46. package/package.json +3 -22
  47. package/src/App.jsx +150 -2624
  48. package/src/agent-progress.js +79 -0
  49. package/src/agent-turn-mark.js +30 -0
  50. package/src/analytics.js +1 -19
  51. package/src/app-context.js +5 -0
  52. package/src/app-stage.jsx +2 -34
  53. package/src/asset-pane.jsx +6 -5
  54. package/src/camera-block.js +21 -0
  55. package/src/camera-direction.js +120 -0
  56. package/src/character-kind.js +3 -9
  57. package/src/command-bus.js +8 -6
  58. package/src/commands/cast.js +5 -34
  59. package/src/commands/elements/character.js +1 -1
  60. package/src/commands/elements/motion.js +1 -6
  61. package/src/commands/elements/object.js +6 -2
  62. package/src/commands/elements/shot.js +4 -1
  63. package/src/commands/elements.js +38 -14
  64. package/src/commands/index.js +3 -1
  65. package/src/commands/kits.js +37 -0
  66. package/src/commands/motion-timing.js +57 -0
  67. package/src/commands/motion.js +9 -152
  68. package/src/commands/motion3-compile.js +65 -0
  69. package/src/commands/motion3.js +207 -0
  70. package/src/commands/objects.js +6 -4
  71. package/src/commands/shot.js +49 -11
  72. package/src/commands/stage.js +14 -1
  73. package/src/commands/view.js +4 -1
  74. package/src/document-mirrors.js +42 -0
  75. package/src/document-store.js +4 -0
  76. package/src/domains/cast.js +19 -194
  77. package/src/domains/motion/motion-range-pin-rules.js +1 -1
  78. package/src/domains/motion/take-source.js +51 -0
  79. package/src/domains/motion.js +60 -1838
  80. package/src/domains/scenes.js +12 -55
  81. package/src/domains/shots.js +2 -2
  82. package/src/domains/stage.js +4 -2
  83. package/src/draft-ghost.js +46 -0
  84. package/src/draft-ghost.jsx +129 -0
  85. package/src/dualview.jsx +4 -3
  86. package/src/effects/EffectsLayer.jsx +112 -0
  87. package/src/effects/effect-meshes.js +232 -0
  88. package/src/effects/effect-record.js +103 -0
  89. package/src/effects/emitter.js +59 -0
  90. package/src/effects/simulate.js +261 -0
  91. package/src/effects/state.js +59 -0
  92. package/src/execution-telemetry.js +2 -3
  93. package/src/first-success-guide.jsx +5 -5
  94. package/src/ghost-set.js +257 -0
  95. package/src/held-object-edit.jsx +113 -0
  96. package/src/held-object-pose.js +175 -0
  97. package/src/hierarchy-model.js +1 -1
  98. package/src/hierarchy-panel.jsx +1 -1
  99. package/src/imported-mesh.jsx +103 -0
  100. package/src/kits/held.js +84 -0
  101. package/src/kits/index.js +70 -0
  102. package/src/kits/smoking.js +57 -0
  103. package/src/light-blockers.js +93 -0
  104. package/src/motion/beat-board-model.js +84 -0
  105. package/src/motion/beat-board.css +124 -0
  106. package/src/motion/beat-board.jsx +59 -0
  107. package/src/motion/center-of-mass.js +66 -0
  108. package/src/motion/fix-collisions.js +850 -0
  109. package/src/motion/physics-review.js +118 -0
  110. package/src/{ardy → motion}/physics-support.js +1 -76
  111. package/src/motion/rig-snapshot.js +22 -0
  112. package/src/motion/take-segments.jsx +140 -0
  113. package/src/{ardy → motion}/timeline-coordinates.js +0 -21
  114. package/src/{ardy → motion}/timeline.css +1 -2
  115. package/src/{ardy → motion}/timeline.jsx +42 -413
  116. package/src/motion/waypoints.js +76 -0
  117. package/src/motion3/beats.js +83 -0
  118. package/src/motion3/body.js +158 -0
  119. package/src/motion3/bones.js +47 -0
  120. package/src/motion3/carried.js +47 -0
  121. package/src/motion3/compile-job.js +75 -0
  122. package/src/motion3/compile-worker.js +10 -0
  123. package/src/motion3/compiler/anchors.js +105 -0
  124. package/src/motion3/compiler/arm-orient.js +128 -0
  125. package/src/motion3/compiler/channels.js +125 -0
  126. package/src/motion3/compiler/compile.js +205 -0
  127. package/src/motion3/compiler/gait-rhythm.js +97 -0
  128. package/src/motion3/compiler/grip.js +171 -0
  129. package/src/motion3/compiler/head-steady.js +48 -0
  130. package/src/motion3/compiler/hold.js +134 -0
  131. package/src/motion3/compiler/idle.js +113 -0
  132. package/src/motion3/compiler/limbs.js +170 -0
  133. package/src/motion3/compiler/math.js +72 -0
  134. package/src/motion3/compiler/pose.js +162 -0
  135. package/src/motion3/compiler/quat.js +49 -0
  136. package/src/motion3/compiler/skeleton.js +74 -0
  137. package/src/motion3/compiler/validate-common.js +32 -0
  138. package/src/motion3/compiler/validate-goals.js +118 -0
  139. package/src/motion3/compiler/validate-objects.js +143 -0
  140. package/src/motion3/compiler/validate-parts.js +116 -0
  141. package/src/motion3/compiler/validate.js +122 -0
  142. package/src/motion3/compiler/vocab.js +73 -0
  143. package/src/motion3/compiler/walk-pelvis.js +275 -0
  144. package/src/motion3/compiler/walk.js +207 -0
  145. package/src/motion3/compiler/wrist-clamp.js +32 -0
  146. package/src/motion3/delta.js +47 -0
  147. package/src/motion3/describe.js +174 -0
  148. package/src/motion3/docs.js +27 -0
  149. package/src/motion3/edit-carry.js +21 -0
  150. package/src/motion3/fix/ease.js +16 -0
  151. package/src/motion3/fix/ground.js +37 -0
  152. package/src/motion3/fix/index.js +52 -0
  153. package/src/motion3/fix/push.js +71 -0
  154. package/src/motion3/fix/reach.js +46 -0
  155. package/src/motion3/fix/retime.js +79 -0
  156. package/src/motion3/fix/self.js +211 -0
  157. package/src/motion3/fix/slide.js +70 -0
  158. package/src/motion3/fix/turn.js +51 -0
  159. package/src/motion3/follow.js +39 -0
  160. package/src/motion3/free-motion.js +173 -0
  161. package/src/motion3/grip-choice.js +130 -0
  162. package/src/motion3/hold-plan.js +157 -0
  163. package/src/motion3/json-patch.js +77 -0
  164. package/src/motion3/key-aim.js +105 -0
  165. package/src/motion3/key-edit.js +82 -0
  166. package/src/motion3/lenient.js +127 -0
  167. package/src/motion3/object-keys.js +236 -0
  168. package/src/motion3/object-pose.js +182 -0
  169. package/src/motion3/object-tracks.js +12 -0
  170. package/src/motion3/pipeline.js +102 -0
  171. package/src/motion3/playback.js +51 -0
  172. package/src/motion3/probes.js +91 -0
  173. package/src/motion3/qa/body-checks.js +34 -0
  174. package/src/motion3/qa/check-names.js +14 -0
  175. package/src/motion3/qa/checks.js +121 -0
  176. package/src/motion3/qa/contact-checks.js +51 -0
  177. package/src/motion3/qa/explain.js +80 -0
  178. package/src/motion3/qa/fmt.js +5 -0
  179. package/src/motion3/qa/foot-checks.js +72 -0
  180. package/src/motion3/qa/geometry.js +77 -0
  181. package/src/motion3/qa/goals.js +191 -0
  182. package/src/motion3/qa/ground.js +60 -0
  183. package/src/motion3/qa/hints-contact.js +179 -0
  184. package/src/motion3/qa/hints-goal.js +160 -0
  185. package/src/motion3/qa/hints-knee.js +24 -0
  186. package/src/motion3/qa/hints-motion.js +209 -0
  187. package/src/motion3/qa/hints-object.js +91 -0
  188. package/src/motion3/qa/index.js +42 -0
  189. package/src/motion3/qa/key-checks.js +82 -0
  190. package/src/motion3/qa/near.js +96 -0
  191. package/src/motion3/qa/object-checks.js +135 -0
  192. package/src/motion3/qa/patch.js +161 -0
  193. package/src/motion3/qa/severity.js +38 -0
  194. package/src/motion3/qa/spec-checks.js +65 -0
  195. package/src/motion3/qa/style.js +218 -0
  196. package/src/motion3/qa/wrist-checks.js +69 -0
  197. package/src/motion3/qa/wrist-obs.js +60 -0
  198. package/src/motion3/refs.js +120 -0
  199. package/src/motion3/repair-tune.js +121 -0
  200. package/src/motion3/repair.js +83 -0
  201. package/src/motion3/report.js +67 -0
  202. package/src/motion3/rigs/index.js +14 -0
  203. package/src/motion3/rigs/x-bot-tpose-body.json +1 -0
  204. package/src/motion3/rigs/x-bot-tpose.json +1 -0
  205. package/src/motion3/rigs/y-bot-tpose-body.json +1 -0
  206. package/src/motion3/rigs/y-bot-tpose.json +1 -0
  207. package/src/motion3/scene.js +60 -0
  208. package/src/motion3/schema/brief.js +89 -0
  209. package/src/motion3/schema/fields.js +44 -0
  210. package/src/motion3/schema/spec-examples.js +46 -0
  211. package/src/motion3/schema/topics.js +111 -0
  212. package/src/motion3/schema/types.js +147 -0
  213. package/src/motion3/search.js +117 -0
  214. package/src/motion3/second-hand.js +112 -0
  215. package/src/motion3/skills/basic.js +82 -0
  216. package/src/motion3/skills/book.js +76 -0
  217. package/src/motion3/skills/car.js +145 -0
  218. package/src/motion3/skills/frames-auto.js +29 -0
  219. package/src/motion3/skills/index.js +83 -0
  220. package/src/motion3/skills/info.js +65 -0
  221. package/src/motion3/skills/smoke-kit.js +109 -0
  222. package/src/motion3/skills/smoke.js +160 -0
  223. package/src/motion3/spec-store.js +59 -0
  224. package/src/motion3/take-edit.js +155 -0
  225. package/src/motion3/take.js +63 -0
  226. package/src/motion3/timeline.js +127 -0
  227. package/src/motion3/views.js +121 -0
  228. package/src/motion3/walk-plan.js +119 -0
  229. package/src/object-catalog.jsx +7 -1
  230. package/src/object-colors.js +98 -0
  231. package/src/object-gizmo-parts.js +115 -0
  232. package/src/object-gizmo.jsx +37 -122
  233. package/src/object-glow.js +139 -0
  234. package/src/object-hidden.js +33 -0
  235. package/src/object-look.js +196 -0
  236. package/src/object-size.js +10 -0
  237. package/src/object-travel.js +71 -6
  238. package/src/panels/CameraPanel.jsx +7 -7
  239. package/src/panels/HdrEnvironmentControls.jsx +59 -0
  240. package/src/panels/LightPanel.jsx +25 -4
  241. package/src/panels/ObjectLookPanel.jsx +88 -0
  242. package/src/panels/PosePanel.jsx +2 -17
  243. package/src/panels/RigControlPanel.jsx +5 -53
  244. package/src/panels/SubjectBox.jsx +4 -1
  245. package/src/panels/details.css +14 -0
  246. package/src/posestudio.jsx +4 -27
  247. package/src/project-browser.jsx +3 -4
  248. package/src/project-resources.js +18 -31
  249. package/src/project.js +13 -104
  250. package/src/props.jsx +25 -280
  251. package/src/rail-dot-drag.js +23 -0
  252. package/src/render-passes.js +10 -0
  253. package/src/resource-status.jsx +1 -0
  254. package/src/result-modal.jsx +4 -19
  255. package/src/room.jsx +20 -12
  256. package/src/scene-assets.js +8 -6
  257. package/src/scene-light-place.js +72 -0
  258. package/src/scene-lights.jsx +148 -0
  259. package/src/scene-objects.js +31 -139
  260. package/src/scenes.js +15 -105
  261. package/src/semantic-edit.js +2 -5
  262. package/src/set-pieces.jsx +183 -0
  263. package/src/settings-menu.jsx +3 -11
  264. package/src/shell/BottomDock.jsx +9 -51
  265. package/src/shell/DetailsSlot.jsx +16 -200
  266. package/src/shell/GhostsMenuGroup.jsx +74 -0
  267. package/src/shell/LibrarySlot.jsx +1 -3
  268. package/src/shell/MenuBar.jsx +3 -3
  269. package/src/shell/PreferencesDialog.jsx +15 -264
  270. package/src/shell/PreferencesSlot.jsx +2 -8
  271. package/src/shell/TopBar.jsx +5 -84
  272. package/src/shell/ViewportToolbar.jsx +10 -70
  273. package/src/shell/agent-glass.css +19 -6
  274. package/src/shell/details-selection.js +42 -0
  275. package/src/shell/ghosts-menu.css +22 -0
  276. package/src/shell/glass-regions.css +29 -3
  277. package/src/shell/preferences.css +6 -1
  278. package/src/shot-authoring.js +4 -7
  279. package/src/soft-shadows.js +37 -0
  280. package/src/stage-attach-frames.js +12 -12
  281. package/src/stage-canvas-rigs.jsx +3 -3
  282. package/src/stage-capture.jsx +42 -8
  283. package/src/stage-characters.jsx +22 -216
  284. package/src/stage-editor-gizmos.jsx +6 -6
  285. package/src/stage-environment.js +93 -0
  286. package/src/stage-hdr-builtins.js +107 -0
  287. package/src/stage-hdr-image.js +116 -0
  288. package/src/stage-hdr-library.js +70 -0
  289. package/src/stage-hdr-map.js +94 -0
  290. package/src/stage-hdr.js +130 -0
  291. package/src/stage-lighting.js +149 -0
  292. package/src/stage-occlusion.js +210 -0
  293. package/src/stage-sky.jsx +159 -0
  294. package/src/stage-startup-defaults.js +5 -9
  295. package/src/studio-actions.js +12 -14
  296. package/src/studio-agent-commands.js +19 -16
  297. package/src/studio-agent-motion.js +9 -9
  298. package/src/studio-agent-protocol.js +41 -71
  299. package/src/studio-app-binding.js +25 -45
  300. package/src/studio-asset-list.js +17 -0
  301. package/src/studio-contact-sheet.js +37 -5
  302. package/src/studio-elements.js +27 -7
  303. package/src/studio-entity-bounds.js +18 -0
  304. package/src/studio-error-codes.js +8 -0
  305. package/src/studio-export-framing.js +152 -0
  306. package/src/studio-lighting-check.js +103 -0
  307. package/src/studio-motion-visual.js +150 -0
  308. package/src/studio-schema-errors.js +80 -0
  309. package/src/studio-support-gap.js +74 -0
  310. package/src/styles.css +1 -19
  311. package/src/timeline-defaults.js +5 -0
  312. package/src/timeline-extent.js +8 -20
  313. package/src/tutorial-walk.js +17 -0
  314. package/src/ui-scrub.js +1 -1
  315. package/src/use-shot-camera-tracks.js +12 -0
  316. package/src/view-ghosts.js +97 -0
  317. package/src/view-ghosts.jsx +49 -0
  318. package/src/workflow/AgentPanel.jsx +47 -166
  319. package/src/workflow/AgentProgressCard.jsx +107 -0
  320. package/src/workflow/AgentReplyText.jsx +37 -0
  321. package/src/workflow/AgentTurnSteps.jsx +84 -0
  322. package/src/workflow/LoginPanel.jsx +140 -0
  323. package/src/workflow/WorkflowBuilder.jsx +7 -23
  324. package/src/workflow/agent-client.js +54 -51
  325. package/src/workflow/agent-panel.css +71 -1
  326. package/src/workflow/agent-progress-card.css +167 -0
  327. package/src/workflow/agent-progress-view.js +47 -0
  328. package/src/workflow/agent-turn-steps.css +113 -0
  329. package/src/workflow/agent-turn.js +191 -0
  330. package/src/workflow/login-client.js +34 -0
  331. package/src/workflow/motion-input.js +18 -31
  332. package/src/workflow/node-schema.js +1 -1
  333. package/src/workflow/reply-markdown.js +69 -0
  334. package/src/workflow/scene-asset-sync.js +8 -8
  335. package/tools/agent-session-stats.mjs +61 -0
  336. package/tools/dev-full.mjs +5 -56
  337. package/tools/eslint-baseline.json +12 -13
  338. package/tools/knip-baseline.json +0 -179
  339. package/tools/loc-baseline.json +31 -81
  340. package/tools/motion3/extract-body.mjs +103 -0
  341. package/tools/motion3/extract-rig.mjs +85 -0
  342. package/tools/process-supervisor.mjs +0 -88
  343. package/tools/run-tests.mjs +8 -124
  344. package/bin/agent/motion-runtime.mjs +0 -76
  345. package/dist/ardy/cskel27-rest.json +0 -557
  346. package/dist/assets/analytics-C9pMpW7s.js +0 -1
  347. package/dist/assets/app-B_2XB9rw.css +0 -1
  348. package/dist/assets/app-DAuvKPP8.js +0 -4920
  349. package/dist/assets/config-Bx7pYsD9.js +0 -1
  350. package/dist/assets/config-DeoFTYzb.css +0 -1
  351. package/dist/assets/demo-CvKuBgy5.js +0 -1
  352. package/dist/assets/scene-asset-sync-DKkpjKBV.js +0 -19
  353. package/dist/assets/scene-asset-sync-DjJ_cJ2R.css +0 -1
  354. package/dist/assets/ticket-BPk2Ni95.js +0 -1
  355. package/dist/assets/workflow-jJRBR94Z.js +0 -179
  356. package/dist/demo/walk-then-stop.npz +0 -0
  357. package/mcp/ardy-prompts.mjs +0 -218
  358. package/src/ardy/auto-fix-panel.css +0 -108
  359. package/src/ardy/auto-physics.js +0 -1194
  360. package/src/ardy/client.js +0 -153
  361. package/src/ardy/convert.js +0 -313
  362. package/src/ardy/cskel27-neutral.js +0 -39
  363. package/src/ardy/cskel27.js +0 -77
  364. package/src/ardy/export.js +0 -165
  365. package/src/ardy/fix-collisions.js +0 -2257
  366. package/src/ardy/foot-lock.js +0 -230
  367. package/src/ardy/motion-calibration.js +0 -118
  368. package/src/ardy/motion-edit.js +0 -213
  369. package/src/ardy/motion-url.js +0 -55
  370. package/src/ardy/mp4-duration.js +0 -102
  371. package/src/ardy/npz.js +0 -595
  372. package/src/ardy/physics-panel.css +0 -21
  373. package/src/ardy/physics-panel.jsx +0 -89
  374. package/src/ardy/physics-refine.js +0 -111
  375. package/src/ardy/physics-review.js +0 -567
  376. package/src/ardy/physics-temporal.js +0 -54
  377. package/src/ardy/platform-fit-panel.css +0 -64
  378. package/src/ardy/platform-fit-panel.jsx +0 -41
  379. package/src/ardy/platform-fit.js +0 -326
  380. package/src/ardy/playback.js +0 -711
  381. package/src/ardy/pose-pin.js +0 -97
  382. package/src/ardy/prompt-clips.js +0 -30
  383. package/src/ardy/retime.js +0 -211
  384. package/src/ardy/root-drop.js +0 -369
  385. package/src/ardy/timeline-resize.js +0 -13
  386. package/src/ardy/to-cskel27.js +0 -225
  387. package/src/ardy/trim.js +0 -33
  388. package/src/ardy/waypoints.js +0 -369
  389. package/src/ardy-bridge-contract.js +0 -281
  390. package/src/domains/motion/motion-video-capture.js +0 -664
  391. package/src/i2v-motion-client.js +0 -77
  392. package/src/i2v-motion-studio.jsx +0 -180
  393. package/src/line-edit.js +0 -1348
  394. package/src/motion/generation.js +0 -105
  395. package/src/motion-readiness-ui.jsx +0 -67
  396. package/src/motion-readiness.js +0 -40
  397. package/src/motion-resources.js +0 -177
  398. package/src/motion-store.js +0 -65
  399. package/src/motion-trail.js +0 -601
  400. package/src/multimodel-ingest.js +0 -394
  401. package/src/panels/PromptBlocksPanel.jsx +0 -444
  402. package/src/panels/VideoCapturePanel.jsx +0 -181
  403. package/src/pose-extract/browser.js +0 -42
  404. package/src/pose-extract/detector.js +0 -100
  405. package/src/pose-extract/fit.js +0 -227
  406. package/src/pose-extract/image-frame.js +0 -51
  407. package/src/pose-extract/index.js +0 -58
  408. package/src/pose-extract/keyframes.js +0 -74
  409. package/src/pose-extract/landmarks.js +0 -162
  410. package/src/pose-extract/mirror.js +0 -153
  411. package/src/pose-extract/take.js +0 -131
  412. package/src/pose-extract/video-frames.js +0 -91
  413. package/src/take-recipe.js +0 -165
  414. package/src/trail-key-conflicts.js +0 -39
  415. package/src/trail-pick.js +0 -59
  416. package/src/use-i2v-capture-modal.js +0 -15
  417. package/tools/ardy/BRIDGE.md +0 -37
  418. package/tools/ardy/GVHMR-NPZ.md +0 -68
  419. package/tools/ardy/README.md +0 -124
  420. package/tools/ardy/__pycache__/cclay_gvhmr_worker.cpython-313.pyc +0 -0
  421. package/tools/ardy/artifacts.mjs +0 -34
  422. package/tools/ardy/bridge.mjs +0 -1732
  423. package/tools/ardy/bvh-cskel27.mjs +0 -1265
  424. package/tools/ardy/cclay_constrained_generate.py +0 -561
  425. package/tools/ardy/cclay_gvhmr_worker.py +0 -264
  426. package/tools/ardy/cclay_motion_edit.py +0 -510
  427. package/tools/ardy/cclay_sequence_generate.py +0 -705
  428. package/tools/ardy/cclay_worker.py +0 -304
  429. package/tools/ardy/dump-npz.py +0 -205
  430. package/tools/ardy/extract-rest.mjs +0 -299
  431. package/tools/ardy/extract.mjs +0 -507
  432. package/tools/ardy/footage.mjs +0 -467
  433. package/tools/ardy/gvhmr-floor.mjs +0 -102
  434. package/tools/ardy/gvhmr-to-cskel27.mjs +0 -21
  435. package/tools/ardy/gvhmr_fastpath.py +0 -168
  436. package/tools/ardy/gvhmr_trajectory.py +0 -240
  437. package/tools/ardy/merge-text-encoder.py +0 -160
  438. package/tools/ardy/mocap-metrics.mjs +0 -200
  439. package/tools/ardy/mocap-quality-gate.mjs +0 -110
  440. package/tools/ardy/motion-stabilize.mjs +0 -348
  441. package/tools/ardy/npz.mjs +0 -414
  442. package/tools/ardy/pose-to-npz.mjs +0 -106
  443. package/tools/ardy/prompt-limits.mjs +0 -5
  444. package/tools/ardy/run-edit-on-box.sh +0 -73
  445. package/tools/ardy/run-local.mjs +0 -233
  446. package/tools/ardy/run-on-box.sh +0 -593
  447. package/tools/ardy/run-sequence-on-box.sh +0 -177
  448. package/tools/ardy/runners/gvhmr-worker.mjs +0 -206
  449. package/tools/ardy/runners/index.mjs +0 -18
  450. package/tools/ardy/runners/local.mjs +0 -455
  451. package/tools/ardy/runners/proc.mjs +0 -125
  452. package/tools/ardy/runners/remote.mjs +0 -252
  453. package/tools/ardy/setup-local.mjs +0 -189
  454. package/tools/ardy/setup-text-encoder-on-box.sh +0 -93
  455. package/tools/ardy/setup-text-encoder.py +0 -306
  456. package/tools/ardy/smpl-cskel27.mjs +0 -178
  457. package/tools/ardy/visual-qa.mjs +0 -196
  458. package/tools/ardy/vq-car.mjs +0 -52
  459. package/tools/bench/EXP3.md +0 -61
  460. package/tools/bench/cclay_bench_extract_incam.py +0 -125
  461. package/tools/bench/cclay_bench_extract_obs.py +0 -204
  462. package/tools/bench/cclay_bench_runner.py +0 -42
  463. package/tools/bench/cube-contact.mjs +0 -162
  464. package/tools/bench/exp3.mjs +0 -152
  465. package/tools/bench/extract-bench-lib.mjs +0 -216
  466. package/tools/bench/extract-bench.mjs +0 -302
  467. package/tools/bench/fal-generate.mjs +0 -88
  468. package/tools/bench/fit/README.md +0 -189
  469. package/tools/bench/fit/camera.mjs +0 -59
  470. package/tools/bench/fit/contact.mjs +0 -419
  471. package/tools/bench/fit/footlock.mjs +0 -234
  472. package/tools/bench/fit/motion.mjs +0 -85
  473. package/tools/bench/fit/pin.mjs +0 -27
  474. package/tools/bench/fit/remote.mjs +0 -105
  475. package/tools/bench/fit-bench.mjs +0 -126
  476. package/tools/bench/fit-sanity.mjs +0 -45
  477. package/tools/bench/metrics.mjs +0 -313
  478. package/tools/bench/obs/depth.mjs +0 -258
  479. package/tools/bench/obs/extrinsics.mjs +0 -175
  480. package/tools/bench/obs/fit_mannequin_betas.py +0 -340
  481. package/tools/bench/obs/ground.mjs +0 -294
  482. package/tools/bench/obs/heading.mjs +0 -151
  483. package/tools/bench/obs/ladder.mjs +0 -555
  484. package/tools/bench/obs/mannequin-betas.json +0 -124
  485. package/tools/bench/obs/remote.mjs +0 -83
  486. package/tools/bench/obs/rest_joints.py +0 -52
  487. package/tools/bench/obs/ybot-targets.mjs +0 -49
  488. package/tools/bench/obs-bench.mjs +0 -520
  489. package/tools/bench/score.mjs +0 -343
  490. package/tools/bench/summarize.mjs +0 -86
  491. package/tools/demo-worker/README.md +0 -137
  492. package/tools/demo-worker/api-client.mjs +0 -233
  493. package/tools/demo-worker/generate.mjs +0 -301
  494. package/tools/demo-worker/index.mjs +0 -466
  495. package/tools/demo-worker/sign-core.mjs +0 -112
  496. package/tools/demo-worker/sign.mjs +0 -161
  497. package/tools/gt-render/browser.mjs +0 -182
  498. package/tools/gt-render/camera-math.mjs +0 -276
  499. package/tools/gt-render/page.mjs +0 -267
  500. package/tools/gt-render/render.mjs +0 -514
  501. package/tools/gt-render/scene-box.mjs +0 -31
  502. package/tools/gt-render/take-transform.mjs +0 -87
  503. package/tools/kimodo/compare-seam.mjs +0 -108
  504. package/tools/kimodo/constraints.mjs +0 -244
  505. package/tools/kimodo/edit.mjs +0 -259
  506. package/tools/kimodo/effector-constraints.mjs +0 -200
  507. package/tools/kimodo/generate.mjs +0 -646
  508. package/tools/kimodo/local-output.mjs +0 -265
  509. package/tools/kimodo/measure-pose.mjs +0 -65
  510. package/tools/kimodo/measure-preserve.mjs +0 -899
  511. package/tools/kimodo/measure-waypoints.mjs +0 -55
  512. package/tools/kimodo/mlx-generate.py +0 -111
  513. package/tools/kimodo/pose-constraints.mjs +0 -248
  514. package/tools/kimodo/preserve-mask.mjs +0 -543
  515. package/tools/kimodo/read-npz.mjs +0 -189
  516. package/tools/kimodo/run-edit-on-box.mjs +0 -155
  517. package/tools/kimodo/run-sequence-on-box.mjs +0 -178
  518. package/tools/kimodo/runner.mjs +0 -284
  519. package/tools/kimodo/seam-batch.mjs +0 -77
  520. package/tools/kimodo/setup-local.mjs +0 -30
  521. package/tools/kimodo/setup-on-box.sh +0 -339
  522. package/tools/kimodo/soma77-to-cskel27.mjs +0 -305
  523. package/tools/morphgs/assets/gen_truth.py +0 -39
  524. package/tools/morphgs/assets/mesh_ori_rig.txt +0 -27
  525. package/tools/morphgs/assets/playback-check.mjs +0 -30
  526. package/tools/morphgs/demo-gate.sh +0 -26
  527. package/tools/morphgs/fbx2morphgs.mjs +0 -68
  528. package/tools/morphgs/morphgs-to-cskel27.mjs +0 -105
  529. package/tools/morphgs/patches/preprocess_src-none-mode.patch +0 -76
  530. package/tools/morphgs/setup-on-cluster.sh +0 -126
  531. package/tools/projflow/driver.py +0 -1069
  532. package/tools/projflow/generate.mjs +0 -805
  533. package/tools/projflow/hml22-to-cskel27.mjs +0 -735
  534. package/tools/projflow/line-edit-job.mjs +0 -547
  535. package/tools/projflow/replay.mjs +0 -452
  536. package/tools/projflow/runner.mjs +0 -269
  537. package/tools/projflow/service.mjs +0 -742
  538. package/tools/track/DESIGN.md +0 -513
  539. package/tools/track/backfill-provenance.mjs +0 -116
  540. package/tools/track/budget.mjs +0 -8
  541. package/tools/track/check-rig.mjs +0 -209
  542. package/tools/track/diagnostics.schema.json +0 -60
  543. package/tools/track/export-rig.mjs +0 -256
  544. package/tools/track/fallback.mjs +0 -7
  545. package/tools/track/fk-parity-fixture.mjs +0 -161
  546. package/tools/track/gate.mjs +0 -349
  547. package/tools/track/masks.mjs +0 -318
  548. package/tools/track/metrics.mjs +0 -201
  549. package/tools/track/publish-obs.mjs +0 -108
  550. package/tools/track/py/check_env.py +0 -61
  551. package/tools/track/py/eval_lr.py +0 -229
  552. package/tools/track/py/lr_viterbi.py +0 -294
  553. package/tools/track/py/masks.py +0 -405
  554. package/tools/track/py/objective.py +0 -382
  555. package/tools/track/py/rig.py +0 -508
  556. package/tools/track/py/scene.py +0 -326
  557. package/tools/track/py/test_joint_indices.py +0 -123
  558. package/tools/track/py/test_lr_viterbi.py +0 -195
  559. package/tools/track/py/test_masks.py +0 -229
  560. package/tools/track/py/test_rig.py +0 -288
  561. package/tools/track/py/test_scene.py +0 -354
  562. package/tools/track/py/test_track.py +0 -328
  563. package/tools/track/py/track.py +0 -411
  564. package/tools/track/remote.mjs +0 -140
  565. package/tools/track/rig-dump.mjs +0 -227
  566. package/tools/track/run-box-tests.mjs +0 -14
  567. package/tools/track/run-box.mjs +0 -168
  568. package/tools/track/setup-box.sh +0 -59
  569. package/tools/track/study-2d.mjs +0 -728
  570. /package/src/{ardy → motion}/collision-blockers.js +0 -0
  571. /package/src/{ardy → motion}/ground.js +0 -0
  572. /package/src/{ardy → motion}/ik-drag.js +0 -0
  573. /package/src/{ardy → motion}/ik-key-json.js +0 -0
  574. /package/src/{ardy → motion}/ik.js +0 -0
  575. /package/src/{ardy → motion}/physics-surface.js +0 -0
  576. /package/src/{ardy → motion}/playback-clock.js +0 -0
  577. /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 };