Installation
pnpm dlx shadcn@latest add https://asciicn.dev/r/hong-kong.jsonUsage
import { HongKong } from "@/components/asciicn/hong-kong";
export function Hero() {
return (
<section className="relative isolate min-h-[480px]">
<HongKong intensity={0.6} className="absolute inset-0 -z-10" />
<h1>Your headline</h1>
</section>
);
}The view looks across Victoria Harbour from Kowloon at blue hour. Victoria Peak fills the middle of the sky as a dark, wooded ridge with a lower spur in front of it. Its slopes facing the afterglow catch a little magenta and the rest falls into shadow, and soft banks of mist lie across its upper slopes. The sky behind it runs from hot magenta along the crest through mauve and violet to a deep, quiet blue overhead, where a few stars show.
Below the Peak, the towers of the Mid-Levels climb its slope in violet haze, and in front of them runs the waterfront: a wall of dark towers lit in warm, white, cool and teal windows, floor by floor, with a few crowns in slowly changing LED colours. Two landmarks stand either side of the frame. The Bank of China Tower is on the left, with dark glass, white edges, softer X braces and slanted roofs that step up to twin masts. Two IFC is on the right, striped with vertical light, with a crown of fins in front of the afterglow.
The harbour mirrors the city in long coloured streaks, broken by slow ripples, and a column of rose glints runs under the afterglow. A junk with three battened red sails crosses it.
Motion is slow and sparse: the junk takes about two minutes to cross a wide screen, the reflections shimmer, a few windows switch on or off over tens of seconds, the mist drifts, the red light on the Bank of China mast pulses and the stars twinkle. Nothing responds to the pointer.
It draws in dots by default on square 7px cells, about 200 columns across a 1440px screen. Dot size carries tone: small, dim dots in the deep sky, the shadowed hills and the open water, and large ones only for the landmarks' lit edges, the windows, the afterglow and its reflection. Dots, braille and quadrants use blue-noise dithering, which blends neighbouring sizes without stripes. In truecolor, the default, every dot takes the scene's own colour on a night paper, so it looks the same on light and dark pages.
The middle of the frame stays calm for a headline. The landmarks stand outside the middle half of the width, the waterfront towers are lowest in the centre and their windows dim there, and the junk sails below the text. In narrow boxes the two towers move to the edges and the Peak stays centred, so a phone crop keeps all three.
intensity dims the colours and shrinks the dots, most of all in the middle band where a headline sits. Lower it to keep text on top easy to read.
Examples
Behind a headline
Full-bleed behind a centred headline and two buttons. intensity={0.65} quiets the middle band so the text reads first, while the two towers frame it.
In a tall card
In a 9:19 box the Bank of China Tower and Two IFC move to the edges and the Peak stays centred, so all three stay in view.
Props
| Prop | Type | Default |
|---|---|---|
| intensity How strongly it draws, from 0 (faint) to 1. Lower values quiet the middle band most, so text on top stays readable. | Type: number | Default 1 |
| lights How strongly the few LED crowns on the waterfront show their slowly changing colours, from 0 (plain white) to 1. | Type: number | Default 1 |
| junk Draws the junk with red sails crossing the harbour, about every two minutes on a wide screen. | Type: boolean | Default true |
| ferry Deprecated. Use junk. false still turns the boat off. | Type: boolean | Default true |
| mist How much mist drifts on Victoria Peak and between its ridges, from 0 (none) to 1. | Type: number | Default 1 |
| charset Which glyphs draw the scene. 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 uses the scene's own colours, mono uses the theme ink or a phosphor, duotone runs tone through a ramp. "mono" when a phosphor is set. | Type: "mono" | "truecolor" | "ansi16" | "duotone" | "palette" | Default "truecolor" |
| phosphor A CRT ink and glass for mono mode. Setting one switches colorMode to mono. | Type: "p1" | "p3" | "ibm" | "blueprint" | Default – |
| ramp In duotone mode, the colour ramp from dark to light. | Type: RampName | string[] | Default – |
| 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 Dithering between neighbouring glyph levels. Blue noise blends dot sizes across the sky's gradient without stripes. | Type: "none" | "bayer2" | "bayer4" | "bayer8" | "blue-noise" | Default "blue-noise" in dots, braille and quadrants, "none" otherwise |
| 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 – |
| interactive Accepted so any stage can pass it, and ignored: the city does not respond to the pointer. | Type: boolean | Default – |
| square Cells as wide as they are tall, so the dots lay an even lattice. Braille and quadrants default to false, since they would stretch. | Type: boolean | Default true for dots and other one-glyph charsets |
| cell Height of one glyph cell in CSS pixels, and its width too when square. | Type: number | Default 7 |
| speed How fast it moves. | 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. The default shows the junk just right of centre. | Type: number | Default 3 |
| handle Filled with a handle that reads back the current frame, for export to text, ANSI, SVG or PNG. | Type: RefObject<AsciiHandle | null> | Default – |
| paper Paper behind the glyphs. By default the scene's night colour in truecolor, ansi16 and duotone, and the theme's paper (or the phosphor's) otherwise. | Type: AsciiColor | Default – |
| fallback Shown without WebGL and until the first frame. By default a blue-hour gradient. | Type: ReactNode | 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.
- 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 blue-hour gradient.
- Nothing responds to the pointer, and there is no
interactionprop. - The whole scene is one GPU pass. The harbour draws the city a second time for its reflection, so its cost follows the number of samples.
braillesamples eight times per cell; a largercellmakes it cheaper. See Performance.