Plugins

Each plugin draws one kind of layer and reads its own [plugin.config] table. Every key is optional, colors are 0.0–1.0 float arrays, and the schema belongs to the plugin: the core passes the table through verbatim, so a plugin you write yourself defines whatever properties it wants.

backgrounds

Meant for the bottom of the stack (low z_index).

pluginwhat it draws
veiland-wallpapera single image
veiland-gradientflowing color ramp
veiland-blobslava-lamp metaballs
veiland-raymarcherinfinite gyroid tunnels
veiland-shaderyour own GLSL, running live

overlays

Transparent plugins meant to sit above a background and below text.

pluginwhat it draws
veiland-vignettesoft corner darkening
veiland-parallaxlayered bokeh depth

particles

Six variations on one idea: a field of independent particles drifting across a transparent buffer, composited over your background. They share two keys — count and a color — plus one size key each; the motion itself (sway, timing, fades) is tuned per effect and not configurable.

count is an absolute number, not a density: the same value puts the same number of particles on a 1080p and a 4K monitor. Sizes (*_px) do scale with the output, so the particles themselves stay the same physical size.

pluginwhat it draws
veiland-particlesrising motes
veiland-sakurafalling petals
veiland-snowdendritic crystals
veiland-rainslanted streaks
veiland-embersrising sparks
veiland-fireflieswandering glow

widgets

Unlike the background plugins (which are Rust), these reference widgets are Python programs, installed as veiland-avatar, veiland-weather, veiland-now-playing, veiland-markup, veiland-shape, and the status pills veiland-wifi / veiland-ethernet / veiland-bluetooth / veiland-battery. They speak the same protocol and read the same [plugin.config] table; the language is an implementation detail. A widget reads live data (battery, network, media, weather) read-only and never receives keyboard input, exactly like any other plugin.

Shared keys. Most widgets honor the same opt-in conventions, so these are documented once here rather than repeated per widget:

Status pills (wifi, ethernet, bluetooth, battery) share a look: a monochrome glyph in a small translucent chip. They all take pill_color (chip background, default a translucent dark navy; [0,0,0,0] draws no chip) and icon_color (glyph tint, default white). Each pill page lists only what is unique to it — the label keys and data source.

pluginwhat it draws
veiland-avatarprofile disc
veiland-weathercurrent conditions
veiland-now-playingcurrent track
veiland-markupdynamic styled text
veiland-shapea rounded colored card
veiland-wifiWi-Fi status pill
veiland-ethernetwired link status pill
veiland-bluetoothBluetooth status pill
veiland-batterybattery status pill

How plugin options work

Plugin options live in the [plugin.config] table of a [[plugin]] entry. The host passes the table through to the plugin process verbatim (see the configuration reference); the keys documented per plugin are each plugin's own schema.

[[plugin]]
name = "sakura"
binary = "veiland-sakura"
z_index = 25

[plugin.config]
count = 40
size_px = 26.0
color = [1.0, 0.9, 0.95, 0.9]

Conventions shared by all first-party plugins:

The stress plugin

Not a lockscreen plugin. stress is a load generator used to benchmark the render→IPC→composite round trip; it burns GPU on a deliberately heavy shader, renders a fixed 1920×1080 buffer, ignores its assigned region by design, and prints frame timings to stderr. It reads no [plugin.config] keys at all — its knobs are compile-time constants. Leave it out of real configs.

Pitfalls

See also