vctrfx-cli
v0.10.1
Published
Apply post-processing effects to any SVG from the terminal. Scanlines, bloom, glitch, halftone and more.
Maintainers
Readme
vctrfx-cli
vctrfx logo.svg -p crt
Post-processing effects for any SVG, straight from your shell.
Pipe it, point it at a file, a directory or a URL — get back a real SVG with scanlines, bloom, glitch, halftone or a dozen other looks baked in. Still vector, still editable, no rasterizing.
Highlights
- ✅ Pipe-first —
cat logo.svg | vctrfx -p vhs > out.svgjust works. - ✅ Every input — file, directory, glob, stdin,
-, or anhttps://URL. - ✅ Stackable effects —
-eis repeatable and order preserving, exactly like the library's array. - ✅ 27 effects + 8 presets — one binary,
vctrfx listto see them all. - ✅ Batch a folder —
vctrfx icons/ -p riso -o dist/. - ✅ Deterministic —
--seedmakes output byte-identical run to run. - ✅ Data URIs —
--data-urifor dropping straight into CSS or HTML. - ✅ Keeps existing animation — an SVG that already animates keeps animating.
Table of contents
Installation
npm install -g vctrfx-cliOr run it without installing:
npx vctrfx-cli logo.svg -p crt -o out.svgQuick start
vctrfx logo.svg -e bloom # one effect, printed to stdout
vctrfx logo.svg -p crt -o out.svg # a preset, written to a file
cat logo.svg | vctrfx -p vhs > out.svg # piped in, redirected out
vctrfx icons/ -p riso -o dist/ # a whole directory
vctrfx list # everything availableEffects stack in the order you pass them, the same way they do in the library:
vctrfx logo.svg -e "bloom:radius=8" -e "scanlines:gap=3" -e "grain:amount=0.3"Input
| Form | Example |
| ---- | ------- |
| File | vctrfx logo.svg -p crt |
| Several files | vctrfx a.svg b.svg -e invert -o dist/ |
| Glob (shell expands it) | vctrfx icons/*.svg -p riso -o dist/ |
| Directory | vctrfx icons/ -p riso -o dist/ |
| Piped stdin | cat logo.svg \| vctrfx -p vhs |
| Explicit stdin | vctrfx - -e grain < logo.svg |
| Remote URL | vctrfx https://example.com/logo.svg -p neon |
Directories are scanned one level deep for .svg files, sorted by name.
Output
| Flag | Behaviour |
| ---- | --------- |
| (none) | Writes the SVG to stdout, so it pipes and redirects |
| -o out.svg | Writes one file |
| -o dist/ | Writes into a directory, keeping each input's filename |
| -i, --in-place | Overwrites the input files |
| -u, --data-uri | Emits a data: URI instead of markup |
| -b, --base64 | Base64-encodes the data URI |
Written paths are reported on stderr, so stdout stays clean for piping. Use -q to silence it.
Effects
vctrfx list prints all of these with their options.
| | |
| --- | --- |
| Light | blur bloom glow shadow |
| Colour | grayscale saturate hue-rotate invert brightness contrast sepia fade posterize threshold duotone tint |
| Texture | grain scanlines chromatic-aberration glitch pixelate halftone vignette outline wave emboss sharpen |
Options go after a colon, comma separated. Keys accept kebab-case or camelCase:
vctrfx logo.svg -e "halftone:size=5,angle=15,keep-source=true"
vctrfx logo.svg -e "glow:color=#ff2d55,radius=8"
vctrfx logo.svg -e "grain:animate" # a bare key means true
Overlays follow your SVG's shape
scanlines, vignette and halftone lay something over the drawing rather than
filtering it. They mask that overlay to the artwork's own silhouette, so a rounded
terminal window, a logo on transparency, or anything with a non-rectangular shape keeps
its edges instead of getting a rectangle painted over it.
vctrfx terminal.svg -p crt -o out.svg # rounded corners survive
vctrfx terminal.svg -e scanlines:clip=viewport # opt out, fill the whole framePresets
| Preset | Look |
| ------ | ---- |
| crt | Phosphor glow, scanlines, colour fringing, vignette |
| vhs | Tape wobble, heavy fringing, rolling lines, noise |
| riso | Two-colour risograph with paper grain |
| xerox | Blown-out photocopy |
| neon | Saturated sign glow |
| film | Halation, grain and a soft vignette |
| newsprint | Halftone dots on off-white stock |
| cyberpunk | Sliced, shifted, bloomed, scanned |
Presets take options too:
vctrfx logo.svg -p "riso:shadow=#2b3a67,highlight=#ff5a5f"
vctrfx logo.svg -p "crt:animate=true"Animation
grain, scanlines, glitch and wave can move. -a switches on every one of them inside
the presets you apply. Inline effects are explicit, so each opts in on its own:
vctrfx logo.svg -p vhs -a # wave, grain and scanlines all move
vctrfx logo.svg -p vhs -a --no-animate "scanlines,grain" # only the wave moves
vctrfx logo.svg -p crt -e grain:animate # still crt, moving grain
vctrfx logo.svg -p "crt:animate" --no-animate # a still frame, whatever asked to moveAn explicit nested option such as crt:scanlines.animate=false always wins over the flags.
Tuning what's inside a preset
A preset is a stack of effects. Reach any one of them with a dot, and the rest of the recipe stays as it was:
vctrfx logo.svg -p "film:grain.amount=0.5"
vctrfx logo.svg -p "crt:scanlines.gap=6,vignette.amount=0.9,animate=true"
vctrfx logo.svg -p "newsprint:halftone.size=8,halftone.angle=15"vctrfx list prints each preset's inner effects and their options. Paths are validated at
both levels, so a typo tells you what was valid where:
$ vctrfx logo.svg -p "film:scanlines.gap=3"
Error: "film" has no option "scanlines". Valid: contrast, bloom, grain, vignette.Options
| Flag | Default | Description |
| ---- | ------- | ----------- |
| -e, --effect | | Effect to apply. Repeatable, order preserving |
| -p, --preset | | Preset to apply. Repeatable |
| -c, --config | | JSON file holding the effect stack |
| -o, --output | stdout | Output file, or directory for several inputs |
| -i, --in-place | false | Overwrite the input files |
| -u, --data-uri | false | Emit a data: URI |
| -b, --base64 | false | Base64-encode the data URI |
| -s, --seed | vctrfx | Seed for every random decision |
| --prefix | vctrfx | Prefix for generated ids |
| --scope | auto | Id namespace, defaults to a hash of the input and effects |
| -a, --animate | false | Animate every animatable effect inside the presets |
| --no-animate | | Comma separated effects to keep still. Bare, forces a still frame |
| -f, --format | preserve | preserve, pretty or minify |
| -q, --quiet | false | Do not report written files |
Recipes
A stack you reuse, kept in a file
[
{ "effect": "duotone", "shadow": "#111d4a", "highlight": "#ffd166" },
{ "effect": "halftone", "size": 5, "angle": 15 },
"grain:amount=0.3"
]vctrfx logo.svg -c poster.json -o poster.svgStraight into CSS
echo "background-image: url('$(vctrfx logo.svg -p crt -u)');"Every icon in a folder, minified
vctrfx icons/ -p riso -f minify -o dist/An SVG that already animates keeps animating
vctrfx spinner.svg -p crt -o spinner-crt.svgReproducible output in CI
vctrfx logo.svg -e glitch --seed release-42 -o out.svgLibrary
This is the terminal front end for
vctrfx.
Every effect, option and default is the same — reach for the library when you want
this inside a build script or an app.
npm install vctrfxLicense
MIT © Tal Hayut
