cozyclay 2.1.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (583) hide show
  1. package/CHANGELOG.md +65 -0
  2. package/README.md +12 -30
  3. package/bin/agent/agent-routes.mjs +40 -113
  4. package/bin/agent/agent-runner.mjs +9 -10
  5. package/bin/agent/cliproxy-provider.mjs +135 -0
  6. package/bin/agent/credential-store.mjs +30 -7
  7. package/bin/agent/pi-tools.mjs +4 -1
  8. package/bin/agent/provider-keys.mjs +32 -0
  9. package/bin/agent/provider-login.mjs +110 -0
  10. package/bin/agent/provider-routes.mjs +99 -0
  11. package/bin/agent/providers.mjs +19 -97
  12. package/bin/agent/script-tool.mjs +17 -4
  13. package/bin/agent/studio-motion-reference.mjs +23 -0
  14. package/bin/agent/studio-prompt.mjs +1 -1
  15. package/bin/agent/studio-rebase-text.mjs +32 -0
  16. package/bin/agent/studio-rebase.mjs +26 -39
  17. package/bin/agent/studio-tools.mjs +9 -28
  18. package/bin/agent/tool-arguments.mjs +49 -0
  19. package/bin/agent/turn-frames.mjs +66 -0
  20. package/bin/codex-auth.mjs +9 -2
  21. package/bin/cozyclay.mjs +10 -116
  22. package/bin/live/cli.mjs +22 -6
  23. package/bin/mcp-runtime.mjs +2 -12
  24. package/bin/package-signature.mjs +0 -4
  25. package/dist/app/index.html +7 -6
  26. package/dist/assets/EXRLoader-CvVIvGVE.js +1 -0
  27. package/dist/assets/analytics-C9sUnndd.js +1 -0
  28. package/dist/assets/app-CCh--1Hc.js +5087 -0
  29. package/dist/assets/app-f-fkV5uP.css +1 -0
  30. package/dist/assets/compile-worker-CkxiD6lH.js +5 -0
  31. package/dist/assets/fflate.module-KbGj5-H6.js +5 -0
  32. package/dist/assets/{first-shot-handoff-BlT33CGf.js → first-shot-handoff-CC4xe4HM.js} +1 -1
  33. package/dist/assets/{landing-BSesrCpL.js → landing-DjHD8u7k.js} +1 -1
  34. package/dist/assets/scene-asset-sync-Hx_FzdOH.js +20 -0
  35. package/dist/assets/scene-asset-sync-_S8NQl5B.css +1 -0
  36. package/dist/assets/workflow-C4yKH1p4.js +179 -0
  37. package/dist/cozyclay-package.json +1 -1
  38. package/dist/index.html +3 -3
  39. package/dist/llms.txt +14 -0
  40. package/dist/sw.js +3 -6
  41. package/dist/workflow/index.html +5 -4
  42. package/mcp/LIVE-PROTOCOL.md +7 -47
  43. package/mcp/README.md +16 -26
  44. package/mcp/live-hub.mjs +6 -10
  45. package/mcp/package.json +1 -3
  46. package/mcp/tool-handlers.mjs +4 -168
  47. package/package.json +3 -22
  48. package/src/App.jsx +174 -2639
  49. package/src/agent-progress.js +79 -0
  50. package/src/agent-turn-mark.js +30 -0
  51. package/src/analytics.js +1 -19
  52. package/src/app-context.js +5 -0
  53. package/src/app-stage.jsx +2 -34
  54. package/src/asset-pane.jsx +6 -5
  55. package/src/camera-block.js +21 -0
  56. package/src/camera-direction.js +120 -0
  57. package/src/character-kind.js +3 -9
  58. package/src/command-bus.js +8 -6
  59. package/src/commands/cast.js +5 -34
  60. package/src/commands/elements/character.js +1 -1
  61. package/src/commands/elements/motion.js +1 -6
  62. package/src/commands/elements/object.js +6 -2
  63. package/src/commands/elements/shot.js +4 -1
  64. package/src/commands/elements.js +38 -14
  65. package/src/commands/index.js +3 -1
  66. package/src/commands/kits.js +37 -0
  67. package/src/commands/motion-timing.js +57 -0
  68. package/src/commands/motion.js +9 -152
  69. package/src/commands/motion3-compile.js +65 -0
  70. package/src/commands/motion3.js +207 -0
  71. package/src/commands/objects.js +6 -4
  72. package/src/commands/shot.js +49 -11
  73. package/src/commands/stage.js +14 -1
  74. package/src/commands/view.js +4 -1
  75. package/src/document-mirrors.js +42 -0
  76. package/src/document-store.js +4 -0
  77. package/src/domains/cast.js +19 -194
  78. package/src/domains/motion/motion-range-pin-rules.js +1 -1
  79. package/src/domains/motion/take-source.js +51 -0
  80. package/src/domains/motion.js +60 -1838
  81. package/src/domains/scenes.js +12 -55
  82. package/src/domains/shots.js +2 -2
  83. package/src/domains/stage.js +4 -2
  84. package/src/draft-ghost.js +46 -0
  85. package/src/draft-ghost.jsx +129 -0
  86. package/src/dualview.jsx +4 -3
  87. package/src/effects/EffectsLayer.jsx +112 -0
  88. package/src/effects/effect-meshes.js +232 -0
  89. package/src/effects/effect-record.js +103 -0
  90. package/src/effects/emitter.js +59 -0
  91. package/src/effects/simulate.js +261 -0
  92. package/src/effects/state.js +59 -0
  93. package/src/execution-telemetry.js +2 -3
  94. package/src/first-success-guide.jsx +5 -5
  95. package/src/ghost-set.js +257 -0
  96. package/src/held-object-edit.jsx +113 -0
  97. package/src/held-object-pose.js +175 -0
  98. package/src/hierarchy-model.js +1 -1
  99. package/src/hierarchy-panel.jsx +1 -1
  100. package/src/imported-mesh.jsx +103 -0
  101. package/src/kits/held.js +84 -0
  102. package/src/kits/index.js +70 -0
  103. package/src/kits/smoking.js +57 -0
  104. package/src/light-blockers.js +93 -0
  105. package/src/motion/beat-board-model.js +84 -0
  106. package/src/motion/beat-board.css +124 -0
  107. package/src/motion/beat-board.jsx +59 -0
  108. package/src/motion/center-of-mass.js +66 -0
  109. package/src/motion/fix-collisions.js +850 -0
  110. package/src/motion/physics-review.js +118 -0
  111. package/src/{ardy → motion}/physics-support.js +1 -76
  112. package/src/motion/rig-snapshot.js +22 -0
  113. package/src/motion/take-segments.jsx +140 -0
  114. package/src/{ardy → motion}/timeline-coordinates.js +0 -21
  115. package/src/{ardy → motion}/timeline.css +1 -2
  116. package/src/{ardy → motion}/timeline.jsx +48 -419
  117. package/src/motion/waypoints.js +76 -0
  118. package/src/motion3/beats.js +83 -0
  119. package/src/motion3/body.js +158 -0
  120. package/src/motion3/bones.js +47 -0
  121. package/src/motion3/carried.js +47 -0
  122. package/src/motion3/compile-job.js +75 -0
  123. package/src/motion3/compile-worker.js +10 -0
  124. package/src/motion3/compiler/anchors.js +105 -0
  125. package/src/motion3/compiler/arm-orient.js +128 -0
  126. package/src/motion3/compiler/channels.js +125 -0
  127. package/src/motion3/compiler/compile.js +205 -0
  128. package/src/motion3/compiler/gait-rhythm.js +97 -0
  129. package/src/motion3/compiler/grip.js +171 -0
  130. package/src/motion3/compiler/head-steady.js +48 -0
  131. package/src/motion3/compiler/hold.js +134 -0
  132. package/src/motion3/compiler/idle.js +113 -0
  133. package/src/motion3/compiler/limbs.js +170 -0
  134. package/src/motion3/compiler/math.js +72 -0
  135. package/src/motion3/compiler/pose.js +162 -0
  136. package/src/motion3/compiler/quat.js +49 -0
  137. package/src/motion3/compiler/skeleton.js +74 -0
  138. package/src/motion3/compiler/validate-common.js +32 -0
  139. package/src/motion3/compiler/validate-goals.js +118 -0
  140. package/src/motion3/compiler/validate-objects.js +143 -0
  141. package/src/motion3/compiler/validate-parts.js +116 -0
  142. package/src/motion3/compiler/validate.js +122 -0
  143. package/src/motion3/compiler/vocab.js +73 -0
  144. package/src/motion3/compiler/walk-pelvis.js +275 -0
  145. package/src/motion3/compiler/walk.js +207 -0
  146. package/src/motion3/compiler/wrist-clamp.js +32 -0
  147. package/src/motion3/delta.js +47 -0
  148. package/src/motion3/describe.js +174 -0
  149. package/src/motion3/docs.js +27 -0
  150. package/src/motion3/edit-carry.js +21 -0
  151. package/src/motion3/fix/ease.js +16 -0
  152. package/src/motion3/fix/ground.js +37 -0
  153. package/src/motion3/fix/index.js +52 -0
  154. package/src/motion3/fix/push.js +71 -0
  155. package/src/motion3/fix/reach.js +46 -0
  156. package/src/motion3/fix/retime.js +79 -0
  157. package/src/motion3/fix/self.js +211 -0
  158. package/src/motion3/fix/slide.js +70 -0
  159. package/src/motion3/fix/turn.js +51 -0
  160. package/src/motion3/follow.js +39 -0
  161. package/src/motion3/free-motion.js +173 -0
  162. package/src/motion3/grip-choice.js +130 -0
  163. package/src/motion3/hold-plan.js +157 -0
  164. package/src/motion3/json-patch.js +77 -0
  165. package/src/motion3/key-aim.js +105 -0
  166. package/src/motion3/key-edit.js +82 -0
  167. package/src/motion3/lenient.js +127 -0
  168. package/src/motion3/object-keys.js +236 -0
  169. package/src/motion3/object-pose.js +182 -0
  170. package/src/motion3/object-tracks.js +12 -0
  171. package/src/motion3/pipeline.js +102 -0
  172. package/src/motion3/playback.js +51 -0
  173. package/src/motion3/probes.js +91 -0
  174. package/src/motion3/qa/body-checks.js +34 -0
  175. package/src/motion3/qa/check-names.js +14 -0
  176. package/src/motion3/qa/checks.js +121 -0
  177. package/src/motion3/qa/contact-checks.js +51 -0
  178. package/src/motion3/qa/explain.js +80 -0
  179. package/src/motion3/qa/fmt.js +5 -0
  180. package/src/motion3/qa/foot-checks.js +72 -0
  181. package/src/motion3/qa/geometry.js +77 -0
  182. package/src/motion3/qa/goals.js +191 -0
  183. package/src/motion3/qa/ground.js +60 -0
  184. package/src/motion3/qa/hints-contact.js +179 -0
  185. package/src/motion3/qa/hints-goal.js +160 -0
  186. package/src/motion3/qa/hints-knee.js +24 -0
  187. package/src/motion3/qa/hints-motion.js +209 -0
  188. package/src/motion3/qa/hints-object.js +91 -0
  189. package/src/motion3/qa/index.js +42 -0
  190. package/src/motion3/qa/key-checks.js +82 -0
  191. package/src/motion3/qa/near.js +96 -0
  192. package/src/motion3/qa/object-checks.js +135 -0
  193. package/src/motion3/qa/patch.js +161 -0
  194. package/src/motion3/qa/severity.js +38 -0
  195. package/src/motion3/qa/spec-checks.js +65 -0
  196. package/src/motion3/qa/style.js +218 -0
  197. package/src/motion3/qa/wrist-checks.js +69 -0
  198. package/src/motion3/qa/wrist-obs.js +60 -0
  199. package/src/motion3/refs.js +120 -0
  200. package/src/motion3/repair-tune.js +121 -0
  201. package/src/motion3/repair.js +83 -0
  202. package/src/motion3/report.js +67 -0
  203. package/src/motion3/rigs/index.js +14 -0
  204. package/src/motion3/rigs/x-bot-tpose-body.json +1 -0
  205. package/src/motion3/rigs/x-bot-tpose.json +1 -0
  206. package/src/motion3/rigs/y-bot-tpose-body.json +1 -0
  207. package/src/motion3/rigs/y-bot-tpose.json +1 -0
  208. package/src/motion3/scene.js +60 -0
  209. package/src/motion3/schema/brief.js +89 -0
  210. package/src/motion3/schema/fields.js +44 -0
  211. package/src/motion3/schema/spec-examples.js +46 -0
  212. package/src/motion3/schema/topics.js +111 -0
  213. package/src/motion3/schema/types.js +147 -0
  214. package/src/motion3/search.js +117 -0
  215. package/src/motion3/second-hand.js +112 -0
  216. package/src/motion3/skills/basic.js +82 -0
  217. package/src/motion3/skills/book.js +76 -0
  218. package/src/motion3/skills/car.js +145 -0
  219. package/src/motion3/skills/frames-auto.js +29 -0
  220. package/src/motion3/skills/index.js +83 -0
  221. package/src/motion3/skills/info.js +65 -0
  222. package/src/motion3/skills/smoke-kit.js +109 -0
  223. package/src/motion3/skills/smoke.js +160 -0
  224. package/src/motion3/spec-store.js +59 -0
  225. package/src/motion3/take-edit.js +155 -0
  226. package/src/motion3/take.js +63 -0
  227. package/src/motion3/timeline.js +127 -0
  228. package/src/motion3/views.js +121 -0
  229. package/src/motion3/walk-plan.js +119 -0
  230. package/src/object-catalog.jsx +7 -1
  231. package/src/object-colors.js +98 -0
  232. package/src/object-gizmo-parts.js +115 -0
  233. package/src/object-gizmo.jsx +37 -122
  234. package/src/object-glow.js +139 -0
  235. package/src/object-hidden.js +33 -0
  236. package/src/object-look.js +196 -0
  237. package/src/object-size.js +10 -0
  238. package/src/object-travel.js +71 -6
  239. package/src/panels/CameraPanel.jsx +7 -7
  240. package/src/panels/HdrEnvironmentControls.jsx +59 -0
  241. package/src/panels/LightPanel.jsx +25 -4
  242. package/src/panels/ObjectLookPanel.jsx +88 -0
  243. package/src/panels/PoseImagePanel.jsx +1 -1
  244. package/src/panels/PosePanel.jsx +2 -17
  245. package/src/panels/RigControlPanel.jsx +5 -53
  246. package/src/panels/SubjectBox.jsx +4 -1
  247. package/src/panels/details.css +14 -0
  248. package/src/posestudio.jsx +4 -27
  249. package/src/project-browser.jsx +3 -4
  250. package/src/project-resources.js +18 -31
  251. package/src/project.js +13 -104
  252. package/src/props.jsx +25 -280
  253. package/src/rail-dot-drag.js +23 -0
  254. package/src/render-passes.js +10 -0
  255. package/src/resource-status.jsx +1 -0
  256. package/src/result-modal.jsx +4 -19
  257. package/src/room.jsx +20 -12
  258. package/src/scene-assets.js +8 -6
  259. package/src/scene-light-place.js +72 -0
  260. package/src/scene-lights.jsx +148 -0
  261. package/src/scene-objects.js +31 -139
  262. package/src/scenes.js +15 -105
  263. package/src/semantic-edit.js +2 -5
  264. package/src/set-pieces.jsx +183 -0
  265. package/src/settings-menu.jsx +3 -11
  266. package/src/shell/BottomDock.jsx +11 -53
  267. package/src/shell/CompositionGuideButton.jsx +20 -0
  268. package/src/shell/DetailsSlot.jsx +16 -200
  269. package/src/shell/GhostsMenuGroup.jsx +74 -0
  270. package/src/shell/LibrarySlot.jsx +1 -3
  271. package/src/shell/MenuBar.jsx +3 -3
  272. package/src/shell/PreferencesDialog.jsx +15 -264
  273. package/src/shell/PreferencesSlot.jsx +2 -8
  274. package/src/shell/ShotPreviewHeader.jsx +17 -0
  275. package/src/shell/TopBar.jsx +5 -83
  276. package/src/shell/ViewportToolbar.jsx +23 -93
  277. package/src/shell/agent-glass.css +19 -6
  278. package/src/shell/details-selection.js +42 -0
  279. package/src/shell/ghosts-menu.css +22 -0
  280. package/src/shell/glass-regions.css +29 -3
  281. package/src/shell/preferences.css +6 -1
  282. package/src/shell/viewport.css +12 -0
  283. package/src/shot-authoring.js +4 -7
  284. package/src/soft-shadows.js +37 -0
  285. package/src/stage-attach-frames.js +12 -12
  286. package/src/stage-canvas-rigs.jsx +3 -3
  287. package/src/stage-capture.jsx +42 -8
  288. package/src/stage-characters.jsx +22 -216
  289. package/src/stage-editor-gizmos.jsx +6 -6
  290. package/src/stage-environment.js +93 -0
  291. package/src/stage-hdr-builtins.js +107 -0
  292. package/src/stage-hdr-image.js +116 -0
  293. package/src/stage-hdr-library.js +70 -0
  294. package/src/stage-hdr-map.js +94 -0
  295. package/src/stage-hdr.js +130 -0
  296. package/src/stage-lighting.js +149 -0
  297. package/src/stage-occlusion.js +210 -0
  298. package/src/stage-sky.jsx +159 -0
  299. package/src/stage-startup-defaults.js +5 -9
  300. package/src/studio-actions.js +12 -14
  301. package/src/studio-agent-commands.js +46 -16
  302. package/src/studio-agent-motion.js +9 -9
  303. package/src/studio-agent-protocol.js +46 -73
  304. package/src/studio-app-binding.js +29 -45
  305. package/src/studio-asset-list.js +17 -0
  306. package/src/studio-contact-sheet.js +37 -5
  307. package/src/studio-elements.js +27 -7
  308. package/src/studio-entity-bounds.js +18 -0
  309. package/src/studio-error-codes.js +8 -0
  310. package/src/studio-export-framing.js +152 -0
  311. package/src/studio-lighting-check.js +103 -0
  312. package/src/studio-motion-visual.js +150 -0
  313. package/src/studio-schema-errors.js +80 -0
  314. package/src/studio-support-gap.js +74 -0
  315. package/src/styles.css +1 -19
  316. package/src/timeline-defaults.js +5 -0
  317. package/src/timeline-extent.js +8 -20
  318. package/src/tutorial-walk.js +17 -0
  319. package/src/ui-scrub.js +1 -1
  320. package/src/use-shot-camera-tracks.js +12 -0
  321. package/src/view-ghosts.js +97 -0
  322. package/src/view-ghosts.jsx +49 -0
  323. package/src/workflow/AgentPanel.jsx +47 -166
  324. package/src/workflow/AgentProgressCard.jsx +107 -0
  325. package/src/workflow/AgentReplyText.jsx +37 -0
  326. package/src/workflow/AgentTurnSteps.jsx +84 -0
  327. package/src/workflow/LoginPanel.jsx +140 -0
  328. package/src/workflow/WorkflowBuilder.jsx +7 -23
  329. package/src/workflow/agent-client.js +54 -51
  330. package/src/workflow/agent-panel.css +71 -1
  331. package/src/workflow/agent-progress-card.css +167 -0
  332. package/src/workflow/agent-progress-view.js +47 -0
  333. package/src/workflow/agent-turn-steps.css +113 -0
  334. package/src/workflow/agent-turn.js +191 -0
  335. package/src/workflow/login-client.js +34 -0
  336. package/src/workflow/motion-input.js +18 -31
  337. package/src/workflow/node-schema.js +1 -1
  338. package/src/workflow/reply-markdown.js +69 -0
  339. package/src/workflow/scene-asset-sync.js +8 -8
  340. package/tools/agent-session-stats.mjs +61 -0
  341. package/tools/dev-full.mjs +5 -56
  342. package/tools/eslint-baseline.json +12 -13
  343. package/tools/headless-studio.mjs +85 -0
  344. package/tools/knip-baseline.json +0 -179
  345. package/tools/loc-baseline.json +33 -83
  346. package/tools/motion3/extract-body.mjs +103 -0
  347. package/tools/motion3/extract-rig.mjs +85 -0
  348. package/tools/process-supervisor.mjs +0 -88
  349. package/tools/run-tests.mjs +9 -124
  350. package/bin/agent/motion-runtime.mjs +0 -76
  351. package/dist/ardy/cskel27-rest.json +0 -557
  352. package/dist/assets/analytics-B41FmPYI.js +0 -1
  353. package/dist/assets/app-Do-Og5Pu.css +0 -1
  354. package/dist/assets/app-DwP-tl2x.js +0 -4920
  355. package/dist/assets/config-Bx7pYsD9.js +0 -1
  356. package/dist/assets/config-DeoFTYzb.css +0 -1
  357. package/dist/assets/demo-Dt0qZfS7.js +0 -1
  358. package/dist/assets/scene-asset-sync-BCWDJB1d.js +0 -19
  359. package/dist/assets/scene-asset-sync-DjJ_cJ2R.css +0 -1
  360. package/dist/assets/ticket-jqMhqL88.js +0 -1
  361. package/dist/assets/workflow-Br-K7Srs.js +0 -179
  362. package/dist/demo/walk-then-stop.npz +0 -0
  363. package/mcp/ardy-prompts.mjs +0 -218
  364. package/src/ardy/auto-fix-panel.css +0 -108
  365. package/src/ardy/auto-physics.js +0 -1194
  366. package/src/ardy/client.js +0 -153
  367. package/src/ardy/convert.js +0 -313
  368. package/src/ardy/cskel27-neutral.js +0 -39
  369. package/src/ardy/cskel27.js +0 -77
  370. package/src/ardy/export.js +0 -165
  371. package/src/ardy/fix-collisions.js +0 -2257
  372. package/src/ardy/foot-lock.js +0 -230
  373. package/src/ardy/motion-calibration.js +0 -118
  374. package/src/ardy/motion-edit.js +0 -213
  375. package/src/ardy/motion-url.js +0 -55
  376. package/src/ardy/mp4-duration.js +0 -102
  377. package/src/ardy/npz.js +0 -595
  378. package/src/ardy/physics-panel.css +0 -21
  379. package/src/ardy/physics-panel.jsx +0 -89
  380. package/src/ardy/physics-refine.js +0 -111
  381. package/src/ardy/physics-review.js +0 -567
  382. package/src/ardy/physics-temporal.js +0 -54
  383. package/src/ardy/platform-fit-panel.css +0 -64
  384. package/src/ardy/platform-fit-panel.jsx +0 -41
  385. package/src/ardy/platform-fit.js +0 -326
  386. package/src/ardy/playback.js +0 -711
  387. package/src/ardy/pose-pin.js +0 -97
  388. package/src/ardy/prompt-clips.js +0 -30
  389. package/src/ardy/retime.js +0 -211
  390. package/src/ardy/root-drop.js +0 -369
  391. package/src/ardy/timeline-resize.js +0 -13
  392. package/src/ardy/to-cskel27.js +0 -225
  393. package/src/ardy/trim.js +0 -33
  394. package/src/ardy/waypoints.js +0 -369
  395. package/src/ardy-bridge-contract.js +0 -281
  396. package/src/domains/motion/motion-video-capture.js +0 -664
  397. package/src/i2v-motion-client.js +0 -77
  398. package/src/i2v-motion-studio.jsx +0 -180
  399. package/src/line-edit.js +0 -1348
  400. package/src/motion/generation.js +0 -105
  401. package/src/motion-readiness-ui.jsx +0 -67
  402. package/src/motion-readiness.js +0 -40
  403. package/src/motion-resources.js +0 -177
  404. package/src/motion-store.js +0 -65
  405. package/src/motion-trail.js +0 -601
  406. package/src/multimodel-ingest.js +0 -394
  407. package/src/panels/PromptBlocksPanel.jsx +0 -444
  408. package/src/panels/VideoCapturePanel.jsx +0 -181
  409. package/src/pose-extract/browser.js +0 -42
  410. package/src/pose-extract/detector.js +0 -100
  411. package/src/pose-extract/fit.js +0 -227
  412. package/src/pose-extract/image-frame.js +0 -51
  413. package/src/pose-extract/index.js +0 -58
  414. package/src/pose-extract/keyframes.js +0 -74
  415. package/src/pose-extract/landmarks.js +0 -162
  416. package/src/pose-extract/mirror.js +0 -153
  417. package/src/pose-extract/take.js +0 -131
  418. package/src/pose-extract/video-frames.js +0 -91
  419. package/src/take-recipe.js +0 -165
  420. package/src/trail-key-conflicts.js +0 -39
  421. package/src/trail-pick.js +0 -59
  422. package/src/use-i2v-capture-modal.js +0 -15
  423. package/tools/ardy/BRIDGE.md +0 -37
  424. package/tools/ardy/GVHMR-NPZ.md +0 -68
  425. package/tools/ardy/README.md +0 -124
  426. package/tools/ardy/__pycache__/cclay_gvhmr_worker.cpython-313.pyc +0 -0
  427. package/tools/ardy/artifacts.mjs +0 -34
  428. package/tools/ardy/bridge.mjs +0 -1732
  429. package/tools/ardy/bvh-cskel27.mjs +0 -1265
  430. package/tools/ardy/cclay_constrained_generate.py +0 -561
  431. package/tools/ardy/cclay_gvhmr_worker.py +0 -264
  432. package/tools/ardy/cclay_motion_edit.py +0 -510
  433. package/tools/ardy/cclay_sequence_generate.py +0 -705
  434. package/tools/ardy/cclay_worker.py +0 -304
  435. package/tools/ardy/dump-npz.py +0 -205
  436. package/tools/ardy/extract-rest.mjs +0 -299
  437. package/tools/ardy/extract.mjs +0 -507
  438. package/tools/ardy/footage.mjs +0 -467
  439. package/tools/ardy/gvhmr-floor.mjs +0 -102
  440. package/tools/ardy/gvhmr-to-cskel27.mjs +0 -21
  441. package/tools/ardy/gvhmr_fastpath.py +0 -168
  442. package/tools/ardy/gvhmr_trajectory.py +0 -240
  443. package/tools/ardy/merge-text-encoder.py +0 -160
  444. package/tools/ardy/mocap-metrics.mjs +0 -200
  445. package/tools/ardy/mocap-quality-gate.mjs +0 -110
  446. package/tools/ardy/motion-stabilize.mjs +0 -348
  447. package/tools/ardy/npz.mjs +0 -414
  448. package/tools/ardy/pose-to-npz.mjs +0 -106
  449. package/tools/ardy/prompt-limits.mjs +0 -5
  450. package/tools/ardy/run-edit-on-box.sh +0 -73
  451. package/tools/ardy/run-local.mjs +0 -233
  452. package/tools/ardy/run-on-box.sh +0 -593
  453. package/tools/ardy/run-sequence-on-box.sh +0 -177
  454. package/tools/ardy/runners/gvhmr-worker.mjs +0 -206
  455. package/tools/ardy/runners/index.mjs +0 -18
  456. package/tools/ardy/runners/local.mjs +0 -455
  457. package/tools/ardy/runners/proc.mjs +0 -125
  458. package/tools/ardy/runners/remote.mjs +0 -252
  459. package/tools/ardy/setup-local.mjs +0 -189
  460. package/tools/ardy/setup-text-encoder-on-box.sh +0 -93
  461. package/tools/ardy/setup-text-encoder.py +0 -306
  462. package/tools/ardy/smpl-cskel27.mjs +0 -178
  463. package/tools/ardy/visual-qa.mjs +0 -196
  464. package/tools/ardy/vq-car.mjs +0 -52
  465. package/tools/bench/EXP3.md +0 -61
  466. package/tools/bench/cclay_bench_extract_incam.py +0 -125
  467. package/tools/bench/cclay_bench_extract_obs.py +0 -204
  468. package/tools/bench/cclay_bench_runner.py +0 -42
  469. package/tools/bench/cube-contact.mjs +0 -162
  470. package/tools/bench/exp3.mjs +0 -152
  471. package/tools/bench/extract-bench-lib.mjs +0 -216
  472. package/tools/bench/extract-bench.mjs +0 -302
  473. package/tools/bench/fal-generate.mjs +0 -88
  474. package/tools/bench/fit/README.md +0 -189
  475. package/tools/bench/fit/camera.mjs +0 -59
  476. package/tools/bench/fit/contact.mjs +0 -419
  477. package/tools/bench/fit/footlock.mjs +0 -234
  478. package/tools/bench/fit/motion.mjs +0 -85
  479. package/tools/bench/fit/pin.mjs +0 -27
  480. package/tools/bench/fit/remote.mjs +0 -105
  481. package/tools/bench/fit-bench.mjs +0 -126
  482. package/tools/bench/fit-sanity.mjs +0 -45
  483. package/tools/bench/metrics.mjs +0 -313
  484. package/tools/bench/obs/depth.mjs +0 -258
  485. package/tools/bench/obs/extrinsics.mjs +0 -175
  486. package/tools/bench/obs/fit_mannequin_betas.py +0 -340
  487. package/tools/bench/obs/ground.mjs +0 -294
  488. package/tools/bench/obs/heading.mjs +0 -151
  489. package/tools/bench/obs/ladder.mjs +0 -555
  490. package/tools/bench/obs/mannequin-betas.json +0 -124
  491. package/tools/bench/obs/remote.mjs +0 -83
  492. package/tools/bench/obs/rest_joints.py +0 -52
  493. package/tools/bench/obs/ybot-targets.mjs +0 -49
  494. package/tools/bench/obs-bench.mjs +0 -520
  495. package/tools/bench/score.mjs +0 -343
  496. package/tools/bench/summarize.mjs +0 -86
  497. package/tools/demo-worker/README.md +0 -137
  498. package/tools/demo-worker/api-client.mjs +0 -233
  499. package/tools/demo-worker/generate.mjs +0 -301
  500. package/tools/demo-worker/index.mjs +0 -466
  501. package/tools/demo-worker/sign-core.mjs +0 -112
  502. package/tools/demo-worker/sign.mjs +0 -161
  503. package/tools/gt-render/browser.mjs +0 -159
  504. package/tools/gt-render/camera-math.mjs +0 -276
  505. package/tools/gt-render/page.mjs +0 -267
  506. package/tools/gt-render/render.mjs +0 -514
  507. package/tools/gt-render/scene-box.mjs +0 -31
  508. package/tools/gt-render/take-transform.mjs +0 -87
  509. package/tools/kimodo/compare-seam.mjs +0 -108
  510. package/tools/kimodo/constraints.mjs +0 -244
  511. package/tools/kimodo/edit.mjs +0 -259
  512. package/tools/kimodo/effector-constraints.mjs +0 -200
  513. package/tools/kimodo/generate.mjs +0 -646
  514. package/tools/kimodo/local-output.mjs +0 -265
  515. package/tools/kimodo/measure-pose.mjs +0 -65
  516. package/tools/kimodo/measure-preserve.mjs +0 -899
  517. package/tools/kimodo/measure-waypoints.mjs +0 -55
  518. package/tools/kimodo/mlx-generate.py +0 -111
  519. package/tools/kimodo/pose-constraints.mjs +0 -248
  520. package/tools/kimodo/preserve-mask.mjs +0 -543
  521. package/tools/kimodo/read-npz.mjs +0 -189
  522. package/tools/kimodo/run-edit-on-box.mjs +0 -155
  523. package/tools/kimodo/run-sequence-on-box.mjs +0 -178
  524. package/tools/kimodo/runner.mjs +0 -284
  525. package/tools/kimodo/seam-batch.mjs +0 -77
  526. package/tools/kimodo/setup-local.mjs +0 -30
  527. package/tools/kimodo/setup-on-box.sh +0 -339
  528. package/tools/kimodo/soma77-to-cskel27.mjs +0 -305
  529. package/tools/morphgs/assets/gen_truth.py +0 -39
  530. package/tools/morphgs/assets/mesh_ori_rig.txt +0 -27
  531. package/tools/morphgs/assets/playback-check.mjs +0 -30
  532. package/tools/morphgs/demo-gate.sh +0 -26
  533. package/tools/morphgs/fbx2morphgs.mjs +0 -68
  534. package/tools/morphgs/morphgs-to-cskel27.mjs +0 -105
  535. package/tools/morphgs/patches/preprocess_src-none-mode.patch +0 -76
  536. package/tools/morphgs/setup-on-cluster.sh +0 -126
  537. package/tools/projflow/driver.py +0 -1069
  538. package/tools/projflow/generate.mjs +0 -805
  539. package/tools/projflow/hml22-to-cskel27.mjs +0 -735
  540. package/tools/projflow/line-edit-job.mjs +0 -547
  541. package/tools/projflow/replay.mjs +0 -452
  542. package/tools/projflow/runner.mjs +0 -269
  543. package/tools/projflow/service.mjs +0 -742
  544. package/tools/track/DESIGN.md +0 -513
  545. package/tools/track/backfill-provenance.mjs +0 -116
  546. package/tools/track/budget.mjs +0 -8
  547. package/tools/track/check-rig.mjs +0 -209
  548. package/tools/track/diagnostics.schema.json +0 -60
  549. package/tools/track/export-rig.mjs +0 -256
  550. package/tools/track/fallback.mjs +0 -7
  551. package/tools/track/fk-parity-fixture.mjs +0 -161
  552. package/tools/track/gate.mjs +0 -349
  553. package/tools/track/masks.mjs +0 -318
  554. package/tools/track/metrics.mjs +0 -201
  555. package/tools/track/publish-obs.mjs +0 -108
  556. package/tools/track/py/check_env.py +0 -61
  557. package/tools/track/py/eval_lr.py +0 -229
  558. package/tools/track/py/lr_viterbi.py +0 -294
  559. package/tools/track/py/masks.py +0 -405
  560. package/tools/track/py/objective.py +0 -382
  561. package/tools/track/py/rig.py +0 -508
  562. package/tools/track/py/scene.py +0 -326
  563. package/tools/track/py/test_joint_indices.py +0 -123
  564. package/tools/track/py/test_lr_viterbi.py +0 -195
  565. package/tools/track/py/test_masks.py +0 -229
  566. package/tools/track/py/test_rig.py +0 -288
  567. package/tools/track/py/test_scene.py +0 -354
  568. package/tools/track/py/test_track.py +0 -328
  569. package/tools/track/py/track.py +0 -411
  570. package/tools/track/remote.mjs +0 -140
  571. package/tools/track/rig-dump.mjs +0 -227
  572. package/tools/track/run-box-tests.mjs +0 -14
  573. package/tools/track/run-box.mjs +0 -168
  574. package/tools/track/setup-box.sh +0 -59
  575. package/tools/track/study-2d.mjs +0 -728
  576. /package/src/{ardy → motion}/collision-blockers.js +0 -0
  577. /package/src/{ardy → motion}/ground.js +0 -0
  578. /package/src/{ardy → motion}/ik-drag.js +0 -0
  579. /package/src/{ardy → motion}/ik-key-json.js +0 -0
  580. /package/src/{ardy → motion}/ik.js +0 -0
  581. /package/src/{ardy → motion}/physics-surface.js +0 -0
  582. /package/src/{ardy → motion}/playback-clock.js +0 -0
  583. /package/src/{ardy → motion}/range-pin.js +0 -0
@@ -1,6 +1,6 @@
1
- import { useEffect, useLayoutEffect, useState } from "react";
2
- import { createPortal } from "react-dom";
1
+ import { useEffect, useState } from "react";
3
2
  import { useStudioShell } from "./studio-shell-context.js";
3
+ import ShotPreviewHeader from "./ShotPreviewHeader.jsx";
4
4
  import { ko } from "../locale.js";
5
5
  import { PRESETS, SHOT_ASPECT_PRESETS } from "../app-stage.jsx";
6
6
  import { CAMERA_PRESETS } from "../camera-move.js";
@@ -10,6 +10,8 @@ import { CHARACTER_MODEL_IDS } from "../scenes.js";
10
10
  import { elementByPath } from "../studio-elements.js";
11
11
  import { saveAutoColor } from "../auto-color.js";
12
12
  import { trackFeature } from "../analytics.js";
13
+ import { GUIDE_LABELS, nextGuideMode } from "../shot-guides.js";
14
+ import GhostsMenuGroup from "./GhostsMenuGroup.jsx";
13
15
  import "./viewport.css";
14
16
 
15
17
  // G1: the single mode+tool pill. Keys 1-5 and W/E/R are bound in App's
@@ -39,7 +41,6 @@ const ICON = {
39
41
  rotate: "M13.25 8A5.25 5.25 0 1 1 11.7 4.3 M13.25 2.5v2.75H10.5",
40
42
  scale: "M2.5 8.5v4a1 1 0 0 0 1 1h4 M8.5 2.5h5v5 M13.5 2.5 7.5 8.5",
41
43
  ik: "M2.5 13.5 6.5 9l3 2.2 4-7.7 M6.5 9h.01 M9.5 11.2h.01",
42
- trail: "M2 12.5c3 0 3-9 6-9s3 9 6 9",
43
44
  pin: "M8 14.5v-4 M5 2h6 M6.2 2v3.6L4.5 10.5h7L9.8 5.6V2",
44
45
  blocks: "M2 3.5h7.5v3.5H2z M6.5 9h7.5v3.5H6.5z",
45
46
  refine: "M10.5 2.5l3 3L6 13H3v-3z",
@@ -62,12 +63,10 @@ function RailIcon({ name, size = 16 }) {
62
63
 
63
64
  // The gizmo's snap increments (TRANSLATE_SNAP / ROTATE_SNAP in
64
65
  // src/scene-objects.js). They are fixed, so the value group names them.
65
- const SNAP_MOVE = "5cm";
66
- const SNAP_TURN = "5°";
66
+ const SNAP_MOVE = "5cm", SNAP_TURN = "5°";
67
67
 
68
68
  // Editor lens range: shotsDomain.changeLens and the FOV slider take 14-90°.
69
- const FOV_MIN = 14;
70
- const FOV_MAX = 90;
69
+ const FOV_MIN = 14, FOV_MAX = 90;
71
70
 
72
71
  // "+ Add › Character" stands the new body one metre along X per existing
73
72
  // character, inside the same stage clamp the Content drag applies.
@@ -113,35 +112,17 @@ function MenuItem({ checked, role = "menuitemradio", className = "", children, .
113
112
  );
114
113
  }
115
114
 
116
- /** The inset card's header (violet dot, shot name, lens) lives in App's
117
- * `.vp-shot-preview-tag`; this region only fills in the words it shows. */
118
- function ShotPreviewHeader({ name, lens }) {
119
- const [host, setHost] = useState(null);
120
- useLayoutEffect(() => {
121
- setHost(document.querySelector(".vp-shot-preview .vp-shot-preview-tag"));
122
- }, []);
123
- if (!host) return null;
124
- return createPortal(
125
- <span className="vp-shot-preview-meta" data-testid="shot-preview-header">
126
- <span className="vp-shot-preview-name">{name}</span>
127
- <span className="vp-shot-preview-lens">{lens}</span>
128
- </span>,
129
- host,
130
- );
131
- }
132
-
133
115
  export default function ViewportToolbar() {
134
116
  const {
135
117
  workflowMode, selectWorkflowMode, poseRefusal, gizmoMode, setGizmoMode, snapEnabled,
136
- setSnapEnabled, preset, applyPreset, cameraPresetId, i2vMotionCameraLocked,
118
+ setSnapEnabled, preset, applyPreset, cameraPresetId,
137
119
  runStudioAction, shotAspectKey, fovDeg, shotsDomain, shot, shots, activeShot,
138
120
  setNonce, workspaceLayout, viewMenuTriggerRef, viewMenuOpen,
139
- setViewMenuOpen, viewLooksActive, gridView, setGridView,
121
+ setViewMenuOpen, viewLooksActive, gridView, setGridView, guideMode,
140
122
  autoColor, setAutoColor, isCharacterSelection, partColoursChoice, embedMode,
141
123
  agentCollapsed, addSceneObject, spawnCharacter, characters, flySpeed,
142
- ikEditTool, setIkEditTool, showTrails, setShowTrails, motion, setRangePinPartPick,
143
- trailFalloffS, setTrailFalloffS, lineEditMode, exitLineEditMode, enterRefineMode,
144
- refineDisabledReason, previsMode, sculptView, requestSculptView,
124
+ ikEditTool, setIkEditTool, motion, setRangePinPartPick,
125
+ previsMode, sculptView, requestSculptView,
145
126
  } = useStudioShell();
146
127
  const menu = useOverlayMenu();
147
128
 
@@ -152,7 +133,6 @@ export default function ViewportToolbar() {
152
133
  setAutoColor(next);
153
134
  };
154
135
 
155
- const refineReason = lineEditMode ? null : refineDisabledReason();
156
136
  const tools = {
157
137
  scene: [
158
138
  { key: "W", id: "move", name: ko("Move", "이동"), active: gizmoMode === "move", pick: () => setGizmoMode("move") },
@@ -161,11 +141,7 @@ export default function ViewportToolbar() {
161
141
  ],
162
142
  pose: [
163
143
  { key: "W", id: "ik", name: ko("Pose fix (IK parts)", "포즈 수정 (IK 파츠)"), active: ikEditTool === "ik", pick: () => setIkEditTool("ik") },
164
- {
165
- key: "E", id: "trail", name: ko("Path fix (motion trail)", "경로 수정 (궤적선)"), active: ikEditTool === "trail",
166
- refused: showTrails ? null : ko("Turn Trails on in Show to edit the motion path", "경로를 수정하려면 표시에서 궤적선을 켜세요"),
167
- pick: () => setIkEditTool("trail"),
168
- },
144
+
169
145
  {
170
146
  key: "R", id: "pin", name: ko("Pin (range pin)", "고정 (범위 고정)"), active: ikEditTool === "pin",
171
147
  refused: motion ? null : ko("Pinning needs a motion take", "고정하려면 모션 테이크가 필요해요"),
@@ -176,16 +152,8 @@ export default function ViewportToolbar() {
176
152
  { key: "W", id: "move", name: ko("Move camera", "카메라 이동"), active: gizmoMode === "move", pick: () => setGizmoMode("move") },
177
153
  { key: "E", id: "rotate", name: ko("Rotate camera", "카메라 회전"), active: gizmoMode === "rotate", pick: () => setGizmoMode("rotate") },
178
154
  ],
179
- motion: [
180
- {
181
- key: "W", id: "blocks", name: ko("Blocks (select and move prompt blocks)", "블록 (프롬프트 블록 선택·이동)"), active: !lineEditMode,
182
- pick: () => { if (lineEditMode) exitLineEditMode(); },
183
- },
184
- {
185
- key: "E", id: "refine", name: ko("Refine (edit the path line)", "다듬기 (경로선 편집)"), active: lineEditMode,
186
- refused: refineReason, pick: () => { if (!lineEditMode) enterRefineMode(); },
187
- },
188
- ],
155
+ // Motion is compiled by the agent (motion.compile); the department has no tools of its own.
156
+ motion: [],
189
157
  // Sculpt mode's W/E/R swing the turntable camera to a reference view.
190
158
  sculpt: [
191
159
  { key: "W", id: "front", name: ko("Front view", "정면 보기"), active: sculptView?.view === "front", pick: () => requestSculptView("front") },
@@ -216,33 +184,6 @@ export default function ViewportToolbar() {
216
184
  <span className="vp-value-part"><RailIcon name="grid" size={14} />{SNAP_MOVE}</span>
217
185
  <span className="vp-value-part"><RailIcon name="angle" size={14} />{SNAP_TURN}</span>
218
186
  </button>
219
- ) : workflowMode === "pose" ? (
220
- <div className="vp-menu-wrap" data-vp-menu="influence">
221
- <button
222
- type="button"
223
- className="vp-value"
224
- aria-haspopup="dialog"
225
- aria-expanded={menu.open === "influence"}
226
- title={ko("Influence range — how far an edit blends into nearby frames", "영향 범위 — 수정이 주변 프레임에 섞이는 길이")}
227
- onClick={() => menu.toggle("influence")}
228
- >
229
- {trimNumber(trailFalloffS)}s
230
- </button>
231
- {menu.open === "influence" && (
232
- <div className="vp-menu vp-slider-popover" role="dialog" aria-label={ko("Influence range", "영향 범위")}>
233
- <input
234
- type="range"
235
- min={0.1}
236
- max={2}
237
- step={0.1}
238
- value={trailFalloffS}
239
- aria-label={ko("Influence range", "영향 범위")}
240
- onChange={(event) => setTrailFalloffS(Number(event.target.value))}
241
- />
242
- <output>{trimNumber(trailFalloffS)}s</output>
243
- </div>
244
- )}
245
- </div>
246
187
  ) : workflowMode === "camera" ? (
247
188
  <>
248
189
  <div className="vp-menu-wrap" data-vp-menu="lens">
@@ -264,7 +205,6 @@ export default function ViewportToolbar() {
264
205
  key={mm}
265
206
  data-lens={mm}
266
207
  checked={shot.focalMm === mm}
267
- disabled={i2vMotionCameraLocked}
268
208
  onClick={() => { shotsDomain.changeLens(fov); menu.close(); }}
269
209
  >
270
210
  {mm}mm
@@ -278,7 +218,6 @@ export default function ViewportToolbar() {
278
218
  max={FOV_MAX}
279
219
  step="1"
280
220
  value={fovDeg}
281
- disabled={i2vMotionCameraLocked}
282
221
  onChange={(event) => shotsDomain.changeLens(Number(event.target.value))}
283
222
  />
284
223
  <output>{Math.round(fovDeg)}°</output>
@@ -476,7 +415,6 @@ export default function ViewportToolbar() {
476
415
  <select
477
416
  aria-label={ko("Camera preset", "카메라 프리셋")}
478
417
  value={cameraPresetId ?? ""}
479
- disabled={i2vMotionCameraLocked}
480
418
  onChange={(event) => {
481
419
  const id = event.target.value;
482
420
  if (!id) { runStudioAction("stage.setFilmback", { cameraPresetId: null }); return; }
@@ -515,20 +453,13 @@ export default function ViewportToolbar() {
515
453
  onClick={() => menu.toggle("shading")}
516
454
  >
517
455
  <RailIcon name="shading" />
518
- <span className="vp-label">{autoColor ? ko("Auto Color", "자동 색") : ko("Clay Lit", "클레이 조명")}</span>
456
+ <span className="vp-label">{ko("Clay Lit", "클레이 조명")}</span>
519
457
  </button>
520
458
  {menu.open === "shading" && (
521
459
  <div className="vp-menu" role="menu" aria-label={ko("Shading", "셰이딩")}>
522
460
  <MenuItem checked={!autoColor} onClick={() => { setAutoColorOn(false); menu.close(); }}>
523
461
  {ko("Clay Lit", "클레이 조명")}
524
462
  </MenuItem>
525
- <MenuItem
526
- checked={autoColor}
527
- title={ko("Flat, distinct colour per object — captures include them while on", "오브젝트별 평면 구분 색 — 켜둔 동안 캡처에도 포함됩니다")}
528
- onClick={() => { setAutoColorOn(true); menu.close(); }}
529
- >
530
- {ko("Auto Color", "자동 색")}
531
- </MenuItem>
532
463
  </div>
533
464
  )}
534
465
  </div>
@@ -590,18 +521,17 @@ export default function ViewportToolbar() {
590
521
  <button
591
522
  type="button"
592
523
  role="menuitemcheckbox"
593
- className={"view-menu-item trails-toggle" + (showTrails ? " active" : "")}
594
- aria-checked={showTrails}
595
- aria-pressed={showTrails}
596
- title={ko("Motion trails while posing", "포즈 편집 중 궤적선")}
597
- onClick={() => {
598
- if (showTrails && ikEditTool === "trail") setIkEditTool("ik");
599
- setShowTrails(!showTrails);
600
- }}
524
+ className={"view-menu-item vp-guide-cycle" + (guideMode === "off" ? "" : " active")}
525
+ aria-checked={guideMode !== "off"}
526
+ aria-pressed={guideMode !== "off"}
527
+ title={ko(GUIDE_LABELS[guideMode].en, GUIDE_LABELS[guideMode].ko) + ko(" · click to cycle", " · 클릭으로 전환")}
528
+ onClick={() => runStudioAction("view.setGuideMode", { mode: nextGuideMode(guideMode) })}
601
529
  >
602
- <span className="view-menu-mark" aria-hidden="true">{showTrails ? "✓" : ""}</span>
603
- {ko("Trails", "궤적선")}
530
+ <span className="view-menu-mark" aria-hidden="true">{guideMode !== "off" ? "✓" : ""}</span>
531
+ {ko("Composition guides", "구도 가이드")}
532
+ <small>{ko(GUIDE_LABELS[guideMode].en, GUIDE_LABELS[guideMode].ko)}</small>
604
533
  </button>
534
+ <GhostsMenuGroup />
605
535
  {/* Part colours repaint a BODY, so the section only exists
606
536
  while a character is selected (R2). */}
607
537
  {isCharacterSelection && (
@@ -23,7 +23,14 @@
23
23
  border: 0;
24
24
  background: none;
25
25
  }
26
- .app[data-shell="glass"] .studio-agent-inspector .agent-title { font: 600 13px var(--sans); color: var(--text-1); }
26
+ .app[data-shell="glass"] .studio-agent-inspector .agent-title {
27
+ min-width: 0;
28
+ overflow: hidden;
29
+ color: var(--text-1);
30
+ font: 600 13px var(--sans);
31
+ white-space: nowrap;
32
+ text-overflow: ellipsis;
33
+ }
27
34
  .app[data-shell="glass"] .studio-agent-inspector .agent-status-dot { display: none; }
28
35
  .app[data-shell="glass"] .studio-agent-inspector .agent-icon-button {
29
36
  display: grid;
@@ -227,7 +234,9 @@
227
234
  font: 400 12.5px/1.5 var(--sans);
228
235
  }
229
236
  .app[data-shell="glass"] .studio-agent-inspector .agent-composer textarea::placeholder { color: var(--text-3); }
230
- .app[data-shell="glass"] .studio-agent-inspector .agent-composer-controls { gap: 2px; margin: 4px 0 0 -6px; }
237
+ /* A narrow dock wraps the controls to a second row instead of crushing the
238
+ model name to its caret or pushing Send past the field's edge. */
239
+ .app[data-shell="glass"] .studio-agent-inspector .agent-composer-controls { flex-wrap: wrap; gap: 4px 2px; margin: 4px 0 0 -6px; }
231
240
  .app[data-shell="glass"] .studio-agent-inspector .agent-attach-chip {
232
241
  display: grid;
233
242
  place-items: center;
@@ -248,9 +257,9 @@
248
257
  .app[data-shell="glass"] .studio-agent-inspector .agent-model-select {
249
258
  -webkit-appearance: none;
250
259
  appearance: none;
251
- flex: 0 1 auto;
252
- min-width: 0;
253
- max-width: 132px;
260
+ flex: 1 1 96px;
261
+ min-width: 96px;
262
+ max-width: none;
254
263
  height: 26px;
255
264
  padding: 0 18px 0 8px;
256
265
  border: 0;
@@ -262,7 +271,7 @@
262
271
  cursor: pointer;
263
272
  }
264
273
  .app[data-shell="glass"] .studio-agent-inspector .agent-model-select:hover { background-color: var(--chip-fill); color: var(--text-1); }
265
- .app[data-shell="glass"] .studio-agent-inspector .agent-effort-select { flex: none; max-width: none; }
274
+ .app[data-shell="glass"] .studio-agent-inspector .agent-effort-select { flex: none; min-width: 0; max-width: none; }
266
275
  .app[data-shell="glass"] .studio-agent-inspector .agent-model-select optgroup,
267
276
  .app[data-shell="glass"] .studio-agent-inspector .agent-model-select option { background: var(--surface-raised); color: var(--text-1); }
268
277
  .app[data-shell="glass"] .studio-agent-inspector .agent-send {
@@ -293,4 +302,8 @@
293
302
 
294
303
  /* Provider keys: the same quiet rows. */
295
304
  .app[data-shell="glass"] .studio-agent-inspector .agent-keys { margin: 0 10px 8px; border: 0; border-radius: 12px; background: var(--card-fill); box-shadow: var(--card-ring); }
305
+ /* Connect a model takes the panel body while it is open: one scroll, and no
306
+ second "Connect a model" card showing through behind it. */
307
+ .app[data-shell="glass"] .studio-agent-inspector .agent-login { flex: 1 1 auto; min-height: 0; max-height: none; }
308
+ .app[data-shell="glass"] .studio-agent-inspector .agent-login ~ .agent-transcript { display: none; }
296
309
  .app[data-shell="glass"] .studio-agent-inspector .agent-key-input { border: 0; border-radius: 8px; background: var(--field-fill); color: var(--text-1); }
@@ -0,0 +1,42 @@
1
+ // The Details panel's selection header: the selected item's name and its
2
+ // "Kind · detail" type line.
3
+ import { ko } from "../locale.js";
4
+ import { sceneObjectNameDisplayKo, HIERARCHY_INSPECTOR_TITLES, CHARACTER_MODEL_LABELS } from "../app-stage.jsx";
5
+ import { CUTOUT_KIND, EMPTY_KIND, SCULPT_KIND } from "../scene-objects.js";
6
+ import { LIGHT_KIND } from "../object-look.js";
7
+
8
+ const characterIndexForRow = (rowId, characters) => rowId === "characterA" ? 0
9
+ : rowId === "characterB" ? 1
10
+ : characters.findIndex((entry) => `character:${entry.id}` === rowId);
11
+ const characterTitle = (index) => ko(`Character ${index + 1}`, `인물 ${index + 1}`);
12
+
13
+ /** The 2a selection header: the selected item's name and a "Kind · detail"
14
+ * type line. Null when nothing that owns settings is selected. */
15
+ export function detailsSelection({ selectedHierarchyId: id, selectedSceneObject, rigSelection, characters, shot, inspectorHasContent }) {
16
+ if (!inspectorHasContent) return null;
17
+ if (selectedSceneObject) {
18
+ const { renderer, light } = selectedSceneObject;
19
+ if (renderer === LIGHT_KIND) return { name: sceneObjectNameDisplayKo(selectedSceneObject.name), type: `${ko("Light", "조명")} · ${light?.type === "spot" ? ko("Spot", "스포트") : ko("Point", "점")}` };
20
+ const kind = renderer === CUTOUT_KIND ? ko("Cutout", "컷아웃") : renderer === EMPTY_KIND ? ko("Empty", "빈 오브젝트") : renderer === SCULPT_KIND ? ko("Sculpt", "조형") : ko("Mesh", "메시");
21
+ return { name: sceneObjectNameDisplayKo(selectedSceneObject.name), type: `${renderer === EMPTY_KIND ? ko("Node", "노드") : ko("Prop", "소품")} · ${kind}` };
22
+ }
23
+ if (rigSelection) {
24
+ const index = characterIndexForRow(rigSelection.rowId, characters);
25
+ const kind = rigSelection.token === "rig" ? ko("Rig", "리그") : ko("Bone", "본");
26
+ return { name: HIERARCHY_INSPECTOR_TITLES[rigSelection.token] ?? kind, type: index >= 0 ? `${kind} · ${characterTitle(index)}` : kind };
27
+ }
28
+ if (id === "camera") return { name: HIERARCHY_INSPECTOR_TITLES.camera, type: `${ko("Camera", "카메라")} · ${shot.focalMm}mm` };
29
+ if (id === "characterA" || id === "characterB" || id.startsWith("character:")) {
30
+ const index = characterIndexForRow(id, characters);
31
+ const model = CHARACTER_MODEL_LABELS[characters[index]?.model];
32
+ return { name: characterTitle(Math.max(index, 0)), type: model ? `${ko("Character", "인물")} · ${model}` : ko("Character", "인물") };
33
+ }
34
+ const types = {
35
+ shot: ko("Scene", "장면"),
36
+ light: ko("Light", "조명"),
37
+ characters: ko("Folder", "폴더"),
38
+ environment: ko("Environment", "환경"),
39
+ props: ko("Folder", "폴더"),
40
+ };
41
+ return { name: HIERARCHY_INSPECTOR_TITLES[id] ?? ko("Selection", "선택 항목"), type: types[id] ?? "" };
42
+ }
@@ -0,0 +1,22 @@
1
+ /* The View menu's Ghosts group (GhostsMenuGroup.jsx): two colour chips in the heading and
2
+ compact number steppers that keep the 24px menu rows. */
3
+ .ghosts-menu .view-menu-label { display: flex; align-items: center; gap: 4px; }
4
+ .ghosts-menu .ghost-swatch { display: inline-block; width: 8px; height: 8px; border-radius: 2px; opacity: 0.8; }
5
+ .ghosts-menu .ghost-swatch:first-of-type { margin-left: 4px; }
6
+ .ghosts-menu .view-menu-item.ghost-stepper { cursor: default; }
7
+ .ghosts-menu .ghost-stepper.disabled { opacity: 0.45; }
8
+ .ghosts-menu .ghost-stepper-label { flex: 1; }
9
+ .ghosts-menu .ghost-stepper button {
10
+ width: 18px;
11
+ height: 18px;
12
+ padding: 0;
13
+ border: 1px solid var(--row-divider, var(--line));
14
+ border-radius: 4px;
15
+ background: none;
16
+ color: inherit;
17
+ font: inherit;
18
+ line-height: 1;
19
+ cursor: pointer;
20
+ }
21
+ .ghosts-menu .ghost-stepper button:disabled { cursor: default; opacity: 0.5; }
22
+ .ghosts-menu .ghost-stepper-value { min-width: 16px; text-align: center; font-variant-numeric: tabular-nums; }
@@ -431,9 +431,9 @@
431
431
  --tl-ruler-height: 24px;
432
432
  --tl-track-row-height: 22px;
433
433
  --tl-track-group-height: 66px;
434
- /* The surface is exactly its rows (ruler + 2 lanes + 2 lane groups), so it
434
+ /* The surface is exactly its rows (ruler + 1 lane + 2 lane groups), so it
435
435
  never asks the body for more height than the dock gives it. */
436
- --tl-surface-height: calc(var(--tl-ruler-height) + var(--tl-track-row-height) * 2 + var(--tl-track-group-height) * 2);
436
+ --tl-surface-height: calc(var(--tl-ruler-height) + var(--tl-track-row-height) + var(--tl-track-group-height) * 2);
437
437
  --tl-camera-bar-height: 28px;
438
438
  --tl-track-tree-width: 170px;
439
439
  --tl-clip-inset: 4px;
@@ -446,7 +446,8 @@
446
446
  height: auto;
447
447
  min-height: 48px;
448
448
  gap: 12px;
449
- padding: 0 16px;
449
+ /* The right inset keeps the pinned collapse toggle clear of the controls. */
450
+ padding: 0 52px 0 16px;
450
451
  border: 0;
451
452
  background: none;
452
453
  }
@@ -500,6 +501,31 @@
500
501
  .app[data-shell="glass"]:not([data-embed-mode]) .v2-sequencer .tl-seq-action:hover:not(:disabled),
501
502
  .app[data-shell="glass"]:not([data-embed-mode]) .v2-sequencer .tl-head-group .tl-btn:hover:not(:disabled) { background: var(--chip-fill); color: var(--text-1); }
502
503
  .app[data-shell="glass"]:not([data-embed-mode]) .v2-sequencer .tl-seq-action:disabled { opacity: .4; }
504
+ /* The take's segment speed sits in the same quiet chip grammar as its neighbours. */
505
+ .app[data-shell="glass"]:not([data-embed-mode]) .v2-sequencer .tl-motion-speed-editor {
506
+ min-width: 0;
507
+ height: 26px;
508
+ gap: 6px;
509
+ padding: 0 8px;
510
+ border: 0;
511
+ border-radius: 13px;
512
+ background: none;
513
+ color: var(--label);
514
+ font: 500 12px var(--sans);
515
+ }
516
+ .app[data-shell="glass"]:not([data-embed-mode]) .v2-sequencer .tl-motion-speed-editor > span { font-weight: 500; }
517
+ .app[data-shell="glass"]:not([data-embed-mode]) .v2-sequencer .tl-motion-speed-editor input[type="range"] { width: 72px; accent-color: var(--primary-fill, var(--select)); }
518
+ .app[data-shell="glass"]:not([data-embed-mode]) .v2-sequencer .tl-motion-speed-editor input[type="number"] {
519
+ width: 40px;
520
+ height: 22px;
521
+ padding: 0 4px;
522
+ border: 0;
523
+ border-radius: 6px;
524
+ background: var(--chip-fill);
525
+ color: var(--text-1);
526
+ font: 500 12px var(--sans);
527
+ }
528
+ .app[data-shell="glass"]:not([data-embed-mode]) .v2-sequencer .tl-motion-speed-editor small { color: var(--label); }
503
529
  .app[data-shell="glass"]:not([data-embed-mode]) .v2-sequencer .tl-btn.wp.on { background: var(--seg-on); box-shadow: var(--seg-on-shadow); color: var(--seg-on-text); }
504
530
  .app[data-shell="glass"]:not([data-embed-mode]) .v2-sequencer .tl-badge {
505
531
  height: 22px;
@@ -381,6 +381,9 @@
381
381
  }
382
382
 
383
383
  .v2-preferences .v2-preferences__language {
384
+ display: inline-flex;
385
+ align-items: center;
386
+ justify-content: center;
384
387
  height: var(--h-control, 28px);
385
388
  padding: 0 var(--sp-2, 12px);
386
389
  border: 0;
@@ -512,6 +515,8 @@
512
515
  color: var(--text-3, #636369);
513
516
  font-size: var(--prefs-secondary-size, 11px);
514
517
  font-weight: 500;
518
+ letter-spacing: 0;
519
+ text-transform: none;
515
520
  }
516
521
 
517
522
  .v2-preferences .v2-preferences__help button {
@@ -519,7 +524,7 @@
519
524
  padding: 0 var(--sp-2, 12px);
520
525
  border: 0;
521
526
  border-radius: var(--r-1, 4px);
522
- background: transparent;
527
+ background: var(--field-fill, var(--surface-raised, #1e1e21));
523
528
  color: var(--text-2, #9b9ba1);
524
529
  font: inherit;
525
530
  font-size: var(--prefs-secondary-size, 11px);
@@ -32,6 +32,18 @@
32
32
  color: var(--text-1);
33
33
  }
34
34
  .app[data-embed-mode] .viewport-titlebar { display: none; }
35
+ .app[data-embed-mode] .vp-embed-guide {
36
+ position: absolute;
37
+ top: var(--sp-1);
38
+ right: var(--sp-1);
39
+ z-index: 6;
40
+ padding: var(--sp-1);
41
+ border-radius: var(--r-2);
42
+ background: var(--surface-panel);
43
+ color: var(--text-2);
44
+ }
45
+ .app[data-embed-mode] .vp-embed-guide:hover,
46
+ .app[data-embed-mode] .vp-embed-guide.on { color: var(--select); }
35
47
 
36
48
  .viewport-titlebar button { font-family: inherit; }
37
49
  .viewport-titlebar button:focus-visible {
@@ -6,6 +6,7 @@
6
6
 
7
7
  import { createTiming, timingIsFlat } from "./speed-envelope.js";
8
8
  import { createShot } from "./cuts.js";
9
+ import { railShotFields } from "./camera-block.js";
9
10
  import { normalizeStableItems } from "./stable-items.js";
10
11
  import { VIDEO_MODEL_PRESETS } from "./model-presets.js";
11
12
  import { elementByPath } from "./studio-elements.js";
@@ -110,7 +111,7 @@ const FOLLOW_BOUNDS = {
110
111
  height: [0.2, Number.POSITIVE_INFINITY],
111
112
  response: [0.1, 3],
112
113
  lead: [0, 1],
113
- maxDollySpeed: [0.2, 8],
114
+ maxDollySpeed: [0.2, 40],
114
115
  pitchOffsetDeg: [-170, 170],
115
116
  orbitOffsetDeg: [-180, 180],
116
117
  };
@@ -299,6 +300,7 @@ function repairCamera(value) {
299
300
  // The dolly's speed curve rides the rail the same way; the envelope
300
301
  // module owns its repair (parse-don't-validate, flat heals to null).
301
302
  dollyTiming: cameraRail ? repairDollyTiming(source.dollyTiming) : null,
303
+ ...railShotFields(source, cameraRail),
302
304
  };
303
305
  }
304
306
 
@@ -310,12 +312,7 @@ function repairDollyTiming(value) {
310
312
  function migratedCamera(followCam, cameraRail, railFollow = null) {
311
313
  const rail = repairRail(cameraRail);
312
314
  const enabled = followCam?.enabled === true;
313
- return repairCamera({
314
- mode: enabled ? (rail ? "rail" : "follow") : "keys",
315
- followCam,
316
- cameraRail: rail,
317
- railFollow,
318
- });
315
+ return repairCamera({ mode: enabled ? (rail ? "rail" : "follow") : "keys", followCam, cameraRail: rail, railFollow });
319
316
  }
320
317
 
321
318
  function repairShared(parsed, frameCount, ids) {
@@ -0,0 +1,37 @@
1
+ // Soft key shadows in the same pass. three r185's PCF filter takes five taps
2
+ // on a Vogel disk of shadow.radius texels, rotated per pixel by interleaved
3
+ // gradient noise; past a radius of about two texels those five taps show as a
4
+ // cross-hatched grain over every penumbra. A wider radius (stage.lighting
5
+ // shadowSoftness) therefore takes SOFT_SHADOW_TAPS taps instead, which keeps
6
+ // the same disk and noise rotation but averages the grain away. Radius 1 —
7
+ // every stage before the look was authorable — runs the original five-tap code
8
+ // unchanged, so studio frames stay pixel-identical.
9
+ //
10
+ // Evaluated against the alternatives: PCFSoftShadowMap is deprecated in r185
11
+ // (it falls back to PCF); VSMShadowMap blurs smoothly but loses contact shadows
12
+ // (a leg's shadow on a box beside it vanished), cannot shadow point lights, and
13
+ // is renderer-wide, so it would restyle the studio look too.
14
+ import { ShaderChunk } from "three";
15
+
16
+ const SOFT_SHADOW_TAPS = 16;
17
+ const tap = (index) => `texture( shadowMap, vec3( shadowCoord.xy + vogelDiskSample( ${index}, 5, phi ) * radius, shadowCoord.z ) )`;
18
+ const FIVE_TAPS = `shadow = (\n${[0, 1, 2, 3, 4].map((index) => `\t\t\t\t\t${tap(index)}`).join(" +\n")}\n\t\t\t\t) * 0.2;`;
19
+ const SOFT_TAPS = `if ( shadowRadius <= 1.0 ) {
20
+ ${FIVE_TAPS}
21
+ } else {
22
+ shadow = 0.0;
23
+ for ( int i = 0; i < ${SOFT_SHADOW_TAPS}; i ++ ) shadow += texture( shadowMap, vec3( shadowCoord.xy + vogelDiskSample( i, ${SOFT_SHADOW_TAPS}, phi ) * radius, shadowCoord.z ) );
24
+ shadow /= ${SOFT_SHADOW_TAPS}.0;
25
+ }`;
26
+
27
+ /** Patch the directional/spot PCF filter once; answers whether the soft path is in. */
28
+ export function installSoftShadows(chunks = ShaderChunk) {
29
+ const source = chunks.shadowmap_pars_fragment;
30
+ if (source.includes(SOFT_TAPS)) return true;
31
+ // A three upgrade that rewrites the filter leaves the stock one in place.
32
+ if (!source.includes(FIVE_TAPS)) return false;
33
+ chunks.shadowmap_pars_fragment = source.replace(FIVE_TAPS, SOFT_TAPS);
34
+ return true;
35
+ }
36
+
37
+ installSoftShadows();
@@ -1,6 +1,6 @@
1
1
  import * as THREE from "three";
2
2
  import { SCENE_ATTACH_BONES } from "./scene-objects.js";
3
- import { TRAIL_EFFECTOR_JOINTS } from "./motion-trail.js";
3
+
4
4
  import { normalizeBoneName } from "./poses.js";
5
5
 
6
6
  /** The rig rows that ARE an attach frame: `rig.<track id>`, the same camel
@@ -8,14 +8,14 @@ import { normalizeBoneName } from "./poses.js";
8
8
  * rig.leftArm …) name a limb, not a frame, so they are deliberately absent. */
9
9
  export const ATTACH_BONE_ROWS = new Map(SCENE_ATTACH_BONES.map((bone) => [`rig.${bone}`, bone]));
10
10
 
11
- /** Attach track id -> the Mixamo bone carrying that frame on the shipped rigs.
12
- * TRAIL_EFFECTOR_JOINTS names the cskel27 joint, and cskel27 and Mixamo agree
13
- * everywhere except the spine, which sits one bone up the Mixamo chain (the
14
- * same shift ardy/playback.js SKINNING_MAP makes). */
15
- export const ATTACH_BONE_NAMES = Object.fromEntries(SCENE_ATTACH_BONES.map((bone) => {
16
- const joint = TRAIL_EFFECTOR_JOINTS[bone];
17
- return [bone, joint === "Spine1" ? "Spine" : joint === "Spine2" ? "Spine1" : joint];
18
- }));
11
+ /** Attach track id -> the Mixamo bone carrying that frame on the shipped rigs. */
12
+ const MIXAMO_ATTACH_BONES = {
13
+ hips: "Hips", spine: "Spine", chest: "Spine1", neck: "Neck", head: "Head",
14
+ leftShoulder: "LeftArm", leftElbow: "LeftForeArm", leftHand: "LeftHand",
15
+ rightShoulder: "RightArm", rightElbow: "RightForeArm", rightHand: "RightHand",
16
+ leftKnee: "LeftLeg", leftFoot: "LeftFoot", rightKnee: "RightLeg", rightFoot: "RightFoot",
17
+ };
18
+ export const ATTACH_BONE_NAMES = Object.fromEntries(SCENE_ATTACH_BONES.map((bone) => [bone, MIXAMO_ATTACH_BONES[bone]]));
19
19
 
20
20
  // One scratch set for the whole module: resolving a frame runs per attached
21
21
  // prop per frame and must never allocate.
@@ -36,7 +36,7 @@ export const placeEuler = new THREE.Euler();
36
36
 
37
37
  /** The bone a rig offers under `mixamoName`, by the project's matching rule
38
38
  * (normalised names equal, or one a suffix of the other; first depth-first
39
- * match wins — poses.js and ardy/playback.js agree). Cached per rig: this is
39
+ * match wins — poses.js and motion3/playback.js agree). Cached per rig: this is
40
40
  * asked once per attached prop per rendered frame. */
41
41
  export const attachBoneCache = new WeakMap();
42
42
  export function attachBoneOf(rig, mixamoName) {
@@ -65,8 +65,8 @@ export function attachBoneOf(rig, mixamoName) {
65
65
  * A carried prop takes the bone's place and facing; its size stays its own.
66
66
  *
67
67
  * `bone === null` is the character's animated ROOT: the hips' travel (during
68
- * playback the whole root trajectory lives in the bones — see
69
- * ardy/playback.js) carried at the character's own yaw, so a prop dropped on
68
+ * playback the hips travel lives in the bones — see motion3/playback.js)
69
+ * carried at the character's own yaw, so a prop dropped on
70
70
  * the character walks with the body instead of rolling with the hips.
71
71
  */
72
72
  export function attachFrameMatrix(rig, bone, out = new THREE.Matrix4()) {
@@ -212,9 +212,7 @@ export function FollowCamRig({ enabled, frame, frameRef, scene, shot, camRef, lo
212
212
  applied.current = null;
213
213
  if (enabled) invalidate();
214
214
  }, [scene, shot, enabled, invalidate]);
215
- useEffect(() => {
216
- if (enabled) invalidate();
217
- }, [frame, enabled, invalidate]);
215
+ useEffect(() => { if (enabled) invalidate(); }, [frame, enabled, invalidate]);
218
216
  useFrame(() => {
219
217
  if (!enabled) return;
220
218
  if (isInterrupted?.()) return; // the user is flying; yield until released
@@ -227,6 +225,8 @@ export function FollowCamRig({ enabled, frame, frameRef, scene, shot, camRef, lo
227
225
  cam.position.set(sample.pos.x, sample.pos.y, sample.pos.z);
228
226
  look.current.yaw = sample.yaw;
229
227
  look.current.pitch = sample.pitch;
228
+ // A rail with a lens of its own carries it; otherwise this is the scene lens.
229
+ if (Math.abs(cam.fov - sample.fovDeg) > 1e-3) { cam.fov = sample.fovDeg; cam.updateProjectionMatrix(); }
230
230
  invalidate();
231
231
  });
232
232
  return null;