cozyclay 2.1.1 → 3.0.1

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