A lightweight, dependency-free JavaScript engine for modeling, manipulating, and visualizing NxN Rubik's Cubes.
Cubit.js is a lightweight, dependency-free JavaScript/npm library for applying Rubik’s Cube scrambles, modeling NxN cube states, and generating framework-agnostic 2D cube net data. Built from the cube engine powering Cubit, an open-source speedcubing platform, and was later extracted into an independent package so other cubing projects can use the same engine.
API Reference · Cube Model · Visualization Guide · Contributing
Cubit.js V1 focuses on one job:
Scramble
↓
Cube State Engine
↓
Scrambled Cube State
↓
2D Net Data
↓
Your UI
The package contains zero runtime dependencies and does not depend on React, Vue, Canvas, SVG, or any other rendering framework.
npm install cubit.jsCubit.js uses ES modules.
import {
applyScramble,
getNetData
} from 'cubit.js';import { applyScramble, getNetData } from 'cubit.js';
const scramble = "R U R' U' F2 U2 R' U";
// Apply the scramble to a solved 3x3 cube
const state = applyScramble(scramble, '3x3');
// Convert the resulting cube state into visualization data
const net = getNetData(state);
console.log(state);
console.log(net);That's the basic Cubit.js workflow:
"R U R' U'"
↓
applyScramble()
↓
CubeState
↓
getNetData()
↓
Renderable 2D Net Data
- Zero runtime dependencies
- Pure JavaScript / ESM
- Immutable cube-state transformations
- 2x2, 3x3, 4x4 and 5x5 support
- Standard face turns
- Prime turns
- Double turns
- Wide moves
- Multi-layer wide moves
- WCA-style scramble notation parsing
- Physically verified cube rotations
- Framework-agnostic visualization data
- Deterministic state transformations
- Comprehensive physical-correctness tests
Cubit.js deliberately separates cube mathematics from rendering.
The package calculates the cube.
You decide how it looks.
Cubit.js includes detailed documentation for developers who want to go beyond the quick-start examples or understand the engine internals.
| Guide | Description |
|---|---|
| API Reference | Complete reference for the public Cubit.js API, including function signatures, parameters, return values, examples, and error behavior. |
| Cube Model & Mathematics | Technical documentation for the cube-state representation, coordinate system, face orientation, rotation mathematics, layer semantics, and immutability model. |
| Visualization Guide | Learn how to turn Cubit.js net data into a visual cube net using HTML/CSS, SVG, Canvas, React, Vue, or other rendering technologies. |
| Contributing | Development setup, architecture guidelines, testing requirements, regression testing, and contribution workflow. |
If you simply want to use Cubit.js:
- Follow the Quick Start below.
- Read the API Reference for available functions.
- Read the Visualization Guide if you're building a cube visualizer.
If you're interested in how Cubit.js works internally, see Cube Model & Mathematics.
Most applications only need
applyScramble()andgetNetData()to get started.
| Puzzle | Supported |
|---|---|
| 2x2 | ✅ |
| 3x3 | ✅ |
| 4x4 | ✅ |
| 5x5 | ✅ |
Example:
applyScramble(scramble, '2x2');
applyScramble(scramble, '3x3');
applyScramble(scramble, '4x4');
applyScramble(scramble, '5x5');Cubit.js uses the following solved orientation:
| Face | Color | Hex |
|---|---|---|
| U (Up) | White | #F8FAFC |
| D (Down) | Yellow | #FACC15 |
| F (Front) | Green | #22C55E |
| B (Back) | Blue | #3B82F6 |
| R (Right) | Red | #EF4444 |
| L (Left) | Orange | #F97316 |
The canonical orientation is therefore:
WHITE
U
ORANGE GREEN RED BLUE
L F R B
YELLOW
D
When comparing a Cubit.js state against a physical cube, use the same orientation.
R L U D F B
R' L' U' D' F' B'
R2 L2 U2 D2 F2 B2
Rw Uw Fw Lw Dw Bw
Lowercase wide notation is also supported:
r u f l d b
Examples:
3Rw
3Rw'
3Fw2
The primary Cubit.js API.
Creates a solved cube and applies the supplied scramble.
const state = applyScramble(
"R U R' U'",
"3x3"
);A scramble string or parsed move array.
"R U R' U'"Supported values:
2x2
3x3
4x4
5x5
Default:
3x3
A new CubeState.
Creates a solved cube.
import { createSolvedCube } from 'cubit.js';
const cube = createSolvedCube('3x3');Example state:
{
dimension: 3,
U: [
['WHITE', 'WHITE', 'WHITE'],
['WHITE', 'WHITE', 'WHITE'],
['WHITE', 'WHITE', 'WHITE']
],
D: [...],
F: [...],
B: [...],
R: [...],
L: [...]
}Each face is represented as an N × N matrix.
Parses scramble notation into structured move objects.
import { parseScramble } from 'cubit.js';
const moves = parseScramble(
"R U R' U'"
);
console.log(moves);A move follows this structure:
{
raw: "R'",
face: "R",
amount: -1,
depth: 1,
isWide: false
}Parses one move.
import { parseMove } from 'cubit.js';
const move = parseMove("3Fw2");Result:
{
raw: "3Fw2",
face: "F",
amount: 2,
depth: 3,
isWide: true
}Applies one parsed move to an existing cube state.
import {
createSolvedCube,
parseMove,
applyMove
} from 'cubit.js';
const cube = createSolvedCube('3x3');
const move = parseMove('R');
const nextState = applyMove(cube, move);Cubit.js transformations are immutable.
cube remains unchanged.
Cubit.js does not force a rendering technology on applications.
Instead, it converts the mathematical cube state into simple JavaScript data.
import {
applyScramble,
getNetData
} from 'cubit.js';
const state = applyScramble(
"R U R' U'",
"3x3"
);
const net = getNetData(state);The returned structure resembles:
{
dimension: 3,
netLayout: {
U: [...],
L: [...],
F: [...],
R: [...],
B: [...],
D: [...]
},
faces: [
{ face: 'U', grid: [...] },
{ face: 'L', grid: [...] },
{ face: 'F', grid: [...] },
{ face: 'R', grid: [...] },
{ face: 'B', grid: [...] },
{ face: 'D', grid: [...] }
]
}Each sticker contains rendering information:
{
colorKey: 'WHITE',
hexColor: '#F8FAFC',
face: 'U',
row: 0,
col: 0,
id: 'U-0-0'
}That means applications can render Cubit.js output using:
- CSS Grid
- HTML
- Canvas
- SVG
- React
- Vue
- Svelte
- mobile UI frameworks
- custom graphics engines
without Cubit.js depending on any of them.
The conventional unfolded layout is:
┌─────┐
│ U │
└─────┘
┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐
│ L │ │ F │ │ R │ │ B │
└─────┘ └─────┘ └─────┘ └─────┘
┌─────┐
│ D │
└─────┘
Cubit.js provides the sticker data for each of these faces.
The positioning and styling remain under the consumer's control.
<div id="cube-net"></div>
<script type="module">
import {
applyScramble,
getNetData
} from 'cubit.js';
const state = applyScramble(
"R U R' U'",
"3x3"
);
const net = getNetData(state);
const container =
document.getElementById('cube-net');
net.faces.forEach(({ face, grid }) => {
const faceElement =
document.createElement('div');
faceElement.dataset.face = face;
faceElement.style.display = 'grid';
faceElement.style.gridTemplateColumns =
`repeat(${net.dimension}, 30px)`;
grid.forEach(row => {
row.forEach(sticker => {
const element =
document.createElement('div');
element.style.width = '30px';
element.style.height = '30px';
element.style.backgroundColor =
sticker.hexColor;
faceElement.appendChild(element);
});
});
container.appendChild(faceElement);
});
</script>This example intentionally keeps rendering simple.
A production application can position the six face elements into the standard unfolded cube-net layout using CSS Grid, Canvas, SVG, or another rendering system.
Cube states can be validated using:
import { validateCubeState } from 'cubit.js';
const valid = validateCubeState(state);Cubit.js validates structural properties of the state before mathematical operations where appropriate.
Invalid developer input produces explicit errors rather than silently changing the requested operation.
Examples include:
createSolvedCube('7x7');parseMove('X');parseScramble('R U SOMETHING');Invalid layer depths and malformed move notation are also rejected.
Cubit.js V1 does not generate scrambles.
It consumes them.
For example:
const scramble =
"R U2 F' L2 D B2 R' U";
const state =
applyScramble(scramble, '3x3');Scrambles may come from:
- a scramble generator
- a competition-compatible scrambling system
- user input
- another cubing library
- your own application
The architecture is intentionally:
Scramble Generator
↓
Scramble String
↓
Cubit.js
↓
Cube State
↓
Net Data
↓
Application UI
This keeps the state engine independent from scramble-generation implementations.
Cubit.js does not mutate the supplied cube state during transformations.
For example:
const solved =
createSolvedCube('3x3');
const afterR =
applyMove(
solved,
parseMove('R')
);solved remains unchanged.
This makes the engine suitable for state-management systems and reactive UI architectures.
Cube mathematics can easily pass algebraic tests while still representating physical rotations incorrectly.
For that reason, Cubit.js uses both mathematical invariant tests and physical-reference tests.
The suite includes:
- solved-state verification
- matrix rotation verification
M⁴ = Identity- move + inverse verification
- double-turn verification
- color conservation
- odd-cube center stability
- all 12 physical quarter turns
- multi-move sequences
- unique sticker permutation verification
- regression scramble verification
- multi-size verification
- randomized scramble cross-validation against an independent cube representation
Run the suite with:
npm testCubit.js is intentionally split into small independent modules:
src/
├── constants.js
├── engine.js
├── index.js
├── mapper.js
├── matrix.js
└── parser.js
Responsible for cube state and physical transformations.
Responsible for converting notation into move operations.
Contains reusable matrix transformation utilities.
Transforms mathematical state into visualization-friendly data.
Defines the public package API.
Cubit.js was born inside Cubit, an open-source speedcubing platform.
Cubit required a cube visualizer capable of taking the exact scramble shown to a user, applying that scramble mathematically to a solved cube, and displaying the resulting physical state.
Instead of coupling that engine permanently to the Cubit application, the reusable cube mathematics and visualization-data layer were extracted into an independent package.
That became Cubit.js.
Cubit remains the product.
Cubit.js is the reusable cube engine that originated from it.
The package is maintained independently so it can be used by other timers, trainers, visualizers, educational tools, cubing applications, experiments, and developer projects.
Current release.
- Scramble parsing
- Cube-state generation
- Move application
- 2x2–5x5 support
- Wide moves
- Multi-layer moves
- 2D visualization data
- Framework-independent API
Planned areas include:
- built-in scramble generation
- higher-level visualization helpers
- SVG output
- Canvas rendering helpers
- optional React components
- possible Vue / Svelte integrations
- visualization customization
Longer-term exploration includes:
- solution generation
- scramble analysis
- move-sequence analysis
- move optimization
- cube-solving utilities
- training-oriented APIs
The roadmap is directional and may evolve as Cubit.js develops.
Contributions, bug reports, test cases, and feature proposals are welcome.
If you discover a scramble that produces an incorrect physical state, please include:
- puzzle size
- scramble
- expected state
- actual state
- reproduction steps
Physical correctness is treated as a core requirement of the project.
Cubit.js is released under the MIT License.
See LICENSE for details.
Built from the cube engine behind Cubit.
Scramble → State → Visualize.