Phase 8: session tooling — handouts to players

- GM "📣 Handout" composer in the header (title + body + optional image) sets
  uiStore.activeHandout; a clear button hides it.
- snapshot gains an optional handout {title, body, imageId}; buildSnapshot streams
  the handout image over the existing image channel (id "handout").
- Player view (local + networked) shows the handout as a prominent card above the
  boards. resizeToMax() keeps handout images compact.
- (Live scene/map switching already works via "Show to players".)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-08 15:48:23 +02:00
parent f923375ebb
commit 7f1ab8f094
10 changed files with 125 additions and 6 deletions
+2
View File
@@ -9,6 +9,7 @@ import { RollTray } from '@/components/ui/RollTray';
import { Select } from '@/components/ui/Input';
import { Button } from '@/components/ui/Button';
import { SessionControl } from '@/features/play/SessionControl';
import { HandoutControl } from '@/features/play/HandoutControl';
import { useSessionBroadcaster } from '@/features/play/useSessionBroadcaster';
const NAV = [
@@ -98,6 +99,7 @@ export function RootLayout() {
})}
</nav>
<div className="ml-auto flex items-center gap-2">
{activeCampaign && <HandoutControl />}
<SessionControl />
<Button size="sm" variant="ghost" onClick={() => setPaletteOpen(true)} title="Command palette (Ctrl/Cmd+K)" aria-label="Open command palette">
K