For the complete documentation index, see llms.txt. Markdown variants are available by appending .md to any URL or sending an Accept: text/markdown header. The asciicn agent skill, for building any ASCII effect on the engine, is at /.well-known/agent-skills/asciicn/SKILL.md.

ASCII countdown

A launch countdown in big glyph digits that scramble as they change.

Controls
Charset
Accent
Colour
Scramble0.45s
Ghost pixels

Installation

pnpm dlx shadcn@latest add https://asciicn.dev/r/ascii-countdown.json

Usage

import { AsciiCountdown } from "@/components/asciicn/ascii-countdown";
 
export function Launch() {
  return (
    <AsciiCountdown
      to="2026-12-01T17:00:00Z"
      onComplete={() => console.log("launched")}
    />
  );
}

to takes a Date, an ISO string or epoch milliseconds. The clock shows days, hours, minutes and seconds, each digit drawn from a 5x7 pixel font. At zero it draws doneText in the same type and calls onComplete once.

The countdown fills its container's width. It picks the largest digit that fits, up to size pixels tall, by changing how many cells each font pixel covers. When one row would make the digits smaller than 40 px, as on a phone, it splits into two rows: days and hours, then minutes and seconds.

When a digit changes, only the cells that differ run through a few glyphs and settle, each at its own moment. scramble sets how long that takes. The colons dim and brighten once a second, in step with the seconds.

Examples

size={22} and 6 px cells keep the digits small enough for a strip at the top of a page. Labels and ghost pixels are off, and only the colons take the accent.

Done state

Five seconds out, with hideZeroDays. At zero the last digits scramble into doneText and onComplete changes the button.

Braille dot matrix

charset="braille" draws each font pixel as a patch of dots. colorMode="duotone" shades each digit from the top of the sodium ramp down. Duotone ramps are tuned for dark paper.

Props

PropTypeDefault
to

The moment to count down to: a Date, an ISO string or epoch milliseconds.

Type: Date | string | numberDefault –
labels

Labels under days, hours, minutes and seconds, or false for none.

Type: readonly [string, string, string, string] | falseDefault ["DAYS", "HRS", "MIN", "SEC"]
doneText

Drawn in the same big type once the countdown reaches zero. Letters, digits and ! ? . - /.

Type: stringDefault "LIVE"
onComplete

Called once when the countdown reaches zero, or on mount if to has already passed.

Type: () => voidDefault –
scramble

Seconds a changed digit scrambles before it settles. 0 turns it off.

Type: numberDefault 0.45
hideZeroDays

Drop the days group once fewer than 24 hours are left.

Type: booleanDefault false
charset

Glyphs the digits are drawn with. blocks draws half blocks, quadrants and braille split each cell, ramps use their densest glyph.

Type: CharsetNameDefault "blocks"
chars

A custom ramp from empty to dense. Its densest glyph inks the digits. Wins over charset.

Type: stringDefault –
colorMode

mono draws digits in ink and the accent; duotone shades the ink digits top to bottom along ramp.

Type: "mono" | "duotone"Default "mono"
ramp

duotone: a ramp name or #rrggbb stops.

Type: RampName | readonly string[]Default "sodium"
accent

The accent colour: a palette name, CSS variable name or any CSS colour.

Type: AsciiColorDefault "orange"
accentOn

Which parts take the accent.

Type: "seconds" | "colons" | "both" | "none"Default "seconds"
ghost

Faint dots on the unlit pixels of each digit.

Type: booleanDefault true
size

Largest digit height in CSS pixels. The digits shrink to fit the width.

Type: numberDefault 128
cell

Glyph cell height in CSS pixels. Smaller cells fit the width more closely.

Type: numberDefault 8
animate

false holds still: no scramble or blinking, though the time still ticks.

Type: booleanDefault true
fps

Frame rate cap.

Type: numberDefault 30
paper

Background behind the glyphs.

Type: AsciiColor | "transparent"Default "transparent"
fx

CRT effects, drawn as a CSS overlay.

Type: PostFxDefault –
handle

Filled with a handle for export: the latest frame and the canvas.

Type: RefObject<AsciiHandle | null>Default –

Other props pass through to the root div.

Notes

  • Changed digits scramble for a beat and settle, the colons blink softly, each group has a label under it, and at zero it shows doneText and calls onComplete.
  • The digits are drawn on a canvas that is aria-hidden. A visually hidden role="timer" element gives the time left to the minute and the target date, so a screen reader is not told every second.
  • Nothing that depends on the clock renders on the server. The first client render matches the server, then the countdown starts, so there is no hydration mismatch.
  • With reduced motion, or animate={false}, digits change without scrambling and the colons hold steady. The time still updates every second.
  • The canvas pauses offscreen and in hidden tabs. When it comes back, the digits that changed while it was away scramble once.
  • Labels are page text under the canvas, so they stay readable at any cell size. They take --ascii-ink at reduced opacity and are hidden from screen readers, which get the timer text instead.