Back to the library
Mirrored sync indicator
Variant: Bold
Two bars advance from opposite edges of a track, meet dead centre, then trade places — a paired-progress cue for anything with two sides negotiating: sync, merge, matchmaking, handshake. The bold sibling claims the widest track and the deepest travel, so it reads as a primary status object rather than a footnote. The travel uses ease-in-out because the bars are moving on screen rather than entering, and the meeting point lands on an exact half of the master clock so the two never drift apart.
loadersyncprogressmirrorstatus
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>Mirrored sync indicator — Bold</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);
/* Weight tokens — the only thing that moves across this family. */
--_bar-h: 14px;
--_track-w: min(360px, 82vw);
--_reach: 46%;
--_alpha-track: 0.5;
--_seam-op: 0.9;
--_seam-w: 2px;
}
* { box-sizing: border-box; }
body {
margin: 0;
min-height: 100vh;
display: grid;
place-items: center;
background: var(--ivory);
color: var(--slate);
font-family: system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
}
.card {
width: min(420px, 92vw);
padding: clamp(18px, 5vw, 28px);
display: grid;
justify-items: center;
gap: clamp(14px, 4vw, 20px);
}
.label {
font-size: clamp(11px, 3vw, 13px);
letter-spacing: 0.12em;
text-transform: uppercase;
color: var(--slate);
opacity: 0.55;
}
.track {
position: relative;
width: var(--_track-w);
height: var(--_bar-h);
border-radius: 999px;
background: color-mix(in oklch, var(--oat) calc(var(--_alpha-track) * 100%), var(--paper));
overflow: hidden;
}
.bar {
position: absolute;
top: 0;
height: 100%;
width: 50%;
border-radius: 999px;
}
/* Each bar rests just outside the track and drives inward to the seam. */
.bar.a {
left: 0;
background: var(--clay);
transform: translateX(calc(-1 * var(--_reach)));
animation: pushA var(--t) var(--ease-in-out) infinite;
}
.bar.b {
right: 0;
background: var(--olive);
transform: translateX(var(--_reach));
animation: pushB var(--t) var(--ease-in-out) infinite;
}
/* The contested centre line: brightest at the instant of contact. */
.seam {
position: absolute;
left: 50%;
top: -20%;
width: var(--_seam-w);
height: 140%;
margin-left: calc(var(--_seam-w) / -2);
background: var(--slate);
opacity: 0;
transform: scaleY(0.5);
animation: seam calc(var(--t) / 2) var(--ease-in-out) infinite;
}
@keyframes pushA {
0% { transform: translateX(calc(-1 * var(--_reach))); }
/* contact at the exact half-clock so both sides always arrive together */
50% { transform: translateX(0%); }
100% { transform: translateX(calc(-1 * var(--_reach))); }
}
@keyframes pushB {
0% { transform: translateX(var(--_reach)); }
50% { transform: translateX(0%); }
100% { transform: translateX(var(--_reach)); }
}
@keyframes seam {
0%, 100% { opacity: 0; transform: scaleY(0.5); }
/* sub-clock is half the loop, so this fires on both approach and retreat */
46% { opacity: 0; transform: scaleY(0.5); }
62% { opacity: var(--_seam-op); transform: scaleY(1); }
88% { opacity: 0; transform: scaleY(0.7); }
}
.legend {
display: flex;
gap: clamp(14px, 5vw, 24px);
font-size: clamp(11px, 3vw, 12px);
color: var(--slate);
opacity: 0.7;
}
.legend span {
display: inline-flex;
align-items: center;
gap: 7px;
}
.dot {
width: 9px;
height: 9px;
border-radius: 50%;
display: inline-block;
}
.dot.a { background: var(--clay); }
.dot.b { background: var(--olive); }
.frame {
padding: clamp(14px, 4vw, 20px);
border-radius: calc(16px * var(--round));
background: var(--paper);
border: 1px solid var(--oat);
display: grid;
justify-items: center;
gap: clamp(12px, 3.5vw, 16px);
}
@media (max-width: 380px) {
.card { padding: 12px; gap: 12px; }
.frame { padding: 12px; }
}
@media (prefers-reduced-motion: reduce) {
/* Movement drops out; the meeting still reads as a paired opacity beat. */
.bar.a,
.bar.b {
animation: none;
transform: translateX(0%);
}
.bar.a { animation: fadeA calc(var(--t) * 2) var(--ease-in-out) infinite; }
.bar.b { animation: fadeB calc(var(--t) * 2) var(--ease-in-out) infinite; }
.seam {
animation: seamQuiet calc(var(--t) * 2) var(--ease-in-out) infinite;
transform: scaleY(1);
}
}
@keyframes fadeA {
0%, 100% { opacity: 0.45; }
50% { opacity: 1; }
}
@keyframes fadeB {
0%, 100% { opacity: 1; }
50% { opacity: 0.45; }
}
@keyframes seamQuiet {
0%, 100% { opacity: 0.25; }
50% { opacity: var(--_seam-op); }
}
</style>
</head>
<body>
<div class="card">
<div class="frame">
<div class="label">Syncing both sides</div>
<div class="track">
<div class="bar a"></div>
<div class="bar b"></div>
<div class="seam"></div>
</div>
<div class="legend">
<span><i class="dot a"></i>Local</span>
<span><i class="dot b"></i>Remote</span>
</div>
</div>
</div>
</body>
</html>The variant family
Same idea, one axis moved. Compare them side by side before you commit.