Titanic's End is a mutant vehicle that debuted at Burning Man 2022 and has since participated in EDC and Framework events.
We are the largest team developing on Chromatik in the open, so other artists can benefit from our work (see the license). This repo contains the shader and pattern code for the 128,000 LEDS, sound reactivity, MIDI control, OSC middleware, and ArtNet bidirectional control.
We use Chromatik (formerly known as LX Studio) to control the show. Although not required, we also support Chromatik financially because it's excellent. This README will get you up and running with it so you, too, can create stunning LED art.
Our work is notable for:
- GLSL shader support
- Developed to team-friendly maintainability standards for long-term enjoyment of the codebase
- AutoVJ: an autopilot that uses Pioneer Rekordbox's phrase and beat analysis to change patterns when a human VJ would
- GigglePixel, Pixelblaze, and ArtNet integration
Want a personal intro to the project and codebase? Contact current team lead Andrew Look by messaging andrew-m-look (s/-/./g) electronically at the big Gm.com thing.
What if I want to know more?
This doc sets out the project vision and has much more information: 2022 Lighting Design Doc
Team members can reference several docs on our Notion for more background including Networking and Front of House and Software / Integration Hub.
Visit https://adoptium.net/installation/ or if you are using macOS and Homebrew use these commands:
brew uninstall temurin # ensure you are running 21
brew install temurin@21Verify your installation:
/Library/Java/JavaVirtualMachines/temurin-21.jdk/Contents/Home/bin/java --versionMake sure JAVA_HOME points to temurin. Add to your .zshrc or equivalent.
export JAVA_HOME=/Library/Java/JavaVirtualMachines/temurin-21.jdk/Contents/Home/After installing the Temurin JDK, we recommend installing and building maven, a package manager for our project:
brew install mavenOne more thing… we have a coding style setup, as described below, so you’ll also need to install google-java-format:
brew install google-java-formatThese are geared toward running Chromatik on macOS with
gitalready installed. If you need help with anything, ask in the Slack #te-lighting-software channel!
First, you'll need an IDE (editor). IntelliJ Community Edition is the best free one available. You can download it here.
-
Clone the git repo you're looking at (and
cdinto it):git clone https://github.com/titanicsend/LXStudio-TE.git && cd LXStudio-TE
-
Clean and Install the Maven dependencies (from inside
LXStudio-TEdirectory):mvn clean -U package && mvn install -
Open the IntelliJ app. On the initial screen, click Open, and select the
LXStudio-TEdirectory you cloned. -
File → Project Structure (or ⌘-;)

-
Platform Settings → SDKs
-
Project Settings → Project
-
-
Select "Titanic's End" in the top bar (in the dropdown) if you want to use the vehicle model.

-
Hit the green arrow "play" button. (If you just want to build, you can hit the hammer.)
-
Assuming things work okay, a UI for Chromatik will pop up: Great! Now, you can play with the buttons.
These are the steps to use google-java-format automatically and ensure that each commit gets formatted before being submitted.
-
As mentioned earlier, run the following to ensure you have
google-java-formatinstalled:brew install google-java-format
-
Set up the git pre-commit hook to run the
google-java-formatCLI tool on changed filescp pre-commit .git/hooks/pre-commit
Commits may now fail if there's a style violation on any files modified in that commit, since this runs
mvn spotless:check. If you really need to commit something and are okay to fix the lint errors later, you can do a
git commit --no-verify just to bypass this check temporarily and save your commit. However, mvn spotless:check is
required to pass on any PR's before they're merge-able, so you'll need to make the lint fixes eventually.
You can manually apply formatting fixes using mvn spotless:apply. It's easiest, though, to have your code reformatted
by the IDE, every time you save.
(IntelliJ Users) Install this plugin: google-java-format plugin
- The google-java-format plugin uses some internal classes that aren't available without extra configuration. To use the
plugin, you need to add some options to your IDE's Java runtime. To do that, go to
Help→Edit Custom VM Options...and paste in these lines:
--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED
--add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED
--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED
--add-exports=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED
--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED
--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED- The plugin will be disabled by default. To enable, open the Project settings, then click
google-java-format Settingsand check theEnable google-java-formatcheckbox. - After plugin install, go to
Settings > Tools > Actions on Saveand enableReformat CodeandOptimize Imports.
(Eclipse Users) Or install the IDE plugin for Eclipse.
Maven resources compiler: Failed to copy [...]/target/generated-test-sources/test-annotations/Icon ' to '[...]/target/test-classes/Icon- Go to the top of your TE repo and run
find . -name Icon\? -delete
- Go to the top of your TE repo and run
So you've got the app up and running. You see some patterns in the code. How do you make sense of them?
To understand the point, edge, and panel naming scheme, see the Visual Map tab of the Modules, Edges and Panels sheet.
TE is using the full IDE-ready distribution instead of the P4 Processing Applet version. Don't struggle, ask questions in #te-lighting-software on Slack.
The tutorials in the LX Studio Wiki are an effective introduction.
Our team has compiled these:
As you really get rolling, you’ll appreciate the API docs and public portion of the source.
Chromatik uses your default audio input device out of the box, so if you're playing music in range of your microphone sound reactivity should mostly work. But there's a better way.
BlackHole is a virtual audio loopback driver for macOS. Using BlackHole, you can route local audio to Chromatik.
First, install BlackHole:
brew install blackhole-2chFor other installation options, see the BlackHole README
After installing, you should see a new BlackHole audio device in the Audio MIDI Setup utility.
At this point you should be able to send audio to Chromatik by selecting BlackHole as your computer's output device, and as Chromatik's audio input device. But since sound output is being sent to BlackHole, you won't hear anything.
To play audio from your computer speakers (and/or another device) while simultaneously sending audio to BlackHole, you can set up a multi-output device:
- Open the Audio MIDI Setup utility
- Click + > Create Multi-Output Device
- Check "Use" for both audio devices
- Right-click the new device and select "Use This Device For Sound Output"
The BlackHole docs recommend setting the non-BlackHole device as the "Primary Device", changing the device order so the primary device appears first in the list, and enabling drift correction for all other devices. Device order and primacy don't seem to affect anything on macOS Sequoia 15.4, but YMMV.
Now, in Chromatik, set the audio input to BlackHole:
After setting the new multi-output device as audio output in macOS, and the BlackHole device as the audio input device in Chromatik, you should be able to hear music from your speakers and see it on the spectrum meter in Chromatik.
VJLab is a stem splitter that extracts audio stems in real time. These stems can be used to control patterns in Chromatik.
To get a recent VJLab build, come chat with the developers in #te-lighting-software on Slack.
To configure VJLab for use with Chromatik, go to Audio Settings and set the input and output device to BlackHole:
To use VJLab's tempo tracker to set the tempo in Chromatik, go to Outputs and enable the Send Beat Messages option:
Chromatik should already be configured to listen for OSC messages on port 3030:
If everything is set up correctly, and music is playing, you should see live audio stem volume in Chromatik:
Can't change multi-output device volume
- Switch back to the output device for which you want to change the volume, e.g. MacBook Pro Speakers
- Change the volume
- Switch back to the multi-output device, which should respect the current volume
But this may lead to another problem...
VJLab stops receiving audio input from BlackHole after switching audio devices
- Switch to the multi-output device you want to use, either in Audio Midi Setup or Preferences > Sound
- Quit VJLab and any applications playing sound
- Start sound-playing applications again
- Start VJLab again
Once it's running, go tell Slack so we can celebrate with you and maybe give you a tour. Or, if you prefer self-guided tours:
- Read the Chromatik Guide
- Or, read the older LX Studio Wiki
- Play with the UI until you have a modulator controlling the parameter for a pattern, and an effect applied on top.
- See this guide from another memorable Burning Man art piece
- Define a new fixture in the UI
- (Optional) Save your playground as a new project with your name:
Playground <YourName>.lxp. You can mess this project up and experiment broadly.
Things that can help improve your experience with LX Studio.
It can be handy to edit Chromatik's JSON config files in the IDE. Add the .lxf and .lxp extensions to be recognized as JSON.
- Open IntelliJ preferences (
⌘-, on Mac) and go toEditor → File Types → JSON5. (Note: JSON5 handles comments, unquoted keys, etc.) - Next, add
*.lxp,*.lxf,*.lxmto the list.
Jeff's enjoying the following (he comes from Sublime and vim):
- CodeGlance
- Rainbow Brackets
- IdeaVim
- CSV
- KeyPromoter X
- Python Community Edition
Many of you may use VS Code in your day-to-day life. If you do, and you'd like IntelliJ to behave more like VS Code, I'd recommend:
- In IntelliJ, open the "IntelliJ IDEA" menu and select "Preferences"
- Click "Plugins"
- Search for "VSCode Keymap"; install
- Go back to "Preferences"
- Go to "Keymap", select one of the VS Code keymap options, (either macOS or not) hit apply, and enjoy increased happiness in your IDE
If you just need to execute Chromatik to run a show without editing anything, you can do that:
-
Install Temurin JDK (see JDK installation above).
-
Build into a runnable JAR:
mvn clean package # Packaging creates the JAR and cleaning is optional -
Execute the JAR (Note that the version number may be different — The version as of this document revision is 0.2.1-SNAPSHOT — substitute the correct version as necessary):
java -XstartOnFirstThread -jar target/te-app-*-jar-with-dependencies.jar Projects/BM2024_TE.lxp -
If the Temurin JDK isn't your default Java, then you can use the full path, for example:
/Library/Java/JavaVirtualMachines/temurin-21.jdk/Contents/Home/bin/java -XstartOnFirstThread -jar target/te-app-*-jar-with-dependencies.jar Projects/BM2024_TE.lxp -
Use Maven to execute the program instead of the
javacommand:mvn clean compile # Cleaning and compiling is optional, depending on your needs mvn exec:exec@Main -Dexec.args="Projects/BM2024_TE.lxp"
Fun fact: The "Main" target isn't defined in the POM to have arguments, but it could, in which case you wouldn't need the
Projects/BM2024_TE.lxpargument.
If your ~/.m2 Maven cache has any conflicting things, you may need to delete
the conflicts, otherwise the execution may complain about things like missing
libraries or invalid versions, and the like. Finding the conflicts is a more
advanced approach. A simple one is to just delete that whole directory:
Note: If you are having trouble with wrong packages installed here, make sure
that you have IntelliJ closed. It may attempt to install missing dependencies when
after you delete .m2 when it re-indexes and they will be wrong. Delete the .m2
and reinstall dependencies through an external terminal.
rm -r ~/.m2To run on machine startup (i.e.: press power button and Chromatik just starts up), you'll need to do three things:
- Add
TE.appto your startup items- System Preferences > Users & Groups
- Click the user to run Chromatik with
- Login Items > "+" button > add TE.app
- Change to automatic login
- System Preferences > Users & Groups
- Click "Login Options" underneath list of accounts (may need to enter password)
- Using the combo box, select desired user, e.g. "te" or whatever
- Uncheck all the boxes underneath
- Remove the password from your user account
- System Preferences > Users & Groups
- Click the user > "Change Password"
- Leave new password blank
- Keep in Dock
- When TE.app is running, right-click on it, and click "Keep in Dock"
- This way, during a show, it's very easy for anyone non-technical to simply quit the program and re-run it if there is an issue
Restart your machine, and you should see Chromatik open automatically on startup.
If Eclipse is like a warm snuggie to you, we'd appreciate you adding any SDK and environment configuration tips here.
The car's main Chromatik instance runs on a Mac Studio that lives on the car, connected to the car's LAN. The UI is controlled via a remote desktop (VNC) connection over a high-speed PTP wireless bridge. Since the VJ at this remote Front-of-House desk will want to use MIDI surfaces and controllers to perform, we needed to come up with a MIDI-over-WiFi solution to connect the USB MIDI devices to the box running Chromatik on the car.
In 2022, we used OSX's arcane built-in support for RTP-MIDI. This was brittle and fickle to maintain.
In 2023, we changed to using a device called a BomeBox that uses a proprietary encapsulation protocol. To make this work:
- The Bome Network tool should be installed on the computer that runs Chromatik. The "Multiple Named Virtual interfaces" upgrade is required.
- The remote BomeBox should be on the same subnet, with updated firmware
- Optionally, renamed the BomeBox. We changed "BomeBox" to "FoH" for "Front of House"
- Connect the MIDI controllers to the BomeBox USB port via a USB Hub. In the Bome Network tool, enable Remote Direct Midi for those devices.
- You can disable MIDI routes that aren't used, such as the DIN ports or MIDI messaging between the USB devices. This likely helps performance. Leave 2 routes per device: The bidirectional pair Chromatik → Device, and Device → Chromatik.
- Register the correct new names in Chromatik. The Bome Remote Direct Midi device
names follow a pattern of "{BomeBoxName}: {DeviceName}", like
"FoH: APC40 mkII". For example, in your main app you may need to
lx.engine.midi.registerSurface(name, class)or match the name with an entry inlx.engine.midi.inputs[].getName(). If using more than one midi device of the same type BoxBox will present each device with a unique name by appending a number such as "FoH: Midi Fighter Twister (2)".registerSurface(name, class)needs to be called for each of these unique names.
Here's a video illustrating our configuration.
- #te-lighting-software on Slack
- Chromatik Wiki
- Chromatik API
- Chromatik Source
- TE Visual Map
- TE Operation Modes and Art Direction Standards
- Using Tempo and Sound
- The APC40 and LX Studio
- Titanic’s End
Please see LICENSE.md — significant parts of this repository are not open source, and we support those authors' wishes.












