Blend Modes
Every source node in the chain has a blend mode that controls how its pixels combine with the current accumulator. The math below uses src for the incoming source value and dst for the value already in the accumulator.
Mode reference
| Mode | Formula | Effect | Typical use |
|---|---|---|---|
over | result = src | Source replaces the accumulator (modulated by opacity). | Default — simple layering on top of whatever is below. |
add | result = min(1, src + dst) | Strong brighten, clips at 1.0. | Glows, lasers, sparkles, additive particles. Pairs well with bloom. |
multiply | result = src * dst | Darkens and tints. | Colour grading, shadows, ink effects. |
screen | result = 1 - (1 - src) * (1 - dst) | Brightens without the hard clip of add. | Light leaks, atmospheric fog, soft luminance boosts. |
overlay | result = dst < 0.5 ? 2*dst*src : 1 - 2*(1-dst)*(1-src) | Multiplies darks and screens lights — contrast boost. | Adding texture to a flat base while keeping its structure legible. |
softlight | result = (1 - 2*src) * dst² + 2*src*dst | Gentler contrast lift than overlay. | Subtle highlighting where overlay is too aggressive. |
dodge | result = min(dst / max(1 - src, 0.001), 1) | The most aggressive brighten mode. | Hot cores, seed layers for bloom, extreme brightening at low opacity. |
difference | result = abs(dst - src) | Absolute difference per channel — subtractive, colour-inverting. | High-contrast psychedelic effects. Dramatic on motion. |
exclusion | result = dst + src - 2 * dst * src | Softer colour-inverting effect than difference. | Muted psychedelic looks where difference is too harsh. |
Per-mode detail
over — Over
result = srcEffect: Source replaces the accumulator (modulated by opacity).
Use: Default — simple layering on top of whatever is below.
add — Add
result = min(1, src + dst)Effect: Strong brighten, clips at 1.0.
Use: Glows, lasers, sparkles, additive particles. Pairs well with bloom.
multiply — Multiply
result = src * dstEffect: Darkens and tints.
Use: Colour grading, shadows, ink effects.
screen — Screen
result = 1 - (1 - src) * (1 - dst)Effect: Brightens without the hard clip of add.
Use: Light leaks, atmospheric fog, soft luminance boosts.
overlay — Overlay
result = dst < 0.5 ? 2*dst*src : 1 - 2*(1-dst)*(1-src)Effect: Multiplies darks and screens lights — contrast boost.
Use: Adding texture to a flat base while keeping its structure legible.
softlight — Soft Light
result = (1 - 2*src) * dst² + 2*src*dstEffect: Gentler contrast lift than overlay.
Use: Subtle highlighting where overlay is too aggressive.
dodge — Dodge
result = min(dst / max(1 - src, 0.001), 1)Effect: The most aggressive brighten mode.
Use: Hot cores, seed layers for bloom, extreme brightening at low opacity.
difference — Difference
result = abs(dst - src)Effect: Absolute difference per channel — subtractive, colour-inverting.
Use: High-contrast psychedelic effects. Dramatic on motion.
exclusion — Exclusion
result = dst + src - 2 * dst * srcEffect: Softer colour-inverting effect than difference.
Use: Muted psychedelic looks where difference is too harsh.
Implementation
These formulas live in packages/engine/src/chain/blend.ts as pure TypeScript functions used by the engine’s unit tests to verify correctness. The actual blending in the render pipeline happens in GLSL inside graphics/src/BlendCompositor.ts. The two are kept in lockstep: any change to one must match the other, and the test suite verifies agreement at a sample of input values.
Related
- The Chain Model — how blend modes fit into the accumulator pipeline.
- How the Chain Works — the hands-on version of chain compositing, including blend mode selection.