# Post effects

Source: https://www.ascii-magic.com/docs/effects (ASCII Magic documentation)

28 passes applied after the style has drawn. 16 are free, 12 need Pro.

A post effect never changes the style. It runs on the frame the style produced, which is why switching styles keeps your effect stack intact, and why an effect that depends on a glyph grid does nothing on a style that has no glyphs.

_The stack is a fixed pipeline, not a layer list. Switching an effect on inserts it at its own position in the sequence, wherever you turned it on._

## They stack in a fixed order

Not the order you switched them on. Every render walks the same sequence:

1. **Colour overlay, then greyscale** Tone is flattened before anything textures it.
2. **Blur** Runs early so later grain and dust stay sharp on top of it.
3. **Vignette, scan lines, bloom** The lighting pass.
4. **Chromatic, RGB split, CRT curve, glitch, film grain** The signal pass.
5. **Pixelate, halftone** Re-rasterising passes, so they quantise everything above them.
6. **The warps: pinch, spherize, twirl, ripple, zigzag, polar, shear** Geometry moves after the texture is in place, so the texture warps with it.
7. **Reduce noise, diffuse, threshold, fragment, ASCII** The reduction pass.
8. **Film dust, sharpen, noise** Final surface detail, applied over everything.
9. **Saturation and hue, then Levels, then Curves** The grade, on the finished frame.
10. **The text layer** Always last, so a caption is never pushed through a tone curve.

> **Note:** Character Bloom and Character Chromatic are the two exceptions. They are drawn per glyph while the character grid is painted, not as a pass over the finished frame, so they exist only for glyph modes and cannot be reordered.

## Every effect

Ranges are the slider bounds the panel enforces. A control with no range is a toggle, a colour or a select, and its options are listed.

| Effect | Key | Tier | Controls |
|---|---|---|---|
| Vignette | `vignette` | Free | `center` (xy), `intensity` 0 to 100, `size` 0 to 100, `feather` 0 to 100, `roundness` 0 to 100, `shape` (round), `color` (color) |
| Scan Lines | `scanLines` | Free | `intensity` 0 to 100, `spacing` 1 to 10, `thickness` 1 to 6, `color` (color) |
| CRT Curvature | `crtCurve` | Free | `intensity` 0 to 100 |
| Chromatic | `chromatic` | Free | `center` (xy), `offset` 1 to 40, `angle` 0 to 360, `radial` 0 to 100 |
| Bloom | `bloom` | Free | `spotlight` (xy), `spotlightR` 0 to 100, `threshold` 0 to 100, `intensity` 0 to 100, `blur` 0 to 100, `spread` 0 to 100, `glow` 0 to 100, `tint` (color), `tintAmount` 0 to 100, `vignette` 0 to 100, `vignetteSoftness` 0 to 100 |
| Character Bloom | `charBloom` | Free | `intensity` 0 to 100 |
| Character Chromatic | `charChroma` | Free | `offset` 1 to 20 |
| Film Grain | `filmGrain` | Free | `intensity` 0 to 100, `colour` 0 to 100 |
| Glitch | `glitch` | Free | `intensity` 0 to 100, `sliceMax` 2 to 80, `rgb` 0 to 100 |
| RGB Split | `rgbSplit` | Free | `offset` 1 to 20 |
| Pixelate | `pixelate` | Free | `size` 2 to 30 |
| Halftone | `halftone` | Free | `size` 2 to 20, `shape` (dots), `colour` (source) |
| ASCII | `ascii` | Pro | `charset` (forensic), `size` 4 to 64, `color` (source), `invert` (select) |
| Diffuse | `diffuse` | Pro | `amount` 0 to 100, `mode` (normal) |
| Threshold | `threshold` | Pro | `cutoff` 0 to 100, `smoothness` 0 to 100 |
| Reduce Noise | `reduceNoise` | Pro | `amount` 0 to 100, `radius` (select) |
| Pinch | `pinch` | Pro | `amount` -150 to 150, `radius` 10 to 150, `centerX` 0 to 100, `centerY` 0 to 100 |
| Spherize | `spherize` | Pro | `amount` -150 to 150, `radius` 10 to 150, `centerX` 0 to 100, `centerY` 0 to 100 |
| Twirl | `twirl` | Pro | `amount` -300 to 300, `radius` 10 to 150, `centerX` 0 to 100, `centerY` 0 to 100 |
| ZigZag | `ripple` | Pro | `amount` 0 to 100, `wavelength` 5 to 100 |
| Ripple | `zigzag` | Pro | `amount` 0 to 100, `ridges` 1 to 20, `radius` 10 to 150, `centerX` 0 to 100, `centerY` 0 to 100 |
| Polar | `polar` | Pro | `mode` (rect2polar), `rotation` 0 to 100 |
| Shear | `shear` | Pro | `amount` -100 to 100, `period` 25 to 300 |
| Fragment | `fragment` | Pro | `offset` 1 to 40, `copies` 2 to 8 |
| Film Dust | `filmDust` | Free | `density` 0 to 100 |
| Noise | `noise` | Free | `amount` 0 to 100, `size` 1 to 10, `colour` 0 to 100 |
| Sharpen | `sharpen` | Free | `amount` 0 to 100 |
| Blur | `advBlur` | Free | `type` (gaussian), `amount` 0 to 100, `focus` 0 to 100, `progNear` 0 to 100, `progFar` 0 to 100, `progAngle` 0 to 360 |

> **Warning:** Two of the warps carry each other's name in the interface. The effect keyed `ripple` is labelled ZigZag and takes Amount and Wavelength. The effect keyed `zigzag` is labelled Ripple and takes Amount, Ridges, Radius and a centre. The labels are swapped relative to the keys, so a recipe that reads `ripple` is the one the editor called ZigZag. Match on the key, not the label.

## Everything scales with the export

Blur radii, scan-line spacing, chromatic offsets, pixelate and halftone cell size, glitch slice height and ASCII cell size are all multiplied by the export scale. A 4x render looks like the preview at four times the size, not like the preview with four times finer grain.

The practical consequence: judge an effect at the preview size and trust it. You do not need to re-tune after choosing an export scale.

## Levels and Curves

Both are Pro, and both sit slightly apart from the other 28 because they are tone grades rather than effect slices. They run on the finished frame, before the text layer, so they grade the rendered art and not the source image.

**Levels** is the Photoshop panel. An input pair picks the slice of the range that survives, gamma bends the midtones inside that slice, and an output pair says which range the slice prints into. It runs per channel or on the composite.

**Curves** is one tone curve per channel plus a composite curve applied last, matching Photoshop's order. The interpolation is monotone by design, so a curve can never overshoot and posterise a band into the image no matter how hard you pull a control point.

## The text layer

Drawn last, on top of everything, so it stays crisp instead of being dissolved into glyphs. Position and size are stored as fractions of the frame rather than pixels, so a caption placed on the preview lands in the same place on a 4x export.

## Reading an effect stack back

A recipe carries the whole stack by key, with only the values that differ from the effect's defaults. Decoding one is the reliable way to see exactly what a look turned on:

`What a decoded stack looks like`
```json
{
  "renderMode": "halftone",
  "postFx": {
    "filmGrain": { "intensity": 20 },
    "vignette": true
  }
}
```

Over MCP the same shape goes in through `post_fx`, where `true` switches an effect on at its defaults and `false` switches it off. See [the tools reference](https://www.ascii-magic.com/docs/mcp-tools).
