@nighthq/icons
v0.3.0
Published
Nightglass line-work icon set and brand mark, as framework-agnostic path data.
Readme
@nighthq/icons
59 line-work icons and the brand mark, as tiered icon data. No framework.
import { iconToSvg, iconNames, markToSvg } from '@nighthq/icons';
el.innerHTML = iconToSvg('search', { title: 'Search sessions' });Prebuilt files are on disk at @nighthq/icons/svg/<name>.svg, generated from
the same data the JS renders — one drawing, not two.
The model
Icons implement the tiered icon model
(docs/0002-tiered-icon-model.md). The
mandatory floor is form: one ordered element list — { id?, geom, mode? },
list order is draw order, geometry a lossless union (path, circle, rect,
line, polyline, polygon, ellipse), mode the whole floor paint
(stroke | fill). Everything above the floor is an opt-in tier, declared
per icon and gated in both directions (src/tiers.ts):
- denotation — label, keywords, category; carried for pickers and search, never interpreted, never auto-applied as a render title. The whole set opts in.
- detail — named cuts of the same drawing for other legibilities; the mark's
smallcut is the first resident.
realize(def, context) is the one deterministic step from definition and
context (detail level today; configuration when state lands) to drawn
elements; both renderers and the generated files consume it, and selection is
loud — an unknown level throws rather than falling back. IconsWith<T>
narrows the name union to a capability at compile time.
Conventions
- a 24x24 grid; stroke only,
fill="none"; - stroke-width 1.6, the mark's own weight, so an icon set beside the logo reads as the same drawing rather than as clip art next to a logo;
currentColor, so an icon is coloured by the token on its container and a theme change reaches it without a second asset;- round caps and joins — the one place the system's "sharp corners" rule does not apply. That rule governs container radii; a butt-capped 1.6px terminal at 16px renders as a visibly chipped edge.
Accessibility
title is the switch. Without it an icon is decorative and marked
aria-hidden — the right default, because most icons sit beside a label that
already says the word, and announcing it twice is noise. Give a title only when
the icon is the only thing carrying the meaning.
The mark
A nightglass graticule: an aperture ring, a hollow centre, four spokes, and seven radial ticks swept 65 degrees off-axis. The seven and the 65 are inherited from the mark this design language descends from — the lineage is in the construction, not in a resemblance. The hollow centre is the point: the instrument is the thing you see through, not the thing you look at.
markToSvg({ small: true }) drops the ticks and thickens the stroke. Below about
32px the ticks close into a grey halo, so the small cut keeps the mark legible
rather than keeping it identical.
Geometry
pathPoints, pathHull and pathBounds parse path data properly rather than
scraping numbers out of it, because scraping is wrong in a way that looks right:
M12 3.5A8.5 8.5 0 1120.5 121120.5 there is the large-arc flag, the sweep flag, and x=20.5 — SVG lets
single-digit flags run together. A scrape also reads arc radii and rotations as
coordinates, so it can pass an icon that clips and fail one that does not. Curves
are bounded by their control hull (conservative, which is the correct direction
for a clipping check); unknown commands throw rather than being skipped.
The family
Five packages, published together from one repository:
| package | what it is |
| -------------------------------------------------------------------------- | ------------------------------------------------------------------------ |
| @nighthq/tokens | the colour system, and the base stylesheets that depend only on it |
| @nighthq/components | the Svelte 5 interface primitives, plus an opt-in atmospheric tier |
| @nighthq/icons | line-work icons and the brand mark, as tiered icon data — no framework |
| @nighthq/model | the framework-neutral view kernel: one semantic model, two presentations |
| @nighthq/host | the effect boundary — history, titles, announcements, focus |
Start with tokens + components. Add icons when you need glyphs, and
model + host when one screen has to render as both a desktop and a compact
presentation.
The repository is private, so homepage and repository links on these npm
pages will not resolve for you — these READMEs and the tarballs are the whole
documented surface, which is why they carry more than a link would.
(No counts in this table on purpose: a number repeated across five files is
five places for it to go stale, and only each package's own README has a
check-docs claim behind its figures.)
