Skip to content

G1TS23/radiant-radiation

Repository files navigation

radiant-radiation

CI Live demo Astro TypeScript code style: Prettier License: MIT

A minimalist, terminal-styled puzzle game. Flip cells with a 2×2 brush until the whole grid is a single color.

🎮 Play: https://radiant-radiation.netlify.app

The puzzle

The board is an N×N grid of black/white cells. A move picks an interior vertex (where 4 cells meet) and flips the 2×2 block around it. There are (N-1)×(N-1) possible moves. Tap/click where four cells meet — the center of the highlighted square — to flip them. Win by making the grid a single shade — either all white or all black.

Puzzles are generated by applying a known set of distinct moves to a monochrome board (the base shade is chosen at random), so every puzzle is guaranteed solvable. The displayed par is the genuine minimum number of moves — the shorter of the all-white and all-black solutions, computed over GF(2), never an overstatement. A move limit (par + margin) defines the challenge per difficulty. The same board is never handed out twice in a row.

Controls

Keyboard Pointer
Move cursor arrows hover
Flip the 2×2 space / enter tap / click
Undo z right-click
Reset puzzle r toolbar
New puzzle n toolbar
Cycle difficulty d / [ ] toolbar
Toggle theme t top-right button
Zen mode esc top-right button
Skip tutorial s link
Change language top-right button

On touch devices the keyboard hints are replaced by an on-screen toolbar, and the history panel becomes a collapsible accordion.

Features

  • Three-step 3×3 tutorial before free play, ending with an unguided puzzle.
  • Difficulty presets (easy/normal/hard/expert) bundling size + par + slack.
  • Move limit with par comparison; auto-advance to the next puzzle after a win.
  • Games history (result, moves, difficulty, board preview) with replay, persisted in localStorage; the in-progress game is autosaved and resumed on reload. Replaying a board in fewer moves upgrades its recorded result.
  • Lifetime stats panel (games played, win rate, current/best streak, average moves, par finishes, total and best solve time) — cumulative beyond the 20-game history cap. Solve time is the active time from the first move (paused while the tab is hidden). History and stats clear independently.
  • Win-streak momentum line under the board (from two wins in a row): one mark per win, the newest pulsing as the streak grows; a loss clears it.
  • Localized in English, French, Spanish, Japanese — auto-detected, switchable at runtime, and remembered (the Japanese title renders in katakana).
  • Soft light/dark themes (follows prefers-color-scheme); a distraction-free zen mode; on a win the grid melts into one solid shade.
  • Radial victory animation; respects prefers-reduced-motion.
  • No accounts, no tracking, fully offline — all states are local.

Deep link: ?d=easy|normal|hard|expert starts free play at that difficulty.

Tech

Astro 6 + TypeScript (no UI framework). Pure game logic in src/game/engine.ts, idempotent rendering in render.ts, input in input.ts, orchestration in main.ts, the pure session→view mapping in view-model.ts, persistence in history.ts, lifetime stats in stats.ts, and dependency-free runtime i18n in i18n.ts. Static build, deployed on Netlify.

Develop

npm install
npm run dev        # local dev server
npm run check      # astro type-check
npm run lint       # eslint
npm test           # unit tests (Vitest)
npm run build      # static build -> dist/

Docker

Production — a multi-stage build compiles the static site (node:22-alpine) and serves it with nginx:1.27-alpine, mirroring the production security headers.

docker compose up -d --build   # build + run -> http://localhost:8080
docker compose down            # stop

Development — a live Astro dev server with hot module reload, source bind-mounted from the host (edit locally, the browser refreshes itself).

docker compose -f docker-compose.dev.yml up --build   # -> http://localhost:4321

The dev container polls for file changes (CHOKIDAR_USEPOLLING) for reliable watching on Docker Desktop; drop that env in docker-compose.dev.yml if native file events work on your setup.

Contributing

Contributions are welcome! Please read the contributing guide to get set up and learn the checks to run, and the code of conduct before taking part. Found a security issue? See the security policy — please don't open a public issue.

Contributors

Created & maintained by Olivier Falahi (olivier.falahi@gmail.com).

Built with assistance from Claude (Anthropic); dependencies kept current by Dependabot.

License

MIT © 2026 Olivier Falahi

About

A minimalist terminal puzzle : flip 2×2 blocks until the whole grid is a single shade.

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors