# Lighthouse

A lighthouse on a rocky headland at blue hour, its lamp glowing amber over a calm sea, painted in halftone dots.

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

## Installation [#installation]

```bash
npx shadcn@latest add https://asciicn.dev/r/lighthouse.json
```

## Usage [#usage]

```tsx
import { Lighthouse } from "@/components/asciicn/lighthouse";

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

A white lighthouse stands on a rocky headland at blue hour. Its lantern room glows amber with a soft halo that breathes slowly, about every eleven seconds. A keeper's cottage beside it keeps one window lit. Below, the headland drops to the sea in a craggy cliff, with a sea stack off its foot.

The sky runs from a peach afterglow low on the left, through rose and violet, to deep blue with the first stars. Long thin clouds catch the afterglow on their undersides and drift slowly right. A low far shore sits hazy on the horizon. The sea mirrors the sky, pale at the horizon and dark near you, and carries the lamp's light as a warm broken path. Slow swells roll in and break into soft foam on the rocks.

Every cell is painted. The default `dots` charset draws each one as a halftone dot whose size follows the brightness, from a faint `·` in the night sky and the deep water to a full `●` in the lamp, the tower and the afterglow. `square` cells, on by default, are as wide as they are tall, so the dots lie on an even lattice like a printed halftone screen; turn it off and the rows sit twice as far apart as the columns. In `truecolor`, the default, each dot takes the scene's own colour on its own night, so the scene looks the same on light and dark pages. `mono` with a `phosphor` and `duotone` with a `ramp` read it by tone alone. `braille` and `quadrants` light a dot only above half tone, so they keep the bright shapes and drop the dark sea and sky; use them with `square={false}`.

On wide boxes the tower stands right of centre, so a headline fits in the middle. On tall boxes it moves nearer the middle and keeps its size.

`intensity` quiets the scene for text on top: colours dim and dots shrink together.

## Examples [#examples]

### Hero [#hero]

`intensity={0.7}` keeps the lamp as the brightest thing on screen while a centred headline and two buttons read first.

```tsx title="examples/lighthouse-hero.tsx"
import { Lighthouse } from "@/components/asciicn/lighthouse";

export default function LighthouseHero() {
  return (
    <section className="relative isolate flex size-full flex-col items-center justify-center gap-4 px-6 text-center text-white">
      <Lighthouse intensity={0.7} className="absolute inset-0 -z-20" />
      {/* A soft shade behind the copy, so it reads over the afterglow. */}
      <div className="absolute inset-0 -z-10 bg-[radial-gradient(ellipse_40%_32%_at_50%_52%,rgb(5_7_15/0.7),transparent)]" />
      <h3 className="max-w-lg text-3xl font-medium tracking-[-0.03em] text-balance sm:text-5xl">
        Keep the light on
      </h3>
      <p className="max-w-sm text-sm text-pretty text-white/75">
        Uptime alerts that wake the right person, and only them.
      </p>
      <div className="mt-2 flex flex-wrap items-center justify-center gap-3">
        <a
          href="#start"
          className="rounded-md bg-[#fcb442] px-4 py-2 text-sm font-medium text-[#1a1206] transition-colors hover:bg-[#ffc664]"
        >
          Start free
        </a>
        <a
          href="#docs"
          className="rounded-md border border-white/25 bg-black/20 px-4 py-2 text-sm font-medium text-white backdrop-blur-sm transition-colors hover:bg-white/10"
        >
          Read the docs
        </a>
      </div>
    </section>
  );
}
```

### Quiet strip [#quiet-strip]

`stars={false}` and `clouds={false}` leave only the lamp, the swells and the foam moving. At `intensity={0.45}` the scene sits behind a short line of text.

```tsx title="examples/lighthouse-quiet.tsx"
import { Lighthouse } from "@/components/asciicn/lighthouse";

// No stars, no clouds and a lower intensity: a calm strip behind a sign-up form.
export default function LighthouseQuiet() {
  return (
    <div className="relative isolate flex h-72 w-full max-w-2xl flex-col justify-end overflow-hidden rounded-xl p-6 text-white">
      <Lighthouse
        intensity={0.45}
        stars={false}
        clouds={false}
        className="absolute inset-0 -z-10"
      />
      <p className="font-mono text-xs tracking-[0.2em] text-white/60 uppercase">
        Harbour notes
      </p>
      <p className="mt-1 max-w-xs text-lg font-medium text-balance">
        One letter a month from the coast.
      </p>
    </div>
  );
}
```

## Props [#props]

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `intensity` | `number` | `1` | How strongly the scene draws, from 0 to 1. Lower it to keep text on top readable. |
| `stars` | `boolean` | `true` | The first stars coming out high in the sky. |
| `clouds` | `boolean` | `true` | Long thin clouds drifting low over the afterglow. |
| `square` | `boolean` | `true` | Cells as wide as they are tall, so the halftone dots lie on an even lattice. Turn it off for Braille, quadrants or typed charsets. |
| `paper` | `AsciiColor` | `–` | The surface behind the glyphs. Without it, truecolor, ansi16 and duotone sit on the scene's own night; 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 amber on the night. |
| `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. |
| `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. |
| `speed` | `number` | `1` | How fast the lamp, the swells, the clouds and the stars 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` | `6` | The moment drawn when motion is off or reduced, in seconds. At 6 the lamp is near its brightest and foam lies along the rocks. |
| `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.
* The whole scene is one shader pass on the GPU, one sample per cell in `dots`. At the default 7px square cell a 1440px wide box is about 200 columns. `braille` samples eight times per cell and `quadrants` four. See [Performance](/docs/engine/performance).