cozyclay 2.1.1 → 3.0.0

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