compw00ter — Hero Builder (Design Spec)
Date: 2026-06-20 Status: Awaiting review Scope of this spec: The backend Hero Builder admin tool — the first buildable piece. The wider game design is captured below as context, but is not built in this phase.
1. Game vision (context, not built yet)
compw00ter is a web-based multiplayer game for an annual 10-friend LAN party. Two modes are planned; we build co-op first, PvP brawler is deferred.
Co-op mode — Keep The LAN Alive: Ten friends vs. entropy. Players don't fight each other — they fight everything threatening to end the LAN party. Goal: survive as long as possible. Score = party uptime.
Decisions locked during brainstorming:
- Genre: real-time, turn-less scramble (cooldown-driven), not strict turns.
- Tech (split): the Hero Builder is a PHP web app served by the existing Apache (no new port). The game engine is a separate Node.js + WebSocket server on port 6767, played over the LAN. They share one SQLite database file: PHP writes hero content, Node reads it at match time.
- Core threat: an Incident Queue with limited slots (~6–8). Incidents have a type (Tech / Social / Supply / Chaos), a size (small / big), and a countdown.
- Small fire: one matching hero ability clears it.
- Big fire: several heroes must hit it together before its timer expires.
- Lose condition: queue overflow. Expired incidents lock in and clog their slot; when a new incident has no free slot, the party collapses.
- Bosses: named social forces that target players, not just the board. E.g. The Wife (removes a player until rescued), The Martin (pulls several players out; +morale, −beer). A rescue/cover path exists so removal isn't always permanent.
- Heroes (the soul): each hero has a superpower and a self-destruct. To get stronger you indulge (beer / edibles / energy drink) for buffs, but indulging pushes you into a state (Drunk / High / Wired / Tilted). When a hero hits their trigger state, their game-ruining trait fires. e.g. b0n1 goes High → spawns a Malware (Chaos) incident.
- Light resources: Beer/Supplies (spent indulging, drained by bosses) and Morale (soft modifier).
- Screens: own-screen-only — each player sees the shared board + their own hero panel on their own device.
The heroes are the content everything depends on, so the Hero Builder is built first.
2. Hero Builder — what we build now
A PHP web application, served by the existing Apache under the site web root (like booking/, racecloud/), to create, edit, and delete heroes and their abilities/traits, plus the shared game vocabularies they reference. Data persists in a SQLite database file. The eventual Node game engine reads the same SQLite file — the database is the contract between the PHP builder and the Node runtime.
2.1 Goals
- Author a roster of heroes, each with several abilities and several traits.
- Edit the shared vocabularies (incident types, vice states, vices→states) since the design is still fluid.
- Fast, friendly, single-page admin UI usable on a laptop.
- Clean data model the future game runtime can consume directly.
2.2 Non-goals (this phase)
- The game loop / real-time WebSocket runtime.
- PvP brawler mode.
- Authentication beyond a simple optional shared token (this is a local/LAN admin tool).
- Player accounts, matchmaking, lobbies.
3. Data model (SQLite)
heroes
id TEXT PRIMARY KEY -- slug, e.g. "b0n1"
name TEXT NOT NULL
tagline TEXT -- short flavour/bio
based_on TEXT -- which real friend
color TEXT -- hex theme colour
created_at TEXT
updated_at TEXT
abilities
id INTEGER PRIMARY KEY
hero_id TEXT NOT NULL REFERENCES heroes(id) ON DELETE CASCADE
name TEXT NOT NULL
description TEXT
counters_type TEXT -- references incident_types.name
target TEXT -- 'small' | 'big' | 'boss' | 'any'
power INTEGER -- effect magnitude (clear / cut timer / contribute X)
cooldown INTEGER -- seconds
boosted_while_indulging INTEGER -- 0/1
sort_order INTEGER
traits
id INTEGER PRIMARY KEY
hero_id TEXT NOT NULL REFERENCES heroes(id) ON DELETE CASCADE
name TEXT NOT NULL
description TEXT
trigger_state TEXT -- references vice_states.name
effect TEXT -- what bad thing happens (free text in v1)
severity TEXT -- 'minor' | 'major' | 'catastrophic'
sort_order INTEGER
-- Editable vocabularies
incident_types (id INTEGER PK, name TEXT UNIQUE, sort_order INTEGER)
vice_states (id INTEGER PK, name TEXT UNIQUE, sort_order INTEGER)
vices (id INTEGER PK, name TEXT UNIQUE, state TEXT, sort_order INTEGER) -- state -> vice_states.name
Seeded defaults:
- incident_types: Tech, Social, Supply, Chaos
- vice_states: Drunk, High, Wired, Tilted
- vices: Beer→Drunk, Edibles→High, Energy Drink→Wired
Seed heroes (starter examples, fully editable):
- Eradicus — ability Fix The Internet (counters Tech, target any, power high, cooldown ~30s); trait Perfectionist Meltdown (trigger Tilted → briefly freezes own abilities, severity major).
- b0n1 — ability Quick Patch (counters Tech, target small, cooldown ~20s); trait Malware Drop (trigger High → spawns a Malware/Chaos incident, severity catastrophic).
These exist so the tool opens with working examples; the user edits/replaces them.
4. Architecture
The repo splits into a PHP builder (built now) and a Node engine (built later), sharing one SQLite file.
compw00ter/ -- served by Apache at https://.../compw00ter/
index.php -- hero list / dashboard
hero_edit.php -- create/edit one hero (identity + abilities + traits)
hero_save.php -- POST handler: validate + persist (then redirect)
hero_delete.php -- POST handler: delete (cascade)
vocab.php -- edit incident types / vice states / vices
classes/
Database.php -- PDO SQLite connection (singleton), WAL mode
HeroRepository.php -- CRUD for heroes + nested abilities/traits
VocabRepository.php -- CRUD for the editable vocabularies
includes/
config.php -- DB path, app constants
bootstrap.php -- session start, CSRF helpers, autoload
header.php / footer.php -- shared XHTML layout (project palette)
sql/
schema.sql -- table definitions
seed.sql -- vocab defaults + Eradicus & b0n1 seeds
assets/
style.css -- styling (project palette)
builder.js -- progressive enhancement: inline add/remove rows
data/ -- NOT web-accessible (.htaccess deny)
compw00ter.db -- shared SQLite file (created on first run)
.htaccess -- Require all denied
engine/ -- Node game engine (LATER, not this phase)
package.json, server.js ... -- WebSocket runtime on port 6767, reads ../data/compw00ter.db
docs/superpowers/specs/...
- Vanilla PHP 8.4, PDO SQLite, prepared statements throughout — matches the house style of the other apps here (
booking/,racecloud/). - The SQLite file lives in
data/with an.htaccessdeny so it is never web-downloadable. - WAL journal mode on the DB so the PHP builder and the Node engine can read/write concurrently without lock contention.
- The Node engine (built in a later phase) lives in
engine/with its ownpackage.jsonand reads the same DB viabetter-sqlite3(already verified to compile here).
4.1 Request flow (no JS required)
Form-POST, server-render, redirect — works fully without JavaScript (progressive enhancement, per house style):
index.php— list heroes; links to edit; “New Hero”.hero_edit.php?id=…— renders the hero form. Abilities and traits are repeatable fieldset rows.hero_save.php— CSRF-checked POST; validates; upserts hero + replaces its abilities/traits inside one transaction; redirects back.hero_delete.php— CSRF-checked POST; cascade delete; redirect.vocab.php— edit incident types / vice states / vices (POST + redirect).
builder.js only enhances: add/remove ability & trait rows client-side without a round-trip. With JS off, an "Add row" submit re-renders the form with one more empty row.
4.2 Validation & security
- All state-changing actions are POST with a CSRF token (session-based).
- Prepared statements for every query; output escaped with
htmlspecialchars(XSS). - Server-side validation: hero
namerequired; abilitycounters_typemust be a known incident type; traittrigger_statemust be a known vice state; numeric fields coerced/bounded. - Builder is unauthenticated for local/LAN admin use in v1 (noted in Open Questions); the
data/deny rule is the key protection.
4.3 UI
- Dashboard: hero cards/list + “New Hero”; link to Vocabularies.
- Hero editor: identity fields; an Abilities section (repeatable rows: name, description, counters-type, target, power, cooldown, indulge-boost); a Traits section (repeatable rows: name, description, trigger-state, effect, severity); Save / Delete.
- Dropdowns for
counters_type,target,trigger_state,severityare populated live from the vocabularies. - XHTML 1.1 Strict, accessible labels, project palette (warm orange
#FF7F4F, nice blue#4A9FCC).
5. How to run
- Builder: nothing to start — it's PHP served by the existing Apache at
https://playground.crisprain.co.uk/compw00ter/. First load createsdata/compw00ter.dbfromschema.sql+seed.sql. (If the first load throws "could not find driver", reload web PHP once:sudo systemctl reload php8.4-fpm apache2.) - Engine (later):
cd engine && npm install && node server.js→ WebSocket runtime on port 6767, reading the shared DB.
6. Open questions / deferred
- Auth: ship unauthenticated for local use now; optional shared-token later.
- Trait
effectis free text in v1; may become structured once the game runtime defines concrete effect types. - Ability
powersemantics will be pinned down precisely when the incident engine is built.