Skip to content

Modifiers

Every modifier, one block each: its preview, what it does, and what each control means, together. A modifier sits between an effect and the output: it reshapes where pixels land (or masks them) without changing the effect's drawing. Modifiers compose: a Layer folds its whole modifier stack each rebuild; a dynamic modifier (one that overrides modifyLive) also runs a per-frame pass, and an animated one keeps a static fold but rebuilds it on its own clock. See ModifierBase for the static-vs-dynamic split. Each block's emoji are its tags() (see the tag emoji legend); Kind is static (baked into the mapping at rebuild) or dynamic (per-frame remap). Modifiers are grouped into sections, and each block carries that modifier's preview, behavior, and control descriptions together. (For how this page maps to the source/asset folders, see the folder-structure decision.)

A modifier folds coordinates rather than drawing, so it reaches for very little of the shared power function toolbox โ€” that page states the split and lists which modifiers use what.

MoonLight modifiers

Module Details
Block ๐Ÿ’ซ ยท static
Block modifier preview
Expands a 1D effect into concentric square rings (Chebyshev distance from the center): the effect's linear position becomes the ring index, so a gradient effect draws nested squares.
โ€”
Tests: Block
API: reference
Details: none yet
Checkerboard ๐Ÿ’ซ ยท static
Checkerboard modifier preview
Masks the layer in a checkerboard: "off" squares are dropped, "on" squares pass through unchanged.
size โ€” checker square edge in lights (1โ€“64).invert โ€” flip which squares pass through vs are masked.
Tests: Checkerboard
API: reference
Details: none yet
Circle ๐Ÿ’ซ ยท static
Circle modifier preview
Expands a 1D effect into concentric circular rings (Euclidean distance from the center): the effect's linear position becomes the radius, so a gradient effect draws nested circles. The circular counterpart to Block.
โ€”
Tests: Circle
API: reference
Details: none yet
Mirror ๐Ÿ’ซ ยท static
Mirror modifier preview
Folds the far half of the box back onto the near half per axis, mirroring the image across the box center (top-left quadrant reflected into the others in 2D, near octant into all eight in 3D).
mirrorX / mirrorY / mirrorZ โ€” mirror across the center on that axis.
Tests: Mirror
API: reference
Details: none yet
Multiply ๐Ÿ’ซ ยท static
Multiply modifier preview
Tiles the logical image across the box multiply times per axis, optionally mirroring alternate tiles (a pure mirror is multiply = 2, mirror = true).
multiplyX / multiplyY / multiplyZ โ€” tiles per axis, 1 meaning none.mirrorX / mirrorY / mirrorZ โ€” reflect alternate tiles on that axis.
Tests: Multiply
API: reference
Details: none yet
Pinwheel ๐Ÿ’ซ ยท static
Pinwheel modifier preview
Remaps the grid into radial petals around the center โ€” the angle to each pixel picks its petal, with an optional swirl (angle sheared by radius), symmetry, and z-twist. Turns a linear or 2D effect into a rotating flower/spokes pattern.
petals โ€” number of petals radiating from the center.swirl โ€” shear the angle by radius (โˆ’127..127; a spiral; negative reverses).reverse โ€” reverse the petal order.symmetry โ€” fold the petals into a factor-of-360 symmetry.zTwist โ€” twist the petals along z (3D).
Tests: Pinwheel
API: reference
Details: none yet
RippleXZ ๐Ÿ’ซ ยท static
RippleXZ modifier preview
Collapses an axis to a single plane so a higher-dimensional effect ripples along the remaining axes โ€” used to drive a 1Dโ†’2D/3D ripple.
shrink โ€” collapse the selected axis (on = collapse).towardsX / towardsZ โ€” which axis collapses to a single line.
Tests: RippleXZ
API: reference
Details: none yet
Transpose ๐Ÿ’ซ ยท static
Transpose modifier preview
Swaps a pair of box axes (and every coordinate through them), then optionally inverts each axis โ€” rotate/flip the image without redrawing the effect.
XY / XZ / YZ โ€” swap that pair of axes.inverse X / inverse Y / inverse Z โ€” flip that axis after the swap.
Tests: Transpose
API: reference
Details: none yet

MoonLight-native modifiers

Module Details
MoonLive ยท static
MoonLive scripted modifier preview
The coordinate transform written as text on the running device: mirror the pattern, shift it, swap its axes. Each hand-written modifier is a class and a reflash, where a script is a line of text applied as you type. The language is MoonLive.
script โ€” which .mlm file runs, picked from the library and edited here.Everything the script declares appears as a real control.
Tests: MoonLive
API: reference ยท what a script transforms
Details: MoonLive, details
RandomMap ๐Ÿ’ซ ยท animated
RandomMap modifier preview
Remaps every light to another via a true 1:1 permutation, reshuffling to a fresh permutation on a bpm timer โ€” the arrangement scrambles each beat, the content is untouched.
bpm โ€” reshuffles per minute, 0 freezing the permutation.
Tests: RandomMap
API: reference
Details: none yet
Region ๐Ÿ’ซ ยท static
Region modifier preview
Carves the layer to a sub-rectangle given as percentages of the physical extent (so it survives a resize); outside the region is dark.
startX โ€ฆ endZ โ€” the bounds as percentages of each axis.
Tests: Region
API: reference
Details: none yet
Rotate ๐Ÿ’ซ ยท dynamic
Rotate modifier preview
Rotates the 2D image around its center, turning continuously over time (the codebase's transform-matrix reference).
speed โ€” rotation speed (1โ€“255; turns faster as it rises).
Tests: Rotate
API: reference
Details: none yet

MoonLive, details

One coordinate at a time

The script transforms one coordinate and needs no loop, because the Layer already calls it once per physical light while building its mapping.

class MirrorModifier {
  void modifyLogical() { setXYZ(width - 1 - xPos, yPos, zPos); }
}

setXYZ(x, y, z) writes the transformed position, mirroring setRGB(index, r, g, b).

Read the grid rather than assuming it

width matters more than it looks. A mirror written against a fixed 255 sends every light of a 16-wide grid outside the grid, the Layer discards each one as out of bounds, and the fixture goes black with no error anywhere, because the script itself ran perfectly.

A computed coordinate is full width. setXYZ hands its three values to the binding as a call rather than storing them as bytes, so setXYZ(767 - xPos, ...) on a 768-wide wall arrives as 767. It was an inline three-byte store once, and that is the bug it caused.

What a script cannot do

A modifier has two hooks: one reshapes the logical box once per rebuild, and one folds each coordinate. A script drives only the second. Transforms keeping the box the same size work, and one that halves it, as the built-in Mirror does, needs the compiled modifier.

A script that fails to compile shows the parse error and the mapping passes coordinates straight through, so the transform disappears until the script parses again and the device keeps rendering.