npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@cubingcenter/scrambler

v0.5.3

Published

Extensible scramble generation toolkit for CubingCenter projects.

Readme

CubingCenter Scrambler

Reusable scramble generation toolkit for CubingCenter projects.

The package currently ships random-state scramblers for 222 (2x2x2), 333 (3x3x3), and a first native reduced-state 444 (4x4x4) path. It does not depend on cstimer, cubing.js, or another external scramble engine at runtime.

Status

  • Package: @cubingcenter/scrambler
  • Runtime: Node.js
  • Language: TypeScript
  • Package manager: pnpm
  • Registered events: 222, 333, 444, 555, 666, 777, pymx, skwb, clck, mgmx
  • Main technical modules: cube2, cube3, cube4, pyraminx, skewb, clock, megaminx, cube5x5, cube6x6, cube7x7
  • 2x2 quality: random-state target + optimal table-guided solver + verified scramble inversion
  • 3x3 quality: random-state target + two-phase solver + verified scramble inversion
  • Pyraminx quality: random-state target + optimal policy-table solver (all 933,120 core states verified)
  • Skewb quality: random-state target + optimal policy-table solver (all 3,149,280 states; exact uniform sampling)
  • 4x4 quality: reduced 4x4 random-state target + existing 3x3 two-phase finish; full center/wing random-state reduction is isolated under cube4.reduction

This library is intended for practice, training, and internal CubingCenter use. Do not present it as an official WCA competition scrambler; sanctioned competitions must use the official program required by the delegate/organization.

Install Locally

From this repository:

pnpm install
pnpm build
pnpm package:check

From another local project, consume it through your workspace setup or a local path/tarball workflow. See Getting Started for practical options.

API Usage

import {
  generateScramble,
  generateScrambles,
  getEventInfo,
  getSupportedEvents
} from "@cubingcenter/scrambler";

const events = getSupportedEvents();
const info222 = getEventInfo("222");
const info333 = getEventInfo("333");
const info444 = getEventInfo("444");
const scramble2 = generateScramble("222", { seed: "demo" });
const scramble3 = generateScramble("333", { seed: "demo" });
const scramble4 = await generateScramble("444");
const batch = generateScrambles("333", 5, { seed: "session-1" });

console.log(events);
console.log(scramble2.scramble);
console.log(scramble3.scramble);
console.log(scramble4.scramble);
console.log(batch.map((item) => item.scramble));

generateScramble("222") returns a legal random-state 2x2 scramble. Its metadata includes the target cubie state, timer-ready facelets, a 24-character facelet string, and solver diagnostics.

generateScramble("333") returns a legal random-state 3x3 scramble. Its metadata includes the target cubie state, timer-ready facelets, a 54-character facelet string, and solver diagnostics.

generateScramble("pymx") returns a legal random-state Pyraminx scramble. Its metadata includes the target state, facelets, solution moves and depth. Pyraminx/2x2/3x3 accept { skipValidation: true } to skip the per-call verification for maximum throughput (the scramble correctness is covered by exhaustive tests).

Scoped imports (web / smaller bundles)

Importing the root entry loads every puzzle. For web apps, import only the puzzle you need — each subpath registers its own generator, so generateScramble works right away:

import { generateScramble, initializeScrambler } from "@cubingcenter/scrambler/puzzles/pyraminx";
// "222" | "333" | "444" | "555" | "666" | "777" | "pymx" | "skwb" | "clck" | "mgmx"
await initializeScrambler("/scrambler-tables", "pymx");
const result = await generateScramble("pymx", { seed: "demo" });

In the browser, solver tables are fetched from the base URL you pass to initializeScrambler and served from puzzles/<puzzle>/solver/generated/. The demo repo ships precompressed .br/.gz variants of the tables (see pnpm tables:web:sync); the loaders download those automatically when DecompressionStream is available (Pyraminx ~470 KB → ~345 KB, cube3 ~6.6 MB → ~2.2 MB).

2x2 Technical Module

import { cube2 } from "@cubingcenter/scrambler";

const solved = cube2.createSolvedCube2State();
const moved = cube2.applyCube2Algorithm(solved, ["R", "U", "R'"]);
const state = cube2.generateRandomCube2State({ seed: "demo" });
const facelets = cube2.toCube2Facelets(state);
const faceletString = cube2.formatCube2Facelets(facelets);
const validation = cube2.validateCube2State(state);

generateRandomCube2State returns a legal cube state, not a scramble sequence.

toCube2Facelets returns six faces with four stickers each in row-major order. The face order is U R F D L B. formatCube2Facelets produces a stable 24-character string for logs, tests, or timer previews.

The cube2.solver namespace is exported for advanced tooling and validation. Normal consumers should prefer generateScramble("222").

3x3 Technical Module

import { cube3 } from "@cubingcenter/scrambler";

const solved = cube3.createSolvedCube3State();
const moved = cube3.applyCube3Algorithm(solved, ["R", "U", "R'"]);
const state = cube3.generateRandomCube3State({ seed: "demo" });
const facelets = cube3.toCube3Facelets(state);
const faceletString = cube3.formatCube3Facelets(facelets);
const validation = cube3.validateCube3State(state);

generateRandomCube3State returns a legal cube state, not a scramble sequence. It does not filter by visual appearance: blocks, repeated colors on a face, or recognizable patterns can still be valid if the cubie state is legal and non-trivial.

toCube3Facelets returns six faces with nine stickers each in row-major order. The face order is U R F D L B. formatCube3Facelets produces a stable 54-character string for logs, tests, or timer previews.

The cube3.solver namespace is exported for advanced tooling and validation. Normal consumers should prefer generateScramble("333").

Pyraminx Technical Module

import { pyraminx } from "@cubingcenter/scrambler";

const solved = pyraminx.createSolvedPyraminxState();
const moved = pyraminx.applyPyraminxAlgorithm(solved, ["R", "U", "R'"]);
const state = pyraminx.generateRandomPyraminxState({ seed: "demo" });
const facelets = pyraminx.toPyraminxFacelets(state);
const faceletString = pyraminx.formatPyraminxFacelets(facelets);
const validation = pyraminx.validatePyraminxState(state);
const solution = await pyraminx.solvePyraminx(state); // optimal, policy-table based

generateRandomPyraminxState returns a legal random state (centers, edges and tips), not a scramble sequence.

toPyraminxFacelets returns four triangular faces (F L R D) with nine stickers each. formatPyraminxFacelets produces a stable 36-character string.

The solver only covers the core (centers + edges); tips are appended by the scrambler. The pyraminx.solver namespace exposes the compact coordinates and the policy table; its optimality is verified exhaustively over all 933,120 core states (pnpm verify:pyraminx:exhaustive). Normal consumers should prefer generateScramble("pymx").

Skewb Technical Module

import { skewb } from "@cubingcenter/scrambler";

const solved = skewb.createSolvedSkewbState();
const moved = skewb.applySkewbAlgorithm(solved, ["R", "U", "R'"]);
const state = await skewb.generateRandomSkewbState({ seed: "demo" });
const facelets = skewb.toSkewbFacelets(state);
const faceletString = skewb.formatSkewbFacelets(facelets);
const validation = skewb.validateSkewbState(state);
const solution = await skewb.solveSkewb(state); // optimal, policy-table based

generateRandomSkewbState returns a legal random state, not a scramble sequence. It samples the compact group rank uniformly, so every one of the 3,149,280 reachable states is exactly as likely as any other.

toSkewbFacelets returns six faces with five stickers each. formatSkewbFacelets produces a stable 30-character string.

Both generateRandomSkewbState and solveSkewb are async: they need the solver tables, which load lazily in Node and are prefetched in the browser via initializeScrambler(baseUrl, "skwb") (or skewb.solveSkewbSync after preloading). The skewb.solver namespace exposes the compact rank coordinates and the 3-bit policy table (all 3,149,280 states, God's number 11). Normal consumers should prefer generateScramble("skwb").

4x4 Technical Module

import { cube4 } from "@cubingcenter/scrambler";

const solved = cube4.createSolvedCube4State();
const moved = cube4.applyCube4Algorithm(solved, ["R", "Uw", "Rw'"]);
const state = cube4.generateRandomCube4State({ seed: 42 });
const reduced = cube4.areCentersReduced(state);
const paired = cube4.areWingsPaired(state);

Cube4State uses Uint8Array for all piece arrays: 8 corners (cp/co), 24 wings (wp), and 24 centers.

Supported moves: U D R L F B (outer) and Uw Dw Rw Lw Fw Bw (wide), each with ' and 2 suffixes.

The public generateScramble("444") path currently returns a reduced 4x4 random-state scramble: centers are solved, wings are paired, and the projected 3x3 state is random and solved with the existing two-phase solver. The full arbitrary center/wing random-state pipeline is being developed under cube4.reduction.

The cube4.reduction namespace is exported for advanced tooling. Normal consumers should prefer generateScramble("444").

CLI

cubingcenter-scrambler --help
cubingcenter-scrambler list
cubingcenter-scrambler 222 --count 5
cubingcenter-scrambler 222 --seed demo
cubingcenter-scrambler 222 --seed demo --json
cubingcenter-scrambler 333 --count 5
cubingcenter-scrambler 333 --seed demo
cubingcenter-scrambler 333 --seed demo --json
cubingcenter-scrambler 444 --count 3

list prints registered events. --json prints structured output with scramble, moves, facelets, and faceletString.

When --count is used with --seed, each scramble derives a stable seed in the form seed:index. For example, --seed demo --count 2 uses demo:0 and demo:1.

Guides

Examples

Development

pnpm install
pnpm lint
pnpm test
pnpm build
pnpm package:check
pnpm verify

Solver tables are versioned as generated binary assets. If cube coordinates, moves, or pruning logic change, regenerate and check them:

pnpm cube3:tables
pnpm cube3:tables:check