cozyclay 2.1.1 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (577) hide show
  1. package/CHANGELOG.md +60 -0
  2. package/README.md +12 -30
  3. package/bin/agent/agent-routes.mjs +40 -113
  4. package/bin/agent/agent-runner.mjs +9 -10
  5. package/bin/agent/cliproxy-provider.mjs +135 -0
  6. package/bin/agent/credential-store.mjs +30 -7
  7. package/bin/agent/pi-tools.mjs +4 -1
  8. package/bin/agent/provider-keys.mjs +32 -0
  9. package/bin/agent/provider-login.mjs +110 -0
  10. package/bin/agent/provider-routes.mjs +99 -0
  11. package/bin/agent/providers.mjs +19 -97
  12. package/bin/agent/script-tool.mjs +17 -4
  13. package/bin/agent/studio-motion-reference.mjs +23 -0
  14. package/bin/agent/studio-prompt.mjs +1 -1
  15. package/bin/agent/studio-rebase-text.mjs +32 -0
  16. package/bin/agent/studio-rebase.mjs +26 -39
  17. package/bin/agent/studio-tools.mjs +9 -28
  18. package/bin/agent/tool-arguments.mjs +49 -0
  19. package/bin/agent/turn-frames.mjs +66 -0
  20. package/bin/codex-auth.mjs +9 -2
  21. package/bin/cozyclay.mjs +10 -116
  22. package/bin/live/cli.mjs +3 -3
  23. package/bin/mcp-runtime.mjs +2 -12
  24. package/bin/package-signature.mjs +0 -4
  25. package/dist/app/index.html +7 -6
  26. package/dist/assets/EXRLoader-CvVIvGVE.js +1 -0
  27. package/dist/assets/analytics-C9sUnndd.js +1 -0
  28. package/dist/assets/app-CCh--1Hc.js +5087 -0
  29. package/dist/assets/app-f-fkV5uP.css +1 -0
  30. package/dist/assets/compile-worker-CkxiD6lH.js +5 -0
  31. package/dist/assets/fflate.module-KbGj5-H6.js +5 -0
  32. package/dist/assets/{first-shot-handoff-msLI71g1.js → first-shot-handoff-CC4xe4HM.js} +1 -1
  33. package/dist/assets/{landing-ChUvB_zL.js → landing-DjHD8u7k.js} +1 -1
  34. package/dist/assets/scene-asset-sync-Hx_FzdOH.js +20 -0
  35. package/dist/assets/scene-asset-sync-_S8NQl5B.css +1 -0
  36. package/dist/assets/workflow-C4yKH1p4.js +179 -0
  37. package/dist/cozyclay-package.json +1 -1
  38. package/dist/index.html +3 -3
  39. package/dist/sw.js +3 -6
  40. package/dist/workflow/index.html +5 -4
  41. package/mcp/LIVE-PROTOCOL.md +7 -47
  42. package/mcp/README.md +16 -26
  43. package/mcp/live-hub.mjs +6 -10
  44. package/mcp/package.json +1 -3
  45. package/mcp/tool-handlers.mjs +4 -168
  46. package/package.json +3 -22
  47. package/src/App.jsx +150 -2624
  48. package/src/agent-progress.js +79 -0
  49. package/src/agent-turn-mark.js +30 -0
  50. package/src/analytics.js +1 -19
  51. package/src/app-context.js +5 -0
  52. package/src/app-stage.jsx +2 -34
  53. package/src/asset-pane.jsx +6 -5
  54. package/src/camera-block.js +21 -0
  55. package/src/camera-direction.js +120 -0
  56. package/src/character-kind.js +3 -9
  57. package/src/command-bus.js +8 -6
  58. package/src/commands/cast.js +5 -34
  59. package/src/commands/elements/character.js +1 -1
  60. package/src/commands/elements/motion.js +1 -6
  61. package/src/commands/elements/object.js +6 -2
  62. package/src/commands/elements/shot.js +4 -1
  63. package/src/commands/elements.js +38 -14
  64. package/src/commands/index.js +3 -1
  65. package/src/commands/kits.js +37 -0
  66. package/src/commands/motion-timing.js +57 -0
  67. package/src/commands/motion.js +9 -152
  68. package/src/commands/motion3-compile.js +65 -0
  69. package/src/commands/motion3.js +207 -0
  70. package/src/commands/objects.js +6 -4
  71. package/src/commands/shot.js +49 -11
  72. package/src/commands/stage.js +14 -1
  73. package/src/commands/view.js +4 -1
  74. package/src/document-mirrors.js +42 -0
  75. package/src/document-store.js +4 -0
  76. package/src/domains/cast.js +19 -194
  77. package/src/domains/motion/motion-range-pin-rules.js +1 -1
  78. package/src/domains/motion/take-source.js +51 -0
  79. package/src/domains/motion.js +60 -1838
  80. package/src/domains/scenes.js +12 -55
  81. package/src/domains/shots.js +2 -2
  82. package/src/domains/stage.js +4 -2
  83. package/src/draft-ghost.js +46 -0
  84. package/src/draft-ghost.jsx +129 -0
  85. package/src/dualview.jsx +4 -3
  86. package/src/effects/EffectsLayer.jsx +112 -0
  87. package/src/effects/effect-meshes.js +232 -0
  88. package/src/effects/effect-record.js +103 -0
  89. package/src/effects/emitter.js +59 -0
  90. package/src/effects/simulate.js +261 -0
  91. package/src/effects/state.js +59 -0
  92. package/src/execution-telemetry.js +2 -3
  93. package/src/first-success-guide.jsx +5 -5
  94. package/src/ghost-set.js +257 -0
  95. package/src/held-object-edit.jsx +113 -0
  96. package/src/held-object-pose.js +175 -0
  97. package/src/hierarchy-model.js +1 -1
  98. package/src/hierarchy-panel.jsx +1 -1
  99. package/src/imported-mesh.jsx +103 -0
  100. package/src/kits/held.js +84 -0
  101. package/src/kits/index.js +70 -0
  102. package/src/kits/smoking.js +57 -0
  103. package/src/light-blockers.js +93 -0
  104. package/src/motion/beat-board-model.js +84 -0
  105. package/src/motion/beat-board.css +124 -0
  106. package/src/motion/beat-board.jsx +59 -0
  107. package/src/motion/center-of-mass.js +66 -0
  108. package/src/motion/fix-collisions.js +850 -0
  109. package/src/motion/physics-review.js +118 -0
  110. package/src/{ardy → motion}/physics-support.js +1 -76
  111. package/src/motion/rig-snapshot.js +22 -0
  112. package/src/motion/take-segments.jsx +140 -0
  113. package/src/{ardy → motion}/timeline-coordinates.js +0 -21
  114. package/src/{ardy → motion}/timeline.css +1 -2
  115. package/src/{ardy → motion}/timeline.jsx +42 -413
  116. package/src/motion/waypoints.js +76 -0
  117. package/src/motion3/beats.js +83 -0
  118. package/src/motion3/body.js +158 -0
  119. package/src/motion3/bones.js +47 -0
  120. package/src/motion3/carried.js +47 -0
  121. package/src/motion3/compile-job.js +75 -0
  122. package/src/motion3/compile-worker.js +10 -0
  123. package/src/motion3/compiler/anchors.js +105 -0
  124. package/src/motion3/compiler/arm-orient.js +128 -0
  125. package/src/motion3/compiler/channels.js +125 -0
  126. package/src/motion3/compiler/compile.js +205 -0
  127. package/src/motion3/compiler/gait-rhythm.js +97 -0
  128. package/src/motion3/compiler/grip.js +171 -0
  129. package/src/motion3/compiler/head-steady.js +48 -0
  130. package/src/motion3/compiler/hold.js +134 -0
  131. package/src/motion3/compiler/idle.js +113 -0
  132. package/src/motion3/compiler/limbs.js +170 -0
  133. package/src/motion3/compiler/math.js +72 -0
  134. package/src/motion3/compiler/pose.js +162 -0
  135. package/src/motion3/compiler/quat.js +49 -0
  136. package/src/motion3/compiler/skeleton.js +74 -0
  137. package/src/motion3/compiler/validate-common.js +32 -0
  138. package/src/motion3/compiler/validate-goals.js +118 -0
  139. package/src/motion3/compiler/validate-objects.js +143 -0
  140. package/src/motion3/compiler/validate-parts.js +116 -0
  141. package/src/motion3/compiler/validate.js +122 -0
  142. package/src/motion3/compiler/vocab.js +73 -0
  143. package/src/motion3/compiler/walk-pelvis.js +275 -0
  144. package/src/motion3/compiler/walk.js +207 -0
  145. package/src/motion3/compiler/wrist-clamp.js +32 -0
  146. package/src/motion3/delta.js +47 -0
  147. package/src/motion3/describe.js +174 -0
  148. package/src/motion3/docs.js +27 -0
  149. package/src/motion3/edit-carry.js +21 -0
  150. package/src/motion3/fix/ease.js +16 -0
  151. package/src/motion3/fix/ground.js +37 -0
  152. package/src/motion3/fix/index.js +52 -0
  153. package/src/motion3/fix/push.js +71 -0
  154. package/src/motion3/fix/reach.js +46 -0
  155. package/src/motion3/fix/retime.js +79 -0
  156. package/src/motion3/fix/self.js +211 -0
  157. package/src/motion3/fix/slide.js +70 -0
  158. package/src/motion3/fix/turn.js +51 -0
  159. package/src/motion3/follow.js +39 -0
  160. package/src/motion3/free-motion.js +173 -0
  161. package/src/motion3/grip-choice.js +130 -0
  162. package/src/motion3/hold-plan.js +157 -0
  163. package/src/motion3/json-patch.js +77 -0
  164. package/src/motion3/key-aim.js +105 -0
  165. package/src/motion3/key-edit.js +82 -0
  166. package/src/motion3/lenient.js +127 -0
  167. package/src/motion3/object-keys.js +236 -0
  168. package/src/motion3/object-pose.js +182 -0
  169. package/src/motion3/object-tracks.js +12 -0
  170. package/src/motion3/pipeline.js +102 -0
  171. package/src/motion3/playback.js +51 -0
  172. package/src/motion3/probes.js +91 -0
  173. package/src/motion3/qa/body-checks.js +34 -0
  174. package/src/motion3/qa/check-names.js +14 -0
  175. package/src/motion3/qa/checks.js +121 -0
  176. package/src/motion3/qa/contact-checks.js +51 -0
  177. package/src/motion3/qa/explain.js +80 -0
  178. package/src/motion3/qa/fmt.js +5 -0
  179. package/src/motion3/qa/foot-checks.js +72 -0
  180. package/src/motion3/qa/geometry.js +77 -0
  181. package/src/motion3/qa/goals.js +191 -0
  182. package/src/motion3/qa/ground.js +60 -0
  183. package/src/motion3/qa/hints-contact.js +179 -0
  184. package/src/motion3/qa/hints-goal.js +160 -0
  185. package/src/motion3/qa/hints-knee.js +24 -0
  186. package/src/motion3/qa/hints-motion.js +209 -0
  187. package/src/motion3/qa/hints-object.js +91 -0
  188. package/src/motion3/qa/index.js +42 -0
  189. package/src/motion3/qa/key-checks.js +82 -0
  190. package/src/motion3/qa/near.js +96 -0
  191. package/src/motion3/qa/object-checks.js +135 -0
  192. package/src/motion3/qa/patch.js +161 -0
  193. package/src/motion3/qa/severity.js +38 -0
  194. package/src/motion3/qa/spec-checks.js +65 -0
  195. package/src/motion3/qa/style.js +218 -0
  196. package/src/motion3/qa/wrist-checks.js +69 -0
  197. package/src/motion3/qa/wrist-obs.js +60 -0
  198. package/src/motion3/refs.js +120 -0
  199. package/src/motion3/repair-tune.js +121 -0
  200. package/src/motion3/repair.js +83 -0
  201. package/src/motion3/report.js +67 -0
  202. package/src/motion3/rigs/index.js +14 -0
  203. package/src/motion3/rigs/x-bot-tpose-body.json +1 -0
  204. package/src/motion3/rigs/x-bot-tpose.json +1 -0
  205. package/src/motion3/rigs/y-bot-tpose-body.json +1 -0
  206. package/src/motion3/rigs/y-bot-tpose.json +1 -0
  207. package/src/motion3/scene.js +60 -0
  208. package/src/motion3/schema/brief.js +89 -0
  209. package/src/motion3/schema/fields.js +44 -0
  210. package/src/motion3/schema/spec-examples.js +46 -0
  211. package/src/motion3/schema/topics.js +111 -0
  212. package/src/motion3/schema/types.js +147 -0
  213. package/src/motion3/search.js +117 -0
  214. package/src/motion3/second-hand.js +112 -0
  215. package/src/motion3/skills/basic.js +82 -0
  216. package/src/motion3/skills/book.js +76 -0
  217. package/src/motion3/skills/car.js +145 -0
  218. package/src/motion3/skills/frames-auto.js +29 -0
  219. package/src/motion3/skills/index.js +83 -0
  220. package/src/motion3/skills/info.js +65 -0
  221. package/src/motion3/skills/smoke-kit.js +109 -0
  222. package/src/motion3/skills/smoke.js +160 -0
  223. package/src/motion3/spec-store.js +59 -0
  224. package/src/motion3/take-edit.js +155 -0
  225. package/src/motion3/take.js +63 -0
  226. package/src/motion3/timeline.js +127 -0
  227. package/src/motion3/views.js +121 -0
  228. package/src/motion3/walk-plan.js +119 -0
  229. package/src/object-catalog.jsx +7 -1
  230. package/src/object-colors.js +98 -0
  231. package/src/object-gizmo-parts.js +115 -0
  232. package/src/object-gizmo.jsx +37 -122
  233. package/src/object-glow.js +139 -0
  234. package/src/object-hidden.js +33 -0
  235. package/src/object-look.js +196 -0
  236. package/src/object-size.js +10 -0
  237. package/src/object-travel.js +71 -6
  238. package/src/panels/CameraPanel.jsx +7 -7
  239. package/src/panels/HdrEnvironmentControls.jsx +59 -0
  240. package/src/panels/LightPanel.jsx +25 -4
  241. package/src/panels/ObjectLookPanel.jsx +88 -0
  242. package/src/panels/PosePanel.jsx +2 -17
  243. package/src/panels/RigControlPanel.jsx +5 -53
  244. package/src/panels/SubjectBox.jsx +4 -1
  245. package/src/panels/details.css +14 -0
  246. package/src/posestudio.jsx +4 -27
  247. package/src/project-browser.jsx +3 -4
  248. package/src/project-resources.js +18 -31
  249. package/src/project.js +13 -104
  250. package/src/props.jsx +25 -280
  251. package/src/rail-dot-drag.js +23 -0
  252. package/src/render-passes.js +10 -0
  253. package/src/resource-status.jsx +1 -0
  254. package/src/result-modal.jsx +4 -19
  255. package/src/room.jsx +20 -12
  256. package/src/scene-assets.js +8 -6
  257. package/src/scene-light-place.js +72 -0
  258. package/src/scene-lights.jsx +148 -0
  259. package/src/scene-objects.js +31 -139
  260. package/src/scenes.js +15 -105
  261. package/src/semantic-edit.js +2 -5
  262. package/src/set-pieces.jsx +183 -0
  263. package/src/settings-menu.jsx +3 -11
  264. package/src/shell/BottomDock.jsx +9 -51
  265. package/src/shell/DetailsSlot.jsx +16 -200
  266. package/src/shell/GhostsMenuGroup.jsx +74 -0
  267. package/src/shell/LibrarySlot.jsx +1 -3
  268. package/src/shell/MenuBar.jsx +3 -3
  269. package/src/shell/PreferencesDialog.jsx +15 -264
  270. package/src/shell/PreferencesSlot.jsx +2 -8
  271. package/src/shell/TopBar.jsx +5 -84
  272. package/src/shell/ViewportToolbar.jsx +10 -70
  273. package/src/shell/agent-glass.css +19 -6
  274. package/src/shell/details-selection.js +42 -0
  275. package/src/shell/ghosts-menu.css +22 -0
  276. package/src/shell/glass-regions.css +29 -3
  277. package/src/shell/preferences.css +6 -1
  278. package/src/shot-authoring.js +4 -7
  279. package/src/soft-shadows.js +37 -0
  280. package/src/stage-attach-frames.js +12 -12
  281. package/src/stage-canvas-rigs.jsx +3 -3
  282. package/src/stage-capture.jsx +42 -8
  283. package/src/stage-characters.jsx +22 -216
  284. package/src/stage-editor-gizmos.jsx +6 -6
  285. package/src/stage-environment.js +93 -0
  286. package/src/stage-hdr-builtins.js +107 -0
  287. package/src/stage-hdr-image.js +116 -0
  288. package/src/stage-hdr-library.js +70 -0
  289. package/src/stage-hdr-map.js +94 -0
  290. package/src/stage-hdr.js +130 -0
  291. package/src/stage-lighting.js +149 -0
  292. package/src/stage-occlusion.js +210 -0
  293. package/src/stage-sky.jsx +159 -0
  294. package/src/stage-startup-defaults.js +5 -9
  295. package/src/studio-actions.js +12 -14
  296. package/src/studio-agent-commands.js +19 -16
  297. package/src/studio-agent-motion.js +9 -9
  298. package/src/studio-agent-protocol.js +41 -71
  299. package/src/studio-app-binding.js +25 -45
  300. package/src/studio-asset-list.js +17 -0
  301. package/src/studio-contact-sheet.js +37 -5
  302. package/src/studio-elements.js +27 -7
  303. package/src/studio-entity-bounds.js +18 -0
  304. package/src/studio-error-codes.js +8 -0
  305. package/src/studio-export-framing.js +152 -0
  306. package/src/studio-lighting-check.js +103 -0
  307. package/src/studio-motion-visual.js +150 -0
  308. package/src/studio-schema-errors.js +80 -0
  309. package/src/studio-support-gap.js +74 -0
  310. package/src/styles.css +1 -19
  311. package/src/timeline-defaults.js +5 -0
  312. package/src/timeline-extent.js +8 -20
  313. package/src/tutorial-walk.js +17 -0
  314. package/src/ui-scrub.js +1 -1
  315. package/src/use-shot-camera-tracks.js +12 -0
  316. package/src/view-ghosts.js +97 -0
  317. package/src/view-ghosts.jsx +49 -0
  318. package/src/workflow/AgentPanel.jsx +47 -166
  319. package/src/workflow/AgentProgressCard.jsx +107 -0
  320. package/src/workflow/AgentReplyText.jsx +37 -0
  321. package/src/workflow/AgentTurnSteps.jsx +84 -0
  322. package/src/workflow/LoginPanel.jsx +140 -0
  323. package/src/workflow/WorkflowBuilder.jsx +7 -23
  324. package/src/workflow/agent-client.js +54 -51
  325. package/src/workflow/agent-panel.css +71 -1
  326. package/src/workflow/agent-progress-card.css +167 -0
  327. package/src/workflow/agent-progress-view.js +47 -0
  328. package/src/workflow/agent-turn-steps.css +113 -0
  329. package/src/workflow/agent-turn.js +191 -0
  330. package/src/workflow/login-client.js +34 -0
  331. package/src/workflow/motion-input.js +18 -31
  332. package/src/workflow/node-schema.js +1 -1
  333. package/src/workflow/reply-markdown.js +69 -0
  334. package/src/workflow/scene-asset-sync.js +8 -8
  335. package/tools/agent-session-stats.mjs +61 -0
  336. package/tools/dev-full.mjs +5 -56
  337. package/tools/eslint-baseline.json +12 -13
  338. package/tools/knip-baseline.json +0 -179
  339. package/tools/loc-baseline.json +31 -81
  340. package/tools/motion3/extract-body.mjs +103 -0
  341. package/tools/motion3/extract-rig.mjs +85 -0
  342. package/tools/process-supervisor.mjs +0 -88
  343. package/tools/run-tests.mjs +8 -124
  344. package/bin/agent/motion-runtime.mjs +0 -76
  345. package/dist/ardy/cskel27-rest.json +0 -557
  346. package/dist/assets/analytics-C9pMpW7s.js +0 -1
  347. package/dist/assets/app-B_2XB9rw.css +0 -1
  348. package/dist/assets/app-DAuvKPP8.js +0 -4920
  349. package/dist/assets/config-Bx7pYsD9.js +0 -1
  350. package/dist/assets/config-DeoFTYzb.css +0 -1
  351. package/dist/assets/demo-CvKuBgy5.js +0 -1
  352. package/dist/assets/scene-asset-sync-DKkpjKBV.js +0 -19
  353. package/dist/assets/scene-asset-sync-DjJ_cJ2R.css +0 -1
  354. package/dist/assets/ticket-BPk2Ni95.js +0 -1
  355. package/dist/assets/workflow-jJRBR94Z.js +0 -179
  356. package/dist/demo/walk-then-stop.npz +0 -0
  357. package/mcp/ardy-prompts.mjs +0 -218
  358. package/src/ardy/auto-fix-panel.css +0 -108
  359. package/src/ardy/auto-physics.js +0 -1194
  360. package/src/ardy/client.js +0 -153
  361. package/src/ardy/convert.js +0 -313
  362. package/src/ardy/cskel27-neutral.js +0 -39
  363. package/src/ardy/cskel27.js +0 -77
  364. package/src/ardy/export.js +0 -165
  365. package/src/ardy/fix-collisions.js +0 -2257
  366. package/src/ardy/foot-lock.js +0 -230
  367. package/src/ardy/motion-calibration.js +0 -118
  368. package/src/ardy/motion-edit.js +0 -213
  369. package/src/ardy/motion-url.js +0 -55
  370. package/src/ardy/mp4-duration.js +0 -102
  371. package/src/ardy/npz.js +0 -595
  372. package/src/ardy/physics-panel.css +0 -21
  373. package/src/ardy/physics-panel.jsx +0 -89
  374. package/src/ardy/physics-refine.js +0 -111
  375. package/src/ardy/physics-review.js +0 -567
  376. package/src/ardy/physics-temporal.js +0 -54
  377. package/src/ardy/platform-fit-panel.css +0 -64
  378. package/src/ardy/platform-fit-panel.jsx +0 -41
  379. package/src/ardy/platform-fit.js +0 -326
  380. package/src/ardy/playback.js +0 -711
  381. package/src/ardy/pose-pin.js +0 -97
  382. package/src/ardy/prompt-clips.js +0 -30
  383. package/src/ardy/retime.js +0 -211
  384. package/src/ardy/root-drop.js +0 -369
  385. package/src/ardy/timeline-resize.js +0 -13
  386. package/src/ardy/to-cskel27.js +0 -225
  387. package/src/ardy/trim.js +0 -33
  388. package/src/ardy/waypoints.js +0 -369
  389. package/src/ardy-bridge-contract.js +0 -281
  390. package/src/domains/motion/motion-video-capture.js +0 -664
  391. package/src/i2v-motion-client.js +0 -77
  392. package/src/i2v-motion-studio.jsx +0 -180
  393. package/src/line-edit.js +0 -1348
  394. package/src/motion/generation.js +0 -105
  395. package/src/motion-readiness-ui.jsx +0 -67
  396. package/src/motion-readiness.js +0 -40
  397. package/src/motion-resources.js +0 -177
  398. package/src/motion-store.js +0 -65
  399. package/src/motion-trail.js +0 -601
  400. package/src/multimodel-ingest.js +0 -394
  401. package/src/panels/PromptBlocksPanel.jsx +0 -444
  402. package/src/panels/VideoCapturePanel.jsx +0 -181
  403. package/src/pose-extract/browser.js +0 -42
  404. package/src/pose-extract/detector.js +0 -100
  405. package/src/pose-extract/fit.js +0 -227
  406. package/src/pose-extract/image-frame.js +0 -51
  407. package/src/pose-extract/index.js +0 -58
  408. package/src/pose-extract/keyframes.js +0 -74
  409. package/src/pose-extract/landmarks.js +0 -162
  410. package/src/pose-extract/mirror.js +0 -153
  411. package/src/pose-extract/take.js +0 -131
  412. package/src/pose-extract/video-frames.js +0 -91
  413. package/src/take-recipe.js +0 -165
  414. package/src/trail-key-conflicts.js +0 -39
  415. package/src/trail-pick.js +0 -59
  416. package/src/use-i2v-capture-modal.js +0 -15
  417. package/tools/ardy/BRIDGE.md +0 -37
  418. package/tools/ardy/GVHMR-NPZ.md +0 -68
  419. package/tools/ardy/README.md +0 -124
  420. package/tools/ardy/__pycache__/cclay_gvhmr_worker.cpython-313.pyc +0 -0
  421. package/tools/ardy/artifacts.mjs +0 -34
  422. package/tools/ardy/bridge.mjs +0 -1732
  423. package/tools/ardy/bvh-cskel27.mjs +0 -1265
  424. package/tools/ardy/cclay_constrained_generate.py +0 -561
  425. package/tools/ardy/cclay_gvhmr_worker.py +0 -264
  426. package/tools/ardy/cclay_motion_edit.py +0 -510
  427. package/tools/ardy/cclay_sequence_generate.py +0 -705
  428. package/tools/ardy/cclay_worker.py +0 -304
  429. package/tools/ardy/dump-npz.py +0 -205
  430. package/tools/ardy/extract-rest.mjs +0 -299
  431. package/tools/ardy/extract.mjs +0 -507
  432. package/tools/ardy/footage.mjs +0 -467
  433. package/tools/ardy/gvhmr-floor.mjs +0 -102
  434. package/tools/ardy/gvhmr-to-cskel27.mjs +0 -21
  435. package/tools/ardy/gvhmr_fastpath.py +0 -168
  436. package/tools/ardy/gvhmr_trajectory.py +0 -240
  437. package/tools/ardy/merge-text-encoder.py +0 -160
  438. package/tools/ardy/mocap-metrics.mjs +0 -200
  439. package/tools/ardy/mocap-quality-gate.mjs +0 -110
  440. package/tools/ardy/motion-stabilize.mjs +0 -348
  441. package/tools/ardy/npz.mjs +0 -414
  442. package/tools/ardy/pose-to-npz.mjs +0 -106
  443. package/tools/ardy/prompt-limits.mjs +0 -5
  444. package/tools/ardy/run-edit-on-box.sh +0 -73
  445. package/tools/ardy/run-local.mjs +0 -233
  446. package/tools/ardy/run-on-box.sh +0 -593
  447. package/tools/ardy/run-sequence-on-box.sh +0 -177
  448. package/tools/ardy/runners/gvhmr-worker.mjs +0 -206
  449. package/tools/ardy/runners/index.mjs +0 -18
  450. package/tools/ardy/runners/local.mjs +0 -455
  451. package/tools/ardy/runners/proc.mjs +0 -125
  452. package/tools/ardy/runners/remote.mjs +0 -252
  453. package/tools/ardy/setup-local.mjs +0 -189
  454. package/tools/ardy/setup-text-encoder-on-box.sh +0 -93
  455. package/tools/ardy/setup-text-encoder.py +0 -306
  456. package/tools/ardy/smpl-cskel27.mjs +0 -178
  457. package/tools/ardy/visual-qa.mjs +0 -196
  458. package/tools/ardy/vq-car.mjs +0 -52
  459. package/tools/bench/EXP3.md +0 -61
  460. package/tools/bench/cclay_bench_extract_incam.py +0 -125
  461. package/tools/bench/cclay_bench_extract_obs.py +0 -204
  462. package/tools/bench/cclay_bench_runner.py +0 -42
  463. package/tools/bench/cube-contact.mjs +0 -162
  464. package/tools/bench/exp3.mjs +0 -152
  465. package/tools/bench/extract-bench-lib.mjs +0 -216
  466. package/tools/bench/extract-bench.mjs +0 -302
  467. package/tools/bench/fal-generate.mjs +0 -88
  468. package/tools/bench/fit/README.md +0 -189
  469. package/tools/bench/fit/camera.mjs +0 -59
  470. package/tools/bench/fit/contact.mjs +0 -419
  471. package/tools/bench/fit/footlock.mjs +0 -234
  472. package/tools/bench/fit/motion.mjs +0 -85
  473. package/tools/bench/fit/pin.mjs +0 -27
  474. package/tools/bench/fit/remote.mjs +0 -105
  475. package/tools/bench/fit-bench.mjs +0 -126
  476. package/tools/bench/fit-sanity.mjs +0 -45
  477. package/tools/bench/metrics.mjs +0 -313
  478. package/tools/bench/obs/depth.mjs +0 -258
  479. package/tools/bench/obs/extrinsics.mjs +0 -175
  480. package/tools/bench/obs/fit_mannequin_betas.py +0 -340
  481. package/tools/bench/obs/ground.mjs +0 -294
  482. package/tools/bench/obs/heading.mjs +0 -151
  483. package/tools/bench/obs/ladder.mjs +0 -555
  484. package/tools/bench/obs/mannequin-betas.json +0 -124
  485. package/tools/bench/obs/remote.mjs +0 -83
  486. package/tools/bench/obs/rest_joints.py +0 -52
  487. package/tools/bench/obs/ybot-targets.mjs +0 -49
  488. package/tools/bench/obs-bench.mjs +0 -520
  489. package/tools/bench/score.mjs +0 -343
  490. package/tools/bench/summarize.mjs +0 -86
  491. package/tools/demo-worker/README.md +0 -137
  492. package/tools/demo-worker/api-client.mjs +0 -233
  493. package/tools/demo-worker/generate.mjs +0 -301
  494. package/tools/demo-worker/index.mjs +0 -466
  495. package/tools/demo-worker/sign-core.mjs +0 -112
  496. package/tools/demo-worker/sign.mjs +0 -161
  497. package/tools/gt-render/browser.mjs +0 -182
  498. package/tools/gt-render/camera-math.mjs +0 -276
  499. package/tools/gt-render/page.mjs +0 -267
  500. package/tools/gt-render/render.mjs +0 -514
  501. package/tools/gt-render/scene-box.mjs +0 -31
  502. package/tools/gt-render/take-transform.mjs +0 -87
  503. package/tools/kimodo/compare-seam.mjs +0 -108
  504. package/tools/kimodo/constraints.mjs +0 -244
  505. package/tools/kimodo/edit.mjs +0 -259
  506. package/tools/kimodo/effector-constraints.mjs +0 -200
  507. package/tools/kimodo/generate.mjs +0 -646
  508. package/tools/kimodo/local-output.mjs +0 -265
  509. package/tools/kimodo/measure-pose.mjs +0 -65
  510. package/tools/kimodo/measure-preserve.mjs +0 -899
  511. package/tools/kimodo/measure-waypoints.mjs +0 -55
  512. package/tools/kimodo/mlx-generate.py +0 -111
  513. package/tools/kimodo/pose-constraints.mjs +0 -248
  514. package/tools/kimodo/preserve-mask.mjs +0 -543
  515. package/tools/kimodo/read-npz.mjs +0 -189
  516. package/tools/kimodo/run-edit-on-box.mjs +0 -155
  517. package/tools/kimodo/run-sequence-on-box.mjs +0 -178
  518. package/tools/kimodo/runner.mjs +0 -284
  519. package/tools/kimodo/seam-batch.mjs +0 -77
  520. package/tools/kimodo/setup-local.mjs +0 -30
  521. package/tools/kimodo/setup-on-box.sh +0 -339
  522. package/tools/kimodo/soma77-to-cskel27.mjs +0 -305
  523. package/tools/morphgs/assets/gen_truth.py +0 -39
  524. package/tools/morphgs/assets/mesh_ori_rig.txt +0 -27
  525. package/tools/morphgs/assets/playback-check.mjs +0 -30
  526. package/tools/morphgs/demo-gate.sh +0 -26
  527. package/tools/morphgs/fbx2morphgs.mjs +0 -68
  528. package/tools/morphgs/morphgs-to-cskel27.mjs +0 -105
  529. package/tools/morphgs/patches/preprocess_src-none-mode.patch +0 -76
  530. package/tools/morphgs/setup-on-cluster.sh +0 -126
  531. package/tools/projflow/driver.py +0 -1069
  532. package/tools/projflow/generate.mjs +0 -805
  533. package/tools/projflow/hml22-to-cskel27.mjs +0 -735
  534. package/tools/projflow/line-edit-job.mjs +0 -547
  535. package/tools/projflow/replay.mjs +0 -452
  536. package/tools/projflow/runner.mjs +0 -269
  537. package/tools/projflow/service.mjs +0 -742
  538. package/tools/track/DESIGN.md +0 -513
  539. package/tools/track/backfill-provenance.mjs +0 -116
  540. package/tools/track/budget.mjs +0 -8
  541. package/tools/track/check-rig.mjs +0 -209
  542. package/tools/track/diagnostics.schema.json +0 -60
  543. package/tools/track/export-rig.mjs +0 -256
  544. package/tools/track/fallback.mjs +0 -7
  545. package/tools/track/fk-parity-fixture.mjs +0 -161
  546. package/tools/track/gate.mjs +0 -349
  547. package/tools/track/masks.mjs +0 -318
  548. package/tools/track/metrics.mjs +0 -201
  549. package/tools/track/publish-obs.mjs +0 -108
  550. package/tools/track/py/check_env.py +0 -61
  551. package/tools/track/py/eval_lr.py +0 -229
  552. package/tools/track/py/lr_viterbi.py +0 -294
  553. package/tools/track/py/masks.py +0 -405
  554. package/tools/track/py/objective.py +0 -382
  555. package/tools/track/py/rig.py +0 -508
  556. package/tools/track/py/scene.py +0 -326
  557. package/tools/track/py/test_joint_indices.py +0 -123
  558. package/tools/track/py/test_lr_viterbi.py +0 -195
  559. package/tools/track/py/test_masks.py +0 -229
  560. package/tools/track/py/test_rig.py +0 -288
  561. package/tools/track/py/test_scene.py +0 -354
  562. package/tools/track/py/test_track.py +0 -328
  563. package/tools/track/py/track.py +0 -411
  564. package/tools/track/remote.mjs +0 -140
  565. package/tools/track/rig-dump.mjs +0 -227
  566. package/tools/track/run-box-tests.mjs +0 -14
  567. package/tools/track/run-box.mjs +0 -168
  568. package/tools/track/setup-box.sh +0 -59
  569. package/tools/track/study-2d.mjs +0 -728
  570. /package/src/{ardy → motion}/collision-blockers.js +0 -0
  571. /package/src/{ardy → motion}/ground.js +0 -0
  572. /package/src/{ardy → motion}/ik-drag.js +0 -0
  573. /package/src/{ardy → motion}/ik-key-json.js +0 -0
  574. /package/src/{ardy → motion}/ik.js +0 -0
  575. /package/src/{ardy → motion}/physics-surface.js +0 -0
  576. /package/src/{ardy → motion}/playback-clock.js +0 -0
  577. /package/src/{ardy → motion}/range-pin.js +0 -0
@@ -0,0 +1,96 @@
1
+ // Measured, not judged (output.observations.near): how close each hand and foot comes to the scene
2
+ // objects. A hand is its palm and its five fingertips, a foot its sole (geometry.js solePoints);
3
+ // every scene body is a box at its pose that frame (object-pose.js: carried, hinged or still).
4
+ // Per frame the nearest body within FAR m names its top group (the object) and the body (the
5
+ // part); consecutive frames near the same object make a run, and the RUNS closest runs are kept,
6
+ // in frame order. gap is the signed distance to the box (sdBox), < 0 inside. No run: nothing
7
+ // within FAR m. A hand is not measured against what it carries (it is on it), and a follow
8
+ // record (it rides the body) is none of these objects.
9
+ // Why: a hand meant to strum floated 20 cm in front of a guitar with QA clean (session df388a9b),
10
+ // and a toe went 4 cm into a stair's edge during a swing (session e7edb718); no other answer said so.
11
+ import { sdBox, solePoints } from "./geometry.js";
12
+ import { objectPoseAt, handOf } from "../object-pose.js";
13
+ import { isFollow } from "../carried.js";
14
+ import { add, apply, dist, len, scale } from "../compiler/math.js";
15
+
16
+ const FAR = 0.3, RUNS = 2, TIPS = ["Thumb4", "Index4", "Middle4", "Ring4", "Pinky4"];
17
+ const r3 = v => Math.round(v * 1000) / 1000;
18
+
19
+ export const NEAR_UNITS = "near: hand (palm, fingertips), foot (sole) to the nearest object within 0.3 m (top group; part: the body at the closest frame), 2 closest runs; gap [min, f, max, f] m, < 0 inside"
20
+
21
+ /** The effector points of a solved pose s: { hand_l, hand_r, foot_l, foot_r } -> [point, ...]. */
22
+ function effectorPoints(sk, s) {
23
+ const I = sk.index, out = {};
24
+ for (const [S, k] of [["Left", "l"], ["Right", "r"]]) {
25
+ const palm = scale(add(s.P[I[`${S}Hand`]], s.P[I[`${S}HandMiddle1`]]), 0.5);
26
+ out[`hand_${k}`] = [palm, ...TIPS.map(t => s.P[I[`${S}Hand${t}`]]).filter(Boolean)];
27
+ out[`foot_${k}`] = Object.values(solePoints(sk, s, S));
28
+ }
29
+ return out;
30
+ }
31
+
32
+ /** True while a spec.objects entry over body `id` (its own or a group's) hides it at absolute frame f. */
33
+ const hiddenAt = (out, id, f) => [id, ...(out.ctx.scene.objects[id].ancestors ?? [])]
34
+ .some(k => { const o = out.ctx.spec.objects?.[k]; return o?.visible && !((out.baked?.[o.visible]?.[f] ?? 0) > 0.5); });
35
+
36
+ /** The scene bodies at absolute frame f as boxes with their top group, the hand carrying them and a bounding sphere; follow records left out. */
37
+ function boxesAt(out, f) {
38
+ const { scene, spec } = out.ctx, boxes = [];
39
+ for (const [id, o] of Object.entries(scene?.objects ?? {})) {
40
+ const up = o.ancestors ?? [];
41
+ if ([id, ...up].some(k => isFollow(spec.objects?.[k])) || hiddenAt(out, id, f)) continue;
42
+ const pose = objectPoseAt(out, id, f);
43
+ if (!pose) continue;
44
+ const box = { pos: pose.pos, R: pose.R, half: o.half };
45
+ boxes.push({ id, root: up[up.length - 1] ?? id, hand: handOf(out, id, f), box, c: add(box.pos, apply(box.R, [0, o.half[1], 0])), r: len(o.half) });
46
+ }
47
+ return boxes;
48
+ }
49
+
50
+ /** Nearest box to a point set: [root, part, gap] within FAR, else null; the boxes hand `side` carries are left out. */
51
+ function nearest(points, boxes, side) {
52
+ const c = scale(points.reduce((a, p) => add(a, p), [0, 0, 0]), 1 / points.length), spread = Math.max(...points.map(p => dist(p, c)));
53
+ let best = null;
54
+ for (const b of boxes) {
55
+ if (side && b.hand === side) continue;
56
+ if (dist(c, b.c) - b.r - spread > (best ? best[2] : FAR)) continue;
57
+ const gap = Math.min(...points.map(p => sdBox(p, b.box)));
58
+ if (gap <= FAR && (!best || gap < best[2])) best = [b.root, b.id, gap];
59
+ }
60
+ return best;
61
+ }
62
+
63
+ /** Runs of frames with the same nearest object -> the RUNS closest, in frame order. */
64
+ function runsOf(rows, f0) {
65
+ const runs = [];
66
+ rows.forEach((row, i) => {
67
+ const last = runs[runs.length - 1];
68
+ if (!row) return;
69
+ const [root, part, gap] = row, f = i + f0;
70
+ if (last && last.object === root && last.frames[1] === f - 1) {
71
+ last.frames[1] = f;
72
+ if (gap < last.gap[0]) { last.gap[0] = gap; last.gap[1] = f; last.part = part; }
73
+ if (gap > last.gap[2]) { last.gap[2] = gap; last.gap[3] = f; }
74
+ } else runs.push({ object: root, part, frames: [f, f], gap: [gap, f, gap, f] });
75
+ });
76
+ return runs.sort((a, b) => a.gap[0] - b.gap[0]).slice(0, RUNS).sort((a, b) => a.frames[0] - b.frames[0])
77
+ .map(({ object, part, frames, gap }) => ({ object, ...(part !== object ? { part } : {}), frames, gap: [r3(gap[0]), gap[1], r3(gap[2]), gap[3]] }));
78
+ }
79
+
80
+ /**
81
+ * observeNear(sk, out) -> { hand_l?, hand_r?, foot_l?, foot_r? } (null when nothing is within FAR m
82
+ * of any of them, or the scene has no bodies). Frames are absolute (out.f0 added).
83
+ */
84
+ export function observeNear(sk, out) {
85
+ if (!Object.keys(out.ctx.scene?.objects ?? {}).length) return null;
86
+ const f0 = out.f0 ?? 0, rows = { hand_l: [], hand_r: [], foot_l: [], foot_r: [] };
87
+ out.frames.forEach(({ s }, i) => {
88
+ const f = i + f0, boxes = boxesAt(out, f), pts = effectorPoints(sk, s);
89
+ for (const k of Object.keys(rows)) {
90
+ // a hand is on what it carries: measure it against everything else
91
+ rows[k].push(nearest(pts[k], boxes, k.startsWith("hand_") ? k.slice(-1) : null));
92
+ }
93
+ });
94
+ const near = Object.fromEntries(Object.entries(rows).map(([k, r]) => [k, runsOf(r, f0)]).filter(([, r]) => r.length));
95
+ return Object.keys(near).length ? near : null;
96
+ }
@@ -0,0 +1,135 @@
1
+ // QA of scene objects the spec carries (C3 and 7.1), as plain issues { kind, msg, frame, value,
2
+ // limit } (frame indexes out.frames):
3
+ // GRAB "<id>: hand 12.0 cm from it at grab", frame = grab, limit = checks.limits.grab
4
+ // (default 0.03 m); the distance runs from the prop origin to the part boxes' surface
5
+ // at their scene pose (where the hand finds them). An object its visible channel shows
6
+ // only from grab on appears in the hand (a cigarette out of a pocket), and one grabbed
7
+ // at frame 0 is in hand from the take's first frame (C3, as with no grab): nothing to
8
+ // pick up (session d5c110a7: a bat kit left on the floor, grab 0, "63.6 cm").
9
+ // COLLIDE "<part> x <id>": a body capsule in a carried object (every part box of a group) at
10
+ // any frame it is shown, the holding hand and forearm excused (the fingers ride on the
11
+ // hand), and a second hand on the frames it grips the object (../second-hand.js): at
12
+ // weight 0.5 or more, or with its palm inside the object (a grip the arm turns only
13
+ // partly still holds the handle: session 6262a69c, f37-40, the agent allowed it);
14
+ // "<id> x <other>": a carried object in another scene box from grab on, the
15
+ // support it stood on at grab excused for +-3 frames around grab and release. The
16
+ // depths and checks.allow work as for the body (checks.js); <id> is the spec.objects
17
+ // key, so a group reads as one object.
18
+ // REACH "<id>: 6.2 cm off its keys": a keyed object the hand could not hold where its keys ask (key-checks.js)
19
+ import { QA_LIMITS, allowance } from "./checks.js";
20
+ import { keyIssues } from "./key-checks.js";
21
+ import { CAPSULES, segPoints, sdBox } from "./geometry.js";
22
+ import { isCarried, propOrigin } from "../carried.js";
23
+ import { objectBoxesAt, partsOf, spanOf, restingAt } from "../object-pose.js";
24
+ import { add, sub, apply, dot, cross, len, dist, scale, norm } from "../compiler/math.js";
25
+
26
+ const NEAR_SUPPORT = 3;
27
+
28
+ const centre = b => add(b.pos, apply(b.R, [0, b.half[1], 0]));
29
+ const col = (R, i) => [R[0][i], R[1][i], R[2][i]];
30
+
31
+ /**
32
+ * Overlap of two boxes (separating axes): { depth, axis } with depth > 0 when they overlap and
33
+ * axis the unit direction that moves `a` out of `b` by depth; depth <= 0 when apart. With
34
+ * `side` (a direction from b toward where a came from) the exit is taken on that side.
35
+ */
36
+ export function boxOverlap(a, b, side = null) {
37
+ const ca = centre(a), cb = centre(b), d = sub(ca, cb), A = [0, 1, 2].map(i => col(a.R, i)), B = [0, 1, 2].map(i => col(b.R, i));
38
+ const axes = [...A, ...B, ...A.flatMap(u => B.map(v => cross(u, v)))];
39
+ let best = { depth: Infinity, axis: [0, 1, 0] };
40
+ for (const raw of axes) {
41
+ if (len(raw) < 1e-6) continue;
42
+ const L = norm(raw), r = (box, U) => U.reduce((s, u, i) => s + Math.abs(dot(u, L)) * box.half[i], 0), reach = r(a, A) + r(b, B);
43
+ if (reach - Math.abs(dot(d, L)) <= 0) return { depth: reach - Math.abs(dot(d, L)), axis: L };
44
+ const out = dot(side ?? d, L) < 0 ? scale(L, -1) : L, depth = reach - dot(d, out);
45
+ if (depth < best.depth) best = { depth, axis: out };
46
+ }
47
+ return best;
48
+ }
49
+
50
+ /** True when the palm of hand k (between its index and middle finger, where a grip holds) is inside one of `boxes`: the hand holds the object there. */
51
+ const palmIn = (sk, s, k, boxes) => {
52
+ const S = k === "l" ? "Left" : "Right", p = scale(add(s.P[sk.index[`${S}HandIndex2`]], s.P[sk.index[`${S}HandMiddle2`]]), 0.5);
53
+ return boxes.some(b => sdBox(p, b) <= 0);
54
+ };
55
+
56
+ /** True while entry o's record is shown (its `visible` channel above 0.5, or no channel) at absolute f. */
57
+ const shownAt = (out, o, f) => !o.visible || (out.baked?.[o.visible]?.[f] ?? 0) > 0.5;
58
+
59
+ /** The part boxes of `id` where the hand finds it (any frame f, the hint asks later ones too): its scene pose, or where a fall before its grab left it (C17). */
60
+ const restingBoxes = (out, id, f) => partsOf(out.ctx.scene, id).map(part => ({ ...out.ctx.scene.objects[part], ...restingAt(out, part, f) }));
61
+
62
+ /** Prop origin to the nearest part box surface of `id` where it rests before grab, at absolute frame f (0 inside). */
63
+ export function grabGap(out, id, f) {
64
+ const { sk, spec } = out.ctx, fr = out.frames[f - (out.f0 ?? 0)];
65
+ if (!fr) return null;
66
+ const p = propOrigin(sk, spec, fr.s, spec.objects[id]);
67
+ return Math.max(0, Math.min(...restingBoxes(out, id, f).map(box => sdBox(p, box))));
68
+ }
69
+
70
+ /** The scene box right below `id` at grab (absolute frame), the support it may touch near grab and release. */
71
+ function supportOf(out, id, grab) {
72
+ const parts = restingBoxes(out, id, grab);
73
+ if (!parts.length) return null;
74
+ const low = Math.min(...parts.map(b => b.pos[1] - Math.abs(b.R[1][0]) * b.half[0] - Math.abs(b.R[1][2]) * b.half[2]));
75
+ const c = scale(parts.map(centre).reduce((s, p) => add(s, p), [0, 0, 0]), 1 / parts.length), probe = [c[0], low - 0.01, c[2]];
76
+ let best = null;
77
+ for (const [oid, box] of Object.entries(out.ctx.objectsAt(grab))) {
78
+ if (box.carried || !box.half) continue;
79
+ const d = sdBox(probe, box);
80
+ if (d <= 0.02 && (!best || d < best[1])) best = [oid, d];
81
+ }
82
+ return best?.[0] ?? null;
83
+ }
84
+
85
+ /**
86
+ * objectChecks(sk, out, spec) -> issues
87
+ * @param {object} sk the rig
88
+ * @param {object} out compileMotion result (out.ctx.spec, out.ctx.scene; object-pose.js)
89
+ * @param {object} spec the expanded spec QA measures (checks, objects)
90
+ * @returns {{ kind: string, msg: string, frame: number, value: number, limit: number }[]}
91
+ */
92
+ export function objectChecks(sk, out, spec) {
93
+ const carried = Object.entries(out.ctx.spec.objects ?? {}).filter(([, o]) => isCarried(o));
94
+ if (!carried.length) return [];
95
+ const checks = spec.checks ?? {}, L = { ...QA_LIMITS, ...checks.limits }, allow = checks.allow, issues = [], f0 = out.f0 ?? 0, I = sk.index;
96
+ const push = (kind, msg, f, value, limit) => issues.push({ kind, msg, frame: f, value: +value.toFixed(4), limit });
97
+ // checks.allow names the carried id or one of its parts, on either side
98
+ const lim = (parts, objs) => parts.reduce((v, p) => objs.reduce((w, x) => w ?? allowance(allow, p, x), v), null) ?? L.allow;
99
+ for (const [id, o] of carried) {
100
+ const [grab, release] = spanOf(out, o), k = spec.props?.[o.prop]?.hand, excused = new Set([`hand_${k}`, `farm_${k}`]);
101
+ if (o.grab !== undefined && grab > 0 && out.frames[grab - f0] && shownAt(out, o, grab - 1)) {
102
+ const gap = grabGap(out, id, grab);
103
+ if (gap > L.grab) push("GRAB", `${id}: hand ${(gap * 100).toFixed(1)} cm from it at grab`, grab - f0, gap, L.grab);
104
+ }
105
+ const support = o.grab !== undefined ? supportOf(out, id, grab) : null;
106
+ const nearSupport = f => Math.abs(f - grab) <= NEAR_SUPPORT || (o.release !== undefined && Math.abs(f - release) <= NEAR_SUPPORT);
107
+ for (let i = 0; i < out.frames.length; i++) {
108
+ const f = i + f0, boxes = objectBoxesAt(out, id, f);
109
+ if (!boxes || !shownAt(out, o, f)) continue;
110
+ const ids = boxes.map(b => b.id), spheres = boxes.map(b => [b, centre(b), len(b.half)]), { s } = out.frames[i];
111
+ const grips = Object.entries(out.frames[i].diag).filter(([k, v]) => /^hold_[lr]$/.test(k) && v?.second === id && (v.w >= 0.5 || palmIn(sk, s, k.slice(-1), boxes))).map(([k]) => `hand_${k.slice(-1)}`);
112
+ for (const [part, a, b, r] of CAPSULES) {
113
+ if (excused.has(part) || grips.includes(part)) continue;
114
+ const A = s.P[I[a]], B = s.P[I[b]], mid = scale(add(A, B), 0.5), reach = r + dist(A, B) / 2, l = lim([part], [id, ...ids]);
115
+ let pts = null, pen = -Infinity;
116
+ for (const [box, c, rb] of spheres) {
117
+ if (reach - (dist(mid, c) - rb) <= l) continue;
118
+ pts ??= segPoints(A, B);
119
+ pen = Math.max(pen, r - Math.min(...pts.map(p => sdBox(p, box))));
120
+ }
121
+ if (pen > l) push("COLLIDE", `${part} x ${id}`, i, pen, l);
122
+ }
123
+ if (f < grab) continue;
124
+ for (const [oid, ob] of Object.entries(out.objectsAt(i))) {
125
+ if (!ob.half || ob.ignore || (oid === support && nearSupport(f))) continue;
126
+ const l = lim([id, ...ids], [oid]), oc = centre(ob), orad = len(ob.half);
127
+ let depth = -Infinity;
128
+ for (const [box, c, rb] of spheres) if (dist(c, oc) < rb + orad + l) depth = Math.max(depth, boxOverlap(box, ob).depth);
129
+ if (depth > l) push("COLLIDE", `${id} x ${oid}`, i, depth, l);
130
+ }
131
+ }
132
+ }
133
+ keyIssues(out, L, push);
134
+ return issues;
135
+ }
@@ -0,0 +1,161 @@
1
+ // C6. Hint fixes -> JSON Patch (RFC 6902, json-patch.js) on the agent's own spec.
2
+ //
3
+ // A hint function may return fix (non-enumerable on the group, never in the output):
4
+ // { channel: "hand_l", f: 106, delta: [dx, dy, dz] | n } move a keyed channel by delta at f
5
+ // { channel: "elbow_r", f: 120, value: [x, y, z] | n } set a channel at f
6
+ // { path: "/fix/retime", value: true } set a spec path
7
+ // { path: "/anchors/cupHandle/p", delta: [dx, dy, dz] } move a spec value by delta
8
+ // { channel: "root", f, delta, hold: true } move the body that stands at f
9
+ // Each becomes g.patch = [{ op, path, value }] against opts.userSpec (the spec as the agent sent
10
+ // it, use[] not expanded): a user key that sets the channel within f +-2 -> replace
11
+ // /keys/<i>/set/<ch>; a standIdle stance moved sideways -> /use/<i>/args/at; otherwise add
12
+ // /keys/- with the frame's value moved. A path fix replaces the value, or adds it when only the
13
+ // last step is missing (or the top-level /fix object). A hold fix moves what placed the body
14
+ // at f by the delta's x and z: a standIdle args.at, a walkTo's length (firstStep with 2 steps,
15
+ // else step; its to when steps follow from it), or the run of the agent's root keys around f.
16
+ // g.patch is set only when the patch applies to userSpec and changes it.
17
+ import { applyPatch } from "../json-patch.js";
18
+
19
+ const NEAR = 2;
20
+ const round4 = v => (Array.isArray(v) ? v.map(round4) : typeof v === "number" ? Math.round(v * 1e4) / 1e4 : v);
21
+ const tokens = path => path.split("/").slice(1).map(t => t.replaceAll("~1", "/").replaceAll("~0", "~"));
22
+ const pointer = parts => parts.map(t => `/${String(t).replaceAll("~", "~0").replaceAll("/", "~1")}`).join("");
23
+ const isNum = x => typeof x === "number" && Number.isFinite(x);
24
+
25
+ /** The value at a JSON pointer, or undefined. */
26
+ function valueAt(doc, parts) {
27
+ let node = doc;
28
+ for (const t of parts) {
29
+ if (node === null || typeof node !== "object" || !Object.hasOwn(node, t)) return undefined;
30
+ node = node[t];
31
+ }
32
+ return node;
33
+ }
34
+
35
+ /** v moved by d (same shape: a number, or a vector of numbers), else undefined. */
36
+ function moved(v, d) {
37
+ if (isNum(v) && isNum(d)) return v + d;
38
+ if (Array.isArray(v) && Array.isArray(d) && v.length === d.length && v.every(isNum) && d.every(isNum)) return v.map((x, i) => x + d[i]);
39
+ return undefined;
40
+ }
41
+
42
+ /** The user key nearest f (within NEAR frames) that sets channel ch, as its index; -1 if none. */
43
+ function userKey(userSpec, ch, f) {
44
+ let best = -1;
45
+ (userSpec.keys ?? []).forEach((k, i) => {
46
+ if (!k?.set || !Object.hasOwn(k.set, ch) || !isNum(k.f) || Math.abs(k.f - f) > NEAR) return;
47
+ if (best < 0 || Math.abs(k.f - f) < Math.abs(userSpec.keys[best].f - f)) best = i;
48
+ });
49
+ return best;
50
+ }
51
+
52
+ /** A standIdle stance moved by the root's sideways delta: /use/<i>/args/at. */
53
+ function standPatch(X, userSpec, fix, near) {
54
+ const m = /^use\[(\d+)\] standIdle$/.exec(near?.src ?? ""), d = fix.delta;
55
+ if (!m || fix.channel !== "root" || !Array.isArray(d) || Math.hypot(d[0], d[2]) < Math.abs(d[1])) return null;
56
+ const i = Number(m[1]), u = userSpec.use?.[i], root = X.fr(near.f).c.root;
57
+ if (u?.skill !== "standIdle") return null;
58
+ const at = Array.isArray(u.args?.at) ? u.args.at : root && [root[0], root[2]];
59
+ if (!at) return null;
60
+ const value = round4(at.map((v, j) => v + (j === 0 ? d[0] : j === at.length - 1 ? d[2] : 0)));
61
+ if (!u.args) return [{ op: "add", path: `/use/${i}/args`, value: { at: value } }];
62
+ return [{ op: Object.hasOwn(u.args, "at") ? "replace" : "add", path: `/use/${i}/args/at`, value }];
63
+ }
64
+
65
+ /** A walkTo made longer or shorter by the delta along the body's heading at f (null when it is mostly sideways). */
66
+ function walkPatch(X, userSpec, i, fix) {
67
+ const u = userSpec.use?.[i], a = u?.args ?? {}, d = fix.delta, h = (X.fr(fix.f).c.yaw ?? 0) * Math.PI / 180;
68
+ const along = d[0] * Math.sin(h) + d[2] * Math.cos(h);
69
+ if (u?.skill !== "walkTo" || Math.abs(d[0] * Math.cos(h) - d[2] * Math.sin(h)) > Math.abs(along)) return null;
70
+ const set = (arg, value) => [u.args ? { op: Object.hasOwn(a, arg) ? "replace" : "add", path: `/use/${i}/args/${arg}`, value: round4(value) } : { op: "add", path: `/use/${i}/args`, value: { [arg]: round4(value) } }];
71
+ if (a.steps === undefined && Array.isArray(a.to)) return set("to", a.to.map((v, j) => v + (j === 0 ? d[0] : j === a.to.length - 1 ? d[2] : 0)));
72
+ const steps = a.steps ?? 8, arg = steps <= 2 ? "firstStep" : "step", now = a[arg] ?? (arg === "step" ? 0.5 : 0.4), value = now + along / Math.max(1, steps - 2);
73
+ return steps >= 2 && value > 0.05 ? set(arg, value) : null;
74
+ }
75
+
76
+ /** The agent's root keys around f (no skill root key between them) moved by the delta's x and z. */
77
+ function rootRunPatch(X, userSpec, fix) {
78
+ const list = X.keys("root"), mine = k => /^keys\[\d+\]$/.test(k.src);
79
+ const at = list.findLastIndex(k => k.f <= fix.f);
80
+ if (at < 0 || !mine(list[at])) return null;
81
+ let a = at, b = at;
82
+ while (a > 0 && mine(list[a - 1])) a -= 1;
83
+ while (b < list.length - 1 && mine(list[b + 1])) b += 1;
84
+ return list.slice(a, b + 1).map(k => {
85
+ const j = Number(/\d+/.exec(k.src)[0]), r = userSpec.keys?.[j]?.set?.root;
86
+ return Array.isArray(r) && r.length === 3 ? { op: "replace", path: `/keys/${j}/set/root`, value: round4([r[0] + fix.delta[0], r[1], r[2] + fix.delta[2]]) } : null;
87
+ }).filter(Boolean);
88
+ }
89
+
90
+ /** fix.hold: what placed the body at f (the root key at or before it) moves. */
91
+ function bodyPatch(X, userSpec, fix) {
92
+ if (!Array.isArray(fix.delta) || !X?.fr) return null;
93
+ const prev = X.bracket("root", fix.f).prev, m = /^use\[(\d+)\] (standIdle|walkTo)\b/.exec(prev?.src ?? "");
94
+ if (m?.[2] === "standIdle") return standPatch(X, userSpec, fix, prev);
95
+ if (m?.[2] === "walkTo") return walkPatch(X, userSpec, Number(m[1]), fix);
96
+ const run = prev && rootRunPatch(X, userSpec, fix);
97
+ return run?.length ? run : null;
98
+ }
99
+
100
+ function channelPatch(X, userSpec, fix) {
101
+ const { channel: ch, f } = fix;
102
+ if (typeof ch !== "string" || !isNum(f)) return null;
103
+ if (fix.hold) return bodyPatch(X, userSpec, fix);
104
+ const to = v => (fix.value !== undefined ? fix.value : moved(v, fix.delta));
105
+ const i = userKey(userSpec, ch, f);
106
+ if (i >= 0) {
107
+ const value = to(userSpec.keys[i].set[ch]);
108
+ return value === undefined ? null : [{ op: "replace", path: pointer(["keys", i, "set", ch]), value: round4(value) }];
109
+ }
110
+ if (!X?.fr) return null;
111
+ const { prev, next } = X.bracket(ch, f);
112
+ const near = prev && f - prev.f <= NEAR ? prev : next && next.f - f <= NEAR ? next : null;
113
+ const stand = fix.delta !== undefined && standPatch(X, userSpec, fix, near);
114
+ if (stand) return stand;
115
+ const value = to(X.fr(f).c[ch]);
116
+ return value === undefined ? null : [{ op: "add", path: "/keys/-", value: { f: Math.round(f), set: { [ch]: round4(value) } } }];
117
+ }
118
+
119
+ function pathPatch(userSpec, fix) {
120
+ if (typeof fix.path !== "string" || !fix.path.startsWith("/")) return null;
121
+ const parts = tokens(fix.path), now = valueAt(userSpec, parts);
122
+ const value = fix.delta === undefined ? fix.value : now === undefined && fix.path.endsWith("/offset") ? fix.delta : moved(now, fix.delta);
123
+ if (value === undefined) return null;
124
+ if (now !== undefined) return [{ op: "replace", path: fix.path, value: round4(value) }];
125
+ const parent = valueAt(userSpec, parts.slice(0, -1));
126
+ if (parent !== undefined) return [{ op: "add", path: fix.path, value: round4(value) }];
127
+ // a missing top-level object (spec.fix): add it with the one member
128
+ if (parts.length === 2 && parts[0] === "fix") return [{ op: "add", path: pointer([parts[0]]), value: { [parts[1]]: round4(value) } }];
129
+ return null;
130
+ }
131
+
132
+ /** The patch for one fix, or null when it does not apply mechanically or changes nothing. */
133
+ function patchOf(fix, X, userSpec) {
134
+ const patch = fix.channel !== undefined ? channelPatch(X, userSpec, fix) : fix.path !== undefined ? pathPatch(userSpec, fix) : null;
135
+ if (!patch) return null;
136
+ try {
137
+ return JSON.stringify(applyPatch(userSpec, patch)) === JSON.stringify(userSpec) ? null : patch;
138
+ } catch {
139
+ return null;
140
+ }
141
+ }
142
+
143
+ /**
144
+ * attachPatches(groups, { X, userSpec }) -> groups (the same array)
145
+ * @param {object[]} groups ranked QA groups, each maybe with a non-enumerable g.fix
146
+ * @param {{ X: object, userSpec?: object }} ctx X = the explain context (qa/explain.js: X.out,
147
+ * X.spec the expanded spec, X.keys(ch), X.bracket(ch, f)); userSpec undefined = no patches
148
+ */
149
+ export function attachPatches(groups, { X, userSpec } = {}) {
150
+ if (!userSpec || typeof userSpec !== "object") return groups;
151
+ for (const g of groups) {
152
+ if (!g.fix) continue;
153
+ try {
154
+ const patch = patchOf(g.fix, X, userSpec);
155
+ if (patch) g.patch = patch;
156
+ } catch {
157
+ // a fix the context cannot place (no frame, no key table) gets no patch
158
+ }
159
+ }
160
+ return groups;
161
+ }
@@ -0,0 +1,38 @@
1
+ // C6. How bad a QA issue group is, one formula for the agent (qa.groups order and severity),
2
+ // the open-parameter search (search.js cost) and repair (repair.js): the issue count weighted by
3
+ // how far the worst issue is past its limit, at most 4x. See docs/motion-api-v3.1.md.
4
+
5
+ /** Kinds whose value must stay ABOVE the limit (a cosine, a drop, a clearance). */
6
+ export const LOW_IS_BAD = new Set(["ORIENT", "BELOW", "CLEARANCE"]);
7
+
8
+ /** How far the worst issue of group g is past its limit (>= 0, in the kind's unit). */
9
+ export const excessOf = g => Math.max(0, LOW_IS_BAD.has(g.kind) ? g.limit - g.worst : g.worst - g.limit);
10
+
11
+ /** Unrounded severity; search.js sums these as its cost. */
12
+ export const weightOf = g => g.count * (1 + Math.min(3, excessOf(g) / Math.max(Math.abs(g.limit), 0.01)));
13
+
14
+ /** Severity of group g, rounded to 2 decimals. */
15
+ export const severityOf = g => Math.round(weightOf(g) * 100) / 100;
16
+
17
+ /** A measurement in a subject: a free-standing number ("12.0 cm", "120deg", "-0.30") or a frame ("f150"). */
18
+ const MEASURE = /(?<![\w\-.[])[-+]?\d+(\.\d+)?|\bf\d+\b/g;
19
+
20
+ /**
21
+ * The grouping key of an issue (kind + subject): every measurement in the subject becomes "#",
22
+ * so one problem at many frames and depths is one group. Digits that are part of a name stay:
23
+ * an id ("cube-6", "empty-2"), a bone ("LeftHandIndex3"), a bracketed index ("contacts[1]", a
24
+ * default check name, qa/check-names.js) and the whole "<name>: " prefix of a named check or goal.
25
+ */
26
+ export const groupKey = g => {
27
+ const cut = g.subject.indexOf(": "), head = cut >= 0 ? g.subject.slice(0, cut + 2) : "";
28
+ return `${g.kind} ${head}${g.subject.slice(head.length).replace(MEASURE, m => (m[0] === "f" ? "f#" : "#"))}`;
29
+ };
30
+
31
+ /**
32
+ * Adds excess (4 decimals) and severity to every group and returns them ordered: GOAL groups
33
+ * first, then severity, then count, both descending (ties keep their order).
34
+ */
35
+ export function rankGroups(groups) {
36
+ for (const g of groups) { g.excess = Math.round(excessOf(g) * 1e4) / 1e4; g.severity = severityOf(g); }
37
+ return groups.sort((a, b) => (b.kind === "GOAL") - (a.kind === "GOAL") || b.severity - a.severity || b.count - a.count);
38
+ }
@@ -0,0 +1,65 @@
1
+ // Task checks the agent declares in spec.checks (balance is style: style.js).
2
+ // contacts: [{ name, point, target, tol, when }] point on target (e.g. filter on lips)
3
+ // orient: [{ name, from, to, along, minCos, when }] direction from->to against "face" | "up" | [x,y,z]
4
+ // below: [{ name, joint, ref, min, when }] joint at least `min` m below ref (no chicken wing)
5
+ // clearance: [{ name, part, object, min, frames }] body part keeps `min` m from an object
6
+ // appear: [{ name, channel, joint, anchor, tol }] a visibility switch happens with joint at anchor
7
+ // supports: [{ object, part, tol }] frames where `part` rests on `object` skip balance (style.js)
8
+ // point/from/to: "joint:Name" | "prop:name.point" | "anchor:name"; when: weight channel (> 0.99) or [f0, f1].
9
+ // f below indexes out.frames (frame out.f0 + f when the compile was windowed).
10
+ import { sub, dot, norm, len } from "../compiler/math.js";
11
+ import { carried } from "../compiler/limbs.js";
12
+ import { resolveAnchor } from "../compiler/anchors.js";
13
+ import { CAPSULES, segPoints, sdBox } from "./geometry.js";
14
+
15
+ export function pointOf(out, f, ref) {
16
+ const { s, diag, c } = out.frames[f], [kind, rest] = ref.split(/:(.*)/s);
17
+ if (kind === "joint") return s.P[out.ctx.sk.index[rest]];
18
+ if (kind === "prop") { const [p, pt] = rest.split("."); return diag.props?.[p]?.[pt] ?? null; }
19
+ if (kind === "anchor") return resolveAnchor(out.ctx, rest, s, diag, c);
20
+ throw new Error(`MOTION_SPEC_INVALID: check point "${ref}"`);
21
+ }
22
+
23
+ const active = (out, f, when) => (Array.isArray(when) ? f + (out.f0 ?? 0) >= when[0] && f + (out.f0 ?? 0) <= when[1] : when ? (out.frames[f].c[when] ?? 0) > 0.99 : true);
24
+
25
+ function alongDir(out, f, along) {
26
+ if (along === "up") return [0, 1, 0];
27
+ if (along === "face") return carried(out.ctx.sk, out.frames[f].s, out.ctx.sk.index.Head, [0, 0, 1]);
28
+ return norm(along);
29
+ }
30
+
31
+ export function specChecks(out, checks = {}) {
32
+ const issues = [], n = out.frames.length, sk = out.ctx.sk, I = sk.index;
33
+ const push = (kind, msg, f, value, limit) => issues.push({ kind, msg, frame: f, value: +value.toFixed(4), limit });
34
+ for (let f = 0; f < n; f++) {
35
+ for (const k of checks.contacts ?? []) if (active(out, f, k.when)) {
36
+ const a = pointOf(out, f, k.point), b = pointOf(out, f, k.target);
37
+ if (!a || !b) continue;
38
+ const e = len(sub(a, b));
39
+ if (e > (k.tol ?? 0.01)) push("CONTACT", `${k.name}: ${(e * 100).toFixed(1)} cm apart`, f, e, k.tol ?? 0.01);
40
+ }
41
+ for (const k of checks.orient ?? []) if (active(out, f, k.when)) {
42
+ const a = pointOf(out, f, k.from), b = pointOf(out, f, k.to);
43
+ if (!a || !b) continue;
44
+ const cosv = dot(norm(sub(b, a)), alongDir(out, f, k.along));
45
+ if (cosv < (k.minCos ?? 0.64)) push("ORIENT", `${k.name}: cos ${cosv.toFixed(2)}`, f, cosv, k.minCos ?? 0.64);
46
+ }
47
+ for (const k of checks.below ?? []) if (active(out, f, k.when)) {
48
+ const { P } = out.frames[f].s, drop = P[I[k.ref]][1] - P[I[k.joint]][1];
49
+ if (drop < (k.min ?? 0.08)) push("BELOW", `${k.name}: ${k.joint} only ${(drop * 100).toFixed(1)} cm below ${k.ref}`, f, drop, k.min ?? 0.08);
50
+ }
51
+ for (const k of checks.clearance ?? []) if (active(out, f, k.frames)) {
52
+ const box = out.objectsAt(f)[k.object], cap = CAPSULES.find(c => c[0] === k.part);
53
+ if (!box || !cap) continue;
54
+ const { P } = out.frames[f].s, d = Math.min(...segPoints(P[I[cap[1]]], P[I[cap[2]]]).map(p => sdBox(p, box))) - cap[3];
55
+ if (d < k.min) push("CLEARANCE", `${k.name}: ${(d * 100).toFixed(1)} cm`, f, d, k.min);
56
+ }
57
+ }
58
+ for (const k of checks.appear ?? []) for (let f = 1; f < n; f++) {
59
+ const was = (out.frames[f - 1].c[k.channel] ?? 0) > 0.5, is = (out.frames[f].c[k.channel] ?? 0) > 0.5;
60
+ if (was === is) continue;
61
+ const e = len(sub(pointOf(out, f, `joint:${k.joint}`), pointOf(out, f, `anchor:${k.anchor}`)));
62
+ if (e > (k.tol ?? 0.035)) push("APPEAR", `${k.name}: switches with the hand ${(e * 100).toFixed(1)} cm from ${k.anchor}`, f, e, k.tol ?? 0.035);
63
+ }
64
+ return issues;
65
+ }