cozyclay 2.1.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (583) hide show
  1. package/CHANGELOG.md +65 -0
  2. package/README.md +12 -30
  3. package/bin/agent/agent-routes.mjs +40 -113
  4. package/bin/agent/agent-runner.mjs +9 -10
  5. package/bin/agent/cliproxy-provider.mjs +135 -0
  6. package/bin/agent/credential-store.mjs +30 -7
  7. package/bin/agent/pi-tools.mjs +4 -1
  8. package/bin/agent/provider-keys.mjs +32 -0
  9. package/bin/agent/provider-login.mjs +110 -0
  10. package/bin/agent/provider-routes.mjs +99 -0
  11. package/bin/agent/providers.mjs +19 -97
  12. package/bin/agent/script-tool.mjs +17 -4
  13. package/bin/agent/studio-motion-reference.mjs +23 -0
  14. package/bin/agent/studio-prompt.mjs +1 -1
  15. package/bin/agent/studio-rebase-text.mjs +32 -0
  16. package/bin/agent/studio-rebase.mjs +26 -39
  17. package/bin/agent/studio-tools.mjs +9 -28
  18. package/bin/agent/tool-arguments.mjs +49 -0
  19. package/bin/agent/turn-frames.mjs +66 -0
  20. package/bin/codex-auth.mjs +9 -2
  21. package/bin/cozyclay.mjs +10 -116
  22. package/bin/live/cli.mjs +22 -6
  23. package/bin/mcp-runtime.mjs +2 -12
  24. package/bin/package-signature.mjs +0 -4
  25. package/dist/app/index.html +7 -6
  26. package/dist/assets/EXRLoader-CvVIvGVE.js +1 -0
  27. package/dist/assets/analytics-C9sUnndd.js +1 -0
  28. package/dist/assets/app-CCh--1Hc.js +5087 -0
  29. package/dist/assets/app-f-fkV5uP.css +1 -0
  30. package/dist/assets/compile-worker-CkxiD6lH.js +5 -0
  31. package/dist/assets/fflate.module-KbGj5-H6.js +5 -0
  32. package/dist/assets/{first-shot-handoff-BlT33CGf.js → first-shot-handoff-CC4xe4HM.js} +1 -1
  33. package/dist/assets/{landing-BSesrCpL.js → landing-DjHD8u7k.js} +1 -1
  34. package/dist/assets/scene-asset-sync-Hx_FzdOH.js +20 -0
  35. package/dist/assets/scene-asset-sync-_S8NQl5B.css +1 -0
  36. package/dist/assets/workflow-C4yKH1p4.js +179 -0
  37. package/dist/cozyclay-package.json +1 -1
  38. package/dist/index.html +3 -3
  39. package/dist/llms.txt +14 -0
  40. package/dist/sw.js +3 -6
  41. package/dist/workflow/index.html +5 -4
  42. package/mcp/LIVE-PROTOCOL.md +7 -47
  43. package/mcp/README.md +16 -26
  44. package/mcp/live-hub.mjs +6 -10
  45. package/mcp/package.json +1 -3
  46. package/mcp/tool-handlers.mjs +4 -168
  47. package/package.json +3 -22
  48. package/src/App.jsx +174 -2639
  49. package/src/agent-progress.js +79 -0
  50. package/src/agent-turn-mark.js +30 -0
  51. package/src/analytics.js +1 -19
  52. package/src/app-context.js +5 -0
  53. package/src/app-stage.jsx +2 -34
  54. package/src/asset-pane.jsx +6 -5
  55. package/src/camera-block.js +21 -0
  56. package/src/camera-direction.js +120 -0
  57. package/src/character-kind.js +3 -9
  58. package/src/command-bus.js +8 -6
  59. package/src/commands/cast.js +5 -34
  60. package/src/commands/elements/character.js +1 -1
  61. package/src/commands/elements/motion.js +1 -6
  62. package/src/commands/elements/object.js +6 -2
  63. package/src/commands/elements/shot.js +4 -1
  64. package/src/commands/elements.js +38 -14
  65. package/src/commands/index.js +3 -1
  66. package/src/commands/kits.js +37 -0
  67. package/src/commands/motion-timing.js +57 -0
  68. package/src/commands/motion.js +9 -152
  69. package/src/commands/motion3-compile.js +65 -0
  70. package/src/commands/motion3.js +207 -0
  71. package/src/commands/objects.js +6 -4
  72. package/src/commands/shot.js +49 -11
  73. package/src/commands/stage.js +14 -1
  74. package/src/commands/view.js +4 -1
  75. package/src/document-mirrors.js +42 -0
  76. package/src/document-store.js +4 -0
  77. package/src/domains/cast.js +19 -194
  78. package/src/domains/motion/motion-range-pin-rules.js +1 -1
  79. package/src/domains/motion/take-source.js +51 -0
  80. package/src/domains/motion.js +60 -1838
  81. package/src/domains/scenes.js +12 -55
  82. package/src/domains/shots.js +2 -2
  83. package/src/domains/stage.js +4 -2
  84. package/src/draft-ghost.js +46 -0
  85. package/src/draft-ghost.jsx +129 -0
  86. package/src/dualview.jsx +4 -3
  87. package/src/effects/EffectsLayer.jsx +112 -0
  88. package/src/effects/effect-meshes.js +232 -0
  89. package/src/effects/effect-record.js +103 -0
  90. package/src/effects/emitter.js +59 -0
  91. package/src/effects/simulate.js +261 -0
  92. package/src/effects/state.js +59 -0
  93. package/src/execution-telemetry.js +2 -3
  94. package/src/first-success-guide.jsx +5 -5
  95. package/src/ghost-set.js +257 -0
  96. package/src/held-object-edit.jsx +113 -0
  97. package/src/held-object-pose.js +175 -0
  98. package/src/hierarchy-model.js +1 -1
  99. package/src/hierarchy-panel.jsx +1 -1
  100. package/src/imported-mesh.jsx +103 -0
  101. package/src/kits/held.js +84 -0
  102. package/src/kits/index.js +70 -0
  103. package/src/kits/smoking.js +57 -0
  104. package/src/light-blockers.js +93 -0
  105. package/src/motion/beat-board-model.js +84 -0
  106. package/src/motion/beat-board.css +124 -0
  107. package/src/motion/beat-board.jsx +59 -0
  108. package/src/motion/center-of-mass.js +66 -0
  109. package/src/motion/fix-collisions.js +850 -0
  110. package/src/motion/physics-review.js +118 -0
  111. package/src/{ardy → motion}/physics-support.js +1 -76
  112. package/src/motion/rig-snapshot.js +22 -0
  113. package/src/motion/take-segments.jsx +140 -0
  114. package/src/{ardy → motion}/timeline-coordinates.js +0 -21
  115. package/src/{ardy → motion}/timeline.css +1 -2
  116. package/src/{ardy → motion}/timeline.jsx +48 -419
  117. package/src/motion/waypoints.js +76 -0
  118. package/src/motion3/beats.js +83 -0
  119. package/src/motion3/body.js +158 -0
  120. package/src/motion3/bones.js +47 -0
  121. package/src/motion3/carried.js +47 -0
  122. package/src/motion3/compile-job.js +75 -0
  123. package/src/motion3/compile-worker.js +10 -0
  124. package/src/motion3/compiler/anchors.js +105 -0
  125. package/src/motion3/compiler/arm-orient.js +128 -0
  126. package/src/motion3/compiler/channels.js +125 -0
  127. package/src/motion3/compiler/compile.js +205 -0
  128. package/src/motion3/compiler/gait-rhythm.js +97 -0
  129. package/src/motion3/compiler/grip.js +171 -0
  130. package/src/motion3/compiler/head-steady.js +48 -0
  131. package/src/motion3/compiler/hold.js +134 -0
  132. package/src/motion3/compiler/idle.js +113 -0
  133. package/src/motion3/compiler/limbs.js +170 -0
  134. package/src/motion3/compiler/math.js +72 -0
  135. package/src/motion3/compiler/pose.js +162 -0
  136. package/src/motion3/compiler/quat.js +49 -0
  137. package/src/motion3/compiler/skeleton.js +74 -0
  138. package/src/motion3/compiler/validate-common.js +32 -0
  139. package/src/motion3/compiler/validate-goals.js +118 -0
  140. package/src/motion3/compiler/validate-objects.js +143 -0
  141. package/src/motion3/compiler/validate-parts.js +116 -0
  142. package/src/motion3/compiler/validate.js +122 -0
  143. package/src/motion3/compiler/vocab.js +73 -0
  144. package/src/motion3/compiler/walk-pelvis.js +275 -0
  145. package/src/motion3/compiler/walk.js +207 -0
  146. package/src/motion3/compiler/wrist-clamp.js +32 -0
  147. package/src/motion3/delta.js +47 -0
  148. package/src/motion3/describe.js +174 -0
  149. package/src/motion3/docs.js +27 -0
  150. package/src/motion3/edit-carry.js +21 -0
  151. package/src/motion3/fix/ease.js +16 -0
  152. package/src/motion3/fix/ground.js +37 -0
  153. package/src/motion3/fix/index.js +52 -0
  154. package/src/motion3/fix/push.js +71 -0
  155. package/src/motion3/fix/reach.js +46 -0
  156. package/src/motion3/fix/retime.js +79 -0
  157. package/src/motion3/fix/self.js +211 -0
  158. package/src/motion3/fix/slide.js +70 -0
  159. package/src/motion3/fix/turn.js +51 -0
  160. package/src/motion3/follow.js +39 -0
  161. package/src/motion3/free-motion.js +173 -0
  162. package/src/motion3/grip-choice.js +130 -0
  163. package/src/motion3/hold-plan.js +157 -0
  164. package/src/motion3/json-patch.js +77 -0
  165. package/src/motion3/key-aim.js +105 -0
  166. package/src/motion3/key-edit.js +82 -0
  167. package/src/motion3/lenient.js +127 -0
  168. package/src/motion3/object-keys.js +236 -0
  169. package/src/motion3/object-pose.js +182 -0
  170. package/src/motion3/object-tracks.js +12 -0
  171. package/src/motion3/pipeline.js +102 -0
  172. package/src/motion3/playback.js +51 -0
  173. package/src/motion3/probes.js +91 -0
  174. package/src/motion3/qa/body-checks.js +34 -0
  175. package/src/motion3/qa/check-names.js +14 -0
  176. package/src/motion3/qa/checks.js +121 -0
  177. package/src/motion3/qa/contact-checks.js +51 -0
  178. package/src/motion3/qa/explain.js +80 -0
  179. package/src/motion3/qa/fmt.js +5 -0
  180. package/src/motion3/qa/foot-checks.js +72 -0
  181. package/src/motion3/qa/geometry.js +77 -0
  182. package/src/motion3/qa/goals.js +191 -0
  183. package/src/motion3/qa/ground.js +60 -0
  184. package/src/motion3/qa/hints-contact.js +179 -0
  185. package/src/motion3/qa/hints-goal.js +160 -0
  186. package/src/motion3/qa/hints-knee.js +24 -0
  187. package/src/motion3/qa/hints-motion.js +209 -0
  188. package/src/motion3/qa/hints-object.js +91 -0
  189. package/src/motion3/qa/index.js +42 -0
  190. package/src/motion3/qa/key-checks.js +82 -0
  191. package/src/motion3/qa/near.js +96 -0
  192. package/src/motion3/qa/object-checks.js +135 -0
  193. package/src/motion3/qa/patch.js +161 -0
  194. package/src/motion3/qa/severity.js +38 -0
  195. package/src/motion3/qa/spec-checks.js +65 -0
  196. package/src/motion3/qa/style.js +218 -0
  197. package/src/motion3/qa/wrist-checks.js +69 -0
  198. package/src/motion3/qa/wrist-obs.js +60 -0
  199. package/src/motion3/refs.js +120 -0
  200. package/src/motion3/repair-tune.js +121 -0
  201. package/src/motion3/repair.js +83 -0
  202. package/src/motion3/report.js +67 -0
  203. package/src/motion3/rigs/index.js +14 -0
  204. package/src/motion3/rigs/x-bot-tpose-body.json +1 -0
  205. package/src/motion3/rigs/x-bot-tpose.json +1 -0
  206. package/src/motion3/rigs/y-bot-tpose-body.json +1 -0
  207. package/src/motion3/rigs/y-bot-tpose.json +1 -0
  208. package/src/motion3/scene.js +60 -0
  209. package/src/motion3/schema/brief.js +89 -0
  210. package/src/motion3/schema/fields.js +44 -0
  211. package/src/motion3/schema/spec-examples.js +46 -0
  212. package/src/motion3/schema/topics.js +111 -0
  213. package/src/motion3/schema/types.js +147 -0
  214. package/src/motion3/search.js +117 -0
  215. package/src/motion3/second-hand.js +112 -0
  216. package/src/motion3/skills/basic.js +82 -0
  217. package/src/motion3/skills/book.js +76 -0
  218. package/src/motion3/skills/car.js +145 -0
  219. package/src/motion3/skills/frames-auto.js +29 -0
  220. package/src/motion3/skills/index.js +83 -0
  221. package/src/motion3/skills/info.js +65 -0
  222. package/src/motion3/skills/smoke-kit.js +109 -0
  223. package/src/motion3/skills/smoke.js +160 -0
  224. package/src/motion3/spec-store.js +59 -0
  225. package/src/motion3/take-edit.js +155 -0
  226. package/src/motion3/take.js +63 -0
  227. package/src/motion3/timeline.js +127 -0
  228. package/src/motion3/views.js +121 -0
  229. package/src/motion3/walk-plan.js +119 -0
  230. package/src/object-catalog.jsx +7 -1
  231. package/src/object-colors.js +98 -0
  232. package/src/object-gizmo-parts.js +115 -0
  233. package/src/object-gizmo.jsx +37 -122
  234. package/src/object-glow.js +139 -0
  235. package/src/object-hidden.js +33 -0
  236. package/src/object-look.js +196 -0
  237. package/src/object-size.js +10 -0
  238. package/src/object-travel.js +71 -6
  239. package/src/panels/CameraPanel.jsx +7 -7
  240. package/src/panels/HdrEnvironmentControls.jsx +59 -0
  241. package/src/panels/LightPanel.jsx +25 -4
  242. package/src/panels/ObjectLookPanel.jsx +88 -0
  243. package/src/panels/PoseImagePanel.jsx +1 -1
  244. package/src/panels/PosePanel.jsx +2 -17
  245. package/src/panels/RigControlPanel.jsx +5 -53
  246. package/src/panels/SubjectBox.jsx +4 -1
  247. package/src/panels/details.css +14 -0
  248. package/src/posestudio.jsx +4 -27
  249. package/src/project-browser.jsx +3 -4
  250. package/src/project-resources.js +18 -31
  251. package/src/project.js +13 -104
  252. package/src/props.jsx +25 -280
  253. package/src/rail-dot-drag.js +23 -0
  254. package/src/render-passes.js +10 -0
  255. package/src/resource-status.jsx +1 -0
  256. package/src/result-modal.jsx +4 -19
  257. package/src/room.jsx +20 -12
  258. package/src/scene-assets.js +8 -6
  259. package/src/scene-light-place.js +72 -0
  260. package/src/scene-lights.jsx +148 -0
  261. package/src/scene-objects.js +31 -139
  262. package/src/scenes.js +15 -105
  263. package/src/semantic-edit.js +2 -5
  264. package/src/set-pieces.jsx +183 -0
  265. package/src/settings-menu.jsx +3 -11
  266. package/src/shell/BottomDock.jsx +11 -53
  267. package/src/shell/CompositionGuideButton.jsx +20 -0
  268. package/src/shell/DetailsSlot.jsx +16 -200
  269. package/src/shell/GhostsMenuGroup.jsx +74 -0
  270. package/src/shell/LibrarySlot.jsx +1 -3
  271. package/src/shell/MenuBar.jsx +3 -3
  272. package/src/shell/PreferencesDialog.jsx +15 -264
  273. package/src/shell/PreferencesSlot.jsx +2 -8
  274. package/src/shell/ShotPreviewHeader.jsx +17 -0
  275. package/src/shell/TopBar.jsx +5 -83
  276. package/src/shell/ViewportToolbar.jsx +23 -93
  277. package/src/shell/agent-glass.css +19 -6
  278. package/src/shell/details-selection.js +42 -0
  279. package/src/shell/ghosts-menu.css +22 -0
  280. package/src/shell/glass-regions.css +29 -3
  281. package/src/shell/preferences.css +6 -1
  282. package/src/shell/viewport.css +12 -0
  283. package/src/shot-authoring.js +4 -7
  284. package/src/soft-shadows.js +37 -0
  285. package/src/stage-attach-frames.js +12 -12
  286. package/src/stage-canvas-rigs.jsx +3 -3
  287. package/src/stage-capture.jsx +42 -8
  288. package/src/stage-characters.jsx +22 -216
  289. package/src/stage-editor-gizmos.jsx +6 -6
  290. package/src/stage-environment.js +93 -0
  291. package/src/stage-hdr-builtins.js +107 -0
  292. package/src/stage-hdr-image.js +116 -0
  293. package/src/stage-hdr-library.js +70 -0
  294. package/src/stage-hdr-map.js +94 -0
  295. package/src/stage-hdr.js +130 -0
  296. package/src/stage-lighting.js +149 -0
  297. package/src/stage-occlusion.js +210 -0
  298. package/src/stage-sky.jsx +159 -0
  299. package/src/stage-startup-defaults.js +5 -9
  300. package/src/studio-actions.js +12 -14
  301. package/src/studio-agent-commands.js +46 -16
  302. package/src/studio-agent-motion.js +9 -9
  303. package/src/studio-agent-protocol.js +46 -73
  304. package/src/studio-app-binding.js +29 -45
  305. package/src/studio-asset-list.js +17 -0
  306. package/src/studio-contact-sheet.js +37 -5
  307. package/src/studio-elements.js +27 -7
  308. package/src/studio-entity-bounds.js +18 -0
  309. package/src/studio-error-codes.js +8 -0
  310. package/src/studio-export-framing.js +152 -0
  311. package/src/studio-lighting-check.js +103 -0
  312. package/src/studio-motion-visual.js +150 -0
  313. package/src/studio-schema-errors.js +80 -0
  314. package/src/studio-support-gap.js +74 -0
  315. package/src/styles.css +1 -19
  316. package/src/timeline-defaults.js +5 -0
  317. package/src/timeline-extent.js +8 -20
  318. package/src/tutorial-walk.js +17 -0
  319. package/src/ui-scrub.js +1 -1
  320. package/src/use-shot-camera-tracks.js +12 -0
  321. package/src/view-ghosts.js +97 -0
  322. package/src/view-ghosts.jsx +49 -0
  323. package/src/workflow/AgentPanel.jsx +47 -166
  324. package/src/workflow/AgentProgressCard.jsx +107 -0
  325. package/src/workflow/AgentReplyText.jsx +37 -0
  326. package/src/workflow/AgentTurnSteps.jsx +84 -0
  327. package/src/workflow/LoginPanel.jsx +140 -0
  328. package/src/workflow/WorkflowBuilder.jsx +7 -23
  329. package/src/workflow/agent-client.js +54 -51
  330. package/src/workflow/agent-panel.css +71 -1
  331. package/src/workflow/agent-progress-card.css +167 -0
  332. package/src/workflow/agent-progress-view.js +47 -0
  333. package/src/workflow/agent-turn-steps.css +113 -0
  334. package/src/workflow/agent-turn.js +191 -0
  335. package/src/workflow/login-client.js +34 -0
  336. package/src/workflow/motion-input.js +18 -31
  337. package/src/workflow/node-schema.js +1 -1
  338. package/src/workflow/reply-markdown.js +69 -0
  339. package/src/workflow/scene-asset-sync.js +8 -8
  340. package/tools/agent-session-stats.mjs +61 -0
  341. package/tools/dev-full.mjs +5 -56
  342. package/tools/eslint-baseline.json +12 -13
  343. package/tools/headless-studio.mjs +85 -0
  344. package/tools/knip-baseline.json +0 -179
  345. package/tools/loc-baseline.json +33 -83
  346. package/tools/motion3/extract-body.mjs +103 -0
  347. package/tools/motion3/extract-rig.mjs +85 -0
  348. package/tools/process-supervisor.mjs +0 -88
  349. package/tools/run-tests.mjs +9 -124
  350. package/bin/agent/motion-runtime.mjs +0 -76
  351. package/dist/ardy/cskel27-rest.json +0 -557
  352. package/dist/assets/analytics-B41FmPYI.js +0 -1
  353. package/dist/assets/app-Do-Og5Pu.css +0 -1
  354. package/dist/assets/app-DwP-tl2x.js +0 -4920
  355. package/dist/assets/config-Bx7pYsD9.js +0 -1
  356. package/dist/assets/config-DeoFTYzb.css +0 -1
  357. package/dist/assets/demo-Dt0qZfS7.js +0 -1
  358. package/dist/assets/scene-asset-sync-BCWDJB1d.js +0 -19
  359. package/dist/assets/scene-asset-sync-DjJ_cJ2R.css +0 -1
  360. package/dist/assets/ticket-jqMhqL88.js +0 -1
  361. package/dist/assets/workflow-Br-K7Srs.js +0 -179
  362. package/dist/demo/walk-then-stop.npz +0 -0
  363. package/mcp/ardy-prompts.mjs +0 -218
  364. package/src/ardy/auto-fix-panel.css +0 -108
  365. package/src/ardy/auto-physics.js +0 -1194
  366. package/src/ardy/client.js +0 -153
  367. package/src/ardy/convert.js +0 -313
  368. package/src/ardy/cskel27-neutral.js +0 -39
  369. package/src/ardy/cskel27.js +0 -77
  370. package/src/ardy/export.js +0 -165
  371. package/src/ardy/fix-collisions.js +0 -2257
  372. package/src/ardy/foot-lock.js +0 -230
  373. package/src/ardy/motion-calibration.js +0 -118
  374. package/src/ardy/motion-edit.js +0 -213
  375. package/src/ardy/motion-url.js +0 -55
  376. package/src/ardy/mp4-duration.js +0 -102
  377. package/src/ardy/npz.js +0 -595
  378. package/src/ardy/physics-panel.css +0 -21
  379. package/src/ardy/physics-panel.jsx +0 -89
  380. package/src/ardy/physics-refine.js +0 -111
  381. package/src/ardy/physics-review.js +0 -567
  382. package/src/ardy/physics-temporal.js +0 -54
  383. package/src/ardy/platform-fit-panel.css +0 -64
  384. package/src/ardy/platform-fit-panel.jsx +0 -41
  385. package/src/ardy/platform-fit.js +0 -326
  386. package/src/ardy/playback.js +0 -711
  387. package/src/ardy/pose-pin.js +0 -97
  388. package/src/ardy/prompt-clips.js +0 -30
  389. package/src/ardy/retime.js +0 -211
  390. package/src/ardy/root-drop.js +0 -369
  391. package/src/ardy/timeline-resize.js +0 -13
  392. package/src/ardy/to-cskel27.js +0 -225
  393. package/src/ardy/trim.js +0 -33
  394. package/src/ardy/waypoints.js +0 -369
  395. package/src/ardy-bridge-contract.js +0 -281
  396. package/src/domains/motion/motion-video-capture.js +0 -664
  397. package/src/i2v-motion-client.js +0 -77
  398. package/src/i2v-motion-studio.jsx +0 -180
  399. package/src/line-edit.js +0 -1348
  400. package/src/motion/generation.js +0 -105
  401. package/src/motion-readiness-ui.jsx +0 -67
  402. package/src/motion-readiness.js +0 -40
  403. package/src/motion-resources.js +0 -177
  404. package/src/motion-store.js +0 -65
  405. package/src/motion-trail.js +0 -601
  406. package/src/multimodel-ingest.js +0 -394
  407. package/src/panels/PromptBlocksPanel.jsx +0 -444
  408. package/src/panels/VideoCapturePanel.jsx +0 -181
  409. package/src/pose-extract/browser.js +0 -42
  410. package/src/pose-extract/detector.js +0 -100
  411. package/src/pose-extract/fit.js +0 -227
  412. package/src/pose-extract/image-frame.js +0 -51
  413. package/src/pose-extract/index.js +0 -58
  414. package/src/pose-extract/keyframes.js +0 -74
  415. package/src/pose-extract/landmarks.js +0 -162
  416. package/src/pose-extract/mirror.js +0 -153
  417. package/src/pose-extract/take.js +0 -131
  418. package/src/pose-extract/video-frames.js +0 -91
  419. package/src/take-recipe.js +0 -165
  420. package/src/trail-key-conflicts.js +0 -39
  421. package/src/trail-pick.js +0 -59
  422. package/src/use-i2v-capture-modal.js +0 -15
  423. package/tools/ardy/BRIDGE.md +0 -37
  424. package/tools/ardy/GVHMR-NPZ.md +0 -68
  425. package/tools/ardy/README.md +0 -124
  426. package/tools/ardy/__pycache__/cclay_gvhmr_worker.cpython-313.pyc +0 -0
  427. package/tools/ardy/artifacts.mjs +0 -34
  428. package/tools/ardy/bridge.mjs +0 -1732
  429. package/tools/ardy/bvh-cskel27.mjs +0 -1265
  430. package/tools/ardy/cclay_constrained_generate.py +0 -561
  431. package/tools/ardy/cclay_gvhmr_worker.py +0 -264
  432. package/tools/ardy/cclay_motion_edit.py +0 -510
  433. package/tools/ardy/cclay_sequence_generate.py +0 -705
  434. package/tools/ardy/cclay_worker.py +0 -304
  435. package/tools/ardy/dump-npz.py +0 -205
  436. package/tools/ardy/extract-rest.mjs +0 -299
  437. package/tools/ardy/extract.mjs +0 -507
  438. package/tools/ardy/footage.mjs +0 -467
  439. package/tools/ardy/gvhmr-floor.mjs +0 -102
  440. package/tools/ardy/gvhmr-to-cskel27.mjs +0 -21
  441. package/tools/ardy/gvhmr_fastpath.py +0 -168
  442. package/tools/ardy/gvhmr_trajectory.py +0 -240
  443. package/tools/ardy/merge-text-encoder.py +0 -160
  444. package/tools/ardy/mocap-metrics.mjs +0 -200
  445. package/tools/ardy/mocap-quality-gate.mjs +0 -110
  446. package/tools/ardy/motion-stabilize.mjs +0 -348
  447. package/tools/ardy/npz.mjs +0 -414
  448. package/tools/ardy/pose-to-npz.mjs +0 -106
  449. package/tools/ardy/prompt-limits.mjs +0 -5
  450. package/tools/ardy/run-edit-on-box.sh +0 -73
  451. package/tools/ardy/run-local.mjs +0 -233
  452. package/tools/ardy/run-on-box.sh +0 -593
  453. package/tools/ardy/run-sequence-on-box.sh +0 -177
  454. package/tools/ardy/runners/gvhmr-worker.mjs +0 -206
  455. package/tools/ardy/runners/index.mjs +0 -18
  456. package/tools/ardy/runners/local.mjs +0 -455
  457. package/tools/ardy/runners/proc.mjs +0 -125
  458. package/tools/ardy/runners/remote.mjs +0 -252
  459. package/tools/ardy/setup-local.mjs +0 -189
  460. package/tools/ardy/setup-text-encoder-on-box.sh +0 -93
  461. package/tools/ardy/setup-text-encoder.py +0 -306
  462. package/tools/ardy/smpl-cskel27.mjs +0 -178
  463. package/tools/ardy/visual-qa.mjs +0 -196
  464. package/tools/ardy/vq-car.mjs +0 -52
  465. package/tools/bench/EXP3.md +0 -61
  466. package/tools/bench/cclay_bench_extract_incam.py +0 -125
  467. package/tools/bench/cclay_bench_extract_obs.py +0 -204
  468. package/tools/bench/cclay_bench_runner.py +0 -42
  469. package/tools/bench/cube-contact.mjs +0 -162
  470. package/tools/bench/exp3.mjs +0 -152
  471. package/tools/bench/extract-bench-lib.mjs +0 -216
  472. package/tools/bench/extract-bench.mjs +0 -302
  473. package/tools/bench/fal-generate.mjs +0 -88
  474. package/tools/bench/fit/README.md +0 -189
  475. package/tools/bench/fit/camera.mjs +0 -59
  476. package/tools/bench/fit/contact.mjs +0 -419
  477. package/tools/bench/fit/footlock.mjs +0 -234
  478. package/tools/bench/fit/motion.mjs +0 -85
  479. package/tools/bench/fit/pin.mjs +0 -27
  480. package/tools/bench/fit/remote.mjs +0 -105
  481. package/tools/bench/fit-bench.mjs +0 -126
  482. package/tools/bench/fit-sanity.mjs +0 -45
  483. package/tools/bench/metrics.mjs +0 -313
  484. package/tools/bench/obs/depth.mjs +0 -258
  485. package/tools/bench/obs/extrinsics.mjs +0 -175
  486. package/tools/bench/obs/fit_mannequin_betas.py +0 -340
  487. package/tools/bench/obs/ground.mjs +0 -294
  488. package/tools/bench/obs/heading.mjs +0 -151
  489. package/tools/bench/obs/ladder.mjs +0 -555
  490. package/tools/bench/obs/mannequin-betas.json +0 -124
  491. package/tools/bench/obs/remote.mjs +0 -83
  492. package/tools/bench/obs/rest_joints.py +0 -52
  493. package/tools/bench/obs/ybot-targets.mjs +0 -49
  494. package/tools/bench/obs-bench.mjs +0 -520
  495. package/tools/bench/score.mjs +0 -343
  496. package/tools/bench/summarize.mjs +0 -86
  497. package/tools/demo-worker/README.md +0 -137
  498. package/tools/demo-worker/api-client.mjs +0 -233
  499. package/tools/demo-worker/generate.mjs +0 -301
  500. package/tools/demo-worker/index.mjs +0 -466
  501. package/tools/demo-worker/sign-core.mjs +0 -112
  502. package/tools/demo-worker/sign.mjs +0 -161
  503. package/tools/gt-render/browser.mjs +0 -159
  504. package/tools/gt-render/camera-math.mjs +0 -276
  505. package/tools/gt-render/page.mjs +0 -267
  506. package/tools/gt-render/render.mjs +0 -514
  507. package/tools/gt-render/scene-box.mjs +0 -31
  508. package/tools/gt-render/take-transform.mjs +0 -87
  509. package/tools/kimodo/compare-seam.mjs +0 -108
  510. package/tools/kimodo/constraints.mjs +0 -244
  511. package/tools/kimodo/edit.mjs +0 -259
  512. package/tools/kimodo/effector-constraints.mjs +0 -200
  513. package/tools/kimodo/generate.mjs +0 -646
  514. package/tools/kimodo/local-output.mjs +0 -265
  515. package/tools/kimodo/measure-pose.mjs +0 -65
  516. package/tools/kimodo/measure-preserve.mjs +0 -899
  517. package/tools/kimodo/measure-waypoints.mjs +0 -55
  518. package/tools/kimodo/mlx-generate.py +0 -111
  519. package/tools/kimodo/pose-constraints.mjs +0 -248
  520. package/tools/kimodo/preserve-mask.mjs +0 -543
  521. package/tools/kimodo/read-npz.mjs +0 -189
  522. package/tools/kimodo/run-edit-on-box.mjs +0 -155
  523. package/tools/kimodo/run-sequence-on-box.mjs +0 -178
  524. package/tools/kimodo/runner.mjs +0 -284
  525. package/tools/kimodo/seam-batch.mjs +0 -77
  526. package/tools/kimodo/setup-local.mjs +0 -30
  527. package/tools/kimodo/setup-on-box.sh +0 -339
  528. package/tools/kimodo/soma77-to-cskel27.mjs +0 -305
  529. package/tools/morphgs/assets/gen_truth.py +0 -39
  530. package/tools/morphgs/assets/mesh_ori_rig.txt +0 -27
  531. package/tools/morphgs/assets/playback-check.mjs +0 -30
  532. package/tools/morphgs/demo-gate.sh +0 -26
  533. package/tools/morphgs/fbx2morphgs.mjs +0 -68
  534. package/tools/morphgs/morphgs-to-cskel27.mjs +0 -105
  535. package/tools/morphgs/patches/preprocess_src-none-mode.patch +0 -76
  536. package/tools/morphgs/setup-on-cluster.sh +0 -126
  537. package/tools/projflow/driver.py +0 -1069
  538. package/tools/projflow/generate.mjs +0 -805
  539. package/tools/projflow/hml22-to-cskel27.mjs +0 -735
  540. package/tools/projflow/line-edit-job.mjs +0 -547
  541. package/tools/projflow/replay.mjs +0 -452
  542. package/tools/projflow/runner.mjs +0 -269
  543. package/tools/projflow/service.mjs +0 -742
  544. package/tools/track/DESIGN.md +0 -513
  545. package/tools/track/backfill-provenance.mjs +0 -116
  546. package/tools/track/budget.mjs +0 -8
  547. package/tools/track/check-rig.mjs +0 -209
  548. package/tools/track/diagnostics.schema.json +0 -60
  549. package/tools/track/export-rig.mjs +0 -256
  550. package/tools/track/fallback.mjs +0 -7
  551. package/tools/track/fk-parity-fixture.mjs +0 -161
  552. package/tools/track/gate.mjs +0 -349
  553. package/tools/track/masks.mjs +0 -318
  554. package/tools/track/metrics.mjs +0 -201
  555. package/tools/track/publish-obs.mjs +0 -108
  556. package/tools/track/py/check_env.py +0 -61
  557. package/tools/track/py/eval_lr.py +0 -229
  558. package/tools/track/py/lr_viterbi.py +0 -294
  559. package/tools/track/py/masks.py +0 -405
  560. package/tools/track/py/objective.py +0 -382
  561. package/tools/track/py/rig.py +0 -508
  562. package/tools/track/py/scene.py +0 -326
  563. package/tools/track/py/test_joint_indices.py +0 -123
  564. package/tools/track/py/test_lr_viterbi.py +0 -195
  565. package/tools/track/py/test_masks.py +0 -229
  566. package/tools/track/py/test_rig.py +0 -288
  567. package/tools/track/py/test_scene.py +0 -354
  568. package/tools/track/py/test_track.py +0 -328
  569. package/tools/track/py/track.py +0 -411
  570. package/tools/track/remote.mjs +0 -140
  571. package/tools/track/rig-dump.mjs +0 -227
  572. package/tools/track/run-box-tests.mjs +0 -14
  573. package/tools/track/run-box.mjs +0 -168
  574. package/tools/track/setup-box.sh +0 -59
  575. package/tools/track/study-2d.mjs +0 -728
  576. /package/src/{ardy → motion}/collision-blockers.js +0 -0
  577. /package/src/{ardy → motion}/ground.js +0 -0
  578. /package/src/{ardy → motion}/ik-drag.js +0 -0
  579. /package/src/{ardy → motion}/ik-key-json.js +0 -0
  580. /package/src/{ardy → motion}/ik.js +0 -0
  581. /package/src/{ardy → motion}/physics-surface.js +0 -0
  582. /package/src/{ardy → motion}/playback-clock.js +0 -0
  583. /package/src/{ardy → motion}/range-pin.js +0 -0
@@ -1,168 +0,0 @@
1
- """Quality-preserving preparation around the existing box-side GVHMR runner.
2
-
3
- No model, dtype, batch size, flip test, tracker, camera or motion math changes.
4
- Only two strictly checkpoint-loaded preprocessing models are cached on CPU.
5
- The upstream/checkpoint files remain untouched; all patches are scoped.
6
- """
7
- import contextlib
8
- import gc
9
- import importlib
10
- import sys
11
- import time
12
- import weakref
13
- from pathlib import Path
14
-
15
- import torch
16
-
17
-
18
- @contextlib.contextmanager
19
- def checked_fast_load():
20
- """Skip only random initialization that a complete checkpoint overwrites.
21
-
22
- Audit live skipped tensors against tensors covered by load_state_dict.
23
- Constants/zeros and non-persistent buffers are not skipped. An incomplete
24
- checkpoint cannot leave uninitialized parameters silently in production.
25
- """
26
- saved = []
27
- skipped = []
28
- covered = []
29
- loads = []
30
- original_load = torch.load
31
- original_state_load = torch.nn.Module.load_state_dict
32
-
33
- def patch(owner, name, value):
34
- saved.append((owner, name, getattr(owner, name)))
35
- setattr(owner, name, value)
36
-
37
- def skip(tensor, *args, **kwargs):
38
- skipped.append(weakref.ref(tensor))
39
- return tensor
40
-
41
- def mmap_load(*args, **kwargs):
42
- if "mmap" in kwargs:
43
- return original_load(*args, **kwargs)
44
- try:
45
- return original_load(*args, **kwargs, mmap=True)
46
- except (RuntimeError, ValueError) as exc:
47
- # Old torch checkpoint serialization cannot be memory-mapped.
48
- if "mmap" not in str(exc).lower():
49
- raise
50
- return original_load(*args, **kwargs)
51
-
52
- def state_load(module, state, *args, **kwargs):
53
- result = original_state_load(module, state, *args, **kwargs)
54
- if result.missing_keys or result.unexpected_keys:
55
- raise RuntimeError("gvhmr-fast-load-incomplete-checkpoint")
56
- loads.append(module)
57
- covered.extend(weakref.ref(v) for v in module.state_dict(keep_vars=True).values())
58
- return result
59
-
60
- try:
61
- for name in ("uniform_", "normal_", "trunc_normal_", "kaiming_uniform_", "kaiming_normal_",
62
- "xavier_uniform_", "xavier_normal_", "orthogonal_", "sparse_"):
63
- patch(torch.nn.init, name, skip)
64
- # timm's imported trunc_normal_ delegates to this module-global helper.
65
- for name in ("timm.layers.weight_init", "timm.models.layers.weight_init"):
66
- module = sys.modules.get(name)
67
- if module is not None and hasattr(module, "_trunc_normal_"):
68
- patch(module, "_trunc_normal_", skip)
69
- patch(torch, "load", mmap_load)
70
- patch(torch.nn.Module, "load_state_dict", state_load)
71
- yield
72
- live = [ref() for ref in skipped if ref() is not None]
73
- covered_storage = {ref().untyped_storage().data_ptr() for ref in covered if ref() is not None}
74
- if not loads or any(t.untyped_storage().data_ptr() not in covered_storage for t in live):
75
- raise RuntimeError("gvhmr-fast-load-uncovered-initialization")
76
- finally:
77
- for owner, name, value in reversed(saved):
78
- setattr(owner, name, value)
79
-
80
-
81
- class FastRuntime:
82
- def __init__(self, runner, enabled=True):
83
- self.runner = runner
84
- self.enabled = enabled
85
- self.cache = {}
86
- self.signature = None
87
- self.stats = {}
88
-
89
- def invalidate_changed_weights(self):
90
- paths = [Path(self.runner.__file__), Path(".git/HEAD"),
91
- Path("inputs/checkpoints/vitpose/vitpose-h-multi-coco.pth"),
92
- Path("inputs/checkpoints/hmr2/epoch=10-step=25000.ckpt")]
93
- signature = tuple((str(p.resolve()), p.stat().st_size, p.stat().st_mtime_ns) for p in paths if p.exists())
94
- if self.signature is not None and signature != self.signature:
95
- self.cache.clear()
96
- gc.collect()
97
- self.signature = signature
98
-
99
- def release_gpu(self):
100
- for item, attribute in self.cache.values():
101
- getattr(item, attribute).cpu()
102
- gc.collect()
103
- torch.cuda.empty_cache()
104
-
105
- def acquire(self, name, factory, attribute):
106
- started = time.perf_counter()
107
- if name in self.cache:
108
- item = self.cache[name][0]
109
- getattr(item, attribute).cuda().eval()
110
- self.stats["modelCacheHits"].append(name)
111
- else:
112
- with checked_fast_load():
113
- item = factory()
114
- self.cache[name] = (item, attribute)
115
- self.stats["modelLoadSeconds"][name] = time.perf_counter() - started
116
- return item
117
-
118
- @contextlib.contextmanager
119
- def job(self, evidence=None):
120
- self.invalidate_changed_weights()
121
- self.stats = {"modelCacheHits": [], "modelLoadSeconds": {}, "decodeCropCalls": 0,
122
- "sharedCropHits": 0, "decodeCropSeconds": 0, "mode": "exact-fast" if self.enabled else "reference"}
123
- runner = self.runner
124
- vp = importlib.import_module("hmr4d.utils.preproc.vitpose")
125
- vf = importlib.import_module("hmr4d.utils.preproc.vitfeat_extractor")
126
- original_crop, original_vp_crop = vf.get_batch, vp.get_batch
127
- original_preprocess, original_release = runner.preprocess, runner._release_gpu
128
- original_vit, original_hmr = runner.VitPoseExtractor, runner.Extractor
129
- crops = []
130
-
131
- def shared_crop(path, boxes, *args, **kwargs):
132
- for prior_path, prior_boxes, prior_args, prior_kwargs, output in crops:
133
- if str(path) == prior_path and args == prior_args and kwargs == prior_kwargs and torch.equal(boxes, prior_boxes):
134
- self.stats["sharedCropHits"] += 1
135
- # Both consumers read their input. Cloning prevents a future
136
- # in-place consumer from contaminating the other model.
137
- return tuple(v.clone() for v in output)
138
- started = time.perf_counter()
139
- output = original_crop(path, boxes, *args, **kwargs)
140
- self.stats["decodeCropCalls"] += 1
141
- self.stats["decodeCropSeconds"] += time.perf_counter() - started
142
- if self.enabled:
143
- crops.append((str(path), boxes.clone(), args, dict(kwargs), tuple(v.clone() for v in output)))
144
- return output
145
-
146
- def preprocess(*args, **kwargs):
147
- started = time.perf_counter()
148
- data = original_preprocess(*args, **kwargs)
149
- self.stats["preprocessSeconds"] = time.perf_counter() - started
150
- if evidence:
151
- torch.save(data, Path(evidence) / "preprocess.pt")
152
- crops.clear()
153
- return data
154
-
155
- try:
156
- vf.get_batch = vp.get_batch = shared_crop
157
- runner.preprocess = preprocess
158
- if self.enabled:
159
- runner.VitPoseExtractor = lambda: self.acquire("vitpose", original_vit, "pose")
160
- runner.Extractor = lambda: self.acquire("hmr2", original_hmr, "extractor")
161
- runner._release_gpu = self.release_gpu
162
- yield self.stats
163
- finally:
164
- runner.preprocess, runner._release_gpu = original_preprocess, original_release
165
- runner.VitPoseExtractor, runner.Extractor = original_vit, original_hmr
166
- vf.get_batch, vp.get_batch = original_crop, original_vp_crop
167
- crops.clear()
168
- self.release_gpu()
@@ -1,240 +0,0 @@
1
- """Observation-anchored recovery of delayed vertical descents from GVHMR.
2
-
3
- This is NOT a ground-every-frame filter or a general dynamics solver. A
4
- stationary-camera take must contain a large, confident image-space descent
5
- and an observed landing plateau. A delayed world endpoint may be recovered
6
- from that observation when it never settles. Frames, rotations and XZ
7
- are never changed. Ambiguous events retain the original output.
8
- """
9
- import contextlib
10
- import json
11
- import time
12
- from pathlib import Path
13
-
14
- import numpy as np
15
-
16
-
17
- def smooth(values, sigma):
18
- radius = max(1, int(np.ceil(3 * sigma)))
19
- x = np.arange(-radius, radius + 1)
20
- weights = np.exp(-0.5 * (x / max(sigma, 0.25)) ** 2)
21
- weights /= weights.sum()
22
- return np.convolve(np.pad(values, (radius, radius), mode="edge"), weights, mode="valid")
23
-
24
-
25
- def center_of_mass(joints):
26
- """Approximate segment-mass COM; normalized weights, not a pelvis proxy."""
27
- segments = [(0, 12, .497), (12, 15, .081),
28
- (1, 4, .100), (2, 5, .100), (4, 7, .0465), (5, 8, .0465),
29
- (7, 10, .0145), (8, 11, .0145),
30
- (16, 18, .028), (17, 19, .028), (18, 20, .016), (19, 21, .016),
31
- (20, 20, .006), (21, 21, .006)]
32
- return sum((joints[:, a] + joints[:, b]) * (weight * .5)
33
- for a, b, weight in segments) / sum(s[2] for s in segments)
34
-
35
-
36
- def recover_vertical(root, joints, camera_joints, keypoints, intrinsics, camera_up, fps):
37
- """Pure NumPy kernel. Returns Y corrections and inspectable diagnostics.
38
-
39
- Units are meters and seconds. COCO hips 11/12 provide translation
40
- observations; the ballistic proposal uses whole-body COM. FPS is always
41
- the actual source FPS, never inferred from number of frames.
42
- """
43
- root = np.asarray(root, dtype=np.float64)
44
- n = len(root)
45
- delta = np.zeros(n, dtype=np.float64)
46
- report = {"version": 2, "status": "unchanged", "events": [], "rejected": [],
47
- "frames": n, "fps": float(fps), "changedFrames": 0}
48
- arrays = [root, joints, camera_joints, keypoints, intrinsics, camera_up]
49
- if not np.isfinite(fps) or not 5 <= fps <= 240 or n < 12 or any(not np.isfinite(a).all() for a in arrays):
50
- report["reason"] = "invalid-input"
51
- return delta, report
52
- joints, camera_joints = np.asarray(joints), np.asarray(camera_joints)
53
- keypoints, intrinsics = np.asarray(keypoints), np.asarray(intrinsics)
54
- if root.shape != (n, 3) or joints.shape != (n, 22, 3) or camera_joints.shape != (n, 22, 3) or keypoints.shape != (n, 17, 3):
55
- report["reason"] = "unsupported-shape"
56
- return delta, report
57
- k = intrinsics[0] if intrinsics.ndim == 3 else intrinsics
58
- up = np.asarray(camera_up)
59
- projected_up = np.array([k[0, 0] * up[0], k[1, 1] * up[1]])
60
- norm = np.linalg.norm(projected_up)
61
- depth = camera_joints[:, 0, 2]
62
- if norm < .45 * min(k[0, 0], k[1, 1]) or np.median(depth) <= 0:
63
- report["reason"] = "gravity-axis-not-observable"
64
- return delta, report
65
- if intrinsics.ndim == 3 and np.max(np.abs(intrinsics - k)) > .01 * np.max(k):
66
- report["reason"] = "variable-intrinsics"
67
- return delta, report
68
- hip_conf = np.minimum(keypoints[:, 11, 2], keypoints[:, 12, 2])
69
- hips = keypoints[:, [11, 12], :2].mean(axis=1)
70
- # Fixed metric scale over the take avoids bbox/depth breathing as the
71
- # person curls up. Only timing is recovered: endpoint world heights are
72
- # retained, so this does not pretend to solve monocular absolute scale.
73
- scale = np.median(depth) / norm
74
- observed = smooth(hips @ (projected_up / norm) * scale, max(.6, fps * .04))
75
- height = float(np.median(np.linalg.norm(joints[:, 12] - joints[:, 0], axis=1) +
76
- np.linalg.norm(joints[:, 0] - joints[:, 4], axis=1) +
77
- np.linalg.norm(joints[:, 4] - joints[:, 7], axis=1)) * 1.35)
78
- height = max(.8, height)
79
- velocity = np.gradient(observed) * fps
80
- base = root[:, 1]
81
- base_smooth = smooth(base, max(.6, fps * .04))
82
- base_velocity = np.gradient(base_smooth) * fps
83
- settle = max(4, round(.25 * fps))
84
- com_offset = center_of_mass(joints)[:, 1] - base
85
- i = 1
86
- while i < n - settle:
87
- if velocity[i] >= -.65 * height:
88
- i += 1
89
- continue
90
- fast_start = i
91
- while i < n - 1 and velocity[i] < -.3 * height:
92
- i += 1
93
- end_fast = i
94
- start = fast_start
95
- while start > 0 and velocity[start - 1] < -.1 * height and fast_start - start < .4 * fps:
96
- start -= 1
97
- # Landing evidence is a stable observed pelvis, not a local minimum
98
- # of the already incorrect GVHMR root or a hard-coded pose category.
99
- landing = None
100
- for t in range(end_fast, min(n - settle, end_fast + round(.6 * fps)) + 1):
101
- if np.max(observed[t:t + settle]) - np.min(observed[t:t + settle]) < .025 * height:
102
- landing = t
103
- break
104
- if landing is None:
105
- report["rejected"].append({"start": start, "reason": "no-observed-landing"})
106
- continue
107
- drop = observed[start] - np.median(observed[landing:landing + settle])
108
- if drop < .35 * height or not .12 <= (landing - start) / fps <= 2.0:
109
- continue
110
- if np.quantile(hip_conf[start:landing + settle], .1) < .55:
111
- report["rejected"].append({"start": start, "landing": landing, "reason": "uncertain-keypoints"})
112
- continue
113
- if np.ptp(depth[start:landing + settle]) > .35 * np.median(depth[start:landing + settle]):
114
- report["rejected"].append({"start": start, "landing": landing, "reason": "uncertain-depth"})
115
- continue
116
- anchor = None
117
- for t in range(landing, min(n - settle, landing + round(3 * fps)) + 1):
118
- if np.max(np.abs(base_velocity[t:t + settle])) < .08 * height:
119
- anchor = t + settle - 1
120
- break
121
- endpoint_source = "settled-world"
122
- if anchor is None:
123
- # A lagging prediction often keeps descending past the end of a
124
- # short clip. Requiring that same prediction to settle prevented
125
- # recovery exactly when it was needed. Use a persistent observed
126
- # plateau and metric camera scale, NOT the erroneous last height.
127
- anchor = n - 1
128
- if anchor - landing < round(.4 * fps):
129
- report["rejected"].append({"start": start, "landing": landing, "reason": "landing-observation-too-short"})
130
- continue
131
- endpoint_source = "observed-plateau"
132
- # The image must remain on its plateau while the world catches up.
133
- # This rejects another jump, stairs and camera motion during the tail.
134
- if np.ptp(observed[landing:anchor + 1]) > .07 * height:
135
- report["rejected"].append({"start": start, "landing": landing, "reason": "moving-landing"})
136
- continue
137
- tail_drift = base[landing] - base[anchor]
138
- total_drop = base[start] - base[anchor]
139
- if tail_drift < .12 * height or total_drop < .35 * height:
140
- i = landing + settle
141
- continue
142
- stop_observed = float(np.median(observed[landing:anchor + 1]))
143
- endpoint_y = base[anchor] if endpoint_source == "settled-world" else base[start] - (observed[start] - stop_observed)
144
- progress = np.clip((observed[start] - observed[start:anchor + 1]) /
145
- max(observed[start] - stop_observed, 1e-8), 0, 1)
146
- target = base[start] + progress * (endpoint_y - base[start])
147
- # Keep the original endpoint exactly, with a short smooth residual
148
- # bridge inside the observed plateau (no tail offset after the event).
149
- end_blend = min(settle, len(target))
150
- blend = np.linspace(0, 1, end_blend)
151
- blend = blend * blend * (3 - 2 * blend)
152
- target[-end_blend:] += (endpoint_y - target[-1]) * blend
153
- airborne = landing - start + 1
154
- observed_com = target[:airborne] + com_offset[start:landing + 1]
155
- # The stable landing window includes a few post-impact frames.
156
- # Do not force those frames to keep accelerating under gravity.
157
- # Locate an impact endpoint near the plateau, after >=90% descent
158
- # (the short image denoising kernel blurs the impact discontinuity).
159
- ballistic_error, ballistic, gravity_end = float("inf"), None, None
160
- for stop in range(max(4, airborne - round(.15 * fps)), airborne + 1):
161
- if progress[stop - 1] < .9:
162
- continue
163
- times = np.arange(stop) / fps
164
- duration = times[-1]
165
- initial_velocity = (observed_com[stop - 1] - observed_com[0] + .5 * 9.81 * duration ** 2) / duration
166
- proposal = observed_com[0] + initial_velocity * times - .5 * 9.81 * times ** 2
167
- error = float(np.sqrt(np.mean((proposal - observed_com[:stop]) ** 2)))
168
- if error < ballistic_error:
169
- ballistic_error, ballistic, gravity_end = error, proposal, stop
170
- gravity_applied = ballistic_error < .025 * height
171
- if gravity_applied:
172
- target[:gravity_end] = ballistic - com_offset[start:start + gravity_end]
173
- change = target - base[start:anchor + 1]
174
- if np.max(np.abs(change)) > 2.5 * height:
175
- report["rejected"].append({"start": start, "reason": "excessive-correction"})
176
- continue
177
- delta[start:anchor + 1] = change
178
- report["events"].append({"start": start, "landing": landing, "anchor": anchor,
179
- "endpointSource": endpoint_source,
180
- "sourceDropM": float(drop), "worldDropM": float(total_drop),
181
- "tailDriftBeforeM": float(tail_drift),
182
- "tailDriftAfterM": float(target[airborne - 1] - target[-1]),
183
- "maxCorrectionM": float(np.max(np.abs(change))),
184
- "gravityApplied": bool(gravity_applied),
185
- "gravityFitRmseM": ballistic_error if np.isfinite(ballistic_error) else None,
186
- "gravityIntervalEnd": start + gravity_end - 1 if gravity_applied else None,
187
- "mode": "ballistic-com" if gravity_applied else "observed-timing",
188
- "gravityReason": None if gravity_applied else "ballistic-curve-disagrees-with-video"})
189
- i = anchor + 1
190
- report["changedFrames"] = int(np.count_nonzero(np.abs(delta) > 1e-6))
191
- report["status"] = "corrected" if report["events"] else "unchanged"
192
- if not report["events"]:
193
- report["reason"] = "no-confident-delayed-descent"
194
- return delta, report
195
-
196
-
197
- @contextlib.contextmanager
198
- def trajectory_job(runner, video, output_root, *, enabled=True):
199
- """Scoped post-inference hook; upstream files and original runner stay intact."""
200
- stats = {"version": 1, "status": "disabled", "changedFrames": 0}
201
- if not enabled:
202
- yield stats
203
- return
204
- import torch
205
- from pytorch3d.transforms import axis_angle_to_matrix
206
- original = runner.DemoPL.predict
207
- # The legacy NPZ exporter rounds FPS to an integer. Keep fractional
208
- # source rates here so the physical proposal uses seconds, not that label.
209
- fps = float(runner.iio.immeta(str(video), plugin="pyav").get("fps") or runner.video_fps(str(video)))
210
-
211
- def predict(model, data, static_cam=False):
212
- result = original(model, data, static_cam=static_cam)
213
- began = time.perf_counter()
214
- if not static_cam:
215
- stats.update(status="unchanged", reason="moving-camera-not-supported")
216
- return result
217
- with torch.no_grad():
218
- endecoder = model.pipeline.endecoder
219
- gp, cp = result["smpl_params_global"], result["smpl_params_incam"]
220
- w = endecoder.fk_v2(**{k: v[None] for k, v in gp.items()})[0]
221
- c = endecoder.fk_v2(**{k: v[None] for k, v in cp.items()})[0]
222
- r_c2w = axis_angle_to_matrix(gp["global_orient"][0]) @ axis_angle_to_matrix(cp["global_orient"][0]).T
223
- cpu = lambda a: a.detach().cpu().numpy()
224
- delta, report = recover_vertical(cpu(gp["transl"]), cpu(w), cpu(c), cpu(data["kp2d"]),
225
- cpu(data["K_fullimg"]), cpu(r_c2w.T[:, 1]), fps)
226
- if report["events"]:
227
- corrected = gp["transl"].clone()
228
- corrected[:, 1] += torch.as_tensor(delta, device=corrected.device, dtype=corrected.dtype)
229
- gp["transl"] = corrected
230
- result["net_outputs"]["pred_smpl_params_global"]["transl"] = corrected[None]
231
- stats.update(report)
232
- stats["seconds"] = time.perf_counter() - began
233
- Path(output_root, "trajectory.json").write_text(json.dumps(stats, indent=2))
234
- return result
235
-
236
- runner.DemoPL.predict = predict
237
- try:
238
- yield stats
239
- finally:
240
- runner.DemoPL.predict = original
@@ -1,160 +0,0 @@
1
- #!/usr/bin/env python3
2
- """merge-text-encoder.py - bake the MNTP LoRA into the base weights.
3
-
4
- Run under the ARDY text-encoder venv (needs torch, peft, transformers, and
5
- the `ardy` package importable — i.e. from the ARDY checkout):
6
-
7
- cd ~/ardy && .venv/bin/python merge-text-encoder.py --dest ~/cclay-text-encoders
8
-
9
- Why this exists: transformers v5 removed the automatic PEFT-adapter
10
- resolution that `from_pretrained` did in v4 (`find_adapter_config_file` is
11
- gone from modeling_utils). ARDY's vendored LLM2Vec loader relies on that
12
- behavior — it points `from_pretrained` at the MNTP *adapter* repo and lets
13
- transformers chase `adapter_config.json` to the (gated) base. Under v5 that
14
- path simply fails with "no model.safetensors found".
15
-
16
- So instead of an adapter directory, the local MNTP path becomes a full
17
- model: this script loads the ungated base (NousResearch mirror, already
18
- hash-verified by setup-text-encoder.py), applies the MNTP LoRA with peft,
19
- `merge_and_unload()`s it — the exact math upstream LLM2Vec performs at load
20
- time — and saves the merged weights to the path ARDY's TEXT_ENCODERS_DIR
21
- override resolves. Plain full-model loading works identically under
22
- transformers v4 and v5; the supervised LoRA keeps loading through peft
23
- directly, which both versions support.
24
-
25
- Layout before: <dest>/McGill-NLP/...-mntp (downloaded adapter files)
26
- Layout after: <dest>/McGill-NLP/...-mntp-src (the downloads, kept for
27
- provenance + re-merges)
28
- <dest>/McGill-NLP/...-mntp (merged full model +
29
- tokenizer + MERGE_MANIFEST)
30
-
31
- The merged config.json keeps `_name_or_path` =
32
- "meta-llama/Meta-Llama-3-8B-Instruct": it is a metadata string (no download
33
- or gate involved) that LLM2Vec's `prepare_for_tokenization` matches to pick
34
- the Llama-3 chat template — losing it would silently change every prompt
35
- embedding.
36
- """
37
-
38
- import argparse
39
- import hashlib
40
- import json
41
- import os
42
- import shutil
43
- import sys
44
-
45
- BASE = "NousResearch/Meta-Llama-3-8B-Instruct"
46
- MNTP = "McGill-NLP/LLM2Vec-Meta-Llama-3-8B-Instruct-mntp"
47
- MNTP_SRC = MNTP + "-src"
48
- NAME_OR_PATH = "meta-llama/Meta-Llama-3-8B-Instruct"
49
- TOKENIZER_FILES = ["tokenizer.json", "tokenizer_config.json", "special_tokens_map.json"]
50
-
51
-
52
- def log(msg):
53
- print("merge-text-encoder: %s" % msg, flush=True)
54
-
55
-
56
- def fail(msg):
57
- print("merge-text-encoder: ERROR: %s" % msg, file=sys.stderr, flush=True)
58
- sys.exit(1)
59
-
60
-
61
- def sha256_file(path):
62
- h = hashlib.sha256()
63
- with open(path, "rb") as f:
64
- for block in iter(lambda: f.read(1024 * 1024), b""):
65
- h.update(block)
66
- return h.hexdigest()
67
-
68
-
69
- def main():
70
- ap = argparse.ArgumentParser(description=__doc__.splitlines()[0])
71
- ap.add_argument("--dest", default=os.environ.get(
72
- "TEXT_ENCODERS_DIR", os.path.expanduser("~/cclay-text-encoders")))
73
- args = ap.parse_args()
74
- dest = os.path.abspath(os.path.expanduser(args.dest))
75
- base_dir = os.path.join(dest, BASE)
76
- mntp_dir = os.path.join(dest, MNTP)
77
- src_dir = os.path.join(dest, MNTP_SRC)
78
-
79
- if not os.path.isfile(os.path.join(base_dir, "model.safetensors.index.json")):
80
- fail("base model missing under %s — run setup-text-encoder.py first" % base_dir)
81
-
82
- # Migrate a pre-merge tree: the download step used to land the adapter
83
- # files directly at the mntp path.
84
- if os.path.isdir(mntp_dir) and not os.path.isdir(src_dir) \
85
- and os.path.isfile(os.path.join(mntp_dir, "adapter_model.safetensors")) \
86
- and not os.path.isfile(os.path.join(mntp_dir, "model.safetensors.index.json")):
87
- os.rename(mntp_dir, src_dir)
88
- log("moved downloaded adapter layout to %s" % MNTP_SRC)
89
-
90
- if not os.path.isfile(os.path.join(src_dir, "adapter_model.safetensors")):
91
- fail("MNTP adapter missing under %s — run setup-text-encoder.py first" % src_dir)
92
-
93
- adapter_sha = sha256_file(os.path.join(src_dir, "adapter_model.safetensors"))
94
- manifest_path = os.path.join(mntp_dir, "MERGE_MANIFEST.json")
95
- if os.path.isfile(manifest_path):
96
- with open(manifest_path, "r", encoding="utf-8") as f:
97
- manifest = json.load(f)
98
- if manifest.get("mntp_adapter_sha256") == adapter_sha \
99
- and os.path.isfile(os.path.join(mntp_dir, "model.safetensors.index.json")):
100
- log("merged model already present and matches the adapter hash — nothing to do")
101
- return
102
-
103
- import torch # deferred: keep --help fast and errors readable
104
- import peft
105
- import transformers
106
- from peft import PeftModel
107
- from ardy.model.llm2vec.llm2vec import LLM2Vec
108
-
109
- log("loading base (bfloat16, cpu) from %s" % base_dir)
110
- model_class = LLM2Vec._get_model_class("LlamaConfig", enable_bidirectional=True)
111
- model = model_class.from_pretrained(base_dir, torch_dtype=torch.bfloat16)
112
-
113
- log("applying + merging the MNTP LoRA from %s" % src_dir)
114
- model = PeftModel.from_pretrained(model, src_dir)
115
- model = model.merge_and_unload()
116
-
117
- tmp_out = mntp_dir + ".merging"
118
- if os.path.isdir(tmp_out):
119
- shutil.rmtree(tmp_out)
120
- log("saving merged model to %s" % mntp_dir)
121
- model.save_pretrained(tmp_out, safe_serialization=True)
122
- del model
123
-
124
- for name in TOKENIZER_FILES:
125
- src = os.path.join(src_dir, name)
126
- if os.path.isfile(src):
127
- shutil.copy2(src, os.path.join(tmp_out, name))
128
-
129
- # Preserve the chat-template key and the source architecture label.
130
- cfg_path = os.path.join(tmp_out, "config.json")
131
- with open(cfg_path, "r", encoding="utf-8") as f:
132
- cfg = json.load(f)
133
- with open(os.path.join(src_dir, "config.json"), "r", encoding="utf-8") as f:
134
- src_cfg = json.load(f)
135
- cfg["_name_or_path"] = NAME_OR_PATH
136
- if "architectures" in src_cfg:
137
- cfg["architectures"] = src_cfg["architectures"]
138
- with open(cfg_path, "w", encoding="utf-8") as f:
139
- json.dump(cfg, f, indent=2)
140
- f.write("\n")
141
-
142
- with open(os.path.join(tmp_out, "MERGE_MANIFEST.json"), "w", encoding="utf-8") as f:
143
- json.dump({
144
- "base": BASE,
145
- "mntp_adapter_sha256": adapter_sha,
146
- "torch": torch.__version__,
147
- "transformers": transformers.__version__,
148
- "peft": peft.__version__,
149
- "name_or_path": NAME_OR_PATH,
150
- }, f, indent=2)
151
- f.write("\n")
152
-
153
- if os.path.isdir(mntp_dir):
154
- shutil.rmtree(mntp_dir)
155
- os.rename(tmp_out, mntp_dir)
156
- log("done — %s is a full merged model; the supervised LoRA stays a peft adapter" % MNTP)
157
-
158
-
159
- if __name__ == "__main__":
160
- main()