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

@seekalfred/tokens

v0.5.1

Published

Design tokens: three tiers, DTCG source, compiled to CSS custom properties and the single Tailwind @theme block.

Readme

@seekalfred/tokens

Design tokens in three tiers, authored as DTCG JSON and compiled to CSS custom properties plus the single Tailwind @theme block.

You do not install this directly — @seekalfred/styles imports it.

The tiers

| Tier | Prefix | Who may reference it | | --- | --- | --- | | 1. Primitive | --alfred-* | Tier 2 only. Never a component. | | 2. Semantic | --color-*, --shadow-* | Components, themes | | 2b. Scale | --text-*, --radius-*, --leading-*, … | Components | | Density | --density-* | Components |

Tier 1 is unreachable from a component by construction, not by review: it sits outside every Tailwind namespace, so bg-orange-500 cannot compile. The @theme block also opens with --color-*: initial, which deletes Tailwind's default palette so bg-blue-600 cannot compile either.

Every value is verbatim from the Alfred brand system. Do not re-pick them by eye, and port by role rather than by matching a variable name.

Scope axes

Two independent attributes, composable:

<html data-theme="dark" data-density="compact" dir="rtl"></html>
  • data-themelight (default) · dark. Overrides the semantic tier only, which is what keeps a theme a short override instead of a fork. Brand orange, periwinkle and the destructive fill are theme-invariant.
  • data-densitycomfortable (default) · compact · spacious. Changes space, never type. Every scope declares all 21 names, because custom properties inherit and a missing one would let a nested region silently take its parent's metrics. density-contract.test.ts enforces it.

Both axes rely on theme.css being imported inside layer(alfred.tokens). Unlayered @theme output beats every layered rule regardless of specificity, which silently broke dark mode entirely until it was fixed.

Contrast is a contract, not a review note

tokens/contrast-pairs.json lists every foreground/background pair a component actually renders, with its minimum ratio. A node test computes each ratio for every theme and fails the build.

This catches what axe cannot: axe checks text only, on whatever pairs a story happens to render, in whichever theme the run used — and it has no rule at all for borders, icons or focus rings (WCAG 1.4.11).

Two consequences worth internalising:

  • Fills are named as pairs--color-primary-foreground beside --color-primary — so the contract is expressible.
  • A fill is not automatically usable as text. --color-primary is 2.44:1 on the page, under even the 3:1 non-text floor, so the link label and the outline border use --color-primary-strong.

Fonts: tokens ship, files do not

The type tokens name Satoshi first and fall back to ui-sans-serif, system-ui, so an unconfigured consumer gets the system stack rather than a broken page.

The font files are deliberately not shipped. Satoshi is licensed under the ITF Free Font License, which restricts redistribution of the files — obtain it from Fontshare yourself. Bricolage Grotesque, Inter and JetBrains Mono are OFL 1.1 and may be redistributed with their license text.

There is no importable fonts.css, on purpose: CSS url() cannot read a custom property, so a shipped stylesheet could only guess your asset path and 404. Host the files yourself and paste this:

/* Prefer the VARIABLE Satoshi (300–900 axis). The five static weights ship
   300/400/500/700/900 with NO 600 — and --font-weight-semibold is 600, which
   drives every heading, so the static set silently synthesizes up to Bold. */
@font-face {
  font-family: "Satoshi";
  src: url("/fonts/Satoshi-Variable.woff2") format("woff2-variations");
  font-weight: 300 900;
  font-style: normal;
  font-display: swap;
}

--font-mono (JetBrains Mono) and --font-accent (Bricolage Grotesque) follow the same pattern and are optional — both degrade to sensible system stacks.

Gotcha: tailwind-merge and line-height

cn() runs tailwind-merge, which assumes a text-* class also sets line-height — true in Tailwind v3, not here. So a leading-* that appears before a text-* class in a merged class list is silently dropped, with no error and no visual clue.

If a component needs an explicit line-height, put leading-* after its text-* class, or in the same variant string. Controls with a fixed height and flex centring do not need one at all.

Editing

tokens/*.json is the source of truth. dist/ is generated — never hand-edit it. After any change:

node build-tokens.mjs   # or: pnpm --filter @seekalfred/tokens build
pnpm --filter @seekalfred/tokens test

Adding a token is a patch. Renaming or removing one is breaking — while 0.x that means a minor, and it needs a changeset.