Back to CSS Number Counter Animations Space Mission Control CSS + JS
Share
HTML
<div class="cnc-space">
  <div class="cnc-space-mission">
    <div class="cnc-space-left-col">
      <div class="cnc-space-p">
        <div class="cnc-space-ph"><div class="cnc-space-ph-dot"></div>Propulsion</div>
        <div class="cnc-space-side-stat">
          <div class="cnc-space-ss-label">Thrust Output</div>
          <div class="cnc-space-ss-num cnc-space-amber"><span class="cnc-num" data-target="98.4" data-decimals="1">0</span><span class="cnc-space-ss-unit">%</span></div>
          <div class="cnc-space-ss-sub">All engines nominal</div>
        </div>
      </div>
      <div class="cnc-space-p">
        <div class="cnc-space-ph"><div class="cnc-space-ph-dot"></div>Navigation</div>
        <div class="cnc-space-side-stat">
          <div class="cnc-space-ss-label">Velocity</div>
          <div class="cnc-space-ss-num cnc-space-teal"><span class="cnc-num" data-target="28400">0</span><span class="cnc-space-ss-unit">km/h</span></div>
          <div class="cnc-space-ss-sub">Orbital insertion achieved</div>
        </div>
      </div>
      <div class="cnc-space-p">
        <div class="cnc-space-ph"><div class="cnc-space-ph-dot"></div>System Status</div>
        <div class="cnc-space-status-grid">
          <div class="cnc-space-status-item"><div class="cnc-space-s-dot cnc-space-ok"></div>LIFE SUPPORT</div>
          <div class="cnc-space-status-item"><div class="cnc-space-s-dot cnc-space-ok"></div>POWER GRID</div>
          <div class="cnc-space-status-item"><div class="cnc-space-s-dot cnc-space-ok"></div>COMMS LINK</div>
          <div class="cnc-space-status-item"><div class="cnc-space-s-dot cnc-space-warn"></div>SOLAR PNL B</div>
          <div class="cnc-space-status-item"><div class="cnc-space-s-dot cnc-space-ok"></div>NAVIGATION</div>
          <div class="cnc-space-status-item"><div class="cnc-space-s-dot cnc-space-ok"></div>PROPULSION</div>
          <div class="cnc-space-status-item"><div class="cnc-space-s-dot cnc-space-err"></div>GYRO 3</div>
          <div class="cnc-space-status-item"><div class="cnc-space-s-dot cnc-space-ok"></div>THERMAL</div>
        </div>
      </div>
      <div class="cnc-space-p">
        <div class="cnc-space-ph"><div class="cnc-space-ph-dot"></div>Data Feed</div>
        <div class="cnc-space-feed">
          <div class="cnc-space-feed-line cnc-space-fl1">[02:14:33] ALT 408.2km · STABLE</div>
          <div class="cnc-space-feed-line cnc-space-fl2">[02:14:35] WARN: GYRO-3 DRIFT +0.04°</div>
          <div class="cnc-space-feed-line cnc-space-fl3">[02:14:38] THRUSTER B OK 98.4%</div>
          <div class="cnc-space-feed-line cnc-space-fl4">[02:14:41] TELEMETRY UPLINK OK</div>
          <div class="cnc-space-feed-line cnc-space-fl5">[02:14:44] ORBIT PERIOD 92.4MIN</div>
          <div class="cnc-space-feed-line cnc-space-fl6">[02:14:47] SOLAR-B OUTPUT −12%</div>
        </div>
      </div>
    </div>
    <div class="cnc-space-p cnc-space-center-main">
      <div class="cnc-space-ph"><div class="cnc-space-ph-dot"></div>Mission Control · ISS-NEXUS · Day 47</div>
      <div class="cnc-space-orbital">
        <svg class="cnc-space-orbit-svg" viewBox="0 0 220 220" fill="none">
          <ellipse cx="110" cy="110" rx="100" ry="40" stroke="rgba(0,212,200,0.2)" stroke-width="1" stroke-dasharray="4 4"/>
          <circle cx="210" cy="110" r="5" fill="#00d4c8" style="filter:drop-shadow(0 0 6px #00d4c8)"/>
        </svg>
        <svg class="cnc-space-orbit-svg-inner" viewBox="0 0 160 160" fill="none">
          <ellipse cx="80" cy="80" rx="70" ry="28" stroke="rgba(255,180,0,0.15)" stroke-width="1"/>
          <circle cx="150" cy="80" r="3" fill="#ffb400" style="filter:drop-shadow(0 0 4px #ffb400)"/>
        </svg>
        <div class="cnc-space-orbit-center">
          <div class="cnc-space-planet"></div>
        </div>
      </div>
      <div class="cnc-space-readout">
        <div class="cnc-space-readout-label">Altitude · Current Orbit</div>
        <div class="cnc-space-readout-num">
          <span class="cnc-num" data-target="408" data-decimals="1">0</span>
          <span class="cnc-space-readout-unit">km</span>
        </div>
      </div>
      <div class="cnc-space-mission-clock">
        <div class="cnc-space-clock-label">Mission Elapsed Time</div>
        <div class="cnc-space-clock-time">47:02:14:33</div>
      </div>
      <div class="cnc-space-p" style="border:none; background:transparent;">
        <div class="cnc-space-ph" style="border-color: rgba(0,212,200,0.1)"><div class="cnc-space-ph-dot"></div>Telemetry</div>
        <div class="cnc-space-telem">
          <div class="cnc-space-telem-row">
            <span class="cnc-space-telem-id">PWR</span>
            <div class="cnc-space-telem-track"><div class="cnc-space-telem-fill cnc-space-tc" style="width:91%"></div></div>
            <span class="cnc-space-telem-val">91%</span>
          </div>
          <div class="cnc-space-telem-row">
            <span class="cnc-space-telem-id">TEMP</span>
            <div class="cnc-space-telem-track"><div class="cnc-space-telem-fill cnc-space-ta" style="width:67%"></div></div>
            <span class="cnc-space-telem-val">67%</span>
          </div>
          <div class="cnc-space-telem-row">
            <span class="cnc-space-telem-id">O₂</span>
            <div class="cnc-space-telem-track"><div class="cnc-space-telem-fill cnc-space-tg" style="width:88%"></div></div>
            <span class="cnc-space-telem-val">88%</span>
          </div>
          <div class="cnc-space-telem-row">
            <span class="cnc-space-telem-id">FUEL</span>
            <div class="cnc-space-telem-track"><div class="cnc-space-telem-fill cnc-space-tb" style="width:74%"></div></div>
            <span class="cnc-space-telem-val">74%</span>
          </div>
          <div class="cnc-space-telem-row">
            <span class="cnc-space-telem-id">LOAD</span>
            <div class="cnc-space-telem-track"><div class="cnc-space-telem-fill cnc-space-tr" style="width:52%"></div></div>
            <span class="cnc-space-telem-val">52%</span>
          </div>
        </div>
      </div>
    </div>
    <div class="cnc-space-right-col">
      <div class="cnc-space-p">
        <div class="cnc-space-ph"><div class="cnc-space-ph-dot"></div>Crew</div>
        <div class="cnc-space-side-stat">
          <div class="cnc-space-ss-label">Aboard</div>
          <div class="cnc-space-ss-num cnc-space-green"><span class="cnc-num" data-target="7">0</span><span class="cnc-space-ss-unit">crew</span></div>
          <div class="cnc-space-ss-sub">All crew nominal</div>
        </div>
      </div>
      <div class="cnc-space-p">
        <div class="cnc-space-ph"><div class="cnc-space-ph-dot"></div>Comms</div>
        <div class="cnc-space-side-stat">
          <div class="cnc-space-ss-label">Signal Strength</div>
          <div class="cnc-space-ss-num cnc-space-teal"><span class="cnc-num" data-target="99.7" data-decimals="1">0</span><span class="cnc-space-ss-unit">%</span></div>
          <div class="cnc-space-ss-sub">Uplink: 3 satellites</div>
        </div>
      </div>
      <div class="cnc-space-p">
        <div class="cnc-space-ph"><div class="cnc-space-ph-dot"></div>Thermal</div>
        <div class="cnc-space-side-stat">
          <div class="cnc-space-ss-label">External Temp</div>
          <div class="cnc-space-ss-num cnc-space-amber"><span class="cnc-num" data-target="-157">0</span><span class="cnc-space-ss-unit">°C</span></div>
          <div class="cnc-space-ss-sub">Shadow pass cycle</div>
        </div>
      </div>
      <div class="cnc-space-p">
        <div class="cnc-space-ph"><div class="cnc-space-ph-dot"></div>Orbits Completed</div>
        <div class="cnc-space-side-stat">
          <div class="cnc-space-ss-label">Total Revolutions</div>
          <div class="cnc-space-ss-num cnc-space-red"><span class="cnc-num" data-target="736">0</span></div>
          <div class="cnc-space-ss-sub">Next: 47d 3h 22m</div>
        </div>
      </div>
    </div>
  </div>
</div>
CSS
.cnc-space {
  --space-bg: #020b18;
  --space-panel: rgba(8, 28, 55, 0.85);
  --space-amber: #ffb400;
  --space-amber-dim: rgba(255,180,0,0.5);
  --space-teal: #00d4c8;
  --space-red: #ff3d3d;
  --space-green: #39ff14;
  --space-blue: #4da6ff;
  --space-border: rgba(0,212,200,0.2);
  position: relative;
  display: flex; align-items: center; justify-content: center;
  padding: 32px 20px;
  background: var(--space-bg);
  background-image:
    radial-gradient(ellipse at 50% 0%, rgba(0,212,200,0.04) 0%, transparent 60%),
    radial-gradient(ellipse at 0% 100%, rgba(255,180,0,0.03) 0%, transparent 50%);
  font-family: 'Space Mono', monospace;
  color: var(--space-teal);
  overflow: hidden;
}
.cnc-space::before {
  content: ''; position: absolute; inset: 0;
  background-image:
    radial-gradient(1px 1px at 10% 15%, rgba(255,255,255,0.6) 0%, transparent 100%),
    radial-gradient(1px 1px at 20% 60%, rgba(255,255,255,0.4) 0%, transparent 100%),
    radial-gradient(1px 1px at 35% 25%, rgba(255,255,255,0.5) 0%, transparent 100%),
    radial-gradient(1px 1px at 50% 80%, rgba(255,255,255,0.3) 0%, transparent 100%),
    radial-gradient(1px 1px at 65% 10%, rgba(255,255,255,0.6) 0%, transparent 100%),
    radial-gradient(1px 1px at 75% 45%, rgba(255,255,255,0.4) 0%, transparent 100%),
    radial-gradient(1px 1px at 85% 70%, rgba(255,255,255,0.5) 0%, transparent 100%),
    radial-gradient(1px 1px at 90% 30%, rgba(255,255,255,0.3) 0%, transparent 100%);
  pointer-events: none; z-index: 0;
}
.cnc-space-mission {
  position: relative; z-index: 1;
  width: 1000px;
  display: grid;
  grid-template-columns: 200px 1fr 200px;
  grid-template-rows: auto auto auto;
  gap: 10px;
}
.cnc-space-p {
  background: var(--space-panel);
  border: 1px solid var(--space-border);
  backdrop-filter: blur(12px);
  position: relative; overflow: hidden;
  opacity: 0; animation: cnc-space-panelIn 0.6s ease forwards;
}
.cnc-space-p::after {
  content: ''; position: absolute;
  top: 0; left: 0; right: 0; height: 1px;
  background: linear-gradient(90deg, transparent, var(--space-teal), transparent);
  opacity: 0.5;
}
@keyframes cnc-space-panelIn {
  from { opacity: 0; transform: scale(0.98); }
  to { opacity: 1; transform: scale(1); }
}
.cnc-space-left-col > .cnc-space-p:nth-child(1) { animation-delay: 0.0s; }
.cnc-space-left-col > .cnc-space-p:nth-child(2) { animation-delay: 0.1s; }
.cnc-space-left-col > .cnc-space-p:nth-child(3) { animation-delay: 0.2s; }
.cnc-space-left-col > .cnc-space-p:nth-child(4) { animation-delay: 0.3s; }
.cnc-space-center-main { animation-delay: 0.15s; }
.cnc-space-right-col > .cnc-space-p:nth-child(1) { animation-delay: 0.25s; }
.cnc-space-right-col > .cnc-space-p:nth-child(2) { animation-delay: 0.35s; }
.cnc-space-right-col > .cnc-space-p:nth-child(3) { animation-delay: 0.45s; }
.cnc-space-right-col > .cnc-space-p:nth-child(4) { animation-delay: 0.55s; }
.cnc-space-ph {
  padding: 8px 12px;
  border-bottom: 1px solid var(--space-border);
  font-size: 7px; letter-spacing: 3px; text-transform: uppercase;
  color: var(--space-amber);
  display: flex; align-items: center; gap: 6px;
}
.cnc-space-ph-dot {
  width: 5px; height: 5px; border-radius: 50%;
  background: var(--space-amber);
  box-shadow: 0 0 6px var(--space-amber);
  animation: cnc-space-blinkAmber 2s step-end infinite;
}
@keyframes cnc-space-blinkAmber {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.2; }
}
.cnc-space-center-main {
  grid-column: 2; grid-row: 1 / 4;
  padding: 24px;
  display: flex; flex-direction: column; gap: 20px;
}
.cnc-space-orbital {
  display: flex; justify-content: center; align-items: center;
  padding: 16px 0; position: relative;
}
.cnc-space-orbit-svg {
  width: 220px; height: 220px;
  animation: cnc-space-orbitSpin 30s linear infinite;
  position: absolute;
}
@keyframes cnc-space-orbitSpin { to { transform: rotate(360deg); } }
.cnc-space-orbit-svg-inner {
  width: 160px; height: 160px;
  animation: cnc-space-orbitSpin 20s linear infinite reverse;
  position: absolute;
}
.cnc-space-orbit-center {
  width: 220px; height: 220px;
  display: flex; align-items: center; justify-content: center;
  position: relative; z-index: 2;
}
.cnc-space-planet {
  width: 80px; height: 80px; border-radius: 50%;
  background: radial-gradient(circle at 35% 35%, #4da6ff, #021830);
  box-shadow:
    0 0 30px rgba(77,166,255,0.4),
    inset 0 0 20px rgba(0,0,0,0.5);
}
.cnc-space-readout { text-align: center; }
.cnc-space-readout-label {
  font-size: 8px; letter-spacing: 4px; text-transform: uppercase;
  color: var(--space-amber); margin-bottom: 6px;
}
.cnc-space-readout-num {
  font-family: 'Exo 2', sans-serif;
  font-size: clamp(48px, 6vw, 72px); font-weight: 900;
  color: #fff; letter-spacing: -2px; line-height: 1;
  text-shadow: 0 0 30px var(--space-teal), 0 0 60px rgba(0,212,200,0.3);
  display: flex; align-items: baseline; justify-content: center; gap: 6px;
}
.cnc-space-readout-unit {
  font-size: 0.3em;
  font-family: 'Space Mono', monospace;
  font-weight: 400; color: var(--space-teal); letter-spacing: 3px;
}
.cnc-space-telem {
  padding: 12px;
  display: flex; flex-direction: column; gap: 8px;
}
.cnc-space-telem-row {
  display: flex; align-items: center; gap: 8px;
}
.cnc-space-telem-id {
  font-size: 7px; letter-spacing: 2px;
  color: var(--space-amber-dim); width: 36px; flex-shrink: 0;
}
.cnc-space-telem-track {
  flex: 1; height: 3px;
  background: rgba(255,255,255,0.05);
  position: relative; overflow: hidden;
}
.cnc-space-telem-fill {
  height: 100%; transform: scaleX(0); transform-origin: left;
  animation: cnc-space-tlFill 1.5s ease forwards;
}
.cnc-space-tc { background: var(--space-teal); animation-delay: 0.8s; }
.cnc-space-ta { background: var(--space-amber); animation-delay: 0.95s; }
.cnc-space-tg { background: var(--space-green); animation-delay: 1.1s; }
.cnc-space-tb { background: var(--space-blue); animation-delay: 1.25s; }
.cnc-space-tr { background: var(--space-red); animation-delay: 1.4s; }
@keyframes cnc-space-tlFill { to { transform: scaleX(1); } }
.cnc-space-telem-val {
  font-size: 9px; color: rgba(255,255,255,0.5);
  width: 32px; text-align: right; flex-shrink: 0;
}
.cnc-space-side-stat { padding: 12px 14px; }
.cnc-space-ss-label {
  font-size: 7px; letter-spacing: 3px;
  color: var(--space-amber-dim); text-transform: uppercase;
  margin-bottom: 6px;
}
.cnc-space-ss-num {
  font-family: 'Exo 2', sans-serif;
  font-size: clamp(26px, 3vw, 38px); font-weight: 900;
  line-height: 1; letter-spacing: -1px;
}
.cnc-space-teal { color: var(--space-teal); text-shadow: 0 0 16px var(--space-teal); }
.cnc-space-amber { color: var(--space-amber); text-shadow: 0 0 16px var(--space-amber); }
.cnc-space-green { color: var(--space-green); text-shadow: 0 0 16px var(--space-green); }
.cnc-space-red { color: var(--space-red); text-shadow: 0 0 16px var(--space-red); }
.cnc-space-ss-unit {
  font-size: 0.35em;
  font-family: 'Space Mono', monospace;
  font-weight: 400; opacity: 0.5; margin-left: 2px;
}
.cnc-space-ss-sub {
  font-size: 8px; color: rgba(255,255,255,0.2);
  margin-top: 4px; letter-spacing: 1px;
}
.cnc-space-mission-clock {
  text-align: center; padding: 10px;
  background: rgba(0,212,200,0.04);
  border: 1px solid rgba(0,212,200,0.1);
  margin: 0 8px;
}
.cnc-space-clock-label {
  font-size: 7px; letter-spacing: 4px;
  color: var(--space-amber); margin-bottom: 4px;
}
.cnc-space-clock-time {
  font-size: 22px; font-weight: 700;
  color: var(--space-teal);
  text-shadow: 0 0 12px var(--space-teal);
  letter-spacing: 3px;
}
.cnc-space-status-grid {
  padding: 10px 12px;
  display: grid; grid-template-columns: 1fr 1fr; gap: 6px;
}
.cnc-space-status-item {
  display: flex; align-items: center; gap: 6px;
  font-size: 7px; letter-spacing: 1px;
  color: rgba(255,255,255,0.4);
}
.cnc-space-s-dot {
  width: 6px; height: 6px; border-radius: 50%; flex-shrink: 0;
}
.cnc-space-ok { background: var(--space-green); box-shadow: 0 0 6px var(--space-green); }
.cnc-space-warn { background: var(--space-amber); box-shadow: 0 0 6px var(--space-amber); }
.cnc-space-err {
  background: var(--space-red);
  box-shadow: 0 0 6px var(--space-red);
  animation: cnc-space-blinkAmber 0.8s step-end infinite;
}
.cnc-space-feed {
  padding: 10px 12px;
  font-size: 7px; letter-spacing: 1px;
  overflow: hidden; height: 90px; position: relative;
}
.cnc-space-feed-line {
  padding: 3px 0;
  border-bottom: 1px solid rgba(0,212,200,0.05);
  white-space: nowrap;
  animation: cnc-space-feedScroll 12s linear infinite;
}
@keyframes cnc-space-feedScroll {
  0% { opacity: 0; }
  5%, 85% { opacity: 1; }
  100% { opacity: 0; }
}
.cnc-space-fl1 { color: var(--space-teal); animation-delay: 0s; }
.cnc-space-fl2 { color: var(--space-amber); animation-delay: 2s; }
.cnc-space-fl3 { color: var(--space-green); animation-delay: 4s; }
.cnc-space-fl4 { color: rgba(255,255,255,0.4); animation-delay: 6s; }
.cnc-space-fl5 { color: var(--space-teal); animation-delay: 8s; }
.cnc-space-fl6 { color: var(--space-red); animation-delay: 10s; }
.cnc-space-left-col {
  grid-column: 1;
  display: flex; flex-direction: column; gap: 10px;
}
.cnc-space-right-col {
  grid-column: 3;
  display: flex; flex-direction: column; gap: 10px;
}
@media (prefers-reduced-motion: reduce) {
  .cnc-space-p, .cnc-space-orbit-svg, .cnc-space-orbit-svg-inner,
  .cnc-space-telem-fill, .cnc-space-ph-dot, .cnc-space-s-dot.cnc-space-err,
  .cnc-space-feed-line { animation: none; }
  .cnc-space-p { opacity: 1; }
  .cnc-space-telem-fill { transform: scaleX(1); }
}
JS
(function () {
  function ease(t) { return 1 - Math.pow(1 - t, 3); }
  var root = document.querySelector('.cnc-space');
  if (!root) return;
  root.querySelectorAll('.cnc-num[data-target]').forEach(function (el) {
    var target = parseFloat(el.dataset.target);
    var decimals = parseInt(el.dataset.decimals || 0, 10);
    var duration = 2000;
    setTimeout(function () {
      var start = performance.now();
      function tick(now) {
        var t = Math.min((now - start) / duration, 1);
        var val = ease(t) * target;
        el.textContent = decimals > 0
          ? val.toFixed(decimals)
          : Math.round(val).toLocaleString();
        if (t < 1) requestAnimationFrame(tick);
      }
      requestAnimationFrame(tick);
    }, 300);
  });
  var clockEl = root.querySelector('.cnc-space-clock-time');
  if (clockEl) {
    var baseSec = 47 * 24 * 3600 + 2 * 3600 + 14 * 60 + 33;
    var startMs = Date.now();
    function updateClock() {
      var elapsed = Math.floor((Date.now() - startMs) / 1000);
      var total = baseSec + elapsed;
      var d = Math.floor(total / 86400);
      var h = String(Math.floor((total % 86400) / 3600)).padStart(2, '0');
      var m = String(Math.floor((total % 3600) / 60)).padStart(2, '0');
      var s = String(total % 60).padStart(2, '0');
      clockEl.textContent = d + ':' + h + ':' + m + ':' + s;
    }
    updateClock();
    setInterval(updateClock, 1000);
  }
})();