Icon cloud
Also called 3D icon sphere, tag sphere, or tech stack sphere
A 3D sphere of icons that turns on its own and can be dragged, with front icons large and solid and back icons small and faded.
import { useEffect, useRef, type ReactNode } from 'react';
import { useInView, useReducedMotion } from 'motion/react';
const RADIUS = 130; // px
const SPIN = 0.35; // radians per second of automatic rotation
export function IconCloud({ icons }: { icons: ReactNode[] }) {
const ref = useRef<HTMLDivElement>(null);
const inView = useInView(ref);
const reduceMotion = useReducedMotion();
const view = useRef({ yaw: 0, pitch: -0.3, dragging: false });
useEffect(() => {
if (!inView) return; // no work while off screen
const tiles = Array.from(ref.current!.children) as HTMLElement[];
// Even spacing on a sphere: a Fibonacci spiral from pole to pole.
const points = tiles.map((_, i) => {
const y = 1 - (2 * (i + 0.5)) / tiles.length;
const ring = Math.sqrt(1 - y * y);
const theta = i * Math.PI * (3 - Math.sqrt(5));
return { x: Math.cos(theta) * ring, y, z: Math.sin(theta) * ring };
});
let frame = 0;
let last = performance.now();
const paint = (now: number) => {
const v = view.current;
if (!reduceMotion && !v.dragging) v.yaw += (SPIN * (now - last)) / 1000;
last = now;
tiles.forEach((tile, i) => {
// Rotate around the vertical axis, then tilt.
const p = points[i]!;
const x = p.x * Math.cos(v.yaw) + p.z * Math.sin(v.yaw);
const z = p.z * Math.cos(v.yaw) - p.x * Math.sin(v.yaw);
const y = p.y * Math.cos(v.pitch) - z * Math.sin(v.pitch);
const depth = (p.y * Math.sin(v.pitch) + z * Math.cos(v.pitch) + 1) / 2;
// Front icons big and solid; back icons small, faded, and beneath.
tile.style.transform = `translate(${x * RADIUS}px, ${y * RADIUS}px) scale(${0.5 + depth * 0.6})`;
tile.style.opacity = String(0.15 + depth * 0.85);
tile.style.zIndex = String(Math.round(depth * 100));
});
frame = requestAnimationFrame(paint);
};
frame = requestAnimationFrame(paint);
return () => cancelAnimationFrame(frame);
}, [inView, reduceMotion, icons.length]);
return (
<div
onPointerDown={(e) => {
e.currentTarget.setPointerCapture(e.pointerId);
view.current.dragging = true;
}}
onPointerMove={(e) => {
if (!view.current.dragging) return;
view.current.yaw += e.movementX * 0.008;
view.current.pitch -= e.movementY * 0.008;
}}
onPointerUp={() => (view.current.dragging = false)}
className='grid size-80 cursor-grab touch-none place-items-center active:cursor-grabbing'
>
{/* Painted directly each frame, so React never re-renders the tiles. */}
<div ref={ref} aria-hidden className='relative size-0'>
{icons.map((icon, i) => (
<span
key={i}
className='absolute -top-5 -left-5 grid size-10 place-items-center rounded-xl border bg-background'
>
{icon}
</span>
))}
</div>
</div>
);
}Add an icon cloud next to the integrations copy: 28 icons in 40px rounded tiles spread evenly over a 260px sphere with a Fibonacci spiral. Turn it on its own at about 20° per second around the vertical axis with a slight downward tilt, scale icons from 0.5 at the back to 1.1 at the front, fade back icons to 15% opacity, and stack front icons on top. Let people drag to turn it, keep spinning after a flick and slow to a stop within a second, pause the loop while off screen, and skip the automatic spin when prefers-reduced-motion is set.
Paste into Layerwise or any AI coding tool.
What is Icon cloud?
An icon cloud spreads a few dozen icons over the surface of an invisible sphere and slowly turns it. Icons on the near side are drawn larger and fully opaque, icons on the far side smaller and faded, so a flat page reads as a 3D ball. Landing pages use it to show a tech stack, a set of integrations, or the tools a team works with.
A little trigonometry is enough to build it. Place the icons evenly with a Fibonacci spiral, rotate every point by the current angles each frame, then use its depth (z) to set the icon's scale, opacity, and z-index. Dragging adds to the rotation, and keeping some of the drag speed after release lets a flick keep it spinning while it slows down.
Keep it to 20 to 40 icons; more turns into noise, and each one is a moving element. Write the transforms straight to the DOM instead of re-rendering React every frame, pause the loop off screen, and stop the automatic spin under prefers-reduced-motion while still letting people drag. The sphere is decoration, so list the same tools as plain text nearby for screen readers.
Often confused with
- Orbit animation
- An orbit moves icons around flat rings on a fixed path. An icon cloud spreads them over a 3D sphere that people can turn by dragging.
Related terms
All termsOrbit animation
Small icons or dots circling a central element on one or more rings, often used to show the tools a product connects to.
Globe
A 3D Earth drawn in dots that turns on its own and can be dragged, with markers and arcs for cities, offices, or network routes.
Perspective
A CSS property that sets how far the viewer sits from a 3D scene, so rotated elements look deep up close and flatter from far away.
Drag gesture
Moving an element by pressing on it and sliding the pointer or finger, usually within set bounds and with a glide after release.
Build it with Layerwise
Describe your app, watch it run in a live preview, and publish it with a database, storage, and sign-in built in.