diff --git a/apps/editor/src/ui/editor-app.tsx b/apps/editor/src/ui/editor-app.tsx
index 52c23bf..b49dd73 100644
--- a/apps/editor/src/ui/editor-app.tsx
+++ b/apps/editor/src/ui/editor-app.tsx
@@ -89,7 +89,6 @@ import { createCreatorPathSteps, type CreatorPathStep } from "../creator-path";
import {
AiContextSummary,
AiProviderBoundary,
- AssetStudioSidebar,
BuildWorkspace,
CollapsedPanelRail,
iconSize,
@@ -263,13 +262,9 @@ import { aiStudioReducer, initialAiStudioState } from "./features/ai/ai-studio-s
import { AiStudioSteps } from "./features/ai/ai-studio-steps";
import { AiStudioWorkspace } from "./features/ai/ai-studio-workspace";
import { assetStudioReducer, initialAssetStudioState, type AssetStudioTool } from "./features/assets/asset-studio-state";
-import { AssetStudioWorkspace } from "./features/assets/asset-studio-workspace";
-import { AssetStudioPreview } from "./features/assets/asset-studio-preview";
-import { AssetStudioToolPanel } from "./features/assets/asset-studio-tool-panel";
+import { AssetStudioLaunchpad } from "./features/assets/asset-studio-launchpad";
import { initialSceneStudioState, sceneStudioReducer } from "./features/scenes/scene-studio-state";
-import { SceneTree } from "./features/scenes/scene-tree";
-import { SceneViewport } from "./features/scenes/scene-viewport";
-import { ScenesWorkspace } from "./features/scenes/scenes-workspace";
+import { SceneTreeLaunchpad, ScenesLaunchpad } from "./features/scenes/scenes-launchpad";
import {
buildProjectResourceIndex,
filterProjectResources,
@@ -8104,39 +8099,43 @@ export function EditorApp({ gateway: injectedGateway }: EditorAppProps = {}) {
}
if (workspace === "scene") {
return (
-
);
}
@@ -9712,108 +9711,117 @@ export function EditorApp({ gateway: injectedGateway }: EditorAppProps = {}) {
) : workspace === "assets" ? (
-
-
{activeAssetTool === "animation" ? (
Character Gym
@@ -10125,7 +10133,7 @@ export function EditorApp({ gateway: injectedGateway }: EditorAppProps = {}) {
) : null}
-
+
) : workspace === "narrative" && currentFlowDraft ? (
) : (
-
-
-
+ }}
+ actions={{
+ viewport: {
+ boundsForGenerationGuideShape,
+ generationGuideColor,
+ insertGenerationGuidePointFromEvent,
+ insertWalkAreaPointFromEvent,
+ onCreateActor: createActor,
+ onCreateHotspot: createHotspot,
+ onCreateSceneLayer: createSceneLayer,
+ onSelectActor: selectActor,
+ onSelectHotspot: selectHotspot,
+ onSelectPickup: selectPickup,
+ onSelectPlayerInScene: selectPlayerInScene,
+ onSetActiveSceneTool: setActiveSceneTool,
+ onSetSceneInspectorTarget: setSceneInspectorTarget,
+ onSetSelectedGenerationGuideId: setSelectedGenerationGuideId,
+ onStartActorInteraction: startActorInteraction,
+ onStartActorSpotInteraction: startActorSpotInteraction,
+ onStartGenerationGuidePointInteraction: startGenerationGuidePointInteraction,
+ onStartGenerationGuideShapeInteraction: startGenerationGuideShapeInteraction,
+ onStartHotspotInteraction: startHotspotInteraction,
+ onStartHotspotSpotInteraction: startHotspotSpotInteraction,
+ onStartPickupInteraction: startPickupInteraction,
+ onStartPlayerStartInteraction: startPlayerStartInteraction,
+ onStartWalkAreaPointInteraction: startWalkAreaPointInteraction,
+ updateSceneDraft
+ }
+ }}
+ />
)}
diff --git a/apps/editor/src/ui/features/assets/asset-studio-launchpad.tsx b/apps/editor/src/ui/features/assets/asset-studio-launchpad.tsx
new file mode 100644
index 0000000..d829d95
--- /dev/null
+++ b/apps/editor/src/ui/features/assets/asset-studio-launchpad.tsx
@@ -0,0 +1,55 @@
+import type { ComponentProps, ReactNode } from "react";
+import { AssetStudioSidebar } from "../../editor-shell";
+import { AssetStudioPreview, type AssetStudioPreviewProps } from "./asset-studio-preview";
+import { AssetStudioToolPanel, type AssetStudioToolPanelProps } from "./asset-studio-tool-panel";
+import {
+ AssetStudioWorkspace,
+ type AssetStudioWorkspaceModel
+} from "./asset-studio-workspace";
+
+type AssetStudioSidebarProps = ComponentProps;
+
+type ActionKeys = {
+ [Key in keyof T]-?: T[Key] extends (...args: never[]) => unknown ? Key : never;
+}[keyof T];
+
+type ModelPart = Omit>;
+type ActionsPart = Pick>;
+
+export interface AssetStudioLaunchpadModel {
+ preview: ModelPart;
+ sidebar: ModelPart;
+ toolPanel: ModelPart;
+ workspace: AssetStudioWorkspaceModel;
+}
+
+export interface AssetStudioLaunchpadActions {
+ preview: ActionsPart;
+ sidebar: ActionsPart;
+ toolPanel: ActionsPart;
+}
+
+export interface AssetStudioLaunchpadProps {
+ actions: AssetStudioLaunchpadActions;
+ children?: ReactNode;
+ model: AssetStudioLaunchpadModel;
+}
+
+/**
+ * Asset Studio's composition boundary. The composition root supplies a
+ * serializable view model and explicit action groups; feature agents can own
+ * the preview, tool panel, and future animation surface without reaching into
+ * EditorGateway or sibling workspace state.
+ */
+export function AssetStudioLaunchpad({ actions, children, model }: AssetStudioLaunchpadProps) {
+ return (
+
+
+ {children}
+
+ );
+}
diff --git a/apps/editor/src/ui/features/scenes/scenes-launchpad.tsx b/apps/editor/src/ui/features/scenes/scenes-launchpad.tsx
new file mode 100644
index 0000000..0aa1bc2
--- /dev/null
+++ b/apps/editor/src/ui/features/scenes/scenes-launchpad.tsx
@@ -0,0 +1,46 @@
+import { SceneTree, type SceneTreeProps } from "./scene-tree";
+import { SceneViewport, type SceneViewportProps } from "./scene-viewport";
+import {
+ ScenesWorkspace,
+ type ScenesWorkspaceModel
+} from "./scenes-workspace";
+
+type ActionKeys = {
+ [Key in keyof T]-?: T[Key] extends (...args: never[]) => unknown ? Key : never;
+}[keyof T];
+
+type ModelPart = Omit>;
+type ActionsPart = Pick>;
+
+export interface ScenesLaunchpadModel {
+ viewport: ModelPart;
+ workspace: ScenesWorkspaceModel;
+}
+
+export interface ScenesLaunchpadActions {
+ viewport: ActionsPart;
+}
+
+export interface ScenesLaunchpadProps {
+ actions: ScenesLaunchpadActions;
+ model: ScenesLaunchpadModel;
+}
+
+export interface SceneTreeLaunchpadProps {
+ actions: ActionsPart;
+ model: ModelPart;
+}
+
+/** Scene navigator boundary for the parallel Scenes workstream. */
+export function SceneTreeLaunchpad({ actions, model }: SceneTreeLaunchpadProps) {
+ return ;
+}
+
+/** Scene viewport boundary for the parallel Scenes workstream. */
+export function ScenesLaunchpad({ actions, model }: ScenesLaunchpadProps) {
+ return (
+
+
+
+ );
+}