# Material graphs

> Build animated and procedural surfaces by wiring typed nodes into a material, starting from ready-made templates.

Source: https://feather-engine.com/docs/rendering/material-graphs/

A material asset can carry a typed node graph. The graph computes the surface's base colour,
roughness, metallic, emission, opacity and a vertex offset, and compiles to a shader. The editor,
the command API, validation, previews and the runtime all use the same graph and the same compiler,
so a graph built by hand and one built by an agent behave identically.

Materials without a graph keep the standard or toon path described in
[Materials](/docs/rendering/materials/).

## Start from a template

1. Open **Window → Materials & textures** and select the **Material Graph** tab.
2. Select a material, or click **+ New graph material**.
3. Open **Templates ▾** and choose a template.
4. Assign the material to objects as usual.

Applying a template replaces the material's graph and sets the matching surface defaults (alpha,
roughness, two-sided rendering and shading) in one undo step.

| Template | Result |
| --- | --- |
| Toon Basic | Constant colour and roughness with toon surface settings |
| Facade Windows | A window grid on walls, with some windows lit warm at night (Windows, Night) |
| Glowing Crystal | A rim glow (Fresnel Glow) |
| Dissolve | World-space noise animated over time |
| Hologram | Animated scan lines (Scanline) |
| Stylized Water | Animated world-space noise |
| Wind Foliage | Vertex sway (Wind Sway) |
| Lava | Animated world-space noise |

**Clear graph** removes the graph and returns the material to the standard path. **Fit graph** frames
every node on the canvas.

## Edit a graph

The workspace has the node palette on the left, the canvas in the centre, and a large live preview
with the inspector and diagnostics on the right.

1. Find a node in the **Node palette**, or type in **Search nodes…**. **Fresnel Glow** and **Wind
   Sway** are pinned as quick effect nodes.
2. Add the node and drag it into place. Pan and zoom the canvas to navigate.
3. Drag from an output pin to an input pin of the same type. Connecting to an input that already has
   a wire replaces the old wire.
4. Select a node to edit its values in the inspector.

Pins and wires are colour-coded by type: Float, Vector2, Vector3 and Color. Every node shows a small
preview, and the large preview renders the material with its compiled shader. The status line shows
**Compiled** with the node count and shader size, or **Compile error** with the reason.

Every canvas edit goes through the same commands agents use, so each one is a single undo step and an
invalid edit is rejected without changing the project.

## Material Output

Each graph has exactly one **Material Output** node. Unconnected inputs keep the material's own
values.

| Input | Type | Description |
| --- | --- | --- |
| Base Color | Color | Surface colour |
| Roughness | Float | |
| Metallic | Float | |
| Emissive | Color | Emitted light |
| Opacity | Float | Used with the Cutout and Transparent alpha modes |
| World Position Offset | Vector3 | Moves vertices, for wind and waves |

## Node reference

| Group | Node | Outputs | Description |
| --- | --- | --- | --- |
| Constants | Scalar | Value | A float constant |
| Constants | Color | Color | An sRGB colour constant |
| Constants | Vector 2, Vector 3 | Vector | Vector constants |
| Inputs | Base Color | Color | The material's colour and base texture after sampling |
| Inputs | Texture Coordinates | UV | Mesh UVs after the material's UV tiling |
| Inputs | World Position | Position | Position in world metres |
| Inputs | Surface Normal | Normal | World-space normal |
| Inputs | Time | Seconds | Elapsed game time |
| Inputs | Night | Value | 0 in daylight, 1 at night, smooth through dusk and dawn |
| Math | Add, Subtract, Multiply, Divide, Lerp | Result | Typed as Float, Vector2, Vector3 or Color. Divide is safe against zero. Lerp blends A to B by Alpha |
| Math | Sine, One Minus | Result | Float operations |
| Math | Clamp | Result | Clamps a float between `min` and `max` |
| Math | Power | Result | Raises a non-negative float to `exponent` (0.01–32) |
| Math | Smoothstep | Result | Smooth threshold between `low` and `high` |
| Math | Posterize | Result | Quantizes a float into `steps` bands (2–32) |
| Effects | Noise | Value | Animated, seamless value noise in world space; `scale`, `speed` |
| Effects | Scanline | Value | Animated horizontal scan lines; `scale`, `speed`, `width` |
| Effects | Windows | Glass, Lit | A window grid on walls in world metres, none on roofs. Glass masks the panes; Lit picks windows to glow at night |
| Effects | Colorize | Color | Multiplies a colour by a float mask |
| Effects | Fresnel Glow | Color | Rim glow; `color`, `power`, `strength` |
| Effects | Wind Sway | Offset | World-position offset for foliage and cloth-like surfaces; `direction`, `strength`, `speed`, `scale` |

Fresnel Glow and Wind Sway have defaults on their optional inputs, so you can wire only their result.
Time, Noise, Scanline and Wind Sway animate from a per-material clock. Combine **Night** with
**Windows → Lit** and **Emissive** to light buildings after dark.

## Runtime behaviour

Each graph material compiles to one shader. It keeps the material's textures, alpha mode and
lighting, and applies the graph's outputs on top. A graph takes precedence over a toon shading
setting; clearing the graph restores the normal path. Invalid graphs are reported during validation
and never reach the renderer.

## Limits

- Up to 96 nodes and 192 wires per graph.
- Generated shader code is limited to 64 KiB.
- Each input takes one wire, pin types must match exactly, and cycles are rejected.
- Disconnected nodes are allowed, so you can build a graph step by step.

## Automate it

Create a material from a template, add a Fresnel Glow node, and wire it into the emission. Use the
material ID and node ID that each command returns:

```bash
feather-cli --connect .feather-session.json command material.create \
  --json '{"name":"Crystal","graph_template":"Glowing Crystal"}'

feather-cli --connect .feather-session.json command material.add_node \
  --json '{"id":1,"operation":{"type":"FresnelGlow","color":[0.2,0.8,1.0],"power":2.5,"strength":4.0},"position":[280,160]}'

feather-cli --connect .feather-session.json command material.connect \
  --json '{"id":1,"from":20,"from_pin":"Color","to":1,"to_pin":"Emissive"}'
```

| Command | Purpose |
| --- | --- |
| `material.nodes` | Lists the node palette with operation JSON, typed pins and templates; filter with `query` or `group` |
| `material.get` | With `id`, returns the graph, each node's typed pins, the compiled WGSL and diagnostics |
| `material.add_node` | Adds a node; creates the Material Output graph when absent |
| `material.set_node` | Changes a node's operation or position; wires to removed pins are dropped |
| `material.connect` | Wires an output pin to an input pin of the same type |
| `material.disconnect` | Removes a wire by `edge`, or the wires on a `node` and optional `pin` |
| `material.remove_node` | Removes a node and its wires; the Material Output cannot be removed |
| `material.create` / `material.update` | Apply a `graph_template`, or replace the whole `graph` |

See [Agents & automation](/docs/agents/overview/) for connecting a live session.
