nika:image_fx is the deterministic sibling of
nika:image_generate: a pure pixel transform —
no provider, no network, no clock. Style a PNG through an ordered pipeline of
effects and get an artifact that is byte-identical forever for identical
(input, args).
That determinism is the point, not a detail. The artifact’s sha256 joins the
run’s hash-chained trace, re-rendering the recipe is the tamper check, and the
full recipe (contract tag image_fx/v1 · input sha256 · seed · ops) travels
inside the PNG as a nika tEXt chunk — no timestamp, ever. Your workflow
draws its own receipts.
The 30-second pipeline
skipped_existing: true and the artifact
hash never moves. Mutate one byte of the PNG and a re-render no longer matches
— that mismatch is the tamper detection.
The op vocabulary (closed · v1)
ops: is an ordered list of single-key maps — a linear pipeline by design.
Branching and fan-out belong to the workflow (with:/after: edges ·
for_each), never inside the builtin.
Palettes: presets
bw · gray4 · gameboy · cga · okabe_ito, or an inline list
of 2–256 colors. Unknown op parameters are rejected loudly
(NIKA-BUILTIN-IMAGE_FX-001) — a typo’d knob never silently lies about the
style.
Why deterministic styling matters
Every incumbent styling path is nondeterministic by default — image tools timestamp their outputs, and generative models can’t reproduce bytes across hardware at all. That makes styled assets un-verifiable: you can sign them, but you can’t re-derive them.image_fx inverts that: integer/fixed-point pixel math, a seeded noise
stream, zero wall-clock. So the artifact can be:
- chained — its sha256 lands in the trace (
nika trace verifycovers it); - re-rendered — the same input + the recipe reproduces the exact bytes;
- carried — the recipe rides the artifact itself, so any holder of the input can verify the styling.
for_each and every one of them is a receipt.
Output contract
ascii with
emit: text|ansi) land as .txt/.ans, report width/height 0, and are
sha256’d like any other artifact.
Errors are typed NIKA-BUILTIN-IMAGE_FX-001..006 — invalid args · input read
· unsupported format · decode · pixel budget · save — plus the boundary
NIKA-SEC-004 when a path resolves outside permits.fs.