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
@@ -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
+ }