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,77 @@
1
+ // Collision proxies for motion QA: body capsules on Mixamo joints, scene objects as oriented
2
+ // boxes (base pivot = bottom centre, CozyClay convention), the head as the measured ellipsoid.
3
+ import { add, sub, scale, dot, len, apply, T, clamp } from "../compiler/math.js";
4
+ import { bonePoint } from "../compiler/skeleton.js";
5
+
6
+ // [part, from joint, to joint, radius m]. Radii are fitted to the X/Y Bot skin.
7
+ export const CAPSULES = [
8
+ ["torso_lo", "Spine", "Spine2", 0.12], ["torso_hi", "Spine2", "Neck", 0.105], ["hips", "LeftUpLeg", "RightUpLeg", 0.095],
9
+ ["neck", "Neck", "Head", 0.055],
10
+ ...["Left", "Right"].flatMap(S => {
11
+ const k = S === "Left" ? "l" : "r";
12
+ return [[`thigh_${k}`, `${S}UpLeg`, `${S}Leg`, 0.07], [`shin_${k}`, `${S}Leg`, `${S}Foot`, 0.05],
13
+ [`uarm_${k}`, `${S}Arm`, `${S}ForeArm`, 0.042], [`farm_${k}`, `${S}ForeArm`, `${S}Hand`, 0.033],
14
+ [`hand_${k}`, `${S}Hand`, `${S}HandMiddle3`, 0.022]];
15
+ }),
16
+ ];
17
+
18
+ export const segPoints = (a, b, n = 9) => Array.from({ length: n }, (_, i) => add(a, scale(sub(b, a), i / (n - 1))));
19
+
20
+ /** Signed distance from p to a box (negative inside). */
21
+ export function sdBox(p, box) {
22
+ const q = apply(T(box.R), sub(p, box.pos));
23
+ const c = [0, box.half[1], 0];
24
+ const d = [Math.abs(q[0] - c[0]) - box.half[0], Math.abs(q[1] - c[1]) - box.half[1], Math.abs(q[2] - c[2]) - box.half[2]];
25
+ const outside = len([Math.max(d[0], 0), Math.max(d[1], 0), Math.max(d[2], 0)]);
26
+ return outside + Math.min(Math.max(d[0], d[1], d[2]), 0);
27
+ }
28
+
29
+ export function segDist(p1, q1, p2, q2) {
30
+ let best = Infinity;
31
+ const d2 = sub(q2, p2), dd = dot(d2, d2);
32
+ for (const a of segPoints(p1, q1)) {
33
+ const u = dd < 1e-12 ? 0 : clamp(dot(sub(a, p2), d2) / dd, 0, 1);
34
+ best = Math.min(best, len(sub(a, add(p2, scale(d2, u)))));
35
+ }
36
+ return best;
37
+ }
38
+
39
+ /** Depth (m) of point p inside the head ellipsoid, negative when outside. */
40
+ export function headDepth(sk, s, p) {
41
+ const c = bonePoint(s, sk.index.Head, sk.landmarks.headCentre), R = s.R[sk.index.Head];
42
+ const q = apply(T(R), sub(p, c)), r = sk.landmarks.headRadii;
43
+ const v = len([q[0] / r[0], q[1] / r[1], q[2] / r[2]]);
44
+ return (1 - v) * Math.min(...r);
45
+ }
46
+
47
+ /** The rig's standing ankle height (m): where foot_* stands a flat foot on the floor (X Bot 0.087, Y Bot 0.105). */
48
+ export const ankleY = sk => Math.round(sk.restWorldPos[sk.index.LeftFoot][1] * 1000) / 1000;
49
+
50
+ /** A point `drop` m straight below bone b's joint at bind, carried by b (the joint itself when 0). */
51
+ const below = (sk, s, b, drop) => (drop ? bonePoint(s, b, apply(T(sk.restWorldRot[b]), [0, -drop, 0])) : s.P[b]);
52
+
53
+ /**
54
+ * Sole points carried by a foot, on the skin's sole (the surface verify_result's floor measure
55
+ * reads): heel 4.5 cm behind and 0.5 cm above the bottom of the ankle at bind; ball under the
56
+ * ToeBase joint at the toe pad; tip at the front edge. The rig's sole landmark says how far the
57
+ * skin lies below the joints (X Bot: on the ball joint; Y Bot: 3.3 cm under it).
58
+ */
59
+ export function solePoints(sk, s, side) {
60
+ const I = sk.index, P = sk.restWorldPos, drop = sk.landmarks.sole ?? {};
61
+ const foot = I[`${side}Foot`], toe = I[`${side}ToeBase`], toeEnd = I[`${side}Toe_End`] ?? toe;
62
+ const heelRest = [P[foot][0], 0.005, P[foot][2] - 0.045];
63
+ const heelLocal = apply(T(sk.restWorldRot[foot]), sub(heelRest, P[foot]));
64
+ return { heel: bonePoint(s, foot, heelLocal), ball: below(sk, s, toe, drop.ball), tip: below(sk, s, toeEnd, drop.tip) };
65
+ }
66
+
67
+ /** Outward unit normal of a box at p (the nearest face from inside, the closest direction from outside). */
68
+ export function boxNormal(p, box) {
69
+ const q = apply(T(box.R), sub(p, box.pos));
70
+ q[1] -= box.half[1];
71
+ const d = q.map((v, i) => Math.abs(v) - box.half[i]);
72
+ let n;
73
+ if (Math.max(...d) < 0) { const i = d.indexOf(Math.max(...d)); n = [0, 0, 0]; n[i] = Math.sign(q[i]) || 1; }
74
+ else n = q.map((v, i) => (d[i] > 0 ? Math.sign(v) * d[i] : 0));
75
+ const l = len(n);
76
+ return apply(box.R, l > 1e-12 ? scale(n, 1 / l) : [0, 1, 0]);
77
+ }
@@ -0,0 +1,191 @@
1
+ // Goals (C8): what the motion must achieve, measured on the compiled frames. A goal names one
2
+ // predicate and the frames it must hold on (at: an absolute frame or [f0, f1]):
3
+ // near: [a, b] refDistance(a, b) <= tol (default 0.05 m)
4
+ // above: [a, b] a.y - b.y >= by (default 0 m)
5
+ // moved: ref an object's point (default its base) is at least by (default 0.05 m) from
6
+ // where the scene put it; any other point ref (prop:, joint:, landmark:, anchor:)
7
+ // gets at least by from where it was at at[0]: one value, its farthest frame
8
+ // still: ref the point stays within tol (default 0.01 m) of the same home moved measures
9
+ // from (an object: where the scene put it; any other point: where it is at at[0])
10
+ // speed: ref the point's speed (central difference, m/s) is at least by (no default)
11
+ // mode "all" (every frame of at; the default, except speed) or "any" (one frame; speed's default).
12
+ // after / before: "<goal name>" cut at to the frames after (before) the first frame the named goal
13
+ // holds, so an event the agent did not place on a frame can still order two goals ("the can moves
14
+ // after the kick"). A named goal that never holds, or holds too late, leaves no frames: the goal
15
+ // fails with value and at null and one GOAL issue (value 0.01) at at[0]; the named goal's own GOAL
16
+ // group carries the measure. Each goal answers one result { name, kind, ok, value, at, need }: for
17
+ // "all" the frame closest to failing (or the worst failure), for "any" the best frame. A failed goal
18
+ // adds GOAL issues (value = the shortfall, limit 0): "all" one per failing frame, so the group's
19
+ // count and first..last show how much of at fails and the search (search.js) sees progress; "any"
20
+ // one, at the best frame. Issue frames index out.frames (out.f0 + i); goals[].at and every frame in
21
+ // a message are absolute.
22
+ import { refPoint, refDistance } from "../refs.js";
23
+ import { partsOf } from "../object-pose.js";
24
+ import { add, apply, len, sub } from "../compiler/math.js";
25
+ import { m3 } from "./fmt.js";
26
+
27
+ /** The goal predicates, one per goal. */
28
+ export const GOAL_KINDS = ["near", "above", "moved", "still", "speed"];
29
+ const DEFAULT_NEED = { near: 0.05, above: 0, moved: 0.05, still: 0.01 };
30
+ /** Predicates met at value <= need (tol); the others are met at value >= need (by). */
31
+ const AT_MOST = new Set(["near", "still"]);
32
+ /** Predicates on one point ref (the others take [ref, ref]). */
33
+ export const ONE_REF = new Set(["moved", "still", "speed"]);
34
+
35
+ /** The predicates goal g names (validation wants exactly one). */
36
+ export const goalKinds = g => GOAL_KINDS.filter(k => g?.[k] !== undefined);
37
+ /** A goal's name: its own, else its place in spec.goals ("goals[1]", which groupKey keeps apart). */
38
+ export const goalName = (g, i) => g.name ?? `goals[${i}]`;
39
+ /** The bound: tol for near and still, by for above, moved and speed. */
40
+ export const goalNeed = (g, kind) => (AT_MOST.has(kind) ? g.tol : g.by) ?? DEFAULT_NEED[kind];
41
+ /** "all" or "any": the goal's own, else any for speed (a speed is reached) and all for the rest. */
42
+ const goalMode = (g, kind) => g.mode ?? (kind === "speed" ? "any" : "all");
43
+
44
+ /** moved and still measure the named point of an object ref (its base when none is named), any other ref as it is. */
45
+ export const movedRef = ref => (!ref.startsWith("object:") || /\.(center|top|base)$/.test(ref) ? ref : `${ref}.base`);
46
+
47
+ /** Where the scene put the point of a moved object ref: the same AABB point refs.js answers, from the scene boxes. */
48
+ function scenePoint(scene, ref) {
49
+ const [, id, which] = /^object:(.+)\.(center|top|base)$/s.exec(movedRef(ref)) ?? [];
50
+ const boxes = partsOf(scene, id).map(p => scene.objects[p]);
51
+ if (!boxes.length) return null;
52
+ const lo = [Infinity, Infinity, Infinity], hi = [-Infinity, -Infinity, -Infinity];
53
+ for (const b of boxes) for (const x of [-1, 1]) for (const y of [0, 2]) for (const z of [-1, 1]) {
54
+ const p = add(b.pos, apply(b.R, [x * b.half[0], y * b.half[1], z * b.half[2]]));
55
+ for (let i = 0; i < 3; i++) { lo[i] = Math.min(lo[i], p[i]); hi[i] = Math.max(hi[i], p[i]); }
56
+ }
57
+ const c = [(lo[0] + hi[0]) / 2, (lo[1] + hi[1]) / 2, (lo[2] + hi[2]) / 2];
58
+ return which === "top" ? [c[0], hi[1], c[2]] : which === "base" ? [c[0], lo[1], c[2]] : c;
59
+ }
60
+
61
+ /** The point ref of a moved or still goal. */
62
+ const homeRef = g => g.moved ?? g.still;
63
+
64
+ /** Where a moved or still goal measures from: an object's point where the scene put it, any other point where it is at `from` (default at[0]). */
65
+ export const movedHome = (out, g, from = Array.isArray(g.at) ? g.at[0] : g.at) => (homeRef(g).startsWith("object:") ? scenePoint(out.ctx.scene, homeRef(g)) : refPoint(out, from, homeRef(g)));
66
+
67
+ /** The speed of point ref at absolute frame f (m/s): central difference, one-sided at the window's edges; null when unknown. */
68
+ function speedAt(out, ref, f) {
69
+ const p = refPoint(out, f, ref), fps = out.fps ?? 24;
70
+ if (!p) return null;
71
+ const a = refPoint(out, f - 1, ref), b = refPoint(out, f + 1, ref);
72
+ if (a && b) return (len(sub(b, a)) * fps) / 2;
73
+ const q = a ?? b;
74
+ return q ? len(sub(p, q)) * fps : null;
75
+ }
76
+
77
+ /** The measured value of goal g at absolute frame f (metres, m/s for speed), or null when a ref is unknown there. */
78
+ function measure(out, g, kind, f, home) {
79
+ if (kind === "near") return refDistance(out, f, g.near[0], g.near[1]);
80
+ if (kind === "above") {
81
+ const a = refPoint(out, f, g.above[0]), b = refPoint(out, f, g.above[1]);
82
+ return a && b ? a[1] - b[1] : null;
83
+ }
84
+ if (kind === "speed") return speedAt(out, g.speed, f);
85
+ const p = home && refPoint(out, f, movedRef(homeRef(g)));
86
+ return p ? len(sub(p, home)) : null;
87
+ }
88
+
89
+ /** How far value v is from meeting the bound (> 0 fails). */
90
+ const shortOf = (kind, v, need) => (AT_MOST.has(kind) ? v - need : need - v);
91
+ const round4 = x => Math.max(1e-4, Math.round(x * 1e4) / 1e4);
92
+
93
+ /** The measured frames of goal g over [a, b]: [{ f, v, short }], and the frame its point is measured from (a point's moved or still). */
94
+ function rowsOf(X, g, kind, a, b) {
95
+ const need = goalNeed(g, kind), point = (kind === "moved" || kind === "still") && !homeRef(g).startsWith("object:");
96
+ // a point is measured from where it is at the window's first frame (outside a windowed trial compile: unknown, so nothing is measured)
97
+ const home = kind === "moved" || kind === "still" ? movedHome(X.out, g, a) : null, rows = [];
98
+ for (let f = Math.max(a, X.f0); f <= Math.min(b, X.last); f++) {
99
+ const v = measure(X.out, g, kind, f, home);
100
+ if (v !== null) rows.push({ f, v, short: shortOf(kind, v, need) });
101
+ }
102
+ return { rows, from: point ? a : undefined };
103
+ }
104
+
105
+ /**
106
+ * The first frame goal j holds (its own window, cut by its own after/before): a frame, null when
107
+ * it never holds there (or sits in an after/before loop), undefined when no frame of it is measured
108
+ * (a windowed trial compile that does not reach it).
109
+ */
110
+ function eventOf(X, j) {
111
+ if (X.events.has(j)) return X.events.get(j);
112
+ if (X.visiting.has(j)) return null;
113
+ X.visiting.add(j);
114
+ const g = X.goals[j], kind = goalKinds(g)[0], w = kind && windowOf(X, j);
115
+ let e;
116
+ if (w && !w.wait) {
117
+ const { rows } = rowsOf(X, g, kind, w.a, w.b);
118
+ e = rows.length ? (rows.find(r => r.short <= 0)?.f ?? null) : undefined;
119
+ } else e = w?.wait ? null : undefined;
120
+ X.visiting.delete(j);
121
+ X.events.set(j, e);
122
+ return e;
123
+ }
124
+
125
+ /** The frames goal i measures: at cut by after and before ({ a, b }), or { wait } when that leaves none, or { skip } when unknown here. */
126
+ function windowOf(X, i) {
127
+ const g = X.goals[i];
128
+ let [a, b] = Array.isArray(g.at) ? g.at : [g.at, g.at];
129
+ for (const side of ["after", "before"]) {
130
+ if (g[side] === undefined) continue;
131
+ const j = X.names.get(g[side]);
132
+ if (j === undefined || j === i) return { wait: `${side} "${g[side]}" names no other goal` };
133
+ const e = eventOf(X, j);
134
+ if (e === undefined) return { skip: true };
135
+ if (e === null) return { wait: `waits for "${g[side]}" (${side}), which never holds` };
136
+ if (side === "after") a = Math.max(a, e + 1); else b = Math.min(b, e - 1);
137
+ if (a > b) return { wait: `no frames left ${side} "${g[side]}" (it holds first at f${e}; at is f${Array.isArray(g.at) ? `${g.at[0]}-f${g.at[1]}` : g.at})` };
138
+ }
139
+ return { a, b };
140
+ }
141
+
142
+ function message(name, kind, row, need, any, from) {
143
+ const where = any ? `f${row.f}, the best of f${any[0]}-f${any[1]}` : `f${row.f}`;
144
+ if (kind === "near") return `${name}: ${m3(row.v)} m at ${where} (needs <= ${need})`;
145
+ if (kind === "above") return `${name}: ${m3(row.v)} m above at ${where} (needs >= ${need})`;
146
+ if (kind === "speed") return `${name}: ${m3(row.v)} m/s at ${where} (needs >= ${need})`;
147
+ if (kind === "still") return `${name}: ${m3(row.v)} m from ${from === undefined ? "its scene pose" : `f${from}`} at ${where} (needs <= ${need})`;
148
+ return `${name}: moved ${m3(row.v)} m${from === undefined ? "" : ` from f${from}`} at ${where} (needs >= ${need})`;
149
+ }
150
+
151
+ /** The frames goal i measures in compile result out (after/before applied): { a, b } | { wait } | { skip } (hints-goal.js). */
152
+ export function goalWindow(out, goals, i) {
153
+ const f0 = out.f0 ?? 0, names = new Map(goals.map((g, j) => [goalName(g, j), j]));
154
+ return windowOf({ out, goals, names, f0, last: f0 + (out.frames?.length ?? 0) - 1, events: new Map(), visiting: new Set() }, i);
155
+ }
156
+
157
+ /**
158
+ * goalChecks(out, goals) -> { issues, results }
159
+ * @param {object} out compileMotion result (refs.js reads it)
160
+ * @param {object[]} goals spec.goals
161
+ * @returns {{ issues: object[], results: { name: string, kind: string, ok: boolean, value: number|null, at: number|null, need: number }[] }}
162
+ */
163
+ export function goalChecks(out, goals) {
164
+ const issues = [], results = [], f0 = out.f0 ?? 0;
165
+ const X = { out, goals, names: new Map(goals.map((g, j) => [goalName(g, j), j])), f0, last: f0 + (out.frames?.length ?? 0) - 1, events: new Map(), visiting: new Set() };
166
+ goals.forEach((g, i) => {
167
+ const kind = goalKinds(g)[0];
168
+ if (!kind) return;
169
+ const name = goalName(g, i), need = goalNeed(g, kind), w = windowOf(X, i), at0 = Array.isArray(g.at) ? g.at[0] : g.at;
170
+ if (w.skip) return;
171
+ if (w.wait) {
172
+ results.push({ name, kind, ok: false, value: null, at: null, need });
173
+ if (at0 >= f0 && at0 <= X.last) issues.push({ kind: "GOAL", msg: `${name}: ${w.wait}`, frame: at0 - f0, value: 0.01, limit: 0 });
174
+ return;
175
+ }
176
+ let { rows, from } = rowsOf(X, g, kind, w.a, w.b);
177
+ // a windowed trial compile (search.js) may not reach at; those frames cannot change there
178
+ if (!rows.length) return;
179
+ // a point's moved is one value: the farthest it gets from where it was at at[0]
180
+ if (kind === "moved" && from !== undefined) rows = [rows.reduce((p, r) => (r.v > p.v ? r : p))];
181
+ const any = goalMode(g, kind) === "any", cut = Array.isArray(g.at) ? w.a !== w.b : false;
182
+ const pick = rows.reduce((p, r) => ((any ? r.short < p.short : r.short > p.short) ? r : p));
183
+ const ok = pick.short <= 0;
184
+ results.push({ name, kind, ok, value: m3(pick.v), at: pick.f, need });
185
+ if (ok) return;
186
+ for (const r of any ? [pick] : rows.filter(r => r.short > 0)) {
187
+ issues.push({ kind: "GOAL", msg: message(name, kind, r, need, any && cut ? [w.a, w.b] : null, from), frame: r.f - f0, value: round4(r.short), limit: 0 });
188
+ }
189
+ });
190
+ return { issues, results };
191
+ }
@@ -0,0 +1,60 @@
1
+ // The ground under a foot: the floor (y 0) or the top of a scene obstacle the sole stands on.
2
+ // Every ground measurement reads sole heights from here: QA's air runs, FLOAT and balance
3
+ // (style.js), SLIDE (checks.js), the timeline's planted runs, and the fixes that keep to QA's
4
+ // planted definition (fix/slide.js, fix/turn.js). A foot on a box top is then on the ground as one
5
+ // on the floor is. Session 68d305dc: a foot on a 0.7 m cube read as "no foot on the ground"
6
+ // (FLOAT n57), and naming the cube in checks.supports did not clear it (a support rests the hips).
7
+ // The obstacles are out.objectsAt(i): carried and follow objects are not ground, a hinge is at its
8
+ // turned pose. GROUND (a sole under the floor) and fix.ground stay on the floor.
9
+ import { T, apply, sub, len } from "../compiler/math.js";
10
+ import { solePoints } from "./geometry.js";
11
+
12
+ /** A top up to this far (m) above a sole point is still the ground under it: a sole sunk into a top stands on it. */
13
+ const SINK = 0.05;
14
+
15
+ const prepared = new WeakMap();
16
+
17
+ /** The obstacle boxes of one frame's map, with what the vertical-line test needs. */
18
+ function boxesOf(objs) {
19
+ let list = prepared.get(objs);
20
+ if (!list) {
21
+ list = Object.values(objs).filter(box => box.half && !box.ignore).map(box => {
22
+ const RT = T(box.R), c = [box.pos[0] + box.R[0][1] * box.half[1], box.pos[1] + box.R[1][1] * box.half[1], box.pos[2] + box.R[2][1] * box.half[1]];
23
+ return { RT, c, half: box.half, up: [box.R[1][0], box.R[1][1], box.R[1][2]], r: len(box.half) };
24
+ });
25
+ prepared.set(objs, list);
26
+ }
27
+ return list;
28
+ }
29
+
30
+ /** Height of the box's top on the vertical line through p (any rotation), or null when the line misses it. */
31
+ function topOver(b, p) {
32
+ if (Math.hypot(p[0] - b.c[0], p[2] - b.c[2]) > b.r) return null;
33
+ const q = apply(b.RT, sub(p, b.c));
34
+ let lo = -Infinity, hi = Infinity;
35
+ for (let k = 0; k < 3; k++) {
36
+ const d = b.up[k], h = b.half[k];
37
+ if (Math.abs(d) < 1e-9) { if (Math.abs(q[k]) > h) return null; continue; }
38
+ const t1 = (-h - q[k]) / d, t2 = (h - q[k]) / d;
39
+ lo = Math.max(lo, Math.min(t1, t2));
40
+ hi = Math.min(hi, Math.max(t1, t2));
41
+ }
42
+ return lo <= hi ? p[1] + hi : null;
43
+ }
44
+
45
+ /** World height of the ground under point p at frame index i of out (out.frames[i]). */
46
+ export function groundY(out, i, p) {
47
+ let g = 0;
48
+ for (const b of boxesOf(out.objectsAt(i))) {
49
+ const top = topOver(b, p);
50
+ if (top !== null && top <= p[1] + SINK && top > g) g = top;
51
+ }
52
+ return g;
53
+ }
54
+
55
+ /** solePoints of frame index i with y the height above the ground under each point (x, z are world). */
56
+ export function groundSole(out, i, side) {
57
+ const sp = solePoints(out.ctx.sk, out.frames[i].s, side);
58
+ for (const key of ["heel", "ball", "tip"]) sp[key] = [sp[key][0], sp[key][1] - groundY(out, i, sp[key]), sp[key][2]];
59
+ return sp;
60
+ }
@@ -0,0 +1,179 @@
1
+ // Hints for contact-type issues: a body part inside a box, the floor, the head, the torso or the
2
+ // other limb. Each answers a world move (direction x amount) for whatever drives that part.
3
+ import { add, sub, scale, norm, dot, len, clamp, apply, ry, T } from "../compiler/math.js";
4
+ import { bonePoint } from "../compiler/skeleton.js";
5
+ import { CAPSULES, segPoints, sdBox, boxNormal, headDepth, segDist, solePoints, ankleY } from "./geometry.js";
6
+ import { vec, m3 } from "./fmt.js";
7
+ import { kneeFoldHint, kneeWhy } from "./hints-knee.js";
8
+ import { objectFrame } from "../compiler/anchors.js";
9
+ import { bodyFor, bodyNormal, limbDepth } from "../body.js";
10
+ import { footProbes, footDepths } from "./foot-checks.js";
11
+
12
+ const MARGIN = 0.003;
13
+ /** The most a foot hint lifts a foot over a body it went into through a side (a stair riser); higher, it backs out. */
14
+ const LIFT_MAX = 0.25;
15
+ const sideOf = name => (/(^|_)l$|^Left/.test(name) ? "l" : /(^|_)r$|^Right/.test(name) ? "r" : null);
16
+
17
+ /** fix (qa/patch.js) moving anchor `name` of hand k by a world delta at f: its own point, in the frame that point is written in. */
18
+ function anchorFix(X, name, f, delta, k) {
19
+ const a = X.spec.anchors?.[name], path = field => `/anchors/${name}/${field}`;
20
+ if (a?.kind === "world") return { path: path("p"), delta };
21
+ if (a?.kind === "body") return { path: path("p"), delta: apply(ry(-(X.fr(f).c.yaw ?? 0)), delta) };
22
+ if (["bone", "segment", "prop"].includes(a?.kind)) return { path: path("offset"), delta };
23
+ if (a?.kind !== "object") return undefined;
24
+ // local is in the object's axes where that hand's target read it (anchors.js objectFrame)
25
+ const fr = X.fr(f), o = objectFrame(X.out.ctx, a, name, { ...fr, diag: { ...fr.diag, frame: f } }, k);
26
+ return { path: path("local"), delta: apply(T(o.R), delta) };
27
+ }
28
+
29
+ /** cause + hint (+ fix, qa/patch.js) for moving a body part (capsule name, prop_<name>, hand_<k>) by `delta` at frame f. */
30
+ export function moveHint(X, part, f, delta, why = "") {
31
+ const prop = /^prop_(.+)$/.exec(part);
32
+ const k = prop ? X.spec.props?.[prop[1]]?.hand : sideOf(part);
33
+ let label, cause, fix, shown = delta;
34
+ if (/^(hand|farm|uarm)_/.test(part) || prop) {
35
+ const d = X.hand(k, f);
36
+ label = d.label;
37
+ fix = d.anchor ? anchorFix(X, d.anchor, f, delta, k) : d.ch === `hand_${k}` ? { channel: d.ch, f, delta } : undefined;
38
+ // an object anchor moves its point on the object (local, in the object's axes), never the object
39
+ const on = d.anchor && X.spec.anchors[d.anchor]?.kind === "object" ? X.spec.anchors[d.anchor].object : null;
40
+ if (on && fix) { label = `anchors.${d.anchor}.local (a point on ${on}, in ${on}'s axes; ${on} stays)`; shown = fix.delta; }
41
+ cause = d.anchor ? `anchor ${d.anchor}${d.fit !== null ? ` (fits[${d.fit}])` : ""} via ${X.cause(d.ch, f)}` : X.cause(d.ch, f);
42
+ } else if (/^(shin|foot|sole)_/.test(part)) { label = `foot_${k}`; cause = X.cause(label, f); fix = { channel: label, f, delta }; }
43
+ // a body held since its key (it breathes and sways there, compiler/idle.js): move what placed it (patch.js hold)
44
+ else { label = "root"; cause = X.cause("root", f); fix = { channel: "root", f, delta, ...(/^root held since /.test(cause) ? { hold: true } : {}) }; }
45
+ // a key the walk generator wrote: the agent changes the walk, not the key
46
+ const walk = / (walk|walkTo) /.test(` ${cause}`) && /step|start|end/.test(cause);
47
+ if (walk && !/^anchor/.test(label)) return { cause, hint: `walk path: ${label} needs ${vec(delta)} m at f${f}${why}; change that walk's heading/turnDistance/step (or give one a { range: [lo, hi] })` };
48
+ return { cause, hint: `${label}: move ${vec(shown)} m at f${f}${why}`, fix };
49
+ }
50
+
51
+ const capsule = name => CAPSULES.find(c => c[0] === name);
52
+
53
+ /** Deepest point of a capsule in a box at frame f and the box's outward normal there. */
54
+ function deepest(X, f, part, box) {
55
+ const [, a, b] = capsule(part), { s } = X.fr(f);
56
+ const pts = segPoints(s.P[X.I[a]], s.P[X.I[b]]), ds = pts.map(p => sdBox(p, box)), m = Math.min(...ds);
57
+ return { p: pts[ds.indexOf(m)], n: boxNormal(pts[ds.indexOf(m)], box), d: m };
58
+ }
59
+
60
+ function boxHint(X, g, part, id, need) {
61
+ const f = g.worstFrame, box = X.out.objectsAt(X.rel(f))[id];
62
+ if (!box || !capsule(part)) return null;
63
+ const { n } = deepest(X, f, part, box);
64
+ return moveHint(X, part, f, scale(n, need), ` (out of ${id})`);
65
+ }
66
+
67
+ /**
68
+ * A foot in a box (foot-checks.js): through a side face (a toe swung into a stair's riser) the foot rises over the
69
+ * box's top by what its deepest probe lacks, with the way straight out of that side as the other choice; through
70
+ * the top face (a sole sunk in a step) it comes out along that face.
71
+ */
72
+ function footHint(X, g, part, id) {
73
+ const f = g.worstFrame, box = X.out.objectsAt(X.rel(f))[id];
74
+ if (!box) return null;
75
+ const probes = footProbes(X.sk, X.fr(f).s, part.endsWith("_l") ? "Left" : "Right"), d = footDepths(probes, box), need = g.worst - g.limit + MARGIN;
76
+ if (!(d.side > 0)) return d.topAt ? moveHint(X, part, f, scale(boxNormal(d.topAt, box), need), ` (out of ${id}'s top)`) : null;
77
+ const under = p => 2 * box.half[1] - apply(T(box.R), sub(p, box.pos))[1];
78
+ const rise = Math.max(...probes.filter(p => sdBox(p, box) < 0).map(under)) + MARGIN, out = scale(boxNormal(d.sideAt, box), need);
79
+ // a step's riser is cleared by lifting the swing; a panel the foot kicks or a wall is left the way the foot came
80
+ if (rise > LIFT_MAX) return moveHint(X, part, f, out, ` (out of ${id}'s side)`);
81
+ const r = moveHint(X, part, f, apply(box.R, [0, rise, 0]), ` (over ${id}'s top; its ${g.worst.toFixed(3)} m is through a side)`);
82
+ r.hint += /^walk path/.test(r.hint) ? "; a higher lift raises the swing" : `; or move ${vec(out)} m out of that side`;
83
+ return r;
84
+ }
85
+
86
+ function towardFrom(X, g, part, from, need, what) {
87
+ return moveHint(X, part, g.worstFrame, scale(norm(from), need), ` (away from the ${what})`);
88
+ }
89
+
90
+ /** Probe points of a hand or prop at frame f (as the FACE/BODY checks probe them). */
91
+ function probes(X, f, nm) {
92
+ const { s, diag } = X.fr(f), I = X.I;
93
+ if (nm.startsWith("hand_")) { const S = nm.endsWith("l") ? "Left" : "Right"; return segPoints(s.P[I[`${S}Hand`]], s.P[I[`${S}HandMiddle3`]], 5); }
94
+ return Object.entries(diag.props?.[nm.slice(5)] ?? {}).filter(([k, p]) => Array.isArray(p) && k !== "origin").map(([, p]) => p);
95
+ }
96
+
97
+ export const contactHints = {
98
+ COLLIDE(X, g) {
99
+ const [, part, id] = /^(\S+) x (.+)$/.exec(g.subject) ?? [];
100
+ if (/^foot_[lr]$/.test(part ?? "")) return footHint(X, g, part, id);
101
+ const r = boxHint(X, g, part, id, g.worst - g.limit + MARGIN);
102
+ if (r && /^(hand|farm)_/.test(part) && !X.spec.fix?.penetration && g.worst - g.limit <= 0.05) {
103
+ r.hint += "; or fix.penetration: 0.02 pushes shallow hand hits out";
104
+ if (X.spec.fix !== false) r.fix = { path: "/fix/penetration", value: 0.02 };
105
+ }
106
+ return r;
107
+ },
108
+ CLEARANCE(X, g) {
109
+ const k = (X.spec.checks?.clearance ?? []).find(c => g.subject.startsWith(`${c.name}:`));
110
+ return k && boxHint(X, g, k.part, k.object, k.min - g.worst + MARGIN);
111
+ },
112
+ GROUND(X, g) {
113
+ const k = g.subject.startsWith("Left") ? "l" : "r", f = g.worstFrame, c = X.fr(f).c, fold = X.fr(f).diag[`leg_fold_${k}`];
114
+ // the knee on its stop left the ankle under its target (compiler/limbs.js): raising the foot folds it further, the root comes up
115
+ if (fold) return kneeFoldHint(X, k, f, kneeWhy("the sole is in the floor because the knee is on its stop: ", fold), c[`foot_${k}`]);
116
+ const pitch = c[`fpitch_${k}`] ? `, or less fpitch_${k} (now ${m3(c[`fpitch_${k}`])} deg; + lifts the heel)` : "";
117
+ return { cause: X.cause(`foot_${k}`, f), hint: `foot_${k}: raise ${m3(g.worst + 0.001)} m at f${f} (foot_* is the ankle; it stands ${ankleY(X.sk)} m above the floor)${pitch}`,
118
+ fix: { channel: `foot_${k}`, f, delta: [0, g.worst + 0.001, 0] } };
119
+ },
120
+ FACE(X, g) {
121
+ const nm = g.subject.replace(/ into head$/, ""), f = g.worstFrame, { s } = X.fr(f);
122
+ const c = bonePoint(s, X.I.Head, X.sk.landmarks.headCentre);
123
+ const p = probes(X, f, nm).reduce((best, q) => (headDepth(X.sk, s, q) > headDepth(X.sk, s, best) ? q : best));
124
+ return towardFrom(X, g, nm, sub(p, c), g.worst - g.limit + MARGIN, "head");
125
+ },
126
+ BODY(X, g) {
127
+ const [, nm, part] = /^(\S+) into (\S+)$/.exec(g.subject) ?? [];
128
+ const cap = capsule(part), f = g.worstFrame, { s } = X.fr(f);
129
+ // an arm on the fitted skin (body-checks.js): the hand target moves out along the skin where it goes deepest;
130
+ // an upper arm or forearm says so, since turning its elbow (elbow_<k>) away from the body may do instead
131
+ const limb = /^(hand|farm|uarm)_([lr])$/.exec(nm ?? ""), body = limb && bodyFor(X.sk);
132
+ if (body) {
133
+ const bone = X.I[`${limb[2] === "l" ? "Left" : "Right"}${{ hand: "Hand", farm: "ForeArm", uarm: "Arm" }[limb[1]]}`], hit = limbDepth(body, X.sk, s, bone);
134
+ const out = hit.p && bodyNormal(body, s, hit.p, body.skip.get(bone));
135
+ if (out) {
136
+ const r = moveHint(X, nm, f, scale(out, g.worst - g.limit + MARGIN), ` (out of the ${part})`);
137
+ if (limb[1] !== "hand") r.hint += `; or turn elbow_${limb[2]} away from the ${part}`;
138
+ return r;
139
+ }
140
+ }
141
+ if (!cap) return null;
142
+ const A = s.P[X.I[cap[1]]], B = s.P[X.I[cap[2]]], ab = sub(B, A);
143
+ const axis = p => add(A, scale(ab, clamp(dot(sub(p, A), ab) / dot(ab, ab), 0, 1)));
144
+ const p = probes(X, f, nm).reduce((best, q) => (len(sub(q, axis(q))) < len(sub(best, axis(best))) ? q : best));
145
+ return towardFrom(X, g, nm, sub(p, axis(p)), g.worst - g.limit + MARGIN, "torso");
146
+ },
147
+ SELF(X, g) {
148
+ const f = g.worstFrame, { s } = X.fr(f), P = s.P, I = X.I;
149
+ if (g.subject === "hands overlap") {
150
+ const d = norm(sub(P[I.LeftHand], P[I.RightHand])), need = (g.worst - g.limit + MARGIN) / 2;
151
+ const r = moveHint(X, "hand_l", f, scale(d, need));
152
+ return { cause: r.cause, hint: `${r.hint}; and ${moveHint(X, "hand_r", f, scale(d, -need)).hint}`, fix: moveHint(X, "hand_l", f, scale(d, 2 * need)).fix };
153
+ }
154
+ const shins = g.subject === "shins touch", min = shins ? 0.1 : 0.135;
155
+ const [a, b] = shins ? ["Leg", "Foot"] : ["UpLeg", "Leg"];
156
+ const gap = segDist(P[I[`Left${a}`]], P[I[`Left${b}`]], P[I[`Right${a}`]], P[I[`Right${b}`]]);
157
+ const d = sub(P[I[`Left${b}`]], P[I[`Right${b}`]]); d[1] = 0;
158
+ const need = (min - gap + MARGIN) / 2, dir = norm(d);
159
+ return { cause: X.cause("foot_l", f), hint: `foot_l: move ${vec(scale(dir, need))} m and foot_r ${vec(scale(dir, -need))} m at f${f} (${shins ? "shins" : "thighs"} ${m3(gap)} m apart, need ${min}); or spread knee_l/knee_r`,
160
+ fix: { channel: "foot_l", f, delta: scale(dir, 2 * need) } };
161
+ },
162
+ OBJECT(X, g) {
163
+ const [, id, oid] = /^(\S+) into (.+)$/.exec(g.subject) ?? [];
164
+ const ch = X.spec.objects?.[id]?.channel;
165
+ if (!ch) return null;
166
+ const at = f => X.out.baked[ch]?.[f] ?? 0, clean = g.first > 0 ? at(g.first - 1) : at(0);
167
+ return { cause: X.cause(ch, g.worstFrame), hint: `${ch}: keep it within ${m3(clean)} deg (it reaches ${m3(at(g.worstFrame))} at f${g.worstFrame}, ${m3(g.worst)} m into ${oid}), or move ${oid}`,
168
+ fix: { channel: ch, f: g.worstFrame, value: clean } };
169
+ },
170
+ BALANCE(X, g) {
171
+ const f = g.worstFrame, { s } = X.fr(f), P = s.P, I = X.I;
172
+ if (g.subject === "no foot on the ground") return { cause: X.cause("root", f), hint: `at f${f} lower foot_l or foot_r onto the ground, the floor or the top of an object under it (the ankle stands ${ankleY(X.sk)} m above it), or declare checks.supports for the seat the hips rest on` };
173
+ const com = scale(["Hips", "Spine1", "Spine2", "Head"].reduce((acc, j) => add(acc, P[I[j]]), [0, 0, 0]), 0.25);
174
+ const feet = ["Left", "Right"].flatMap(S => Object.values(solePoints(X.sk, s, S)));
175
+ const xs = feet.map(p => p[0]), zs = feet.map(p => p[2]), mg = 0.08 - 0.01;
176
+ const to = [clamp(com[0], Math.min(...xs) - mg, Math.max(...xs) + mg), com[1], clamp(com[2], Math.min(...zs) - mg, Math.max(...zs) + mg)];
177
+ return { cause: X.cause("root", f), hint: `root: move ${vec(sub(to, com))} m at f${f} (centre of mass over the feet), or step a foot under it`, fix: { channel: "root", f, delta: sub(to, com) } };
178
+ },
179
+ };