# Solstice — A Light-Routing Puzzle Game

> Source: <https://dev.to/vinny_0f23e2d307e45b62614/solstice-a-light-routing-puzzle-game-1827>
> Published: 2026-06-21 17:15:40+00:00

*This is a submission for the June Solstice Game Jam*

**What I Built**

Solstice is a puzzle game where you place mirrors to guide light beams across a grid. Each level has two modes — SUN and MOON. You toggle between them to route both beams to their targets. Both need to be lit at the same time to win.

Click a cell to place a `/`

mirror, click again for `\`

, again to remove. Right-click removes it. Ctrl+Z to undo. That's the whole mechanic — but the levels get hard fast.

There are 18 levels split into 7 tiers. It starts simple (one mirror, one beam) and builds up to puzzles where you have fewer than 10 free cells and every placement has to count. I verified every level with a Python solver to make sure they're all solvable at the stated par.

The game has a terminal with a Bletchley Park theme. You get 3 questions, the AI responds like a trapped wartime consciousness, and at the end you decide if it was human or machine. It connects to the Gemini API if you have a key, otherwise it uses pre-written responses.

**VIDEO DEMO**

{[https://youtu.be/gqtylwILuJ8](https://youtu.be/gqtylwILuJ8)}

Code

**A light-routing puzzle game with a custom ray-tracing engine, dual-spectrum beam physics, 18 levels across 7 tiers, a CRT terminal narrative, undo/redo, and a star-based rating system.**

Built with vanilla JavaScript, rendered on HTML Canvas 2D, with audio synthesis via the Web Audio API and optional AI-powered dialogue through Google Gemini. Deployed as a static site on the Vercel CDN.

Each subsystem is a standalone ES module communicating through a central game state, orchestrated by a `requestAnimationFrame`

game loop.

```
flowchart LR
    subgraph Pipeline[Core Pipeline]
        direction LR
        GL["GAME LOOP<br>main.js<br>requestAnimationFrame<br>renderer.draw()<br>updateUI()"]
        RT["RAY TRACER<br>raytracer.js<br>Dual-pass simulation<br>SUN + MOON paths<br>Cycle detection"]
        RD["RENDERER<br>renderer.js<br>3-pass canvas draw<br>Glow + dashes + pulses<br>Particle integration"]
        PS["PARTICLES<br>particles.js<br>emit() / burst()<br>update(dt) / draw()<br>Lifecycle management"]
    end

    GL --> RT --> RD --> PS

    style GL fill:#1a1a3a,stroke:#ffd700,color:#ffd700
    style RT fill:#1a1a3a,stroke:#4a90d9,color:#4a90d9
    style RD fill:#1a1a3a,stroke:#7b68ee,color:#7b68ee
    style PS fill:#1a1a3a,stroke:#00ff88,color:#00ff88
    style Pipeline fill:#0a0a1a,stroke:#333,color:#888
flowchart TB
    subgraph Systems[Supporting Systems]
        direction TB
        IM["INPUT<br>input.js<br>Mouse +
```

…Play it here: [https://solstice-game-pi.vercel.app](https://solstice-game-pi.vercel.app)

**HOW I BUILT IT**

Vanilla JavaScript with HTML Canvas for rendering. No frameworks, no libraries — just ES modules and the Canvas 2D API.

The ray tracer uses grid-based ray marching. Each frame runs twice — once for SUN, once for MOON. Mirrors transform the direction vector: `/`

does `[dx, dy] → [-dy, -dx]`

, `\`

does `[dx, dy] → [dy, dx]`

. Cycle detection prevents infinite loops from mirror pairs facing each other.

Audio is all Web Audio API oscillators — no sound files at all. The terminal uses the Gemini API when configured, with a system prompt that keeps the Bletchley persona consistent.

Levels are hand-designed with increasing wall density. Levels 11-18 went through multiple redesigns after my Python solver kept finding unintended shortcuts.

**Prize Category**

BEST ODE TO ALAN TURING ;

The terminal is a Turing Test. You talk to something that believes it was a code-breaker at Bletchley Park in 1945. Three questions, then you judge. The dialogue touches on Enigma, ration books, the hum of valves. The ending asks the same question Turing posed — can you tell the difference?

Best Google AI Usage

The terminal connects to the Gemini API for dynamic responses. The AI stays in character as a wartime consciousness. Without a key it falls back to pre-written dialogue, but with Gemini every conversation is unique.
