To see TwistySim in action, check out this demonstrator app.
Download the latest version here:
This software is licensed under the Creative Commons Attribution-ShareAlike 4.0 International License (CC BY-SA 4.0).
For commercial use, a separate commercial license agreement is required. Please refer to the TwistySim Commercial Licence Agreement 1.0 for details.
TwistySim JavaScript API
To use TwistySim in your web-page, simply include twistysim.js in a <script> tag, and generate the images using the API calls described below. Here is a complete example:
<html>
<head>
<script type="text/javascript" src="twistysim.js"></script>
</head>
<body>
<div id="tp1"></div>
<script type="text/javascript">
TTk.TiwstyPuzzle(3)('#tp1');
</script>
</body>
</html>
TwistyPuzzle
This is the base puzzle rendering class. It is used by all other classes to render puzzle images. Use it directly to render static puzzle images.
Basic render into div with selector
TTk.TiwstyPuzzle(3)('#tp1');
Custom size and face definition
TTk.TwistyPuzzle(2)
.size({width:100, height:150})
.fc('wwwwrddrdbbddyyd')
('#tp2');
Manipulation of 3D transform
// Initialise
var cube = TTk.TwistyPuzzle('pyraminx');
// Adjust rendering context
cube.context().transform()
.pitch(1.4)
.yaw(0.2)
.scale(1.3);
// Render into div
cube('#tp3');
Manipulation of 3D projection
// Initialise
var cube = TTk.TwistyPuzzle('skewb');
// Adjust rendering context
cube.context().projection()
.focalFac(1.5);
// Render into div
cube('#tp4');
Application of algorithm
TTk.TwistyPuzzle(3)
.alg("M2 E2 S2")
('#tp5');
Random scramble
TTk.TwistyPuzzle('megaminx')
.scramble()
('#tp6');
InteractivePuzzle
A twisty puzzle visualisation that can be drag-rotated and manipulated with mouse clicks or keyboard strokes.
The InteractivePuzzle API supports the same functions as TwistyPuzzle, with added features related to interactivity.
Basic render into div with selector
drag to rotate, click to apply moves
Once focused, use enter to scramble and other keyboard keys to move
TTk.InteractivePuzzle(3)('#ip1');
Adjustment of animation speed
TTk.InteractivePuzzle('square1')
.movePeriod(300)
.scramblePeriod(1000)
('#ip2');
Toggling interaction features
var cube = TTk.InteractivePuzzle(4)
// Enable/disable scene rotation
.rotate(false);
cube.moveInteract()
// Set whether to use mouse clicks to move
.mouse(false)
// Set whether to use keystrokes to move
.keyboard(true);
// Render
cube('#ip3');
AlgorithmPuzzle
A twisty puzzle visualisation that plays a given algorithm, and can be drag-rotated.
Basic render with algorithm
TTk.AlgorithmPuzzle(3)
.alg("R U R' U R U2 R'")
('#ap1');
Render without controls
TTk.AlgorithmPuzzle(6)
.case("r u r' u r u2' r'")
.controls(false)
('#ap2');
Toggle other features
TTk.AlgorithmPuzzle('megaminx')
// Set the alg to apply
.case("R U R' U R U3 R'")
// Whether to display the algorithm
.showAlg(true)
// Whether to show buttons on hover
.hoverButtons(false)
// Whether to show alg on hover
.hoverAlg(false)
('#ap3');
Programmatic control
The algorithm puzzle can be controlled using the following JavaScript calls:
// Create and render the instance
var cube = TTk.AlgorithmPuzzle(3)
.alg("R U R' U R U2 R'")
('#ap4');
// Play from the beginning
cube.play();
// Pause if currently playing
cube.pause();
// Step forward in the sequence
cube.forward();
// Step back in the sequence
cube.back();
// Move to the end of the sequence
cube.end();
// Move to the start of the sequence
cube.rewind();
// Move to a specific point in the sequence
cube.moveTo(4);
ModalPuzzle
Any of the above twisty puzzle classes displayed in a full-screen modal box.
Modal for InteractivePuzzle
var c = TTk.InteractivePuzzle('skewb');
TTk.ModalPuzzle(c)('#mp1');
Modal from AlgorithmPuzzle
var s = TTk.AlgorithmPuzzle('square1')
.alg("U D' / U3 D3 / D6 / U3 D3 /");
TTk.ModalPuzzle(s)('#mp2');
Puzzle Definitions
TwistySim uses a twisty puzzle definition object to generate each puzzle type, allowing the system to simulate any twisty puzzle. Built in definitions are provided for all twisty puzzles used in WCA competitions. As an example, the definition for the Skewb puzzle has been provided below:
// The puzzle is defined as an object on the TTk.Puzzle namespace
TTk.Puzzle.SKEWB = {};
// 3D coordinates for the panels that make up the puzzle
// The puzzle is defined within a coordinate space ranging
// from -0.5 to 0.5 in all dimensions
TTk.Puzzle.SKEWB.panels = [
[[-.0, -.5, -.5], [-.5, -.0, -.5], [-.0, +.5, -.5], [+.5, -.0, -.5]],
[[-.0, -.5, -.5], [-.5, -.0, -.5], [-.5, -.5, -.5]],
[[-.5, +.0, -.5], [-.0, +.5, -.5], [-.5, +.5, -.5]],
[[+.0, +.5, -.5], [+.5, +.0, -.5], [+.5, +.5, -.5]],
[[+.5, -.0, -.5], [+.0, -.5, -.5], [+.5, -.5, -.5]],
[[-.0, -.5, +.5], [-.5, -.0, +.5], [-.0, +.5, +.5], [+.5, -.0, +.5]],
[[-.0, -.5, +.5], [-.5, -.0, +.5], [-.5, -.5, +.5]],
[[-.5, +.0, +.5], [-.0, +.5, +.5], [-.5, +.5, +.5]],
[[+.0, +.5, +.5], [+.5, +.0, +.5], [+.5, +.5, +.5]],
[[+.5, -.0, +.5], [+.0, -.5, +.5], [+.5, -.5, +.5]],
[[+.0, -.5, -.5], [+.5, -.5, -.0], [+.0, -.5, +.5], [-.5, -.5, +.0]],
[[+.0, -.5, -.5], [+.5, -.5, -.0], [+.5, -.5, -.5]],
[[+.0, -.5, +.5], [+.5, -.5, +.0], [+.5, -.5, +.5]],
[[-.0, -.5, -.5], [-.5, -.5, -.0], [-.5, -.5, -.5]],
[[-.0, -.5, +.5], [-.5, -.5, +.0], [-.5, -.5, +.5]],
[[+.0, +.5, -.5], [+.5, +.5, -.0], [+.0, +.5, +.5], [-.5, +.5, +.0]],
[[+.0, +.5, -.5], [+.5, +.5, -.0], [+.5, +.5, -.5]],
[[+.0, +.5, +.5], [+.5, +.5, +.0], [+.5, +.5, +.5]],
[[-.0, +.5, -.5], [-.5, +.5, -.0], [-.5, +.5, -.5]],
[[-.0, +.5, +.5], [-.5, +.5, +.0], [-.5, +.5, +.5]],
[[+.5, -.0, -.5], [+.5, +.5, -.0], [+.5, -.0, +.5], [+.5, -.5, +.0]],
[[+.5, -.0, -.5], [+.5, -.5, -.0], [+.5, -.5, -.5]],
[[+.5, -.5, +.0], [+.5, -.0, +.5], [+.5, -.5, +.5]],
[[+.5, +.0, +.5], [+.5, +.5, +.0], [+.5, +.5, +.5]],
[[+.5, +.5, -.0], [+.5, +.0, -.5], [+.5, +.5, -.5]],
[[-.5, -.0, -.5], [-.5, +.5, -.0], [-.5, -.0, +.5], [-.5, -.5, +.0]],
[[-.5, -.0, -.5], [-.5, -.5, -.0], [-.5, -.5, -.5]],
[[-.5, -.5, +.0], [-.5, -.0, +.5], [-.5, -.5, +.5]],
[[-.5, +.0, +.5], [-.5, +.5, +.0], [-.5, +.5, +.5]],
[[-.5, +.5, -.0], [-.5, +.0, -.5], [-.5, +.5, -.5]]
];
pnl = TTk.Puzzle.SKEWB.panels;
// Define unique faces, the face's plane is used to detect solved state
TTk.Puzzle.SKEWB.faces = {
U:pnl[0],
D:pnl[5],
F:pnl[10],
B:pnl[15],
R:pnl[20],
L:pnl[25]
};
// Define moves
TTk.Puzzle.SKEWB.moves = {
'L': {plane: [pnl[20][0], pnl[20][3], pnl[25][2], pnl[25][1]], angle:-120, type: T.ABOVE},
'R': {plane: [pnl[0][0], pnl[0][1], pnl[5][2], pnl[5][3]], angle:120, type: T.ABOVE},
'B': {plane: [pnl[0][3], pnl[0][0], pnl[5][2], pnl[5][1]], angle:120, type: T.ABOVE},
'U': {plane: [pnl[5][2], pnl[5][1], pnl[0][0], pnl[0][3]], angle:-120, type: T.ABOVE},
'r': {plane: [pnl[25][1], pnl[25][2], pnl[20][3], pnl[20][0]], angle:-120, type: T.ABOVE},
'l': {plane: [pnl[5][3], pnl[5][2], pnl[0][1], pnl[0][0]], angle:-120, type: T.ABOVE},
'b': {plane: [pnl[5][0], pnl[5][3], pnl[0][2], pnl[0][1]], angle:-120, type: T.ABOVE},
'f': {plane: [pnl[0][1], pnl[0][2], pnl[5][3], pnl[5][0]], angle:-120, type: T.ABOVE},
'y': {plane: [pnl[1][2], pnl[2][2], pnl[3][2], pnl[4][2]], angle:90, type: T.ROTATE},
'z': {plane: [pnl[16][2], pnl[17][2], pnl[18][2], pnl[19][2]], angle:90, type: T.ROTATE},
'x': {plane: [pnl[26][2], pnl[27][2], pnl[28][2], pnl[29][2]], angle:90, type: T.ROTATE}
};
// Panels to use for mouse-activated moves
TTk.Puzzle.SKEWB.panelMoves = {
'L' : [13, 1, 26],
'B' : [2, 29, 18],
'R' : [24, 16, 3],
'U' : [22, 12, 9],
'f' : [11, 21, 4],
'r' : [17, 8, 23],
'l' : [14, 6, 27],
'b' : [7, 28, 19],
};
// Move-keyboard bindings
TTk.Puzzle.SKEWB.keys = {
73: "R" ,
75: "R'" ,
87: "B" ,
79: "B'" ,
83: "D" ,
76: "D'" ,
68: "L" ,
69: "L'" ,
74: "U" ,
70: "U'" ,
72: "F" ,
71: "F'" ,
78: "F" ,
86: "F'" ,
67: "l",
82: "l'",
85: "r",
77: "r'",
84: "x" ,
89: "x" ,
66: "x'" ,
186:"y" ,
59: "y" ,
65: "y'" ,
80: "z" ,
81: "z'"
};
// Colours to use for facelets
TTk.Puzzle.SKEWB.palette = {
'y': '#E6D223', // Yellow
'r': '#7F0000', // Red
'o': '#DF622D', // Orange
'b': '#010080', // Blue
'g': '#008001', // Green
'w': '#FFFFFF' // White
};
// Colours to set on each facelet
TTk.Puzzle.SKEWB.fc = "yyyyywwwwwbbbbbgggggooooorrrrr";
// Initial rotation
TTk.Puzzle.SKEWB.rotation = { pitch:30, yaw:45 };