Ghost Cubes
Translucent cubes drift upward and fade away, creating a subtle ghost-like background motion.
1. Copy the component file
Create a new file called ghost-cubes-background.jsx in
your reusable components folder (for example
/src/components/) and paste the following code
into it.
ghost-cubes-background.jsx
import { useCallback, useEffect, useState } from "react";
import styles from "./ghost-cubes-background.module.css";
const Cube = (props) => {
const {
index,
} = props;
const getCube = useCallback(() => ({
id: `cube-${Math.floor(Math.random() * 10000)}`,
xPos: Math.random() * 100, // position in % of width
size: Math.random() * 100, // size in px
durationMs: 10000 + Math.random() * 20000,
delayMs: Math.random() * 5000 * index,
}), [index]);
const [cube, setCube] = useState(getCube);
useEffect(() => {
const timeoutId = setTimeout(() => {
setCube(getCube());
}, cube.durationMs + cube.delayMs + 1000);
return () => {
clearTimeout(timeoutId);
};
}, [cube, getCube]);
return (
<span
key={cube.id}
aria-hidden={true}
className={styles["cube"]}
style={{
"--size": `${cube.size}px`,
"--xPos": `${cube.xPos}%`,
"--durationMs": `${cube.durationMs}ms`,
"--delayMs": `${cube.delayMs}ms`,
}}
/>
);
};
const GhostCubesBackground = (props) => {
const {
children,
className = "",
style = null,
wrapperProps = {},
wrapperTagName = "div",
backgroundColor = "#d37185",
...rest
} = props;
const cubesCount = 20;
const {
className: wrapperClassName = "",
...restWrapperProps
} = wrapperProps;
const Wrapper = wrapperTagName || "div";
return (
<div
{...rest}
className={[
className,
styles["ghost-cube-background"]
].join(" ")}
style={{
...style,
"--background-color": backgroundColor,
}}
>
<div
aria-hidden={true}
className={styles["cubes"]}
>
{new Array(cubesCount).fill(0).map((_, index) => (
<Cube
key={`cube-${index}`}
index={index}
/>
))}
</div>
<Wrapper
{...restWrapperProps}
className={[
wrapperClassName,
styles["wrapper"]
].join(" ")}
>
{children}
</Wrapper>
</div>
);
};
export default GhostCubesBackground; 2. Copy the CSS module file
In the same folder, create a file called ghost-cubes-background.module.css and paste the following CSS.
ghost-cubes-background.module.css
.ghost-cube-background {
--cube-background-color: rgba(255, 255, 255, 0.25);
@media(prefers-color-scheme: dark) {
--cube-background-color: rgba(0, 0, 0, 0.25);
}
position: relative;
background: var(--background-color);
.cubes {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 100%;
height: 100%;
z-index: 1;
pointer-events: none;
.cube {
position: absolute;
left: var(--xPos);
bottom: calc(var(--size) * -1.5);
opacity: 0.5;
width: var(--size);
height: var(--size);
transform:rotate(45deg);
background: rgba(255, 255, 255, 0.25);
z-index: 1;
pointer-events: none;
animation: ghost-cube-keyframes var(--durationMs) ease-in forwards;
animation-delay: var(--delayMs);
}
}
.wrapper {
position: relative;
z-index: 3;
}
}
@keyframes ghost-cube-keyframes {
0% {
transform: translateY(0px) rotate(45deg);
opacity: 0.5;
border-radius: 5%;
}
50% {
border-radius: 45%;
}
100% {
transform: translateY(calc(-100vh - var(--size))) rotate(900deg);
opacity: 0;
border-radius: 45%;
}
} 3. Use the component
Now you can import and use the component anywhere in your project.
ghost-cubes-background-preview.jsx
import GhostCubesBackground from "@/components/backgrounds/ghost-cubes-background/ghost-cubes-background.jsx";
const GhostCubesBackgroundPreview = () => {
return (
<GhostCubesBackground
style={{
width: "100%",
height: "100%",
}}
wrapperProps = {{
style: {
display: "grid",
placeItems: "center",
height: "100%"
}
}}
>
<h1>Ghost Cubes</h1>
</GhostCubesBackground>
);
};
export default GhostCubesBackgroundPreview; Props
Configure the component with the following props:
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
| children | ReactNode | Yes | — | Content displayed on top of the ghost cubes background. |
| className | string | No | — | Additional CSS classes applied to the main container. |
| style | React.CSSProperties | No | — | Inline styles applied to the main container. |
| wrapperProps | React.HTMLAttributes<any> | No | — | Additional props passed to the wrapper element containing the children. |
| wrapperTagName | string | No | "div" | HTML tag used as the wrapper element around the children. |
| backgroundColor | string | No | "#d37185" | Background color behind the floating ghost cubes animation. |