Files
Dimension-47/.planning/research/FEATURES.md

30 KiB
Raw Blame History

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


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