Inspiration

the idea came from thinking about what makes reddit different from every other platform a game could live on. reddit is not a solo experience. it's a place where thousands of people pile onto the same post, react to the same thing, and leave a visible trace that others respond to.

most devvit games treat the community as an audience. i wanted to make the community the actual material the game is built from.

the specific mechanic — your death coordinates becoming a permanent platform for the next player — came from thinking about what "collective joy" actually means. joy isn't just winning together. sometimes it's watching someone else fail exactly where you failed, or discovering that a pile of 400 anonymous strangers' corpses accidentally built a staircase to somewhere the level designer never intended.

What it does

chroma canvas is a daily community precision platformer running natively inside a reddit post via devvit web.

the objective is simple: carry a fragile chroma orb from the start pedestal to the exit gate without dying.

what makes it different:

  • when you die, your snoovatar petrifies at the exact x,y coordinates of your death and becomes a permanent solid platform in the level
  • every player who joins after you can jump on your corpse to reach places that were previously unreachable
  • once someone finally beats the level, the top 5 upvoted comments containing a !hazard command (e.g. !hazard spike 45 90) are parsed and merged into tomorrow's level geometry
  • a devvit scheduler fires at midnight UTC, generates the new level, posts an automated update to the subreddit, and resets the corpse pile for day 2

retention mechanics:

  • daily streaks with flair tiers (3 days: "persistent", 7 days: "orb keeper", 30 days: "ancient")
  • daily leaderboard ranked by completion time, resets with each new level
  • first win of each day auto-assigns the "orb bearer" flair
  • comment section becomes the level design tool — players debate, upvote, and campaign for their hazard placements

How we built it

frontend: phaser 3 handles all physics, collision detection, corpse rendering, particle effects on death, and camera behavior. player snoovatar is loaded from getSnoovatarUrl() server-side and injected into the phaser scene at runtime.

backend: devvit web's node.js server manages all state via redis. corpse coordinates, level JSON, player streaks, and leaderboard data live in redis. the client webview makes zero direct external calls — everything routes through /api/ endpoints.

daily loop: devvit scheduler cron job at midnight UTC handles level rotation, comment parsing, flair assignment batch processing, and automated subreddit post creation.

comment integration: an onCommentCreate trigger listens for !hazard commands in real time, validates coordinate bounds, and queues them for the midnight scheduler to consume.

storage strategy: live corpse coordinates stay in redis for fast loading. once a level closes, the full corpse history is archived to blob storage, keeping redis well within quota.

Challenges we ran into

the biggest technical challenge was the localStorage volatility issue — devvit wipes localStorage on every app version update, which means any game state stored client-side is silently destroyed on patch. discovering this early forced a complete rethink of the state architecture toward a redis-first model for everything persistent.

the CSP restrictions on the client webview were a close second. the instinct to call external APIs directly from phaser had to be completely unlearned — every fetch goes through the server, which added latency overhead that required careful optimization of the /api/getCorpses endpoint to keep initial load fast enough for the inline mode lighthouse threshold.

fitting a phaser physics game into a performant enough webview to score >80 on lighthouse while loading snoovatar assets for every corpse in the level required aggressive asset caching and a first screen customization splash while assets resolved.

Accomplishments that we're proud of

the comment-to-level pipeline is the thing i'm most proud of. the idea that a player types !hazard spike 45 90 in a comment, gets 200 upvotes from people who want to watch tomorrow's runners suffer, and then wakes up the next day to see that spike physically in the level — and then watches others die on it — closes a feedback loop that feels genuinely native to how reddit works. it's not a feature bolted onto reddit. it's something that only makes sense on reddit.

What we learned

reddit users don't just want to play games. they want to author experiences for each other. the most retentive mechanic isn't a streak counter or a leaderboard — it's giving someone the ability to make other people suffer in a way that gets upvotes.

the platform constraints (redis-only persistence, server-side CSP, no outbound client fetch) look like limitations but they actually enforce a cleaner architecture than most mobile game backends. the constraints are good.

What's next for Chroma Canvas

  • procedural level generation seeded by community vote (not just hazard placement but full terrain shape)
  • faction system where the subreddit splits into "builders" (who want the level solved) and "saboteurs" (who want it to stay unsolved) with competing comment strategies
  • blob storage gallery of every completed level's final corpse topology — a permanent visual history of how the community moved through each challenge
  • cross-subreddit events where two communities race to beat the same level and the aggregate corpse data from both gets merged into a shared "legacy level"

Built With

Share this project:

Updates