Skip to content

Cube

A 3D-styled cube visualization composed of three visible sides (left, right, top), each divided into a grid of cells. Cells can “flash” (light up) over time according to configurable rules, making the component useful for status dashboards, activity indicators, or decorative effects. Optional axis lines can be shown for orientation.

  • Farbe (color utilities)

See the Example by Serhii Pimenov on CodePen.

Include the Metro build outputs (make sure you ran npm run dev or npm run build):

<link rel="stylesheet" href="./lib/metro.css">
<script src="./lib/metro.js"></script>
<div data-role="cube"></div>

By default, the cube uses built-in flashing rules and hides axis lines.

<div data-role="cube" data-show-axis="true" data-axis-style="arrow"></div>

Available axis styles: arrow (default), line, no-style.

<div data-role="cube" data-cells="5" data-numbers="true"></div>
  • data-cells controls the N×N grid for each side. Default is 4.
  • data-numbers renders cell numbers for development or demonstration.
<div
data-role="cube"
data-color="#222831"
data-flash-color="#00bcd4"
></div>
  • data-color sets the base cell background color.
  • data-flash-color sets the flashing (active) color.

Rules define which cells on which side turn on/off at each tick. Provide as JSON via data-rules or set programmatically. Each rule step can specify on and/or off per side (left, right, top) with arrays of 1-based cell ids.

<div
id="cube1"
data-role="cube"
data-rules='[
{ "on": { "top": [1,2], "left": [3], "right": [4] } },
{ "off": { "top": [2], "left": [3], "right": [4] },
"on": { "top": [5,6] } },
{ "on": { "left": [7,8], "right": [9] } }
]'
></div>

If data-rules is omitted, a built-in pattern (Metro.cubeDefaultRules) is used.

<div id="myCube"></div>
<script>
// Create the plugin
const el = Metro.makePlugin("#myCube", "cube", {
showAxis: true,
axisStyle: "line",
cells: 4,
numbers: false,
});
// Access the API
const cube = Metro.getPlugin("#myCube", "cube");
cube.toRule(2); // move to rule #2 (0-based index) and hold, then auto-restart if configured
</script>
ParameterTypeDefaultDescription
cubeDeferrednumber0Optional deferred initialization time (ms) handled by Metro’s core (common across components).
rulesobjectstringnull
colorstringnullnull
flashColorstringnullnull
flashIntervalnumber1000Interval in ms used as a base for ticks and rule step timing.
numbersbooleanfalseIf true, displays 1-based indices inside cells.
cellsnumber4Number of cells per side edge (N). Each side contains N×N cells.
showAxisbooleanfalseShow/hide axis guides over the cube.
axisStylestring”arrow”Axis rendering style: arrow, line, or no-style.
cellClickbooleanfalseIf true, clicking a cell toggles its light state.
autoRestartnumber5000After calling toRule(index, ...), automatically restart the autoplay after this timeout (ms). Use 0 or non-integer to disable.
clsCubestring""Extra class(es) for the root cube element.
clsCellstring""Extra class(es) added to each cell.
clsSidestring""Extra class(es) for every side.
clsSideLeftstring""Extra class(es) for the left side.
clsSideRightstring""Extra class(es) for the right side.
clsSideTopstring""Extra class(es) for the top side.
clsAxisstring""Extra class(es) for each axis element.
clsAxisXstring""Extra class(es) for X axis.
clsAxisYstring""Extra class(es) for Y axis.
clsAxisZstring""Extra class(es) for Z axis.
onTickfunctionMetro.noopCallback executed on every rule tick. Receives the tick index.
onCubeCreatefunctionMetro.noopCallback when cube is created (also emitted as cube-create event).

Notes:

  • The options clsSideLeftCell, clsSideRightCell, clsSideTopCell are present in defaults for potential styling, but are not applied in the current implementation.
<div
data-role="cube"
data-show-axis="true"
data-axis-style="line"
data-cells="6"
data-numbers="true"
data-color="#0f172a"
data-flash-color="#22d3ee"
></div>
EventDescription
cube-createFired when the cube structure and events are initialized.
tickFired on each rule step tick; includes { index } in event detail.
<div id="cube2" data-role="cube" data-on-cube-create="onCreated" data-on-tick="onTick"></div>
<script>
function onCreated(e) {
console.log("cube created", e.detail);
}
function onTick(e) {
console.log("tick", e.detail.index);
}
</script>
  • start() — Start/restart the flashing sequence from the beginning of the rules.
  • stop() — Stop any ongoing flashing and clear timers.
  • toRule(index, speed) — Show the cumulative result up to the rule at index (0-based). Optional speed overrides the default step timing for this call. If autoRestart is a positive integer, the autoplay restarts after that timeout.
  • rule() — Getter; returns the currently active rules object.
  • rule(rules) — Setter; accepts object or JSON string rules, applies them, and restarts the sequence.
  • axis(show) — Show/hide axis programmatically (true to show, false to hide).
  • changeRules() — Re-read data-rules from the element, apply, and restart.
  • changeAxisVisibility() — Re-read data-show-axis from the element and apply visibility.
  • changeAxisStyle() — Re-read data-axis-style from the element and apply style (arrow, line, no-style).
  • changeAttribute(name) — Internal helper used by Metro when data-* attributes change; routes to the corresponding change method.
  • destroy() — Remove event handlers and timers. Returns the element.
const cube = Metro.getPlugin('#cube1', 'cube');
cube.stop();
// Jump to a specific rule step (0-based). Optionally pass a custom speed for tick spacing.
cube.toRule(3, 300);
// Update rules programmatically
cube.rule([
{ on: { left: [1,2,3] } },
{ on: { right: [4,5,6] }, off: { left: [2] } },
]);
// Toggle axis programmatically
cube.axis(true);
VariableDefault (Light)Dark ModeDescription
--cube-size24px24pxCell size (width/height). Computed at runtime to fill the side but can be overridden.
--cube-gap4px4pxGap between cells within a side.
--cube-border-color#767676#767676Cell border color.
--cube-backgroundvar(—default-background)var(—default-background)Base cell background color.
--cube-colorvar(—default-color)var(—default-color)Cell text color (used with numbers).
--cube-background-flashvar(—color-primary)var(—color-primary)Flashing background color for active cells.
--cube-color-flash#ffffff#ffffffText color when a cell is lit.
--cube-axis-color#191919#ffffffAxis color.
--cube-side-border-colortransparenttransparentBorder color for each side container.
#myCube {
--cube-size: 18px; /* make cells smaller */
--cube-gap: 2px; /* tighter grid */
--cube-background: #111827; /* slate-900 */
--cube-background-flash: #22c55e; /* emerald-500 */
--cube-axis-color: #94a3b8; /* slate-400 */
}
  • .cube — Root element of the component.
  • .side — A cube face container. Specific side classes are added together with this base class.
  • .left-side, .right-side, .top-side — Specific faces of the cube.
  • .cube-cell — Individual cell inside a side grid.
  • .axis — Axis guide element.
  • .light — Applied to cells that are lit; enables animation and flash colors.
  • .axis-x, .axis-y, .axis-z — X/Y/Z axes.
  • .arrow, .line, .no-style — Axis styles.
  • The component auto-generates the required DOM structure (sides, cells, axes). You only need a container element with data-role="cube" or initialize via Metro.makePlugin().
  • The cube uses built-in rules if none are provided. When you provide custom rules, validate your JSON; malformed JSON is ignored and a warning is logged.
  • Cell IDs are 1-based within each side and go from 1 to cells*cells.
  • When cellClick is true, manual toggles do not affect the automated schedule; subsequent ticks may override cell states.
  • Keep flashInterval reasonable; very small values can create a large number of timers.
  • If you jump to a rule using toRule, consider autoRestart to resume playback automatically.
  • Prefer programmatic rule updates via cube.rule(newRules) during dynamic interactions; it validates and restarts safely.
  • Override CSS variables on the root cube element or a wrapper for scoped theming.