Skip to main content
T1 fan-out · creators / media: nika:glob lists the folder, for_each fans one nika:image_fx task per photo, and a fixed ops chain (grayscale → dither → pixelate) renders each one. No model in the loop — the pipeline is pure pixels, so the same input produces the same bytes on every run, on every machine.

The job

Batch-stylizing a shoot means opening an editor, replaying the same five clicks per photo, and hoping you replayed them identically. This workflow IS the preset: the ops chain is written once in YAML, the batch fans out in parallel, and re-running it a year from now yields byte-identical output — the style is version-controlled with your repo.

The shape

The file

image-fx-batch.nika.yaml

Two things this file teaches

  1. The ops vocabulary is a closed setdither: { mode: bayer4 } is one of the engine’s named modes; misspell it (bayer) and nika check answers with the whole legal set instead of guessing. The checker teaches the vocabulary before the run spends a cycle.
  2. A fan-out that can produce nothing still binds — the collect step guards with ${{ tasks.stylize.output != null ? … : [] }} (quoted, because a bare CEL ternary contains : and YAML would claim it). An empty folder degrades to an empty manifest, not a crash.

Run it

The 0.107 pack embeds this workflow: nika new image-fx-batch <dest> lands the file verbatim with its ingredients (the two sample photos, at the exact relative path the yaml names). Proven against the released 0.107.0: the taken copy runs offline end-to-end — 3/3 done · $0.00, two renders in out/darkroom/.
Point const.photos at any directory of PNG files. Because every op is deterministic, the diff of out/darkroom/ across two runs is empty — which makes the output safe to commit, and the workflow safe to put in CI.