Back to the library

Liquid sync status, heavy

Variant: Heavy

The loudest rung: thick lobed rings pushed to the edge of the frame, a large core, and a visible halo bloom on each breath, for an empty-state or a full-screen 'restoring your account' moment where the indicator is the only thing on the page. Only weight changes — the ring periods, the ease-in-out breath and the halo's phase offset are the same numbers as the standard, so the heavy version does not read as faster. The halo tops out at 1.55x and the SVG allows overflow, so nothing clips at the smallest card size.

loaderstatusambientsvgbold

The source

A complete HTML document. Paste it into an empty .html file and it plays — no stylesheet, script, font, or image to fetch.

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Liquid sync status — heavy</title>
<style>
:root {
  /* Neutrals — fixed, never remixed. */
  --ivory: #faf9f5;
  --paper: #ffffff;
  --oat: #e3dacc;
  --slate: #141413;

  /* Knobs — the remix API. A knob exists iff declared here and used below. */
  --hue: 38.8;
  --lift: 0;
  --chroma: 1;
  --round: 1;
  --speed: 1;

  /* Accents — derived from the knobs with the family's offsets baked in,
     so one hue roll moves them together. Defaults reproduce the original hex
     (#d97757 / #b85c3e / #788c5d / #b04a3f). */
  --clay: oklch(calc(0.6724 + var(--lift)) calc(0.1308 * var(--chroma)) var(--hue));
  --clay-d: oklch(calc(0.5797 + var(--lift)) calc(0.127 * var(--chroma)) var(--hue));
  --olive: oklch(calc(0.6118 + var(--lift)) calc(0.0713 * var(--chroma)) calc(var(--hue) + 88.3));
  --rust: oklch(calc(0.5408 + var(--lift)) calc(0.1357 * var(--chroma)) calc(var(--hue) - 10.3));

  /* Clock — every duration in the document runs off --t. */
  --cycle: 3.2s;
  --t: calc(var(--cycle) / var(--speed));

  --ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);

  /* File-specific: the heaviest rung of the weight axis. */
  --_stroke-a: 6;
  --_stroke-b: 4.4;
  --_lobe: 1.06;
  --_core: 10;
  --_glow: 0.34;
  --_swell: 1.11;
  --_ringspin: calc(var(--t) * 2.5);
}

* { box-sizing: border-box; }

body {
  margin: 0;
  min-height: 100vh;
  display: grid;
  place-items: center;
  background: var(--ivory);
  font-family: system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  color: var(--slate);
}

.card {
  width: min(360px, 92vw);
  padding: clamp(18px, 5vw, 26px);
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: center;
  gap: clamp(14px, 4vw, 20px);
  background: var(--paper);
  border: 1px solid var(--oat);
  border-radius: calc(16px * var(--round));
}

.dial {
  width: clamp(64px, 18vw, 78px);
  height: clamp(64px, 18vw, 78px);
  display: block;
  overflow: visible;
}

.ring {
  fill: none;
  stroke-linecap: round;
  transform-origin: 50% 50%;
}

.ring-a {
  stroke: var(--clay);
  stroke-width: var(--_stroke-a);
  opacity: 0.95;
  animation: spin-cw var(--_ringspin) linear infinite;
}

.ring-b {
  stroke: var(--olive);
  stroke-width: var(--_stroke-b);
  opacity: 0.85;
  animation: spin-ccw calc(var(--_ringspin) * 1.5) linear infinite;
}

/* Outer lobe sits slightly past the viewBox; overflow is visible by design. */
.lobes { transform-origin: 50% 50%; transform: scale(var(--_lobe)); }

.core {
  fill: var(--rust);
  transform-origin: 50% 50%;
  animation: breathe var(--t) var(--ease-in-out) infinite;
}

.halo {
  fill: var(--clay);
  transform-origin: 50% 50%;
  opacity: var(--_glow);
  animation: halo var(--t) var(--ease-in-out) infinite;
}

@keyframes spin-cw  { to { transform: rotate(360deg); } }
@keyframes spin-ccw { to { transform: rotate(-360deg); } }

@keyframes breathe {
  0%, 100% { transform: scale(0.94); opacity: 0.72; }
  46%      { transform: scale(var(--_swell)); opacity: 1; }
}

@keyframes halo {
  0%, 100% { transform: scale(0.9); opacity: 0; }
  40%      { opacity: var(--_glow); }
  100%     { transform: scale(1.55); }
}

.copy { display: grid; gap: 4px; min-width: 0; }

.label {
  font-size: clamp(13px, 3.6vw, 15px);
  font-weight: 600;
  letter-spacing: -0.01em;
}

.sub {
  font-size: clamp(11px, 3vw, 12.5px);
  color: color-mix(in oklab, var(--slate) 55%, var(--ivory));
}

@media (max-width: 380px) {
  .card { padding: 16px; gap: 13px; }
}

@media (prefers-reduced-motion: reduce) {
  .ring-a, .ring-b, .halo { animation: none; }
  .halo { opacity: 0; }
  .core {
    animation: breathe-soft calc(var(--t) * 2) var(--ease-in-out) infinite;
  }
  @keyframes breathe-soft {
    0%, 100% { opacity: 0.6; transform: scale(1); }
    50%      { opacity: 1;   transform: scale(1); }
  }
}
</style>
</head>
<body>
  <div class="card">
    <svg class="dial" viewBox="0 0 100 100" aria-hidden="true">
      <g class="lobes">
        <path class="ring ring-a"
              d="M50 8 C72 8 92 28 92 50 C92 72 72 92 50 92 C28 92 8 72 8 50 C8 28 28 8 50 8 Z"
              pathLength="100" stroke-dasharray="17 8" />
        <path class="ring ring-b"
              d="M50 20 C64 26 74 36 80 50 C74 64 64 74 50 80 C36 74 26 64 20 50 C26 36 36 26 50 20 Z"
              pathLength="100" stroke-dasharray="11 6" />
      </g>
      <circle class="halo" cx="50" cy="50" r="16" />
      <circle class="core" cx="50" cy="50" r="10" />
    </svg>
    <div class="copy">
      <div class="label">Syncing library</div>
      <div class="sub">1,284 items · keeping up</div>
    </div>
  </div>
</body>
</html>

The variant family

Same idea, one axis moved. Compare them side by side before you commit.