Files
scrying-pool/_bmad-output/planning-artifacts/prds/prd-video-view-manager-2026-05-19/prd.md
T
2026-05-25 10:32:49 +02:00

632 lines
43 KiB
Markdown

---
title: "Video View Manager — FoundryVTT Webcam Visibility Control Module"
status: draft
created: 2026-05-19
updated: 2026-05-25
version: 0.1.0
---
# PRD: Video View Manager
## 0. Document Purpose
This PRD is the authoritative specification for **Video View Manager** (module ID: `scrying-pool`), a FoundryVTT v14 module. It is written for the module author (Morr) and future contributors, and it is the source of record for scope decisions during development.
This document uses Glossary terms from §3 throughout §4+ and keeps functional requirements globally numbered FR-1 through FR-32 for stable reference. Inline `[ASSUMPTION]` tags in §4 mark unconfirmed inferences and are indexed in §9. The primary upstream input is `_bmad-output/brainstorming/brainstorming-session-2026-05-19-221747.md`.
**Implementation Updates:** This version incorporates enhancements from live testing completed May 25, 2026, including full AV dock replacement, configurable dock layouts, and position persistence.
---
## 1. Vision
Video View Manager gives the GM granular, real-time control over webcam visibility in FoundryVTT v14. Its core value is simple: **the GM can hide or reveal any Participant's camera in one click, and every Viewer updates immediately.** Existing FoundryVTT AV controls do not provide this.
From that core, the module extends into session cinematography. Scene Presets let the GM configure camera states during prep and apply them on scene transitions. The Director's Board gives the GM bulk visibility control for larger groups. Contextual Notifications explain camera-state changes so feeds never disappear silently.
The module follows the **Progressive Enhancement Architecture**. Level 1 adds a right-click action to existing AV Tiles. Level 2 adds the Director's Board. Level 3 adds Scene Presets and automation. Participants stay informed, automation that changes an individual's on-screen presence requires explicit opt-in, and the GM always has an immediate override.
**Live Test Enhancements (May 2026):**
- Full replacement of Foundry's native AV dock with custom ScryingPoolStrip
- Configurable dock layouts (vertical, horizontal, mosaic) with size variants
- Position persistence across sessions
- Enhanced portrait fallback handling
---
## 2. Target Users
### 2.1 Primary Personas
**Marcus — The Veteran GM**
Marcus runs a biweekly campaign with 6 players on FoundryVTT. He preps meticulously and wants zero friction during play. He wants camera automation he can configure once, not an interface he must reopen mid-session. Every automation needs an obvious one-click override. He will use Scene Presets and the Director's Board extensively.
**Sofia — The Privacy-Conscious Player**
Sofia joins two games a week. She has a home office setup and is comfortable on camera, but she does not want her face spotlighted unexpectedly during a dramatic moment she did not choose. She needs to know what state her feed is in at all times, and she expects a way to opt out of any effect that touches her camera automatically.
**Jake — The Actual-Play Streamer**
Jake runs a public streamed game. He needs complete independence between what his players see and what his stream audience sees. Keyboard shortcuts are essential during live broadcast. He sees the Browser Source API and Spectator View (Later roadmap) as the features that turn this module into a production stack.
**Alex — The New Player**
Alex has just joined their first online TTRPG. They are comfortable with Zoom but have never used FoundryVTT. They need the interface to use plain language ("Show" / "Hide") rather than technical vocabulary, toast notifications that explain what is happening, and a Portrait Fallback if their camera fails.
### 2.2 Jobs to Be Done
**Functional**
- Hide a distracting Participant's video feed without removing them from the session
- Spotlight one Participant for a dramatic reveal or emotional scene climax
- Apply a Scene Preset when transitioning between scenes without manual intervention
- Know at a glance which of 6+ Participants are hidden, visible, or offline
- Configure dock layout to match table preferences (vertical, horizontal, mosaic)
- Maintain dock position and size preferences across sessions
**Social / Emotional**
- Feel in control of the table atmosphere as a GM — the visual equivalent of adjusting the lights
- Trust that no Participant is hidden without knowing it (Participant transparency)
- Participate fully in the session even when camera equipment fails (Portrait Fallback, Reaction Clip System)
### 2.3 Non-Users (v1.0)
- Solo FoundryVTT users with no AV participants
- Groups using FoundryVTT v13 or earlier
- Streamers requiring independent audience layouts (served in the later roadmap — §10)
---
## 3. Glossary
- **AV Tile** — The FoundryVTT UI element that renders a Participant's audio/video feed. The primary surface for right-click interactions in Level 1 of the Progressive Enhancement Architecture.
- **Browser Source API** — A Later-roadmap streaming interface that exposes camera-layout outputs for external broadcast tooling such as OBS.
- **Combat Cinematics Mode** — An automation mode that manages the Visibility Matrix during active FoundryVTT combat, spotlighting the active combatant's feed. Part of the Later roadmap.
- **Director's Board** — The floating window for bulk Visibility Matrix management. Primary UI surface for Level 2/3 interactions. Synonyms are not permitted — this is not "the settings panel" or "the popout."
- **Director's Board Stage Lighting States** — A Later-roadmap preset vocabulary tier for cinematic bulk actions such as Wash, Focus, and Blackout.
- **Dock Layout** — Configurable layout options for the AV dock strip: `vertical-sm`, `vertical-md`, `horizontal-sm`, `horizontal-md`, `mosaic-sm`, `mosaic-md`. Controlled via world setting `dockLayout` with client-scoped override via `dockLayoutExpanded`.
- **Dual Layout System** — A Later-roadmap architecture that separates the Participant-facing layout from the Spectator View.
- **Full AV Replacement** — Complete replacement of FoundryVTT's native AV dock with custom ScryingPoolStrip and RoleRenderer components, providing full control over participant feed display.
- **GM** — Game Master. The FoundryVTT user with the `GAMEMASTER` role. Has exclusive authority over the Visibility Matrix unless Player Permissions are extended (future roadmap).
- **HP-Reactive Cam Styling** — An opt-in automation effect that changes the presentation of a Participant's feed based on HP-related game events. Part of the Later roadmap.
- **NPC Presence Tiles** — A Later-roadmap feature that displays static image tiles for NPC voice actors or other non-camera presences.
- **Participant** — Any connected FoundryVTT user with an AV presence (camera, microphone, or both), including the GM.
- **Participant State** — One of eight enumerated states describing a Participant's AV presence: `active`, `hidden`, `self-muted`, `offline`, `cam-lost`, `reconnecting`, `never-connected`, `ghost`. Defined in §4.1.
- **Player Privacy Panel** — The per-user settings interface for opting in or out of cinematic automation effects. Scoped to the current user; accessible from module settings.
- **Portrait Fallback** — A static image (user avatar or actor portrait) displayed in place of a live camera feed when a Participant has no camera, or when their feed is `cam-lost`. Enhanced with custom portrait handler integration via `PortraitFallbackHandler`.
- **PortraitFallbackHandler** — Component that manages custom portrait fallback images for participants, with priority: custom fallback → user avatar → character portrait → mystery-man placeholder.
- **Progressive Enhancement Architecture** — The three-level UI model: Level 1 (right-click on existing AV Tiles — zero new UI), Level 2 (Director's Board), Level 3 (Scene Presets + full automation). Each level is independently useful.
- **Pull Visibility Model** — A Later-roadmap visibility model in which feeds remain hidden until a Viewer explicitly requests them.
- **Reaction Cam** — An opt-in feature that automatically spotlights a Participant's feed during key game moments (for example, taking damage in combat). Part of the Later roadmap.
- **Reaction Clip System** — A Later-roadmap fallback that shows a short video snippet when a Participant has no live camera feed.
- **RoleRenderer** — Custom component that replaces Foundry's native AV tile rendering, integrating with ScryingPoolStrip and PortraitFallbackHandler for consistent participant display.
- **Scene Preset** — A saved snapshot of the Visibility Matrix, optionally linked to a FoundryVTT Scene for automatic application on scene activation.
- **ScryingPoolStrip** — The custom AV dock strip component that replaces Foundry's native AV dock, implementing configurable layouts, position persistence, and integrated participant feed management.
- **Spectator View** — A read-only camera layout independent from the Participant layout, intended for streaming audiences. Part of the Later roadmap.
- **The Living Table** — A Later-roadmap concept that exposes the full seating-chart UI for `Map<participantId, Map<viewerId, VisibilityState>>` relationships.
- **Token-Anchored Floating Cams** — A Later-roadmap feature that links camera surfaces to canvas tokens.
- **Visibility Matrix** — The authoritative data structure representing all camera visibility relationships: `Map<participantId, Map<viewerId, VisibilityState>>`. Stored in world-level settings and broadcast to all clients on change.
- **Visibility State** — The visibility setting for one Participant's camera as seen by one Viewer. Distinct from Participant State: a feed can be `active` but have a `hidden` Visibility State for specific viewers.
- **Viewer** — A Participant who is receiving (watching) another Participant's camera feed.
- **Zero-UI Full Automation Mode** — A Later-roadmap mode that minimizes manual camera control after initial configuration.
---
## 4. Features
### 4.1 Core Visibility Toggle
**Description:** The North Star feature. The GM right-clicks any AV Tile to toggle that Participant's visibility for all Viewers. The change broadcasts to all connected clients, persists across reconnections, and updates the AV Tile with a clear indicator explaining *why* the feed is in its current state. All eight Participant States render without layout disruption. Realizes UJ-1, UJ-4.
This feature implements **Level 1** of the Progressive Enhancement Architecture. It adds no new UI beyond a context-menu action on existing AV Tiles.
**Participant States (FR-5):**
| State | Description |
|---|---|
| `active` | Camera on; feed visible to permitted Viewers |
| `hidden` | Camera on; GM has set Visibility State to hidden |
| `self-muted` | Participant voluntarily turned off their own camera |
| `offline` | Participant's connection dropped entirely |
| `cam-lost` | Participant connected but camera device failed |
| `reconnecting` | Transitional; feed is expected to return |
| `never-connected` | Participant joined with no camera device |
| `ghost` | GM observing silently (no AV presence broadcast) |
**Functional Requirements:**
#### FR-1: GM toggles Participant visibility via right-click
The GM can hide or show any Participant's camera feed by right-clicking their AV Tile and selecting "Hide Camera" / "Show Camera." Realizes UJ-1, UJ-4.
**Consequences (testable):**
- Selecting "Hide Camera" sets the target Participant's Visibility State to `hidden` for all Viewers.
- Selecting "Show Camera" sets the target Participant's Visibility State to `active` for all Viewers.
- The AV Tile indicator updates on all connected clients within 500 ms.
- The context-menu entry appears on all AV Tiles when the user is logged in as GM.
**Out of Scope:** Asymmetric visibility (hiding from specific Viewers only) — deferred to Later roadmap.
#### FR-2: Visibility state broadcast via socket
All Visibility Matrix changes are broadcast to all connected clients in real time.
**Consequences (testable):**
- A client that joins mid-session receives the current Visibility Matrix on connection.
- State-change latency from GM action to all-client update stays at or below 500 ms on a local network.
- The module uses the native FoundryVTT socket API through a registered module event (for example, `module.video-view-manager.visibilityUpdate`).
#### FR-3: Visibility state persistence
Visibility Matrix state persists in world-level settings across page refreshes and session breaks.
**Consequences (testable):**
- A Participant who disconnects and reconnects returns to the previously set Visibility State.
- The saved state survives a full FoundryVTT server restart.
- A new Participant defaults to `active` on first connection to the world [ASSUMPTION].
#### FR-4: AV Tile visual indicator for Participant State
Each AV Tile displays a state indicator that distinguishes all relevant Participant States by using plain language and an icon. Realizes UJ-4.
**Consequences (testable):**
- `hidden` state renders a grey overlay, a lock icon, and the tooltip "Camera hidden by GM."
- `self-muted` state renders a camera-off icon distinct from the lock icon.
- `offline` state renders a disconnection icon and the tooltip "Participant offline."
- `cam-lost` state renders a camera-error icon and the tooltip "Camera unavailable."
- `reconnecting` state renders a spinner icon.
- All icons come from the FoundryVTT icon library; the module adds no external dependency.
#### FR-5: Eight Participant States rendered without layout disruption
All Participant States produce appropriate visual feedback and do not cause AV Tile reflow or layout shift for other Participants.
**Consequences (testable):**
- Hiding or revealing a Participant's feed does not change the position of other AV Tiles.
- Mid-combat state transitions (`active` -> `offline` -> `reconnecting`) do not shift the combat tracker or map canvas layout.
- A Participant in `ghost` state has no AV Tile rendered for other Participants.
#### FR-6: GM sees all activated Participant feeds; GM self-view is configurable
The GM always sees all activated Participant feeds regardless of Visibility State. The GM's own feed in their own view can be toggled in a module setting.
**Consequences (testable):**
- Hidden tiles in the GM's view render at reduced opacity with a lock icon overlay.
- The GM hears audio from all Participants regardless of Visibility State.
- The module setting "Show my own feed to myself" (default: ON) controls whether the GM's own AV Tile appears in the GM's interface.
- Other Participants do not render hidden feeds.
#### FR-7: WebRTC track disabling with CSS fallback
Real WebRTC track disabling is the preferred implementation when the FoundryVTT v14 API allows programmatic track access. CSS/DOM cosmetic hiding is the fallback.
**Consequences (testable):**
- When WebRTC track disabling is active, a hidden feed does not consume inbound video bandwidth on the receiving client.
- A world setting reports which mode is active: WebRTC track disabling or CSS fallback.
- [ASSUMPTION: FoundryVTT v14's `game.webrtc` exposes RTCPeerConnection access sufficient for track disabling; see OQ-1.]
**Out of Scope:** Audio track manipulation — this module manages video visibility only. Audio muting remains native FoundryVTT functionality.
#### FR-8: Portrait Fallback for no-camera Participants
When a Participant has no camera device (`never-connected`) or enters `cam-lost` state, their AV Tile displays a Portrait Fallback image.
**Consequences (testable):**
- The default Portrait Fallback uses the FoundryVTT user avatar and falls back to a system placeholder if no avatar is set.
- Participants can set a custom Portrait Fallback through the Player Privacy Panel (FR-26).
- Portrait Fallback renders at the same dimensions as a live camera-feed tile.
- Custom PortraitFallbackHandler integrates with priority: custom fallback portrait -> user.avatar -> user.character?.img -> mystery-man placeholder.
**Feature-specific NFRs:**
- Visibility Matrix updates must not block the FoundryVTT rendering loop; state changes apply asynchronously.
- The module must not interfere with FoundryVTT's native AV mute/unmute controls.
---
### 4.2 Director's Board
**Description:** The Director's Board is a floating window for bulk Visibility Matrix management in sessions with 4+ Participants. It is **Level 2** of the Progressive Enhancement Architecture. The seating-chart layout matches how TTRPG groups visualize the table. Realizes UJ-3.
**Functional Requirements:**
#### FR-9: GM opens Director's Board via sidebar button and keyboard shortcut
A dedicated button in the FoundryVTT controls sidebar opens the Director's Board. A keyboard shortcut (default: `Ctrl+Shift+V`) also opens it. Realizes UJ-3.
**Consequences (testable):**
- The Director's Board opens as a resizable, draggable ApplicationV2 window [ASSUMPTION].
- Opening the Director's Board does not change the existing AV Tile strip.
- The keyboard shortcut is configurable in module settings.
- The window closes and reopens instantly, supporting both a pre-session setup workflow and a live-monitor workflow.
#### FR-10: Director's Board displays full Visibility Matrix in seating-chart layout
All connected Participants are shown with their current Visibility State, name, and portrait.
**Consequences (testable):**
- Every Participant card displays the name, portrait, current Participant State, and current Visibility State.
- The layout reads as a seating chart, not a list.
- Updates to Visibility State appear in the Director's Board within 500 ms, matching FR-2.
- Dock layout selector is available in Director's Board for GM to configure world-level layout preference.
#### FR-11: Per-Participant visibility toggle from Director's Board
The GM can toggle any single Participant's Visibility State from that Participant's card in the Director's Board.
**Consequences (testable):**
- The action matches FR-1 for behavior and persistence.
- The GM toggles a Participant with a single click on that Participant card.
#### FR-12: Bulk actions — Show All and Hide All
Two bulk-action buttons apply Show or Hide to all Participants simultaneously.
**Consequences (testable):**
- "Show All" sets every eligible Participant Visibility State to `active`.
- "Hide All" sets every eligible Participant Visibility State to `hidden`.
- A one-step "Undo" action restores the Visibility Matrix state that existed immediately before the bulk action.
- Participants in `ghost` state are excluded from bulk actions.
#### FR-13: Spotlight action on a single Participant
"Spotlight" shows exactly one Participant's feed and hides all others in a single action.
**Consequences (testable):**
- Spotlight stores the current Visibility Matrix as a pre-spotlight snapshot.
- A "Restore" action reverts to that pre-spotlight snapshot.
- Spotlight remains distinct from a manual Hide All plus Show One sequence: one dedicated action and one undo step.
#### FR-14: Keyboard shortcuts for Director's Board actions
All primary Director's Board actions are accessible without a mouse. Realizes UJ-3.
**Consequences (testable):**
- `Space` or `Enter` toggles the focused Participant.
- Arrow keys move focus between Participant cards.
- `Ctrl+Shift+S` runs Show All, `Ctrl+Shift+H` runs Hide All, and `Ctrl+Shift+P` spotlights the focused Participant.
- The `?` key opens a shortcut reference panel within the Director's Board.
- All shortcuts are configurable and documented in module settings.
---
### 4.3 Scene-Aware Visibility Presets
**Description:** Scene Presets are saved Visibility Matrix configurations that can be applied manually or automatically when a FoundryVTT Scene activates. This is **Level 3** of the Progressive Enhancement Architecture: configure during prep, then use during play. Realizes UJ-1.
**Functional Requirements:**
#### FR-15: GM saves a named Scene Preset from the current Visibility Matrix
Any current Visibility Matrix state can be saved as a named preset with a single action from the Director's Board or module settings.
**Consequences (testable):**
- The preset captures the full current Visibility Matrix at save time.
- The preset name is editable, and names remain unique within a world.
- Up to 50 presets can be stored in world settings [ASSUMPTION: adequate for any campaign].
#### FR-16: GM loads a Scene Preset at any time
Applying a preset overrides the current Visibility Matrix.
**Consequences (testable):**
- All clients receive the preset state within 500 ms through the same path as FR-2.
- Loading a preset generates the Contextual Notification defined in FR-20: "GM applied preset: [Preset Name]."
- The preset applies regardless of which Participants are online; offline Participants receive the stored state on reconnection under FR-3.
#### FR-17: Scene Preset auto-applies on FoundryVTT Scene activation
A preset can be linked to a Scene; it applies automatically when that Scene is activated.
**Consequences (testable):**
- The Scene-to-Preset association is configured in Scene settings or module settings.
- Auto-apply fires on the `updateScene` hook, and a configurable 0-5000 ms pre-delay supports dramatic transitions [ASSUMPTION: sufficient hook timing — to be verified during FR-17 development].
- All clients receive the notification "Scene changed: camera layout updated." matching UJ-1.
#### FR-18: Scene Preset auto-apply can be disabled per scene or globally
GMs retain full manual override.
**Consequences (testable):**
- A per-scene toggle disables auto-apply for that Scene without removing the association.
- A global "Disable All Auto-Apply" toggle in module settings overrides all per-Scene configurations.
- The Director's Board always provides a manual override during play, regardless of automation state.
#### FR-19: Preset import/export as JSON
Presets can be exported to and imported from a JSON file.
**Consequences (testable):**
- Export writes all presets to one human-readable JSON file that the browser downloads.
- Import reads a JSON file and merges or replaces existing presets, based on user choice; invalid JSON shows an error.
- The module README documents the exported JSON format for community sharing.
---
### 4.4 Contextual Notifications
**Description:** Contextual Notifications use plain-language toasts to inform Participants when camera states change. They prevent silent surprises, and notification verbosity is configurable. Realizes UJ-4.
**Functional Requirements:**
#### FR-20: Toast notification on GM visibility change
When the GM changes any Participant's Visibility State, all Participants receive a toast notification in plain language.
**Consequences (testable):**
- The message uses the Participant display name: "GM hid [Name]'s camera" or "GM showed [Name]'s camera."
- The toast uses FoundryVTT's native notification UI.
- The affected Participant receives a distinct personal notification: "GM has hidden your camera. Your portrait is shown to other Participants."
#### FR-21: Notification verbosity configuration
Notification output is configurable per user.
**Consequences (testable):**
- Three modes are available: `All` (default), `GM Only`, and `Silent`.
- The configuration is stored in user-level client settings, not world settings.
- `Silent` mode still shows the personal notification to the affected Participant; the GM cannot suppress the FR-20 personal message.
#### FR-22: Persistent feed status indicator on own AV Tile
Each Participant always sees the current state of their own feed through a persistent status badge on their own AV Tile.
**Consequences (testable):**
- The badge shows one of these states: "Live," "Hidden by GM," "Muted," or "No Camera."
- The badge updates within 500 ms when the state changes.
- Only the owning Participant sees the badge; other Participants do not see badges on other AV Tiles.
---
### 4.5 Player Privacy Panel
**Description:** The Player Privacy Panel contains per-user settings for consenting to, or withdrawing consent from, cinematic automation effects that touch individual Participants. Design principle: **automation effects that touch a Participant's on-screen presence require explicit opt-in and remain off by default.** The GM retains unconditional hide/show authority under FR-1. Automation that auto-spotlights or visually modifies a Participant remains opt-in by user choice. Realizes UJ-2.
**Functional Requirements:**
#### FR-23: Player Privacy Panel accessible from module settings
Each user can open their Player Privacy Panel from the module settings tab in FoundryVTT.
**Consequences (testable):**
- The panel lists every automation effect that can touch the owning user, along with the current opt-in status.
- The owning user can edit the panel; the GM can view but not edit another Participant's panel settings.
- The settings persist in world-level user flags.
#### FR-24: Opt-in to Reaction Cam automation
A Participant must explicitly opt in before Reaction Cam (Later roadmap) can auto-spotlight them. The default is **off**.
**Consequences (testable):**
- Reaction Cam remains disabled for a Participant unless that Participant explicitly enables it in the Player Privacy Panel.
- The Director's Board displays a "Reaction Cam: Enabled" badge on opted-in Participant cards; no badge means off.
- The opt-in flag persists across sessions until the user changes it.
- Combat Cinematics Mode and any other Reaction Cam trigger respect this flag; they skip opted-out Participants silently.
#### FR-25: Opt-in to HP-Reactive Cam Styling
A Participant must explicitly opt in before HP-Reactive Cam Styling (Later roadmap) applies to their feed. The default is **off**.
**Consequences (testable):**
- HP-Reactive Cam Styling remains disabled for a Participant unless that Participant explicitly enables it.
- The GM is not notified of individual styling opt-in statuses; this preference remains private.
#### FR-26: Custom Portrait Fallback
A Participant can set a custom image as their Portrait Fallback (used in FR-8 when the camera is unavailable).
**Consequences (testable):**
- A file picker in the Player Privacy Panel sets the custom portrait.
- Accepted formats are PNG, JPG, WEBP, and static GIF.
- The image falls back to the FoundryVTT user avatar if no custom portrait is set, then to the system placeholder if no avatar exists.
- Custom portraits are handled by PortraitFallbackHandler with proper priority chain.
---
### 4.6 Full AV Dock Replacement
**Description:** Complete replacement of FoundryVTT's native AV dock with custom implementation via ScryingPoolStrip and RoleRenderer. This provides full control over participant feed rendering, layout, and display.
**Functional Requirements:**
#### FR-27: Custom AV dock strip (ScryingPoolStrip)
The module replaces Foundry's native AV dock with ScryingPoolStrip, a custom ApplicationV2-based component.
**Consequences (testable):**
- ScryingPoolStrip opens automatically for all users (GM and players) when AV is active.
- The strip is implemented using FoundryVTT v14 ApplicationV2 API with HandlebarsApplicationMixin.
- Custom templates (roster-strip.hbs) render participant tiles with configurable layout.
- Strip integrates with PortraitFallbackHandler for consistent portrait display.
#### FR-28: Custom role rendering (RoleRenderer)
RoleRenderer component handles individual participant feed rendering and management.
**Consequences (testable):**
- RoleRenderer coordinates between StateStore, ScryingPoolController, AVTileAdapter, and PortraitFallbackHandler.
- Participant list is built with proper priority for fallback portraits (custom -> user avatar -> character portrait -> mystery-man).
- RoleRenderer manages strip lifecycle (open, close, rerender).
---
### 4.7 Dock Layout System
**Description:** Configurable dock layout options for the AV dock strip, allowing GMs and users to customize how participant tiles are arranged.
**Functional Requirements:**
#### FR-29: Dock layout configuration
The module provides 6 layout options via world-scoped `dockLayout` setting.
**Consequences (testable):**
- Available layouts: `vertical-sm`, `vertical-md`, `horizontal-sm`, `horizontal-md`, `mosaic-sm`, `mosaic-md`.
- Layout is configured via Director's Board UI with visual selector.
- Changing layout re-renders the strip for all users via onChange callback.
- Default layout is `vertical-sm`.
#### FR-30: Per-user layout size override
Users can override the GM's layout size preference via client-scoped `dockLayoutExpanded` setting.
**Consequences (testable):**
- Setting values: `''` (inherit from world), `'sm'` (force small), `'md'` (force large).
- Client setting only affects size, not layout direction (vertical/horizontal/mosaic).
- Changing client override re-renders the strip for that user only.
- Legacy boolean values are migrated to string format automatically.
---
### 4.8 Position Persistence
**Description:** The ScryingPoolStrip remembers its window position across sessions for consistent user experience.
**Functional Requirements:**
#### FR-31: Window position persistence
ScryingPoolStrip position is saved and restored from GM user flags.
**Consequences (testable):**
- Position (left, top coordinates) is saved when strip is moved.
- Position is loaded on module initialization via `_loadPosition()` method.
- Saved position applies only to the GM user; player strip positions follow GM configuration.
- First-time users get default position (left: 0, top: 0) or system default.
---
### 4.9 Implementation Quality
**Description:** Code quality improvements and FoundryVTT v14 compatibility.
**Functional Requirements:**
#### FR-32: ApplicationV2 API compatibility
All UI components properly extend and use FoundryVTT v14 ApplicationV2 API.
**Consequences (testable):**
- ScryingPoolStrip extends HandlebarsApplicationMixin(ApplicationV2).
- DirectorsBoard extends HandlebarsApplicationMixin(ApplicationV2).
- All _onRender, _prepareContext, and _onClose methods properly implemented.
- jQuery parameter handling is compatible with ApplicationV2 expectations.
---
## 5. Non-Goals (Explicit)
- **Not an AV transport layer.** This module does not host, relay, or record audio/video streams. FoundryVTT's native WebRTC / AV stack handles all transport.
- **No audio control.** The module manages video visibility only. Muting audio remains native FoundryVTT functionality.
- **No recording or archiving.** No session video capture or replay features in v1.0.
- **FoundryVTT v13 and earlier are not supported.** v14 is the minimum compatibility floor; no backport is planned.
- **No central preset registry.** Community preset sharing is a local JSON export/import workflow only. No cloud or server-side storage.
- **No AI-driven visibility decisions.** All visibility changes are GM-initiated or rule-based (Scene Preset auto-apply). No ML or heuristic automation.
- **No asymmetric per-Viewer visibility (v1.0).** The Visibility Matrix is GM-to-everyone in v1.0; the full `Map<participantId, Map<viewerId, VisibilityState>>` model is architecturally supported but is not exposed in the UI until the Later roadmap.
- **No third-party streaming platform integration.** No OBS, Twitch, or YouTube API in v1.0. Browser Source API is a Later roadmap item.
- **Native WebRTC AV backend only (v1.0).** The module operates exclusively with FoundryVTT's built-in WebRTC stack. Jitsi Meeting Server and other third-party AV backends are not supported in v1.0; they are deferred to the Later roadmap.
---
## 6. MVP Scope
### 6.1 In Scope (v1.0)
- Core Visibility Toggle (FR-1 - FR-8): right-click toggle, broadcast, persistence, visual indicators, 8 Participant States, WebRTC track disabling with CSS fallback, Portrait Fallback
- Director's Board (FR-9 - FR-14): seating-chart window, bulk actions, Spotlight, keyboard shortcuts
- Scene-Aware Visibility Presets (FR-15 - FR-19): save, load, auto-apply, and JSON import/export
- Contextual Notifications (FR-20 - FR-22): toast system, verbosity configuration, persistent self-status badge
- Player Privacy Panel (FR-23 - FR-26): opt-in controls for future automation effects, custom portrait
- **Full AV Dock Replacement (FR-27 - FR-28)**: ScryingPoolStrip and RoleRenderer components
- **Dock Layout System (FR-29 - FR-30)**: 6 layout options with per-user override
- **Position Persistence (FR-31)**: Window position saved and restored
- **ApplicationV2 Compatibility (FR-32)**: Full v14 API compliance
- FoundryVTT v14+ compatibility; `module.json` per v14 manifest schema
- English UI strings; i18n-ready string keys for community translation
- CSS build pipeline with postinstall script for automatic CSS compilation
### 6.2 Out of Scope for MVP
- Combat Cinematics Mode (auto-spotlight active combatant) — deferred to Later; see §10. `[NOTE FOR PM: This is emotionally load-bearing for Marcus-persona GMs. Consider as v1.1 if Day 1 ship goes smoothly.]`
- Reaction Cam (auto-spotlight on damage/dramatic event) — deferred to Later; see §10
- Director's Board Stage Lighting States (Wash / Focus / Blackout presets) — deferred to Later
- Token-Anchored Floating Cams — deferred to Later; requires deep canvas integration
- HP-Reactive Cam Styling — deferred to Later
- Spectator View / Dual Layout System — deferred to Later
- Browser Source API (OBS-ready tile URLs) — deferred to Later
- NPC Presence Tiles — deferred to Later
- Zero-UI Full Automation Mode — deferred to Later
- Pull Visibility Model (opt-in to see feeds) — deferred to Later
- Reaction Clip System (video snippet fallback for no-camera Participants) — deferred to Later
- Full asymmetric per-Viewer visibility in the Director's Board — deferred to Later
- FoundryVTT v13 compatibility backport — will not build
---
## 7. Success Metrics
**Primary**
- **SM-1: Installation count** — 500 installs within 90 days of Foundry Hub listing. Validates FR-1 through FR-8 (broad appeal of the core feature).
- **SM-2: Weekly active worlds** — ≥30% of installing worlds use the module in at least one session per week after the first week. Validates overall module stickiness across all v1.0 features.
**Secondary**
- **SM-3: Core toggle regression-free** — Zero bug reports for FR-1 through FR-4 (basic toggle + persistence) in the first 30 days. Validates Day 1 reliability.
- **SM-4: Open P1 bug count** — No more than 3 open P1 bugs at any point in the first 90 days. Validates overall module quality.
- **SM-5: State-persistence failures** — Zero user-reported Visibility State loss across reconnection (FR-3) after 30 days.
**Counter-metrics (do not optimize)**
- **SM-C1: Feature depth penetration** — Do not optimize for users enabling every feature. The module is successful if most users remain at Level 1 (right-click only) and only power users reach Level 3 (Scene Presets + Director's Board). Depth adoption is a health signal, not the goal. Counterbalances SM-1 and SM-2.
- **SM-C2: Notification frequency** — Do not make toast notifications more prominent, frequent, or verbose. FR-20 notifications exist to remove confusion, not to draw attention. Counterbalances SM-3.
---
## 8. Open Questions
1. **OQ-1:** Does FoundryVTT v14's `game.webrtc` / `AVMaster` API expose a programmatic method for disabling a specific peer's incoming video track (RTCPeerConnection track manipulation), or must the module hook at a lower level? To be resolved by inspecting the v14 AV API during development. FR-7 CSS fallback is the safe default until confirmed.
2. ~~**OQ-2 (Phase blocker):** Is `socketlib` the recommended socket broadcast approach for v14, or does FoundryVTT v14 expose a sufficient native socket API?~~ **RESOLVED:** Native FoundryVTT socket API will be used. `socketlib` dependency will not be added.
3. ~~**OQ-3:** What is the intended behavior when the GM's own feed is set to `hidden` — should the GM see their own feed in their view unchanged, or see the hidden state overlay like other GMs would?~~ **RESOLVED:** The GM always sees all activated Participant feeds. The GM's own feed visibility in their own view is a configurable option (show/hide self-view).
4. ~~**OQ-4:** Should the module operate with Jitsi Meeting Server and other non-native AV backends (beyond native WebRTC), or is native WebRTC the only supported backend for v1.0?~~ **RESOLVED:** Native WebRTC only for v1.0. Non-native backends (Jitsi, etc.) are deferred to the Later roadmap.
5. **OQ-5:** Do FoundryVTT v14 scene activation hooks fire early enough for Scene Preset auto-apply (FR-17) to avoid a visible flash of the wrong camera layout before the preset applies? Not a concern for the first implementation stage — defer to testing.
6. **OQ-6:** Should Scene Presets support partial application — applying only to currently connected Participants and deferring state for offline ones — or should they always apply to all participant slots unconditionally? This cannot be decided yet and will be resolved during FR-15/FR-16 implementation.
7. **OQ-7 (NEW):** Does the full AV dock replacement (FR-27-28) properly handle all edge cases of Foundry's native AV system, including dynamic participant join/leave, device changes, and AV mode toggles?
---
## 9. Assumptions Index
- **§4.1 / FR-3:** New Participants default to `active` Visibility State on first connection to a world. This is the socially safe default.
- **§4.1 / FR-7:** FoundryVTT v14's WebRTC implementation exposes RTCPeerConnection objects at a level accessible to a module, enabling programmatic track disabling without patching the core AV system.
- **§4.2 / FR-9:** FoundryVTT v14's `ApplicationV2` API is the correct pattern for a resizable floating window with persistent state.
- **§4.3 / FR-15:** 50 presets per world is an adequate upper bound for any campaign use case. If communities surface larger preset libraries, this can increase.
- **§4.3 / FR-17:** The `updateScene` hook (or its v14 equivalent) fires early enough in the scene-transition lifecycle to apply the preset before the AV Tile strip re-renders.
- **§4.6 / FR-27:** ScryingPoolStrip as ApplicationV2-based component can fully replace Foundry's native AV dock without breaking core functionality.
- **§4.7 / FR-29:** 6 dock layout options (vertical-sm/md, horizontal-sm/md, mosaic-sm/md) cover the majority of table configuration needs.
- **§4.8 / FR-31:** GM user flags are the appropriate storage mechanism for strip position persistence.
---
## 10. Product Roadmap (Later Features)
The following concepts from the brainstorming session are architecturally consistent with v1.0 but are deferred to keep the initial release focused. They are listed here to prevent scope creep in v1.0 tickets while preserving the broader product vision.
| Concept | Brainstorm ID | Theme | Notes |
|---|---|---|---|
| Combat Cinematics Mode | #4 | Automation | Auto-spotlight active combatant; requires Reaction Cam opt-in (FR-24) already in v1.0 |
| Reaction Cam | #5, #17 | Cinematic | Opt-in per FR-24; triggers from game events |
| Director's Board Stage Lighting States | #7 | Cinematic | Wash / Focus / Blackout vocabulary tier |
| Token-Anchored Floating Cams | #8 | Cinematic | Deep canvas integration; high complexity |
| HP-Reactive Cam Styling | #9 | Cinematic | Opt-in per FR-25 already scaffolded in v1.0 |
| NPC Presence Tiles | #10 | Extended Presence | Static image tiles for NPC voice actors |
| Spectator View | #11 | Streaming | Independent audience layout |
| Zero-UI Full Automation Mode | #12 | Automation | Full configure-once, no-touch operation |
| The Living Table (full seating chart) | #1 | Core Architecture | Full `Map<p, Map<v, State>>` UI exposure |
| Pull Visibility Model | #14 | Core Architecture | Nothing is visible until actively requested |
| Reaction Clip System | #15 | Privacy + Presence | Video snippet fallback for no-camera Participants |
| Dual Layout System + Browser Source API | #18, #19 | Streaming | OBS-ready tile URLs; production stack |
---
## Cross-Cutting NFRs
**Compatibility**
- The module must not conflict with other popular FoundryVTT modules (Monk's Hotbar, Token Action HUD, etc.) by patching shared DOM selectors or overriding core FoundryVTT hooks without proper chaining.
- All hooks must use FoundryVTT's `Hooks.on()` registration pattern, never `Hooks.once()` for persistent behavior.
- **NEW:** Full AV replacement must coexist with other modules that patch AV-related hooks; proper hook chaining is required.
**Performance**
- No Visibility Matrix operation should block the FoundryVTT main render loop.
- The Director's Board must render and become interactive within 1 second even with 12 Participants.
- Socket message payload for a Visibility Matrix update must be ≤ 4 KB.
- **NEW:** Strip rendering with 6+ participants must maintain 60fps in all layout modes.
**Reliability**
- If the socket broadcast fails because of a network interruption, the GM client retries up to 3 times before surfacing an error notification.
- The module must fail gracefully if `game.webrtc` is unavailable (for example, when AV is disabled); all UI elements are hidden or disabled rather than erroring.
- **NEW:** Position persistence must handle corrupted or invalid saved positions gracefully.
**Privacy**
- The module does not transmit any data outside the FoundryVTT world. No analytics, telemetry, or third-party calls.
- Participant names and portraits are used only within the FoundryVTT session; no external storage is allowed.
- **NEW:** Custom portrait images are stored in FoundryVTT's standard file storage; no external uploads.
**Accessibility**
- All interactive elements in the Director's Board have ARIA labels and are keyboard navigable (FR-14).
- State-indicator icons (FR-4) include tooltip text for screen-reader compatibility.
- **NEW:** All dock layout options are keyboard-navigable and have proper ARIA labels.
**Language and Voice**
- Default UI labels use plain language: "Show," "Hide," "Spotlight," "Hidden by GM," "No Camera." Technical or cinematic vocabulary (for example, "Visibility Matrix" or "Wash / Focus / Blackout") is reserved for documentation, tooltips in advanced mode, and developer-facing strings — never as primary interface labels.
- This two-tier vocabulary principle applies to all present and future features. Downstream contributors must follow the plain-language default; advanced or cinematic terms may appear only in optional advanced mode.
**GM Override Guarantee**
- Every automation feature — present (Scene Presets, FR-17/FR-18) and future (Combat Cinematics Mode, Reaction Cam, Zero-UI Full Automation Mode) — must expose an obvious one-click GM override that is accessible without opening configuration UI.
- The Director's Board "Hide All" action (FR-12) serves as the module's emergency path: the GM can silence all cameras in one click at any time, regardless of active automation state.
- This is a non-negotiable cross-cutting rule: no automation may be implemented if it cannot be interrupted or overridden immediately by the GM.
**Delivery Risk Note (v1.0 scope)**
- v1.0 intentionally combines the Day 1 core toggle (FR-1-8) with Week 1-2 enhancements (FR-9-26) and live-test enhancements (FR-27-32) into a single release. The brainstorming established Day 1 as a shippable standalone product; if delivery constraints arise, the Level 1 core toggle (FR-1-8) is the minimum shippable increment, and all higher-level features can shift to v1.1 without breaking the architecture.
---