cozyclay 2.1.0 → 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 (583) hide show
  1. package/CHANGELOG.md +65 -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 +22 -6
  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-BlT33CGf.js → first-shot-handoff-CC4xe4HM.js} +1 -1
  33. package/dist/assets/{landing-BSesrCpL.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/llms.txt +14 -0
  40. package/dist/sw.js +3 -6
  41. package/dist/workflow/index.html +5 -4
  42. package/mcp/LIVE-PROTOCOL.md +7 -47
  43. package/mcp/README.md +16 -26
  44. package/mcp/live-hub.mjs +6 -10
  45. package/mcp/package.json +1 -3
  46. package/mcp/tool-handlers.mjs +4 -168
  47. package/package.json +3 -22
  48. package/src/App.jsx +174 -2639
  49. package/src/agent-progress.js +79 -0
  50. package/src/agent-turn-mark.js +30 -0
  51. package/src/analytics.js +1 -19
  52. package/src/app-context.js +5 -0
  53. package/src/app-stage.jsx +2 -34
  54. package/src/asset-pane.jsx +6 -5
  55. package/src/camera-block.js +21 -0
  56. package/src/camera-direction.js +120 -0
  57. package/src/character-kind.js +3 -9
  58. package/src/command-bus.js +8 -6
  59. package/src/commands/cast.js +5 -34
  60. package/src/commands/elements/character.js +1 -1
  61. package/src/commands/elements/motion.js +1 -6
  62. package/src/commands/elements/object.js +6 -2
  63. package/src/commands/elements/shot.js +4 -1
  64. package/src/commands/elements.js +38 -14
  65. package/src/commands/index.js +3 -1
  66. package/src/commands/kits.js +37 -0
  67. package/src/commands/motion-timing.js +57 -0
  68. package/src/commands/motion.js +9 -152
  69. package/src/commands/motion3-compile.js +65 -0
  70. package/src/commands/motion3.js +207 -0
  71. package/src/commands/objects.js +6 -4
  72. package/src/commands/shot.js +49 -11
  73. package/src/commands/stage.js +14 -1
  74. package/src/commands/view.js +4 -1
  75. package/src/document-mirrors.js +42 -0
  76. package/src/document-store.js +4 -0
  77. package/src/domains/cast.js +19 -194
  78. package/src/domains/motion/motion-range-pin-rules.js +1 -1
  79. package/src/domains/motion/take-source.js +51 -0
  80. package/src/domains/motion.js +60 -1838
  81. package/src/domains/scenes.js +12 -55
  82. package/src/domains/shots.js +2 -2
  83. package/src/domains/stage.js +4 -2
  84. package/src/draft-ghost.js +46 -0
  85. package/src/draft-ghost.jsx +129 -0
  86. package/src/dualview.jsx +4 -3
  87. package/src/effects/EffectsLayer.jsx +112 -0
  88. package/src/effects/effect-meshes.js +232 -0
  89. package/src/effects/effect-record.js +103 -0
  90. package/src/effects/emitter.js +59 -0
  91. package/src/effects/simulate.js +261 -0
  92. package/src/effects/state.js +59 -0
  93. package/src/execution-telemetry.js +2 -3
  94. package/src/first-success-guide.jsx +5 -5
  95. package/src/ghost-set.js +257 -0
  96. package/src/held-object-edit.jsx +113 -0
  97. package/src/held-object-pose.js +175 -0
  98. package/src/hierarchy-model.js +1 -1
  99. package/src/hierarchy-panel.jsx +1 -1
  100. package/src/imported-mesh.jsx +103 -0
  101. package/src/kits/held.js +84 -0
  102. package/src/kits/index.js +70 -0
  103. package/src/kits/smoking.js +57 -0
  104. package/src/light-blockers.js +93 -0
  105. package/src/motion/beat-board-model.js +84 -0
  106. package/src/motion/beat-board.css +124 -0
  107. package/src/motion/beat-board.jsx +59 -0
  108. package/src/motion/center-of-mass.js +66 -0
  109. package/src/motion/fix-collisions.js +850 -0
  110. package/src/motion/physics-review.js +118 -0
  111. package/src/{ardy → motion}/physics-support.js +1 -76
  112. package/src/motion/rig-snapshot.js +22 -0
  113. package/src/motion/take-segments.jsx +140 -0
  114. package/src/{ardy → motion}/timeline-coordinates.js +0 -21
  115. package/src/{ardy → motion}/timeline.css +1 -2
  116. package/src/{ardy → motion}/timeline.jsx +48 -419
  117. package/src/motion/waypoints.js +76 -0
  118. package/src/motion3/beats.js +83 -0
  119. package/src/motion3/body.js +158 -0
  120. package/src/motion3/bones.js +47 -0
  121. package/src/motion3/carried.js +47 -0
  122. package/src/motion3/compile-job.js +75 -0
  123. package/src/motion3/compile-worker.js +10 -0
  124. package/src/motion3/compiler/anchors.js +105 -0
  125. package/src/motion3/compiler/arm-orient.js +128 -0
  126. package/src/motion3/compiler/channels.js +125 -0
  127. package/src/motion3/compiler/compile.js +205 -0
  128. package/src/motion3/compiler/gait-rhythm.js +97 -0
  129. package/src/motion3/compiler/grip.js +171 -0
  130. package/src/motion3/compiler/head-steady.js +48 -0
  131. package/src/motion3/compiler/hold.js +134 -0
  132. package/src/motion3/compiler/idle.js +113 -0
  133. package/src/motion3/compiler/limbs.js +170 -0
  134. package/src/motion3/compiler/math.js +72 -0
  135. package/src/motion3/compiler/pose.js +162 -0
  136. package/src/motion3/compiler/quat.js +49 -0
  137. package/src/motion3/compiler/skeleton.js +74 -0
  138. package/src/motion3/compiler/validate-common.js +32 -0
  139. package/src/motion3/compiler/validate-goals.js +118 -0
  140. package/src/motion3/compiler/validate-objects.js +143 -0
  141. package/src/motion3/compiler/validate-parts.js +116 -0
  142. package/src/motion3/compiler/validate.js +122 -0
  143. package/src/motion3/compiler/vocab.js +73 -0
  144. package/src/motion3/compiler/walk-pelvis.js +275 -0
  145. package/src/motion3/compiler/walk.js +207 -0
  146. package/src/motion3/compiler/wrist-clamp.js +32 -0
  147. package/src/motion3/delta.js +47 -0
  148. package/src/motion3/describe.js +174 -0
  149. package/src/motion3/docs.js +27 -0
  150. package/src/motion3/edit-carry.js +21 -0
  151. package/src/motion3/fix/ease.js +16 -0
  152. package/src/motion3/fix/ground.js +37 -0
  153. package/src/motion3/fix/index.js +52 -0
  154. package/src/motion3/fix/push.js +71 -0
  155. package/src/motion3/fix/reach.js +46 -0
  156. package/src/motion3/fix/retime.js +79 -0
  157. package/src/motion3/fix/self.js +211 -0
  158. package/src/motion3/fix/slide.js +70 -0
  159. package/src/motion3/fix/turn.js +51 -0
  160. package/src/motion3/follow.js +39 -0
  161. package/src/motion3/free-motion.js +173 -0
  162. package/src/motion3/grip-choice.js +130 -0
  163. package/src/motion3/hold-plan.js +157 -0
  164. package/src/motion3/json-patch.js +77 -0
  165. package/src/motion3/key-aim.js +105 -0
  166. package/src/motion3/key-edit.js +82 -0
  167. package/src/motion3/lenient.js +127 -0
  168. package/src/motion3/object-keys.js +236 -0
  169. package/src/motion3/object-pose.js +182 -0
  170. package/src/motion3/object-tracks.js +12 -0
  171. package/src/motion3/pipeline.js +102 -0
  172. package/src/motion3/playback.js +51 -0
  173. package/src/motion3/probes.js +91 -0
  174. package/src/motion3/qa/body-checks.js +34 -0
  175. package/src/motion3/qa/check-names.js +14 -0
  176. package/src/motion3/qa/checks.js +121 -0
  177. package/src/motion3/qa/contact-checks.js +51 -0
  178. package/src/motion3/qa/explain.js +80 -0
  179. package/src/motion3/qa/fmt.js +5 -0
  180. package/src/motion3/qa/foot-checks.js +72 -0
  181. package/src/motion3/qa/geometry.js +77 -0
  182. package/src/motion3/qa/goals.js +191 -0
  183. package/src/motion3/qa/ground.js +60 -0
  184. package/src/motion3/qa/hints-contact.js +179 -0
  185. package/src/motion3/qa/hints-goal.js +160 -0
  186. package/src/motion3/qa/hints-knee.js +24 -0
  187. package/src/motion3/qa/hints-motion.js +209 -0
  188. package/src/motion3/qa/hints-object.js +91 -0
  189. package/src/motion3/qa/index.js +42 -0
  190. package/src/motion3/qa/key-checks.js +82 -0
  191. package/src/motion3/qa/near.js +96 -0
  192. package/src/motion3/qa/object-checks.js +135 -0
  193. package/src/motion3/qa/patch.js +161 -0
  194. package/src/motion3/qa/severity.js +38 -0
  195. package/src/motion3/qa/spec-checks.js +65 -0
  196. package/src/motion3/qa/style.js +218 -0
  197. package/src/motion3/qa/wrist-checks.js +69 -0
  198. package/src/motion3/qa/wrist-obs.js +60 -0
  199. package/src/motion3/refs.js +120 -0
  200. package/src/motion3/repair-tune.js +121 -0
  201. package/src/motion3/repair.js +83 -0
  202. package/src/motion3/report.js +67 -0
  203. package/src/motion3/rigs/index.js +14 -0
  204. package/src/motion3/rigs/x-bot-tpose-body.json +1 -0
  205. package/src/motion3/rigs/x-bot-tpose.json +1 -0
  206. package/src/motion3/rigs/y-bot-tpose-body.json +1 -0
  207. package/src/motion3/rigs/y-bot-tpose.json +1 -0
  208. package/src/motion3/scene.js +60 -0
  209. package/src/motion3/schema/brief.js +89 -0
  210. package/src/motion3/schema/fields.js +44 -0
  211. package/src/motion3/schema/spec-examples.js +46 -0
  212. package/src/motion3/schema/topics.js +111 -0
  213. package/src/motion3/schema/types.js +147 -0
  214. package/src/motion3/search.js +117 -0
  215. package/src/motion3/second-hand.js +112 -0
  216. package/src/motion3/skills/basic.js +82 -0
  217. package/src/motion3/skills/book.js +76 -0
  218. package/src/motion3/skills/car.js +145 -0
  219. package/src/motion3/skills/frames-auto.js +29 -0
  220. package/src/motion3/skills/index.js +83 -0
  221. package/src/motion3/skills/info.js +65 -0
  222. package/src/motion3/skills/smoke-kit.js +109 -0
  223. package/src/motion3/skills/smoke.js +160 -0
  224. package/src/motion3/spec-store.js +59 -0
  225. package/src/motion3/take-edit.js +155 -0
  226. package/src/motion3/take.js +63 -0
  227. package/src/motion3/timeline.js +127 -0
  228. package/src/motion3/views.js +121 -0
  229. package/src/motion3/walk-plan.js +119 -0
  230. package/src/object-catalog.jsx +7 -1
  231. package/src/object-colors.js +98 -0
  232. package/src/object-gizmo-parts.js +115 -0
  233. package/src/object-gizmo.jsx +37 -122
  234. package/src/object-glow.js +139 -0
  235. package/src/object-hidden.js +33 -0
  236. package/src/object-look.js +196 -0
  237. package/src/object-size.js +10 -0
  238. package/src/object-travel.js +71 -6
  239. package/src/panels/CameraPanel.jsx +7 -7
  240. package/src/panels/HdrEnvironmentControls.jsx +59 -0
  241. package/src/panels/LightPanel.jsx +25 -4
  242. package/src/panels/ObjectLookPanel.jsx +88 -0
  243. package/src/panels/PoseImagePanel.jsx +1 -1
  244. package/src/panels/PosePanel.jsx +2 -17
  245. package/src/panels/RigControlPanel.jsx +5 -53
  246. package/src/panels/SubjectBox.jsx +4 -1
  247. package/src/panels/details.css +14 -0
  248. package/src/posestudio.jsx +4 -27
  249. package/src/project-browser.jsx +3 -4
  250. package/src/project-resources.js +18 -31
  251. package/src/project.js +13 -104
  252. package/src/props.jsx +25 -280
  253. package/src/rail-dot-drag.js +23 -0
  254. package/src/render-passes.js +10 -0
  255. package/src/resource-status.jsx +1 -0
  256. package/src/result-modal.jsx +4 -19
  257. package/src/room.jsx +20 -12
  258. package/src/scene-assets.js +8 -6
  259. package/src/scene-light-place.js +72 -0
  260. package/src/scene-lights.jsx +148 -0
  261. package/src/scene-objects.js +31 -139
  262. package/src/scenes.js +15 -105
  263. package/src/semantic-edit.js +2 -5
  264. package/src/set-pieces.jsx +183 -0
  265. package/src/settings-menu.jsx +3 -11
  266. package/src/shell/BottomDock.jsx +11 -53
  267. package/src/shell/CompositionGuideButton.jsx +20 -0
  268. package/src/shell/DetailsSlot.jsx +16 -200
  269. package/src/shell/GhostsMenuGroup.jsx +74 -0
  270. package/src/shell/LibrarySlot.jsx +1 -3
  271. package/src/shell/MenuBar.jsx +3 -3
  272. package/src/shell/PreferencesDialog.jsx +15 -264
  273. package/src/shell/PreferencesSlot.jsx +2 -8
  274. package/src/shell/ShotPreviewHeader.jsx +17 -0
  275. package/src/shell/TopBar.jsx +5 -83
  276. package/src/shell/ViewportToolbar.jsx +23 -93
  277. package/src/shell/agent-glass.css +19 -6
  278. package/src/shell/details-selection.js +42 -0
  279. package/src/shell/ghosts-menu.css +22 -0
  280. package/src/shell/glass-regions.css +29 -3
  281. package/src/shell/preferences.css +6 -1
  282. package/src/shell/viewport.css +12 -0
  283. package/src/shot-authoring.js +4 -7
  284. package/src/soft-shadows.js +37 -0
  285. package/src/stage-attach-frames.js +12 -12
  286. package/src/stage-canvas-rigs.jsx +3 -3
  287. package/src/stage-capture.jsx +42 -8
  288. package/src/stage-characters.jsx +22 -216
  289. package/src/stage-editor-gizmos.jsx +6 -6
  290. package/src/stage-environment.js +93 -0
  291. package/src/stage-hdr-builtins.js +107 -0
  292. package/src/stage-hdr-image.js +116 -0
  293. package/src/stage-hdr-library.js +70 -0
  294. package/src/stage-hdr-map.js +94 -0
  295. package/src/stage-hdr.js +130 -0
  296. package/src/stage-lighting.js +149 -0
  297. package/src/stage-occlusion.js +210 -0
  298. package/src/stage-sky.jsx +159 -0
  299. package/src/stage-startup-defaults.js +5 -9
  300. package/src/studio-actions.js +12 -14
  301. package/src/studio-agent-commands.js +46 -16
  302. package/src/studio-agent-motion.js +9 -9
  303. package/src/studio-agent-protocol.js +46 -73
  304. package/src/studio-app-binding.js +29 -45
  305. package/src/studio-asset-list.js +17 -0
  306. package/src/studio-contact-sheet.js +37 -5
  307. package/src/studio-elements.js +27 -7
  308. package/src/studio-entity-bounds.js +18 -0
  309. package/src/studio-error-codes.js +8 -0
  310. package/src/studio-export-framing.js +152 -0
  311. package/src/studio-lighting-check.js +103 -0
  312. package/src/studio-motion-visual.js +150 -0
  313. package/src/studio-schema-errors.js +80 -0
  314. package/src/studio-support-gap.js +74 -0
  315. package/src/styles.css +1 -19
  316. package/src/timeline-defaults.js +5 -0
  317. package/src/timeline-extent.js +8 -20
  318. package/src/tutorial-walk.js +17 -0
  319. package/src/ui-scrub.js +1 -1
  320. package/src/use-shot-camera-tracks.js +12 -0
  321. package/src/view-ghosts.js +97 -0
  322. package/src/view-ghosts.jsx +49 -0
  323. package/src/workflow/AgentPanel.jsx +47 -166
  324. package/src/workflow/AgentProgressCard.jsx +107 -0
  325. package/src/workflow/AgentReplyText.jsx +37 -0
  326. package/src/workflow/AgentTurnSteps.jsx +84 -0
  327. package/src/workflow/LoginPanel.jsx +140 -0
  328. package/src/workflow/WorkflowBuilder.jsx +7 -23
  329. package/src/workflow/agent-client.js +54 -51
  330. package/src/workflow/agent-panel.css +71 -1
  331. package/src/workflow/agent-progress-card.css +167 -0
  332. package/src/workflow/agent-progress-view.js +47 -0
  333. package/src/workflow/agent-turn-steps.css +113 -0
  334. package/src/workflow/agent-turn.js +191 -0
  335. package/src/workflow/login-client.js +34 -0
  336. package/src/workflow/motion-input.js +18 -31
  337. package/src/workflow/node-schema.js +1 -1
  338. package/src/workflow/reply-markdown.js +69 -0
  339. package/src/workflow/scene-asset-sync.js +8 -8
  340. package/tools/agent-session-stats.mjs +61 -0
  341. package/tools/dev-full.mjs +5 -56
  342. package/tools/eslint-baseline.json +12 -13
  343. package/tools/headless-studio.mjs +85 -0
  344. package/tools/knip-baseline.json +0 -179
  345. package/tools/loc-baseline.json +33 -83
  346. package/tools/motion3/extract-body.mjs +103 -0
  347. package/tools/motion3/extract-rig.mjs +85 -0
  348. package/tools/process-supervisor.mjs +0 -88
  349. package/tools/run-tests.mjs +9 -124
  350. package/bin/agent/motion-runtime.mjs +0 -76
  351. package/dist/ardy/cskel27-rest.json +0 -557
  352. package/dist/assets/analytics-B41FmPYI.js +0 -1
  353. package/dist/assets/app-Do-Og5Pu.css +0 -1
  354. package/dist/assets/app-DwP-tl2x.js +0 -4920
  355. package/dist/assets/config-Bx7pYsD9.js +0 -1
  356. package/dist/assets/config-DeoFTYzb.css +0 -1
  357. package/dist/assets/demo-Dt0qZfS7.js +0 -1
  358. package/dist/assets/scene-asset-sync-BCWDJB1d.js +0 -19
  359. package/dist/assets/scene-asset-sync-DjJ_cJ2R.css +0 -1
  360. package/dist/assets/ticket-jqMhqL88.js +0 -1
  361. package/dist/assets/workflow-Br-K7Srs.js +0 -179
  362. package/dist/demo/walk-then-stop.npz +0 -0
  363. package/mcp/ardy-prompts.mjs +0 -218
  364. package/src/ardy/auto-fix-panel.css +0 -108
  365. package/src/ardy/auto-physics.js +0 -1194
  366. package/src/ardy/client.js +0 -153
  367. package/src/ardy/convert.js +0 -313
  368. package/src/ardy/cskel27-neutral.js +0 -39
  369. package/src/ardy/cskel27.js +0 -77
  370. package/src/ardy/export.js +0 -165
  371. package/src/ardy/fix-collisions.js +0 -2257
  372. package/src/ardy/foot-lock.js +0 -230
  373. package/src/ardy/motion-calibration.js +0 -118
  374. package/src/ardy/motion-edit.js +0 -213
  375. package/src/ardy/motion-url.js +0 -55
  376. package/src/ardy/mp4-duration.js +0 -102
  377. package/src/ardy/npz.js +0 -595
  378. package/src/ardy/physics-panel.css +0 -21
  379. package/src/ardy/physics-panel.jsx +0 -89
  380. package/src/ardy/physics-refine.js +0 -111
  381. package/src/ardy/physics-review.js +0 -567
  382. package/src/ardy/physics-temporal.js +0 -54
  383. package/src/ardy/platform-fit-panel.css +0 -64
  384. package/src/ardy/platform-fit-panel.jsx +0 -41
  385. package/src/ardy/platform-fit.js +0 -326
  386. package/src/ardy/playback.js +0 -711
  387. package/src/ardy/pose-pin.js +0 -97
  388. package/src/ardy/prompt-clips.js +0 -30
  389. package/src/ardy/retime.js +0 -211
  390. package/src/ardy/root-drop.js +0 -369
  391. package/src/ardy/timeline-resize.js +0 -13
  392. package/src/ardy/to-cskel27.js +0 -225
  393. package/src/ardy/trim.js +0 -33
  394. package/src/ardy/waypoints.js +0 -369
  395. package/src/ardy-bridge-contract.js +0 -281
  396. package/src/domains/motion/motion-video-capture.js +0 -664
  397. package/src/i2v-motion-client.js +0 -77
  398. package/src/i2v-motion-studio.jsx +0 -180
  399. package/src/line-edit.js +0 -1348
  400. package/src/motion/generation.js +0 -105
  401. package/src/motion-readiness-ui.jsx +0 -67
  402. package/src/motion-readiness.js +0 -40
  403. package/src/motion-resources.js +0 -177
  404. package/src/motion-store.js +0 -65
  405. package/src/motion-trail.js +0 -601
  406. package/src/multimodel-ingest.js +0 -394
  407. package/src/panels/PromptBlocksPanel.jsx +0 -444
  408. package/src/panels/VideoCapturePanel.jsx +0 -181
  409. package/src/pose-extract/browser.js +0 -42
  410. package/src/pose-extract/detector.js +0 -100
  411. package/src/pose-extract/fit.js +0 -227
  412. package/src/pose-extract/image-frame.js +0 -51
  413. package/src/pose-extract/index.js +0 -58
  414. package/src/pose-extract/keyframes.js +0 -74
  415. package/src/pose-extract/landmarks.js +0 -162
  416. package/src/pose-extract/mirror.js +0 -153
  417. package/src/pose-extract/take.js +0 -131
  418. package/src/pose-extract/video-frames.js +0 -91
  419. package/src/take-recipe.js +0 -165
  420. package/src/trail-key-conflicts.js +0 -39
  421. package/src/trail-pick.js +0 -59
  422. package/src/use-i2v-capture-modal.js +0 -15
  423. package/tools/ardy/BRIDGE.md +0 -37
  424. package/tools/ardy/GVHMR-NPZ.md +0 -68
  425. package/tools/ardy/README.md +0 -124
  426. package/tools/ardy/__pycache__/cclay_gvhmr_worker.cpython-313.pyc +0 -0
  427. package/tools/ardy/artifacts.mjs +0 -34
  428. package/tools/ardy/bridge.mjs +0 -1732
  429. package/tools/ardy/bvh-cskel27.mjs +0 -1265
  430. package/tools/ardy/cclay_constrained_generate.py +0 -561
  431. package/tools/ardy/cclay_gvhmr_worker.py +0 -264
  432. package/tools/ardy/cclay_motion_edit.py +0 -510
  433. package/tools/ardy/cclay_sequence_generate.py +0 -705
  434. package/tools/ardy/cclay_worker.py +0 -304
  435. package/tools/ardy/dump-npz.py +0 -205
  436. package/tools/ardy/extract-rest.mjs +0 -299
  437. package/tools/ardy/extract.mjs +0 -507
  438. package/tools/ardy/footage.mjs +0 -467
  439. package/tools/ardy/gvhmr-floor.mjs +0 -102
  440. package/tools/ardy/gvhmr-to-cskel27.mjs +0 -21
  441. package/tools/ardy/gvhmr_fastpath.py +0 -168
  442. package/tools/ardy/gvhmr_trajectory.py +0 -240
  443. package/tools/ardy/merge-text-encoder.py +0 -160
  444. package/tools/ardy/mocap-metrics.mjs +0 -200
  445. package/tools/ardy/mocap-quality-gate.mjs +0 -110
  446. package/tools/ardy/motion-stabilize.mjs +0 -348
  447. package/tools/ardy/npz.mjs +0 -414
  448. package/tools/ardy/pose-to-npz.mjs +0 -106
  449. package/tools/ardy/prompt-limits.mjs +0 -5
  450. package/tools/ardy/run-edit-on-box.sh +0 -73
  451. package/tools/ardy/run-local.mjs +0 -233
  452. package/tools/ardy/run-on-box.sh +0 -593
  453. package/tools/ardy/run-sequence-on-box.sh +0 -177
  454. package/tools/ardy/runners/gvhmr-worker.mjs +0 -206
  455. package/tools/ardy/runners/index.mjs +0 -18
  456. package/tools/ardy/runners/local.mjs +0 -455
  457. package/tools/ardy/runners/proc.mjs +0 -125
  458. package/tools/ardy/runners/remote.mjs +0 -252
  459. package/tools/ardy/setup-local.mjs +0 -189
  460. package/tools/ardy/setup-text-encoder-on-box.sh +0 -93
  461. package/tools/ardy/setup-text-encoder.py +0 -306
  462. package/tools/ardy/smpl-cskel27.mjs +0 -178
  463. package/tools/ardy/visual-qa.mjs +0 -196
  464. package/tools/ardy/vq-car.mjs +0 -52
  465. package/tools/bench/EXP3.md +0 -61
  466. package/tools/bench/cclay_bench_extract_incam.py +0 -125
  467. package/tools/bench/cclay_bench_extract_obs.py +0 -204
  468. package/tools/bench/cclay_bench_runner.py +0 -42
  469. package/tools/bench/cube-contact.mjs +0 -162
  470. package/tools/bench/exp3.mjs +0 -152
  471. package/tools/bench/extract-bench-lib.mjs +0 -216
  472. package/tools/bench/extract-bench.mjs +0 -302
  473. package/tools/bench/fal-generate.mjs +0 -88
  474. package/tools/bench/fit/README.md +0 -189
  475. package/tools/bench/fit/camera.mjs +0 -59
  476. package/tools/bench/fit/contact.mjs +0 -419
  477. package/tools/bench/fit/footlock.mjs +0 -234
  478. package/tools/bench/fit/motion.mjs +0 -85
  479. package/tools/bench/fit/pin.mjs +0 -27
  480. package/tools/bench/fit/remote.mjs +0 -105
  481. package/tools/bench/fit-bench.mjs +0 -126
  482. package/tools/bench/fit-sanity.mjs +0 -45
  483. package/tools/bench/metrics.mjs +0 -313
  484. package/tools/bench/obs/depth.mjs +0 -258
  485. package/tools/bench/obs/extrinsics.mjs +0 -175
  486. package/tools/bench/obs/fit_mannequin_betas.py +0 -340
  487. package/tools/bench/obs/ground.mjs +0 -294
  488. package/tools/bench/obs/heading.mjs +0 -151
  489. package/tools/bench/obs/ladder.mjs +0 -555
  490. package/tools/bench/obs/mannequin-betas.json +0 -124
  491. package/tools/bench/obs/remote.mjs +0 -83
  492. package/tools/bench/obs/rest_joints.py +0 -52
  493. package/tools/bench/obs/ybot-targets.mjs +0 -49
  494. package/tools/bench/obs-bench.mjs +0 -520
  495. package/tools/bench/score.mjs +0 -343
  496. package/tools/bench/summarize.mjs +0 -86
  497. package/tools/demo-worker/README.md +0 -137
  498. package/tools/demo-worker/api-client.mjs +0 -233
  499. package/tools/demo-worker/generate.mjs +0 -301
  500. package/tools/demo-worker/index.mjs +0 -466
  501. package/tools/demo-worker/sign-core.mjs +0 -112
  502. package/tools/demo-worker/sign.mjs +0 -161
  503. package/tools/gt-render/browser.mjs +0 -159
  504. package/tools/gt-render/camera-math.mjs +0 -276
  505. package/tools/gt-render/page.mjs +0 -267
  506. package/tools/gt-render/render.mjs +0 -514
  507. package/tools/gt-render/scene-box.mjs +0 -31
  508. package/tools/gt-render/take-transform.mjs +0 -87
  509. package/tools/kimodo/compare-seam.mjs +0 -108
  510. package/tools/kimodo/constraints.mjs +0 -244
  511. package/tools/kimodo/edit.mjs +0 -259
  512. package/tools/kimodo/effector-constraints.mjs +0 -200
  513. package/tools/kimodo/generate.mjs +0 -646
  514. package/tools/kimodo/local-output.mjs +0 -265
  515. package/tools/kimodo/measure-pose.mjs +0 -65
  516. package/tools/kimodo/measure-preserve.mjs +0 -899
  517. package/tools/kimodo/measure-waypoints.mjs +0 -55
  518. package/tools/kimodo/mlx-generate.py +0 -111
  519. package/tools/kimodo/pose-constraints.mjs +0 -248
  520. package/tools/kimodo/preserve-mask.mjs +0 -543
  521. package/tools/kimodo/read-npz.mjs +0 -189
  522. package/tools/kimodo/run-edit-on-box.mjs +0 -155
  523. package/tools/kimodo/run-sequence-on-box.mjs +0 -178
  524. package/tools/kimodo/runner.mjs +0 -284
  525. package/tools/kimodo/seam-batch.mjs +0 -77
  526. package/tools/kimodo/setup-local.mjs +0 -30
  527. package/tools/kimodo/setup-on-box.sh +0 -339
  528. package/tools/kimodo/soma77-to-cskel27.mjs +0 -305
  529. package/tools/morphgs/assets/gen_truth.py +0 -39
  530. package/tools/morphgs/assets/mesh_ori_rig.txt +0 -27
  531. package/tools/morphgs/assets/playback-check.mjs +0 -30
  532. package/tools/morphgs/demo-gate.sh +0 -26
  533. package/tools/morphgs/fbx2morphgs.mjs +0 -68
  534. package/tools/morphgs/morphgs-to-cskel27.mjs +0 -105
  535. package/tools/morphgs/patches/preprocess_src-none-mode.patch +0 -76
  536. package/tools/morphgs/setup-on-cluster.sh +0 -126
  537. package/tools/projflow/driver.py +0 -1069
  538. package/tools/projflow/generate.mjs +0 -805
  539. package/tools/projflow/hml22-to-cskel27.mjs +0 -735
  540. package/tools/projflow/line-edit-job.mjs +0 -547
  541. package/tools/projflow/replay.mjs +0 -452
  542. package/tools/projflow/runner.mjs +0 -269
  543. package/tools/projflow/service.mjs +0 -742
  544. package/tools/track/DESIGN.md +0 -513
  545. package/tools/track/backfill-provenance.mjs +0 -116
  546. package/tools/track/budget.mjs +0 -8
  547. package/tools/track/check-rig.mjs +0 -209
  548. package/tools/track/diagnostics.schema.json +0 -60
  549. package/tools/track/export-rig.mjs +0 -256
  550. package/tools/track/fallback.mjs +0 -7
  551. package/tools/track/fk-parity-fixture.mjs +0 -161
  552. package/tools/track/gate.mjs +0 -349
  553. package/tools/track/masks.mjs +0 -318
  554. package/tools/track/metrics.mjs +0 -201
  555. package/tools/track/publish-obs.mjs +0 -108
  556. package/tools/track/py/check_env.py +0 -61
  557. package/tools/track/py/eval_lr.py +0 -229
  558. package/tools/track/py/lr_viterbi.py +0 -294
  559. package/tools/track/py/masks.py +0 -405
  560. package/tools/track/py/objective.py +0 -382
  561. package/tools/track/py/rig.py +0 -508
  562. package/tools/track/py/scene.py +0 -326
  563. package/tools/track/py/test_joint_indices.py +0 -123
  564. package/tools/track/py/test_lr_viterbi.py +0 -195
  565. package/tools/track/py/test_masks.py +0 -229
  566. package/tools/track/py/test_rig.py +0 -288
  567. package/tools/track/py/test_scene.py +0 -354
  568. package/tools/track/py/test_track.py +0 -328
  569. package/tools/track/py/track.py +0 -411
  570. package/tools/track/remote.mjs +0 -140
  571. package/tools/track/rig-dump.mjs +0 -227
  572. package/tools/track/run-box-tests.mjs +0 -14
  573. package/tools/track/run-box.mjs +0 -168
  574. package/tools/track/setup-box.sh +0 -59
  575. package/tools/track/study-2d.mjs +0 -728
  576. /package/src/{ardy → motion}/collision-blockers.js +0 -0
  577. /package/src/{ardy → motion}/ground.js +0 -0
  578. /package/src/{ardy → motion}/ik-drag.js +0 -0
  579. /package/src/{ardy → motion}/ik-key-json.js +0 -0
  580. /package/src/{ardy → motion}/ik.js +0 -0
  581. /package/src/{ardy → motion}/physics-surface.js +0 -0
  582. /package/src/{ardy → motion}/playback-clock.js +0 -0
  583. /package/src/{ardy → motion}/range-pin.js +0 -0
@@ -1,304 +0,0 @@
1
- #!/usr/bin/env python3
2
- # SPDX-License-Identifier: GPL-3.0-or-later
3
- # SPDX-FileCopyrightText: CozyClay contributors
4
- #
5
- # cclay-owned script. Source of truth lives in the CozyClay repo at
6
- # tools/ardy/cclay_worker.py.
7
- """Persistent local generation worker for the CozyClay ARDY bridge.
8
-
9
- Loading the motion model and compiling its GPU kernels costs minutes on MPS,
10
- while the sampling itself takes seconds. Spawning a fresh python per request
11
- (the remote-box contract run-local.mjs mirrors) pays that cost every time, so
12
- this worker pays it ONCE: it loads the model, runs a tiny no-text warmup to
13
- force kernel compilation, and then serves generation jobs from the warm
14
- process. run-local.mjs prefers the worker and silently falls back to a direct
15
- spawn when it is not running, so the worker is an accelerator, never a
16
- dependency.
17
-
18
- Protocol (loopback TCP, one connection per job, one job at a time):
19
-
20
- client -> worker one JSON line
21
- {"mode": "ping"}
22
- {"mode": "single"|"sequence"|"edit", "argv": [...]}
23
- worker -> client the generator's stdout lines, verbatim, then
24
- "worker: pong" (ping) or "worker: exit <code>"
25
-
26
- `argv` is exactly the CLI argument vector of the corresponding
27
- cclay_*_generate/edit script; the worker calls that script's main() in
28
- process with the cached model injected, so worker and direct-spawn runs share
29
- one code path and cannot drift.
30
-
31
- env:
32
- CCLAY_ARDY_WORKER_PORT listen port (default 9552, loopback only)
33
- CHECKPOINTS_DIR / TEXT_ENCODER_URL / TEXT_ENCODERS_DIR as usual
34
- """
35
-
36
- import importlib
37
- import json
38
- import os
39
- import socket
40
- import sys
41
- import traceback
42
-
43
- HERE = os.path.dirname(os.path.abspath(__file__))
44
- sys.path.insert(0, HERE)
45
-
46
- MODULES = {
47
- "single": "cclay_constrained_generate",
48
- "sequence": "cclay_sequence_generate",
49
- "edit": "cclay_motion_edit",
50
- }
51
-
52
-
53
- class _Tee:
54
- """Mirror generator stdout to the job's socket AND the worker console.
55
-
56
- A vanished client must not kill the job: the generation keeps running,
57
- the npz still lands on disk, and only the socket copy is dropped.
58
- """
59
-
60
- def __init__(self, sock_file):
61
- self._sock_file = sock_file
62
-
63
- def write(self, data):
64
- sys.__stdout__.write(data)
65
- try:
66
- self._sock_file.write(data)
67
- self._sock_file.flush()
68
- except OSError:
69
- pass
70
-
71
- def flush(self):
72
- sys.__stdout__.flush()
73
-
74
-
75
- def requested_model_name(mode, argv, resolve_model_name, default_model, checkpoints_dir):
76
- """The model a job's argv asks for (edit has no --model flag)."""
77
- name = default_model
78
- if mode != "edit":
79
- for index, arg in enumerate(argv):
80
- if arg == "--model" and index + 1 < len(argv):
81
- name = argv[index + 1]
82
- return resolve_model_name(name, checkpoints_dir=checkpoints_dir)
83
-
84
-
85
- def fix_text_encoder_device(model, device):
86
- """Move an in-process LLM2Vec encoder onto the generation device, fast.
87
-
88
- ARDY's load_text_encoder ends with `.to(device or "cuda"/"cpu")`, so on a
89
- Mac the fallback encoder lands on CPU even when TEXT_ENCODER_DEVICE says
90
- mps. On MPS the dtype matters as much as the device: bf16 matmuls are
91
- emulated (a single prompt costs ~30-50 s) while fp16 is native, so fp16
92
- is tried first and a canary encode guards against fp16 overflow — NaNs
93
- demote back to bf16. Only the real in-process encoder has a `.model`;
94
- the API client stub is left alone.
95
- """
96
- encoder = getattr(model, "text_encoder", None)
97
- if encoder is None or not hasattr(encoder, "model") or device == "cpu":
98
- return
99
- import torch
100
-
101
- for dtype in (torch.float16, torch.bfloat16):
102
- try:
103
- encoder.to(device=device, dtype=dtype)
104
- canary, _ = encoder(["a person walks forward"])
105
- if bool(torch.isfinite(canary.float()).all()):
106
- print(f"worker: text encoder on {device} as {dtype}", flush=True)
107
- return
108
- print(f"worker: text encoder {dtype} produced non-finite values; trying next dtype", flush=True)
109
- except Exception as exc:
110
- print(f"worker: text encoder {dtype} on {device} failed ({exc}); trying next dtype", flush=True)
111
- try: # both GPU dtypes failed: back to the slow-but-correct CPU encoder
112
- encoder.to(device="cpu", dtype=torch.bfloat16)
113
- print("worker: text encoder stays on cpu", flush=True)
114
- except Exception as exc:
115
- print(f"worker: text encoder left as loaded ({exc})", flush=True)
116
-
117
-
118
- class _CachingEncoder:
119
- """Per-prompt embedding cache in front of the in-process encoder.
120
-
121
- Authoring iterates on ONE prompt (new seed, new pose pin, new waypoints),
122
- so most requests re-encode text the worker has already seen. Embeddings
123
- are deterministic per (model, dtype) — exactly the cache key's tag — and
124
- a few KB each, so they live in memory and under ~/.cozyclay/embed-cache
125
- across worker restarts. Misses are timed on the console; hits are free.
126
- """
127
-
128
- def __init__(self, inner, cache_dir, tag):
129
- import os
130
-
131
- self._inner = inner
132
- self._dir = cache_dir
133
- self._tag = tag
134
- self._mem = {}
135
- os.makedirs(cache_dir, exist_ok=True)
136
-
137
- def _key(self, text):
138
- import hashlib
139
-
140
- return hashlib.sha256(f"{self._tag}\x00{text}".encode("utf-8")).hexdigest()
141
-
142
- def _encode_one(self, text):
143
- import os
144
- import time
145
-
146
- import numpy as np
147
-
148
- key = self._key(text)
149
- if key in self._mem:
150
- return self._mem[key]
151
- path = os.path.join(self._dir, f"{key}.npy")
152
- if os.path.isfile(path):
153
- try:
154
- embedding = np.load(path)
155
- self._mem[key] = embedding
156
- return embedding
157
- except Exception:
158
- pass # unreadable cache entry: re-encode below
159
- started = time.time()
160
- tensor, _ = self._inner([text])
161
- embedding = tensor[0].detach().float().cpu().numpy()
162
- print(f"worker: text encode took {time.time() - started:.1f}s (cache miss)", flush=True)
163
- self._mem[key] = embedding
164
- try:
165
- np.save(path, embedding)
166
- except Exception:
167
- pass # cache write failure must never fail the job
168
- return embedding
169
-
170
- def __call__(self, texts):
171
- import numpy as np
172
- import torch
173
-
174
- is_string = isinstance(texts, str)
175
- text_list = [texts] if is_string else list(texts)
176
- stacked = np.stack([self._encode_one(text) for text in text_list])
177
- device = getattr(self._inner, "_device", "cpu")
178
- encoded = torch.from_numpy(stacked).to(device)
179
- lengths = [1] * len(text_list)
180
- if is_string:
181
- return encoded[0], 1
182
- return encoded, lengths
183
-
184
- def __getattr__(self, name):
185
- return getattr(self._inner, name)
186
-
187
-
188
- def warmup(model, device):
189
- """One throwaway sampling call so kernel compilation happens off the clock.
190
-
191
- Zero text features skip the text encoder entirely — the warmup must not
192
- drag the 16 GB Llama encoder into RAM just to compile Metal shaders.
193
- """
194
- import torch
195
- from ardy.motion_rep.tools import length_to_mask
196
-
197
- try:
198
- frames = int(model.gen_horizon_len)
199
- lengths = torch.tensor([frames], device=device)
200
- with torch.no_grad():
201
- model(
202
- [""],
203
- frames,
204
- num_denoising_steps=1,
205
- pad_mask=length_to_mask(lengths),
206
- first_heading_angle=torch.zeros(1, device=device),
207
- motion_mask=None,
208
- observed_motion=None,
209
- cfg_weight=2.0,
210
- text_feat=torch.zeros(1, 1, 4096, device=device),
211
- text_pad_mask=torch.ones(1, 1, device=device, dtype=torch.bool),
212
- progress_bar=lambda iterable: iterable,
213
- )
214
- print("worker: warmup complete", flush=True)
215
- except Exception as exc: # non-fatal: first real job just pays the compile
216
- print(f"worker: warmup skipped ({exc})", flush=True)
217
-
218
-
219
- def main():
220
- port = int(os.environ.get("CCLAY_ARDY_WORKER_PORT", "9552"))
221
-
222
- single = importlib.import_module(MODULES["single"])
223
- device = single.cclay_pick_device()
224
- single.cclay_mps_compat(device)
225
-
226
- from ardy.model import DEFAULT_MODEL, load_model
227
- from ardy.model.loading import get_env_var
228
- from ardy.model.registry import resolve_model_name
229
-
230
- checkpoints_dir = get_env_var("CHECKPOINTS_DIR", None)
231
- cached_name = resolve_model_name(DEFAULT_MODEL, checkpoints_dir=checkpoints_dir)
232
- print(f"worker: loading {cached_name} on {device} ...", flush=True)
233
- cached_model = load_model(cached_name, device=device, checkpoints_dir=checkpoints_dir)
234
- cached_model.eval()
235
- fix_text_encoder_device(cached_model, device)
236
- encoder = getattr(cached_model, "text_encoder", None)
237
- if encoder is not None and hasattr(encoder, "model"):
238
- try:
239
- param = next(encoder.model.parameters())
240
- tag = f"llm2vec:{param.dtype}:{param.device.type}"
241
- except Exception:
242
- tag = "llm2vec:unknown"
243
- cache_dir = os.path.join(os.path.expanduser("~"), ".cozyclay", "embed-cache")
244
- cached_model.text_encoder = _CachingEncoder(encoder, cache_dir, tag)
245
- print(f"worker: embedding cache at {cache_dir} ({tag})", flush=True)
246
- warmup(cached_model, device)
247
-
248
- server = socket.create_server(("127.0.0.1", port))
249
- print(f"worker: ready on 127.0.0.1:{port} (model {cached_name}, device {device})", flush=True)
250
-
251
- while True:
252
- conn, _ = server.accept()
253
- with conn:
254
- rfile = conn.makefile("r", encoding="utf-8")
255
- wfile = conn.makefile("w", encoding="utf-8")
256
- try:
257
- job = json.loads(rfile.readline())
258
- except (ValueError, OSError):
259
- continue
260
- mode = job.get("mode") if isinstance(job, dict) else None
261
- if mode == "ping":
262
- try:
263
- wfile.write("worker: pong\n")
264
- wfile.flush()
265
- except OSError:
266
- pass
267
- continue
268
- argv = job.get("argv") if isinstance(job, dict) else None
269
- if mode not in MODULES or not isinstance(argv, list) or not all(isinstance(a, str) for a in argv):
270
- try:
271
- wfile.write("worker: exit 2\n")
272
- wfile.flush()
273
- except OSError:
274
- pass
275
- continue
276
-
277
- module = importlib.import_module(MODULES[mode])
278
- code = 0
279
- old_stdout = sys.stdout
280
- sys.stdout = _Tee(wfile)
281
- try:
282
- wanted = requested_model_name(mode, argv, resolve_model_name, DEFAULT_MODEL, checkpoints_dir)
283
- if wanted != cached_name:
284
- print(f"worker: switching model {cached_name} -> {wanted}", flush=True)
285
- cached_model = load_model(wanted, device=device, checkpoints_dir=checkpoints_dir)
286
- cached_model.eval()
287
- cached_name = wanted
288
- module.main(argv, preloaded_model=cached_model)
289
- except SystemExit as exit_exc:
290
- code = exit_exc.code if isinstance(exit_exc.code, int) else 1
291
- except Exception:
292
- traceback.print_exc(file=sys.stdout)
293
- code = 1
294
- finally:
295
- sys.stdout = old_stdout
296
- try:
297
- wfile.write(f"worker: exit {code}\n")
298
- wfile.flush()
299
- except OSError:
300
- pass
301
-
302
-
303
- if __name__ == "__main__":
304
- main()
@@ -1,205 +0,0 @@
1
- #!/usr/bin/env python3
2
- """Dump one frame of an ARDY motion npz as a JSON document on stdout.
3
-
4
- Runs under the ARDY box python (``~/ardy/.venv/bin/python``); it needs numpy
5
- but no torch. Usage::
6
-
7
- python dump-npz.py <motion.npz> <frame>
8
-
9
- Emitted document (schema "ardy.frame.v1"):
10
-
11
- {
12
- "schema": "ardy.frame.v1",
13
- "source_npz": "<basename of the npz>",
14
- "frame": <requested frame index>,
15
- "frames_total": <frame count of the motion>,
16
- "members": {"<member name>": {"shape": [...], "dtype": "..."}, ...},
17
- "local_rot_mats": [ 27 x [[3],[3],[3]] row-major ],
18
- "posed_joints": [ 27 x [x, y, z] ]
19
- }
20
-
21
- Member names and axis order match the ARDY archives exactly as consumed by
22
- CozyClay (blender-addon/cclay): ``local_rot_mats[frame, joint]`` is the
23
- per-joint LOCAL rotation matrix in cskel27 order (Hips = joint 0), and
24
- ``posed_joints[frame, joint]`` the joint center position. ``foot_contacts``
25
- is optional and reported only when present. ``members`` lists every array in
26
- the archive (sorted), including carried members like ``fps``, so a consumer
27
- can see the exact contents without re-opening the npz.
28
-
29
- Before emitting, every one of the 27 rotation matrices of the requested frame
30
- is checked for finite entries, orthonormal rows/columns, and determinant +1,
31
- with the same tolerance CozyClay's motion_retarget uses
32
- (ROTATION_MATRIX_TOLERANCE = 1e-3 on squared norms, pairwise dots, and
33
- determinant). On the first violation the matrix index and the failing
34
- quantity are printed to stderr, the exit status is 1, and NO JSON is emitted:
35
- a garbage rotation must not silently reach a downstream consumer.
36
- """
37
-
38
- import json
39
- import math
40
- import sys
41
-
42
- import numpy as np
43
-
44
- SCHEMA = "ardy.frame.v1"
45
- JOINTS = 27
46
- # Mirror of CozyClay motion_retarget.ROTATION_MATRIX_TOLERANCE: applies to
47
- # squared row/column norms, pairwise dot products, and determinant, in
48
- # float64. float32 ARDY serialization noise stays far below 1e-3.
49
- TOLERANCE = 1e-3
50
-
51
-
52
- def _fail(message):
53
- """Report a fatal error on stderr and exit 1 without emitting JSON."""
54
- print(f"dump-npz: {message}", file=sys.stderr)
55
- sys.exit(1)
56
-
57
-
58
- def _check_rotation(matrix, frame, joint):
59
- """Return a list of violation strings for one 3x3 matrix, or [] if clean."""
60
- violations = []
61
- rows = [[float(matrix[i][j]) for j in range(3)] for i in range(3)]
62
- columns = [[rows[i][j] for i in range(3)] for j in range(3)]
63
- prefix = f"frame {frame} joint {joint}"
64
- for label, vectors in (("row", rows), ("column", columns)):
65
- for index, vector in enumerate(vectors):
66
- squared_norm = sum(c * c for c in vector)
67
- if not math.isfinite(squared_norm):
68
- violations.append(
69
- f"{prefix} {label} {index} has non-finite entries"
70
- )
71
- elif abs(squared_norm - 1.0) > TOLERANCE:
72
- violations.append(
73
- f"{prefix} {label} {index} squared norm {squared_norm:.6f} "
74
- f"differs from 1.0 by more than {TOLERANCE}"
75
- )
76
- for first, second in ((0, 1), (0, 2), (1, 2)):
77
- dot = sum(
78
- vectors[first][i] * vectors[second][i] for i in range(3)
79
- )
80
- if not math.isfinite(dot):
81
- violations.append(
82
- f"{prefix} {label} {first}/{second} dot is non-finite"
83
- )
84
- elif abs(dot) > TOLERANCE:
85
- violations.append(
86
- f"{prefix} {label} {first}/{second} dot {dot:.6f} "
87
- f"exceeds {TOLERANCE} in magnitude"
88
- )
89
- determinant = (
90
- rows[0][0] * (rows[1][1] * rows[2][2] - rows[1][2] * rows[2][1])
91
- - rows[0][1] * (rows[1][0] * rows[2][2] - rows[1][2] * rows[2][0])
92
- + rows[0][2] * (rows[1][0] * rows[2][1] - rows[1][1] * rows[2][0])
93
- )
94
- if not math.isfinite(determinant):
95
- violations.append(f"{prefix} determinant is non-finite")
96
- elif abs(determinant - 1.0) > TOLERANCE:
97
- violations.append(
98
- f"{prefix} determinant {determinant:.6f} differs from 1.0 "
99
- f"by more than {TOLERANCE}"
100
- )
101
- return violations
102
-
103
-
104
- def main(argv):
105
- if len(argv) != 3:
106
- _fail(f"usage: {argv[0]} <motion.npz> <frame>")
107
- npz_path, frame_text = argv[1], argv[2]
108
- try:
109
- frame = int(frame_text)
110
- except ValueError:
111
- _fail(f"frame must be an integer, got {frame_text!r}")
112
- if frame < 0:
113
- _fail(f"frame must be >= 0, got {frame}")
114
-
115
- try:
116
- data = np.load(npz_path, allow_pickle=False)
117
- except Exception as exc:
118
- _fail(f"cannot load {npz_path}: {exc}")
119
-
120
- try:
121
- if "local_rot_mats" not in data.files:
122
- _fail(f"{npz_path} has no 'local_rot_mats' member")
123
- if "posed_joints" not in data.files:
124
- _fail(f"{npz_path} has no 'posed_joints' member")
125
- rotations = data["local_rot_mats"]
126
- joints = data["posed_joints"]
127
- if rotations.shape[1:] != (JOINTS, 3, 3):
128
- _fail(
129
- f"local_rot_mats must have shape (F, {JOINTS}, 3, 3), "
130
- f"got {rotations.shape}"
131
- )
132
- if joints.shape[1:] != (JOINTS, 3):
133
- _fail(
134
- f"posed_joints must have shape (F, {JOINTS}, 3), "
135
- f"got {joints.shape}"
136
- )
137
- if joints.shape[0] != rotations.shape[0]:
138
- _fail(
139
- "local_rot_mats and posed_joints frame counts differ "
140
- f"({rotations.shape[0]} vs {joints.shape[0]})"
141
- )
142
- frames_total = int(rotations.shape[0])
143
- if frames_total < 1:
144
- _fail(f"motion has no frames ({frames_total})")
145
- if frame >= frames_total:
146
- _fail(
147
- f"frame {frame} out of range: motion has {frames_total} frames"
148
- )
149
-
150
- # Validate every rotation matrix of the requested frame BEFORE any
151
- # JSON is written; a violation aborts with a stderr report and a
152
- # non-zero exit status instead of emitting garbage.
153
- violations = []
154
- for joint in range(JOINTS):
155
- violations.extend(_check_rotation(rotations[frame][joint], frame, joint))
156
- for joint in range(JOINTS):
157
- for axis in range(3):
158
- if not math.isfinite(float(joints[frame][joint][axis])):
159
- violations.append(
160
- f"frame {frame} joint {joint} axis {axis} "
161
- "position is not finite"
162
- )
163
- if violations:
164
- for violation in violations[:20]:
165
- print(f"dump-npz: VIOLATION {violation}", file=sys.stderr)
166
- if len(violations) > 20:
167
- print(
168
- f"dump-npz: ... and {len(violations) - 20} more",
169
- file=sys.stderr,
170
- )
171
- _fail(
172
- f"refusing to emit {npz_path} frame {frame}: "
173
- f"{len(violations)} rotation/position check(s) failed"
174
- )
175
-
176
- members = {}
177
- for name in sorted(data.files):
178
- member = data[name]
179
- members[name] = {
180
- "shape": [int(size) for size in member.shape],
181
- "dtype": str(member.dtype),
182
- }
183
-
184
- document = {
185
- "schema": SCHEMA,
186
- "source_npz": npz_path.rsplit("/", 1)[-1],
187
- "frame": frame,
188
- "frames_total": frames_total,
189
- "members": members,
190
- "local_rot_mats": [
191
- [[float(value) for value in row] for row in rotations[frame][joint]]
192
- for joint in range(JOINTS)
193
- ],
194
- "posed_joints": [
195
- [float(value) for value in joints[frame][joint]]
196
- for joint in range(JOINTS)
197
- ],
198
- }
199
- print(json.dumps(document, indent=2))
200
- finally:
201
- data.close()
202
-
203
-
204
- if __name__ == "__main__":
205
- main(sys.argv)