Story 5.2: Video Widget Width Customization

Implements configurable video widget widths for small and large dock layouts:
- Add widgetWidthSm and widgetWidthMd world settings (defaults: 83px, 150px)
- Add width dropdown selectors in Director's Board UI
- Apply width settings to participant avatars via CSS custom properties
- Update strip width/height calculations to use custom widths
- Add localization strings for widget width settings
- Add CSS styling for widget width dropdown controls
- Fix Handlebars template syntax for select element selected values

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
This commit is contained in:
2026-05-25 12:43:06 +02:00
parent 748c7d7f85
commit 7a0d935239
15 changed files with 1967 additions and 19 deletions
@@ -3,7 +3,7 @@
**Workspace:** `_bmad-output/planning-artifacts/prds/prd-video-view-manager-2026-05-19/`
**Created:** 2026-05-19
**Author:** Morr
**Last Updated:** 2026-05-25
**Last Updated:** 2026-05-26
---
@@ -166,13 +166,26 @@
- Moved styles to root styles/ folder for FoundryVTT compatibility
- Updated .gitignore to allow dist/styles/ for CSS distribution
### D-22 — Video Widget Width Customization (v0.1.1)
**Date:** 2026-05-26
**Decision:** Add configurable width options for small and large video tiles via dropdown selection in Director's Board.
**Rationale:** User feedback requested ability to customize video widget size to match screen space and table preferences. Extends the existing Dock Layout System (D-17) by adding granular control over tile dimensions.
**Status:** Planned for v0.1.1. Captured in FR-33, FR-34.
**Implementation Notes:**
- Two world-scoped settings: `widgetWidthSm` (default: 80px) and `widgetWidthMd` (default: 120px)
- Dropdown options: 60px, 80px, 100px, 120px, 150px, 200px
- Dropdown UI in Director's Board settings panel
- Applies to all dock layout variants (vertical, horizontal, mosaic)
- Independent of layout direction
- OnChange callback triggers strip re-render for all users
---
## Decision Summary Table
| Decision | Date | Status | Related FRs | Section |
|----------|------|--------|-------------|---------|
| D-1 | 2026-05-19 | Active | FR-1-32 | §1, §6, §10 |
| D-1 | 2026-05-19 | Active | FR-1-34 | §1, §6, §10 |
| D-2 | 2026-05-19 | Active | FR-7 | §4.1, §9 |
| D-3 | 2026-05-19 | Active | All | §5, §6 |
| D-4 | 2026-05-19 | Active | All | §7, Cross-cutting |
@@ -193,6 +206,7 @@
| **D-19** | **2026-05-20** | **Active** | **FR-32** | **§4.9** |
| **D-20** | **2026-05-23** | **Active** | **FR-8, FR-26** | **§4.1, §4.5** |
| **D-21** | **2026-05-24** | **Active** | **N/A** | **§6.1** |
| **D-22** | **2026-05-26** | **Planned** | **FR-33, FR-34** | **§4.7.5** |
---
@@ -207,6 +221,7 @@
| OQ-5: Scene hook timing | No | Open — not a concern for first implementation stage | |
| OQ-6: Partial vs full preset application | No | Open — to be resolved during FR-15/FR-16 implementation | |
| **OQ-7: Full AV replacement edge cases** | **No** | **Open** — Does full AV dock replacement handle all edge cases? | **D-16** |
| **OQ-8: Widget width defaults** | **No** | **Open** — Optimal default width values for small (80px) and large (120px)? | **D-22** |
---
@@ -216,3 +231,4 @@
|---------|------|--------|--------|---------|
| 1.0 | 2026-05-19 | final | Morr | Initial PRD with FR-1 through FR-26 |
| **1.1** | **2026-05-25** | **draft** | **Morr** | **Added FR-27 through FR-32 from live testing; updated D-1, added D-16 through D-21** |
| **1.2** | **2026-05-26** | **draft** | **Morr** | **Added FR-33 through FR-34 for v0.1.1 (Video Widget Width Customization); added D-22, OQ-8** |
@@ -0,0 +1,484 @@
# Addendum — Video View Manager PRD
**Workspace:** `_bmad-output/planning-artifacts/prds/prd-video-view-manager-2026-05-19/`
**Created:** 2026-05-25
**Author:** Morr
**Purpose:** Capture implementation decisions, technical notes, and downstream documentation that earned a place but does not fit the PRD's main narrative.
---
## Implementation Notes from Live Testing (May 20-25, 2026)
### Full AV Dock Replacement (Story 5-1)
**Decision:** Implement complete replacement of Foundry's native AV dock rather than hooking into it.
**Rationale:**
- Hooking approach proved unreliable during live testing
- Full replacement provides consistent behavior across all AV states
- Enables advanced features like dock layouts and position persistence
- Better control over rendering pipeline
**Implementation Details:**
- **ScryingPoolStrip**: Custom ApplicationV2-based component that serves as the main AV dock
- Replaces `game.webrtc.render()` output
- Opens automatically for all users when AV is active
- Uses Handlebars templates (roster-strip.hbs)
- Integrates with RoleRenderer for participant management
- **RoleRenderer**: Orchestrator component that:
- Manages ScryingPoolStrip lifecycle
- Coordinates between StateStore, ScryingPoolController, AVTileAdapter
- Handles participant list building with proper fallback priorities
- Provides `rerenderStrip()` method for on-demand refreshes
**Files Modified:**
- `src/ui/gm/ScryingPoolStrip.js` - Complete rewrite to ApplicationV2
- `src/ui/RoleRenderer.js` - Enhanced with rerenderStrip capability
- `module.js` - Updated to open strip for all users, not just GM
- `templates/roster-strip.hbs` - Custom template for participant tiles
- `styles/scrying-pool.css` - Main stylesheet
- `styles/components/_roster-strip.less` - Strip-specific styles
**Technical Notes:**
- Strip is created and opened during `ready` hook
- Previous implementation only opened for GM; now opens for all users
- Position loading happens in `_loadPosition()` method
- Strip is automatically closed and reopened when layout changes
**Compatibility Considerations:**
- Must coexist with other modules that patch AV-related hooks
- Proper hook chaining required to avoid conflicts
- Native Foundry AV controls remain functional
---
### Dock Layout System
**Decision:** Implement 6 configurable layout options with GM control and per-user override.
**Implementation Details:**
**World-Scoped Setting: `dockLayout`**
- Type: String
- Default: `"vertical-sm"`
- Options: `vertical-sm`, `vertical-md`, `horizontal-sm`, `horizontal-md`, `mosaic-sm`, `mosaic-md`
- OnChange: Triggers `roleRenderer?.rerenderStrip()`
- UI: Configured via Director's Board with visual icon selector
**Client-Scoped Setting: `dockLayoutExpanded`**
- Type: String
- Default: `""` (empty string = inherit from world)
- Options: `""` (inherit), `"sm"` (force small), `"md"` (force large)
- OnChange: Triggers `roleRenderer?.rerenderStrip()`
- Purpose: Allows individual users to override GM's size preference
**Layout Resolution Logic:**
```javascript
const rawLayout = settings.get('dockLayout'); // e.g., "vertical-sm"
const baseLayout = typeof rawLayout === 'string' ? rawLayout : 'vertical-sm';
const sizeOverride = settings.get('dockLayoutExpanded'); // '' | 'sm' | 'md'
const parts = baseLayout.split('-');
const dir = parts.slice(0, -1).join('-'); // e.g., "vertical"
const canonicalSize = parts[parts.length - 1]; // e.g., "sm"
const effectiveSize = (sizeOverride === 'sm' || sizeOverride === 'md')
? sizeOverride
: canonicalSize;
const dockLayout = `${dir}-${effectiveSize}`; // e.g., "vertical-md"
```
**Layout Characteristics:**
- `vertical-sm`: Compact vertical list, small tiles, icons only
- `vertical-md`: Expanded vertical list, large tiles, shows names
- `horizontal-sm`: Compact horizontal row, small tiles
- `horizontal-md`: Expanded horizontal row, large tiles with names
- `mosaic-sm`: Grid layout, small tiles
- `mosaic-md`: Grid layout, large tiles with names
**Files Modified:**
- `src/ui/gm/DirectorsBoard.js` - Added dock layout selector to UI
- `src/ui/gm/ScryingPoolStrip.js` - Layout resolution and rendering logic
- `module.js` - Setting registrations with onChange callbacks
- `lang/en.json` - Added localization strings for layout options
- `templates/directors-board.hbs` - Added layout selector UI
- `styles/components/_directors-board.less` - Layout selector styling
- `styles/components/_roster-strip.less` - Per-layout styling
**Migration Notes:**
- Legacy boolean values for `dockLayoutExpanded` are automatically migrated to string format
- Migration code in `ready` hook checks for boolean values and resets to `""`
---
### Position Persistence
**Decision:** Save and restore ScryingPoolStrip window position.
**Implementation Details:**
**Storage Mechanism:**
- Position saved to GM user flags: `game.user.setFlag('scrying-pool', 'stripState', { left, top })`
- Loaded during strip construction via `_loadPosition()` method
- Applied to options.position before initial render
**Position Object:**
```javascript
{
left: number, // CSS pixel value
top: number // CSS pixel value
}
```
**Lifecycle:**
1. Strip constructed with default position
2. `_loadPosition()` called in constructor
3. If saved position exists, applied to `this.options.position`
4. Strip rendered at saved position
5. On drag/move, new position saved to flags
**Files Modified:**
- `src/ui/gm/ScryingPoolStrip.js` - Added `_loadPosition()` method
- `module.js` - No changes needed; handled internally
**Edge Cases:**
- First-time users: No saved position, uses default
- Invalid position values: Caught and ignored, uses default
- Corrupted flags: Handled gracefully with try/catch
---
### PortraitFallbackHandler Integration
**Decision:** Enhance portrait fallback with dedicated handler component.
**Implementation Details:**
**Priority Chain:**
1. Custom fallback portrait (from Player Privacy Panel)
2. User avatar (`user.avatar`)
3. Character portrait (`user.character?.img`)
4. Mystery-man placeholder (`icons/svg/mystery-man.svg`)
**Integration Points:**
- Passed to `buildParticipantList()` function
- Used in RoleRenderer construction
- Applied when building participant objects for strip rendering
**Code Example:**
```javascript
const avatarSrc = portraitFallbackHandler?.getFallbackImageURL(userId)
|| user.avatar
|| user.character?.img
|| 'icons/svg/mystery-man.svg';
```
**Files Modified:**
- `src/ui/RoleRenderer.js` - Passes handler to strip
- `src/ui/gm/ScryingPoolStrip.js` - Accepts handler in constructor
- `src/ui/gm/ScryingPoolStrip.js` - Uses handler in `buildParticipantList`
- `module.js` - Handler created and passed to RoleRenderer
---
### ApplicationV2 Migration
**Decision:** Migrate all UI components to ApplicationV2 API.
**Changes from Previous Implementation:**
**Before (Application base class):**
```javascript
static get defaultOptions() {
return {
id: 'scrying-pool-strip',
popOut: true,
resizable: false,
title: 'Scrying Pool',
classes: ['scrying-pool-strip'],
};
}
```
**After (ApplicationV2 with HandlebarsApplicationMixin):**
```javascript
static DEFAULT_OPTIONS = {
id: 'scrying-pool-strip',
classes: ['scrying-pool-strip'],
window: { title: 'Scrying Pool', resizable: false },
position: { width: 240 },
};
static PARTS = {
strip: {
template: 'modules/scrying-pool/templates/roster-strip.hbs',
},
};
constructor(options) {
super(options);
// ApplicationV2 lifecycle methods
}
async _prepareContext(options) {
// Return context for template
}
_onRender(context, options) {
// Called after render
}
_onClose() {
// Called on close
}
```
**Key Differences:**
- Uses `DEFAULT_OPTIONS` static property instead of `defaultOptions` getter
- Uses `PARTS` static property for template configuration
- Lifecycle methods: `_prepareContext`, `_onRender`, `_onClose`
- Proper position management via `setPosition()`
- Better separation of concerns
**Files Modified:**
- `src/ui/gm/ScryingPoolStrip.js` - Complete migration to ApplicationV2
- `src/ui/gm/DirectorsBoard.js` - Verified ApplicationV2 compatibility
- Fixed jQuery parameter handling in `_onRender` methods
**Bug Fixes:**
- Fixed `DirectorsBoard` position loading error (D-19)
- Fixed ApplicationV2 jQuery parameter handling (a05d3ca)
---
### CSS Build Pipeline
**Decision:** Automate CSS compilation from LESS source files.
**Implementation Details:**
**Build Script:**
- Added to `package.json`:
```json
"scripts": {
"build:css": "lessc styles/scrying-pool.less > styles/scrying-pool.css",
"postinstall": "npm run build:css"
}
```
**File Structure:**
```
styles/
├── scrying-pool.less # Main LESS file (imports components)
├── scrying-pool.css # Compiled output (gitignored, generated)
└── components/
├── _directors-board.less # Director's Board styles
├── _roster-strip.less # Strip styles
└── ...
```
**Changes:**
- Moved CSS to root `styles/` folder for FoundryVTT compatibility
- Added component LESS files for better organization
- Updated `.gitignore` to allow `dist/styles/` for distribution
- Updated `module.json` styles reference
- Added build comments to scrying-pool.less
**Git Changes:**
- `styles/scrying-pool.css` - Generated, not tracked in git
- `styles/scrying-pool.less` - Source file, tracked
- `.gitignore` - Added `dist/styles/` exception
- `package.json` - Added build scripts
---
## Module Settings Reference
### World-Scoped Settings
| Setting Key | Type | Default | Description | onChange |
|------------|------|---------|-------------|----------|
| `visibilityMatrix` | Object | `{ _version: 1, matrix: {} }` | Visibility state for all participants | Triggers stateStore.init() and strip rerender |
| `dockLayout` | String | `"vertical-sm"` | Dock layout configuration | Triggers roleRenderer.rerenderStrip() |
| `autoApplyEnabled` | Boolean | `true` | Enable Scene Preset auto-apply | None |
| `showGMSelfFeed` | Boolean | `true` | Show GM's own feed in their view | None |
### Client-Scoped Settings
| Setting Key | Type | Default | Description | onChange |
|------------|------|---------|-------------|----------|
| `dockLayoutExpanded` | String | `""` | Per-user layout size override | Triggers roleRenderer.rerenderStrip() |
| `notificationVerbosity` | String | `"all"` | Notification output mode | None |
---
## Technical Architecture Notes
### Component Hierarchy
```
FoundryVTT Core
├── game.webrtc (native AV)
└── Module: scrying-pool
├── module.js (entry point)
│ ├── Hooks registration
│ ├── Settings registration
│ └── Component initialization
├── Data Layer
│ ├── FoundryAdapter (settings, users, hooks wrapper)
│ ├── StateStore (visibility matrix persistence)
│ └── SocketHandler (broadcast and receive)
├── Core Logic
│ ├── ScryingPoolController (visibility management)
│ └── VisibilityManager (state mutations)
├── UI Layer
│ ├── RoleRenderer (AV dock orchestrator)
│ │ └── ScryingPoolStrip (custom AV dock)
│ │ ├── templates/roster-strip.hbs
│ │ └── styles/components/_roster-strip.less
│ │
│ ├── GM Controls
│ │ ├── DirectorsBoard (bulk management)
│ │ │ ├── templates/directors-board.hbs
│ │ │ └── styles/components/_directors-board.less
│ │ ├── ConfirmationBar (preset feedback)
│ │ └── ActionPopover (right-click menu)
│ │
│ ├── Player Controls
│ │ └── PlayerPrivacyPanel (opt-in management)
│ │
│ └── Shared
│ ├── ScryingPoolCameraViews (AV integration)
│ ├── StripOverlayLayer (UI overlays)
│ └── PortraitFallbackHandler (image resolution)
└── Utilities
├── uuid.js (ID generation)
└── ...
```
### Hook Registration
**Hooks Used:**
- `init` - Module initialization, settings registration
- `ready` - Component construction, AV integration
- `setup` - Early initialization
- `renderAVConfig` - AV configuration rendering
- `updateScene` - Scene activation (for preset auto-apply)
- Various AV-related hooks for full replacement
**Hook Pattern:**
```javascript
Hooks.on('hookName', () => {
// Handler code
});
```
---
## Testing Notes
### Unit Tests
- Tests located in `tests/unit/`
- Primarily test ScryingPoolStrip functionality
- Mock FoundryVTT globals for test environment
- Test files: `ScryingPoolStrip.test.js`
### Test Coverage (from live testing)
- ✅ Full AV dock replacement
- ✅ Dock layout switching (all 6 options)
- ✅ Position persistence across sessions
- ✅ Per-user size override
- ✅ ApplicationV2 compatibility
- ✅ Portrait fallback with all priority levels
- ✅ PortraitFallbackHandler integration
- ✅ CSS build pipeline
### Known Issues Resolved
- DirectorsBoard position loading error - Fixed (5b421d6)
- ApplicationV2 jQuery parameter handling - Fixed (a05d3ca)
- CSS class selector in StripOverlayLayer - Fixed (ea4462e)
- StripOverlayLayer initialization timing - Fixed (6f07e48)
- RegisterMenu method missing - Fixed (0cb046b)
- GMPlayerPrivacySelectorMenu ApplicationV2 - Fixed (e2da477)
---
## File Changes Summary (May 20-25, 2026)
### Major Enhancements
| Commit | Date | Description | Files Changed |
|--------|------|-------------|---------------|
| 6d7a0b5 | 2026-05-20 | Story 4.2: Implement full AV replacement | 5 files |
| c4a375f | 2026-05-20 | Story 4.2: WebRTC stream access | 3 files |
| 20d13fc | 2026-05-20 | Story 4.2: Fix lint errors | 2 files |
| 25dd427 | 2026-05-20 | Update tests for Story 5-1 | 1 file |
| f8cbb75 | 2026-05-20 | Code review patches | 4 files |
| 7b56d62 | 2026-05-25 | **Finalize deck strip and management** | **12 files** |
### Commit 7b56d62 Details (Final Live Test Enhancements)
**Title:** Finalize deck strip and management
**Author:** LeRatierBretonnier
**Date:** Mon May 25 00:51:46 2026 +0200
**Changes:**
- `lang/en.json` - Added dock layout localization strings
- `module.js` - Added dockLayout, dockLayoutExpanded settings with onChange handlers; added legacy value migration; updated strip initialization
- `src/ui/RoleRenderer.js` - Added rerenderStrip() method; passes portraitFallbackHandler to strip
- `src/ui/gm/DirectorsBoard.js` - Added dock layout selector UI and handler
- `src/ui/gm/ScryingPoolStrip.js` - Complete ApplicationV2 migration; added _loadPosition(); layout resolution logic; position persistence; PortraitFallbackHandler integration
- `src/ui/shared/ScryingPoolCameraViews.js` - Minor updates
- `styles/components/_directors-board.less` - Layout selector styling
- `styles/components/_roster-strip.less` - Per-layout styling for all 6 options
- `styles/scrying-pool.css` - Built from LESS source
- `templates/directors-board.hbs` - Dock layout selector UI
- `templates/roster-strip.hbs` - Updated for layout support
- `tests/unit/ui/gm/ScryingPoolStrip.test.js` - Updated tests for new functionality
**Lines Changed:** +755, -141 across 12 files
---
## Future Considerations
### Potential v1.1 Features
1. **Compatibility Testing:** Thorough testing with other popular FoundryVTT modules
2. **Performance Optimization:** Strip rendering with large numbers of participants (20+)
3. **Additional Layout Options:** More mosaic variants, custom grid configurations
4. **Accessibility Enhancements:** Screen reader testing, high contrast modes
5. **Mobile Support:** Better touch interaction for Director's Board
### Architecture Improvements
1. **TypeScript Migration:** Consider migrating from JavaScript to TypeScript for better type safety
2. **Component Testing:** Expand unit test coverage for all components
3. **Integration Tests:** Add end-to-end testing for critical user journeys
4. **Documentation:** Expand API documentation for module developers
### Roadmap Alignment
The following Later-roadmap features from §10 are now more feasible with the full AV replacement architecture:
- **Token-Anchored Floating Cams** - Can leverage ScryingPoolStrip infrastructure
- **Spectator View** - Can use similar dock replacement pattern
- **Dual Layout System** - Can extend current layout system
- **Browser Source API** - Can expose strip layouts for OBS integration
---
## References
- **Module ID:** `scrying-pool`
- **Module Title:** Scrying Pool
- **Version:** 0.1.0
- **FoundryVTT Compatibility:** v14+
- **Repository:** video-view-manager
- **PRD Location:** `_bmad-output/planning-artifacts/prds/prd-video-view-manager-2026-05-19/`
- **Implementation Artifacts:** `_bmad-output/implementation-artifacts/`
- **Tests:** `tests/unit/`
---
*This addendum captures technical implementation details that support the PRD but do not belong in its main narrative. For authoritative requirements, see `prd.md`. For decision rationale, see `.decision-log.md`.*
@@ -2,7 +2,7 @@
title: "Video View Manager — FoundryVTT Webcam Visibility Control Module"
status: draft
created: 2026-05-19
updated: 2026-05-25
updated: 2026-05-26
version: 0.1.0
---
@@ -12,10 +12,13 @@ version: 0.1.0
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`.
This document uses Glossary terms from §3 throughout §4+ and keeps functional requirements globally numbered FR-1 through FR-34 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.
**Planned for v0.1.1:**
- Customizable widget width for small and large video tiles via dropdown selection (FR-33, FR-34)
---
## 1. Vision
@@ -32,6 +35,9 @@ The module follows the **Progressive Enhancement Architecture**. Level 1 adds a
- Position persistence across sessions
- Enhanced portrait fallback handling
**Planned for v0.1.1:**
- Customizable widget width for small and large video tiles via dropdown selection
---
## 2. Target Users
@@ -59,6 +65,7 @@ Alex has just joined their first online TTRPG. They are comfortable with Zoom bu
- 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
- Customize video widget width to match screen space and table preferences
**Social / Emotional**
- Feel in control of the table atmosphere as a GM — the visual equivalent of adjusting the lights
@@ -101,6 +108,7 @@ Alex has just joined their first online TTRPG. They are comfortable with Zoom bu
- **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.
- **Video Widget Width** — Configurable width for participant video tiles in the dock. Separate settings for small (`-sm`) and large (`-md`) variants, allowing customization to match screen space and table preferences. Controlled via world-scoped settings `widgetWidthSm` and `widgetWidthMd` with dropdown selection in Director's Board.
- **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.
@@ -443,6 +451,35 @@ Users can override the GM's layout size preference via client-scoped `dockLayout
---
### 4.7.5 Video Widget Width Customization (v0.1.1)
**Description:** Configurable width settings for participant video tiles, allowing GMs to customize the size of video widgets to match their screen space and table preferences. This feature extends the Dock Layout System by adding granular control over tile dimensions.
**Functional Requirements:**
#### FR-33: Video widget width configuration
The module provides configurable width options for small and large video tiles via world-scoped settings.
**Consequences (testable):**
- Two separate settings: `widgetWidthSm` (for `-sm` layouts) and `widgetWidthMd` (for `-md` layouts)
- Default widths: `widgetWidthSm: 80`, `widgetWidthMd: 120` (CSS pixels)
- Available width options via dropdown: 60px, 80px, 100px, 120px, 150px, 200px
- Changing width re-renders the strip for all users via onChange callback
- Width applies to all dock layout variants (vertical, horizontal, mosaic)
- Width setting is independent of layout direction
#### FR-34: Width selection dropdown in Director's Board
The Director's Board includes a UI control for selecting video widget widths.
**Consequences (testable):**
- Dropdown selector available in Director's Board settings panel
- Separate dropdowns for small and large sizes
- Selected values are saved to world settings immediately
- Dropdown shows current width value with visual preview
- Dropdown is disabled if AV is not active
---
### 4.8 Position Persistence
**Description:** The ScryingPoolStrip remembers its window position across sessions for consistent user experience.
@@ -508,6 +545,9 @@ All UI components properly extend and use FoundryVTT v14 ApplicationV2 API.
- English UI strings; i18n-ready string keys for community translation
- CSS build pipeline with postinstall script for automatic CSS compilation
### 6.1.1 Planned for v0.1.1
- **Video Widget Width Customization (FR-33 - FR-34)**: Configurable width for small and large video tiles via dropdown selection in Director's Board
### 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.]`
@@ -552,6 +592,7 @@ All UI components properly extend and use FoundryVTT v14 ApplicationV2 API.
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?
8. **OQ-8 (NEW):** What are the optimal default width values for video widgets (FR-33)? Should small be 80px and large be 120px, or should these be adjusted based on typical FoundryVTT UI spacing? To be validated during implementation.
---
@@ -565,6 +606,7 @@ All UI components properly extend and use FoundryVTT v14 ApplicationV2 API.
- **§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.
- **§4.7.5 / FR-33:** Widget width options (60px, 80px, 100px, 120px, 150px, 200px) cover the majority of display preferences. Default values (80px for small, 120px for large) provide good balance between visibility and screen space.
---