cozyclay 2.1.1 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (585) hide show
  1. package/CHANGELOG.md +88 -0
  2. package/README.md +12 -30
  3. package/bin/agent/agent-routes.mjs +43 -116
  4. package/bin/agent/agent-runner.mjs +14 -15
  5. package/bin/agent/cliproxy-provider.mjs +135 -0
  6. package/bin/agent/credential-store.mjs +30 -7
  7. package/bin/agent/pi-tools.mjs +4 -1
  8. package/bin/agent/provider-keys.mjs +32 -0
  9. package/bin/agent/provider-login.mjs +110 -0
  10. package/bin/agent/provider-routes.mjs +99 -0
  11. package/bin/agent/providers.mjs +19 -97
  12. package/bin/agent/script-tool.mjs +17 -4
  13. package/bin/agent/session-store.mjs +2 -2
  14. package/bin/agent/studio-context-budget.mjs +93 -0
  15. package/bin/agent/studio-motion-reference.mjs +23 -0
  16. package/bin/agent/studio-prompt.mjs +1 -1
  17. package/bin/agent/studio-rebase-text.mjs +32 -0
  18. package/bin/agent/studio-rebase.mjs +26 -39
  19. package/bin/agent/studio-tools.mjs +9 -28
  20. package/bin/agent/tool-arguments.mjs +49 -0
  21. package/bin/agent/turn-frames.mjs +66 -0
  22. package/bin/codex-auth.mjs +9 -2
  23. package/bin/cozyclay.mjs +10 -116
  24. package/bin/live/cli.mjs +3 -3
  25. package/bin/mcp-runtime.mjs +2 -12
  26. package/bin/package-signature.mjs +0 -4
  27. package/dist/app/index.html +7 -6
  28. package/dist/assets/EXRLoader-CvVIvGVE.js +1 -0
  29. package/dist/assets/analytics-BWCqdgWA.js +1 -0
  30. package/dist/assets/app-DfTCxaKk.js +5087 -0
  31. package/dist/assets/app-f-fkV5uP.css +1 -0
  32. package/dist/assets/compile-worker-BxKXh07s.js +5 -0
  33. package/dist/assets/fflate.module-KbGj5-H6.js +5 -0
  34. package/dist/assets/{first-shot-handoff-msLI71g1.js → first-shot-handoff-DNO8kv_N.js} +1 -1
  35. package/dist/assets/{landing-ChUvB_zL.js → landing-yfZaJkWc.js} +1 -1
  36. package/dist/assets/scene-asset-sync-U3kS2rvK.js +20 -0
  37. package/dist/assets/scene-asset-sync-_S8NQl5B.css +1 -0
  38. package/dist/assets/workflow-D78eiKTa.js +179 -0
  39. package/dist/cozyclay-package.json +1 -1
  40. package/dist/index.html +3 -3
  41. package/dist/sw.js +3 -6
  42. package/dist/workflow/index.html +5 -4
  43. package/mcp/LIVE-PROTOCOL.md +7 -47
  44. package/mcp/README.md +16 -26
  45. package/mcp/live-hub.mjs +6 -10
  46. package/mcp/package.json +1 -3
  47. package/mcp/tool-handlers.mjs +4 -168
  48. package/package.json +3 -22
  49. package/src/App.jsx +151 -2625
  50. package/src/agent-progress.js +80 -0
  51. package/src/agent-turn-mark.js +30 -0
  52. package/src/analytics.js +1 -19
  53. package/src/app-context.js +12 -2
  54. package/src/app-stage.jsx +2 -34
  55. package/src/asset-pane.jsx +6 -5
  56. package/src/camera-block.js +21 -0
  57. package/src/camera-direction.js +120 -0
  58. package/src/character-kind.js +3 -9
  59. package/src/command-bus.js +10 -8
  60. package/src/commands/cast.js +5 -34
  61. package/src/commands/elements/character.js +1 -1
  62. package/src/commands/elements/motion.js +1 -6
  63. package/src/commands/elements/object.js +6 -2
  64. package/src/commands/elements/shot.js +4 -1
  65. package/src/commands/elements.js +38 -14
  66. package/src/commands/index.js +3 -1
  67. package/src/commands/kits.js +37 -0
  68. package/src/commands/motion-timing.js +57 -0
  69. package/src/commands/motion.js +9 -152
  70. package/src/commands/motion3-compile.js +65 -0
  71. package/src/commands/motion3.js +214 -0
  72. package/src/commands/objects.js +6 -4
  73. package/src/commands/shot.js +55 -13
  74. package/src/commands/stage.js +14 -1
  75. package/src/commands/view.js +4 -1
  76. package/src/document-mirrors.js +42 -0
  77. package/src/document-store.js +4 -0
  78. package/src/domains/cast.js +19 -194
  79. package/src/domains/motion/motion-range-pin-rules.js +1 -1
  80. package/src/domains/motion/take-source.js +53 -0
  81. package/src/domains/motion.js +60 -1838
  82. package/src/domains/scenes.js +12 -55
  83. package/src/domains/shots.js +2 -2
  84. package/src/domains/stage.js +4 -2
  85. package/src/draft-ghost.js +47 -0
  86. package/src/draft-ghost.jsx +129 -0
  87. package/src/dualview.jsx +4 -3
  88. package/src/effects/EffectsLayer.jsx +112 -0
  89. package/src/effects/effect-meshes.js +232 -0
  90. package/src/effects/effect-record.js +103 -0
  91. package/src/effects/emitter.js +59 -0
  92. package/src/effects/simulate.js +261 -0
  93. package/src/effects/state.js +59 -0
  94. package/src/execution-telemetry.js +2 -3
  95. package/src/first-success-guide.jsx +5 -5
  96. package/src/ghost-set.js +257 -0
  97. package/src/held-object-edit.jsx +113 -0
  98. package/src/held-object-pose.js +175 -0
  99. package/src/hierarchy-model.js +1 -1
  100. package/src/hierarchy-panel.jsx +1 -1
  101. package/src/imported-mesh.jsx +103 -0
  102. package/src/kits/held.js +84 -0
  103. package/src/kits/index.js +70 -0
  104. package/src/kits/smoking.js +57 -0
  105. package/src/light-blockers.js +93 -0
  106. package/src/motion/beat-board-model.js +84 -0
  107. package/src/motion/beat-board.css +124 -0
  108. package/src/motion/beat-board.jsx +60 -0
  109. package/src/motion/center-of-mass.js +66 -0
  110. package/src/motion/fix-collisions.js +850 -0
  111. package/src/motion/physics-review.js +118 -0
  112. package/src/{ardy → motion}/physics-support.js +1 -76
  113. package/src/motion/rig-snapshot.js +22 -0
  114. package/src/motion/take-segments.jsx +140 -0
  115. package/src/{ardy → motion}/timeline-coordinates.js +0 -21
  116. package/src/{ardy → motion}/timeline.css +1 -2
  117. package/src/{ardy → motion}/timeline.jsx +42 -413
  118. package/src/motion/waypoints.js +76 -0
  119. package/src/motion3/beats.js +83 -0
  120. package/src/motion3/body.js +158 -0
  121. package/src/motion3/bones.js +47 -0
  122. package/src/motion3/carried.js +47 -0
  123. package/src/motion3/compile-job.js +79 -0
  124. package/src/motion3/compile-worker.js +10 -0
  125. package/src/motion3/compiler/anchors.js +113 -0
  126. package/src/motion3/compiler/arm-orient.js +128 -0
  127. package/src/motion3/compiler/channels.js +125 -0
  128. package/src/motion3/compiler/compile.js +205 -0
  129. package/src/motion3/compiler/gait-rhythm.js +97 -0
  130. package/src/motion3/compiler/grip.js +171 -0
  131. package/src/motion3/compiler/head-steady.js +48 -0
  132. package/src/motion3/compiler/hold.js +134 -0
  133. package/src/motion3/compiler/idle.js +113 -0
  134. package/src/motion3/compiler/limbs.js +197 -0
  135. package/src/motion3/compiler/math.js +72 -0
  136. package/src/motion3/compiler/pose.js +177 -0
  137. package/src/motion3/compiler/quat.js +49 -0
  138. package/src/motion3/compiler/skeleton.js +74 -0
  139. package/src/motion3/compiler/validate-common.js +32 -0
  140. package/src/motion3/compiler/validate-goals.js +118 -0
  141. package/src/motion3/compiler/validate-objects.js +144 -0
  142. package/src/motion3/compiler/validate-parts.js +118 -0
  143. package/src/motion3/compiler/validate.js +122 -0
  144. package/src/motion3/compiler/vocab.js +74 -0
  145. package/src/motion3/compiler/walk-pelvis.js +275 -0
  146. package/src/motion3/compiler/walk.js +207 -0
  147. package/src/motion3/compiler/wrist-clamp.js +32 -0
  148. package/src/motion3/delta.js +47 -0
  149. package/src/motion3/describe.js +177 -0
  150. package/src/motion3/docs.js +27 -0
  151. package/src/motion3/edit-carry.js +21 -0
  152. package/src/motion3/fix/ease.js +16 -0
  153. package/src/motion3/fix/ground.js +37 -0
  154. package/src/motion3/fix/index.js +52 -0
  155. package/src/motion3/fix/push.js +71 -0
  156. package/src/motion3/fix/reach.js +46 -0
  157. package/src/motion3/fix/retime.js +79 -0
  158. package/src/motion3/fix/self.js +211 -0
  159. package/src/motion3/fix/slide.js +70 -0
  160. package/src/motion3/fix/turn.js +51 -0
  161. package/src/motion3/follow.js +39 -0
  162. package/src/motion3/free-motion.js +204 -0
  163. package/src/motion3/grip-choice.js +130 -0
  164. package/src/motion3/hold-plan.js +157 -0
  165. package/src/motion3/json-patch.js +77 -0
  166. package/src/motion3/key-aim.js +105 -0
  167. package/src/motion3/key-edit.js +82 -0
  168. package/src/motion3/lenient.js +127 -0
  169. package/src/motion3/object-keys.js +236 -0
  170. package/src/motion3/object-pose.js +182 -0
  171. package/src/motion3/object-tracks.js +12 -0
  172. package/src/motion3/people.js +82 -0
  173. package/src/motion3/pipeline.js +102 -0
  174. package/src/motion3/playback.js +51 -0
  175. package/src/motion3/probes.js +91 -0
  176. package/src/motion3/qa/body-checks.js +34 -0
  177. package/src/motion3/qa/check-names.js +14 -0
  178. package/src/motion3/qa/checks.js +125 -0
  179. package/src/motion3/qa/contact-checks.js +51 -0
  180. package/src/motion3/qa/explain.js +80 -0
  181. package/src/motion3/qa/fmt.js +5 -0
  182. package/src/motion3/qa/foot-checks.js +72 -0
  183. package/src/motion3/qa/geometry.js +77 -0
  184. package/src/motion3/qa/goals.js +191 -0
  185. package/src/motion3/qa/ground.js +60 -0
  186. package/src/motion3/qa/hints-contact.js +195 -0
  187. package/src/motion3/qa/hints-goal.js +160 -0
  188. package/src/motion3/qa/hints-knee.js +24 -0
  189. package/src/motion3/qa/hints-motion.js +209 -0
  190. package/src/motion3/qa/hints-object.js +91 -0
  191. package/src/motion3/qa/index.js +44 -0
  192. package/src/motion3/qa/key-checks.js +82 -0
  193. package/src/motion3/qa/near.js +96 -0
  194. package/src/motion3/qa/object-checks.js +135 -0
  195. package/src/motion3/qa/patch.js +161 -0
  196. package/src/motion3/qa/people-checks.js +37 -0
  197. package/src/motion3/qa/severity.js +38 -0
  198. package/src/motion3/qa/spec-checks.js +65 -0
  199. package/src/motion3/qa/style.js +228 -0
  200. package/src/motion3/qa/wrist-checks.js +69 -0
  201. package/src/motion3/qa/wrist-obs.js +60 -0
  202. package/src/motion3/refs.js +129 -0
  203. package/src/motion3/repair-tune.js +121 -0
  204. package/src/motion3/repair.js +83 -0
  205. package/src/motion3/report.js +67 -0
  206. package/src/motion3/rigs/index.js +14 -0
  207. package/src/motion3/rigs/x-bot-tpose-body.json +1 -0
  208. package/src/motion3/rigs/x-bot-tpose.json +1 -0
  209. package/src/motion3/rigs/y-bot-tpose-body.json +1 -0
  210. package/src/motion3/rigs/y-bot-tpose.json +1 -0
  211. package/src/motion3/scene.js +60 -0
  212. package/src/motion3/schema/brief.js +89 -0
  213. package/src/motion3/schema/fields.js +44 -0
  214. package/src/motion3/schema/spec-examples.js +46 -0
  215. package/src/motion3/schema/topics.js +113 -0
  216. package/src/motion3/schema/types.js +149 -0
  217. package/src/motion3/search.js +117 -0
  218. package/src/motion3/second-hand.js +112 -0
  219. package/src/motion3/settle.js +136 -0
  220. package/src/motion3/skills/basic.js +83 -0
  221. package/src/motion3/skills/book.js +76 -0
  222. package/src/motion3/skills/car.js +145 -0
  223. package/src/motion3/skills/flip.js +200 -0
  224. package/src/motion3/skills/frames-auto.js +29 -0
  225. package/src/motion3/skills/impact.js +109 -0
  226. package/src/motion3/skills/index.js +85 -0
  227. package/src/motion3/skills/info.js +80 -0
  228. package/src/motion3/skills/smoke-kit.js +109 -0
  229. package/src/motion3/skills/smoke.js +160 -0
  230. package/src/motion3/spec-store.js +59 -0
  231. package/src/motion3/take-edit.js +155 -0
  232. package/src/motion3/take.js +63 -0
  233. package/src/motion3/timeline.js +127 -0
  234. package/src/motion3/views.js +121 -0
  235. package/src/motion3/walk-plan.js +119 -0
  236. package/src/object-catalog.jsx +7 -1
  237. package/src/object-colors.js +98 -0
  238. package/src/object-gizmo-parts.js +115 -0
  239. package/src/object-gizmo.jsx +37 -122
  240. package/src/object-glow.js +139 -0
  241. package/src/object-hidden.js +33 -0
  242. package/src/object-look.js +196 -0
  243. package/src/object-size.js +10 -0
  244. package/src/object-travel.js +71 -6
  245. package/src/panels/CameraPanel.jsx +7 -7
  246. package/src/panels/HdrEnvironmentControls.jsx +59 -0
  247. package/src/panels/LightPanel.jsx +25 -4
  248. package/src/panels/ObjectLookPanel.jsx +88 -0
  249. package/src/panels/PosePanel.jsx +2 -17
  250. package/src/panels/RigControlPanel.jsx +5 -53
  251. package/src/panels/SubjectBox.jsx +4 -1
  252. package/src/panels/details.css +14 -0
  253. package/src/posestudio.jsx +4 -27
  254. package/src/project-browser.jsx +3 -4
  255. package/src/project-resources.js +18 -31
  256. package/src/project.js +13 -104
  257. package/src/props.jsx +25 -280
  258. package/src/qa-label.js +25 -0
  259. package/src/rail-dot-drag.js +23 -0
  260. package/src/render-passes.js +10 -0
  261. package/src/resource-status.jsx +1 -0
  262. package/src/result-modal.jsx +4 -19
  263. package/src/room.jsx +20 -12
  264. package/src/scene-assets.js +8 -6
  265. package/src/scene-light-place.js +72 -0
  266. package/src/scene-lights.jsx +148 -0
  267. package/src/scene-objects.js +31 -139
  268. package/src/scenes.js +15 -105
  269. package/src/semantic-edit.js +2 -5
  270. package/src/set-pieces.jsx +183 -0
  271. package/src/settings-menu.jsx +3 -11
  272. package/src/shell/BottomDock.jsx +9 -51
  273. package/src/shell/DetailsSlot.jsx +16 -200
  274. package/src/shell/GhostsMenuGroup.jsx +74 -0
  275. package/src/shell/LibrarySlot.jsx +1 -3
  276. package/src/shell/MenuBar.jsx +3 -3
  277. package/src/shell/PreferencesDialog.jsx +15 -264
  278. package/src/shell/PreferencesSlot.jsx +2 -8
  279. package/src/shell/TopBar.jsx +5 -84
  280. package/src/shell/ViewportToolbar.jsx +10 -70
  281. package/src/shell/agent-glass.css +19 -6
  282. package/src/shell/details-selection.js +42 -0
  283. package/src/shell/ghosts-menu.css +22 -0
  284. package/src/shell/glass-regions.css +29 -3
  285. package/src/shell/preferences.css +6 -1
  286. package/src/shot-authoring.js +4 -7
  287. package/src/soft-shadows.js +37 -0
  288. package/src/stage-attach-frames.js +12 -12
  289. package/src/stage-canvas-rigs.jsx +3 -3
  290. package/src/stage-capture.jsx +42 -8
  291. package/src/stage-characters.jsx +22 -216
  292. package/src/stage-editor-gizmos.jsx +6 -6
  293. package/src/stage-environment.js +93 -0
  294. package/src/stage-hdr-builtins.js +107 -0
  295. package/src/stage-hdr-image.js +116 -0
  296. package/src/stage-hdr-library.js +70 -0
  297. package/src/stage-hdr-map.js +94 -0
  298. package/src/stage-hdr.js +130 -0
  299. package/src/stage-lighting.js +149 -0
  300. package/src/stage-occlusion.js +210 -0
  301. package/src/stage-sky.jsx +159 -0
  302. package/src/stage-startup-defaults.js +5 -9
  303. package/src/studio-actions.js +16 -14
  304. package/src/studio-agent-commands.js +19 -16
  305. package/src/studio-agent-motion.js +9 -9
  306. package/src/studio-agent-protocol.js +47 -77
  307. package/src/studio-app-binding.js +27 -47
  308. package/src/studio-asset-list.js +17 -0
  309. package/src/studio-contact-sheet.js +37 -5
  310. package/src/studio-elements.js +27 -7
  311. package/src/studio-entity-bounds.js +18 -0
  312. package/src/studio-error-codes.js +15 -0
  313. package/src/studio-export-framing.js +152 -0
  314. package/src/studio-lighting-check.js +103 -0
  315. package/src/studio-motion-visual.js +150 -0
  316. package/src/studio-schema-errors.js +80 -0
  317. package/src/studio-support-gap.js +74 -0
  318. package/src/styles.css +1 -19
  319. package/src/timeline-defaults.js +5 -0
  320. package/src/timeline-extent.js +8 -20
  321. package/src/tutorial-walk.js +17 -0
  322. package/src/ui-scrub.js +1 -1
  323. package/src/use-shot-camera-tracks.js +12 -0
  324. package/src/view-ghosts.js +97 -0
  325. package/src/view-ghosts.jsx +49 -0
  326. package/src/workflow/AgentPanel.jsx +47 -166
  327. package/src/workflow/AgentProgressCard.jsx +109 -0
  328. package/src/workflow/AgentReplyText.jsx +37 -0
  329. package/src/workflow/AgentTurnSteps.jsx +84 -0
  330. package/src/workflow/LoginPanel.jsx +140 -0
  331. package/src/workflow/WorkflowBuilder.jsx +7 -23
  332. package/src/workflow/agent-client.js +54 -51
  333. package/src/workflow/agent-panel.css +71 -1
  334. package/src/workflow/agent-progress-card.css +167 -0
  335. package/src/workflow/agent-progress-view.js +47 -0
  336. package/src/workflow/agent-turn-steps.css +113 -0
  337. package/src/workflow/agent-turn.js +191 -0
  338. package/src/workflow/login-client.js +34 -0
  339. package/src/workflow/motion-input.js +18 -31
  340. package/src/workflow/node-schema.js +1 -1
  341. package/src/workflow/reply-markdown.js +69 -0
  342. package/src/workflow/scene-asset-sync.js +8 -8
  343. package/tools/agent-session-stats.mjs +61 -0
  344. package/tools/dev-full.mjs +5 -56
  345. package/tools/eslint-baseline.json +12 -13
  346. package/tools/knip-baseline.json +0 -179
  347. package/tools/loc-baseline.json +31 -81
  348. package/tools/motion3/extract-body.mjs +103 -0
  349. package/tools/motion3/extract-rig.mjs +85 -0
  350. package/tools/process-supervisor.mjs +0 -88
  351. package/tools/run-tests.mjs +9 -125
  352. package/bin/agent/motion-runtime.mjs +0 -76
  353. package/dist/ardy/cskel27-rest.json +0 -557
  354. package/dist/assets/analytics-C9pMpW7s.js +0 -1
  355. package/dist/assets/app-B_2XB9rw.css +0 -1
  356. package/dist/assets/app-DAuvKPP8.js +0 -4920
  357. package/dist/assets/config-Bx7pYsD9.js +0 -1
  358. package/dist/assets/config-DeoFTYzb.css +0 -1
  359. package/dist/assets/demo-CvKuBgy5.js +0 -1
  360. package/dist/assets/scene-asset-sync-DKkpjKBV.js +0 -19
  361. package/dist/assets/scene-asset-sync-DjJ_cJ2R.css +0 -1
  362. package/dist/assets/ticket-BPk2Ni95.js +0 -1
  363. package/dist/assets/workflow-jJRBR94Z.js +0 -179
  364. package/dist/demo/walk-then-stop.npz +0 -0
  365. package/mcp/ardy-prompts.mjs +0 -218
  366. package/src/ardy/auto-fix-panel.css +0 -108
  367. package/src/ardy/auto-physics.js +0 -1194
  368. package/src/ardy/client.js +0 -153
  369. package/src/ardy/convert.js +0 -313
  370. package/src/ardy/cskel27-neutral.js +0 -39
  371. package/src/ardy/cskel27.js +0 -77
  372. package/src/ardy/export.js +0 -165
  373. package/src/ardy/fix-collisions.js +0 -2257
  374. package/src/ardy/foot-lock.js +0 -230
  375. package/src/ardy/motion-calibration.js +0 -118
  376. package/src/ardy/motion-edit.js +0 -213
  377. package/src/ardy/motion-url.js +0 -55
  378. package/src/ardy/mp4-duration.js +0 -102
  379. package/src/ardy/npz.js +0 -595
  380. package/src/ardy/physics-panel.css +0 -21
  381. package/src/ardy/physics-panel.jsx +0 -89
  382. package/src/ardy/physics-refine.js +0 -111
  383. package/src/ardy/physics-review.js +0 -567
  384. package/src/ardy/physics-temporal.js +0 -54
  385. package/src/ardy/platform-fit-panel.css +0 -64
  386. package/src/ardy/platform-fit-panel.jsx +0 -41
  387. package/src/ardy/platform-fit.js +0 -326
  388. package/src/ardy/playback.js +0 -711
  389. package/src/ardy/pose-pin.js +0 -97
  390. package/src/ardy/prompt-clips.js +0 -30
  391. package/src/ardy/retime.js +0 -211
  392. package/src/ardy/root-drop.js +0 -369
  393. package/src/ardy/timeline-resize.js +0 -13
  394. package/src/ardy/to-cskel27.js +0 -225
  395. package/src/ardy/trim.js +0 -33
  396. package/src/ardy/waypoints.js +0 -369
  397. package/src/ardy-bridge-contract.js +0 -281
  398. package/src/domains/motion/motion-video-capture.js +0 -664
  399. package/src/i2v-motion-client.js +0 -77
  400. package/src/i2v-motion-studio.jsx +0 -180
  401. package/src/line-edit.js +0 -1348
  402. package/src/motion/generation.js +0 -105
  403. package/src/motion-readiness-ui.jsx +0 -67
  404. package/src/motion-readiness.js +0 -40
  405. package/src/motion-resources.js +0 -177
  406. package/src/motion-store.js +0 -65
  407. package/src/motion-trail.js +0 -601
  408. package/src/multimodel-ingest.js +0 -394
  409. package/src/panels/PromptBlocksPanel.jsx +0 -444
  410. package/src/panels/VideoCapturePanel.jsx +0 -181
  411. package/src/pose-extract/browser.js +0 -42
  412. package/src/pose-extract/detector.js +0 -100
  413. package/src/pose-extract/fit.js +0 -227
  414. package/src/pose-extract/image-frame.js +0 -51
  415. package/src/pose-extract/index.js +0 -58
  416. package/src/pose-extract/keyframes.js +0 -74
  417. package/src/pose-extract/landmarks.js +0 -162
  418. package/src/pose-extract/mirror.js +0 -153
  419. package/src/pose-extract/take.js +0 -131
  420. package/src/pose-extract/video-frames.js +0 -91
  421. package/src/take-recipe.js +0 -165
  422. package/src/trail-key-conflicts.js +0 -39
  423. package/src/trail-pick.js +0 -59
  424. package/src/use-i2v-capture-modal.js +0 -15
  425. package/tools/ardy/BRIDGE.md +0 -37
  426. package/tools/ardy/GVHMR-NPZ.md +0 -68
  427. package/tools/ardy/README.md +0 -124
  428. package/tools/ardy/__pycache__/cclay_gvhmr_worker.cpython-313.pyc +0 -0
  429. package/tools/ardy/artifacts.mjs +0 -34
  430. package/tools/ardy/bridge.mjs +0 -1732
  431. package/tools/ardy/bvh-cskel27.mjs +0 -1265
  432. package/tools/ardy/cclay_constrained_generate.py +0 -561
  433. package/tools/ardy/cclay_gvhmr_worker.py +0 -264
  434. package/tools/ardy/cclay_motion_edit.py +0 -510
  435. package/tools/ardy/cclay_sequence_generate.py +0 -705
  436. package/tools/ardy/cclay_worker.py +0 -304
  437. package/tools/ardy/dump-npz.py +0 -205
  438. package/tools/ardy/extract-rest.mjs +0 -299
  439. package/tools/ardy/extract.mjs +0 -507
  440. package/tools/ardy/footage.mjs +0 -467
  441. package/tools/ardy/gvhmr-floor.mjs +0 -102
  442. package/tools/ardy/gvhmr-to-cskel27.mjs +0 -21
  443. package/tools/ardy/gvhmr_fastpath.py +0 -168
  444. package/tools/ardy/gvhmr_trajectory.py +0 -240
  445. package/tools/ardy/merge-text-encoder.py +0 -160
  446. package/tools/ardy/mocap-metrics.mjs +0 -200
  447. package/tools/ardy/mocap-quality-gate.mjs +0 -110
  448. package/tools/ardy/motion-stabilize.mjs +0 -348
  449. package/tools/ardy/npz.mjs +0 -414
  450. package/tools/ardy/pose-to-npz.mjs +0 -106
  451. package/tools/ardy/prompt-limits.mjs +0 -5
  452. package/tools/ardy/run-edit-on-box.sh +0 -73
  453. package/tools/ardy/run-local.mjs +0 -233
  454. package/tools/ardy/run-on-box.sh +0 -593
  455. package/tools/ardy/run-sequence-on-box.sh +0 -177
  456. package/tools/ardy/runners/gvhmr-worker.mjs +0 -206
  457. package/tools/ardy/runners/index.mjs +0 -18
  458. package/tools/ardy/runners/local.mjs +0 -455
  459. package/tools/ardy/runners/proc.mjs +0 -125
  460. package/tools/ardy/runners/remote.mjs +0 -252
  461. package/tools/ardy/setup-local.mjs +0 -189
  462. package/tools/ardy/setup-text-encoder-on-box.sh +0 -93
  463. package/tools/ardy/setup-text-encoder.py +0 -306
  464. package/tools/ardy/smpl-cskel27.mjs +0 -178
  465. package/tools/ardy/visual-qa.mjs +0 -196
  466. package/tools/ardy/vq-car.mjs +0 -52
  467. package/tools/bench/EXP3.md +0 -61
  468. package/tools/bench/cclay_bench_extract_incam.py +0 -125
  469. package/tools/bench/cclay_bench_extract_obs.py +0 -204
  470. package/tools/bench/cclay_bench_runner.py +0 -42
  471. package/tools/bench/cube-contact.mjs +0 -162
  472. package/tools/bench/exp3.mjs +0 -152
  473. package/tools/bench/extract-bench-lib.mjs +0 -216
  474. package/tools/bench/extract-bench.mjs +0 -302
  475. package/tools/bench/fal-generate.mjs +0 -88
  476. package/tools/bench/fit/README.md +0 -189
  477. package/tools/bench/fit/camera.mjs +0 -59
  478. package/tools/bench/fit/contact.mjs +0 -419
  479. package/tools/bench/fit/footlock.mjs +0 -234
  480. package/tools/bench/fit/motion.mjs +0 -85
  481. package/tools/bench/fit/pin.mjs +0 -27
  482. package/tools/bench/fit/remote.mjs +0 -105
  483. package/tools/bench/fit-bench.mjs +0 -126
  484. package/tools/bench/fit-sanity.mjs +0 -45
  485. package/tools/bench/metrics.mjs +0 -313
  486. package/tools/bench/obs/depth.mjs +0 -258
  487. package/tools/bench/obs/extrinsics.mjs +0 -175
  488. package/tools/bench/obs/fit_mannequin_betas.py +0 -340
  489. package/tools/bench/obs/ground.mjs +0 -294
  490. package/tools/bench/obs/heading.mjs +0 -151
  491. package/tools/bench/obs/ladder.mjs +0 -555
  492. package/tools/bench/obs/mannequin-betas.json +0 -124
  493. package/tools/bench/obs/remote.mjs +0 -83
  494. package/tools/bench/obs/rest_joints.py +0 -52
  495. package/tools/bench/obs/ybot-targets.mjs +0 -49
  496. package/tools/bench/obs-bench.mjs +0 -520
  497. package/tools/bench/score.mjs +0 -343
  498. package/tools/bench/summarize.mjs +0 -86
  499. package/tools/demo-worker/README.md +0 -137
  500. package/tools/demo-worker/api-client.mjs +0 -233
  501. package/tools/demo-worker/generate.mjs +0 -301
  502. package/tools/demo-worker/index.mjs +0 -466
  503. package/tools/demo-worker/sign-core.mjs +0 -112
  504. package/tools/demo-worker/sign.mjs +0 -161
  505. package/tools/gt-render/browser.mjs +0 -182
  506. package/tools/gt-render/camera-math.mjs +0 -276
  507. package/tools/gt-render/page.mjs +0 -267
  508. package/tools/gt-render/render.mjs +0 -514
  509. package/tools/gt-render/scene-box.mjs +0 -31
  510. package/tools/gt-render/take-transform.mjs +0 -87
  511. package/tools/kimodo/compare-seam.mjs +0 -108
  512. package/tools/kimodo/constraints.mjs +0 -244
  513. package/tools/kimodo/edit.mjs +0 -259
  514. package/tools/kimodo/effector-constraints.mjs +0 -200
  515. package/tools/kimodo/generate.mjs +0 -646
  516. package/tools/kimodo/local-output.mjs +0 -265
  517. package/tools/kimodo/measure-pose.mjs +0 -65
  518. package/tools/kimodo/measure-preserve.mjs +0 -899
  519. package/tools/kimodo/measure-waypoints.mjs +0 -55
  520. package/tools/kimodo/mlx-generate.py +0 -111
  521. package/tools/kimodo/pose-constraints.mjs +0 -248
  522. package/tools/kimodo/preserve-mask.mjs +0 -543
  523. package/tools/kimodo/read-npz.mjs +0 -189
  524. package/tools/kimodo/run-edit-on-box.mjs +0 -155
  525. package/tools/kimodo/run-sequence-on-box.mjs +0 -178
  526. package/tools/kimodo/runner.mjs +0 -284
  527. package/tools/kimodo/seam-batch.mjs +0 -77
  528. package/tools/kimodo/setup-local.mjs +0 -30
  529. package/tools/kimodo/setup-on-box.sh +0 -339
  530. package/tools/kimodo/soma77-to-cskel27.mjs +0 -305
  531. package/tools/morphgs/assets/gen_truth.py +0 -39
  532. package/tools/morphgs/assets/mesh_ori_rig.txt +0 -27
  533. package/tools/morphgs/assets/playback-check.mjs +0 -30
  534. package/tools/morphgs/demo-gate.sh +0 -26
  535. package/tools/morphgs/fbx2morphgs.mjs +0 -68
  536. package/tools/morphgs/morphgs-to-cskel27.mjs +0 -105
  537. package/tools/morphgs/patches/preprocess_src-none-mode.patch +0 -76
  538. package/tools/morphgs/setup-on-cluster.sh +0 -126
  539. package/tools/projflow/driver.py +0 -1069
  540. package/tools/projflow/generate.mjs +0 -805
  541. package/tools/projflow/hml22-to-cskel27.mjs +0 -735
  542. package/tools/projflow/line-edit-job.mjs +0 -547
  543. package/tools/projflow/replay.mjs +0 -452
  544. package/tools/projflow/runner.mjs +0 -269
  545. package/tools/projflow/service.mjs +0 -742
  546. package/tools/track/DESIGN.md +0 -513
  547. package/tools/track/backfill-provenance.mjs +0 -116
  548. package/tools/track/budget.mjs +0 -8
  549. package/tools/track/check-rig.mjs +0 -209
  550. package/tools/track/diagnostics.schema.json +0 -60
  551. package/tools/track/export-rig.mjs +0 -256
  552. package/tools/track/fallback.mjs +0 -7
  553. package/tools/track/fk-parity-fixture.mjs +0 -161
  554. package/tools/track/gate.mjs +0 -349
  555. package/tools/track/masks.mjs +0 -318
  556. package/tools/track/metrics.mjs +0 -201
  557. package/tools/track/publish-obs.mjs +0 -108
  558. package/tools/track/py/check_env.py +0 -61
  559. package/tools/track/py/eval_lr.py +0 -229
  560. package/tools/track/py/lr_viterbi.py +0 -294
  561. package/tools/track/py/masks.py +0 -405
  562. package/tools/track/py/objective.py +0 -382
  563. package/tools/track/py/rig.py +0 -508
  564. package/tools/track/py/scene.py +0 -326
  565. package/tools/track/py/test_joint_indices.py +0 -123
  566. package/tools/track/py/test_lr_viterbi.py +0 -195
  567. package/tools/track/py/test_masks.py +0 -229
  568. package/tools/track/py/test_rig.py +0 -288
  569. package/tools/track/py/test_scene.py +0 -354
  570. package/tools/track/py/test_track.py +0 -328
  571. package/tools/track/py/track.py +0 -411
  572. package/tools/track/remote.mjs +0 -140
  573. package/tools/track/rig-dump.mjs +0 -227
  574. package/tools/track/run-box-tests.mjs +0 -14
  575. package/tools/track/run-box.mjs +0 -168
  576. package/tools/track/setup-box.sh +0 -59
  577. package/tools/track/study-2d.mjs +0 -728
  578. /package/src/{ardy → motion}/collision-blockers.js +0 -0
  579. /package/src/{ardy → motion}/ground.js +0 -0
  580. /package/src/{ardy → motion}/ik-drag.js +0 -0
  581. /package/src/{ardy → motion}/ik-key-json.js +0 -0
  582. /package/src/{ardy → motion}/ik.js +0 -0
  583. /package/src/{ardy → motion}/physics-surface.js +0 -0
  584. /package/src/{ardy → motion}/playback-clock.js +0 -0
  585. /package/src/{ardy → motion}/range-pin.js +0 -0
@@ -11,6 +11,7 @@ import { elementByPath } from "../studio-elements.js";
11
11
  import { saveAutoColor } from "../auto-color.js";
12
12
  import { trackFeature } from "../analytics.js";
13
13
  import { GUIDE_LABELS, nextGuideMode } from "../shot-guides.js";
14
+ import GhostsMenuGroup from "./GhostsMenuGroup.jsx";
14
15
  import "./viewport.css";
15
16
 
16
17
  // G1: the single mode+tool pill. Keys 1-5 and W/E/R are bound in App's
@@ -40,7 +41,6 @@ const ICON = {
40
41
  rotate: "M13.25 8A5.25 5.25 0 1 1 11.7 4.3 M13.25 2.5v2.75H10.5",
41
42
  scale: "M2.5 8.5v4a1 1 0 0 0 1 1h4 M8.5 2.5h5v5 M13.5 2.5 7.5 8.5",
42
43
  ik: "M2.5 13.5 6.5 9l3 2.2 4-7.7 M6.5 9h.01 M9.5 11.2h.01",
43
- trail: "M2 12.5c3 0 3-9 6-9s3 9 6 9",
44
44
  pin: "M8 14.5v-4 M5 2h6 M6.2 2v3.6L4.5 10.5h7L9.8 5.6V2",
45
45
  blocks: "M2 3.5h7.5v3.5H2z M6.5 9h7.5v3.5H6.5z",
46
46
  refine: "M10.5 2.5l3 3L6 13H3v-3z",
@@ -63,12 +63,10 @@ function RailIcon({ name, size = 16 }) {
63
63
 
64
64
  // The gizmo's snap increments (TRANSLATE_SNAP / ROTATE_SNAP in
65
65
  // src/scene-objects.js). They are fixed, so the value group names them.
66
- const SNAP_MOVE = "5cm";
67
- const SNAP_TURN = "5°";
66
+ const SNAP_MOVE = "5cm", SNAP_TURN = "5°";
68
67
 
69
68
  // Editor lens range: shotsDomain.changeLens and the FOV slider take 14-90°.
70
- const FOV_MIN = 14;
71
- const FOV_MAX = 90;
69
+ const FOV_MIN = 14, FOV_MAX = 90;
72
70
 
73
71
  // "+ Add › Character" stands the new body one metre along X per existing
74
72
  // character, inside the same stage clamp the Content drag applies.
@@ -117,15 +115,14 @@ function MenuItem({ checked, role = "menuitemradio", className = "", children, .
117
115
  export default function ViewportToolbar() {
118
116
  const {
119
117
  workflowMode, selectWorkflowMode, poseRefusal, gizmoMode, setGizmoMode, snapEnabled,
120
- setSnapEnabled, preset, applyPreset, cameraPresetId, i2vMotionCameraLocked,
118
+ setSnapEnabled, preset, applyPreset, cameraPresetId,
121
119
  runStudioAction, shotAspectKey, fovDeg, shotsDomain, shot, shots, activeShot,
122
120
  setNonce, workspaceLayout, viewMenuTriggerRef, viewMenuOpen,
123
121
  setViewMenuOpen, viewLooksActive, gridView, setGridView, guideMode,
124
122
  autoColor, setAutoColor, isCharacterSelection, partColoursChoice, embedMode,
125
123
  agentCollapsed, addSceneObject, spawnCharacter, characters, flySpeed,
126
- ikEditTool, setIkEditTool, showTrails, setShowTrails, motion, setRangePinPartPick,
127
- trailFalloffS, setTrailFalloffS, lineEditMode, exitLineEditMode, enterRefineMode,
128
- refineDisabledReason, previsMode, sculptView, requestSculptView,
124
+ ikEditTool, setIkEditTool, motion, setRangePinPartPick,
125
+ previsMode, sculptView, requestSculptView,
129
126
  } = useStudioShell();
130
127
  const menu = useOverlayMenu();
131
128
 
@@ -136,7 +133,6 @@ export default function ViewportToolbar() {
136
133
  setAutoColor(next);
137
134
  };
138
135
 
139
- const refineReason = lineEditMode ? null : refineDisabledReason();
140
136
  const tools = {
141
137
  scene: [
142
138
  { key: "W", id: "move", name: ko("Move", "이동"), active: gizmoMode === "move", pick: () => setGizmoMode("move") },
@@ -145,11 +141,7 @@ export default function ViewportToolbar() {
145
141
  ],
146
142
  pose: [
147
143
  { key: "W", id: "ik", name: ko("Pose fix (IK parts)", "포즈 수정 (IK 파츠)"), active: ikEditTool === "ik", pick: () => setIkEditTool("ik") },
148
- {
149
- key: "E", id: "trail", name: ko("Path fix (motion trail)", "경로 수정 (궤적선)"), active: ikEditTool === "trail",
150
- refused: showTrails ? null : ko("Turn Trails on in Show to edit the motion path", "경로를 수정하려면 표시에서 궤적선을 켜세요"),
151
- pick: () => setIkEditTool("trail"),
152
- },
144
+
153
145
  {
154
146
  key: "R", id: "pin", name: ko("Pin (range pin)", "고정 (범위 고정)"), active: ikEditTool === "pin",
155
147
  refused: motion ? null : ko("Pinning needs a motion take", "고정하려면 모션 테이크가 필요해요"),
@@ -160,16 +152,8 @@ export default function ViewportToolbar() {
160
152
  { key: "W", id: "move", name: ko("Move camera", "카메라 이동"), active: gizmoMode === "move", pick: () => setGizmoMode("move") },
161
153
  { key: "E", id: "rotate", name: ko("Rotate camera", "카메라 회전"), active: gizmoMode === "rotate", pick: () => setGizmoMode("rotate") },
162
154
  ],
163
- motion: [
164
- {
165
- key: "W", id: "blocks", name: ko("Blocks (select and move prompt blocks)", "블록 (프롬프트 블록 선택·이동)"), active: !lineEditMode,
166
- pick: () => { if (lineEditMode) exitLineEditMode(); },
167
- },
168
- {
169
- key: "E", id: "refine", name: ko("Refine (edit the path line)", "다듬기 (경로선 편집)"), active: lineEditMode,
170
- refused: refineReason, pick: () => { if (!lineEditMode) enterRefineMode(); },
171
- },
172
- ],
155
+ // Motion is compiled by the agent (motion.compile); the department has no tools of its own.
156
+ motion: [],
173
157
  // Sculpt mode's W/E/R swing the turntable camera to a reference view.
174
158
  sculpt: [
175
159
  { key: "W", id: "front", name: ko("Front view", "정면 보기"), active: sculptView?.view === "front", pick: () => requestSculptView("front") },
@@ -200,33 +184,6 @@ export default function ViewportToolbar() {
200
184
  <span className="vp-value-part"><RailIcon name="grid" size={14} />{SNAP_MOVE}</span>
201
185
  <span className="vp-value-part"><RailIcon name="angle" size={14} />{SNAP_TURN}</span>
202
186
  </button>
203
- ) : workflowMode === "pose" ? (
204
- <div className="vp-menu-wrap" data-vp-menu="influence">
205
- <button
206
- type="button"
207
- className="vp-value"
208
- aria-haspopup="dialog"
209
- aria-expanded={menu.open === "influence"}
210
- title={ko("Influence range — how far an edit blends into nearby frames", "영향 범위 — 수정이 주변 프레임에 섞이는 길이")}
211
- onClick={() => menu.toggle("influence")}
212
- >
213
- {trimNumber(trailFalloffS)}s
214
- </button>
215
- {menu.open === "influence" && (
216
- <div className="vp-menu vp-slider-popover" role="dialog" aria-label={ko("Influence range", "영향 범위")}>
217
- <input
218
- type="range"
219
- min={0.1}
220
- max={2}
221
- step={0.1}
222
- value={trailFalloffS}
223
- aria-label={ko("Influence range", "영향 범위")}
224
- onChange={(event) => setTrailFalloffS(Number(event.target.value))}
225
- />
226
- <output>{trimNumber(trailFalloffS)}s</output>
227
- </div>
228
- )}
229
- </div>
230
187
  ) : workflowMode === "camera" ? (
231
188
  <>
232
189
  <div className="vp-menu-wrap" data-vp-menu="lens">
@@ -248,7 +205,6 @@ export default function ViewportToolbar() {
248
205
  key={mm}
249
206
  data-lens={mm}
250
207
  checked={shot.focalMm === mm}
251
- disabled={i2vMotionCameraLocked}
252
208
  onClick={() => { shotsDomain.changeLens(fov); menu.close(); }}
253
209
  >
254
210
  {mm}mm
@@ -262,7 +218,6 @@ export default function ViewportToolbar() {
262
218
  max={FOV_MAX}
263
219
  step="1"
264
220
  value={fovDeg}
265
- disabled={i2vMotionCameraLocked}
266
221
  onChange={(event) => shotsDomain.changeLens(Number(event.target.value))}
267
222
  />
268
223
  <output>{Math.round(fovDeg)}°</output>
@@ -460,7 +415,6 @@ export default function ViewportToolbar() {
460
415
  <select
461
416
  aria-label={ko("Camera preset", "카메라 프리셋")}
462
417
  value={cameraPresetId ?? ""}
463
- disabled={i2vMotionCameraLocked}
464
418
  onChange={(event) => {
465
419
  const id = event.target.value;
466
420
  if (!id) { runStudioAction("stage.setFilmback", { cameraPresetId: null }); return; }
@@ -577,21 +531,7 @@ export default function ViewportToolbar() {
577
531
  {ko("Composition guides", "구도 가이드")}
578
532
  <small>{ko(GUIDE_LABELS[guideMode].en, GUIDE_LABELS[guideMode].ko)}</small>
579
533
  </button>
580
- <button
581
- type="button"
582
- role="menuitemcheckbox"
583
- className={"view-menu-item trails-toggle" + (showTrails ? " active" : "")}
584
- aria-checked={showTrails}
585
- aria-pressed={showTrails}
586
- title={ko("Motion trails while posing", "포즈 편집 중 궤적선")}
587
- onClick={() => {
588
- if (showTrails && ikEditTool === "trail") setIkEditTool("ik");
589
- setShowTrails(!showTrails);
590
- }}
591
- >
592
- <span className="view-menu-mark" aria-hidden="true">{showTrails ? "✓" : ""}</span>
593
- {ko("Trails", "궤적선")}
594
- </button>
534
+ <GhostsMenuGroup />
595
535
  {/* Part colours repaint a BODY, so the section only exists
596
536
  while a character is selected (R2). */}
597
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);
@@ -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;
@@ -25,7 +25,9 @@ export function CaptureRig({ apiRef, camRef, width = CAPTURE_W, height = CAPTURE
25
25
  useEffect(() => {
26
26
  // Each attempt owns its target independently of the live output size.
27
27
  // Resizing the editor cannot dispose an in-flight export's resources.
28
- function createExportCapture({ width, height }) {
28
+ // `camera` makes the camera of each render: a clone of the shot camera unless a caller
29
+ // (renderView) brings its own; the shot camera itself is never moved.
30
+ function createExportCapture({ width, height }, camera = () => camRef.current?.clone()) {
29
31
  const target = new THREE.WebGLRenderTarget(width, height, {
30
32
  colorSpace: THREE.SRGBColorSpace,
31
33
  samples: 4,
@@ -35,9 +37,8 @@ export function CaptureRig({ apiRef, camRef, width = CAPTURE_W, height = CAPTURE
35
37
  scene,
36
38
  dispose: () => target.dispose(),
37
39
  render() {
38
- const source = camRef.current;
39
- if (!source) return null;
40
- const cam = source.clone();
40
+ const cam = camera();
41
+ if (!cam) return null;
41
42
  // the transform gizmo is UI: it never reaches an exported frame
42
43
  cam.layers.disable(GIZMO_LAYER);
43
44
  // QA hook: the layer mask the export camera actually renders
@@ -53,13 +54,27 @@ export function CaptureRig({ apiRef, camRef, width = CAPTURE_W, height = CAPTURE
53
54
  // exported frame wants the opposite: the horizon IS the vanishing
54
55
  // point, and without it the floor has no far edge to read depth
55
56
  // against. Push the falloff back for this draw only, then restore
56
- // it so the viewport is untouched.
57
+ // it so the viewport is untouched. Haze (stage.lighting.fog, set by
58
+ // StageAtmosphere) is part of the look, so it brings its own range.
57
59
  const fog = scene.fog;
58
60
  const fogNear = fog?.near;
59
61
  const fogFar = fog?.far;
62
+ const look = scene.userData.stageCapture;
60
63
  if (fog) {
61
- fog.near = CAPTURE_FOG_NEAR;
62
- fog.far = CAPTURE_FOG_FAR;
64
+ fog.near = look?.fog?.near ?? CAPTURE_FOG_NEAR;
65
+ fog.far = look?.fog?.far ?? CAPTURE_FOG_FAR;
66
+ }
67
+ // three tone-maps only the canvas, never a render target, so the
68
+ // viewport's exposure reaches an export as light: every light, and
69
+ // the environment light, is scaled by it for this draw and put back after.
70
+ const scaled = [], environmentIntensity = scene.environmentIntensity, backgroundIntensity = scene.backgroundIntensity, fogColor = fog?.color.clone();
71
+ if (look && look.exposure !== 1) scene.traverse((node) => { if (node.isLight) scaled.push([node, node.intensity]); });
72
+ for (const [light, intensity] of scaled) light.intensity = intensity * look.exposure;
73
+ if (look && look.exposure !== 1) scene.environmentIntensity = environmentIntensity * look.exposure;
74
+ // An HDR backdrop (stage.lighting.hdrBackground) is light too, and so is the horizon the deck fades into.
75
+ if (look?.backdrop && look.exposure !== 1) {
76
+ scene.backgroundIntensity = backgroundIntensity * look.exposure;
77
+ fog?.color.multiplyScalar(look.exposure);
63
78
  }
64
79
  try {
65
80
  gl.setRenderTarget(target);
@@ -71,12 +86,31 @@ export function CaptureRig({ apiRef, camRef, width = CAPTURE_W, height = CAPTURE
71
86
  fog.near = fogNear;
72
87
  fog.far = fogFar;
73
88
  }
89
+ for (const [light, intensity] of scaled) light.intensity = intensity;
90
+ scene.environmentIntensity = environmentIntensity;
91
+ scene.backgroundIntensity = backgroundIntensity;
92
+ if (fogColor) fog.color.copy(fogColor);
74
93
  }
75
94
  return buffer;
76
95
  },
77
96
  };
78
97
  }
79
- const api = { ...createExportCapture({ width, height }), createExportCapture };
98
+ // verify_result's own views (src/motion3/views.js): one read-back, rows bottom-up, from a
99
+ // camera at eye with quaternion [x, y, z, w] and a vertical fov, on a target of its own size.
100
+ function renderView({ eye, quaternion, fovDeg, output }) {
101
+ const own = createExportCapture(output, () => {
102
+ const source = camRef.current;
103
+ if (!source) return null;
104
+ const cam = source.clone();
105
+ cam.clearViewOffset();
106
+ cam.position.set(...eye);
107
+ cam.quaternion.set(...quaternion);
108
+ cam.fov = fovDeg;
109
+ return cam;
110
+ });
111
+ try { return own.render(); } finally { own.dispose(); }
112
+ }
113
+ const api = { ...createExportCapture({ width, height }), createExportCapture, renderView };
80
114
  apiRef.current = api;
81
115
  if (width === MCP_CAPTURE_W && height === MCP_CAPTURE_H) {
82
116
  window.__cozyclayMcpCaptureReady = true;