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 🙏

© 2025 – Pkg Stats / Ryan Hefner

pre-vhs

v0.2.0

Published

An intuitive, highly configurable pre-processor for writing charmbracelet/vhs scripts with more complex command sequences in fewer words

Downloads

85

Readme

pre-vhs

preview image

A lightweight macro engine and DSL for writing VHS tapes faster, cleaner, and safer.

pre-vhs transforms a compact, expressive .tape.pre file into a valid VHS .tape. It gives you a tiny language for automating common VHS patterns while staying 100% compatible with standard VHS syntax.


Why?

VHS tapes are powerful but verbose. Typing commands, fixing mistakes, waiting between steps—these become repetitive fast.

pre-vhs makes .tape authoring dramatically easier by adding:

  • Macros (only Type is always on; everything else is opt-in)
  • Header aliases for reusable patterns
  • Positional arguments ($1, $2, …)
  • Phase-based transforms (typing styles, doublers, gap insertion, etc.)
  • Optional packs, opt-in via Use ...
  • Absolutely no runtime dependency—output is plain VHS.

You still write VHS. You just write less of it.


Basic Usage

  1. Install

npm install -D pre-vhs

  1. Write a .tape.pre

header

Use BackspaceAll Gap
TypeEnter = Type $1, Enter

body

> Gap 200ms
> Type $1, Enter
echo "hello"

> TypeEnter $1
echo "bye"

3. Build the tape

npx pre-vhs demo # reads demo.tape.pre → writes demo.tape

Or use stdin→stdout:

cat demo.tape.pre | npx pre-vhs > demo.tape


Language Reference

  1. Meta-directives (> lines)

A directive line:

> CmdA, CmdB arg, CmdC

expands to a sequence of VHS commands.

If any command references $1, $2, … the next lines become its arguments:

> Type $1, Enter
ls -la

produces:

Type "ls -la"
Enter

Expansion model (quick reference):
- `$n` substitution happens before macro lookup.
- Inline args vs payload: if a header token has explicit text after the macro name, that text is treated as the payload; otherwise the payload comes from the consumed lines ($1 etc.).
- Macro outputs are treated as final VHS unless they name another macro; recursion is allowed with guards (depth/step limits, cycle detection).

2. Positional Arguments ($1..$n)

Each $n in a directive consumes one line beneath it:

> Type $1, Enter, Type $2, Enter
echo "first"
echo "second"

3. Header Aliases

Aliases only appear at the top of the file before the first non-header line.

TypeEnter = Type $1, Enter
Clear = BackspaceAll $1, Type "", Enter

Usage:

> TypeEnter $1
whoami

> Clear $1
garbage

Aliases expand just like directives. They may reference built-ins or other aliases.


4. Built-ins & Use

Only Type is always available for correct escaping. All other helpers are opt-in via packs + Use ....

Examples:

Macro Description BackspaceAll Deletes entire payload text BackspaceAllButOne Deletes payload except last char Gap Inserts a timed Sleep between commands TypeEnter (example alias pack) types payload + Enter ClearLine (example alias) remove text + newline

To activate:

Use BackspaceAll BackspaceAllButOne Gap


5. Typing Styles (optional pack)

If you enable the typing-styles pack in pre-vhs.config.js:

module.exports = { packs: [ "./packs/typingStyles.js" ] };

…you can write:

> SetTypingStyle human
> Type $1, Enter
echo "smoothly typed"

Human style breaks your text into chunks and emits randomized Type@xxms commands.

Another example:

> SetTypingStyle sloppy
> Type $1
git commit -m "oops"

Sloppy style injects occasional mistakes and corrections for realism.


6. Transforms & Phases (advanced)

Packs can hook into multiple phases:

  • header: rewrite header tokens before expansion (e.g., Type→HumanType).
  • preExpandToken: per-token tweaks before macro lookup.
  • postExpand: operate on emitted VHS lines (e.g., Gap inserts Sleep between commands, screenshot-after-every-command).
  • finalize: last chance to rewrite the entire tape. Transform ordering: runs in registration order within a phase.

Example: Doubling every command (header phase):

Use Doubler

Now:

> Type $1, Enter
echo hi

becomes:

Type "echo hi"
Type "echo hi"
Enter
Enter

Typing styles use the same mechanism.


7. Recursive Macros (advanced)

Macros can expand into other macro calls; the engine recurses with guards (depth/step limits and cycle detection). This makes layered helpers like:

TypeSleep = Type $1, Sleep 1s
EnterEcho = Enter, Type $1
RunAndEcho = TypeSleep $1, EnterEcho $2

work as expected without manual “with-gap” variants.


8. Importing Packs (Project-wide)

Optional packs may be enabled globally with a configuration file.

pre-vhs.config.js:

module.exports = {
  packs: [
    "./packs/typingStyles.js",
    "./packs/gitBasics.js",
    "./packs/emojiShortcuts.js",
  ],
};

These behave like Vim plugins: they provide macros, but the user still chooses whether to activate them with Use ....


Examples

Example: Git demo

Use Gap BackspaceAll

GitInit = Type "git init -q", Enter, Sleep 200ms GitStatus = Type "git status", Enter

> GitInit

> Type $1, Enter
git add .

> GitStatus

Example: Complex one-liner

Use BackspaceAll Gap

> Type $1, Sleep 200ms, Type $2, Enter, Gap 400ms, Type "Done", Enter
echo
"hello"

CLI Options

pre-vhs # reads .tape.pre, outputs .tape pre-vhs --config path cat file | pre-vhs # stdin → stdout mode


Testing

The test suite consists of:

  • Golden file tests: .tape.pre → expected .tape
  • Unit tests: header parsing, alias resolution, built-ins, error reporting
  • Pack tests: typing styles, git, emoji shortcuts
  • Lint/format hooks: npm run lint, npm run format, pre-commit runs lint-staged

Design Principles

  • Opt-in everything except Type
  • No magic: preprocessing is visible, predictable, diff-able
  • Tiny DSL: aliases and Use, not a programming language
  • Composable: chain packs, transforms, macros
  • Zero overhead: output is plain VHS

Roadmap

  • More built-in macro packs (filesystem, shortcuts, demos)
  • Optional fenced JS header sections if needed
  • Examples gallery / cookbook
  • VS Code syntax highlighting for .tape.pre
  • Playground website