← back to Rubik Cube 3d
README.md
43 lines
# Rubik's Cube 3D
A single-file, zero-dependency 3D Rubik's cube — pure CSS 3D transforms + vanilla JS.
Open `index.html` in any browser.
Origin: Model Arena challenge "All-Models — Rubik Cube 3D". Started from Claude
(Max plan)'s artifact, then hardened and extended.
## Features
- **Drag to orbit** the camera (pointer events, works with touch), **scroll / pinch-trackpad to zoom** (`+` / `-` keys too)
- **Animated face turns** — buttons for U D L R F B **plus slice moves M E S**, each with a prime (counter-clockwise) variant
- **Keyboard**: U/D/L/R/F/B/M/E/S, Shift = counter-clockwise, ⌘Z / Ctrl+Z = undo
- **Scramble** (22 random outer turns, no immediate repeats) and **Reset**
- **Undo** with full move history
- **Move counter + timer** — timer starts on your first turn after a scramble
- **Solved detection** — sticker-orientation math (`m·d == d` for every sticker), so it also
understands slice-move states; a 🎉 banner shows moves + time when you solve a scramble
- Responsive: cube re-sizes on window resize / rotation
## What was fixed vs. the starting artifact
- No solved detection, move counter, timer, or undo — added all four
- No slice moves (M/E/S) — added, with correct standard-notation directions
- No zoom — added wheel/keyboard zoom with clamping
- Cube size was computed once at load and never updated — added a debounced resize handler
- Holding a key down flooded the animation queue — `keydown` now ignores auto-repeat
- Exposed a `window.__cube` debug/test hook so behavior is verifiable headlessly
## Internals
Each of the 26 cubies carries a logical position `(x,y,z) ∈ {-1,0,1}³` and an integer
3×3 rotation matrix `m`. A face turn animates a rotation `R(t)` composed on top
(`matrix3d(R·m)`, position `R·p`), then snaps: `m ← round(R90·m)`, `p ← round(R90·p)`.
Matrices stay exactly integer forever, so there is no drift. Solved ⇔ every sticker's
world direction `m·d` equals its home direction `d`.
## Tests
```sh
node tests/e2e.mjs # headless Playwright: 18 assertions incl. orbit, zoom, undo, Mx4=identity
```