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

@docsxai/viewer

v0.2.0

Published

Interactive docs-app generator + burned-annotation renderer: overlays (or bakes) halos, badges and callouts from annotations.json over clean screenshots.

Readme

@docsxai/viewer

Static-HTML interactive viewer + burned-annotation renderer + Starlight docs-site emitter. The viewer overlays a pulsing halo, a numbered badge (when a step has multiple call-outs), and a hover-revealed Popper-placed callout from annotations.json over clean screenshots at render time. Per-annotation nudge: { x, y } lets the author shift a callout aside when two would otherwise overlap; the halo stays anchored on the target.

PNGs in the doc pack stay clean (no baked annotations) — re-stylable, re-localisable, and machine-inspectable. For delivery surfaces that can't run the interactive viewer (Confluence, Notion, plain wikis), burn bakes the same annotations into copies of the PNGs.

Surface

  • buildViewer({ docsDir, outDir }) — reads <docsDir>/<flow>/annotations.json + screenshots, emits <outDir>/index.html + per-flow pages. Idempotent.
  • placeCallout(input) in src/placement.ts — Popper-like placement logic. Pure, coordinate-space-agnostic; tested independently. The single placement implementation shared by the browser overlay and the burner.
  • burnAnnotations({ screenshotPath | screenshotBuffer, annotations, options? }) — returns the burned PNG as a Buffer.
  • burnFlow({ docsDir, flow, outDir? }) — batch helper: burns every screenshot of a flow into docs/<flow>/burned/ (annotation-less steps are copied unchanged so the directory is the complete drop-in image set).
  • emitStarlightSite({ workspaceDir, outDir, config? }) / buildStarlightSite({ siteDir }) — the production docs-site renderer; see Starlight site.
  • docsxai-viewer bin:
    • docsxai-viewer build <docs-dir> <out-dir> [--flow <name>]... — the engine's docsxai render shells out to this.
    • docsxai-viewer burn <workspace> [--flow <name>]... [--out <dir>] — writes docs/<flow>/burned/<step>.png.
    • docsxai-viewer site <workspace> [--out <dir>] [--build] [--title <t>] [--accent <hex>] [--flow <name>]... — emits (and with --build builds) the Starlight site.

Starlight site

emitStarlightSite writes a complete, buildable Astro Starlight project from a doc pack — the production docs-site renderer beside the single-file interactive viewer, not a replacement for it. The first-party plugin package @docsxai/plugin-starlight exposes it to the engine's plugin runtime as the starlight:site renderer.

What gets emitted:

  • One MDX page per flow — an H2 per step, the step's <step>.md prose verbatim, and an <AnnotatedShot> figure per screenshot. The figure's caption lists each annotation's copy, numbered (<li value>) to match the badge indexes burned into the image — caption numbering and burned pixels can't drift apart.
  • Burned-image preferencedocs/<flow>/burned/<step>.png is copied when present, the clean screenshot is the fallback, and a missing image becomes a placeholder plus a warning (never a failure).
  • A landing page of flow link-cards with step/annotation counts, and a sidebar ordered by the workspace's flow extends graph (roots alphabetical, children nested DFS; flows without a flow-file append alphabetically) — the same shape as docsxai flow-tree.
  • Theme from the style artifactdocs/style.json's visual keys (brand_color > accent > primary_color) become a derived --sl-color-accent-* scale for both color schemes; visual.logo is copied in. Explicit --title / --accent / --logo config overrides win. An unparsable style accent is a warning; an unparsable explicit accent is an error.
  • Pinned, self-contained output — the emitted package.json exact-pins [email protected] + @astrojs/[email protected] (both MIT; matching this package's devDependencies, where the pair is tested). No remote fonts, no CDN imports anywhere in the emitted tree — Starlight ships its own assets and Pagefind search at build time; a test greps every emitted text file for external URLs.
  • Deterministic — same doc pack + same config → byte-identical file tree (no timestamps, sorted writes), asserted by a two-emit golden test.

buildStarlightSite({ siteDir }) runs astro build programmatically: it resolves the astro bin from this package's own install and, when the emitted site has no node_modules, symlinks the astro + starlight installs in individually — so building never touches the network. ASTRO_TELEMETRY_DISABLED=1 is always set. That zero-install shortcut requires the site directory to share a filesystem ancestor with the docsxai install (the normal case — the site is emitted inside the repo that installed it); for a fully detached site directory, npm install inside the emitted site and build there. The real-build E2E test is opt-in via DOCSX_STARLIGHT_BUILD=1 (the default test run never invokes astro).

Overlay single-sourcing

The script inlined into every flow page is generated, not hand-maintained. src/overlay-runtime.ts (browser-side DOM logic) imports the real placeCallout from src/placement.ts; the package build runs scripts/bundle-overlay.mjs (esbuild API) before tsc, bundling it to dist/generated/overlay.js — an unminified es2019 IIFE with no sourcemap, kept readable for auditability. render.ts reads that bundle at render time (resolved relative to import.meta.url, with a src/../dist/ fallback for running from source) and inlines it into each page. The bundle is byte-deterministic for a given esbuild version and is not committed; pnpm build (or pnpm test, which bundles first) produces it.

CSP posture

Every emitted page carries Content-Security-Policy: default-src 'none'; img-src 'self' data:; style-src 'unsafe-inline'; script-src 'unsafe-inline' — matching the inline-asset reality (inline <style>/<script>, workspace-local images) while blocking all network egress: no CDN fetches, no remote fonts, no beacons. The emitted HTML is fully self-contained.

Step write-ups

docs/<flow>/<step>.md files render through micromark in its safe default mode: raw HTML in the markdown is escaped and dangerous link protocols are dropped, so a write-up can't introduce markup or script into the page.

Burned annotations (burn.ts)

Design constraints, in order:

  • Browser-free. No Chromium, no Playwright, no DOM. The pipeline is Satori (HTML/CSS-subset flexbox layout → SVG) → @resvg/resvg-js (SVG → PNG). A regression test asserts no viewer source module imports playwright.
  • Deterministic. Same inputs → byte-identical PNG, asserted by a two-run golden test. The clean screenshot is embedded in the Satori tree as a data-URI <img>, so the whole frame rasterises in a single resvg pass — one encoder produces every output byte and there is no separate composite/re-encode step. Satori layout and resvg rasterisation are pure functions of their inputs; system fonts are never loaded; text is emitted as glyph paths; resvg writes no timestamps.
  • Faithful to the interactive viewer. Halo (accent border + glow) on the bounding box, numbered badge when index is present, rounded-rect callout (white background, 1px border) with copy wrapped to the same 280px outer clamp, triangle arrow per arrow_style (8 directions), nudge offsets applied to callout + arrow only. Placement reuses placeCallout; text measurement/wrapping uses the vendored font's own cmap/hmtx metrics (src/font-metrics.ts) as the burner's stand-in for the overlay's DOM measuring probe.
  • Engine-decoupled. The annotation record type is redeclared structurally in src/annotations.ts — it mirrors the docsxai/annotations@1 schema; the viewer never imports the engine package.

Vendored font

assets/fonts/inter-regular.ttf — Inter Regular v4.1 from the official rsms/inter release, licensed under the SIL Open Font License 1.1 (assets/fonts/LICENSE.txt). Satori needs raw font bytes; only the Regular weight ships, so bold-ish elements (the badge) render in Regular.

License

Apache-2.0. Runtime deps: satori (MPL-2.0), @resvg/resvg-js (MPL-2.0), micromark (MIT); vendored Inter font (OFL-1.1).