npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@nighthq/icons

v0.5.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.

Where an icon lives

One icon, one document. set/<name>.json is the icon: an IconDef as JSON, the file name its name, shipped in the tarball so a tool or a person can read one on its own. It opens with "schema": "ng.icon/1" — the envelope's id, which versions the file's conventions (an IconDef body, a tiers block that declares form at the version the icon was authored against, $icon references) separately from the tiers, which each version their own concepts — and the build refuses a document with no schema, another schema, a version it does not implement, or no form, naming the file. Everything else is generated from the documents and held to them by check:generated — the TypeScript literal in src/set/icons.ts (kept for its type; IconName and IconsWith<T> are computed from it) and the .svg files. A document may reference another icon's base drawing as { "$icon": "<name>" } where an element list is expected, so a drawing that is both a standalone icon and another icon's variant is authored once. The documents export carries every document's text by name, references intact, for a page that shows what an icon is authored as. The brand mark is the one drawing without a document: it is computed from a construction in src/set/mark.ts, and the construction is its source.

What the build refuses is one callable, and you can call it too. validateHouse holds every rule that makes a document a nightglass icon rather than merely a valid IconDef — the envelope, the tier laws, the viewBox rule across the base and every cut and variant, element-id uniqueness, and the denotation floor — and parseDocument reads a document's text without touching the filesystem. The build runs it, the corpus tests assert it, and a tool that generates icons validates against it rather than against a second copy of the rules. Findings carry a stable code from HOUSE_CODES, so a generator can decide what is worth another attempt.

set/README.md is the manual for the directory — the document format, how to add an icon, what the build refuses by file name, and the design record that used to sit beside each definition as comments.

A landed pack lives beside the set. packs/<pack>/ is what the icon factory (nightmill, at the repository root) publishes through its export verb: a manifest.json naming the pack's icons, icons/<name>.json — documents in the same envelope as set/'s, with the provenance tier filled — and the pack's own svg/, sheet, measures, changelog and evidence, which the build does not read. The build reads the documents into ONE set under their plain names: iconNames is one union and iconToSvg('cloud-upload') does not care who drew it. A name held twice — by set/ and a pack, or by two packs — is refused by file name (name.duplicate), as is a pack whose manifest and icons/ disagree. set/ stays curated by hand; nothing in the factory writes into it.

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/model/tiers.ts): a declared tier must be fulfilled, and a field whose tier is undeclared is refused. Eleven are registered, each with its own version and stability channel:

  • stable — denotation (label, keywords, category; carried for pickers and search, never auto-applied as a render title; the whole set opts in), detail (named cuts of one drawing; the mark's small cut), and state (typed attributes, toggle pairs, replacement or patch variants; eye flips between visible and hidden).
  • experimental, each carrying the question it exists to answer — structure, parts, anchors, tokens, paint, motion and provenance. The mark declares six of the seven; alert binds its dot to a colour token; eye blinks.

The floor also carries extensions, the one unchecked bag: keys are <namespace>.<name> by law, values are never validated, and nothing that draws ever reads it.

realize(def, context) is the one deterministic step from definition and context — detail level, state configuration, token overrides, rendered size — to a realization: resolved elements in a resolved space, colour as an abstract source, transforms as values. The model ends there. Five backends spell it — SVG (the string renderer, the generated files, the Svelte binding), Canvas2D, a mesh backend that turns every stroke into triangles because a GPU only fills, and WebGL and WebGPU on top of that mesh — and none knows the corpus or interprets a tier. Two GPU backends over one tessellation is what makes the mesh a shared substrate rather than one backend's private step. Selection is loud — an unknown level, an out-of-domain value or an unregistered operation id 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 12

1120.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.)