# Balloon valley

Early morning over a river valley in halftone dots on cream: cool blue hills fading into haze, pale gold mist, a river catching the low sun and hot-air balloons at different depths.

> 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/balloon-valley.json](https://asciicn.dev/r/balloon-valley.json), under `files[].content`.

## Installation [#installation]

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

## Usage [#usage]

```tsx
import { BalloonValley } from "@/components/asciicn/balloon-valley";

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

It is early morning. The sky is a soft blue overhead, paling to cream in the middle and pale peach at the horizon, and a gold sun sits half over the farthest ridge in a warm glow. Four ridges in cool blue shadow step down towards you and open in a V under the sun. Each is paler than the one in front, sinking into the haze, and the faces turned to the sun warm up. Pale gold mist pools in the low ground of every V. At the bottom, two blue hills frame a sage valley floor, where the river winds towards you as a pale ribbon with gold glints on it.

Five hot-air balloons hang in the sky at different depths. The nearest is large and striped red and gold, lit from the sun's side and glowing through its shaded side. The far ones are smaller and fade into the haze. Two of them rise and sink over a few minutes, and the low one drops behind the ridges and comes back up.

The scene is printed like ink on warm cream paper: the dot grows with how far a colour is from the paper. The pale sky is the faintest dots, so the middle of the box is almost bare paper. The cool blue hills and the gold mist are small and medium dots, and only the sun, the river's glints and the balloons get large ones. `bayer4` dithering, the default, mixes neighbouring dot sizes so gradients stay smooth. `square` cells, on by default, lay the dots on an even lattice like a halftone screen, about 200 columns across a 1440px screen at the default 7px cell. In `truecolor`, the default, the scene prints on its own cream paper, so it looks the same in light and dark themes. Put dark text on it. `duotone` with a `ramp` and `mono` with a `phosphor` read the same scene by tone alone.

The motion is slow: mist drifts along the valley, the river's glints shimmer and breathe, and the balloons bob. Nothing reacts to the pointer.

The land sits in the lower third, so a centred headline lands on quiet sky with the sun just below it. On wide boxes the sun sits a little right of centre and the balloons keep to the sides and the top. On tall boxes the balloons gather above the headline and the sun and the river sit below it.

## Examples [#examples]

### Hero [#hero]

A centred headline and two buttons over the full scene at full intensity. The headline is a dark slate blue taken from the hills and lands on almost bare cream; a soft wash of the paper behind it keeps it clean.

```tsx title="examples/balloon-valley-hero.tsx"
import { BalloonValley } from "@/components/asciicn/balloon-valley";

// Full-bleed behind a centred headline and two buttons. The scene prints on
// cream paper, so the type is a dark slate blue taken from its hills.
export default function BalloonValleyHero() {
  return (
    <section className="relative isolate flex min-h-[560px] w-full flex-col items-center justify-center gap-5 overflow-hidden px-6 py-24 text-center">
      <BalloonValley className="absolute inset-0 -z-10" />
      {/* A soft wash of the paper behind the text only. */}
      <div
        aria-hidden
        className="pointer-events-none absolute inset-0 -z-10 bg-[radial-gradient(ellipse_36%_22%_at_50%_46%,rgb(246_239_230/0.7),transparent)]"
      />
      <h1 className="max-w-2xl text-4xl font-medium tracking-[-0.03em] text-balance text-[#1f2a44] sm:text-6xl">
        Up before the sun
      </h1>
      <p className="max-w-md text-base text-pretty text-[#1f2a44]/75">
        Dawn flights over the river valley, every morning the wind allows.
      </p>
      <div className="flex flex-wrap items-center justify-center gap-3">
        <a
          href="#book"
          className="rounded-md bg-[#1f2a44] px-4 py-2 text-sm font-medium text-[#f6efe6] shadow-sm"
        >
          Book a flight
        </a>
        <a
          href="#routes"
          className="rounded-md border border-[#1f2a44]/25 bg-[#f6efe6]/70 px-4 py-2 text-sm font-medium text-[#1f2a44] backdrop-blur-sm"
        >
          See the routes
        </a>
      </div>
    </section>
  );
}
```

### Duotone print [#duotone-print]

`colorMode="duotone"` with a four-stop `ramp` draws the valley in rust and slate on the cream, like a two-ink print. `cell={6}` adds detail in a smaller card.

```tsx title="examples/balloon-valley-duotone.tsx"
import { BalloonValley } from "@/components/asciicn/balloon-valley";

// The same valley read by tone alone through a two-ink ramp, in a card.
export default function BalloonValleyDuotone() {
  return (
    <div className="relative isolate h-80 w-full max-w-2xl overflow-hidden rounded-xl">
      <BalloonValley
        colorMode="duotone"
        ramp={["#ebdfcf", "#d9a273", "#8a6a8f", "#33406b"]}
        cell={6}
        className="absolute inset-0"
      />
    </div>
  );
}
```

## Props [#props]

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `intensity` | `number` | `1` | How strongly the valley draws, from 0 to 1. Lower values fade it back into its paper. |
| `paper` | `AsciiColor` | `–` | The surface behind the glyphs. Without it, truecolor, ansi16 and duotone print on a warm cream; 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 " ·∙•●". 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[]` | `cream to slate` | In duotone mode, the colour ramp from the faintest dots to the strongest. The default runs from the paper's cream to slate-blue ink. |
| `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. |
| `edgeThreshold` | `number` | `0.22` | Edge charset: how strong a change in tone must be to draw - / \| or \. |
| `dither` | `"none" \| "bayer2" \| "bayer4" \| "bayer8" \| "blue-noise"` | `"bayer4"` | Ordered dithering between neighbouring dot sizes. The default turns four dots into smooth tone. |
| `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, and its width too with square cells. |
| `square` | `boolean` | `true` | Square cells, so the dots lie on an even lattice. false uses the font's narrower cells. |
| `speed` | `number` | `1` | How fast the mist, the river and the balloons 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. At 0 the low balloon is part way up from behind the ridges. |
| `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 dawn gradient.
* The whole valley is one shader pass on the GPU, one sample per cell in `dots`. Mist and ridge texture use a few octaves of noise, so it costs a little more than a flat gradient. See [Performance](/docs/engine/performance).