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

@amplemarket/design-system-web

v0.1.2

Published

Website-scoped design system for Amplemarket. Inherits primitives from @amplemarket/design-system and adds a semantic layer plus website-only primitive extensions.

Readme

@amplemarket/design-system-web

The website-scoped design system for Amplemarket. Inherits the primitives from @amplemarket/design-system and adds website-specific layers on top:

  1. Primitive extensions — extra stops on existing core scales that only marketing pages need (e.g. color.neutral.25, color.blue.25).
  2. Semantics — usage roles that are unique to the website surface (e.g. surface.primary, text.primary, typography.label-m). These reference primitives directly; there are intentionally no per-component semantic tokens.
  3. Astro components — atoms (<Button variant="primary" />, <Header />) shipped as .astro source and compiled by the consuming Astro project. Each component's CSS reads from var(--…) tokens, so the token surface stands on its own and components are an optional convenience.

Anything brand-universal (the indigo ramp, the spacing scale, Labil Grotesk) lives in the core and is consumed unchanged. This package never re-declares core primitives — it only adds what the website surface needs and assigns roles. Other surfaces (product UI, email, decks) maintain their own semantic and component layers in their own repos.

The two halves are independent: the token system (Style Dictionary → CSS/SCSS/JS/JSON in dist/) builds and publishes on its own; the Astro component layer carries no build step and consumes the emitted token CSS vars.


Install

This package is published publicly to the npmjs registry. The core package is a transitive dependency and is pulled in automatically — consumers never need to install or import it directly.

# npm
npm install @amplemarket/design-system-web

# pnpm
pnpm add @amplemarket/design-system-web

# yarn
yarn add @amplemarket/design-system-web

Pin to an exact package version:

npm install @amplemarket/[email protected]

astro is a peerDependency (^4 || ^5 || ^6 || ^7) — consumers compile the shipped .astro files with their own Astro version.

How publishing works

dist/ is not committed. The publish workflow builds it in CI before npm publish, and the generated files are included in the public npmjs tarball. The build resolves against the core's source tokens (a transitive dependency) and emits a single self-contained bundle: core primitives + website extensions + semantics, all in one file per platform. The .astro components need no build — they ship as source.

The prepare lifecycle script remains for local npm pack / npm publish and git-URL fallback installs, but registry consumers should receive the already-built dist/ output from the package.


Usage

The token bundle is self-contained: every primitive a website token references is also declared in the bundle's output. Consumers import this package only — the core is an implementation detail.

CSS custom properties

@import "@amplemarket/design-system-web/css";

.hero {
  background: var(--surface-primary);
  padding: var(--spacing-64) var(--spacing-24);
  color: var(--color-indigo-900);
}

.faq-row:hover {
  background: var(--color-blue-25);
}

Core primitives (--color-indigo-900, --spacing-64, --shadow-300, …) are declared right alongside the website's own tokens (--color-neutral-25, --surface-primary, …) — one import, everything resolves.

SCSS variables

@use "@amplemarket/design-system-web/scss" as ds;

.hero { background: ds.$surface-primary; }
.cta  { color: ds.$color-indigo-900; }

JavaScript / TypeScript

The build also emits a nested JS/TS object (dist/index.mjs, index.cjs, index.d.ts) so tokens can be read programmatically — every core primitive plus every website extension and semantic, in one tree.

import ds from "@amplemarket/design-system-web";

const pageBg = ds.surface.primary;      // resolved value
const indigo = ds.color.indigo["900"];  // "#10054d"
const gap    = ds.spacing["24"];        // "24px"

Raw JSON (tool-to-tool, AI prompts, scripts)

import webTokens from "@amplemarket/design-system-web/json";

Or read any source file directly, e.g. @amplemarket/design-system-web/tokens/semantic/color.json.

Astro components

Components are exported per-file under ./astro/* and imported by path (there is no barrel — .astro files can't be named-exported from an index.ts):

---
import Button from "@amplemarket/design-system-web/astro/Button.astro";
import "@amplemarket/design-system-web/css";             // token CSS vars, once at the app root
import "@amplemarket/design-system-web/astro/styles.css"; // component CSS, once
---
<Button variant="primary" size="large">Click me</Button>

.astro files are compiled by the consuming Astro project — this package ships them as source and runs no component build. Components own only structural markup and CSS modifier classes (variant, size); every visual property comes from a var(--…) token, so opting out and rebuilding the markup against the raw tokens is a no-cost path.


What's inside

tokens/
├── primitives/                   Website-only extensions to core scales.
│   └── color.json                color.neutral.25, color.blue.25
└── semantic/                     Role assignments unique to the website surface.
    ├── color.json                surface.* (primary, secondary) + text.* (primary, muted, inverse)
    └── typography.json           typography.label-m, … (each: fontFamily/fontSize/fontWeight/lineHeight)

src/
└── astro/                        Astro component layer — shipped as source, no build step.
    ├── Button/
    │   ├── Button.astro          Markup + variant/size modifier classes, no inline values.
    │   ├── Button.css            All values via var(--…) — no hex, no px.
    │   └── Button.stories.ts     Storybook stories (.astro renderer).
    └── Header/
        ├── Header.astro          Vendored Amplemarket nav.
        ├── header.client.ts      Client behavior (transpiled by Vite; never inline TS in <script>).
        ├── Header.stories.ts
        └── webflow/              Vendored Webflow markup + CSS layers (see sync:header).

Semantic files are organized by primitive category, not usage namespace: color.json holds both surface.* and text.* at the top level; a new color role (e.g. border.subtle) goes under a new top-level namespace in color.json, not in a new border.json. Token paths stay role-first (surface > primary), so emitted CSS vars are --surface-primary, not --color-surface-primary.

Token files use the W3C DTCG format ($value, $type, $description) — same as the core.

What goes in primitives/ vs semantic/

  • primitives/ — extra stops on a core scale that the website needs but other surfaces don't. The keys still encode values (color.neutral.25, color.blue.25); they are just additions to scales the core already owns. If a value would also be useful in product/email/decks, it belongs in the core instead — not here.
  • semantic/ — usage roles that are website-specific, referencing primitives directly (surface.primary{color.neutral.25}, typography.label-m → composite of fontFamily/fontSize/…). Values are always references ({color.neutral.25}), never raw hex / px. Roles describe intent (what this color is in the design) and can be repointed without touching consumers.

There are intentionally no per-component semantic tokens (no button.json). A component reads primitives and abstract semantic roles straight from its CSS and owns its own variation logic via modifier classes. Only introduce a new semantic role when the abstraction is shared across multiple components — not for one-off component values.

Anything cross-surface — "this is our brand primary", "this is the workhorse weight" — does not belong here. Each surface (product, email, decks, …) makes its own semantic calls; only primitives are shared.

Theming

Themes are declared per-token via an optional $extensions.themes.<name> map; tokens that don't change across themes omit it. The custom css/themed-variables formatter emits one :root block of defaults plus one [data-theme="<name>"] block per theme. An app opts in by setting data-theme="dark" on <html>. There is intentionally no prefers-color-scheme query — OS-preference mapping is an application-shell concern.

How the merge works in the build

style-dictionary.config.js reads the core's raw DTCG tokens via include and this package's tokens via source. Both are emitted into this package's dist/, producing a single self-contained bundle per platform. Consumers see the merged tree in the JS object, and a single CSS file declares the full set of custom properties.

We deliberately consume the core's source tokens rather than its compiled dist/. That keeps reference paths ({color.indigo.900}) identical to how the core itself uses them, so semantic refs always resolve cleanly. outputReferences: true keeps semantic vars compiled to var(--color-neutral-50) rather than the literal hex, so when a core primitive's value changes (after a core bump), the semantic role picks it up without an edit here.


Build

npm install            # installs deps; `prepare` hook auto-builds dist/ (tokens)
npm run build          # alias for build:tokens — components need no build
npm run build:tokens   # Style Dictionary only — re-run after tokens/**/*.json edits
npm run clean          # rimraf dist

build runs a single Style Dictionary v4 pass over tokens/**/*.json (with the core's tokens resolvable via include). The Astro components have no build step — they are published as source and compiled by consumers.

Outputs under dist/:

| Output | Path | Use | |--------------|---------------------|--------------------------------------| | Token CSS | dist/tokens.css | Browsers, any CSS pipeline | | Token SCSS | dist/_tokens.scss | Sass-based projects | | Token ESM | dist/index.mjs | Modern JS/TS (nested default export) | | Token CJS | dist/index.cjs | Node / legacy bundlers | | Token types | dist/index.d.ts | TypeScript | | Token JSON | dist/tokens.json | Arbitrary consumers, AI tools |

dist/ is generated — it is not committed (it holds only token output). The prepare script regenerates it on every npm install of this package (including git-URL installs by the website repo) and before npm publish / npm pack.

See style-dictionary.config.js to add a new token output target.

Storybook

npm run storybook        # dev server at http://localhost:6006 (needs a built dist/)
npm run build-storybook  # static site → storybook-static/

Storybook is the visual verification path, via the community @storybook-astro/framework, which renders .astro components server-side. Stories live next to their component as src/astro/<Name>/<Name>.stories.ts. The framework renders each component to an HTML fragment and does not run Astro's page pipeline that hoists frontmatter CSS imports, so .storybook/preview.ts imports all CSS globally: dist/tokens.css (run npm run build first), an import.meta.glob over every co-located src/astro/**/*.css, and the core font side-effect import. storybook-static/ is gitignored.

Adding or changing a token

  1. Decide the layer: a new stop on a core scale → tokens/primitives/; a new website role → tokens/semantic/. If the value is meaningful to other surfaces, raise it into the core repo instead.
  2. Edit (or create) the relevant file under tokens/. Add new color roles to color.json under a new top-level namespace — don't create a per-namespace file. Use DTCG format. Semantic values must be references ({color.neutral.25}), not literals.
  3. If you bump the core dependency to pick up a primitive you need, update the @amplemarket/design-system version in package.json and call out the bump in the changelog entry.
  4. Run npm run build locally to verify dist/ regenerates cleanly. Do not commit the generated dist/ output — it is gitignored and rebuilt on install.
  5. Add an entry to CHANGELOG.md describing the change (see Versioning below).
  6. Bump the version in package.json according to the versioning policy before merge.
  7. Open a PR. When it lands on main / master, the publish workflow tags the version and publishes the public npmjs package.

Adding a component

  1. Component folder. Create src/astro/<Name>/<Name>.astro plus a sibling <Name>.css. The CSS uses only var(--…) references — no hex, no px, no fallbacks. The .astro file owns structural markup and modifier classes (variant, size); size/density variants are CSS modifier classes that rebind a private --_* local at the base class. Do not scaffold a tokens/semantic/<name>.json — components own their variation logic.
  2. Export. Add an ./astro/<Name>.astro entry to exports in package.json (and fold the component CSS into the shared ./astro/styles.css entry). There is no barrel re-export.
  3. Story. Add src/astro/<Name>/<Name>.stories.ts (typed satisfies Meta<AstroRenderer>). Slot content maps to the reserved slots arg; all other args map to props.
  4. Conventions. Keep CSS in a sibling .css file (a bare <style> block is scoped and would mangle .ds-*). Any client behavior goes in a sibling .ts module imported by a plain-JS <script> — never inline TypeScript in <script>.
  5. Verify. npm run storybook for visual verification.

See CLAUDE.md for the full set of .astro authoring conventions.

Versioning

This package follows Semantic Versioning. "Breaking" is defined from the point of view of a consumer who has built against a specific version of dist/ (tokens) or a pinned version of the .astro source:

| Change | Bump | |-------------------------------------------------------------------------|-------| | Renaming or removing any existing token key (primitive extension or semantic role) | major | | Repointing a semantic role to a different primitive such that the resolved value shifts visibly | major | | Changing the value of a website-owned primitive extension | major | | Removing or renaming a component, prop, or variant | major | | Changing a component's default rendered DOM in a way that's visible to users | major | | Bumping the astro peerDependency range so a previously-supported version is dropped | major | | Removing a build output (CSS/SCSS/ESM/CJS/JSON/d.ts) or an exports path (token or ./astro/*) | major | | Bumping the core @amplemarket/design-system version to one that is itself breaking — the core's break leaks through | major | | Adding a new primitive extension, semantic role, output target, component, prop, or variant | minor | | Bumping the core to a non-breaking minor / patch | minor | | Cosmetic re-ordering of keys, comment edits, $description additions | patch | | Internal-only refactors of component markup that don't change the rendered output | patch | | Fixing an obvious typo in a value (with negligible visual impact) | patch |

If in doubt, assume major. Consumers snapshot the resolved tokens — we would rather over-signal a breaking change than silently ship one.

Pre-1.0 caveat: while the package is on 0.x, treat a minor bump as potentially breaking (per SemVer's 0.x convention) and pin exactly in the website repo until 1.0.

Automated publishing

Merges to main or master publish a public package to the npmjs registry through .github/workflows/publish-package.yml.

  • If the merged PR did not change package.json's version, CI applies an automatic patch bump, commits it back to the branch, tags vX.Y.Z, and publishes that version.
  • If the merged PR does not change package.json's version, CI fails the release.
  • If the merged PR already changed the version, CI uses that version as-is, tags the merge commit, and publishes it.
  • The workflow publishes with npm trusted publishing / OIDC, not a long-lived npm token. Configure the package's trusted publisher on npmjs.com for GitHub Actions, repository amplemarket/design-system-web, workflow filename publish-package.yml, and allow npm publish.
  • Do not set "private": true in package.json — that flag means "never publish" to npm. Public package access is controlled by publishConfig.access.
  • If @amplemarket/design-system is private and the default GITHUB_TOKEN cannot read it during npm ci, add a repository secret named DEPENDENCY_GITHUB_TOKEN with read access to that dependency repo.

Changelog

All notable changes are recorded in CHANGELOG.md. The repo follows the Keep a Changelog convention. Every version bump must be accompanied by a changelog entry, with a clear note when a change is considered breaking.

Rules for contributors

  • Don't re-declare core primitives. If color.indigo.900 already exists in the core, don't redefine it here. Only add what the core doesn't ship.
  • Semantic values are references. A semantic token's $value is {color.neutral.25}, never #fdfcfb. If you can't write the reference, the underlying primitive is missing — add it (here or in the core) first.
  • Roles describe intent. surface.primary says "this is the default website surface", not "this is #fdfcfb". The whole point of the semantic layer is that we can repoint it without touching consumers.
  • No per-component tokens. Components own their variation logic in CSS modifier classes. Add a semantic role only when an abstraction is shared across multiple components (a new typography role, a new surface color) — never a button.* / card.* slot.
  • No surface-crossing semantics. This package is for the website only. Roles like surface.primary or text.primary belong here as long as the values they encode are website-specific opinions — every other surface (product UI, email, decks) defines its own. If you find yourself wanting the same role to apply identically across surfaces, the value belongs in the core primitives.
  • Keys still encode values where possible. Primitive extensions follow the core's convention: color.neutral.25 is a stop on the neutral ramp; color.blue.25 is a stop on the blue ramp. Use ordinal integers only when the value isn't a single scalar.
  • Brand-universal facts go in the core. If you find yourself writing a $description that any surface would benefit from, the token probably belongs in the core repo, not here.