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

@emirotin/zerp

v0.9.0

Published

Zero-config presentation framework for slide decks authored in HTML and/or Markdown.

Readme

zerp

zerp is a zero-config presentation framework. Slides can be authored in HTML, Markdown, or a mix of both.

Each presentation can be authored as just a slides/ folder:

my-deck/
  slides/
    00-title.html
    10-intro.md
    20-content.md
    images/
      cover.jpg

zerp finds slides/**/*.html and slides/**/*.md, sorts them by filename, rewrites relative asset URLs so slide-local assets keep working, injects default styles/runtime, and serves or builds a single-page deck. Fonts are bundled into the output, so a built deck is one self-contained file that presents fully offline.

Maintainer Policy

I use zerp myself and find it useful, which is why I am making it public as free open-source software.

That does not mean I am available for general collaboration. Issues and pull requests are intentionally disabled. I do not have the capacity to debug other people's problems for free, and I do not want to spend time triaging low-signal or AI-generated contributions.

If you want to use the project as-is, please do. If you need a fix, a feature, or help integrating it into your workflow, contact me directly for paid support.

Usage

Install from a local checkout:

pnpm add -D file:../zerp
pnpm exec zerp serve .

Or from a registry:

pnpm add -D @emirotin/zerp
pnpm exec zerp build .

Commands:

pnpm exec zerp serve                      # serve the current deck on http://localhost:8000 (live-reloads on save)
pnpm exec zerp serve . 3000 --theme dark  # explicit deck dir, port, default theme
pnpm exec zerp build --theme light        # write ./index.html (light default)
pnpm exec zerp check                      # APCA contrast + font-size report (both themes; --theme dark|light|both, --json for tooling)
pnpm exec zerp slides                     # deck position → source file mapping (--json for tooling)
pnpm exec zerp verify                     # headless-browser frame/layout check (both themes, 1280x720; --json for tooling)

Browsers

zerp verify needs a Chromium-class browser. It never bundles one — it resolves an external browser in this order:

  1. CHROME_BIN — if set, it is used verbatim. Point it at any Chrome/Chromium binary; a wrapper script that execs one with extra flags works too.
  2. The playwright-managed Chromium — run zerp install-browser once to download it; nothing else needs configuring afterward.
  3. A system Chrome/Chromium — Google Chrome or Chromium found on the usual macOS app paths or on PATH (google-chrome, chromium, chromium-browser).

If none is found, zerp verify says so and points here. On a machine with no system Chrome, install one once:

pnpm exec zerp install-browser   # download the managed Chromium
# — or —
export CHROME_BIN="/path/to/chrome"

The browser stays external and optional: the package itself is browser-free, so installs are light and offline-friendly.

Tooling

This repo pins Node and pnpm via Volta metadata in package.json:

volta pin [email protected] [email protected]

Quality commands:

pnpm lint
pnpm lint:fix
pnpm format
pnpm format:check
pnpm test:browser # opt-in headless-browser regression test (requires Chrome/Chromium)

husky runs lint-staged and a build check before each commit. dist/ is not checked into git; it is built on demand and included in the npm package via prepublishOnly.

Authoring

  • Put all authored content in slides/.
  • Use filename prefixes for ordering, for example 00-, 10-, 20-.
  • Store deck assets under slides/ too. Relative links like src="./images/foo.jpg" are rewritten automatically.
  • Each .html file can contain one or more <div class="slide"> blocks.
  • .md files are also supported. Each Markdown file is automatically wrapped in <div class="slide"> at build time — no manual wrapper needed. Use --- on its own line to separate multiple slides within a single .md file.
  • Raw HTML inside Markdown files passes through unchanged, so you can embed interactive <script> blocks, custom <div> layouts, or <style> elements alongside Markdown content.
  • At build time, every real .slide is placed inside a framework-owned <div data-zerp-slide>. The frame controls visibility; the inner .slide is the full-size layout surface, so custom roots may use display: grid or another layout safely. Do not style the reserved frame attributes.
  • The framework default CSS and browser runtime are stored as separate source assets and inlined into generated HTML during serve and build.
  • Colors come from design tokens (var(--zerp-*)) generated from the Harmony palette; decks render in dark and light themes. Do not hardcode colors.
  • The page title comes from the first slide's top heading (override via the title build option; folder name as fallback).
  • Run zerp check after authoring: it reports APCA contrast and font-size violations per slide, for both themes.
  • Run zerp verify after layout or framework changes: it opens each theme in headless Chrome/Chromium (resolved as described under Browsers — run zerp install-browser once if you have no system Chrome) and checks that exactly one full-size slide frame is active and visible without page overflow. Overflow is relative to the checked viewport (--size WxH, default 1280x720) — verify a deck at its actual target screen size; the summary and --json's viewport field record exactly what was checked.
  • zerp verify --safe-margin px additionally requires every top-level element of each slide to stay at least that many px inside all page edges — a print-safe inset for decks headed to PDF. Mark intentionally full-bleed elements with data-zerp-bleed to exempt them. Off by default; choose a margin below the slide padding so ordinary content never trips it.
  • "Slide N" means the 1-based deck position (what the on-screen counter shows) — file prefixes only order files. zerp slides prints the position → file mapping; pressing s in a running deck shows the active slide's source.

Printing and PDF export

A built deck is print-ready as-is. Printing (browser print dialog, or a headless print backend) produces one page per slide in deck order: presentation chrome (nav, counter, progress bar, theme switch, source badge) is hidden, and steps are rendered in their final state — every data-step reveal shown, every data-until-step element gone.

Print with a page size equal to the presentation viewport and backgrounds enabled. One slide fills exactly one page at any page size, in either theme. Content that overflows a slide is clipped at the bottom of the page rather than spilling onto a second page, so keep slides within the frame (the same as on screen — zerp check/zerp verify catch overflow).

Example: render a deck to PDF at 1280×720 with Playwright:

from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch()
    page = browser.new_page(viewport={"width": 1280, "height": 720})
    page.goto("file:///abs/path/to/index.html")
    page.pdf(path="deck.pdf", width="1280px", height="720px", print_background=True)
    browser.close()

The explicit width/height already describe the page — do not also pass landscape=True, because Chromium swaps the two dimensions when landscape is set and you get a portrait page.

Library API

import { buildPresentationHtml, writePresentation } from "@emirotin/zerp";

Example

This repository includes a migrated example deck at examples/casino/. Its authored source is only examples/casino/slides/.