Installation
pnpm dlx shadcn@latest add https://asciicn.dev/r/rio.jsonUsage
import { Rio } from "@/components/asciicn/rio";
export function Hero() {
return (
<section className="relative isolate min-h-[480px]">
<Rio intensity={0.85} className="absolute inset-0 -z-10" />
<h1>Your headline</h1>
</section>
);
}The whole frame is painted in halftone dots. Each dot takes its own colour, and its size carries the light: the biggest dots gather in the gold afterglow on the horizon and its reflection, middle dots run through the rose and violet sky, and the deep sky and the shadowed mountains fall to the smallest dots, close to the paper.
The sun has just set between the mountains. Sugarloaf rises out of the bay on the right as a great dark dome that leans towards the lower, forested Morro da Urca beside it. Its flank towards the afterglow catches a rose light and a lit rim, while the face towards you stays in shadow. A cable runs from the top of Urca to the top of Sugarloaf, a fine dark line against the glow, and one cable car's light crosses it: it waits about 12 seconds at each station, then takes about half a minute to cross. On the left, Corcovado climbs out of the Tijuca range, hazier and paler because it stands farther off, to a granite needle with Christ the Redeemer on the summit, small and lit pale by floodlights. Below it, the lamps of Copacabana curve along the shore in a crescent in front of a low wall of apartment blocks, and homes are lit on the lower slopes.
The bay mirrors all of it, darker and cooler, broken into ripples that widen towards you. Under the afterglow runs a long gold reflection, and the beach lamps draw short warm lines down into the water.
Motion is slow: the cable car crosses, the reflections shimmer as the ripples drift, the lamps along the beach twinkle gently, a few windows turn on or off every couple of minutes, thin clouds drift and stars twinkle faintly. The pointer does nothing.
On wide boxes Corcovado and Sugarloaf frame the middle, so the sky over the afterglow stays calm for a headline. On tall boxes the scene is drawn smaller and lower, so both peaks stay in view beneath the headline.
It draws in dots by default on square 7px cells, so the dots lie in an even lattice, about 200 across a 1440px screen. square={false} returns to the usual text cells, twice as tall as wide. Other ramp charsets such as standard or dense read the same tones as typed glyphs. braille and quadrants light a dot only above half tone, so they keep the lit parts (the afterglow, the lights and the reflection) and leave the dark sky and mountains empty. In truecolor, the default, the scene paints its own dusk paper in both themes. duotone with a ramp and mono with a phosphor read the same scene by tone alone.
intensity dims the colours in step and shrinks the dots more gently, so the shapes keep their place behind text.
Examples
Hero
intensity={0.85} quiets the scene a little behind a centred headline and two buttons. Corcovado and Sugarloaf stand either side of the text on wide screens and below it on phones.
Gold print
colorMode="duotone" runs the tones through the sodium ramp, gold on night blue, and cell={5} packs finer dots into a small card.
Props
| Prop | Type | Default |
|---|---|---|
| intensity How strongly the city draws, from 0 to 1. Lower it to keep text on top readable. | Type: number | Default 1 |
| cableCar The cable from Urca to Sugarloaf, its two stations and the car crossing it. | Type: boolean | Default true |
| paper The surface behind the glyphs. Without it, truecolor, ansi16 and duotone sit on a dusk indigo; mono and palette use the theme's paper or the phosphor's. | Type: AsciiColor | Default – |
| square Cells as wide as they are tall, so the dots lie in an even lattice. Off by default for braille and quadrants, which would stretch. | Type: boolean | Default true for dots |
| fallback Shown without WebGL and until the first frame: the dusk as a flat gradient. | Type: ReactNode | Default a gradient |
| charset Which glyphs draw the tones. 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 paints the scene's own colours; mono uses one ink or a phosphor; duotone runs tone through a ramp. | Type: "mono" | "truecolor" | "ansi16" | "duotone" | "palette" | Default "truecolor" |
| phosphor A CRT ink and glass. Setting one switches the default colour mode to mono. | Type: "p1" | "p3" | "ibm" | "blueprint" | Default – |
| ramp In duotone mode, the colour ramp from dark to light. | Type: RampName | string[] | Default "sodium" |
| 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. Lower it to bring the dusk sky and the mountains back. | 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 Blends neighbouring dot sizes so the sky's gradient reads smooth. Blue noise for dots, braille and quadrants; none for other charsets and custom chars. | Type: "none" | "bayer2" | "bayer4" | "bayer8" | "blue-noise" | Default "blue-noise" for dots |
| 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 – |
| cell Height of one glyph cell in CSS pixels. | 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 12 |
| handle Filled with a handle that reads back the current frame, for export to text, ANSI, SVG or PNG. | Type: RefObject<AsciiHandle | null> | 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.
- It ignores the pointer: no parallax and no hover effect.
- With reduced motion turned on, it draws one still frame at
stillTimeand stops. The default, 12 seconds, catches the cable car halfway across. - 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 the dusk as a flat gradient.
- The whole city is one shader pass on the GPU, one sample per dot. See Performance.