- Player view: a Quest log now syncs to players (snapshot += quests; broadcaster
passes campaign quests; PlayerBoards renders titles + objective checkboxes).
- AI (DeepSeek etc.): robust JSON extraction — strip code fences anywhere + a
brace-balanced scanner that ignores prose/braces in strings. Fixes "AI unavailable
(parse)" with OpenAI-compatible providers. +4 tests.
- Encounter advisor: now bidirectional — for an over-tuned (too-hard) fight it
suggests REMOVING/swapping monsters instead of only ever adding. +3 tests.
- Character share: works on iPad — native share sheet → clipboard → a copyable
link modal fallback (was a silently-failing clipboard write).
230 unit + 34 e2e + 2 realtime green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Players set a display name in the session panel ("Your name"); it persists
(sessionStore.guestName) and is sent via a new `setName` message on join + edit.
- Server stores the name per connection and uses it in the roster + chat; the roster
entry now also carries the player's character, so the GM sees "Alice · Lia".
- Realtime e2e: a player names themselves and the GM's roster/share update to match.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Sidebar gains tabs: Chat / Rolls / (GM) Recap. Chat supports table messages and
private whispers (GM→player via a recipient picker; player→GM via a toggle).
Server routes table to all and whispers to the target only (+server tests).
- Rolls + chat are persisted to a per-campaign session recap (Dexie v13 sessionLog
table + sessionLogRepo); the GM's "Recap" tab shows it (survives reloads/sessions).
- wsSync: chat send/receive, optimistic local echo, persistLog for the GM.
- Realtime e2e: GM table message reaches the player; the player's reply reaches the GM.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Session sidebar (header "☰ Session" toggle, mobile drawer) visible to GM AND
players: which session you're in, who's here (GM + players), and the live roll
feed. The GM's own public rolls now mirror into the local feed too.
- Server roster broadcast to everyone (sendRoster on join/seatGrant/disconnect/
host-resume); includes the GM. Players now see the roster, not just the GM.
- Targeted private channel (backend, wired to UI next): privateState (GM→server→
one player only) + privateHandout; image sent INLINE so non-recipients never get
it. roster/privateHandout schemas + stores + wsSync handlers + senders.
- Adversarial-review fixes: GM included in roster; roster refreshes on GM
disconnect; privateState returns a forbidden error on auth failure. +3 server tests.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Players claim a seat (GM approves) and drive their own character live —
HP/slots/resources/conditions/dice broadcast to the table — via new seat
protocol messages and per-seat ownership enforced in RoomHub. GM persists
player edits (charactersRepo.update → liveQuery → rebroadcast). Offline dev:
"Share with player" encodes a claim link (src/lib/sync/playerLink.ts) → /player
imports the character locally for full-sheet editing, bundled back as an
offlineSnapshot on seat claim for GM review.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>