/Phlux language Live examples Reference Recipes Try in browser
The language behind Phluxel

Phlux.
One line per cell.

Phlux is a tiny rule language for cellular automata. A rule answers exactly one question — given this cell and its neighbors right now, what should this cell become next step? Write that as an assignment to a color channel, and the grid does the rest.

your first rule Phlux
R = {AVG, (-1:1,-1:1).R}   // red spreads to its neighbors. that's a rule.
live · running in your browser

What Phlux is

Not a general-purpose language. Phlux does one thing: it describes how a grid of cells changes, one step at a time. That narrowness is the point — the useful rules are one to five lines long, and you can read someone else's rule in about as long as it takes to read a sentence.

🎨

The picture is the state

There is no separate simulation buffer hiding behind the canvas. Each cell's R G B A channels are its state, in the 0–255 range. Paint a pixel and you have edited the simulation.

👀

A cell can only look nearby

Read yourself with R, a neighbor with N.R, a whole region with {AVG, MOORE.R}. Everything complex on this page comes out of local reads — no cell has a view of the whole grid.

Simple rules go to the GPU

Rules that only use channels, maths and area reductions compile to a shader automatically. Reach for randomness, functions or scatter and it falls back to the CPU — same result, just slower on big grids.

Six rules, actually running

Every animation below is being computed in your browser right now from the rule printed underneath it — these are not recorded GIFs. Each is the complete rule, not an excerpt.

GPU

Game of Life

The classic, in two lines. MOORE is the 8 surrounding cells, so COUNTNZ is literally "how many neighbors are alive".

life.phlux
LET _n = {COUNTNZ, MOORE.R}
_n == 3 | (_n == 2 & R > 0)
  ? [255,255,255,255] : [255,0,0,0]
CPU

Rain over your artwork

Spawn drops along the top edge, move them down, and let BASE — the original untouched pixel — restore the scene behind them.

rain.phlux
PARAM _rate = 6
Y == 0 ? (RN < _rate ? [255,90,150,255] : [BASE]) :
(N.B > 230 & N.R < 120 ? [255,90,150,255] :
(B > 230 & R < 120 ? [BASE]))
GPU

Reaction–diffusion

Gray–Scott, with the two chemicals living in R and G. The bracketed term is the discrete Laplacian.

coral.phlux
LET _f = (255 - R) * G * G / 65025
R = R + .2 * (N.R+S.R+E.R+W.R - R*4) + _f - .035*R
G = G + .1 * (N.G+S.G+E.G+W.G - G*4) + _f - .095*G
B = {SAT, 70 - R - G}
CPU

Wave interference

A wave needs to know where it was, so G is used as a time-delay buffer: it holds R from one step ago.

wave.phlux
LET _r = R - 128
LET _p = G - 128
LET _l = N.R+S.R+E.R+W.R - 4*R
LET _n = (2*_r - _p + .4*_l) * .9985
G = R
R = {SAT, _n + 128}
B = {SAT, 128 + (_r - _p) * 3.5}
CPU

Sandpile SCATTER

Most rules only write to themselves. N.R += writes into a neighbor — so a toppling pile pushes grains outward.

sandpile.phlux
LET _t = {FLOOR, R / 256}
_t > 0 ? N.R += _t * 64
_t > 0 ? S.R += _t * 64
_t > 0 ? E.R += _t * 64
_t > 0 ? W.R += _t * 64
R = R - _t * 256
CPU

Inherited color

An empty cell takes the mean color of its living neighbors plus a small mutation. Color becomes a heritable trait, and lineages drift apart.

lichen.phlux
LET _v = {COUNTNZ, MOORE.R}
LET _r = {SUM, MOORE.R} / _v
LET _g = {SUM, MOORE.G} / _v
LET _b = {SUM, MOORE.B} / _v
R+G+B < 40 & _v > 0 & RN < 24 ?
  [255, _r + RN*.22 - 28,
        _g + RN*.22 - 28,
        _b + RN*.22 - 28]

Why the browser versions look slightly different. These canvases are a small JavaScript re-implementation written for this page. The real engine runs at 16-bit precision per channel and on much larger grids, so a rule that decays slowly will hold detail there that gets crushed here. The browser demo runs the actual engine.

What people actually build with it

Phlux started as a way to animate pixel art without drawing frames, and grew into a general cellular-automata language. Both uses are first class.

Game & sprite effects

  • Rain, snow and ash that fall behind your art
  • Fire, smoke, embers and heat shimmer
  • Hit flashes, dissolves, freeze and burn
  • Water ripples and reflective surfaces
  • Glow, bloom and neon flicker

Classical automata

  • Life-like rules — any B/S notation
  • Cyclic CA and excitable media
  • Brian's Brain, Seeds, Day & Night
  • Abelian sandpiles and avalanches
  • Langton-style growth and dendrites

Generative art

  • Reaction–diffusion — Gray–Scott, Turing
  • Belousov–Zhabotinsky spiral waves
  • Multi-scale pattern formation
  • Color inheritance and genetic drift
  • Flow fields and noise-driven texture

Image processing

  • Blur, sharpen, edge detect, median
  • Dilation, erosion and other morphology
  • Palette shifts and channel remaps
  • Feedback trails and motion smear
  • Dithering and stylised downsampling

Want to see finished pieces rather than rules? Browse 62 animated examples →

The language, A to Z

This is all of it. Phlux has no imports, no classes, no loops and no I/O — the grid loop is the program, and your rule is its body.

01 Channels

Every cell holds four values in the 0–255 range. Reading gives the current value; assigning sets what the cell becomes next step.

TokenMeaning
R G B ARed, green, blue and alpha of this cell.
channels
R = G          // copy green into red
A = 255        // force fully opaque

Channels are just numbers. Nothing forces them to mean color. Use G as a velocity, an age counter, a chemical concentration or a previous frame — several examples on this page do exactly that.

02 Neighbors

Prefix a channel with a direction to read the cell next door.

TokenOffsetTokenOffset
N(0, −1)NE(+1, −1)
S(0, +1)NW(−1, −1)
E(+1, 0)SE(+1, +1)
W(−1, 0)SW(−1, +1)
FormMeaning
(dx, dy).RRelative offset — (2,-1).R is two right, one up.
[x, y].RAbsolute coordinate.
BASE.RThis cell's original value — what Reset restores.
TAGThe cell's painted tag, 0–15. A label you can branch on.

Out-of-bounds neighbors read as the edge, unless wrap (toroidal) is on — then they come from the opposite side.

03 Special tokens

TokenMeaning
X YThis cell's coordinate. R = X is a gradient.
GW GHGrid width and height, for normalized coordinates.
TICKThe step counter, 0, 1, 2 … Reset returns it to 0. Drives time-based animation.
RNA fresh random 0–255, per cell, per step. Seedable for reproducibility.
BASEThe original design state of this cell.
time and chance
R = {WAVE255, TICK * .2}     // pulse without drawing frames
RN < 3 ? G = 255              // ~1% of cells light up each step

04 Operators

operators
arithmetic   +  -  *  /  %(mod)  ^(power)  $(root)    unary minus: -R
compare      ==  !=  <  >  <=  >=
logical      & (and)   | (or)   ! (not)
group        ( … )

Comparisons return 1 or 0, so they work directly in arithmetic — R = R * (G > 128) zeroes red unless green is bright.

Two things that bite people. Unary minus binds tighter than ^, so -2 ^ 2 is 4, not −4. And division or mod by zero yields 0, not infinity or NaN — deliberately, so a rule can't poison a grid with NaN.

05 Assignment & statements

FormMeaning
R = exprSet the channel.
R += / -= / *=Compound assignment. R *= .95 is a fade.
[A, R, G, B]Color literal — assign the whole cell at once. An empty slot keeps the current value.
[BASE]Restore the entire original cell.
[{SAMPLEC, dx, dy}]Read the whole current pixel at an offset — this is what makes feedback trails possible.
a ; bSeveral statements. A newline separates them too, so ; is optional at line ends.
// commentTo end of line.

06 Conditions

The ternary ? : works two ways — as a value inside an expression, and as a statement whose branches do something.

both forms
R = R > 128 ? 255 : 0                     // value form
R > 128 ? [255,255,255,255] : [255,0,0,0]  // statement form
RN < 3 ? G = 255                           // else is optional

Omit the : and cells that fail the test are simply left unchanged. Nest by parenthesising a branch: a ? x : (b ? y : z).

07 Areas & folds

An area selector scans a rectangle of neighbors.

SelectorMeaning
(-1:1, -1:1)A 3×3 block centered on this cell.
(-2:2, 0:0)A horizontal line of 5 cells.
MOOREThe 8 surrounding cells — the 3×3 block without this one.

That last one is what life-like automata mean by "my neighbors", so the classic live count is simply:

neighbor count
LET _n = {COUNTNZ, MOORE.R}

The terse prefixes +area.R (sum), #area.R (count) and -area.R (range) exist as shorthand, but the named functions below read better and compile to the GPU just the same.

08 Functions

Call as {NAME, arg, …}.

Over an area

FunctionMeaning
{AVG, a.ch}Average — blur, smoothing.
{SUM, a.ch} {COUNT, a}Sum, and number of cells.
{COUNTNZ, a.ch}Count of non-zero cells — alive neighbors.
{MIN, a.ch} {MAX, a.ch}Extremes. Morphology: erosion and dilation.
{RANGE, a.ch}max − min — edge strength.
{MEDIAN, a.ch}Median — removes salt-and-pepper noise.
{STDDEV, a.ch} {VAR, a.ch}Spread — texture and edge detection.
{LAPLACE, a.ch}Discrete Laplacian — diffusion.

Maths & helpers

GroupFunctions
RangeCLAMP SAT SAT01 LERP MIX REMAP REMAP01
NumericMIN MAX ABS SIGN FLOOR CEIL ROUND FRAC
PowerSQRT SQ POW EXP LOG
TrigSIN COS TAN ATAN2 RAD DEG
ShapingSTEP SMOOTH SIGMOID GAIN GAMMA THRESHOLD PULSE
ColorLUMA INVERT BRIGHTEN OVER SCREEN MULT ADDSAT
SpaceDIST LEN MANHATTAN NOISE NOISE255
TimingSAW PINGPONG PROG EASEIN EASEOUT EASEINOUT IMPULSE SWING
SpriteSAMPLE SAMPLEC ROTDX ROTDY SCALEDX SCALEDY

You can define your own with the same {NAME, …} syntax, either globally or per project.

09 Scatter — writing to other cells

Normally a rule writes only to itself. Scatter lets a cell deposit into its neighbors. Only += and -= are allowed: many cells may target the same place, so deposits accumulate, which keeps the result order-independent and deterministic.

scatter
N.R += R * .5              // push half my red upward
(1,1).G += 10             // into the cell down-right
N.G += 60 WHERE R < 25   // only if the RECEIVING cell is dark

This is the one construct that inverts the usual direction of a cellular automaton, and it is what makes falling sand, particle deposition and flow accumulation expressible.

10 LET and PARAM

LET freezes a value for the rest of this cell's evaluation — essential when you use RN twice and need the same number both times, or when several channels must read the same snapshot.

locals and knobs
LET _n = {COUNTNZ, MOORE.R}   // compute once, use many times
_v = 12                          // LET is optional for _names
PARAM _rate = 5                 // a live knob with a default

PARAM is the same thing with a dial attached: it appears as a slider while the simulation runs, and the timeline can keyframe and interpolate it — so rain can get heavier over a loop without touching the rule.

11 GPU vs CPU

You never choose. A rule compiles to a shader when it can, and silently falls back otherwise — the result is the same either way.

Runs on GPUFalls back to CPU
Channels, neighbors, mathsRN randomness
Conditions and color literalsScatter
Area reductions — AVG SUM COUNT COUNTNZ MIN MAX RANGEBASE, LET, PARAM, TAG
Folds and wrapMEDIAN, STDDEV, LAPLACE, user functions

The precision difference is real. The GPU path is 8 bits per channel per step, so R = R * 0.98 reaches zero much faster there than on the 16-bit CPU path. For slow decays, that difference is visible.

12 Global vs per-cell rules

A rule is either global — it runs on every cell in the grid — or it is painted onto specific cells with the rule brush and runs only there. Sweeping effects like weather are global; a rule that makes one torch flicker is not.

A rule can also carry a separate condition that gates it entirely, which is often cheaper and clearer than wrapping the whole body in a ternary.

Recipes worth stealing

Short rules that do a surprising amount. Copy any of them straight into a rule editor.

Blur

blur
[{AVG, (-1:1,-1:1)}]

Average the whole 3×3 cell and assign it back. Runs on the GPU at any grid size.

Edge detect

edges
R = {RANGE, (-1:1,-1:1).R}
G = R
B = R

Max minus min over the neighborhood is high exactly where the image changes.

Motion trail

trail
[{SAMPLEC, -1, 0} * .92]

Read the pixel to the left of the current picture and dim it. Always multiply by a decay — feedback accumulates.

Any life-like rule

B3/S23
LET _n = {COUNTNZ, MOORE.R}
_n == 3 | (_n == 2 & R > 0)
  ? [255,255,255,255]
  : [255,0,0,0]

Change the numbers and you have HighLife, Seeds, Day & Night — any B/S notation.

Fade to original

heal
[{MIX, BASE, .06}]

Every effect that damages a scene wants this: the artwork slowly heals back to what you painted.

Sparkle

sparkle
RN < 2 ? [255,255,255,255]
R *= .88
G *= .88
B *= .88

Rare bright pixels plus a global decay is the whole of glitter, embers and starfields.

Write your first rule in about a minute

Phlux runs inside Phluxel, a cellular automata and pixel animation editor for Windows. The browser demo needs no install and no account — paint a few pixels, type one line, press play.

Questions about Phlux

What is Phlux?

Phlux is a small domain-specific language for describing cellular automata. A Phlux rule takes one cell and its neighborhood and produces that cell's next state, written as assignments to its color channels. It is the rule language of Phluxel, an editor for cellular automata and pixel art animation.

Is Phlux a general-purpose programming language?

No, and deliberately so. There are no loops, functions with side effects, imports, file access or network calls. The only control flow is a conditional. The grid iteration is the loop, and your rule is its body — which is why useful rules stay one to five lines long.

Do I need to know how to program?

No. The most common first rule is one line — R = {AVG, (-1:1,-1:1).R} — and the editor ships with a library of ready-made rules you can apply with one click and then edit. If you can read a spreadsheet formula you can read Phlux.

What's the difference between Phlux and Phluxel?

Phlux is the language; Phluxel is the application you write it in. Phluxel provides the canvas, the drawing tools, the simulation engine, the timeline and the GIF, MP4, APNG and sprite sheet exporters. Phlux is the part you type.

How is this different from writing a CA in Python or a shader?

Mostly in how much is already decided for you. There is no grid allocation, no double-buffering, no neighbor indexing, no boundary handling and no render loop — all of that is the runtime's job. You write only the part that differs between one automaton and another.

The other difference is that the canvas is directly editable. You can pause a simulation, paint into it with a brush, and resume — which is awkward when your state lives in a numpy array or a texture you have to round-trip.

Does Phlux run on the GPU?

When it can. Rules using only channels, neighbors, arithmetic, conditions and area reductions are compiled to a fragment shader automatically. Randomness, scatter, BASE, LET, PARAM and user-defined functions run on the CPU instead. You do not choose or annotate anything; the editor shows you which path a rule took.

Can I use Phlux for classical cellular automata research?

For anything that fits a 2D grid with four channels per cell, yes — life-like rules, cyclic automata, excitable media, reaction–diffusion, sandpiles and totalistic rules are all straightforward. It is not built for 1D elementary automata, hexagonal or non-rectangular lattices, or continuous-space models.

Where can I try it without installing anything?

The browser demo runs the real engine in WebAssembly. The free desktop edition for Windows has every feature, with a watermark on exports.