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

@abreen/tada

v1.22.7

Published

A static site generator

Readme

Tada :tada:

CI/CD npm version

A static site generator. The successor to Presto.

Visit the example site ↗

Features

  • Modern design

    • Light & dark mode following system, customizable tint
    • Standard & high contrast picker
    • Sans-serif & serif font picker
    • Precisely tuned optical sizing of Inter, by Nan Xiao
    • Plus, provide your own web fonts (with many tuning options)
  • LaTeX math support

    • Provided by KaTeX
    • Rendered completely at build time (zero load time on the client)
  • Automatically generated favicon

    • Text, color, font and font weight taken from config file
    • Or, provide your own favicon file
  • High quality output and ergonomic authoring

    • Exhaustive internal link validation (broken links fail the build)
    • External link handling (special visual treatment for external links, no need to type target="_blank")
    • Internal links automatically prefixed with base path, if specified (no need to keep writing the same URL prefix everywhere)
  • Built-in search powered by Pagefind

    • Only pages in content/ reachable from /index.html are indexed
    • If mutool is installed, text inside PDFs in content/ is indexed
  • Generated HTML pages for source code

    • Automatic code highlighting, clickable line numbers
    • Dynamic table of contents for each method/function
    • Converts new Markdown comment syntax (added in Java 23) to HTML
    • Indexed by Pagefind (classes, interfaces, methods, and fields)
  • Dynamic table of contents

    • Floats on the side of the screen when window is large enough
    • Renders headings, alert boxes, and <hr> elements
    • Highlights the heading currently being viewed
  • Document indexes for ordered sections, like a course's labs

    • An index.yml lists pages as a tree
    • Pages get a sidebar tree and previous and next links
  • Extended Markdown syntax

    • !!! note ... !!! and !!! warning ... !!! render alert boxes
    • ??? question ... ??? renders a Q&A section; answer is hidden until click
      • To display clickable multiple choice options, use a task list
    • +++ ... +++ ... +++ renders a two-column layout
    • [Title][Description](url) renders a two-line superlink
    • [[Page Title]] or [[Page Title|link text]] wikilinks link to a page by its title
    • Special heading subtitles with ## Heading # A subtitle here
    • {{{ _partial.md }}} syntax for including partials
    • Styled <details> elements, including "Show more" previews (see Details elements)
    • [Label| ... ] renders tabs; consecutive tabs form one group
      • Number the labels 1., 2., ... to render a stepper with Back and Next buttons
  • Extremely efficient client-side navigation

    • A miniature SPA that uses internal links tagged at build time
    • Get the benefits of DOM tree replacement without an entire bloated framework
    • Thoroughly covered by browser tests across multiple engines
    • Clear loading indicators for slow requests
    • Also detects a new version of the current page and supplies a reload button
  • Your own TypeScript and Sass, compiled with the site

    • List scripts from src/ in a page's front matter instead of writing <script> tags
    • Each script mounts and unmounts with its page, even across client-side navigation
    • Minified, content-hashed, and code-split in production builds

Experimental features

  • Interactive execution traces via fenced trace code blocks

    • Supports Java and Python source files
    • Renders step-by-step source highlighting, output, and memory diagrams
  • Slides mode: separate content by --- and present sections as full-screen slides

    • Click icon near slide titles to start presenting at that slide
    • Right-click in presentation mode to annotate
    • Hold Shift while annotating to erase

Prerequisites

  • Bun
  • MuPDF (optional)
    • macOS (using Homebrew): brew install mupdf-tools
    • Fedora Linux: sudo dnf install mupdf
    • Ubuntu Linux: sudo apt-get install mupdf-tools
    • Windows: winget install mutool

[!NOTE] You may skip MuPDF if you don't need search results to include links to PDF pages. You can also turn off features.search in the config to disable search entirely.

If you plan to use trace blocks to generate traces of Java or Python code, the appropriate compiler/interpreter must be installed.

Installation

Install Tada globally:

bun install --global @abreen/tada

To update Tada to the latest version:

bun update --global @abreen/tada

Quick start

Create a new site:

tada init mysite

This will ask you a few questions (site title, logo symbol, theme color, etc.) and create a new directory with everything you need.

Then build and preview your site:

cd mysite
tada dev
tada serve

Visit http://localhost:8080/index.html.

CLI commands

tada init <dirname>

Create a new Tada site in a new directory. Prompts for:

  • Site title: displayed in the header and <title> tag
  • Symbol: short text (1-5 uppercase characters) shown in the logo and favicon, or a single emoji shown in the logo (defaults to 🎉; emoji symbols turn off generated favicons)
  • Theme color: CSS color, e.g. hsl(195 70% 40%) (defaults to darkturquoise)
  • Background tint hue: hue (0-360) for background/foreground tinting (defaults to 190)
  • Background tint amount: percentage (0-100) of tint to apply (defaults to 100)
  • Production base URL: e.g. https://example.edu
  • Production base path: e.g. /cs101 (defaults to /)

Pass --no-interactive to skip prompts and use default values for all options. You can also override specific defaults with flags:

tada init mysite --no-interactive --prod-base https://example.edu --prod-base-path /cs101

Available flags: --title, --symbol, --theme-color, --tint-hue, --tint-amount, --prod-base, --prod-base-path.

tada dev

Build the site for local development (using site.dev.yaml by default) into the dist/ directory.

tada serve

Start a development web server at http://localhost:8080 which serves the files in the dist/ directory.

tada watch

Start a development web server, watch for changes and rebuild automatically. Exactly one site.dev.yaml, site.dev.yml, or site.dev.json must exist before starting; otherwise, correct the configuration files and restart the command. Once watching, build errors can be fixed without restarting.

tada clean

Remove the dist/ directory. Pass --prod to also prune old production builds (keeps the latest two versions).

tada prod

Build the site for production (uses site.prod.yaml by default). Each prod build is saved to a versioned directory under dist-prod/ (e.g., dist-prod/v1/, dist-prod/v2/) with a manifest file that records the SHA-256 hash of every output file.

tada diff

Compare two production builds and list added, changed, and removed files. With no arguments, compares the last two builds. You can also specify version numbers explicitly:

tada diff          # compare latest two builds
tada diff 1 3      # compare v1 and v3

Use --copy <dir> to copy only the changed and added files to a directory:

tada diff --copy upload/

The output directory will also include a manifest.json for the newer build.

Development vs. production builds

tada dev and tada watch build to the dist/ directory using site.dev.* (typically localhost URLs). tada watch includes a development server with live reload; tada serve is a standalone server for previewing a tada dev build. Dev builds overwrite dist/ each time.

tada prod builds to a new versioned directory under dist-prod/ each time it runs. Previous production builds are preserved, so you can compare any two versions with tada diff.

Deploying to S3

If you host your site in an S3 bucket, tada diff --copy lets you upload only the files that changed between prod builds instead of re-uploading everything.

First time:

tada prod
# Upload the entire dist-prod/v1/ directory to your S3 bucket

After making changes:

tada prod
tada diff --copy upload/
# Upload just the upload/ directory to S3 (only changed files)

If tada diff reports removed files, delete those from your S3 bucket manually.

Configuration

Build-time site config lives in:

  • site.dev.yaml (used by tada dev / tada watch)
  • site.prod.yaml (used by tada prod)
  • nav.yaml (navigation structure, optional)
  • authors.yaml (author data, optional)

Tada also accepts .yml and .json for each of these files. Keep only one variant for each logical config name; for example, nav.yaml and nav.json in the same site root is an error.

Example site configuration YAML file:

title: Intro to Computer Science
titlePostfix: " - CS 0"
banner: |
  The semester is now closed. Final grades will become available on
  [Gradescope](https://example.org/course/12345) on December 30.

  This site is an archive. This is how the site appeared on December 27, 2020.
symbol: CS 0
themeColor: hsl(351 70% 40%)
tintAmount: 0
defaultFont: serif
defaultContrast: high
fontOverrides:
  serif:
    regular: fonts/body-regular.woff2
    tuning:
      scale: 1.125
      lineHeight: 1.5
      headingScale: 0.9
      headingWeight: 400
  serifMono:
    regular: fonts/mono-regular.woff2
    features: [ss02]
    tuning:
      scale: 0.94
      lineHeight: 1.5
features:
  search: true
  favicon: true
  pickers: true
base: https://example.edu
basePath: /cs0
internalDomains:
  - example.edu
extensionToShikiLanguage:
  java: java
  py: python
shikiLanguages:
  - java
  - python
vars:
  staffEmail: [email protected]

| Field | Description | |-------|-------------| | title | Title for the whole site (also used to derive titlePostfix) | | titlePostfix | Optional, the string to append to each page's title | | banner | Optional, Markdown rendered in a bordered box above every page | | symbol | Text (1-5 chars) or a single emoji displayed in header when logo is absent; also used for generated favicons | | logo | Optional, image path relative to public/, replacing the header symbol | | favicon | Optional, .ico path relative to public/, replacing generated favicons and the web app manifest | | themeColor | Theme color for the site (e.g., "tomato", "#c04040", "hsl(195 70% 40%)") | | tintHue | Optional, hue (0-360) for background and foreground tinting (default 190) | | tintAmount | Optional, percentage (0-100) of tint to apply to the neutral palette (default 100); link saturation stays fixed | | defaultFont | Optional, initial font pairing: sans or serif (default sans) | | defaultContrast | Optional, initial neutral-palette contrast: standard or high (default standard) | | fontOverrides | Optional, custom serif and serif-monospace WOFF2 faces from public/; each configured family requires regular and may include styled faces, OpenType features, and font-specific tuning | | faviconSymbol | Optional, the text to use instead of symbol in generated favicons; required when symbol is an emoji and favicons are generated | | features.search | Enable search UI and Pagefind index generation | | features.favicon | Enable favicon links and generation (default true); false also omits custom favicon links | | features.footer | Show the Tada footer at the bottom of every page | | features.pickers | Show the font and contrast pickers at the bottom of every page (default true) | | base | Full base URL of the deployed site, used for metadata and URL generation | | basePath | URL prefix for deployment under a subpath (e.g., "/cs101"), use "/" at root | | internalDomains | Domain names treated as internal by link processing (not marked external) | | extensionToShikiLanguage | Optional, map from source-file extension to the Shiki language used for generated code pages and copied-source processing | | shikiLanguages | Optional, list of Shiki languages permitted in code blocks | | scripts | Optional, list of scripts in src/ that every page loads (see Scripts) | | faviconColor | Optional, background color for generated favicons (defaults to themeColor) | | faviconFontWeight | Optional, font weight used for generated favicon text (default 700) | | vars | Arbitrary key/value variables inserted into content with {{ name }} (e.g., {{ staffEmail }}) | | proofread | Optional, site.dev.* only; words lists extra words the tada watch spelling check accepts, dialect picks the English dialect, rules turns Harper rules on or off, and false turns the check off (see Proofreading) |

Custom logo and favicon

Place your assets in public/ and configure their relative paths:

logo: branding/logo.svg
favicon: branding/favicon.ico
symbol: TADA

Here the files are public/branding/logo.svg and public/branding/favicon.ico. Both fields are optional and independent. The logo replaces the header symbol and works without JavaScript. Without a custom favicon, Tada generates favicons from faviconSymbol or symbol, never from the logo image. A custom favicon replaces all generated icon assets, the web app manifest, and related web app metadata; symbol can be omitted when both logo and favicon are supplied.

Paths must use forward slashes and cannot contain absolute paths, empty segments, . or .. segments, query strings, or fragments. Assets must exist and be readable. The favicon must end in .ico; logo extensions are unrestricted, so choose a browser-supported image format. Asset URLs encode filenames and respect basePath, and files are copied unchanged.

features.favicon: false omits all favicon links and generation. Configured assets are still validated and public files still copy normally. See Header logo and Favicons for details.

nav.yaml

Defines the site navigation structure. The file contains an array of section objects. Each section contains an array of link objects (internal or external, and whether the link is disabled). You should specify at least two sections, but three or more sections are supported.

The file is optional. Without it (or with an empty array), the header has no menu: it shows the logo and site title, plus the search field when search is enabled. If search is also turned off, the header is not fixed; it sits centered at the top of each page.

- title: Navigation
  links:
    - text: Home
      internal: /index.html
- title: Topics
  links:
    - text: Lectures
      internal: /lectures/index.html
    - text: Problem Sets
      internal: /problem_sets/index.html
      disabled: true
- title: Links
  links:
    - text: Zoom
      external: https://zoom.com

authors.yaml

Maps author handles (used in front matter author fields) to display names and avatars. Each key is a handle (e.g., jsmith) and each value is an object with name, avatar, and optionally url.

jsmith:
  name: Jane Smith
  avatar: /avatars/jsmith.jpg
ajones:
  name: Alex Jones
  avatar: /avatars/ajones.jpg
  url: /staff/ajones.html

Content

Site content lives in the content/ directory. Markdown is converted to HTML. HTML files should contain front matter and are also built.

Any other kinds of files are copied into dist/ in the same locations, except document indexes.

Document indexes

An index.yml (or index.yaml) file anywhere in content/ orders pages into a tree. Paths are relative to the file's directory:

page: index.md
children:
  - page: 00/index.md
    children:
      - 00/VowelCounter.java.md
  - 01/index.md

Each listed page shows the part of the tree around it, including its ancestors, and links to the previous and next pages in order. Listed pages must have a title and may not set breadcrumbs, since the tree shows their ancestors instead.

All files in public/ are copied directly into dist/ with zero processing. Files in public/ are not included in the search index.

Front matter fields

Each file in content/ should start with "front matter" (a YAML-formatted list of variables parsed using the front-matter library).

| Field | Description | |-------|-------------| | title (required) | Page title (<title> tag and page heading); optional on the home page (content/index.md), which then has no heading | | skip | Set to true to skip building this page completely | | author | Author handle (e.g. jsmith) resolved to a full object via the authors config | | description | Meta description for the page | | toc | Set to true to show a table of contents | | slides | Set to true on Markdown pages to treat top-level --- as slide separators and add presentation controls | | breadcrumbs | Ordered ancestor links with label and url; not allowed on pages in a document index | | published | Year, month, and day of publishing (e.g, 2025-09-09) | | scripts | Scripts in src/ to compile and run on this page (see Scripts) |

Other fields are ignored with a warning. To reuse a value across pages, add it to vars in the site config instead (see below).

Scripts

Put your site's own TypeScript, JavaScript, and Sass in src/, then list the scripts a page needs in its front matter, as paths relative to src/:

---
title: Lectures
scripts: [lectures/timezone.ts]
---

Tada compiles listed scripts and everything they import. Nothing in src/ is published as-is, so .ts and .js files in content/ can still be course material. A script's default export runs each time its page is shown, and it can clean up when the visitor leaves:

import './timezone.scss';
import type { Mount } from '@abreen/tada';

const mount: Mount = ({ window, signal }) => {
  window.addEventListener('resize', () => {}, { signal });
};
export default mount;

A script can also have a renderer next to it, such as src/lectures/timezone.render.ts, which runs at build time and fills custom elements on the pages that list the script. The page then includes the script's HTML, such as a control, before any JavaScript runs:

import type { Renderers } from '@abreen/tada';

const renderers: Renderers = {
  'tz-chooser': () => '<label>Show times in <select disabled>...</select></label>',
};
export default renderers;

Write <tz-chooser> and </tz-chooser> on lines of their own in the page.

The script can define the element with customElements.define at the top level of its module. Tada loads a page's scripts before showing it on a client-side navigation, so the element is upgraded before the visitor sees it, and state in module variables lasts across pages.

Imported stylesheets are added to the page's <head>, so they work without JavaScript. Scripts can't import images or other files: put them in content/ or public/ and refer to them by URL, such as url(/images/paper.png) in a stylesheet (Tada adds the base path). In styles, use Tada's CSS custom properties (e.g. var(--theme-color)) to match the site theme. Run bun install in your site for editor type checking; builds don't need it. The starter site's Lectures page is an example.

Variable substitution

Use {{ name }} to insert a variable from the vars property of the site config, or {{ a.b }} for a nested value:

Email the course staff at {{ staffEmail }}.

Variables are replaced everywhere in Markdown and HTML pages, partials, front matter values, nav and authors config values, and source code files whose extension is listed in extensionToShikiLanguage, including inside code blocks. Referencing an undefined variable fails the build. When a code sample needs literal double braces (Vue, Jinja, Python f-strings), write \{{ name }}. In YAML, quote a value that starts with a variable: title: "{{ courseName }}".

Only vars is available. Other config fields (like title) and front matter fields can't be inserted, and there are no conditionals or loops.

Markdown partials

Use the {{{ _partial.md }}} syntax to include a partial (a fragment of Markdown in a separate file whose name must start with _) at that particular location in a Markdown file.

This is useful for reducing duplication across multiple documents which use the exact same content, or for breaking up a large document into building blocks which are easier to edit.

Partials are never built into their own pages, and they don't have front matter.

The {{{ ... }}} syntax is not a simple string replacement; instead, the Markdown syntax tree of the partial is added to the syntax tree of the Markdown file that includes it. This is a powerful feature because it allows you to include content as a subtree.

For example, this partial _groceries.md

* apples
* oranges
* pears

can be inserted as a sub-list of a larger list in a Markdown page

title: To do list

* Grocery shopping
  {{{ _groceries.md }}}
* Car wash

which results in:

* Grocery shopping
  * apples
  * oranges
  * pears
* Car wash

Details elements

Write raw HTML <details> elements in Markdown or HTML content. Each one is drawn as a bordered box, and all variants open and close without JavaScript.

| Variant | Markup | Result | |---------|--------|--------| | Standard | <details> with a <summary> | Collapsed to its summary. When open and taller than the screen, the summary sticks to the top of the viewport so the reader can close it from anywhere | | Preview | <details> with no <summary> | Shows the first 10em of the body, fading out behind a "Show more" link; when open, its "Show less" link sticks to the bottom of the viewport |