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

@bannerboy/playground

v1.0.1

Published

Playground Design System — Precis Digital

Readme

Playground Design System

Precis Digital’s light, playful pastel foundation — tokens, typography, components, and icons in one package.

npm: @bannerboy/playground · Figma: Playground Design System · Preview: run npm run preview


Contents


For the team

| Role | Start here | | ---- | ---------- | | Designer | Figma file (link above) → match tokens & text styles → check live preview | | Frontend | Install package → import @bannerboy/playground/css → use .pg-* classes | | New joiner | Run npm run preview locally → browse foundations + components side by side |

Naming conventions

| Kind | Pattern | Example | | ---- | ------- | ------- | | CSS classes | pg- prefix | .pg-btn, .pg-heading-medium | | CSS variables | -- prefix | --color-accent-green, --sp-4 | | npm imports | @bannerboy/playground/… | @bannerboy/playground/css |

Three layers — use the right one

| Layer | When | Example | | ----- | ---- | ------- | | Tokens | Custom CSS, JS/TS, Tailwind preset | var(--font-text-medium-size) | | Typography utilities | All visible copy in HTML/JSX | .pg-text-medium, .pg-heading-small | | Component classes | Layout & chrome only | .pg-modal, .pg-card-slide |

Stack typography on components:

<p class="pg-modal__title pg-heading-medium">Invite people</p>
<p class="pg-modal__desc pg-text-medium pg-muted">Need a colleague to help you out?</p>

Install

npm install @bannerboy/playground

Requires access to the @bannerboy scope on npm. See PUBLISHING.md for setup.

Alternative (no npm registry):

npm install github:Precis-Digital/playground-design-system

Quick start

HTML

<link rel="stylesheet" href="node_modules/@bannerboy/playground/fonts.css" />
<link rel="stylesheet" href="node_modules/@bannerboy/playground/playground.css" />

React / Vite

// main.tsx
import "@bannerboy/playground/fonts";
import "@bannerboy/playground/css";
import { color, spacing } from "@bannerboy/playground";

export function Welcome() {
  return (
    <div className="pg-card">
      <h1 className="pg-heading-medium">Hello</h1>
      <p className="pg-text-medium">Built with Playground.</p>
      <button type="button" className="pg-btn pg-btn--primary">
        Get started
      </button>
    </div>
  );
}

TypeScript tokens

import { color, spacing, radius, typography, alert, gray } from "@bannerboy/playground";

Package structure

@bannerboy/playground
├── playground.css      ← import this (tokens + base + components)
├── fonts.css           ← optional Google Fonts loader
├── tokens.css          ← CSS custom properties only
├── base.css            ← reset + typography utilities
├── components.css      ← all component styles (imports below)
├── components/
│   ├── core.css        ← buttons, badges, inputs, cards shell
│   ├── cards.css
│   ├── modals.css
│   ├── loaders.css
│   ├── tooltips.css
│   └── headers.css
├── dist/               ← compiled tokens.ts + theme helpers
├── assets/
│   ├── icons/          ← 790 SVG icons (outlined + filled)
│   └── *.svg           ← logos
└── preview/            ← local docs site (not published to npm)

Exports map

| Import path | What you get | | ----------- | ------------ | | @bannerboy/playground | TypeScript tokens + theme API | | @bannerboy/playground/css | Full stylesheet | | @bannerboy/playground/fonts | Inter + Space Grotesk loader | | @bannerboy/playground/tokens.css | Tokens only | | @bannerboy/playground/base.css | Typography utilities only | | @bannerboy/playground/components.css | Components only | | @bannerboy/playground/tailwind | Tailwind preset | | @bannerboy/playground/assets/* | Icons, logos |


Design principles

  1. Light-mode first — dark mode is supported via data-theme="dark".
  2. One accent per surface — green, purple, and yellow are equals; pick one per view.
  3. Body text uses --ink (#1F242B), not --color-core-black (#000).
  4. Brand colours never flip in dark mode — pastels, --ink, and core black stay fixed.
  5. Sentence case on buttons — no uppercase CTAs.
  6. Figma is source of truth — tokens marked [Figma] in code match variables exactly.

Tokens

Primary & accent

| Token | Value | Use | | ----- | ----- | --- | | --color-core-black | #000000 | Brand swatch, strong borders | | --color-core-neutral-grey | #F6F5F1 | Paper / recessed surfaces | | --color-accent-green | #CDFAA5 | Accent surface | | --color-accent-purple | #D2ABFF | Accent surface | | --color-accent-yellow | #FFF07B | Accent surface | | --ink | #1F242B | Text on light surfaces |

Surfaces & text (theme-aware)

| Token | Light | Dark | | ----- | ----- | ---- | | --bg-base | #FFFFFF | #141414 | | --bg-paper | #F6F5F1 | #0A0A0A | | --text-primary | --ink | white | | --text-secondary | 60% ink | 64% white | | --text-muted | 40% ink | 40% white |

Alert colours

Pair background + text for alert banners and inline messages.

| Alert | Background | Text | | ----- | ---------- | ---- | | Success | --alert-success-bg · hsl(120, 60%, 96%) | --alert-success-text · hsl(120, 45%, 30%) | | Warning | --alert-warning-bg · hsl(45, 90%, 95%) | --alert-warning-text · hsl(40, 70%, 45%) | | Error | --alert-error-bg · hsl(0, 80%, 96%) | --alert-error-text · hsl(0, 65%, 45%) |

Spacing (4px base)

| Token | Size | | ----- | ---- | | --sp-1 | 4px | | --sp-2 | 8px | | --sp-3 | 12px | | --sp-4 | 16px | | --sp-5 | 20px | | --sp-6 | 24px | | --sp-8 | 32px | | --sp-10 | 40px | | --sp-12 | 48px | | --sp-16 | 64px |

Corner radius

| Token | Size | Typical use | | ----- | ---- | ----------- | | --radius-xs | 4px | Chips | | --radius-sm | 6px | Buttons, inputs | | --radius-md | 8px | Cards, modals | | --radius-lg | 12px | Large panels | | --radius-xl | 16px | Marketing surfaces | | --radius-pill | 999px | Tags, pill CTAs |

Grey ramp

--gray-50--gray-900 — warm neutral scale for borders, disabled states, and UI chrome.


Typography

Display & Heading — Space Grotesk Bold
Text — Inter Regular (default), Medium (.pg-medium), SemiBold (.pg-semibold)

Display

| Class | Size | Line-height | Tracking | | ----- | ---- | ----------- | -------- | | .pg-display-large | 96px | 95% | −4% | | .pg-display-medium | 76px | 100% | −3% | | .pg-display-small | 64px | 100% | −2% |

Heading

| Class | Size | Line-height | Tracking | | ----- | ---- | ----------- | -------- | | .pg-heading-x-large | 48px | 115% | −1.5% | | .pg-heading-large | 38px | 120% | −1.5% | | .pg-heading-medium | 28px | 130% | −1.5% | | .pg-heading-small | 22px | 140% | −1.5% | | .pg-heading-x-small | 16px | 140% | 0% |

Text

| Class | Size | | ----- | ---- | | .pg-text-x-large | 24px | | .pg-text-large | 20px | | .pg-text-medium | 16px | | .pg-text-small | 14px | | .pg-text-x-small | 12px |

All text sizes use 150% line-height and 0% tracking.

Utilities

| Class | Purpose | | ----- | ------- | | .pg-medium | Inter Medium (500) | | .pg-semibold | Inter SemiBold (600) | | .pg-muted | Secondary copy colour | | .pg-eyebrow | 12px uppercase section label |


Components

Core

| Element | Classes | | ------- | ------- | | Card shell | .pg-card · .pg-card--paper · .pg-card--dark | | Buttons | .pg-btn--primary · .pg-btn--outline · .pg-btn--accent-{green\|purple\|yellow} | | Pill CTAs | .pg-btn--action · .pg-btn--action-outline · .pg-btn--sm | | Badges | .pg-badge · .pg-badge--{green\|purple\|yellow} | | Inputs | .pg-input · .pg-input--underline · .pg-input--embed |

<button type="button" class="pg-btn pg-btn--primary">Save</button>
<input type="text" class="pg-input" placeholder="Email" />
<span class="pg-badge pg-badge--purple">Draft</span>

Cards

From Figma Cards (node 136:3766).

| Pattern | Classes | | ------- | ------- | | Slide card | .pg-card-slide (+ --selected, --simple) | | Template card | .pg-card-template | | Image split | .pg-card-split (image column first in DOM) | | CTA split | .pg-cta-card (+ .pg-cta-card__panel--invert) |

Modals

From Figma Modals (node 136:3751).

| Piece | Classes | | ----- | ------- | | Shell | .pg-modal · .pg-modal__close · .pg-modal__title · .pg-modal__desc | | Fields | .pg-modal-field · .pg-input | | Dropdown | .pg-modal-dropdown__trigger · .pg-modal-dropdown__list · .pg-modal-dropdown__option | | Wizard | .pg-modal-progress · [data-wizard-step] | | Success | .pg-modal-success | | Tags | .pg-modal-tags · .pg-modal-tag |

Modal copy always uses typography utilities:

<div class="pg-modal">
  <p class="pg-modal__title pg-heading-medium">Request template</p>
  <p class="pg-modal__desc pg-text-medium pg-muted">Missing a template?</p>
  <!-- fields… -->
</div>

Loaders

From Figma Loaders (node 136:3773).

| Pattern | Class | | ------- | ----- | | Dot ring | .pg-loader · .pg-loader--sm | | Text + dots | .pg-loader-text |

Both respect prefers-reduced-motion.

Tooltips

From Figma Tooltips (node 136:3775).

<div class="pg-tooltip">
  <button type="button" class="pg-tooltip__trigger" aria-label="Help">…</button>
  <div class="pg-tooltip__bubble">
    <p class="pg-tooltip__title pg-text-small pg-medium">Title</p>
    <p class="pg-tooltip__desc pg-text-x-small pg-muted">Description</p>
  </div>
</div>

Add .pg-tooltip--open to force visible (docs/screenshots).

Headers

From Figma Headers (node 140:2469).

| Pattern | Classes | | ------- | ------- | | Page header | .pg-header · .pg-header--compact | | Crumbs / meta | .pg-header__crumbs · .pg-header__meta | | Card header | .pg-card-header · .pg-card-header__kebab |


Icons

790 SVG icons in assets/icons/outlined/ and filled/, grouped by category.

import icon from "@bannerboy/playground/assets/icons/outlined/arrows/chevron-down.svg";

Icons use currentColor — they inherit text colour. In dark mode, inline SVGs flip to white automatically (accent buttons keep --ink).

Browse the full set: npm run previewIcons section.


Dark mode

Semantic surfaces, text, and borders flip when data-theme="dark" is set on <html>. Brand pastels and --ink stay fixed.

import {
  setPlaygroundTheme,
  persistPlaygroundTheme,
  initPlaygroundTheme,
} from "@bannerboy/playground";

setPlaygroundTheme("dark");           // one-shot
persistPlaygroundTheme("dark");       // + localStorage
initPlaygroundTheme();                // restore on load

React toggle example:

import { useEffect, useState } from "react";
import {
  getPlaygroundTheme,
  persistPlaygroundTheme,
  type PlaygroundTheme,
} from "@bannerboy/playground";

export function ThemeToggle() {
  const [theme, setTheme] = useState<PlaygroundTheme>("light");

  useEffect(() => setTheme(getPlaygroundTheme()), []);

  function toggle() {
    const next = theme === "dark" ? "light" : "dark";
    persistPlaygroundTheme(next);
    setTheme(next);
  }

  return (
    <button type="button" className="pg-btn pg-btn--outline" onClick={toggle}>
      {theme === "dark" ? "Light" : "Dark"}
    </button>
  );
}

Frameworks

Next.js (App Router)

// app/layout.tsx
import "@bannerboy/playground/css";
import { Inter, Space_Grotesk } from "next/font/google";

const inter = Inter({
  subsets: ["latin"],
  weight: ["400", "500", "600"],
  variable: "--font-inter",
});

const spaceGrotesk = Space_Grotesk({
  subsets: ["latin"],
  weight: ["700"],
  variable: "--font-space-grotesk",
});

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en" className={`${inter.variable} ${spaceGrotesk.variable}`}>
      <body>{children}</body>
    </html>
  );
}

Map font variables in global CSS (skip @bannerboy/playground/fonts when using next/font):

:root {
  --font-primary: var(--font-space-grotesk), system-ui, sans-serif;
  --font-secondary: var(--font-inter), system-ui, sans-serif;
}

Tailwind (optional)

// tailwind.config.js
import playground from "@bannerboy/playground/tailwind";

export default {
  presets: [playground],
  content: ["./src/**/*.{js,ts,jsx,tsx}"],
};

Import @bannerboy/playground/css alongside Tailwind for component classes, or use the preset for token-aligned utilities only.


Preview & development

Local reference site with foundations, live component demos, and icon browser.

npm run preview
# → http://localhost:4173

After editing demos or icons:

npm run preview:build

Build TypeScript output:

npm run build

Contributing checklist

  1. Match Figma tokens — don’t invent one-off colours or radii.
  2. Component CSS = layout/chrome only; typography = utility classes in markup.
  3. One accent colour per surface.
  4. Run preview and check light + dark before opening a PR.
  5. Bump version in package.json before npm publish.

Publishing

Package publishes to npm as @bannerboy/playground. Source stays on GitHub.

See PUBLISHING.md for npm login, 2FA, and install instructions for consuming repos.