darkwatch/docs/specs/2026-04-08-shadowdark-character-manager-design.md

164 lines
6.8 KiB
Markdown

# Shadowdark Character Sheet Manager — Design Spec
## Overview
A web app for managing Shadowdark RPG character sheets in real-time. Players in a campaign can view and edit characters simultaneously, with changes syncing live across all connected clients. Hosted locally and exposed via ngrok for group access.
## Tech Stack
- **Frontend:** React + Vite (TypeScript)
- **Backend:** Node.js + Express + Socket.IO
- **Database:** SQLite (single file, zero config)
- **Project location:** `/Users/aaron.wood/workspace/shadowdark/`
- **Structure:** `client/` and `server/` directories
## Data Model
### campaigns
| Column | Type | Notes |
| ---------- | ------- | -------------------------- |
| id | INTEGER | Primary key, autoincrement |
| name | TEXT | Campaign name |
| created_by | TEXT | For future auth |
| created_at | TEXT | ISO timestamp |
### characters
| Column | Type | Notes |
| ----------- | ------- | -------------------------------------------------- |
| id | INTEGER | Primary key, autoincrement |
| campaign_id | INTEGER | FK to campaigns |
| created_by | TEXT | For future auth |
| name | TEXT | Character name |
| class | TEXT | Fighter / Priest / Thief / Wizard |
| ancestry | TEXT | Human / Elf / Dwarf / Halfling / Goblin / Half-Orc |
| level | INTEGER | Default 1 |
| xp | INTEGER | Default 0 |
| hp_current | INTEGER | |
| hp_max | INTEGER | |
| ac | INTEGER | |
| alignment | TEXT | Lawful / Neutral / Chaotic |
| title | TEXT | Optional, e.g. "the Brave" |
| notes | TEXT | Freeform notes |
### character_stats
| Column | Type | Notes |
| ------------ | ------- | --------------------------------- |
| character_id | INTEGER | FK to characters |
| stat_name | TEXT | STR / DEX / CON / INT / WIS / CHA |
| value | INTEGER | Raw score (3-18 typically) |
One row per stat per character. Ability modifiers are derived, not stored:
| Score | Modifier |
| ----- | -------- |
| 1-3 | -4 |
| 4-5 | -3 |
| 6-7 | -2 |
| 8-9 | -1 |
| 10-11 | +0 |
| 12-13 | +1 |
| 14-15 | +2 |
| 16-17 | +3 |
| 18 | +4 |
### character_gear
| Column | Type | Notes |
| ------------ | ------- | ----------------------------------------------------- |
| id | INTEGER | Primary key, autoincrement |
| character_id | INTEGER | FK to characters |
| name | TEXT | Item name |
| type | TEXT | weapon / armor / gear / spell |
| slot_count | INTEGER | Gear slots used (Shadowdark inventory system) |
| properties | TEXT | JSON — e.g. `{"damage":"1d6","melee":true,"bonus":1}` |
Spells are stored as gear entries with `type: "spell"` and a `tier` property in the JSON.
### character_talents
| Column | Type | Notes |
| ------------ | ------- | ----------------------------------------- |
| id | INTEGER | Primary key, autoincrement |
| character_id | INTEGER | FK to characters |
| name | TEXT | Talent name |
| description | TEXT | Flavor/rules text |
| effect | TEXT | JSON — mechanical bonuses for dice roller |
## UI Layout
### Campaign List (home page)
- Grid/list of existing campaigns
- "+ New Campaign" button
- Click a campaign to enter it
### Campaign View (main screen)
- Campaign name header
- Responsive character card grid:
- Desktop: 4 cards across
- Tablet: 2 cards across
- Mobile: 1 card, stacked
- Cards flow naturally — 6 characters = 4 + 2 rows on desktop, just scroll
- "+ Add Character" button
- Future: dice log panel (right side on desktop, bottom drawer on mobile)
### Character Card (in the grid)
- Name, class, ancestry, level header
- HP bar with +/- buttons (current / max)
- AC display
- Six stats in compact 3x2 layout: score, modifier, +/- buttons
- Gear summary (slots used / total)
- Click to expand into full detail view
### Character Detail (expanded / modal)
- Full stat editing with +/- buttons
- Gear/inventory management: add/remove items with type and properties
- Talents list: add/remove with name, description, effect
- Spell list (for Priests/Wizards — gear items with type "spell")
- Notes freeform text field
- Future: dice roll buttons next to weapons/spells
## Real-time Sync
- Client joins a Socket.IO room per campaign (room ID = campaign ID)
- Mutation flow: client -> server API -> save to SQLite -> broadcast to room
- Other clients receive update and patch local state (no full reload)
- Optimistic UI: editing client updates immediately, server confirms
- On reconnect, client fetches latest full state from server
## Auth (v1: none, future-ready)
- v1 is open free-for-all: anyone with the link can create/edit anything
- `created_by` fields exist in the schema for future use
- Migration path to light auth (name/pin per character) or GM controls requires adding middleware, not restructuring
## Future: Dice Rolling (not in v1)
Design accommodations for future dice rolling:
- **Shared dice log panel** — layout reserves space for it
- **Inline roll buttons** — next to weapons/spells and stats
- **Server-side rolls** — server calculates d20 + ability modifier + gear/talent bonuses, broadcasts result
- **Log entries** — show who rolled, what for, full breakdown (e.g. "Kira attacks with Longsword +1: d20(14) + STR(+2) + weapon(+1) = 17"), and timestamp
- **Data model supports it** — `character_gear.properties` and `character_talents.effect` JSON fields carry the mechanical data the roller needs
## Deployment
- Run `server/` on localhost with a configured port
- `client/` built and served by Express (or Vite dev server during development)
- Expose via ngrok for friends to access
- SQLite file lives in `server/data/shadowdark.db`
## Out of Scope for v1
- Authentication / permissions
- Dice rolling
- Character import/export
- Multiple themes / dark mode
- Mobile native app