How to automate monochrome svg conversion for icon libraries and asset pipelines
- Step 1Install and pair the runner — Install
@jadapps/runnerfrom the docs at /docs/runner and pair it with your API key. The runner listens on127.0.0.1:9789and is what actually processes files. - Step 2Fetch the schema —
GET /api/v1/tools/svg-monochrome-converterwith your API key returns the option schema:monochromeMode(enum single|grayscale, default single) andmonochromeColor(colour, default #000000). Build your payload from this. - Step 3Normalise colours if you'll grayscale — Grayscale only parses hex and eleven named colours. If your icons use
rgb()/hsl(), run them through a hex-normalising step first (or use single mode). Skip this for single mode — it overwrites any format. - Step 4POST each file to the runner — POST
{ monochromeMode, monochromeColor }plus the SVG tohttp://127.0.0.1:9789/v1/tools/svg-monochrome-converter/run. Loop over your icon directory; the runner returns the converted SVG per file. - Step 5Respect your tier's batch ceiling — Chunk your loop to your tier's batch-files limit (Pro 20, Pro + Media 100, Developer unlimited) and keep file sizes under the cap (Pro 50 MB; icons are tiny, so size is rarely the constraint).
- Step 6Write outputs to a parallel tree — Emit to
icons/monochrome/alongside the colour set so design-system consumers pick the variant they need. Keep the original colour set untouched.
Endpoints and execution model
JAD's hosted API never receives uploads. The runner does the work locally.
| Step | Endpoint | What it returns / does |
|---|---|---|
| Get schema | GET /api/v1/tools/svg-monochrome-converter | The two-option schema + execution metadata |
| Hosted /run | POST /api/v1/tools/svg-monochrome-converter/run | 400 'Runner required' (no uploads accepted) — by design |
| Runner /run | POST http://127.0.0.1:9789/v1/tools/svg-monochrome-converter/run | Executes in-process, returns the converted SVG |
Request payload
The complete option set — there are only two options. Send the file content alongside per the runner protocol.
| Field | Type | Default | Notes |
|---|---|---|---|
monochromeMode | single | grayscale | single | Single = flat colour; grayscale = per-colour luminance |
monochromeColor | hex colour | #000000 | Used only when mode is single; ignored for grayscale |
Batch limits by tier
SVG-family batch and size caps. Monochrome requires Pro or higher.
| Tier | Batch files / run | Max file size |
|---|---|---|
| Pro | 20 | 50 MB |
| Pro + Media | 100 | 200 MB |
| Developer | unlimited | 2 GB |
| Enterprise | unlimited | unlimited |
Cookbook
Automation snippets. Adjust to your runner client; the option payload is the same everywhere.
Fetch the schema
Confirm the contract before building payloads. The response lists the two options and that execution runs via the engine (no headless browser).
curl -H "Authorization: Bearer $JAD_API_KEY" \
https://jadapps.com/api/v1/tools/svg-monochrome-converter
# → options: [
# { name: "monochromeMode", type: "enum",
# values: ["single","grayscale"], default: "single" },
# { name: "monochromeColor", type: "color", default: "#000000" }
# ]
# → execution.runnerMode: "engine"Hosted /run refuses uploads (expected)
Proves the model: the cloud endpoint never takes files. Point your client at the local runner instead.
POST https://jadapps.com/api/v1/tools/svg-monochrome-converter/run
→ 400 {
"error": "Runner required",
"runnerEndpoint": "http://127.0.0.1:9789/v1/tools/svg-monochrome-converter/run",
"schemaEndpoint": ".../api/v1/tools/svg-monochrome-converter"
}Batch a directory to flat black via the runner
Loop your colour icons through the local runner in single mode. Files stay on your machine.
for f in icons/color/*.svg; do
curl -s -X POST \
http://127.0.0.1:9789/v1/tools/svg-monochrome-converter/run \
-F file=@"$f" \
-F monochromeMode=single \
-F monochromeColor=%23000000 \
-o "icons/monochrome/$(basename "$f")"
done
# (%23 = URL-encoded '#')Off-white variant for a dark theme
Same loop, single mode, light target — produces an icon set that reads on dark surfaces.
monochromeMode=single monochromeColor=#e5e7eb → every fill/stroke attribute becomes #e5e7eb Output dir: icons/monochrome-dark/
Normalise rgb() before grayscale
Grayscale skips rgb()/hsl(). Convert to hex in a prior step so grayscale actually acts on every colour.
Step 1: convert rgb()/hsl() → hex (hex swapper or your own pass) Step 2: runner /run with monochromeMode=grayscale Without step 1: rgb()/hsl() colours pass through unchanged. With step 1: every colour maps to its luminance grey.
Edge cases and what actually happens
Posting files to the hosted API
400 Runner requiredPOST /api/v1/tools/svg-monochrome-converter/run on jadapps.com always returns 400 with pairing instructions — the hosted API is upload-free by design. Send files only to the local runner at 127.0.0.1:9789. This keeps brand assets on your network.
Grayscale batch leaves rgb()/hsl() icons in colour
Preserved (unchanged)The grayscale path parses only hex and eleven named colours; rgb(), rgba(), and hsl() pass through. In a batch this looks like 'half my icons converted'. Normalise colours to hex first, or use single mode which overwrites regardless of format.
currentColor in source attributes during single-mode batch
OverwrittenSingle mode replaces fill="currentColor" with the target colour (only none/transparent/url(...) are skipped), so themeable icons lose their inheritance. If your library relies on currentColor, don't run single mode over it — keep colour theming via the CSS variable injector.
Colours defined in <style> blocks across the library
By designOnly the fill/stroke/stop-color attributes are rewritten. Icons whose colours live in a <style> block (some sprite/export pipelines) won't change. Re-export with presentation attributes before batching, or flatten styles upstream.
Batch exceeds the tier file count
RejectedPro caps at 20 files per run, Pro + Media at 100. Chunk your loop accordingly, or upgrade. The runner enforces the same per-tier limits as the browser tool.
A single icon exceeds the size cap
RejectedPro rejects SVGs over 50 MB. Icons are typically kilobytes, so this only happens with embedded base64 rasters or pathological auto-traced paths. Run minify first, or strip the embedded raster.
Rate limit hit during a large batch
429 Rate limit exceededSchema fetches against the hosted API are rate limited per key; the response includes X-RateLimit-Reset. Fetch the schema once and cache it — the per-file work happens on the runner and isn't gated by the hosted API rate limit.
Embedded raster icons in the set
Preserved (unchanged)Icons containing <image> base64 bitmaps keep their raster colour; only vector attributes convert. Audit your set for embedded images before assuming the whole library went monochrome.
Output filename collisions
ExpectedThe tool names output <stem>-monochrome.svg. If your batch script writes to a flat folder by stem, two source files with the same stem will collide. Preserve subdirectory structure or namespace your output paths.
Frequently asked questions
Can I upload my icons to a JAD endpoint to convert them?
No. JAD's API and MCP layer never accept uploads — the hosted /run endpoint returns 400 with pairing instructions. Files are processed only by a paired @jadapps/runner on your own machine at 127.0.0.1:9789.
What's the real request payload?
Just two options: monochromeMode (single or grayscale, default single) and monochromeColor (hex, default #000000, used only in single mode), plus the SVG file content per the runner protocol. There are no other parameters.
Does the runner need a headless browser for this tool?
No. Monochrome is a pure-text transform, so its execution.runnerMode is engine — the runner imports the engine and runs it in-process. Headless browsers are only needed for tools producing binary output or needing Canvas/DOM.
Will the runner output match the browser tool exactly?
Yes. Both call the same logic — the same 0.299R + 0.587G + 0.114B grayscale formula and the same attribute regex — so output is byte-identical for the same input and options.
How do I batch a whole directory?
Loop over your files and POST each to the runner's /run endpoint with your chosen mode/colour. Chunk to your tier's batch-files limit (20 on Pro, 100 on Pro + Media). Write outputs to a parallel icons/monochrome/ tree.
Why did only some icons convert in grayscale mode?
Grayscale only parses hex and eleven named colours; rgb()/hsl() and other named colours pass through unchanged. Normalise colours to hex before the grayscale run, or use single mode which overwrites any format.
Can I produce both colour and monochrome sets in one pipeline?
Yes. Keep your colour source set as-is and run the runner over a copy into icons/monochrome/. Two output trees, one source — consumers pick the variant. The original colour set is never modified.
Does conversion preserve IDs, viewBox, and structure?
Yes. Only the fill, stroke, and stop-color attribute values change. Paths, shapes, groups, IDs, viewBox, and ARIA attributes are preserved exactly.
What about SVGs with embedded raster images?
Embedded <image> bitmaps aren't vector colour attributes and aren't converted — they stay full colour while vector shapes go monochrome. Handle bitmaps separately.
What are the size and batch limits?
Pro: 50 MB per file, 20 files per run. Pro + Media: 200 MB, 100. Developer: 2 GB, unlimited batch. Monochrome requires Pro or higher; it isn't available on Free.
Is grayscale's formula configurable?
No. It's fixed at BT.601 weights 0.299R + 0.587G + 0.114B. If you need different weighting, post-process the resulting greys, or compute your own greys and apply them with the hex swapper.
How do I avoid leaking brand assets?
You don't have to do anything special — files never leave your machine. The runner processes everything locally; only the schema (no file content) is fetched from the hosted API. That's the whole point of the runner model.
Privacy first
Every JAD SVG tool runs entirely in your browser using the DOM API and Canvas. Your SVG files never leave your device — verified by zero outbound network requests during processing.