This component no longer exists. It was in ns-ui’s manifest when we first indexed it and is not there now — the registry served its inventory on 2026-08-07 and this item was not on it. The install command below will fail. It is kept here because a tutorial somewhere still tells people to run it.
Countdown Vapor Digits
ns-ui/countdown-vapor-digitsRemovedComponent
Live countdown where each digit change is a phase transition: the outgoing digit sublimates into grains on curl-noise wind while the incoming digit condenses from the same cloud.
Live preview
live · rendered by the registry
Rendered by ns-ui on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://design.helpmarq.com/r/countdown-vapor-digits.jsonSource
1"use client";23import { useEffect, useRef } from "react";45// ---------------------------------------------------------------------------6// deterministic 2-octave value noise — house field, no deps7// ---------------------------------------------------------------------------8function hash2(x: number, y: number) {9 const n = Math.sin(x * 127.1 + y * 311.7) * 43758.5453123;10 return n - Math.floor(n);11}12function vnoise(x: number, y: number) {13 const xi = Math.floor(x);14 const yi = Math.floor(y);15 const xf = x - xi;16 const yf = y - yi;17 const u = xf * xf * (3 - 2 * xf);18 const v = yf * yf * (3 - 2 * yf);19 const a = hash2(xi, yi);20 const b = hash2(xi + 1, yi);21 const c = hash2(xi, yi + 1);22 const d = hash2(xi + 1, yi + 1);23 return a + (b - a) * u + (c - a) * v + (a - b - c + d) * u * v;24}25function noise2(x: number, y: number) {26 return 0.65 * vnoise(x, y) + 0.35 * vnoise(x * 2.1 + 19.7, y * 2.1 + 7.3);27}2829// ---------------------------------------------------------------------------30// VaporCountdown — live countdown where every digit change is a phase31// transition: the outgoing digit sublimates into monochrome grains drifting up32// on curl-noise wind while the incoming digit condenses from the same cloud,33// grains spring-seeking their new glyph homes. Canvas 2D over a real <time>34// element (screen-reader truth). Direct-DOM rAF loop, no React state on the35// hot path; hour/minute columns sleep between their rare transitions.36// ---------------------------------------------------------------------------3738const FLOATS = 6; // grains: x, y, vx, vy, hx, hy · vapor: x, y, vx, vy, age, life39const MAX_GRAINS = 2500; // per digit40const SAMPLE_STRIDE = 3; // px between alpha samples on the glyph raster41const SPRING_K = 90; // s⁻² — hero-gravity-well constants exactly42const ZETA = 0.55; // damping ratio; < 1 gives a soft condensation overshoot43const DRAG = 0.92; // per-frame velocity drag44const DT_MAX = 0.032; // s — clamp tab-switch jumps45const FIELD_SCALE = 0.008; // px → noise units for the wind field46const CURL_EPS = 0.75; // noise-space finite-difference step for curl47const PAD_X = 40; // canvas overdraw so vapor is not clipped at the digits' box48const PAD_TOP = 110;49const PAD_BOTTOM = 20;5051const DEFAULT_LABELS = ["HOURS", "MINUTES", "SECONDS"] as const;5253type Slot = {54 g: Float32Array; // incoming/settled grains55 v: Float32Array; // sublimating vapor grains56 gc: number;57 vc: number;58 active: boolean;59};6061// … truncated
