Inspiration

Bloxorz the classic Flash puzzle game where you roll a block into a hole. I wanted to bring that satisfying spatial reasoning challenge to Reddit as a native experience, with a neon aesthetic, daily challenges, leaderboards, and a full level editor so the community can create and share puzzles as Reddit posts.

What it does

Prism Rift is a deterministic grid puzzle game embedded directly in Reddit posts. Players roll a 1x1x2 block across a grid, trying to land it upright on the goal tile. The block can be upright (occupying one cell) or lying flat (occupying two cells), and every move changes its orientation — so you have to think ahead.

Key features:

  • 30 curated levels with a difficulty curve from tutorial to brain-melting
  • Daily challenge with a seeded level selection and per-day leaderboard
  • Leaderboards ranked by fewest moves, with time as a tiebreaker
  • Level editor with a visual grid painter, test-play mode, and one-tap publish
  • UGC sharing — published levels can be shared as standalone Reddit posts with custom splash screens
  • Server-side verification — every submitted run is replayed move-by-move on the server to prevent cheating
  • Original music — five synthwave tracks with an in-game music player

How I built it

The architecture splits into three layers:

  1. Shared engine (src/shared/engine/) — a pure, deterministic simulation with no DOM or randomness. Handles block state transitions, fall detection, win conditions, and full replay verification. This same code runs on both client and server.

  2. Client (src/client/) — React 19 + Tailwind CSS 4 for UI, HTML Canvas 2D for the game board. The renderer uses an isometric projection with neon glow effects, vortex particles on the goal tile, and aurora-style tile shading. Input is handled via D-pad buttons, keyboard arrows, and swipe gestures. Framer Motion powers the menu animations.

  3. Server (src/server/) — Express 5 REST API running on Devvit's Node.js runtime. Uses Redis for all persistence: levels, runs, leaderboards, UGC index, post associations, and rate limiting. The UGC publish pipeline runs a BFS solver to guarantee every user-created level is solvable before it goes live.

The solver (src/shared/solver/) does a breadth-first search over (x, y, orientation) state space, rejects unsolvable or trivially easy levels, and assigns a difficulty band (easy/medium/hard) based on solution length and search complexity.

Challenges I ran into

  • Animation loop vs React staterequestAnimationFrame callbacks that depended on gameState caused the animation loop to restart on every move, freezing controls and making the block shake. Fixed by storing game state in refs and keeping the render callback stable.

  • Mobile layoutflex-1 on the canvas container pushed the D-pad controls off-screen on mobile. Switched to explicit calc() heights so header, canvas, and controls all fit without scrolling.

  • Run verification after falls — when the player fell off the grid and respawned, the move history wasn't cleared. The server would replay the full history (including pre-fall moves) from the start position and reject the run. Fixed by resetting move history and timer on every respawn.

  • Particle memory leaks — the vortex particle system on goal tiles was creating new particles every frame instead of recycling them, causing FPS drops over time. Switched to a persistent particle pool with object recycling.

What I learned

  • Deterministic engines are worth the upfront investment — having the same replay logic on client and server made anti-cheat trivial.
  • In React + Canvas apps, keep your useCallback dependencies minimal and use refs for frequently-changing state.
  • BFS over (x, y, orientation) is a clean way to validate puzzle solvability without needing a full pathfinding library.
  • Mobile-first layout testing saves hours of debugging later.

What's next

  • New tile mechanics: fragile tiles, switches, bridges, teleporters
  • Seeded procedural level generation for infinite daily variety
  • Multiplayer race mode
  • Community voting and featured levels

Built With

  • express-5
  • framer-motion
  • html-canvas-2d
  • react-19
  • reddit-devvit-platform
  • redis
  • tailwind-css-4
  • typescript
  • vite-6
  • vitest
Share this project:

Updates