feat: scene traps, material legends, and scene editor window

Add trap overlays with session state, material legend editor/panel, and a dedicated scene editor window wired through IPC and project persistence.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Ivan Fontosh
2026-07-24 16:29:43 +08:00
parent d3b1c4660d
commit 02d73ddf81
39 changed files with 2563 additions and 36 deletions
+21
View File
@@ -8,12 +8,15 @@ import { SceneDarknessOverlay } from './effects/SceneDarknessOverlay';
import { useEffectsState } from './effects/useEffectsState';
import { useSceneDarknessState } from './effects/useSceneDarknessState';
import { DEFAULT_MATERIALS_OVERLAY_LAYOUT, DEFAULT_NPCS_OVERLAY_LAYOUT } from '../../shared/types';
import { MaterialLegendPanel } from './materials/MaterialLegendPanel';
import { MaterialOverlay } from './materials/MaterialOverlay';
import { useMaterialsOverlayState } from './materials/useMaterialsOverlayState';
import { NpcsSceneOverlay } from './npcs/NpcsSceneOverlay';
import { useNpcsOverlayState } from './npcs/useNpcsOverlayState';
import { SceneOverlayHost } from './sceneOverlay/SceneOverlayHost';
import { useSceneViewState } from './sceneView/useSceneViewState';
import { SceneTrapsOverlay } from './traps/SceneTrapsOverlay';
import { useSceneTrapsState } from './traps/useSceneTrapsState';
import styles from './PresentationView.module.css';
import { RotatedImage } from './RotatedImage';
import { useAssetUrl } from './useAssetImageUrl';
@@ -35,6 +38,7 @@ export function PresentationView({
}: PresentationViewProps) {
const [fxState] = useEffectsState();
const [sdState] = useSceneDarknessState();
const [sceneTraps] = useSceneTrapsState();
const [sceneView] = useSceneViewState();
const [materialsOverlay] = useMaterialsOverlayState();
const [npcsOverlay] = useNpcsOverlayState();
@@ -165,6 +169,14 @@ export function PresentationView({
}
/>
) : null}
{scene?.previewAssetType === 'image' && contentRect ? (
<SceneTrapsOverlay
traps={scene.traps ?? []}
session={sceneTraps}
viewport={contentRect}
mode="presentation"
/>
) : null}
{showEffects && scene?.previewAssetType === 'image' && scene.darkenScene && contentRect ? (
<SceneDarknessOverlay state={sdState} overlayAlpha={1} viewport={contentRect} />
) : null}
@@ -174,6 +186,15 @@ export function PresentationView({
embedded
assetId={activeMaterial.assetId}
layout={materialsOverlay?.layout ?? DEFAULT_MATERIALS_OVERLAY_LAYOUT}
legendMarkers={
activeMaterial.legend?.enabled ? (activeMaterial.legend.markers ?? []) : undefined
}
/>
) : null}
{activeMaterial?.legend?.enabled ? (
<MaterialLegendPanel
legend={activeMaterial.legend}
layout={materialsOverlay?.legendLayout ?? DEFAULT_MATERIALS_OVERLAY_LAYOUT}
/>
) : null}
{activeNpcItems.length > 0 ? <NpcsSceneOverlay embedded items={activeNpcItems} /> : null}