P21: player seats + two-way live play + offline handoff

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>
This commit is contained in:
2026-06-08 12:34:00 +02:00
parent c28c29a6c6
commit 360d9ff842
21 changed files with 863 additions and 25 deletions
+7
View File
@@ -89,6 +89,13 @@ export const charactersRepo = {
return db.characters.get(id);
},
/** Fetch several characters by id (missing ids are dropped). */
async getMany(ids: string[]): Promise<Character[]> {
if (ids.length === 0) return [];
const rows = await db.characters.bulkGet(ids);
return rows.filter((c): c is Character => !!c);
},
async create(
campaignId: string,
draft: Pick<Character, 'name' | 'kind' | 'ancestry' | 'className' | 'level'> & {