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
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");