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

aectl

v1.1.0

Published

Drive Adobe After Effects from the shell or an AI agent: lint + run ExtendScript as one undo step, dump comps, render frames to contact sheets.

Readme

aectl: drive After Effects from the shell (and from your AI agent)

A small CLI (ae) and an ExtendScript library (lib.jsx) for scripting a running Adobe After Effects on macOS. It is built for coding agents such as Claude Code, but works just as well by hand.

ae sel                                    # what the user selected, and where the playhead is
ae tree                                   # every comp, plus the layers of the active one
ae dump "Main" --layer "Title"            # transforms, keys with easing, expressions, text
ae run retime.jsx --diff                  # lint, run as ONE undo step, print the log and what changed
ae snap "Main" 0-120:30 --sheet           # render frames to PNG + a labelled contact sheet
ae graph "Main" "Title" pos               # value + speed curves: see the easing

Why

  • Nothing to install inside AE. No CEP panel, no bridge to keep open. Scripts go through osascript to DoScriptFile, so AE only has to be running.
  • Lint before AE sees the script. ExtendScript is ES3. A stray let, => or {in: 1} opens a modal error dialog that blocks AE until someone clicks it. ae run parses the script against the rules of the real engine (checked in AE 2026), catches typos like AE.setTxt ("did you mean AE.setText?"), and refuses to send a broken script. As a Claude Code plugin it also lints every .jsx the agent writes, right after it is written.
  • Safe edits. Every run is one Cmd+Z step, with dialogs suppressed and errors caught. Errors are reported with the line in your file.
  • Visual feedback. ae snap renders frames to PNG and waits until the files are complete. --sheet tiles them into one image that an agent (or you) can look at. ae graph draws the motion curves of a property.
  • Works with you, not around you. ae sel reads your selection and playhead, ae markers reads the notes you leave as markers, and ae run --diff shows exactly what a script changed.
  • A tutor in your timeline. Ask the agent to teach you instead of doing the work: it leaves the tasks as markers where they happen, checks what you did, and hints before it takes over. See below.
  • Helpers for the parts AE gets wrong. Trims that silently don't stick, Source Text read through a typewriter expression, keyframe ease arrays of the wrong length, "x" + array throwing. See the pitfalls in the reference.

Install

Requirements: macOS, After Effects (tested with 2026), node 22+, ffmpeg (brew install ffmpeg) for the image and video tools.

As a Claude Code plugin (the agent also gets the full API reference as a skill):

/plugin marketplace add thdctrt/aectl
/plugin install aectl@aectl

From npm (puts ae and aectl on your PATH):

npm install -g aectl

To get the lint hook without the plugin, add this to ~/.claude/settings.json:

{ "hooks": { "PostToolUse": [ { "matcher": "Write|Edit|MultiEdit", "hooks": [ { "type": "command", "command": "ae hook" } ] } ] } }

Install it once instead of calling it through npx: an agent makes many calls, and npx resolves the package on every one.

From git:

git clone https://github.com/thdctrt/aectl && ln -s "$PWD/aectl/ae" /usr/local/bin/ae

Then run the check. It tells you exactly what to fix:

ae doctor      # node, ffmpeg, the AE scripting pref, macOS Automation permission, a round trip to AE
ae selftest    # 76 checks + a rollback round trip in a throwaway comp, cleaned up afterwards

Two things usually need a one-time click:

  1. In AE: Settings > Scripting & Expressions > Allow Scripts to Write Files and Access Network. The CLI reads the log file your script writes.
  2. macOS asks whether your terminal may control After Effects. Allow it (System Settings > Privacy & Security > Automation).

zsh completion (commands, options, .jsx and video files, and comp/layer names from the running AE):

echo 'eval "$(ae completion zsh)"' >> ~/.zshrc

Writing a script

// retime.jsx:  ae run retime.jsx
AE.run("Retime intro", function (log) {
    var c = AE.comp("Main");
    var L = AE.layer(c, "Title");
    AE.trim(L, 144, 194);                        // comp frames; WARNs if AE won't keep the trim
    AE.setText(L, "Hello world", "#806600");     // keeps font/size, safe with typewriter expressions
    log("now", AE.span(L));
    AE.snap(c, [150, 190]);                      // ae run waits for the PNGs
});

Everything is in skills/after-effects/SKILL.md: every command and option, the full AE.* API, and the pitfalls. It doubles as the skill that tells an agent how to use the tool.

Learning After Effects with your agent

An agent that can see and edit your project can also teach you, in your own timeline. Ask it to ("teach me easing", "show me how parenting works, I want to do it myself") and it turns the lesson into markers: a short task at the frame and on the layer where it happens, which you then do by hand.

$ ae markers "Practice"
COMP 'Practice' id=12
  f0 #1 'Box' 'try 1/3: select both Position keys (P), make them ease' label=9
  f45 #1 'Box' 'try 2/3: make it land softer (Graph Editor)' label=9
  f55 comp 'try 3/3: start the move 10 frames later' label=9
  • It works on your project, or on a practice comp it builds with the problem already in it: a box on linear keys to ease, a title to parent to a null, a layer to trim to the beat.
  • It checks what you did. When you say "done", it compares the layer with how it was before the step (ae dump), reads the ease you made (ae graph: peak/avg 1.00 means still linear), looks at the frame (ae snap) and tells you what worked and what is off.
  • Hints come in steps: first the goal, then where to look (panel, property, shortcut), then the exact clicks. Only if you ask does it do the step itself, with a before/after sheet (ae run --ab), and Cmd+Z lets you try again.
  • It works both ways. Leave a marker starting with ? ("? why does it jump here") and ask the agent to read your markers: it looks at that frame and explains. To learn from someone else's template, ask for a tour: it leaves note markers on the interesting parts (an expression, a control layer, a precomp) and walks you through them.
  • Nothing sticks around. The lesson markers share one prefix and label, and the agent removes them (and the practice comp) at the end. It never saves the project.

This is a separate skill, after-effects-tutor, installed with the plugin. Only its one-line description sits in the agent's context until you ask to learn, so it costs nothing in other sessions.

Commands

| command | what | |---|---| | ae run script.jsx | lint, run as one undo step, print the log, wait for PNGs; exit 1 on ERR; a run that throws is undone | | ae eval 'js' | run a one-liner; the value of the last expression is printed | | ae check script.jsx | syntax + ExtendScript lint only, no AE needed | | ae run edit.jsx --diff / --ab "Comp" --frames 0,60 | also print what changed in the project / a before-after contact sheet | | ae sel | the active comp, playhead frame, work area, selected layers, properties and keyframes | | ae tree / ae dump "Comp" | project overview / one comp in detail (read-only) | | ae markers / ae mark "Comp" 120 "note" | read comp and layer markers (notes from the user) / add one | | ae health / ae find "text" | missing footage and fonts, expression errors, off-screen layers, text past the edge / search names, text, expressions, files, effects, markers | | ae effects blur | installed effects with their matchNames | | ae snap "Comp" 0-90:15 --sheet | render frames to PNG, optionally as a contact sheet or cropped to a region (--crop) | | ae graph "Comp" "Layer" "Transform/Position" | value and speed curves as a PNG, plus the numbers of each ease | | ae sheet out.png a.png b.png | contact sheet from any images | | ae measure a.png [b.png] | ink bounding box, centre and mean colour of an image; with two, how far b is off from a | | ae frames video.mp4 / ae probe video.mp4 | sample a clip into a sheet / size, fps (flags VFR), duration | | ae beats "Comp" --layer "Music" | music accents (onsets) in the comp's frames, to key animation to the beat; --mark adds them as markers | | ae export "Comp" --preset youtube-1080 | render and encode for YouTube, Shorts/Reels, web, ProRes, alpha, GIF (--list); --ame uses Media Encoder; --quick takes snapped frames for a fast preview | | ae save [--backup] | save the project (only when you mean it) | | ae doctor / ae selftest | check the setup / run the self-test | | ae completion zsh | print the zsh completion script | | ae mcp | the same tools as an MCP server (see below) |

Exit codes: 0 ok, 1 the script logged ERR, 2 usage or lint error, 3 AE not running or timeout (usually a modal dialog in AE).

MCP server (Claude Desktop and other clients without a shell)

Claude Code needs nothing more than the plugin: it calls the CLI. Clients that cannot run shell commands on your Mac (the Claude Desktop chat, other MCP-capable agents) can use ae mcp, an MCP server over stdin/stdout. It is part of the same CLI: no extra package, no network, nothing fetched at start. The commands above are tools (ae_run, ae_snap, ae_selection, ...); ae_snap, ae_graph and ae_run with ab_comp return their images directly, and ae_docs hands the model the full reference.

In Claude Desktop: Settings > Developer > Edit Config, then add (absolute paths: GUI apps start servers with a minimal PATH; which node and the path to your ae give them):

{
  "mcpServers": {
    "aectl": { "command": "/opt/homebrew/bin/node", "args": ["/path/to/aectl/ae", "mcp"] }
  }
}

With a global npm install the second path is $(npm root -g)/aectl/ae. Restart Claude Desktop. The first call makes macOS ask whether Claude may control After Effects: allow it (System Settings > Privacy & Security > Automation).

Limitations

  • macOS only: the transport is AppleScript. Windows would need AfterFX.exe -r and a port of the CLI.
  • Tested on After Effects 2026 (26.x). Older versions probably work, but some pitfalls are version-specific.
  • AE runs one script at a time, and a modal dialog in AE blocks everything until it is closed.

Development

The CLI is TypeScript in src/, bundled into dist/ae.mjs. pnpm install && pnpm check type-checks, runs the tests (vitest) and verifies that the committed dist/ is up to date. See AGENTS.md.

License

MIT