Installation
pnpm dlx shadcn@latest add https://asciicn.dev/r/redwood-light.jsonUsage
import { RedwoodLight } from "@/components/asciicn/redwood-light";
export function Hero() {
return (
<section className="relative isolate min-h-[480px]">
<RedwoodLight intensity={0.6} className="absolute inset-0 -z-10" />
<h1>Your headline</h1>
</section>
);
}The view is from the forest floor, looking up. Two huge trunks frame the view, dark red-brown and furrowed, with a warm rim of light on the side that faces the sun. Three medium trunks stand a little behind them, then three rows of thinner trunks recede into the haze, each row paler and cooler than the one in front: a few broad trunks and many thin ones. Every trunk leans towards one point high above the middle of the box, and each also has its own lean, bow and taper, with bark breaking both edges, so the forest reads as seen from below and never as a row of strips. Sprays of far foliage and drifting mist hide parts of the distant trunks.
Three layers of canopy overlap overhead, far to near: clumped masses with ragged, leafy edges, the nearest hanging low in sprays at the sides.
The sun shines through the canopy, upper right, as a small soft halo, and the leaves around it glow gold where it backlights them. Four soft-edged shafts of light fall from it, nearly straight down, broken into dapples by the leaves in their way, and the air around them is a soft green-gold. Fern clumps get smaller and hazier towards the far edge of the floor, and a row of fronds crosses the bottom of the box.
The motion is slow. Dust and pollen drift through the shafts and catch the light, each mote fading in and out. The shafts brighten and dim a little, and a thin mist drifts between the far trunks. Nothing reacts to the pointer.
The middle of the box is calm green air between the trunks. The light stays upper right and the shafts fade where they near the middle, so a centred headline sits on quiet ground. On tall boxes the giants narrow, the halo shrinks and the shafts dim, so a phone shows the light above the headline and the trunks beside it.
It draws in dots by default on square 7px cells, about 200 columns across a 1440px screen, so the dots sit on an even lattice like a halftone screen. square={false} goes back to the font's narrower cells. Dot size carries the light and truecolor gives every dot its own colour, while the shade falls to the smallest dots, close to the paper, or to none. braille and quadrants draw the same forest in finer dots. In truecolor, ansi16 and duotone it paints on its own dark green shade, so it looks the same on the light and dark site themes. mono with a phosphor and duotone with a ramp read the scene by tone alone.
intensity dims the colours and shrinks the dots together. Around 0.6 the forest falls back behind a headline.
Examples
Behind a headline
intensity={0.6} keeps the light shafts and the giants but lets a centred headline and two buttons read first.
Sepia duotone
colorMode="duotone" with ramp="sodium" reads the forest by brightness alone, in warm amber like an old print. mist={false} leaves the far trunks clear.
Props
| Prop | Type | Default |
|---|---|---|
| intensity How strongly the forest draws, from 0 to 1. Lower it to keep text on top readable. | Type: number | Default 1 |
| motes Dust and pollen drifting through the light shafts. | Type: boolean | Default true |
| mist The mist drifting between the far trunks. | Type: boolean | Default true |
| paper The surface behind the glyphs. Without it, truecolor, ansi16 and duotone sit on a deep green shade; 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 draws gold on the shade. | 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. | Type: number | Default 0.5 |
| 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 |
| square Square cells, as wide as they are tall, so the dots form an even lattice. false uses the font's narrower cells. | Type: boolean | Default true |
| speed How fast the motes, the shafts and the mist 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. | 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. - 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 soft gradient of the scene.
- The whole forest is one shader pass on the GPU, one sample per cell in
dots.braillesamples eight times per cell andquadrantsfour. See Performance.