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

@nomiedge/tokens

v1.0.0

Published

Nomiedge design tokens — color, typography, spacing, radius, motion, shadow and breakpoints.

Readme

@nomiedge/tokens

Design tokens: color, typography, spacing, radius, motion, shadow and breakpoints — every token category Pack 03 named is now built, plus a generated Tailwind v4 theme. A full token review (30-token-review.md) remains.

Tailwind integration

Tailwind v4 is CSS-first — there's no tailwind.config.js preset to extend. Instead, this package generates a @theme CSS file (tailwind-theme.css, built by tailwind-theme.ts) and a semantic light/dark CSS-custom-property file (semantic.css), both built entirely from this package's own token exports — nothing in either is a value typed a second time. A consumer imports both from their own CSS entrypoint, alongside Tailwind itself:

/* src/app/globals.css */
@import "tailwindcss";
@import "@nomiedge/tokens/tailwind-theme.css";
@import "@nomiedge/tokens/semantic.css";
@source "../../node_modules/@nomiedge/ui/dist";

(@source tells Tailwind v4's automatic content detection to also scan @nomiedge/ui's compiled output for classes — without it, utilities this package's components use but a consumer's own source never types wouldn't be generated. Adjust the relative path to wherever your app's CSS entrypoint actually lives — see apps/brand-portal/src/app/globals.css or any of packages/templates/src/{app-shell,marketing,docs}/app/globals.css for the real pattern in use elsewhere in this repo.)

tailwind-theme.css wires up every primitive token category (raw neutral/accent color scales, type scale, spacing, radius, shadow, motion, breakpoints) as Tailwind theme values. semantic.css wires up the semantic light/dark color layer (color.light/color.dark) as CSS custom properties (--color-*) with a .dark override, resolved against @nomiedge/ui/the brand portal (Pack 04/05) as the real consumer. See docs/adr/0007-tailwind-v4-migration.md for why this replaced the old nomiedgePreset JS preset.

Breakpoints

Aligned with Tailwind's default scale (28-breakpoints.md), not a bespoke set — anything on this system built with Tailwind (the likely case, since most Next.js apps are) gets breakpoints that already match theme(screens.*), no translation layer needed.

import { breakpoints } from "@nomiedge/tokens";

// breakpoints.md = "768px", breakpoints.lg = "1024px", ...

Shadow

sm/md/lg (27-shadow-elevation.md) — minimal, built from the brand ink color at low opacity rather than generic black, and restrained relative to most component libraries' shadow scales: prefer color.*.border.default alone over reaching for shadow where either would do.

import { shadow } from "@nomiedge/tokens";

// box-shadow: shadow.md

Shadow barely works in dark mode — a low-opacity black shadow is nearly invisible against a near-black background. Dark-mode elevation should come from color.dark.surface.default being lighter than the background (established in colors.ts) plus color.dark.border.default, not from shadow.*. shadow.lg still has a real, narrow use in dark mode: large overlays (modals) above a dimmed backdrop, where the backdrop itself gives the shadow something to read against.

Motion

duration (fast/base/slow) and easing (standard/decelerate/accelerate — Material's well-established curve set, not a spring/bounce; overshoot reads as playful, ruled out by .claude/project.md's "calm, precise, premium").

import { duration, easing, reducedMotionDuration } from "@nomiedge/tokens";

// transition: `${duration.base} ${easing.standard}`

Reduced motion is a real, applied mechanism, not a note to add one later: reducedMotionDuration (0.01ms, not 0ms, so transitionend still fires) is meant to be swapped in via @media (prefers-reduced-motion: reduce) in CSS — not a JS matchMedia runtime check, which can cause a hydration mismatch in SSR. See the usage example in motion.ts.

Radius

none/sm/md/lg/xl/2xl/full (25-radius-system.md) — a consistent progression in px (not rem: corner rounding shouldn't scale with text zoom).

import { radius } from "@nomiedge/tokens";

// radius.md = 8px, radius.xl = 16px, radius.full = 9999px (pills, avatars), ...

Resolves a tracked gap: KNOWN_ISSUES.md flagged that brand/logo-inverted.svg's rx=24 wasn't tied to a token. It still isn't, on purpose — the mark's corner radii (16/14/18/24 across brand/*.svg) are fixed geometric constants chosen for optical balance in the logo's own construction, not UI radius decisions. radius["2xl"] happens to equal 24px too (radius.xl is 16px, a different step), but that's a coincidence — the same way color.dark.background.default (neutral[950]) happens to land close to, but not exactly on, the brand ink color — noted in radius.ts/colors.ts, not a real dependency between packages/logo and packages/tokens.

Spacing

A 4px-based scale (24-spacing-system.md) — 4px steps through 24px, 8px steps beyond. Keyed by the 4px multiplier, Tailwind's convention: spacing[4] is 16px (4 × 4px).

import { spacing } from "@nomiedge/tokens";

// spacing[2] = 8px, spacing[6] = 24px, spacing[16] = 64px, ...

No semantic layer (spacing.componentGap, etc.) yet — that depends on real layout decisions @nomiedge/ui hasn't made yet. Adding semantic names now would be guessing.

Typography

Geist Sans (UI, body, display) and Geist Mono (code) — confirmed system-wide in 23-typography-tokens.md, the same choice ADR 0002 made for the wordmark specifically.

Reference typography.*, a complete, ready-to-apply style object per semantic use — not fontSize.lg and fontWeight.bold assembled separately at the call site:

import { typography } from "@nomiedge/tokens";

// typography.display.lg, typography.body.md, typography.code.sm, ...

The type scale (fontSize) is a major-third (1.25) ratio, base 16px, rounded to whole pixels — see the inline comments in typography.ts for the exact math behind each step.

Known duplication (tracked in ../../KNOWN_ISSUES.md): @nomiedge/logo's LogoWordmark hard-codes its own copy of the Geist font stack rather than importing fontFamily.sans from here, because packages/logo doesn't depend on packages/tokens (a deliberate choice — see ARCHITECTURE.md). Now that both independently arrived at Geist, that's a real argument for adding the dependency; not done in this milestone since it's outside its scope.

Color

neutral and accent — a monochrome base plus exactly one cobalt/indigo accent, per prompts/Pack-03-Design-Tokens/21-color-system.md. No other hues exist in this package on purpose: no separate green/red/yellow status palette.

This is a known gap, not an oversight (tracked in ../../KNOWN_ISSUES.md): a serious product UI eventually needs to communicate success/warning/danger, and this token set doesn't have colors for that yet. When that need becomes concrete (building @nomiedge/ui's form validation states, for instance), it needs a deliberate decision — add a scoped exception (e.g. a danger hue for destructive actions, still no rainbow of status colors), or lean on icon/weight/pattern instead of color for status. Don't quietly bolt on a red and a green the first time a component needs one.

Import semantic tokens, not the raw scale, from component code — pick the theme, then the token:

import { color } from "@nomiedge/tokens";

// color.light.foreground.primary, color.dark.background.default, color.light.accent.default, ...

neutral/accent (the raw 11-step scales) are exported too, for the rare case a semantic token doesn't exist yet — but a component reaching for neutral[700] directly instead of a semantic token is a sign a semantic token is missing, not license to skip the semantic layer.

Dark mode is a different mapping, not an inverted formula

color.dark maps the same semantic keys to different steps of the same neutral/accent scales — it isn't 1 - lightness computed automatically, because that produces genuinely wrong results for at least one case here: accent at its light-mode step (52% lightness) reads as muddy against a 6%-lightness dark background, so dark mode uses a lighter accent step (62%) instead, and lightens further on hover/active (the opposite direction from light mode, which darkens on hover/active). Surfaces also read as "elevated" by being lighter than the page background in dark mode — the reverse of light mode's card-on-lighter-background/shadow-driven elevation. Every one of these choices is deliberate, not derived; see the inline comments in colors.ts for the reasoning behind each.

Contrast is tested, not eyeballed

colors.test.ts computes real WCAG contrast ratios (contrast.ts, a standard relative-luminance implementation per the WCAG 2.x formula) for every semantic pair that needs to meet AA — normal text (4.5:1) or UI-component boundaries (3:1, WCAG 1.4.11) — in both themes. This caught two real bugs during development, one per theme: light mode's border.default only reached 1.41:1 (fixed to 4.15:1); dark mode's first attempt at border.default only reached 1.86:1 (fixed to 4.24:1) — the same category of mistake, caught the same way, in an independently-chosen value.

Run pnpm --filter @nomiedge/tokens test after changing any color value, in either theme.