CLI

The optical-center binary. Asset-level batch processing — point it at a folder of SVGs and it rewrites their viewBoxes on disk. JSON-able output, clean stream contracts, composes inside CI pipelines.

When to use the CLI

The CLI operates on SVG files directly — it has no view of CSS rules or JSX wrappers. Reach for it when you want to:

  • Pre-process an icon set once and check the corrected files into a repo.
  • Inspect a single icon to see what the pipeline computes for it.
  • Aggregate a library to find which icons need the largest correction.
  • Run in CI as a check (with --strict) that no icon trips a warning.

For runtime use inside a build, prefer the Vite or PostCSS plugin — the CLI is for batch operations, not per-build wiring.

Interactive wizard

Run the binary with no arguments in a real terminal and it opens a menu instead of printing the help page: pick a command with the arrow keys, fill in the inputs (paths are validated against the filesystem before anything runs), and the wizard prints the equivalent one-shot invocation before dispatching — so it doubles as a flag tutorial. After each command the menu returns; run several in one session and leave with exit or esc.

npx optical-center

The wizard only ever appears on a TTY. Pipes, CI logs, --json, and --silent always get the stable plain-text contract, so nothing scripted ever blocks on a prompt. A session closed normally exits 0 regardless of per-command warnings — the codes below are the contract for the non-interactive surface.

Commands

init

Wires optical-center into a project. Detects the framework (Vite, Astro, Tailwind, PostCSS, Babel) from package.json and existing config files, detects the package manager from the lockfile, installs the dependency, and patches the config — opticalCenter() first in Vite's plugins array, after Tailwind in PostCSS's, and so on. Creates a minimal config when none exists.

npx optical-center init                          # interactive: select + confirm
npx optical-center init --integration vite --yes # non-interactive
npx optical-center init ./my-app --dry-run       # report, write nothing

Flags: --integration=<vite|astro|postcss|tailwind|babel>, --yes, --no-install, --pm=<npm|pnpm|yarn|bun>, --dry-run. When a config file's shape can't be edited confidently, init prints a paste-ready snippet and exits 1 instead of guessing — it never rewrites code it doesn't recognise, and re-running it is always safe (already-wired files are left untouched).

transform

Rewrites every SVG in <input> and writes results to [output]. Folder in, folder out.

npx optical-center transform <input> [output]

info

Inspects a single SVG. Returns the original viewBox, the corrected viewBox, and the offset in both pixels and percent.

npx optical-center info <svg> [--json]

analyze

Aggregates a folder of SVGs. Returns a top-N report sorted by offset magnitude — useful for finding which icons in a library need the largest corrections.

npx optical-center analyze <folder> [--json]

clear-cache

Drops the content-addressable cache. The cache is normally self-managing (keyed by SVG bytes + algorithm version) so manual clears are rarely needed.

npx optical-center clear-cache [--all]

version

Prints the package version and algorithm version. Useful inside CI logs.

npx optical-center version

Common flags

Flag Effect
--json Emits machine-readable JSON on stdout. Progress and warnings still go to stderr.
--strict Promotes warnings to a non-zero exit code so CI fails on (for example) OPTICAL_CLIP_DETECTED.
--no-cache Skips the disk cache; recomputes every icon from scratch.
--cache-dir=<path> Overrides the cache directory. Defaults to the OS cache location.
--emit-metadata Adds data-optical-original-viewbox and data-optical-offset attributes for DevTools inspection. On for info, off for production transform.
--silent Suppresses progress logs on stderr. Errors still surface.
--quiet Suppresses warnings on stderr. Stronger than --silent.

Exit codes

The exit code is the contract between the CLI and your CI script. Every command follows the same scheme:

Code Meaning
0Success.
1Success with warnings (or --strict tripped on a warning).
2Recoverable error — one or more files failed but the run continued.
3Fatal — the run aborted (invalid args, IO failure, etc).

Heads-up for script runners: exit code 1 means success with warnings (clip detection, derived viewBox), but yarn and npm print a "command failed" banner for any non-zero exit. That banner is the runner talking, not a crash — the actual warning is on stderr. Use --strict when you want warnings to fail CI; otherwise treat 1 as a soft pass.

JSON output

With --json, stdout is data only — pipe it into jq or read from a CI job.

terminal bash
$ optical-center info ./icons/play.svg --json
stdout json
{
  "schemaVersion": 1,
  "command": "info",
  "result": {
    "file": ".../play.svg",
    "originalViewBox": { "x": 0, "y": 0, "w": 24, "h": 24, "source": "attribute" },
    "newViewBox": "-0.3239 -0.6226 24 24",
    "offset": {
      "dxPercent": 1.3497,
      "dyPercent": 2.5944,
      "dx": 1.62,
      "dy": 3.11
    },
    "clipDetected": false,
    "breadcrumb": {
      "data-optical-center": "",
      "data-optical-original-viewbox": "0 0 24 24",
      "data-optical-offset": "1.3497% 2.5944%"
    }
  },
  "version": {
    "package": "0.2.0-alpha.0",
    "algorithm": "1.0.0-v2",
    "schema": 1
  }
}