AetherBeam: A Cooperative Optics Grid Sandbox Inspiration The inspiration for AetherBeam stems from a blend of classic retro-futuristic arcade games, the physics of ray optics, and a desire to build a truly cooperative multiplayer experience on Reddit. While most puzzle games on Reddit are single-player, turn-based, or static, we wanted to create a live, reactive grid-based "sandbox" where players have to communicate and align laser beams together. We imagined players as engineers on a cosmic gateway, working collectively to align high-energy light beams to activate celestial sectors.

What it does AetherBeam is a real-time cooperative optics puzzle game. Players work together (or play solo in simulator mode) to guide a glowing laser beam from its starting emitter to a target core on a grid by placing, rotating, and erasing deflecting mirrors and prisms.

Solo Simulator: Allows private, offline sandbox puzzle solving. Community Gateway: A live cooperative sandbox where multiple online Redditors join a first-come, first-served (FCFS) active turn queue to collaboratively place optics on a shared grid. Progressive Difficulties: Stages range from Easy (8x8 with simple routing) to Hard (10x10 with static obstacles and multiple deflections). Cosmic Gateway Selector: A highly vibrant sci-fi dashboard featuring animated white stars and neon glowing nodes mapping clear/unlocked level progress. How we built it AetherBeam is built on a modern, decoupled architecture:

Server Router (Hono + Redis): Runs on Reddit's serverless Devvit platform. It manages global state, active turn queues, player coordinates, and grid configurations. Client Render Engine (React + Phaser 3): A lightweight, responsive web app that renders the glowing grid, laser rays, targets, and obstacles. Optic Simulation Engine: The game dynamically simulates laser raycasts using 2D grid matrix coordinates. 📐 Mathematical Formulation of Ray Reflections (LaTeX) When a laser beam traveling in a 2D grid plane hits a reflective mirror, its direction changes instantly. We can model the laser direction as a unit velocity vector $\vec{d} \in {(1,0), (-1,0), (0,1), (0,-1)}$.

When the beam hits a mirror with a surface normal vector $\vec{n}$, the reflected ray direction vector $\vec{d}'$ is given by the reflection formula:

$$\vec{d}' = \vec{d} - 2(\vec{d} \cdot \vec{n})\vec{n}$$

In our grid coordinates, mirrors are placed at exactly $45^\circ$ or $135^\circ$ angles relative to the axes. We can model these as reflection matrices:

For a / mirror (normal $\vec{n} = \frac{1}{\sqrt{2}}(-1, 1)$): $$\begin{pmatrix} d'_x \ d'_y \end{pmatrix} = \begin{pmatrix} 0 & -1 \ -1 & 0 \end{pmatrix} \begin{pmatrix} d_x \ d_y \end{pmatrix}$$ This swaps and negates the velocity components: a beam moving right $(1, 0)$ is redirected down $(0, -1)$, and a beam moving up $(0, -1)$ is redirected left $(-1, 0)$.

For a \ mirror (normal $\vec{n} = \frac{1}{\sqrt{2}}(1, 1)$): $$\begin{pmatrix} d'_x \ d'_y \end{pmatrix} = \begin{pmatrix} 0 & 1 \ 1 & 0 \end{pmatrix} \begin{pmatrix} d_x \ d_y \end{pmatrix}$$ This swaps the velocity components: a beam moving right $(1, 0)$ is redirected up $(0, 1)$, and a beam moving down $(0, 1)$ is redirected right $(1, 0)$.

Challenges we ran into Phaser Event Interception (Mobile Scrolling): Initially, the Phaser canvas captured all touch events on mobile frames (event.preventDefault()). This prevented the browser window from receiving swipe gestures, trapping players and stopping them from scrolling the page vertically to read game details. We resolved this by overriding the Phaser input manager settings (preventDefault: false) to let touch events bubble up cleanly. React stale closures in Phaser: Because the Phaser instance runs as a persistent singleton inside the React wrapper, it captured a stale copy of the onMoveAttempt callback closure. When players joined the FCFS turn queue, their clicks executed old validation rules. We resolved this using a stable React useRef wrapper that always references the current state context. API Typing Mismatches: Reddit Devvit's Redis client type definition for zRange claimed to return objects, but at runtime returned raw string arrays. This caused active queue members to be incorrectly filtered out. We solved this by implementing defensive mapping checks: typeof m === 'string' ? m : m.member. Accomplishments that we're proud of Zero-Lag Real-Time Sync: Successfully integrated a Hono API and Redis backend that polls and synchronizes moves across multiple active browser sessions within seconds, creating a seamless co-op feeling. Stunning Sci-Fi Visuals: Iterated on visual quality to provide custom space nebulae backgrounds, neon glowing PROGRESS nodes, rotating holographic components, and animated starry skies while keeping the grid board background dark and clean for high readability. Smooth Mobile/Desktop Adaptability: Resized the Phaser canvas, set responsive margins, and configured layout wrapping so the game board fits perfectly on mobile screens and allows players to scroll the entire screen easily by swiping directly on the grid. What we learned This project taught us the importance of bridging the gap between persistent canvas engines (Phaser) and reactive UI frameworks (React). We gained deep experience in real-time serverless state management via Redis, handling concurrent player racing conditions, and designing responsive layouts that look sleek, high-contrast, and beautiful on both small mobile frames and widescreen desktops.

What's next for AetherBeam We plan to expand AetherBeam by introducing:

Complex Optics: Refracting lenses that split a single laser beam into two paths, and filters that only let specific light wavelengths pass. Live Chat/Emote Wheel: An integrated, compact emote reaction wheel so players in the community queue can react or direct their teammates in real-time. Custom Level Builder: Allowing community members to generate, seed, and publish their own custom optic routing challenges directly to the subreddit.

Built With

Share this project:

Updates

Submission history