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

slide-cli

v1.0.9

Published

CLI to create beautiful slide cards (9:16, 16:9, 1:1) from JSON + HTML templates

Readme

slide-cli

npm version npm downloads CI license bun ko-fi

A TypeScript CLI to create beautiful slide cards from JSON data + HTML templates. Supports 9:16 (Stories/Reels), 16:9 (presentations/YouTube), and 1:1 (feed) aspect ratios.

slide create        --data ./templates/minimal/sample.json --template minimal --out ./output
slide list          [--verbose]
slide add-template  <path>  [--force]

Installation

From npm (end users)

npm install -g slide-cli
slide --help

Requires: Node.js ≥ 18 · Chrome/Chromium (bundled via Puppeteer)

From source (contributors)

git clone https://github.com/doum1004/slide-cli.git
cd slide-cli
bun install       # Bun is required for building and running tests
bun run build     # outputs to dist/
npm link          # exposes the `slide` command globally
slide --help

Requires: Bun ≥ 1.0 (build + test only) · Node.js ≥ 18 (runtime)

Why both Bun and Node?

The published dist/ runs on Node — so any end user with Node can install and use slide via npm without touching Bun. Bun is only needed locally to build (bun build) and run tests (bun test). This avoids the Windows issue where npm link detected Bun and generated a .ps1 wrapper that caused Puppeteer to hang silently.


Quick start (from source)

bun install
bun run build
slide list --verbose
slide create --data ./templates/minimal/sample.json --template minimal 

Commands

slide create

slide create --data ./templates/minimal/sample.json --template minimal --out ./output

| Flag | Default | Description | |---|---|---| | -d, --data <file> | (required) | Path to data JSON | | -t, --template <id> | (required) | Template id or name | | -o, --out <dir> | ./output | Output directory | | -f, --format <png\|jpg> | jpg | Screenshot format | | --no-images | off | Skip screenshots (HTML only) | | --allow-missing-images | off | Render slides without unresolvable image slots instead of aborting |

Output:

output/
├── slide-1.html   slide-1.jpg
├── slide-2.html   slide-2.jpg
│   …
├── index.html     ← presentation viewer
├── data.json      ← copy of your input
└── manifest.json  ← machine-readable index (slideIndex, htmlPath, imagePath)

Backends and agents should read manifest.json to get the ordered image paths:

const manifest = JSON.parse(fs.readFileSync(`${outDir}/manifest.json`, "utf-8"));
const images = manifest.slides
  .filter(s => s.imagePath)
  .map(s => path.join(outDir, s.imagePath));

slide list

slide list
slide list --verbose    # full slot schema

slide add-template

slide add-template ./my-template/
slide add-template ./my-template/ --force

Data JSON format

{
  "title": "My Presentation",
  "slides": [
    {
      "layout": "minimal",
      "heading": "Less is more",
      "body": "Simplicity is the ultimate sophistication.",
      "label": "Chapter 01",
      "accent": "#c8b89a",
      "bg": "#0f0e0c"
    }
  ]
}

Built-in templates

| id | Ratio | Required slots | Style | |---|---|---|---| | minimal | 9:16 | heading | Dark typographic, Fraunces serif | | bold-title | 9:16 | title | Gradient editorial, Bebas Neue | | quote-card | 9:16 | quote | Light serif pull-quote card | | minimal-wide | 16:9 | heading | Dark typographic, two-column layout | | bold-title-wide | 16:9 | title | Gradient editorial, title left / subtitle right | | quote-card-wide | 16:9 | quote | Light serif pull-quote, quote left / attribution right |


Creating a custom template

my-template/
├── template.json    ← manifest + slot definitions
└── template.html    ← Handlebars HTML at your chosen dimensions

template.json

Set aspectRatio, width, and height to match your target format:

| aspectRatio | width | height | Use case | |---|---|---|---| | "9:16" | 1080 | 1920 | Instagram Stories, TikTok, Reels | | "16:9" | 1920 | 1080 | YouTube thumbnails, presentations | | "1:1" | 1080 | 1080 | Instagram feed, Twitter/X |

{
  "name": "My Template",
  "id": "my-template",
  "version": "1.0.0",
  "description": "Short description",
  "aspectRatio": "16:9",
  "width": 1920,
  "height": 1080,
  "slots": [
    { "id": "headline", "type": "text",  "label": "Headline",   "required": true },
    { "id": "bg",       "type": "color", "label": "Background", "required": false, "default": "#fff" }
  ]
}

Slot types: text · color · image · number · url

template.html

Match width and height in CSS to the values in your manifest:

<!DOCTYPE html><html>
<head><style>
  html, body { width: 1920px; height: 1080px; background: {{bg}}; }
</style></head>
<body>
  <h1>{{headline}}</h1>
  {{#if subtitle}}<p>{{subtitle}}</p>{{/if}}
  <footer>{{slideIndex}} / {{totalSlides}}</footer>
</body></html>

Always available: {{slideIndex}} · {{totalSlides}} · {{title}}
Helpers: {{#if}} · {{upper val}} · {{lower val}} · {{default val "fallback"}}


Presentation viewer

The generated index.html has:

  • ← → keys or buttons · Space = autoplay · F = fullscreen
  • Home/End · touch/swipe support
  • Speed selector · progress bar · dot nav

Template storage

| Path | Purpose | |---|---| | ~/.slide-cli/templates/ | User templates (via add-template) | | <install>/dist/templates/ | Built-in templates (shipped with the package) |

User templates take priority over built-ins on id collision.


Docker

Production (installs from npm):

docker build -t slide-cli .
docker run --rm -v $(pwd)/output:/work/output slide-cli \
  slide list
docker run --rm -v $(pwd)/output:/work/output slide-cli \
  slide create --data ./templates/minimal/sample.json --template minimal

Local dev (installs from local build):

bun run build
docker build -f Dockerfile.dev -t slide-cli-dev .