showcase · tier 1 · content
Image FX batch
glob lists the folder, for_each styles every photo through the same deterministic ops chain: no model, pure pixels.
The whole file
2 tasks · 2 waves · the plan falls out of the bindings, nothing is scheduled by hand.
t1-image-fx-batch.nika.yamlsource
nika: v1workflow: id: image-fx-batch description: "Folder of PNG files → deterministic art (grayscale · dither · pixelate) · offline batch"vars: photos: "./photos" # the input folder · every .png in it gets the treatmentpermits: exec: false fs: # a RELATIVE glob walks from `.` (the engine gates the walk root), so # the read boundary is the cwd subtree — and `const.photos` is caller- # overridable, so no narrower literal glob can be proven to cover it. # Fixing the folder? Tighten this to `photos/**`. The write stays tight read: ["**"] write: ["out/**"] tools: ["nika:glob", "nika:image_fx"]tasks: # The folder is the work list — no hand-maintained array to drift. shots: invoke: tool: "nika:glob" args: { pattern: "${{ vars.photos }}/*.png" } # One deterministic darkroom pass per photo · the ops run IN ORDER. stylize: with: shots: ${{ tasks.shots.output }} for_each: ${{ with.shots }} max_parallel: 4 invoke: tool: "nika:image_fx" args: input: "${{ item }}" ops: - grayscale: {} - dither: { mode: bayer4 } - pixelate: { block: 4 } out: "out/${{ item }}"outputs: rendered: # an empty ./photos skips the fan-out (its output is null) — the guard # keeps the typed contract honest on the very first exploratory run value: "${{ tasks.stylize.output != null ? tasks.stylize.output : [] }}" description: "The stylized artifact receipts · one per input photo"nika inspect · engine 0.105.0 · vendored graph, never re-derived
1 declared edge · 2 waves · the plan falls out of the bindings