cozyclay 2.1.1 → 3.0.1

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