cozyclay 2.1.1 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (577) hide show
  1. package/CHANGELOG.md +60 -0
  2. package/README.md +12 -30
  3. package/bin/agent/agent-routes.mjs +40 -113
  4. package/bin/agent/agent-runner.mjs +9 -10
  5. package/bin/agent/cliproxy-provider.mjs +135 -0
  6. package/bin/agent/credential-store.mjs +30 -7
  7. package/bin/agent/pi-tools.mjs +4 -1
  8. package/bin/agent/provider-keys.mjs +32 -0
  9. package/bin/agent/provider-login.mjs +110 -0
  10. package/bin/agent/provider-routes.mjs +99 -0
  11. package/bin/agent/providers.mjs +19 -97
  12. package/bin/agent/script-tool.mjs +17 -4
  13. package/bin/agent/studio-motion-reference.mjs +23 -0
  14. package/bin/agent/studio-prompt.mjs +1 -1
  15. package/bin/agent/studio-rebase-text.mjs +32 -0
  16. package/bin/agent/studio-rebase.mjs +26 -39
  17. package/bin/agent/studio-tools.mjs +9 -28
  18. package/bin/agent/tool-arguments.mjs +49 -0
  19. package/bin/agent/turn-frames.mjs +66 -0
  20. package/bin/codex-auth.mjs +9 -2
  21. package/bin/cozyclay.mjs +10 -116
  22. package/bin/live/cli.mjs +3 -3
  23. package/bin/mcp-runtime.mjs +2 -12
  24. package/bin/package-signature.mjs +0 -4
  25. package/dist/app/index.html +7 -6
  26. package/dist/assets/EXRLoader-CvVIvGVE.js +1 -0
  27. package/dist/assets/analytics-C9sUnndd.js +1 -0
  28. package/dist/assets/app-CCh--1Hc.js +5087 -0
  29. package/dist/assets/app-f-fkV5uP.css +1 -0
  30. package/dist/assets/compile-worker-CkxiD6lH.js +5 -0
  31. package/dist/assets/fflate.module-KbGj5-H6.js +5 -0
  32. package/dist/assets/{first-shot-handoff-msLI71g1.js → first-shot-handoff-CC4xe4HM.js} +1 -1
  33. package/dist/assets/{landing-ChUvB_zL.js → landing-DjHD8u7k.js} +1 -1
  34. package/dist/assets/scene-asset-sync-Hx_FzdOH.js +20 -0
  35. package/dist/assets/scene-asset-sync-_S8NQl5B.css +1 -0
  36. package/dist/assets/workflow-C4yKH1p4.js +179 -0
  37. package/dist/cozyclay-package.json +1 -1
  38. package/dist/index.html +3 -3
  39. package/dist/sw.js +3 -6
  40. package/dist/workflow/index.html +5 -4
  41. package/mcp/LIVE-PROTOCOL.md +7 -47
  42. package/mcp/README.md +16 -26
  43. package/mcp/live-hub.mjs +6 -10
  44. package/mcp/package.json +1 -3
  45. package/mcp/tool-handlers.mjs +4 -168
  46. package/package.json +3 -22
  47. package/src/App.jsx +150 -2624
  48. package/src/agent-progress.js +79 -0
  49. package/src/agent-turn-mark.js +30 -0
  50. package/src/analytics.js +1 -19
  51. package/src/app-context.js +5 -0
  52. package/src/app-stage.jsx +2 -34
  53. package/src/asset-pane.jsx +6 -5
  54. package/src/camera-block.js +21 -0
  55. package/src/camera-direction.js +120 -0
  56. package/src/character-kind.js +3 -9
  57. package/src/command-bus.js +8 -6
  58. package/src/commands/cast.js +5 -34
  59. package/src/commands/elements/character.js +1 -1
  60. package/src/commands/elements/motion.js +1 -6
  61. package/src/commands/elements/object.js +6 -2
  62. package/src/commands/elements/shot.js +4 -1
  63. package/src/commands/elements.js +38 -14
  64. package/src/commands/index.js +3 -1
  65. package/src/commands/kits.js +37 -0
  66. package/src/commands/motion-timing.js +57 -0
  67. package/src/commands/motion.js +9 -152
  68. package/src/commands/motion3-compile.js +65 -0
  69. package/src/commands/motion3.js +207 -0
  70. package/src/commands/objects.js +6 -4
  71. package/src/commands/shot.js +49 -11
  72. package/src/commands/stage.js +14 -1
  73. package/src/commands/view.js +4 -1
  74. package/src/document-mirrors.js +42 -0
  75. package/src/document-store.js +4 -0
  76. package/src/domains/cast.js +19 -194
  77. package/src/domains/motion/motion-range-pin-rules.js +1 -1
  78. package/src/domains/motion/take-source.js +51 -0
  79. package/src/domains/motion.js +60 -1838
  80. package/src/domains/scenes.js +12 -55
  81. package/src/domains/shots.js +2 -2
  82. package/src/domains/stage.js +4 -2
  83. package/src/draft-ghost.js +46 -0
  84. package/src/draft-ghost.jsx +129 -0
  85. package/src/dualview.jsx +4 -3
  86. package/src/effects/EffectsLayer.jsx +112 -0
  87. package/src/effects/effect-meshes.js +232 -0
  88. package/src/effects/effect-record.js +103 -0
  89. package/src/effects/emitter.js +59 -0
  90. package/src/effects/simulate.js +261 -0
  91. package/src/effects/state.js +59 -0
  92. package/src/execution-telemetry.js +2 -3
  93. package/src/first-success-guide.jsx +5 -5
  94. package/src/ghost-set.js +257 -0
  95. package/src/held-object-edit.jsx +113 -0
  96. package/src/held-object-pose.js +175 -0
  97. package/src/hierarchy-model.js +1 -1
  98. package/src/hierarchy-panel.jsx +1 -1
  99. package/src/imported-mesh.jsx +103 -0
  100. package/src/kits/held.js +84 -0
  101. package/src/kits/index.js +70 -0
  102. package/src/kits/smoking.js +57 -0
  103. package/src/light-blockers.js +93 -0
  104. package/src/motion/beat-board-model.js +84 -0
  105. package/src/motion/beat-board.css +124 -0
  106. package/src/motion/beat-board.jsx +59 -0
  107. package/src/motion/center-of-mass.js +66 -0
  108. package/src/motion/fix-collisions.js +850 -0
  109. package/src/motion/physics-review.js +118 -0
  110. package/src/{ardy → motion}/physics-support.js +1 -76
  111. package/src/motion/rig-snapshot.js +22 -0
  112. package/src/motion/take-segments.jsx +140 -0
  113. package/src/{ardy → motion}/timeline-coordinates.js +0 -21
  114. package/src/{ardy → motion}/timeline.css +1 -2
  115. package/src/{ardy → motion}/timeline.jsx +42 -413
  116. package/src/motion/waypoints.js +76 -0
  117. package/src/motion3/beats.js +83 -0
  118. package/src/motion3/body.js +158 -0
  119. package/src/motion3/bones.js +47 -0
  120. package/src/motion3/carried.js +47 -0
  121. package/src/motion3/compile-job.js +75 -0
  122. package/src/motion3/compile-worker.js +10 -0
  123. package/src/motion3/compiler/anchors.js +105 -0
  124. package/src/motion3/compiler/arm-orient.js +128 -0
  125. package/src/motion3/compiler/channels.js +125 -0
  126. package/src/motion3/compiler/compile.js +205 -0
  127. package/src/motion3/compiler/gait-rhythm.js +97 -0
  128. package/src/motion3/compiler/grip.js +171 -0
  129. package/src/motion3/compiler/head-steady.js +48 -0
  130. package/src/motion3/compiler/hold.js +134 -0
  131. package/src/motion3/compiler/idle.js +113 -0
  132. package/src/motion3/compiler/limbs.js +170 -0
  133. package/src/motion3/compiler/math.js +72 -0
  134. package/src/motion3/compiler/pose.js +162 -0
  135. package/src/motion3/compiler/quat.js +49 -0
  136. package/src/motion3/compiler/skeleton.js +74 -0
  137. package/src/motion3/compiler/validate-common.js +32 -0
  138. package/src/motion3/compiler/validate-goals.js +118 -0
  139. package/src/motion3/compiler/validate-objects.js +143 -0
  140. package/src/motion3/compiler/validate-parts.js +116 -0
  141. package/src/motion3/compiler/validate.js +122 -0
  142. package/src/motion3/compiler/vocab.js +73 -0
  143. package/src/motion3/compiler/walk-pelvis.js +275 -0
  144. package/src/motion3/compiler/walk.js +207 -0
  145. package/src/motion3/compiler/wrist-clamp.js +32 -0
  146. package/src/motion3/delta.js +47 -0
  147. package/src/motion3/describe.js +174 -0
  148. package/src/motion3/docs.js +27 -0
  149. package/src/motion3/edit-carry.js +21 -0
  150. package/src/motion3/fix/ease.js +16 -0
  151. package/src/motion3/fix/ground.js +37 -0
  152. package/src/motion3/fix/index.js +52 -0
  153. package/src/motion3/fix/push.js +71 -0
  154. package/src/motion3/fix/reach.js +46 -0
  155. package/src/motion3/fix/retime.js +79 -0
  156. package/src/motion3/fix/self.js +211 -0
  157. package/src/motion3/fix/slide.js +70 -0
  158. package/src/motion3/fix/turn.js +51 -0
  159. package/src/motion3/follow.js +39 -0
  160. package/src/motion3/free-motion.js +173 -0
  161. package/src/motion3/grip-choice.js +130 -0
  162. package/src/motion3/hold-plan.js +157 -0
  163. package/src/motion3/json-patch.js +77 -0
  164. package/src/motion3/key-aim.js +105 -0
  165. package/src/motion3/key-edit.js +82 -0
  166. package/src/motion3/lenient.js +127 -0
  167. package/src/motion3/object-keys.js +236 -0
  168. package/src/motion3/object-pose.js +182 -0
  169. package/src/motion3/object-tracks.js +12 -0
  170. package/src/motion3/pipeline.js +102 -0
  171. package/src/motion3/playback.js +51 -0
  172. package/src/motion3/probes.js +91 -0
  173. package/src/motion3/qa/body-checks.js +34 -0
  174. package/src/motion3/qa/check-names.js +14 -0
  175. package/src/motion3/qa/checks.js +121 -0
  176. package/src/motion3/qa/contact-checks.js +51 -0
  177. package/src/motion3/qa/explain.js +80 -0
  178. package/src/motion3/qa/fmt.js +5 -0
  179. package/src/motion3/qa/foot-checks.js +72 -0
  180. package/src/motion3/qa/geometry.js +77 -0
  181. package/src/motion3/qa/goals.js +191 -0
  182. package/src/motion3/qa/ground.js +60 -0
  183. package/src/motion3/qa/hints-contact.js +179 -0
  184. package/src/motion3/qa/hints-goal.js +160 -0
  185. package/src/motion3/qa/hints-knee.js +24 -0
  186. package/src/motion3/qa/hints-motion.js +209 -0
  187. package/src/motion3/qa/hints-object.js +91 -0
  188. package/src/motion3/qa/index.js +42 -0
  189. package/src/motion3/qa/key-checks.js +82 -0
  190. package/src/motion3/qa/near.js +96 -0
  191. package/src/motion3/qa/object-checks.js +135 -0
  192. package/src/motion3/qa/patch.js +161 -0
  193. package/src/motion3/qa/severity.js +38 -0
  194. package/src/motion3/qa/spec-checks.js +65 -0
  195. package/src/motion3/qa/style.js +218 -0
  196. package/src/motion3/qa/wrist-checks.js +69 -0
  197. package/src/motion3/qa/wrist-obs.js +60 -0
  198. package/src/motion3/refs.js +120 -0
  199. package/src/motion3/repair-tune.js +121 -0
  200. package/src/motion3/repair.js +83 -0
  201. package/src/motion3/report.js +67 -0
  202. package/src/motion3/rigs/index.js +14 -0
  203. package/src/motion3/rigs/x-bot-tpose-body.json +1 -0
  204. package/src/motion3/rigs/x-bot-tpose.json +1 -0
  205. package/src/motion3/rigs/y-bot-tpose-body.json +1 -0
  206. package/src/motion3/rigs/y-bot-tpose.json +1 -0
  207. package/src/motion3/scene.js +60 -0
  208. package/src/motion3/schema/brief.js +89 -0
  209. package/src/motion3/schema/fields.js +44 -0
  210. package/src/motion3/schema/spec-examples.js +46 -0
  211. package/src/motion3/schema/topics.js +111 -0
  212. package/src/motion3/schema/types.js +147 -0
  213. package/src/motion3/search.js +117 -0
  214. package/src/motion3/second-hand.js +112 -0
  215. package/src/motion3/skills/basic.js +82 -0
  216. package/src/motion3/skills/book.js +76 -0
  217. package/src/motion3/skills/car.js +145 -0
  218. package/src/motion3/skills/frames-auto.js +29 -0
  219. package/src/motion3/skills/index.js +83 -0
  220. package/src/motion3/skills/info.js +65 -0
  221. package/src/motion3/skills/smoke-kit.js +109 -0
  222. package/src/motion3/skills/smoke.js +160 -0
  223. package/src/motion3/spec-store.js +59 -0
  224. package/src/motion3/take-edit.js +155 -0
  225. package/src/motion3/take.js +63 -0
  226. package/src/motion3/timeline.js +127 -0
  227. package/src/motion3/views.js +121 -0
  228. package/src/motion3/walk-plan.js +119 -0
  229. package/src/object-catalog.jsx +7 -1
  230. package/src/object-colors.js +98 -0
  231. package/src/object-gizmo-parts.js +115 -0
  232. package/src/object-gizmo.jsx +37 -122
  233. package/src/object-glow.js +139 -0
  234. package/src/object-hidden.js +33 -0
  235. package/src/object-look.js +196 -0
  236. package/src/object-size.js +10 -0
  237. package/src/object-travel.js +71 -6
  238. package/src/panels/CameraPanel.jsx +7 -7
  239. package/src/panels/HdrEnvironmentControls.jsx +59 -0
  240. package/src/panels/LightPanel.jsx +25 -4
  241. package/src/panels/ObjectLookPanel.jsx +88 -0
  242. package/src/panels/PosePanel.jsx +2 -17
  243. package/src/panels/RigControlPanel.jsx +5 -53
  244. package/src/panels/SubjectBox.jsx +4 -1
  245. package/src/panels/details.css +14 -0
  246. package/src/posestudio.jsx +4 -27
  247. package/src/project-browser.jsx +3 -4
  248. package/src/project-resources.js +18 -31
  249. package/src/project.js +13 -104
  250. package/src/props.jsx +25 -280
  251. package/src/rail-dot-drag.js +23 -0
  252. package/src/render-passes.js +10 -0
  253. package/src/resource-status.jsx +1 -0
  254. package/src/result-modal.jsx +4 -19
  255. package/src/room.jsx +20 -12
  256. package/src/scene-assets.js +8 -6
  257. package/src/scene-light-place.js +72 -0
  258. package/src/scene-lights.jsx +148 -0
  259. package/src/scene-objects.js +31 -139
  260. package/src/scenes.js +15 -105
  261. package/src/semantic-edit.js +2 -5
  262. package/src/set-pieces.jsx +183 -0
  263. package/src/settings-menu.jsx +3 -11
  264. package/src/shell/BottomDock.jsx +9 -51
  265. package/src/shell/DetailsSlot.jsx +16 -200
  266. package/src/shell/GhostsMenuGroup.jsx +74 -0
  267. package/src/shell/LibrarySlot.jsx +1 -3
  268. package/src/shell/MenuBar.jsx +3 -3
  269. package/src/shell/PreferencesDialog.jsx +15 -264
  270. package/src/shell/PreferencesSlot.jsx +2 -8
  271. package/src/shell/TopBar.jsx +5 -84
  272. package/src/shell/ViewportToolbar.jsx +10 -70
  273. package/src/shell/agent-glass.css +19 -6
  274. package/src/shell/details-selection.js +42 -0
  275. package/src/shell/ghosts-menu.css +22 -0
  276. package/src/shell/glass-regions.css +29 -3
  277. package/src/shell/preferences.css +6 -1
  278. package/src/shot-authoring.js +4 -7
  279. package/src/soft-shadows.js +37 -0
  280. package/src/stage-attach-frames.js +12 -12
  281. package/src/stage-canvas-rigs.jsx +3 -3
  282. package/src/stage-capture.jsx +42 -8
  283. package/src/stage-characters.jsx +22 -216
  284. package/src/stage-editor-gizmos.jsx +6 -6
  285. package/src/stage-environment.js +93 -0
  286. package/src/stage-hdr-builtins.js +107 -0
  287. package/src/stage-hdr-image.js +116 -0
  288. package/src/stage-hdr-library.js +70 -0
  289. package/src/stage-hdr-map.js +94 -0
  290. package/src/stage-hdr.js +130 -0
  291. package/src/stage-lighting.js +149 -0
  292. package/src/stage-occlusion.js +210 -0
  293. package/src/stage-sky.jsx +159 -0
  294. package/src/stage-startup-defaults.js +5 -9
  295. package/src/studio-actions.js +12 -14
  296. package/src/studio-agent-commands.js +19 -16
  297. package/src/studio-agent-motion.js +9 -9
  298. package/src/studio-agent-protocol.js +41 -71
  299. package/src/studio-app-binding.js +25 -45
  300. package/src/studio-asset-list.js +17 -0
  301. package/src/studio-contact-sheet.js +37 -5
  302. package/src/studio-elements.js +27 -7
  303. package/src/studio-entity-bounds.js +18 -0
  304. package/src/studio-error-codes.js +8 -0
  305. package/src/studio-export-framing.js +152 -0
  306. package/src/studio-lighting-check.js +103 -0
  307. package/src/studio-motion-visual.js +150 -0
  308. package/src/studio-schema-errors.js +80 -0
  309. package/src/studio-support-gap.js +74 -0
  310. package/src/styles.css +1 -19
  311. package/src/timeline-defaults.js +5 -0
  312. package/src/timeline-extent.js +8 -20
  313. package/src/tutorial-walk.js +17 -0
  314. package/src/ui-scrub.js +1 -1
  315. package/src/use-shot-camera-tracks.js +12 -0
  316. package/src/view-ghosts.js +97 -0
  317. package/src/view-ghosts.jsx +49 -0
  318. package/src/workflow/AgentPanel.jsx +47 -166
  319. package/src/workflow/AgentProgressCard.jsx +107 -0
  320. package/src/workflow/AgentReplyText.jsx +37 -0
  321. package/src/workflow/AgentTurnSteps.jsx +84 -0
  322. package/src/workflow/LoginPanel.jsx +140 -0
  323. package/src/workflow/WorkflowBuilder.jsx +7 -23
  324. package/src/workflow/agent-client.js +54 -51
  325. package/src/workflow/agent-panel.css +71 -1
  326. package/src/workflow/agent-progress-card.css +167 -0
  327. package/src/workflow/agent-progress-view.js +47 -0
  328. package/src/workflow/agent-turn-steps.css +113 -0
  329. package/src/workflow/agent-turn.js +191 -0
  330. package/src/workflow/login-client.js +34 -0
  331. package/src/workflow/motion-input.js +18 -31
  332. package/src/workflow/node-schema.js +1 -1
  333. package/src/workflow/reply-markdown.js +69 -0
  334. package/src/workflow/scene-asset-sync.js +8 -8
  335. package/tools/agent-session-stats.mjs +61 -0
  336. package/tools/dev-full.mjs +5 -56
  337. package/tools/eslint-baseline.json +12 -13
  338. package/tools/knip-baseline.json +0 -179
  339. package/tools/loc-baseline.json +31 -81
  340. package/tools/motion3/extract-body.mjs +103 -0
  341. package/tools/motion3/extract-rig.mjs +85 -0
  342. package/tools/process-supervisor.mjs +0 -88
  343. package/tools/run-tests.mjs +8 -124
  344. package/bin/agent/motion-runtime.mjs +0 -76
  345. package/dist/ardy/cskel27-rest.json +0 -557
  346. package/dist/assets/analytics-C9pMpW7s.js +0 -1
  347. package/dist/assets/app-B_2XB9rw.css +0 -1
  348. package/dist/assets/app-DAuvKPP8.js +0 -4920
  349. package/dist/assets/config-Bx7pYsD9.js +0 -1
  350. package/dist/assets/config-DeoFTYzb.css +0 -1
  351. package/dist/assets/demo-CvKuBgy5.js +0 -1
  352. package/dist/assets/scene-asset-sync-DKkpjKBV.js +0 -19
  353. package/dist/assets/scene-asset-sync-DjJ_cJ2R.css +0 -1
  354. package/dist/assets/ticket-BPk2Ni95.js +0 -1
  355. package/dist/assets/workflow-jJRBR94Z.js +0 -179
  356. package/dist/demo/walk-then-stop.npz +0 -0
  357. package/mcp/ardy-prompts.mjs +0 -218
  358. package/src/ardy/auto-fix-panel.css +0 -108
  359. package/src/ardy/auto-physics.js +0 -1194
  360. package/src/ardy/client.js +0 -153
  361. package/src/ardy/convert.js +0 -313
  362. package/src/ardy/cskel27-neutral.js +0 -39
  363. package/src/ardy/cskel27.js +0 -77
  364. package/src/ardy/export.js +0 -165
  365. package/src/ardy/fix-collisions.js +0 -2257
  366. package/src/ardy/foot-lock.js +0 -230
  367. package/src/ardy/motion-calibration.js +0 -118
  368. package/src/ardy/motion-edit.js +0 -213
  369. package/src/ardy/motion-url.js +0 -55
  370. package/src/ardy/mp4-duration.js +0 -102
  371. package/src/ardy/npz.js +0 -595
  372. package/src/ardy/physics-panel.css +0 -21
  373. package/src/ardy/physics-panel.jsx +0 -89
  374. package/src/ardy/physics-refine.js +0 -111
  375. package/src/ardy/physics-review.js +0 -567
  376. package/src/ardy/physics-temporal.js +0 -54
  377. package/src/ardy/platform-fit-panel.css +0 -64
  378. package/src/ardy/platform-fit-panel.jsx +0 -41
  379. package/src/ardy/platform-fit.js +0 -326
  380. package/src/ardy/playback.js +0 -711
  381. package/src/ardy/pose-pin.js +0 -97
  382. package/src/ardy/prompt-clips.js +0 -30
  383. package/src/ardy/retime.js +0 -211
  384. package/src/ardy/root-drop.js +0 -369
  385. package/src/ardy/timeline-resize.js +0 -13
  386. package/src/ardy/to-cskel27.js +0 -225
  387. package/src/ardy/trim.js +0 -33
  388. package/src/ardy/waypoints.js +0 -369
  389. package/src/ardy-bridge-contract.js +0 -281
  390. package/src/domains/motion/motion-video-capture.js +0 -664
  391. package/src/i2v-motion-client.js +0 -77
  392. package/src/i2v-motion-studio.jsx +0 -180
  393. package/src/line-edit.js +0 -1348
  394. package/src/motion/generation.js +0 -105
  395. package/src/motion-readiness-ui.jsx +0 -67
  396. package/src/motion-readiness.js +0 -40
  397. package/src/motion-resources.js +0 -177
  398. package/src/motion-store.js +0 -65
  399. package/src/motion-trail.js +0 -601
  400. package/src/multimodel-ingest.js +0 -394
  401. package/src/panels/PromptBlocksPanel.jsx +0 -444
  402. package/src/panels/VideoCapturePanel.jsx +0 -181
  403. package/src/pose-extract/browser.js +0 -42
  404. package/src/pose-extract/detector.js +0 -100
  405. package/src/pose-extract/fit.js +0 -227
  406. package/src/pose-extract/image-frame.js +0 -51
  407. package/src/pose-extract/index.js +0 -58
  408. package/src/pose-extract/keyframes.js +0 -74
  409. package/src/pose-extract/landmarks.js +0 -162
  410. package/src/pose-extract/mirror.js +0 -153
  411. package/src/pose-extract/take.js +0 -131
  412. package/src/pose-extract/video-frames.js +0 -91
  413. package/src/take-recipe.js +0 -165
  414. package/src/trail-key-conflicts.js +0 -39
  415. package/src/trail-pick.js +0 -59
  416. package/src/use-i2v-capture-modal.js +0 -15
  417. package/tools/ardy/BRIDGE.md +0 -37
  418. package/tools/ardy/GVHMR-NPZ.md +0 -68
  419. package/tools/ardy/README.md +0 -124
  420. package/tools/ardy/__pycache__/cclay_gvhmr_worker.cpython-313.pyc +0 -0
  421. package/tools/ardy/artifacts.mjs +0 -34
  422. package/tools/ardy/bridge.mjs +0 -1732
  423. package/tools/ardy/bvh-cskel27.mjs +0 -1265
  424. package/tools/ardy/cclay_constrained_generate.py +0 -561
  425. package/tools/ardy/cclay_gvhmr_worker.py +0 -264
  426. package/tools/ardy/cclay_motion_edit.py +0 -510
  427. package/tools/ardy/cclay_sequence_generate.py +0 -705
  428. package/tools/ardy/cclay_worker.py +0 -304
  429. package/tools/ardy/dump-npz.py +0 -205
  430. package/tools/ardy/extract-rest.mjs +0 -299
  431. package/tools/ardy/extract.mjs +0 -507
  432. package/tools/ardy/footage.mjs +0 -467
  433. package/tools/ardy/gvhmr-floor.mjs +0 -102
  434. package/tools/ardy/gvhmr-to-cskel27.mjs +0 -21
  435. package/tools/ardy/gvhmr_fastpath.py +0 -168
  436. package/tools/ardy/gvhmr_trajectory.py +0 -240
  437. package/tools/ardy/merge-text-encoder.py +0 -160
  438. package/tools/ardy/mocap-metrics.mjs +0 -200
  439. package/tools/ardy/mocap-quality-gate.mjs +0 -110
  440. package/tools/ardy/motion-stabilize.mjs +0 -348
  441. package/tools/ardy/npz.mjs +0 -414
  442. package/tools/ardy/pose-to-npz.mjs +0 -106
  443. package/tools/ardy/prompt-limits.mjs +0 -5
  444. package/tools/ardy/run-edit-on-box.sh +0 -73
  445. package/tools/ardy/run-local.mjs +0 -233
  446. package/tools/ardy/run-on-box.sh +0 -593
  447. package/tools/ardy/run-sequence-on-box.sh +0 -177
  448. package/tools/ardy/runners/gvhmr-worker.mjs +0 -206
  449. package/tools/ardy/runners/index.mjs +0 -18
  450. package/tools/ardy/runners/local.mjs +0 -455
  451. package/tools/ardy/runners/proc.mjs +0 -125
  452. package/tools/ardy/runners/remote.mjs +0 -252
  453. package/tools/ardy/setup-local.mjs +0 -189
  454. package/tools/ardy/setup-text-encoder-on-box.sh +0 -93
  455. package/tools/ardy/setup-text-encoder.py +0 -306
  456. package/tools/ardy/smpl-cskel27.mjs +0 -178
  457. package/tools/ardy/visual-qa.mjs +0 -196
  458. package/tools/ardy/vq-car.mjs +0 -52
  459. package/tools/bench/EXP3.md +0 -61
  460. package/tools/bench/cclay_bench_extract_incam.py +0 -125
  461. package/tools/bench/cclay_bench_extract_obs.py +0 -204
  462. package/tools/bench/cclay_bench_runner.py +0 -42
  463. package/tools/bench/cube-contact.mjs +0 -162
  464. package/tools/bench/exp3.mjs +0 -152
  465. package/tools/bench/extract-bench-lib.mjs +0 -216
  466. package/tools/bench/extract-bench.mjs +0 -302
  467. package/tools/bench/fal-generate.mjs +0 -88
  468. package/tools/bench/fit/README.md +0 -189
  469. package/tools/bench/fit/camera.mjs +0 -59
  470. package/tools/bench/fit/contact.mjs +0 -419
  471. package/tools/bench/fit/footlock.mjs +0 -234
  472. package/tools/bench/fit/motion.mjs +0 -85
  473. package/tools/bench/fit/pin.mjs +0 -27
  474. package/tools/bench/fit/remote.mjs +0 -105
  475. package/tools/bench/fit-bench.mjs +0 -126
  476. package/tools/bench/fit-sanity.mjs +0 -45
  477. package/tools/bench/metrics.mjs +0 -313
  478. package/tools/bench/obs/depth.mjs +0 -258
  479. package/tools/bench/obs/extrinsics.mjs +0 -175
  480. package/tools/bench/obs/fit_mannequin_betas.py +0 -340
  481. package/tools/bench/obs/ground.mjs +0 -294
  482. package/tools/bench/obs/heading.mjs +0 -151
  483. package/tools/bench/obs/ladder.mjs +0 -555
  484. package/tools/bench/obs/mannequin-betas.json +0 -124
  485. package/tools/bench/obs/remote.mjs +0 -83
  486. package/tools/bench/obs/rest_joints.py +0 -52
  487. package/tools/bench/obs/ybot-targets.mjs +0 -49
  488. package/tools/bench/obs-bench.mjs +0 -520
  489. package/tools/bench/score.mjs +0 -343
  490. package/tools/bench/summarize.mjs +0 -86
  491. package/tools/demo-worker/README.md +0 -137
  492. package/tools/demo-worker/api-client.mjs +0 -233
  493. package/tools/demo-worker/generate.mjs +0 -301
  494. package/tools/demo-worker/index.mjs +0 -466
  495. package/tools/demo-worker/sign-core.mjs +0 -112
  496. package/tools/demo-worker/sign.mjs +0 -161
  497. package/tools/gt-render/browser.mjs +0 -182
  498. package/tools/gt-render/camera-math.mjs +0 -276
  499. package/tools/gt-render/page.mjs +0 -267
  500. package/tools/gt-render/render.mjs +0 -514
  501. package/tools/gt-render/scene-box.mjs +0 -31
  502. package/tools/gt-render/take-transform.mjs +0 -87
  503. package/tools/kimodo/compare-seam.mjs +0 -108
  504. package/tools/kimodo/constraints.mjs +0 -244
  505. package/tools/kimodo/edit.mjs +0 -259
  506. package/tools/kimodo/effector-constraints.mjs +0 -200
  507. package/tools/kimodo/generate.mjs +0 -646
  508. package/tools/kimodo/local-output.mjs +0 -265
  509. package/tools/kimodo/measure-pose.mjs +0 -65
  510. package/tools/kimodo/measure-preserve.mjs +0 -899
  511. package/tools/kimodo/measure-waypoints.mjs +0 -55
  512. package/tools/kimodo/mlx-generate.py +0 -111
  513. package/tools/kimodo/pose-constraints.mjs +0 -248
  514. package/tools/kimodo/preserve-mask.mjs +0 -543
  515. package/tools/kimodo/read-npz.mjs +0 -189
  516. package/tools/kimodo/run-edit-on-box.mjs +0 -155
  517. package/tools/kimodo/run-sequence-on-box.mjs +0 -178
  518. package/tools/kimodo/runner.mjs +0 -284
  519. package/tools/kimodo/seam-batch.mjs +0 -77
  520. package/tools/kimodo/setup-local.mjs +0 -30
  521. package/tools/kimodo/setup-on-box.sh +0 -339
  522. package/tools/kimodo/soma77-to-cskel27.mjs +0 -305
  523. package/tools/morphgs/assets/gen_truth.py +0 -39
  524. package/tools/morphgs/assets/mesh_ori_rig.txt +0 -27
  525. package/tools/morphgs/assets/playback-check.mjs +0 -30
  526. package/tools/morphgs/demo-gate.sh +0 -26
  527. package/tools/morphgs/fbx2morphgs.mjs +0 -68
  528. package/tools/morphgs/morphgs-to-cskel27.mjs +0 -105
  529. package/tools/morphgs/patches/preprocess_src-none-mode.patch +0 -76
  530. package/tools/morphgs/setup-on-cluster.sh +0 -126
  531. package/tools/projflow/driver.py +0 -1069
  532. package/tools/projflow/generate.mjs +0 -805
  533. package/tools/projflow/hml22-to-cskel27.mjs +0 -735
  534. package/tools/projflow/line-edit-job.mjs +0 -547
  535. package/tools/projflow/replay.mjs +0 -452
  536. package/tools/projflow/runner.mjs +0 -269
  537. package/tools/projflow/service.mjs +0 -742
  538. package/tools/track/DESIGN.md +0 -513
  539. package/tools/track/backfill-provenance.mjs +0 -116
  540. package/tools/track/budget.mjs +0 -8
  541. package/tools/track/check-rig.mjs +0 -209
  542. package/tools/track/diagnostics.schema.json +0 -60
  543. package/tools/track/export-rig.mjs +0 -256
  544. package/tools/track/fallback.mjs +0 -7
  545. package/tools/track/fk-parity-fixture.mjs +0 -161
  546. package/tools/track/gate.mjs +0 -349
  547. package/tools/track/masks.mjs +0 -318
  548. package/tools/track/metrics.mjs +0 -201
  549. package/tools/track/publish-obs.mjs +0 -108
  550. package/tools/track/py/check_env.py +0 -61
  551. package/tools/track/py/eval_lr.py +0 -229
  552. package/tools/track/py/lr_viterbi.py +0 -294
  553. package/tools/track/py/masks.py +0 -405
  554. package/tools/track/py/objective.py +0 -382
  555. package/tools/track/py/rig.py +0 -508
  556. package/tools/track/py/scene.py +0 -326
  557. package/tools/track/py/test_joint_indices.py +0 -123
  558. package/tools/track/py/test_lr_viterbi.py +0 -195
  559. package/tools/track/py/test_masks.py +0 -229
  560. package/tools/track/py/test_rig.py +0 -288
  561. package/tools/track/py/test_scene.py +0 -354
  562. package/tools/track/py/test_track.py +0 -328
  563. package/tools/track/py/track.py +0 -411
  564. package/tools/track/remote.mjs +0 -140
  565. package/tools/track/rig-dump.mjs +0 -227
  566. package/tools/track/run-box-tests.mjs +0 -14
  567. package/tools/track/run-box.mjs +0 -168
  568. package/tools/track/setup-box.sh +0 -59
  569. package/tools/track/study-2d.mjs +0 -728
  570. /package/src/{ardy → motion}/collision-blockers.js +0 -0
  571. /package/src/{ardy → motion}/ground.js +0 -0
  572. /package/src/{ardy → motion}/ik-drag.js +0 -0
  573. /package/src/{ardy → motion}/ik-key-json.js +0 -0
  574. /package/src/{ardy → motion}/ik.js +0 -0
  575. /package/src/{ardy → motion}/physics-surface.js +0 -0
  576. /package/src/{ardy → motion}/playback-clock.js +0 -0
  577. /package/src/{ardy → motion}/range-pin.js +0 -0
package/src/scenes.js CHANGED
@@ -4,17 +4,17 @@
4
4
 
5
5
  import { DEFAULT_SENSOR_FORMAT, SENSOR_FORMATS } from "./shot.js";
6
6
  import { normalizeStableItems } from "./stable-items.js";
7
- import { normalizeMotionCalibration } from "./ardy/motion-calibration.js";
8
- import { normalizeTrailEdits } from "./motion-trail.js";
7
+
9
8
  import { elementByPath } from "./studio-elements.js";
10
9
  import { wrapAngle } from "./scene-objects.js";
10
+ import { normalizeTakeSource } from "./domains/motion/take-source.js";
11
+ import { createKeyLight, normalizeLighting } from "./stage-lighting.js";
11
12
  // The timeline clock lives in timeline-fps.js (three-free, so the agent
12
13
  // sidecar can import it); re-exported here for every scene-side caller.
13
14
  import { LEGACY_FRAME_FPS, TIMELINE_FRAME_FPS, toTimelineFrame } from "./timeline-fps.js";
14
15
 
15
16
  const CHARACTER_POSITION_LIMITS = elementByPath("character.position");
16
17
  const CHARACTER_SCALE_LIMITS = elementByPath("character.scale");
17
- const KEY_LIGHT_LIMITS = Object.fromEntries(["x", "y", "z", "intensity", "warmth"].map((axis) => [axis, elementByPath(`stage.keyLight.${axis}`)]));
18
18
 
19
19
  export const SCENES_VERSION = 5;
20
20
  export const SCENES_STORAGE_KEY = "cozyclay.scenes.v5";
@@ -71,30 +71,8 @@ const DEFAULT_SCENE_STAGE = Object.freeze({
71
71
  shotAspect: "16:9",
72
72
  cameraPresetId: null,
73
73
  sensorId: DEFAULT_SENSOR_FORMAT,
74
- // The key light the user can grab: position of the sun puck, the rig's
75
- // master brightness, and a warm/cool colour offset. Values mirror the
76
- // tuned StageLights defaults, so a stage saved before the light was
77
- // movable renders exactly as it did.
78
- keyLight: Object.freeze({ x: 6, y: 9, z: 4, intensity: 1.12, warmth: 0.5 }),
79
74
  });
80
75
 
81
- /** Clamp a stored key light back into the stage's usable envelope. */
82
- export function createKeyLight(value) {
83
- const source = plainObject(value) ? value : {};
84
- const fallback = DEFAULT_SCENE_STAGE.keyLight;
85
- const finite = (entry, base, bounds) => (typeof entry === "number" && Number.isFinite(entry)
86
- ? Math.max(bounds.min, Math.min(bounds.max, entry))
87
- : base);
88
- return {
89
- x: finite(source.x, fallback.x, KEY_LIGHT_LIMITS.x),
90
- y: finite(source.y, fallback.y, KEY_LIGHT_LIMITS.y),
91
- z: finite(source.z, fallback.z, KEY_LIGHT_LIMITS.z),
92
- intensity: finite(source.intensity, fallback.intensity, KEY_LIGHT_LIMITS.intensity),
93
- // 0 = cool daylight, 0.5 = the tuned warm default, 1 = sunset amber
94
- warmth: finite(source.warmth, fallback.warmth, KEY_LIGHT_LIMITS.warmth),
95
- };
96
- }
97
-
98
76
  let sceneSequence = 1;
99
77
 
100
78
  const plainObject = (value) => !!value && typeof value === "object" && !Array.isArray(value);
@@ -135,28 +113,14 @@ export function normalizeReferenceImage(value) {
135
113
  return typeof value === "string" && value.startsWith("data:image/") ? value : null;
136
114
  }
137
115
 
138
- /** Stature band for a cast member. Wider than ardy/npz.js's mocap band
139
- * (0.6-1.5, a sanity clamp on ESTIMATED statures): the gizmo's scale handles
140
- * are a deliberate artistic ask, and a previs giant or child is legitimate. */
116
+ /** Stature band for a cast member: the gizmo's scale handles are a deliberate
117
+ * artistic ask, and a previs giant or child is legitimate. */
141
118
  export const CHARACTER_SCALE_MIN = CHARACTER_SCALE_LIMITS.min;
142
119
  export const CHARACTER_SCALE_MAX = CHARACTER_SCALE_LIMITS.max;
143
120
  const clampScale = (value) => (Number.isFinite(value) && value > 0
144
121
  ? Math.max(CHARACTER_SCALE_LIMITS.min, Math.min(CHARACTER_SCALE_LIMITS.max, value))
145
122
  : 1);
146
123
 
147
- /** Where an extra extraction take's performer stands: the filmed offset from
148
- * person 0, rotated into the ACTIVE character's facing. Pure geometry, so the
149
- * placement can be proven without a renderer. */
150
- export function takeAnchor(active, offsetX, offsetZ) {
151
- const rad = (finiteOr(active?.rot, 0) * Math.PI) / 180;
152
- const dx = finiteOr(offsetX, 0);
153
- const dz = finiteOr(offsetZ, 0);
154
- return {
155
- x: finiteOr(active?.x, 0) + dx * Math.cos(rad) + dz * Math.sin(rad),
156
- z: finiteOr(active?.z, 0) - dx * Math.sin(rad) + dz * Math.cos(rad),
157
- };
158
- }
159
-
160
124
  /** One character entry in the stage envelope. `source` may be a v3 entry, a
161
125
  * partial (spawn dialog), or null — every field falls back to a sane default
162
126
  * and every object is freshly owned by the caller. */
@@ -190,25 +154,17 @@ export function createCharacterEntry(source = null, index = 0) {
190
154
  // take's root travel was authored against it — see the render path.
191
155
  scale: clampScale(s.scale),
192
156
  subject: typeof s.subject === "string" ? s.subject : index === 0 ? DEFAULT_SUBJECT_ONE : DEFAULT_SUBJECT_TWO,
193
- // The character's animation layer: its own root path and prompt-block
194
- // schedule. The generated clip itself is heavy, so only a lightweight
195
- // reference (bridge URL + generation params) is persisted — enough to
196
- // re-fetch and decode it on the next session.
157
+ // The character's animation layer: its own root path.
197
158
  layer: normalizeLayer(s.layer),
198
- motionRef: normalizeMotionRef(s.motionRef),
199
159
  // The Pose-mode / IK edits on this character's layer (encoded keys, range
200
160
  // pins and their residuals). The motion domain owns them while the scene
201
161
  // is open; this is what the saved scene carries so a reload keeps them.
202
162
  ikEdits: normalizeIkEdits(s.ikEdits),
163
+ // A compiled take v3 saves its source; the motion layer compiles it again on load.
164
+ motionTake: normalizeTakeSource(s.motionTake),
203
165
  };
204
166
  }
205
167
 
206
- const MOTION_ID_RE = /^[0-9a-f]{64}$/i;
207
-
208
- // A motionRef names its take by content (motionId: SHA-256 of the npz, kept
209
- // in the project's embedded motions) and/or by location (url: a bridge run,
210
- // which is what pre-motionId documents carry). Either one alone is a valid
211
- // ref; the restore path prefers the embedded bytes when both are present.
212
168
  function normalizeIkEdits(value) {
213
169
  if (!plainObject(value)) return null;
214
170
  const rows = (list, valid) => (Array.isArray(list) ? list.filter(valid).map((entry) => cloneValue(entry)) : []);
@@ -218,40 +174,10 @@ function normalizeIkEdits(value) {
218
174
  return keys.length || pins.length ? { keys, pins, pinResiduals } : null;
219
175
  }
220
176
 
221
- function normalizeMotionRef(ref) {
222
- if (!plainObject(ref)) return null;
223
- const motionId = typeof ref.motionId === "string" && MOTION_ID_RE.test(ref.motionId) ? ref.motionId.toLowerCase() : null;
224
- const url = typeof ref.url === "string" && ref.url ? ref.url : null;
225
- if (!motionId && !url) return null;
226
- const normalized = {};
227
- // Field order matters only for byte-stable serialization; a url-only ref
228
- // keeps the exact legacy shape (url first, no motionId key).
229
- if (motionId) normalized.motionId = motionId;
230
- if (url) normalized.url = url;
231
- Object.assign(normalized, {
232
- prompt: typeof ref.prompt === "string" ? ref.prompt : "",
233
- rotationDeg: Number.isFinite(ref.rotationDeg) ? ref.rotationDeg : 0,
234
- anchorX: Number.isFinite(ref.anchorX) ? ref.anchorX : 0,
235
- anchorZ: Number.isFinite(ref.anchorZ) ? ref.anchorZ : 0,
236
- });
237
- // Scene calibration is deliberately metadata on the lightweight motionRef,
238
- // never an NPZ member. Keep it optional so old documents retain their exact
239
- // shape, while preserving the calibration produced by the extraction/load
240
- // boundary for a later scene reload. cloneValue also strips non-finite values
241
- // and recursively owns the object, so a caller cannot mutate the saved stage.
242
- if (plainObject(ref.calibration)) normalized.calibration = normalizeMotionCalibration(ref.calibration);
243
- if (ref.trailEdits != null) normalized.trailEdits = normalizeTrailEdits(ref.trailEdits);
244
- // An agent-installed take keeps the Studio take id its receipts name, so a
245
- // reload still reports the same take. Optional, like calibration.
246
- if (typeof ref.studioTakeId === "string" && ref.studioTakeId) normalized.studioTakeId = ref.studioTakeId;
247
- return normalized;
248
- }
249
-
250
177
  function normalizeLayer(layer) {
251
178
  const source = plainObject(layer) ? layer : {};
252
179
  return {
253
180
  waypoints: normalizeStableItems(cloneValue(source.waypoints), "waypoint"),
254
- promptClips: normalizeStableItems(cloneValue(source.promptClips), "prompt-clip"),
255
181
  };
256
182
  }
257
183
 
@@ -265,7 +191,6 @@ function normalizeStageLayers(stage) {
265
191
  ...character,
266
192
  layer: {
267
193
  waypoints: normalizeStableItems(cloneValue(character.layer?.waypoints), "waypoint", ids),
268
- promptClips: normalizeStableItems(cloneValue(character.layer?.promptClips), "prompt-clip", ids),
269
194
  },
270
195
  }))
271
196
  : source.characters,
@@ -273,16 +198,12 @@ function normalizeStageLayers(stage) {
273
198
  }
274
199
 
275
200
  export function createCharacterLayer() {
276
- return { waypoints: [], promptClips: [] };
201
+ return { waypoints: [] };
277
202
  }
278
203
 
279
204
  /** Retime one animation layer from the 20 fps authoring clock onto the 24 fps
280
- * production clock. Frame numbers only: positions, headings and prompt text
281
- * are untouched. The mapping is strictly increasing, so ascending order and
282
- * the gaps between prompt blocks survive it — the guards below re-establish
283
- * both anyway, because a hand-edited body may never have had them. Prompt
284
- * ranges are half-open [start, end), matching movePromptClipFrames: touching
285
- * blocks are legal, overlapping ones are not. */
205
+ * production clock. Frame numbers only: positions and headings are untouched.
206
+ * The mapping is strictly increasing, so ascending order survives it. */
286
207
  function migrateLayerFrames(layer) {
287
208
  if (!plainObject(layer)) return layer;
288
209
  const next = { ...cloneValue(layer) };
@@ -295,20 +216,6 @@ function migrateLayerFrames(layer) {
295
216
  }
296
217
  next.waypoints = [...byFrame.values()].sort((a, b) => a.frame - b.frame);
297
218
  }
298
- if (Array.isArray(layer.promptClips)) {
299
- const ordered = layer.promptClips
300
- .filter((clip) => plainObject(clip) && Number.isFinite(clip.startFrame) && Number.isFinite(clip.endFrame))
301
- .sort((a, b) => a.startFrame - b.startFrame);
302
- const clips = [];
303
- let floor = 0;
304
- for (const clip of ordered) {
305
- const startFrame = Math.max(floor, toTimelineFrame(Math.round(clip.startFrame)));
306
- const endFrame = Math.max(startFrame, toTimelineFrame(Math.round(clip.endFrame)));
307
- clips.push({ ...cloneValue(clip), startFrame, endFrame });
308
- floor = endFrame;
309
- }
310
- next.promptClips = clips;
311
- }
312
219
  return next;
313
220
  }
314
221
 
@@ -337,7 +244,7 @@ function migrateLegacyCast(source) {
337
244
  }
338
245
 
339
246
  const STAGE_ENVELOPE_KEYS = new Set([
340
- "characters", "hasCharSheet", "environmentImage", "environment", "style", "hasEnvSheet", "shotAspect", "cameraPresetId", "sensorId", "keyLight",
247
+ "characters", "hasCharSheet", "environmentImage", "environment", "style", "hasEnvSheet", "shotAspect", "cameraPresetId", "sensorId", "keyLight", "lighting",
341
248
  "charA", "charB", "showB", "poseA", "poseB", "subject", "subject2",
342
249
  ]);
343
250
 
@@ -376,7 +283,10 @@ export function createSceneStage(stage = null) {
376
283
  sensorId: Object.hasOwn(SENSOR_FORMATS, source.sensorId ?? source.sensorFormat)
377
284
  ? (source.sensorId ?? source.sensorFormat)
378
285
  : DEFAULT_SCENE_STAGE.sensorId,
286
+ // The key light the user grabs (puck position, master brightness, warmth or
287
+ // colour) and the stage look; a stage saved before either renders as it did.
379
288
  keyLight: createKeyLight(source.keyLight),
289
+ lighting: normalizeLighting(source.lighting),
380
290
  };
381
291
  }
382
292
 
@@ -23,17 +23,14 @@ function equal(a, b) {
23
23
  return keys.length === Object.keys(b).length && keys.every((key) => Object.hasOwn(b, key) && equal(a[key], b[key]));
24
24
  }
25
25
  const poseValue = (pose) => ({ bones: pose?.bones ?? {}, rootY: pose?.rootY ?? 0 });
26
- const blockValues = (blocks) => blocks.map(({ id, ...value }) => value);
26
+
27
27
  const keyValues = (keys = []) => keys.map(({ frame, framing }) => ({ frame, framing }));
28
28
  const shotValue = (shot) => ({ ...shot, camera: createCameraBlock(shot.camera), cameraKeys: keyValues(shot.cameraKeys) });
29
29
 
30
30
  export function semanticEditKind(domain, before, after) {
31
31
  if (before === after) return null;
32
32
  if (domain === "pose") return equal(before, after) ? null : "pose_edit";
33
- if (domain === "promptClips") {
34
- if (equal(blockValues(before), blockValues(after))) return null;
35
- return after.length > before.length ? "prompt_block_add" : "prompt_block_edit";
36
- }
33
+
37
34
  if (domain === "objects") {
38
35
  const added = after.find((item) => !before.some((previous) => previous.id === item.id));
39
36
  if (added) return added.renderer === "cutout" ? "cutout_insert" : "object_insert";
@@ -0,0 +1,183 @@
1
+ /**
2
+ * The hand-built set pieces: a car, a small plane and a chair, modelled from
3
+ * primitives in the same clay style as the room and the character tint.
4
+ * Dimensions are metres against real sizes so the 1.8 m figure keeps honest
5
+ * scale. Each takes `autoColor` (the viewport's auto-colour mode) and then
6
+ * tints its primary surfaces flat; glass, tyres and rims keep their own.
7
+ */
8
+
9
+ // Blender's solid-view response for auto-colored surfaces. Workbench shades
10
+ // with a neutral studio rig, so the derived hue reaches the eye unmultiplied;
11
+ // under our warm key light a plain standard material turns every hue olive.
12
+ // Full roughness kills the specular sheen and a self-light of the same hue
13
+ // lifts the shadow side the way workbench's studio lighting does.
14
+ export function autoFlat(hex) {
15
+ return { color: hex, roughness: 1, metalness: 0, emissive: hex, emissiveIntensity: 0.4 };
16
+ }
17
+
18
+ const CLAY_CAR = "#d98770";
19
+ const CLAY_CAR_TOP = "#e49a84";
20
+ const CLAY_TIRE = "#41484c";
21
+ const CLAY_RIM = "#7c8588";
22
+ const CLAY_GLASS = "#55697a";
23
+ const CLAY_PLANE = "#7896a4";
24
+ const CLAY_PLANE_TRIM = "#e1a849";
25
+ const CLAY_CHAIR = "#b9855d";
26
+ const CLAY_CHAIR_LIGHT = "#cf9d72";
27
+
28
+ function Wheel({ position }) {
29
+ return (
30
+ <group position={position}>
31
+ <mesh rotation={[0, 0, Math.PI / 2]}>
32
+ <cylinderGeometry args={[0.33, 0.33, 0.24, 20]} />
33
+ <meshStandardMaterial color={CLAY_TIRE} roughness={0.95} />
34
+ </mesh>
35
+ <mesh rotation={[0, 0, Math.PI / 2]}>
36
+ <cylinderGeometry args={[0.17, 0.17, 0.26, 16]} />
37
+ <meshStandardMaterial color={CLAY_RIM} roughness={0.5} metalness={0.35} />
38
+ </mesh>
39
+ </group>
40
+ );
41
+ }
42
+ /**
43
+ * A generic 5-door-ish sedan silhouette, ~4.5 m long. Origin at the centre
44
+ * of the footprint, +Z forward.
45
+ */
46
+ export function Car({ position = [0, 0, 0], rotY = 0, color = CLAY_CAR, topColor = CLAY_CAR_TOP, autoColor = undefined }) {
47
+ const bodyMaterial = autoColor
48
+ ? { ...autoFlat(autoColor) }
49
+ : { color, roughness: 0.55, metalness: 0.25 };
50
+ const topMaterial = autoColor
51
+ ? { ...autoFlat(autoColor) }
52
+ : { color: topColor, roughness: 0.5, metalness: 0.2 };
53
+ return (
54
+ <group position={position} rotation={[0, rotY, 0]}>
55
+ <mesh position={[0, 0.62, 0]}>
56
+ <boxGeometry args={[1.78, 0.62, 4.45]} />
57
+ <meshStandardMaterial {...bodyMaterial} />
58
+ </mesh>
59
+ <mesh position={[0, 1.12, -0.15]}>
60
+ <boxGeometry args={[1.58, 0.5, 2.2]} />
61
+ <meshStandardMaterial {...topMaterial} />
62
+ </mesh>
63
+ <mesh position={[0, 1.14, -0.15]}>
64
+ <boxGeometry args={[1.62, 0.3, 1.9]} />
65
+ <meshStandardMaterial color={CLAY_GLASS} roughness={0.15} metalness={0.6} />
66
+ </mesh>
67
+ <mesh position={[0, 1.05, 0.95]} rotation={[0.5, 0, 0]}>
68
+ <boxGeometry args={[1.56, 0.42, 0.08]} />
69
+ <meshStandardMaterial color={CLAY_GLASS} roughness={0.15} metalness={0.6} />
70
+ </mesh>
71
+ <mesh position={[0, 1.05, -1.25]} rotation={[-0.55, 0, 0]}>
72
+ <boxGeometry args={[1.56, 0.42, 0.08]} />
73
+ <meshStandardMaterial color={CLAY_GLASS} roughness={0.15} metalness={0.6} />
74
+ </mesh>
75
+ <Wheel position={[0.82, 0.33, 1.45]} />
76
+ <Wheel position={[-0.82, 0.33, 1.45]} />
77
+ <Wheel position={[0.82, 0.33, -1.45]} />
78
+ <Wheel position={[-0.82, 0.33, -1.45]} />
79
+ </group>
80
+ );
81
+ }
82
+
83
+ /** Compact single-engine propeller plane, ~3.4 m wingspan and +Z forward. */
84
+ export function SmallPlane({ position = [0, 0, 0], rotY = 0, autoColor = undefined }) {
85
+ // Auto-color mode tints the PRIMARY surfaces only (fuselage, wings, trim);
86
+ // glass, tires and rims keep their materials so the silhouette still reads.
87
+ // Each mesh keeps its own hand-tuned roughness when the mode is off.
88
+ const mat = (color, roughness, metalness) =>
89
+ autoColor ? autoFlat(autoColor) : { color, roughness, metalness };
90
+ return (
91
+ <group position={position} rotation={[0, rotY, 0]}>
92
+ <mesh position={[0, 0.76, 0]} rotation={[Math.PI / 2, 0, 0]}>
93
+ <cylinderGeometry args={[0.23, 0.31, 2.75, 16]} />
94
+ <meshStandardMaterial {...mat(CLAY_PLANE, 0.58, 0.18)} />
95
+ </mesh>
96
+ <mesh position={[0, 0.76, 1.55]} rotation={[Math.PI / 2, 0, 0]}>
97
+ <coneGeometry args={[0.23, 0.55, 16]} />
98
+ <meshStandardMaterial {...mat(CLAY_PLANE_TRIM, 0.52, 0.2)} />
99
+ </mesh>
100
+
101
+ <mesh position={[0, 0.73, 0.15]}>
102
+ <boxGeometry args={[3.4, 0.09, 0.58]} />
103
+ <meshStandardMaterial {...mat(CLAY_PLANE, 0.62, 0.14)} />
104
+ </mesh>
105
+ <mesh position={[0, 0.84, -1.18]}>
106
+ <boxGeometry args={[1.45, 0.07, 0.38]} />
107
+ <meshStandardMaterial {...mat(CLAY_PLANE_TRIM, 0.62, 0.12)} />
108
+ </mesh>
109
+ <mesh position={[0, 1.08, -1.2]} rotation={[0.22, 0, 0]}>
110
+ <boxGeometry args={[0.08, 0.62, 0.48]} />
111
+ <meshStandardMaterial {...mat(CLAY_PLANE, 0.62, 0.12)} />
112
+ </mesh>
113
+
114
+ <mesh position={[0, 1.02, 0.42]} scale={[0.62, 0.46, 0.9]}>
115
+ <sphereGeometry args={[0.42, 16, 10, 0, Math.PI * 2, 0, Math.PI / 2]} />
116
+ <meshStandardMaterial color={CLAY_GLASS} roughness={0.16} metalness={0.55} />
117
+ </mesh>
118
+
119
+ <group position={[0, 0.76, 1.86]}>
120
+ <mesh rotation={[Math.PI / 2, 0, 0]}>
121
+ <cylinderGeometry args={[0.11, 0.11, 0.2, 12]} />
122
+ <meshStandardMaterial color={CLAY_RIM} roughness={0.45} metalness={0.4} />
123
+ </mesh>
124
+ <mesh position={[0, 0, 0.12]} rotation={[0, 0, 0.28]}>
125
+ <boxGeometry args={[1.25, 0.08, 0.06]} />
126
+ <meshStandardMaterial color={CLAY_TIRE} roughness={0.8} />
127
+ </mesh>
128
+ </group>
129
+
130
+ {[-0.55, 0.55].map((x) => (
131
+ <group key={x} position={[x, 0.2, 0.15]}>
132
+ <mesh position={[0, 0.24, 0]} rotation={[0, 0, x < 0 ? -0.35 : 0.35]}>
133
+ <boxGeometry args={[0.045, 0.55, 0.045]} />
134
+ <meshStandardMaterial color={CLAY_RIM} roughness={0.65} metalness={0.3} />
135
+ </mesh>
136
+ <mesh rotation={[0, 0, Math.PI / 2]}>
137
+ <cylinderGeometry args={[0.16, 0.16, 0.09, 14]} />
138
+ <meshStandardMaterial color={CLAY_TIRE} roughness={0.95} />
139
+ </mesh>
140
+ </group>
141
+ ))}
142
+ </group>
143
+ );
144
+ }
145
+
146
+ export function Chair({ position = [0, 0, 0], rotY = 0, autoColor = undefined }) {
147
+ // Auto-color mode tints seat/back and frame together; undefined keeps the
148
+ // hand-picked clay pair exactly as it ships.
149
+ const seat = autoColor ? autoFlat(autoColor) : { color: CLAY_CHAIR_LIGHT, roughness: 0.86 };
150
+ const frame = autoColor ? autoFlat(autoColor) : { color: CLAY_CHAIR, roughness: 0.9 };
151
+ const legPositions = [
152
+ [-0.24, 0.23, -0.22],
153
+ [0.24, 0.23, -0.22],
154
+ [-0.24, 0.23, 0.22],
155
+ [0.24, 0.23, 0.22],
156
+ ];
157
+ return (
158
+ <group position={position} rotation={[0, rotY, 0]} scale={0.9}>
159
+ <mesh position={[0, 0.49, 0]} castShadow receiveShadow>
160
+ <boxGeometry args={[0.6, 0.12, 0.58]} />
161
+ <meshStandardMaterial {...seat} />
162
+ </mesh>
163
+ {legPositions.map((leg, index) => (
164
+ <mesh key={index} position={leg} castShadow receiveShadow>
165
+ <boxGeometry args={[0.09, 0.46, 0.09]} />
166
+ <meshStandardMaterial {...frame} />
167
+ </mesh>
168
+ ))}
169
+ <mesh position={[-0.24, 0.92, -0.245]} castShadow receiveShadow>
170
+ <boxGeometry args={[0.09, 0.86, 0.09]} />
171
+ <meshStandardMaterial {...frame} />
172
+ </mesh>
173
+ <mesh position={[0.24, 0.92, -0.245]} castShadow receiveShadow>
174
+ <boxGeometry args={[0.09, 0.86, 0.09]} />
175
+ <meshStandardMaterial {...frame} />
176
+ </mesh>
177
+ <mesh position={[0, 1.08, -0.245]} castShadow receiveShadow>
178
+ <boxGeometry args={[0.52, 0.38, 0.1]} />
179
+ <meshStandardMaterial {...seat} />
180
+ </mesh>
181
+ </group>
182
+ );
183
+ }
@@ -1,4 +1,4 @@
1
- import { useCallback, useEffect, useRef, useState } from "react";
1
+ import { useCallback, useRef, useState } from "react";
2
2
  import { ko, localeChosen } from "./locale.js";
3
3
  import PreferencesDialog from "./shell/PreferencesDialog.jsx";
4
4
 
@@ -14,7 +14,7 @@ const LANGUAGES = [
14
14
  { id: "ko", label: "한국어", action: "한국어로 전환" },
15
15
  ];
16
16
 
17
- export default function SettingsMenu({ motionSetup, motionSetupReveal = 0 }) {
17
+ export default function SettingsMenu() {
18
18
  const [open, setOpen] = useState(false);
19
19
  const triggerRef = useRef(null);
20
20
  const close = useCallback(() => {
@@ -39,13 +39,6 @@ export default function SettingsMenu({ motionSetup, motionSetupReveal = 0 }) {
39
39
  </>
40
40
  );
41
41
 
42
- // A contextual readiness action can reveal Preferences directly on the
43
- // motion connection page without changing the topbar or adding a second
44
- // settings surface.
45
- useEffect(() => {
46
- if (motionSetupReveal) setOpen(true);
47
- }, [motionSetupReveal]);
48
-
49
42
  // First-run cue: the studio starts in English even on a Korean browser, so
50
43
  // the only visible hint that Korean exists used to be the old locale button.
51
44
  // Until a language is stored, a ko-* browser sees the trigger in Korean.
@@ -70,8 +63,7 @@ export default function SettingsMenu({ motionSetup, motionSetupReveal = 0 }) {
70
63
  <PreferencesDialog
71
64
  open={open}
72
65
  onClose={close}
73
- motionSetup={motionSetup}
74
- initialSection={motionSetupReveal ? "ARDY Connection" : "Appearance"}
66
+ initialSection="Appearance"
75
67
  cameraTutorial={cameraTutorial}
76
68
  />
77
69
  </div>
@@ -5,9 +5,9 @@ import "./dock.css";
5
5
  import LibrarySlot from "./LibrarySlot.jsx";
6
6
  import BoardSlot from "./BoardSlot.jsx";
7
7
  import { ko } from "../locale.js";
8
- import Timeline from "../ardy/timeline.jsx";
8
+ import Timeline, { timelineTake } from "../motion/timeline.jsx";
9
9
  import { DEFAULT_PLAYBACK_SPEED, SHOT_ASPECT_PRESETS, sceneObjectNameDisplayKo } from "../app-stage.jsx";
10
- import { motionEditLayout, createMotionEdit } from "../ardy/motion-edit.js";
10
+
11
11
  import { trackFeature } from "../analytics.js";
12
12
  import { defaultRailRange } from "../camera-rail-schedule.js";
13
13
  import { insertPathMark, pathMarks } from "../object-path.js";
@@ -74,9 +74,8 @@ export default function BottomDock({ tab: requestedTab = "animation", onTabChang
74
74
  tlFrame, motion, waypointMode, craneSelectedIndex,
75
75
  isCameraSelection, addActiveCranePoint, deleteSelectedCranePoint, setCraneSelectedIndex, tlFrameCount,
76
76
  tlFps, characters, activeCharIndex, ghostLayers, pathSpeed,
77
- tlPlaying, workflowMode, waypoints, pendingWaypointFrame, promptClips,
78
- selectedPromptId, stateBadge, ikMode, ikChains, applyMotionTrim,
79
- resetMotionTrim, cutMotionAtPlayhead, changeMotionSegmentSpeed, removeMotionSegmentById, ikFrames,
77
+ tlPlaying, workflowMode, waypoints, pendingWaypointFrame,
78
+ stateBadge, ikMode, ikChains, ikFrames,
80
79
  rangePins, rangePinSelection, ikEditTool, rangePinPreview, footSnap,
81
80
  bodyContact, shots, shotAspectKey, activeShotIdx, railDraw,
82
81
  pathDraw, pathTarget, setPathDraw, setRailDraw, setWorkspaceLayout,
@@ -85,13 +84,12 @@ export default function BottomDock({ tab: requestedTab = "animation", onTabChang
85
84
  setBodyContact, setToast, setFootSnap, setTlFrame, advanceFrame,
86
85
  stepFrame, cameraPreviewEndRef, manualCameraOverrideRef, setTlPlaying, toggleWaypointMode,
87
86
  setWaypointMode, selectActiveCharacterInHierarchy, setActiveWaypointId, setPendingWaypointFrame, removeWaypoint,
88
- queueRootWaypointFrame, addPromptClip, revealPromptBlocks, setSelectedPromptId, setArdyPrompt,
89
- changePromptClip, resizePromptClip, movePromptClip, removePromptClip, setSelectedHierarchyId,
87
+ queueRootWaypointFrame, setSelectedHierarchyId,
90
88
  selectWorkflowMode, addCameraKeyframe, moveCameraKeyframe, removeCameraKeyframe, syncActiveCameraFraming,
91
89
  activeCamera, activeShotDuration, changeActiveCamera, cameraRail, previewCameraShot,
92
90
  toggleCameraRailDraw, deleteCameraRail, selectTimelineShot, shotsDomain, runStudioAction,
93
- clearMotion, subscribeToasts, exportStatus, exportPhaseLabel, ardyRunning, ardyStatus,
94
- ardyOutcome, pathPointIndex, setPathPointIndex,
91
+ clearMotion, subscribeToasts, exportStatus, exportPhaseLabel,
92
+ pathPointIndex, setPathPointIndex,
95
93
  } = useStudioShell();
96
94
  const dockRef = useRef(null);
97
95
  const [dockHeight, setDockHeight] = useState(readDockHeight);
@@ -160,20 +158,6 @@ export default function BottomDock({ tab: requestedTab = "animation", onTabChang
160
158
  useEffect(() => subscribeToasts((toast) => logStore.push({ kind: "toast", text: toast.uiMessage })),
161
159
  // eslint-disable-next-line react-hooks/exhaustive-deps
162
160
  []);
163
- const generationWasRunning = useRef(false);
164
- useEffect(() => {
165
- if (ardyRunning && !generationWasRunning.current) logStore.push({ kind: "generation", text: ko("Motion generation started", "모션 생성을 시작했어요") });
166
- generationWasRunning.current = ardyRunning;
167
- }, [ardyRunning]);
168
- useEffect(() => {
169
- if (ardyRunning && ardyStatus) logStore.push({ kind: "generation", key: "generation:status", text: ardyStatus });
170
- }, [ardyRunning, ardyStatus]);
171
- useEffect(() => {
172
- if (!ardyOutcome) return;
173
- logStore.push({ kind: "generation", text: ardyOutcome.ok
174
- ? ko("Motion generation finished", "모션 생성을 마쳤어요")
175
- : ko(`Motion generation failed — ${ardyOutcome.message}`, `모션 생성 실패 — ${ardyOutcome.message}`) });
176
- }, [ardyOutcome]);
177
161
  const exportPhase = exportStatus?.phase, exportLabel = exportStatus?.label, exportMessage = exportStatus?.message;
178
162
  const exportDone = exportStatus?.completedFrames, exportTotal = exportStatus?.frameCount;
179
163
  useEffect(() => {
@@ -238,22 +222,10 @@ export default function BottomDock({ tab: requestedTab = "animation", onTabChang
238
222
  waypointMode={waypointMode}
239
223
  waypoints={waypoints}
240
224
  pendingWaypointFrame={pendingWaypointFrame}
241
- previsMode={previsMode}
242
- promptClips={promptClips}
243
- selectedPromptId={selectedPromptId}
244
225
  badge={stateBadge}
245
226
  ikMode={ikMode}
246
227
  ikDisabled={!ikChains}
247
- motion={motion ? {
248
- frames: motion.frames,
249
- label: motion.prompt || ko("Loaded take", "불러온 테이크"),
250
- segments: motionEditLayout(motion.editSegments ?? createMotionEdit(motion.frames)),
251
- } : null}
252
- onMotionTrim={applyMotionTrim}
253
- onMotionTrimReset={resetMotionTrim}
254
- onMotionCut={cutMotionAtPlayhead}
255
- onMotionSpeedChange={changeMotionSegmentSpeed}
256
- onMotionSegmentRemove={removeMotionSegmentById}
228
+ motion={timelineTake(motion, characters[activeCharIndex]?.id, runStudioAction)}
257
229
  ikFrames={ikFrames}
258
230
  rangePins={rangePins}
259
231
  selectedPinId={rangePinSelection}
@@ -351,21 +323,7 @@ export default function BottomDock({ tab: requestedTab = "animation", onTabChang
351
323
  }}
352
324
  onMarkerRemove={removeWaypoint}
353
325
  onRootKeyframeAdd={queueRootWaypointFrame}
354
- onPromptAdd={(frame) => {
355
- addPromptClip(frame);
356
- selectActiveCharacterInHierarchy();
357
- revealPromptBlocks();
358
- }}
359
- onPromptSelect={(id) => {
360
- setSelectedPromptId(id);
361
- setArdyPrompt(promptClips.find((clip) => clip.id === id)?.text ?? "");
362
- selectActiveCharacterInHierarchy();
363
- revealPromptBlocks();
364
- }}
365
- onPromptChange={changePromptClip}
366
- onPromptResize={resizePromptClip}
367
- onPromptMove={movePromptClip}
368
- onPromptRemove={removePromptClip}
326
+
369
327
  onCameraMoveSelect={() => {
370
328
  setSelectedHierarchyId("camera");
371
329
  if (workflowMode !== "camera") selectWorkflowMode("camera");