config.toml
A small per-user file under the same directory the presets live in — %APPDATA%\Ritmolux\ on
Windows, ~/Library/Application Support/Ritmolux/ on macOS, and $XDG_DATA_HOME/Ritmolux/ on
Linux, which is ~/.local/share/Ritmolux/ when XDG_DATA_HOME is unset (the capital R matters
there). It is read once at startup and written back whenever a hotkey or a settings row changes a
choice, so a stage setup survives a restart.
Every key is optional. A missing file, a missing section and an unknown extra key all degrade to the built-in default rather than failing, so the file below is a complete listing rather than something you have to write.
The other file: marks.toml
Beside config.toml, in the same directory, sits a second and much smaller file the app writes:
marks.toml, holding the presets you have marked (see Running the app). It is
user state rather than settings — it grows, it is edited from a hotkey rather than from the
settings menu, and its two keys are lists rather than scalars — which is why it is not a section of
the file below.
favourite = ["Echo Plate", "Gyre"]hidden = ["Multibrot"]Both keys are optional and both are lists of preset names. A missing, empty or malformed file means “no marks” and never stops the app starting; a malformed one says so on the console. Delete the file to forget every mark.
The third thing in that directory: thumbnails/
Beside the two files sits a directory the app fills by itself: thumbnails/, one cache entry per
preset, each a 160x90 still of what that preset looks like. Nothing ships in it — the pictures are
rendered on this machine, because the binary has room for neither the images nor an image codec
(ADR-0230). The
[thumbnails] section below turns the pass that fills it on and off.
An entry is named for its preset and carries the modification time and length of the .toml it
was rendered from, which is what makes it stale: edit a preset in an RLX_PRESET_DIR library and its
picture is rendered again. It is cache rather than state — delete the directory and it refills,
and a directory that cannot be created turns the feature off with one line in diagnostics.log
rather than stopping the app. Nothing prunes it, so an entry for a preset you no longer have stays
until you delete it, the same standing cost marks.toml accepts.
[output]
Which display the show opens on, whether it opens fullscreen, and which graphics adapter draws it.
| Key | Default | What it means |
|---|---|---|
display | 0 | Target monitor index — the fallback when no display_name matches |
display_name | unset | Preferred monitor identity, matched by name before the raw index. Unset means “use the index” |
fullscreen | false | Open borderless-fullscreen on the target display; windowed otherwise |
gpu | unset | The graphics adapter to render on, spelled as --gpu is: a name ("NVIDIA", or the full name the settings menu writes) or a bare roster index. Unset means the high-performance adapter |
The name is tried before the index because the window system’s monitor ordering can shift across a boot or a hotplug, so a stored index alone may point at the wrong screen.
gpu is stored by name for the same reason: the adapter roster orders differently per operating
system and driver, so an index alone can name the wrong GPU after an update. --gpu overrides it
for one run without writing it. A name that matches more than one adapter is ambiguous, and a stored
adapter that is absent, ambiguous or cannot drive the window falls back to the high-performance
default with a line saying so, where the flag would refuse to start — see
--gpu above. The settings menu’s Adapter row moves the
running show and writes this key; Running the app says what a
switch costs.
[input]
Where audio comes from. Windows-only; the macOS path taps system audio and the Linux path the default output’s monitor, and neither takes an endpoint choice — the keys are read and inert there.
| Key | Default | What it means |
|---|---|---|
mode | "loopback" | "loopback" taps a render device (what the system is playing); "line-in" captures an input device |
device | "default" | Friendly device name to capture. "default", or a name matching no active endpoint, falls back to the selected mode’s default endpoint |
[rotate]
The scene director’s auto-rotate policy.
| Key | Default | What it means |
|---|---|---|
auto | false | Auto-rotate on the dwell timer; manual-only (Space) when off |
order | "shuffled" | The order rotation walks the eligible set in: "shuffled", or "sequential" for ascending preset-name order, wrapping |
min_dwell_secs | 20 | Never rotate sooner than this many seconds after the last change |
max_dwell_secs | 90 | Always rotate by this many seconds, even through a steady passage |
track_change | true | Let the track-change novelty signal nudge rotation in on the same dwell |
source | "all" | Which part of the library rotation draws from: "all", or "favourites" for the presets you have marked |
seed | absent | Pins the shuffle’s order. Absent, the shell picks a different number each launch; set, the walk repeats exactly. Ignored by "sequential" |
What rotation draws from, and in what order. Hidden presets are excluded from both sources —
that is what hiding one means. "favourites" is a hard filter with a fallback: it narrows to the
marked presets, and while none are marked it draws from the whole eligible set rather than holding
one scene forever. Within whichever set that leaves, order decides the walk. "shuffled", the
default, shows every eligible preset once before showing any of them twice, reshuffles when the
cycle is exhausted, and never ends one cycle and begins the next on the same preset.
"sequential" walks the eligible set in ascending preset-name order and wraps, recomputing the
successor against the set each draw — so hiding a preset mid-show skips it without the walk losing
its place. Backspace steps back through what was actually shown, under either order. Both keys are
also the R and L hotkeys and two rows of the settings menu, and a change made there is written
back here.
seed is how a run is reproduced. With no seed key the shuffle starts from a number the shell
varies per launch, so two runs of one build do not replay one order — which is what the shuffle has
always claimed to do. That matters most on the --stream path, where rotation runs even with
auto = false and nobody is at the keyboard to notice the order changed: a headless run someone
wants to reproduce frame for frame needs seed set. Nothing enforces it. "sequential" ignores the
key entirely, because its order is the library’s.
Hold one scene by default. Out of the box the app stays on a single scene until you opt in — the
A hotkey, or auto = true here. Manual Space works either way. When auto is on the defaults
favour a mostly-predictable, timer-led rotation: a steady passage holds to the 90 s cap and never
rotates before 20 s. An energy drop can land a change early, but only well past the minimum dwell
(a softened gate, around 37.5 s at these defaults), so it cannot flip scenes every few seconds.
[quality]
| Key | Default | What it means |
|---|---|---|
tier | "auto" | "auto" lets the engine resolve rich and demote it if the frame time says so; "floor" and "rich" pin it |
grid_scale | "auto" | The fraction of the window the internal grids are drawn at: a number from 0.25 to 1, or "auto" to let the engine pick one for the tier and the kind of GPU from the table below. A number outside the range makes the file fail to parse, which the app reports before starting on the defaults |
What "auto" resolves to in a window, by tier and the kind of GPU the adapter reports:
| Tier | Integrated GPU | Discrete GPU | Software rasterizer, other |
|---|---|---|---|
floor | 1 | 1 | 1 |
rich | 0.75 | 1 | 1 |
The integrated row is a measurement: the largest scale at which the reference laptop’s integrated
GPU held 60 fps at 1080p across the ten heaviest presets
(ADR-0245). It is not a promise above
1080p, where no rich scale held on that machine. The other rows are 1 by decision. A tier change
re-resolves the scale, so a rich window the governor demotes to floor goes back to 1. A
headless run (shot, --stream) takes 1 whatever the GPU unless --grid-scale says otherwise.
Precedence, highest first, for both keys alike:
| Key | Highest | Lowest | ||
|---|---|---|---|---|
tier | --tier | RLX_TIER | [quality] tier | auto |
grid_scale | --grid-scale | RLX_GRID_SCALE | [quality] grid_scale | auto |
A choice made from inside the app — [ and ] or the settings menu’s Quality row for the tier, the
Grid scale row for the scale — is written here, so it survives a restart, and the flag and the
variable still win at the next launch.
[hud]
The furniture the shell paints over the show. Separate from [output] because it is about what is
painted, not about which screen the window opens on.
| Key | Default | What it means |
|---|---|---|
preset_name | true | Draw the active preset’s name in the top-left corner. Even when on, the name yields to a menu and to the F3 panel — this is “never show it”, not “show it always” |
now_playing | true | Announce the current track in the lower-left corner when it changes. Off means no track ever reaches the visualizer, not a banner drawn transparent |
next_rotation | true | Count down to the next auto-rotate, under the preset name. Nothing is drawn while auto-rotate is off, so this key only decides whether the line appears when there is a countdown |
diagnostics | false | Paint the diagnostics overlay — the panel F3 and the settings menu’s Diagnostics row toggle. Set it to true to come up with the panel already open on a machine you are measuring |
[osc]
The lighting telemetry sink. Off by default, like every optional sink: a user who runs no lighting rig must not have a socket bound or a datagram leaving their machine because they installed the app.
| Key | Default | What it means |
|---|---|---|
enabled | false | Publish telemetry |
target | "127.0.0.1:9000" | Where to send, as host:port. Inert until enabled (or --osc) turns the sink on |
rate_hz | 60 | Datagram sets per second; 0 means every rendered frame, whatever the frame rate |
--osc overrides target and turns the sink on, and leaves rate_hz to the file — the one key it
has no spelling for.
[control]
The studio control-in listener — the socket a studio, a lighting console or a MIDI bridge drives this player from (the control protocol). Off by default, and loopback by default, and those are two separate promises: off means a machine that was never asked to be driven binds no port at all, and loopback means one that was asked, and named no host, is reachable only from itself.
| Key | Default | What it means |
|---|---|---|
enabled | false | Listen for control messages |
listen | "127.0.0.1:9001" | Where to listen, as host:port. Inert until enabled (or --control) turns the listener on |
--control overrides listen and turns the listener on, exactly as --osc does for the sink.
The port is one above [osc] target’s so the two OSC surfaces read as a pair and a machine
running both needs neither moved.
Binding anywhere but loopback is a decision, not a default. Anything that can reach the port
can move a parameter on the running show, which is the whole feature and also the whole of the
exposure — there is no authentication, and OSC has no channel to carry one. On a venue network,
leave it on 127.0.0.1 and run the studio on the same machine.
[console]
The operator console’s second window. Off by default, for the reason every optional surface here is: a config that has never heard of a console produces exactly one window, one surface, no intermediate render target and no extra copy per frame.
| Key | Default | What it means |
|---|---|---|
enabled | false | Open the console at launch |
display_name | unset | Preferred monitor identity for the console, matched by name before the index. Unset means “use the index” |
display | 1 | Fallback monitor index when no display_name matches |
frame_latency | 1 | The console swapchain’s desired_maximum_frame_latency, clamped to 1..=3. At 1 the surface holds a single in-flight image, so acquiring the next one waits for its own previous present to retire |
present_every_n | 1 | Present the console every Nth output frame. At 1 every frame; at 2 the console’s readout updates at half rate, which is visible on the transport strip and the preview |
Neither of the last two needs touching on a machine that keeps up. They exist so the console’s cost can be measured rather than argued about; the defaults above are the shipped ones, and what they cost in practice is in Running the app.
display defaults to 1, not 0: a console’s whole point is to be on a display other than the
show’s, and the show defaults to 0. On a single-monitor machine this falls back to the only
monitor there is, which is the correct degrade rather than a failure.
[thumbnails]
The background pass that renders the browser’s pictures into
thumbnails/. On by default, because the
pictures are what the browser’s pane is for.
| Key | Default | What it means |
|---|---|---|
enabled | true | Render missing and stale pictures in the background, from launch |
The pass starts when the app does, whether or not the browser is ever opened, and renders one
preset at a time by starting the app’s own executable with --thumb, at low priority (nice on
Linux and macOS, below-normal priority on Windows). It parks when every preset has a current
picture, walks the library again when an RLX_PRESET_DIR edit reloads it, and at the next launch
picks up whatever is still missing. It never waits in the
show’s frame loop, and closing the app kills a render in flight; the half-written file that leaves
is discarded by the next pass.
It gives up rather than retrying. A render that fails is named once in diagnostics.log with the
reason the child printed, and is not retried until its file changes or the app restarts; three failures in a row stop the
pass for the rest of the run. That is where a machine with no room for a second graphics context, or
security software that blocks an app from starting copies of itself, shows up. Every pass writes a
thumbnail pass: line to the same log when it starts and when it ends, which splits the log’s
frame-time rows into the stretch the pass ran in and the stretch after it.
Turn it off on a machine running on battery or under security software that objects: the settings menu’s Thumbnails row writes this key, and turning it off also stops a pass that is running. Pictures already in the cache still show either way.
[ui]
How the interface drawn over the show behaves, where [hud] is what it draws.
| Key | Default | What it means |
|---|---|---|
motion | "full" | "full": the browser and the settings menu fade and slide as they open and close, the selection glides between rows, the corner name crossfades when the preset changes, and the now-playing banner eases in and out. "reduced": every one of those is a step, so things appear and vanish in one frame |
| hints | true | Show the key hint — ? help Tab browse S settings — in the lower-right corner for a few seconds at launch, and again whenever the pointer moves over the window. It is never drawn while a menu is open |
The animation is only ever a view: a key pressed while a menu is still opening acts on that frame, under either value. The settings menu’s Motion and Key hints rows write these two keys.
A complete file
Every key at its default. display_name in [output] and [console], and gpu in [output],
are absent because “unset” is their default and the file format has no spelling for one.
[output]display = 0fullscreen = false
[input]mode = "loopback"device = "default"
[rotate]auto = falseorder = "shuffled"min_dwell_secs = 20max_dwell_secs = 90track_change = truesource = "all"# seed = 7 # absent: the shuffle varies per launch. Set: it repeats exactly.
[quality]tier = "auto"grid_scale = "auto"
[hud]preset_name = truenow_playing = truenext_rotation = truediagnostics = false
[osc]enabled = falsetarget = "127.0.0.1:9000"rate_hz = 60
[control]enabled = falselisten = "127.0.0.1:9001"
[console]enabled = falsedisplay = 1frame_latency = 1present_every_n = 1
[thumbnails]enabled = true
[ui]motion = "full"hints = trueBuilt from 13c7582 at version 0.158.0. This site tracks main and is not versioned per release.