# Feature Research

**Domain:** PF2e TTRPG companion app — next milestone (Level-Up + PWA + Battle-Display + Dice/Chat + GM Live Tools + Obsidian Vault)
**Researched:** 2026-04-27
**Confidence:** HIGH (PF2e rules + PWA tech are HIGH; competitor UX details are MEDIUM)

## Scope Note

This is a **subsequent milestone** for an existing app. Already-shipped features (HP, conditions, skills, saves, inventory, alchemy, rest, alchemy-tab, character-import, battle-MVP, GM-library, JWT-auth) are NOT re-evaluated here. The categorization below applies **only to the new milestone scope**.

The bar for "table stakes" is calibrated to the actual user — the **own gaming group at the table**. Things that would be table-stakes for a public SaaS (multi-tenant onboarding, account recovery flows, etc.) are not table-stakes here.

## Feature Landscape

### Table Stakes (Without these, the milestone fails its goal)

#### Level-Up System

| Feature | Why Expected | Complexity | Notes |
|---------|--------------|------------|-------|
| **Attribute Boosts at level 5/10/15/20** (4 free boosts; +2 to four different attributes, capped at +4 / 18) | PF2e core rule, every PF2e tool implements it | MEDIUM | Trigger HP-Max recompute on CON-Boost; +1 trained skill on INT-Boost |
| **Class feat at every even level** (2, 4, 6, 8, 10, 12, 14, 16, 18, 20) | PF2e core rule | HIGH | Filter by class + level + prerequisites; many feats have multi-condition prereqs (skill rank, other feat, ancestry) |
| **Skill feat at every even level** (2, 4, 6, ...) | PF2e core rule | MEDIUM | Filter by skill rank prereq; some require Trained/Expert/Master/Legendary in named skill |
| **General feat every 4 levels** (3, 7, 11, 15, 19) | PF2e core rule | MEDIUM | Skill feats ALSO count as general feats (one-way) |
| **Skill increase at level 3 and every 2 levels thereafter** (3, 5, 7, 9, 11, 13, 15, 17, 19) | PF2e core rule, Rogues earlier/more | MEDIUM | Untrained→Trained, Trained→Expert (level 3+), Expert→Master (level 7+), Master→Legendary (level 15+) |
| **Ancestry feat at level 5, 9, 13, 17** | PF2e core rule | MEDIUM | Filter by ancestry, heritage, prerequisites |
| **Class features per class table** (e.g. Fighter Bravery at 3, Weapon Mastery at 5, etc.) | PF2e core rule, class-specific | HIGH | Per-class lookup table; some grant additional choices (e.g. specialization) |
| **Prerequisite validation** (e.g. "Trained in Athletics required") | Without this it's not "regelkonform" | HIGH | Need to evaluate prerequisite expressions: skill rank, feat ownership, level, ancestry, deity, spellcasting tradition |
| **Auto-recompute derived stats** (HP-Max, Save proficiency increases, AC proficiency, Class DC) | Core promise of "regelkonform" — values must be correct after Level-Up | HIGH | Class-specific proficiency progression tables; HP-Max = ancestry HP + (class HP + CON-Mod) × Level |
| **Undo / Cancel before commit; commit creates change record** | Already in PROJECT.md as requirement; users will misclick | MEDIUM | Implement as draft state; on commit, write all changes atomically |
| **Free Archetype variant rule** (extra archetype-only feat at every even level) | Group's preferred PF2e variant; Pathbuilder + Foundry's PF2e Leveler both support it | MEDIUM | Toggle per character; second feat slot, restricted to archetype feats only |
| **Spellcaster slot/cantrip progression on Level-Up** | Spellcasters need correct slot tables to play | HIGH | Per-tradition progression; spell repertoire/preparation also needs increment for spontaneous casters |

#### PWA

| Feature | Why Expected | Complexity | Notes |
|---------|--------------|------------|-------|
| **Web App Manifest + Icons + Splash + Service Worker registration** | Without manifest, app can't be installed | LOW | Standard Vite PWA plugin (`vite-plugin-pwa`) handles boilerplate |
| **Cache-first read of own character sheet (offline)** | "Always-on companion at the table" with flaky table Wi-Fi | MEDIUM | Cache GET responses for `/characters/:id`, `/equipment/:id`, `/feats/:id` etc.; show "offline" indicator |
| **"Add to Home Screen" prompt** (Android automatic via `beforeinstallprompt`, iOS guided manual) | Without it users won't install and miss push | LOW | iOS needs in-app instruction overlay since no programmatic prompt — see PITFALLS |
| **Web Push for GM→player ping** (turn alert, dice request, custom message) | Whole point of having a PWA at the table | HIGH | VAPID keys, Service Worker `push` event handler, Push subscription persisted per device, opt-in flow per user |

#### Multi-Screen Battle Display

| Feature | Why Expected | Complexity | Notes |
|---------|--------------|------------|-------|
| **Read-only Display-Mode route** (e.g. `/battle/:id/display`) | Existing battle page is GM-only mixed; table screen needs a "no controls" view | MEDIUM | Same WebSocket subscription, conditionally hide drag handles + controls; optimize layout for landscape table screen |
| **Display-Mode auth model** (player or shared GM session, no controls) | Tisch-Display likely runs as a shared/auto-login terminal | MEDIUM | Either anonymous read-only via session token OR dedicated "display" pseudo-user with read-only role |
| **Initiative Tracker as sortable list with current-turn highlight** | Currently only badges on tokens; players need to see "wer ist dran" at a glance from across the table | LOW-MEDIUM | Sorted list; large-font for table-display readability; "next" button on GM side; advances turn via WebSocket event |
| **Token effects/conditions/auras on Display-Mode** | Players need to see "I'm flat-footed and frightened 2" without asking GM | MEDIUM | Already have conditions on character; need same model on tokens; per-token condition list rendered on/near token + in init list |
| **Token add/remove broadcast as WebSocket event** (not just query-invalidate) | Currently mid-battle changes desync until refresh | LOW | Existing gateway pattern; add `token:added` / `token:removed` events |

#### Dice + Chat

| Feature | Why Expected | Complexity | Notes |
|---------|--------------|------------|-------|
| **In-app dice with PF2e notation (`1d20+7`, `2d6+3`)** | Primary play mechanic; no external dice tabs | MEDIUM | Use `@dice-roller/rpg-dice-roller` or `dice-notation-js`; standard d4/6/8/10/12/20/100 |
| **Crit success / crit failure flagging** (PF2e: nat 20 / +10 / +0 / -10) | PF2e's defining mechanic — degree of success | MEDIUM | Compare result vs DC; degree-of-success calc lives in app (not in dice lib) |
| **Roll log per campaign + per battle, visible to all** | Without log, contested rolls become arguments | LOW | Append-only log table; WebSocket broadcast on new roll |
| **Roll attribution** (who rolled, what for, when) | Logs without attribution are useless | LOW | User + character + label (e.g. "Athletics Check") + timestamp |
| **In-game chat per campaign + per battle** | GM/player coordination during play | LOW-MEDIUM | Append-only message table; same WebSocket pattern; rendered with roll embeds inline |

#### GM Live Tools

| Feature | Why Expected | Complexity | Notes |
|---------|--------------|------------|-------|
| **GM can set HP / damage / heal on player character** | Already infra exists; just needs GM-facing UI | LOW | Reuse existing `character:update` events; add GM permission check + "GM action" log entry |
| **GM can add/remove/update conditions on player character** | Same | LOW | Reuse existing condition gateway events |
| **GM can give item to player character** | Loot distribution | LOW | Reuse existing inventory events; pick from equipment DB |
| **GM can adjust money (credits)** | Loot/cost management | LOW | Reuse existing money events |
| **GM can send push/chat ping to specific player(s) or all** | "Du bist dran" workflow | MEDIUM | Combines push (Web Push) with in-app chat — see Pitfalls about double-delivery |

#### Obsidian Vault Read-Only

| Feature | Why Expected | Complexity | Notes |
|---------|--------------|------------|-------|
| **Markdown rendering** (CommonMark + GFM tables/code blocks/images) | Bare-minimum vault reader | LOW | `react-markdown` + `remark-gfm` + `rehype-sanitize` |
| **Wikilinks `[[Note]]` and `[[Note\|Alias]]`** | Obsidian's primary linking syntax — without this, every link is broken | MEDIUM | `@portaljs/remark-wiki-link` or `@flowershow/remark-wiki-link` (handles shortest-path) |
| **Image embeds `![[image.png]]`** | Notes are useless if maps/illustrations don't render | MEDIUM | Custom remark plugin or extension of wiki-link; serve via vault endpoint |
| **Folder tree navigation** | Vaults aren't flat; navigation must mirror structure | LOW | Tree control over directory listing endpoint |
| **Full-text search** | Vaults grow large; finding "the inn name" without search is painful | MEDIUM | Server-side grep-like or `flexsearch`-style index over markdown body; Postgres FTS is acceptable |
| **Cache last-N read notes for offline** | "I want to look up that NPC" while at the table without Wi-Fi | MEDIUM | Service-Worker cache-on-read with LRU eviction; server stays source-of-truth |

### Differentiators (would make Dimension47 noticeably better than Pathbuilder/Foundry/Owlbear for this group)

| Feature | Value Proposition | Complexity | Notes |
|---------|-------------------|------------|-------|
| **German UI everywhere — including PF2e rules text** | Pathbuilder is English-only; Foundry's PF2e is partial-German with Babele/translation modules. Dimension47 already has a translation pipeline (Claude-API cached) | MEDIUM | Extend existing translation cache to feats and class-features text on Level-Up |
| **One-screen, integrated experience** (character sheet ↔ battle ↔ vault notes ↔ chat) without context-switching apps | At the table users today juggle Pathbuilder + Discord + Obsidian + a dice-roller — all in one app reduces friction | MEDIUM | Architecture choice: deep-linking + state-preserving navigation; vault note can be opened side-by-side with character |
| **PF2e dice with degree-of-success + auto-condition application** (e.g. "Frightened 1 on critical hit with X spell") | Most VTTs roll dice but leave degree-of-success and condition-application to player; auto-application removes one-step-per-attack friction | HIGH | Spell/attack-templates with embedded "on-hit"/"on-crit" effects; data model heavy — defer to v1.x |
| **Animated transition: GM "Du bist dran" ping → player phone vibrates → in-app initiative-card pop-up** | Combines push + visual + haptic; nobody else does it well at-the-table because nobody else is PWA-first | MEDIUM | Layer Web Push + Vibration API + in-app modal |
| **Battle-Display dark/cinematic mode** (large initiative card for active turn, dimmed for off-turn) | The table screen is part of the table aesthetic; sterile Foundry UI breaks immersion | LOW | CSS-only theme variant for `/battle/:id/display` route |
| **Vault note → character "see also" chips** (note marked with frontmatter `npc: true` shows as hoverable chip in chat / battle) | Connects worldbuilding (Obsidian) to play (battle/chat) without manual lookup | HIGH | Frontmatter parsing + tag/type indexing; defer to v1.x |
| **Roll history per character is exportable** (matches existing HTML-export ethos) | Group keeps session memory beyond runtime | LOW | Reuse export-character-html pattern |
| **Offline-cached vault search** (FlexSearch index served as static asset for installed PWA) | Read-and-search Obsidian notes with zero connectivity | HIGH | Build-step or on-demand index download; defer to v1.x or call out as risky |
| **GM can assign initiative roll-prompt** ("Roll Initiative for Perception" → all players get push + dice button pre-populated) | Removes 30-second "everyone roll initiative" coordination at the table | MEDIUM | Combines GM-tools + dice + push |

### Anti-Features (Commonly tempting, deliberately NOT building)

| Feature | Why Tempting | Why Problematic | Alternative |
|---------|--------------|-----------------|-------------|
| **Bidirectional Obsidian sync** (write-back from app to vault) | "Wouldn't it be great to edit notes from phone too" | Conflict resolution is its own product; group already uses Obsidian on desktop for editing | Read-only is explicitly in PROJECT.md Out of Scope |
| **Offline editing with sync queue** (offline character changes that re-sync later) | Looks pro, modern PWAs have it | Two players editing same character offline = last-write-wins corruption; complexity vs value at the table is bad — game is online anyway | PROJECT.md already excludes this; offline is read-only |
| **Native app (Capacitor / React Native wrapper)** | "Better push reliability, better install UX, app-store presence" | App-store overhead, build pipelines, two more codebases. PWA solves 95 % of need | PWA + careful Service-Worker; iOS Safari supports installed-PWA Push since 16.4 |
| **In-app character creation from scratch** | "Why force users out to Pathbuilder?" | Pathbuilder is a 5-year-mature character builder; rebuilding it duplicates years of work for one-time-per-character benefit | Pathbuilder import stays. Level-Up in app handles ongoing changes |
| **Generic VTT (other systems, D&D 5e, etc.)** | "More users" | Self-hosted for own group; data model is PF2e-specific (action-economy, proficiency tiers, archetypes); generalizing kills sharpness | Keep PF2e-only |
| **Public multi-tenant SaaS / signup flow** | Default mental model for "web app" | Self-hosted for own group; account-onboarding is 0-value | No public registration; ADMIN provisions accounts |
| **Presence indicators** ("Alex is viewing the map", "Spieler X tippt...") | Social-app default | Real value tiny vs WebSocket complexity, especially with mobile screen-locks | PROJECT.md already excludes this |
| **Fog of War on battle map** | Owlbear/Foundry have it | Group plays in-person with 3D minis on a table screen; fog of war with a flat overhead in-person doesn't make sense | Already out-of-scope in PROJECT.md |
| **Voice chat / video** | Discord-replacement temptation | Discord works fine; reinventing it costs a milestone for zero gain | Use existing Discord |
| **3D dice physics** (rolling animation, ringtone) | Feels premium | Burns CPU on mobile, distracts from in-person play, every player has real dice on the table anyway | Plain text "rolled 17" with crit-color highlight |
| **Real-time collaborative vault editing** (Obsidian Live-style) | Trendy | Group edits Obsidian on desktop; collaborative-CRDT for Markdown is a quarter-of-engineering for unclear gain | Read-only stays read-only |
| **AI-generated NPCs / encounters** | LLM hype | Out of scope; group's GM has Obsidian for prep | Vault read is enough |
| **Dynamic lighting** (Foundry's flagship feature) | "Looks like a real VTT" | In-person with table screen and minis; lighting is the room's lighting | No |
| **Token vision / line-of-sight calc** | Same | Same — minis on a table | No |
| **Auto-applying attack rolls to enemy HP** | "PF2e is so click-heavy, just automate it!" | High data-model cost (every attack-feat needs structured "on hit"/"on crit"/save-DC linking); error-recovery is messy when GM disagrees | GM applies HP changes manually via Live-Tools — already in-scope |
| **Marketplace for community NPCs / maps** | "GMs would love to share" | Group of 1 GM + N players; library is internal; sharing is out-of-scope (self-hosted, single-tenant) | GM-Library is internal-only |

## Feature Dependencies

```
PWA Manifest + Service Worker
    ├──enables──> Web Push
    │              └──used-by──> GM "Du bist dran" ping
    │              └──used-by──> Dice-roll-request push
    └──enables──> Offline-cache
                   ├──used-by──> Character sheet offline read
                   └──used-by──> Vault notes offline read

Web Push subscription endpoint persistence
    └──requires──> Per-user device-list table (server-side)

Level-Up system
    ├──requires──> Feat-prerequisite evaluator (DSL or interpreter)
    ├──requires──> Class-progression-table data (per-class proficiency by level)
    ├──requires──> Boost-cap recomputation (HP, save bonuses, AC)
    └──enables──> "Level" WebSocket event already exists, Level-Up can broadcast

Battle Display-Mode read-only route
    ├──requires──> Auth model decision (anon-token vs display-pseudo-user)
    ├──requires──> Token-effect data model (new schema)
    └──requires──> WebSocket event for token-add/remove (not query-invalidate)

Initiative Tracker upgrade
    └──depends-on──> Existing battle-session schema; pure UI + small server change

Dice roller
    ├──requires──> Roll-log table (campaign + battle scoped)
    ├──enables──> Chat with embedded rolls
    └──enables──> GM "request roll" feature (combines push + dice)

In-game Chat
    ├──requires──> Message table (campaign + battle scoped)
    ├──depends-on──> Existing JWT/role for whisper/visibility
    └──integrates-with──> Dice-roll-log (rolls render inline)

GM Live-Tools UI
    └──reuses──> All existing character WebSocket events (HP, conditions, items, money)
                 └──just-needs──> GM-facing UI surface (no new server events)

Obsidian Vault
    ├──requires──> Vault-endpoint protocol decision (HTTP-served-files vs Git-pull vs custom)
    ├──requires──> Markdown renderer (react-markdown + remark-wiki-link)
    ├──requires──> Image proxy for ![[image.png]]
    └──enables──> Vault-search (FlexSearch or Postgres FTS)

GM Push-Ping → Player feature
    ├──requires──> Web Push (PWA prerequisite)
    ├──requires──> In-game Chat (so the message has a destination)
    └──requires──> GM Live-Tools UI (the trigger surface)
```

### Dependency Notes

- **Web Push depends on PWA Manifest + Service Worker.** Cannot ship Push before installable PWA exists.
- **iOS Push requires installed-to-Home-Screen PWA** (Safari 16.4+). Test plan must include "is the PWA actually installed?" check.
- **Level-Up auto-recompute depends on per-class progression tables.** These are not currently in the DB schema (the existing app reads class-features from Pathbuilder import only, no progression model). New table needed: class progression by level, per-class.
- **Free Archetype is a per-character toggle**, not a global config. UI must show this toggle on character creation/edit.
- **GM-Live-Tools requires no new server events** — everything reuses existing character/inventory/condition/money WebSocket events. Risk: existing events probably don't enforce "is the actor a GM in this campaign" — needs server-side authorization audit.
- **Display-Mode auth needs a decision early.** Anonymous-token vs pseudo-user has long downstream effects on chat/roll attribution from the table screen.
- **Vault endpoint protocol is unresolved.** PROJECT.md says "selbst-gehosteter Endpoint, Protokoll noch zu wählen" — research/spike needed before vault phase.

## MVP Definition

(For the new milestone — not the whole app)

### Launch With (milestone v1)

Minimum viable to ship the milestone:

- [ ] **Level-Up regelkonform** — all six choice points (boost / class feat / skill feat / general feat / skill increase / ancestry feat / class feature) with prerequisite validation, auto-recompute, undo-before-commit, Free Archetype variant. Spellcaster slot/cantrip progression included.
- [ ] **PWA Manifest + Service Worker + Add-to-Home-Screen flow** — Android automatic, iOS guided
- [ ] **Cache-first offline read** for character sheet, inventory, feats, actions, alchemy, vault notes (already-visited only)
- [ ] **Web Push for GM→player ping** — VAPID keys, subscription persistence, GM-trigger UI
- [ ] **Battle Display-Mode route** — read-only, large initiative tracker, token effects/conditions visible
- [ ] **Token-effect data model + GM editor** — per-token list of named effects with optional duration
- [ ] **Token add/remove WebSocket event** — convert existing query-invalidate
- [ ] **Initiative Tracker upgrade** — sortable list, current-turn highlight, GM next-turn button
- [ ] **In-app dice with PF2e notation + degree-of-success + roll log** per campaign and battle, broadcast via WebSocket
- [ ] **In-game chat** per campaign and battle, with inline roll embeds
- [ ] **GM Live-Tools UI** — set HP/conditions/items/money on player character via existing events; send-message-to-player UI
- [ ] **Obsidian Vault read-only browser** — folder tree, file read, markdown + wikilinks + image embeds, full-text search, last-N offline-cached
- [ ] **German translation cache extension** for new feat-prereq text and class-feature descriptions

### Add After Milestone (v1.x — defer if scope tight)

- [ ] **Animated push-ping arrival** with vibration + in-app initiative-card overlay
- [ ] **Battle Display cinematic theme** — dim off-turn, large active-turn card
- [ ] **GM "request roll" from player** — combined push + pre-populated dice button
- [ ] **Roll-history export** to HTML/PDF
- [ ] **Vault frontmatter NPC chips** — type-tagged notes auto-link in chat/battle
- [ ] **Level-up history view** on character — what was chosen at each level

### Future Consideration (post-milestone)

- [ ] **Auto-condition application from spells/attacks** — heavy data-model cost, defer until Level-Up + Battle stabilize
- [ ] **Vault offline FlexSearch index** — full vault offline-search; only matters if vault grows large
- [ ] **Background-sync of stale character data** — limited iOS support; complex; nice-to-have
- [ ] **Multi-language UI beyond German** — only relevant if new players join who don't read German

## Feature Prioritization Matrix

| Feature | User Value | Implementation Cost | Priority |
|---------|------------|---------------------|----------|
| Level-Up: 6 choice points + validation + auto-recompute | HIGH | HIGH | P1 |
| Level-Up: Free Archetype variant | HIGH (group uses it) | MEDIUM | P1 |
| Level-Up: Spellcaster progression | HIGH (group has casters) | HIGH | P1 |
| PWA installable + offline character read | HIGH | MEDIUM | P1 |
| Web Push GM→player | HIGH | HIGH | P1 |
| Battle Display-Mode read-only route | HIGH | MEDIUM | P1 |
| Initiative tracker upgrade | HIGH | LOW-MEDIUM | P1 |
| Token effects/conditions | HIGH | MEDIUM | P1 |
| Token add/remove WebSocket | MEDIUM | LOW | P1 |
| Dice roller + roll log | HIGH | MEDIUM | P1 |
| In-app chat | HIGH | LOW-MEDIUM | P1 |
| GM Live-Tools (HP/conditions/items/money) | HIGH | LOW | P1 |
| Obsidian read + wikilinks + images | HIGH | MEDIUM | P1 |
| Vault search | MEDIUM-HIGH | MEDIUM | P1 |
| Vault offline-cache (last-N) | MEDIUM | MEDIUM | P1 |
| Battle cinematic theme | MEDIUM | LOW | P2 |
| Animated push-ping with vibration | MEDIUM | MEDIUM | P2 |
| GM "request roll" feature | MEDIUM-HIGH | MEDIUM | P2 |
| Level-up history view | MEDIUM | LOW | P2 |
| Vault frontmatter NPC chips | MEDIUM | HIGH | P3 |
| Auto-condition from spells | MEDIUM | HIGH | P3 |
| Vault offline FlexSearch full-index | LOW-MEDIUM | HIGH | P3 |

## PF2e-Specific Complexity Notes (Level-Up)

The Level-Up feature is structurally the most complex single piece in this milestone. Worth calling out:

1. **Six independent choice axes per level** (not all triggered every level): attribute boost, class feat, skill feat, general feat, skill increase, ancestry feat, class feature. Each has its own filter logic.
2. **Prerequisites are a mini-DSL.** Examples:
   - `"Trained in Athletics"` → simple skill-rank check
   - `"Strength 14, trained in Intimidation"` → composite check
   - `"Power Attack, level 4"` → feat ownership + level
   - `"Cleric"` → class check
   - Roughly 200+ feats have non-trivial prereqs; treating each as a free-text string and asking the GM is the cheap way out — but kills the "regelkonform" promise.
3. **Class progression tables vary widely.** Fighter has 5 weapon-specialization steps; Wizard has school-specific arcana progressions; Rogue has skill-increases at every level (not every other). No single shared table.
4. **Boost rules have an "above 18" cap rule.** Each boost is +2, but if attribute is already 18+, only +1. This is one of the most frequently-misunderstood PF2e rules — must be implemented correctly.
5. **Free Archetype variant** doubles the class-feat slots but restricts to archetype feats only AFTER dedication is taken. Once a dedication is chosen, the slot can take any feat from THAT archetype's list.
6. **Skill-increase scaling caps.** Trained→Expert allowed at level 3+; Expert→Master at level 7+; Master→Legendary at level 15+. Pre-cap selections must be filtered out.
7. **Multiple-class-feature characters.** A Champion at level 9 might have: Champion's Reaction, Deity's Domain Spell, Divine Ally, an Ancestry feat slot, a Class feat slot, plus a Free Archetype slot. UI needs to make this navigable, not overwhelming.

**Recommendation:** Phase Level-Up as its own implementation phase. Treat prerequisite-DSL as a sub-deliverable. Plan for an "escape hatch" where a non-evaluated prerequisite shows as a warning ("kann nicht automatisch geprüft werden") rather than a hard block, so unusual feats don't break the flow.

## Competitor Feature Analysis

| Feature | Pathbuilder 2e | Wanderer's Guide | Foundry VTT (PF2e) | Owlbear Rodeo | Our Approach |
|---------|----------------|------------------|---------------------|---------------|--------------|
| Level-Up | Full, mature, English-only | Full, web-based, English-only | Full via PF2e Leveler / PF2e Level-Up Wizard modules | N/A (no character system) | Full, German, integrated, with Free Archetype |
| Dice roller | Basic | Basic | Excellent (PF2e-specific) | Built-in, simple | PF2e degree-of-success + roll log + chat embed |
| Chat | None | None | Yes, with whisper/blind | Yes, simple | Yes, with roll embed + push-ping |
| Battle map | None | None | Heavy, feature-rich (lighting, vision, fog) | Lightweight, fast, in-person-friendly | Lightweight + dedicated table-display mode |
| Player display screen | N/A | N/A | Possible via second browser, not optimized | Cast feature (Chromecast/separate monitor) — fully read-only player view | Dedicated `/battle/:id/display` route, read-only, optimized for embedded table screen |
| Push notifications | None | None | None (it's Electron, not PWA) | None | Web Push with VAPID, GM→player ping |
| Offline | No (web app) | No (web app) | Local install, but no field offline | Browser-cached after load | Service Worker cache-first for read |
| Obsidian integration | No | No | Possible via 3rd-party module | No | Native vault browser |
| German UI | No | No | Partial via Babele + community pack | Partial | Full, including auto-translated PF2e text |
| Hosting model | SaaS | SaaS | Self-hosted | SaaS (free + paid tiers) | Self-hosted (matches PROJECT.md) |
| Mobile-first | Tablet-first | Desktop+tablet | Desktop, mobile painful | Mobile-acceptable | Yes (already shipped for character sheet) |
| Cost | One-time app purchase | Free | One-time license fee | Free + paid tiers | Self-hosted, group only |

### Key Takeaways

- **No competitor combines all six target areas** of this milestone in one app. Pathbuilder excels at character (esp. level-up) but is character-only. Foundry has battle + chat + dice but desktop-heavy and module-fragmented. Owlbear has the cleanest player-display-screen story but no character system. Obsidian is its own thing entirely.
- **The "all-in-one for our group, in German, on mobile-first PWA" niche is unoccupied.** This is the differentiator.
- **PF2e Leveler and PF2e Level-Up Wizard (Foundry modules) prove that prerequisite-validating Level-Up is feasible** — they exist and are maintained. We can study their data models without using their code (license / system difference).
- **Owlbear's "cast" feature is the closest to our table-display goal** — read-only, joins as fake-player, cannot see GM-only content. That's a solid mental model.

## Sources

- [Pathfinder 2e Leveling Up — Archives of Nethys](https://2e.aonprd.com/Rules.aspx?ID=2065)
- [Pathfinder 2e Ability Boosts — Archives of Nethys](https://2e.aonprd.com/Rules.aspx?ID=75)
- [Pathfinder 2e Skill Increases — Archives of Nethys](https://2e.aonprd.com/Rules.aspx?ID=2109)
- [Pathfinder 2e Free Archetype — Archives of Nethys](https://2e.aonprd.com/Rules.aspx?ID=2751)
- [Wanderer's Guide character builder](https://wanderersguide.app/)
- [PF2e Leveler — Foundry VTT module](https://foundryvtt.com/packages/pf2e-leveler)
- [PF2e Level-Up Wizard — Foundry VTT module](https://foundryvtt.com/packages/pf2e-level-up-wizard)
- [Owlbear Rodeo Casting documentation](https://docs.owlbear.rodeo/docs/casting/)
- [Foundry VTT Basic Dice](https://foundryvtt.com/article/dice/)
- [Roll20 Dice Reference](https://help.roll20.net/hc/en-us/articles/360037773133-Dice-Reference)
- [PWA Best Practices 2026 — Wirefuture](https://wirefuture.com/post/progressive-web-apps-pwa-best-practices-for-2026)
- [PWA iOS Limitations and Safari Support 2026 — MagicBell](https://www.magicbell.com/blog/pwa-ios-limitations-safari-support-complete-guide)
- [Apple reverses decision about blocking web apps in EU — TechCrunch](https://techcrunch.com/2024/03/01/apple-reverses-decision-about-blocking-web-apps-on-iphones-in-the-eu/)
- [@portaljs/remark-wiki-link — npm](https://www.npmjs.com/package/@portaljs/remark-wiki-link)
- [react-markdown documentation](https://remarkjs.github.io/react-markdown/)
- [airjp73/dice-notation — GitHub](https://github.com/airjp73/dice-notation)
- [Foundry VTT vs Roll20 vs Owlbear Rodeo 2026](https://gmcrafttavern.com/foundry-vs-roll20-owlbear-2026/)

---
*Feature research for: Dimension47 next milestone (PWA + multi-screen battle + extended WebSockets + Obsidian read-only vault + full PF2e Level-Up)*
*Researched: 2026-04-27*
