DNA — the helixui theme engine
DNA — Design Nucleotide Allele. It’s how helixui names its theme system.
A DNA is a complete theme genome — eight genes, one allele each. You
can clone DNAs, mutate them, breed two parents into a child, or run
generations of breeding over a population. Dominant alleles win in crossover;
recessive alleles still surface occasionally. That’s where surprise looks
come from across generations.
Live demo: /showcase/dna-lab — every component on the
page renders under a DNA you can mutate live.
Genes (8)
| Gene | Trait | Sample alleles |
|---|---|---|
accent | Brand hue (drives the OKLCH 50–900 ramp) | blue, violet, cyan, green, orange, crimson… |
chroma | Saturation multiplier across the brand ramp | muted, standard, vibrant |
lightness | Light / dark / auto | light, dark, auto |
radius | Corner-radius scale factor | sharp, subtle, standard, rounded, extreme |
density | Spacing scale factor | compact, comfortable, spacious |
typography | Font family + scale | sans, grotesk, rounded, serif, mono |
surface | Shadow / depth treatment | flat, elevated, glassy |
motion | Animation duration scale | subtle, standard, lively |
Each allele has a dominance score (1–10) and an optional recessive flag.
The full registry lives in @helixui/dna/src/alleles.ts.
API
import { wildtype, PRESETS, clone, mutate, compose, evolve, express, type DNA,} from '@helixui/dna';
const a = wildtype(); // base DNAconst b = PRESETS.botanic(); // a presetconst c = mutate(a, { gene: 'accent', allele: 'crimson' });const child = compose(a, b); // cross two DNAsconst next = evolve([a, b, c, child]); // run a generation
const { cssVars, dataTheme } = express(child); // → CSS custom propertiesApply a DNA to a subtree via <HelixUIDNAProvider> (from @helixui/core):
import { HelixUIDNAProvider, Button } from '@helixui/core';
<HelixUIDNAProvider dna={child}> <Button>This button renders under the bred DNA.</Button></HelixUIDNAProvider>Inheritance rules
When two DNAs cross, for each gene:
- Higher dominance wins. Ties are decided by coin flip.
- Recessive surfacing. If the loser allele is flagged
recessive, it takes the locus ~15% of the time anyway. That’s how visual surprises emerge. - Mutation. A small per-gene mutation rate (default ~4%) replaces the winner with a random other allele.
Tune all three per call (compose(a, b, { mutationRate: 0.2 }) or
evolve(pop, { fitness: contrastScore })).
Why DNA changes are instant
helixui tokens ship in two layers:
- Primitives (
color.brand.500,space.4,radius.md,font.size.md,shadow.md) — concrete CSS variable values. - Semantic aliases (
color.bg.action.brand.default = {color.brand.500}) — emitted asvar(--helixui-color-brand-500)in the built CSS.
When DNA’s express() overrides a primitive (e.g.
--helixui-color-brand-500), every semantic that references it follows
through the cascade automatically. No re-render. No recomputation. Just
a style mutation on the DNA provider’s wrapping div.
Phenotype
express(dna) produces:
- A color ramp generated with
oklch(L% C H)from theaccentandchromagenes (10 shades, 50–900). - Spacing tokens scaled by
density.spacing. - Radius tokens scaled by
radius.factor. - Font family + size scale from
typography. - Shadow set per
surface.style(flat / elevated / glassy). - Motion duration tokens (
--helixui-motion-duration-*). - A
data-themeattribute whenlightnessislightordark.
{ '--helixui-color-brand-500': 'oklch(56% 0.16 234)', '--helixui-color-brand-600': 'oklch(47% 0.155 234)', '--helixui-radius-md': '11.20px', '--helixui-space-4': '20.00px', '--helixui-font-family-sans': "'Geist', 'Space Grotesk', …", '--helixui-shadow-md': '0 4px 6px -1px rgb(0 0 0 / 0.1), …', '--helixui-motion-duration-normal': '200ms', /* …38 vars total… */}Persistence
A DNA is a plain JSON-serialisable object. To persist a user’s chosen
theme, JSON.stringify(dna) to localStorage / your backend; JSON.parse to
restore. Allele values are inert data — no functions or class instances.