Perspective Grid Detection Without Fixed Overlay Boxes
Many older webcam cube scanners force you to hold the cube inside a rigid 3×3 square drawn in the middle of the video feed and press a “Capture” button six times. That approach is slow and error-prone: if your hand tilts slightly, the background bleeds into the sampling squares.
On rubik.page, you simply show each face to the camera in any order, anywhere in the frame:
- Adaptive edge and contour extraction: Each video frame is analyzed with OpenCV to locate quadrilateral sticker candidates and outer cube face boundaries, even on stickerless cubes with rounded plastic corners.
- Projective 3×3 lattice fitting: Using homography and perspective grid scoring, the detector fits a 3×3 projective grid over the visible face (or a pair of adjacent faces meeting at a shared edge) and rejects accidental background grids such as keyboards, bookshelves, or tiled walls via a 3-frame grid-jump consensus filter.
- Core patch sampling: Once a 3×3 grid is locked, the detector samples the interior of each of the 9 cells—ignoring black plastic borders and specular highlight edges—and converts the pixels into the perceptual CIELAB (
L*, a*, b*) color space.
Joint CIELAB Palette Calibration Across All 54 Stickers
The hardest challenge in camera-based cube scanning is that colors change dramatically under different lighting and cube finishes:
- Under warm indoor tungsten or yellow LED bulbs, white stickers look cream-yellow, and red vs. orange shift close together in standard RGB/HSV thresholds.
- On modern frosted or pastel “macaron” speedcubes, mint green and sky blue have high lightness
L*and low saturation, looking almost white to a naive classifier. - In a dim room, dark blue and dark green lose brightness and can be confused with black plastic borders.
To solve this reliably, rubik.page uses a joint Bayesian palette fitter in CIELAB space rather than fixed RGB cutoffs:
- Three-frame confirmation per face: As soon as you hold a face steady for three consistent frames (~0.5 seconds), its nine CIELAB measurements are recorded and an animated green checkmark confirms that you can turn to the next side.
- Relative hue-sector priors: Colors are evaluated relative to the cube's own measured white point in the
(a*, b*)chromaticity plane, enforcing the natural angular ordering of warm hues (Red → Orange → Yellow) and cool hues (Green → Blue). - Global 6×9 assignment: As more faces are scanned, the tracker fits all six color clusters simultaneously across all observed stickers, ensuring that no color is assigned to more than 9 stickers and automatically re-labeling earlier faces as the lighting model refines.
Glare Rejection and Automatic Exposure Compensation
Webcams and phone cameras automatically adjust their exposure based on the whole room. If you sit in front of a bright window or hold a glossy cube close to a desk lamp, the camera can clip pale yellow stickers to pure white (L* ≥ 97) or wash out a single sticker under a direct reflection.
Our scanner handles harsh lighting on both the client and the server:
- Highlight clipping mask: Within each sticker cell, pixels that are bleached white by side-light glare are excluded before computing the cell's median CIELAB color.
- Temporal glare freeze: If a sticker that already has stable color measurements suddenly jumps in lightness (
L*) and drops in chroma while the rest of the face stays steady, the tracker recognizes a passing lamp reflection and preserves the previous clean measurement instead of overwriting the sticker with white. - Hardware exposure & torch control: On browsers and devices that expose the MediaStream `exposureCompensation` and `torch` APIs, the page automatically steps down exposure when overexposure is detected and offers a one-tap Flashlight button (with automatic negative exposure compensation so the LED does not bleach the stickers) when the room is too dark.
Aligning Six Unordered Grids Across 4,096 Rotations
Because each face on the 2D cube net is placed by its center sticker color, you can show the six faces to the camera in any order and with any face rotation (0°, 90°, 180°, or 270°). Once all six faces are scanned, each of the 6 faces has 4 possible quarter-turn orientations, giving:
4^6 = 4,096 possible 3D net orientations
Instead of asking you to manually rotate every face on the net, the server tests all 4,096 orientations in milliseconds against the exact mathematical solvability laws of the 3×3 cube:
- If exactly one solvable 3D cube exists in the standard color scheme, it is accepted automatically and you can immediately press Solve or Train.
- If symmetric patterns on your cube allow multiple solvable orientations (or if your cube uses an alternate color scheme such as blue on the left), the scanner displays interactive 3D cube previews with the differing stickers highlighted so you can pick the one that matches the cube in your hand.
- If zero orientations are solvable, the solver checks single-pair color swaps for borderline red/orange stickers and runs the physical defect diagnosis (`twist`, `flip`, `swap`, `centers`).
Herbert Kociemba's Two-Phase Algorithm and God's Number (20)
A 3×3 Rubik's Cube has 4.325 × 1019 reachable states. In 2010, researchers proved that God's Number in the half-turn metric is 20: every solvable configuration can be solved in 20 moves or fewer (where a 90° or 180° turn of a face counts as 1 move). However, searching a brute-force tree of 1820 branches directly is impossible in real time.
To find a near-optimal solution of 18–22 moves in a fraction of a second, rubik.page uses Herbert Kociemba's Two-Phase Algorithm, which splits the search into two nested mathematical subgroups using iterative-deepening A* (IDA*) with precomputed pruning tables:
| Phase | Mathematical Subgroup | What the Search Achieves | State Space Size |
|---|---|---|---|
Phase 1G0 → G1 |
All 18 moves:⟨U, D, L, R, F, B⟩ |
Orients all 8 corners, orients all 12 edges, and places the 4 middle-layer edges (FR, FL, BR, BL) into the middle equator slice. |
37 × 211 × C(12, 4) = 2,217,093,120 states (max 12 moves) |
Phase 2G1 → {I} |
Half turns on side faces:⟨U, D, L2, R2, F2, B2⟩ |
Permutes the 8 corners, the 8 U/D edges, and the 4 equator edges into their exact solved positions without disturbing orientations. | 8! × 8! × 4! ÷ 2 = 19,508,428,800 states (max 18 moves) |
Why is splitting into G0 → G1 → {I} so fast? Because instead of multiplying two 10-billion-state spaces together (4.3 × 1019), IDA* searches Phase 1 (~2.2 billion states) and Phase 2 (~19.5 billion states) sequentially with compact coordinate lookup tables, finding a complete solution of around 20 moves almost instantaneously.
Fast Solve Mode vs. Interactive 7-Stage Train Mode
Once your cube is scanned on rubik.page, you can choose between two completely different engines:
- Solve (Kociemba Two-Phase Engine): Computes a short ~20-move solution designed to get your physical cube back in order as quickly as possible. Every move is animated on an interactive 3D cube with a fixed reference miniature and plain-language directions (“turn the right face clockwise”).
- Train (7-Stage Human Layer-by-Layer Engine): Simulates our 7-step beginner's method directly on your exact scanned scramble. Instead of opaque computer shortcuts, it breaks the solve into human stages (Daisy, White Cross, White Corners, Middle Layer, Yellow Cross, Yellow Edges, Corner Positions, Corner Twists), highlights the exact piece and target slot on the 3D model, explains why each algorithm is chosen, and includes a Test yourself quiz mode.