← back to the game

Battle of the Bands

v0.3.2
Rules & Changelog · Issue №0.3.2

Rules

A turn-based JRPG band brawler. Build a band, pick a foe, fight.

This document is the single source of truth for game mechanics. Edit content/rules.md to update what's published here.


Team building

  • A band is exactly 5 characters.
  • There are three slots: Rhythm, Melody, Harmony.
  • Max 2 characters per slot — so every valid band runs a 2 / 2 / 1 distribution.
  • Slot determines class (see below).

Classes

Class is derived from slot — no separate pick.

SlotClassRole
RhythmTankSoaks hits. Taunts. Shields.
MelodyDPSBurns the enemy down. AoE + debuffs.
HarmonySupportHeals, buffs, accelerates.

Because every band runs 2 / 2 / 1, every band has at least one of each class.

Genres (types)

Each character has a genre, which is their type — same idea as Pokémon. There are 8 genres in 4 families:

FamilyGenres
LoudMetal · Punk
AcousticPop · Folk
EdgyGoth · Emo
DigitalElectronic · Hip-hop

Type effectiveness

Each family beats two others, is neutral on itself, and loses to one:

Attacker → DefenderLoudAcousticEdgyDigital
Loud×1×1.5×1.5×0.66
Acoustic×0.66×1×1.5×1.5
Edgy×1.5×0.66×1×1.5
Digital×1.5×1.5×0.66×1
  • Super effective: ×1.5 damage
  • Resisted: ×0.66 damage
  • Neutral (same family): ×1

Applied to all damage moves (basic, single-target damage, AoE, vampiric — per-target for AoE).

Heals, buffs, speed-boost, taunt, shield, and the debuffs (mute / feedback / detune) ignore type effectiveness. The hearing-damage status uses the snapshot damage value set when applied and doesn't re-roll types on each tick.

Genre synergies

If a band has 3 or more characters of the same genre, that genre's synergy is active for the whole battle:

GenreSynergy effect
Metal+25% max HP on metal members (computed at battle start)
Punk−1 SP cost on punk members' moves (minimum 1)
Pop+50% heal value on pop healers
Folk+50% buff value on folk buffers
Electronic+1 to speed-boost amount, +50% shield amount on electronic members
Hip-hop+25% damage on hip-hop attackers
Goth+50% heal on vampiric moves by goth members
EmoHearing damage applied by emo members lasts 1 extra turn

Synergies stack across genres — a band with both 3-Metal and 3-Punk would get both. With 5 members and max 2 per slot, you can have at most one 3-genre synergy unless you weight a single genre into multiple slots.


Speed points (SP)

Every character has a pool of speed points that limits how often they can act.

  • Cap: 10 SP
  • Start of battle: 3 SP
  • Regen: +1 SP at the start of the character's own side's turn
  • Moves spend SP equal to their cost.
  • If a character can't afford any of their moves, they sit out the turn.
  • If an entire side can't act, the turn passes to the other side.

Move cost ladder

TierCostExamples
Basic1 SPevery character's chip attack
Cheap support2 SPFolk Chord, Campfire Song, Sync Pulse
Heavy support3 SPBackup Chorus, BPM Up, Bit Crush
Tank special3 SPall taunts, all shields
DPS special4 SPAoE, Mute, Feedback, Detune

Specials are commitments — you'll save up for 2-4 turns before firing one.

Moves

Each character has two moves: a basic and a special.

Basic attacks

Every character has a 1-SP single-target damage move with a genre-flavored name:

  • Metal: Headbang
  • Punk: Quick Slam
  • Pop: Mic Tap
  • Folk: Easy Strum
  • Electronic: Pulse
  • Hip-hop: Quick Bar

All basics deal 18 damage before type/synergy modifiers.

Special moves

The special move is class-specific:

Tank specials — protection

  • Taunt: caster enters a locked stance. They can't act, but every opposing single-target damage attack is redirected onto them. The taunt is consumed by the next opposing damage move (single-target or AoE) — on consumption, the taunter unlocks (SP at current value, ready to act next turn).
  • Shield: applies a temporary HP layer to an ally. Damage is absorbed by shield before HP. Stacks if cast again.

DPS specials — AoE, debuffs, and edgy/loud signatures

  • AoE damage: hits every alive opposing character. Per-target type multiplier. Bypasses single-target taunt redirection, but consumes any active taunt on the opposing side.
  • Mute: hidden status applied to a random opposing character. You do not know which one. The next action that character attempts fizzles and reveals the mute, then clears it. SP is still spent on the fizzled action.
  • Feedback: visible status applied to a chosen enemy. Their next damage move (basic or AoE) backfires — the damage is applied to themselves instead of the target. Cleared after the backfire.
  • Detune: visible status applied to a chosen enemy. Their next damage move (basic or AoE) hits a random ally on their own band instead of you, then clears. Detune does not affect heals, buffs, speed-boosts, or shields — those resolve normally; the detune waits for a damage move.
  • Vampiric (edgy — goth, emo): single-target damage that drains health from the enemy into the attacker. Only damage that actually reaches HP heals you — shield absorption doesn't bleed, so a shielded enemy yields nothing to the lifesteal until you chew through the shield. The heal is 50% of HP damage dealt (rounded), or 75% with the Goth synergy. Type multipliers and damage buffs scale the heal because they scale the damage.
  • Hearing damage (loud — metal, punk): applies a damage-over-time status to one enemy. Small damage per turn for several turns, ticking at the start of the affected character's own turn. Any heal applied to that character cures hearing damage (regardless of heal size).

One debuff per target. Mute, Feedback, and Detune don't stack on the same character — applying a second debuff to an already-debuffed enemy fizzles (SP still spent). Hearing damage is a separate status and stacks with debuffs (but re-applying refreshes its turn counter).

Support specials — buffs

  • Heal: restores HP to an ally (capped at max HP).
  • Buff-damage: adds a flat damage bonus that's consumed by the target ally's next damage move (basic or AoE).
  • Speed-boost: grants the target ally bonus SP, capped at max SP (5).

Combat flow

Manual mode

  1. It's your turn. Tap a ready bandmate to select them as the attacker.
  2. The MovePicker appears with Basic and Special buttons. Each shows its SP cost and effect; buttons you can't afford are disabled. Pick one.
  3. Targeting:
    • Single-target damage / heal / buff / speed-boost / shield / feedback / detune → tap the target.
    • Self-target (taunt) → fires immediately.
    • Random-enemy (mute) → fires immediately, target chosen by the game.
    • All-enemies (AoE) → fires immediately, hits all alive opposing characters.
  4. The action resolves. SP is deducted. Turn passes to the foe.

Auto mode

Each side's AI picks a ready actor, a move (basic or special), and a target according to a fixed priority list. Sit back and watch.

The AI priority (roughly, each side, every turn):

  1. Re-cast taunt if a tank's special is taunt and they aren't currently taunting
  2. Shield a low-HP ally with no current shield
  3. Heal an ally below ~55% HP
  4. Speed-boost an ally that's low on SP
  5. Buff-damage an unbuffed damager
  6. Cast a debuff (mute / feedback / detune)
  7. AoE if 2+ opponents alive
  8. Otherwise — basic attack the lowest-HP enemy

Status reference

These appear as badges on combatant cards in battle:

BadgeMeaning
⚡NCurrent SP
🛡N (cyan)Shield amount remaining
🛡TTaunt stance — locked, drawing single-target damage
✨+NPending damage bonus — applied to next attack
🔁Feedback rigged — next damage move backfires
🎶❌Detuned — next damage move flips to own ally
🩸NHearing damage — N turns of DoT remaining
(hidden)Mute is hidden until tripped. The enemy team may also have one of yours muted.

Type chart (quick reference)

Attacker → DefenderLoudAcousticEdgyDigital
Loud×1×1.5×1.5×0.66
Acoustic×0.66×1×1.5×1.5
Edgy×1.5×0.66×1×1.5
Digital×1.5×1.5×0.66×1

Victory

Wipe the opposing band. KO'd characters can't be targeted, healed, or revived. Last band standing wins the night.

Changelog

Versions follow SemVer: MAJOR.MINOR.PATCH.

Each entry summarizes what shipped. When a change came from playtester feedback, it's called out as such so the link from "real player ran into X" → "fix Y" stays visible.

To cut a release: bump version in package.json, add an entry below, then vercel deploy --prod. The /rules page renders this file automatically.

Working agreement: every user-visible change in a commit must land with a ## Unreleased bullet in this file. Cutting a release renames ## Unreleased to ## X.Y.Z — YYYY-MM-DD and starts a fresh empty ## Unreleased section. See AGENTS.md ("Changelog discipline") for the full rule.

Unreleased

  • Admin: /admin/balance editor + version history. New sidebar tab (⚖️ Balance) lets admins tune every numeric balance lever the engine reads: synergy multipliers per genre (metal HP %, punk cost reduction, pop heal %, folk buff %, electronic +BPM / shield %, hip-hop damage %, goth lifesteal, emo damage when below half HP, alternative damage), crit and miss curves (base, type bonuses/penalties, DPS bonus, max chance, multiplier), looper growth base, vamp default rate, plus game-shape constants (team size, max per slot, taunt charges, synergy threshold, BPM max/start/regen). Editing never mutates the active row — "Save as new version" appends a new row in game_balance_versions and (optionally) activates it inside a transaction; the version-history table at the bottom lists every prior cut with creator + timestamp + notes, and a one-click "Activate" button reverts to it. Type-chart editing is intentionally deferred (81 cells; expose via MCP/SQL for now). Notes: changing team size / max-per-slot / synergy threshold also affects band-builder UI and validation, which still read code constants — the editor warns about that in the Game shape section. Routes: GET/POST /api/admin/balance/versions, POST /api/admin/balance/versions/[id]/activate. Page: app/admin/balance/. Validators: lib/balance/validators.ts.

  • MCP server: balance tools for agents. The same operations are exposed to the admin MCP server at /api/mcp for tokenized agent use: get_active_balance (current snapshot), list_balance_versions, get_balance_version, create_balance_version (with optional activate: true), and activate_balance_version. All admin-gated via the existing bearer-token flow. Useful for letting a tuning agent run experiments without going through the web UI.

  • Game balance is now versioned in the database. Every numeric tuning the engine reads — synergy multipliers (metal HP %, hip-hop damage %, pop heal %, folk buff %, electronic shield % / +BPM, goth lifesteal, emo conditional damage, alternative damage, punk cost reduction, metal & punk hearing-damage extra turns), the genre matchup matrix, crit/miss curves, the looper growth exponent, and the default vampiric rate — now lives in a new game_balance_versions row instead of as hardcoded consts in code. The active row (one at a time, enforced by a partial unique index) drives the engine; admins will be able to edit it, save as a new version, and revert by activating an older row. Each row records created_by (FK to user), created_at, and parent_id, so we get a "who tuned what, when, and from where" audit trail. Structural rules (which side an effect targets, that emo only fires below half HP, that vampiric ignores shields) stay in code — only the numbers move. Engine reads through getBalance() (lib/balance/active.ts); server hydrates from the DB at request time, browsers hydrate via a one-shot GET /api/balance on app mount (app/_components/balance-hydrator.tsx). Fallback at every layer is the code baseline in lib/balance/baseline.ts, which mirrors the shipping defaults — so an unhydrated boot, a 5xx on /api/balance, or a fresh DB with no active row all play the game identically to before this change. Migration 0016_game_balance_versions.sql; seed (pnpm db:seed) writes the initial baseline row. No combat numbers shift in this release — this is the plumbing that makes future balance passes safe.

  • nopeople battle music. Seeded the four mastered tracks from the Bad Idea release ("That's What I Need", "Bad Idea", "Wide Awake", "Bike the Presidio") as band_id="nopeople" rows in audio_tracks. Battle audio (/api/battle/track) now returns a random pick whenever any nopeople member is on stage. WAVs are transcoded to 192 kbps mp3 before upload — keeps each file at 3–7 MB so the <audio> element can start playing without a 40 MB cold download. Reproducible via npx dotenv -e .env.local -- tsx scripts/seed-nopeople-audio.ts (idempotent; reuses Lee Harrold's self-grant).

  • Friends list — see everyone you've battled in PvP. New /friends page lists every user you've played a PvP match against, with W/L from your POV, total shows, last-played timestamp, and the band they last brought. Powered live from battle_records via GROUP BY opponent_user_id (no separate follow graph). PvP battles now stamp opponent_user_id on the row (migration 0017_friend_opponents) so the join into user.name works. AI/canned battles leave it null. Reachable from the global ☰ menu and from the "Challenge a friend" CTA on the empty state. Seed adds a second user (friend@local.test) and two PvP rows so the page is non-empty out of the box. Files: app/friends/page.tsx, app/api/player/friends/route.ts, lib/player-data/server.ts#listFriends.

  • Past Battles view — every show with both rosters as clickable emblems. New /battles page lists every battle this player has played, newest first. Each card has a top stripe showing Win / Loss in green/red, the game mode (vs AI / PvP / Ranked), and a timestamp. Below that, both bands sit side-by-side with their lineups rendered as small zine-style emblems — emoji glyph + first-name mono label — and every emblem is a Link to that musician's /p/[slug] profile. AI/canned opponents resolve their full 5-up lineup via ENEMY_BANDS; PvP rows don't yet snapshot the opposing roster on the battle row, so they render dashed "?" placeholders until that follow-up lands. Header tally shows total W/L. Reachable from the new global ☰ menu as 📓 Battles. Files: app/battles/page.tsx.

  • Global "☰ Menu" puck on every page. Companion to the corner Feedback tab — pinned bottom-left, opens a zine-styled menu listing every top-level destination (Game, Catalog, Battles, Tutorial, Rules, Scan, Account, Admin). Active route is highlighted; closes on link click, Escape, or backdrop tap. Hidden on /intake/* so kiosk operators stay in the form. Files: app/_components/global-nav.tsx, mounted in app/layout.tsx.

  • Rhythm now owns BPM (formerly "speed points"); player-facing copy renamed throughout. Codified the role design rule that rhythm/melody/harmony each own one combat resource — rhythm = BPM, melody = enemy HP, harmony = ally amplification (with heal as the deliberate exception). New design doc at lib/moves/CLAUDE.md. Mechanical changes: speed-boost moved from support → tank in lib/moves/kind.ts#KIND_TO_CLASS; Synth Sam re-slotted from harmony → rhythm (his "BPM Up" special is the slot's flagship move) with HP bumped 95→130 to fit a tank stat line; Viola Vega's "Sync Pulse" reworked from +1 BPM (speed-boost) to +20 dmg buff (buff-damage) so she stays a harmony character and Final Encore keeps its hip-hop synergy intact. Neon Nocturnes shifted from bongo-baylooper-lou so its slot counts stay legal with Synth Sam now occupying a rhythm seat. Player-facing strings — fighter-stage's pip meter, the bottom-panel attacker readout, team-focus, every move card across catalog/team-builder/admin/tutorial/spotlight/preview, and tutorial dialog — now read BPM instead of SP / speed points. Internal identifiers (speed field, MAX_SPEED, kind strings speed-boost/redistribute-sp) intentionally kept their legacy names to avoid a DB migration.

  • Crits and misses, with instrument-specific flair animations. Damage-flavored moves (damage, looper, vampiric, aoe-damage) now roll for crit (base 10%, ×1.5 damage; +5% on super-effective and on DPS klass, −4% on resisted; capped at 50%). Single-target damage moves also roll for miss (base 8%; +5% on resisted, −3% on super-effective or when the attacker is already buffed; capped at 30%). AoE skips miss — one swing across 3+ targets shouldn't whiff entirely — but still rolls a single crit for the whole swing. Every crit and miss pops a per-instrument animation on the attacker's tile, driven off Character.title: drummer crit throws both drumsticks in opposite arcs, guitarist crit snaps a string with ~~SNAP~~, bassist crit BWOMPs the cab, vocalist crit mic-drops, keys cascade ♪♬♩, strings/wind bow-snap ╱╱╱, with a default ⚡ starburst for anything we can't classify. Misses get their own glyphs too: drummer tumbles a stick, guitarist's strap slips, bass cable unplugs, vocalist gets a ~crack~, keys hit a ♭, strings/wind ~SQUEAK~, default 💨 puff. Each flair floats a CRIT! or miss… banner above the fighter. Math: lib/battle/engine.ts (with instrumentFromTitle in lib/game.ts). Visuals: new flair ResolveEffect kind, rendered by app/_components/battle/flair-overlay.tsx with keyframes in app/globals.css.

  • Character spotlight: Maestro's tour for any bandmate. New route /tutorial/spotlight/[characterId] runs a short Maestro-Magnus-narrated mini-tutorial — intro → reveal card → plain-words explanation of the SPECIAL → scripted 1v1 demo battle where the character auto-fires BASIC then SPECIAL against a softened Daphne, with Maestro narrating each step → outro. Built so any new character added to ROSTER gets a "here's how they play" walkthrough for free; the explanation text is generated per-move-kind so it stays accurate as new specials ship. Entry point: a ▶ Maestro's tour button on the catalog character detail (/catalog → tap a character), alongside the SIGNATURE row. Files: lib/tutorial-spotlight.ts (scripts + per-move explanations + demo timeline), app/tutorial/spotlight/[characterId]/page.tsx (self-contained client flow reusing the shared resolveMove battle engine).

  • Admin: moves catalog (CRUD + search + class sort). New /admin/moves page lists every canonical move with a search box (matches name + description), a kind filter, a class filter (tank/dps/support — class is derived from kind via lib/moves/kind.ts#KIND_TO_CLASS), and a sort selector (class / name / kind / cost). Class chips, parameters, and SP cost are rendered per row. /admin/moves/new and /admin/moves/[id]/edit use a shared MoveForm that only shows the numeric fields each kind actually uses (per KIND_FIELDS), and surface 409s on duplicate names with a deep-link to "edit the existing one". Backed by a new moves table (lib/db/migrations/0015_moves.sql) with UNIQUE(name) enforcing the working rule "same effect = same name". REST surface: GET/POST /api/admin/moves and GET/PATCH/DELETE /api/admin/moves/[id]. The catalog is seeded from ROSTER on pnpm db:seed (40 distinct moves across all 16 kinds) — re-runs are idempotent via ON CONFLICT (name) DO NOTHING, so admin edits are preserved across seed.

  • In-app feedback for alpha. A 💬 Feedback tab is pinned to the corner of every page; clicking it opens a quick form that stamps the current path, server-side OTel trace id, and (when present) Sentry replay id onto a row in the new user_feedback table. The result screen also surfaces a "How was that show?" prompt that attaches the full battle log + opponent/band metadata as context. Every submission mirrors to Sentry's Feedback inbox so alpha notes show up next to any captured replay.

  • Admin: alpha feedback inbox + battle-log viewer. New /admin/feedback page (sidebar link + dashboard stat card) lists every user_feedback row with category filters (general / post-battle / bug / idea). Expanding a row shows the full message, attached context, and — for post-battle submissions — the in-game battle log line-by-line in a monospace pane. Trace ids link to Honeycomb and replay ids link to Sentry (set NEXT_PUBLIC_HONEYCOMB_TRACE_URL / NEXT_PUBLIC_SENTRY_REPLAY_URL to enable). Backed by GET /api/admin/feedback?category=…, gated by requireAdminApi(). Counts on the overview pull in the same data.

  • Admin: appearances index + full move palette in character form. New /admin/appearances lands a grouped-by-event view of every band appearance so admins can jump straight to "Add character" without drilling through events first. VersionForm now exposes the rhythm/melody specials added in 0.3.x — looper, aoe-shield, redistribute-sp, clipping — so admin-created characters can use any move kind in the engine, not just the pre-0.3 subset.

From playtester feedback — audit pass against the open feedback list.

  • Starter band now ships all 5 nopeople members, with Andrew as the 5th. The seed-starter route was handing new accounts a 4/5 band (dan, dax, lee, brant). Renamed the placeholder pop-harmony / Backing Vox character from "Ramona" → Andrew (lib/game.ts) and added "andrew" to STARTER_MEMBER_IDS / STARTER_SEEN_IDS in app/api/player/seed-starter/route.ts so the first-load lineup matches the real band. The canonical nopeople entry in ENEMY_BANDS also points at the new id. No cutout art for Andrew yet — falls back to the 🎤 emoji until a portrait is shot.

  • Type and move emojis removed to stop colliding with character emojis. Playtesters reported that genre/class emojis (🤘 🧷 💖 🌾 ⚡ 🎧 🦇 💔 / 🛡 ⚔ ✨) and move-descriptor emojis (🛡 🤫 🔁 🎶❌ 🩸 🥁 📈) overlapped with individual character emojis (🥁 Devin, 🎸 Dan/Dax, etc.), making it hard to tell roster icons apart from type/move icons. Cleared the emoji field on every entry of GENRE_INFO and CLASS_INFO in lib/game.ts, swapped the affected chips/badges (fighter-stage, opponent-select, intake header, team-builder synergy strip, tutorial fighter chip, pills.tsx#TypePill) to render the genre label instead of an empty span, and stripped leading emojis from every line of moveDescriptor in lib/format.ts (taunt, mute, feedback, detune, hearing-damage, redistribute-sp, aoe-shield, looper, clipping). Updated content/rules.md (Classes table + Genres-by-Family table) to match. In-combat status icons (taunt/mute/feedback/shield in phase-row.tsx) intentionally kept their emoji glyphs — those are transient state indicators, not types or moves.

  • PvP: turn-flip notifications when you've tabbed away. Players couldn't tell when an opponent had moved in a backgrounded tab. Two-layer fix in app/_components/battle/use-turn-notifications.ts, wired into pvp-battle.tsx against the existing TurnResolved event. Always-on title flash: when the turn flips to you while document.hidden, the tab title becomes "⚡ Your turn — Aux"; restored on visibilitychange or when the turn flips away. Opt-in louder layer behind a new 🔔/🔕 toggle in the battle header (persisted to localStorage under aux.pvp.notifyOnTurn): plays a short two-tone Web Audio chime, calls navigator.vibrate(80), and — if Notification.permission === "granted" and the tab is hidden — fires a system toast tagged aux-pvp-turn whose click brings the tab forward. Flipping the toggle on for the first time triggers Notification.requestPermission(); declining still leaves the chime + vibration working. Exit is unchanged — the ✕ Exit chip in the battle header was already always-clickable, so players can leave a match at any point in either AI or PvP mode.

0.3.2 — 2026-05-20

From playtester feedback (round of friends-of-friends notes). Every item below was raised by a playtester; this is the audit-and-fix pass.

  • Shield UI is now light blue (#7CC6E8) on the HP bar and the 🛡 N chip, so a healthy fighter's shield reads against the harmony-green HP fill instead of blending into it. (app/_components/battle/fighter-stage.tsx)
  • Damage / heal / SP numbers got bigger and stay longer — 26pt, 1.6 s float-up — so they don't blink out before you can read them. (floating-hit lifetime in app/_components/battle/battle.tsx; type styles in fighter-stage.tsx)
  • Band names sit above each half of the battlefield with the active side highlighted in ink, so it's obvious at a glance which column belongs to which band. (BandLabel in app/_components/battle/battle.tsx)
  • Rules link in battle opens in a new tab (target="_blank") so consulting the rules no longer dumps you out of the current battle.
  • AI / auto-battle no longer drains everyone's SP at once. The applyAction path was reading stale players/enemies from closure on AI turns; SP-regen ticks now flow through stateOverride so only the actual attacker pays SP.
  • Type Advantages modal title is now readable — explicit text-white on the heading (was black-on-black), and inner clicks dismiss the modal so the on-screen "tap anywhere to dismiss" copy matches behavior.
  • Click another ally to redirect a support ability — once an attacker + heal/buff/shield is selected, tapping a different bandmate now retargets and fires without falling back to the cycle arrows. (handlePlayerColumnClick in app/_components/battle/battle.tsx)
  • "Build a band" lives on the home menu. New title-screen CTA routes through the team-builder with buildOnly=true and returns you to the bands picker — you no longer have to start a battle to author a deck. (startCreateFromHome in app/page.tsx)
  • Emo synergy reworked. Was a dead "+1 turn hearing damage" — no emo character dealt hearing damage. Now: band-wide +25% damage when the attacker is below half HP ("sad and angry"). The hearing-damage duration bonus moved to the loud family (Metal and Punk synergies), matching where the loud-flavored Tinnitus actually lives.

0.3.1 — 2026-05-13

Vampiric tuning — shields don't bleed, and the drain is no longer free 1:1.

  • Vampiric only drains HP damage. When the target has a shield, the shield absorbs the hit first; only damage that actually reaches HP counts toward the lifesteal. Hitting a shielded enemy yields zero heal until you break through.
  • Vampiric heal is now percentage-based. Lifesteal returns 50% of HP damage dealt (rounded), or 75% with the Goth synergy. Because it's a fraction of the actual HP damage, damage boosts (type effectiveness, buff-damage, hip-hop synergy, etc.) increase the heal proportionally — but never to 1:1. Drain ≤ damage, always.
  • Goth synergy reworded: from "+50% heal on vampiric" → "Vampiric lifesteal rate 50% → 75% on goth members".
  • Battle log now annotates vampiric hits with shield absorption ("shield ate N") and total HP drained.

0.3.0 — 2026-05-13

New family, new genres, two new specials.

  • New family: Edgy (genres: Goth 🦇 and Emo 💔). Roster grows from 18 → 25 with 7 new characters: Bones Bri, Echo Eli, Wail Wendy, Pining Pete, Crow Cara, Mope Mara, plus one new loud-genre DPS (Ringer Reagan).
  • New 4-family type chart replacing the old 3-family cycle:
    • Loud ×1.5 vs Acoustic, Edgy · ×0.66 vs Digital
    • Acoustic ×1.5 vs Digital, Edgy · ×0.66 vs Loud
    • Edgy ×1.5 vs Loud, Digital · ×0.66 vs Acoustic
    • Digital ×1.5 vs Loud, Acoustic · ×0.66 vs Edgy
  • New move kind: Vampiric (DPS, edgy flavor). Single-target damage that heals the attacker by the damage dealt. Type multipliers scale both the damage and the steal. Goth synergy buffs the heal portion +50%.
  • New move kind: Hearing damage (DPS, loud flavor). Applies a damage-over-time status that ticks at the start of the affected character's own turn for several turns. Any heal applied to that character cures it. Emo synergy extends the duration by 1 turn (yes, an emo support packs a meta-synergy).
  • New enemy band: The Crypt Society — goth-synergy lineup featuring vampiric and hearing damage so you can taste them as a foe.
  • Two new synergies: Goth (3+) buffs vampiric heal, Emo (3+) extends hearing damage duration.
  • Rules page updated with the new type chart and special-move descriptions.

0.2.2 — 2026-05-13

  • The changelog now renders on /rules directly below the rules. Every iteration's notes are visible without leaving the game.
  • Added a "Rules / Changelog" jump-nav at the top of the page.

0.2.1 — 2026-05-13

From playtester feedback ("every turn I was able to use 2-3 specials which never gave a reason to not use them" + "building debuffs basically protects you from the enemy ever getting hurt and steals all of the buffs an enemy support offers"):

  • Speed cap raised from 5 → 10. Starting SP 2 → 3. Regen unchanged at +1 / own turn.
  • Special costs raised across the board so specials feel like commitments rather than free actions every turn:
    • Cheap supports (Folk Chord, Campfire Song, Sync Pulse): 1 → 2 SP
    • Heavy supports (Backup Chorus, BPM Up, Bit Crush): 2 → 3 SP
    • All tank specials (taunts, shields): 2 → 3 SP
    • All DPS specials (AoE, Mute, Feedback, Detune): 3 → 4 SP
  • Detune no longer steals enemy support buffs. It now triggers only on damage moves (basic or AoE), redirecting them to the affected character's own ally. Heal / Buff / Speed-boost / Shield resolve normally while detune sits armed.
  • One debuff per target. Mute, Feedback, and Detune no longer stack on the same enemy; casting a second debuff on an already-debuffed target fizzles (SP still spent). Mute now hides on a random clean foe; if every foe is debuffed, Mute fizzles.

0.2.0 — 2026-05-13

First versioned release under the Aux: the Gathering name.

Combat

  • Replaced discrete cooldowns with a speed point (SP) system (cap 5, start 2, regen +1 per own turn).
  • Every character now has a basic attack (1 SP, 18 dmg, genre-flavored name) in addition to a class-specific special.
  • DPS specials reworked to debuffs + AoE: Mute (hidden, random foe), Feedback (next damage backfires), Detune (next move flips sides), and AoE damage.
  • Tank specials restricted to Taunt (locked stance, consumed by next opposing damage) and Shield (temp HP layer absorbed before HP).
  • Support specials unchanged in role (heal, buff-damage, speed-boost) but speed-boost now adds SP.

Bands & types

  • 18-character roster across 6 genres (Metal, Punk, Pop, Folk, Electronic, Hip-hop) and 3 families (Loud, Acoustic, Digital).
  • Pokémon-style type chart: Loud › Acoustic › Digital › Loud, with ×1.5 / ×0.66 multipliers on damage and AoE.
  • Genre synergies activate at 3+ same-genre band members (HP boost, cost reduction, heal/buff/speed/shield/damage modifiers).
  • Slot determines class: Rhythm → Tank, Melody → DPS, Harmony → Support. Max 2 per slot → every band runs 2/2/1.

Site

  • Rebranded from "Battle of the Bands" to Aux: the Gathering.
  • New /rules page rendered from content/rules.md.
  • Mobile-first responsive pass on the battle screen and team builder.

0.1.0 — initial

  • Scaffolded Next.js project, basic JRPG combat loop, team selection, manual and auto battle modes.