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

assistanimate

v0.1.0

Published

Convert local MP4, AVI, and MOV videos to animated GIFs with FFmpeg.

Readme

assistanimate

A local video-to-GIF CLI for screen recordings, product demos, and documentation. Set the frame rate and dimensions, choose an output path, and get JSON results for scripts and coding agents.

The problem

A screen recording is useful for showing a feature or reproducing a bug, but sharing it often means opening a video editor or uploading it to a conversion website. Running FFmpeg directly gives you control, but even a basic conversion requires knowing its filters and output options.

assistanimate turns a local MP4, AVI, or MOV recording into an animated GIF with one command:

assistanimate convert recording.mp4 --fps 12 --resolution width:640 -o demo.gif

The conversion runs on your machine. Video files stay local, and the installed CLI needs only Node.js, FFmpeg, and ffprobe.

What you can do

Create demos for documentation

Turn a screen recording into a GIF for a README, issue, pull request, or product guide. Choose an exact filename with --output, or let the CLI create a timestamped name in your chosen directory.

assistanimate convert 'Feature walkthrough.mov' --fps 12 --resolution width:640 --output ./docs/images/walkthrough.gif

Control dimensions and frame rate

Keep the source settings, choose a resolution preset, or fit the recording within a custom size. Width-only and height-only targets preserve the aspect ratio and avoid enlarging the selected dimension.

assistanimate convert recording.mp4 --fps 10 --resolution 800x600

Automate conversions

Use --json to receive the output path, dimensions, frame rate, and file size. Commands return exit codes and structured errors that scripts and coding agents can handle without parsing terminal prose.

assistanimate convert recording.mp4 --output demo.gif --json
assistanimate probe demo.gif --json

Quick start

Install FFmpeg first. On macOS with Homebrew:

brew install ffmpeg

Install the CLI, check its dependencies, and convert a recording:

npm install -g assistanimate
assistanimate doctor
assistanimate convert recording.mp4 --fps 12 --resolution width:640 --output demo.gif

Replace recording.mp4 with a real video path. This example creates demo.gif in the current directory, with a maximum width of 640 pixels and a target rate of 12 FPS.

Install

npm

npm install -g assistanimate

Bun

bun install -g assistanimate

Run with npx

npx -y assistanimate convert recording.mp4 --fps 12 --resolution width:640

All three options use the same Node executable. FFmpeg and ffprobe must be installed separately and available on PATH.

Requirements

| Requirement | Used for | | --- | --- | | Node.js 20 or newer | Runs the installed CLI. | | ffmpeg | Converts video frames to GIF. | | ffprobe | Reads input and output metadata. | | Bun | Builds and tests a source checkout. Not required to run the npm package. |

Run assistanimate doctor to check both FFmpeg executables. If either is missing, the command explains which one and exits with status 1.

FFmpeg installation options are listed on the FFmpeg download page.

Features

  • Converts MP4, AVI, and MOV files, including paths containing spaces.
  • Preserves source FPS and dimensions when options are omitted.
  • Accepts explicit frame rates, resolution presets, bounding boxes, and width-only or height-only targets.
  • Creates parent directories for output paths.
  • Generates sanitized, timestamped filenames when an exact output path is omitted.
  • Refuses to replace an existing destination unless --force is supplied.
  • Validates the generated GIF before saving it to the destination.
  • Cleans up partial output after conversion failures and interruptions.
  • Provides JSON results, structured errors, and nonzero exit codes for automation.
  • Runs locally without an API server, Python environment, account, or model provider.

CLI reference

assistanimate convert <video> [options]       Convert one local video
assistanimate <video> [options]               Shorthand for convert
assistanimate probe <file> [--json]           Inspect FPS, dimensions, and size
assistanimate doctor [--json]                Check FFmpeg and ffprobe
assistanimate --help                         Show usage
assistanimate --version                      Show the installed version

Conversion options

| Option | Default | Behavior | | --- | --- | --- | | -o, --output <path> | Timestamped filename | Exact .gif output path. Parent directories are created. | | --output-dir <dir> | Current directory | Destination for timestamped GIFs. | | --output-name <name> | Source filename stem | Name to sanitize and place before the timestamp. | | -f, --fps <number> | Source FPS | Finite numeric value greater than or equal to 1. | | -r, --resolution <value> | original | Output scaling, as described below. | | --force | Off | Replace an existing destination after conversion succeeds. | | --json | Off | Print a compact JSON result. |

Use --output for an exact filename, or combine --output-dir and --output-name for a timestamped filename. These two approaches cannot be combined.

Unknown options, repeated options, and extra input files are rejected. probe and doctor accept --json, but reject conversion-only options.

Resolution values

| Value | Behavior | | --- | --- | | original | Preserve the source dimensions. | | 1080p | Fit within 1920 × 1080. | | 720p | Fit within 1280 × 720. | | 480p | Fit within 854 × 480. | | width:640 | Reduce width to at most 640 pixels. | | height:480 | Reduce height to at most 480 pixels. | | 800x600 | Fit within an 800 × 600 bounding box. |

Scaling preserves the aspect ratio. A bounding box sets maximum dimensions, so the resulting GIF may be smaller in one dimension. It does not crop or add padding.

Width-only and height-only targets do not upscale the selected dimension. FFmpeg rounds the other dimension to an even number. Presets and bounding boxes can upscale smaller recordings, matching the original converter.

Dimensions must be integers between 1 and 65535. Available memory and encoding time still limit practical output sizes.

Output naming

An exact output path creates the requested filename:

assistanimate convert recording.mp4 --output ./gifs/demo.gif

Without --output, the CLI uses the source filename and a local-time timestamp:

recording_YYYYMMDD_HHMMSS.gif

Choose a different stem and directory with:

assistanimate convert recording.mp4 --output-dir ./gifs --output-name 'My demo'

The result is a file such as gifs/My_demo_20260915_120000.gif. The CLI replaces spaces and unsupported filename characters with underscores and removes leading or trailing dots, underscores, and hyphens.

Relative paths are resolved from the directory where you run the command. The default output directory is your current directory, even when the input video is elsewhere.

Scripts and coding agents

Use an explicit output path and --json when another process needs to consume the result:

assistanimate convert recording.mp4 --output demo.gif --fps 12 --resolution width:640 --json

A successful conversion writes one JSON object to stdout. For example:

{
  "output_path": "/work/demos/demo.gif",
  "filename": "demo.gif",
  "final_fps": 12,
  "encoded_fps": 12.5,
  "resolution": { "width": 640, "height": 360 },
  "size_bytes": 12717175
}

| Field | Meaning | | --- | --- | | output_path | Absolute path to the completed GIF. | | filename | Output filename, including .gif. | | final_fps | Requested frame rate, or the source frame rate when omitted. | | encoded_fps | Generated GIF's average frame rate reported by ffprobe. | | resolution | Actual output width and height in pixels. | | size_bytes | Completed file size in bytes. |

GIF frame delays use hundredths of a second, so final_fps and encoded_fps can differ. For example, an eight-hundredths delay corresponds to 12.5 FPS, even when the target was 12 FPS.

probe --json returns input_path, fps, width, height, and size_bytes. It can inspect generated GIFs and other local media that ffprobe can read, in addition to the three supported conversion formats.

doctor --json returns an ok boolean and a checks array with the availability and version or error for each executable. It writes this result to stdout even when a dependency is missing.

Errors and exit codes

Failed conversions and argument errors leave stdout empty and write diagnostics to stderr. With --json, the error has this shape:

{
  "error": {
    "code": "OUTPUT_EXISTS",
    "message": "Output already exists: /work/demos/demo.gif. Use --force to replace it."
  }
}

Error codes are INVALID_INPUT, DEPENDENCY_MISSING, CONVERSION_FAILED, OUTPUT_EXISTS, and CANCELLED.

| Exit code | Meaning | | --- | --- | | 0 | Success. | | 1 | Conversion, dependency, or output error. | | 2 | Invalid arguments or input. | | 130 | Conversion interrupted. |

Help and version output remain plain text, including when --json is supplied.

How conversion works

  1. Validate the options and local input file.
  2. Read the source FPS and dimensions with ffprobe.
  3. Apply the FPS and scale filters with FFmpeg, writing to a temporary directory beside the destination.
  4. Probe the generated GIF and read its size.
  5. Save the completed GIF to the requested path and remove the temporary directory.

Conversions time out after 300 seconds. Metadata probes and dependency checks time out after 20 seconds. An interruption stops the active encoder or probe before cleanup.

Without --force, saving uses a hard link so two conversions cannot silently overwrite the same destination. The output filesystem must support hard links. With --force, the CLI uses a same-filesystem rename to replace the destination after conversion succeeds. Failed conversions preserve the existing destination in both modes.

Current scope

The CLI converts one complete local video per invocation. It does not currently expose trimming, cropping, captions, target file sizes, palette controls, batch commands, or URL downloads. GIF output contains no audio and uses FFmpeg's default infinite looping.

Automation uses CLI commands and JSON output. This package does not include an MCP server, agent skill installer, or conversational interface.

FAQ

Why is my GIF still large?

Duration, dimensions, frame rate, and visual content all affect the result. assistanimate converts the full recording and has no target-size option. Try a lower frame rate and smaller dimensions:

assistanimate convert recording.mp4 --fps 8 --resolution width:480 --output smaller.gif

Use a shorter source recording if you only need to show part of a workflow.

Why did I get 640 × 360 instead of 640 × 480?

Scaling preserves the source aspect ratio. A 16:9 recording scaled to a width of 640 becomes 640 × 360. Bounding-box options also preserve the aspect ratio.

Why did a preset enlarge my recording?

Presets fit the source into the chosen bounding box and can upscale. Use width:<n> or height:<n> to cap a dimension without enlarging it, or use original to keep the source dimensions.

Where did the GIF go?

The command prints its absolute output path. Without --output or --output-dir, it saves to the directory where you ran the command.

Can I overwrite an existing GIF?

Yes, with an explicit output path and --force:

assistanimate convert recording.mp4 --output demo.gif --force

The existing file is replaced only after the new GIF has been generated and validated.

Can I use paths containing spaces or starting with a dash?

Quote paths containing spaces. Place a filename starting with - after --:

assistanimate convert 'My recording.mov' --output 'My demo.gif'
assistanimate convert --fps 12 -- -recording.mp4

Why does doctor report a missing binary?

Both ffmpeg and ffprobe must be available to the process running the CLI. Install FFmpeg, ensure its executable directory is on PATH, and run assistanimate doctor again. A terminal, editor, and automation runner may inherit different environments.

Build from source

From the repository root:

bun install --frozen-lockfile
npm run build
node dist/cli.js doctor
node dist/cli.js convert recording.mp4 --fps 12 --resolution width:640

You can also run the TypeScript entrypoint during development:

bun run dev convert recording.mp4 --fps 12 --resolution width:640

To install a locally built package:

npm pack
npm install -g ./assistanimate-0.1.0.tgz
assistanimate --version

Development and verification

| Command | Purpose | | --- | --- | | npm run typecheck | Check TypeScript source, scripts, and tests. | | npm run lint | Run Oxlint with warnings treated as failures. | | npm test | Run the unit tests. | | npm run test:integration | Build and test the CLI with Node and real FFmpeg. | | npm run test:all | Run all checks. | | npm run prepack:inspect | Build and inspect the npm package contents. |

Integration tests generate MP4, AVI, and MOV fixtures in temporary directories and verify GIF dimensions and frame counts. They also cover output collisions, concurrent conversions, missing binaries, malformed inputs, encoder failures, and interruption cleanup. FFmpeg and ffprobe are required for these tests.

Bun bundles the TypeScript entrypoint into dist/cli.js. The npm package includes that executable, its package metadata, and this README. The development dependencies and test media are excluded. Installation does not run setup scripts or install FFmpeg.

Publishing

Verify the npm account and inspect the release package:

npm login --auth-type=web
npm whoami
npm publish --dry-run

Inspect the file list, then publish the release:

npm publish --access public

prepublishOnly runs all checks, and prepack rebuilds the executable. The repository's files list limits package contents to the distributable files. Keep the version aligned with the intended release; later releases need a new version number.

See npm's publishing guide for its account and authentication requirements.

Origins

assistanimate is a TypeScript port of the FFmpeg conversion services in Video-To-Animated-Gif-Converter. Its package and build conventions follow Assist Graph CLI.

| Original module | CLI implementation | | --- | --- | | api/services/converter.py | src/core/converter.ts, src/core/probe.ts, src/core/process.ts | | api/services/resolution.py | src/core/resolution.ts | | api/services/validation.py | src/core/validation.ts, src/core/output.ts |

The port preserves the original FPS and scale filters, metadata fallback, supported video extensions, filename sanitization, and timeout values. CLI additions include explicit output paths, overwrite protection, finite-number validation, dependency diagnostics, and JSON output.

Licence

UNLICENSED, as declared in package.json.