Implements PF2e encounter difficulty alongside the existing D&D system.
PF2e uses creature level vs party level to derive XP, compares against
5-tier budgets (Trivial/Low/Moderate/Severe/Extreme), and adjusts
thresholds for party size. The indicator shows 4 bars in PF2e mode.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Render persistent damage tags before the "+" button, not after
- Use insertion order for conditions on the row instead of definition order
- Differentiate Undetected condition (EyeClosed/slate) from Invisible (Ghost/violet)
- Use purple for void persistent damage to distinguish from violet conditions
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Expands persistent damage from 7 to 12 types to cover all PF2e damage
types that have verified persistent damage sources in published content.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Persistent damage displayed as compact tags with damage type icon and
formula (e.g., Flame + "2d6"). Supports fire, bleed, acid, cold,
electricity, poison, and mental types. One instance per type, added via
sub-picker in the condition picker. PF2e only, persists across reload.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Weak/Normal/Elite toggle in PF2e stat block header applies standard
adjustments (level, AC, HP, saves, Perception, attacks, damage) to
individual combatants. Adjusted stats are highlighted blue (elite) or
red (weak). Persisted via creatureAdjustment field on Combatant.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Show inline on-hit effects on attack lines (e.g., "plus Grab"), frequency
limits on abilities (e.g., "(1/day)"), and perception details text alongside
senses. Strip redundant frequency lines from Foundry descriptions.
Also add resilient PF2e source fetching: batched requests with retry,
graceful handling of ad-blocker-blocked creature files (partial success
with toast warning and re-fetch prompt for missing creatures).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Show inline on-hit effects on attack lines (e.g., "plus Grab"), frequency
limits on abilities (e.g., "(1/day)"), and perception details text alongside
senses. Strip redundant frequency lines from Foundry descriptions.
Also add resilient PF2e source fetching: batched requests with retry,
graceful handling of ad-blocker-blocked creature files (partial success
with toast warning and re-fetch prompt for missing creatures).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Extract shared DetailPopover shell from spell popovers. Normalize
weapon/consumable/equipment/armor items from Foundry data into
mundane (Items line) and detailed (Equipment section with clickable
popovers). Scrolls/wands show embedded spell info. Bump IDB cache v7.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Display Recall Knowledge line below trait tags showing DC (from level
via standard DC-by-level table, adjusted for rarity) and associated
skill derived from creature type trait. Omitted for D&D creatures and
creatures with no recognized type trait.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Clicking a spell name in a PF2e creature's stat block now opens a
popover (desktop) or bottom sheet (mobile) showing full spell details:
description, traits, rank, range, target, area, duration, defense,
action cost icons, and heightening rules. All data is sourced from
the embedded Foundry VTT spell items already in the bestiary cache.
- Add SpellReference type replacing bare string spell arrays
- Extract full spell data in pf2e-bestiary-adapter (description,
traits, traditions, range, target, area, duration, defense,
action cost, heightening, overlays)
- Strip inline heightening text from descriptions to avoid duplication
- Bold save outcome labels (Critical Success/Failure) in descriptions
- Bump DB_VERSION to 6 for cache invalidation
- Add useSwipeToDismissDown hook for mobile bottom sheet
- Portal popover to document.body to escape transformed ancestors
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
--deny warnings was a no-op (not a valid category); the correct flag
is --deny-warnings. Fixed all 8 pre-existing warnings and removed
every biome-ignore from source and test files. Simplified the check
script to zero-tolerance: any biome-ignore now fails the build.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Align cutout edges to 45° angles parallel to outer diamond shape.
Multi-action icons use outlined diamonds with matched border width.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
PF2e uses action-based spell sustaining, not damage-triggered
concentration checks. The Brain icon, purple border accent, and
damage pulse animation are now hidden when PF2e is active, and
the freed gutter column is reclaimed for row content. Concentration
state is preserved so switching back to D&D restores it.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Cap dying (4), doomed (3), wounded (3), and slowed (3) at their
rule-defined maximums. The domain clamps values in setConditionValue
and the condition picker disables the [+] button at the cap.
Closes#31
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace the stagnant Pf2eTools bestiary with Foundry VTT PF2e system
data (github.com/foundryvtt/pf2e, v13-dev branch). This gives us 4,355
remaster-era creatures across 49 sources including Monster Core 1+2 and
all adventure paths.
Changes:
- Rewrite index generation script to walk Foundry pack directories
- Rewrite PF2e normalization adapter for Foundry JSON shape (system.*
fields, items[] for attacks/abilities/spells)
- Add stripFoundryTags utility for Foundry HTML + enrichment syntax
- Implement multi-file source fetching (one request per creature file)
- Add spellcasting section to PF2e stat block (ranked spells + cantrips)
- Add saveConditional and hpDetails to PF2e domain type and stat block
- Add size and rarity to PF2e trait tags
- Filter redundant glossary abilities (healing when in hp.details,
spell mechanic reminders, allSaves duplicates)
- Add PF2e stat block component tests (22 tests)
- Bump IndexedDB cache version to 5 for clean migration
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Replace unicode action cost chars with custom SVG icons (diamond
with chevron for actions, outlined diamond for free, curved arrow
for reaction) rendered inline via ActivityCost on TraitBlock
- Add activity icons to attacks (all Strikes default to single action)
- Add trigger/effect rendering for reaction abilities (bold labels)
- Fix nested tag stripping ({@b ...{@spell ...}...}) by looping
- Move icon after ability name to match AoN format
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Show Unicode action icons (◆/◆◆/◆◆◆ for actions, ◇ for free,
↺ for reaction) in ability names from the activity field.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Parse and display traits (concentrate, divine, polymorph, etc.)
on ability entries, matching how attack traits are already shown.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Broaden stripDiceBrackets to stripAngleBrackets to handle all
PF2e tools angle-bracket formatting (e.g. <10 feet>, <15 feet>),
not just dice notation. Also strip in damage text.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Correct inaccurate PF2e condition descriptions against official AoN
rules (blinded, deafened, confused, grabbed, hidden, paralyzed,
unconscious, drained, fascinated, enfeebled, stunned). Sort condition
picker alphabetically per game system.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Format senses with type (imprecise/precise) and range in feet,
and strip {@ability} tags (e.g. tremorsense)
- Strip angle-bracket dice notation in attack traits (<d8> → d8)
- Fix existing weakness/resistance tests to nest under defenses
- Fix non-null assertions in 5e bestiary adapter tests
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Some PF2e creatures (e.g. Giant Mining Bee) have qualitative
weaknesses without a numeric amount, causing "undefined" to
render in the stat block. Handle missing amounts gracefully.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Stat block traits containing 5etools list (e.g. Confusing Burble d4
effects) or table entries were silently dropped. The adapter now
produces structured TraitSegment[] instead of flat text, preserving
lists and tables as first-class data. The stat block component renders
labeled list items inline (bold label + flowing text) matching the
5etools layout. Also fixes support for the singular "entry" field on
list items and bumps the bestiary cache version to force re-normalize.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Support the 2014 DMG encounter difficulty as an alternative to the 5.5e
system behind the existing Rules Edition toggle. The 2014 system uses
Easy/Medium/Hard/Deadly thresholds, an encounter multiplier based on
monster count, and party size adjustment (×0.5–×5 range).
- Extract RulesEdition to its own domain module
- Refactor DifficultyTier to abstract numeric values (0–3)
- Restructure DifficultyResult with thresholds array
- Add 2014 XP thresholds table and encounter multiplier logic
- Wire edition from context into difficulty hooks
- Edition-aware labels in indicator and breakdown panel
- Show multiplier, adjusted XP, and party size note for 2014
- Rename settings label from "Conditions" to "Rules Edition"
- Update spec 008 with issue #23 requirements
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Combatants can now be assigned to party or enemy side via a toggle
in the difficulty breakdown panel. Party-side NPCs subtract their XP
from the encounter total, letting allied NPCs reduce difficulty.
PCs default to party, non-PCs to enemy — users who don't use sides
see no change. Side persists across reload and export/import.
Closes#22
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Use a three-column grid (1fr / auto / 1fr) so the active combatant
name stays centered while round badge and difficulty indicator are
anchored in the left and right zones. Prevents layout jumps when
the name changes between turns.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
On touch devices, the Brain icon was fully hidden (opacity-0) unlike
the edit and condition buttons. Add pointer-coarse:opacity-50 so it
appears as a discoverable grey icon, matching the other action buttons.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Implement issue #21: custom combatants can now have a challenge rating
assigned via a new breakdown panel, opened by tapping the difficulty
indicator. Bestiary-linked combatants show read-only CR with source name;
custom combatants get a CR picker with all standard 5e values. CR persists
across reloads and round-trips through JSON export/import.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace direct adapter/persistence imports with context-based injection
(AdapterContext + useAdapters) so tests use in-memory implementations
instead of vi.mock. Migrate component tests from context mocking to
AllProviders with real hooks. Extract export/import logic from ActionBar
into useEncounterExportImport hook. Add bestiary-cache and
bestiary-index-adapter test suites. Raise adapter coverage thresholds
(68→80 lines, 56→62 branches).
77 test files, 891 tests, all passing.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Bestiary sources like AWM store 0 for unknown HP. Passing maxHp: 0
into addCombatant triggered domain validation rejection, silently
dropping the creature. Treat hp: 0 as undefined, matching existing
ac: 0 handling.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds disable-model-invocation and allowed-tools restrictions
that structurally enforce commit safety.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Clarify that spec.md is a living capability document, plan.md/tasks.md
are bounded work packages, and tests are the executable ground truth.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Slim Vitest pre-commit output with dot reporter and coverage summary.
Ignore .agent-tests/ and docs/agents/research/ in git.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move niche conventions (component props, export compat) to
docs/conventions.md, trim Speckit/Constitution sections to link to
source files, and add a one-line project description.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds void to floating promise in bestiary-cache.ts, extracts shared
polyfillDialog() helper to eliminate unbound-method warnings in 3 test
files. Adds --deny warnings to oxlint so future warnings fail the
build.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Fixes packages/app → packages/application path, expands scripts table,
documents the parallel merge gate, adds contributing workflow with
spec-driven process and Claude Code skills, and documents bestiary
index regeneration.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Dialog: open/close lifecycle, cancel event handling, DialogHeader.
Tooltip: show on pointer enter, hide on pointer leave. Raises
components/ui coverage threshold to enforce testing of future
primitives.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Tests browse mode toggle, export/import dialog opening, overflow menu
callbacks (manage players, settings), and custom stat field submission.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Tests search/suggestion filtering, queued creature counting, form
submission with custom stats, browse mode, and dismiss/clear behavior.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds tests for DifficultyIndicator, Toast, RollModeMenu, OverflowMenu,
useTheme, and useRulesEdition. Covers rendering, user interactions,
auto-dismiss timers, external store sync, and localStorage persistence.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Exports encounterReducer and EncounterState for testing. Adds 26
pure-function tests covering all action types: CRUD, turn navigation,
HP/AC/conditions, undo/redo, bestiary add with auto-numbering,
player character add, import, and event accumulation.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replaces 18 useCallback wrappers with a typed action union and
encounterReducer. Undo/redo wrapping is now systematic per-case in
the reducer instead of ad-hoc per operation. Complex cases (undo/redo,
bestiary add, player character add) are extracted into helper functions.
The stat block auto-show on bestiary add now uses lastCreatureId from
reducer state instead of the synchronous return value, with a useEffect
in use-action-bar-state to react to changes.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds missing tests for undoUseCase, redoUseCase, and setTempHpUseCase,
bringing application layer coverage from ~81% to 97%. Removes
autoUpdate from coverage thresholds and sets floors to actual values
so they enforce a real minimum.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>