A Rubik's cube, held in memory.
Feed it moves and it tells you what the cube looks like, which stages are solved, and how a recorded solve was actually put together.
0 runtime dependencies 3x3 and 2x2 CJS + ESM + types MIT
npm install cube-state-engine
Watch it solve
The page replays real recorded solves at their recorded speed. The
3D view, the flat net, the stage checklist and the predicate checks
below all read from one CubeEngine instance — every
tick is the engine reporting what it sees, move by move. Take over
whenever you like: press a key, or scramble it.
Keyboard
Break a solve into stages
Hand analyzeSolution() a timed move list and it replays
the solve, works out which method was used, and reports when each
stage finished. This is the same solve playing above, as data.
The API
Everything is a named export. Predicates accept a
CubeEngine, a state() object, or a flat
sticker array.
Engine
- new CubeEngine(scramble?, { size }) Size 2 or 3. The scramble is applied but not recorded.
- applyMoves(seq, { record }) U D L R F B, wide Uw Dw Lw Rw Fw, slices M E S, rotations x y z, with ' and 2.
- state()Six faces as color matrices.
- isSolved()Every face a single color.
- getMoves(asString?)Move history.
- reset()Back to solved, history cleared.
- rotateU / D / L / R / F / B Plus Uw Dw Lw Rw Fw, M E S, and X Y Z. Each takes a clockwise flag.
Predicates
- isCubeSolved(cube)
- isCrossComplete(cube, { color })
- isF2LComplete(cube, { cross })
- isLastLayerOriented(cube, { face })
- areLastLayerCornersSolved(cube, { face })
- matchesGoal(cube, goal) full · cross · f2l · oll · oll+cp, or your own function.
- getCubeGeometry(size) Derived edges, corners, neighbors and opposites.
Analysis
- analyzeSolution(moves, { size }) Detects CFOP and Roux. Reports per-stage timing and TPS.
- simplifyMoves(moves) Joins identical quarter turns into doubles. Never cancels.
- invertSequence(tokens) Reverses and inverts a move list.
- getMovePermutations(size) The cached permutation tables the engine runs on.
// How this page is wired
import { CubeEngine, matchesGoal, simplifyMoves } from "cube-state-engine";
const cube = new CubeEngine();
function onKey(move) {
cube.applyMoves(move, { record: true });
paintNet(cube.state());
player.alg = cube.getMoves();
solvedEl.textContent = cube.isSolved();
crossLamp.dataset.on = matchesGoal(cube, "cross");
countEl.textContent = simplifyMoves(cube.getMoves(false)).length;
}