ezu-style 0.3.0

Ezu Style Spec: declarative style specification for painterly map rendering
Documentation

ezu-style

Ezu Style Spec parser for the ezu workspace.

A pure serde-based reader for the node-DAG style language. Parsing this crate produces a [Document] — a data structure, not an evaluator. To execute a document, feed it to ezu-graph::build_graph with a NodeRegistry.

Spec at a glance

{
  "name": "watercolor-basic",
  "tile-size": 512,
  "pad": 24,
  "sources": {
    "glazing": { "type": "brush", "src": "builtin:watercolor_glazing" }
  },
  "nodes": {
    "bg":            { "op": "solid", "color": "#fbf6e6" },
    "water_feat":    { "op": "features", "name": "tile.water" },
    "water":         { "op": "fill-dabs", "features": "@water_feat",
                       "color": "#5876a0", "opacity": 0.22,
                       "radius-px": 7, "spacing-px": 3 },
    "out":           { "op": "blend", "base": "@bg", "over": "@water" }
  },
  "output": "@out"
}

References inside node fields use a prefix:

  • @name — node reference (input wiring)
  • $nameparams substitution at build time

Each features node references a host-bound layer by name (tile.<layer> for per-tile MVT/GeoJSON data) and carries an optional filter (entries AND-combined; values are single literals or membership lists) and an optional min-zoom-field.

The sources block is the single home for every external resource the renderer pulls in — document-scoped files (brushes, images) sit next to tile-scoped pyramids (MVT, PMTiles, DEM). Each entry's type discriminates the variant; document-scoped variants carry a src URI, tile-scoped variants a url template.

src URIs are explicit-scheme — pick one of:

  • builtin:NAME — bundled brush / image included in ezu-paint's built-in bank, or a host-registered resource of the same name.
  • file:PATH — local file resolved against --assets-dir (or absolute). .myb / .png / .webp extensions are inferred from the source type if omitted.
  • http(s)://... — fetched by the host (CLI native, prefetch_doc_assets) before the first render, then cached in the in-memory bank.

Tile-scoped source kinds:

  • dem — raster-DEM tile pyramid (terrarium or mapbox-rgb encoding). The host stitches the 3×3 neighbourhood into a per-tile ScalarField (with geo_scale populated) and binds it under tile.<source-name>, ready for the dem source node to pick up.
  • mvt — XYZ MVT URL template (or a TileJSON document). The host fetches one tile per render, decodes every layer, and binds each one under tile.<layer-name> — the same names existing features nodes already reference.
  • pmtiles — PMTiles archive (local path or http(s):// URL). Decoded layers bind the same way as mvt.
"sources": {
  "terrain":  { "type": "dem", "encoding": "terrarium",
                 "url": "https://terrain.reearth.land/mapterhorn-egm08/terrarium/ellipsoid/{z}/{x}/{y}.webp",
                 "tile-size": 512, "max-zoom": 14 },
  "basemap":  { "type": "mvt",
                 "url": "https://example.com/tiles/{z}/{x}/{y}.pbf" }
}

For mvt / pmtiles, the source key (basemap above) is a label — bindings still use the layer names from the decoded tile. Declare only one MVT-flavoured source per style; later entries are ignored.

Types

pub struct Document {
    pub name: String,
    pub tile_size: u32,
    pub pad: u32,
    pub params: IndexMap<String, ParamDecl>,
    /// Document- and tile-scoped external data: brushes, images,
    /// MVT / PMTiles / DEM pyramids.
    pub sources: IndexMap<String, SourceDecl>,
    pub nodes: IndexMap<String, NodeSpec>,
    pub output: NodeRef,
}
pub struct NodeSpec { pub op: String, pub fields: serde_json::Map<String, Value> }
pub type FeatureFilter = HashMap<String, FilterMatch>;
pub enum FilterMatch { One(FilterAtom), Any(Vec<FilterAtom>) }
pub enum FilterAtom { Bool, Int, Float, Str }

Example

let doc = ezu_style::Document::from_json(&json_text)?;
println!("{} ({} nodes)", doc.name, doc.nodes.len());

License

MIT or Apache-2.0, at your option.