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![]() 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![]() 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![]() 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![]() 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![]() 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![]() 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![]() 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![]() 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![]() 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![]() 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![]() 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![]() 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.
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.











