An Android port (with added features) of Josef Jelinek's AnimCube Java Web applet.
| Animating moves towards a solution | Touch interactions |
|---|---|
![]() |
![]() |
Add the cube to your view hierarchy:
<com.catalinjurjiu.animcubeandroid.AnimCube
android:id="@+id/animcube"
android:layout_width="match_parent"
android:layout_height="match_parent"
cube:backFacesDistance="4"/>
And you'll get:
| No back faces | With back faces |
|---|---|
![]() |
![]() |
To start an animation, first you need to define the move sequence. This can be either either through XML:
<com.catalinjurjiu.animcubeandroid.AnimCube
android:id="@+id/animcube"
android:layout_width="match_parent"
android:layout_height="match_parent"
cube:backFacesDistance="4"
cube:moves="R2' U M U' R2' U M' U'"/>
Or from code:
AnimCube animCube = findViewById(R.id.animcube);
animCube.setMoveSequence("R2' U M U' R2' U M' U'");
Then, tell the cube to perform the specified moves:
animCube.animateMoveSequence();
//or animate it in reverse, from the end and with opposite twisting direction
animCube.animateMoveSequenceReversed();
Or you can animate only one move at a time:
animCube.animateMove();
//or in reverse
animCube.animateMoveReversed();
To stop an animation prematurely, use stopAnimation:
animCube.stopAnimation();
As a side effect, stopAnimation instantly the applies the move it interrupted.
You can also just apply a move sequence, or an individual move, without an animation:
animCube.applyMoveSequence();
//individual move
animCube.applyMove();
Both apply methods also have reverse equivalents.
If the default colors don't play nicely with your theme's color palette, or if you just don't fancy them, custom ones can be specified through XML.
To do so, just define your 6 custom colors as a XML color array, in arrays.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<array name="custom_cube_colors">
<item>#ce3232</item>
<item>#ffa239</item>
<item>#737581</item>
<item>#e7dc00</item>
<item>#01641c</item>
<item>#141291</item>
</array>
</resources>
Then apply them on the cube through XML:
<com.catalinjurjiu.animcubeandroid.AnimCube
android:id="@+id/animcube"
android:layout_width="match_parent"
android:layout_height="match_parent"
cube:backFacesDistance="4"
cube:backgroundColor="#3A393A"
cube:cubeColors="@array/custom_cube_colors"
cube:faceletsContourColor="#ffffff"/>
As it can be seen, the background color & the contour of the facelets can also be customized. This yields:

When a configuration change occurs, the cube knows how to save its state, but it needs to be told to do so. This will likely be change to happen automatically in the future.

For now however, ensuring the cube saves its state is relatively simple. Just add the following to your Activity/Fragment:
public class MainActivity extends Activity {
public static final String ANIM_CUBE_SAVE_STATE_BUNDLE_ID = "animCube";
private AnimCube animCube;
...
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBundle(ANIM_CUBE_SAVE_STATE_BUNDLE_ID, animCube.saveState());
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
animCube.restoreState(savedInstanceState.getBundle(ANIM_CUBE_SAVE_STATE_BUNDLE_ID));
}
}
To be notified whenever an animation is finished, you can register an OnCubeAnimationFinishedListener. This makes AnimCube call onAnimationFinished every time a call to animate, or apply for one or move moves has finished making its changes.
Note: When animating/applying a move sequence (i.e. not individual moves) onAnimationFinished is only called when the end of the move sequence is reached, or when stopAnimation is called. It is not called for every move in the sequence.
All the animate/apply calls change the underlying cube model. Additionally, this can also happen when the cube is editable and the user manually twists a layer.
To be notified when the cube model is changed, use an OnCubeModelUpdatedListener. This also allows you to be notified when each move is applied, when animating a move sequence, since the OnCubeAnimationFinishedListener is only notified when the whole sequence has finished animating.
Note: The set OnCubeModelUpdatedListener is also notified for each move in a move sequence, when it is applied with AnimCube#applyMoveSequence & AnimCube#applyMoveSequenceReversed. This happens because, although to the user the whole move sequence seems to be applied instantly, internally the moves are applied one by one, and rendering occurrs only at the end.
TL;DR: Always use AnimCube.java, only use AnimCubeDebuggable.java when you need detailed logs to file an issue.
Long version:
Currently the library contains two classes: AnimCube.java & AnimCubeDebug.java. In terms of behavior they are equivalent, and generally you should only ever use AnimCube.java. Strictly speaking though, when it comes to the debug mode, their behavior differs.
When debug mode is on, AnimCube.java prints some warnings, if they happen. With debug mode off, the warnings are omitted and nothing else happens.
On the other hand, AnimCubeDebug.java prints a plethora of debug & info messages to LogCat when debug mode is on, and prints nothing when it's off.
The decision to have two different classes was not an easy one. Internally, both classes rely on utility methods to decide whether to print a certain message or not. However, even if in the end logging to logcat doesn't happen, the string message is still allocated. An alternative would've been to check the condition before allocating the string, but then the code itself would be polluted with tons of conditional checks.
By removing all debug & info logs from AnimCube.java, memory is not polluted with strings that never get printed when debug mode is off. Yet, all the debug messages can still be obtained if AnimCube is swapped with AnimCubeDebug when attempting to reproduce an issue.
To turn debug mode on from code, use AnimCube#setDebuggable(boolean). To enable it from XML, use the debuggable attribute:
<com.catalinjurjiu.animcubeandroid.AnimCube
android:id="@+id/animcube"
android:layout_width="match_parent"
android:layout_height="match_parent"
cube:debuggable="true"/>
By default, debug mode is disabled.
Many of the original parameters have been kept with equivalent behavior. However, certain names were changed.
This section describes just the configuration params supported by AnimCube-Android, however if you are interested in an actual changelog between the list of parameters provided by the original and this version, see the Changelog from original AnimCube.
Parameters list: * backgroundColor * cubeColors * faceletContourColor * initialState * moves * editable * backFacesDistance * touchSensitivity * initialRotation * perspective * scale * singleRotationSpeed * doubleRotationSpeed * verticalAlign * debuggable
Specifies the background color of the cube view.
Specifies 6 custom colors to be used by the cube, instead of the default colors. Must be an array defined in XML.
Specifies the color of the region between cube facelets.
Specifies the initial state of the cube. Needs to contain an array of exactly 54 color indexes. Valid indexes are in the range [0,5], with each index corresponding to the following default color: * 0 - White * 1 - Yellow * 2 - Orange * 3 - Red * 4 - Blue * 5 - Green
If custom colors are defined, then the indexes will map on the array of custom colors. For example, if in a custom color scheme Black replaces White, then the index 0 would map to Black.
Example value of initialState for a solved cube:
cube:initialState="000000000111111111222222222333333333444444444555555555"
By default, the cube is in the state mentioned above as example.
Sets the sequence of moves that need to be performed (and optionally, animated). Some of the moves affect centers and they can be moved to another layer from the user's point of view. Such movements do not affect the notation from the user's point of view. The characters are not fixed to particular centers.
For example, if an "M" is performed and then an "F" is needed, it should affect the front layer seen in the front position and not the bottom layer, where the center that was in the front position is now placed. The chosen way is very familiar to the "corner-starters" (solving the cube starting from the corners).
The sequence is defined in extended Singmaster's notation. The basis for the turns are six letters of the following meaning.
The letter case is important here, because the same - but lowercase - letters are used for different moves. Modifiers can be appended to the move character.
There are also some advanced modifiers that are written immediately after the move letter and right before the basic modifiers already defined. The possible modifiers are:
The library supports some additional characters to represent specific moves. The center layers can be rotated using the following characters in combination with previous modifiers.
The library also supports turns of the entire cube. This feature can be used to rotate the cube in order to show the cube in the best position for the current situation to watch the move sequence. The available symbols to rotate the cube are shown in the following table (they can be also combined with the modifiers).
There is also a possibility to rotate two adjacent layers simultaneously. The notation and meaning is similar to the fac
$ claude mcp add AnimCubeAndroid \
-- python -m otcore.mcp_server <graph>