Back to the library
Console warm-up ready (slow beat)
Variant: Slow beat
The same warm-up panel with the resolve stretched across a longer, calmer master loop — the needle takes most of the cycle to reach its mark and the hold at the top is short. Use it when the underlying wait is genuinely slow (firmware handshake, cold start) and a fast settle would over-promise. Only the clock and the keyframe percentages move; the arc geometry, the swing angles, and the ease pairing are identical to the single beat.
statusloaderdialpanelambient
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>Console warm-up ready — slow beat</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: 5.6s; /* the authored master loop */
--t: calc(var(--cycle) / var(--speed));
--ease-out: cubic-bezier(0.23, 1, 0.32, 1);
--ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);
--_lamp-1: calc(0.3s / var(--speed));
--_lamp-2: calc(0.45s / var(--speed));
--_lamp-3: calc(0.6s / var(--speed));
--_chrome: #cfd2d4;
}
* { box-sizing: border-box; }
html, body { margin: 0; }
body {
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);
}
.console {
width: min(360px, 90vw);
padding: clamp(14px, 4.4vw, 20px);
background: var(--paper);
border: 1px solid var(--oat);
border-radius: calc(14px * var(--round));
box-shadow: 0 1px 0 var(--oat) inset;
display: grid;
gap: clamp(12px, 3.6vw, 16px);
}
.head {
display: flex;
align-items: center;
justify-content: space-between;
gap: 10px;
}
.label {
font-size: clamp(11px, 3vw, 12px);
letter-spacing: 0.16em;
text-transform: uppercase;
font-weight: 600;
color: var(--slate);
}
.lamps { display: flex; gap: 6px; }
.lamp {
width: 20px;
height: 7px;
border-radius: 999px;
background: var(--oat);
opacity: 0.55;
transform-origin: left center;
animation: lamp-latch var(--t) var(--ease-out) infinite;
}
.lamp:nth-child(1) { animation-delay: var(--_lamp-1); }
.lamp:nth-child(2) { animation-delay: var(--_lamp-2); }
.lamp:nth-child(3) { animation-delay: var(--_lamp-3); }
@keyframes lamp-latch {
0% { opacity: 0.35; background: var(--oat); transform: scaleX(0.92); }
12%, 88% { opacity: 1; background: var(--clay); transform: scaleX(1); }
100% { opacity: 0.35; background: var(--oat); transform: scaleX(0.92); }
}
.face {
position: relative;
border-radius: calc(10px * var(--round));
background: linear-gradient(180deg, var(--ivory), var(--paper));
border: 1px solid var(--oat);
padding: clamp(10px, 3vw, 14px);
overflow: hidden;
}
svg { display: block; width: 100%; height: auto; }
.arc { stroke: var(--oat); }
.arc-live {
stroke: var(--clay);
stroke-dasharray: 150;
stroke-dashoffset: 150;
animation: arc-fill var(--t) var(--ease-out) infinite;
}
/* Long rise, short hold: the climb itself is the information here. */
@keyframes arc-fill {
0% { stroke-dashoffset: 150; }
72% { stroke-dashoffset: 42; }
92% { stroke-dashoffset: 42; }
100% { stroke-dashoffset: 150; }
}
.needle {
transform-origin: 110px 78px;
animation: needle-swing var(--t) var(--ease-in-out) infinite;
}
@keyframes needle-swing {
0% { transform: rotate(-58deg); }
72% { transform: rotate(34deg); }
92% { transform: rotate(34deg); }
100% { transform: rotate(-58deg); }
}
.pip { fill: var(--oat); }
.hub { fill: var(--slate); }
.sweep {
position: absolute;
inset: 0;
background: linear-gradient(105deg, transparent 38%, var(--_chrome) 50%, transparent 62%);
opacity: 0.5;
transform: translateX(-120%);
animation: sweep var(--t) linear infinite;
pointer-events: none;
}
@keyframes sweep {
0%, 30% { transform: translateX(-120%); }
78% { transform: translateX(120%); }
100% { transform: translateX(120%); }
}
.foot {
display: flex;
align-items: center;
justify-content: space-between;
gap: 10px;
font-size: clamp(10.5px, 2.9vw, 11.5px);
letter-spacing: 0.1em;
text-transform: uppercase;
color: var(--clay-d);
}
.foot .right { color: var(--olive); }
.bar {
height: 4px;
border-radius: 999px;
background: var(--oat);
overflow: hidden;
}
.bar i {
display: block;
height: 100%;
border-radius: 999px;
background: var(--rust);
transform-origin: left center;
transform: scaleX(0.06);
animation: bar-fill var(--t) var(--ease-out) infinite;
}
@keyframes bar-fill {
0% { transform: scaleX(0.06); }
72% { transform: scaleX(1); }
92% { transform: scaleX(1); }
100% { transform: scaleX(0.06); }
}
@media (max-width: 380px) {
.console { padding: 13px; gap: 11px; }
.face { padding: 9px; }
.lamp { width: 17px; }
}
@media (prefers-reduced-motion: reduce) {
.needle, .sweep, .bar i, .arc-live { animation: none; }
.needle { transform: rotate(34deg); }
.bar i { transform: scaleX(1); }
.arc-live { stroke-dashoffset: 42; }
.sweep { display: none; }
.lamp {
transform: none;
animation: lamp-dim calc(var(--t) * 1.6) ease-in-out infinite;
}
.lamp:nth-child(1) { animation-delay: var(--_lamp-1); }
.lamp:nth-child(2) { animation-delay: var(--_lamp-2); }
.lamp:nth-child(3) { animation-delay: var(--_lamp-3); }
@keyframes lamp-dim {
0%, 100% { opacity: 0.6; background: var(--clay); }
50% { opacity: 1; background: var(--clay); }
}
}
</style>
</head>
<body>
<div class="console" role="img" aria-label="Device warming up to ready state">
<div class="head">
<span class="label">Link status</span>
<div class="lamps">
<span class="lamp"></span>
<span class="lamp"></span>
<span class="lamp"></span>
</div>
</div>
<div class="face">
<svg viewBox="0 0 220 96" aria-hidden="true">
<path class="arc" d="M 42 78 A 68 68 0 0 1 178 78" fill="none" stroke-width="6" stroke-linecap="round" />
<path class="arc-live" d="M 42 78 A 68 68 0 0 1 178 78" fill="none" stroke-width="6" stroke-linecap="round" />
<g class="pip">
<rect x="54" y="44" width="2.5" height="8" rx="1.2" transform="rotate(-52 55 48)" />
<rect x="108.5" y="22" width="2.5" height="9" rx="1.2" />
<rect x="163" y="44" width="2.5" height="8" rx="1.2" transform="rotate(52 164 48)" />
</g>
<g class="needle">
<rect x="108.6" y="30" width="2.8" height="50" rx="1.4" fill="currentColor" />
</g>
<circle class="hub" cx="110" cy="78" r="5" />
</svg>
<span class="sweep"></span>
</div>
<div class="bar"><i></i></div>
<div class="foot">
<span>Warming</span>
<span class="right">Ready</span>
</div>
</div>
</body>
</html>
The variant family
Same idea, one axis moved. Compare them side by side before you commit.