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,593 +0,0 @@
1
- #!/usr/bin/env bash
2
- # run-on-box.sh - generate an ARDY clip on the remote box.
3
- #
4
- # run-on-box.sh [<pose.npz>] --base <motion-id|npz-path> --prompt "<prompt>" \
5
- # --duration <seconds> [--dst-frame <N>] [--src-frame <N>] [--seed <S>] \
6
- # [--root-2d FRAME X Z HEADING ...] [--output <local.npz>] [--dry-run]
7
-
8
- #
9
- # The pose npz is an ARDY motion npz (it must carry local_rot_mats and
10
- # posed_joints; the frame at SRC_FRAME holds the pose). It is pushed to a
11
- # fresh remote temp dir and handed to the generator as
12
- # --pose-from <tmp>/pose.npz <src-frame> <dst-frame>
13
- # which pins the FULL-BODY pose onto <dst-frame> of the new clip. The base
14
- # motion supplies the unconstrained first pass (--base) and the generated
15
- # npz is pulled back. Nothing is ever written inside the ARDY checkout: the
16
- # base npz is read from ~/ardy/outputs/ (or outputs/omb/), the pose and the
17
- # result live under the remote temp dir, and the temp dir is removed on
18
- # exit.
19
- #
20
- # Three modes, chosen by what is given:
21
- # pose <pose.npz> present (the default): the pose npz is pushed to a
22
- # fresh remote temp dir and handed to the constrained generator
23
- # as --pose-from <tmp>/pose.npz <src-frame> <dst-frame>, pinning
24
- # the FULL-BODY pose onto <dst-frame> of the new clip. Requires
25
- # --base and --dst-frame.
26
- # waypoints no pose npz but one or more --root-2d groups: the constrained
27
- # generator runs WITHOUT --pose-from, so the clip follows the
28
- # path and prompt only, with no full-body pose constraint.
29
- # --dst-frame is ignored. --base is optional: given, it is the
30
- # unconstrained first pass; omitted, the script free-generates
31
- # the base clip itself first (two-pass mode: scripts/generate.py
32
- # with the same prompt/duration/seed under the remote temp dir,
33
- # then the constrained pass with --base pointing at that npz).
34
- # free no pose npz and no --root-2d: scripts/generate.py on the box,
35
- # the unconstrained generator (the constrained script refuses a
36
- # run with no target, pose or waypoint). --base and --dst-frame
37
- # are ignored.
38
- #
39
- # Each --root-2d group pins the root on the X/Z ground plane at one 0-based
40
- # clip frame (ARDY is Y-up; the horizontal plane is X and Z in meters, Y is
41
- # not constrained). X and Z must be within -20..20, HEADING is a yaw in
42
- # radians within -2π..2π or the literal 'none' to leave facing free. The
43
- # request carries 2..32 sparse authored keys starting at frame 0. Intermediate
44
- # root positions are left for the model to generate. Values are validated
45
- # locally and %q-quoted into the remote command like all other args.
46
- #
47
- # CPU is forced with CUDA_VISIBLE_DEVICES="" and that is deliberate: the
48
- # box's RTX 3070 has only 8.2 GB VRAM against 94 GB RAM, and nvidia-smi is
49
- # broken there (NVML driver/library version mismatch) even though
50
- # torch.cuda.is_available() still returns True - so without the override the
51
- # generator's `device = "cuda:0" if torch.cuda.is_available() else "cpu"`
52
- # line would pick a GPU that cannot hold the model. The preflight probe
53
- # below mirrors that exact line under the same env and prints the device the
54
- # generator will actually use.
55
- #
56
- # env (names shared with CozyClay scripts/ardy/sync-to-box):
57
- # CCLAY_ARDY_HOST ssh destination for the ARDY host (required)
58
- # CCLAY_ARDY_REPO ARDY checkout on the box (default $HOME/ardy)
59
- # CCLAY_ARDY_VENV venv python on the box (default ~/ardy/.venv-cuda/bin/python)
60
- set -euo pipefail
61
-
62
- HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
63
- HOST="${CCLAY_ARDY_HOST:-}"
64
- # REMOTE's default is escaped so the REMOTE shell expands $HOME (the same
65
- # trick sync-to-box uses); VENV_PY's default keeps a literal ~ so the REMOTE
66
- # shell tilde-expands it. Both resolve to the same ~/ardy on the box.
67
- REMOTE="${CCLAY_ARDY_REPO:-\$HOME/ardy}"
68
- # The box carries two venvs and they are NOT interchangeable: .venv runs the
69
- # CPU text-encoder service, .venv-cuda is what the motion generator was actually
70
- # run under (scripts/generate.py in generate_pc_monitor.log, 1060 MiB of VRAM).
71
- VENV_PY="${CCLAY_ARDY_VENV:-~/ardy/.venv-cuda/bin/python}"
72
- # Text encoder URL the generator falls back to when TEXT_ENCODER_URL is unset:
73
- # ardy/model/registry.py:47 DEFAULT_TEXT_ENCODER_URL. Generation dies without it,
74
- # so the preflight checks it rather than letting the run fail minutes in.
75
- ENCODER_URL="${CCLAY_ARDY_ENCODER_URL:-http://127.0.0.1:9550/}"
76
- # Force the motion model onto the CPU as well. Off by default: the encoder --
77
- # the part that does not fit beside the model in 8.2 GB -- already runs on the
78
- # CPU as its own service, and the model itself only needs about 1 GB.
79
- FORCE_CPU=0
80
-
81
- # BatchMode: never hang on a password prompt mid-pipeline. ConnectTimeout
82
- # fails fast on a dead host; ServerAlive* drops a wedged connection instead
83
- # of leaving the user staring at a silent ssh (30 s interval * 240 = 2 h).
84
- SSH_OPTS=(-o BatchMode=yes -o ConnectTimeout=10 -o ServerAliveInterval=30 -o ServerAliveCountMax=240)
85
- SCP_OPTS=(-o BatchMode=yes -o ConnectTimeout=10)
86
-
87
- usage() {
88
- cat >&2 <<'EOF'
89
- usage: run-on-box.sh [<pose.npz>] --base <motion-id|npz-path> --prompt "<prompt>" \
90
- --duration <seconds> [--dst-frame <N>] [--src-frame <N>] [--seed <S>] \
91
- [--root-2d FRAME X Z HEADING ...] [--output <local.npz>] [--dry-run]
92
-
93
-
94
- <pose.npz> OPTIONAL local ARDY motion npz (local_rot_mats +
95
- posed_joints) whose frame <src-frame> holds the CozyClay
96
- pose to honour. Omit it to generate without a full-body pose
97
- constraint: with --root-2d groups the clip is
98
- path/prompt-only constrained (with --base, or two-pass: the
99
- free generator produces the base clip first); without them
100
- it is free generation (scripts/generate.py on the box).
101
- --base base motion on the box: a bare id or bare <name>.npz
102
- (looked up in ~/ardy/outputs/<name>.npz, then
103
- ~/ardy/outputs/omb/<name>.npz), or a path containing /
104
- relative to the ARDY checkout / absolute. Required in pose
105
- mode; optional in waypoints mode (omitted = two-pass: the
106
- free generator first produces the base clip on the box);
107
- ignored in free mode.
108
- --prompt generation prompt for the constrained clip
109
- --duration clip duration in seconds (20 fps, 0.15..1200)
110
- --dst-frame clip frame to pin the pose onto, 0 <= dst < duration*20
111
- (pose mode only)
112
- --src-frame frame of <pose.npz> to copy (default 0; pose mode only)
113
- --seed optional seed for reproducible results
114
- --output local destination for the generated npz
115
- (default tools/ardy/out/<pose>-constrained.npz, or
116
- tools/ardy/out/<epoch>-generated.npz without a pose)
117
-
118
- --dry-run run the preflight checks, print the exact remote command,
119
- and exit without pushing, generating, or pulling
120
- --root-2d repeatable root waypoint: FRAME (0-based, inside the clip),
121
- X and Z in meters within -20..20 (ARDY is Y-up; the ground
122
- plane is X/Z, Y is not constrained), HEADING a yaw in
123
- radians within -2π..2π or the literal 'none' to leave
124
- facing free. Supply 2..32 sparse keys beginning at frame 0;
125
- ARDY generates all intermediate root motion.
126
-
127
- env:
128
- CCLAY_ARDY_HOST ssh destination for the ARDY host (required)
129
- CCLAY_ARDY_REPO ARDY checkout on the box (default $HOME/ardy)
130
- --cpu also run the motion model on the CPU (slower; the text encoder
131
- is on the CPU either way, as its own service)
132
-
133
- env:
134
- CCLAY_ARDY_VENV venv python on the box (default ~/ardy/.venv-cuda/bin/python)
135
- CCLAY_ARDY_ENCODER_URL text encoder service (default http://127.0.0.1:9550/)
136
- EOF
137
- exit 2
138
- }
139
-
140
- POSE_NPZ="" # legacy positional pose; normalized into POSE_ARGS after parsing
141
- POSE_ARGS=() # repeatable triples: LOCAL_NPZ SRC_FRAME DST_FRAME
142
- ROOT_MARGIN=""
143
- CONTACT_THRESHOLD=""
144
- HISTORY_FRAMES=""
145
- BASE=""
146
- PROMPT=""
147
- DURATION=""
148
- DST_FRAME=""
149
- SRC_FRAME=0
150
- SEED=""
151
- OUTPUT=""
152
- DRY_RUN=0
153
- ROOT_2D_ARGS=()
154
-
155
- while [[ $# -gt 0 ]]; do
156
- case "$1" in
157
- --base)
158
- [[ $# -ge 2 ]] || { echo "run-on-box: --base needs a motion id or npz path" >&2; usage; }
159
- BASE="$2"; shift 2 ;;
160
- --prompt)
161
- [[ $# -ge 2 ]] || { echo "run-on-box: --prompt needs text" >&2; usage; }
162
- PROMPT="$2"; shift 2 ;;
163
- --duration)
164
- [[ $# -ge 2 ]] || { echo "run-on-box: --duration needs seconds" >&2; usage; }
165
- [[ "$2" =~ ^[0-9]+([.][0-9]+)?$ ]] || { echo "run-on-box: --duration must be a number, got '$2'" >&2; usage; }
166
- DURATION="$2"; shift 2 ;;
167
- --dst-frame)
168
- [[ $# -ge 2 ]] || { echo "run-on-box: --dst-frame needs a frame number" >&2; usage; }
169
- [[ "$2" =~ ^[0-9]+$ ]] || { echo "run-on-box: --dst-frame must be a non-negative integer, got '$2'" >&2; usage; }
170
- DST_FRAME="$2"; shift 2 ;;
171
- --src-frame)
172
- [[ $# -ge 2 ]] || { echo "run-on-box: --src-frame needs a frame number" >&2; usage; }
173
- [[ "$2" =~ ^[0-9]+$ ]] || { echo "run-on-box: --src-frame must be a non-negative integer, got '$2'" >&2; usage; }
174
- SRC_FRAME="$2"; shift 2 ;;
175
- --seed)
176
- [[ $# -ge 2 ]] || { echo "run-on-box: --seed needs an integer" >&2; usage; }
177
- [[ "$2" =~ ^[0-9]+$ ]] || { echo "run-on-box: --seed must be a non-negative integer, got '$2'" >&2; usage; }
178
- SEED="$2"; shift 2 ;;
179
- --pose-from)
180
- [[ $# -ge 4 ]] || { echo "run-on-box: --pose-from needs LOCAL_NPZ SRC_FRAME DST_FRAME" >&2; usage; }
181
- [[ "$3" =~ ^[0-9]+$ && "$4" =~ ^[0-9]+$ ]] || { echo "run-on-box: --pose-from frames must be non-negative integers" >&2; usage; }
182
- POSE_ARGS+=("$2" "$3" "$4"); shift 4 ;;
183
- --root-2d)
184
- [[ $# -ge 5 ]] || { echo "run-on-box: --root-2d needs FRAME X Z HEADING" >&2; usage; }
185
- ROOT_2D_ARGS+=("$2" "$3" "$4" "$5"); shift 5 ;;
186
- --cpu)
187
- FORCE_CPU=1; shift ;;
188
- --root-margin)
189
- [[ $# -ge 2 && "$2" =~ ^[0-9]+([.][0-9]+)?$ ]] || { echo "run-on-box: --root-margin needs a non-negative number" >&2; usage; }
190
- ROOT_MARGIN="$2"; shift 2 ;;
191
- --history-frames)
192
- [[ $# -ge 2 && "$2" =~ ^[0-9]+$ ]] || { echo "run-on-box: --history-frames needs a non-negative integer" >&2; usage; }
193
- HISTORY_FRAMES="$2"; shift 2 ;;
194
- --contact-threshold)
195
- [[ $# -ge 2 && "$2" =~ ^[0-9]+([.][0-9]+)?$ ]] || { echo "run-on-box: --contact-threshold needs a non-negative number" >&2; usage; }
196
- CONTACT_THRESHOLD="$2"; shift 2 ;;
197
- --output)
198
- [[ $# -ge 2 ]] || { echo "run-on-box: --output needs a path" >&2; usage; }
199
- OUTPUT="$2"; shift 2 ;;
200
- --dry-run)
201
- DRY_RUN=1; shift ;;
202
- -h|--help)
203
- usage ;;
204
- -*)
205
- echo "run-on-box: unknown option '$1'" >&2; usage ;;
206
- *)
207
- [[ -z "$POSE_NPZ" ]] || { echo "run-on-box: one pose npz only, got '$1'" >&2; usage; }
208
- POSE_NPZ="$1"; shift ;;
209
- esac
210
- done
211
-
212
- [[ -n "$HOST" ]] || {
213
- echo "run-on-box: CCLAY_ARDY_HOST is required (for example: user@ardy-host)" >&2
214
- exit 2
215
- }
216
-
217
- # Normalize the legacy positional pose into the repeatable pose list.
218
- if [[ -n "$POSE_NPZ" ]]; then
219
- [[ -n "$DST_FRAME" ]] || usage
220
- POSE_ARGS+=("$POSE_NPZ" "$SRC_FRAME" "$DST_FRAME")
221
- fi
222
-
223
- # Mode by what is given: one or more pose npz files pin the full body,
224
- # waypoints alone constrain the path, and neither is free generation.
225
- MODE=""
226
- if [[ ${#POSE_ARGS[@]} -gt 0 ]]; then
227
- MODE="pose"
228
- elif [[ ${#ROOT_2D_ARGS[@]} -gt 0 ]]; then
229
- MODE="waypoints"
230
- else
231
- MODE="free"
232
- fi
233
- # Waypoints run the constrained generator: ONE model sampling call for the
234
- # whole clip. ARDY's trained window is 10 s — frames beyond it sit outside
235
- # the model's temporal horizon and the motion visibly degrades, so the last
236
- # line of defence refuses what every upstream layer should already have.
237
- if [[ "$MODE" == "waypoints" ]] && ! awk -v d="$DURATION" 'BEGIN { exit !(d <= 10) }'; then
238
- echo "run-on-box: --root-2d requires --duration <= 10 s (one-shot constrained generation; ARDY trained window), got ${DURATION}s" >&2
239
- exit 1
240
- fi
241
- # Waypoints without --base is two-pass: the free generator first produces
242
- # the base clip on the box (pass 1), then the constrained pass uses it.
243
- TWO_PASS=0
244
- [[ "$MODE" == "waypoints" && -z "$BASE" ]] && TWO_PASS=1
245
- IMPLICIT_POSE_BASE=0
246
-
247
- [[ -n "$PROMPT" && -n "$DURATION" ]] || usage
248
- if [[ "$MODE" == "pose" && -z "$BASE" ]]; then
249
- # Internal parser/reference baseline only. Full-body poses are the actual
250
- # constraints; users never select a semantic base motion.
251
- BASE="${CCLAY_ARDY_REFERENCE_BASE:-stand-upright-facing-forward-bring-both--0722140757}"
252
- IMPLICIT_POSE_BASE=1
253
- fi
254
- # --- local validation, mirroring the CozyClay wrapper's bounds -------------
255
- if [[ "$MODE" == "pose" ]]; then
256
- for ((i = 0; i < ${#POSE_ARGS[@]}; i += 3)); do
257
- pose_path="${POSE_ARGS[$i]}"
258
- [[ -f "$pose_path" ]] || { echo "run-on-box: pose npz not found: $pose_path" >&2; exit 1; }
259
- done
260
- fi
261
-
262
- [[ -n "$PROMPT" ]] || { echo "run-on-box: --prompt must not be empty" >&2; exit 1; }
263
- # The clip is int(duration * 20) frames at ARDY's 20 fps, capped at 1200 s
264
- # like the wrapper; the remote rejects anything below 3 frames because
265
- # inter-frame continuity is undefined there.
266
- awk -v d="$DURATION" 'BEGIN { exit !(d > 0 && d <= 1200) }' || {
267
- echo "run-on-box: --duration must be > 0 and <= 1200 seconds, got '$DURATION'" >&2; exit 1; }
268
- CLIP_FRAMES="$(awk -v d="$DURATION" 'BEGIN { printf "%d", d * 20 }')"
269
- [[ "$CLIP_FRAMES" -ge 3 ]] || {
270
- echo "run-on-box: --duration ${DURATION}s yields ${CLIP_FRAMES} frame(s) at 20 fps; a clip needs at least 3" >&2; exit 1; }
271
- if [[ "$MODE" == "pose" ]]; then
272
- for ((i = 0; i < ${#POSE_ARGS[@]}; i += 3)); do
273
- dst="${POSE_ARGS[$((i + 2))]}"
274
- awk -v f="$dst" -v m="$CLIP_FRAMES" 'BEGIN { exit !(f < m) }' || {
275
- echo "run-on-box: --pose-from destination $dst is outside 0..$((CLIP_FRAMES - 1)) (duration ${DURATION}s at 20 fps)" >&2; exit 1; }
276
- done
277
- fi
278
- # --- --root-2d validation: each group, then the set as a whole -------------
279
- # Mirrors the bridge contract: 2..32 sparse keys beginning at frame 0,
280
- # strictly ascending, X/Z in meters within -20..20, HEADING a finite number
281
- # of radians within -2π..2π or the literal 'none'.
282
- FLOAT_RE='^[+-]?([0-9]+([.][0-9]*)?|[.][0-9]+)([eE][+-]?[0-9]+)?$'
283
- validate_root_2d() {
284
- local n="${#ROOT_2D_ARGS[@]}" i frame x z heading prev=-1 count
285
- [[ $((n % 4)) -eq 0 ]] || { echo "run-on-box: internal error: --root-2d group list is misaligned" >&2; exit 1; }
286
- count=$((n / 4))
287
- if [[ "$count" -ne 0 && ( "$count" -lt 2 || "$count" -gt 32 ) ]]; then
288
- echo "run-on-box: --root-2d needs 2..32 sparse waypoints, got $count" >&2
289
- exit 1
290
- fi
291
- for ((i = 0; i < n; i += 4)); do
292
- frame="${ROOT_2D_ARGS[$i]}"
293
- x="${ROOT_2D_ARGS[$((i + 1))]}"
294
- z="${ROOT_2D_ARGS[$((i + 2))]}"
295
- heading="${ROOT_2D_ARGS[$((i + 3))]}"
296
- [[ "$frame" =~ ^[0-9]+$ ]] || { echo "run-on-box: --root-2d FRAME must be a non-negative integer, got '$frame'" >&2; exit 1; }
297
- awk -v f="$frame" -v m="$CLIP_FRAMES" 'BEGIN { exit !(f >= 0 && f < m) }' || {
298
- echo "run-on-box: --root-2d frame $frame is outside 0..$((CLIP_FRAMES - 1)) (duration ${DURATION}s at 20 fps)" >&2
299
- exit 1
300
- }
301
- awk -v f="$frame" -v p="$prev" 'BEGIN { exit !(f > p) }' || {
302
- echo "run-on-box: --root-2d frames must be strictly ascending; frame $frame repeats or precedes frame $prev" >&2
303
- exit 1
304
- }
305
- if [[ $i -eq 0 && "$frame" -ne 0 ]]; then
306
- echo "run-on-box: --root-2d start must be at frame 0, got frame $frame" >&2
307
- exit 1
308
- fi
309
- prev="$frame"
310
- [[ "$x" =~ $FLOAT_RE ]] || { echo "run-on-box: --root-2d X must be a number, got '$x'" >&2; exit 1; }
311
- awk -v v="$x" 'BEGIN { exit !(v >= -20 && v <= 20) }' || {
312
- echo "run-on-box: --root-2d X $x is outside -20..20 meters" >&2
313
- exit 1
314
- }
315
- [[ "$z" =~ $FLOAT_RE ]] || { echo "run-on-box: --root-2d Z must be a number, got '$z'" >&2; exit 1; }
316
- awk -v v="$z" 'BEGIN { exit !(v >= -20 && v <= 20) }' || {
317
- echo "run-on-box: --root-2d Z $z is outside -20..20 meters" >&2
318
- exit 1
319
- }
320
- if [[ "$heading" != "none" ]]; then
321
- [[ "$heading" =~ $FLOAT_RE ]] || {
322
- echo "run-on-box: --root-2d HEADING must be a number of radians or the literal 'none', got '$heading'" >&2
323
- exit 1
324
- }
325
- awk -v h="$heading" 'BEGIN { pi = atan2(0, -1); exit !(h >= -2*pi && h <= 2*pi) }' || {
326
- echo "run-on-box: --root-2d HEADING $heading rad is outside -2π..2π" >&2
327
- exit 1
328
- }
329
- fi
330
- done
331
- }
332
- validate_root_2d
333
- # SRC_FRAME indexes the pose npz; its real bound is only knowable on the
334
- # box, so like the reference wrapper we accept any non-negative integer here
335
- # and let the remote range-check it against the npz's frame count.
336
- if [[ "$MODE" == "pose" ]]; then
337
- FIRST_POSE="${POSE_ARGS[0]}"
338
- OUTPUT="${OUTPUT:-$HERE/out/$(basename "${FIRST_POSE%.npz}")-constrained.npz}"
339
- else
340
- OUTPUT="${OUTPUT:-$HERE/out/$(date +%s)-generated.npz}"
341
- fi
342
-
343
-
344
- # --- preflight: fail fast, cheapest first ---------------------------------
345
- if ! ssh "${SSH_OPTS[@]}" "$HOST" ":" </dev/null; then
346
- echo "run-on-box: cannot ssh to ${HOST} (BatchMode). Check network reachability and the SSH key agent." >&2
347
- exit 1
348
- fi
349
- echo "run-on-box: ssh to ${HOST} ok"
350
-
351
- # Free generation runs scripts/generate.py (the constrained script refuses a
352
- # run with no target, pose or waypoint); every other mode runs the
353
- # constrained generator. Two-pass waypoints mode needs BOTH scripts:
354
- # generate.py for the free base pass, then the constrained script.
355
- GEN_SCRIPT="scripts/cclay_constrained_generate.py"
356
- [[ "$MODE" == "free" ]] && GEN_SCRIPT="scripts/generate.py"
357
- GEN_CHECK="test -x ${VENV_PY} && test -f ${REMOTE}/${GEN_SCRIPT}"
358
- GEN_LABEL="${REMOTE}/${GEN_SCRIPT}"
359
- if [[ "$TWO_PASS" -eq 1 || "$IMPLICIT_POSE_BASE" -eq 1 ]]; then
360
- GEN_CHECK="test -x ${VENV_PY} && test -f ${REMOTE}/scripts/generate.py && test -f ${REMOTE}/scripts/cclay_constrained_generate.py"
361
- GEN_LABEL="${REMOTE}/scripts/generate.py and ${REMOTE}/scripts/cclay_constrained_generate.py"
362
- fi
363
- # shellcheck disable=SC2029 # REMOTE/VENV_PY expand remotely by design
364
- if ! ssh "${SSH_OPTS[@]}" "$HOST" "$GEN_CHECK" </dev/null; then
365
- echo "run-on-box: ${HOST} is missing ${VENV_PY} or ${GEN_LABEL}; sync the ARDY sources to the box first (CozyClay scripts/ardy/sync-to-box --apply)" >&2
366
- exit 1
367
- fi
368
-
369
- # The constrained generator is cclay-owned: the repo copy next to this
370
- # script is the source of truth, synced up on every run so the box can
371
- # never drift behind it (same pattern as run-sequence-on-box.sh).
372
- if ! ssh "${SSH_OPTS[@]}" "$HOST" "cat > ${REMOTE}/scripts/cclay_constrained_generate.py" \
373
- < "${HERE}/cclay_constrained_generate.py"; then
374
- echo "run-on-box: could not sync cclay_constrained_generate.py to ${HOST}" >&2
375
- exit 1
376
- fi
377
- echo "run-on-box: constrained generator synced to ${HOST}"
378
- echo "run-on-box: venv python and generator script present on ${HOST}"
379
-
380
-
381
- # Resolve --base on the box: anything containing a slash is a repo-relative
382
- # or absolute path and passes through; a bare id or bare <name>.npz is
383
- # looked up under outputs/ then outputs/omb/ (repo-relative, i.e.
384
- # ~/ardy/outputs*). Free mode takes no base, and waypoints mode without one
385
- # is two-pass: the pass-1 output is a fresh absolute temp path verified with
386
- # a plain test -f at the pass-1 step, never through this candidate lookup.
387
- if [[ -n "$BASE" ]]; then
388
- if [[ "$BASE" == */* ]]; then
389
- BASE_CANDIDATES="$(printf '%q' "$BASE")"
390
- BASE_LOOKED="'${BASE}'"
391
- else
392
- BASE_NAME="${BASE%.npz}"
393
- BASE_CANDIDATES="$(printf '%q' "outputs/${BASE_NAME}.npz") $(printf '%q' "outputs/omb/${BASE_NAME}.npz")"
394
- BASE_LOOKED="outputs/${BASE_NAME}.npz or outputs/omb/${BASE_NAME}.npz under ${REMOTE}"
395
- fi
396
- # shellcheck disable=SC2029 # REMOTE expands remotely by design
397
- if ! BASE_RESOLVED="$(ssh "${SSH_OPTS[@]}" "$HOST" "cd ${REMOTE} && for c in ${BASE_CANDIDATES}; do if test -f \"\$c\"; then printf '%s' \"\$c\"; exit 0; fi; done; exit 1" </dev/null)"; then
398
- echo "run-on-box: base motion '${BASE}' does not exist on ${HOST} (looked for ${BASE_LOOKED})" >&2
399
- exit 1
400
- fi
401
- echo "run-on-box: base motion on ${HOST}: ${BASE_RESOLVED}"
402
- fi
403
-
404
- # The hidden upright reference is only a convenient baseline when it is long
405
- # enough. A loaded clip can be longer than that fixture; in that case generate
406
- # an exact-duration base first instead of letting cclay_constrained_generate.py
407
- # fail after model load with "base has N frames but requested M".
408
- if [[ "$IMPLICIT_POSE_BASE" -eq 1 ]]; then
409
- # shellcheck disable=SC2029 # resolved path is selected from the box listing
410
- if ! BASE_FRAMES="$(ssh "${SSH_OPTS[@]}" "$HOST" \
411
- "cd ${REMOTE} && ${VENV_PY} -c 'import numpy as np,sys; print(np.load(sys.argv[1])[\"local_rot_mats\"].shape[0])' $(printf '%q' "$BASE_RESOLVED")" </dev/null)"; then
412
- echo "run-on-box: could not inspect implicit pose base ${BASE_RESOLVED}" >&2
413
- exit 1
414
- fi
415
- [[ "$BASE_FRAMES" =~ ^[0-9]+$ ]] || {
416
- echo "run-on-box: implicit pose base returned invalid frame count '${BASE_FRAMES}'" >&2
417
- exit 1
418
- }
419
- if [[ "$BASE_FRAMES" -lt "$CLIP_FRAMES" ]]; then
420
- echo "run-on-box: implicit pose base has ${BASE_FRAMES} frames; will free-generate ${CLIP_FRAMES}-frame base first"
421
- BASE_RESOLVED=""
422
- TWO_PASS=1
423
- fi
424
- fi
425
-
426
-
427
- # Probe the device the generator will use, with the SAME env it will run
428
- # under (CUDA_VISIBLE_DEVICES="" included). The one-liner mirrors the
429
- # generator's `device = "cuda:0" if torch.cuda.is_available() else "cpu"`
430
- # exactly, so what is printed is what the generation will pick.
431
- # shellcheck disable=SC2029 # REMOTE/VENV_PY expand remotely by design
432
- CUDA_ENV=""
433
- [[ "$FORCE_CPU" -eq 1 ]] && CUDA_ENV='CUDA_VISIBLE_DEVICES="" '
434
-
435
- # The text encoder is a separate CPU service; without it the generator loads the
436
- # model, then dies. Check it before spending minutes on the rest.
437
- if ! ENCODER_CODE="$(ssh "${SSH_OPTS[@]}" "$HOST" "curl -s -o /dev/null -w '%{http_code}' -m 10 ${ENCODER_URL}" </dev/null)"; then
438
- echo "run-on-box: could not reach ${HOST} to probe the text encoder" >&2
439
- exit 1
440
- fi
441
- if [[ "$ENCODER_CODE" != "200" ]]; then
442
- echo "run-on-box: text encoder at ${ENCODER_URL} answered '${ENCODER_CODE}', not 200." >&2
443
- echo "run-on-box: start it with: ssh ${HOST} 'cd ~/ardy && .venv/bin/python -u scripts/run_text_encoder_server.py --host 127.0.0.1 --port 9550 --device cpu'" >&2
444
- exit 1
445
- fi
446
- echo "run-on-box: text encoder ${ENCODER_URL} responding (cpu service)"
447
-
448
- if ! DEVICE="$(ssh "${SSH_OPTS[@]}" "$HOST" "cd ${REMOTE} && ${CUDA_ENV}${VENV_PY} -c 'import torch; print(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")'" </dev/null)"; then
449
- echo "run-on-box: device probe on ${HOST} failed (venv python erroring?)" >&2
450
- exit 1
451
- fi
452
- [[ -n "$DEVICE" ]] || { echo "run-on-box: device probe on ${HOST} returned nothing" >&2; exit 1; }
453
- echo "run-on-box: generator will use device '${DEVICE}' on ${HOST}"
454
-
455
- # --- the generator invocation ---------------------------------------------
456
- # Args are shell-quoted with printf %q so prompts and paths survive the
457
- # remote shell. The output base is absolute (under the remote temp dir), so
458
- # the generator's _resolve_output_base honors it instead of placing it under
459
- # outputs/.
460
- # scripts/generate.py is the unconstrained generator: its prompt is
461
- # positional and it has no --base / --pose-from / --root-2d. Used for free
462
- # mode and for the two-pass base pass (pass 1); the npz lands at
463
- # <out_base>.npz.
464
- build_free_cmd() {
465
- local out_base="$1" cmd
466
- cmd="cd ${REMOTE} && ${CUDA_ENV}${VENV_PY} scripts/generate.py $(printf '%q' "$PROMPT")"
467
- cmd+=" --duration $(printf '%q' "$DURATION")"
468
- cmd+=" --output $(printf '%q' "$out_base")"
469
- if [[ -n "$SEED" ]]; then
470
- cmd+=" --seed $(printf '%q' "$SEED")"
471
- fi
472
- printf '%s' "$cmd"
473
- }
474
-
475
- build_remote_cmd() {
476
- local tmp_dir="$1" cmd i
477
- # Two-pass waypoints mode has no user base: BASE_RESOLVED stays empty and
478
- # pass 1's output npz (under the same remote temp dir, cleaned by the EXIT
479
- # trap) becomes the --base of the constrained pass.
480
- local base_arg="${BASE_RESOLVED:-${tmp_dir}/base.npz}"
481
- if [[ "$MODE" == "free" ]]; then
482
- cmd="$(build_free_cmd "${tmp_dir}/out")"
483
- else
484
- cmd="cd ${REMOTE} && ${CUDA_ENV}${VENV_PY} scripts/cclay_constrained_generate.py"
485
- cmd+=" --prompt $(printf '%q' "$PROMPT")"
486
- cmd+=" --duration $(printf '%q' "$DURATION")"
487
- cmd+=" --base $(printf '%q' "$base_arg")"
488
- if [[ "$MODE" == "pose" ]]; then
489
- for ((i = 0; i < ${#POSE_ARGS[@]}; i += 3)); do
490
- pose_index=$((i / 3))
491
- cmd+=" --pose-from $(printf '%q' "${tmp_dir}/pose-${pose_index}.npz")"
492
- cmd+=" $(printf '%q' "${POSE_ARGS[$((i + 1))]}") $(printf '%q' "${POSE_ARGS[$((i + 2))]}")"
493
- done
494
- fi
495
- # Each validated --root-2d group is %q-quoted value by value, so no
496
- # waypoint text can ever reach the remote shell unquoted.
497
- for ((i = 0; i < ${#ROOT_2D_ARGS[@]}; i += 4)); do
498
- cmd+=" --root-2d $(printf '%q' "${ROOT_2D_ARGS[$i]}")"
499
- cmd+=" $(printf '%q' "${ROOT_2D_ARGS[$((i + 1))]}")"
500
- cmd+=" $(printf '%q' "${ROOT_2D_ARGS[$((i + 2))]}")"
501
- cmd+=" $(printf '%q' "${ROOT_2D_ARGS[$((i + 3))]}")"
502
- done
503
- [[ -z "$ROOT_MARGIN" ]] || cmd+=" --root-margin $(printf '%q' "$ROOT_MARGIN")"
504
- [[ -z "$CONTACT_THRESHOLD" ]] || cmd+=" --contact-threshold $(printf '%q' "$CONTACT_THRESHOLD")"
505
- [[ -z "$HISTORY_FRAMES" ]] || cmd+=" --history_frames $(printf '%q' "$HISTORY_FRAMES")"
506
- cmd+=" --output $(printf '%q' "${tmp_dir}/out")"
507
- if [[ -n "$SEED" ]]; then
508
- cmd+=" --seed $(printf '%q' "$SEED")"
509
- fi
510
- fi
511
- printf '%s' "$cmd"
512
- }
513
-
514
-
515
- if [[ $DRY_RUN -eq 1 ]]; then
516
- REMOTE_TMP_PLACEHOLDER="<mktemp-dir-on-box>"
517
- MODE_LABEL="free generation (generate.py)"
518
- [[ "$MODE" == "pose" ]] && MODE_LABEL="full-body pose pin"
519
- [[ "$MODE" == "waypoints" ]] && MODE_LABEL="frame-0 root start + prompt (no pose)"
520
- [[ "$MODE" == "waypoints" && "$TWO_PASS" -eq 1 ]] && MODE_LABEL="frame-0 root start + prompt (no pose) - two-pass (free base first)"
521
- echo "run-on-box: DRY RUN - preflight done, nothing pushed, nothing generated, nothing pulled."
522
- echo "run-on-box: mode ${MODE} - ${MODE_LABEL}"
523
- [[ "$MODE" == "pose" ]] || echo "run-on-box: pose npz <none>"
524
- [[ "$MODE" != "pose" ]] || echo "run-on-box: pose pins $(( ${#POSE_ARGS[@]} / 3 ))"
525
- if [[ "$TWO_PASS" -eq 1 ]]; then
526
- echo "run-on-box: base motion pass-1 output ${REMOTE_TMP_PLACEHOLDER}/base.npz on ${HOST} (free-generated first)"
527
- else
528
- [[ -z "${BASE_RESOLVED:-}" ]] || echo "run-on-box: base motion ${BASE_RESOLVED} on ${HOST}"
529
- fi
530
- echo "run-on-box: device ${DEVICE}"
531
- echo "run-on-box: root-2d $(( ${#ROOT_2D_ARGS[@]} / 4 )) waypoint(s)"
532
- [[ "$MODE" != "pose" ]] || echo "run-on-box: would push $(( ${#POSE_ARGS[@]} / 3 )) pose npz file(s) to ${HOST}:${REMOTE_TMP_PLACEHOLDER}"
533
- if [[ "$TWO_PASS" -eq 1 ]]; then
534
- echo "run-on-box: pass 1/2 would run ssh ${HOST} \"$(build_free_cmd "${REMOTE_TMP_PLACEHOLDER}/base")\""
535
- echo "run-on-box: pass 2/2 would run ssh ${HOST} \"$(build_remote_cmd "$REMOTE_TMP_PLACEHOLDER")\""
536
- else
537
- echo "run-on-box: would run ssh ${HOST} \"$(build_remote_cmd "$REMOTE_TMP_PLACEHOLDER")\""
538
- fi
539
- echo "run-on-box: would pull scp -q -o BatchMode=yes ${HOST}:${REMOTE_TMP_PLACEHOLDER}/out.npz ${OUTPUT}"
540
- echo "run-on-box: would clean ssh ${HOST} \"rm -rf ${REMOTE_TMP_PLACEHOLDER}\""
541
- exit 0
542
- fi
543
-
544
- mkdir -p "$(dirname "$OUTPUT")"
545
-
546
- # Fresh temp dir on the box; the EXIT trap removes it even on failure, and
547
- # cleanup failure never masks the real result. Guard the path (must be
548
- # absolute, as mktemp guarantees) before it can reach the cleanup rm -rf.
549
- if ! REMOTE_TMP="$(ssh "${SSH_OPTS[@]}" "$HOST" "mktemp -d" </dev/null)"; then
550
- echo "run-on-box: could not create a temp dir on ${HOST} (mktemp failed)" >&2
551
- exit 1
552
- fi
553
- [[ "$REMOTE_TMP" == /* ]] || { echo "run-on-box: remote mktemp returned a non-absolute path '${REMOTE_TMP}'; aborting" >&2; exit 1; }
554
- trap 'ssh "${SSH_OPTS[@]}" "$HOST" "rm -rf ${REMOTE_TMP}" </dev/null >/dev/null 2>&1 || true' EXIT
555
-
556
- if [[ "$TWO_PASS" -eq 1 ]]; then
557
- # Pass 1: free-generate the base clip with the same prompt/duration/seed
558
- # the constrained pass will use. Its npz lives under REMOTE_TMP, so the
559
- # EXIT trap removes it with everything else.
560
- PASS1_CMD="$(build_free_cmd "${REMOTE_TMP}/base")"
561
- echo "run-on-box: pass 1/2: free-generating base clip on ${HOST} ..."
562
- # shellcheck disable=SC2029 # PASS1_CMD is a remote command by design
563
- ssh "${SSH_OPTS[@]}" "$HOST" "$PASS1_CMD" </dev/null
564
- BASE_RESOLVED="${REMOTE_TMP}/base.npz"
565
- # The pass-1 output is a fresh absolute temp path, not a listed base: no
566
- # BASE_CANDIDATES lookup, just verify the file appeared.
567
- # shellcheck disable=SC2029 # REMOTE_TMP expands remotely by design
568
- if ! ssh "${SSH_OPTS[@]}" "$HOST" "test -f ${BASE_RESOLVED}" </dev/null; then
569
- echo "run-on-box: pass 1/2 failed: ${BASE_RESOLVED} was not produced on ${HOST}" >&2
570
- exit 1
571
- fi
572
- echo "run-on-box: pass 1/2: base clip at ${HOST}:${BASE_RESOLVED}"
573
- fi
574
-
575
- if [[ "$MODE" == "pose" ]]; then
576
- for ((i = 0; i < ${#POSE_ARGS[@]}; i += 3)); do
577
- pose_index=$((i / 3))
578
- pose_path="${POSE_ARGS[$i]}"
579
- echo "run-on-box: pushing pose $((pose_index + 1))/$(( ${#POSE_ARGS[@]} / 3 )) to ${HOST}:${REMOTE_TMP}/pose-${pose_index}.npz ..."
580
- scp -q "${SCP_OPTS[@]}" "$pose_path" "$HOST:${REMOTE_TMP}/pose-${pose_index}.npz"
581
- done
582
- fi
583
-
584
- REMOTE_CMD="$(build_remote_cmd "$REMOTE_TMP")"
585
- echo "run-on-box: generating on ${HOST} ..."
586
- # shellcheck disable=SC2029 # REMOTE_CMD is a remote command by design
587
- ssh "${SSH_OPTS[@]}" "$HOST" "$REMOTE_CMD" </dev/null
588
-
589
- echo "run-on-box: pulling ${HOST}:${REMOTE_TMP}/out.npz -> ${OUTPUT} ..."
590
- # shellcheck disable=SC2029 # HOST:REMOTE_TMP is a remote path by design
591
- scp -q "${SCP_OPTS[@]}" "$HOST:${REMOTE_TMP}/out.npz" "$OUTPUT"
592
- [[ -s "$OUTPUT" ]] || { echo "run-on-box: pulled ${OUTPUT} is empty; the generation failed" >&2; exit 1; }
593
- echo "run-on-box: done - ${OUTPUT} ($(wc -c < "$OUTPUT" | tr -d ' ') bytes)"