CSS + JS Shapes & solids #generated #loop

Point sphere in CSS + JavaScript

JS places the dots on a Fibonacci sphere once; the spin itself is a plain CSS animation.

  • 30 lines of CSS
  • 3 lines of HTML
  • 13 lines of JS
  • No dependencies
  • Snippet under MIT
GitHub

How it works

  1. Writing 120 dots by hand is not realistic — JS generates them once from the Fibonacci-sphere formula.
  2. Each dot gets rotateY(longitude) rotateX(latitude) translateZ(radius): aim, then push outward. Same idea as the carousel, in two axes.
  3. After that JS is done. The rotation is an ordinary CSS keyframe animation on the container.
  4. The container is 0×0 so every dot rotates around the exact centre.
  5. Every length is a multiple of one base unit, --u, tied to the canvas. JS writes translateZ(var(--r)) rather than a pixel radius, so the radius (130 units) stays in CSS and the ball is the same share of a gallery card, the editor and a recording canvas.

Key techniques

  • DOM generated from a formula
  • rotateY · rotateX · translateZ per dot
  • CSS keyframe spin

Copy-paste code

HTML 3 lines

<div class="scene">
  <div class="ball"></div>
</div>

CSS 30 lines

.scene {
  /* one base unit: every length below is a multiple of it, so the ball is the same share of a
     card, the editor, a full screen and a recording canvas */
  --u: 0.245vmin;
  perspective: calc(600 * var(--u));
}

.ball {
  --r: calc(130 * var(--u));
  position: relative;
  width: 0;
  height: 0;
  transform-style: preserve-3d;
  animation: ball-spin 16s linear infinite;
}

.ball i {
  position: absolute;
  top: calc(-4 * var(--u));
  left: calc(-4 * var(--u));
  width: calc(8 * var(--u));
  height: calc(8 * var(--u));
  border-radius: 50%;
  background: radial-gradient(circle, #fff 15%, #ffb547 60%);
}

@keyframes ball-spin {
  from { transform: rotateX(-18deg) rotateY(0deg); }
  to   { transform: rotateX(-18deg) rotateY(360deg); }
}

JS 13 lines

const ball = document.querySelector('.ball');
const COUNT = 120;
const GOLDEN_ANGLE = Math.PI * (3 - Math.sqrt(5));

for (let i = 0; i < COUNT; i++) {
  const lat = Math.asin(1 - (i / (COUNT - 1)) * 2);  // -90° … 90°
  const lon = i * GOLDEN_ANGLE;

  const dot = document.createElement('i');
  dot.style.transform =
    'rotateY(' + lon + 'rad) rotateX(' + lat + 'rad) translateZ(var(--r))';
  ball.append(dot);
}
Standalone snippet · plain CSS, no build step, no dependencies.