Back to experiments
LARAVEL + CANVAS 2D

Deck Brawl

A turn-based fight you play with a friend by passing a link. Pick five attacks and five blocks, send the link over, and once they've done the same the whole bout plays out move-by-move on the deck.

Loading the deck…

ABOUT
TECH STACK
Laravel Statamic 6 MariaDB JavaScript Canvas 2D API
YEAR
2026

What I did

Every other experiment here is a self-contained Canvas piece. This one needed a back end — the first that touches a database and server routes — so I used it to wire a small asynchronous game into the Statamic site without dragging in a framework on the front.

You name your fighter and lock in five attacks and five defences, each high, mid or low. That creates a fight and hands you a share link. A friend opens it, picks their own ten moves, and the bout becomes playable — then the link replays the whole thing, deterministically, for both of you. No accounts, no sockets, no live turn-taking: just a row in a table and a link you paste into a chat.

How it works

The state lives in a single fights row — a UUID, a status, and the two sets of moves as JSON. A tiny JSON API in routes/web.php handles three things: create a fight, read its status, and join it. The first person to submit on a link becomes Player 2 and flips the fight to active; join-after-active is rejected, so the link can only be claimed once. Moves aren't revealed until both players are in, so you can't peek at what you're up against.

The fight itself is pure resolution — no randomness. For each of the five rounds it plays your attack against their block, then theirs against yours. A hit only lands when the block is at the wrong height; a matching tier blocks it dead. Every landed hit takes a quarter of the energy bar, so four clean hits is a knockout, and a knockout ends the bout on the spot — no polite counter-punch from a fighter who's already down.

Playback is a small Canvas 2D state machine: one shared sprite sheet drawn from a frame-map, Player 2 mirrored with a flipped transform, energy bars and names across the top, and the sequence stepped through on a timer with a flash on each hit and a crumpled pose on the KO. The sprites are deliberately plain amber placeholders — the interesting part was the plumbing, and they're a single file to swap later.