registry
@automindzsheets 01–77shadcn 4.x
SHEET 43

Icon Cloud

component / motion

Icons spread over a real 3D sphere by a Fibonacci lattice, turning, each one counter-rotated to face the viewer and shaded by its own depth — in pure CSS.

type
component
files
2
registry deps
none
npm deps
none

installs

  • components/automindz/icon-cloud.tsx
  • styles/automindz-cloud.css
  • Fibonacci lattice: near-uniform on a sphere at any count — 1.11× spacing spread at 60
  • Glyphs never turn edge-on — spin and counter-spin share one duration, and the tilt too
  • Depth for free: perspective scales it, each icon's fade phased to its own azimuth
  • preserve-3d sorts back behind front, so no overflow, filter or opacity on the field
  • Reduced motion stops it fully composed: every icon placed, shaded, facing you

The stylesheet is not optional: add import "@/styles/automindz-cloud.css" to your root layout once, or nothing turns. Skipping it is safe, never blank — the projection (perspective, transform-style, the lattice translate3d) is inline, so every icon still sits at its lattice point, scaled and faded by its real depth, facing the viewer. That is also the prefers-reduced-motion path. IconCloud takes the icons as children and sizes itself from radius, iconSize and perspective together; there is no height prop, because perspective magnifies the near side and a hand-set box shaves it in motion. Depth sorting is transform-style: preserve-3d, so **do not put overflow, filter, mask or opacity on the field or the sphere** — any of them flattens the 3D context and collapses the sphere into a pile of icons in DOM order; put them on an ancestor (the field is already sized so nothing needs clipping). Shading dials are CSS custom properties: --automindz-cloud-front (default 1) and --automindz-cloud-back (default 0.3). The sphere is aria-hidden and inert by default — pass label when the icons carry real accessible names. Radii are px, so render a smaller one below sm if you need two sizes; there is no reverse, because flipping the spin also requires mirroring every icon's depth phase.

Variations

one state per section

01

Twenty-eight icons on a real sphere

Watch one chip for a full lap: it travels round the sphere but never turns, because the sphere's rotation and the chip's are two animations sharing one duration. Then watch the far side — those chips are smaller because perspective divides by their depth, and fainter because each one carries its own fade, phased to its own azimuth. Nothing measures anything; there is no JavaScript in the loop.

fluid
02

The lattice holds at any count

Seven and sixty, same rule. The golden-angle spiral steps equal slices of area rather than equal slices of latitude, so no count produces a bald patch at the poles or a crowd at the equator — nearest-neighbour spacing varies by 1.11x at sixty. The version everyone writes first puts a point on each pole and varies by 1.70x, which reads as a wireframe globe.

fluid
7 icons
60 icons
03

Depth is the lens, and the lens is a prop

The same sphere through a 420px camera and a 2000px one. Short is a wide lens: the near side is magnified hard and the far side collapses, so the sphere reads as deep. Long flattens it toward a disc of icons. The field re-sizes itself for each — a wide lens needs a bigger box, not a smaller one, which is the direction hand-built versions guess wrong and then clip the near side in motion.

fluid
perspective 420
perspective 2000
04

Tilt the axis, and the glyphs still face you

At tilt 0 you look at the equator. At 34 you look down over the top pole. Every glyph stays square-on in both, because the counter-rotation undoes the tilt as well as the spin — undo only the spin and each glyph is foreshortened by cos(tilt) forever, a squash rather than a crash, which is why that bug survives review. The field size does not change: rotations map the sphere onto itself, so the box is a bound at every tilt.

fluid
tilt 0°
tilt 34°
05

A labelled sphere, with real links

The sphere is aria-hidden and inert by default, because thirty unlabelled glyphs read out in lattice order is noise landing between the heading and the copy that explains it. Passing label takes it out of that default in one prop: it becomes a named group, its items regain pointer events and the tab order, and each link carries its own name. Tab into the preview to reach them — and note the focus ring lands on a glyph that is still turning.

fluid
06

One icon, and none at all

A single icon is placed dead in front of the viewer rather than wherever the formula lands it, so standing still it is centred and full size instead of parked off to one side looking like a bug. Beside it, a sphere passed no children: it renders nothing at all, not an empty 350px box, so a roster that empties out leaves no hole in the page. Neither case needs a guard at the call site.

fluid
1 icon
0 icons — nothing rendered
07

Standing still is the base state

Turn on Reduce Motion in your OS and reload: the sphere stops fully composed — every icon at its lattice point, facing front, scaled and shaded by its real depth, because the projection is inline and only the rotation lives in the stylesheet. That is also what an install renders with the stylesheet import forgotten, which is why forgetting it is safe. Nothing is hidden, flattened into a pile, or waiting for a trigger.

fluid