Back to the library

Grid settle, held result

Variant: Held result

Rows land on the quick 220ms beat, then the readout wipe is deliberately withheld for 320ms before it runs. Use this when the value is the point and the rows are only context — the gap makes the number feel arrived at rather than pre-rendered. The hold is long enough to read as a pause but short enough that the total sequence still finishes inside a second.

settlestate-changepaneldelayreadout

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>Grid settle — held result</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-out: cubic-bezier(0.23, 1, 0.32, 1);

  --_hold: calc(0.32s / var(--speed)); /* gap between rows landing and the readout */
}

* { 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);
}

.panel {
  width: min(400px, 90vw);
  padding: clamp(14px, 4vw, 20px);
  background: var(--paper);
  border: 1px solid var(--oat);
  border-radius: calc(4px * var(--round));
}

.head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  padding-bottom: clamp(9px, 2.6vw, 12px);
  border-bottom: 1px solid var(--oat);
}

.head b {
  font-size: clamp(11.5px, 3.1vw, 13px);
  font-weight: 600;
  letter-spacing: 0.02em;
}

.head span {
  font-size: clamp(11px, 2.9vw, 11.5px);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--clay-d);
}

.rows {
  display: grid;
  gap: clamp(8px, 2.4vw, 11px);
  margin-top: clamp(11px, 3vw, 14px);
}

.row {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: 10px;
  animation: settle-loop var(--t) linear infinite both;
}

.label {
  height: 7px;
  background: var(--oat);
  border-radius: 999px;
}

.row:nth-child(1) .label { width: 62%; }
.row:nth-child(2) .label { width: 44%; }
.row:nth-child(3) .label { width: 71%; }
.row:nth-child(4) .label { width: 52%; }

.dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--oat);
}

.row:nth-child(2) .dot { background: var(--clay); }
.row:nth-child(4) .dot { background: var(--olive); }

.meter {
  margin-top: clamp(13px, 3.4vw, 17px);
  height: 6px;
  background: var(--oat);
  border-radius: 999px;
  overflow: hidden;
}

/* Rows finish at 220ms; the readout waits out the hold before wiping. */
.meter i {
  display: block;
  height: 100%;
  background: var(--clay);
  border-radius: 999px;
  animation: wipe var(--t) linear infinite both;
  animation-delay: calc(0.22s / var(--speed) + var(--_hold));
}

.foot {
  margin-top: clamp(9px, 2.6vw, 11px);
  font-size: clamp(11px, 2.9vw, 11.5px);
  letter-spacing: 0.06em;
  color: var(--slate);
  opacity: 0.55;
  animation: label-in var(--t) linear infinite both;
  animation-delay: calc(0.22s / var(--speed) + var(--_hold));
}

@keyframes settle-loop {
  0%      { transform: translateY(7px); opacity: 0.35; animation-timing-function: var(--ease-out); }
  6.875%  { transform: translateY(0);   opacity: 1; }
  100%    { transform: translateY(0);   opacity: 1; }
}

@keyframes wipe {
  0%      { clip-path: inset(0 100% 0 0); animation-timing-function: var(--ease-out); }
  6.875%  { clip-path: inset(0 32% 0 0); }
  100%    { clip-path: inset(0 32% 0 0); }
}

@keyframes label-in {
  0%      { opacity: 0; animation-timing-function: var(--ease-out); }
  6.875%  { opacity: 0.55; }
  100%    { opacity: 0.55; }
}

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

@media (prefers-reduced-motion: reduce) {
  .row {
    animation-name: settle-fade;
    animation-duration: calc(var(--cycle) * 2 / var(--speed));
  }
  .meter i {
    animation-name: hold-fade;
    animation-duration: calc(var(--cycle) * 2 / var(--speed));
    animation-delay: calc((0.22s / var(--speed) + var(--_hold)) * 2);
    clip-path: inset(0 32% 0 0);
  }
  .foot {
    animation-duration: calc(var(--cycle) * 2 / var(--speed));
    animation-delay: calc((0.22s / var(--speed) + var(--_hold)) * 2);
  }
  @keyframes settle-fade {
    0%   { transform: none; opacity: 0.5; }
    12%  { transform: none; opacity: 1; }
    100% { transform: none; opacity: 1; }
  }
  @keyframes hold-fade {
    0%   { opacity: 0.5; }
    12%  { opacity: 1; }
    100% { opacity: 1; }
  }
}
</style>
</head>
<body>
  <div class="panel">
    <div class="head">
      <b>Output settings</b>
      <span>Applied</span>
    </div>
    <div class="rows">
      <div class="row"><div class="label"></div><div class="dot"></div></div>
      <div class="row"><div class="label"></div><div class="dot"></div></div>
      <div class="row"><div class="label"></div><div class="dot"></div></div>
      <div class="row"><div class="label"></div><div class="dot"></div></div>
    </div>
    <div class="meter"><i></i></div>
    <div class="foot">Recalculated from 4 inputs</div>
  </div>
</body>
</html>

The variant family

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