cozyclay 2.1.1 → 3.0.0

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