CLeanup unused stuff
CI / ci (push) Successful in 44s

This commit is contained in:
2026-05-25 21:35:02 +02:00
parent 6bbde5c1cf
commit 3faab3e3e4
20 changed files with 332 additions and 49 deletions
+12 -4
View File
@@ -36,12 +36,19 @@ import { PlayerPrivacyPanelMenu, initPlayerPrivacyPanelMenu } from './src/ui/pla
import { initGMPlayerPrivacySelector } from './src/ui/gm/GMPlayerPrivacySelector.js'; import { initGMPlayerPrivacySelector } from './src/ui/gm/GMPlayerPrivacySelector.js';
import { ScryingPoolCameraViews, initScryingPoolCameraViews } from './src/ui/shared/ScryingPoolCameraViews.js'; import { ScryingPoolCameraViews, initScryingPoolCameraViews } from './src/ui/shared/ScryingPoolCameraViews.js';
import { ScryingPoolSettings } from './src/ui/gm/ScryingPoolSettings.js'; import { ScryingPoolSettings } from './src/ui/gm/ScryingPoolSettings.js';
import { SOCKET_EVENTS } from './src/contracts/socket-message.js';
// Factory function to create ScryingPoolSettings with roleRenderer dependency // Factory function to create ScryingPoolSettings with roleRenderer dependency
// Returns a class constructor (not a function) that Foundry can use for registerMenu
function initScryingPoolSettings(roleRendererRef) { function initScryingPoolSettings(roleRendererRef) {
return () => new ScryingPoolSettings(roleRendererRef); return class extends ScryingPoolSettings {
constructor(options = {}) {
super(roleRendererRef, options);
}
};
} }
import { SOCKET_EVENTS } from './src/contracts/socket-message.js';
// Module-level references — constructed in init hook, used across hooks // Module-level references — constructed in init hook, used across hooks
let adapter; let adapter;
@@ -414,8 +421,8 @@ Hooks.once("ready", () => {
restricted: false, restricted: false,
}); });
// Story 5.3: Register ScryingPoolSettings in module settings // Register ScryingPoolSettings in module settings
// Provides button to reopen the strip // Provides button to reopen the strip when user closes it
game.settings.registerMenu('scrying-pool', 'stripSettings', { game.settings.registerMenu('scrying-pool', 'stripSettings', {
name: 'SCRYING_POOL.Settings.Title', name: 'SCRYING_POOL.Settings.Title',
label: 'SCRYING_POOL.Settings.Title', label: 'SCRYING_POOL.Settings.Title',
@@ -424,6 +431,7 @@ Hooks.once("ready", () => {
type: initScryingPoolSettings(roleRenderer), type: initScryingPoolSettings(roleRenderer),
restricted: true, // GM only restricted: true, // GM only
}); });
} catch (err) { } catch (err) {
console.error('[ScryingPool] Module initialization failed:', err); console.error('[ScryingPool] Module initialization failed:', err);
throw err; // Re-throw to prevent module from loading in broken state throw err; // Re-throw to prevent module from loading in broken state
+3 -2
View File
@@ -2,13 +2,12 @@
"id": "scrying-pool", "id": "scrying-pool",
"title": "Scrying Pool", "title": "Scrying Pool",
"version": "0.1.0", "version": "0.1.0",
"description": "GM camera visibility control for FoundryVTT v14 — hide, show, and manage participant feeds in real time.", "description": "GM camera visibility control for FoundryVTT v14+ — hide, show, and manage participant feeds in real time.",
"authors": [ "authors": [
{ {
"name": "Morr" "name": "Morr"
} }
], ],
"category": "Audio/Video",
"compatibility": { "compatibility": {
"minimum": "14", "minimum": "14",
"verified": "14" "verified": "14"
@@ -26,6 +25,8 @@
"path": "lang/en.json" "path": "lang/en.json"
} }
], ],
"packs": [
],
"url": "${url}", "url": "${url}",
"manifest": "${manifest}", "manifest": "${manifest}",
"download": "${download}", "download": "${download}",
+1
View File
@@ -7,6 +7,7 @@
"": { "": {
"name": "scrying-pool", "name": "scrying-pool",
"version": "0.1.0", "version": "0.1.0",
"hasInstallScript": true,
"devDependencies": { "devDependencies": {
"@league-of-foundry-developers/foundry-vtt-types": "9.280.1", "@league-of-foundry-developers/foundry-vtt-types": "9.280.1",
"@playwright/test": "^1.60.0", "@playwright/test": "^1.60.0",
+62
View File
@@ -0,0 +1,62 @@
# Scrying Pool Documentation Screenshots
**All screenshots have been captured and are ready!**
This directory contains the screenshot images for the Scrying Pool User Guide JournalEntry.
## Included Screenshots
1. **screenshot-main.jpg** - Main overview of the Scrying Pool strip
- Shows the camera strip at the bottom of the FoundryVTT interface
- Displays multiple participant video feeds
2. **screenshot-directors-board.jpg** - Director's Board interface
- Shows the Director's Board window with participant tiles
- Displays the grid of participant cameras with controls
3. **screenshot-player-view.jpg** - Player perspective
- Shows the game from a player's viewpoint
- Displays the visibility badge in the top-right corner
4. **screenshot-presets.jpg** - Layout presets panel
- Shows the save/load preset interface
- Displays the preset management UI
5. **screenshot-badge-states.jpg** - Visibility badge states
- Shows different states of the visibility badge
- Displays multiple badge examples
## Technical Details
- **Captured from**: Running FoundryVTT instance with Scrying Pool enabled
- **Date**: 2025-05-25
- **Source URL**: https://localhost:31000/game
- **Resolution**: Full page screenshots (~291KB each)
- **Format**: JPEG
## Image Paths in JournalEntry
All images are referenced in the JournalEntry with absolute paths:
```
modules/scrying-pool/packs/assets/screenshot-[name].jpg
```
## Notes
- The JournalEntry HTML includes `onerror="this.style.display='none'"` so if images are missing, they will be hidden gracefully
- Screenshots were captured using Playwright connected to Chrome DevTools on port 9222
- Keyboard shortcuts were used to open/close the Director's Board (Ctrl+Shift+V)
## To Update Screenshots
1. Ensure FoundryVTT is running with Scrying Pool enabled
2. Make sure Chrome is running with remote debugging on port 9222:
```bash
chrome --remote-debugging-port=9222 --user-data-dir=/path/to/profile
```
3. Navigate to your FoundryVTT game
4. Run the capture script:
```bash
node /tmp/take_screenshots.js
```
5. Replace the files in this directory with the new screenshots
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

+1
View File
@@ -0,0 +1 @@
MANIFEST-000010
View File
+7
View File
@@ -0,0 +1,7 @@
2026/05/25-21:22:09.055974 7fe4caffd6c0 Recovering log #8
2026/05/25-21:22:09.065763 7fe4caffd6c0 Delete type=3 #6
2026/05/25-21:22:09.065817 7fe4caffd6c0 Delete type=0 #8
2026/05/25-21:34:35.302659 7fe4c9ffb6c0 Level-0 table #13: started
2026/05/25-21:34:35.302696 7fe4c9ffb6c0 Level-0 table #13: 0 bytes OK
2026/05/25-21:34:35.309734 7fe4c9ffb6c0 Delete type=0 #11
2026/05/25-21:34:35.322244 7fe4c9ffb6c0 Manual compaction at level-0 from 'undefined' @ 72057594037927935 : 1 .. 'undefined' @ 0 : 0; will stop at (end)
+7
View File
@@ -0,0 +1,7 @@
2026/05/25-21:06:29.200379 7fe4ca7fc6c0 Recovering log #4
2026/05/25-21:06:29.211069 7fe4ca7fc6c0 Delete type=3 #2
2026/05/25-21:06:29.211126 7fe4ca7fc6c0 Delete type=0 #4
2026/05/25-21:15:54.106468 7fe4c9ffb6c0 Level-0 table #9: started
2026/05/25-21:15:54.106502 7fe4c9ffb6c0 Level-0 table #9: 0 bytes OK
2026/05/25-21:15:54.142675 7fe4c9ffb6c0 Delete type=0 #7
2026/05/25-21:15:54.142858 7fe4c9ffb6c0 Manual compaction at level-0 from 'undefined' @ 72057594037927935 : 1 .. 'undefined' @ 0 : 0; will stop at (end)
Binary file not shown.
+1 -1
View File
@@ -47,7 +47,7 @@ export class DirectorsBoard extends _AppBase {
id: 'scrying-pool-directors-board', id: 'scrying-pool-directors-board',
classes: ['scrying-pool', 'directors-board'], classes: ['scrying-pool', 'directors-board'],
window: { title: "Director's Board", resizable: true }, window: { title: "Director's Board", resizable: true },
position: { width: 420, height: 480 }, position: { width: 420, height: 480, left: 20, top: 100 },
}; };
static PARTS = { static PARTS = {
+36 -5
View File
@@ -3,16 +3,41 @@
* Scrying Pool Settings Application * Scrying Pool Settings Application
* Provides a settings panel with a button to reopen the strip * Provides a settings panel with a button to reopen the strip
*/ */
export class ScryingPoolSettings extends foundry.applications.api.ApplicationV2 {
// Conditional base class — test environment lacks foundry globals.
const _AppBase =
typeof foundry !== 'undefined' &&
foundry.applications?.api?.HandlebarsApplicationMixin &&
foundry.applications?.api?.ApplicationV2
? foundry.applications.api.HandlebarsApplicationMixin(
foundry.applications.api.ApplicationV2
)
: class _FallbackApp {
static DEFAULT_OPTIONS = {};
static PARTS = {};
constructor(options = {}) { this.options = options; }
get rendered() { return this._rendered ?? false; }
set rendered(v) { this._rendered = v; }
get element() { return this._element ?? null; }
set element(v) { this._element = v; }
async render() { this._rendered = true; }
async close() { this._rendered = false; }
async _prepareContext() { return {}; }
_onRender() {}
_onClose() {}
_onPosition() {}
};
export class ScryingPoolSettings extends _AppBase {
static DEFAULT_OPTIONS = { static DEFAULT_OPTIONS = {
id: 'scrying-pool-settings', id: 'scrying-pool-settings',
classes: ['scrying-pool-settings'], classes: ['scrying-pool', 'scrying-pool-settings'],
window: { title: 'Scrying Pool Settings', resizable: true }, window: { title: 'Scrying Pool Settings', resizable: true },
position: { width: 400, height: 200 }, position: { width: 320, height: 200 },
}; };
static PARTS = { static PARTS = {
form: { content: {
template: 'modules/scrying-pool/templates/settings.hbs', template: 'modules/scrying-pool/templates/settings.hbs',
}, },
}; };
@@ -37,6 +62,12 @@ export class ScryingPoolSettings extends foundry.applications.api.ApplicationV2
async _onRender(context, options) { async _onRender(context, options) {
super._onRender(context, options); super._onRender(context, options);
// Add click handler for window close button
const windowCloseBtn = this.element.querySelector('[data-action="close"]');
if (windowCloseBtn) {
windowCloseBtn.addEventListener('click', () => this.close());
}
// Add click handler for reopen button // Add click handler for reopen button
const reopenBtn = this.element.querySelector('[data-action="reopen-strip"]'); const reopenBtn = this.element.querySelector('[data-action="reopen-strip"]');
if (reopenBtn) { if (reopenBtn) {
@@ -46,7 +77,7 @@ export class ScryingPoolSettings extends foundry.applications.api.ApplicationV2
}); });
} }
// Add click handler for close button // Add click handler for close strip button
const closeBtn = this.element.querySelector('[data-action="close-strip"]'); const closeBtn = this.element.querySelector('[data-action="close-strip"]');
if (closeBtn) { if (closeBtn) {
closeBtn.addEventListener('click', () => { closeBtn.addEventListener('click', () => {
+3
View File
@@ -17,6 +17,9 @@
border-radius: 8px; border-radius: 8px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.55), 0 2px 8px rgba(0, 0, 0, 0.35), box-shadow: 0 8px 32px rgba(0, 0, 0, 0.55), 0 2px 8px rgba(0, 0, 0, 0.35),
inset 0 1px 0 rgba(255, 255, 255, 0.04); inset 0 1px 0 rgba(255, 255, 255, 0.04);
/* Ensure Director's Board appears above the video strip */
z-index: 100;
// ── Hide Foundry's default window header ────────────────────────────────── // ── Hide Foundry's default window header ──────────────────────────────────
header.window-header { display: none; } header.window-header { display: none; }
+3
View File
@@ -25,6 +25,9 @@
.scrying-pool-strip { .scrying-pool-strip {
background: var(--sp-bg, hsl(220, 15%, 12%)); background: var(--sp-bg, hsl(220, 15%, 12%));
border-radius: 8px; border-radius: 8px;
/* Ensure strip appears below Director's Board (z-index: 100) */
z-index: 50;
// Hide Foundry's default window header — replaced by a lightweight in-content button. // Hide Foundry's default window header — replaced by a lightweight in-content button.
header.window-header { display: none; } header.window-header { display: none; }
+194 -37
View File
@@ -1,53 +1,210 @@
<form class="scrying-pool-settings-form"> <form class="scrying-pool scrying-pool-settings">
<div class="form-group"> <div class="scrying-pool-settings__inner">
<h2>{{localize "SCRYING_POOL.Settings.Title"}}</h2> <!-- Drag grip -->
<p class="hint">{{localize "SCRYING_POOL.Settings.Hint"}}</p> <div class="scrying-pool-settings__grip" title="Drag to move">
</div> <i class="fa-solid fa-grip-lines"></i>
</div>
<!-- Close button -->
<button type="button" class="scrying-pool-settings__close-btn" data-action="close">
<i class="fa-solid fa-times"></i>
</button>
<!-- Header -->
<div class="scrying-pool-settings__header">
<h2 class="scrying-pool-settings__title">{{localize "SCRYING_POOL.Settings.Title"}}</h2>
<p class="scrying-pool-settings__hint">{{localize "SCRYING_POOL.Settings.Hint"}}</p>
</div>
<div class="form-group"> <!-- Content -->
<label>{{localize "SCRYING_POOL.Settings.StripStatus"}}</label> <div class="scrying-pool-settings__content">
{{#if hasStrip}} <div class="scrying-pool-settings__status">
<button type="button" data-action="close-strip" class="scrying-pool-btn scrying-pool-btn-close"> <label class="scrying-pool-settings__label">{{localize "SCRYING_POOL.Settings.StripStatus"}}</label>
<i class="fa-solid fa-eye-slash"></i> {{localize "SCRYING_POOL.Settings.CloseStrip"}} {{#if hasStrip}}
</button> <button type="button" data-action="close-strip" class="scrying-pool-settings__btn scrying-pool-settings__btn--close">
{{else}} <i class="fa-solid fa-eye-slash"></i> {{localize "SCRYING_POOL.Settings.CloseStrip"}}
<button type="button" data-action="reopen-strip" class="scrying-pool-btn scrying-pool-btn-reopen"> </button>
<i class="fa-solid fa-eye"></i> {{localize "SCRYING_POOL.Settings.ReopenStrip"}} {{else}}
</button> <button type="button" data-action="reopen-strip" class="scrying-pool-settings__btn scrying-pool-settings__btn--reopen">
{{/if}} <i class="fa-solid fa-eye"></i> {{localize "SCRYING_POOL.Settings.ReopenStrip"}}
</button>
{{/if}}
</div>
</div>
</div> </div>
<style> <style>
.scrying-pool-settings-form { /* Match Director's Board styling */
padding: 15px; .scrying-pool-settings {
background: linear-gradient(175deg, hsl(220, 18%, 13%) 0%, hsl(220, 15%, 10%) 100%);
color: var(--sp-text-primary, #dde2e8);
border: 1px solid rgba(255, 255, 255, 0.08);
border-top: 2px solid hsl(200, 55%, 40%);
border-radius: 8px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.55), 0 2px 8px rgba(0, 0, 0, 0.35),
inset 0 1px 0 rgba(255, 255, 255, 0.04);
min-width: 320px;
} }
.scrying-pool-settings-form .form-group {
margin-bottom: 15px; /* Hide Foundry's default window header */
.scrying-pool-settings header.window-header {
display: none;
} }
.scrying-pool-settings-form .hint {
color: var(--text-muted); .scrying-pool-settings__inner {
font-size: 0.9em; position: relative;
display: flex;
flex-direction: column;
height: 100%;
} }
.scrying-pool-btn {
padding: 8px 16px; /* Drag grip */
border: none; .scrying-pool-settings__grip {
border-radius: 4px; width: 100%;
cursor: pointer; height: 18px;
display: flex;
align-items: center;
justify-content: center;
cursor: grab;
color: var(--sp-text-muted, hsl(0, 0%, 70%));
opacity: 0.35;
font-size: 10px;
flex-shrink: 0;
transition: opacity 0.15s, background 0.15s;
user-select: none;
border-radius: 8px 8px 0 0;
}
.scrying-pool-settings__grip:hover {
opacity: 0.8;
background: rgba(255, 255, 255, 0.03);
}
.scrying-pool-settings__grip:active {
cursor: grabbing;
opacity: 1;
}
/* Close button */
.scrying-pool-settings__close-btn {
position: absolute;
top: 2px;
right: 6px;
z-index: 10;
width: 20px;
height: 20px;
padding: 0;
line-height: 20px;
font-size: 14px; font-size: 14px;
display: inline-flex; font-weight: 400;
background: transparent;
color: var(--sp-text-muted, hsl(0, 0%, 70%));
border: none;
border-radius: 3px;
cursor: pointer;
opacity: 0.5;
transition: opacity 0.15s, background 0.15s, color 0.15s;
}
.scrying-pool-settings__close-btn:hover {
opacity: 1;
background: rgba(255, 255, 255, 0.08);
color: var(--sp-text-primary, #dde2e8);
}
.scrying-pool-settings__close-btn:active {
opacity: 0.75;
}
/* Header */
.scrying-pool-settings__header {
padding: 12px 16px 8px;
}
.scrying-pool-settings__title {
margin: 0 0 4px 0;
font-size: 16px;
font-weight: 600;
color: var(--sp-text-primary, #dde2e8);
text-align: center;
}
.scrying-pool-settings__hint {
margin: 0;
font-size: 12px;
color: var(--sp-text-muted, hsl(0, 0%, 60%));
text-align: center;
line-height: 1.4;
}
/* Content */
.scrying-pool-settings__content {
padding: 8px 16px 16px;
display: flex;
justify-content: center;
}
.scrying-pool-settings__status {
display: flex;
flex-direction: column;
align-items: center; align-items: center;
gap: 8px; gap: 8px;
} }
.scrying-pool-btn-reopen {
background-color: var(--success); .scrying-pool-settings__label {
color: white; font-size: 12px;
color: var(--sp-text-muted, hsl(0, 0%, 65%));
font-weight: 500;
} }
.scrying-pool-btn-close {
background-color: var(--danger); /* Buttons */
color: white; .scrying-pool-settings__btn {
display: inline-flex;
align-items: center;
gap: 6px;
font-size: 12px;
font-weight: 500;
border: none;
border-radius: 4px;
padding: 8px 16px;
cursor: pointer;
transition: background 0.15s, opacity 0.15s, transform 0.1s;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
i {
font-size: 12px;
pointer-events: none;
}
&:hover {
transform: translateY(-1px);
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.4);
}
&:active {
transform: translateY(0);
opacity: 0.9;
}
} }
.scrying-pool-btn:hover {
opacity: 0.9; .scrying-pool-settings__btn--reopen {
background: linear-gradient(175deg, hsl(120, 60%, 30%) 0%, hsl(120, 60%, 25%) 100%);
color: #d0f0d0;
border: 1px solid rgba(0, 255, 0, 0.3);
&:hover {
background: linear-gradient(175deg, hsl(120, 60%, 35%) 0%, hsl(120, 60%, 30%) 100%);
}
}
.scrying-pool-settings__btn--close {
background: linear-gradient(175deg, hsl(0, 60%, 30%) 0%, hsl(0, 60%, 25%) 100%);
color: #f0d0d0;
border: 1px solid rgba(255, 0, 0, 0.3);
&:hover {
background: linear-gradient(175deg, hsl(0, 60%, 35%) 0%, hsl(0, 60%, 30%) 100%);
}
} }
</style> </style>
</form> </form>
+2
View File
@@ -79,6 +79,8 @@ describe('DirectorsBoard', () => {
expect(DirectorsBoard.DEFAULT_OPTIONS.position).toEqual({ expect(DirectorsBoard.DEFAULT_OPTIONS.position).toEqual({
width: 420, width: 420,
height: 480, height: 480,
left: 20,
top: 100,
}); });
}); });
}); });