@vscubing/cubing
Version:
A collection of JavaScript cubing libraries.
1,636 lines (1,621 loc) • 211 kB
JavaScript
import {
DEGREES_PER_RADIAN,
FreshListenerManager,
HTMLElementShim,
HintFaceletProp,
ManagedCustomElement,
NO_VALUE,
RenderScheduler,
SimpleTwistyPropSource,
StaleDropper,
Twisty3DVantage,
TwistyPropDerived,
TwistyPropSource,
bulk3DCode,
cssStyleSheetShim,
customElementsShim,
hintFaceletStyles,
rawRenderPooled,
setCameraFromOrbitCoordinates,
setTwistyDebug
} from "../chunks/chunk-6WKNZNVA.js";
import {
countAnimatedLeaves,
countLeavesInExpansionForSimultaneousMoveIndexer,
countMetricMoves
} from "../chunks/chunk-AJYS6ZN4.js";
import {
puzzles
} from "../chunks/chunk-LYOTMOJT.js";
import {
PuzzleStickering,
StickeringManager,
cube3x3x3,
customPGPuzzleLoader,
getPartialAppendOptionsForPuzzleSpecificSimplifyOptions,
getPieceStickeringMask
} from "../chunks/chunk-SMJZNAUN.js";
import {
KPattern
} from "../chunks/chunk-TMCMUPQG.js";
import {
Alg,
AlgBuilder,
Conjugate,
Grouping,
LineComment,
Move,
Newline,
Pause,
TraversalDownUp,
TraversalUp,
direct,
directedGenerator,
endCharIndexKey,
experimentalAppendMove,
functionFromTraversal,
offsetMod,
startCharIndexKey
} from "../chunks/chunk-QVWFSWHJ.js";
// src/cubing/twisty/controllers/AnimationTypes.ts
function directionScalar(direction) {
return direction;
}
var BoundaryType = /* @__PURE__ */ ((BoundaryType2) => {
BoundaryType2["Move"] = "move";
BoundaryType2["EntireTimeline"] = "entire-timeline";
return BoundaryType2;
})(BoundaryType || {});
// src/cubing/twisty/controllers/indexer/AlgDuration.ts
function defaultDurationForAmount(amount) {
switch (Math.abs(amount)) {
case 0:
return 0;
case 1:
return 1e3;
case 2:
return 1500;
default:
return 2e3;
}
}
var AlgDuration = class extends TraversalUp {
// TODO: Pass durationForAmount as Down type instead?
constructor(durationForAmount = defaultDurationForAmount) {
super();
this.durationForAmount = durationForAmount;
}
traverseAlg(alg) {
let total = 0;
for (const algNode of alg.childAlgNodes()) {
total += this.traverseAlgNode(algNode);
}
return total;
}
traverseGrouping(grouping) {
return grouping.amount * this.traverseAlg(grouping.alg);
}
traverseMove(move) {
return this.durationForAmount(move.amount);
}
traverseCommutator(commutator) {
return 2 * (this.traverseAlg(commutator.A) + this.traverseAlg(commutator.B));
}
traverseConjugate(conjugate) {
return 2 * this.traverseAlg(conjugate.A) + this.traverseAlg(conjugate.B);
}
traversePause(_pause) {
return this.durationForAmount(1);
}
traverseNewline(_newline) {
return this.durationForAmount(1);
}
traverseLineComment(_comment) {
return this.durationForAmount(0);
}
};
// src/cubing/twisty/controllers/indexer/SimpleAlgIndexer.ts
var SimpleAlgIndexer = class {
constructor(kpuzzle, alg) {
this.kpuzzle = kpuzzle;
this.moves = new Alg(alg.experimentalExpand());
}
moves;
// TODO: Allow custom `durationFn`.
durationFn = new AlgDuration(
defaultDurationForAmount
);
getAnimLeaf(index) {
return Array.from(this.moves.childAlgNodes())[index];
}
indexToMoveStartTimestamp(index) {
const alg = new Alg(Array.from(this.moves.childAlgNodes()).slice(0, index));
return this.durationFn.traverseAlg(alg);
}
timestampToIndex(timestamp) {
let cumulativeTime = 0;
let i;
for (i = 0; i < this.numAnimatedLeaves(); i++) {
cumulativeTime += this.durationFn.traverseMove(this.getAnimLeaf(i));
if (cumulativeTime >= timestamp) {
return i;
}
}
return i;
}
patternAtIndex(index) {
return this.kpuzzle.defaultPattern().applyTransformation(this.transformationAtIndex(index));
}
transformationAtIndex(index) {
let pattern = this.kpuzzle.identityTransformation();
for (const move of Array.from(this.moves.childAlgNodes()).slice(0, index)) {
pattern = pattern.applyMove(move);
}
return pattern;
}
algDuration() {
return this.durationFn.traverseAlg(this.moves);
}
numAnimatedLeaves() {
return countAnimatedLeaves(this.moves);
}
moveDuration(index) {
return this.durationFn.traverseMove(this.getAnimLeaf(index));
}
};
// src/cubing/twisty/controllers/indexer/tree/AlgWalker.ts
var AlgWalkerDecoration = class {
constructor(moveCount, duration, forward, backward, children = []) {
this.moveCount = moveCount;
this.duration = duration;
this.forward = forward;
this.backward = backward;
this.children = children;
}
};
var DecoratorConstructor = class extends TraversalUp {
constructor(kpuzzle) {
super();
this.kpuzzle = kpuzzle;
this.identity = kpuzzle.identityTransformation();
this.dummyLeaf = new AlgWalkerDecoration(
0,
0,
this.identity,
this.identity,
[]
);
}
identity;
dummyLeaf;
durationFn = new AlgDuration(
defaultDurationForAmount
);
cache = {};
traverseAlg(alg) {
let moveCount = 0;
let duration = 0;
let transformation = this.identity;
const child = [];
for (const algNode of alg.childAlgNodes()) {
const apd = this.traverseAlgNode(algNode);
moveCount += apd.moveCount;
duration += apd.duration;
if (transformation === this.identity) {
transformation = apd.forward;
} else {
transformation = transformation.applyTransformation(apd.forward);
}
child.push(apd);
}
return new AlgWalkerDecoration(
moveCount,
duration,
transformation,
transformation.invert(),
child
);
}
traverseGrouping(grouping) {
const dec = this.traverseAlg(grouping.alg);
return this.mult(dec, grouping.amount, [dec]);
}
traverseMove(move) {
const key = move.toString();
let r2 = this.cache[key];
if (r2) {
return r2;
}
const transformation = this.kpuzzle.moveToTransformation(move);
r2 = new AlgWalkerDecoration(
1,
this.durationFn.traverseAlgNode(move),
transformation,
transformation.invert()
);
this.cache[key] = r2;
return r2;
}
traverseCommutator(commutator) {
const decA = this.traverseAlg(commutator.A);
const decB = this.traverseAlg(commutator.B);
const AB = decA.forward.applyTransformation(decB.forward);
const ApBp = decA.backward.applyTransformation(decB.backward);
const ABApBp = AB.applyTransformation(ApBp);
const dec = new AlgWalkerDecoration(
2 * (decA.moveCount + decB.moveCount),
2 * (decA.duration + decB.duration),
ABApBp,
ABApBp.invert(),
[decA, decB]
);
return this.mult(dec, 1, [dec, decA, decB]);
}
traverseConjugate(conjugate) {
const decA = this.traverseAlg(conjugate.A);
const decB = this.traverseAlg(conjugate.B);
const AB = decA.forward.applyTransformation(decB.forward);
const ABAp = AB.applyTransformation(decA.backward);
const dec = new AlgWalkerDecoration(
2 * decA.moveCount + decB.moveCount,
2 * decA.duration + decB.duration,
ABAp,
ABAp.invert(),
[decA, decB]
);
return this.mult(dec, 1, [dec, decA, decB]);
}
traversePause(pause) {
if (pause.experimentalNISSGrouping) {
return this.dummyLeaf;
}
return new AlgWalkerDecoration(
1,
this.durationFn.traverseAlgNode(pause),
this.identity,
this.identity
);
}
traverseNewline(_newline) {
return this.dummyLeaf;
}
traverseLineComment(_comment) {
return this.dummyLeaf;
}
mult(apd, n, child) {
const absn = Math.abs(n);
const st = apd.forward.selfMultiply(n);
return new AlgWalkerDecoration(
apd.moveCount * absn,
apd.duration * absn,
st,
st.invert(),
child
);
}
};
var WalkerDown = class {
constructor(apd, back) {
this.apd = apd;
this.back = back;
}
};
var AlgWalker = class extends TraversalDownUp {
constructor(kpuzzle, algOrAlgNode, apd) {
super();
this.kpuzzle = kpuzzle;
this.algOrAlgNode = algOrAlgNode;
this.apd = apd;
this.i = -1;
this.dur = -1;
this.goalIndex = -1;
this.goalDuration = -1;
this.move = void 0;
this.back = false;
this.moveDuration = 0;
this.st = this.kpuzzle.identityTransformation();
this.root = new WalkerDown(this.apd, false);
}
move;
moveDuration;
back;
st;
root;
i;
dur;
goalIndex;
goalDuration;
moveByIndex(loc) {
if (this.i >= 0 && this.i === loc) {
return this.move !== void 0;
}
return this.dosearch(loc, Infinity);
}
moveByDuration(dur) {
if (this.dur >= 0 && this.dur < dur && this.dur + this.moveDuration >= dur) {
return this.move !== void 0;
}
return this.dosearch(Infinity, dur);
}
dosearch(loc, dur) {
this.goalIndex = loc;
this.goalDuration = dur;
this.i = 0;
this.dur = 0;
this.move = void 0;
this.moveDuration = 0;
this.back = false;
this.st = this.kpuzzle.identityTransformation();
const r2 = this.algOrAlgNode.is(Alg) ? this.traverseAlg(this.algOrAlgNode, this.root) : this.traverseAlgNode(this.algOrAlgNode, this.root);
return r2;
}
traverseAlg(alg, wd) {
if (!this.firstcheck(wd)) {
return false;
}
let i = wd.back ? alg.experimentalNumChildAlgNodes() - 1 : 0;
for (const algNode of directedGenerator(
alg.childAlgNodes(),
wd.back ? -1 /* Backwards */ : 1 /* Forwards */
)) {
if (this.traverseAlgNode(
algNode,
new WalkerDown(wd.apd.children[i], wd.back)
)) {
return true;
}
i += wd.back ? -1 : 1;
}
return false;
}
traverseGrouping(grouping, wd) {
if (!this.firstcheck(wd)) {
return false;
}
const back = this.domult(wd, grouping.amount);
return this.traverseAlg(
grouping.alg,
new WalkerDown(wd.apd.children[0], back)
);
}
traverseMove(move, wd) {
if (!this.firstcheck(wd)) {
return false;
}
this.move = move;
this.moveDuration = wd.apd.duration;
this.back = wd.back;
return true;
}
traverseCommutator(commutator, wd) {
if (!this.firstcheck(wd)) {
return false;
}
const back = this.domult(wd, 1);
if (back) {
return this.traverseAlg(
commutator.B,
new WalkerDown(wd.apd.children[2], !back)
) || this.traverseAlg(
commutator.A,
new WalkerDown(wd.apd.children[1], !back)
) || this.traverseAlg(
commutator.B,
new WalkerDown(wd.apd.children[2], back)
) || this.traverseAlg(commutator.A, new WalkerDown(wd.apd.children[1], back));
} else {
return this.traverseAlg(
commutator.A,
new WalkerDown(wd.apd.children[1], back)
) || this.traverseAlg(
commutator.B,
new WalkerDown(wd.apd.children[2], back)
) || this.traverseAlg(
commutator.A,
new WalkerDown(wd.apd.children[1], !back)
) || this.traverseAlg(
commutator.B,
new WalkerDown(wd.apd.children[2], !back)
);
}
}
traverseConjugate(conjugate, wd) {
if (!this.firstcheck(wd)) {
return false;
}
const back = this.domult(wd, 1);
if (back) {
return this.traverseAlg(
conjugate.A,
new WalkerDown(wd.apd.children[1], !back)
) || this.traverseAlg(
conjugate.B,
new WalkerDown(wd.apd.children[2], back)
) || this.traverseAlg(conjugate.A, new WalkerDown(wd.apd.children[1], back));
} else {
return this.traverseAlg(
conjugate.A,
new WalkerDown(wd.apd.children[1], back)
) || this.traverseAlg(
conjugate.B,
new WalkerDown(wd.apd.children[2], back)
) || this.traverseAlg(conjugate.A, new WalkerDown(wd.apd.children[1], !back));
}
}
traversePause(pause, wd) {
if (!this.firstcheck(wd)) {
return false;
}
this.move = pause;
this.moveDuration = wd.apd.duration;
this.back = wd.back;
return true;
}
traverseNewline(_newline, _wd) {
return false;
}
traverseLineComment(_lineComment, _wd) {
return false;
}
firstcheck(wd) {
if (wd.apd.moveCount + this.i <= this.goalIndex && wd.apd.duration + this.dur < this.goalDuration) {
return this.keepgoing(wd);
}
return true;
}
domult(wd, amount) {
let back = wd.back;
if (amount === 0) {
return back;
}
if (amount < 0) {
back = !back;
amount = -amount;
}
const base = wd.apd.children[0];
const full = Math.min(
Math.floor((this.goalIndex - this.i) / base.moveCount),
Math.ceil((this.goalDuration - this.dur) / base.duration - 1)
);
if (full > 0) {
this.keepgoing(new WalkerDown(base, back), full);
}
return back;
}
keepgoing(wd, mul = 1) {
this.i += mul * wd.apd.moveCount;
this.dur += mul * wd.apd.duration;
if (mul !== 1) {
if (wd.back) {
this.st = this.st.applyTransformation(
wd.apd.backward.selfMultiply(mul)
);
} else {
this.st = this.st.applyTransformation(wd.apd.forward.selfMultiply(mul));
}
} else {
if (wd.back) {
this.st = this.st.applyTransformation(wd.apd.backward);
} else {
this.st = this.st.applyTransformation(wd.apd.forward);
}
}
return false;
}
};
// src/cubing/twisty/controllers/indexer/tree/chunkAlgs.ts
var MIN_CHUNKING_THRESHOLD = 16;
function chunkifyAlg(alg, chunkMaxLength) {
const mainAlgBuilder = new AlgBuilder();
const chunkAlgBuilder = new AlgBuilder();
for (const algNode of alg.childAlgNodes()) {
chunkAlgBuilder.push(algNode);
if (chunkAlgBuilder.experimentalNumAlgNodes() >= chunkMaxLength) {
mainAlgBuilder.push(new Grouping(chunkAlgBuilder.toAlg()));
chunkAlgBuilder.reset();
}
}
mainAlgBuilder.push(new Grouping(chunkAlgBuilder.toAlg()));
return mainAlgBuilder.toAlg();
}
var ChunkAlgs = class extends TraversalUp {
traverseAlg(alg) {
const algLength = alg.experimentalNumChildAlgNodes();
if (algLength < MIN_CHUNKING_THRESHOLD) {
return alg;
}
return chunkifyAlg(alg, Math.ceil(Math.sqrt(algLength)));
}
traverseGrouping(grouping) {
return new Grouping(
this.traverseAlg(grouping.alg),
grouping.amount
// TODO
);
}
traverseMove(move) {
return move;
}
traverseCommutator(commutator) {
return new Conjugate(
this.traverseAlg(commutator.A),
this.traverseAlg(commutator.B)
);
}
traverseConjugate(conjugate) {
return new Conjugate(
this.traverseAlg(conjugate.A),
this.traverseAlg(conjugate.B)
);
}
traversePause(pause) {
return pause;
}
traverseNewline(newline) {
return newline;
}
traverseLineComment(comment) {
return comment;
}
};
var chunkAlgs = functionFromTraversal(ChunkAlgs);
// src/cubing/twisty/controllers/indexer/tree/TreeAlgIndexer.ts
var TreeAlgIndexer = class {
constructor(kpuzzle, alg) {
this.kpuzzle = kpuzzle;
const deccon = new DecoratorConstructor(this.kpuzzle);
const chunkedAlg = chunkAlgs(alg);
this.decoration = deccon.traverseAlg(chunkedAlg);
this.walker = new AlgWalker(this.kpuzzle, chunkedAlg, this.decoration);
}
decoration;
walker;
getAnimLeaf(index) {
if (this.walker.moveByIndex(index)) {
if (!this.walker.move) {
throw new Error("`this.walker.mv` missing");
}
const move = this.walker.move;
if (this.walker.back) {
return move.invert();
}
return move;
}
return null;
}
indexToMoveStartTimestamp(index) {
if (this.walker.moveByIndex(index) || this.walker.i === index) {
return this.walker.dur;
}
throw new Error(`Out of algorithm: index ${index}`);
}
indexToMovesInProgress(index) {
if (this.walker.moveByIndex(index) || this.walker.i === index) {
return this.walker.dur;
}
throw new Error(`Out of algorithm: index ${index}`);
}
patternAtIndex(index, startPattern) {
this.walker.moveByIndex(index);
return (startPattern ?? this.kpuzzle.defaultPattern()).applyTransformation(
this.walker.st
);
}
// TransformAtIndex does not reflect the start pattern; it only reflects
// the change from the start pattern to the current move index. If you
// want the actual pattern, use patternAtIndex.
transformationAtIndex(index) {
this.walker.moveByIndex(index);
return this.walker.st;
}
numAnimatedLeaves() {
return this.decoration.moveCount;
}
timestampToIndex(timestamp) {
this.walker.moveByDuration(timestamp);
return this.walker.i;
}
algDuration() {
return this.decoration.duration;
}
moveDuration(index) {
this.walker.moveByIndex(index);
return this.walker.moveDuration;
}
};
// src/cubing/twisty/model/props/viewer/BackViewProp.ts
var backViewLayouts = {
none: true,
// default
"side-by-side": true,
"top-right": true
};
var BackViewProp = class extends SimpleTwistyPropSource {
getDefaultValue() {
return "auto";
}
};
// src/cubing/twisty/patternChecker.ts
var getSolveAnalyzer = async (puzzleLoader) => {
const kpuzzle = await puzzleLoader.kpuzzle();
const IGNORED_PIECE_VALUE = 9999;
const ORIENTATION_ONLY_PIECE_VALUE = 9998;
function applyPuzzleStickering(pattern, flatPuzzleStickering) {
const newPatternData = {};
for (const orbitDefinition of kpuzzle.definition.orbits) {
const patternOrbit = pattern.patternData[orbitDefinition.orbitName];
const maskOrbit = flatPuzzleStickering[orbitDefinition.orbitName];
const newOrbitData = {
pieces: [],
orientation: [],
orientationMod: []
};
for (let i = 0; i < orbitDefinition.numPieces; i++) {
switch (maskOrbit[i]) {
case "PermuteNonPrimary" /* PermuteNonPrimary */:
// fallthrough
case "Regular" /* Regular */:
// fallthrough
case "Dim" /* Dim */: {
newOrbitData.pieces.push(patternOrbit.pieces[i]);
newOrbitData.orientation.push(patternOrbit.orientation[i]);
newOrbitData.orientationMod.push(
patternOrbit.orientationMod?.[i] ?? 0
);
break;
}
case "Ignored" /* Ignored */:
// fallthrough
case "Invisible" /* Invisible */: {
newOrbitData.pieces.push(IGNORED_PIECE_VALUE);
newOrbitData.orientation.push(0);
newOrbitData.orientationMod.push(1);
break;
}
case "IgnoreNonPrimary" /* IgnoreNonPrimary */:
// fallthrough
case "Ignoriented" /* Ignoriented */:
// fallthrough
case "OrientationWithoutPermutation" /* OrientationWithoutPermutation */:
// fallthrough
case "OrientationStickers" /* OrientationStickers */: {
newOrbitData.pieces.push(ORIENTATION_ONLY_PIECE_VALUE);
newOrbitData.orientation.push(patternOrbit.orientation[i]);
newOrbitData.orientationMod.push(
patternOrbit.orientationMod?.[i] ?? 0
);
break;
}
// case PieceStickering.Mystery: {
// newOrbitData.pieces.push(MYSTERY_PIECE_VALUE);
// newOrbitData.orientation.push(0);
// newOrbitData.orientationMod.push(1);
// break;
// }
default: {
throw new Error(
`Unrecognized \`PieceMaskAction\` value: ${maskOrbit[i]}`
);
}
}
}
newPatternData[orbitDefinition.orbitName] = newOrbitData;
}
return new KPattern(pattern.kpuzzle, newPatternData);
}
const cubeOrientations = [];
for (const moveToSetU of [
null,
new Move("x"),
new Move("x2"),
new Move("x'"),
new Move("z"),
new Move("z'")
]) {
for (const moveToSetF of [
null,
new Move("y"),
new Move("y2"),
new Move("y'")
]) {
const algBuilder = new AlgBuilder();
if (moveToSetU) {
algBuilder.push(moveToSetU);
}
if (moveToSetF) {
algBuilder.push(moveToSetF);
}
const algToNormalize = algBuilder.toAlg();
const inverseTransformation = kpuzzle.algToTransformation(algToNormalize);
cubeOrientations.push({
inverseTransformation,
algToNormalize
});
}
}
const orientedSolvedPattern = kpuzzle.defaultPattern();
class PatternChecker {
constructor(name, flatPuzzleStickering, orientationAnchor, obviates = []) {
this.name = name;
this.flatPuzzleStickering = flatPuzzleStickering;
this.orientationAnchor = orientationAnchor;
this.obviates = obviates;
for (const cubeOrientation of cubeOrientations) {
const orientedPattern = orientedSolvedPattern.applyTransformation(
cubeOrientation.inverseTransformation
);
const maskedPattern = applyPuzzleStickering(
orientedPattern,
flatPuzzleStickering
);
const { anchorPieceIndex, anchorOrientationIndex } = this.extractAnchorCoordinates(orientedPattern);
const byOrientation = this.solvedPatternsByAnchorCoordinates[anchorPieceIndex] ??= {};
byOrientation[anchorOrientationIndex] = maskedPattern;
}
}
solvedPatternsByAnchorCoordinates = {};
extractAnchorCoordinates(pattern) {
const orbitData = pattern.patternData[this.orientationAnchor.orbitName];
if ((orbitData.orientationMod?.[this.orientationAnchor.pieceIndex] ?? 0) !== 0) {
throw new Error("Unexpected partially known orientation");
}
return {
anchorPieceIndex: orbitData.pieces[this.orientationAnchor.pieceIndex],
anchorOrientationIndex: orbitData.orientation[this.orientationAnchor.pieceIndex]
};
}
check(candidateFull3x3x3Pattern) {
for (const cubeOrientation of cubeOrientations) {
const reorientedCandidate = candidateFull3x3x3Pattern.applyTransformation(
cubeOrientation.inverseTransformation
);
const candidateMasked = applyPuzzleStickering(
reorientedCandidate,
this.flatPuzzleStickering
);
const { anchorPieceIndex, anchorOrientationIndex } = this.extractAnchorCoordinates(reorientedCandidate);
const solvedPatternByDRF = this.solvedPatternsByAnchorCoordinates[anchorPieceIndex][anchorOrientationIndex];
if (candidateMasked.isIdentical(solvedPatternByDRF)) {
const { algToNormalize } = cubeOrientation;
return { isSolved: true, algToNormalize };
}
}
return { isSolved: false };
}
}
const R = "Regular" /* Regular */;
const I = "Ignored" /* Ignored */;
const F2L1 = [
{
EDGES: [I, I, I, I, R, R, R, R, R, I, I, I],
CORNERS: [I, I, I, I, R, I, I, I],
CENTERS: [I, R, R, R, R, R]
},
{ orbitName: "EDGES", pieceIndex: 4 }
];
const F2L2A = [
{
EDGES: [I, I, I, I, R, R, R, R, R, R, I, I],
CORNERS: [I, I, I, I, R, R, I, I],
CENTERS: [I, R, R, R, R, R]
},
{ orbitName: "EDGES", pieceIndex: 4 }
];
const F2L2O = [
{
EDGES: [I, I, I, I, R, R, R, R, R, I, I, R],
CORNERS: [I, I, I, I, R, I, R, I],
CENTERS: [I, R, R, R, R, R]
},
{ orbitName: "EDGES", pieceIndex: 4 }
];
const F2L3 = [
{
EDGES: [I, I, I, I, R, R, R, R, I, R, R, R],
CORNERS: [I, I, I, I, I, R, R, R],
CENTERS: [I, R, R, R, R, R]
},
{ orbitName: "EDGES", pieceIndex: 4 }
];
const FirstLayer = [
{
EDGES: [I, I, I, I, R, R, R, R, I, I, I, I],
CORNERS: [I, I, I, I, R, R, R, R],
CENTERS: [I, R, R, R, R, R]
},
{ orbitName: "EDGES", pieceIndex: 4 }
];
const Roux1L = [
{
EDGES: [I, I, I, I, I, I, I, R, I, R, I, R],
CORNERS: [I, I, I, I, I, R, R, I],
CENTERS: [I, R, I, I, I, I]
},
{ orbitName: "CORNERS", pieceIndex: 5 }
];
const Roux2 = [
{
EDGES: [I, I, I, I, I, R, I, R, R, R, R, R],
CORNERS: [I, I, I, I, R, R, R, R],
CENTERS: [I, R, I, R, I, I]
},
{ orbitName: "CORNERS", pieceIndex: 5 }
];
const patternCheckers = [];
async function addSimpleStep(stickering, orbitName, pieceIndex, name, obviates = []) {
patternCheckers.push(
new PatternChecker(
name ?? stickering,
Object.fromEntries(
(await cubeLikePuzzleStickering(puzzleLoader, stickering)).stickerings.entries()
),
{
orbitName,
pieceIndex
},
obviates
)
);
}
const LSLLStuff = ["OLL", "OCLL", "EOLL", "F2L", "CLS", "ELS"];
const XCrosses = [
"X-Cross",
"Double X-Cross (adjacent)",
"Double X-Cross (opposite)",
"Triple X-Cross",
"First Layer"
];
const RouxBlocks = ["Both Roux blocks", "1st Roux block"];
const CFOP_Stuff = [...XCrosses, ...LSLLStuff];
const XRoux = [...XCrosses, ...RouxBlocks];
await addSimpleStep("full", "EDGES", 4, "Solved");
await addSimpleStep("PLL", "EDGES", 4);
await addSimpleStep("L6E", "EDGES", 4);
await addSimpleStep("OLL", "EDGES", 4, void 0, [
"ELS",
"CLS",
"CLL",
"Solved",
"L6E"
]);
await addSimpleStep("OLL", "EDGES", 4);
await addSimpleStep("OCLL", "EDGES", 4);
await addSimpleStep("EOLL", "EDGES", 4);
await addSimpleStep("F2L", "EDGES", 4, void 0, ["CLS"]);
await addSimpleStep("CLS", "EDGES", 4, void 0, [
"OLL",
"OCLL",
"EOLL",
"F2L",
"Solved",
"L6E"
]);
await addSimpleStep("ELS", "EDGES", 4, void 0, [
"OLL",
"OCLL",
"EOLL",
"F2L"
]);
patternCheckers.push(new PatternChecker("Triple X-Cross", ...F2L3, XRoux));
patternCheckers.push(new PatternChecker("F2L Slot 3", ...F2L3, XRoux));
patternCheckers.push(
new PatternChecker("Double X-Cross (opposite)", ...F2L2O, XRoux)
);
patternCheckers.push(
new PatternChecker("Double X-Cross (adjacent)", ...F2L2A, XRoux)
);
patternCheckers.push(
new PatternChecker("F2L Slot 2 (adjacent)", ...F2L2A, XRoux)
);
patternCheckers.push(
new PatternChecker("F2L Slot 2 (opposite)", ...F2L2O, XRoux)
);
patternCheckers.push(new PatternChecker("X-Cross", ...F2L1, XRoux));
patternCheckers.push(new PatternChecker("First Layer", ...FirstLayer, XRoux));
patternCheckers.push(new PatternChecker("F2L Slot 1", ...F2L1, XRoux));
await addSimpleStep("2x2x3", "CORNERS", 6);
await addSimpleStep("CMLL", "CORNERS", 4, void 0, CFOP_Stuff);
patternCheckers.push(
new PatternChecker("Both Roux blocks", ...Roux2, [
...CFOP_Stuff,
"Solved",
"PLL"
])
);
patternCheckers.push(
new PatternChecker("1st Roux block", ...Roux1L, CFOP_Stuff)
);
await addSimpleStep("Cross", "EDGES", 4, void 0, XCrosses);
await addSimpleStep("2x2x2", "CORNERS", 6);
const obviated = /* @__PURE__ */ new Set();
let lastI = patternCheckers.length + 1;
return function multiCheck(pattern) {
for (const [i, patternChecker] of patternCheckers.entries()) {
if (i >= lastI) {
return null;
}
if (obviated.has(patternChecker.name)) {
continue;
}
const isSolvedInfo = patternChecker.check(pattern);
if (isSolvedInfo.isSolved) {
lastI = i;
obviated.add(patternChecker.name);
for (const newlyObviated of patternChecker.obviates) {
obviated.add(newlyObviated);
}
return patternChecker.name;
} else {
}
}
return null;
};
async function cubeLikePuzzleStickering(puzzleLoader2, stickering) {
const kpuzzle2 = await puzzleLoader2.kpuzzle();
const puzzleStickering = new PuzzleStickering(kpuzzle2);
const m = new StickeringManager(kpuzzle2);
const LL = () => m.move("U");
const orUD = () => m.or(m.moves(["U", "D"]));
const orLR = () => m.or(m.moves(["L", "R"]));
const M = () => m.not(orLR());
const F2L = () => m.not(LL());
const CENTERS = () => m.orbitPrefix("CENTER");
const CENTER = (faceMove) => m.and([m.move(faceMove), CENTERS()]);
const EDGES = () => m.orbitPrefix("EDGE");
const EDGE = (faceMoves) => m.and([m.and(m.moves(faceMoves)), EDGES()]);
const CORNERS = () => m.or([
m.orbitPrefix("CORNER"),
m.orbitPrefix("C4RNER"),
m.orbitPrefix("C5RNER")
]);
const L6E = () => m.or([M(), m.and([LL(), EDGES()])]);
const centerLL = () => m.and([LL(), CENTERS()]);
const edgeFR = () => m.and([m.and(m.moves(["F", "R"])), EDGES()]);
const cornerDFR = () => m.and([m.and(m.moves(["F", "R"])), CORNERS(), m.not(LL())]);
const slotFR = () => m.or([cornerDFR(), edgeFR()]);
function dimF2L() {
puzzleStickering.set(F2L(), "Dim" /* Dim */);
}
function setPLL() {
puzzleStickering.set(LL(), "PermuteNonPrimary" /* PermuteNonPrimary */);
puzzleStickering.set(centerLL(), "Dim" /* Dim */);
}
function setOLL() {
puzzleStickering.set(LL(), "IgnoreNonPrimary" /* IgnoreNonPrimary */);
puzzleStickering.set(centerLL(), "Regular" /* Regular */);
}
function dimOLL() {
puzzleStickering.set(LL(), "Ignoriented" /* Ignoriented */);
puzzleStickering.set(centerLL(), "Dim" /* Dim */);
}
switch (stickering) {
case "full":
break;
case "PLL": {
dimF2L();
setPLL();
break;
}
case "CLS": {
dimF2L();
puzzleStickering.set(cornerDFR(), "Regular" /* Regular */);
puzzleStickering.set(LL(), "Ignoriented" /* Ignoriented */);
puzzleStickering.set(m.and([LL(), CENTERS()]), "Dim" /* Dim */);
puzzleStickering.set(
m.and([LL(), CORNERS()]),
"IgnoreNonPrimary" /* IgnoreNonPrimary */
);
break;
}
case "OLL": {
dimF2L();
setOLL();
break;
}
case "EOLL": {
dimF2L();
setOLL();
puzzleStickering.set(m.and([LL(), CORNERS()]), "Ignored" /* Ignored */);
break;
}
case "COLL": {
dimF2L();
puzzleStickering.set(
m.and([LL(), EDGES()]),
"Ignoriented" /* Ignoriented */
);
puzzleStickering.set(m.and([LL(), CENTERS()]), "Dim" /* Dim */);
puzzleStickering.set(m.and([LL(), CORNERS()]), "Regular" /* Regular */);
break;
}
case "OCLL": {
dimF2L();
dimOLL();
puzzleStickering.set(
m.and([LL(), CORNERS()]),
"IgnoreNonPrimary" /* IgnoreNonPrimary */
);
break;
}
case "CPLL": {
dimF2L();
puzzleStickering.set(
m.and([CORNERS(), LL()]),
"PermuteNonPrimary" /* PermuteNonPrimary */
);
puzzleStickering.set(
m.and([m.not(CORNERS()), LL()]),
"Dim" /* Dim */
);
break;
}
case "CLL": {
dimF2L();
puzzleStickering.set(
m.not(m.and([CORNERS(), LL()])),
"Dim" /* Dim */
);
break;
}
case "EPLL": {
dimF2L();
puzzleStickering.set(LL(), "Dim" /* Dim */);
puzzleStickering.set(
m.and([LL(), EDGES()]),
"PermuteNonPrimary" /* PermuteNonPrimary */
);
break;
}
case "ELL": {
dimF2L();
puzzleStickering.set(LL(), "Dim" /* Dim */);
puzzleStickering.set(m.and([LL(), EDGES()]), "Regular" /* Regular */);
break;
}
case "ELS": {
dimF2L();
setOLL();
puzzleStickering.set(m.and([LL(), CORNERS()]), "Ignored" /* Ignored */);
puzzleStickering.set(edgeFR(), "Regular" /* Regular */);
puzzleStickering.set(cornerDFR(), "Ignored" /* Ignored */);
break;
}
case "LL": {
dimF2L();
break;
}
case "F2L": {
puzzleStickering.set(LL(), "Ignored" /* Ignored */);
break;
}
case "ZBLL": {
dimF2L();
puzzleStickering.set(LL(), "PermuteNonPrimary" /* PermuteNonPrimary */);
puzzleStickering.set(centerLL(), "Dim" /* Dim */);
puzzleStickering.set(m.and([LL(), CORNERS()]), "Regular" /* Regular */);
break;
}
case "ZBLS": {
dimF2L();
puzzleStickering.set(slotFR(), "Regular" /* Regular */);
setOLL();
puzzleStickering.set(m.and([LL(), CORNERS()]), "Ignored" /* Ignored */);
break;
}
case "VLS": {
dimF2L();
puzzleStickering.set(slotFR(), "Regular" /* Regular */);
setOLL();
break;
}
case "WVLS": {
dimF2L();
puzzleStickering.set(slotFR(), "Regular" /* Regular */);
puzzleStickering.set(
m.and([LL(), EDGES()]),
"Ignoriented" /* Ignoriented */
);
puzzleStickering.set(m.and([LL(), CENTERS()]), "Dim" /* Dim */);
puzzleStickering.set(
m.and([LL(), CORNERS()]),
"IgnoreNonPrimary" /* IgnoreNonPrimary */
);
break;
}
case "LS": {
dimF2L();
puzzleStickering.set(slotFR(), "Regular" /* Regular */);
puzzleStickering.set(LL(), "Ignored" /* Ignored */);
puzzleStickering.set(centerLL(), "Dim" /* Dim */);
break;
}
case "LSOLL": {
dimF2L();
setOLL();
puzzleStickering.set(slotFR(), "Regular" /* Regular */);
break;
}
case "LSOCLL": {
dimF2L();
dimOLL();
puzzleStickering.set(
m.and([LL(), CORNERS()]),
"IgnoreNonPrimary" /* IgnoreNonPrimary */
);
puzzleStickering.set(slotFR(), "Regular" /* Regular */);
break;
}
case "EO": {
puzzleStickering.set(CORNERS(), "Ignored" /* Ignored */);
puzzleStickering.set(
EDGES(),
"OrientationWithoutPermutation" /* OrientationWithoutPermutation */
);
break;
}
case "EOline": {
puzzleStickering.set(CORNERS(), "Ignored" /* Ignored */);
puzzleStickering.set(
EDGES(),
"OrientationWithoutPermutation" /* OrientationWithoutPermutation */
);
puzzleStickering.set(
m.and(m.moves(["D", "M"])),
"Regular" /* Regular */
);
break;
}
case "EOcross": {
puzzleStickering.set(
EDGES(),
"OrientationWithoutPermutation" /* OrientationWithoutPermutation */
);
puzzleStickering.set(m.move("D"), "Regular" /* Regular */);
puzzleStickering.set(CORNERS(), "Ignored" /* Ignored */);
break;
}
case "CMLL": {
puzzleStickering.set(F2L(), "Dim" /* Dim */);
puzzleStickering.set(L6E(), "Ignored" /* Ignored */);
puzzleStickering.set(m.and([LL(), CORNERS()]), "Regular" /* Regular */);
break;
}
case "L10P": {
puzzleStickering.set(m.not(L6E()), "Dim" /* Dim */);
puzzleStickering.set(m.and([CORNERS(), LL()]), "Regular" /* Regular */);
break;
}
case "L6E": {
puzzleStickering.set(m.not(L6E()), "Dim" /* Dim */);
break;
}
case "L6EO": {
puzzleStickering.set(m.not(L6E()), "Dim" /* Dim */);
puzzleStickering.set(
L6E(),
"ExperimentalOrientationWithoutPermutation2" /* ExperimentalOrientationWithoutPermutation2 */
);
puzzleStickering.set(
m.and([CENTERS(), orUD()]),
"ExperimentalOrientationWithoutPermutation2" /* ExperimentalOrientationWithoutPermutation2 */
);
puzzleStickering.set(
m.and([m.move("M"), m.move("E")]),
"Ignored" /* Ignored */
);
break;
}
case "Daisy": {
puzzleStickering.set(m.all(), "Ignored" /* Ignored */);
puzzleStickering.set(CENTERS(), "Dim" /* Dim */);
puzzleStickering.set(
m.and([m.move("D"), CENTERS()]),
"Regular" /* Regular */
);
puzzleStickering.set(
m.and([m.move("U"), EDGES()]),
"IgnoreNonPrimary" /* IgnoreNonPrimary */
);
break;
}
case "Cross": {
puzzleStickering.set(m.all(), "Ignored" /* Ignored */);
puzzleStickering.set(CENTERS(), "Dim" /* Dim */);
puzzleStickering.set(
m.and([m.move("D"), CENTERS()]),
"Regular" /* Regular */
);
puzzleStickering.set(
m.and([m.move("D"), EDGES()]),
"Regular" /* Regular */
);
break;
}
case "2x2x2": {
puzzleStickering.set(
m.or(m.moves(["U", "F", "R"])),
"Ignored" /* Ignored */
);
puzzleStickering.set(
m.and([m.or(m.moves(["U", "F", "R"])), CENTERS()]),
"Dim" /* Dim */
);
break;
}
case "2x2x3": {
puzzleStickering.set(m.all(), "Dim" /* Dim */);
puzzleStickering.set(
m.or(m.moves(["U", "F", "R"])),
"Ignored" /* Ignored */
);
puzzleStickering.set(
m.and([m.or(m.moves(["U", "F", "R"])), CENTERS()]),
"Dim" /* Dim */
);
puzzleStickering.set(
m.and([m.move("F"), m.not(m.or(m.moves(["U", "R"])))]),
"Regular" /* Regular */
);
break;
}
case "G1": {
puzzleStickering.set(
m.all(),
"ExperimentalOrientationWithoutPermutation2" /* ExperimentalOrientationWithoutPermutation2 */
);
puzzleStickering.set(
m.or(m.moves(["E"])),
"OrientationWithoutPermutation" /* OrientationWithoutPermutation */
);
puzzleStickering.set(
m.and(m.moves(["E", "S"])),
"Ignored" /* Ignored */
);
break;
}
case "L2C": {
puzzleStickering.set(
m.or(m.moves(["L", "R", "B", "D"])),
"Dim" /* Dim */
);
puzzleStickering.set(m.not(CENTERS()), "Ignored" /* Ignored */);
break;
}
case "PBL": {
puzzleStickering.set(m.all(), "Ignored" /* Ignored */);
puzzleStickering.set(
m.or(m.moves(["U", "D"])),
"PermuteNonPrimary" /* PermuteNonPrimary */
);
break;
}
case "FirstBlock": {
puzzleStickering.set(
m.not(m.and([m.and(m.moves(["L"])), m.not(LL())])),
"Ignored" /* Ignored */
);
puzzleStickering.set(CENTER("R"), "Dim" /* Dim */);
break;
}
case "SecondBlock": {
puzzleStickering.set(
m.not(m.and([m.and(m.moves(["L"])), m.not(LL())])),
"Ignored" /* Ignored */
);
puzzleStickering.set(
m.and([m.and(m.moves(["L"])), m.not(LL())]),
"Dim" /* Dim */
);
puzzleStickering.set(
m.and([m.and(m.moves(["R"])), m.not(LL())]),
"Regular" /* Regular */
);
break;
}
case "EODF": {
dimF2L();
puzzleStickering.set(
m.or([cornerDFR(), m.and([LL(), CORNERS()])]),
"Ignored" /* Ignored */
);
puzzleStickering.set(
m.or([m.and([LL(), EDGES()]), edgeFR()]),
"OrientationWithoutPermutation" /* OrientationWithoutPermutation */
);
puzzleStickering.set(EDGE(["D", "F"]), "Regular" /* Regular */);
puzzleStickering.set(CENTER("F"), "Regular" /* Regular */);
break;
}
case "Void Cube": {
puzzleStickering.set(CENTERS(), "Invisible" /* Invisible */);
break;
}
case "picture":
// fallthrough
case "invisible": {
puzzleStickering.set(m.all(), "Invisible" /* Invisible */);
break;
}
case "centers-only": {
puzzleStickering.set(m.not(CENTERS()), "Ignored" /* Ignored */);
break;
}
case "opposite-centers": {
puzzleStickering.set(
m.not(m.and([CENTERS(), m.or(m.moves(["U", "D"]))])),
"Ignored" /* Ignored */
);
break;
}
default:
console.warn(
`Unsupported stickering for ${puzzleLoader2.id}: ${stickering}. Setting all pieces to dim.`
);
puzzleStickering.set(m.and(m.moves([])), "Dim" /* Dim */);
}
return puzzleStickering;
}
};
// src/cubing/twisty/views/2D/TwistyAnimatedSVG.ts
var xmlns = "http://www.w3.org/2000/svg";
var DATA_COPY_ID_ATTRIBUTE = "data-copy-id";
var svgCounter = 0;
function nextSVGID() {
svgCounter += 1;
return `svg${svgCounter.toString()}`;
}
var colorMaps = {
dim: {
white: "#dddddd",
orange: "#884400",
limegreen: "#008800",
red: "#660000",
"rgb(34, 102, 255)": "#000088",
// TODO
yellow: "#888800",
"rgb(102, 0, 153)": "rgb(50, 0, 76)",
purple: "#3f003f"
},
oriented: "#44ddcc",
ignored: "#555555",
invisible: "#00000000"
};
var TwistyAnimatedSVG = class {
constructor(kpuzzle, svgSource, experimentalStickeringMask, showUnknownOrientations = false) {
this.kpuzzle = kpuzzle;
this.showUnknownOrientations = showUnknownOrientations;
if (!svgSource) {
throw new Error(`No SVG definition for puzzle type: ${kpuzzle.name()}`);
}
this.svgID = nextSVGID();
this.wrapperElement = document.createElement("div");
this.wrapperElement.classList.add("svg-wrapper");
this.wrapperElement.innerHTML = svgSource;
const svgElem = this.wrapperElement.querySelector("svg");
if (!svgElem) {
throw new Error("Could not get SVG element");
}
this.svgElement = svgElem;
if (xmlns !== svgElem.namespaceURI) {
throw new Error("Unexpected XML namespace");
}
svgElem.style.maxWidth = "100%";
svgElem.style.maxHeight = "100%";
this.gradientDefs = document.createElementNS(xmlns, "defs");
svgElem.insertBefore(this.gradientDefs, svgElem.firstChild);
for (const orbitDefinition of kpuzzle.definition.orbits) {
for (let idx = 0; idx < orbitDefinition.numPieces; idx++) {
for (let orientation = 0; orientation < orbitDefinition.numOrientations; orientation++) {
const id = this.elementID(
orbitDefinition.orbitName,
idx,
orientation
);
const elem = this.elementByID(id);
let originalColor = elem?.style.fill;
if (experimentalStickeringMask) {
(() => {
const a = experimentalStickeringMask.orbits;
if (!a) {
return;
}
const orbitStickeringMask = a[orbitDefinition.orbitName];
if (!orbitStickeringMask) {
return;
}
const pieceStickeringMask = orbitStickeringMask.pieces[idx];
if (!pieceStickeringMask) {
return;
}
const faceletStickeringMasks = pieceStickeringMask.facelets[orientation];
if (!faceletStickeringMasks) {
return;
}
const stickeringMask = typeof faceletStickeringMasks === "string" ? faceletStickeringMasks : faceletStickeringMasks?.mask;
const colorMap = colorMaps[stickeringMask];
if (typeof colorMap === "string") {
originalColor = colorMap;
} else if (colorMap) {
originalColor = colorMap[originalColor];
}
})();
} else {
originalColor = elem?.style.fill;
}
this.originalColors[id] = originalColor;
this.gradients[id] = this.newGradient(id, originalColor);
this.gradientDefs.appendChild(this.gradients[id]);
elem?.setAttribute("style", `fill: url(#grad-${this.svgID}-${id})`);
}
}
}
for (const hintElem of Array.from(
svgElem.querySelectorAll(`[${DATA_COPY_ID_ATTRIBUTE}]`)
)) {
const id = hintElem.getAttribute(DATA_COPY_ID_ATTRIBUTE);
hintElem.setAttribute("style", `fill: url(#grad-${this.svgID}-${id})`);
}
if (this.showUnknownOrientations) {
this.drawPattern(this.kpuzzle.defaultPattern());
}
}
wrapperElement;
svgElement;
gradientDefs;
originalColors = {};
gradients = {};
svgID;
drawPattern(pattern, nextPattern, fraction) {
this.draw(pattern, nextPattern, fraction);
}
// TODO: save definition in the constructor?
draw(pattern, nextPattern, fraction) {
const nextTransformation = nextPattern?.experimentalToTransformation();
if (!pattern) {
throw new Error("Distinguishable pieces are not handled for SVG yet!");
}
for (const orbitDefinition of pattern.kpuzzle.definition.orbits) {
const currentPatternOrbit = pattern.patternData[orbitDefinition.orbitName];
const nextTransformationOrbit = nextTransformation ? nextTransformation.transformationData[orbitDefinition.orbitName] : null;
for (let idx = 0; idx < orbitDefinition.numPieces; idx++) {
for (let orientation = 0; orientation < orbitDefinition.numOrientations; orientation++) {
const id = this.elementID(
orbitDefinition.orbitName,
idx,
orientation
);
const fromCur = this.elementID(
orbitDefinition.orbitName,
currentPatternOrbit.pieces[idx],
(orbitDefinition.numOrientations - currentPatternOrbit.orientation[idx] + orientation) % orbitDefinition.numOrientations
);
let singleColor = false;
if (nextTransformationOrbit) {
const fromNext = this.elementID(
orbitDefinition.orbitName,
nextTransformationOrbit.permutation[idx],
(orbitDefinition.numOrientations - nextTransformationOrbit.orientationDelta[idx] + orientation) % orbitDefinition.numOrientations
);
if (fromCur === fromNext) {
singleColor = true;
}
fraction = fraction || 0;
const easedBackwardsPercent = 100 * (1 - fraction * fraction * (2 - fraction * fraction));
this.gradients[id].children[0].setAttribute(
"stop-color",
this.originalColors[fromCur]
);
this.gradients[id].children[0].setAttribute(
"offset",
`${Math.max(easedBackwardsPercent - 5, 0)}%`
);
this.gradients[id].children[1].setAttribute(
"offset",
`${Math.max(easedBackwardsPercent - 5, 0)}%`
);
this.gradients[id].children[2].setAttribute(
"offset",
`${easedBackwardsPercent}%`
);
this.gradients[id].children[3].setAttribute(
"offset",
`${easedBackwardsPercent}%`
);
this.gradients[id].children[3].setAttribute(
"stop-color",
this.originalColors[fromNext]
);
} else {
singleColor = true;
}
if (singleColor) {
if (this.showUnknownOrientations && currentPatternOrbit.orientationMod?.[idx] === 1) {
this.gradients[id].children[0].setAttribute("stop-color", "#000");
this.gradients[id].children[0].setAttribute("offset", "5%");
this.gradients[id].children[1].setAttribute("offset", "5%");
this.gradients[id].children[2].setAttribute("offset", "20%");
this.gradients[id].children[3].setAttribute("offset", "20%");
this.gradients[id].children[3].setAttribute(
"stop-color",
this.originalColors[fromCur]
);
} else {
this.gradients[id].children[0].setAttribute(
"stop-color",
this.originalColors[fromCur]
);
this.gradients[id].children[0].setAttribute("offset", "100%");
this.gradients[id].children[1].setAttribute("offset", "100%");
this.gradients[id].children[2].setAttribute("offset", "100%");
this.gradients[id].children[3].setAttribute("offset", "100%");
}
}
}
}
}
}
newGradient(id, originalColor) {
const grad = document.createElementNS(
xmlns,
"radialGradient"
);
grad.setAttribute("id", `grad-${this.svgID}-${id}`);
grad.setAttribute("r", "70.7107%");
const stopDefs = [
{ offset: 0, color: originalColor },
{ offset: 0, color: "black" },
{ offset: 0, color: "black" },
{ offset: 0, color: originalColor }
];
for (const stopDef of stopDefs) {
const stop = document.createElementNS(xmlns, "stop");
stop.setAttribute("offset", `${stopDef.offset}%`);
stop.setAttribute("stop-color", stopDef.color);
stop.setAttribute("stop-opacity", "1");
grad.appendChild(stop);
}
return grad;
}
elementID(orbitName, idx, orientation) {
return `${orbitName}-l${idx}-o${orientation}`;
}
elementByID(id) {
return this.wrapperElement.querySelector(`#${id}`);
}
};
// src/cubing/twisty/views/document.ts
var globalSafeDocument = typeof document === "undefined" ? null : document;
// src/cubing/twisty/views/control-panel/TwistyScrubber.css.ts
var twistyScrubberCSS = new cssStyleSheetShim();
twistyScrubberCSS.replaceSync(
`
:host {
width: 384px;
height: 16px;
display: grid;
}
.wrapper {
width: 100%;
height: 100%;
display: grid;
overflow: hidden;
backdrop-filter: blur(4px);
-webkit-backdrop-filter: blur(4px);
background: rgba(196, 196, 196, 0.75);
}
input:not(:disabled) {
cursor: ew-resize;
}
.wrapper.dark-mode {
background: #666666;
}
`
);
// src/cubing/twisty/views/control-panel/TwistyScrubber.ts
var SLOW_DOWN_SCRUBBING = false;
var isMouseDown = false;
globalSafeDocument?.addEventListener(
"mousedown",
(event) => {
if (event.which) {
isMouseDown