cozyclay 1.9.0 → 2.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 (286) hide show
  1. package/CHANGELOG.md +171 -0
  2. package/bin/agent/agent-routes.mjs +74 -70
  3. package/bin/agent/agent-runner.mjs +10 -3
  4. package/bin/agent/motion-runtime.mjs +32 -260
  5. package/bin/agent/providers.mjs +46 -3
  6. package/bin/agent/session-store.mjs +41 -5
  7. package/bin/agent/studio-prompt.mjs +1 -1
  8. package/bin/agent/studio-tools.mjs +48 -11
  9. package/bin/cozyclay.mjs +26 -8
  10. package/bin/live/cli.mjs +22 -3
  11. package/bin/mcp-runtime.mjs +35 -20
  12. package/bin/telemetry-state.mjs +5 -2
  13. package/bin/update-check.mjs +15 -0
  14. package/dist/app/index.html +6 -6
  15. package/dist/assets/analytics-MVZOEW8O.js +1 -0
  16. package/dist/assets/app-C1sdVbg4.css +1 -0
  17. package/dist/assets/app-CA55tcI3.js +4876 -0
  18. package/dist/assets/{demo-B-eg1CT8.js → demo-ByeYp-dY.js} +1 -1
  19. package/dist/assets/{first-shot-handoff-CGgnvNu8.js → first-shot-handoff-DgT28ZiV.js} +1 -1
  20. package/dist/assets/{landing-IbRp3FnQ.js → landing-BaXkpFip.js} +1 -1
  21. package/dist/assets/shot-prompt-CbqWcWYi.css +1 -0
  22. package/dist/assets/shot-prompt-Yrt99wZx.js +17 -0
  23. package/dist/assets/{ticket-BgIzOBOf.js → ticket-BcmsnHn5.js} +1 -1
  24. package/dist/assets/workflow-DRdwoDBT.css +1 -0
  25. package/dist/assets/workflow-dNPGY9xz.js +179 -0
  26. package/dist/cozyclay-package.json +1 -1
  27. package/dist/fonts/IBM-Plex-Sans-OFL.txt +92 -0
  28. package/dist/fonts/JetBrains-Mono-OFL.txt +93 -0
  29. package/dist/fonts/README.md +13 -9
  30. package/dist/fonts/ibm-plex-sans-400-latin.woff2 +0 -0
  31. package/dist/fonts/ibm-plex-sans-500-latin.woff2 +0 -0
  32. package/dist/fonts/ibm-plex-sans-600-latin.woff2 +0 -0
  33. package/dist/fonts/jetbrains-mono-400-latin.woff2 +0 -0
  34. package/dist/fonts/jetbrains-mono-500-latin.woff2 +0 -0
  35. package/dist/index.html +7 -7
  36. package/dist/privacy/index.html +13 -8
  37. package/dist/sitemap.xml +6 -6
  38. package/dist/workflow/index.html +5 -5
  39. package/mcp/LIVE-PROTOCOL.md +1 -1
  40. package/mcp/live-hub.mjs +35 -93
  41. package/mcp/mesh-file.mjs +48 -0
  42. package/mcp/server.mjs +6 -77
  43. package/mcp/tool-handlers.mjs +224 -377
  44. package/package.json +2 -1
  45. package/src/App.jsx +1273 -9075
  46. package/src/analytics.js +393 -9
  47. package/src/app-context.js +211 -0
  48. package/src/app-stage.jsx +25 -24
  49. package/src/ardy/auto-fix-panel.css +108 -0
  50. package/src/ardy/collision-blockers.js +9 -3
  51. package/src/ardy/fix-collisions.js +10 -66
  52. package/src/ardy/ground.js +4 -4
  53. package/src/ardy/ik-drag.js +101 -0
  54. package/src/ardy/ik-key-json.js +43 -0
  55. package/src/ardy/ik.js +122 -76
  56. package/src/ardy/physics-panel.css +2 -0
  57. package/src/ardy/physics-panel.jsx +17 -5
  58. package/src/ardy/platform-fit-panel.css +64 -0
  59. package/src/ardy/platform-fit-panel.jsx +40 -0
  60. package/src/ardy/platform-fit.js +326 -0
  61. package/src/ardy/playback.js +166 -20
  62. package/src/ardy/range-pin.js +299 -0
  63. package/src/ardy/timeline-coordinates.js +26 -0
  64. package/src/ardy/timeline.css +1199 -0
  65. package/src/ardy/timeline.jsx +149 -41
  66. package/src/ardy/waypoints.js +2 -2
  67. package/src/asset-pane.css +462 -0
  68. package/src/asset-pane.jsx +461 -232
  69. package/src/command-bus.js +349 -0
  70. package/src/commands/ai.js +31 -0
  71. package/src/commands/cast.js +140 -0
  72. package/src/commands/elements/character.js +13 -0
  73. package/src/commands/elements/motion.js +14 -0
  74. package/src/commands/elements/object.js +22 -0
  75. package/src/commands/elements/scene.js +16 -0
  76. package/src/commands/elements/shot.js +9 -0
  77. package/src/commands/elements/stage.js +11 -0
  78. package/src/commands/elements.js +155 -0
  79. package/src/commands/export.js +20 -0
  80. package/src/commands/index.js +40 -0
  81. package/src/commands/motion.js +231 -0
  82. package/src/commands/objects.js +174 -0
  83. package/src/commands/project.js +53 -0
  84. package/src/commands/scene.js +81 -0
  85. package/src/commands/shared.js +19 -0
  86. package/src/commands/shot.js +103 -0
  87. package/src/commands/stage.js +17 -0
  88. package/src/commands/view.js +42 -0
  89. package/src/document-store.js +144 -0
  90. package/src/domains/cast.js +1007 -0
  91. package/src/domains/motion.js +3219 -0
  92. package/src/domains/objects.js +932 -0
  93. package/src/domains/scenes.js +817 -0
  94. package/src/domains/shots.js +404 -0
  95. package/src/domains/stage.js +93 -0
  96. package/src/dualview.jsx +113 -57
  97. package/src/facing-marks.js +3 -0
  98. package/src/first-success-guide.jsx +14 -14
  99. package/src/grid-view.js +18 -5
  100. package/src/hierarchy-model.js +24 -16
  101. package/src/hierarchy-panel.css +386 -0
  102. package/src/hierarchy-panel.jsx +150 -21
  103. package/src/{fal-motion-client.js → i2v-motion-client.js} +13 -13
  104. package/src/i2v-motion-studio.jsx +180 -0
  105. package/src/ik-camera.js +3 -0
  106. package/src/main.jsx +6 -0
  107. package/src/motion/generation.js +105 -0
  108. package/src/motion-readiness-ui.jsx +4 -4
  109. package/src/motion-readiness.js +11 -0
  110. package/src/motion-trail.js +366 -9
  111. package/src/object-gizmo.jsx +7 -1
  112. package/src/otio.js +2 -1
  113. package/src/panels/CameraPanel.jsx +60 -0
  114. package/src/panels/CharacterTransformPanel.jsx +48 -0
  115. package/src/panels/EnvironmentPanel.jsx +40 -0
  116. package/src/panels/Foldout.jsx +32 -0
  117. package/src/panels/LightPanel.jsx +24 -0
  118. package/src/panels/ObjectTransformPanel.jsx +554 -0
  119. package/src/panels/PosePanel.jsx +97 -0
  120. package/src/panels/ProjectPanel.jsx +33 -0
  121. package/src/panels/PromptBlocksPanel.jsx +442 -0
  122. package/src/panels/PropsPanel.jsx +70 -0
  123. package/src/panels/ReferenceImageField.jsx +91 -0
  124. package/src/panels/RigControlPanel.jsx +78 -0
  125. package/src/panels/RigPanel.jsx +37 -0
  126. package/src/panels/SubjectBox.jsx +47 -0
  127. package/src/panels/SubjectsPanel.jsx +39 -0
  128. package/src/panels/VideoCapturePanel.jsx +180 -0
  129. package/src/panels/details.css +1171 -0
  130. package/src/panels/motion.css +197 -0
  131. package/src/panels/pose.css +39 -0
  132. package/src/planview.jsx +60 -31
  133. package/src/posestudio.jsx +59 -4
  134. package/src/project-browser.css +1073 -0
  135. package/src/project-browser.jsx +284 -123
  136. package/src/range-pin-object-transform.js +19 -0
  137. package/src/range-pin-panel.css +518 -0
  138. package/src/range-pin-panel.jsx +344 -0
  139. package/src/result-modal.jsx +5 -5
  140. package/src/room.jsx +79 -51
  141. package/src/scene-objects.js +37 -1
  142. package/src/scenes.js +5 -0
  143. package/src/semantic-edit.js +2 -0
  144. package/src/settings-menu.jsx +39 -105
  145. package/src/shell/BottomDock.jsx +450 -0
  146. package/src/shell/DetailsSlot.jsx +513 -0
  147. package/src/shell/LibrarySlot.jsx +86 -0
  148. package/src/shell/MenuBar.jsx +601 -0
  149. package/src/shell/OutlinerSlot.jsx +50 -0
  150. package/src/shell/PreferencesDialog.jsx +538 -0
  151. package/src/shell/PreferencesSlot.jsx +40 -0
  152. package/src/shell/StatusBar.jsx +125 -0
  153. package/src/shell/StudioShell.jsx +92 -0
  154. package/src/shell/TopBar.jsx +129 -0
  155. package/src/shell/ViewportToolbar.jsx +656 -0
  156. package/src/shell/agent-glass.css +296 -0
  157. package/src/shell/dock.css +93 -0
  158. package/src/shell/glass-regions.css +985 -0
  159. package/src/shell/glass.css +687 -0
  160. package/src/shell/log-store.js +52 -0
  161. package/src/shell/mode.css +9 -0
  162. package/src/shell/preferences.css +651 -0
  163. package/src/shell/shell.css +282 -0
  164. package/src/shell/studio-shell-context.js +19 -0
  165. package/src/shell/topbar.css +435 -0
  166. package/src/shell/viewport.css +451 -0
  167. package/src/store/authored-intent.js +22 -0
  168. package/src/store/runtime-adapters.js +92 -0
  169. package/src/store/scene-stage.js +21 -0
  170. package/src/store/use-document-store.js +14 -0
  171. package/src/studio-actions.js +210 -0
  172. package/src/studio-agent-commands.js +41 -271
  173. package/src/studio-agent-context.js +39 -10
  174. package/src/studio-agent-motion.js +122 -373
  175. package/src/studio-agent-protocol.js +67 -31
  176. package/src/studio-app-binding.js +379 -0
  177. package/src/studio-contact-sheet.js +73 -0
  178. package/src/studio-elements.js +58 -51
  179. package/src/styles/themes.css +200 -0
  180. package/src/styles/tokens.css +69 -0
  181. package/src/styles.css +460 -1742
  182. package/src/theme.js +44 -0
  183. package/src/timeline-extent.js +16 -0
  184. package/src/trail-key-conflicts.js +39 -0
  185. package/src/trail-pick.js +59 -0
  186. package/src/ui.jsx +8 -8
  187. package/src/use-case-question.jsx +66 -0
  188. package/src/workflow/AgentPanel.jsx +82 -69
  189. package/src/workflow/agent-client.js +12 -2
  190. package/src/workflow/agent-panel.css +34 -32
  191. package/src/workflow/cozy-scene-node.css +2 -0
  192. package/src/workflow/workflow.css +2 -0
  193. package/tools/ardy/__pycache__/cclay_gvhmr_worker.cpython-313.pyc +0 -0
  194. package/tools/ardy/bridge.mjs +164 -146
  195. package/tools/ardy/visual-qa.mjs +5 -5
  196. package/tools/bench/EXP3.md +61 -0
  197. package/tools/bench/cclay_bench_extract_incam.py +125 -0
  198. package/tools/bench/cclay_bench_extract_obs.py +204 -0
  199. package/tools/bench/cclay_bench_runner.py +42 -0
  200. package/tools/bench/cube-contact.mjs +162 -0
  201. package/tools/bench/exp3.mjs +152 -0
  202. package/tools/bench/extract-bench-lib.mjs +216 -0
  203. package/tools/bench/extract-bench.mjs +302 -0
  204. package/tools/bench/fal-generate.mjs +88 -0
  205. package/tools/bench/fit/README.md +189 -0
  206. package/tools/bench/fit/camera.mjs +59 -0
  207. package/tools/bench/fit/contact.mjs +419 -0
  208. package/tools/bench/fit/footlock.mjs +234 -0
  209. package/tools/bench/fit/motion.mjs +85 -0
  210. package/tools/bench/fit/pin.mjs +27 -0
  211. package/tools/bench/fit/remote.mjs +105 -0
  212. package/tools/bench/fit-bench.mjs +126 -0
  213. package/tools/bench/fit-sanity.mjs +45 -0
  214. package/tools/bench/metrics.mjs +313 -0
  215. package/tools/bench/obs/depth.mjs +258 -0
  216. package/tools/bench/obs/extrinsics.mjs +175 -0
  217. package/tools/bench/obs/fit_mannequin_betas.py +340 -0
  218. package/tools/bench/obs/ground.mjs +294 -0
  219. package/tools/bench/obs/heading.mjs +151 -0
  220. package/tools/bench/obs/ladder.mjs +555 -0
  221. package/tools/bench/obs/mannequin-betas.json +124 -0
  222. package/tools/bench/obs/remote.mjs +83 -0
  223. package/tools/bench/obs/rest_joints.py +52 -0
  224. package/tools/bench/obs/ybot-targets.mjs +49 -0
  225. package/tools/bench/obs-bench.mjs +520 -0
  226. package/tools/bench/score.mjs +343 -0
  227. package/tools/bench/summarize.mjs +86 -0
  228. package/tools/dev/pages/privacy.html +13 -8
  229. package/tools/gt-render/browser.mjs +159 -0
  230. package/tools/gt-render/camera-math.mjs +276 -0
  231. package/tools/gt-render/page.mjs +267 -0
  232. package/tools/gt-render/render.mjs +514 -0
  233. package/tools/gt-render/scene-box.mjs +31 -0
  234. package/tools/gt-render/take-transform.mjs +87 -0
  235. package/tools/morphgs/assets/gen_truth.py +39 -0
  236. package/tools/morphgs/assets/mesh_ori_rig.txt +27 -0
  237. package/tools/morphgs/assets/playback-check.mjs +30 -0
  238. package/tools/morphgs/demo-gate.sh +26 -0
  239. package/tools/morphgs/fbx2morphgs.mjs +68 -0
  240. package/tools/morphgs/morphgs-to-cskel27.mjs +105 -0
  241. package/tools/morphgs/patches/preprocess_src-none-mode.patch +76 -0
  242. package/tools/morphgs/setup-on-cluster.sh +126 -0
  243. package/tools/qa/css-rule-usage.mjs +283 -0
  244. package/tools/qa/studio-control-count.mjs +70 -32
  245. package/tools/run-tests.mjs +134 -12
  246. package/tools/track/DESIGN.md +513 -0
  247. package/tools/track/backfill-provenance.mjs +116 -0
  248. package/tools/track/budget.mjs +8 -0
  249. package/tools/track/check-rig.mjs +209 -0
  250. package/tools/track/diagnostics.schema.json +60 -0
  251. package/tools/track/export-rig.mjs +256 -0
  252. package/tools/track/fallback.mjs +7 -0
  253. package/tools/track/fk-parity-fixture.mjs +161 -0
  254. package/tools/track/gate.mjs +349 -0
  255. package/tools/track/masks.mjs +318 -0
  256. package/tools/track/metrics.mjs +201 -0
  257. package/tools/track/publish-obs.mjs +108 -0
  258. package/tools/track/py/check_env.py +61 -0
  259. package/tools/track/py/eval_lr.py +229 -0
  260. package/tools/track/py/lr_viterbi.py +294 -0
  261. package/tools/track/py/masks.py +405 -0
  262. package/tools/track/py/objective.py +382 -0
  263. package/tools/track/py/rig.py +508 -0
  264. package/tools/track/py/scene.py +326 -0
  265. package/tools/track/py/test_joint_indices.py +123 -0
  266. package/tools/track/py/test_lr_viterbi.py +195 -0
  267. package/tools/track/py/test_masks.py +229 -0
  268. package/tools/track/py/test_rig.py +288 -0
  269. package/tools/track/py/test_scene.py +354 -0
  270. package/tools/track/py/test_track.py +328 -0
  271. package/tools/track/py/track.py +411 -0
  272. package/tools/track/remote.mjs +140 -0
  273. package/tools/track/rig-dump.mjs +227 -0
  274. package/tools/track/run-box-tests.mjs +14 -0
  275. package/tools/track/run-box.mjs +168 -0
  276. package/tools/track/setup-box.sh +59 -0
  277. package/tools/track/study-2d.mjs +728 -0
  278. package/dist/assets/analytics-B1hnH66c.js +0 -1
  279. package/dist/assets/app-BWusbqgO.js +0 -4861
  280. package/dist/assets/app-qKDo4PBX.css +0 -1
  281. package/dist/assets/shot-prompt-CHUtw6af.js +0 -17
  282. package/dist/assets/shot-prompt-C_g2BHVc.css +0 -1
  283. package/dist/assets/workflow-CVwzMhz2.js +0 -179
  284. package/dist/assets/workflow-DsudxKHF.css +0 -1
  285. package/src/fal-motion-studio.jsx +0 -180
  286. package/src/scene-history.js +0 -129
@@ -0,0 +1,282 @@
1
+ @layer shell {
2
+ /* #570 floating-glass frame. The viewport fills the window; the top bar,
3
+ both columns, the dock and the status strip float over it. Region
4
+ controls keep their own styles; glass.css restyles their surfaces. */
5
+ .app:not([data-embed-mode]) {
6
+ --shell-gap: var(--float-gap, 12px);
7
+ --shell-left: var(--shell-left-width, var(--shell-left-default));
8
+ --shell-right: var(--shell-right-width, var(--shell-right-default));
9
+ --shell-left-default: 260px;
10
+ --shell-right-default: 300px;
11
+ --shell-dock: var(--shell-dock-height, var(--shell-dock-default));
12
+ /* The sequencer's fixed grid: 48px head + 28px camera bar (always
13
+ reserved, see glass-regions.css) + 24px ruler + the lane rows
14
+ (22 + 66 + 22 + 66 = 176) = 276px. The dock is exactly that tall, so
15
+ every lane is on screen, the body never scrolls vertically, and no
16
+ empty band sits under the last lane. */
17
+ --shell-dock-default: 276px;
18
+ /* The shot card never takes more than 36 % of the dock, so the
19
+ Sequencer keeps room on narrow windows. */
20
+ --shell-camera: min(var(--shell-camera-width, 340px), calc((100vw - var(--shell-center-left) - var(--shell-center-right)) * .36));
21
+ /* No standing status row (StatusBar.jsx): live status floats instead. */
22
+ --shell-status-h: 0px;
23
+ --shell-dock-bottom: var(--shell-gap);
24
+ --shell-center-left: calc(var(--shell-left) + var(--shell-gap) * 2);
25
+ --shell-center-right: calc(var(--shell-right) + var(--shell-gap) * 2);
26
+ --shell-center-bottom: calc(var(--shell-dock) + var(--shell-status-h) + var(--shell-dock-bottom) + var(--shell-gap));
27
+ /* The shot card's picture. The slot is the room the card leaves between
28
+ its 48px head and the 84px of ratios + footer under it; the picture is
29
+ the shot aspect fitted into that slot and centred in it, so the stage
30
+ shows exactly the frame, with no letterbox bars above or below.
31
+ Offsets are from the dock's right edge and from its bottom edge
32
+ (above the status row). --shot-aspect comes from App. */
33
+ --shot-slot-w: calc(var(--shell-camera) - 28px);
34
+ --shot-slot-h: max(60px, calc(var(--shell-dock) - 132px));
35
+ --shot-pic-w: min(var(--shot-slot-w), calc(var(--shot-slot-h) * var(--shot-aspect, 1.7778)));
36
+ --shot-pic-h: calc(var(--shot-pic-w) / var(--shot-aspect, 1.7778));
37
+ --shot-pic-right: calc(14px + (var(--shot-slot-w) - var(--shot-pic-w)) / 2);
38
+ --shot-pic-bottom: calc(84px + (var(--shot-slot-h) - var(--shot-pic-h)) / 2);
39
+ position: relative;
40
+ display: block;
41
+ height: 100vh;
42
+ min-height: 0;
43
+ overflow: hidden;
44
+ background: var(--surface-0);
45
+ }
46
+
47
+ @media (max-width: 1440px) {
48
+ .app:not([data-embed-mode]) { --shell-left-default: 236px; --shell-right-default: 272px; }
49
+ }
50
+ @media (max-width: 1180px) {
51
+ .app:not([data-embed-mode]) { --shell-left-default: 212px; --shell-right-default: 248px; }
52
+ }
53
+
54
+ .app:not([data-embed-mode]) > .main { display: contents; }
55
+ .app:not([data-embed-mode]) .workspace {
56
+ position: absolute;
57
+ inset: 0;
58
+ display: block;
59
+ min-width: 0;
60
+ min-height: 0;
61
+ }
62
+
63
+ /* The stage is full-bleed: panels are glass over it. */
64
+ .app:not([data-embed-mode]) .viewport {
65
+ position: absolute;
66
+ inset: 0;
67
+ width: auto;
68
+ height: auto;
69
+ min-height: 0;
70
+ padding: 0;
71
+ }
72
+ /* No entrance animation on the full-bleed stage: stageIn starts at
73
+ scale(.985), and the canvas measures its box at mount, so the drawing
74
+ buffer stayed ~1.5% short of the layout box and the scene was stretched
75
+ (soft edges, misaligned pixels). */
76
+ .app:not([data-embed-mode]) .stage { border: 0; animation: none; }
77
+
78
+ .app:not([data-embed-mode]) .topbar {
79
+ position: absolute;
80
+ z-index: 20;
81
+ top: var(--shell-gap);
82
+ left: var(--shell-center-left);
83
+ right: var(--shell-center-right);
84
+ height: 40px;
85
+ padding: 0;
86
+ border: 0;
87
+ background: none;
88
+ }
89
+
90
+ .app:not([data-embed-mode]) .studio-left-column,
91
+ .app:not([data-embed-mode]) .studio-right-column {
92
+ position: absolute;
93
+ z-index: 12;
94
+ top: var(--shell-gap);
95
+ bottom: var(--shell-gap);
96
+ display: flex;
97
+ flex-direction: column;
98
+ min-width: 0;
99
+ min-height: 0;
100
+ overflow: hidden;
101
+ }
102
+ /* The left column stops above the dock, which runs under it to the
103
+ window's left edge. */
104
+ .app:not([data-embed-mode]) .studio-left-column {
105
+ left: var(--shell-gap);
106
+ bottom: var(--shell-center-bottom);
107
+ width: var(--shell-left);
108
+ }
109
+ .app:not([data-embed-mode]) .studio-right-column {
110
+ right: var(--shell-gap);
111
+ width: var(--shell-right);
112
+ }
113
+ .studio-left-column > .panel,
114
+ .studio-right-column > .panel {
115
+ width: 100%;
116
+ min-width: 0;
117
+ max-width: none;
118
+ min-height: 0;
119
+ max-height: none;
120
+ padding: 0;
121
+ border: 0;
122
+ overflow: hidden;
123
+ background: none;
124
+ }
125
+ .studio-left-column > .hierarchy-left {
126
+ flex: 1 1 auto;
127
+ }
128
+ .studio-right-column > .inspector-sidebar {
129
+ flex: 1 1 auto;
130
+ display: flex;
131
+ flex-direction: column;
132
+ }
133
+ .studio-right-column .inspector-pane {
134
+ flex: 1 1 auto;
135
+ min-height: 0;
136
+ display: flex;
137
+ flex-direction: column;
138
+ }
139
+ .studio-right-column .studio-agent-inspector {
140
+ position: relative;
141
+ flex: 0 0 auto;
142
+ display: flex;
143
+ flex-direction: column;
144
+ height: var(--shell-agent-height, 380px);
145
+ min-height: 0;
146
+ }
147
+ .studio-right-column .studio-agent-inspector[hidden] { display: none; }
148
+
149
+ .app:not([data-embed-mode]) .studio-dock-slot {
150
+ position: absolute;
151
+ z-index: 12;
152
+ left: var(--shell-gap);
153
+ right: var(--shell-center-right);
154
+ bottom: var(--shell-dock-bottom);
155
+ height: calc(var(--shell-dock) + var(--shell-status-h));
156
+ min-width: 0;
157
+ min-height: 0;
158
+ }
159
+ /* The status line is the dock's own last row (see .brandbar below). */
160
+ .app:not([data-embed-mode]) .bottom-window {
161
+ height: calc(100% - var(--shell-status-h));
162
+ border: 0;
163
+ }
164
+ .app:not([data-embed-mode]) .bottom-timeline {
165
+ min-width: 0;
166
+ overflow: auto;
167
+ }
168
+ .app:not([data-embed-mode]) .timeline:not(.collapsed) {
169
+ flex: 1 1 auto;
170
+ height: 0;
171
+ min-height: 0;
172
+ max-height: none;
173
+ }
174
+
175
+ /* Live status floats in the viewport window's bottom-left corner, a
176
+ gutter in from its edges, like the rails. */
177
+ .app:not([data-embed-mode]) .brandbar {
178
+ position: absolute;
179
+ z-index: 13;
180
+ left: calc(var(--shell-center-left) + var(--shell-gap));
181
+ bottom: calc(var(--shell-center-bottom) + var(--shell-gap));
182
+ max-width: calc(100% - var(--shell-center-left) - var(--shell-center-right) - var(--shell-gap) * 2);
183
+ height: 32px;
184
+ border: 0;
185
+ }
186
+ .app:not([data-embed-mode]) .brandbar::before { display: none; }
187
+
188
+ /* Resize hit areas sit in the 12px gutters between floating panels. */
189
+ .app:not([data-embed-mode]) .shell-splitter {
190
+ position: absolute;
191
+ z-index: 14;
192
+ margin: 0;
193
+ background: none;
194
+ touch-action: none;
195
+ }
196
+ .app:not([data-embed-mode]) .shell-left-splitter {
197
+ top: var(--shell-gap);
198
+ bottom: var(--shell-center-bottom);
199
+ left: calc(var(--shell-gap) + var(--shell-left));
200
+ width: var(--shell-gap);
201
+ cursor: col-resize;
202
+ }
203
+ .app:not([data-embed-mode]) .shell-sidebar-splitter {
204
+ top: var(--shell-gap);
205
+ bottom: var(--shell-gap);
206
+ right: calc(var(--shell-gap) + var(--shell-right));
207
+ width: var(--shell-gap);
208
+ cursor: col-resize;
209
+ }
210
+ .app:not([data-embed-mode]) .shell-agent-splitter {
211
+ position: absolute;
212
+ top: calc(var(--shell-gap) * -1);
213
+ left: 0;
214
+ right: 0;
215
+ height: 12px;
216
+ cursor: row-resize;
217
+ }
218
+ .app:not([data-embed-mode]) .shell-camera-splitter {
219
+ top: 0;
220
+ bottom: 0;
221
+ right: calc(var(--shell-camera) - 6px);
222
+ width: 12px;
223
+ cursor: col-resize;
224
+ }
225
+ /* The stage canvas is full-bleed (the shot preview is drawn into it under
226
+ the dock's card), but the scene is only meant to be SEEN in two places:
227
+ the open viewport between the panels and that preview card. Everywhere
228
+ else — the gutters, the window margins, the band between the top pills,
229
+ and under the panels' glass — a raw slice of floor and horizon read as a
230
+ crack in the UI (and tinted the dock grey next to the columns). This
231
+ frame paints all of that in the shell surface, with the viewport window
232
+ (20px round, as the panels) and the shot card's frame (10px round) cut
233
+ out, so the stage sits in a window of the UI instead of leaking around it.
234
+ The Assets tab has no shot card, so its hole closes. */
235
+ .app:not([data-embed-mode]) .workspace::after {
236
+ content: "";
237
+ position: absolute;
238
+ inset: 0;
239
+ z-index: 6;
240
+ pointer-events: none;
241
+ /* The panel tone, not the window tone: the dock and the columns blur
242
+ this frame through their glass, and on the darker --surface-0 they
243
+ went a step darker than designed. */
244
+ background: var(--shell-frame, var(--surface-panel));
245
+ --shell-view-top: calc(var(--shell-gap) * 2 + 40px);
246
+ --shell-cut-w: calc(100% - var(--shell-center-left) - var(--shell-center-right));
247
+ --shell-view-h: max(0px, calc(100% - var(--shell-view-top) - var(--shell-center-bottom)));
248
+ --shell-shot-w: var(--shot-pic-w);
249
+ --shell-shot-h: var(--shot-pic-h);
250
+ /* An SVG without a viewBox keeps rx in CSS pixels at any mask-size, so
251
+ the cut-outs stay 20px-round however the panels are resized. rx is the
252
+ panels' --float-radius (themes.css); a data URI cannot read the token. */
253
+ --shell-round-cut: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Crect width='100%25' height='100%25' rx='20'/%3E%3C/svg%3E");
254
+ --shell-shot-cut: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Crect width='100%25' height='100%25' rx='10'/%3E%3C/svg%3E");
255
+ -webkit-mask-image: linear-gradient(#000 0 0), var(--shell-round-cut), var(--shell-shot-cut);
256
+ mask-image: linear-gradient(#000 0 0), var(--shell-round-cut), var(--shell-shot-cut);
257
+ -webkit-mask-size: 100% 100%, var(--shell-cut-w) var(--shell-view-h), var(--shell-shot-w) var(--shell-shot-h);
258
+ mask-size: 100% 100%, var(--shell-cut-w) var(--shell-view-h), var(--shell-shot-w) var(--shell-shot-h);
259
+ /* The shot cut-out is placed from the bottom-right edges: a percentage
260
+ in mask-position is relative to (box - mask size), so calc(100% - ...)
261
+ would land it hundreds of px off. Same spot as .vp-shot-preview. */
262
+ -webkit-mask-position: 0 0, var(--shell-center-left) var(--shell-view-top), right calc(var(--shell-center-right) + var(--shot-pic-right)) bottom calc(var(--shell-dock-bottom) + var(--shell-status-h) + var(--shot-pic-bottom));
263
+ mask-position: 0 0, var(--shell-center-left) var(--shell-view-top), right calc(var(--shell-center-right) + var(--shot-pic-right)) bottom calc(var(--shell-dock-bottom) + var(--shell-status-h) + var(--shot-pic-bottom));
264
+ -webkit-mask-repeat: no-repeat;
265
+ mask-repeat: no-repeat;
266
+ -webkit-mask-composite: xor;
267
+ mask-composite: exclude;
268
+ }
269
+ .app[data-dock-tab="assets"]:not([data-embed-mode]) .workspace::after,
270
+ .app[data-shot-look]:not([data-embed-mode]) .workspace::after { --shell-shot-w: 0px; --shell-shot-h: 0px; }
271
+ .app[data-dock-tab="assets"]:not([data-embed-mode]) .vp-shot-preview,
272
+ .app[data-dock-tab="assets"]:not([data-embed-mode]) .shell-camera-splitter { display: none; }
273
+
274
+ .preferences-slot { display: contents; }
275
+
276
+ /* Embeds keep the viewport-only / compact transport layout. */
277
+ .app[data-embed-mode] .studio-right-column,
278
+ .app[data-embed-mode] .studio-left-column,
279
+ .app[data-embed-mode] .shell-splitter { display: none; }
280
+ .app[data-embed-mode] .studio-dock-slot { position: relative; min-width: 0; min-height: 0; }
281
+ .app[data-embed-mode="playview"] .studio-dock-slot { display: none; }
282
+ }
@@ -0,0 +1,19 @@
1
+ import { createContext, useContext } from "react";
2
+
3
+ // App owns the document/domain wiring. Region components consume this one
4
+ // render snapshot and call its named actions; they never acquire domain state
5
+ // or call authored-state writers themselves. Ref cells keep their identity.
6
+ //
7
+ // In addition to the extracted controls, the public region contract includes:
8
+ // - spawnCharacter/addSceneObject/beginAssetDrag/runStudioAction, mode/IK tools;
9
+ // - saveStatus, all exporters, exportStatus.cancel/retry, setToast and
10
+ // subscribeToasts (the Content Log can tee notifications without replacing UI);
11
+ // - generation, blocks/refine, takes/recipe and preserve strength;
12
+ // - agentOpen/toggleAgent, preferencesOpen/setPreferencesOpen;
13
+ // - statusText/setStatusText, previewRanges/setPreviewRanges, liveHubStatus,
14
+ // flySpeed (the navigation multiplier, not metres per second).
15
+ export const StudioShellContext = createContext(null);
16
+
17
+ export function useStudioShell() {
18
+ return useContext(StudioShellContext);
19
+ }