@anupjon/crnch
v0.2.0
Published
crnch — crunch your media. A developer CLI for optimizing images and videos.
Maintainers
Readme
crnch
crnch — crunch your media.
A developer-first CLI for optimizing images and videos, built on Sharp and FFmpeg. Three ways to use it:
- Interactive terminal shell — a persistent, slash-command-driven shell for exploring and running operations.
- Guided walkthrough — a step-by-step wizard for single files or whole folders.
- Non-interactive mode — flags, presets, and config files for scripts and CI/CD.
crnch is deterministic and local. It does not use an LLM, cloud service, or network access to make decisions — every optimization is driven by explicit configuration, presets, or your answers in the wizard.
Inspect → Recommend → Confirm → Optimize → ReportRequirements
- Node.js 20 or later.
- Sharp — installed automatically as an npm dependency.
- FFmpeg / FFprobe — required for video features only. Not bundled; install separately and make sure both are on your
PATH. Image-only usage works fine without them.
Run crnch doctor any time to check your environment — Node version, Sharp health, FFmpeg/FFprobe presence, supported codecs (H.264/H.265/AV1), image formats (WebP/AVIF), and available hardware-accelerated encoders.
Install
Not yet published to npm. To use it from a local checkout:
npm install
npm run build
npm link # exposes the `crnch` command globallyOr run it directly without installing:
node dist/cli/index.js --helpQuick start
# Launch the interactive shell
crnch
# Optimize a single image or video (guided wizard on a TTY, direct engine otherwise)
crnch optimize hero.jpg
crnch optimize hero.mp4
# Optimize a whole folder, non-interactively, with a preset
crnch optimize ./assets --preset web --yes
# See what would happen without changing anything
crnch optimize hero.jpg --dry-run
# Check environment / dependencies
crnch doctorOptimized output is written to an optimized/ subdirectory next to the source by default — originals are never modified unless you explicitly ask for that (--replace-originals).
Commands
| Command | Description |
|---|---|
| crnch | Launch the interactive shell (on a TTY) |
| crnch optimize <path> | Optimize an image, video, or folder |
| crnch image <path> | Optimize an image directly |
| crnch video <path> | Optimize a video directly |
| crnch inspect <path> | Show technical metadata without modifying files |
| crnch analyze <path> | Find optimization opportunities and recommend actions |
| crnch check <path> | Validate media against configured size budgets (CI gate) |
| crnch watch <directory> | Watch a directory and apply a policy to new/changed media |
| crnch presets | List available presets |
| crnch doctor | Check environment and dependency health |
Inside the interactive shell, the same commands are available as slash-commands (/optimize, /inspect, /analyze, /check, /presets, /doctor, /history, /status, /help, /clear, /exit). /watch is CLI-only — run crnch watch <dir> directly in a terminal instead.
Presets
| Preset | Use case |
|---|---|
| web | Balanced size/quality for general web delivery (default) |
| web-mobile | Smaller dimensions/bitrates for mobile-first delivery |
| high-quality | Minimal visible quality loss |
| smallest | Maximum size reduction |
| archive | Long-term storage — preserves dimensions, metadata, HDR |
| keep-format | Optimizes without converting format |
crnch optimize hero.jpg --preset smallest
crnch presets # list with descriptions
crnch presets --jsonCommon flags
| Flag | Applies to | Description |
|---|---|---|
| --preset <name> | image/video/folder | Select a named preset |
| --config <path> | any | Use a specific crnch.config.json instead of discovering one |
| --dry-run | image/video/folder | Show what would happen; write nothing |
| --explain | image/video | Explain why the current configuration was selected |
| --json | most commands | Machine-readable output on stdout (all logs go to stderr) |
| --quiet / --verbose | most commands | Suppress or expand normal output |
| --yes | folder/CI | Bypass confirmation (non-interactive commands never prompt anyway) |
| --replace-originals | image/video | Delete sources after a successful conversion (requires this flag, --yes alone is not enough) |
| --output <path> | image/video/folder | Output directory |
| --format <list> | image | Comma-separated output formats: webp,avif,jpeg,png |
| --quality <1-100> | image | Encode quality (mapped per format internally) |
| --long-side / --width / --height | image | Resize strategy (mutually exclusive) |
| --responsive / --responsive-widths | image | Generate a set of width variants instead of one output |
| --codec <name> | video | h264, h265, av1, auto |
| --resolution / --max-height / --max-width | video | Resize strategy |
| --target-size <size> | video | Target an approximate output size, e.g. 25MB |
| --hwaccel <name> | video | none, nvenc, qsv, vaapi, videotoolbox |
| --budget-image <size> / --budget-video <size> | check | Per-file size budgets, e.g. 500KB / 20MB |
Run crnch --help for the full list.
Configuration file
Drop a crnch.config.json anywhere in your project — crnch discovers it by walking up from the current directory, same resolution model as tsconfig.json.
{
"preset": "web",
"images": {
"longSide": 1920,
"formats": ["webp", "avif"],
"quality": 80,
"stripMetadata": true
},
"videos": {
"maxHeight": 1080,
"codec": "h265",
"audioBitrate": "128k"
},
"output": {
"directory": "optimized",
"skipExisting": true
},
"budgets": {
"image": "500KB",
"video": "20MB"
}
}Precedence (highest wins): CLI flags > config file > preset > built-in defaults.
CI usage
crnch optimize ./public --preset web --yes --json > result.json
crnch check ./public --budget-image 500KB --budget-video 20MB # exit code 4 on violationExit codes: 0 success · 1 processing failure · 2 invalid arguments · 3 missing dependency · 4 budget violation · 130 interrupted.
Development
npm run dev # run from source via tsx
npm run build # compile to dist/
npm run typecheck # type-check without emitting
npm test # run the test suite (vitest)Test fixtures are generated programmatically (via Sharp and ffmpeg -f lavfi) rather than committed as binary files, so the test suite stays hermetic. FFmpeg-dependent tests skip automatically if FFmpeg isn't installed.
License
MIT
