# Loaders Indeterminate progress indicators. Gold-by-default, recolorable via a single CSS variable. The Aurora loader set is 20 variants drawn from a common color/size knob so they can be swapped without any per-variant styling work. ## When to use Use a loader when: - the wait is indeterminate (unknown duration, unknown percent) - blocking a region of UI that cannot render yet - signaling an active background process that should keep the user patient For **known-percent** work use [Progress Bars](progress-bars.md) instead. Loaders show *aliveness*, not *completion*. ## Rule Loaders are a **hero** signal — an active system state that the user is waiting on. They may glow. Do **not** route the loader color knob to amber; amber is a matte warning color and must not outrank hero intent. This follows the same gold-vs-amber rule as the rest of the system. If a process is *stalled* or *degraded* (warning, not progress), pair the loader with a warning badge — don't recolor the loader itself. ## Drop-in usage ```html
``` The base class `.aurora-loader` sets size, color, and the derivative tints. The variant class (`.aurora-loader-orbit`, `.aurora-loader-triple`, etc.) picks the motion pattern. ## Recolor Override `--aurora-loader-color` at any scope — root, a region, or a single loader: ```css /* Recolor one loader */ .my-loader { --aurora-loader-color: var(--accent-purple); } /* Recolor every loader inside a region */ .analytics-panel { --aurora-loader-color: var(--accent-blue); } ``` Derivative tints (`soft`, `faint`, `ghost` — 55% / 15% / 6%) are recomputed automatically with `color-mix(in oklab, ...)`. There is no per-variant recolor code. ## Resize Override `--aurora-loader-size` (default `120px`). Bars, pixel, square-loop, shift, and helix variants use the size as a base and scale their children proportionally. ```css .toolbar .aurora-loader { --aurora-loader-size: 48px; } ``` ## Accessibility - Mark each loader `role="status"` and give it an `aria-label` describing what is loading. - Under `prefers-reduced-motion: reduce` the CSS stretches every animation to ~3s — movement is slowed, not removed, so the indeterminate signal is preserved. - Don't rely on loader color alone to carry meaning — pair with text when the wait is contextually ambiguous. ## The 20 variants | # | Variant | Technique | Best for | |---|---|---|---| | 01 | `aurora-loader-orbit` | Rotating arc on a ghost ring | Generic indeterminate | | 02 | `aurora-loader-triple` | Three counter-rotating rings | Multi-stage work | | 03 | `aurora-loader-bars` | Five bar-chart bars pulsing | Data or analytics contexts | | 04 | `aurora-loader-hex` | Hex outline with sweeping chord (SVG) | Security / policy scans | | 05 | `aurora-loader-square` | Dot traveling a square perimeter | Compact square slots | | 06 | `aurora-loader-glitch` | 4×4 grid flicker-fill | Data-loading motif | | 07 | `aurora-loader-cross` | Crosshair reticle + counter-rotating ticks (SVG) | Search / target lock | | 08 | `aurora-loader-pixel` | 3×3 LED wave | Hardware / status panels | | 09 | `aurora-loader-wave` | Oscilloscope stroke (SVG) | Audio / signal flows | | 10 | `aurora-loader-orb` | Pulsing core with rotating halos | Hero / splash loads | | 11 | `aurora-loader-diamond` | Diamond dashed runner (SVG) | Compact accents | | 12 | `aurora-loader-trail` | 8 dots around a circle, tail fade | Classic spinner | | 13 | `aurora-loader-scan` | Horizontal scanline across a box | File / document scans | | 14 | `aurora-loader-star` | 6-spoke star, firing in sequence | Celebratory or flashy | | 15 | `aurora-loader-circuit` | Snake tracing through a node grid (SVG) | Build / graph / routing | | 16 | `aurora-loader-holo` | Four corner brackets breathing | Hologram / targeting | | 17 | `aurora-loader-shift` | Three offset blocks translating | Migrations / batches | | 18 | `aurora-loader-bloom` | Three concentric arcs blooming outward | Transmit / broadcast | | 19 | `aurora-loader-segring` | 12 ticks chasing around a ring | Clock / cycle work | | 20 | `aurora-loader-helix` | Two dots tracing a sine wave | Sync / pairing | ## Anatomy Every variant inherits the same anatomy from `:where(.aurora-loader)`: ```css --aurora-loader-color: var(--accent-gold); /* override me */ --aurora-loader-size: 120px; /* override me */ --_c: var(--aurora-loader-color); --_c-soft: color-mix(in oklab, var(--_c) 55%, transparent); --_c-faint: color-mix(in oklab, var(--_c) 15%, transparent); --_c-ghost: color-mix(in oklab, var(--_c) 6%, transparent); ``` - `--_c` — primary stroke / fill / glow source - `--_c-soft` — secondary arcs, glow halo, second dot in helix - `--_c-faint` — faded grid, glitch resting fill - `--_c-ghost` — scaffolding, backdrop outlines These derivatives are the key to the whole set: recoloring one variable updates every shade coherently. ## Cross-platform reimplementation The CSS reference is the source of truth, but the loaders are simple enough to port. A few platform notes: ### SwiftUI / iOS - Rebuild each variant as a `View` with `@State var t: Double` driven by `TimelineView(.animation)` — don't use `withAnimation(.repeatForever)`, it silently drops frames on background tabs. - Use `Color(hue:saturation:brightness:opacity:)` and compute the three derivatives (`0.55`, `0.15`, `0.06` alpha) from the resolved hero color. That mirrors `color-mix(... transparent)`. - Shadow-glow uses `.shadow(color:radius:)`; match `drop-shadow(0 0 6px)` with `radius: 6`. ### Jetpack Compose / Android - Animate with `rememberInfiniteTransition` for spinners; use `Canvas` + `drawPath` for the SVG-based variants (hex, cross, wave, circuit, diamond). - Derive tints with `color.copy(alpha = 0.55f)` etc. Use Android 12+'s `BlendMode` or stack semi-transparent draws to approximate `color-mix`. - Honor `View.isReduceMotionEnabled` via `AccessibilityManager` — slow animations to ~3s rather than disabling them. ### Rust / egui / iced - Tokens already ship in `libs/rust/` — resolve `tokens.accent.gold` at runtime and derive the three alpha shades once per frame. - For SVG-heavy variants use `lyon` or simple tessellation; for orbit/triple/trail variants a single-line `ctx.request_repaint()` loop with a rotating angle is enough. ### Python / Qt / Tk / Rich - `libs/python/aurora_core` exposes the same tokens. For Qt, use `QPropertyAnimation` + a custom `QWidget` `paintEvent`. - For Rich (terminal), approximate the orbit and pixel variants with rotating Unicode glyphs and the resolved ANSI color. ### Flutter - Use `AnimationController(vsync: this, duration: ...)` with `repeat()` and `CustomPainter` for the SVG variants. Color derivations: `color.withOpacity(0.55)`, etc. ### Vanilla / any web framework - The CSS file works as-is. No JS required for the loaders themselves. Recolor by setting `--aurora-loader-color` on any ancestor — React, Vue, Svelte, and Angular all support CSS variables through the `style` prop / binding. ## Avoid - **Don't** route the color knob to `--accent-amber` — amber is matte-warning, not hero-progress. - **Don't** use an indeterminate loader when you know the percent. Use a progress bar. - **Don't** stack two loaders in the same region. One per waiting surface. - **Don't** disable animation entirely under reduced-motion — slow it; keep the signal alive. ## Source - CSS asset: `assets/aurora-loaders.css` - Portal preview: `portal/index.html` sections `#loaders-featured` and `#loaders-gallery` - Origin: Claude Design handoff bundle, 2026-04-17 (cyberpunk-set iteration)