Commit Graph

16 Commits

Author SHA1 Message Date
NilsBriggen 3d2c68a1a1 V2 Phase 4: Signals engine — proactive, app-wide one-click assists
The "buttons, not chatbot" core: the app recognizes a situation and offers the
fix; the user never has to formulate a request.

- src/lib/assistant/signals.ts: buildSignals() aggregates the existing advisor
  detectors with new kernel-aware ones — quest-complete (all objectives done →
  "Mark complete"), caster out-of-slots → "Short rest", concentrating-while-
  bloodied warning — deduped and severity-sorted. 6 unit tests.
- extended SuggestAction with shortRest + completeQuest; one shared dispatcher
  (useSignalAction) used by both surfaces so behaviour can't drift.
- SignalsBell: an ambient bell + popover in the top bar, visible from every
  screen, with a count badge, one-click actions, and per-signal/clear-all
  dismiss. AssistantPage refactored onto the same buildSignals + dispatcher.
- the AI cards were already actionable (NpcGen → npcsRepo, EncounterTip → add
  to encounter, Assistant encounter builder → combat).

Also fixed a pre-existing invalid-HTML bug: ConditionPicker rendered a <Check>
SVG inside <option> (React hydration error spam) → plain "✓" text.

Build + 277 unit tests green; bell verified live (popover, actions, no errors).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-09 08:30:26 +02:00
NilsBriggen 8ba38d893d V2 Phase 3: combat rules automation (conditions, damage types, reminders)
Completes the deployable Phase 1-3 chunk: the combat tracker now runs the math.

- condition-effects engine: declarative CONDITION_EFFECTS_5E/PF2E table +
  deriveState(system, speed, conditions) → effective speed / advantage state /
  incapacitation / pf2e status penalty. Tracker shows effect badges
  ("Speed 0", "Disadv. attacks", "−2 status"); pure + 10 unit tests.
- damage types: applyDamage(c, amount, type?) consults snapshotted monster
  DamageDefenses (immune→0, resist→halve, vulnerable→double), back-compatible.
  Monster add snapshots damageDefenses; tracker shows a type picker only when a
  creature has typed defenses, and the log notes resisted/vulnerable amounts.
- concentration + death saves are surfaced as REMINDERS, never auto-rolled:
  damaging a concentrating PC logs "roll a DC N Con save…"; a downed PC's turn
  logs "make a death saving throw." The player rolls and resolves via the Drop
  button / death-save pips they already own. (Per user: no auto dice rolls —
  it removes the player from their character.)

Build + 271 unit tests green. Verified live: grapple → Speed 0 badge;
fire-immune creature shows the immune-labelled damage picker.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-09 01:23:52 +02:00
NilsBriggen 026927b5f5 V2 Phase 1: mechanics kernel + compendium→sheet integration
Lay the foundation for full rules enforcement: a new pure, testable
mechanics kernel (src/lib/mechanics/) that derives structured, enforceable
game data from the loosely-typed compendium, plus the first user-facing
payoff (accurate armor AC + spell mechanics on the sheet).

- normalizers: spell (5e + pf2e), armor, monster defenses → typed
  SpellMechanics / ArmorMechanics / DamageDefenses, with memoized derivers
  wrapping the existing lazy compendium loaders (no new assets). 11 unit tests.
- character schema: spell entries snapshot concentration/save/damage at
  compendium-link time; new top-level `concentration` slot and structured
  `equippedArmor` (additive, defaulted). Dexie v14 migration backfills.
- AC model: baseArmorClass now consults equippedArmor (heavy = flat, medium =
  Dex-capped) and falls back to the old 10+Dex formula when unarmored. Threaded
  through every AC call site; armor picker added to the sheet (5e).
- compendium "Add spell to character" snapshots real mechanics via the kernel.

Backward-compatible: un-enriched spells/characters behave exactly as before.
Build + 244 unit tests green; armor→AC verified live in preview.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-09 00:58:31 +02:00
NilsBriggen 740cf20b93 UI/UX "Living Codex" 4/n: assistant features + emoji purge
- Replace all emoji icons (~26 instances) with Lucide icons across the app
  (DashboardPage, SessionSidebar, PlayerBoards, MyCharacterPanel,
  PlayerViewPage, EncounterTracker, CampaignsPage, HandoutControl,
  SessionControl, CharacterSheet, EncounterTipCard, ActionGuide)
- Expose real 5e race data in wizard (ASI/vision/traits instead of stub desc);
  add vision field to loadRaces5e return type
- Surface subclass descriptions after picking a subclass in the wizard
- Add per-class tips, race synergy notes, and ability/skill guidance in wizard
- New ActionGuide component: collapsible "What can I do on my turn?" in player view
- New SessionPrepCard: AI + fallback session hook generator on assistant page
- New NpcGenCard: AI + fallback quick NPC generator with "Add to campaign" action
- Inline NPC detail generator (wand button) on each NPC card in NpcsPage
- Quest hook generator button in QuestsPage header
- Condition tooltips in player party view (useConditionGlossary)
- Pass campaign.system through session snapshot so player view is system-aware

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-08 23:29:06 +02:00
NilsBriggen 235cdecb53 Fixes batch 3: autosave, campaign-agnostic PCs, live push, builder
- Autosave: while signed in, a debounced full backup pushes whenever durable data
  changes (useCloudAutosave watches a fingerprint of the main tables; high-churn
  tables excluded). No-op signed out.
- Campaign-agnostic characters: PCs are now global — the Characters roster shows
  every player character regardless of active campaign, and any PC can be added to
  a fight. NPCs stay per-campaign. (charactersRepo.listAllPcs / useAllPcs; difficulty
  fallback stays campaign-scoped.)
- Live "bring your own character": a joining player can push one of their own local
  characters; the GM's grant inserts it into the campaign and seats them.
- Character builder: a system picker (5e / PF2e, defaults to the campaign) so creation
  no longer assumes 5e; PF2e skill wording ("Trained" vs "proficient"); spell step now
  explains how many to pick + that they're known spells prepared later.

230 unit + 34 e2e + 2 realtime green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 22:12:18 +02:00
NilsBriggen 426824fd78 Fixes batch 1: modal focus, campaign system, combat difficulty, origin desc
- Modal: focus into the dialog ONCE on open (not on every parent re-render), and
  prefer the first field over the X button — fixes focus jumping to the close
  button on each keystroke in the handout composer (and every other composer).
- Campaign edit: hide the System selector entirely (it's fixed after creation).
- Combat difficulty: rate against the PCs actually in the encounter (falls back to
  the roster) so adding a player updates the reading.
- Character builder: ancestry/background description is now a scrollable panel
  instead of clamped to 3 lines (no longer cut off on small screens).

223 unit + key e2e green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 21:48:31 +02:00
NilsBriggen 99c7657f96 UI overhaul "Living Codex" E: per-screen layouts
Ported all 9 screens to the prototype layout (visual only; all data wiring, text,
aria-labels, and testids preserved) via parallel agents + central verification:
- Dashboard: editorial hero, party roster w/ HP meters + avatars, quests, threats, rolls.
- Campaigns: cover-art deck cards + gilt rule + footer.
- Character sheet + roster: hero header, StatCoin abilities, prof rows; grimoire cards.
- Combat: glowing initiative rows (PC gilt / foe ember), condition badges, log.
- Dice: die-pool glyphs, adv/dis segmented toggle, crit/fumble stage, history.
- Compendium: Spectral stat blocks (ember headers, ability row).
- Settings: grouped icon-tile cards. Live Session: room-code card, seat grid, player board.
- Battle Map: carded list + tooled editor chrome (canvas untouched).

Regression fixes after the ports: dice die-buttons aria-label `d4` not `Roll 1d4`
(was colliding with the primary Roll button); map "Open player view" link uses an
ExternalLink icon (test updated, ↗ glyph removed); seat-claim card gets a stable
data-testid="seat-option" (redesign moved rounded-lg→rounded-xl).

223 unit + 34 e2e + 2 realtime green; tsc + eslint + build clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 21:37:00 +02:00
NilsBriggen dbbf68752e Phase 14: LLM-grounded encounter-balancing tip
- src/lib/assistant/prompts.ts: balanceSuggestionSchema + buildBalancePrompt
  (system message leads with the grounding constraint; restricts choices to the
  provided compendium candidates).
- useEncounterAdvisor hook: builds context → picks system-correct candidates →
  asks the LLM (when configured) for a structured pick, validates + filters names
  to the candidate set, else falls back to the deterministic buildSuggestedEncounter.
  Apply adds the creatures transactionally via encountersRepo.mutate.
- EncounterTipCard in the combat tracker: leads with the detected difficulty
  tendency (or the current difficulty), offers a one-click grounded suggestion
  (AI or deterministic) with propose→confirm Apply.

prompts unit tests + e2e for both the deterministic apply flow and the AI path
(stubbed provider); the AI test also confirms candidate-grounding (only
shortlisted creatures survive).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 09:17:23 +02:00
NilsBriggen f84e429ca4 Phase 13: grounding context + deterministic pattern detection
- src/lib/assistant/context.ts: buildCampaignContext() assembles a system-aware
  snapshot led by an explicit systemConstraint (anti cross-system hallucination),
  party, recent encounters with computed difficulty, quest/note summaries.
  pickCreatureCandidates() pulls level/CR-appropriate creatures from the correct
  bestiary so LLM tips are grounded in real data.
- src/lib/assistant/patterns.ts: difficultyTendency() + detectThemes() classify
  whether the DM's encounters skew too easy/hard, rating each fight against its
  party-level snapshot.
- Encounter schema gains optional partyLevelsSnapshot + outcome (Dexie v7, additive).
  Combat tracker snapshots PC levels at start and rates difficulty against them.

17 assistant unit tests (context + patterns).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 09:08:14 +02:00
NilsBriggen 744e91f703 Phase 8: player view (local/projector) + sync seam
- Player View (/play): read-only projector screen — party HP bars + conditions,
  active-encounter initiative with current turn; enemy HP hidden behind a
  Healthy/Bloodied/Down status band; Fullscreen button
- SyncAdapter seam (src/lib/sync): local-first default via Dexie liveQuery;
  documents where a future networked (WebSocket/CRDT) backend plugs in
- Dashboard + routes get a Player View entry
- Robustness: encountersRepo.mutate() does transactional read-modify-write so
  rapid combat mutations can't overwrite each other (old C19 race); tracker uses it

New player-view e2e. Networked multiplayer backend intentionally deferred.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 02:07:27 +02:00
NilsBriggen d5977e4c63 Fixes: adv/dis as a global toggle, auto-number duplicate combatants
- Advantage/Disadvantage are now toggle modes (rollStore.mode) applied to d20
  rolls everywhere (dice page, sheet skills/saves/attacks), preserving modifiers;
  applyRollMode() rewrites the first d20 -> 2d20kh1/kl1
- addCombatant auto-numbers duplicate names (Goblin 1, Goblin 2, …); the first
  duplicate also renames the original. Quantity add relies on this.
- Tests for applyRollMode + duplicate numbering

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 01:50:02 +02:00
NilsBriggen 3e5bdc06e2 Phase 3: combat depth
- Condition durations + auto-expiry: timed conditions tick down on the affected
  combatant's turn and drop at 0 (engine tickConditions; UI rounds field + (Nr) chip)
- Initiative: Roll-all (d20 + per-combatant bonus, re-sort anchored) + group/quantity add
- Combat log: per-round event feed (turns, round changes, damage/heal, expiries,
  removals) + in-memory Undo of the last change
- Encounter difficulty budget: 5e XP thresholds + PF2e level budget (pure lib +
  tests); live difficulty/XP-award readout from monster combatants vs the party
- Combatants carry initBonus + cr/level; compendium add-to-combat passes them

18 new unit tests (durations, applyInitiatives, budget), new combat-depth e2e.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 01:23:13 +02:00
NilsBriggen 379b79e6c4 Phase 2: full compendium across all categories + PF2e data
- Scraped PF2e reference from Archives of Nethys ES into public/data/pf2e/
  (spells, creatures, feats, equipment, weapons, armor, ancestries, heritages,
  backgrounds, archetypes, actions, conditions, deities) via scripts/fetch_pf2e.ts
- Registry-driven compendium: system toggle + per-category nav + generic filters
- 5e expanded: weapons, armor, feats, conditions added alongside spells/monsters/items
- PF2e data served as static assets (fetched, not bundled) for fast native parse
- Cross-links: add spell->spellbook / item->inventory to a campaign character;
  add monster/creature -> open encounter
- Condition tooltips in combat sourced from the conditions glossary
- Tests: registry filter unit tests, compendium e2e (browse + cross-link)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 01:00:40 +02:00
NilsBriggen 0b356adf82 Combat: condition dropdown picker with tag chips
- System-aware condition list (5e PHB / pf2e) in src/lib/rules/conditions.ts
- Dropdown replaces free-text input; non-valued conditions add instantly,
  valued ones (Exhaustion, Frightened N, etc.) show a value field, plus Custom
- Already-applied conditions disabled in the list; chips remain click-to-remove
- New e2e covering preset + valued add and tag removal

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 00:44:37 +02:00
NilsBriggen 866f1e1bf1 Fixes + UX: combat HP, char delete, dice animation, compendium filters, import/export
- Combat: relabel HP controls Dmg/Heal, disabled at 0 (were silent no-ops)
- Characters: per-card Delete (confirm) + Export; header Import from JSON
- Dice: tumbling roll animation that settles on the result (a11y-safe)
- Compendium: per-category filters (monster type/CR, spell level/school, item rarity/type) + Clear
- Character import/export to portable JSON (reassigns id, validates on import)
- New: 4 io unit tests, e2e fixes spec (HP damage, delete, CR filter)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 00:40:43 +02:00
NilsBriggen 1a9e5e2c18 Build MVP: campaigns, characters, combat, dice, compendium
- Rules abstraction (5e + pf2e) behind one interface, fully tested
- Pure combat engine: turn-order safe across add/remove/reorder/init-change
- Dexie storage with real cascade deletes + Zod validation on write
- Seedable dice engine with notation parser
- Lazy SRD compendium (code-split), bestiary -> combat
- Strict TS, 54 unit tests, Playwright e2e smoke (all green)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 00:09:42 +02:00