Code on a show
Most people in this industry write code only when a show needs it — a console macro, a bit of glue between two systems, a bridge to an automation platform. Those are three different jobs, and the reason "just use Python" is sometimes right and sometimes dangerous.
Start here
Three places code shows up, and they are not the same job
The confusion that wastes the most time is treating these as one skill. They have different tools, different constraints, and completely different definitions of the word working.
Scripting inside a tool
You are writing inside somebody else's application, using the language they chose to embed. The application decides when your code runs and what it can touch.
Lua in grandMA3 plugins · Python in TouchDesigner and Ableton control-surface scripts · AppleScript and JavaScript in QLab · JavaScript modules in Companion
Glue between systems
A small program of your own that listens to one thing and talks to another — OSC in, HTTP out; a webhook that fires a cue; a translator between two vendors who will never support each other.
Python or Node most often · runs on a laptop or a small PC · nothing moves if it crashes, which is exactly why it is allowed to be simple
Machine control
Something physical moves. Winches, lifts, revolves, kinetic scenery. The code must run on a guaranteed schedule, and the safety chain is separate hardware regardless of what the code does.
PLC platforms — TwinCAT, Siemens TIA, CODESYS · IEC 61131-3 languages · EtherCAT or PROFINET underneath
The vocabulary
What actually separates one language from another
Three distinctions do most of the work, and once you have them the landscape stops being a list of names.
Compiled or interpreted. A compiled language (C, C++, Rust, Go) is translated to machine code once, before it runs; from then on the processor is executing it directly. An interpreted language (Python, JavaScript, Lua) ships as source and a runtime reads and executes it as it goes. Compiled is faster and less forgiving; interpreted is quicker to change and easier to get running, which is why so much show glue is written in it.
Managed or manual memory. Most modern languages have a garbage collector: it finds memory you are no longer using and reclaims it, at a moment of its own choosing. That is a huge convenience and it is also a timing hazard, because "a moment of its own choosing" can land in the middle of something you needed to happen on time. C and C++ have no collector — you manage memory yourself, which is more work and more dangerous, and it is why they are still what real-time media engines and firmware are written in.
General-purpose or embedded. Some languages are designed to be the application; some are designed to live inside one. Lua is the clearest example — small, fast to embed, easy to sandbox — which is precisely why it turns up inside so many consoles and media servers rather than as anybody's main language.
The landscape
What each one is actually for
This is not a ranking. Every row is the right answer to some question and the wrong answer to most of the others.
| Language | Kind | What it is good at | Where you meet it on a show |
|---|---|---|---|
| HTML + CSS | markup | Not programming languages at all. HTML describes structure; CSS describes appearance. Neither can make a decision. | Touch-panel layouts, web remotes, lower-third and overlay templates, any browser-based control surface. |
| JavaScript | interpreted | The one language every browser runs. Event-driven by nature, so it is comfortable waiting for things. Also runs outside the browser as Node. | Companion modules, browser-based controllers, web remotes, small OSC-to-HTTP bridges. |
| Python | interpreted | The fastest way from an idea to a working script, with a library for almost everything. Slow in raw terms, and almost never slow enough to matter for glue. | TouchDesigner, Blender, Ableton remote scripts, disguise scripting, and most one-off integration tools in this industry. |
| Lua | embedded | Tiny, fast, trivially embeddable and easy to sandbox. Designed to be hosted inside another application rather than to stand alone. | grandMA3 plugins, and scripting hooks inside a range of consoles, media servers and control systems. |
| C / C++ | compiled | Direct control of memory and timing, no garbage collector, no runtime surprises. Correspondingly unforgiving. | Fixture and console firmware, media server engines, audio DSP, plug-ins, and custom TwinCAT modules. |
| C# | compiled + managed | Comfortable, strongly typed, excellent tooling. Garbage collected, so not for hard real time. | Unity-based interactive and XR work, Windows show tools, plenty of vendor SDKs. |
| Structured Text | PLC (IEC 61131-3) | Looks like ordinary code and compiles to a guaranteed scan cycle. Written to be reviewable by someone who did not write it. | Automation: winches, lifts, revolves, turntables, kinetic scenery. |
| Ladder / FBD | PLC (IEC 61131-3) | Graphical. Ladder reads like a relay schematic; function block diagram reads like a signal flow. Both are chosen for auditability, not for expressiveness. | The same automation systems — often alongside Structured Text in the same project. |
| Shell / batch | scripting | Starting things, moving files, wiring existing tools together. Not for logic of any depth. | Show-machine startup, log collection, backup jobs, media prep. |
- "HTML5" is not a language you program a show in. It is a name for a generation of web capabilities. When a spec says "HTML5 interface", the logic is JavaScript and HTML is just the surface.
- The language rarely decides the outcome. The protocol you speak and the timing you can guarantee do. A well-written Python bridge and a well-written Node bridge will both work; neither should be moving scenery.
- An embedded scripting language is not a promise of access. "It has Lua" tells you nothing about which parts of the application that Lua can reach.
The word that matters
Determinism, and why it disqualifies almost everything
Ask a laptop to do something every 10 milliseconds and it will, on average. Most cycles will be close to 10 ms. Some will not: the operating system schedules something else, the garbage collector runs, a network driver takes a moment, an antivirus scanner wakes up. Averages are excellent and individual guarantees are absent.
For a cue-triggering bridge that is completely fine — a few milliseconds late is invisible. For a motion control loop it is not fine at all, because the loop is what keeps a moving load under control, and "usually on time" is not a property you can write a safety case around.
A real-time system inverts the priority. It is not necessarily fast; it is predictable. The cycle happens every cycle, on time, and if it cannot, the system faults rather than quietly running late. That guarantee is the entire reason PLC platforms exist, and it is why show automation runs on them instead of on the laptop that is already sitting there.
The platform
What TwinCAT actually is
TwinCAT is Beckhoff's automation platform, and the thing that makes it interesting is what it does to an ordinary industrial PC: it runs a hard real-time kernel alongside Windows, with CPU cores reserved for the real-time side. Windows can be as busy or as badly behaved as Windows normally is, and the control task still runs on its cycle.
TwinCAT 3 is developed inside Microsoft Visual Studio, which means the control engineering and any surrounding software tooling live in one environment. It supports the IEC 61131-3 languages — Structured Text, Ladder, Function Block Diagram, Sequential Function Chart, Instruction List — and it will also take compiled C++ modules and models exported from MATLAB/Simulink, so a control algorithm designed in simulation can be deployed as a real-time task rather than rewritten.
Underneath it, EtherCAT is the fieldbus: drives, I/O and sensors on one line, updated every cycle with the determinism the whole design exists to protect. Upward, an OPC UA server is the usual way the automation platform exposes state to the rest of the building — which is also, in practice, how a show-control system asks it a question without being anywhere near the control loop.
Everything on the show-network side of that boundary is advisory. The automation platform decides what it does.
the same idea in three languages
Read those three again and notice what changes. The first runs when a human asks. The second runs when a message arrives. The third runs whether anything happened or not — and that is the difference the whole page is about.
The boundary
Where custom code is allowed to be, and where it is not
This is the same principle as the arming chain on the drone and pyro page, and it is worth stating in the same words.
Functional safety — emergency stops, limits, guarding, the interlocks that stop a load before it hurts somebody — is a separate, rated channel. On a Beckhoff system that is TwinSAFE; other vendors have their own. It is certified, it is reviewed, and it is not where your code goes. It remains valid regardless of what the control program does, which is exactly the point: it has to be true even when the control program is wrong.
Custom code belongs on the control side of that boundary and on the show network above it. It can request, sequence, report and integrate. It cannot be the reason a machine stops safely.
- Determinism is a property of the runtime, not of your skill. Well-written Python on a general-purpose OS still has no cycle guarantee. That is not something you can fix by being careful.
- A test that passed once has proved nothing about timing. Jitter is a distribution. Measure the worst case over hours, not the average over a minute.
- Glue code becomes infrastructure quietly. The script written at 2am to get through a preview is running the following tour. Give it a repository and a name the moment it survives one show.
- Read the sandbox before designing around a scripting hook. Embedded scripting is usually restricted deliberately — no filesystem, no network, no threads — and finding that out late costs a rewrite.
If you are starting
What is actually worth learning first
For almost everyone in this industry the honest answer is Python, and it is not close. It reads clearly, the library ecosystem covers every protocol you are likely to meet, and it is what the tools you already use have embedded.
Learn JavaScript when what you need lives in a browser or in Companion — which is often enough that it is a fair second.
Learn Lua when the console you are on has it, because it is a small language and you can be useful in it in an afternoon.
Learn Structured Text and a PLC platform when you are moving into automation — and treat that as a career decision rather than a language decision, because the discipline around it is the substantial part, not the syntax.
What survives across all four is not syntax. It is the protocol and timing thinking the rest of this section is about: knowing what you are speaking, and what promises it does and does not make.
Every collection here is plain JSON at a fixed URL with permissive CORS — no key, no rate limit — so it is a reasonable thing to hang a script off. Start at /api/v1/index.json, and see how software talks to software for the protocol-versus-API-versus-SDK distinction that decides most integration questions.
- Which language should I learn?
- What is determinism?
- What is TwinCAT for?
Where to go next
These pages are a chain rather than a library — the next one along usually answers the question this one raised.
Everything on this page, in the index
Each of these has its own entry with sources, ports, gotchas and an open gap where a field is missing.