← All text IRs

NIR

Read as text Niagara graphs

A Niagara system is a binary node graph — emitters, module stacks, renderers, parameter stores, simulation stages and per-node script wiring — that you can only really read by opening the Niagara editor and clicking through emitter after emitter. NIR decompiles that same asset into compact, line-based text: the system and its emitters, every module row in stack order with its resolved inputs, the renderers, and the underlying script graphs written out node by node. It reads the graph out to text for review and AI context; compiling text back into the asset is a planned follow-up, not something it does today.

Why it matters

Diffable in version control

An emitter tweak becomes a handful of readable lines you can diff between revisions instead of an opaque .uasset no reviewer can open in a pull request. The same text lands in the asset-dump cache as nir.txt, so git log -p and grep both work on it.

Reviewable like code

Module stacks read top to bottom in execution order, each input resolved to a literal, a linked parameter like $User.Speed, or a nested dynamic input — so you audit what an emitter actually does without tracing pins across the canvas by eye.

A format an AI can actually read

Your assistant gets the whole system as text in one call — emitters, stacks, renderers, and the node-by-node script bodies — so it can answer questions and reason about the effect instead of poking at the graph blind.

Faithful and deterministic

The RPC and the nir.txt sidecar both call the same decompiler, so on-disk text and live output are byte-identical. Any node class outside the known set is surfaced as # unknown-node with a matching warning rather than silently dropped.

A taste

A system block names exposed param values, then nests an emitter per handle. Inside each emitter, module rows carry their stack order and enabled state, and each input resolves to a literal, a linked $-parameter, or a nested dynamic input:

system "NS_ThrusterExhaust" {
    param User.SpawnRate : Float = 12.0 @scope user
    emitter "Exhaust" {
        simTarget CPUSim
        stack ParticleSpawn {
            module InitializeParticle @0 enabled
                input Lifetime = 2.0
                input Color = $User.Color
            module AddVelocity @1 enabled
                input Velocity = dynamic NoiseClamp { input Range = 0.5 }
        }
        renderer Sprite
    }
}

Standalone scripts, simulation stages and event handlers additionally expand into a graph <Usage> { ... } body of node identity lines and explicit link From.Pin -> To.Pin wiring, so the per-node data flow is inspectable, not just the stack.

How your assistant uses it

It reads the current system out as text with niagara.decompile_nir — a single call that returns the whole system, emitters and script bodies for review or context. This IR is decompile-only, so the flow is read and reason, never write:

You: What does NS_ThrusterExhaust spawn, and at what rate?

  call("niagara.decompile_nir", {assetPath:"/Game/FX/NS_ThrusterExhaust"})
    → {ir:"system \"NS_ThrusterExhaust\" {\n  param User.SpawnRate : Float = 12.0 ... }"}

One CPU sprite emitter at 12/sec, 2s lifetime, with noise-clamped velocity.
Early Access. NIR is decompile-only today — it reads Niagara systems, emitters and scripts out to text for review and AI context; compiling text back into the asset is a future follow-up. Positions are recorded as @(x, y) for traceability, but equivalence is logical, not visual, and referenced module scripts are emitted as path references rather than expanded inline.

← Back to all text IRs