feat(play): hide NPC tokens from the player screen

A token can be hidden per session from the control menu. The GM still sees it, and its path keeps moving. Scene editor grid labels no longer call a removed helper.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Ivan Fontosh
2026-10-02 10:15:32 +08:00
parent 060bbd471a
commit f6c301a12b
10 changed files with 165 additions and 23 deletions
@@ -51,6 +51,8 @@ function NpcSprite({
gridFit,
disposition,
inactive,
hiddenFromPlayers,
concealed,
onMove,
onResize,
resizeTitle,
@@ -71,6 +73,8 @@ function NpcSprite({
gridFit: number;
disposition: NpcDisposition;
inactive: boolean;
hiddenFromPlayers: boolean;
concealed: boolean;
onMove?: (placementId: string, nx: number, ny: number) => void;
onResize?: (placementId: string, sizeN: number) => void;
resizeTitle?: string;
@@ -153,6 +157,8 @@ function NpcSprite({
styles.token,
canDrag ? styles.editable : '',
initiativeActive ? styles.initiativeActive : '',
hiddenFromPlayers && !concealed ? styles.hiddenFromPlayers : '',
concealed ? styles.concealedFromPlayers : '',
]
.filter(Boolean)
.join(' ')}
@@ -274,6 +280,7 @@ export function SceneNpcTokensOverlay({
snapNorm,
poseOverrides = null,
dragEnabledById = null,
concealFromPlayers = false,
}: {
placements: readonly SceneNpcToken[];
library: readonly ProjectNpc[];
@@ -289,6 +296,8 @@ export function SceneNpcTokensOverlay({
snapNorm?: (nx: number, ny: number) => { nx: number; ny: number };
poseOverrides?: Record<string, { nx: number; ny: number }> | null;
dragEnabledById?: Record<string, boolean> | null;
/** На презентации скрытый от игроков токен остаётся в DOM, чтобы путь продолжал идти. */
concealFromPlayers?: boolean;
}) {
const [initiative] = useInitiativeState();
if (!viewport) return null;
@@ -305,6 +314,7 @@ export function SceneNpcTokensOverlay({
const override = session?.byPlacementId[key];
const disposition = resolveNpcTokenDisposition(placement, npc, override?.disposition);
const inactive = Boolean(override?.inactive);
const hiddenFromPlayers = Boolean(override?.hiddenFromPlayers);
const dragEnabled = dragEnabledById ? Boolean(dragEnabledById[key]) : true;
return (
<NpcSprite
@@ -321,6 +331,8 @@ export function SceneNpcTokensOverlay({
gridFit={gridFit}
disposition={disposition}
inactive={inactive}
hiddenFromPlayers={hiddenFromPlayers}
concealed={concealFromPlayers && hiddenFromPlayers}
initiativeActive={initiativeHighlightForNpc(initiative, key)}
initiativeConditions={initiativeConditionsForNpc(initiative, key)}
{...(onMove ? { onMove } : {})}