Hexpunk
InstallConceptsElementsProsehp-cellhp-codehp-copyhp-hexhp-latexhp-visually-hiddenhp-buttonhp-checkboxhp-formhp-labelhp-radiohp-selecthp-sliderhp-togglehp-toggle-grouphp-badgehp-taghp-progresshp-spinnerhp-backgroundhp-clusterhp-collapsiblehp-demohp-gridhp-scroll-areahp-separatorhp-sidebarhp-toolbarhp-avatarhp-iconhp-pixelhp-linkhp-menubarhp-navigation-menuhp-tabshp-alert-dialoghp-context-menuhp-dialoghp-dropdown-menuhp-hover-cardhp-popoverhp-tooltiphp-bannerhp-toasthp-tetherhp-module-handlehp-unfold-listhp-unfold-overlayhp-unfold-pagehp-bondhp-link-nodePaletteAnimationsReleases

Elements

@hexpunk/core/elements.css ships a token-driven baseline for native HTML primitives — paragraphs, links, lists, tables, code, form fields. Import it once at the document root and raw HTML in your app picks up the design system's typography, colour, focus ring, and forced-colors fallbacks. No <hp-*> wrapper required.

Two layers in one file. The bare reset auto-applies to every native element. The .hp-prose class is an opt-in rhythm scope for long-form content — see the Prose page.

Installation

<!-- Import the three CSS files once at your app's entry. --> <link rel="stylesheet" href="/path/to/@hexpunk/core/tokens.dark.css" /> <link rel="stylesheet" href="/path/to/@hexpunk/core/tokens.light.css" /> <link rel="stylesheet" href="/path/to/@hexpunk/core/elements.css" /> <!-- Then write plain HTML — every native element picks up the design system's tokens automatically. --> <p>Hello, hex world.</p>

Or, if your build pipeline supports CSS-via-JS imports (Vite, Astro, Next, etc.):

import "@hexpunk/core/tokens.dark.css"; import "@hexpunk/core/tokens.light.css"; import "@hexpunk/core/elements.css";

Headings

Heading 1 — display lg

Heading 2 — headline lg

Heading 3 — headline md

Heading 4 — title md

Heading 5 — label md (uppercase)
Heading 6 — label sm (uppercase)
<body> <h1>Heading 1 — display lg</h1> <h2>Heading 2 — headline lg</h2> <h3>Heading 3 — headline md</h3> <h4>Heading 4 — title md</h4> <h5>Heading 5 — label md (uppercase)</h5> <h6>Heading 6 — label sm (uppercase)</h6> </body>

Headings carry zero default margin so they compose freely. Use .hp-prose on a wrapping element to opt into vertical rhythm.

Inline text

Paragraphs default to --hp-on-surface. Strong and b tighten weight; emphasis and i italicise. Small text drops to body-sm.

Marked text uses the warn container tokens. Deleted strikes through; inserted underlines with the secondary hue. Press Ctrl + K for command palettes — kbd reads as a key cap.

H2O and E = mc2. Variables read as x, samples as OK.

<body> <p> <strong>Strong</strong> / <b>b</b>, <em>emphasis</em> / <i>i</i>, <small>small text</small>, <mark>marked</mark>, <del>del</del>, <ins>ins</ins>, <kbd>Ctrl</kbd>, <abbr title="Keyboard">kbd</abbr>. </p> <p>H<sub>2</sub>O — E = mc<sup>2</sup>. <var>x</var> / <samp>OK</samp>.</p> </body>

Links

Raw <a> is the *anchor-as-text* primitive — for in-sentence references like a link to elsewhere. For *anchor-as-affordance* (hover trace, hex geometry), reach for <hp-link> or <hp-cell variant="anchor">.

<body> <p> Visit <a href="https://example.com">example.com</a> for details. </p> </body>

Code

For syntax-highlighted code with line numbers, per-line hover, and a copy button, reach for <hp-code> — it accepts a consumer-registered highlighter (Shiki, highlight.js, Prism). The raw primitives below are the right call for short inline snippets and unhighlighted block samples.

Inline const x = 1 renders as a chip. Block-level code uses <pre><code>:

function hex(q, r) {
  return [q * (3 / 2), r * Math.sqrt(3) + q * Math.sqrt(3) / 2];
}
<body> <p>Inline <code>const x = 1</code> reads as a chip.</p> <pre> <code> function hex(q, r) { return [q * (3 / 2), r * Math.sqrt(3) + q * Math.sqrt(3) / 2]; } </code> </pre> </body>

Blockquote

The system is the source of truth — the chrome is just the surface.

— Hexpunk DESIGN.md
<body> <blockquote> <p>The system is the source of truth — the chrome is just the surface.</p> <cite>— Hexpunk DESIGN.md</cite> </blockquote> </body>

Lists

  • Atoms — single-hex elements (hp-cell, hp-icon)
  • Molecules — composed structures (hp-grid, hp-cluster)
  • Primitives — the bigger ideas
    • Bonding (adjacency)
    • Linking (arcs at distance)
    • Unfolding (in-place / overlay / camera-zoom)
  1. Read DESIGN.md
  2. Read PLAN.md
  3. Pick a step, propose, confirm, ship
Cell
Universal labelled hex element with interactive variants.
Cluster
Canonical 5-hex rosette layout.
Tether
Curved arc between two anchors.
<body> <div class="hp-prose"> <ul> <li>Atoms — single-hex elements</li> <li> Molecules — composed structures <ul> <li>Bonding (adjacency)</li> <li>Linking (arcs at distance)</li> </ul> </li> </ul> <ol> <li>Read DESIGN.md</li> <li>Pick a step, propose, confirm, ship</li> </ol> <dl> <dt>Cell</dt> <dd>Universal labelled hex element.</dd> </dl> </div> </body>

Bullet glyphs use the secondary hue via ::marker. Padding shown here comes from the .hp-prose wrapper — bare-reset lists ship with zero padding so consumers control list indentation per-surface.

Tables

Density modes
Mode Cell sm Cell md Cell lg
compact4480140
default50100180
comfortable60120220
<body> <table> <caption>Density modes</caption> <thead> <tr> <th>Mode</th> <th>Cell sm</th> <th>Cell md</th> <th>Cell lg</th> </tr> </thead> <tbody> <tr><td>compact</td><td>44</td><td>80</td><td>140</td></tr> <tr><td>default</td><td>50</td><td>100</td><td>180</td></tr> </tbody> </table> </body>

Details / summary

Why hexagons?

Hexagons are the densest regular tiling of the plane — six neighbours per cell, uniform distance, and a directionality that maps cleanly to a six-state colour system. Every Hexpunk component starts from that geometry.

What's the difference between hp-cell and hp-hex?

<hp-hex> is the raw geometric primitive — pure shape, no semantics. <hp-cell> is the universal labelled atom built on top, with interactive variants (anchor / action / secondary / utility) and decorative variants (content / support / slot).

Open by default

The open attribute starts the disclosure expanded.

<body> <details> <summary>Why hexagons?</summary> <p>Hexagons are the densest regular tiling of the plane...</p> </details> <details open> <summary>Open by default</summary> <p>The <code>open</code> attribute starts expanded.</p> </details> </body>

Horizontal rule

For dividers with orientation (horizontal / vertical), tone, and optional centred marks, use <hp-separator>. Raw <hr> stays useful for inline section breaks inside long-form content.

Above the rule.


Below the rule.

<body> <p>Above the rule.</p> <hr /> <p>Below the rule.</p> </body>

Form primitives

Raw form inputs get tokenised typography, restrained borders, and a focus ring that matches the rest of the system. They deliberately don't carry hex geometry — for the full Hexpunk aesthetic (hex buttons, hex-bonded toggles, single/multi toggle groups, sliders, labelled selects, form-association via <hp-form>), reach for: hp-button · hp-checkbox · hp-radio · hp-select · hp-slider · hp-toggle · hp-toggle-group · hp-label.
<body> <form> <label> Name <input type="text" placeholder="Hissalia" /> </label> <label> Email <input type="email" required placeholder="izzy@example.com" /> </label> <label> Bio <textarea></textarea> </label> <label> Country <select> <option>United Kingdom</option> <option>United States</option> </select> </label> </form> </body>
<body> <button>raw button</button> <button disabled>disabled</button> <label><input type="checkbox" checked /> Subscribe</label> <label><input type="radio" name="r" /> A</label> <input type="range" min="0" max="100" value="42" /> <input type="color" value="#00cc88" /> </body>
Display preferences
<body> <fieldset> <legend>Display preferences</legend> <label><input type="checkbox" /> Reduce motion</label> <label><input type="checkbox" checked /> Show focus rings</label> <label><input type="checkbox" /> High contrast</label> </fieldset> </body>

What this file does NOT do

  • Restyle <hp-*> elements — they live in shadow DOM and own their own chrome.
  • Repaint <button> / <input> as full hp-button / hp-input lookalikes — hex geometry stays reserved for the components.
  • Force a max-width or font-size root override — the page shell is yours.
esc