cozyclay 2.1.1 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (585) hide show
  1. package/CHANGELOG.md +88 -0
  2. package/README.md +12 -30
  3. package/bin/agent/agent-routes.mjs +43 -116
  4. package/bin/agent/agent-runner.mjs +14 -15
  5. package/bin/agent/cliproxy-provider.mjs +135 -0
  6. package/bin/agent/credential-store.mjs +30 -7
  7. package/bin/agent/pi-tools.mjs +4 -1
  8. package/bin/agent/provider-keys.mjs +32 -0
  9. package/bin/agent/provider-login.mjs +110 -0
  10. package/bin/agent/provider-routes.mjs +99 -0
  11. package/bin/agent/providers.mjs +19 -97
  12. package/bin/agent/script-tool.mjs +17 -4
  13. package/bin/agent/session-store.mjs +2 -2
  14. package/bin/agent/studio-context-budget.mjs +93 -0
  15. package/bin/agent/studio-motion-reference.mjs +23 -0
  16. package/bin/agent/studio-prompt.mjs +1 -1
  17. package/bin/agent/studio-rebase-text.mjs +32 -0
  18. package/bin/agent/studio-rebase.mjs +26 -39
  19. package/bin/agent/studio-tools.mjs +9 -28
  20. package/bin/agent/tool-arguments.mjs +49 -0
  21. package/bin/agent/turn-frames.mjs +66 -0
  22. package/bin/codex-auth.mjs +9 -2
  23. package/bin/cozyclay.mjs +10 -116
  24. package/bin/live/cli.mjs +3 -3
  25. package/bin/mcp-runtime.mjs +2 -12
  26. package/bin/package-signature.mjs +0 -4
  27. package/dist/app/index.html +7 -6
  28. package/dist/assets/EXRLoader-CvVIvGVE.js +1 -0
  29. package/dist/assets/analytics-BWCqdgWA.js +1 -0
  30. package/dist/assets/app-DfTCxaKk.js +5087 -0
  31. package/dist/assets/app-f-fkV5uP.css +1 -0
  32. package/dist/assets/compile-worker-BxKXh07s.js +5 -0
  33. package/dist/assets/fflate.module-KbGj5-H6.js +5 -0
  34. package/dist/assets/{first-shot-handoff-msLI71g1.js → first-shot-handoff-DNO8kv_N.js} +1 -1
  35. package/dist/assets/{landing-ChUvB_zL.js → landing-yfZaJkWc.js} +1 -1
  36. package/dist/assets/scene-asset-sync-U3kS2rvK.js +20 -0
  37. package/dist/assets/scene-asset-sync-_S8NQl5B.css +1 -0
  38. package/dist/assets/workflow-D78eiKTa.js +179 -0
  39. package/dist/cozyclay-package.json +1 -1
  40. package/dist/index.html +3 -3
  41. package/dist/sw.js +3 -6
  42. package/dist/workflow/index.html +5 -4
  43. package/mcp/LIVE-PROTOCOL.md +7 -47
  44. package/mcp/README.md +16 -26
  45. package/mcp/live-hub.mjs +6 -10
  46. package/mcp/package.json +1 -3
  47. package/mcp/tool-handlers.mjs +4 -168
  48. package/package.json +3 -22
  49. package/src/App.jsx +151 -2625
  50. package/src/agent-progress.js +80 -0
  51. package/src/agent-turn-mark.js +30 -0
  52. package/src/analytics.js +1 -19
  53. package/src/app-context.js +12 -2
  54. package/src/app-stage.jsx +2 -34
  55. package/src/asset-pane.jsx +6 -5
  56. package/src/camera-block.js +21 -0
  57. package/src/camera-direction.js +120 -0
  58. package/src/character-kind.js +3 -9
  59. package/src/command-bus.js +10 -8
  60. package/src/commands/cast.js +5 -34
  61. package/src/commands/elements/character.js +1 -1
  62. package/src/commands/elements/motion.js +1 -6
  63. package/src/commands/elements/object.js +6 -2
  64. package/src/commands/elements/shot.js +4 -1
  65. package/src/commands/elements.js +38 -14
  66. package/src/commands/index.js +3 -1
  67. package/src/commands/kits.js +37 -0
  68. package/src/commands/motion-timing.js +57 -0
  69. package/src/commands/motion.js +9 -152
  70. package/src/commands/motion3-compile.js +65 -0
  71. package/src/commands/motion3.js +214 -0
  72. package/src/commands/objects.js +6 -4
  73. package/src/commands/shot.js +55 -13
  74. package/src/commands/stage.js +14 -1
  75. package/src/commands/view.js +4 -1
  76. package/src/document-mirrors.js +42 -0
  77. package/src/document-store.js +4 -0
  78. package/src/domains/cast.js +19 -194
  79. package/src/domains/motion/motion-range-pin-rules.js +1 -1
  80. package/src/domains/motion/take-source.js +53 -0
  81. package/src/domains/motion.js +60 -1838
  82. package/src/domains/scenes.js +12 -55
  83. package/src/domains/shots.js +2 -2
  84. package/src/domains/stage.js +4 -2
  85. package/src/draft-ghost.js +47 -0
  86. package/src/draft-ghost.jsx +129 -0
  87. package/src/dualview.jsx +4 -3
  88. package/src/effects/EffectsLayer.jsx +112 -0
  89. package/src/effects/effect-meshes.js +232 -0
  90. package/src/effects/effect-record.js +103 -0
  91. package/src/effects/emitter.js +59 -0
  92. package/src/effects/simulate.js +261 -0
  93. package/src/effects/state.js +59 -0
  94. package/src/execution-telemetry.js +2 -3
  95. package/src/first-success-guide.jsx +5 -5
  96. package/src/ghost-set.js +257 -0
  97. package/src/held-object-edit.jsx +113 -0
  98. package/src/held-object-pose.js +175 -0
  99. package/src/hierarchy-model.js +1 -1
  100. package/src/hierarchy-panel.jsx +1 -1
  101. package/src/imported-mesh.jsx +103 -0
  102. package/src/kits/held.js +84 -0
  103. package/src/kits/index.js +70 -0
  104. package/src/kits/smoking.js +57 -0
  105. package/src/light-blockers.js +93 -0
  106. package/src/motion/beat-board-model.js +84 -0
  107. package/src/motion/beat-board.css +124 -0
  108. package/src/motion/beat-board.jsx +60 -0
  109. package/src/motion/center-of-mass.js +66 -0
  110. package/src/motion/fix-collisions.js +850 -0
  111. package/src/motion/physics-review.js +118 -0
  112. package/src/{ardy → motion}/physics-support.js +1 -76
  113. package/src/motion/rig-snapshot.js +22 -0
  114. package/src/motion/take-segments.jsx +140 -0
  115. package/src/{ardy → motion}/timeline-coordinates.js +0 -21
  116. package/src/{ardy → motion}/timeline.css +1 -2
  117. package/src/{ardy → motion}/timeline.jsx +42 -413
  118. package/src/motion/waypoints.js +76 -0
  119. package/src/motion3/beats.js +83 -0
  120. package/src/motion3/body.js +158 -0
  121. package/src/motion3/bones.js +47 -0
  122. package/src/motion3/carried.js +47 -0
  123. package/src/motion3/compile-job.js +79 -0
  124. package/src/motion3/compile-worker.js +10 -0
  125. package/src/motion3/compiler/anchors.js +113 -0
  126. package/src/motion3/compiler/arm-orient.js +128 -0
  127. package/src/motion3/compiler/channels.js +125 -0
  128. package/src/motion3/compiler/compile.js +205 -0
  129. package/src/motion3/compiler/gait-rhythm.js +97 -0
  130. package/src/motion3/compiler/grip.js +171 -0
  131. package/src/motion3/compiler/head-steady.js +48 -0
  132. package/src/motion3/compiler/hold.js +134 -0
  133. package/src/motion3/compiler/idle.js +113 -0
  134. package/src/motion3/compiler/limbs.js +197 -0
  135. package/src/motion3/compiler/math.js +72 -0
  136. package/src/motion3/compiler/pose.js +177 -0
  137. package/src/motion3/compiler/quat.js +49 -0
  138. package/src/motion3/compiler/skeleton.js +74 -0
  139. package/src/motion3/compiler/validate-common.js +32 -0
  140. package/src/motion3/compiler/validate-goals.js +118 -0
  141. package/src/motion3/compiler/validate-objects.js +144 -0
  142. package/src/motion3/compiler/validate-parts.js +118 -0
  143. package/src/motion3/compiler/validate.js +122 -0
  144. package/src/motion3/compiler/vocab.js +74 -0
  145. package/src/motion3/compiler/walk-pelvis.js +275 -0
  146. package/src/motion3/compiler/walk.js +207 -0
  147. package/src/motion3/compiler/wrist-clamp.js +32 -0
  148. package/src/motion3/delta.js +47 -0
  149. package/src/motion3/describe.js +177 -0
  150. package/src/motion3/docs.js +27 -0
  151. package/src/motion3/edit-carry.js +21 -0
  152. package/src/motion3/fix/ease.js +16 -0
  153. package/src/motion3/fix/ground.js +37 -0
  154. package/src/motion3/fix/index.js +52 -0
  155. package/src/motion3/fix/push.js +71 -0
  156. package/src/motion3/fix/reach.js +46 -0
  157. package/src/motion3/fix/retime.js +79 -0
  158. package/src/motion3/fix/self.js +211 -0
  159. package/src/motion3/fix/slide.js +70 -0
  160. package/src/motion3/fix/turn.js +51 -0
  161. package/src/motion3/follow.js +39 -0
  162. package/src/motion3/free-motion.js +204 -0
  163. package/src/motion3/grip-choice.js +130 -0
  164. package/src/motion3/hold-plan.js +157 -0
  165. package/src/motion3/json-patch.js +77 -0
  166. package/src/motion3/key-aim.js +105 -0
  167. package/src/motion3/key-edit.js +82 -0
  168. package/src/motion3/lenient.js +127 -0
  169. package/src/motion3/object-keys.js +236 -0
  170. package/src/motion3/object-pose.js +182 -0
  171. package/src/motion3/object-tracks.js +12 -0
  172. package/src/motion3/people.js +82 -0
  173. package/src/motion3/pipeline.js +102 -0
  174. package/src/motion3/playback.js +51 -0
  175. package/src/motion3/probes.js +91 -0
  176. package/src/motion3/qa/body-checks.js +34 -0
  177. package/src/motion3/qa/check-names.js +14 -0
  178. package/src/motion3/qa/checks.js +125 -0
  179. package/src/motion3/qa/contact-checks.js +51 -0
  180. package/src/motion3/qa/explain.js +80 -0
  181. package/src/motion3/qa/fmt.js +5 -0
  182. package/src/motion3/qa/foot-checks.js +72 -0
  183. package/src/motion3/qa/geometry.js +77 -0
  184. package/src/motion3/qa/goals.js +191 -0
  185. package/src/motion3/qa/ground.js +60 -0
  186. package/src/motion3/qa/hints-contact.js +195 -0
  187. package/src/motion3/qa/hints-goal.js +160 -0
  188. package/src/motion3/qa/hints-knee.js +24 -0
  189. package/src/motion3/qa/hints-motion.js +209 -0
  190. package/src/motion3/qa/hints-object.js +91 -0
  191. package/src/motion3/qa/index.js +44 -0
  192. package/src/motion3/qa/key-checks.js +82 -0
  193. package/src/motion3/qa/near.js +96 -0
  194. package/src/motion3/qa/object-checks.js +135 -0
  195. package/src/motion3/qa/patch.js +161 -0
  196. package/src/motion3/qa/people-checks.js +37 -0
  197. package/src/motion3/qa/severity.js +38 -0
  198. package/src/motion3/qa/spec-checks.js +65 -0
  199. package/src/motion3/qa/style.js +228 -0
  200. package/src/motion3/qa/wrist-checks.js +69 -0
  201. package/src/motion3/qa/wrist-obs.js +60 -0
  202. package/src/motion3/refs.js +129 -0
  203. package/src/motion3/repair-tune.js +121 -0
  204. package/src/motion3/repair.js +83 -0
  205. package/src/motion3/report.js +67 -0
  206. package/src/motion3/rigs/index.js +14 -0
  207. package/src/motion3/rigs/x-bot-tpose-body.json +1 -0
  208. package/src/motion3/rigs/x-bot-tpose.json +1 -0
  209. package/src/motion3/rigs/y-bot-tpose-body.json +1 -0
  210. package/src/motion3/rigs/y-bot-tpose.json +1 -0
  211. package/src/motion3/scene.js +60 -0
  212. package/src/motion3/schema/brief.js +89 -0
  213. package/src/motion3/schema/fields.js +44 -0
  214. package/src/motion3/schema/spec-examples.js +46 -0
  215. package/src/motion3/schema/topics.js +113 -0
  216. package/src/motion3/schema/types.js +149 -0
  217. package/src/motion3/search.js +117 -0
  218. package/src/motion3/second-hand.js +112 -0
  219. package/src/motion3/settle.js +136 -0
  220. package/src/motion3/skills/basic.js +83 -0
  221. package/src/motion3/skills/book.js +76 -0
  222. package/src/motion3/skills/car.js +145 -0
  223. package/src/motion3/skills/flip.js +200 -0
  224. package/src/motion3/skills/frames-auto.js +29 -0
  225. package/src/motion3/skills/impact.js +109 -0
  226. package/src/motion3/skills/index.js +85 -0
  227. package/src/motion3/skills/info.js +80 -0
  228. package/src/motion3/skills/smoke-kit.js +109 -0
  229. package/src/motion3/skills/smoke.js +160 -0
  230. package/src/motion3/spec-store.js +59 -0
  231. package/src/motion3/take-edit.js +155 -0
  232. package/src/motion3/take.js +63 -0
  233. package/src/motion3/timeline.js +127 -0
  234. package/src/motion3/views.js +121 -0
  235. package/src/motion3/walk-plan.js +119 -0
  236. package/src/object-catalog.jsx +7 -1
  237. package/src/object-colors.js +98 -0
  238. package/src/object-gizmo-parts.js +115 -0
  239. package/src/object-gizmo.jsx +37 -122
  240. package/src/object-glow.js +139 -0
  241. package/src/object-hidden.js +33 -0
  242. package/src/object-look.js +196 -0
  243. package/src/object-size.js +10 -0
  244. package/src/object-travel.js +71 -6
  245. package/src/panels/CameraPanel.jsx +7 -7
  246. package/src/panels/HdrEnvironmentControls.jsx +59 -0
  247. package/src/panels/LightPanel.jsx +25 -4
  248. package/src/panels/ObjectLookPanel.jsx +88 -0
  249. package/src/panels/PosePanel.jsx +2 -17
  250. package/src/panels/RigControlPanel.jsx +5 -53
  251. package/src/panels/SubjectBox.jsx +4 -1
  252. package/src/panels/details.css +14 -0
  253. package/src/posestudio.jsx +4 -27
  254. package/src/project-browser.jsx +3 -4
  255. package/src/project-resources.js +18 -31
  256. package/src/project.js +13 -104
  257. package/src/props.jsx +25 -280
  258. package/src/qa-label.js +25 -0
  259. package/src/rail-dot-drag.js +23 -0
  260. package/src/render-passes.js +10 -0
  261. package/src/resource-status.jsx +1 -0
  262. package/src/result-modal.jsx +4 -19
  263. package/src/room.jsx +20 -12
  264. package/src/scene-assets.js +8 -6
  265. package/src/scene-light-place.js +72 -0
  266. package/src/scene-lights.jsx +148 -0
  267. package/src/scene-objects.js +31 -139
  268. package/src/scenes.js +15 -105
  269. package/src/semantic-edit.js +2 -5
  270. package/src/set-pieces.jsx +183 -0
  271. package/src/settings-menu.jsx +3 -11
  272. package/src/shell/BottomDock.jsx +9 -51
  273. package/src/shell/DetailsSlot.jsx +16 -200
  274. package/src/shell/GhostsMenuGroup.jsx +74 -0
  275. package/src/shell/LibrarySlot.jsx +1 -3
  276. package/src/shell/MenuBar.jsx +3 -3
  277. package/src/shell/PreferencesDialog.jsx +15 -264
  278. package/src/shell/PreferencesSlot.jsx +2 -8
  279. package/src/shell/TopBar.jsx +5 -84
  280. package/src/shell/ViewportToolbar.jsx +10 -70
  281. package/src/shell/agent-glass.css +19 -6
  282. package/src/shell/details-selection.js +42 -0
  283. package/src/shell/ghosts-menu.css +22 -0
  284. package/src/shell/glass-regions.css +29 -3
  285. package/src/shell/preferences.css +6 -1
  286. package/src/shot-authoring.js +4 -7
  287. package/src/soft-shadows.js +37 -0
  288. package/src/stage-attach-frames.js +12 -12
  289. package/src/stage-canvas-rigs.jsx +3 -3
  290. package/src/stage-capture.jsx +42 -8
  291. package/src/stage-characters.jsx +22 -216
  292. package/src/stage-editor-gizmos.jsx +6 -6
  293. package/src/stage-environment.js +93 -0
  294. package/src/stage-hdr-builtins.js +107 -0
  295. package/src/stage-hdr-image.js +116 -0
  296. package/src/stage-hdr-library.js +70 -0
  297. package/src/stage-hdr-map.js +94 -0
  298. package/src/stage-hdr.js +130 -0
  299. package/src/stage-lighting.js +149 -0
  300. package/src/stage-occlusion.js +210 -0
  301. package/src/stage-sky.jsx +159 -0
  302. package/src/stage-startup-defaults.js +5 -9
  303. package/src/studio-actions.js +16 -14
  304. package/src/studio-agent-commands.js +19 -16
  305. package/src/studio-agent-motion.js +9 -9
  306. package/src/studio-agent-protocol.js +47 -77
  307. package/src/studio-app-binding.js +27 -47
  308. package/src/studio-asset-list.js +17 -0
  309. package/src/studio-contact-sheet.js +37 -5
  310. package/src/studio-elements.js +27 -7
  311. package/src/studio-entity-bounds.js +18 -0
  312. package/src/studio-error-codes.js +15 -0
  313. package/src/studio-export-framing.js +152 -0
  314. package/src/studio-lighting-check.js +103 -0
  315. package/src/studio-motion-visual.js +150 -0
  316. package/src/studio-schema-errors.js +80 -0
  317. package/src/studio-support-gap.js +74 -0
  318. package/src/styles.css +1 -19
  319. package/src/timeline-defaults.js +5 -0
  320. package/src/timeline-extent.js +8 -20
  321. package/src/tutorial-walk.js +17 -0
  322. package/src/ui-scrub.js +1 -1
  323. package/src/use-shot-camera-tracks.js +12 -0
  324. package/src/view-ghosts.js +97 -0
  325. package/src/view-ghosts.jsx +49 -0
  326. package/src/workflow/AgentPanel.jsx +47 -166
  327. package/src/workflow/AgentProgressCard.jsx +109 -0
  328. package/src/workflow/AgentReplyText.jsx +37 -0
  329. package/src/workflow/AgentTurnSteps.jsx +84 -0
  330. package/src/workflow/LoginPanel.jsx +140 -0
  331. package/src/workflow/WorkflowBuilder.jsx +7 -23
  332. package/src/workflow/agent-client.js +54 -51
  333. package/src/workflow/agent-panel.css +71 -1
  334. package/src/workflow/agent-progress-card.css +167 -0
  335. package/src/workflow/agent-progress-view.js +47 -0
  336. package/src/workflow/agent-turn-steps.css +113 -0
  337. package/src/workflow/agent-turn.js +191 -0
  338. package/src/workflow/login-client.js +34 -0
  339. package/src/workflow/motion-input.js +18 -31
  340. package/src/workflow/node-schema.js +1 -1
  341. package/src/workflow/reply-markdown.js +69 -0
  342. package/src/workflow/scene-asset-sync.js +8 -8
  343. package/tools/agent-session-stats.mjs +61 -0
  344. package/tools/dev-full.mjs +5 -56
  345. package/tools/eslint-baseline.json +12 -13
  346. package/tools/knip-baseline.json +0 -179
  347. package/tools/loc-baseline.json +31 -81
  348. package/tools/motion3/extract-body.mjs +103 -0
  349. package/tools/motion3/extract-rig.mjs +85 -0
  350. package/tools/process-supervisor.mjs +0 -88
  351. package/tools/run-tests.mjs +9 -125
  352. package/bin/agent/motion-runtime.mjs +0 -76
  353. package/dist/ardy/cskel27-rest.json +0 -557
  354. package/dist/assets/analytics-C9pMpW7s.js +0 -1
  355. package/dist/assets/app-B_2XB9rw.css +0 -1
  356. package/dist/assets/app-DAuvKPP8.js +0 -4920
  357. package/dist/assets/config-Bx7pYsD9.js +0 -1
  358. package/dist/assets/config-DeoFTYzb.css +0 -1
  359. package/dist/assets/demo-CvKuBgy5.js +0 -1
  360. package/dist/assets/scene-asset-sync-DKkpjKBV.js +0 -19
  361. package/dist/assets/scene-asset-sync-DjJ_cJ2R.css +0 -1
  362. package/dist/assets/ticket-BPk2Ni95.js +0 -1
  363. package/dist/assets/workflow-jJRBR94Z.js +0 -179
  364. package/dist/demo/walk-then-stop.npz +0 -0
  365. package/mcp/ardy-prompts.mjs +0 -218
  366. package/src/ardy/auto-fix-panel.css +0 -108
  367. package/src/ardy/auto-physics.js +0 -1194
  368. package/src/ardy/client.js +0 -153
  369. package/src/ardy/convert.js +0 -313
  370. package/src/ardy/cskel27-neutral.js +0 -39
  371. package/src/ardy/cskel27.js +0 -77
  372. package/src/ardy/export.js +0 -165
  373. package/src/ardy/fix-collisions.js +0 -2257
  374. package/src/ardy/foot-lock.js +0 -230
  375. package/src/ardy/motion-calibration.js +0 -118
  376. package/src/ardy/motion-edit.js +0 -213
  377. package/src/ardy/motion-url.js +0 -55
  378. package/src/ardy/mp4-duration.js +0 -102
  379. package/src/ardy/npz.js +0 -595
  380. package/src/ardy/physics-panel.css +0 -21
  381. package/src/ardy/physics-panel.jsx +0 -89
  382. package/src/ardy/physics-refine.js +0 -111
  383. package/src/ardy/physics-review.js +0 -567
  384. package/src/ardy/physics-temporal.js +0 -54
  385. package/src/ardy/platform-fit-panel.css +0 -64
  386. package/src/ardy/platform-fit-panel.jsx +0 -41
  387. package/src/ardy/platform-fit.js +0 -326
  388. package/src/ardy/playback.js +0 -711
  389. package/src/ardy/pose-pin.js +0 -97
  390. package/src/ardy/prompt-clips.js +0 -30
  391. package/src/ardy/retime.js +0 -211
  392. package/src/ardy/root-drop.js +0 -369
  393. package/src/ardy/timeline-resize.js +0 -13
  394. package/src/ardy/to-cskel27.js +0 -225
  395. package/src/ardy/trim.js +0 -33
  396. package/src/ardy/waypoints.js +0 -369
  397. package/src/ardy-bridge-contract.js +0 -281
  398. package/src/domains/motion/motion-video-capture.js +0 -664
  399. package/src/i2v-motion-client.js +0 -77
  400. package/src/i2v-motion-studio.jsx +0 -180
  401. package/src/line-edit.js +0 -1348
  402. package/src/motion/generation.js +0 -105
  403. package/src/motion-readiness-ui.jsx +0 -67
  404. package/src/motion-readiness.js +0 -40
  405. package/src/motion-resources.js +0 -177
  406. package/src/motion-store.js +0 -65
  407. package/src/motion-trail.js +0 -601
  408. package/src/multimodel-ingest.js +0 -394
  409. package/src/panels/PromptBlocksPanel.jsx +0 -444
  410. package/src/panels/VideoCapturePanel.jsx +0 -181
  411. package/src/pose-extract/browser.js +0 -42
  412. package/src/pose-extract/detector.js +0 -100
  413. package/src/pose-extract/fit.js +0 -227
  414. package/src/pose-extract/image-frame.js +0 -51
  415. package/src/pose-extract/index.js +0 -58
  416. package/src/pose-extract/keyframes.js +0 -74
  417. package/src/pose-extract/landmarks.js +0 -162
  418. package/src/pose-extract/mirror.js +0 -153
  419. package/src/pose-extract/take.js +0 -131
  420. package/src/pose-extract/video-frames.js +0 -91
  421. package/src/take-recipe.js +0 -165
  422. package/src/trail-key-conflicts.js +0 -39
  423. package/src/trail-pick.js +0 -59
  424. package/src/use-i2v-capture-modal.js +0 -15
  425. package/tools/ardy/BRIDGE.md +0 -37
  426. package/tools/ardy/GVHMR-NPZ.md +0 -68
  427. package/tools/ardy/README.md +0 -124
  428. package/tools/ardy/__pycache__/cclay_gvhmr_worker.cpython-313.pyc +0 -0
  429. package/tools/ardy/artifacts.mjs +0 -34
  430. package/tools/ardy/bridge.mjs +0 -1732
  431. package/tools/ardy/bvh-cskel27.mjs +0 -1265
  432. package/tools/ardy/cclay_constrained_generate.py +0 -561
  433. package/tools/ardy/cclay_gvhmr_worker.py +0 -264
  434. package/tools/ardy/cclay_motion_edit.py +0 -510
  435. package/tools/ardy/cclay_sequence_generate.py +0 -705
  436. package/tools/ardy/cclay_worker.py +0 -304
  437. package/tools/ardy/dump-npz.py +0 -205
  438. package/tools/ardy/extract-rest.mjs +0 -299
  439. package/tools/ardy/extract.mjs +0 -507
  440. package/tools/ardy/footage.mjs +0 -467
  441. package/tools/ardy/gvhmr-floor.mjs +0 -102
  442. package/tools/ardy/gvhmr-to-cskel27.mjs +0 -21
  443. package/tools/ardy/gvhmr_fastpath.py +0 -168
  444. package/tools/ardy/gvhmr_trajectory.py +0 -240
  445. package/tools/ardy/merge-text-encoder.py +0 -160
  446. package/tools/ardy/mocap-metrics.mjs +0 -200
  447. package/tools/ardy/mocap-quality-gate.mjs +0 -110
  448. package/tools/ardy/motion-stabilize.mjs +0 -348
  449. package/tools/ardy/npz.mjs +0 -414
  450. package/tools/ardy/pose-to-npz.mjs +0 -106
  451. package/tools/ardy/prompt-limits.mjs +0 -5
  452. package/tools/ardy/run-edit-on-box.sh +0 -73
  453. package/tools/ardy/run-local.mjs +0 -233
  454. package/tools/ardy/run-on-box.sh +0 -593
  455. package/tools/ardy/run-sequence-on-box.sh +0 -177
  456. package/tools/ardy/runners/gvhmr-worker.mjs +0 -206
  457. package/tools/ardy/runners/index.mjs +0 -18
  458. package/tools/ardy/runners/local.mjs +0 -455
  459. package/tools/ardy/runners/proc.mjs +0 -125
  460. package/tools/ardy/runners/remote.mjs +0 -252
  461. package/tools/ardy/setup-local.mjs +0 -189
  462. package/tools/ardy/setup-text-encoder-on-box.sh +0 -93
  463. package/tools/ardy/setup-text-encoder.py +0 -306
  464. package/tools/ardy/smpl-cskel27.mjs +0 -178
  465. package/tools/ardy/visual-qa.mjs +0 -196
  466. package/tools/ardy/vq-car.mjs +0 -52
  467. package/tools/bench/EXP3.md +0 -61
  468. package/tools/bench/cclay_bench_extract_incam.py +0 -125
  469. package/tools/bench/cclay_bench_extract_obs.py +0 -204
  470. package/tools/bench/cclay_bench_runner.py +0 -42
  471. package/tools/bench/cube-contact.mjs +0 -162
  472. package/tools/bench/exp3.mjs +0 -152
  473. package/tools/bench/extract-bench-lib.mjs +0 -216
  474. package/tools/bench/extract-bench.mjs +0 -302
  475. package/tools/bench/fal-generate.mjs +0 -88
  476. package/tools/bench/fit/README.md +0 -189
  477. package/tools/bench/fit/camera.mjs +0 -59
  478. package/tools/bench/fit/contact.mjs +0 -419
  479. package/tools/bench/fit/footlock.mjs +0 -234
  480. package/tools/bench/fit/motion.mjs +0 -85
  481. package/tools/bench/fit/pin.mjs +0 -27
  482. package/tools/bench/fit/remote.mjs +0 -105
  483. package/tools/bench/fit-bench.mjs +0 -126
  484. package/tools/bench/fit-sanity.mjs +0 -45
  485. package/tools/bench/metrics.mjs +0 -313
  486. package/tools/bench/obs/depth.mjs +0 -258
  487. package/tools/bench/obs/extrinsics.mjs +0 -175
  488. package/tools/bench/obs/fit_mannequin_betas.py +0 -340
  489. package/tools/bench/obs/ground.mjs +0 -294
  490. package/tools/bench/obs/heading.mjs +0 -151
  491. package/tools/bench/obs/ladder.mjs +0 -555
  492. package/tools/bench/obs/mannequin-betas.json +0 -124
  493. package/tools/bench/obs/remote.mjs +0 -83
  494. package/tools/bench/obs/rest_joints.py +0 -52
  495. package/tools/bench/obs/ybot-targets.mjs +0 -49
  496. package/tools/bench/obs-bench.mjs +0 -520
  497. package/tools/bench/score.mjs +0 -343
  498. package/tools/bench/summarize.mjs +0 -86
  499. package/tools/demo-worker/README.md +0 -137
  500. package/tools/demo-worker/api-client.mjs +0 -233
  501. package/tools/demo-worker/generate.mjs +0 -301
  502. package/tools/demo-worker/index.mjs +0 -466
  503. package/tools/demo-worker/sign-core.mjs +0 -112
  504. package/tools/demo-worker/sign.mjs +0 -161
  505. package/tools/gt-render/browser.mjs +0 -182
  506. package/tools/gt-render/camera-math.mjs +0 -276
  507. package/tools/gt-render/page.mjs +0 -267
  508. package/tools/gt-render/render.mjs +0 -514
  509. package/tools/gt-render/scene-box.mjs +0 -31
  510. package/tools/gt-render/take-transform.mjs +0 -87
  511. package/tools/kimodo/compare-seam.mjs +0 -108
  512. package/tools/kimodo/constraints.mjs +0 -244
  513. package/tools/kimodo/edit.mjs +0 -259
  514. package/tools/kimodo/effector-constraints.mjs +0 -200
  515. package/tools/kimodo/generate.mjs +0 -646
  516. package/tools/kimodo/local-output.mjs +0 -265
  517. package/tools/kimodo/measure-pose.mjs +0 -65
  518. package/tools/kimodo/measure-preserve.mjs +0 -899
  519. package/tools/kimodo/measure-waypoints.mjs +0 -55
  520. package/tools/kimodo/mlx-generate.py +0 -111
  521. package/tools/kimodo/pose-constraints.mjs +0 -248
  522. package/tools/kimodo/preserve-mask.mjs +0 -543
  523. package/tools/kimodo/read-npz.mjs +0 -189
  524. package/tools/kimodo/run-edit-on-box.mjs +0 -155
  525. package/tools/kimodo/run-sequence-on-box.mjs +0 -178
  526. package/tools/kimodo/runner.mjs +0 -284
  527. package/tools/kimodo/seam-batch.mjs +0 -77
  528. package/tools/kimodo/setup-local.mjs +0 -30
  529. package/tools/kimodo/setup-on-box.sh +0 -339
  530. package/tools/kimodo/soma77-to-cskel27.mjs +0 -305
  531. package/tools/morphgs/assets/gen_truth.py +0 -39
  532. package/tools/morphgs/assets/mesh_ori_rig.txt +0 -27
  533. package/tools/morphgs/assets/playback-check.mjs +0 -30
  534. package/tools/morphgs/demo-gate.sh +0 -26
  535. package/tools/morphgs/fbx2morphgs.mjs +0 -68
  536. package/tools/morphgs/morphgs-to-cskel27.mjs +0 -105
  537. package/tools/morphgs/patches/preprocess_src-none-mode.patch +0 -76
  538. package/tools/morphgs/setup-on-cluster.sh +0 -126
  539. package/tools/projflow/driver.py +0 -1069
  540. package/tools/projflow/generate.mjs +0 -805
  541. package/tools/projflow/hml22-to-cskel27.mjs +0 -735
  542. package/tools/projflow/line-edit-job.mjs +0 -547
  543. package/tools/projflow/replay.mjs +0 -452
  544. package/tools/projflow/runner.mjs +0 -269
  545. package/tools/projflow/service.mjs +0 -742
  546. package/tools/track/DESIGN.md +0 -513
  547. package/tools/track/backfill-provenance.mjs +0 -116
  548. package/tools/track/budget.mjs +0 -8
  549. package/tools/track/check-rig.mjs +0 -209
  550. package/tools/track/diagnostics.schema.json +0 -60
  551. package/tools/track/export-rig.mjs +0 -256
  552. package/tools/track/fallback.mjs +0 -7
  553. package/tools/track/fk-parity-fixture.mjs +0 -161
  554. package/tools/track/gate.mjs +0 -349
  555. package/tools/track/masks.mjs +0 -318
  556. package/tools/track/metrics.mjs +0 -201
  557. package/tools/track/publish-obs.mjs +0 -108
  558. package/tools/track/py/check_env.py +0 -61
  559. package/tools/track/py/eval_lr.py +0 -229
  560. package/tools/track/py/lr_viterbi.py +0 -294
  561. package/tools/track/py/masks.py +0 -405
  562. package/tools/track/py/objective.py +0 -382
  563. package/tools/track/py/rig.py +0 -508
  564. package/tools/track/py/scene.py +0 -326
  565. package/tools/track/py/test_joint_indices.py +0 -123
  566. package/tools/track/py/test_lr_viterbi.py +0 -195
  567. package/tools/track/py/test_masks.py +0 -229
  568. package/tools/track/py/test_rig.py +0 -288
  569. package/tools/track/py/test_scene.py +0 -354
  570. package/tools/track/py/test_track.py +0 -328
  571. package/tools/track/py/track.py +0 -411
  572. package/tools/track/remote.mjs +0 -140
  573. package/tools/track/rig-dump.mjs +0 -227
  574. package/tools/track/run-box-tests.mjs +0 -14
  575. package/tools/track/run-box.mjs +0 -168
  576. package/tools/track/setup-box.sh +0 -59
  577. package/tools/track/study-2d.mjs +0 -728
  578. /package/src/{ardy → motion}/collision-blockers.js +0 -0
  579. /package/src/{ardy → motion}/ground.js +0 -0
  580. /package/src/{ardy → motion}/ik-drag.js +0 -0
  581. /package/src/{ardy → motion}/ik-key-json.js +0 -0
  582. /package/src/{ardy → motion}/ik.js +0 -0
  583. /package/src/{ardy → motion}/physics-surface.js +0 -0
  584. /package/src/{ardy → motion}/playback-clock.js +0 -0
  585. /package/src/{ardy → motion}/range-pin.js +0 -0
@@ -1,8 +1,7 @@
1
1
  import { useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
2
- import { frameFromClientX, groupKeyRuns, KEY_RUN_MIN, motionTrimRange, promptMoveStartFrame, rangePinBandGeometry, shotBlockGeometry } from "./timeline-coordinates.js";
3
- import { motionSegmentSpeedForFrames } from "./motion-edit.js";
2
+ import { frameFromClientX, groupKeyRuns, KEY_RUN_MIN, rangePinBandGeometry, shotBlockGeometry } from "./timeline-coordinates.js";
4
3
  import { createPlaybackClock } from "./playback-clock.js";
5
- import { promptResizeFrame } from "./timeline-resize.js";
4
+
6
5
  import { ko, isKo } from "../locale.js";
7
6
  import { isImeComposing } from "../ime.js";
8
7
  import { buildRail, craneHeightAt } from "../camera-follow.js";
@@ -10,7 +9,9 @@ import { insertPathMark, pathMarks, pathMetrics, pathProgressAt, MAX_PATH_LEAN }
10
9
  import { NumberField } from "../ui.jsx";
11
10
  import { flatTiming, timingIsFlat, envelopeDrag, insertCut, removeCut, CUT_MIN_GAP } from "../speed-envelope.js";
12
11
  import { checkShotAgainstPreset, presetById } from "../model-presets.js";
12
+ import { TakeSegmentClips, TakeSegmentTools } from "./take-segments.jsx"; import { BeatBoard } from "./beat-board.jsx";
13
13
  import "./timeline.css";
14
+ export { timelineTake } from "./take-segments.jsx";
14
15
 
15
16
  /**
16
17
  * ARDY Viser-style animation timeline — the live motion workspace.
@@ -43,13 +44,12 @@ const WHEEL_STEP_PX = 50;
43
44
  const MAX_WHEEL_STEPS = 3;
44
45
 
45
46
  const TRACKS = [
46
- "Prompts",
47
47
  "Full-Body",
48
48
  "2D Root",
49
49
  "Shots",
50
50
  ];
51
51
  const TRACK_LABELS_KO = {
52
- Prompts: ko("Prompt", "프롬프트"),
52
+
53
53
  "Full-Body": ko("Body", "바디"),
54
54
  "2D Root": ko("Root path", "루트 경로"),
55
55
  Shots: ko("Camera Cuts", "카메라 컷"),
@@ -60,7 +60,7 @@ const TRACK_LABELS_KO = {
60
60
  const IK_LANE = "Full-Body";
61
61
  const SHOTS_LANE = "Shots";
62
62
  // Ruler labels and lane gridlines share one 10-frame cadence, so authored
63
- // elements (40-frame prompt blocks, camera key dots) always land on visible
63
+ // elements (camera key dots, root pins) always land on visible
64
64
  // lines. Label density adapts to zoom in 10-based steps.
65
65
  const GRID_STEP_FRAMES = 10;
66
66
  const LABEL_STEPS = [10, 20, 50, 100, 200, 500, 1000];
@@ -899,7 +899,7 @@ function CameraBlockEditor({
899
899
  </label>
900
900
  <label title={ko("Cap dolly travel speed", "돌리의 최고 이동 속도를 제한합니다")}>
901
901
  <span>{ko("Speed", "속도")}</span>
902
- <input type="number" min="0.2" max="8" step="0.1" value={follow.maxDollySpeed} onChange={(event) => patchFollow({ maxDollySpeed: numberValue(event) })} />
902
+ <input type="number" min="0.2" max="40" step="0.1" value={follow.maxDollySpeed} onChange={(event) => patchFollow({ maxDollySpeed: numberValue(event) })} />
903
903
  <small>m/s</small>
904
904
  </label>
905
905
  {!(mode === "rail" && crane) && (
@@ -1005,30 +1005,25 @@ export default function Timeline({
1005
1005
  playing,
1006
1006
  // Which cast member's animation layer these tracks edit ("S2", …).
1007
1007
  trackOwner = null,
1008
- // Read-only previews of the OTHER cast members' layers: their prompt
1009
- // blocks and root pins render dimmed with an owner chip, so the whole
1010
- // cast's schedule is visible while only the active layer is editable.
1011
- ghostLayers = [], // [{ owner, promptClips: [], waypointFrames: [] }]
1008
+ // Read-only previews of the OTHER cast members' layers: their root pins
1009
+ // render dimmed with an owner chip, so the whole cast's schedule is
1010
+ // visible while only the active layer is editable.
1011
+ ghostLayers = [], // [{ owner, waypointFrames: [] }]
1012
1012
  waypointMode,
1013
1013
  // Which department the studio is in ("scene" | "camera" | "motion"). The
1014
- // motion-layer track tools — Prompts +, the Full-Body Cut, the trim and
1015
- // retime grips — only mean something while motion is the job, so they are
1016
- // not rendered anywhere else. The Root path (Waypoint) toggle stays in
1017
- // every mode: blocking uses it to stage where a subject walks.
1014
+ // camera-cut tools (Cut, Draw rail, + Track) belong to Scene and Camera.
1015
+ // The Root path (Waypoint) toggle stays in every mode: blocking uses it to
1016
+ // stage where a subject walks.
1018
1017
  workflowMode = "motion",
1019
- // A storyboard works in panels: it has no Prompts lane, chips or + Block.
1020
- previsMode = null,
1021
1018
  waypoints = [],
1022
1019
  pathSpeed = null, // { min, max, warn } in m/s, shown on the 2D Root label
1023
- badge,
1024
- promptClips = [],
1025
- selectedPromptId,
1020
+ badge,
1026
1021
  pendingWaypointFrame = null,
1027
1022
  ikMode = false,
1028
1023
  ikDisabled = false, // a loaded motion owns the rig
1029
1024
  // The ACTIVE cast member's loaded take, drawn as a passive strip on the
1030
1025
  // Full-Body lane. Frames are already on the timeline's 24 fps clock.
1031
- motion = null, // { frames, label } | null
1026
+ motion = null, // { frames, label, segments, cut, speed, remove, trim, reset } (take-segments.jsx timelineTake) | null
1032
1027
  ikFrames = [], // sorted full-body key frames
1033
1028
  rangePins = [], // active character's inclusive pin ranges
1034
1029
  previewRanges = [], // amber preview spans shown under the Body track
@@ -1052,12 +1047,7 @@ export default function Timeline({
1052
1047
  onMarkerSelect,
1053
1048
  onMarkerRemove,
1054
1049
  onRootKeyframeAdd,
1055
- onPromptAdd,
1056
- onPromptSelect,
1057
- onPromptChange,
1058
- onPromptResize,
1059
- onPromptMove,
1060
- onPromptRemove,
1050
+
1061
1051
  onClearMotion,
1062
1052
  onIkKeyframeAdd,
1063
1053
  onIkKeyframeRemove,
@@ -1102,11 +1092,7 @@ export default function Timeline({
1102
1092
  onShotCut,
1103
1093
  onShotSplit,
1104
1094
  onShotMove,
1105
- onMotionTrim,
1106
- onMotionTrimReset,
1107
- onMotionCut,
1108
- onMotionSpeedChange,
1109
- onMotionSegmentRemove,
1095
+
1110
1096
  // One undo entry per editing GESTURE. Fired once when a continuous drag
1111
1097
  // (or a keyboard nudge, or a text-editing session) begins, BEFORE the
1112
1098
  // first mutation lands, so App can snapshot the pre-gesture state exactly
@@ -1115,7 +1101,7 @@ export default function Timeline({
1115
1101
  }) {
1116
1102
  const [expanded, setExpanded] = useState(true);
1117
1103
  const [zoom, setZoom] = useState(ZOOM_DEFAULT);
1118
- const [movingPromptId, setMovingPromptId] = useState(null);
1104
+
1119
1105
  const [renamingShotId, setRenamingShotId] = useState(null);
1120
1106
  const [movingShotId, setMovingShotId] = useState(null);
1121
1107
  const [localCameraBlockIdx, setLocalCameraBlockIdx] = useState(null);
@@ -1132,7 +1118,7 @@ export default function Timeline({
1132
1118
  // The window key/interval handlers register once; the latest callbacks
1133
1119
  // are read through a ref so they never go stale mid-playback.
1134
1120
  const handlers = useRef({});
1135
- handlers.current = { onScrub, onAdvance, onStep, onPlayToggle, onWaypointToggle, onMarkerSelect, onMarkerRemove, onRootKeyframeAdd, onPromptAdd, onPromptSelect, onPromptChange, onPromptResize, onPromptMove, onPromptRemove, onIkKeyframeAdd, onIkKeyframeRemove, onPinSelect, onFootSnapToggle, onBodyContactToggle, onCameraMoveSelect, onCameraKeyframeAdd, onCameraKeyframeMove, onCameraKeyframeRemove, onCameraBlockSelect, onCameraBlockChange, onCameraPreview, onCameraRailDrawToggle, onCameraRailDelete, onObjectPathDrawToggle, onObjectPathChange, onObjectPathClear, onObjectTimingGestureStart, onObjectTimingGestureEnd, onObjectMarkAdd, onObjectMarkLean, onObjectMarkScrubStart, onObjectMarkScrubEnd, onShotSelect, onShotBoundaryMove, onShotRename, onShotRemove, onShotDuplicate, onShotCut, onShotSplit, onShotMove, onMotionTrim, onMotionTrimReset, onMotionCut, onMotionSpeedChange, onMotionSegmentRemove, onEditGestureStart };
1121
+ handlers.current = { onScrub, onAdvance, onStep, onPlayToggle, onWaypointToggle, onMarkerSelect, onMarkerRemove, onRootKeyframeAdd, onIkKeyframeAdd, onIkKeyframeRemove, onPinSelect, onFootSnapToggle, onBodyContactToggle, onCameraMoveSelect, onCameraKeyframeAdd, onCameraKeyframeMove, onCameraKeyframeRemove, onCameraBlockSelect, onCameraBlockChange, onCameraPreview, onCameraRailDrawToggle, onCameraRailDelete, onObjectPathDrawToggle, onObjectPathChange, onObjectPathClear, onObjectTimingGestureStart, onObjectTimingGestureEnd, onObjectMarkAdd, onObjectMarkLean, onObjectMarkScrubStart, onObjectMarkScrubEnd, onShotSelect, onShotBoundaryMove, onShotRename, onShotRemove, onShotDuplicate, onShotCut, onShotSplit, onShotMove, onEditGestureStart };
1136
1122
 
1137
1123
  // Trackpad/wheel zoom over the FRAME ruler lane only. React registers
1138
1124
  // onWheel as passive, so a synthetic onWheel could never preventDefault —
@@ -1284,187 +1270,13 @@ export default function Timeline({
1284
1270
  pin,
1285
1271
  geometry: rangePinBandGeometry(pin, frameCount, displayFrameCount),
1286
1272
  })).filter((entry) => entry.geometry), [displayFrameCount, frameCount, rangePins]);
1287
- const moveRef = useRef(null);
1288
- const suppressPromptClickRef = useRef(false);
1289
- const resizeRef = useRef(null);
1290
- const camDragRef = useRef(null);
1273
+ const camDragRef = useRef(null);
1291
1274
  const camSuppressClickRef = useRef(false);
1292
1275
  const shotBoundaryRef = useRef(null);
1293
1276
  const shotMoveRef = useRef(null);
1294
1277
  const shotSuppressClickRef = useRef(false);
1295
1278
 
1296
- function beginPromptMove(e, clip) {
1297
- if (e.button !== 0 || e.target.closest(".tl-chip-handle")) return;
1298
- const lane = e.currentTarget.closest(".tl-lane");
1299
- if (!lane) return;
1300
- const rect = lane.getBoundingClientRect();
1301
- moveRef.current = {
1302
- id: clip.id,
1303
- pointerId: e.pointerId,
1304
- startClientX: e.clientX,
1305
- startFrame: clip.startFrame,
1306
- laneWidth: rect.width,
1307
- displayFrameCount,
1308
- moving: false,
1309
- };
1310
- handlers.current.onEditGestureStart?.("prompt-move");
1311
- handlers.current.onPromptSelect?.(clip.id);
1312
- }
1313
-
1314
- function movePrompt(e) {
1315
- const active = moveRef.current;
1316
- if (!active || e.pointerId !== active.pointerId) return;
1317
- if (!active.moving) {
1318
- if (Math.abs(e.clientX - active.startClientX) < 4) return;
1319
- active.moving = true;
1320
- e.currentTarget.setPointerCapture(e.pointerId);
1321
- setMovingPromptId(active.id);
1322
- document.activeElement?.blur();
1323
- }
1324
- e.preventDefault();
1325
- e.stopPropagation();
1326
- const rawStart = promptMoveStartFrame(
1327
- active.startFrame,
1328
- active.startClientX,
1329
- e.clientX,
1330
- active.laneWidth,
1331
- active.displayFrameCount
1332
- );
1333
- handlers.current.onPromptMove?.(active.id, rawStart);
1334
- }
1335
-
1336
- function endPromptMove(e) {
1337
- const active = moveRef.current;
1338
- if (!active || e.pointerId !== active.pointerId) return;
1339
- if (active.moving) {
1340
- e.preventDefault();
1341
- e.stopPropagation();
1342
- suppressPromptClickRef.current = true;
1343
- if (e.currentTarget.hasPointerCapture(e.pointerId)) e.currentTarget.releasePointerCapture(e.pointerId);
1344
- queueMicrotask(() => { suppressPromptClickRef.current = false; });
1345
- }
1346
- moveRef.current = null;
1347
- setMovingPromptId(null);
1348
- }
1349
-
1350
- function blockPromptClick(e) {
1351
- if (!suppressPromptClickRef.current) return;
1352
- e.preventDefault();
1353
- e.stopPropagation();
1354
- }
1355
-
1356
- function beginPromptResize(e, clip, edge) {
1357
- if (e.button !== 0) return;
1358
- e.preventDefault();
1359
- e.stopPropagation();
1360
- e.currentTarget.setPointerCapture?.(e.pointerId);
1361
- resizeRef.current = {
1362
- id: clip.id,
1363
- edge,
1364
- startClientX: e.clientX,
1365
- startFrame: edge === "start" ? clip.startFrame : clip.endFrame,
1366
- lastFrame: edge === "start" ? clip.startFrame : clip.endFrame,
1367
- };
1368
- handlers.current.onEditGestureStart?.("prompt-resize");
1369
- handlers.current.onPromptSelect?.(clip.id);
1370
- }
1371
-
1372
- function movePromptResize(e) {
1373
- const active = resizeRef.current;
1374
- if (!active) return;
1375
- const nextFrame = promptResizeFrame(active.startFrame, active.startClientX, e.clientX);
1376
- if (nextFrame === active.lastFrame) return;
1377
- active.lastFrame = nextFrame;
1378
- handlers.current.onPromptResize?.(active.id, active.edge, nextFrame);
1379
- }
1380
-
1381
- function endPromptResize(e) {
1382
- if (!resizeRef.current) return;
1383
- resizeRef.current = null;
1384
- e.currentTarget.releasePointerCapture?.(e.pointerId);
1385
- }
1386
-
1387
- // Motion trim: frame-accurate drag of the loaded take's in/out point on
1388
- // the Full-Body strip. No block snapping — a cut lands on the exact frame
1389
- // the hand releases. The preview lives here; the CUT itself is App's.
1390
- const motionTrimRef = useRef(null);
1391
- const [trimPreview, setTrimPreview] = useState(null);
1392
-
1393
- function beginMotionTrim(e, edge) {
1394
- if (e.button !== 0 || !motion) return;
1395
- e.preventDefault();
1396
- e.stopPropagation();
1397
- e.currentTarget.setPointerCapture?.(e.pointerId);
1398
- const rect = e.currentTarget.closest(".tl-lane")?.getBoundingClientRect();
1399
- if (!rect || rect.width < 2) return;
1400
- const max = Math.min(motion.frames, displayFrameCount) - 1;
1401
- // The preview always restarts from the FULL take: App composes the cut
1402
- // as trimOffset + start, so an end-only drag must still report start 0.
1403
- motionTrimRef.current = { edge, rect, max, displayFrameCount, preview: { start: 0, end: max } };
1404
- setTrimPreview({ start: 0, end: max });
1405
- }
1406
-
1407
- function moveMotionTrim(e) {
1408
- const active = motionTrimRef.current;
1409
- if (!active) return;
1410
- // Same pixel→frame transform as every other lane, off the pointer-down
1411
- // geometry, so the handle stays under the cursor at any zoom.
1412
- const frame = Math.min(active.max, frameFromClientX(e.clientX, active.rect.left, active.rect.width, active.displayFrameCount, frameCount));
1413
- const next = motionTrimRange(active.edge, frame, active.preview, active.max);
1414
- active.preview = next;
1415
- setTrimPreview(next);
1416
- }
1417
-
1418
- function endMotionTrim(e) {
1419
- const active = motionTrimRef.current;
1420
- motionTrimRef.current = null;
1421
- e.currentTarget.releasePointerCapture?.(e.pointerId);
1422
- setTrimPreview(null);
1423
- if (active && (active.preview.start > 0 || active.preview.end < active.max)) {
1424
- handlers.current.onMotionTrim?.(active.preview.start, active.preview.end);
1425
- }
1426
- }
1427
-
1428
- // Segment speed by stretch: dragging a segment's right-edge grip resizes it
1429
- // on the strip, and the width IS the playback rate — wider is slower. The
1430
- // preview lives here; the retime itself is App's, committed once on release.
1431
- const motionSpeedRef = useRef(null);
1432
- const [speedPreview, setSpeedPreview] = useState(null);
1433
-
1434
- function beginMotionSpeed(e, segment) {
1435
- if (e.button !== 0 || !motion) return;
1436
- e.preventDefault();
1437
- e.stopPropagation();
1438
- e.currentTarget.setPointerCapture?.(e.pointerId);
1439
- const rect = e.currentTarget.closest(".tl-lane")?.getBoundingClientRect();
1440
- if (!rect || rect.width < 2) return;
1441
- motionSpeedRef.current = { segment, rect, displayFrameCount, preview: null };
1442
- }
1443
-
1444
- function moveMotionSpeed(e) {
1445
- const active = motionSpeedRef.current;
1446
- if (!active) return;
1447
- const pointerFrame = frameFromClientX(e.clientX, active.rect.left, active.rect.width, active.displayFrameCount, frameCount);
1448
- const frames = Math.max(1, Math.round(pointerFrame) - active.segment.timelineStart + 1);
1449
- const speed = motionSegmentSpeedForFrames(active.segment, frames);
1450
- const sourceFrames = active.segment.sourceEnd - active.segment.sourceStart + 1;
1451
- const next = { id: active.segment.id, timelineFrames: Math.max(1, Math.round(sourceFrames / speed)), speed };
1452
- if (active.preview?.speed === next.speed && active.preview?.timelineFrames === next.timelineFrames) return;
1453
- active.preview = next;
1454
- setSpeedPreview(next);
1455
- }
1456
-
1457
- function endMotionSpeed(e) {
1458
- const active = motionSpeedRef.current;
1459
- motionSpeedRef.current = null;
1460
- e.currentTarget.releasePointerCapture?.(e.pointerId);
1461
- setSpeedPreview(null);
1462
- if (active?.preview && active.preview.speed !== active.segment.speed) {
1463
- handlers.current.onMotionSpeedChange?.(active.segment.id, active.preview.speed);
1464
- }
1465
- }
1466
-
1467
- // Camera key dots re-time by dragging, like prompt clips move: the frame
1279
+ // Camera key dots re-time by dragging: the frame
1468
1280
  // delta comes from the pointer-down geometry so a growing timeline cannot
1469
1281
  // feed back into the next pointermove.
1470
1282
  function beginCameraKeyDrag(e, key, shotIndex) {
@@ -1756,53 +1568,11 @@ export default function Timeline({
1756
1568
  onReset: () => commitDolly(flatTiming()),
1757
1569
  }
1758
1570
  : null;
1759
- const motionSegments = motion?.segments ?? [];
1760
- const selectedMotionSegment = motionSegments.find((segment) => frame >= segment.timelineStart && frame <= segment.timelineEnd) ?? motionSegments[0] ?? null;
1761
- const visibleMotionSegments = trimPreview
1762
- ? [{
1763
- id: "motion-trim-preview",
1764
- timelineStart: trimPreview.start,
1765
- timelineEnd: trimPreview.end,
1766
- speed: null,
1767
- preview: true,
1768
- }]
1769
- : motionSegments;
1770
- // While a speed grip is held, the dragged segment shows its would-be width
1771
- // and everything after it slides by the delta — the same reflow the commit
1772
- // will produce, so the release is never a surprise.
1773
- const displayMotionSegments = (() => {
1774
- if (!speedPreview || trimPreview) return visibleMotionSegments;
1775
- let shift = 0;
1776
- return visibleMotionSegments.map((segment) => {
1777
- if (segment.id === speedPreview.id) {
1778
- const shown = {
1779
- ...segment,
1780
- timelineStart: segment.timelineStart + shift,
1781
- timelineEnd: segment.timelineStart + shift + speedPreview.timelineFrames - 1,
1782
- previewSpeed: speedPreview.speed,
1783
- };
1784
- shift += speedPreview.timelineFrames - (segment.timelineEnd - segment.timelineStart + 1);
1785
- return shown;
1786
- }
1787
- return shift === 0 ? segment : { ...segment, timelineStart: segment.timelineStart + shift, timelineEnd: segment.timelineEnd + shift };
1788
- });
1789
- })();
1790
- // The motion-layer track tools (Prompts +, the Full-Body Cut, the trim and
1791
- // retime grips) edit the take, so Scene and Camera never render them.
1571
+ // Motion and Pose own the character layer; the camera-cut tools stay out of them.
1792
1572
  const motionTools = workflowMode === "motion";
1793
- const promptBlocksHidden = previsMode === "storyboard";
1794
- const tracks = promptBlocksHidden ? TRACKS.filter((name) => name !== "Prompts") : TRACKS;
1573
+ const tracks = TRACKS;
1795
1574
  const activeShotForCut = shots[activeShotIdx] ?? null;
1796
1575
  const canCutShot = Boolean(activeShotForCut && frame > activeShotForCut.startFrame && frame <= activeShotForCut.endFrame);
1797
- // A trim or retime grip edits ONE segment: it belongs to the segment the
1798
- // playhead selects. The trim preview clip carries the live gesture, so it
1799
- // keeps its grips while the pointer is down.
1800
- const segmentTools = (segment) => motionTools && (segment.preview === true || selectedMotionSegment?.id === segment.id);
1801
- const changeSelectedMotionSpeed = (speed) => {
1802
- if (!selectedMotionSegment || !Number.isFinite(speed)) return;
1803
- handlers.current.onMotionSpeedChange?.(selectedMotionSegment.id, Math.max(0.1, Math.min(4, speed)));
1804
- };
1805
-
1806
1576
  return (
1807
1577
  <section className={"timeline v2-sequencer" + (expanded ? "" : " collapsed") + (!shots.length ? " empty-shots" : "")} data-testid="sequencer" aria-label={ko("Animation timeline", "애니메이션 타임라인")}>
1808
1578
  {expanded ? (
@@ -1842,37 +1612,7 @@ export default function Timeline({
1842
1612
  </span>
1843
1613
  </div>
1844
1614
  <div className="tl-sequencer-actions" role="group" aria-label={ko("Sequencer actions", "시퀀서 작업")}>
1845
- {motionTools ? (<>
1846
- <button
1847
- type="button"
1848
- className="tl-seq-action cut"
1849
- data-testid="sequencer-cut"
1850
- disabled={!selectedMotionSegment || frame <= 0 || frame >= motion.frames}
1851
- title={ko("Cut the Body clip at the playhead", "재생 헤드에서 바디 클립 자르기")}
1852
- onClick={() => handlers.current.onMotionCut?.()}
1853
- >
1854
- {ko("Cut", "컷")}
1855
- </button>
1856
- {!promptBlocksHidden && <button
1857
- type="button"
1858
- className="tl-seq-action"
1859
- data-testid="sequencer-add-block"
1860
- title={ko("Add a prompt block at the playhead", "재생 헤드에 프롬프트 블록 추가")}
1861
- onClick={() => handlers.current.onPromptAdd?.(frame)}
1862
- >
1863
- {ko("+ Block", "+ 블록")}
1864
- </button>}
1865
- </>) : workflowMode === "pose" || ikMode ? (
1866
- selectedMotionSegment ? <button
1867
- type="button"
1868
- className="tl-seq-action cut"
1869
- data-testid="sequencer-cut"
1870
- disabled={!selectedMotionSegment || frame <= 0 || frame >= (motion?.frames ?? 0)}
1871
- onClick={() => handlers.current.onMotionCut?.()}
1872
- >
1873
- {ko("Cut", "컷")}
1874
- </button> : null
1875
- ) : (<>
1615
+ {motionTools || workflowMode === "pose" || ikMode ? null : (<>
1876
1616
  {shots.length > 0 && <button
1877
1617
  type="button"
1878
1618
  className="tl-seq-action cut"
@@ -1961,43 +1701,18 @@ export default function Timeline({
1961
1701
  </>)}
1962
1702
  </>)}
1963
1703
  </div>
1964
- {(selectedMotionSegment || onClearMotion) && (
1704
+ {onClearMotion && (
1965
1705
  <div className="tl-head-group tl-motion-tools" role="group" aria-label={ko("Motion controls", "모션 컨트롤")}>
1966
- {selectedMotionSegment && (
1967
- <label className="tl-motion-speed-editor">
1968
- <span>{ko(`Segment ${motionSegments.indexOf(selectedMotionSegment) + 1} speed`, `구간 ${motionSegments.indexOf(selectedMotionSegment) + 1} 배율`)}</span>
1969
- <input
1970
- type="range"
1971
- min="0.1"
1972
- max="4"
1973
- step="0.1"
1974
- value={selectedMotionSegment.speed}
1975
- aria-label={ko("Selected Full-Body segment speed", "선택한 전신 구간 배율")}
1976
- onChange={(event) => changeSelectedMotionSpeed(event.currentTarget.valueAsNumber)}
1977
- />
1978
- <input
1979
- type="number"
1980
- min="0.1"
1981
- max="4"
1982
- step="0.1"
1983
- value={selectedMotionSegment.speed}
1984
- aria-label={ko("Selected Full-Body segment speed value", "선택한 전신 구간 배율 값")}
1985
- onChange={(event) => changeSelectedMotionSpeed(event.currentTarget.valueAsNumber)}
1986
- />
1987
- <small>×</small>
1988
- </label>
1989
- )}
1990
- {onClearMotion && (
1991
- <button
1992
- type="button"
1993
- className="tl-btn clear"
1994
- aria-label={ko("Clear loaded motion", "불러온 모션 지우기")}
1995
- title={ko("Clear motion and prompt blocks, then restore the blocking pose", "모션과 프롬프트 블록을 지우고 블로킹 포즈로 되돌리기")}
1996
- onClick={onClearMotion}
1997
- >
1998
- ✕ {ko("Clear motion", "모션 지우기")}
1999
- </button>
2000
- )}
1706
+ {motion?.segments && motionTools && <TakeSegmentTools motion={motion} frame={frame} />}
1707
+ <button
1708
+ type="button"
1709
+ className="tl-btn clear"
1710
+ aria-label={ko("Clear loaded motion", "불러온 모션 지우기")}
1711
+ title={ko("Clear the compiled take, then restore the blocking pose", "컴파일된 테이크를 지우고 블로킹 포즈로 되돌리기")}
1712
+ onClick={onClearMotion}
1713
+ >
1714
+ ✕ {ko("Clear motion", "모션 지우기")}
1715
+ </button>
2001
1716
  </div>
2002
1717
  )}
2003
1718
  {waypointMode && (
@@ -2109,7 +1824,7 @@ export default function Timeline({
2109
1824
  onMarkScrubEnd={(...args) => handlers.current.onObjectMarkScrubEnd?.(...args)}
2110
1825
  />
2111
1826
  ) : tracks.map((name) => (
2112
- <div className={"tl-track" + (name === "Prompts" ? " prompts" : "") + (name === IK_LANE ? " ik" : "") + (name === SHOTS_LANE ? " shots" : "")} data-track-id={name} key={name}>
1827
+ <div className={"tl-track" + (name === IK_LANE ? " ik" : "") + (name === SHOTS_LANE ? " shots" : "")} data-track-id={name} key={name}>
2113
1828
  <span className="tl-track-label tl-track-tree">
2114
1829
  {name === IK_LANE ? (
2115
1830
  <span className="tl-track-label-stack">
@@ -2124,9 +1839,9 @@ export default function Timeline({
2124
1839
  <span className="tl-track-subrow indent"><span className="tl-track-chip crane" data-lane-label="Crane">{ko("Crane", "크레인")}</span></span>
2125
1840
  </span>
2126
1841
  ) : (
2127
- <span className="tl-track-subrow"><span className={"tl-track-chip " + (name === "2D Root" ? "root" : "prompt")} data-lane-label={TRACK_LABELS_KO[name]}>{TRACK_LABELS_KO[name]}</span></span>
1842
+ <span className="tl-track-subrow"><span className="tl-track-chip root" data-lane-label={TRACK_LABELS_KO[name]}>{TRACK_LABELS_KO[name]}</span></span>
2128
1843
  )}
2129
- {trackOwner && (name === "Prompts" || name === "2D Root") && <em className="tl-track-owner">{trackOwner}</em>}
1844
+ {trackOwner && name === "2D Root" && <em className="tl-track-owner">{trackOwner}</em>}
2130
1845
  {name === "2D Root" && pathSpeed && (
2131
1846
  <em
2132
1847
  className={"tl-path-speed" + (pathSpeed.warn ? " warn" : "")}
@@ -2137,7 +1852,7 @@ export default function Timeline({
2137
1852
  : `${pathSpeed.min.toFixed(1)}–${pathSpeed.max.toFixed(1)} m/s`}
2138
1853
  </em>
2139
1854
  )}
2140
- {motionTools && name === "Prompts" && <button className="tl-track-add" type="button" title={ko("Add a 2–4 second prompt clip — one action per block", "2–4초 프롬프트 클립 추가 — 한 블록에 한 동작")} onClick={() => handlers.current.onPromptAdd?.(frame)}>+</button>}
1855
+
2141
1856
  {name === SHOTS_LANE && (
2142
1857
  <button
2143
1858
  type="button"
@@ -2159,20 +1874,7 @@ export default function Timeline({
2159
1874
  +
2160
1875
  </button>
2161
1876
  )}
2162
- {/* Cutting the take addresses the selected segment, so it is
2163
- offered only where that selection means something (R2). */}
2164
- {name === IK_LANE && motion && motionTools && selectedMotionSegment && (
2165
- <button
2166
- className="tl-track-add motion-cut"
2167
- type="button"
2168
- disabled={frame <= 0 || frame >= motion.frames}
2169
- title={ko("Cut the Full-Body clip at the playhead", "재생 헤드에서 전신 클립 컷")}
2170
- onClick={() => handlers.current.onMotionCut?.()}
2171
- >
2172
- {ko("Cut", "컷")}
2173
- </button>
2174
- )}
2175
- </span>
1877
+ </span>
2176
1878
  <div
2177
1879
  className={"tl-lane" + (name === "2D Root" ? " root" : "") + (name === SHOTS_LANE ? " shots" : "")}
2178
1880
  onPointerDown={
@@ -2373,26 +2075,6 @@ export default function Timeline({
2373
2075
  </div>
2374
2076
  );
2375
2077
  })}
2376
- {name === "Prompts" && ghostLayers.map((layer) => layer.promptClips.map((clip) => (
2377
- <div
2378
- key={`${layer.owner}:${clip.id}`}
2379
- className="tl-chip ghost"
2380
- style={{ "--tl-f-start": clipPct(clip.startFrame), "--tl-f-end": clipPct(clip.endFrame) }}
2381
- title={`${layer.owner} · ${clip.text}`}
2382
- >
2383
- <span className="tl-chip-ghost-label">{layer.owner} · {clip.text || "…"}</span>
2384
- </div>
2385
- )))}
2386
- {name === "Prompts" && promptClips.map((clip) => {
2387
- const duration = ((clip.endFrame - clip.startFrame) / Math.max(1, fps)).toFixed(1);
2388
- return (
2389
- <div key={clip.id} className={"tl-chip" + (selectedPromptId === clip.id ? " selected" : "") + (movingPromptId === clip.id ? " moving" : "")} style={{ "--tl-f-start": clipPct(clip.startFrame), "--tl-f-end": clipPct(clip.endFrame) }} title={ko("Drag to move · edge handles resize · right-click removes", "드래그로 이동 · 가장자리 핸들로 길이 조절 · 오른쪽 클릭으로 삭제")} onPointerDown={(e) => beginPromptMove(e, clip)} onPointerMove={movePrompt} onPointerUp={endPromptMove} onPointerCancel={endPromptMove} onClick={blockPromptClick} onContextMenu={(e) => { e.preventDefault(); handlers.current.onPromptRemove?.(clip.id); }}>
2390
- <button className="tl-chip-handle start" type="button" aria-label={ko("Resize prompt start", "프롬프트 시작점 조절")} onPointerDown={(e) => beginPromptResize(e, clip, "start")} onPointerMove={movePromptResize} onPointerUp={endPromptResize} onPointerCancel={endPromptResize} />
2391
- <input className="tl-chip-input" value={clip.text} placeholder={isKo ? `${duration}초 · 모션 프롬프트` : `${duration}s · motion prompt`} maxLength={500} onFocus={() => handlers.current.onEditGestureStart?.("prompt-text", clip.id)} onChange={(e) => handlers.current.onPromptChange?.(clip.id, e.target.value)} />
2392
- <button className="tl-chip-handle end" type="button" aria-label={ko("Resize prompt end", "프롬프트 끝점 조절")} onPointerDown={(e) => beginPromptResize(e, clip, "end")} onPointerMove={movePromptResize} onPointerUp={endPromptResize} onPointerCancel={endPromptResize} />
2393
- </div>
2394
- );
2395
- })}
2396
2078
  {name === IK_LANE && pinBands.map(({ pin, geometry }) => {
2397
2079
  return (
2398
2080
  <button
@@ -2428,60 +2110,7 @@ export default function Timeline({
2428
2110
  aria-label={ko(`Pending pin range ${geometry.startFrame}–${geometry.endFrame}`, `대기 중인 고정 범위 ${geometry.startFrame}–${geometry.endFrame}`)}
2429
2111
  />;
2430
2112
  })()}
2431
- {name === IK_LANE && displayMotionSegments.map((segment, index) => (
2432
- <div
2433
- key={segment.id}
2434
- className={"tl-motion-clip" + (trimPreview ? " trimming" : "") + (segment.previewSpeed !== undefined ? " retiming" : "") + (selectedMotionSegment?.id === segment.id ? " selected" : "")}
2435
- style={{
2436
- "--tl-f-start": clipPct(trimPreview ? trimPreview.start : Math.min(segment.timelineStart, displayFrameCount)),
2437
- "--tl-f-end": clipPct(trimPreview ? trimPreview.end + 1 : Math.min(segment.timelineEnd + 1, displayFrameCount)),
2438
- }}
2439
- title={segment.preview ? undefined : isKo
2440
- ? `전신 구간 ${index + 1} — ${segment.speed}×. 컷은 재생 헤드에서 · 오른쪽 그립을 끌어 배속 조절 · 우클릭으로 구간 삭제`
2441
- : `Full-Body segment ${index + 1} — ${segment.speed}×. Cut at the playhead; drag the right grip to retime; right-click to delete`}
2442
- onContextMenu={segment.preview ? undefined : (e) => {
2443
- e.preventDefault();
2444
- e.stopPropagation();
2445
- handlers.current.onMotionSegmentRemove?.(segment.id);
2446
- }}
2447
- >
2448
- {index === 0 && segmentTools(segment) && <button
2449
- className="tl-motion-clip-handle start"
2450
- type="button"
2451
- aria-label={ko("Trim take start", "테이크 시작점 자르기")}
2452
- onPointerDown={(e) => beginMotionTrim(e, "start")}
2453
- onPointerMove={moveMotionTrim}
2454
- onPointerUp={endMotionTrim}
2455
- onPointerCancel={endMotionTrim}
2456
- onContextMenu={(e) => { e.preventDefault(); handlers.current.onMotionTrimReset?.(); }}
2457
- />}
2458
- <span className="tl-motion-clip-label">
2459
- {segment.preview
2460
- ? `${trimPreview.start}–${trimPreview.end} (${trimPreview.end - trimPreview.start + 1}f)`
2461
- : `${index + 1} · ${segment.previewSpeed ?? segment.speed}×`}
2462
- </span>
2463
- {!segment.preview && segmentTools(segment) && <button
2464
- className="tl-motion-clip-handle speed"
2465
- type="button"
2466
- aria-label={ko("Retime segment by stretch", "드래그로 구간 배속 조절")}
2467
- title={ko("Drag — wider is slower, narrower is faster", "드래그 — 늘리면 느리게, 줄이면 빠르게")}
2468
- onPointerDown={(e) => beginMotionSpeed(e, segment)}
2469
- onPointerMove={moveMotionSpeed}
2470
- onPointerUp={endMotionSpeed}
2471
- onPointerCancel={endMotionSpeed}
2472
- />}
2473
- {index === displayMotionSegments.length - 1 && segmentTools(segment) && <button
2474
- className="tl-motion-clip-handle end"
2475
- type="button"
2476
- aria-label={ko("Trim take end", "테이크 끝점 자르기")}
2477
- onPointerDown={(e) => beginMotionTrim(e, "end")}
2478
- onPointerMove={moveMotionTrim}
2479
- onPointerUp={endMotionTrim}
2480
- onPointerCancel={endMotionTrim}
2481
- onContextMenu={(e) => { e.preventDefault(); handlers.current.onMotionTrimReset?.(); }}
2482
- />}
2483
- </div>
2484
- ))}
2113
+ {name === IK_LANE && motion?.segments && <TakeSegmentClips motion={motion} frame={frame} frameCount={frameCount} displayFrameCount={displayFrameCount} clipPct={clipPct} tools={motionTools} />}{name === IK_LANE && <BeatBoard motion={motion} frame={frame} displayFrameCount={displayFrameCount} clipPct={clipPct} onJump={(f) => handlers.current.onScrub?.(f)} />}
2485
2114
 
2486
2115
  {name === IK_LANE &&
2487
2116
  ikRuns.flatMap((run) => (run.length < KEY_RUN_MIN