bottega

experimental

Firefox Cube

An isometric stack of nine 3D blocks built purely from skewed <span>s and their ::before/::after faces — no images, no JS (server component). A continuous hue-rotate gives the greyscale stack a slow ambient shimmer; hovering any block snaps it to --cube-accent (default --primary) with a soft glow, then fades back over 1.5s. The three faces derive from --cube-shade (default --foreground) via color-mix so the stack stays legible on any theme. Decorative (role=img). Original by Greg Vissing (public CodePen, MIT), curated from a uiverse.io repost by csemszepp.

Ported from Greg Vissing (MIT)


Install

1. Register the namespace (once per project):

json
// components.json — register the @bottega namespace once
{
  "registries": {
    "@bottega": { "url": "https://bottega.ariacode.ca/r/{name}.json" }
  }
}

2. Add the component:

bash
npx shadcn add @bottega/firefox-cube

Usage

Usagetsx
<FirefoxCube />

Props

PropTypeDefaultDescription
labelstringAnimated isometric cubeAccessible label for the decorative stack. Default "Animated isometric cube".

Source

firefox-cube.tsxtsx
import type React from "react";
import styles from "./firefox-cube.module.css";

export interface FirefoxCubeProps extends React.HTMLAttributes<HTMLDivElement> {
  /** Accessible label for the decorative stack. Default "Animated isometric cube". */
  label?: string;
}

// Three offset cubes; each cube is three columns; each column stacks three
// blocks. Geometry is driven by the --x / --y / --i custom props the CSS reads.
const COLUMNS = [-1, 0, 1] as const;
const DEPTHS = [3, 2, 1] as const;

/**
 * Firefox Cube — an isometric stack of nine 3D blocks built purely from skewed
 * `<span>`s and their `::before` / `::after` faces (no images, no JS, server
 * component). A continuous hue-rotate gives the stack a slow ambient shimmer;
 * hovering any block snaps it to `--cube-accent` (default `--primary`) with a
 * glow, then fades back over 1.5s. Faces derive from `--cube-shade`
 * (default `--foreground`) so the stack stays legible on any theme.
 *
 * Decorative: rendered as role="img". The hue-rotate is removed under
 * prefers-reduced-motion (see the module CSS).
 *
 * Ported from a uiverse.io card by csemszepp, originally a CodePen by Greg Vissing.
 */
export function FirefoxCube({
  label = "Animated isometric cube",
  className = "",
  ...props
}: FirefoxCubeProps) {
  return (
    <div
      role="img"
      aria-label={label}
      className={[styles.root, className].filter(Boolean).join(" ")}
      {...props}
    >
      {[0, 1, 2].map((cube) => (
        <div key={cube} className={styles.cube}>
          {COLUMNS.map((x) => (
            <div
              key={x}
              className={styles.col}
              style={{ "--x": x, "--y": 0 } as React.CSSProperties}
            >
              {DEPTHS.map((i) => (
                <span
                  key={i}
                  className={styles.block}
                  style={{ "--i": i } as React.CSSProperties}
                />
              ))}
            </div>
          ))}
        </div>
      ))}
    </div>
  );
}

Dependencies

  • @bottega/tokens