GitHub - punnerud/MPErubiks: Rubik's cube solver & trainer in Rust/WebAssembly — camera scanning, 3D GPU cube, MPEE-style macro routing over YOUR algorithms. Free for noncommercial use.

GitHub

5 min read Original article ↗

▶ Try it live: https://punnerud.github.io/MPErubiks/ (camera scanning works right in the browser — phones included).

A visual-first Rubik's cube app in Rust, running in the browser via WebAssembly (GPU-rendered with wgpu): scan your real cube with the camera, watch it in 3D, and follow a step-by-step guide — then train the standard algorithm sets with a timer and per-algorithm scores. Once you know an algorithm, the solver prefers solutions that use it and can even stop there so you execute it from memory.

Designed so children who can't read yet can use it: big colored buttons, painter-drawn icons, animations and color cues carry the meaning; text is always secondary. English/Norwegian with a flag switch, dark/light theme.

Screenshots

All images are the app's live screenshot tests (crates/cube-app/tests/snapshots/) — they regenerate with the code, so this is what the app looks like right now.

Menu (dark / light) Solve guide Solved!
Practice-stop Settings Training cards
Lesson player Algorithm demo Practice unlocked

Features

  • 📷 Camera scanning — auto-aligning grid (position and scale), per-pixel Oklab hue voting, evidence averaged over a hold-steady window, and a backtracking constraint resolver that fills uncertain cells using the cube's hard rules (9 per color, every piece once, solvability). The result is rotated + relabeled so every color sits on its standard face.
  • 🧭 Solve guide — near-instant solutions (≤23 moves; a shallow pre-pass returns truly short ones for nearly-solved cubes), stepped one move at a time with karaoke notation, two-stage double turns, and a confetti cannon.
  • ⚙️ Practice-stop mode — the guide halts where a chosen algorithm applies, shows only its name ("★ T-Perm — you know this one!"), and you execute it from memory; "I did it" fast-forwards, "Show me" reveals.
  • 🎓 Lessons — beginner steps (daisy → cross → corners → second layer → top) with a steppable demo player and Practice buttons into the drill loop.
  • 💪 Training — PLL · OLL · F2L · beginner cards with demo player, drill timer, success/fail stats and a persistent trained-set (MPEdb).
  • 🎲 Practice scrambles — pick the algorithms you are drilling (gear in Play): the shuffle then produces a scramble whose solution actually uses them, and a card reports how many moves it is and what share of it is your algorithm.
  • 🌍 31 languages — Nordic, most of Europe, and Chinese (Simplified and Traditional), Japanese, Korean, Vietnamese. Tap the flag for a scrollable picker. CJK scripts arrive as font subsets fetched on demand (38-94 KB, containing only the characters this UI uses), so the download stays small no matter how many scripts are supported.

See INNOVATIONS.md for what this repo invented, borrowed, and moved somewhere unusual — including the measured negative results.

Layout

crate what
cube-core dependency-free cube model: 54-facelet state, moves derived from integer sticker geometry, notation parser, case recognizer (patterns derived from algorithm inverses)
cube-solver kewb (Kociemba two-phase) integration, scan constraint resolver, hint/guided-solution engine, packed-table codec
cube-vision dependency-free Oklab color voting, grid auto-fit, field-data eval harness
cube-render wgpu: instanced cubies, procedural sticker shader, move animation, offscreen depth + blit into egui, tap picking
cube-store MPEdb storage (file+WAL native, in-memory + localStorage dump on wasm)
cube-app eframe/egui app: menu, play, scan, solve guide, trainer, lessons, settings
xtask gen-table, pack-table, benchmarks

assets/algorithms.json holds 127 validated cases — every algorithm is checked mechanically (its inverse must produce a state of the claimed kind, and no two cases may be AUF-indistinguishable), so data errors fail the build. assets/table.pack is the solver table the app ships: nibble-packed pruning depths + route-compressed move tables (per-column deltas along the coordinate order — the enumeration is already the optimal "route") + per-section deflate — 0.9 MB instead of 6.8 MB (13 %), unpacking in ~15 ms.

Targets & build

  • Web (primary): trunk serve → WebGPU with automatic WebGL2 fallback. Camera scanning needs HTTPS or localhost (trunk serve --tls for phones).
  • Native desktop: cargo run -p cube-app (same UI, manual cube entry instead of camera).
cargo run -p xtask -- gen-table     # once: generates assets/table.bin
cargo run -p xtask -- pack-table    # packs it into assets/table.pack
trunk serve                         # browser dev build

Tests

cargo test --workspace                   # core properties, recognizer, vision, solver, store
cargo test -p cube-solver -- --ignored   # 1000 random solves within the bound
UPDATE_SNAPSHOTS=true cargo test -p cube-app --test screenshots  # headless UI PNGs
RUBIKS_SCANS_DIR=... cargo test -p cube-vision --test eval_scans # field eval (dataset outside the repo)

The screenshot suite renders real app screens through wgpu (lavapipe works) into crates/cube-app/tests/snapshots/. Scan telemetry (cell crops) uploads to a private dev server for offline tuning; personal photos are never committed to this repo.

License

PolyForm Noncommercial 1.0.0: free for everyone to use, modify and share for any noncommercial purpose. All commercial rights remain with the copyright owner (Morten Punnerud-Engelstad) — only the owner may commercialize this software or license it onward for commercial use. Third-party dependencies keep their own licenses.