# ezu-cli
Command-line renderer for the Ezu Style Spec — the `ezu` binary of the
[`ezu`](../../README.md) workspace.
```sh
cargo install ezu-cli
```
Or without a Rust toolchain: `brew install reearth/tap/ezu`, or take one
of the prebuilt binaries for Linux, macOS and Windows attached to every
[release](https://github.com/reearth/ezu/releases/latest).
Point it at any style (URL or local path) and it renders PNGs. A style
declares its own tile sources in a `sources` block (MVT, PMTiles, raster
DEM, RGBA raster, GeoJSON), so most commands need nothing but a
`--style` and a tile address; CLI flags override anything declared there
for one-off swaps.
## Commands
| `ezu tile` | Render a single `z/x/y` tile to PNG, lossless WebP or raw straight RGBA (by `--out`'s extension or `--format`) |
| `ezu bbox` | Stitch the tiles covering a lon/lat box at one zoom into a single image, `--concurrency` tiles at a time |
| `ezu frame` | Render a map at a print scale and paper size (`--scale 1000 --dpi 200 --size-mm 245x174`), cropped exactly to that frame; `--pages` renders a list of pages in one run |
| `ezu tiles` | Bulk-render an XYZ pyramid into `<out>/<z>/<x>/<y>.png` over a zoom range, `--concurrency` tiles at a time |
| `ezu check` | Validate a style — parse + build graph + resolve assets. Exits non-zero on error, so it drops into a pre-commit hook or CI step. `--no-fetch` stays offline (parse + graph only) |
| `ezu translate` | Lower a MapLibre GL style into an ezu recipe via [`ezu-translate`](../ezu-translate). `--font "NAME=SOURCE"` maps a fontstack entry to a real font; skipped or approximated layers are reported on stderr |
| `ezu graph` | Emit a Mermaid `graph LR` diagram of the style's node dependencies — or, with `--tile`, an HTML page of the same graph with each node's own intermediate tile drawn on it |
| `ezu legend` | Emit the style's declared legend as JSON, with `--swatch-dir` writing each entry's swatch image, for a host to lay out beside the map |
| `ezu schema` | Print the Ezu Style JSON Schema, assembled from the registered ops (`--out FILE` to write it). Feed it to an editor's JSON language server, an `ajv` CI check, or a docs generator — [custom ops](../ezu-graph#custom-ops) are included |
| `ezu serve` | Live editor + tile server (below) |
Global flags: `--verbose` / `-v` turns on per-node debug logs from the
evaluator (op name, cache hit/miss, output shape, eval duration).
Render commands share `--style`, `--assets-dir`, `--pmtiles` / `--mvt`,
`--overzoom-levels`, `--pad`, `--strict` (refuse a style that raises build
warnings), `--png-compression`, and repeatable `--param NAME=VALUE` overrides
validated against the style's `params` declarations. `tile`, `bbox`,
`tiles` and `serve` also take `--tile-size`, to render at another size than
the style's `tile-size`, and `--pixel-ratio`, to render the same map at a
higher density for hi-DPI screens; `serve` answers `{y}@2x.png` with the tile
at pixel ratio 2. `tile`, `bbox` and `frame` take repeatable
`--features NODE=PATH` to write a features node's contents as GeoJSON, in
tile units, lon/lat or pixels (`--features-coords`). Source tiles a run
fetches are kept within `EZU_TILE_CACHE_MB` (default 256 MB).
```sh
# Single tile — the reference styles bundle their own `sources` block,
# so no `--pmtiles` / `--mvt` is needed.
ezu tile --style crates/ezu/examples/styles/watercolor.json \
--tile 13/7276/3225 --out tile.png
ezu bbox --style URL_OR_PATH \
--bbox 139.74,35.65,139.78,35.69 --zoom 13 --out tokyo.png
# A 1:1000 page, 245 × 174 mm at 200 dpi.
ezu frame --style URL_OR_PATH \
--center 139.70,35.66 --scale 1000 --dpi 200 --size-mm 245x174 --out page.png
ezu tiles --style URL_OR_PATH \
--bbox 139.74,35.65,139.78,35.69 --min-zoom 10 --max-zoom 14 --out pyramid
ezu check style.json --no-fetch
ezu translate maplibre-style.json --out recipe.json
# Parameter overrides, validated against the style's `params` block.
ezu tile --style watercolor.json --tile 13/7276/3225 \
--param 'paper=#ffe0f0' --param softness=2 --out tile.png
```
## `ezu serve` — live editor + tile server
```sh
ezu serve # default example style
ezu serve crates/ezu/examples/styles/pencil-sketch.json # a specific style
ezu serve https://example.com/style.json # or fetch one over http(s)
# Open http://127.0.0.1:8080
```
The server hosts the browser editor at `/`, rendered tiles at
`/tiles/{z}/{x}/{y}.{png,webp}`, raw MVT bytes at `/mvt/{z}/{x}/{y}`,
and a registry-derived JSON Schema at `/schemas/ezu-style.json` — the
same schema the editor validates against as you type, so
[custom ops](../ezu-graph#custom-ops) get autocomplete for free.
`/style/params` serves the current style's parameter schema and
`/style/attribution` the merged source attributions.
The editor (MapLibre GL based) supports:
- **Open / URL / Save** — load a style from a local file or http(s) URL,
save the current buffer as `<name>.json`. Open on Chromium browsers
uses the File System Access API so Save writes back in place.
- **Apply** with `⌘↵` / `Ctrl+↵` (works anywhere on the page).
- **Live preview** — when enabled, auto-applies on every keystroke that
parses + schema-validates + server-validates clean.
- **External-edit reload** — when launched with a local path
(`ezu serve foo.json`), the server polls the file and pushes
Server-Sent Events on every change. The editor swaps the buffer
silently when clean, or surfaces a Reload banner when the user has
unsaved edits. The `↻ HH:MM:SS` indicator in the toolbar shows the
last auto-reload. On Chromium, the same watch also runs against
files opened via the in-browser file picker. Opening a different
file via `Open…` / `URL…` detaches the server watch for that
session.
- **Params panel** — controls generated from the style's `params`
declarations (sliders for bounded numbers, color pickers, toggles,
and for a `string` param a menu of its `enum` or a text field).
Adjustments ride the tile requests as query-string overrides and
re-render live without touching the style text; `reset` returns to
the declared defaults. See
[parametric styles](../ezu-style#params).
- **Source MVT inspector** — toggle a vector overlay of the underlying
MVT, with per-layer ON/OFF and click-to-inspect feature properties.
Layers are discovered from the tile at the map center; pan/zoom
rescans automatically.
- **Tile grid + zoom indicator** — toggle a `z/x/y` boundary overlay
(drawn per tile via `maplibregl.addProtocol`), and read the live
zoom value (click to copy `z @ lat,lng`).
A self-contained [`ezu-wasm`](../ezu-wasm) demo page and the routes it
needs (including the COOP/COEP headers the threads build requires) ship
with `ezu serve` too.
## License
MIT or Apache-2.0, at your option.