← Smartshow LMS Online manual · v1.2.6 · Not in English? Right-click anywhere and choose your browser's Translate option. ⬇ PDF

Writing LMS Scripts

LMS Script is a small, friendly language for generating live LED-matrix animations. You write a bit of setup and a bit of per-frame drawing, and LMS runs it straight onto your wall. It's the same format as classic Jinx! scripts (.jns), so scripts from the wider community work too.

Quick start

Every script has two parts: :init (runs once) and :render (runs every frame). Here's a complete script that scatters coloured sparkles:

:init
    # runs ONCE when the effect starts
    w = matrix_x
    h = matrix_y
end

:render
    # runs EVERY frame — draw into the matrix
    clear
    x = rnd(w - 1)
    y = rnd(h - 1)
    pset x, y, autocolor_red, autocolor_green, autocolor_blue
end

Open the Edit script button under the effect's Script dropdown to try it — you get a live preview and instant error checking as you type.

Importing Jinx scripts

LMS Script is Jinx!Script — the same language and the same .jns file format used by the classic Jinx! software. That means the huge library of scripts people have written and shared over the years runs straight in LMS, no conversion needed.

To import a script

In the effect's Script dropdown, open the My scripts section at the bottom and choose:

+ Load .jns file…Pick any .jns file from your computer. It's added to your library, appears in the list, and starts playing.
+ New script…Start a blank script from scratch in the editor.
⚙ Manage my scripts…Rename, edit or delete the scripts you've added.

Imported scripts are saved inside your project (the .lmc file), so they travel with it — share a project and your scripts go along. Load as many as you like; they all stack up in the list.

Where to find scripts: search the web for "Jinx script" or .jns — there are collections on forums, GitHub and the LED-hobby community. Drop the file in via Load .jns file… and it's yours.
If an imported script "does nothing": it's usually the script, not LMS — some are near-invisible test patterns, or need a bigger matrix. Open it with Edit script to see the live preview and any errors, tweak it, and save your own version.

Structure

A script is a list of plain-text lines. Blank lines and anything after a # are ignored (comments).

BlockRunsUse it for
:initendOnce, at the startSet starting values, sizes, arrays, config settings.
:renderendEvery frameDraw the current frame. Runs ~30–60 times a second.

Variables you set in :init keep their values between frames, so :render can move things along a little each time — that's how animation works.

The matrix & colour

The matrix is a grid of pixels. (0, 0) is the top-left; x goes right, y goes down. The size is always available as matrix_x (width) and matrix_y (height) — write to those instead of hard-coding a size, and your script works on any wall.

Colours are three numbers — red, green, blue, each 0255. So 255, 0, 0 is red and 255, 255, 255 is white.

Variables & arrays

Just assign to create a variable — no declarations. Numbers can be whole or decimal.

count = 0
angle = 3.14
count = count + 1

Arrays use square brackets and grow as needed (index from 0):

red[0] = 255
red[1] = 0
x[i] = x[i] + speed[i]

config settings

Use config in :init to declare a named value with a sensible default:

:init
    config dot_count = 100
    config speed = 2
end

It behaves like a normal variable you can read anywhere. (Per-script sliders for these are on the roadmap; for now they run at their default, and the effect's global Speed, Auto-colour speed and Brightness controls sit on top.)

Loops & conditions

Repeat a fixed number of times — for … next

for i = 0 to dot_count step 1
    pset i, 0, 255, 255, 255
next

step is optional (defaults to 1) and can be negative to count down.

Repeat while true — while … wend

i = 0
while i < w
    pset i, i, 0, 255, 0
    i = i + 1
wend

Make decisions — if … else … endif

if x > w
    x = 0
else if x < 0
    x = w
endif

Use & (and) and | (or) to combine conditions: if x > 0 & x < w. A trailing then is allowed but optional.

Subroutines — gosub

Give a block a label, jump to it with gosub, and come back with return:

:render
    gosub new_dot
end

:new_dot
    px = rnd(matrix_x)
    py = rnd(matrix_y)
    return

Operators & maths

KindOperators
Arithmetic+ - * / % (remainder) ^ (power)
Compare= (equal) <> (not equal) < > <= >=
Logic& or && (and) · | or || (or)

Note = does double duty: x = 5 assigns, but inside an if it means "equals".

Drawing commands

CommandWhat it does
clearBlank the whole matrix to black.
fade NDim every pixel by N (0–255). Great for trails — draw without clearing and let old pixels fade.
pset x, y, r, g, bSet one pixel to a colour.
pget x, y, rVar, gVar, bVarRead a pixel's colour into three variables (handy for reacting to what's on screen).
line x1, y1, x2, y2, r, g, bDraw a straight line.
rect x1, y1, x2, y2, r, g, b, fillRectangle between two corners. fill = 1 solid, 0 outline.
circle x, y, radius, r, g, b, fillCircle at a centre. fill = 1 solid disc, 0 outline.
text x, y, align, size, r, g, b, "string", "font", styleDraw text. align: 0 = left, 1 = centre, 2 = right (horizontal anchor at x; y is the vertical centre). size = font height in pixels. "font" = a font name (e.g. "Arial"). style: 0 = normal, 1 = bold, 2 = italic, 3 = bold+italic. The string must be a literal in quotes — Jinx! (and LMS) can't use a variable for the text content. New in this build — makes countdown / scrolling-message / bingo-style community scripts work.
hsv2rgb hue, sat, val, rVar, gVar, bVarConvert a colour from Hue/Saturation/Value into r,g,b variables. hue is 0–360°, sat and val are 0–255. The easy way to cycle rainbows.

Built-in values

NameMeaning
matrix_x, matrix_yMatrix width and height in pixels.
autocolor_red
autocolor_green
autocolor_blue
A colour that cycles automatically over time (its speed is the effect's Auto-colour speed control). Draw with these for a built-in colour show — no maths needed.
frame_countHow many frames have rendered — a steadily rising counter.
audio_triggerLive music level, 0–255 — the louder of the beat transient and overall loudness. Detect a beat by comparing to the previous frame (if audio_trigger > trigger_old). Needs an audio input running (Settings › Audio). Reads 0 when no audio is active.
audio_levelOverall loudness, 0–255 (mean of all frequency bands).
audio_bass
audio_mid
audio_treble
Per-band energy, 0–255 — lows (~20–200 Hz), mids (~200–1500 Hz), highs (~3–12 kHz). Drive different parts of a pattern off different frequencies.
audio_beatBeat / onset envelope, 0–255 — spikes on kicks and decays smoothly. Cleaner for pulsing than audio_trigger.
pi3.14159… — for angles and circles.

Functions

FunctionReturns
rnd(n)A random whole number from 0 to n (inclusive).
sin(a), cos(a), tan(a)Trig — angle in radians (multiply degrees by pi/180).
sqr(n)Square root of n (also sqrt(n)).
abs(n)Absolute (positive) value.
floor(n), ceil(n), round(n)Round down / up / nearest. int(n) = floor.
min(a, b), max(a, b)Smaller / larger of two values.
atan2(y, x), pow(a, b)Angle of a vector; a to the power b.

Worked examples

A dot bouncing around

:init
    x = 5
    y = 5
    dx = 1
    dy = 1
end

:render
    fade 40                       # leave a fading trail
    x = x + dx
    y = y + dy
    if x <= 0 | x >= matrix_x - 1
        dx = 0 - dx                 # bounce off the sides
    endif
    if y <= 0 | y >= matrix_y - 1
        dy = 0 - dy
    endif
    pset x, y, autocolor_red, autocolor_green, autocolor_blue
end

A rainbow sweep

:render
    for x = 0 to matrix_x - 1
        hue = x * 360 / matrix_x + frame_count * 4
        hsv2rgb hue, 255, 255, r, g, b
        for y = 0 to matrix_y - 1
            pset x, y, r, g, b
        next
    next
end

Tips & performance

Trails: use fade N at the top of :render instead of clear to leave glowing tails behind moving shapes. Bigger N = shorter tail.
Colour for free: draw with autocolor_red / green / blue and the whole thing cycles colour on its own — control the speed with the effect's Auto-colour slider.
Watch nested loops. :render runs every frame. A loop over every pixel that also loops again inside (width × height × more) gets very heavy on big walls and will drop the frame rate. Prefer drawing a handful of shapes/points per frame over scanning the whole grid.

The live editor (Edit script) checks your script as you type and shows the exact line of any problem. Experiment freely — a built-in preset opens as an editable copy, so you can never break the originals.