Installation
pnpm dlx shadcn@latest add https://asciicn.dev/r/rice-terraces.jsonUsage
import { RiceTerraces } from "@/components/asciicn/rice-terraces";
export function Hero() {
return (
<section className="relative isolate min-h-[480px]">
<RiceTerraces intensity={0.8} className="absolute inset-0 -z-10" />
<h1>Your headline</h1>
</section>
);
}A terraced hillside fills the middle ground. Its crest is high on the left and falls away to the right, with a line of trees along the top. The terraces wrap the hill: they climb with the crest, bow toward you over each spur and tuck back into each gully, and no two are the same width. Each level is a flooded field, then the dark earthen retaining wall of the level above, then that wall's top edge, where grass catches the low sun in green-gold. Each level breaks into separate fields of uneven length. Where a field ends, its top edge curves down onto the bank below, so it closes in a rounded tip, and every bank edge wobbles a little, as a hand-built one does. Each field mirrors the sky at its own angle, blue near you and silver farther up, darkens along its far edge where it reflects the wall above, and glitters where it lies under the sun. A few fields are planted with young rice instead.
In front of it a darker ridge crosses the bottom of the frame, with a few trees and tufts of grass in silhouette against the fields. Behind it a second terraced hill sits back in the haze, and mist fills the valley at its foot. Three ridges step back, each with less detail, lower contrast and smaller dots than the one in front, and their crests dissolve into a slate sky that brightens to silver along the horizon, with soft drifts of light gathering under the sun. The sun stands high on the right in a soft cream glow.
Most of the frame is quiet. The sky is sparse specks, thinning toward the zenith. Walls, shadowed faces and the front ridge are fine points only a little lighter than the paper. Large bright dots are kept for the sun, its glitter, the lit bank tops and the near fields, so near and far separate at a glance. The dots charset draws ·, • and ●, so a dot's size carries its tone, and in truecolor, the default, each dot takes its own colour. Cells are square by default, 7px each way, so the dots lie on an even lattice like a halftone screen. square={false} uses the font's tall cells instead.
The motion is slow. Mist drifts through the valley, the fields shimmer, the sun glitters on the water below it, a few last stars twinkle, and one pale egret glides across the sky every few minutes.
The middle of the frame is mist and far ridges in low contrast, so a centred headline sits on calm ground. On wide boxes the sun stands in the upper right; on tall boxes it rises above the headline, with the terraces below it.
The scene paints its own deep slate paper in truecolor, ansi16 and duotone, so it looks the same on light and dark pages. mono with a phosphor reads it by tone alone.
intensity dims the scene: colours fade in step with it, and the dots shrink more slowly.
Examples
Hero
intensity={0.8} dims the scene a little and quiets the middle further, so a centred headline and two buttons read first.
Banner
cell={6} draws finer dots, about 6px apart, so the terraces keep their steps in a wide strip only 224px tall. bird={false} leaves only the mist and the water moving.
Props
| Prop | Type | Default |
|---|---|---|
| intensity How strongly the scene draws, from 0 to 1. Lower it to keep text on top readable. | Type: number | Default 1 |
| bird The one bird gliding slowly across the sky. | Type: boolean | Default true |
| square Square cells, so the dots lie on an even halftone lattice. false uses the font's taller cells. | Type: boolean | Default true |
| paper The surface behind the glyphs. Without it, truecolor, ansi16 and duotone sit on a deep slate; mono and palette use the theme's paper or the phosphor's. | Type: AsciiColor | Default – |
| fallback Shown without WebGL and until the first frame. | 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. The default runs slate through blue to silver. | Type: RampName | string[] | Default "heliograph" |
| 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 glyph levels. | Type: "none" | "bayer2" | "bayer4" | "bayer8" | "blue-noise" | Default "none" |
| 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 the mist, the water and the bird move. | 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. At 0 the bird is a quarter of the way across. | Type: number | Default 0 |
| 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. - 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 flat dawn gradient.
- The whole scene is one shader pass on the GPU, one sample per cell in
dots.braillesamples eight times per cell andquadrantsfour. See Performance.