Primary: Best Use of User Contributions (UGC).
Every competitor is a user drawing: stroke capture, morph close, marching squares, simplify, Matter.Bodies.fromVertices (poly-decomp, convex hull fallback). Nightly brackets, champion defense, and auto result comments turn UGC into the full social loop.

Secondary: Hook + Phaser.
Champion re-seed, grudge/spar, and morning bracket browsing are the return reasons. Live client Matter re-sim of the same seeded fight is the spectacle layer on top of server authority.

What it is (player loop in 10 seconds)

  1. Expand → paper canvas, draw a champion (stroke limits enforced).
  2. Submit: server traces ink → collider verts + stats (mass, reach, stamina, crit).
  3. Same-session spar vs champion (or mini-spar) so payoff is instant.
  4. Fighter enters tonight's roster.
  5. Nightly job runs the bracket; morning: watch rounds, POST RESULT, grudge a rival.

Why we built it

UGC wins when user content is not decoration. Here the drawing is the physics body and the competitive unit. Server-side headless Matter makes outcomes authoritative for comments and brackets. Seed fighters keep empty nights playable for judges without faking a human roster as "real players."

How it works (architecture)

Layer Role
Devvit webview splash.html ink feed card; game.html Phaser + draw overlay
Client Phaser 4.2 Home, Draw, Bracket, Replay/Grudge; optional live Matter re-sim
Hono API Draw submit, init/roster, bracket fetch, grudge, share comment
Redis Fighters, pending queue, bracket trees, champion, leaderboard, moderation flags
Scheduler 0 3 * * * nightly-bracket: seed, sim matches, store replays, update champion
Shared trace.ts, fightSim.ts (same Matter core client/server), replay codec
Mod tools Review pending drawings form; "Run nightly bracket now" menu for demos

Fight authority: server simulateFight packs frames and results. Client LiveMatterFight re-runs with the same seed and verts for spectacle; lerp fallback if live init fails.

Virality / hook (why return tomorrow + why share)

Return: Did my scrawl win the night? Champion badge auto-re-enters seed #1. Grudge match against a named rival's latest fighter.

Share: POST /api/share posts result lines to the feed. Fight poster CTAs. Friend challenge + crest on splash for "draw something better than this."

Reddit-native features

  • UGC fighters identified with real Reddit usernames.
  • Nightly tournament results as comment surface (margin-flavored copy).
  • Moderator review queue for pending drawings.
  • Crest renown chip + friend challenge row (invite by username energy).
  • Grudge API targets another user's fighter by username.
  • Async multiplayer: draw today, fight tonight, spectate tomorrow.

Not karma-as-theme: ink, sumo ring, champion throne. Reddit is authorship and trash-talk venue.

Demo post / subreddit

Field Value
Subreddit r/scrawl_fight_dev
App owner u/proffesor1729
Devvit package scrawl-fight
Product name Scroll Fighter
Demo post (mod menu: "Create a new post" → paste URL here after publish)
Demo tip Use "Run nightly bracket now" after a few draws so judges see a full tree

Tech stack

  • Client: Phaser 4.2, Matter.js, Vite 8, TypeScript, DOM draw surface
  • Server: Hono, Devvit 0.13.6, headless Matter + poly-decomp, Redis
  • Shared: trace pipeline, fight sim, constants contract
  • Tests: npm run test:brawl
  • Platform: Node >= 22.2; Redis + Reddit permissions

What judges / users should do first (60s path)

  1. Open the demo post → expand.
  2. Draw a bold blob with a few detail strokes → BRAWL!
  3. Watch submit celebration / spar vs champion.
  4. Open Bracket (or run nightly now if empty) → tap a match.
  5. Watch live Matter or packed replay.
  6. POST RESULT / share once; optional grudge by username.

Proof of production

  • Package name scrawl-fight with real cron, forms, and Redis fighter storage.
  • Tracing and stats derived from submitted strokes/masks, not preset avatars.
  • Bracket outcomes from headless Matter; shared fightSim used for determinism.
  • ensureSeedFighters fills thin rosters with AI shapes so nights resolve; human draws still enter the same pipeline.
  • Share hits POST /api/share → Reddit comment when post context exists.
  • Brawl tests cover sim/codec without placeholder outcomes.

Built With

  • devvit
  • hono
  • matter.js
  • phaser-4.2
  • reddit-karma
  • reddit-usernames-for-ugc
Share this project:

Updates