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

@agent-scope/site

v1.20.0

Published

Static HTML gallery generator for Scope — reads .reactscope/ output and produces a component gallery website

Readme

@agent-scope/site

Static HTML gallery generator for Scope — reads .reactscope/ output and produces a self-contained component documentation website with a gallery, analytics dashboard, per-component detail pages, and design token compliance visualization.

Table of Contents


Installation

npm install @agent-scope/site

The package is also bundled with @agent-scope/cli. If you have the CLI installed, scope site build is the recommended way to invoke it.


Usage

Via the CLI (recommended)

# Build the site from .reactscope/ output
scope site build

# Build with custom options
scope site build \
  --output ./docs/components \
  --base-path /docs/ \
  --title "Acme Component Library" \
  --compliance .reactscope/compliance.json

# Serve locally for preview
scope site serve
scope site serve --port 8080

See @agent-scope/cli for the full scope site command reference.

Programmatic API

import { buildSite } from '@agent-scope/site';

await buildSite({
  inputDir: '.reactscope',
  outputDir: '.reactscope/site',
  basePath: '/docs/',
  title: 'My Component Library',
  compliancePath: '.reactscope/compliance.json',
});

Output Structure

buildSite() generates a directory of static HTML files with all CSS and JavaScript embedded inline — no web server or build step needed after generation.

outputDir/                            # default: .reactscope/site/
├── index.html                        # Gallery homepage — component grid with search
├── dashboard.html                    # Analytics dashboard
├── button.html                       # Detail page for "Button" component
├── search-page.html                  # Detail page for "SearchPage" component
├── complex-form.html                 # Detail page for "ComplexForm" component
└── ...                               # One file per component (PascalCase → kebab-case)

File naming: Component names are slugified from PascalCase to kebab-case:

  • Buttonbutton.html
  • SearchPagesearch-page.html
  • ComplexFormcomplex-form.html

Total files generated: N (components) + 2 (index + dashboard)

All HTML files are fully self-contained: CSS variables, layout styles, syntax highlighting, and client-side search JavaScript are all inlined. No external assets or CDN requests are required.


Pages

Gallery (index.html)

The gallery homepage provides an overview of all components with real-time search.

Header:

  • Site title
  • Total component count
  • Search box (filters component cards in real time, client-side)

Statistics grid:

| Stat | Description | |------|-------------| | Total Components | Count of all components in the manifest | | Simple | Components classified as simple complexity | | Complex | Components classified as complex complexity | | Memoized | Components wrapped in React.memo |

Component card grid:

Each card shows:

  • Rendered screenshot (base64 PNG from .reactscope/renders/) if available
  • Component name
  • Prop count
  • Complexity badge (simple / complex)
  • Hook count

Cards link to the corresponding detail page. The grid uses CSS auto-fill / minmax(280px) for responsive layout.


Dashboard (dashboard.html)

The analytics dashboard provides a library-wide view of component health and design token compliance.

Key metrics grid:

  • Total components
  • Average props per component
  • Components with screenshots
  • Overall design token compliance percentage

Complexity breakdown:

  • Simple / complex counts and percentage

Top components by prop count: A ranked table (top 10) with: component name (linked to detail page), prop count, complexity badge.

Design token compliance section (requires --compliance / compliancePath):

  • Overall compliance percentage with visual progress bar
  • Per-component compliance scores
  • On-system and off-system property counts per component

Component Detail Pages

Each component gets its own page (<slug>.html) with ten expandable sections.

Playground

  • Props reference table: prop name, type (syntax-highlighted), required/optional, default value, possible enum values
  • Rendered preview: embedded base64 PNG screenshot, or "not generated" if no render exists

Matrix

Grid of renders across prop axis combinations (from scope render matrix):

  • Each cell shows the rendered output or an error message
  • Cell labels show the axis values for that combination
  • Grid column count adapts to the number of cells

Docs

Placeholder for component documentation. Currently displays "No documentation file found."

Analysis

Statistics grid:

  • Complexity class badge
  • Prop count
  • Hook count
  • Side effect count
  • Export type (named / default)
  • Memoized (Yes / No)
  • Forwarded ref (Yes / No)

Analysis grid (2 columns):

  • Detected hooks (tagged list: useState, useEffect, etc.)
  • Required contexts (tagged list)
  • HOC wrappers (tagged list)
  • Side effects (tagged list: fetch URLs, timers, subscriptions, global listeners)

X-Ray

Collapsible DOM tree from the rendered component:

  • First 2 levels open by default, deeper levels collapsed
  • Syntax-highlighted element attributes and values
  • Total element count shown in header

Optional computed styles table:

  • CSS selector (element path)
  • CSS property name
  • Computed value

Tokens

Design token compliance audit (requires --compliance / compliancePath):

  • Compliance percentage with visual bar
  • Per-property audit table:

| Column | Description | |--------|-------------| | Property | CSS property name (monospace) | | Value | Computed value (with color swatch for hex values) | | Status | ✓ on-system (token.path) or ✗ off-system | | Nearest | Closest on-system token (when off-system) |

Accessibility

WCAG accessibility audit (from scope render data):

  • Component ARIA role badge
  • Accessible name
  • Violation list (red-highlighted) or success confirmation

Composition

Component dependency graph:

  • Left column: components this component composes (children)
  • Right column: components that compose this component (parents)
  • All entries link to their respective detail pages

Responsive

Multi-viewport renders. Placeholder: "Not generated."

Stress Tests

Edge case and stress test renders. Placeholder: "Not generated."


Configuration Options

SiteOptions

| Option | Type | Default | Description | |--------|------|---------|-------------| | inputDir | string | ".reactscope" | Directory containing manifest and renders | | outputDir | string | ".reactscope/site" | Output directory for generated HTML files | | basePath | string | "/" | Base URL path prefix for subdirectory deployment | | compliancePath | string | — | Path to compliance batch report JSON (optional) | | title | string | "Scope — Component Gallery" | Site title shown in header and <title> |

basePath for subdirectory deployment

When deploying to a path other than the domain root, set basePath so that inter-page links resolve correctly:

await buildSite({
  basePath: '/docs/components/',
  // ...
});

This prefixes all href attributes in the generated HTML with the given path.


Architecture

The package is a zero-dependency static site generator organized into focused modules:

src/
├── index.ts                     # Public API: exports buildSite()
├── builder.ts                   # Main orchestrator: read → render → write
├── reader.ts                    # Input reading: manifest.json, renders/, compliance
├── types.ts                     # TypeScript interfaces (ManifestData, RenderFileData, etc.)
├── css.ts                       # Inline CSS string (design tokens, layout, components)
├── utils.ts                     # escapeHtml(), slugify(), syntaxHighlightJSX(), renderDOMTree()
└── templates/
    ├── layout.ts                # HTML shell, top nav, sidebar, "On This Page" nav
    ├── component-index.ts       # Gallery homepage template
    ├── component-detail.ts      # Per-component detail page template
    └── dashboard.ts             # Analytics dashboard template

Data flow

.reactscope/manifest.json          ─┐
.reactscope/renders/*.json          ├─→  reader.ts  →  builder.ts  →  templates/  →  *.html
.reactscope/compliance.json (opt.)  ─┘
  1. reader.ts reads the manifest JSON, optionally scans the renders/ directory for per-component JSON files, and optionally reads the compliance report.
  2. builder.ts iterates over all components, calls templates for each page, and writes HTML files to outputDir.
  3. templates/ functions receive typed data objects and return HTML strings. All templates call layout.ts to wrap content in the shared shell (nav, sidebar, "On This Page").
  4. css.ts exports a single inline CSS string embedded in every page's <style> tag.
  5. utils.ts provides XSS-safe HTML escaping, PascalCase-to-kebab-case slugification, JSX syntax highlighting, and recursive DOM tree rendering.

Design principles

  • Zero dependencies — the package has no runtime NPM dependencies. All output is pure HTML/CSS/JS.
  • Embedded assets — CSS and JavaScript are inlined into every HTML file. No separate asset directory.
  • XSS safety — all user-controlled strings (component names, prop values, file paths) pass through escapeHtml() before insertion into HTML.
  • Idempotent builds — running buildSite() multiple times on the same input produces identical output.
  • Progressive enhancement — pages are readable without JavaScript; search filtering and collapsible sections are added via inline <script> tags.

CSS design system

The generated HTML uses CSS custom properties for consistent styling:

--color-text: #0f0f0f;
--color-muted: #6b7280;
--color-border: #e5e7eb;
--color-bg: #ffffff;
--color-bg-subtle: #f9fafb;
--color-bg-code: #1a1a2e;
--color-accent: #2563eb;
--color-success: #16a34a;
--color-warn: #d97706;
--color-error: #dc2626;

--font-body: 'Inter', system-ui, -apple-system, sans-serif;
--font-mono: 'JetBrains Mono', 'Fira Code', monospace;

Layout: Three-column design — left sidebar (220px, component list with search), main content (flex, max 900px), right sidebar (200px, "On This Page" nav). The left sidebar collapses at 768px, the right sidebar at 1024px.


Data Formats

Input: manifest.json

interface ManifestData {
  version: string;
  generatedAt: string;
  components: Record<string, ComponentData>;
  tree: Record<string, { children: string[]; parents: string[] }>;
}

interface ComponentData {
  filePath: string;
  exportType: "named" | "default" | "none";
  displayName: string;
  props: Record<string, PropData>;
  composes: string[];
  composedBy: string[];
  forwardedRef: boolean;
  hocWrappers: string[];
  memoized: boolean;
  loc: { start: number; end: number };
  complexityClass: "simple" | "complex";
  requiredContexts: string[];
  detectedHooks: string[];
  sideEffects: {
    fetches: string[];
    timers: boolean;
    subscriptions: string[];
    globalListeners: boolean;
  };
}

interface PropData {
  type: string;
  values?: string[];   // enum values
  default?: string;
  required: boolean;
  rawType: string;
}

Input: renders/<Component>.json

interface RenderFileData {
  screenshot?: string;          // Base64-encoded PNG
  width?: number;
  height?: number;
  renderTimeMs?: number;
  computedStyles?: Record<string, Record<string, string>>;
  dom?: {
    tree: DOMNodeData;
    elementCount: number;
    boundingBox: { x: number; y: number; width: number; height: number };
  };
  console?: {
    errors: string[];
    warnings: string[];
    logs: string[];
  };
  accessibility?: {
    role: string;
    name: string;
    violations: string[];
  };
  // Matrix render fields
  cells?: MatrixCellData[];
  axisLabels?: string[][];
  stats?: {
    total: number;
    success: number;
    failed: number;
    avgRenderTimeMs: number;
  };
}

Input: compliance.json

interface ComplianceBatchData {
  components: Record<string, ComplianceReportData>;
}

interface ComplianceReportData {
  properties: Record<string, PropertyResultData>;
  total: number;
  onSystem: number;
  offSystem: number;
  compliance: number;   // 0–1
  auditedAt: string;
}

interface PropertyResultData {
  property: string;
  value: string;
  status: "on_system" | "OFF_SYSTEM";
  token?: string;
  nearest?: { token: string; value: string; distance: number };
}