Alg is a class that encapsulates a structured alg. To create an Alg from a string, use:

new Alg("R U R'"); // Convenient
Alg.fromString(dynamicString); // Recommended when the string input is user-provided.

Once you have an Alg, you can call methods to transform it:

new Alg("[[R: U], R U R2']").expand().experimentalSimplify({cancel: true}).invert().log()

To convert an Alg to a string, use .toString():

new Alg("R U F").invert().toString();

If you need to debug, you may also find it convenient to use .log():

if (alg.isIdentical(alg.invert())) {
alg.log("A self-inverse!")

For more information, see:


  • AlgCommon<Alg>
    • Alg



#algNodes: Iterable<AlgNode>


  • get log(): ((message?) => void)
  • Returns ((message?) => void)

      • (message?): void
      • Parameters

        • Optional message: any

        Returns void


  • Type Parameters

    • T


    • c: (new (...args) => T)
        • new (...args): T
        • Parameters

          • Rest ...args: any

          Returns T

    Returns null | T

  • Expands all Grouping, Commutator, and Conjugate parts nested inside the alg.

    // F R U R' U' F'
    new Alg("[F: [R, U]]").expand().log();

    // F [R, U] F'
    new Alg("[F: [R, U]]").expand(({ depth: 1 }).log();

    Avoid calling this on a user-provided alg unless the user explicitly asks to see the expanded alg. Otherwise, it's easy to make your program freeze when someone passes in an alg like: (R U)10000000

    Generally, if you want to perform an operation on an entire alg, you'll want to use something based on the Traversal mechanism, like countMoves() from cubing/notation.


    • Optional options: {
          depth?: number;
      • Optional depth?: number

    Returns Alg

  • Parameters

    • iterDir: IterationDirection = IterationDirection.Forwards
    • Optional depth: number

    Returns Generator<AlgLeaf, any, unknown>


    Use Alg.expand instead.

  • experimentalSimplify can perform several mostly-syntactic simplifications on an alg:

    // Logs: R' U3
    import { Alg } from "cubing/alg";
    new Alg("R R2' U U2").experimentalSimplify({ cancel: true }).log()

    You can pass in a PuzzleLoader (currently only for 3x3x3) for puzzle-specific simplifications:

    // Logs: R' U'
    import { Alg } from "cubing/alg";
    import { cube3x3x3 } from "cubing/puzzles";
    new Alg("R R2' U U2").experimentalSimplify({ cancel: true, puzzleLoader: cube3x3x3 }).log()

    You can also cancel only moves that are in the same direction:

    // Logs: R R2' U'
    import { Alg } from "cubing/alg";
    import { cube3x3x3 } from "cubing/puzzles";
    new Alg("R R2' U U2").experimentalSimplify({
    cancel: { directional: "same-direction" },
    puzzleLoader: cube3x3x3

    Additionally, you can specify how moves are "wrapped":

    import { Alg } from "cubing/alg";
    import { cube3x3x3 } from "cubing/puzzles";

    function example(puzzleSpecificModWrap) {
    cancel: { puzzleSpecificModWrap },
    puzzleLoader: cube3x3x3

    const alg = new Alg("R7' . R6' . R5' . R6")
    example("none") // R7' . R6' . R5' . R6
    example("gravity") // R . R2' . R' . R2
    example("canonical-centered") // R . R2 . R' . R2
    example("canonical-positive") // R . R2 . R3 . R2
    example("preserve-sign") // R3' . R2' . R' . R2

    Same-axis and simultaneous move canonicalization is not implemented yet:

    // Logs: R L R
    import { Alg } from "cubing/alg";
    import { cube3x3x3 } from "cubing/puzzles";
    new Alg("R L R").experimentalSimplify({ cancel: true, puzzleLoader: cube3x3x3 }).log()


    Returns Alg

  • Returns the inverse of the given alg.

    Note that that this does not make any assumptions about what puzzle the alg is for. For example, U2 is its own inverse on a cube, but U2' has the same effect U3 (and not U2) on Megaminx:

    // Outputs: R U2' L'
    new Alg("L U2 R'").invert().log();

    Returns Alg

  • Checks whether this Alg is structurally identical to another Alg. This essentially means that they are written identically apart from whitespace.

    const alg1 = new Alg("R U L'");
    const alg2 = new Alg("L U' R'").invert();
    // true

    // false
    new Alg("[R, U]").isIdentical(new Alg("R U R' U'"));
    // true
    new Alg("[R, U]").expand().isIdentical(new Alg("R U R' U'"));

    Note that .isIdentical() efficiently compares algorithms, but mainly exists to help optimize code when the structure of an algorithm hasn't changed. There are many ways to write the "same" alg on most puzzles, but is highly recommended to avoid expanding two Alg instances to compare them, since that can easily slow your program to a crawl if someone inputs an alg containing a large repetition. In general, you should use cubing/kpuzzle to compare if two algs have the same effect on a puzzle.

    Also note that parser annotations are not taken into account while comparing algs:

    const alg = new Alg([new Move("R"), new Move("U2")]);
    // true, even though one of the algs has parser annotations
    alg.isIdentical(new Alg("R U2"))


    • other: Comparable

    Returns boolean

  • Converts the Alg to a string:

    const alg = new Alg([new Move("R"), new Move("U2"), new Move("L")])
    // R U2 L

    Returns string