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.
Button Cooldown Heat
ns-ui/button-cooldown-heatRemovedComponent
A rate-limited button that heat-soaks: each press deposits heat into a visible bottom-up fill, dilates its letter-spacing, swells its surface and brightens its border, growing a heat-haze shimmer as it nears the limit and decaying exponentially (fill draining, haze fading) when idle — hammered past its duty cycle it soaks into a distinct hazard-hatched dead state, going dead on a flat 1px dip until it visibly cools back below the re-arm mark.
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/button-cooldown-heat.jsonSource
1"use client";23import { useEffect, useId, useRef, useState, type ReactNode } from "react";45// ---------------------------------------------------------------------------6// HeatSoak — a rate-limited button whose own body is the thermometer. A7// scalar `h` ("heat") accumulates +0.34 per press and decays exponentially8// (half-life 2.5s) in a single rAF loop, written straight onto the button as9// a `--heat` CSS custom property. All visual layers read that one property10// (clamped to 1 via CSS `min()` as `--h`, plus a `--warm` ramp that's 0 below11// h=0.7 and climbs 0->1 across 0.7-1.0): letter-spacing, scale and12// border-color dilate the button itself; a bottom-up fill layer reads --h13// directly so the accumulated heat has an actual gauge to point at, not just14// a swelling border; a soft haze band sweeps the surface at an opacity gated15// to --warm, so it's only visible once the button is genuinely close to (or16// still cooling from) the limit — never at rest. No progress bar, no digit:17// the fill and the shimmer *are* the gauge.18//19// Past a duty cycle (h >= 1.0) it "soaks": the flag latches (hysteresis —20// re-arms only once h decays back to <= 0.05, i.e. genuinely cooled, not21// merely below the limit again, so one press right after re-arming can't22// instantly punch it back over SOAK_AT and the lockout holds for the whole23// cooldown, not a sliver of it), the fill grows a diagonal hazard hatch and24// breathes gently — a distinct, unmissable "dead" read, not just the same25// warm tone held longer —26// and the label itself dims toward --muted. Further presses no-op the actual27// action, instead getting a flat, dead 1px translateY dip that eases back28// with no spring overshoot — an "overdamped" non-response, not a bigger29// animation (the hazard breathing is a separate, deliberately ambient loop,30// not the dip's feedback). aria-disabled (never the native `disabled`31// attribute) keeps the button in the tab order and clickable the whole time;32// a visible Geist Mono caption under the button duplicates every thermal cue33// in words ("heat 62%", then "cooling down, ready in about 4s") so nothing34// here rides on motion alone, and a separate sr-only aria-live=polite span35// announces only the two discrete transitions (entered soak / re-armed)36// rather than re-reading a ticking countdown.37//38// The same fill and haze double as the cooldown display: nothing resets when39// … truncated
