feat(scene): video map editor parity and help updates

Enable scene editor, overlays, effects, and darkness on video scenes; brighten GM trap markers; document snap, NPC types, materials, and control controls in RU/EN help.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Ivan Fontosh
2026-08-07 08:23:08 +08:00
parent 8d5a68c71e
commit 1fbaaa6e77
17 changed files with 443 additions and 98 deletions
+31 -20
View File
@@ -29,6 +29,7 @@ import { useSceneTokensSession } from './tokens/useSceneTokensSession';
import { SceneTrapsOverlay } from './traps/SceneTrapsOverlay';
import { useSceneTrapsState } from './traps/useSceneTrapsState';
import styles from './PresentationView.module.css';
import { ContainedVideo } from './ContainedVideo';
import { RotatedImage } from './RotatedImage';
import { useAssetUrl } from './useAssetImageUrl';
import { useVideoPlaybackState } from './video/useVideoPlaybackState';
@@ -171,26 +172,29 @@ export function PresentationView({
/>
</div>
) : originalUrl && scene?.previewAssetType === 'video' ? (
<video
ref={videoElRef}
className={styles.video}
src={originalUrl}
muted
playsInline
loop={Boolean(scene?.settings?.loopVideo)}
preload="auto"
onError={() => {
// noop: status surfaced in control app; keep presentation clean
}}
/>
<div className={styles.fill}>
<ContainedVideo
url={originalUrl}
videoRef={videoElRef}
muted
playsInline
loop={Boolean(scene?.settings?.loopVideo)}
preload="auto"
viewCamera={sceneView}
onContentRectChange={setContentRect}
onError={() => {
// noop: status surfaced in control app; keep presentation clean
}}
/>
</div>
) : (
<div className={styles.placeholderBg} />
)}
{scene?.previewAssetType === 'image' ? (
{scene?.previewAssetType === 'image' || scene?.previewAssetType === 'video' ? (
<SceneGridOverlay grid={scene.grid} viewport={contentRect} />
) : null}
<div className={styles.vignette} />
{scene?.previewAssetType === 'image' && contentRect ? (
{(scene?.previewAssetType === 'image' || scene?.previewAssetType === 'video') && contentRect ? (
<SceneTokensOverlay
placements={scene.tokens ?? []}
library={appTokens}
@@ -198,7 +202,9 @@ export function PresentationView({
viewport={contentRect}
/>
) : null}
{USERS_BRANCH_FEATURES_ENABLED && scene?.previewAssetType === 'image' && contentRect ? (
{USERS_BRANCH_FEATURES_ENABLED &&
(scene?.previewAssetType === 'image' || scene?.previewAssetType === 'video') &&
contentRect ? (
<SceneNpcTokensOverlay
placements={scene.npcTokens ?? []}
library={project?.npcs ?? []}
@@ -207,7 +213,9 @@ export function PresentationView({
grid={scene.grid}
/>
) : null}
{USERS_BRANCH_FEATURES_ENABLED && scene?.previewAssetType === 'image' && contentRect ? (
{USERS_BRANCH_FEATURES_ENABLED &&
(scene?.previewAssetType === 'image' || scene?.previewAssetType === 'video') &&
contentRect ? (
<ScenePlayerTokensOverlay
library={appPlayers}
session={scenePlayerTokensSession}
@@ -216,7 +224,7 @@ export function PresentationView({
grid={scene.grid}
/>
) : null}
{scene?.previewAssetType === 'image' && contentRect ? (
{(scene?.previewAssetType === 'image' || scene?.previewAssetType === 'video') && contentRect ? (
<SceneTrapsOverlay
traps={scene.traps ?? []}
session={sceneTraps}
@@ -224,7 +232,7 @@ export function PresentationView({
mode="presentation"
/>
) : null}
{showEffects && scene?.previewAssetType !== 'video' ? (
{showEffects && (scene?.previewAssetType === 'image' || scene?.previewAssetType === 'video') ? (
<PixiEffectsOverlay
state={fxState}
style={{ zIndex: 6 }}
@@ -235,10 +243,13 @@ export function PresentationView({
}
/>
) : null}
{showEffects && scene?.previewAssetType !== 'video' ? (
{showEffects && (scene?.previewAssetType === 'image' || scene?.previewAssetType === 'video') ? (
<ExplosionVideoOverlay state={fxState} viewport={contentRect} />
) : null}
{showEffects && scene?.previewAssetType === 'image' && scene.darkenScene && contentRect ? (
{showEffects &&
(scene?.previewAssetType === 'image' || scene?.previewAssetType === 'video') &&
scene.darkenScene &&
contentRect ? (
<SceneDarknessOverlay state={sdState} overlayAlpha={1} viewport={contentRect} style={{ zIndex: 30 }} />
) : null}
<SceneOverlayHost active={activeMaterialItems.length > 0 || activeNpcItems.length > 0}>