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

@kud/cli-shot

v0.2.1

Published

Automatic screenshots of interactive CLIs — pty capture, terminal emulation, PNG out

Readme

📸 cli-shot

Automatic screenshots of interactive CLIs — pty capture, terminal emulation, PNG out.

Website · Documentation · npm

Point it at a CLI. It asks which screens the CLI has, opens each one, and writes an image per screen. No per-project script, no keystroke tables, no hand-cropped window captures that go stale the next time the UI moves.

Features

  • Screens discovered, not hardcoded — asks the CLI via --screen list, so a tab you add shows up in the next run without touching this package
  • Real terminal emulation — the pty stream is resolved to the grid a user would see, rather than every redraw concatenated
  • Fixtures by default--mock is on unless you opt out, because a screenshot outlives the moment it was taken
  • Deterministic and headless — fixed size, fixed data, no window manager, runnable in CI
  • Scriptable last mile--keys reaches state a screen name can't address

Install

npm install --global @kud/cli-shot
brew install charmbracelet/tap/freeze   # the renderer

Usage

cli-shot --out assets/screenshots -- pcloud

Everything after -- is the command being driven, so its own flags stay clear of cli-shot's.

cli-shot adds --mock and --screen to that command, but only where you haven't. Anything you pass wins:

cli-shot --out shots -- pcloud --screen sync    # shoots Sync, writes sync.png
cli-shot --out shots --only sync -- pcloud      # the same thing, said from here

Naming a screen yourself is already an answer to "which one", so cli-shot skips the discovery loop and takes the filename from your value.

cli-shot --out shots --only sync -- pcloud        # one screen
cli-shot --out shots --list -- pcloud             # what screens exist
cli-shot --out shots --keys $'jjj\r' -- pcloud    # drive deeper first
cli-shot --out shots --no-mock -- pcloud          # real data (careful)

| flag | | | ------------------- | ------------------------------------------------- | | -o, --out <dir> | directory to write PNGs into | | --only <screen> | shoot one screen instead of every screen | | --list | print the screens the command offers, and stop | | --cols / --rows | terminal size (default 110×32) | | --settle <ms> | how long the screen must hold still (default 350) | | --jobs <n> | screens shot at once; defaults to the core count | | --keys <sequence> | keystrokes sent once the screen has drawn | | --font <family> | font to render with; defaults to a Nerd Font | | --no-mock | drive real data instead of fixtures |

The contract

A CLI is shootable when it implements three things:

| | | | ----------------- | ------------------------------------------------------ | | --mock | swap every data source to fixtures, all or nothing | | --screen <name> | open directly on that screen | | --screen list | print the screen names, one per line |

--screen list is what keeps this package generic: cli-shot asks rather than knowing. Add a tab to your app and it appears in the next run's output without this package being touched — and a tab nobody ever captured stops being invisible.

Mock data is the default, deliberately. A folder listing says more about someone than they usually intend, and a screenshot outlives the moment it was taken.

How it works

node-pty  →  @xterm/headless  →  serialize  →  freeze  →  png

The middle step is the one that isn't obvious. A pty hands back every redraw in order, not a picture of the screen — write that straight out and you render the whole animation concatenated, with the alternate-screen escape on top. So the stream is fed through a real terminal emulator, which resolves cursor moves, clears and repaints into the grid a user would actually be looking at. Only that grid is serialised.

Limits

Terminal graphics protocols don't survive. Inline images (iTerm2, sixel) are escape sequences carrying base64 payloads; no ANSI renderer can rasterise them. A CLI drawing thumbnails needs a real terminal and a window capture for those screens.

Compound state needs --keys. --screen addresses which screen; scroll position, an open dialog or a filtered view are beyond what a name can carry.

Related

  • @kud/cli-testing — the test-side sibling. Same app contract, no dependency between them.

Licence

MIT © Erwann Mest


📚 Full documentation → cli-shot/docs