Installation
pnpm dlx shadcn@latest add https://asciicn.dev/r/tokyo.jsonUsage
import { Tokyo } from "@/components/asciicn/tokyo";
export function Hero() {
return (
<section className="relative isolate min-h-[480px]">
<Tokyo intensity={0.6} className="absolute inset-0 -z-10" />
<h1>Your headline</h1>
</section>
);
}The view looks west from a rooftop in the east of the city, 64 m up. The scene is built in 3D and raymarched from that camera: the city is a grid of lots, each with its own block, walked front to back so every wall, roof and street is a real surface at a real distance. The grid runs at an angle to the view, so blocks show two faces and the avenues run off toward the horizon as lines of light. Past a few kilometres the city carries on in long steps until it melts into the haze.
The Tokyo Skytree stands at the right, about 1.7 km away, drawn to its real proportions: a tripod base that narrows into a round lattice shaft, the three-tier Tembo Deck at 350 m, the Tembo Galleria ring at 450 m and the antenna mast to 634 m. It is lit in pale blue round a white core, its decks bright and rimmed in violet, with red lights on the mast. Tokyo Tower stands far off at the left, small and orange. Mount Fuji rises a few degrees above the horizon, 90 km away, its snow cap bright on the side facing the low moon.
Light comes from the moon in the west, the glow of the sky, warm street light caught in the low haze, and the city's own lights: office floors in white and cyan, homes in warm light, vertical neon signs on the near streets and red aircraft lights on the tall roofs. Haze thickens with distance, so each layer of blocks is a little lighter than the one in front of it.
Motion is slow and sparse: a few windows switch on or off over tens of seconds, aircraft lights pulse out of step, traffic creeps along the avenues, the neon breathes, haze drifts and stars twinkle. Nothing responds to the pointer.
It draws in dots by default on square 7px cells, about 200 columns across a 1440px screen. Every colour is snapped to a palette of 46 chosen for the scene, and dot size follows brightness through bayer4 ordered dithering, so it reads like a print. In truecolor, the default, it paints its own night on a night paper, so it looks the same on light and dark pages. The Skytree stays right of centre on a wide screen; in a tall box the view narrows and gains height, so the tower fills a phone.
The central band, the middle half of the width from 30% to 65% of the height, holds sky and the far horizon. intensity dims the colours and shrinks the dots, most of all in that band. Lower it to keep text on top easy to read.
Examples
Behind a headline
Full-bleed behind a centred headline and two buttons. intensity={0.6} quiets the middle band so the text reads first, while the Skytree and the city still frame it.
In a tall card
In a 9:19 box the view narrows and gains height, so the Skytree fills the frame above the city.
In sodium duotone
colorMode="duotone" with ramp="sodium" runs every dot's tone through one amber ramp, so dot size alone draws the Skytree, the city and Fuji.
Props
| Prop | Type | Default |
|---|---|---|
| intensity How strongly it draws, from 0 (faint) to 1. Lower values quiet the middle band most, so text on top stays readable. | Type: number | Default 1 |
| fuji Draws Mount Fuji, small and moonlit on the far horizon. | Type: boolean | Default true |
| tokyoTower Draws Tokyo Tower, small and orange in the distance at the left. | Type: boolean | Default true |
| charset Which glyphs draw the scene. See Charsets. | Type: CharsetName | Default "dots" |
| chars A custom ramp from empty to dense, such as " .oO@". Wins over charset. | Type: string | Default – |
| colorMode How glyphs are coloured. truecolor uses the scene's own colours, mono uses the theme ink or a phosphor, duotone runs tone through a ramp. "mono" when a phosphor is set. | Type: "mono" | "truecolor" | "ansi16" | "duotone" | "palette" | Default "truecolor" |
| phosphor A CRT ink and glass for mono mode. Setting one switches colorMode to mono. | Type: "p1" | "p3" | "ibm" | "blueprint" | Default – |
| ramp In duotone mode, the colour ramp from dark to light. | Type: RampName | string[] | Default – |
| ansi In ansi16 mode, which 16-colour table. | Type: "vga" | "xterm" | Default "vga" |
| grade Brightness, contrast, gamma and saturation applied to tones before glyphs are picked. | Type: Grade | Default – |
| invert Dense glyphs for dark tones instead of bright ones. | Type: boolean | Default false |
| threshold Braille and quadrants: the tone that lights a dot. | Type: number | Default 0.5 |
| edgeThreshold Edge charset: how strong a change in tone must be to draw - / | or \. | Type: number | Default 0.22 |
| dither Ordered dithering between neighbouring dot sizes, which turns five dots into smooth tone like a print. | Type: "none" | "bayer2" | "bayer4" | "bayer8" | "blue-noise" | Default "bayer4" |
| background "transparent" draws the glyphs only, over your own surface. | Type: "paper" | "transparent" | Default "paper" |
| fx CRT finish: scanlines, bloom, curvature, glitch, flicker and vignette, each 0 to 1. | Type: PostFx | Default – |
| interactive Accepted so any stage can pass it, and ignored: the city does not respond to the pointer. | Type: boolean | Default – |
| square Cells as wide as they are tall, so the dots lay an even lattice. Braille and quadrants default to false, since they would stretch. | Type: boolean | Default true for dots and other one-glyph charsets |
| cell Height of one glyph cell in CSS pixels, and its width too when square. | Type: number | Default 7 |
| speed How fast it moves. | Type: number | Default 1 |
| animate false stops the motion: a still frame if it starts off, the current frame if it was moving. | Type: boolean | Default true |
| fps Frame rate cap. | Type: number | Default 30 |
| stillTime The moment drawn when motion is off or reduced, in seconds. | Type: number | Default 4 |
| handle Filled with a handle that reads back the current frame, for export to text, ANSI, SVG or PNG. | Type: RefObject<AsciiHandle | null> | Default – |
| paper Paper behind the glyphs. By default the scene's night colour in truecolor, ansi16 and duotone, and the theme's paper (or the phosphor's) otherwise. | Type: AsciiColor | Default – |
| fallback Shown without WebGL and until the first frame. By default a night gradient. | Type: ReactNode | Default – |
| className Size and position. The background fills this box. | Type: string | Default – |
Notes
- It is decorative and hidden from assistive technology. Put real text on top of it, not inside it.
- With reduced motion turned on, it draws one still frame at
stillTimeand stops. - It pauses when scrolled out of view or when the tab is hidden, and releases its WebGL context when far offscreen. Without WebGL it shows a night gradient.
- Nothing responds to the pointer, and there is no
interactionprop. - The whole scene is one GPU pass that raymarches the city for every sample, so its cost depends on the number of samples.
braillesamples eight times per cell; a largercellmakes it cheaper. See Performance.