# CLI, local Studio, and Node rendering

## Interactive web Studio

```sh
npx badgecraft studio
npx badgecraft studio --open
npx badgecraft studio --port 8080
```

Open the printed URL to upload, drop, or paste an SVG, adjust materials and
lighting, export PNG images, or copy code for a website. `--open` opens Google
Chrome; you can also open the URL yourself in a WebGL2-capable browser. Node.js
22+ is required. No source checkout or development dependencies are needed.

The app is bundled in the package and works offline after installation. SVGs
are read by the browser; the local server never receives them or serves your
working directory. Valid drafts are saved in that browser's local storage.
The hosted version is at https://parthjadhav.github.io/badgecraft/studio.html.

The server listens on `127.0.0.1`, port 5199. If the default is occupied, it picks
an available port and prints the URL. An explicitly requested occupied port
fails with an explanation. Use `--port 0` to always pick an available port.
Press Ctrl+C to stop. Use a consistent port to keep using the same saved draft
(browser storage is tied to the URL's origin).

Studio accepts SVGs up to 1 MiB and exports PNG at 512, 1024, or 2048 pixels.
For WebP/JPEG or automation, use image conversion below.

## Image conversion

The CLI turns a self-contained SVG into a static badge image with the same
WebGL2 renderer as the browser library. It runs locally; it does not upload
artwork or fetch remote assets.

## Install

Use Node.js 22 or newer and install [Google Chrome](https://www.google.com/chrome/).
Chrome is required only for image exports from Node or the CLI. Browser components
use the visitor's WebGL2 browser and do not need a local Chrome installation.

```sh
# Run without a global installation
npx badgecraft icon.svg --output badge.png

# Or install globally
npm install -g badgecraft
badgecraft icon.svg --output badge.png
```

`playwright-core` controls your installed Chrome; installing this package does
not download a browser or run an installation script. macOS, Windows, and Linux
with Chrome are supported. On a minimal Linux machine, install Chrome's system
libraries too. `npx playwright-core install chrome` is an alternative Chrome
installer and may need administrator access.

If Chrome is in a nonstandard location, pass `--chrome-path /path/to/chrome` or
set `BADGECRAFT_CHROME_PATH`. Chrome runs headlessly with software WebGL, so
no display server or dedicated GPU is needed. In containers where Chrome's
sandbox cannot run, configure the container for Chrome sandboxing or explicitly
pass `--no-sandbox`. Sandbox disabling is never the default.

## Examples

```sh
# Creates icon.badge.png next to the SVG
badgecraft icon.svg

# A silver badge on a hexagonal backplate
badgecraft icon.svg -o silver.png --metal silver --frame hexagon --size 1024

# Copper under warm lighting
badgecraft icon.svg -o copper.webp --metal copper --environment sunset

# Opaque JPEG with a custom background and camera pose
badgecraft icon.svg -o badge.jpg --background '#17191e' --yaw=-18 --pitch=-10

# Pipe SVG in, pipe PNG out (diagnostics go to stderr)
cat icon.svg | badgecraft - --output - > badge.png

# Discover all 23 materials or view all options
badgecraft --list-presets
badgecraft --help
```

Use `--flag=-10` for negative numeric values. Values with spaces must be quoted.
The output extension selects PNG, WebP, or JPEG; `--format` selects the format
when stdout or a filename without an extension is used. `--format` and a filename
extension must agree. PNG and WebP have transparent backgrounds by default.
JPEG always has an opaque background (white unless customized).

Existing files are protected unless `--force` is supplied. Parent directories
are created automatically. A conversion error exits with status 1, writes an
explanation to stderr, and does not create a new output file.

Image size is square and limited to 16–2048 pixels. `--quality` controls the relief
map resolution (64–2048); `--image-quality` controls WebP/JPEG compression (0–1).
The render uses a fixed pose with animation and pointer interaction disabled.
Software WebGL keeps rendering portable; byte-identical output across different
Chrome versions and operating systems is not guaranteed.

## Input and output boundaries

Input must be an SVG file path or SVG markup on stdin, up to 10 MiB. Paths, fills,
strokes, gradients, masks, clip paths, inline styles, and embedded images are
supported by the underlying renderer. Embed images as data URLs and convert text
to paths for consistent results on machines with different installed fonts.

SVG scripts, event handlers, embedded HTML, and animations are removed. External
resources are blocked, including CSS imports, fonts, images, and image-based
lighting. CLI lighting accepts the five built-in environments. Conversions work
offline once the npm package and Chrome are installed.

The result is a raster image, not an editable vector SVG. Use the browser exports
for interactive badges. A missing WebGL2 context fails explicitly instead of
silently exporting the original flat SVG.

## Node API

```js
import { readFile, writeFile } from 'node:fs/promises'
import { renderBadge } from 'badgecraft/node'

const svg = await readFile('icon.svg', 'utf8')
const image = await renderBadge(svg, {
  size: 1024,
  format: 'png',
  metal: { preset: 'gold', roughness: 0.25 },
  frame: { shape: 'circle', padding: 0.2 },
  relief: { depth: 0.06 },
  environment: 'studio',
  pose: { pitch: -5, yaw: -12 },
})
await writeFile('badge.png', image)
```

`renderBadge(svg, options)` returns a `Promise<Buffer>`. Its `RenderOptions` type
includes the library's static badge options, plus `size`, `format`, `background`,
`imageQuality`, `timeout`, `executablePath`, and `sandbox`. The SVG argument must
be markup, not a URL. The Node entry is ESM; CommonJS callers can use
`await import('badgecraft/node')`. Import only the browser entry in frontend
bundles; Chrome and Node code are isolated in `badgecraft/node`.

Each call creates and closes an isolated Chrome process. For a batch, process
files sequentially or keep concurrency low to bound memory use. `timeout`
defaults to 60 seconds for startup and separately 60 seconds for rendering.
