cozyclay 2.1.1 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (585) hide show
  1. package/CHANGELOG.md +88 -0
  2. package/README.md +12 -30
  3. package/bin/agent/agent-routes.mjs +43 -116
  4. package/bin/agent/agent-runner.mjs +14 -15
  5. package/bin/agent/cliproxy-provider.mjs +135 -0
  6. package/bin/agent/credential-store.mjs +30 -7
  7. package/bin/agent/pi-tools.mjs +4 -1
  8. package/bin/agent/provider-keys.mjs +32 -0
  9. package/bin/agent/provider-login.mjs +110 -0
  10. package/bin/agent/provider-routes.mjs +99 -0
  11. package/bin/agent/providers.mjs +19 -97
  12. package/bin/agent/script-tool.mjs +17 -4
  13. package/bin/agent/session-store.mjs +2 -2
  14. package/bin/agent/studio-context-budget.mjs +93 -0
  15. package/bin/agent/studio-motion-reference.mjs +23 -0
  16. package/bin/agent/studio-prompt.mjs +1 -1
  17. package/bin/agent/studio-rebase-text.mjs +32 -0
  18. package/bin/agent/studio-rebase.mjs +26 -39
  19. package/bin/agent/studio-tools.mjs +9 -28
  20. package/bin/agent/tool-arguments.mjs +49 -0
  21. package/bin/agent/turn-frames.mjs +66 -0
  22. package/bin/codex-auth.mjs +9 -2
  23. package/bin/cozyclay.mjs +10 -116
  24. package/bin/live/cli.mjs +3 -3
  25. package/bin/mcp-runtime.mjs +2 -12
  26. package/bin/package-signature.mjs +0 -4
  27. package/dist/app/index.html +7 -6
  28. package/dist/assets/EXRLoader-CvVIvGVE.js +1 -0
  29. package/dist/assets/analytics-BWCqdgWA.js +1 -0
  30. package/dist/assets/app-DfTCxaKk.js +5087 -0
  31. package/dist/assets/app-f-fkV5uP.css +1 -0
  32. package/dist/assets/compile-worker-BxKXh07s.js +5 -0
  33. package/dist/assets/fflate.module-KbGj5-H6.js +5 -0
  34. package/dist/assets/{first-shot-handoff-msLI71g1.js → first-shot-handoff-DNO8kv_N.js} +1 -1
  35. package/dist/assets/{landing-ChUvB_zL.js → landing-yfZaJkWc.js} +1 -1
  36. package/dist/assets/scene-asset-sync-U3kS2rvK.js +20 -0
  37. package/dist/assets/scene-asset-sync-_S8NQl5B.css +1 -0
  38. package/dist/assets/workflow-D78eiKTa.js +179 -0
  39. package/dist/cozyclay-package.json +1 -1
  40. package/dist/index.html +3 -3
  41. package/dist/sw.js +3 -6
  42. package/dist/workflow/index.html +5 -4
  43. package/mcp/LIVE-PROTOCOL.md +7 -47
  44. package/mcp/README.md +16 -26
  45. package/mcp/live-hub.mjs +6 -10
  46. package/mcp/package.json +1 -3
  47. package/mcp/tool-handlers.mjs +4 -168
  48. package/package.json +3 -22
  49. package/src/App.jsx +151 -2625
  50. package/src/agent-progress.js +80 -0
  51. package/src/agent-turn-mark.js +30 -0
  52. package/src/analytics.js +1 -19
  53. package/src/app-context.js +12 -2
  54. package/src/app-stage.jsx +2 -34
  55. package/src/asset-pane.jsx +6 -5
  56. package/src/camera-block.js +21 -0
  57. package/src/camera-direction.js +120 -0
  58. package/src/character-kind.js +3 -9
  59. package/src/command-bus.js +10 -8
  60. package/src/commands/cast.js +5 -34
  61. package/src/commands/elements/character.js +1 -1
  62. package/src/commands/elements/motion.js +1 -6
  63. package/src/commands/elements/object.js +6 -2
  64. package/src/commands/elements/shot.js +4 -1
  65. package/src/commands/elements.js +38 -14
  66. package/src/commands/index.js +3 -1
  67. package/src/commands/kits.js +37 -0
  68. package/src/commands/motion-timing.js +57 -0
  69. package/src/commands/motion.js +9 -152
  70. package/src/commands/motion3-compile.js +65 -0
  71. package/src/commands/motion3.js +214 -0
  72. package/src/commands/objects.js +6 -4
  73. package/src/commands/shot.js +55 -13
  74. package/src/commands/stage.js +14 -1
  75. package/src/commands/view.js +4 -1
  76. package/src/document-mirrors.js +42 -0
  77. package/src/document-store.js +4 -0
  78. package/src/domains/cast.js +19 -194
  79. package/src/domains/motion/motion-range-pin-rules.js +1 -1
  80. package/src/domains/motion/take-source.js +53 -0
  81. package/src/domains/motion.js +60 -1838
  82. package/src/domains/scenes.js +12 -55
  83. package/src/domains/shots.js +2 -2
  84. package/src/domains/stage.js +4 -2
  85. package/src/draft-ghost.js +47 -0
  86. package/src/draft-ghost.jsx +129 -0
  87. package/src/dualview.jsx +4 -3
  88. package/src/effects/EffectsLayer.jsx +112 -0
  89. package/src/effects/effect-meshes.js +232 -0
  90. package/src/effects/effect-record.js +103 -0
  91. package/src/effects/emitter.js +59 -0
  92. package/src/effects/simulate.js +261 -0
  93. package/src/effects/state.js +59 -0
  94. package/src/execution-telemetry.js +2 -3
  95. package/src/first-success-guide.jsx +5 -5
  96. package/src/ghost-set.js +257 -0
  97. package/src/held-object-edit.jsx +113 -0
  98. package/src/held-object-pose.js +175 -0
  99. package/src/hierarchy-model.js +1 -1
  100. package/src/hierarchy-panel.jsx +1 -1
  101. package/src/imported-mesh.jsx +103 -0
  102. package/src/kits/held.js +84 -0
  103. package/src/kits/index.js +70 -0
  104. package/src/kits/smoking.js +57 -0
  105. package/src/light-blockers.js +93 -0
  106. package/src/motion/beat-board-model.js +84 -0
  107. package/src/motion/beat-board.css +124 -0
  108. package/src/motion/beat-board.jsx +60 -0
  109. package/src/motion/center-of-mass.js +66 -0
  110. package/src/motion/fix-collisions.js +850 -0
  111. package/src/motion/physics-review.js +118 -0
  112. package/src/{ardy → motion}/physics-support.js +1 -76
  113. package/src/motion/rig-snapshot.js +22 -0
  114. package/src/motion/take-segments.jsx +140 -0
  115. package/src/{ardy → motion}/timeline-coordinates.js +0 -21
  116. package/src/{ardy → motion}/timeline.css +1 -2
  117. package/src/{ardy → motion}/timeline.jsx +42 -413
  118. package/src/motion/waypoints.js +76 -0
  119. package/src/motion3/beats.js +83 -0
  120. package/src/motion3/body.js +158 -0
  121. package/src/motion3/bones.js +47 -0
  122. package/src/motion3/carried.js +47 -0
  123. package/src/motion3/compile-job.js +79 -0
  124. package/src/motion3/compile-worker.js +10 -0
  125. package/src/motion3/compiler/anchors.js +113 -0
  126. package/src/motion3/compiler/arm-orient.js +128 -0
  127. package/src/motion3/compiler/channels.js +125 -0
  128. package/src/motion3/compiler/compile.js +205 -0
  129. package/src/motion3/compiler/gait-rhythm.js +97 -0
  130. package/src/motion3/compiler/grip.js +171 -0
  131. package/src/motion3/compiler/head-steady.js +48 -0
  132. package/src/motion3/compiler/hold.js +134 -0
  133. package/src/motion3/compiler/idle.js +113 -0
  134. package/src/motion3/compiler/limbs.js +197 -0
  135. package/src/motion3/compiler/math.js +72 -0
  136. package/src/motion3/compiler/pose.js +177 -0
  137. package/src/motion3/compiler/quat.js +49 -0
  138. package/src/motion3/compiler/skeleton.js +74 -0
  139. package/src/motion3/compiler/validate-common.js +32 -0
  140. package/src/motion3/compiler/validate-goals.js +118 -0
  141. package/src/motion3/compiler/validate-objects.js +144 -0
  142. package/src/motion3/compiler/validate-parts.js +118 -0
  143. package/src/motion3/compiler/validate.js +122 -0
  144. package/src/motion3/compiler/vocab.js +74 -0
  145. package/src/motion3/compiler/walk-pelvis.js +275 -0
  146. package/src/motion3/compiler/walk.js +207 -0
  147. package/src/motion3/compiler/wrist-clamp.js +32 -0
  148. package/src/motion3/delta.js +47 -0
  149. package/src/motion3/describe.js +177 -0
  150. package/src/motion3/docs.js +27 -0
  151. package/src/motion3/edit-carry.js +21 -0
  152. package/src/motion3/fix/ease.js +16 -0
  153. package/src/motion3/fix/ground.js +37 -0
  154. package/src/motion3/fix/index.js +52 -0
  155. package/src/motion3/fix/push.js +71 -0
  156. package/src/motion3/fix/reach.js +46 -0
  157. package/src/motion3/fix/retime.js +79 -0
  158. package/src/motion3/fix/self.js +211 -0
  159. package/src/motion3/fix/slide.js +70 -0
  160. package/src/motion3/fix/turn.js +51 -0
  161. package/src/motion3/follow.js +39 -0
  162. package/src/motion3/free-motion.js +204 -0
  163. package/src/motion3/grip-choice.js +130 -0
  164. package/src/motion3/hold-plan.js +157 -0
  165. package/src/motion3/json-patch.js +77 -0
  166. package/src/motion3/key-aim.js +105 -0
  167. package/src/motion3/key-edit.js +82 -0
  168. package/src/motion3/lenient.js +127 -0
  169. package/src/motion3/object-keys.js +236 -0
  170. package/src/motion3/object-pose.js +182 -0
  171. package/src/motion3/object-tracks.js +12 -0
  172. package/src/motion3/people.js +82 -0
  173. package/src/motion3/pipeline.js +102 -0
  174. package/src/motion3/playback.js +51 -0
  175. package/src/motion3/probes.js +91 -0
  176. package/src/motion3/qa/body-checks.js +34 -0
  177. package/src/motion3/qa/check-names.js +14 -0
  178. package/src/motion3/qa/checks.js +125 -0
  179. package/src/motion3/qa/contact-checks.js +51 -0
  180. package/src/motion3/qa/explain.js +80 -0
  181. package/src/motion3/qa/fmt.js +5 -0
  182. package/src/motion3/qa/foot-checks.js +72 -0
  183. package/src/motion3/qa/geometry.js +77 -0
  184. package/src/motion3/qa/goals.js +191 -0
  185. package/src/motion3/qa/ground.js +60 -0
  186. package/src/motion3/qa/hints-contact.js +195 -0
  187. package/src/motion3/qa/hints-goal.js +160 -0
  188. package/src/motion3/qa/hints-knee.js +24 -0
  189. package/src/motion3/qa/hints-motion.js +209 -0
  190. package/src/motion3/qa/hints-object.js +91 -0
  191. package/src/motion3/qa/index.js +44 -0
  192. package/src/motion3/qa/key-checks.js +82 -0
  193. package/src/motion3/qa/near.js +96 -0
  194. package/src/motion3/qa/object-checks.js +135 -0
  195. package/src/motion3/qa/patch.js +161 -0
  196. package/src/motion3/qa/people-checks.js +37 -0
  197. package/src/motion3/qa/severity.js +38 -0
  198. package/src/motion3/qa/spec-checks.js +65 -0
  199. package/src/motion3/qa/style.js +228 -0
  200. package/src/motion3/qa/wrist-checks.js +69 -0
  201. package/src/motion3/qa/wrist-obs.js +60 -0
  202. package/src/motion3/refs.js +129 -0
  203. package/src/motion3/repair-tune.js +121 -0
  204. package/src/motion3/repair.js +83 -0
  205. package/src/motion3/report.js +67 -0
  206. package/src/motion3/rigs/index.js +14 -0
  207. package/src/motion3/rigs/x-bot-tpose-body.json +1 -0
  208. package/src/motion3/rigs/x-bot-tpose.json +1 -0
  209. package/src/motion3/rigs/y-bot-tpose-body.json +1 -0
  210. package/src/motion3/rigs/y-bot-tpose.json +1 -0
  211. package/src/motion3/scene.js +60 -0
  212. package/src/motion3/schema/brief.js +89 -0
  213. package/src/motion3/schema/fields.js +44 -0
  214. package/src/motion3/schema/spec-examples.js +46 -0
  215. package/src/motion3/schema/topics.js +113 -0
  216. package/src/motion3/schema/types.js +149 -0
  217. package/src/motion3/search.js +117 -0
  218. package/src/motion3/second-hand.js +112 -0
  219. package/src/motion3/settle.js +136 -0
  220. package/src/motion3/skills/basic.js +83 -0
  221. package/src/motion3/skills/book.js +76 -0
  222. package/src/motion3/skills/car.js +145 -0
  223. package/src/motion3/skills/flip.js +200 -0
  224. package/src/motion3/skills/frames-auto.js +29 -0
  225. package/src/motion3/skills/impact.js +109 -0
  226. package/src/motion3/skills/index.js +85 -0
  227. package/src/motion3/skills/info.js +80 -0
  228. package/src/motion3/skills/smoke-kit.js +109 -0
  229. package/src/motion3/skills/smoke.js +160 -0
  230. package/src/motion3/spec-store.js +59 -0
  231. package/src/motion3/take-edit.js +155 -0
  232. package/src/motion3/take.js +63 -0
  233. package/src/motion3/timeline.js +127 -0
  234. package/src/motion3/views.js +121 -0
  235. package/src/motion3/walk-plan.js +119 -0
  236. package/src/object-catalog.jsx +7 -1
  237. package/src/object-colors.js +98 -0
  238. package/src/object-gizmo-parts.js +115 -0
  239. package/src/object-gizmo.jsx +37 -122
  240. package/src/object-glow.js +139 -0
  241. package/src/object-hidden.js +33 -0
  242. package/src/object-look.js +196 -0
  243. package/src/object-size.js +10 -0
  244. package/src/object-travel.js +71 -6
  245. package/src/panels/CameraPanel.jsx +7 -7
  246. package/src/panels/HdrEnvironmentControls.jsx +59 -0
  247. package/src/panels/LightPanel.jsx +25 -4
  248. package/src/panels/ObjectLookPanel.jsx +88 -0
  249. package/src/panels/PosePanel.jsx +2 -17
  250. package/src/panels/RigControlPanel.jsx +5 -53
  251. package/src/panels/SubjectBox.jsx +4 -1
  252. package/src/panels/details.css +14 -0
  253. package/src/posestudio.jsx +4 -27
  254. package/src/project-browser.jsx +3 -4
  255. package/src/project-resources.js +18 -31
  256. package/src/project.js +13 -104
  257. package/src/props.jsx +25 -280
  258. package/src/qa-label.js +25 -0
  259. package/src/rail-dot-drag.js +23 -0
  260. package/src/render-passes.js +10 -0
  261. package/src/resource-status.jsx +1 -0
  262. package/src/result-modal.jsx +4 -19
  263. package/src/room.jsx +20 -12
  264. package/src/scene-assets.js +8 -6
  265. package/src/scene-light-place.js +72 -0
  266. package/src/scene-lights.jsx +148 -0
  267. package/src/scene-objects.js +31 -139
  268. package/src/scenes.js +15 -105
  269. package/src/semantic-edit.js +2 -5
  270. package/src/set-pieces.jsx +183 -0
  271. package/src/settings-menu.jsx +3 -11
  272. package/src/shell/BottomDock.jsx +9 -51
  273. package/src/shell/DetailsSlot.jsx +16 -200
  274. package/src/shell/GhostsMenuGroup.jsx +74 -0
  275. package/src/shell/LibrarySlot.jsx +1 -3
  276. package/src/shell/MenuBar.jsx +3 -3
  277. package/src/shell/PreferencesDialog.jsx +15 -264
  278. package/src/shell/PreferencesSlot.jsx +2 -8
  279. package/src/shell/TopBar.jsx +5 -84
  280. package/src/shell/ViewportToolbar.jsx +10 -70
  281. package/src/shell/agent-glass.css +19 -6
  282. package/src/shell/details-selection.js +42 -0
  283. package/src/shell/ghosts-menu.css +22 -0
  284. package/src/shell/glass-regions.css +29 -3
  285. package/src/shell/preferences.css +6 -1
  286. package/src/shot-authoring.js +4 -7
  287. package/src/soft-shadows.js +37 -0
  288. package/src/stage-attach-frames.js +12 -12
  289. package/src/stage-canvas-rigs.jsx +3 -3
  290. package/src/stage-capture.jsx +42 -8
  291. package/src/stage-characters.jsx +22 -216
  292. package/src/stage-editor-gizmos.jsx +6 -6
  293. package/src/stage-environment.js +93 -0
  294. package/src/stage-hdr-builtins.js +107 -0
  295. package/src/stage-hdr-image.js +116 -0
  296. package/src/stage-hdr-library.js +70 -0
  297. package/src/stage-hdr-map.js +94 -0
  298. package/src/stage-hdr.js +130 -0
  299. package/src/stage-lighting.js +149 -0
  300. package/src/stage-occlusion.js +210 -0
  301. package/src/stage-sky.jsx +159 -0
  302. package/src/stage-startup-defaults.js +5 -9
  303. package/src/studio-actions.js +16 -14
  304. package/src/studio-agent-commands.js +19 -16
  305. package/src/studio-agent-motion.js +9 -9
  306. package/src/studio-agent-protocol.js +47 -77
  307. package/src/studio-app-binding.js +27 -47
  308. package/src/studio-asset-list.js +17 -0
  309. package/src/studio-contact-sheet.js +37 -5
  310. package/src/studio-elements.js +27 -7
  311. package/src/studio-entity-bounds.js +18 -0
  312. package/src/studio-error-codes.js +15 -0
  313. package/src/studio-export-framing.js +152 -0
  314. package/src/studio-lighting-check.js +103 -0
  315. package/src/studio-motion-visual.js +150 -0
  316. package/src/studio-schema-errors.js +80 -0
  317. package/src/studio-support-gap.js +74 -0
  318. package/src/styles.css +1 -19
  319. package/src/timeline-defaults.js +5 -0
  320. package/src/timeline-extent.js +8 -20
  321. package/src/tutorial-walk.js +17 -0
  322. package/src/ui-scrub.js +1 -1
  323. package/src/use-shot-camera-tracks.js +12 -0
  324. package/src/view-ghosts.js +97 -0
  325. package/src/view-ghosts.jsx +49 -0
  326. package/src/workflow/AgentPanel.jsx +47 -166
  327. package/src/workflow/AgentProgressCard.jsx +109 -0
  328. package/src/workflow/AgentReplyText.jsx +37 -0
  329. package/src/workflow/AgentTurnSteps.jsx +84 -0
  330. package/src/workflow/LoginPanel.jsx +140 -0
  331. package/src/workflow/WorkflowBuilder.jsx +7 -23
  332. package/src/workflow/agent-client.js +54 -51
  333. package/src/workflow/agent-panel.css +71 -1
  334. package/src/workflow/agent-progress-card.css +167 -0
  335. package/src/workflow/agent-progress-view.js +47 -0
  336. package/src/workflow/agent-turn-steps.css +113 -0
  337. package/src/workflow/agent-turn.js +191 -0
  338. package/src/workflow/login-client.js +34 -0
  339. package/src/workflow/motion-input.js +18 -31
  340. package/src/workflow/node-schema.js +1 -1
  341. package/src/workflow/reply-markdown.js +69 -0
  342. package/src/workflow/scene-asset-sync.js +8 -8
  343. package/tools/agent-session-stats.mjs +61 -0
  344. package/tools/dev-full.mjs +5 -56
  345. package/tools/eslint-baseline.json +12 -13
  346. package/tools/knip-baseline.json +0 -179
  347. package/tools/loc-baseline.json +31 -81
  348. package/tools/motion3/extract-body.mjs +103 -0
  349. package/tools/motion3/extract-rig.mjs +85 -0
  350. package/tools/process-supervisor.mjs +0 -88
  351. package/tools/run-tests.mjs +9 -125
  352. package/bin/agent/motion-runtime.mjs +0 -76
  353. package/dist/ardy/cskel27-rest.json +0 -557
  354. package/dist/assets/analytics-C9pMpW7s.js +0 -1
  355. package/dist/assets/app-B_2XB9rw.css +0 -1
  356. package/dist/assets/app-DAuvKPP8.js +0 -4920
  357. package/dist/assets/config-Bx7pYsD9.js +0 -1
  358. package/dist/assets/config-DeoFTYzb.css +0 -1
  359. package/dist/assets/demo-CvKuBgy5.js +0 -1
  360. package/dist/assets/scene-asset-sync-DKkpjKBV.js +0 -19
  361. package/dist/assets/scene-asset-sync-DjJ_cJ2R.css +0 -1
  362. package/dist/assets/ticket-BPk2Ni95.js +0 -1
  363. package/dist/assets/workflow-jJRBR94Z.js +0 -179
  364. package/dist/demo/walk-then-stop.npz +0 -0
  365. package/mcp/ardy-prompts.mjs +0 -218
  366. package/src/ardy/auto-fix-panel.css +0 -108
  367. package/src/ardy/auto-physics.js +0 -1194
  368. package/src/ardy/client.js +0 -153
  369. package/src/ardy/convert.js +0 -313
  370. package/src/ardy/cskel27-neutral.js +0 -39
  371. package/src/ardy/cskel27.js +0 -77
  372. package/src/ardy/export.js +0 -165
  373. package/src/ardy/fix-collisions.js +0 -2257
  374. package/src/ardy/foot-lock.js +0 -230
  375. package/src/ardy/motion-calibration.js +0 -118
  376. package/src/ardy/motion-edit.js +0 -213
  377. package/src/ardy/motion-url.js +0 -55
  378. package/src/ardy/mp4-duration.js +0 -102
  379. package/src/ardy/npz.js +0 -595
  380. package/src/ardy/physics-panel.css +0 -21
  381. package/src/ardy/physics-panel.jsx +0 -89
  382. package/src/ardy/physics-refine.js +0 -111
  383. package/src/ardy/physics-review.js +0 -567
  384. package/src/ardy/physics-temporal.js +0 -54
  385. package/src/ardy/platform-fit-panel.css +0 -64
  386. package/src/ardy/platform-fit-panel.jsx +0 -41
  387. package/src/ardy/platform-fit.js +0 -326
  388. package/src/ardy/playback.js +0 -711
  389. package/src/ardy/pose-pin.js +0 -97
  390. package/src/ardy/prompt-clips.js +0 -30
  391. package/src/ardy/retime.js +0 -211
  392. package/src/ardy/root-drop.js +0 -369
  393. package/src/ardy/timeline-resize.js +0 -13
  394. package/src/ardy/to-cskel27.js +0 -225
  395. package/src/ardy/trim.js +0 -33
  396. package/src/ardy/waypoints.js +0 -369
  397. package/src/ardy-bridge-contract.js +0 -281
  398. package/src/domains/motion/motion-video-capture.js +0 -664
  399. package/src/i2v-motion-client.js +0 -77
  400. package/src/i2v-motion-studio.jsx +0 -180
  401. package/src/line-edit.js +0 -1348
  402. package/src/motion/generation.js +0 -105
  403. package/src/motion-readiness-ui.jsx +0 -67
  404. package/src/motion-readiness.js +0 -40
  405. package/src/motion-resources.js +0 -177
  406. package/src/motion-store.js +0 -65
  407. package/src/motion-trail.js +0 -601
  408. package/src/multimodel-ingest.js +0 -394
  409. package/src/panels/PromptBlocksPanel.jsx +0 -444
  410. package/src/panels/VideoCapturePanel.jsx +0 -181
  411. package/src/pose-extract/browser.js +0 -42
  412. package/src/pose-extract/detector.js +0 -100
  413. package/src/pose-extract/fit.js +0 -227
  414. package/src/pose-extract/image-frame.js +0 -51
  415. package/src/pose-extract/index.js +0 -58
  416. package/src/pose-extract/keyframes.js +0 -74
  417. package/src/pose-extract/landmarks.js +0 -162
  418. package/src/pose-extract/mirror.js +0 -153
  419. package/src/pose-extract/take.js +0 -131
  420. package/src/pose-extract/video-frames.js +0 -91
  421. package/src/take-recipe.js +0 -165
  422. package/src/trail-key-conflicts.js +0 -39
  423. package/src/trail-pick.js +0 -59
  424. package/src/use-i2v-capture-modal.js +0 -15
  425. package/tools/ardy/BRIDGE.md +0 -37
  426. package/tools/ardy/GVHMR-NPZ.md +0 -68
  427. package/tools/ardy/README.md +0 -124
  428. package/tools/ardy/__pycache__/cclay_gvhmr_worker.cpython-313.pyc +0 -0
  429. package/tools/ardy/artifacts.mjs +0 -34
  430. package/tools/ardy/bridge.mjs +0 -1732
  431. package/tools/ardy/bvh-cskel27.mjs +0 -1265
  432. package/tools/ardy/cclay_constrained_generate.py +0 -561
  433. package/tools/ardy/cclay_gvhmr_worker.py +0 -264
  434. package/tools/ardy/cclay_motion_edit.py +0 -510
  435. package/tools/ardy/cclay_sequence_generate.py +0 -705
  436. package/tools/ardy/cclay_worker.py +0 -304
  437. package/tools/ardy/dump-npz.py +0 -205
  438. package/tools/ardy/extract-rest.mjs +0 -299
  439. package/tools/ardy/extract.mjs +0 -507
  440. package/tools/ardy/footage.mjs +0 -467
  441. package/tools/ardy/gvhmr-floor.mjs +0 -102
  442. package/tools/ardy/gvhmr-to-cskel27.mjs +0 -21
  443. package/tools/ardy/gvhmr_fastpath.py +0 -168
  444. package/tools/ardy/gvhmr_trajectory.py +0 -240
  445. package/tools/ardy/merge-text-encoder.py +0 -160
  446. package/tools/ardy/mocap-metrics.mjs +0 -200
  447. package/tools/ardy/mocap-quality-gate.mjs +0 -110
  448. package/tools/ardy/motion-stabilize.mjs +0 -348
  449. package/tools/ardy/npz.mjs +0 -414
  450. package/tools/ardy/pose-to-npz.mjs +0 -106
  451. package/tools/ardy/prompt-limits.mjs +0 -5
  452. package/tools/ardy/run-edit-on-box.sh +0 -73
  453. package/tools/ardy/run-local.mjs +0 -233
  454. package/tools/ardy/run-on-box.sh +0 -593
  455. package/tools/ardy/run-sequence-on-box.sh +0 -177
  456. package/tools/ardy/runners/gvhmr-worker.mjs +0 -206
  457. package/tools/ardy/runners/index.mjs +0 -18
  458. package/tools/ardy/runners/local.mjs +0 -455
  459. package/tools/ardy/runners/proc.mjs +0 -125
  460. package/tools/ardy/runners/remote.mjs +0 -252
  461. package/tools/ardy/setup-local.mjs +0 -189
  462. package/tools/ardy/setup-text-encoder-on-box.sh +0 -93
  463. package/tools/ardy/setup-text-encoder.py +0 -306
  464. package/tools/ardy/smpl-cskel27.mjs +0 -178
  465. package/tools/ardy/visual-qa.mjs +0 -196
  466. package/tools/ardy/vq-car.mjs +0 -52
  467. package/tools/bench/EXP3.md +0 -61
  468. package/tools/bench/cclay_bench_extract_incam.py +0 -125
  469. package/tools/bench/cclay_bench_extract_obs.py +0 -204
  470. package/tools/bench/cclay_bench_runner.py +0 -42
  471. package/tools/bench/cube-contact.mjs +0 -162
  472. package/tools/bench/exp3.mjs +0 -152
  473. package/tools/bench/extract-bench-lib.mjs +0 -216
  474. package/tools/bench/extract-bench.mjs +0 -302
  475. package/tools/bench/fal-generate.mjs +0 -88
  476. package/tools/bench/fit/README.md +0 -189
  477. package/tools/bench/fit/camera.mjs +0 -59
  478. package/tools/bench/fit/contact.mjs +0 -419
  479. package/tools/bench/fit/footlock.mjs +0 -234
  480. package/tools/bench/fit/motion.mjs +0 -85
  481. package/tools/bench/fit/pin.mjs +0 -27
  482. package/tools/bench/fit/remote.mjs +0 -105
  483. package/tools/bench/fit-bench.mjs +0 -126
  484. package/tools/bench/fit-sanity.mjs +0 -45
  485. package/tools/bench/metrics.mjs +0 -313
  486. package/tools/bench/obs/depth.mjs +0 -258
  487. package/tools/bench/obs/extrinsics.mjs +0 -175
  488. package/tools/bench/obs/fit_mannequin_betas.py +0 -340
  489. package/tools/bench/obs/ground.mjs +0 -294
  490. package/tools/bench/obs/heading.mjs +0 -151
  491. package/tools/bench/obs/ladder.mjs +0 -555
  492. package/tools/bench/obs/mannequin-betas.json +0 -124
  493. package/tools/bench/obs/remote.mjs +0 -83
  494. package/tools/bench/obs/rest_joints.py +0 -52
  495. package/tools/bench/obs/ybot-targets.mjs +0 -49
  496. package/tools/bench/obs-bench.mjs +0 -520
  497. package/tools/bench/score.mjs +0 -343
  498. package/tools/bench/summarize.mjs +0 -86
  499. package/tools/demo-worker/README.md +0 -137
  500. package/tools/demo-worker/api-client.mjs +0 -233
  501. package/tools/demo-worker/generate.mjs +0 -301
  502. package/tools/demo-worker/index.mjs +0 -466
  503. package/tools/demo-worker/sign-core.mjs +0 -112
  504. package/tools/demo-worker/sign.mjs +0 -161
  505. package/tools/gt-render/browser.mjs +0 -182
  506. package/tools/gt-render/camera-math.mjs +0 -276
  507. package/tools/gt-render/page.mjs +0 -267
  508. package/tools/gt-render/render.mjs +0 -514
  509. package/tools/gt-render/scene-box.mjs +0 -31
  510. package/tools/gt-render/take-transform.mjs +0 -87
  511. package/tools/kimodo/compare-seam.mjs +0 -108
  512. package/tools/kimodo/constraints.mjs +0 -244
  513. package/tools/kimodo/edit.mjs +0 -259
  514. package/tools/kimodo/effector-constraints.mjs +0 -200
  515. package/tools/kimodo/generate.mjs +0 -646
  516. package/tools/kimodo/local-output.mjs +0 -265
  517. package/tools/kimodo/measure-pose.mjs +0 -65
  518. package/tools/kimodo/measure-preserve.mjs +0 -899
  519. package/tools/kimodo/measure-waypoints.mjs +0 -55
  520. package/tools/kimodo/mlx-generate.py +0 -111
  521. package/tools/kimodo/pose-constraints.mjs +0 -248
  522. package/tools/kimodo/preserve-mask.mjs +0 -543
  523. package/tools/kimodo/read-npz.mjs +0 -189
  524. package/tools/kimodo/run-edit-on-box.mjs +0 -155
  525. package/tools/kimodo/run-sequence-on-box.mjs +0 -178
  526. package/tools/kimodo/runner.mjs +0 -284
  527. package/tools/kimodo/seam-batch.mjs +0 -77
  528. package/tools/kimodo/setup-local.mjs +0 -30
  529. package/tools/kimodo/setup-on-box.sh +0 -339
  530. package/tools/kimodo/soma77-to-cskel27.mjs +0 -305
  531. package/tools/morphgs/assets/gen_truth.py +0 -39
  532. package/tools/morphgs/assets/mesh_ori_rig.txt +0 -27
  533. package/tools/morphgs/assets/playback-check.mjs +0 -30
  534. package/tools/morphgs/demo-gate.sh +0 -26
  535. package/tools/morphgs/fbx2morphgs.mjs +0 -68
  536. package/tools/morphgs/morphgs-to-cskel27.mjs +0 -105
  537. package/tools/morphgs/patches/preprocess_src-none-mode.patch +0 -76
  538. package/tools/morphgs/setup-on-cluster.sh +0 -126
  539. package/tools/projflow/driver.py +0 -1069
  540. package/tools/projflow/generate.mjs +0 -805
  541. package/tools/projflow/hml22-to-cskel27.mjs +0 -735
  542. package/tools/projflow/line-edit-job.mjs +0 -547
  543. package/tools/projflow/replay.mjs +0 -452
  544. package/tools/projflow/runner.mjs +0 -269
  545. package/tools/projflow/service.mjs +0 -742
  546. package/tools/track/DESIGN.md +0 -513
  547. package/tools/track/backfill-provenance.mjs +0 -116
  548. package/tools/track/budget.mjs +0 -8
  549. package/tools/track/check-rig.mjs +0 -209
  550. package/tools/track/diagnostics.schema.json +0 -60
  551. package/tools/track/export-rig.mjs +0 -256
  552. package/tools/track/fallback.mjs +0 -7
  553. package/tools/track/fk-parity-fixture.mjs +0 -161
  554. package/tools/track/gate.mjs +0 -349
  555. package/tools/track/masks.mjs +0 -318
  556. package/tools/track/metrics.mjs +0 -201
  557. package/tools/track/publish-obs.mjs +0 -108
  558. package/tools/track/py/check_env.py +0 -61
  559. package/tools/track/py/eval_lr.py +0 -229
  560. package/tools/track/py/lr_viterbi.py +0 -294
  561. package/tools/track/py/masks.py +0 -405
  562. package/tools/track/py/objective.py +0 -382
  563. package/tools/track/py/rig.py +0 -508
  564. package/tools/track/py/scene.py +0 -326
  565. package/tools/track/py/test_joint_indices.py +0 -123
  566. package/tools/track/py/test_lr_viterbi.py +0 -195
  567. package/tools/track/py/test_masks.py +0 -229
  568. package/tools/track/py/test_rig.py +0 -288
  569. package/tools/track/py/test_scene.py +0 -354
  570. package/tools/track/py/test_track.py +0 -328
  571. package/tools/track/py/track.py +0 -411
  572. package/tools/track/remote.mjs +0 -140
  573. package/tools/track/rig-dump.mjs +0 -227
  574. package/tools/track/run-box-tests.mjs +0 -14
  575. package/tools/track/run-box.mjs +0 -168
  576. package/tools/track/setup-box.sh +0 -59
  577. package/tools/track/study-2d.mjs +0 -728
  578. /package/src/{ardy → motion}/collision-blockers.js +0 -0
  579. /package/src/{ardy → motion}/ground.js +0 -0
  580. /package/src/{ardy → motion}/ik-drag.js +0 -0
  581. /package/src/{ardy → motion}/ik-key-json.js +0 -0
  582. /package/src/{ardy → motion}/ik.js +0 -0
  583. /package/src/{ardy → motion}/physics-surface.js +0 -0
  584. /package/src/{ardy → motion}/playback-clock.js +0 -0
  585. /package/src/{ardy → motion}/range-pin.js +0 -0
@@ -1,369 +0,0 @@
1
- import { sliceMotion } from "./trim.js";
2
-
3
- // A vertical drop authored ONTO a take. ARDY generates motion on flat
4
- // ground — nothing in a generated clip can carry a body off a 14 m roof.
5
- // The plunge is previs staging, not motion synthesis, so it is applied to
6
- // the decoded clip as a rigid vertical offset: every joint of a frame moves
7
- // down by the same amount, and the amount follows a gravity curve.
8
- //
9
- // Seconds, not frames: a take crosses two clocks on its way in (ARDY's
10
- // 20 fps, the 24 fps production timeline), and a boundary in seconds means
11
- // the caller never has to know which side of the retime it is speaking to.
12
-
13
- /** Validated {fromS, toS, meters} or null — malformed input is no drop. */
14
- export function normalizeRootDrop(drop) {
15
- if (!drop || typeof drop !== "object" || Array.isArray(drop)) return null;
16
- const fromS = Number(drop.fromS ?? drop.from_s);
17
- const toS = Number(drop.toS ?? drop.to_s);
18
- const meters = Number(drop.meters);
19
- if (!Number.isFinite(fromS) || !Number.isFinite(toS) || !Number.isFinite(meters)) return null;
20
- if (fromS < 0 || toS <= fromS || meters <= 0) return null;
21
- return { fromS, toS, meters };
22
- }
23
-
24
- /** Point-in-footprint on the floor plane, honouring the support's yaw. */
25
- function insideSupport(support, px, pz) {
26
- const yaw = ((support.rotDeg ?? 0) * Math.PI) / 180;
27
- const cos = Math.cos(yaw);
28
- const sin = Math.sin(yaw);
29
- const dx = px - support.x;
30
- const dz = pz - support.z;
31
- const lx = cos * dx - sin * dz;
32
- const lz = sin * dx + cos * dz;
33
- return Math.abs(lx) <= support.width / 2 && Math.abs(lz) <= support.depth / 2;
34
- }
35
-
36
- const SUPPORT_FEET = [21, 22, 25, 26];
37
- const smoothstep = (value) => {
38
- const t = Math.max(0, Math.min(1, value));
39
- return t * t * (3 - 2 * t);
40
- };
41
-
42
- /**
43
- * Lift a take onto an explicitly authored scene surface. ARDY clips are
44
- * normally rooted on the deck, so a performer climbing onto a prop needs a
45
- * small, time-continuous offset while their root is inside that prop's
46
- * footprint. We require a real upward root trend before applying anything;
47
- * a flat walk through a prop therefore stays untouched.
48
- *
49
- * `supports` are world-space rectangles with an explicit `supportY` (the top
50
- * of the surface). `subjectX/Y/Z` supply the character's scene anchor and
51
- * `worldScale` converts canonical clip units to scene metres, matching the
52
- * transform used by `autoRoofDrop`. The input motion is never mutated. The
53
- * returned object carries `surfaceRise` diagnostics.
54
- */
55
- export function applySupportRise(
56
- motion,
57
- supports,
58
- { subjectX = 0, subjectY = 0, subjectZ = 0, rotationDeg = 0, minRise = 0.08, minSlope = 0.04, lookbackFrames = 6, blendFrames = 6, maxOffset = 1.5, worldScale = 1 } = {},
59
- ) {
60
- if (!motion || !Number.isFinite(motion.fps) || motion.fps <= 0 || !motion.rootPos || !motion.posedJoints) return motion;
61
- const frames = Number(motion.frames);
62
- if (!Number.isInteger(frames) || frames < 2 || motion.rootPos.length < frames * 3) return motion;
63
- const joints = motion.posedJoints.length / (frames * 3);
64
- if (!Number.isInteger(joints) || joints <= 0) return motion;
65
- const scale = Number.isFinite(Number(worldScale)) && Number(worldScale) > 0 ? Number(worldScale) : 1;
66
- if (!Array.isArray(supports) || !supports.length) return motion;
67
- const candidates = supports.filter((support) =>
68
- support && Number.isFinite(Number(support.supportY)) && Number(support.width) > 0 && Number(support.depth) > 0,
69
- );
70
- if (!candidates.length) return motion;
71
- const radians = (Number(rotationDeg) || 0) * Math.PI / 180;
72
- const cos = Math.cos(radians), sin = Math.sin(radians);
73
- const worldAt = (frame) => {
74
- const dx = motion.rootPos[frame * 3] - motion.rootPos[0];
75
- const dz = motion.rootPos[frame * 3 + 2] - motion.rootPos[2];
76
- return { x: Number(subjectX) + (dx * cos + dz * sin) * scale, z: Number(subjectZ) + (-dx * sin + dz * cos) * scale };
77
- };
78
- const points = Array.from({ length: frames }, (_, frame) => worldAt(frame));
79
- const feet = SUPPORT_FEET.filter((joint) => joint < joints);
80
- const footWorldAt = (frame, joint) => {
81
- const p = (frame * joints + joint) * 3;
82
- // posedJoints and rootPos are both frame-local; subtract the root from
83
- // the same frame before rotating into world space. Using frame zero here
84
- // made a walking foot drift with the accumulated root travel and caused
85
- // support detection to miss later chair/platform contacts.
86
- const dx = motion.posedJoints[p] - motion.rootPos[frame * 3];
87
- const dz = motion.posedJoints[p + 2] - motion.rootPos[frame * 3 + 2];
88
- return { x: Number(subjectX) + (dx * cos + dz * sin) * scale, z: Number(subjectZ) + (-dx * sin + dz * cos) * scale };
89
- };
90
- const inside = candidates.map((support) => points.map((point, frame) => insideSupport({
91
- x: Number(support.x) || 0, z: Number(support.z) || 0,
92
- rotDeg: Number(support.rotDeg) || 0, width: Number(support.width), depth: Number(support.depth),
93
- }, point.x, point.z) || feet.some((joint) => {
94
- const foot = footWorldAt(frame, joint);
95
- return insideSupport({
96
- x: Number(support.x) || 0, z: Number(support.z) || 0,
97
- rotDeg: Number(support.rotDeg) || 0, width: Number(support.width), depth: Number(support.depth),
98
- }, foot.x, foot.z);
99
- })));
100
- let selected = null;
101
- for (let si = 0; si < candidates.length; si += 1) {
102
- const support = candidates[si];
103
- // A performer often enters a prop's footprint before lifting a foot
104
- // (approach, brace, then climb). Search the first second of continuous
105
- // support occupancy instead of requiring the rise on the boundary frame.
106
- let entry = -1;
107
- for (let frame = 0; frame < frames; frame += 1) {
108
- if (!inside[si][frame]) { entry = -1; continue; }
109
- // A take can begin already standing on a platform. Treat frame 0 as
110
- // an entry so the same evidence search handles both approaches and
111
- // starts-on-support clips.
112
- if (entry < 0 && (frame === 0 || !inside[si][frame - 1])) entry = frame;
113
- if (entry < 0 || frame - entry > Math.round(motion.fps)) continue;
114
- const from = Math.max(0, frame - Math.max(1, Math.round(lookbackFrames)));
115
- // A foot can enter the footprint one or two frames before the body
116
- // commits to the climb. Look a short distance ahead, while retaining
117
- // the entry frame as the point where the blend begins.
118
- const evidenceFrame = Math.min(frames - 1, frame + Math.max(1, Math.round(lookbackFrames)));
119
- const rise = (motion.rootPos[evidenceFrame * 3 + 1] - motion.rootPos[from * 3 + 1]) * scale;
120
- const slope = rise / ((evidenceFrame - from) / motion.fps);
121
- if (rise < Number(minRise) || slope < Number(minSlope)) continue;
122
- if (!feet.length) continue;
123
- const supportRect = {
124
- x: Number(support.x) || 0, z: Number(support.z) || 0,
125
- rotDeg: Number(support.rotDeg) || 0, width: Number(support.width), depth: Number(support.depth),
126
- };
127
- const occupiedYs = [];
128
- for (let probe = evidenceFrame; probe < frames && inside[si][probe] && probe <= evidenceFrame + Math.round(motion.fps * 0.75); probe += 1) {
129
- // A climb often straddles the deck and the prop: one foot remains
130
- // on the floor while the other is already on the seat. Measuring the
131
- // minimum of *all* feet therefore used the deck foot as the seat
132
- // datum and left the climbing foot below the authored support. Use
133
- // only feet whose XZ footprint is actually on this support.
134
- const onSupport = feet.filter((joint) => {
135
- const foot = footWorldAt(probe, joint);
136
- return insideSupport(supportRect, foot.x, foot.z);
137
- });
138
- // Root occupancy is valid evidence while the pelvis is over a support
139
- // but the feet have not entered its rectangle yet. In that phase keep
140
- // the legacy all-foot fallback; once a foot is actually on the support,
141
- // use only those feet so a deck foot cannot set the seat datum.
142
- const ys = (onSupport.length ? onSupport : feet)
143
- .map((joint) => motion.posedJoints[(probe * joints + joint) * 3 + 1] * scale).filter(Number.isFinite);
144
- // If a second foot is still on the deck but its footprint overlaps
145
- // the prop edge, the lower sample is not the seat contact. The upper
146
- // supported foot is the conservative datum; when both feet are on
147
- // the same surface their heights agree.
148
- if (ys.length) occupiedYs.push(Math.max(...ys));
149
- }
150
- occupiedYs.sort((a, b) => a - b);
151
- const observedFootY = occupiedYs[Math.floor(occupiedYs.length * 0.7)];
152
- const onSupportAtEvidence = feet.filter((joint) => {
153
- const foot = footWorldAt(evidenceFrame, joint);
154
- return insideSupport(supportRect, foot.x, foot.z);
155
- });
156
- const footYs = (onSupportAtEvidence.length ? onSupportAtEvidence : feet)
157
- .map((joint) => motion.posedJoints[(evidenceFrame * joints + joint) * 3 + 1] * scale).filter(Number.isFinite);
158
- if (!footYs.length) continue;
159
- const baseY = Number(subjectY) || 0;
160
- const offsetWorld = Number(support.supportY) - (baseY + (Number.isFinite(observedFootY) ? observedFootY : Math.min(...footYs)));
161
- if (!(offsetWorld > 0.01) || offsetWorld > Number(maxOffset)) continue;
162
- selected = {
163
- si,
164
- frame,
165
- support,
166
- offset: offsetWorld / scale,
167
- offsetWorld,
168
- rise,
169
- slope,
170
- baseRootY: motion.rootPos[from * 3 + 1],
171
- };
172
- break;
173
- }
174
- if (selected) break;
175
- }
176
- if (!selected) return motion;
177
- const { si, frame: enter, offset, offsetWorld, support, rise, slope, baseRootY } = selected;
178
- let exit = frames - 1;
179
- for (let frame = enter + 1; frame < frames; frame += 1) {
180
- if (!inside[si][frame]) { exit = frame; break; }
181
- }
182
- // Some shots climb and then step down while the root remains inside a
183
- // generous footprint (a chair turn, a platform landing, or a jump in
184
- // place). Release the lift when the root has come back near its pre-climb
185
- // level; otherwise the rigid support offset would leave the performer
186
- // floating even though the take has visibly descended.
187
- let release = exit;
188
- const descendThreshold = Math.max(Number(minRise), 0.08);
189
- let peakRootY = motion.rootPos[enter * 3 + 1];
190
- for (let frame = enter + 1; frame <= exit; frame += 1) {
191
- peakRootY = Math.max(peakRootY, motion.rootPos[frame * 3 + 1]);
192
- const current = motion.rootPos[frame * 3 + 1];
193
- if (peakRootY - current >= descendThreshold && current <= baseRootY + descendThreshold * 0.5) {
194
- release = frame;
195
- break;
196
- }
197
- }
198
- const blend = Math.max(1, Math.round(blendFrames));
199
- const offsets = new Float32Array(frames);
200
- for (let frame = enter; frame < frames; frame += 1) {
201
- const up = smoothstep((frame - enter + 1) / blend);
202
- const down = release < frames - 1 ? smoothstep((release - frame) / blend) : 1;
203
- offsets[frame] = offset * Math.min(up, down);
204
- }
205
- const rootPos = Float32Array.from(motion.rootPos);
206
- const posedJoints = Float32Array.from(motion.posedJoints);
207
- const jointCount = Math.round(posedJoints.length / frames / 3);
208
- for (let frame = 0; frame < frames; frame += 1) {
209
- const dy = offsets[frame];
210
- if (!dy) continue;
211
- rootPos[frame * 3 + 1] += dy;
212
- for (let joint = 0; joint < jointCount; joint += 1) posedJoints[(frame * jointCount + joint) * 3 + 1] += dy;
213
- }
214
- return {
215
- ...motion,
216
- rootPos,
217
- posedJoints,
218
- surfaceRise: { applied: true, supportY: Number(support.supportY), offset, offsetWorld, worldScale: scale, enterFrame: enter, exitFrame: exit, releaseFrame: release, rise, slope },
219
- };
220
- }
221
-
222
- /**
223
- * Stage a fall the author did not have to ask for: a character standing on a
224
- * raised support (a roof — place_character's y) whose take walks past the
225
- * support's edge should drop, because ARDY only generates flat-ground motion.
226
- *
227
- * `subject` is { x, z, y, rotationDeg } — the character's blocking, with the
228
- * take's root rotation. `supports` are world-space tops: { x, z, rotDeg,
229
- * topY, width, depth }. The walk is sampled with the same root convention
230
- * playback uses (frame-zero anchored, yaw-rotated into scene space).
231
- *
232
- * Returns a { fromS, toS, meters } drop, or null when the character is on
233
- * the ground, never stood on a support, or never leaves it — null means
234
- * "stage nothing", so this is safe to leave on the load path.
235
- */
236
- export function autoRoofDrop(motion, subject, supports, { gravity = 9.81, topTolerance = 0.3, fallTimeScale = 1.15, worldScale = 1 } = {}) {
237
- if (!motion || !Number.isFinite(motion.fps) || motion.fps <= 0 || !motion.rootPos) return null;
238
- const frames = motion.frames;
239
- if (!Number.isFinite(frames) || frames < 2) return null;
240
- const y = Number(subject?.y) || 0;
241
- if (y <= 0.05 || !Array.isArray(supports) || supports.length === 0) return null;
242
- const scale = Number.isFinite(Number(worldScale)) && Number(worldScale) > 0 ? Number(worldScale) : 1;
243
-
244
- const radians = ((Number.isFinite(subject.rotationDeg) ? subject.rotationDeg : 0) * Math.PI) / 180;
245
- const cos = Math.cos(radians);
246
- const sin = Math.sin(radians);
247
- const worldAt = (frame) => {
248
- const dx = motion.rootPos[frame * 3] - motion.rootPos[0];
249
- const dz = motion.rootPos[frame * 3 + 2] - motion.rootPos[2];
250
- return {
251
- x: subject.x + (dx * cos + dz * sin) * scale,
252
- z: subject.z + (-dx * sin + dz * cos) * scale,
253
- };
254
- };
255
-
256
- const start = worldAt(0);
257
- const carriers = supports.filter((support) =>
258
- support.width > 0 && support.depth > 0 &&
259
- Math.abs(support.topY - y) <= topTolerance &&
260
- insideSupport(support, start.x, start.z));
261
- if (carriers.length === 0) return null;
262
-
263
- for (let frame = 1; frame < frames; frame += 1) {
264
- const point = worldAt(frame);
265
- if (carriers.some((support) => insideSupport(support, point.x, point.z))) continue;
266
- // Land on the tallest lower support under the exit point, else the street.
267
- const landing = supports.reduce((top, support) =>
268
- support.topY < y - topTolerance && support.topY > top && insideSupport(support, point.x, point.z)
269
- ? support.topY
270
- : top, 0);
271
- const meters = y - landing;
272
- if (meters <= 0) return null;
273
- const fromS = frame / motion.fps;
274
- // Near-real gravity: a lightly stretched clock keeps weight without
275
- // drifting into moon-fall. The readability comes from applyAutoFall's
276
- // ballistic arc and impact cut, not from slowing the clock down.
277
- return { fromS, toS: fromS + Math.sqrt((2 * meters) / gravity) * fallTimeScale, meters };
278
- }
279
- return null;
280
- }
281
-
282
- /**
283
- * Bake an auto-staged fall so it reads like a stunt, not a glitch:
284
- * - past the edge the root leaves the authored walk path and flies a true
285
- * ballistic arc — the exit velocity carries, gravity owns the vertical;
286
- * - the horizontal drift stops at impact (bodies do not keep strolling);
287
- * - the take is cut just after the landing, because whatever the flat-ground
288
- * clip does next (walking away twelve metres underground-level) is comedy.
289
- * Explicit MCP drops keep the rigid applyRootDrop bake below.
290
- */
291
- export function applyAutoFall(motion, spec, { landHoldS = 0.35, launchLookbackS = 0.15, worldScale = 1 } = {}) {
292
- if (!spec || !motion || !Number.isFinite(motion.fps) || motion.fps <= 0) return motion;
293
- const fps = motion.fps;
294
- const scale = Number.isFinite(Number(worldScale)) && Number(worldScale) > 0 ? Number(worldScale) : 1;
295
- const fExit = Math.max(0, Math.round(spec.fromS * fps));
296
- if (fExit >= motion.frames - 1) return motion;
297
- const fallS = Math.max(spec.toS - spec.fromS, 1 / fps);
298
- const joints = Math.round(motion.posedJoints.length / motion.frames / 3);
299
- const rootPos = Float32Array.from(motion.rootPos);
300
- const posedJoints = Float32Array.from(motion.posedJoints);
301
- const lookback = Math.max(1, Math.round(launchLookbackS * fps));
302
- const f0 = Math.max(0, fExit - lookback);
303
- const span = Math.max(1, fExit - f0);
304
- const vx = ((rootPos[fExit * 3] - rootPos[f0 * 3]) / span) * fps;
305
- const vz = ((rootPos[fExit * 3 + 2] - rootPos[f0 * 3 + 2]) / span) * fps;
306
- const exitX = rootPos[fExit * 3];
307
- const exitZ = rootPos[fExit * 3 + 2];
308
- const fLand = Math.min(motion.frames - 1, Math.ceil(spec.toS * fps));
309
- for (let f = fExit + 1; f < motion.frames; f += 1) {
310
- const t = (f - fExit) / fps;
311
- const progress = Math.min(t / fallS, 1);
312
- const air = Math.min(t, fallS);
313
- const dy = -(spec.meters / scale) * progress * progress;
314
- const dx = exitX + vx * air - rootPos[f * 3];
315
- const dz = exitZ + vz * air - rootPos[f * 3 + 2];
316
- rootPos[f * 3] += dx;
317
- rootPos[f * 3 + 1] += dy;
318
- rootPos[f * 3 + 2] += dz;
319
- for (let j = 0; j < joints; j += 1) {
320
- const base = (f * joints + j) * 3;
321
- posedJoints[base] += dx;
322
- posedJoints[base + 1] += dy;
323
- posedJoints[base + 2] += dz;
324
- }
325
- }
326
- const rotMats = Float32Array.from(motion.rotMats);
327
- for (let f = fLand + 1; f < motion.frames; f += 1) {
328
- rootPos.set(rootPos.subarray(fLand * 3, fLand * 3 + 3), f * 3);
329
- posedJoints.set(
330
- posedJoints.subarray(fLand * joints * 3, (fLand + 1) * joints * 3),
331
- f * joints * 3,
332
- );
333
- rotMats.set(
334
- rotMats.subarray(fLand * joints * 9, (fLand + 1) * joints * 9),
335
- f * joints * 9,
336
- );
337
- }
338
- const baked = { ...motion, rootPos, posedJoints, rotMats };
339
- const fEnd = Math.min(motion.frames - 1, Math.ceil((spec.toS + landHoldS) * fps));
340
- return fEnd < motion.frames - 1 ? sliceMotion(baked, 0, fEnd) : baked;
341
- }
342
-
343
- /**
344
- * The clip with the drop applied. The input clip is never mutated — the
345
- * caller may hold it as a trim source — and an invalid drop returns the
346
- * clip untouched, so this is safe to leave on the load path unconditionally.
347
- *
348
- * The curve is t² (uniform acceleration): a body leaving a roof gathers
349
- * speed, and an eased-both-ends fall reads as a elevator, not gravity.
350
- */
351
- export function applyRootDrop(motion, drop, { worldScale = 1 } = {}) {
352
- const spec = normalizeRootDrop(drop);
353
- if (!spec || !motion || !Number.isFinite(motion.fps) || motion.fps <= 0) return motion;
354
- const scale = Number.isFinite(Number(worldScale)) && Number(worldScale) > 0 ? Number(worldScale) : 1;
355
- const frames = motion.frames;
356
- if (!Number.isFinite(frames) || frames <= 0) return motion;
357
-
358
- const posedJoints = Float32Array.from(motion.posedJoints);
359
- const rootPos = Float32Array.from(motion.rootPos);
360
- const joints = Math.round(posedJoints.length / frames / 3);
361
- for (let f = 0; f < frames; f += 1) {
362
- const t = Math.min(Math.max((f / motion.fps - spec.fromS) / (spec.toS - spec.fromS), 0), 1);
363
- if (t === 0) continue;
364
- const dy = -(spec.meters / scale) * t * t;
365
- for (let j = 0; j < joints; j += 1) posedJoints[(f * joints + j) * 3 + 1] += dy;
366
- rootPos[f * 3 + 1] += dy;
367
- }
368
- return { ...motion, posedJoints, rootPos };
369
- }
@@ -1,13 +0,0 @@
1
- import { TIMELINE_FRAME_FPS } from "../scenes.js";
2
-
3
- const PROMPT_BLOCK_FRAMES = 2 * TIMELINE_FRAME_FPS;
4
- const PROMPT_RESIZE_BLOCK_PX = 120; // one deliberate drag step = one prompt block
5
-
6
- /** Resize from the immutable pointer-down frame. Keeping both the frame and
7
- * pixel origin fixed prevents a growing timeline from feeding its new frame
8
- * count back into the next pointermove and exploding exponentially. */
9
- export function promptResizeFrame(startFrame, startClientX, clientX) {
10
- const blocks = (clientX - startClientX) / PROMPT_RESIZE_BLOCK_PX;
11
- const blockDelta = Math.sign(blocks) * Math.round(Math.abs(blocks));
12
- return startFrame + blockDelta * PROMPT_BLOCK_FRAMES;
13
- }
@@ -1,225 +0,0 @@
1
- /**
2
- * CozyClayPoseV1 -> the two npz arrays cclay_constrained_generate.load_poses
3
- * reads (local_rot_mats 27x3x3, posed_joints 27x3; the generator then runs its
4
- * own FK, consulting only posed_joints[0] as the root).
5
- *
6
- * The 19 joints CozyClay authors map through each Mixamo bone's armature-space
7
- * rest rotation Rb (cskel27-rest.json): L = Rb @ basis @ Rb^T. ARDY has four
8
- * torso segments where Mixamo has three, so Mixamo Spine/Spine1 target ARDY
9
- * Spine1/Spine2, matching playback's map. The remaining joints get identity;
10
- * `filled_identity` records them and `rotation_constraint_indices` identifies
11
- * the rotations that are genuinely authored.
12
- *
13
- * Proportions are never hardcoded: bone offsets come from the reference frame
14
- * of the same base clip the pose will constrain (mirroring
15
- * motion_constraints.derive_bone_offsets), and the root rides on that frame's
16
- * own root. If ARDY ever reproportions cskel27, the clip proportions stay
17
- * correct by construction.
18
- */
19
-
20
- import {
21
- COZYCLAY_BONES,
22
- COZYCLAY_TO_CSKEL27,
23
- CSKEL27_JOINTS,
24
- } from "./cskel27.js";
25
- import { CSKEL27_NEUTRAL } from "./cskel27-neutral.js";
26
- import {
27
- basisQuaternionToLocalRotation,
28
- deriveBoneOffsets,
29
- forwardKinematics,
30
- } from "./convert.js";
31
-
32
- // Tolerance on |norm - 1| for pose quaternions, and on orthonormality /
33
- // determinant for emitted matrices. Float32-serialized source data is off by
34
- // ~1e-7 at worst, so 1e-6 is comfortably above input noise while still
35
- // catching real corruption.
36
- const UNIT_TOLERANCE = 1e-6;
37
-
38
- const IDENTITY = [
39
- [1, 0, 0],
40
- [0, 1, 0],
41
- [0, 0, 1],
42
- ];
43
-
44
- const SOURCE_BY_TARGET = new Map(
45
- COZYCLAY_BONES.map((source) => [
46
- CSKEL27_JOINTS[COZYCLAY_TO_CSKEL27[source]],
47
- source,
48
- ])
49
- );
50
-
51
- const CANONICAL_ROOT_Y = -Math.min(...CSKEL27_NEUTRAL.map((joint) => joint[1]));
52
-
53
- /** Floor-aligned CoreSkeleton27 reference used when no clip reference is
54
- * supplied. A generated motion is not a skeleton definition: borrowing its
55
- * frame-zero root made a rolling clip lower every authored pose by 10 cm.
56
- * The neutral skeleton is stable, deterministic, and keeps both toes at Y=0. */
57
- export function canonicalCskel27Reference() {
58
- return {
59
- local_rot_mats: CSKEL27_JOINTS.map(() => IDENTITY.map((row) => row.slice())),
60
- posed_joints: CSKEL27_NEUTRAL.map(([x, y, z]) => [x, y + CANONICAL_ROOT_Y, z]),
61
- };
62
- }
63
-
64
- function isFiniteNumber(value) {
65
- return typeof value === "number" && Number.isFinite(value);
66
- }
67
-
68
- function determinant3(m) {
69
- return (
70
- m[0][0] * (m[1][1] * m[2][2] - m[1][2] * m[2][1]) -
71
- m[0][1] * (m[1][0] * m[2][2] - m[1][2] * m[2][0]) +
72
- m[0][2] * (m[1][0] * m[2][1] - m[1][1] * m[2][0])
73
- );
74
- }
75
-
76
- function requireUnitQuaternion(q, bone) {
77
- if (!Array.isArray(q) || q.length !== 4 || !q.every(isFiniteNumber)) {
78
- throw new Error(
79
- `poseToCskel27: bone "${bone}" is not a [w, x, y, z] quaternion of four finite numbers`
80
- );
81
- }
82
- const norm = Math.hypot(q[0], q[1], q[2], q[3]);
83
- if (Math.abs(norm - 1) > UNIT_TOLERANCE) {
84
- throw new Error(
85
- `poseToCskel27: bone "${bone}" is not a unit quaternion (norm ${norm})`
86
- );
87
- }
88
- }
89
-
90
- // A matrix must stay inside the rotation group: rows orthonormal (unit
91
- // length, pairwise orthogonal) and right-handed.
92
- function requireRotationMatrix(m, label) {
93
- for (let i = 0; i < 3; i += 1) {
94
- const row = m[i];
95
- const normSq = row[0] * row[0] + row[1] * row[1] + row[2] * row[2];
96
- if (Math.abs(normSq - 1) > UNIT_TOLERANCE) {
97
- throw new Error(
98
- `poseToCskel27: ${label} is not orthonormal (row ${i} has squared length ${normSq})`
99
- );
100
- }
101
- for (let j = i + 1; j < 3; j += 1) {
102
- const other = m[j];
103
- const dot = row[0] * other[0] + row[1] * other[1] + row[2] * other[2];
104
- if (Math.abs(dot) > UNIT_TOLERANCE) {
105
- throw new Error(
106
- `poseToCskel27: ${label} is not orthonormal (rows ${i} and ${j} dot to ${dot})`
107
- );
108
- }
109
- }
110
- }
111
- const det = determinant3(m);
112
- if (Math.abs(det - 1) > UNIT_TOLERANCE) {
113
- throw new Error(`poseToCskel27: ${label} has determinant ${det}, not +1`);
114
- }
115
- }
116
-
117
- /**
118
- * Convert a CozyClayPoseV1 into the frame arrays the ARDY generator expects.
119
- * `rest` is the parsed public/ardy/cskel27-rest.json, `reference` a parsed
120
- * ardy.frame.v1 fixture from the base motion the pose will constrain.
121
- * Returns { local_rot_mats, posed_joints, filled_identity }.
122
- */
123
- export function poseToCskel27({ pose, rest, reference }) {
124
- if (!pose || typeof pose !== "object") {
125
- throw new Error(
126
- `poseToCskel27: pose is ${pose === null ? "null" : typeof pose}, expected an object`
127
- );
128
- }
129
- if (pose.schema !== "cozyclay.pose.v1") {
130
- throw new Error(
131
- `poseToCskel27: unsupported pose schema ${JSON.stringify(pose.schema)} — expected "cozyclay.pose.v1"`
132
- );
133
- }
134
- if (!pose.bones || typeof pose.bones !== "object" || Array.isArray(pose.bones)) {
135
- throw new Error("poseToCskel27: pose.bones must be an object keyed by mixamo bone name");
136
- }
137
- if (pose.root !== undefined) {
138
- if (!Array.isArray(pose.root) || pose.root.length !== 3 || !pose.root.every(isFiniteNumber)) {
139
- throw new Error("poseToCskel27: pose.root must be [x, y, z] finite metres when present");
140
- }
141
- }
142
-
143
- for (const bone of COZYCLAY_BONES) {
144
- if (!(bone in pose.bones)) {
145
- throw new Error(`poseToCskel27: pose.bones is missing "${bone}"`);
146
- }
147
- requireUnitQuaternion(pose.bones[bone], bone);
148
- }
149
-
150
- if (!rest || !Array.isArray(rest.joints)) {
151
- throw new Error("poseToCskel27: rest must be parsed cskel27-rest.json with a joints array");
152
- }
153
- const restByJoint = new Map();
154
- for (const entry of rest.joints) {
155
- if (!entry || typeof entry.name !== "string") {
156
- throw new Error("poseToCskel27: rest.joints entries must carry a string name");
157
- }
158
- if (entry.rest !== null) {
159
- if (
160
- !Array.isArray(entry.rest) ||
161
- entry.rest.length !== 3 ||
162
- !entry.rest.every(
163
- (row) => Array.isArray(row) && row.length === 3 && row.every(isFiniteNumber)
164
- )
165
- ) {
166
- throw new Error(
167
- `poseToCskel27: rest for "${entry.name}" is neither null nor a 3x3 finite matrix`
168
- );
169
- }
170
- }
171
- restByJoint.set(entry.name, entry.rest);
172
- }
173
-
174
- const local_rot_mats = new Array(CSKEL27_JOINTS.length);
175
- const filled_identity = [];
176
- const rotation_constraint_indices = [];
177
- for (let index = 0; index < CSKEL27_JOINTS.length; index += 1) {
178
- const name = CSKEL27_JOINTS[index];
179
- const sourceName = SOURCE_BY_TARGET.get(name);
180
- const rb = sourceName ? restByJoint.get(sourceName) : null;
181
- if (sourceName && rb !== null && rb !== undefined) {
182
- // L = Rb @ basis @ Rb^T; basisQuaternionToLocalRotation is the
183
- // quatToMat + basisToLocal composition from convert.js.
184
- local_rot_mats[index] = basisQuaternionToLocalRotation(
185
- pose.bones[sourceName],
186
- rb
187
- );
188
- rotation_constraint_indices.push(index);
189
- } else {
190
- // Fresh identity per joint so callers can never alias a shared
191
- // constant by mutating one row.
192
- local_rot_mats[index] = IDENTITY.map((row) => row.slice());
193
- filled_identity.push({
194
- joint: name,
195
- reason: sourceName ? "no rest rotation" : "not authored",
196
- });
197
- }
198
- }
199
-
200
- for (let index = 0; index < CSKEL27_JOINTS.length; index += 1) {
201
- requireRotationMatrix(
202
- local_rot_mats[index],
203
- `${CSKEL27_JOINTS[index]} (local_rot_mats[${index}])`
204
- );
205
- }
206
-
207
- // A reference may still supply different skeleton proportions, but its
208
- // frame-zero root is never copied. Placement is authored explicitly in
209
- // pose.root; otherwise the canonical floor-aligned neutral root is used.
210
- // This decouples body shape from whichever motion happened to be selected.
211
- const skeleton = reference ?? canonicalCskel27Reference();
212
- if (!Array.isArray(skeleton.posed_joints) || !Array.isArray(skeleton.local_rot_mats)) {
213
- throw new Error("poseToCskel27: reference must carry posed_joints and local_rot_mats");
214
- }
215
- const offsets = deriveBoneOffsets(skeleton.posed_joints, skeleton.local_rot_mats);
216
- const canonicalRoot = canonicalCskel27Reference().posed_joints[0];
217
- const posed_joints = forwardKinematics(local_rot_mats, offsets, pose.root ?? canonicalRoot);
218
-
219
- return {
220
- local_rot_mats,
221
- posed_joints,
222
- filled_identity,
223
- rotation_constraint_indices,
224
- };
225
- }
package/src/ardy/trim.js DELETED
@@ -1,33 +0,0 @@
1
- // trim.js — cut a loaded take to a frame range. The slice is a NEW motion
2
- // object in the exact npz-decoded shape; the caller keeps the original, so
3
- // trimming is non-destructive and re-trimming always cuts from the full
4
- // take. Frame 0 of the slice becomes the playback anchor: applyMotionFrame
5
- // re-anchors X/Z on the anchor frame, so a mid-clip cut plays at the
6
- // character's placement instead of teleporting to the original frame 0.
7
- // The spread carries every non-array field with the slice — `personScale`
8
- // included: a cut is the same performer, and a take that lost its stature
9
- // mid-edit would replay the remaining frames at the wrong stride length.
10
-
11
- import { CSKEL27_JOINTS } from "./cskel27.js";
12
-
13
- export function sliceMotion(motion, startFrame, endFrame) {
14
- if (!motion || !Number.isInteger(motion.frames) || motion.frames < 1) {
15
- throw new Error("sliceMotion: motion.frames must be a positive integer");
16
- }
17
- if (!Number.isInteger(startFrame) || !Number.isInteger(endFrame)) {
18
- throw new Error("sliceMotion: startFrame and endFrame must be integers");
19
- }
20
- if (startFrame < 0 || endFrame >= motion.frames || startFrame > endFrame) {
21
- throw new Error(`sliceMotion: range ${startFrame}..${endFrame} is outside 0..${motion.frames - 1}`);
22
- }
23
- const joints = CSKEL27_JOINTS.length;
24
- const frames = endFrame - startFrame + 1;
25
- return {
26
- ...motion,
27
- frames,
28
- rotMats: motion.rotMats.slice(startFrame * joints * 9, (endFrame + 1) * joints * 9),
29
- rootPos: motion.rootPos.slice(startFrame * 3, (endFrame + 1) * 3),
30
- posedJoints: motion.posedJoints.slice(startFrame * joints * 3, (endFrame + 1) * joints * 3),
31
- anchorFrame: 0,
32
- };
33
- }