Cubes
cubesRenders an interactive field of perspective cubes with animated depth.
Usage
Basic usage
Default 8×8 cube array: The cube that the pointer is close to is attenuated and tilted according to the distance, and automatically wanders when idle. Click to spread the ripples outward. Containers need to be of given size.
<div className="h-56 w-56">
<Cubes />
</div>Grid density
gridSize controls the array side length (the number of DOM is square, recommended ≤ 12); cooperates with maxAngle / radius to adjust the tilt amplitude and influence radius.
<div className="h-56 w-56">
<Cubes gridSize={12} maxAngle={60} radius={4} />
</div>Brand color ripples
faceColor / edgeColor / rippleColor Eat all token; click to spread the highlight outwards from the hit point in a circular shape, rippleSpeed to control the diffusion speed.
<div className="h-56 w-56">
<Cubes
faceColor="var(--color-surface)"
edgeColor="var(--color-primary)"
rippleColor="var(--color-chart-2)"
rippleSpeed={3}
/>
</div>Still (turn off automatic wandering)
autoAnimate={false} Turn off idle roaming, the cube only tilts when the pointer interacts, and stays flat normally.
<div className="h-56 w-56">
<Cubes gridSize={6} autoAnimate={false} />
</div>When to Use
Use it when you need a grid background/decorative panel with a 3D feel that responds to pointer tilt. It is suitable for visual embellishment of hero areas, empty consoles, and active landing pages. It is a regular grid array; if you want a softer particle/spot type atmosphere background, look at other effects background components; if you want a single element to hover and emit light, use GlareHover.
Import
import { Cubes } from "@hulianui/ui"Props
| Name | Type | Default | Description |
|---|---|---|---|
| gridSize | number | 8 | Grid side length (row = column), generate gridSize² cubes; DOM is square level, recommended ≤ 12 |
| cubeSize | number | — | Single cube side length (px); when passed in, the container has a fixed size, otherwise the container will adapt (width 100%·1:1) |
| maxAngle | number | 45 | The maximum tilt angle of the cube at the pointer (degrees), the closer it is, the bigger it is and the farther it is, the closer it is to 0 |
| radius | number | 3 | Tilt influence radius (in "grid"), participate in tilt within the range, and return to normal outside |
| cellGap | number | { row?: number | string; col?: number | string } | "5%" | Unit spacing, numbers in px, objects specify rows and columns respectively (percentage strings scale with the container) |
| faceColor | string | var(--color-surface) | Cube face background color, must be prefixed with --color- |
| edgeColor | string | var(--color-border) | Cube surface border color |
| rippleColor | string | var(--color-primary) | The ripple highlight color that spreads outward from the hit point when clicked |
| rippleSpeed | number | 2 | Ripple diffusion speed multiplier, the bigger the faster |
| autoAnimate | boolean | true | Whether to automatically wander and tilt when idle (automatically disabled to remain stationary under reduced-motion) |
| rippleOnClick | boolean | true | Whether to enable click ripples |
| className | string | — | Forward the additional class name of the root container |
| style | CSSProperties | — | Forward the root container inline style |
Usage Guidelines
- When
cubeSizeis omitted, the container uses a responsive 1:1 aspect ratio. Give its parent explicit dimensions, for example with a fixed-width, fixed-height wrapper, or the container may collapse. - All color props (faceColor/edgeColor/rippleColor) must be tokenized with the
--color-prefix. See [[hulian-token-color-var-needs-color-prefix]]. - The number of DOMs is
gridSize². Don’t setgridSizetoo large (recommended ≤ 12), otherwise the number of nodes and rearrangement costs will soar. - Under reduced-motion,
autoAnimateautomatically fails and the cube becomes stationary.
Related
BorderBeam · ShineBorder · GlareHover · Lens · AnimatedBeam · OrbitingCircles
Playground
<div className="h-56 w-56">
<Cubes
gridSize={8}
maxAngle={45}
radius={3}
rippleSpeed={2}
autoAnimate={true}
rippleOnClick={true}
/>
</div>