Installation
pnpm dlx shadcn@latest add https://asciicn.dev/r/dna-helix.jsonUsage
import { DnaHelix } from "@/components/asciicn/dna-helix";
export function Hero() {
return <DnaHelix className="h-96 w-64" />;
}The two backbones and every rung are built from lit spheres, drawn into a depth buffer one sample at a time. Where a strand swings behind the other, or a rung passes behind a backbone, the nearer surface wins, so the helix stays readable at any angle and in any charset. Braille samples each cell 2×4 times, which gives the finest strands.
The strands sit less than half a turn apart, as in real DNA, which opens a wide groove and a narrow one. Each rung is one base pair: A with T, or G with C. In truecolor each half takes its own base's colour, with a hairline gap in the middle where the pair bonds. The far side of the helix fades towards the paper, and the whole molecule slides slowly along its axis.
It does not react to hover. Press and drag sideways to spin it. When it stands upright, drag up or down to tilt it. Let go mid-drag and it keeps spinning, then settles back to its own pace. With keyboard focus, the arrow keys spin and tilt it.
Examples
Beside a headline
Upright in a narrow column on a transparent background, so it sits on the page instead of in a box.
Your own sequence
sequence repeats any string of A, C, G and T along one strand, and the other strand pairs with it. Here it is GATTACA in the classic charset, with its own baseColors.
Props
Every ASCII image look prop also applies, with charset defaulting to "braille", plus fx for a CRT finish.
| Prop | Type | Default |
|---|---|---|
| speed Spin around the helix axis, in radians per second. Negative spins the other way. | Type: number | Default 0.35 |
| twist How tightly the strands wind. 1 is the shape of B-DNA, one turn every 3.4 radii; 2 winds twice as tight. | Type: number | Default 1 |
| rungs Base pairs per turn, 4 to 20. | Type: number | Default 10 |
| scroll Base pairs per second that slide along the axis. 0 holds the helix in place. | Type: number | Default 0.5 |
| orientation Which way the helix axis runs across the box. | Type: "vertical" | "horizontal" | Default "vertical" |
| sequence Bases read along one strand and repeated. Letters other than A, C, G and T are skipped. | Type: string | Default A fixed mixed sequence |
| color Backbone colour in truecolor. | Type: AsciiColor | Default "--ascii-ink" |
| baseColors Rung colours by base in truecolor. | Type: Partial<Record<"A" | "C" | "G" | "T", AsciiColor>> | Default { A: "green", T: "pink", G: "orange", C: "blue" } |
| colorMode How glyphs are coloured. | Type: "mono" | "truecolor" | "ansi16" | "duotone" | "palette" | Default "truecolor" |
| interactive Drag or use the arrow keys to spin and tilt it. | Type: boolean | Default true |
| cell Glyph cell height in CSS pixels. | Type: number | Default 10 |
| animate false draws one still frame. | Type: boolean | Default true |
| handle Filled with a handle for export. | Type: RefObject<AsciiHandle | null> | Default – |
Notes
- It is announced as an image. Pass
aria-labelto describe what it stands for on your page. - Under reduced motion it draws one still frame and stays put.
- It draws at up to 60 fps on the CPU and pauses offscreen and in hidden tabs. The cost grows with the number of samples, so a smaller box or a larger
cellis cheaper. - On a touch screen, vertical swipes scroll the page. Sideways swipes spin the helix.