- Ruby 79%
- HTML 19.8%
- CSS 1%
- Shell 0.2%
| .opencode | ||
| app | ||
| bin | ||
| config | ||
| db | ||
| docs | ||
| lib | ||
| public/css | ||
| test | ||
| .gitignore | ||
| AGENTS.md | ||
| app.rb | ||
| Gemfile | ||
| Gemfile.lock | ||
| PHASE1.md | ||
| PHASE2.md | ||
| PHASE3.md | ||
| PHASE4.md | ||
| PHASE5.md | ||
| PHASE6.md | ||
| Rakefile | ||
| README.md | ||
| SPECIFICATION.md | ||
Campaigner
A system-agnostic tabletop RPG campaign manager. Character sheets, game mechanics, and stats are not hardcoded — the Dungeon Master defines them dynamically through the web interface. Players join campaigns and create characters from the DM-defined templates.
Built with minimal dependencies: Ruby stdlib (WEBrick, ERB, JSON, YAML) plus Sequel ORM, sqlite3, and bcrypt.
Current Features
Accounts & Authentication
- User registration — Create a DM or player account
- Login / Logout — Sign in and out of your account
- Dashboard — See all your campaigns at a glance
Campaign Management
- Create and manage campaigns — DMs set up and run campaigns
- Player invitations — Add or remove players by username
- Transfer ownership — Hand a campaign off to another DM
- Import/Export — Back up or share entire campaigns
- In-game time — Track elapsed time with formatted display
- Game phases — Define named game states (exploration, combat, rest, etc.) that display with human-readable names
Character Sheet Templates
- Design your own sheets — DMs create custom templates with a visual tree-based builder (Guide)
- 12 field types: containers (vertical/horizontal boxes), labels, images, player avatars, DM-only fields, player-editable fields, creation-only fields, computed formulas, inventory lists, checkboxes, and phase-locked fields (Reference)
- Drag-free reordering — Move fields up/down or reparent between containers
- Conditional visibility — Show fields only when another field has a specific value (e.g., show spell slots only for wizards)
- Live preview — See how the sheet will look before players use it
Characters
- Create from templates — Players pick a template and fill it in; DMs can make NPCs
- Inline editing — Edit fields right on the sheet view with a Save button (players edit their own fields, DMs also edit DM-designated fields)
- Creation-only fields — Set once during character creation, locked afterward
- Smart inputs — Text, numbers, dropdowns, checkboxes, and inventory tables render automatically from the template
- Import/Export — Share or back up individual characters
- Delete protection — Only the creator (player or DM) can delete a character
Mechanics & Dice
- 8 mechanic types: dice rolls, pools, checks (vs DC), formulas, table lookups, composite multi-step actions, phase definitions, and transitions
- Dice expressions — Roll standard notation (
d20,2d6,d20+5) with advantage/disadvantage - Composite actions — Multi-step sequences (attack → damage → apply to HP) with branching, target selection, and choices
- Apply results — Send roll outcomes directly to character fields (set, add, subtract, or append)
- Quick roll bar — Ad-hoc dice expression on every campaign page
- Phase system — Define game states (exploration, combat, rest) with transitions, time costs, and optional roll requirements
- Share mechanics — Export and import individual mechanics between campaigns
Game Sessions
- Live play — DMs start a session from the campaign page; only one active session per campaign at a time
- Session Play screen — Dedicated view showing session status, current phase (human-readable), and in-game time
- Phase control — Switch phases during play; transitions respect time costs and roll rules
- Advance time — Move time forward by preset durations (1 round, 1 minute, 1 hour, etc.) or directly to a time of day (dawn, morning, noon, etc.)
- Session log — Chronological log of everything that happens: session start/end, phase changes, time advancements, and DM-written narrative entries. DM can mark entries as DM-only (hidden from players). Previous session's log shown for continuity.
- Player view — Players see the active session with phase, time, and log (public entries only)
- Player actions — Players can roll mechanics from the session view; results go to the DM for confirmation
- Pending queue — DM reviews pending player rolls and confirms or rejects them; confirmed rolls are logged and effects applied
- DM quick roll — DMs can roll dice directly within a session, with results logged to the session log
- Composite execution — Multi-step mechanics run within a session with each step logged
- Auto-cleanup — Sessions auto-end after 12 hours of inactivity
- Session history — Browse past sessions with their status and phase
Setup
git clone <repo-url> && cd campaigner
bin/setup
This installs gems, creates the db/ directory, and runs migrations.
Running the Server
bin/server
Starts WEBrick on http://0.0.0.0:8080 (configurable via config/app.yml — port and bind keys).
Usage
Open your browser to http://localhost:8080 and create an account. From there everything is driven through the web interface — register as a DM or player, create or join campaigns, design character templates, manage characters, define mechanics and dice rules, and run live game sessions.
Running Tests
bin/test
Executes all tests (350+) against a temporary test database.
Project Structure
app.rb Entry point — router config, WEBrick server
app/
boot.rb Loads config, connects DB, requires app files
controllers/ One file per controller
models/ Sequel model files with FieldValueModel mixin
views/ ERB templates organized by controller
layouts/ Master layout with nav and flash messages
config/ Database and app configuration
db/migrations/ Sequel migration files
lib/
router.rb HTTP request router with named params
controller.rb Base controller (session, auth, rendering)
field_value_store.rb Dot-path key/value <-> nested hash conversion
view_helper.rb ERB helpers and template builder renderers
dice_roller.rb Dice notation parser and roller (NdM, pools, checks, tables)
composite_executor.rb Multi-step composite mechanic execution engine
session_logger.rb Session log entry creation (for future Phase 6b+)
timekeeper.rb In-game time formatting, duration parsing, time-of-day
public/css/ Stylesheet
test/ Unit, controller, and integration tests
Architecture
All entity data uses a hybrid model: core columns (id, FKs, timestamps, password_hash) live in fixed database columns. Everything else is stored as rows in a companion {entity}_field_values table using dot-path keys (e.g. stats.strength, equipment.0.name). This allows arbitrary character attributes and game settings without schema migrations.
The FieldValueModel mixin handles bidirectional conversion between flat database rows and nested Ruby hashes.
Template fields form a tree via a self-referential parent_id foreign key on the template_fields table, where each node stores its configuration (type, label, key, etc.) as field value rows.
Mechanics (game rules, dice rolls, phases, transitions) and game sessions use the same EAV pattern — a core table for identity and relationships, and a _field_values companion table for all mutable attributes. This means new mechanic types and session features can be added without schema changes. (Architecture Reference)