The end result looks similar to a ring spinner — a circle that appears to spin — but the mechanism differs: nothing actually rotates, and dots at fixed positions simply brighten and dim in sequence. This is how iOS's built-in activity indicator works, and because only opacity is animated rather than transform: rotate, it stays smooth even on low-power devices.
8–12 dots are placed around a circle by rotating each one by (360° ÷ dot count), then every dot gets a keyframe that dims and restores its opacity, with animation-delay offset by (full cycle ÷ dot count) per dot. The rotate used for placement never animates — it just fixes each dot's position — which is exactly what avoids the jank a rotating transform can introduce, while still creating the illusion of spin.
A skeleton fits a long wait covering the whole screen better; skip this under 200ms. Give the wrapper role="status" and aria-live="polite", and hide the dots with aria-hidden="true" since they're decorative. Under prefers-reduced-motion, simplify the sequential brightening into the whole ring of dots pulsing faintly together.