ImageNim: Transforming Classic Nim Game Theory into a Visual Pixel XOR Puzzle with Rust & WebAssembly
ImageNim: Transforming Classic Nim Game Theory into a Visual Pixel XOR Puzzle
For centuries, mathematicians and game theorists have been fascinated by Nimโa mathematical game of strategy where players take turns removing counters from distinct piles. In 1901, Harvard mathematician Charles L. Bouton proved that Nim is completely solved using binary arithmetic and the bitwise XOR operation (โ). The binary XOR sum of pile sizes, often called the Nim-sum, dictates whether a game state is a winning or losing position.
I actually had the idea for this game about 15 years ago and originally implemented it as a Java desktop application. While working on recent web projects like Cyclic Demons and exploring high-performance browser technology, I realized I could easily build a modern web version of ImageNim: an interactive visual puzzle game where instead of numbers or matchsticks, players manipulate full RGBA pixel buffers using real-time bitwise XOR operations.

You can play with the live application right now in your browser:
๐ Play ImageNim Live
(Source code available on GitHub)
๐จ How ImageNim Works: Visual Bitwise XOR
In standard digital graphics, blending two image layers usually involves alpha compositing or additive blending. In ImageNim, images are blended using pure bitwise XOR (โ) logic applied to raw RGB byte buffers.
The game layout surrounds a central target canvas with 8 outer image cards. When you click an outer image card, its pixel buffer is XORed directly into the central canvas:
Because bitwise XOR possesses three key mathematical properties, the visual mechanics feel both magical and intuitive:
- Self-Inverse (A โ A = 0): Clicking an image card a second time immediately toggles that layer off, canceling out its contribution pixel-by-pixel.
- Identity (A โ 0 = A): An all-black canvas (where RGB bytes are zero) acts as the identity element. XORing any image into black yields the exact original image.
- Commutativity (A โ B = B โ A): The order in which you click the image cards does not matterโthe resulting composite image depends strictly on which set of cards is selected.
๐น๏ธ Game Modes & Features
ImageNim features versatile game modes, difficulty levels, move scoring, and custom asset capabilities:
๐งฉ 1-Player Solitaire Mode
In Solitaire mode, the central canvas starts pre-loaded with a complex composite image created by XORing a secret random subset of the outer cards. Your goal is to clear the canvas back to solid black () in the fewest moves possible.
Because , finding the solution means discovering the exact combination of cards that were originally used to generate the puzzle.
โญ Performance Score Ratings
At the end of each solitaire game, your solution is evaluated based on how close your total moves are to the minimum Optimal Score:
- Perfect Score: Solved in the minimal optimal moves.
- Great: Solved within 2 moves over optimal.
- Good: Solved within 4 moves over optimal.
โ๏ธ 2-Player Versus Mode
In 2-Player Versus mode, two players take turns dueling on the same device. Each player is secretly assigned a unique target card. On each turn, a player selects one outer card to toggle its pixels on the shared central canvas.
The first player to make the central canvas match their assigned target card wins!
๐ฑ Easy vs ๐ฅ Hard Difficulty
ImageNim offers customizable difficulty settings:
- Easy Mode: Exactly 2 cards are initially XORed into the central canvas, making for an approachable entry-level puzzle.
- Hard Mode: A random selection of 3 to 8 cards is XORed together, producing significantly more intricate composite targets.
๐ Explore Mode
Turn Explore Mode ON to freely experiment with XOR tile combinations without triggering endgame popups. It serves as a visual sandbox for studying how color channels interact. Turning Explore Mode OFF restarts the puzzle.
๐ผ๏ธ Custom Image Set Uploads & Built-in Themes
Players can select from curated built-in photography theme packsโincluding Bryce Canyon, Zion National Park, Flowers & Flora, and Sunsets & Skiesโor upload 8+ photos from their device or camera roll to play with custom image sets.
๐งฎ The Math: Nim-Sum as a Linear Vector Space over
Why does XOR work so naturally for puzzle generation?
In linear algebra, the set of binary vectors of length forms a vector space over the finite field (where addition is XOR). In ImageNim, if an image contains pixels with 3 color channels (8 bits per channel), the entire image can be represented as a high-dimensional vector in .
Selecting a card is equivalent to adding a basis vector to our current state.
When generating a puzzle, the system picks a bitmask . The target canvas state is constructed as:
Because the vector space is linear over , solving the puzzle is equivalent to finding such that . Since each card toggles independently, every initial puzzle configuration has a unique minimal solution!
โก High-Performance Architecture: Rust + WASM + React
Performing real-time XOR bitwise math across thousands or millions of pixel bytes at 60 frames per second can place a heavy burden on JavaScript engines if not carefully engineered. Passing large byte arrays across the JavaScript/DOM boundary frequently causes severe garbage collection spikes.
To deliver sub-millisecond responsiveness, ImageNim uses a hybrid architecture:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ React + TypeScript UI โ
โ (State, Card Grid, Controls, Canvas) โ
โโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโ
โ Zero-Copy Shared Memory
โโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโ
โ Rust + WebAssembly Core Engine โ
โ (xor_buffers, Knuth Sampling, LCG) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
1. Zero-Copy WebAssembly Shared Memory
The Rust core crate (wasm-bindgen) allocates static RGBA pixel buffers directly inside the WebAssembly memory sandbox. When the user toggles an image card, JavaScript passes the pointer offset to Rust, and Rust executes the bitwise XOR loop in compiled native assembly:
#[wasm_bindgen]
pub fn xor_buffers(target: &mut [u8], src: &[u8]) {
let len = target.len().min(src.len());
let mut i = 0;
while i + 3 < len {
target[i] ^= src[i]; // Red
target[i + 1] ^= src[i + 1]; // Green
target[i + 2] ^= src[i + 2]; // Blue
target[i + 3] = 255; // Opaque Alpha
i += 4;
}
}
The HTML5 <canvas> context then paints the modified pixel buffer directly out of WASM memory without duplicating arrays or allocating transient objects.
2. Fast Deterministic Subset Generation
Puzzle initialization relies on Knuth's algorithm and a Linear Congruential Generator (LCG) implemented in Rust to deterministically select initial card subsets and guarantee solvable puzzle states without relying on external web browser random seeds.
๐ Conclusion
ImageNim has been a fantastic project for combining mathematical game theory with high-performance web engineering. It turns abstract bitwise XOR arithmetic into a tangible visual experience where colors flip, cancel out, and morph into complex artistic compositions.
Check out the live game, upload your own images, or explore the codebase:
- ๐ฎ Live App: https://imagenim.netlify.app/
- ๐ป GitHub Repository: https://github.com/dmaynard/ImageNim