# Canyon river

A desert canyon in late golden hour from a high rim: sunlit terracotta walls with blue shadows step back to glowing buttes while a river winds below, mirroring the blue sky.

> For the complete documentation index, see [llms.txt](/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](/.well-known/agent-skills/asciicn/SKILL.md).

> **This is an example, not the only option.** It is one component built on the asciicn engine. Install it when it is what you were asked for. For any other look, don't stretch its props to fit: write your own field on `AsciiShader` ([Write your own](/docs/engine/write-your-own.md)), or draw a CPU grid with `AsciiGrid`, and read this example's source for technique. Its full source is in [https://asciicn.dev/r/canyon-river.json](https://asciicn.dev/r/canyon-river.json), under `files[].content`.

## Installation [#installation]

```bash
npx shadcn@latest add https://asciicn.dev/r/canyon-river.json
```

## Usage [#usage]

```tsx
import { CanyonRiver } from "@/components/asciicn/canyon-river";

export function Hero() {
  return (
    <section className="relative isolate min-h-[480px]">
      <CanyonRiver intensity={0.6} className="absolute inset-0 -z-10" />
      <h1>Your headline</h1>
    </section>
  );
}
```

You look down a desert canyon from its rim in late golden hour. Eroded walls rise on both sides. Their rims are broken at several scales and notched where gullies cut them, the strata tilt and break at faults, gullies branch down from the rim with slanting tributaries, and rounded scree spreads at the foot of the middle wall. Each buttress splits into planes: on the sunward wall, terracotta and rust planes in warm sunlight beside shaded ones under a lit rim; on the far wall, blue shadow planes that catch the sky, with light reflected up from the river low down. Behind them a middle wall and two overlapping rows of buttes step back towards a hazy plateau on the horizon, each farther layer paler and softer. Each butte has its own tilted, chipped cap, weathered shoulders and an uneven talus skirt. The buttes stand at the sides, so the middle stays open.

The sun hangs low over the plateau in a soft halo. A river leaves through a notch in the plateau below it and winds towards you, showing through the gap in each wall in turn. It mirrors the sky: gold under the sun, clear blue where you look down into it. The sky runs from amber at the horizon through pale blue to a deeper blue overhead, with a few thin streaks of cloud lit gold underneath.

Only light moves. The light slides slowly along the rims, streaks of shimmer cross the water, the clouds drift and the glow breathes. The pointer does nothing.

On wide boxes the sun sits well right of centre, so the middle stays calm for a headline. On tall boxes the view narrows and the horizon rises, so on a phone the sun sits above a centred headline and the river runs down beside it.

It draws in `dots` by default: dot size follows brightness, and in `truecolor` every dot takes its own colour, so shadow and the high sky stay a quiet grain of small, dim dots and the largest dots are kept for the sun, its reflection and the sunlit rims. Cells are square by default, so the dots sit on an even halftone lattice about 200 columns across a 1440px screen. With `square={false}` the cells are tall again and `dots` lights every other column to keep the lattice even. The scene paints its own sky on a deep blue paper, so it looks the same on light and dark pages. Text charsets such as `standard` and `dense` give a typed look and read best with `square={false}`, and `braille` and `quadrants` light a dot only above half tone. `mono` with a `phosphor` and `duotone` with a `ramp` read the same scene by tone alone.

`intensity` dims the scene: colours fade in step with it and the dots shrink a little. It quiets the middle of the box more than the edges, so a centred headline reads first while the walls and the sky still frame it.

## Examples [#examples]

### Behind a headline [#behind-a-headline]

`intensity={0.65}` pushes the canyon back, most of all in the middle, so a centred headline and two buttons read first.

```tsx title="examples/canyon-river-hero.tsx"
import { CanyonRiver } from "@/components/asciicn/canyon-river";

export default function CanyonRiverHero() {
  return (
    <section className="relative isolate flex size-full min-h-96 flex-col items-center justify-center gap-4 overflow-hidden bg-[#0b0a1c] px-6 text-center text-white">
      <CanyonRiver intensity={0.65} className="absolute inset-0 -z-10" />
      <h3 className="max-w-2xl text-4xl font-medium tracking-[-0.03em] text-balance [text-shadow:0_1px_24px_rgb(11_10_28/0.9)] sm:text-5xl">
        Ship before the light goes
      </h3>
      <p className="max-w-sm text-sm text-pretty text-white/75 [text-shadow:0_1px_16px_rgb(11_10_28/0.9)]">
        At 0.65 intensity the middle of the canyon sits back and the headline
        reads first.
      </p>
      <div className="mt-2 flex gap-3">
        <a
          href="#get-started"
          className="rounded-md bg-[#fcb442] px-4 py-2 text-sm font-medium text-[#1a0c12]"
        >
          Get started
        </a>
        <a
          href="#docs"
          className="rounded-md border border-white/25 bg-[#0b0a1c]/60 px-4 py-2 text-sm font-medium text-white backdrop-blur-sm"
        >
          Read the docs
        </a>
      </div>
    </section>
  );
}
```

### On an amber monitor [#on-an-amber-monitor]

`colorMode="mono"` with `phosphor="p3"` draws every glyph in one amber, so the canyon reads by tone alone. The `standard` charset, a 10px cell and `fx` scanlines, bloom and vignette finish the look.

```tsx title="examples/canyon-river-phosphor.tsx"
import { CanyonRiver } from "@/components/asciicn/canyon-river";

// One amber phosphor and classic glyphs in tall cells: the canyon on an old monitor.
export default function CanyonRiverPhosphor() {
  return (
    <div className="relative isolate flex h-80 w-full max-w-2xl flex-col overflow-hidden rounded-xl border border-[#3a2a0a] bg-[#0a0700] font-mono">
      <CanyonRiver
        charset="standard"
        colorMode="mono"
        phosphor="p3"
        cell={10}
        square={false}
        fx={{ bloom: 0.5, scanlines: 0.4, vignette: 0.45 }}
        className="absolute inset-0 -z-10"
      />
      <div className="flex items-center justify-between border-b border-[#3a2a0a] bg-[#0a0700]/80 px-3 py-1.5 text-[11px] text-[#ffb000]/70">
        <span>rim.cam</span>
        <span>18:51 · golden hour</span>
      </div>
    </div>
  );
}
```

## Props [#props]

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `intensity` | `number` | `1` | How strongly the canyon draws, from 0 to 1. Lower it to keep text on top readable. |
| `clouds` | `boolean` | `true` | Thin streaks of cloud drifting across the sky. |
| `paper` | `AsciiColor` | `–` | The surface behind the glyphs. Without it, truecolor, ansi16 and duotone sit on a deep blue; mono and palette use the theme's paper or the phosphor's. |
| `fallback` | `ReactNode` | `a gradient` | Shown without WebGL and until the first frame. |
| `charset` | `CharsetName` | `"dots"` | Which glyphs draw the tones. See Charsets. |
| `chars` | `string` | `–` | A custom ramp from empty to dense, such as " .oO@". Wins over charset. |
| `colorMode` | `"mono" \| "truecolor" \| "ansi16" \| "duotone" \| "palette"` | `"truecolor"` | How glyphs are coloured. truecolor paints the scene's own colours; mono uses one ink or a phosphor; duotone runs tone through a ramp. |
| `phosphor` | `"p1" \| "p3" \| "ibm" \| "blueprint"` | `–` | A CRT ink and glass. Setting one switches the default colour mode to mono. |
| `ramp` | `RampName \| string[]` | `"sodium"` | In duotone mode, the colour ramp from dark to light. The default draws gold on dark. |
| `ansi` | `"vga" \| "xterm"` | `"vga"` | In ansi16 mode, which 16-colour table. |
| `grade` | `Grade` | `–` | Brightness, contrast, gamma and saturation applied to tones before glyphs are picked. |
| `invert` | `boolean` | `false` | Dense glyphs for dark tones instead of bright ones. |
| `threshold` | `number` | `0.5` | Braille and quadrants: the tone that lights a dot. |
| `dither` | `"none" \| "bayer2" \| "bayer4" \| "bayer8" \| "blue-noise"` | `"none"` | Ordered dithering between neighbouring glyph levels. |
| `square` | `boolean` | `true` | Cells as wide as they are tall, so dots lay an even lattice. Turn it off for text charsets. |
| `background` | `"paper" \| "transparent"` | `"paper"` | "transparent" draws the glyphs only, over your own surface. |
| `fx` | `PostFx` | `–` | CRT finish: scanlines, bloom, curvature, glitch, flicker and vignette, each 0 to 1. |
| `cell` | `number` | `7` | Height of one glyph cell in CSS pixels. In dots, also the spacing of the dot grid. |
| `speed` | `number` | `1` | How fast the light, the water and the clouds move. |
| `animate` | `boolean` | `true` | false stops the motion: a still frame if it starts off, the current frame if it was moving. |
| `fps` | `number` | `30` | Frame rate cap. |
| `stillTime` | `number` | `0` | The moment drawn when motion is off or reduced, in seconds. |
| `handle` | `RefObject<AsciiHandle \| null>` | `–` | Filled with a handle that reads back the current frame, for export to text, ANSI, SVG or PNG. |
| `className` | `string` | `–` | Size and position. The background fills this box. |

## Notes [#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 `stillTime` and 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 gradient of the scene.
* The whole canyon is one shader pass on the GPU, one sample per cell in `dots`. `braille` samples eight times per cell and `quadrants` four. See [Performance](/docs/engine/performance).