cozyclay 2.1.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (583) hide show
  1. package/CHANGELOG.md +65 -0
  2. package/README.md +12 -30
  3. package/bin/agent/agent-routes.mjs +40 -113
  4. package/bin/agent/agent-runner.mjs +9 -10
  5. package/bin/agent/cliproxy-provider.mjs +135 -0
  6. package/bin/agent/credential-store.mjs +30 -7
  7. package/bin/agent/pi-tools.mjs +4 -1
  8. package/bin/agent/provider-keys.mjs +32 -0
  9. package/bin/agent/provider-login.mjs +110 -0
  10. package/bin/agent/provider-routes.mjs +99 -0
  11. package/bin/agent/providers.mjs +19 -97
  12. package/bin/agent/script-tool.mjs +17 -4
  13. package/bin/agent/studio-motion-reference.mjs +23 -0
  14. package/bin/agent/studio-prompt.mjs +1 -1
  15. package/bin/agent/studio-rebase-text.mjs +32 -0
  16. package/bin/agent/studio-rebase.mjs +26 -39
  17. package/bin/agent/studio-tools.mjs +9 -28
  18. package/bin/agent/tool-arguments.mjs +49 -0
  19. package/bin/agent/turn-frames.mjs +66 -0
  20. package/bin/codex-auth.mjs +9 -2
  21. package/bin/cozyclay.mjs +10 -116
  22. package/bin/live/cli.mjs +22 -6
  23. package/bin/mcp-runtime.mjs +2 -12
  24. package/bin/package-signature.mjs +0 -4
  25. package/dist/app/index.html +7 -6
  26. package/dist/assets/EXRLoader-CvVIvGVE.js +1 -0
  27. package/dist/assets/analytics-C9sUnndd.js +1 -0
  28. package/dist/assets/app-CCh--1Hc.js +5087 -0
  29. package/dist/assets/app-f-fkV5uP.css +1 -0
  30. package/dist/assets/compile-worker-CkxiD6lH.js +5 -0
  31. package/dist/assets/fflate.module-KbGj5-H6.js +5 -0
  32. package/dist/assets/{first-shot-handoff-BlT33CGf.js → first-shot-handoff-CC4xe4HM.js} +1 -1
  33. package/dist/assets/{landing-BSesrCpL.js → landing-DjHD8u7k.js} +1 -1
  34. package/dist/assets/scene-asset-sync-Hx_FzdOH.js +20 -0
  35. package/dist/assets/scene-asset-sync-_S8NQl5B.css +1 -0
  36. package/dist/assets/workflow-C4yKH1p4.js +179 -0
  37. package/dist/cozyclay-package.json +1 -1
  38. package/dist/index.html +3 -3
  39. package/dist/llms.txt +14 -0
  40. package/dist/sw.js +3 -6
  41. package/dist/workflow/index.html +5 -4
  42. package/mcp/LIVE-PROTOCOL.md +7 -47
  43. package/mcp/README.md +16 -26
  44. package/mcp/live-hub.mjs +6 -10
  45. package/mcp/package.json +1 -3
  46. package/mcp/tool-handlers.mjs +4 -168
  47. package/package.json +3 -22
  48. package/src/App.jsx +174 -2639
  49. package/src/agent-progress.js +79 -0
  50. package/src/agent-turn-mark.js +30 -0
  51. package/src/analytics.js +1 -19
  52. package/src/app-context.js +5 -0
  53. package/src/app-stage.jsx +2 -34
  54. package/src/asset-pane.jsx +6 -5
  55. package/src/camera-block.js +21 -0
  56. package/src/camera-direction.js +120 -0
  57. package/src/character-kind.js +3 -9
  58. package/src/command-bus.js +8 -6
  59. package/src/commands/cast.js +5 -34
  60. package/src/commands/elements/character.js +1 -1
  61. package/src/commands/elements/motion.js +1 -6
  62. package/src/commands/elements/object.js +6 -2
  63. package/src/commands/elements/shot.js +4 -1
  64. package/src/commands/elements.js +38 -14
  65. package/src/commands/index.js +3 -1
  66. package/src/commands/kits.js +37 -0
  67. package/src/commands/motion-timing.js +57 -0
  68. package/src/commands/motion.js +9 -152
  69. package/src/commands/motion3-compile.js +65 -0
  70. package/src/commands/motion3.js +207 -0
  71. package/src/commands/objects.js +6 -4
  72. package/src/commands/shot.js +49 -11
  73. package/src/commands/stage.js +14 -1
  74. package/src/commands/view.js +4 -1
  75. package/src/document-mirrors.js +42 -0
  76. package/src/document-store.js +4 -0
  77. package/src/domains/cast.js +19 -194
  78. package/src/domains/motion/motion-range-pin-rules.js +1 -1
  79. package/src/domains/motion/take-source.js +51 -0
  80. package/src/domains/motion.js +60 -1838
  81. package/src/domains/scenes.js +12 -55
  82. package/src/domains/shots.js +2 -2
  83. package/src/domains/stage.js +4 -2
  84. package/src/draft-ghost.js +46 -0
  85. package/src/draft-ghost.jsx +129 -0
  86. package/src/dualview.jsx +4 -3
  87. package/src/effects/EffectsLayer.jsx +112 -0
  88. package/src/effects/effect-meshes.js +232 -0
  89. package/src/effects/effect-record.js +103 -0
  90. package/src/effects/emitter.js +59 -0
  91. package/src/effects/simulate.js +261 -0
  92. package/src/effects/state.js +59 -0
  93. package/src/execution-telemetry.js +2 -3
  94. package/src/first-success-guide.jsx +5 -5
  95. package/src/ghost-set.js +257 -0
  96. package/src/held-object-edit.jsx +113 -0
  97. package/src/held-object-pose.js +175 -0
  98. package/src/hierarchy-model.js +1 -1
  99. package/src/hierarchy-panel.jsx +1 -1
  100. package/src/imported-mesh.jsx +103 -0
  101. package/src/kits/held.js +84 -0
  102. package/src/kits/index.js +70 -0
  103. package/src/kits/smoking.js +57 -0
  104. package/src/light-blockers.js +93 -0
  105. package/src/motion/beat-board-model.js +84 -0
  106. package/src/motion/beat-board.css +124 -0
  107. package/src/motion/beat-board.jsx +59 -0
  108. package/src/motion/center-of-mass.js +66 -0
  109. package/src/motion/fix-collisions.js +850 -0
  110. package/src/motion/physics-review.js +118 -0
  111. package/src/{ardy → motion}/physics-support.js +1 -76
  112. package/src/motion/rig-snapshot.js +22 -0
  113. package/src/motion/take-segments.jsx +140 -0
  114. package/src/{ardy → motion}/timeline-coordinates.js +0 -21
  115. package/src/{ardy → motion}/timeline.css +1 -2
  116. package/src/{ardy → motion}/timeline.jsx +48 -419
  117. package/src/motion/waypoints.js +76 -0
  118. package/src/motion3/beats.js +83 -0
  119. package/src/motion3/body.js +158 -0
  120. package/src/motion3/bones.js +47 -0
  121. package/src/motion3/carried.js +47 -0
  122. package/src/motion3/compile-job.js +75 -0
  123. package/src/motion3/compile-worker.js +10 -0
  124. package/src/motion3/compiler/anchors.js +105 -0
  125. package/src/motion3/compiler/arm-orient.js +128 -0
  126. package/src/motion3/compiler/channels.js +125 -0
  127. package/src/motion3/compiler/compile.js +205 -0
  128. package/src/motion3/compiler/gait-rhythm.js +97 -0
  129. package/src/motion3/compiler/grip.js +171 -0
  130. package/src/motion3/compiler/head-steady.js +48 -0
  131. package/src/motion3/compiler/hold.js +134 -0
  132. package/src/motion3/compiler/idle.js +113 -0
  133. package/src/motion3/compiler/limbs.js +170 -0
  134. package/src/motion3/compiler/math.js +72 -0
  135. package/src/motion3/compiler/pose.js +162 -0
  136. package/src/motion3/compiler/quat.js +49 -0
  137. package/src/motion3/compiler/skeleton.js +74 -0
  138. package/src/motion3/compiler/validate-common.js +32 -0
  139. package/src/motion3/compiler/validate-goals.js +118 -0
  140. package/src/motion3/compiler/validate-objects.js +143 -0
  141. package/src/motion3/compiler/validate-parts.js +116 -0
  142. package/src/motion3/compiler/validate.js +122 -0
  143. package/src/motion3/compiler/vocab.js +73 -0
  144. package/src/motion3/compiler/walk-pelvis.js +275 -0
  145. package/src/motion3/compiler/walk.js +207 -0
  146. package/src/motion3/compiler/wrist-clamp.js +32 -0
  147. package/src/motion3/delta.js +47 -0
  148. package/src/motion3/describe.js +174 -0
  149. package/src/motion3/docs.js +27 -0
  150. package/src/motion3/edit-carry.js +21 -0
  151. package/src/motion3/fix/ease.js +16 -0
  152. package/src/motion3/fix/ground.js +37 -0
  153. package/src/motion3/fix/index.js +52 -0
  154. package/src/motion3/fix/push.js +71 -0
  155. package/src/motion3/fix/reach.js +46 -0
  156. package/src/motion3/fix/retime.js +79 -0
  157. package/src/motion3/fix/self.js +211 -0
  158. package/src/motion3/fix/slide.js +70 -0
  159. package/src/motion3/fix/turn.js +51 -0
  160. package/src/motion3/follow.js +39 -0
  161. package/src/motion3/free-motion.js +173 -0
  162. package/src/motion3/grip-choice.js +130 -0
  163. package/src/motion3/hold-plan.js +157 -0
  164. package/src/motion3/json-patch.js +77 -0
  165. package/src/motion3/key-aim.js +105 -0
  166. package/src/motion3/key-edit.js +82 -0
  167. package/src/motion3/lenient.js +127 -0
  168. package/src/motion3/object-keys.js +236 -0
  169. package/src/motion3/object-pose.js +182 -0
  170. package/src/motion3/object-tracks.js +12 -0
  171. package/src/motion3/pipeline.js +102 -0
  172. package/src/motion3/playback.js +51 -0
  173. package/src/motion3/probes.js +91 -0
  174. package/src/motion3/qa/body-checks.js +34 -0
  175. package/src/motion3/qa/check-names.js +14 -0
  176. package/src/motion3/qa/checks.js +121 -0
  177. package/src/motion3/qa/contact-checks.js +51 -0
  178. package/src/motion3/qa/explain.js +80 -0
  179. package/src/motion3/qa/fmt.js +5 -0
  180. package/src/motion3/qa/foot-checks.js +72 -0
  181. package/src/motion3/qa/geometry.js +77 -0
  182. package/src/motion3/qa/goals.js +191 -0
  183. package/src/motion3/qa/ground.js +60 -0
  184. package/src/motion3/qa/hints-contact.js +179 -0
  185. package/src/motion3/qa/hints-goal.js +160 -0
  186. package/src/motion3/qa/hints-knee.js +24 -0
  187. package/src/motion3/qa/hints-motion.js +209 -0
  188. package/src/motion3/qa/hints-object.js +91 -0
  189. package/src/motion3/qa/index.js +42 -0
  190. package/src/motion3/qa/key-checks.js +82 -0
  191. package/src/motion3/qa/near.js +96 -0
  192. package/src/motion3/qa/object-checks.js +135 -0
  193. package/src/motion3/qa/patch.js +161 -0
  194. package/src/motion3/qa/severity.js +38 -0
  195. package/src/motion3/qa/spec-checks.js +65 -0
  196. package/src/motion3/qa/style.js +218 -0
  197. package/src/motion3/qa/wrist-checks.js +69 -0
  198. package/src/motion3/qa/wrist-obs.js +60 -0
  199. package/src/motion3/refs.js +120 -0
  200. package/src/motion3/repair-tune.js +121 -0
  201. package/src/motion3/repair.js +83 -0
  202. package/src/motion3/report.js +67 -0
  203. package/src/motion3/rigs/index.js +14 -0
  204. package/src/motion3/rigs/x-bot-tpose-body.json +1 -0
  205. package/src/motion3/rigs/x-bot-tpose.json +1 -0
  206. package/src/motion3/rigs/y-bot-tpose-body.json +1 -0
  207. package/src/motion3/rigs/y-bot-tpose.json +1 -0
  208. package/src/motion3/scene.js +60 -0
  209. package/src/motion3/schema/brief.js +89 -0
  210. package/src/motion3/schema/fields.js +44 -0
  211. package/src/motion3/schema/spec-examples.js +46 -0
  212. package/src/motion3/schema/topics.js +111 -0
  213. package/src/motion3/schema/types.js +147 -0
  214. package/src/motion3/search.js +117 -0
  215. package/src/motion3/second-hand.js +112 -0
  216. package/src/motion3/skills/basic.js +82 -0
  217. package/src/motion3/skills/book.js +76 -0
  218. package/src/motion3/skills/car.js +145 -0
  219. package/src/motion3/skills/frames-auto.js +29 -0
  220. package/src/motion3/skills/index.js +83 -0
  221. package/src/motion3/skills/info.js +65 -0
  222. package/src/motion3/skills/smoke-kit.js +109 -0
  223. package/src/motion3/skills/smoke.js +160 -0
  224. package/src/motion3/spec-store.js +59 -0
  225. package/src/motion3/take-edit.js +155 -0
  226. package/src/motion3/take.js +63 -0
  227. package/src/motion3/timeline.js +127 -0
  228. package/src/motion3/views.js +121 -0
  229. package/src/motion3/walk-plan.js +119 -0
  230. package/src/object-catalog.jsx +7 -1
  231. package/src/object-colors.js +98 -0
  232. package/src/object-gizmo-parts.js +115 -0
  233. package/src/object-gizmo.jsx +37 -122
  234. package/src/object-glow.js +139 -0
  235. package/src/object-hidden.js +33 -0
  236. package/src/object-look.js +196 -0
  237. package/src/object-size.js +10 -0
  238. package/src/object-travel.js +71 -6
  239. package/src/panels/CameraPanel.jsx +7 -7
  240. package/src/panels/HdrEnvironmentControls.jsx +59 -0
  241. package/src/panels/LightPanel.jsx +25 -4
  242. package/src/panels/ObjectLookPanel.jsx +88 -0
  243. package/src/panels/PoseImagePanel.jsx +1 -1
  244. package/src/panels/PosePanel.jsx +2 -17
  245. package/src/panels/RigControlPanel.jsx +5 -53
  246. package/src/panels/SubjectBox.jsx +4 -1
  247. package/src/panels/details.css +14 -0
  248. package/src/posestudio.jsx +4 -27
  249. package/src/project-browser.jsx +3 -4
  250. package/src/project-resources.js +18 -31
  251. package/src/project.js +13 -104
  252. package/src/props.jsx +25 -280
  253. package/src/rail-dot-drag.js +23 -0
  254. package/src/render-passes.js +10 -0
  255. package/src/resource-status.jsx +1 -0
  256. package/src/result-modal.jsx +4 -19
  257. package/src/room.jsx +20 -12
  258. package/src/scene-assets.js +8 -6
  259. package/src/scene-light-place.js +72 -0
  260. package/src/scene-lights.jsx +148 -0
  261. package/src/scene-objects.js +31 -139
  262. package/src/scenes.js +15 -105
  263. package/src/semantic-edit.js +2 -5
  264. package/src/set-pieces.jsx +183 -0
  265. package/src/settings-menu.jsx +3 -11
  266. package/src/shell/BottomDock.jsx +11 -53
  267. package/src/shell/CompositionGuideButton.jsx +20 -0
  268. package/src/shell/DetailsSlot.jsx +16 -200
  269. package/src/shell/GhostsMenuGroup.jsx +74 -0
  270. package/src/shell/LibrarySlot.jsx +1 -3
  271. package/src/shell/MenuBar.jsx +3 -3
  272. package/src/shell/PreferencesDialog.jsx +15 -264
  273. package/src/shell/PreferencesSlot.jsx +2 -8
  274. package/src/shell/ShotPreviewHeader.jsx +17 -0
  275. package/src/shell/TopBar.jsx +5 -83
  276. package/src/shell/ViewportToolbar.jsx +23 -93
  277. package/src/shell/agent-glass.css +19 -6
  278. package/src/shell/details-selection.js +42 -0
  279. package/src/shell/ghosts-menu.css +22 -0
  280. package/src/shell/glass-regions.css +29 -3
  281. package/src/shell/preferences.css +6 -1
  282. package/src/shell/viewport.css +12 -0
  283. package/src/shot-authoring.js +4 -7
  284. package/src/soft-shadows.js +37 -0
  285. package/src/stage-attach-frames.js +12 -12
  286. package/src/stage-canvas-rigs.jsx +3 -3
  287. package/src/stage-capture.jsx +42 -8
  288. package/src/stage-characters.jsx +22 -216
  289. package/src/stage-editor-gizmos.jsx +6 -6
  290. package/src/stage-environment.js +93 -0
  291. package/src/stage-hdr-builtins.js +107 -0
  292. package/src/stage-hdr-image.js +116 -0
  293. package/src/stage-hdr-library.js +70 -0
  294. package/src/stage-hdr-map.js +94 -0
  295. package/src/stage-hdr.js +130 -0
  296. package/src/stage-lighting.js +149 -0
  297. package/src/stage-occlusion.js +210 -0
  298. package/src/stage-sky.jsx +159 -0
  299. package/src/stage-startup-defaults.js +5 -9
  300. package/src/studio-actions.js +12 -14
  301. package/src/studio-agent-commands.js +46 -16
  302. package/src/studio-agent-motion.js +9 -9
  303. package/src/studio-agent-protocol.js +46 -73
  304. package/src/studio-app-binding.js +29 -45
  305. package/src/studio-asset-list.js +17 -0
  306. package/src/studio-contact-sheet.js +37 -5
  307. package/src/studio-elements.js +27 -7
  308. package/src/studio-entity-bounds.js +18 -0
  309. package/src/studio-error-codes.js +8 -0
  310. package/src/studio-export-framing.js +152 -0
  311. package/src/studio-lighting-check.js +103 -0
  312. package/src/studio-motion-visual.js +150 -0
  313. package/src/studio-schema-errors.js +80 -0
  314. package/src/studio-support-gap.js +74 -0
  315. package/src/styles.css +1 -19
  316. package/src/timeline-defaults.js +5 -0
  317. package/src/timeline-extent.js +8 -20
  318. package/src/tutorial-walk.js +17 -0
  319. package/src/ui-scrub.js +1 -1
  320. package/src/use-shot-camera-tracks.js +12 -0
  321. package/src/view-ghosts.js +97 -0
  322. package/src/view-ghosts.jsx +49 -0
  323. package/src/workflow/AgentPanel.jsx +47 -166
  324. package/src/workflow/AgentProgressCard.jsx +107 -0
  325. package/src/workflow/AgentReplyText.jsx +37 -0
  326. package/src/workflow/AgentTurnSteps.jsx +84 -0
  327. package/src/workflow/LoginPanel.jsx +140 -0
  328. package/src/workflow/WorkflowBuilder.jsx +7 -23
  329. package/src/workflow/agent-client.js +54 -51
  330. package/src/workflow/agent-panel.css +71 -1
  331. package/src/workflow/agent-progress-card.css +167 -0
  332. package/src/workflow/agent-progress-view.js +47 -0
  333. package/src/workflow/agent-turn-steps.css +113 -0
  334. package/src/workflow/agent-turn.js +191 -0
  335. package/src/workflow/login-client.js +34 -0
  336. package/src/workflow/motion-input.js +18 -31
  337. package/src/workflow/node-schema.js +1 -1
  338. package/src/workflow/reply-markdown.js +69 -0
  339. package/src/workflow/scene-asset-sync.js +8 -8
  340. package/tools/agent-session-stats.mjs +61 -0
  341. package/tools/dev-full.mjs +5 -56
  342. package/tools/eslint-baseline.json +12 -13
  343. package/tools/headless-studio.mjs +85 -0
  344. package/tools/knip-baseline.json +0 -179
  345. package/tools/loc-baseline.json +33 -83
  346. package/tools/motion3/extract-body.mjs +103 -0
  347. package/tools/motion3/extract-rig.mjs +85 -0
  348. package/tools/process-supervisor.mjs +0 -88
  349. package/tools/run-tests.mjs +9 -124
  350. package/bin/agent/motion-runtime.mjs +0 -76
  351. package/dist/ardy/cskel27-rest.json +0 -557
  352. package/dist/assets/analytics-B41FmPYI.js +0 -1
  353. package/dist/assets/app-Do-Og5Pu.css +0 -1
  354. package/dist/assets/app-DwP-tl2x.js +0 -4920
  355. package/dist/assets/config-Bx7pYsD9.js +0 -1
  356. package/dist/assets/config-DeoFTYzb.css +0 -1
  357. package/dist/assets/demo-Dt0qZfS7.js +0 -1
  358. package/dist/assets/scene-asset-sync-BCWDJB1d.js +0 -19
  359. package/dist/assets/scene-asset-sync-DjJ_cJ2R.css +0 -1
  360. package/dist/assets/ticket-jqMhqL88.js +0 -1
  361. package/dist/assets/workflow-Br-K7Srs.js +0 -179
  362. package/dist/demo/walk-then-stop.npz +0 -0
  363. package/mcp/ardy-prompts.mjs +0 -218
  364. package/src/ardy/auto-fix-panel.css +0 -108
  365. package/src/ardy/auto-physics.js +0 -1194
  366. package/src/ardy/client.js +0 -153
  367. package/src/ardy/convert.js +0 -313
  368. package/src/ardy/cskel27-neutral.js +0 -39
  369. package/src/ardy/cskel27.js +0 -77
  370. package/src/ardy/export.js +0 -165
  371. package/src/ardy/fix-collisions.js +0 -2257
  372. package/src/ardy/foot-lock.js +0 -230
  373. package/src/ardy/motion-calibration.js +0 -118
  374. package/src/ardy/motion-edit.js +0 -213
  375. package/src/ardy/motion-url.js +0 -55
  376. package/src/ardy/mp4-duration.js +0 -102
  377. package/src/ardy/npz.js +0 -595
  378. package/src/ardy/physics-panel.css +0 -21
  379. package/src/ardy/physics-panel.jsx +0 -89
  380. package/src/ardy/physics-refine.js +0 -111
  381. package/src/ardy/physics-review.js +0 -567
  382. package/src/ardy/physics-temporal.js +0 -54
  383. package/src/ardy/platform-fit-panel.css +0 -64
  384. package/src/ardy/platform-fit-panel.jsx +0 -41
  385. package/src/ardy/platform-fit.js +0 -326
  386. package/src/ardy/playback.js +0 -711
  387. package/src/ardy/pose-pin.js +0 -97
  388. package/src/ardy/prompt-clips.js +0 -30
  389. package/src/ardy/retime.js +0 -211
  390. package/src/ardy/root-drop.js +0 -369
  391. package/src/ardy/timeline-resize.js +0 -13
  392. package/src/ardy/to-cskel27.js +0 -225
  393. package/src/ardy/trim.js +0 -33
  394. package/src/ardy/waypoints.js +0 -369
  395. package/src/ardy-bridge-contract.js +0 -281
  396. package/src/domains/motion/motion-video-capture.js +0 -664
  397. package/src/i2v-motion-client.js +0 -77
  398. package/src/i2v-motion-studio.jsx +0 -180
  399. package/src/line-edit.js +0 -1348
  400. package/src/motion/generation.js +0 -105
  401. package/src/motion-readiness-ui.jsx +0 -67
  402. package/src/motion-readiness.js +0 -40
  403. package/src/motion-resources.js +0 -177
  404. package/src/motion-store.js +0 -65
  405. package/src/motion-trail.js +0 -601
  406. package/src/multimodel-ingest.js +0 -394
  407. package/src/panels/PromptBlocksPanel.jsx +0 -444
  408. package/src/panels/VideoCapturePanel.jsx +0 -181
  409. package/src/pose-extract/browser.js +0 -42
  410. package/src/pose-extract/detector.js +0 -100
  411. package/src/pose-extract/fit.js +0 -227
  412. package/src/pose-extract/image-frame.js +0 -51
  413. package/src/pose-extract/index.js +0 -58
  414. package/src/pose-extract/keyframes.js +0 -74
  415. package/src/pose-extract/landmarks.js +0 -162
  416. package/src/pose-extract/mirror.js +0 -153
  417. package/src/pose-extract/take.js +0 -131
  418. package/src/pose-extract/video-frames.js +0 -91
  419. package/src/take-recipe.js +0 -165
  420. package/src/trail-key-conflicts.js +0 -39
  421. package/src/trail-pick.js +0 -59
  422. package/src/use-i2v-capture-modal.js +0 -15
  423. package/tools/ardy/BRIDGE.md +0 -37
  424. package/tools/ardy/GVHMR-NPZ.md +0 -68
  425. package/tools/ardy/README.md +0 -124
  426. package/tools/ardy/__pycache__/cclay_gvhmr_worker.cpython-313.pyc +0 -0
  427. package/tools/ardy/artifacts.mjs +0 -34
  428. package/tools/ardy/bridge.mjs +0 -1732
  429. package/tools/ardy/bvh-cskel27.mjs +0 -1265
  430. package/tools/ardy/cclay_constrained_generate.py +0 -561
  431. package/tools/ardy/cclay_gvhmr_worker.py +0 -264
  432. package/tools/ardy/cclay_motion_edit.py +0 -510
  433. package/tools/ardy/cclay_sequence_generate.py +0 -705
  434. package/tools/ardy/cclay_worker.py +0 -304
  435. package/tools/ardy/dump-npz.py +0 -205
  436. package/tools/ardy/extract-rest.mjs +0 -299
  437. package/tools/ardy/extract.mjs +0 -507
  438. package/tools/ardy/footage.mjs +0 -467
  439. package/tools/ardy/gvhmr-floor.mjs +0 -102
  440. package/tools/ardy/gvhmr-to-cskel27.mjs +0 -21
  441. package/tools/ardy/gvhmr_fastpath.py +0 -168
  442. package/tools/ardy/gvhmr_trajectory.py +0 -240
  443. package/tools/ardy/merge-text-encoder.py +0 -160
  444. package/tools/ardy/mocap-metrics.mjs +0 -200
  445. package/tools/ardy/mocap-quality-gate.mjs +0 -110
  446. package/tools/ardy/motion-stabilize.mjs +0 -348
  447. package/tools/ardy/npz.mjs +0 -414
  448. package/tools/ardy/pose-to-npz.mjs +0 -106
  449. package/tools/ardy/prompt-limits.mjs +0 -5
  450. package/tools/ardy/run-edit-on-box.sh +0 -73
  451. package/tools/ardy/run-local.mjs +0 -233
  452. package/tools/ardy/run-on-box.sh +0 -593
  453. package/tools/ardy/run-sequence-on-box.sh +0 -177
  454. package/tools/ardy/runners/gvhmr-worker.mjs +0 -206
  455. package/tools/ardy/runners/index.mjs +0 -18
  456. package/tools/ardy/runners/local.mjs +0 -455
  457. package/tools/ardy/runners/proc.mjs +0 -125
  458. package/tools/ardy/runners/remote.mjs +0 -252
  459. package/tools/ardy/setup-local.mjs +0 -189
  460. package/tools/ardy/setup-text-encoder-on-box.sh +0 -93
  461. package/tools/ardy/setup-text-encoder.py +0 -306
  462. package/tools/ardy/smpl-cskel27.mjs +0 -178
  463. package/tools/ardy/visual-qa.mjs +0 -196
  464. package/tools/ardy/vq-car.mjs +0 -52
  465. package/tools/bench/EXP3.md +0 -61
  466. package/tools/bench/cclay_bench_extract_incam.py +0 -125
  467. package/tools/bench/cclay_bench_extract_obs.py +0 -204
  468. package/tools/bench/cclay_bench_runner.py +0 -42
  469. package/tools/bench/cube-contact.mjs +0 -162
  470. package/tools/bench/exp3.mjs +0 -152
  471. package/tools/bench/extract-bench-lib.mjs +0 -216
  472. package/tools/bench/extract-bench.mjs +0 -302
  473. package/tools/bench/fal-generate.mjs +0 -88
  474. package/tools/bench/fit/README.md +0 -189
  475. package/tools/bench/fit/camera.mjs +0 -59
  476. package/tools/bench/fit/contact.mjs +0 -419
  477. package/tools/bench/fit/footlock.mjs +0 -234
  478. package/tools/bench/fit/motion.mjs +0 -85
  479. package/tools/bench/fit/pin.mjs +0 -27
  480. package/tools/bench/fit/remote.mjs +0 -105
  481. package/tools/bench/fit-bench.mjs +0 -126
  482. package/tools/bench/fit-sanity.mjs +0 -45
  483. package/tools/bench/metrics.mjs +0 -313
  484. package/tools/bench/obs/depth.mjs +0 -258
  485. package/tools/bench/obs/extrinsics.mjs +0 -175
  486. package/tools/bench/obs/fit_mannequin_betas.py +0 -340
  487. package/tools/bench/obs/ground.mjs +0 -294
  488. package/tools/bench/obs/heading.mjs +0 -151
  489. package/tools/bench/obs/ladder.mjs +0 -555
  490. package/tools/bench/obs/mannequin-betas.json +0 -124
  491. package/tools/bench/obs/remote.mjs +0 -83
  492. package/tools/bench/obs/rest_joints.py +0 -52
  493. package/tools/bench/obs/ybot-targets.mjs +0 -49
  494. package/tools/bench/obs-bench.mjs +0 -520
  495. package/tools/bench/score.mjs +0 -343
  496. package/tools/bench/summarize.mjs +0 -86
  497. package/tools/demo-worker/README.md +0 -137
  498. package/tools/demo-worker/api-client.mjs +0 -233
  499. package/tools/demo-worker/generate.mjs +0 -301
  500. package/tools/demo-worker/index.mjs +0 -466
  501. package/tools/demo-worker/sign-core.mjs +0 -112
  502. package/tools/demo-worker/sign.mjs +0 -161
  503. package/tools/gt-render/browser.mjs +0 -159
  504. package/tools/gt-render/camera-math.mjs +0 -276
  505. package/tools/gt-render/page.mjs +0 -267
  506. package/tools/gt-render/render.mjs +0 -514
  507. package/tools/gt-render/scene-box.mjs +0 -31
  508. package/tools/gt-render/take-transform.mjs +0 -87
  509. package/tools/kimodo/compare-seam.mjs +0 -108
  510. package/tools/kimodo/constraints.mjs +0 -244
  511. package/tools/kimodo/edit.mjs +0 -259
  512. package/tools/kimodo/effector-constraints.mjs +0 -200
  513. package/tools/kimodo/generate.mjs +0 -646
  514. package/tools/kimodo/local-output.mjs +0 -265
  515. package/tools/kimodo/measure-pose.mjs +0 -65
  516. package/tools/kimodo/measure-preserve.mjs +0 -899
  517. package/tools/kimodo/measure-waypoints.mjs +0 -55
  518. package/tools/kimodo/mlx-generate.py +0 -111
  519. package/tools/kimodo/pose-constraints.mjs +0 -248
  520. package/tools/kimodo/preserve-mask.mjs +0 -543
  521. package/tools/kimodo/read-npz.mjs +0 -189
  522. package/tools/kimodo/run-edit-on-box.mjs +0 -155
  523. package/tools/kimodo/run-sequence-on-box.mjs +0 -178
  524. package/tools/kimodo/runner.mjs +0 -284
  525. package/tools/kimodo/seam-batch.mjs +0 -77
  526. package/tools/kimodo/setup-local.mjs +0 -30
  527. package/tools/kimodo/setup-on-box.sh +0 -339
  528. package/tools/kimodo/soma77-to-cskel27.mjs +0 -305
  529. package/tools/morphgs/assets/gen_truth.py +0 -39
  530. package/tools/morphgs/assets/mesh_ori_rig.txt +0 -27
  531. package/tools/morphgs/assets/playback-check.mjs +0 -30
  532. package/tools/morphgs/demo-gate.sh +0 -26
  533. package/tools/morphgs/fbx2morphgs.mjs +0 -68
  534. package/tools/morphgs/morphgs-to-cskel27.mjs +0 -105
  535. package/tools/morphgs/patches/preprocess_src-none-mode.patch +0 -76
  536. package/tools/morphgs/setup-on-cluster.sh +0 -126
  537. package/tools/projflow/driver.py +0 -1069
  538. package/tools/projflow/generate.mjs +0 -805
  539. package/tools/projflow/hml22-to-cskel27.mjs +0 -735
  540. package/tools/projflow/line-edit-job.mjs +0 -547
  541. package/tools/projflow/replay.mjs +0 -452
  542. package/tools/projflow/runner.mjs +0 -269
  543. package/tools/projflow/service.mjs +0 -742
  544. package/tools/track/DESIGN.md +0 -513
  545. package/tools/track/backfill-provenance.mjs +0 -116
  546. package/tools/track/budget.mjs +0 -8
  547. package/tools/track/check-rig.mjs +0 -209
  548. package/tools/track/diagnostics.schema.json +0 -60
  549. package/tools/track/export-rig.mjs +0 -256
  550. package/tools/track/fallback.mjs +0 -7
  551. package/tools/track/fk-parity-fixture.mjs +0 -161
  552. package/tools/track/gate.mjs +0 -349
  553. package/tools/track/masks.mjs +0 -318
  554. package/tools/track/metrics.mjs +0 -201
  555. package/tools/track/publish-obs.mjs +0 -108
  556. package/tools/track/py/check_env.py +0 -61
  557. package/tools/track/py/eval_lr.py +0 -229
  558. package/tools/track/py/lr_viterbi.py +0 -294
  559. package/tools/track/py/masks.py +0 -405
  560. package/tools/track/py/objective.py +0 -382
  561. package/tools/track/py/rig.py +0 -508
  562. package/tools/track/py/scene.py +0 -326
  563. package/tools/track/py/test_joint_indices.py +0 -123
  564. package/tools/track/py/test_lr_viterbi.py +0 -195
  565. package/tools/track/py/test_masks.py +0 -229
  566. package/tools/track/py/test_rig.py +0 -288
  567. package/tools/track/py/test_scene.py +0 -354
  568. package/tools/track/py/test_track.py +0 -328
  569. package/tools/track/py/track.py +0 -411
  570. package/tools/track/remote.mjs +0 -140
  571. package/tools/track/rig-dump.mjs +0 -227
  572. package/tools/track/run-box-tests.mjs +0 -14
  573. package/tools/track/run-box.mjs +0 -168
  574. package/tools/track/setup-box.sh +0 -59
  575. package/tools/track/study-2d.mjs +0 -728
  576. /package/src/{ardy → motion}/collision-blockers.js +0 -0
  577. /package/src/{ardy → motion}/ground.js +0 -0
  578. /package/src/{ardy → motion}/ik-drag.js +0 -0
  579. /package/src/{ardy → motion}/ik-key-json.js +0 -0
  580. /package/src/{ardy → motion}/ik.js +0 -0
  581. /package/src/{ardy → motion}/physics-surface.js +0 -0
  582. /package/src/{ardy → motion}/playback-clock.js +0 -0
  583. /package/src/{ardy → motion}/range-pin.js +0 -0
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");
@@ -482,12 +440,12 @@ function ShotCard() {
482
440
  {ko("Exit", "나가기")}
483
441
  <kbd>Esc</kbd>
484
442
  </button>
485
- ) : (
443
+ ) : activeShot ? (
486
444
  <button type="button" className="dock-shot-look" aria-pressed="false" onClick={enterShotLook} title={ko("Look through the shot camera (Esc returns)", "샷 카메라 시점으로 보기 (Esc로 복귀)")}>
487
445
  <svg viewBox="0 0 16 16" aria-hidden="true"><path d="M1.75 8S4 3.75 8 3.75 14.25 8 14.25 8 12 12.25 8 12.25 1.75 8 1.75 8z M8 6.25a1.75 1.75 0 1 1 0 3.5 1.75 1.75 0 1 1 0-3.5z" /></svg>
488
446
  {ko("Look through", "샷 시점")}
489
447
  </button>
490
- )}
448
+ ) : null}
491
449
  </footer>
492
450
  </section>
493
451
  );
@@ -0,0 +1,20 @@
1
+ import { GUIDE_LABELS, nextGuideMode } from "../shot-guides.js";
2
+ import { ko } from "../locale.js";
3
+
4
+ export default function CompositionGuideButton({ guideMode, onCycle }) {
5
+ return (
6
+ <button
7
+ type="button"
8
+ className={"vp-guide-cycle vp-embed-guide" + (guideMode === "off" ? "" : " on")}
9
+ aria-label={ko("Cycle composition guides", "구도 가이드 전환")}
10
+ aria-pressed={guideMode !== "off"}
11
+ title={ko(GUIDE_LABELS[guideMode].en, GUIDE_LABELS[guideMode].ko) + ko(" · click to cycle", " · 클릭으로 전환")}
12
+ onClick={() => onCycle(nextGuideMode(guideMode))}
13
+ >
14
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" aria-hidden="true">
15
+ <path d="M3 3h18v18H3z" />
16
+ <path d="M9 3v18M15 3v18M3 9h18M3 15h18" />
17
+ </svg>
18
+ </button>
19
+ );
20
+ }