cozyclay 2.0.0 → 2.1.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.
- package/CHANGELOG.md +112 -0
- package/README.md +17 -2
- package/THIRD_PARTY_NOTICES.md +8 -0
- package/bin/agent/agent-routes.mjs +219 -38
- package/bin/agent/agent-runner.mjs +98 -4
- package/bin/agent/codex-client.mjs +2 -1
- package/bin/agent/fal-contract.mjs +0 -17
- package/bin/agent/h3-preservation.mjs +6 -8
- package/bin/agent/provider-keys.mjs +1 -1
- package/bin/agent/providers.mjs +124 -3
- package/bin/agent/script-tool.mjs +74 -0
- package/bin/agent/session-store.mjs +5 -5
- package/bin/agent/studio-prompt.mjs +2 -1
- package/bin/agent/studio-rebase.mjs +314 -0
- package/bin/agent/studio-tools.mjs +21 -14
- package/bin/agent/supervisor.mjs +311 -0
- package/bin/agent/video-adapters.mjs +0 -7
- package/bin/codex-auth.mjs +6 -5
- package/bin/cozyclay.mjs +12 -3
- package/bin/live/cli.mjs +2 -3
- package/bin/live/client.mjs +1 -1
- package/bin/live/studio.mjs +5 -2
- package/bin/mcp-runtime.mjs +12 -2
- package/bin/telemetry-state.mjs +3 -3
- package/dist/app/index.html +6 -6
- package/dist/assets/analytics-B41FmPYI.js +1 -0
- package/dist/assets/app-Do-Og5Pu.css +1 -0
- package/dist/assets/app-DwP-tl2x.js +4920 -0
- package/dist/assets/{demo-ByeYp-dY.js → demo-Dt0qZfS7.js} +1 -1
- package/dist/assets/{first-shot-handoff-DgT28ZiV.js → first-shot-handoff-BlT33CGf.js} +1 -1
- package/dist/assets/{landing-BaXkpFip.js → landing-BSesrCpL.js} +1 -1
- package/dist/assets/scene-asset-sync-BCWDJB1d.js +19 -0
- package/dist/assets/{shot-prompt-CbqWcWYi.css → scene-asset-sync-DjJ_cJ2R.css} +1 -1
- package/dist/assets/{ticket-BcmsnHn5.js → ticket-jqMhqL88.js} +1 -1
- package/dist/assets/workflow-Br-K7Srs.js +179 -0
- package/dist/cozyclay-package.json +1 -1
- package/dist/index.html +328 -222
- package/dist/sitemap.xml +5 -5
- package/dist/workflow/index.html +4 -4
- package/mcp/LIVE-PROTOCOL.md +23 -2
- package/mcp/README.md +37 -2
- package/mcp/ardy-prompts.mjs +1 -1
- package/mcp/image-file.mjs +132 -0
- package/mcp/live-hub.mjs +2 -2
- package/mcp/package.json +1 -0
- package/mcp/runtime/package-lock.json +7 -0
- package/mcp/runtime/package.json +1 -0
- package/mcp/server.mjs +0 -6
- package/mcp/tool-handlers.mjs +289 -87
- package/package.json +11 -2
- package/src/App.jsx +801 -259
- package/src/agent-image-client.js +94 -0
- package/src/analytics.js +47 -3
- package/src/app-stage.jsx +129 -2745
- package/src/ardy/auto-physics.js +6 -16
- package/src/ardy/collision-blockers.js +3 -7
- package/src/ardy/fix-collisions.js +5 -35
- package/src/ardy/ik-drag.js +86 -5
- package/src/ardy/ik-key-json.js +3 -1
- package/src/ardy/ik.js +15 -13
- package/src/ardy/motion-calibration.js +1 -1
- package/src/ardy/npz.js +0 -8
- package/src/ardy/physics-panel.jsx +3 -2
- package/src/ardy/physics-review.js +3 -2
- package/src/ardy/physics-support.js +1 -1
- package/src/ardy/physics-surface.js +1 -1
- package/src/ardy/platform-fit-panel.jsx +2 -1
- package/src/ardy/playback.js +1 -5
- package/src/ardy/range-pin.js +2 -2
- package/src/ardy/root-drop.js +0 -1
- package/src/ardy/timeline.css +196 -3
- package/src/ardy/timeline.jsx +117 -29
- package/src/ardy/to-cskel27.js +0 -2
- package/src/ardy/waypoints.js +1 -4
- package/src/ardy-bridge-contract.js +281 -0
- package/src/asset-pane.jsx +19 -9
- package/src/auto-color.js +1 -1
- package/src/burn-in.js +1 -1
- package/src/camera-block.js +1 -1
- package/src/camera-follow.js +75 -32
- package/src/camera-move.js +0 -6
- package/src/camera-tutorial.jsx +43 -24
- package/src/character-kind.js +79 -0
- package/src/command-bus.js +76 -17
- package/src/commands/cast.js +31 -7
- package/src/commands/elements/object.js +1 -1
- package/src/commands/elements/shot.js +1 -1
- package/src/commands/elements.js +1 -1
- package/src/commands/export.js +3 -3
- package/src/commands/motion.js +2 -2
- package/src/commands/objects.js +105 -10
- package/src/commands/project.js +16 -3
- package/src/commands/sculpt-images.js +53 -0
- package/src/commands/shot.js +88 -10
- package/src/commands/view.js +10 -4
- package/src/coplanar-depth.js +216 -0
- package/src/cuts.js +7 -6
- package/src/domains/cast.js +60 -43
- package/src/domains/motion/motion-intent-codec.js +50 -0
- package/src/domains/motion/motion-range-pin-rules.js +23 -0
- package/src/domains/motion/motion-video-capture.js +664 -0
- package/src/domains/motion.js +253 -742
- package/src/domains/objects.js +106 -5
- package/src/domains/scenes.js +89 -32
- package/src/domains/shots.js +33 -7
- package/src/error-boundary.jsx +1 -1
- package/src/execution-telemetry.js +5 -5
- package/src/facing-marks.js +14 -1
- package/src/first-success-guide.jsx +35 -4
- package/src/gizmo-claim.js +3 -1
- package/src/grid-floor.jsx +1 -4
- package/src/hierarchy-model.js +48 -35
- package/src/hierarchy-panel.css +1 -0
- package/src/hierarchy-panel.jsx +54 -102
- package/src/history.js +0 -2
- package/src/i2v-motion-client.js +1 -4
- package/src/ime.js +6 -0
- package/src/keyframe-pack.js +15 -6
- package/src/line-edit.js +4 -4
- package/src/live-control.js +6 -6
- package/src/matte-editor.js +2 -8
- package/src/matte.js +0 -19
- package/src/mesh-graph-clone.js +16 -2
- package/src/mesh-sniff.js +0 -1
- package/src/monotone-cubic.js +40 -0
- package/src/motion/generation.js +1 -1
- package/src/motion-store.js +4 -4
- package/src/motion-trail.js +5 -11
- package/src/multimodel-ingest.js +1 -3
- package/src/object-catalog.jsx +7 -5
- package/src/object-gizmo.jsx +45 -31
- package/src/object-path.js +310 -67
- package/src/object-travel.js +224 -0
- package/src/otio.js +8 -3
- package/src/panels/CharacterTransformPanel.jsx +24 -6
- package/src/panels/ObjectTransformPanel.jsx +4 -3
- package/src/panels/PoseImagePanel.jsx +205 -0
- package/src/panels/PromptBlocksPanel.jsx +3 -1
- package/src/panels/ProxyFigurePanel.jsx +56 -0
- package/src/panels/ReferenceImageField.jsx +1 -1
- package/src/panels/RigControlPanel.jsx +24 -3
- package/src/panels/RigPanel.jsx +2 -1
- package/src/panels/SculptPanel.jsx +405 -0
- package/src/panels/SubjectBox.jsx +1 -1
- package/src/panels/SubjectsPanel.jsx +0 -2
- package/src/panels/VideoCapturePanel.jsx +2 -1
- package/src/panels/pose-image.css +42 -0
- package/src/panels/pose.css +3 -0
- package/src/panels/sculpt.css +162 -0
- package/src/plan-diagram.js +184 -0
- package/src/planview.jsx +127 -80
- package/src/playground.js +3 -5
- package/src/pose-fade.js +77 -0
- package/src/pose-gizmo.css +23 -0
- package/src/pose-gizmo.js +96 -0
- package/src/posestudio.jsx +134 -83
- package/src/project-browser.css +53 -0
- package/src/project-browser.jsx +52 -3
- package/src/project.js +55 -24
- package/src/props.jsx +177 -36
- package/src/proxy-figure.jsx +69 -0
- package/src/range-pin-panel.jsx +0 -1
- package/src/receipt-findings.js +20 -0
- package/src/render-passes.js +0 -1
- package/src/resource-status.jsx +1 -1
- package/src/root-path.js +48 -0
- package/src/route-owner.js +52 -0
- package/src/scene-asset-cache.js +1 -2
- package/src/scene-assets.js +12 -4
- package/src/scene-fbx.js +1 -1
- package/src/scene-mesh-cache.js +0 -1
- package/src/scene-objects.js +319 -19
- package/src/scenes.js +62 -17
- package/src/sculpt-blueprint.js +65 -0
- package/src/sculpt-compare.js +384 -0
- package/src/sculpt-geometry.js +141 -0
- package/src/sculpt-mode.js +168 -0
- package/src/sculpt-recipe.js +385 -0
- package/src/sculpt-run.js +351 -0
- package/src/sculpt-stage.jsx +221 -0
- package/src/settings-menu.jsx +1 -1
- package/src/shell/BoardSlot.jsx +341 -0
- package/src/shell/BottomDock.jsx +58 -14
- package/src/shell/DetailsSlot.jsx +26 -6
- package/src/shell/MenuBar.jsx +78 -6
- package/src/shell/OutlinerSlot.jsx +3 -1
- package/src/shell/TopBar.jsx +17 -3
- package/src/shell/ViewportToolbar.jsx +18 -3
- package/src/shell/dock.css +239 -0
- package/src/shell/glass-regions.css +3 -2
- package/src/shell/log-store.js +4 -4
- package/src/shell/mode.css +20 -0
- package/src/shell/studio-shell-context.js +4 -1
- package/src/shot-authoring.js +69 -6
- package/src/stable-items.js +1 -1
- package/src/stage-attach-frames.js +169 -0
- package/src/stage-canvas-rigs.jsx +402 -0
- package/src/stage-capture.jsx +216 -0
- package/src/stage-characters.jsx +302 -0
- package/src/stage-editor-gizmos.jsx +1229 -0
- package/src/stage-labels-ko.js +204 -0
- package/src/stage-startup-defaults.js +182 -0
- package/src/starter-scenes.js +1 -1
- package/src/storyboard.js +24 -5
- package/src/studio-actions.js +42 -9
- package/src/studio-agent-commands.js +186 -23
- package/src/studio-agent-context.js +11 -9
- package/src/studio-agent-motion.js +2 -1
- package/src/studio-agent-protocol.js +56 -23
- package/src/studio-app-binding.js +52 -23
- package/src/studio-contact-sheet.js +3 -3
- package/src/studio-elements.js +11 -2
- package/src/studio-geometry-facts.js +114 -0
- package/src/styles.css +111 -10
- package/src/theme.js +1 -1
- package/src/timeline-fps.js +13 -0
- package/src/ui-scrub.js +4 -4
- package/src/ui.jsx +6 -4
- package/src/use-asset-shelf.js +60 -0
- package/src/use-camera-tutorial.js +50 -0
- package/src/use-embed-bridge.js +12 -0
- package/src/use-first-success-prompt.js +7 -0
- package/src/use-i2v-capture-modal.js +15 -0
- package/src/use-sculpt-mode.js +95 -0
- package/src/workflow/AgentPanel.jsx +110 -20
- package/src/workflow/WorkflowBuilder.jsx +1 -1
- package/src/workflow/agent-client.js +113 -45
- package/src/workflow/agent-panel.css +35 -0
- package/src/workflow/attachment-image.js +1 -1
- package/src/workflow/canvas-commands.js +3 -3
- package/src/workflow/cozy-scene-node.js +3 -3
- package/src/workflow/local-workflow.js +2 -2
- package/src/workflow/motion-input.js +3 -3
- package/src/workflow/node-schema.js +1 -1
- package/src/workflow/scene-asset-sync.js +2 -9
- package/src/workflow/shot-prompt-node.js +1 -1
- package/src/workflow/video-contract.js +1 -1
- package/src/workflow/workflow-resources.js +0 -8
- package/src/workflow-send.js +87 -0
- package/tools/ardy/__pycache__/cclay_gvhmr_worker.cpython-313.pyc +0 -0
- package/tools/check-eslint.mjs +57 -0
- package/tools/check-knip.mjs +60 -0
- package/tools/check-loc.mjs +54 -0
- package/tools/demo-worker/api-client.mjs +7 -13
- package/tools/demo-worker/generate.mjs +2 -4
- package/tools/eslint-baseline.json +23 -0
- package/tools/kimodo/effector-constraints.mjs +4 -4
- package/tools/kimodo/generate.mjs +1 -1
- package/tools/knip-baseline.json +331 -0
- package/tools/loc-baseline.json +126 -0
- package/tools/process-supervisor.mjs +1 -1
- package/tools/projflow/replay.mjs +4 -4
- package/tools/projflow/runner.mjs +3 -3
- package/tools/qa/studio-control-count.mjs +2 -0
- package/tools/run-tests.mjs +96 -7
- package/dist/assets/analytics-MVZOEW8O.js +0 -1
- package/dist/assets/app-C1sdVbg4.css +0 -1
- package/dist/assets/app-CA55tcI3.js +0 -4876
- package/dist/assets/shot-prompt-Yrt99wZx.js +0 -17
- package/dist/assets/workflow-dNPGY9xz.js +0 -179
package/src/shell/MenuBar.jsx
CHANGED
|
@@ -170,9 +170,10 @@ const MENUS = [
|
|
|
170
170
|
export default function MenuBar({ preferences }) {
|
|
171
171
|
const shell = useStudioShell();
|
|
172
172
|
const {
|
|
173
|
-
runStudioAction, projectSaveState, recState, exportMenuTriggerRef, exportMenuOpen,
|
|
173
|
+
runStudioAction, projectSaveState, previsMode, recState, exportMenuTriggerRef, exportMenuOpen,
|
|
174
174
|
exportShotIdRef, setExportMenuOpen, shots, exportKeyframePacks, hasCameraKeys, motion,
|
|
175
175
|
exportRenderPasses, exportDepthVideo, exportStoryboard, downloadOtioCutList,
|
|
176
|
+
exportContactSheet, exportPanelPacks, exportAnimatic,
|
|
176
177
|
castDomain, preferencesOpen, setPreferencesOpen, agentOpen, toggleAgent,
|
|
177
178
|
setToast, embedMode, setProjectStartupOpen, setProjectBrowserOpen,
|
|
178
179
|
} = shell;
|
|
@@ -187,7 +188,13 @@ export default function MenuBar({ preferences }) {
|
|
|
187
188
|
const exportOpenRef = useRef(exportMenuOpen);
|
|
188
189
|
exportOpenRef.current = exportMenuOpen;
|
|
189
190
|
const recording = recState === "recording";
|
|
190
|
-
|
|
191
|
+
// A storyboard project exports panels (its stills), never clip packs or shot video.
|
|
192
|
+
const storyboard = previsMode === "storyboard";
|
|
193
|
+
const panelCount = storyboard ? shots.filter((entry) => entry.kind === "still").length : 0;
|
|
194
|
+
const noPanels = ko("Add a panel first — storyboard exports describe panels", "패널을 먼저 추가하세요 — 스토리보드 내보내기는 패널을 담습니다");
|
|
195
|
+
const packReason = storyboard
|
|
196
|
+
? panelCount ? "" : noPanels
|
|
197
|
+
: shots.length ? "" : ko("Add a shot first — a pack describes one cut", "샷을 먼저 추가하세요 — 팩은 컷 하나를 설명합니다");
|
|
191
198
|
|
|
192
199
|
// The camera tutorial's handoff opens Export directly; its flyout lives in File.
|
|
193
200
|
useEffect(() => {
|
|
@@ -223,7 +230,7 @@ export default function MenuBar({ preferences }) {
|
|
|
223
230
|
|
|
224
231
|
// ⌘S saves and ⌘E exports the keyframe pack (G7), from anywhere in the studio.
|
|
225
232
|
const keys = useRef(null);
|
|
226
|
-
keys.current = { runStudioAction, projectSaveState, recording, packReason, exportKeyframePacks, setToast };
|
|
233
|
+
keys.current = { runStudioAction, projectSaveState, recording, packReason, exportKeyframePacks: storyboard ? exportPanelPacks : exportKeyframePacks, setToast };
|
|
227
234
|
useEffect(() => {
|
|
228
235
|
if (embedMode) return undefined;
|
|
229
236
|
const onKeyDown = (event) => {
|
|
@@ -277,6 +284,42 @@ export default function MenuBar({ preferences }) {
|
|
|
277
284
|
closeMenus(false);
|
|
278
285
|
onSelect();
|
|
279
286
|
};
|
|
287
|
+
const panelItem = (testId, label, title, onSelect, shortcut = null) => (
|
|
288
|
+
<button
|
|
289
|
+
type="button"
|
|
290
|
+
role="menuitem"
|
|
291
|
+
className="menubar-item"
|
|
292
|
+
data-testid={testId}
|
|
293
|
+
disabled={!panelCount || recording}
|
|
294
|
+
data-disabled-reason={panelCount ? undefined : "no-panels"}
|
|
295
|
+
title={panelCount ? title : noPanels}
|
|
296
|
+
onClick={() => {
|
|
297
|
+
const shotId = exportShotIdRef.current;
|
|
298
|
+
closeMenus(false);
|
|
299
|
+
onSelect(shotId);
|
|
300
|
+
}}
|
|
301
|
+
>
|
|
302
|
+
<span className="menubar-item-label">{label}</span>
|
|
303
|
+
{shortcut && <Shortcut keys={shortcut} />}
|
|
304
|
+
</button>
|
|
305
|
+
);
|
|
306
|
+
const storyboardExports = (
|
|
307
|
+
<>
|
|
308
|
+
{panelItem("export-contact-sheet", ko("Contact sheet (PNG)", "콘택트 시트 (PNG)"),
|
|
309
|
+
ko("Every panel with its caption on one sheet", "모든 패널과 캡션을 한 장에"), () => void exportContactSheet())}
|
|
310
|
+
{panelItem("export-panel-pack", ko("Panel pack (zip)", "패널 팩 (zip)"),
|
|
311
|
+
ko("The selected panel's frame, stylized image, camera and prompt as one zip", "선택한 패널의 프레임·스타일 이미지·카메라·프롬프트를 zip 하나로"),
|
|
312
|
+
(shotId) => void exportPanelPacks(false, shotId), `${MOD}E`)}
|
|
313
|
+
{panelItem("export-all-panels", ko("All panels (zip)", "모든 패널 (zip)"),
|
|
314
|
+
ko("One zip with a folder per panel", "패널마다 폴더 하나씩 담은 zip"), () => void exportPanelPacks(true, null))}
|
|
315
|
+
{panelItem("export-animatic", ko("Animatic (mp4)", "애니매틱 (mp4)"),
|
|
316
|
+
ko("Every panel held for its hold, as one MP4", "모든 패널을 홀드만큼 이어 MP4 하나로"), () => void exportAnimatic())}
|
|
317
|
+
{panelItem("export-otio", ko("Cut list (OTIO)", "컷 목록 (OTIO)"),
|
|
318
|
+
ko("Download the OTIO cut list; each panel is a clip as long as its hold", "OTIO 컷 목록 다운로드 — 패널마다 홀드 길이의 클립"), () => downloadOtioCutList())}
|
|
319
|
+
{panelItem("export-render-passes", ko("Depth + normal (PNG)", "뎄스 + 노멀 (PNG)"),
|
|
320
|
+
ko("Depth and normal conditioning plates of the current framing", "현재 프레이밍의 뎄스·노멀 컨디션 플레이트"), () => exportRenderPasses())}
|
|
321
|
+
</>
|
|
322
|
+
);
|
|
280
323
|
|
|
281
324
|
const content = {
|
|
282
325
|
file: (
|
|
@@ -303,6 +346,17 @@ export default function MenuBar({ preferences }) {
|
|
|
303
346
|
<button type="button" role="menuitem" className="menubar-item" onClick={item(() => runStudioAction("project.saveAs"))}>
|
|
304
347
|
<span className="menubar-item-label">{ko("Save As…", "다른 이름으로 저장…")}</span>
|
|
305
348
|
</button>
|
|
349
|
+
{previsMode === "storyboard" && (
|
|
350
|
+
<button
|
|
351
|
+
type="button"
|
|
352
|
+
role="menuitem"
|
|
353
|
+
className="menubar-item"
|
|
354
|
+
data-testid="export-animation-project"
|
|
355
|
+
onClick={item(() => runStudioAction("project.exportAsAnimation"))}
|
|
356
|
+
>
|
|
357
|
+
<span className="menubar-item-label">{ko("Export as Animation project…", "애니메이션 프로젝트로 내보내기…")}</span>
|
|
358
|
+
</button>
|
|
359
|
+
)}
|
|
306
360
|
<hr className="menubar-separator" />
|
|
307
361
|
{/* One Export menu for every delivery this studio makes (#193,
|
|
308
362
|
R4). The keyframe pack leads because it is the pack an AI video
|
|
@@ -330,6 +384,7 @@ export default function MenuBar({ preferences }) {
|
|
|
330
384
|
</button>
|
|
331
385
|
{exportMenuOpen && (
|
|
332
386
|
<ExportFlyout anchorRef={exportMenuTriggerRef} autoFocus={flyoutFocus} onAutoFocused={focusedFlyout}>
|
|
387
|
+
{storyboard ? storyboardExports : (<>
|
|
333
388
|
<button
|
|
334
389
|
type="button"
|
|
335
390
|
role="menuitem"
|
|
@@ -357,14 +412,30 @@ export default function MenuBar({ preferences }) {
|
|
|
357
412
|
className="menubar-item"
|
|
358
413
|
data-testid="export-video"
|
|
359
414
|
disabled={recording}
|
|
360
|
-
title={ko("Render the
|
|
415
|
+
title={ko("Render the whole timeline to one MP4 — every shot back to back, camera and motion, no editor chrome", "타임라인 전체를 MP4 하나로 — 모든 샷을 이어서, 카메라·모션만, 편집 UI 제외")}
|
|
416
|
+
onClick={() => {
|
|
417
|
+
closeMenus(false);
|
|
418
|
+
void runStudioAction("export.shotVideo", { scope: "timeline" });
|
|
419
|
+
}}
|
|
420
|
+
>
|
|
421
|
+
<span className="menubar-item-label">{ko("Video — whole timeline (mp4)", "영상 — 타임라인 전체 (mp4)")}</span>
|
|
422
|
+
</button>
|
|
423
|
+
)}
|
|
424
|
+
{shots.length > 0 && (
|
|
425
|
+
<button
|
|
426
|
+
type="button"
|
|
427
|
+
role="menuitem"
|
|
428
|
+
className="menubar-item"
|
|
429
|
+
data-testid="export-video-shot"
|
|
430
|
+
disabled={recording}
|
|
431
|
+
title={ko("Render one shot to its own MP4 — the shot you opened the menu from, or the one under the playhead", "샷 하나만 MP4로 — 메뉴를 연 샷, 아니면 재생 위치의 샷")}
|
|
361
432
|
onClick={() => {
|
|
362
433
|
const shotId = exportShotIdRef.current;
|
|
363
434
|
closeMenus(false);
|
|
364
|
-
void runStudioAction("export.shotVideo", shotId ? { shotId } : {});
|
|
435
|
+
void runStudioAction("export.shotVideo", shotId ? { shotId, scope: "shot" } : { scope: "shot" });
|
|
365
436
|
}}
|
|
366
437
|
>
|
|
367
|
-
<span className="menubar-item-label">{ko("Video (mp4)", "영상 (mp4)")}</span>
|
|
438
|
+
<span className="menubar-item-label">{ko("Video — this shot only (mp4)", "영상 — 이 샷만 (mp4)")}</span>
|
|
368
439
|
</button>
|
|
369
440
|
)}
|
|
370
441
|
<button
|
|
@@ -427,6 +498,7 @@ export default function MenuBar({ preferences }) {
|
|
|
427
498
|
: ko("Add a shot to export video or OTIO", "영상·OTIO를 내보내려면 샷을 추가하세요")}
|
|
428
499
|
</p>
|
|
429
500
|
)}
|
|
501
|
+
</>)}
|
|
430
502
|
</ExportFlyout>
|
|
431
503
|
)}
|
|
432
504
|
</div>
|
|
@@ -9,7 +9,7 @@ export default function OutlinerSlot() {
|
|
|
9
9
|
ikMode, rowIdForCharIndex, activeCharIndex, sceneObjects,
|
|
10
10
|
scenes, activeSceneId, selectSceneDocument, createSceneDocumentFromUi, duplicateSceneDocumentFromUi,
|
|
11
11
|
renameSceneDocumentFromUi, deleteSceneDocumentFromUi, addSceneObject, renameSceneObject, runStudioAction,
|
|
12
|
-
deleteSceneObject, frameSelection, toggleHierarchyHidden, propsDrop, hierarchyReparent,
|
|
12
|
+
deleteSceneObject, frameSelection, groupObjectUnderNewEmpty, renameRequest, toggleHierarchyHidden, propsDrop, hierarchyReparent,
|
|
13
13
|
agentTouchedRows,
|
|
14
14
|
} = useStudioShell();
|
|
15
15
|
return (
|
|
@@ -40,6 +40,8 @@ export default function OutlinerSlot() {
|
|
|
40
40
|
onDuplicateObject={(objectId) => runStudioAction("object.duplicate", objectId ? { objectId } : {})}
|
|
41
41
|
onDeleteObject={deleteSceneObject}
|
|
42
42
|
onFrameObject={frameSelection}
|
|
43
|
+
onGroupObject={groupObjectUnderNewEmpty}
|
|
44
|
+
renameRequest={renameRequest}
|
|
43
45
|
onToggleHidden={toggleHierarchyHidden}
|
|
44
46
|
propsDrop={propsDrop}
|
|
45
47
|
reparent={hierarchyReparent}
|
package/src/shell/TopBar.jsx
CHANGED
|
@@ -10,7 +10,7 @@ import "./topbar.css";
|
|
|
10
10
|
// primary action. Save and Export live in File (G7). #570: the project name
|
|
11
11
|
// and its save state head the left column (ProjectHead below).
|
|
12
12
|
export default function TopBar({ preferences }) {
|
|
13
|
-
const { recState, liveHubStatus, liveWorkspaceHandle } = useStudioShell();
|
|
13
|
+
const { recState, liveHubStatus, liveWorkspaceHandle, previsMode } = useStudioShell();
|
|
14
14
|
const connected = liveHubStatus === "connected";
|
|
15
15
|
return (
|
|
16
16
|
<header className="topbar v2-topbar" data-rec-state={recState}>
|
|
@@ -25,7 +25,7 @@ export default function TopBar({ preferences }) {
|
|
|
25
25
|
<i className="topbar-mcp-dot" aria-hidden="true" />
|
|
26
26
|
<span className="topbar-mcp-text">{connected ? ko("MCP connected", "MCP 연결됨") : ko("MCP offline", "MCP 꺼짐")}</span>
|
|
27
27
|
</span>
|
|
28
|
-
<GenerateMotion />
|
|
28
|
+
{previsMode !== "storyboard" && <GenerateMotion />}
|
|
29
29
|
</header>
|
|
30
30
|
);
|
|
31
31
|
}
|
|
@@ -35,7 +35,7 @@ export default function TopBar({ preferences }) {
|
|
|
35
35
|
export function ProjectHead() {
|
|
36
36
|
const {
|
|
37
37
|
projectMenuOpen, setProjectMenuOpen, projectDirty, projectName, projectStartupOpen,
|
|
38
|
-
projectManifest, saveStatus,
|
|
38
|
+
projectManifest, saveStatus, previsMode,
|
|
39
39
|
} = useStudioShell();
|
|
40
40
|
return (
|
|
41
41
|
<div className="topbar-project studio-project-head">
|
|
@@ -48,10 +48,24 @@ export function ProjectHead() {
|
|
|
48
48
|
projectManifest={projectManifest}
|
|
49
49
|
/>
|
|
50
50
|
<SaveState status={saveStatus} />
|
|
51
|
+
<PrevisModeBadge mode={previsMode} />
|
|
51
52
|
</div>
|
|
52
53
|
);
|
|
53
54
|
}
|
|
54
55
|
|
|
56
|
+
// The project's previs mode, a quiet label under the save state.
|
|
57
|
+
function previsModeLabel(mode) {
|
|
58
|
+
return mode === "storyboard" ? ko("Storyboard", "스토리보드") : ko("Animation", "애니메이션");
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function PrevisModeBadge({ mode }) {
|
|
62
|
+
return (
|
|
63
|
+
<span className="topbar-previs-mode" data-testid="topbar-previs-mode" data-previs-mode={mode}>
|
|
64
|
+
{previsModeLabel(mode)}
|
|
65
|
+
</span>
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
55
69
|
// "Generate Motion" is today's Scene generate (G6) and the one home for
|
|
56
70
|
// generation (IS-2): with authored prompt blocks it runs them all, as the
|
|
57
71
|
// removed Details "Generate all blocks" did; otherwise it runs the prompt.
|
|
@@ -12,14 +12,18 @@ import { saveAutoColor } from "../auto-color.js";
|
|
|
12
12
|
import { trackFeature } from "../analytics.js";
|
|
13
13
|
import "./viewport.css";
|
|
14
14
|
|
|
15
|
-
// G1: the single mode+tool pill. Keys 1-
|
|
15
|
+
// G1: the single mode+tool pill. Keys 1-5 and W/E/R are bound in App's
|
|
16
16
|
// keydown handler; these buttons are the same doors for the pointer.
|
|
17
17
|
const MODES = [
|
|
18
18
|
{ id: "scene", key: "1", label: ko("Stage", "배치") },
|
|
19
19
|
{ id: "pose", key: "2", label: ko("Pose", "포즈") },
|
|
20
20
|
{ id: "camera", key: "3", label: ko("Camera", "카메라") },
|
|
21
21
|
{ id: "motion", key: "4", label: ko("Motion", "모션") },
|
|
22
|
+
// #739: an isolated turntable for one sculpt. Every previs mode has it.
|
|
23
|
+
{ id: "sculpt", key: "5", label: ko("Sculpt", "조각") },
|
|
22
24
|
];
|
|
25
|
+
// A storyboard project has no Motion department: its pill reads 1 2 3 5.
|
|
26
|
+
const modesFor = (previsMode) => (previsMode === "storyboard" ? MODES.filter((mode) => mode.id !== "motion") : MODES);
|
|
23
27
|
|
|
24
28
|
// #570 line icons (16px, 1.3 stroke) for the floating rails.
|
|
25
29
|
const ICON = {
|
|
@@ -27,6 +31,10 @@ const ICON = {
|
|
|
27
31
|
pose: "M8 2.25a1.5 1.5 0 1 1 0 3 1.5 1.5 0 1 1 0-3z M5 7.25h6 M8 7.25v3.5 M6.25 13.75 8 10.75l1.75 3",
|
|
28
32
|
camera: "M2 5.75A1.5 1.5 0 0 1 3.5 4.25h6A1.5 1.5 0 0 1 11 5.75v4.5a1.5 1.5 0 0 1-1.5 1.5h-6A1.5 1.5 0 0 1 2 10.25z M11 7l3-1.5v5L11 9",
|
|
29
33
|
motion: "M1.75 9.5c1.5 0 2-4 3.25-4s1.75 5 3 5 1.75-5 3-5 1.75 4 3.25 4",
|
|
34
|
+
sculpt: "M3.75 11.75c0-3.25 1.9-5.5 4.25-5.5s4.25 2.25 4.25 5.5z M2 11.75h12 M5.25 14h5.5 M10 2.25 8.5 5.25",
|
|
35
|
+
front: "M8 2.5a1.75 1.75 0 1 1 0 3.5 1.75 1.75 0 1 1 0-3.5z M4.5 13.5v-2.75a3.5 3.5 0 0 1 7 0v2.75",
|
|
36
|
+
side: "M7.25 2.5a1.75 1.75 0 1 1 0 3.5 1.75 1.75 0 1 1 0-3.5z M9 4.25h1.5 M6 13.5v-2.75a2.5 2.5 0 0 1 4.5-1.5",
|
|
37
|
+
back: "M8 2.5a1.75 1.75 0 1 1 0 3.5 1.75 1.75 0 1 1 0-3.5z M4.5 13.5v-2.75a3.5 3.5 0 0 1 7 0v2.75 M8 9v4.5",
|
|
30
38
|
move: "M8 2v12 M2 8h12 M6.25 3.75 8 2l1.75 1.75 M6.25 12.25 8 14l1.75-1.75 M3.75 6.25 2 8l1.75 1.75 M12.25 6.25 14 8l-1.75 1.75",
|
|
31
39
|
rotate: "M13.25 8A5.25 5.25 0 1 1 11.7 4.3 M13.25 2.5v2.75H10.5",
|
|
32
40
|
scale: "M2.5 8.5v4a1 1 0 0 0 1 1h4 M8.5 2.5h5v5 M13.5 2.5 7.5 8.5",
|
|
@@ -133,7 +141,7 @@ export default function ViewportToolbar() {
|
|
|
133
141
|
agentCollapsed, addSceneObject, spawnCharacter, characters, flySpeed,
|
|
134
142
|
ikEditTool, setIkEditTool, showTrails, setShowTrails, motion, setRangePinPartPick,
|
|
135
143
|
trailFalloffS, setTrailFalloffS, lineEditMode, exitLineEditMode, enterRefineMode,
|
|
136
|
-
refineDisabledReason,
|
|
144
|
+
refineDisabledReason, previsMode, sculptView, requestSculptView,
|
|
137
145
|
} = useStudioShell();
|
|
138
146
|
const menu = useOverlayMenu();
|
|
139
147
|
|
|
@@ -178,6 +186,12 @@ export default function ViewportToolbar() {
|
|
|
178
186
|
refused: refineReason, pick: () => { if (!lineEditMode) enterRefineMode(); },
|
|
179
187
|
},
|
|
180
188
|
],
|
|
189
|
+
// Sculpt mode's W/E/R swing the turntable camera to a reference view.
|
|
190
|
+
sculpt: [
|
|
191
|
+
{ key: "W", id: "front", name: ko("Front view", "정면 보기"), active: sculptView?.view === "front", pick: () => requestSculptView("front") },
|
|
192
|
+
{ key: "E", id: "side", name: ko("Side view", "측면 보기"), active: sculptView?.view === "side", pick: () => requestSculptView("side") },
|
|
193
|
+
{ key: "R", id: "back", name: ko("Back view", "뒷면 보기"), active: sculptView?.view === "back", pick: () => requestSculptView("back") },
|
|
194
|
+
],
|
|
181
195
|
}[workflowMode] ?? [];
|
|
182
196
|
|
|
183
197
|
// Lens choices are the real primes that fit the editor's FOV range, turned
|
|
@@ -379,7 +393,7 @@ export default function ViewportToolbar() {
|
|
|
379
393
|
|
|
380
394
|
<div className="vp-mode-toolbar" role="toolbar" data-testid="mode-toolbar" aria-label={ko("Mode and tools", "모드와 도구")}>
|
|
381
395
|
<div className="vp-mode-keys" role="tablist" aria-label={ko("Workflow", "작업 모드")}>
|
|
382
|
-
{
|
|
396
|
+
{modesFor(previsMode).map((mode) => {
|
|
383
397
|
const active = workflowMode === mode.id;
|
|
384
398
|
const refused = mode.id === "pose" ? poseRefusal : null;
|
|
385
399
|
return (
|
|
@@ -392,6 +406,7 @@ export default function ViewportToolbar() {
|
|
|
392
406
|
className={"vp-mode-key" + (active ? " active" : "")}
|
|
393
407
|
aria-selected={active}
|
|
394
408
|
aria-disabled={refused ? true : undefined}
|
|
409
|
+
data-disabled-reason={refused || undefined}
|
|
395
410
|
aria-label={mode.label}
|
|
396
411
|
title={refused || `${mode.label} (${mode.key})`}
|
|
397
412
|
onClick={() => selectWorkflowMode(mode.id)}
|
package/src/shell/dock.css
CHANGED
|
@@ -90,4 +90,243 @@
|
|
|
90
90
|
.app[data-embed-mode] .v2-dock-resize {
|
|
91
91
|
display: none;
|
|
92
92
|
}
|
|
93
|
+
|
|
94
|
+
/* Board (storyboard projects): the stills as a strip of panel cards in the
|
|
95
|
+
Sequencer's place, the Shot Camera card still docked at the right end.
|
|
96
|
+
DESIGN.md §2-3: 12 px text, 4 px controls, 6 px cards, the amber
|
|
97
|
+
selection ring and the primary fill for the one add action. */
|
|
98
|
+
.app:not([data-embed-mode]) .v2-dock > .dock-board {
|
|
99
|
+
--board-card-w: 184px;
|
|
100
|
+
grid-column: 1;
|
|
101
|
+
grid-row: 1;
|
|
102
|
+
display: flex;
|
|
103
|
+
flex-direction: column;
|
|
104
|
+
min-width: 0;
|
|
105
|
+
min-height: 0;
|
|
106
|
+
margin-right: var(--shell-camera, 0px);
|
|
107
|
+
color: var(--text-1);
|
|
108
|
+
font: 400 12px var(--sans);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.app:not([data-embed-mode]) .dock-board-head {
|
|
112
|
+
flex: none;
|
|
113
|
+
display: flex;
|
|
114
|
+
align-items: center;
|
|
115
|
+
gap: var(--sp-1);
|
|
116
|
+
height: 48px;
|
|
117
|
+
padding: 0 var(--sp-3) 0 calc(var(--sp-3) + var(--dock-tabs-w, 0px) + var(--sp-3));
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.app:not([data-embed-mode]) .dock-board-count {
|
|
121
|
+
color: var(--label, var(--text-2));
|
|
122
|
+
font-size: 11px;
|
|
123
|
+
font-variant-numeric: tabular-nums;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.app:not([data-embed-mode]) .dock-board-add {
|
|
127
|
+
height: var(--h-control);
|
|
128
|
+
padding: 0 var(--sp-2);
|
|
129
|
+
border: 0;
|
|
130
|
+
border-radius: var(--r-1);
|
|
131
|
+
background: var(--primary-fill, var(--primary));
|
|
132
|
+
color: var(--on-select);
|
|
133
|
+
font: 600 12px var(--sans);
|
|
134
|
+
cursor: pointer;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
.app:not([data-embed-mode]) .dock-board-head > .dock-board-add { margin-left: auto; }
|
|
138
|
+
|
|
139
|
+
.app:not([data-embed-mode]) .dock-board-add:focus-visible,
|
|
140
|
+
.app:not([data-embed-mode]) .dock-board-actions button:focus-visible,
|
|
141
|
+
.app:not([data-embed-mode]) .dock-board-card:focus-visible {
|
|
142
|
+
outline: 2px solid var(--select);
|
|
143
|
+
outline-offset: 2px;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
.app:not([data-embed-mode]) .dock-board-empty {
|
|
147
|
+
flex: 1 1 auto;
|
|
148
|
+
display: flex;
|
|
149
|
+
flex-direction: column;
|
|
150
|
+
align-items: center;
|
|
151
|
+
justify-content: center;
|
|
152
|
+
gap: var(--sp-2);
|
|
153
|
+
padding: var(--sp-3);
|
|
154
|
+
color: var(--text-2);
|
|
155
|
+
text-align: center;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
.app:not([data-embed-mode]) .dock-board-empty p { margin: 0; max-width: 46ch; }
|
|
159
|
+
|
|
160
|
+
.app:not([data-embed-mode]) .dock-board-strip {
|
|
161
|
+
flex: 1 1 auto;
|
|
162
|
+
display: flex;
|
|
163
|
+
align-items: flex-start;
|
|
164
|
+
gap: var(--sp-2);
|
|
165
|
+
min-height: 0;
|
|
166
|
+
margin: 0;
|
|
167
|
+
padding: 2px var(--sp-3) var(--sp-2);
|
|
168
|
+
overflow: auto hidden;
|
|
169
|
+
list-style: none;
|
|
170
|
+
scroll-padding-inline: var(--sp-3);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
.app:not([data-embed-mode]) .dock-board-card {
|
|
174
|
+
position: relative;
|
|
175
|
+
flex: none;
|
|
176
|
+
display: flex;
|
|
177
|
+
flex-direction: column;
|
|
178
|
+
gap: 6px;
|
|
179
|
+
width: var(--board-card-w);
|
|
180
|
+
padding: 6px;
|
|
181
|
+
box-sizing: border-box;
|
|
182
|
+
border-radius: var(--r-2);
|
|
183
|
+
background: var(--card-fill, var(--surface-raised));
|
|
184
|
+
box-shadow: var(--card-ring, none);
|
|
185
|
+
cursor: grab;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
.app:not([data-embed-mode]) .dock-board-card:hover { background: var(--tile-fill, var(--surface-active)); }
|
|
189
|
+
.app:not([data-embed-mode]) .dock-board-card[data-selected] { box-shadow: 0 0 0 1.5px var(--select); }
|
|
190
|
+
.app:not([data-embed-mode]) .dock-board-card[data-dragging] { opacity: .45; cursor: grabbing; }
|
|
191
|
+
|
|
192
|
+
/* The drop slot: a 2 px amber bar in the gap on the side the panel lands. */
|
|
193
|
+
.app:not([data-embed-mode]) .dock-board-card[data-drop]::after {
|
|
194
|
+
content: "";
|
|
195
|
+
position: absolute;
|
|
196
|
+
top: 0;
|
|
197
|
+
bottom: 0;
|
|
198
|
+
width: 2px;
|
|
199
|
+
border-radius: 1px;
|
|
200
|
+
background: var(--select);
|
|
201
|
+
}
|
|
202
|
+
.app:not([data-embed-mode]) .dock-board-card[data-drop="before"]::after { left: calc(var(--sp-2) / -2 - 1px); }
|
|
203
|
+
.app:not([data-embed-mode]) .dock-board-card[data-drop="after"]::after { right: calc(var(--sp-2) / -2 - 1px); }
|
|
204
|
+
|
|
205
|
+
/* Card actions ride above the picture and show on hover or focus, the
|
|
206
|
+
Sequencer's shot-card pattern (#606). */
|
|
207
|
+
.app:not([data-embed-mode]) .dock-board-actions {
|
|
208
|
+
position: absolute;
|
|
209
|
+
z-index: 2;
|
|
210
|
+
top: 10px;
|
|
211
|
+
left: 10px;
|
|
212
|
+
right: 10px;
|
|
213
|
+
display: none;
|
|
214
|
+
flex-wrap: wrap;
|
|
215
|
+
gap: 4px;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
.app:not([data-embed-mode]) .dock-board-card:hover .dock-board-actions,
|
|
219
|
+
.app:not([data-embed-mode]) .dock-board-card:focus-within .dock-board-actions {
|
|
220
|
+
display: flex;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
.app:not([data-embed-mode]) .dock-board-actions button {
|
|
224
|
+
height: 20px;
|
|
225
|
+
padding: 0 6px;
|
|
226
|
+
border: 0;
|
|
227
|
+
border-radius: var(--r-1);
|
|
228
|
+
background: var(--surface-bar);
|
|
229
|
+
box-shadow: 0 0 0 .5px var(--divider-strong);
|
|
230
|
+
color: var(--text-1);
|
|
231
|
+
font: 500 11px var(--sans);
|
|
232
|
+
cursor: pointer;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
.app:not([data-embed-mode]) .dock-board-menu { display: flex; flex-basis: 100%; gap: 4px; }
|
|
236
|
+
.app:not([data-embed-mode]) .dock-board-actions button:hover:not(:disabled) { background: var(--surface-active); }
|
|
237
|
+
.app:not([data-embed-mode]) .dock-board-actions button.danger:hover { color: var(--danger); }
|
|
238
|
+
.app:not([data-embed-mode]) .dock-board-actions button:disabled { color: var(--text-3); cursor: default; }
|
|
239
|
+
|
|
240
|
+
.app:not([data-embed-mode]) .dock-board-thumb {
|
|
241
|
+
position: relative;
|
|
242
|
+
aspect-ratio: 16 / 9;
|
|
243
|
+
overflow: hidden;
|
|
244
|
+
border-radius: var(--r-1);
|
|
245
|
+
background: var(--frame-well, var(--field-deep));
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
.app:not([data-embed-mode]) .dock-board-image {
|
|
249
|
+
display: block;
|
|
250
|
+
width: 100%;
|
|
251
|
+
height: 100%;
|
|
252
|
+
object-fit: contain;
|
|
253
|
+
pointer-events: none;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/* The greybox stays readable under a stylized picture as a corner inset. */
|
|
257
|
+
.app:not([data-embed-mode]) .dock-board-inset {
|
|
258
|
+
position: absolute;
|
|
259
|
+
right: 4px;
|
|
260
|
+
bottom: 4px;
|
|
261
|
+
width: 32%;
|
|
262
|
+
border-radius: var(--r-1);
|
|
263
|
+
box-shadow: 0 0 0 1px var(--overlay);
|
|
264
|
+
pointer-events: none;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
.app:not([data-embed-mode]) .dock-board-index {
|
|
268
|
+
position: absolute;
|
|
269
|
+
left: 4px;
|
|
270
|
+
bottom: 4px;
|
|
271
|
+
min-width: 18px;
|
|
272
|
+
height: 18px;
|
|
273
|
+
padding: 0 4px;
|
|
274
|
+
box-sizing: border-box;
|
|
275
|
+
border-radius: var(--r-1);
|
|
276
|
+
background: var(--overlay);
|
|
277
|
+
color: var(--text-1);
|
|
278
|
+
font: 600 11px/18px var(--sans);
|
|
279
|
+
font-variant-numeric: tabular-nums;
|
|
280
|
+
text-align: center;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
.app:not([data-embed-mode]) .dock-board-card[data-selected] .dock-board-index {
|
|
284
|
+
background: var(--select);
|
|
285
|
+
color: var(--on-select);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
.app:not([data-embed-mode]) .dock-board-caption {
|
|
289
|
+
box-sizing: border-box;
|
|
290
|
+
width: 100%;
|
|
291
|
+
min-height: 36px;
|
|
292
|
+
padding: 2px 6px;
|
|
293
|
+
border: 0;
|
|
294
|
+
border-radius: var(--r-1);
|
|
295
|
+
background: var(--field-fill, var(--field));
|
|
296
|
+
color: var(--text-1);
|
|
297
|
+
font: 400 12px/16px var(--sans);
|
|
298
|
+
resize: none;
|
|
299
|
+
cursor: text;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
.app:not([data-embed-mode]) .dock-board-caption::placeholder { color: var(--text-3); }
|
|
303
|
+
|
|
304
|
+
.app:not([data-embed-mode]) .dock-board-caption:focus-visible,
|
|
305
|
+
.app:not([data-embed-mode]) .dock-board-hold input:focus-visible {
|
|
306
|
+
outline: 1.5px solid var(--select);
|
|
307
|
+
outline-offset: 0;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
.app:not([data-embed-mode]) .dock-board-hold {
|
|
311
|
+
display: flex;
|
|
312
|
+
align-items: center;
|
|
313
|
+
gap: 6px;
|
|
314
|
+
height: var(--h-row);
|
|
315
|
+
color: var(--label, var(--text-2));
|
|
316
|
+
font-size: 11px;
|
|
317
|
+
cursor: default;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
.app:not([data-embed-mode]) .dock-board-hold input {
|
|
321
|
+
width: 56px;
|
|
322
|
+
height: 20px;
|
|
323
|
+
padding: 0 6px;
|
|
324
|
+
box-sizing: border-box;
|
|
325
|
+
border: 0;
|
|
326
|
+
border-radius: var(--r-1);
|
|
327
|
+
background: var(--field-fill, var(--field));
|
|
328
|
+
color: var(--text-1);
|
|
329
|
+
font: 400 12px var(--sans);
|
|
330
|
+
font-variant-numeric: tabular-nums;
|
|
331
|
+
}
|
|
93
332
|
}
|
|
@@ -87,6 +87,7 @@
|
|
|
87
87
|
.app[data-shell="glass"]:not([data-embed-mode]) .v2-outliner .v2-outliner-chip.cast { background: currentColor; -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23000' stroke-width='1.3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2.25a1.5 1.5 0 1 1 0 3 1.5 1.5 0 1 1 0-3z M5 7.25h6 M8 7.25v3.5 M6.25 13.75 8 10.75l1.75 3'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23000' stroke-width='1.3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2.25a1.5 1.5 0 1 1 0 3 1.5 1.5 0 1 1 0-3z M5 7.25h6 M8 7.25v3.5 M6.25 13.75 8 10.75l1.75 3'/%3E%3C/svg%3E"); }
|
|
88
88
|
.app[data-shell="glass"]:not([data-embed-mode]) .v2-outliner .v2-outliner-chip.cam { background: currentColor; -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23000' stroke-width='1.3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2 5.75A1.5 1.5 0 0 1 3.5 4.25h6A1.5 1.5 0 0 1 11 5.75v4.5a1.5 1.5 0 0 1-1.5 1.5h-6A1.5 1.5 0 0 1 2 10.25z M11 7l3-1.5v5L11 9'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23000' stroke-width='1.3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2 5.75A1.5 1.5 0 0 1 3.5 4.25h6A1.5 1.5 0 0 1 11 5.75v4.5a1.5 1.5 0 0 1-1.5 1.5h-6A1.5 1.5 0 0 1 2 10.25z M11 7l3-1.5v5L11 9'/%3E%3C/svg%3E"); }
|
|
89
89
|
.app[data-shell="glass"]:not([data-embed-mode]) .v2-outliner .v2-outliner-chip.light { background: currentColor; -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23000' stroke-width='1.3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 5.5a2.5 2.5 0 1 1 0 5 2.5 2.5 0 1 1 0-5z M8 1.75v1.5 M8 12.75v1.5 M1.75 8h1.5 M12.75 8h1.5 M3.6 3.6l1 1 M11.4 11.4l1 1 M3.6 12.4l1-1 M11.4 4.6l1-1'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23000' stroke-width='1.3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 5.5a2.5 2.5 0 1 1 0 5 2.5 2.5 0 1 1 0-5z M8 1.75v1.5 M8 12.75v1.5 M1.75 8h1.5 M12.75 8h1.5 M3.6 3.6l1 1 M11.4 11.4l1 1 M3.6 12.4l1-1 M11.4 4.6l1-1'/%3E%3C/svg%3E"); }
|
|
90
|
+
.app[data-shell="glass"]:not([data-embed-mode]) .v2-outliner .v2-outliner-chip.empty { background: currentColor; -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23000' stroke-width='1.3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 8V2.25 M8 8l-4.75 3 M8 8l5 2.75'/%3E%3Ccircle cx='8' cy='8' r='1.1'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23000' stroke-width='1.3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 8V2.25 M8 8l-4.75 3 M8 8l5 2.75'/%3E%3Ccircle cx='8' cy='8' r='1.1'/%3E%3C/svg%3E"); }
|
|
90
91
|
/* The toggles draw the same chevron as the rest of the shell. */
|
|
91
92
|
.app[data-shell="glass"]:not([data-embed-mode]) .v2-outliner .hierarchy-toggle:not(.placeholder) {
|
|
92
93
|
font-size: 0;
|
|
@@ -442,7 +443,7 @@
|
|
|
442
443
|
font-family: var(--sans);
|
|
443
444
|
}
|
|
444
445
|
.app[data-shell="glass"]:not([data-embed-mode]) .v2-sequencer .tl-head {
|
|
445
|
-
height:
|
|
446
|
+
height: auto;
|
|
446
447
|
min-height: 48px;
|
|
447
448
|
gap: 12px;
|
|
448
449
|
padding: 0 16px;
|
|
@@ -700,7 +701,7 @@
|
|
|
700
701
|
|
|
701
702
|
/* The Sequencer head drops its secondary groups as the dock narrows. */
|
|
702
703
|
.app[data-shell="glass"]:not([data-embed-mode]) .bottom-timeline { container-type: inline-size; }
|
|
703
|
-
.app[data-shell="glass"]:not([data-embed-mode]) .v2-sequencer .tl-head { overflow:
|
|
704
|
+
.app[data-shell="glass"]:not([data-embed-mode]) .v2-sequencer .tl-head { overflow: visible; }
|
|
704
705
|
@container (max-width: 760px) {
|
|
705
706
|
.app[data-shell="glass"]:not([data-embed-mode]) .v2-sequencer .tl-badge { display: none; }
|
|
706
707
|
}
|
package/src/shell/log-store.js
CHANGED
|
@@ -21,7 +21,7 @@ function publish(next) {
|
|
|
21
21
|
* newest entry updates that entry in place instead of adding a row, so an
|
|
22
22
|
* encoding counter reads as one line that ticks.
|
|
23
23
|
*/
|
|
24
|
-
|
|
24
|
+
function push({ kind = "info", text, key = null, at = Date.now() }) {
|
|
25
25
|
const message = typeof text === "string" ? text.trim() : "";
|
|
26
26
|
if (!message) return null;
|
|
27
27
|
const last = entries[entries.length - 1];
|
|
@@ -36,16 +36,16 @@ export function push({ kind = "info", text, key = null, at = Date.now() }) {
|
|
|
36
36
|
return entry;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
function getEntries() {
|
|
40
40
|
return entries;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
function subscribe(listener) {
|
|
44
44
|
listeners.add(listener);
|
|
45
45
|
return () => listeners.delete(listener);
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
|
|
48
|
+
function clear() {
|
|
49
49
|
if (entries.length) publish([]);
|
|
50
50
|
}
|
|
51
51
|
|
package/src/shell/mode.css
CHANGED
|
@@ -7,3 +7,23 @@
|
|
|
7
7
|
.app[data-workflow-mode="pose"] .workflow-toolbar-hint { display: inline-flex; }
|
|
8
8
|
.app[data-workflow-mode="pose"] .vp-inset,
|
|
9
9
|
.app[data-workflow-mode="pose"] .vp-shot-preview { display: none !important; }
|
|
10
|
+
|
|
11
|
+
/* A storyboard project (#650) is stills: the take, motion and pose-correction
|
|
12
|
+
tools, the root-path (waypoint) switch and a prop's Top-View travel path
|
|
13
|
+
never show, whatever the mode. */
|
|
14
|
+
.app[data-previs-mode="storyboard"] .take-bar,
|
|
15
|
+
.app[data-previs-mode="storyboard"] .tl-motion-tools,
|
|
16
|
+
.app[data-previs-mode="storyboard"] .tl-pose-tools,
|
|
17
|
+
.app[data-previs-mode="storyboard"] .tl-btn.wp,
|
|
18
|
+
.app[data-previs-mode="storyboard"] .tl-wp-hint,
|
|
19
|
+
.app[data-previs-mode="storyboard"] .tl-track.objmo { display: none !important; }
|
|
20
|
+
|
|
21
|
+
/* The project mode under the project name: secondary text, never a control. */
|
|
22
|
+
.topbar-previs-mode {
|
|
23
|
+
color: var(--text-2, #9b9ba1);
|
|
24
|
+
font-size: 11px;
|
|
25
|
+
font-weight: 500;
|
|
26
|
+
line-height: 1.3;
|
|
27
|
+
letter-spacing: .02em;
|
|
28
|
+
white-space: nowrap;
|
|
29
|
+
}
|
|
@@ -11,7 +11,10 @@ import { createContext, useContext } from "react";
|
|
|
11
11
|
// - generation, blocks/refine, takes/recipe and preserve strength;
|
|
12
12
|
// - agentOpen/toggleAgent, preferencesOpen/setPreferencesOpen;
|
|
13
13
|
// - statusText/setStatusText, previewRanges/setPreviewRanges, liveHubStatus,
|
|
14
|
-
// flySpeed (the navigation multiplier, not metres per second)
|
|
14
|
+
// flySpeed (the navigation multiplier, not metres per second);
|
|
15
|
+
// - previsMode ("storyboard" | "animation"), sceneRevision (bumps on every
|
|
16
|
+
// authored edit) and capturePanelThumbnail(shot) (the shot's first frame as
|
|
17
|
+
// a PNG data URL, or null) for the Board dock tab.
|
|
15
18
|
export const StudioShellContext = createContext(null);
|
|
16
19
|
|
|
17
20
|
export function useStudioShell() {
|