General
How to configure Veila using config.toml.
Config lives at ~/.config/veila/config.toml by default. If it doesn't exist, the packaged default theme from themes/default.toml kicks in and if that's unavailable too, hardcoded safety defaults take over. No config file required to run.
To create a starter config explicitly:
veila init
veila init --theme windowveila init writes a minimal config.toml with a validated theme selection. It refuses to replace an existing config unless you pass --force.
To use a different config file, pass --config
veilad --config=/path/to/config.toml
veila lockValidate the active config before restarting or locking:
veila check-configFor a custom path:
veila --config=/path/to/config.toml init --theme default
veila check-config --config=/path/to/config.tomlThe command checks TOML syntax, theme and include loading, config value types, color parsing, and unknown keys in config.toml, active includes, and the selected theme. It exits non-zero when validation fails.
Color Values
All color fields in the config accept the following formats:
color = "#202833" # hex RGB
color = "#202833CC" # hex RGBA (last two digits = alpha)
color = "rgb(32, 40, 51)"
color = "rgba(32, 40, 51, 0.8)"Lock
Use Lock to configure what happens while the screen is locked, including retry delays, screen-off timing, suspend behavior, and the text shown inside the password field.
[lock]
acquire_timeout_seconds = 5
auto_reload_config = true
auto_reload_debounce_ms = 250
log_to_file = false
log_file_path = "~/.local/state/veila/veilad.log"
auth_backoff_base_ms = 750
auth_backoff_max_seconds = 12
hide_cursor = false
allow_empty_password = true
screen_off_seconds = 10
power_off_secondary_outputs = false
suspend_seconds = 300
suspend_only_on_battery = false
skip_suspend_while_media_playing = false| Key | What it does | Default | Accepted values |
|---|---|---|---|
acquire_timeout_seconds | Timeout for the session-lock handshake. | 5 | integer (min 1) |
auto_reload_config | Automatically reload valid config changes | true | true, false |
auto_reload_debounce_ms | Delay before applying config | 250 | integer ms (effective clamp 250..5000) |
log_to_file | Daemon logging to a file | false | true, false |
log_file_path | Path used when log_to_file = true | - | file path |
auth_backoff_base_ms | Base delay after a failed auth attempt | 750 | integer ms |
auth_backoff_max_seconds | Maximum retry delay cap | 12 | integer seconds |
hide_cursor | Hide the pointer cursor while it is over the lock surface | false | true, false |
allow_empty_password | Submit empty Enter presses to PAM, useful for U2F or fingerprint PAM flows | true | true, false |
screen_off_seconds | Powers displays off while locked | none | integer seconds |
power_off_secondary_outputs | Powers off background-only secondary monitors after lock readiness when [visuals.outputs].ui_mode = "single" | false | true, false |
suspend_seconds | Suspend system while locked | none | integer seconds |
suspend_only_on_battery | Suspend system only on battery power | false | true, false |
skip_suspend_while_media_playing | Skip suspend on actively playing MPRIS media | false | true, false |
suspend_seconds is independent from screen_off_seconds. External idle or power-management daemons can conflict with it because the suspend request goes through logind while the session is already locked.
power_off_secondary_outputs is only used when [visuals.outputs].ui_mode = "single". Veila still locks every output first, then powers off only the secondary curtain outputs if the compositor supports output power management.
Auto reload only applies when the updated config parses successfully, whether the change came from config.toml, the active wallpaper, or the active theme file. Invalid edits are ignored and the current active config stays in use.
veila logs is the friendly path for packaged systemd user-service logs. Use veila logs --file when [lock].log_to_file = true. veilad --log-file=/path/to/file.log still exists as a one-off override and takes priority over [lock].log_to_file plus [lock].log_file_path for that launch only.
Fingerprint
Use Fingerprint to enable experimental native fprintd verification
[fingerprint]
enabled = false| Key | What it does | Default | Accepted values |
|---|---|---|---|
enabled | Start native fprintd verification while locked | false | true, false |
When enabled, Veila asks fprintd to verify any enrolled finger for the current user while keeping the password input available. If no supported reader is present, no fingerprints are enrolled, or fprintd fails, Veila remains locked and password authentication continues to work normally.
Per-monitor
Per-monitor wallpapers are configured with repeated [[background.outputs]] tables. name must match the Wayland output name reported by the compositor, such as DP-1, HDMI-A-1, eDP-1, etc. Each override only changes the wallpaper path for that output. blur, dim, tint and fallback still come from [background].
[background]
mode = "file"
path = "/path/to/default.jpg"
[[background.outputs]]
name = "DP-1"
path = "/path/to/left.jpg"
[[background.outputs]]
name = "HDMI-A-1"
path = "/path/to/right.jpg"If an output has no matching override, it will falls back to the normal [background] source. If an override cannot be used, the secure lock surface still renders the fallback color or default background
Using different large images on high-resolution multi-monitor setups can add some lock latency and memory pressure especially on cold cache
Include Files
Extra TOML can be loaded via the top-level include key. Usefull for dynamic color tools like matugen, cwal, wallust, or pywal where the generated file only contains colors and your main config.toml keeps the lockscreen settings.
include = ["~/.cache/matugen/veila.toml"]
theme = "default"
[background]
mode = "file"
path = "/home/user/Pictures/wallpaper.jpg"The included file can contain normal config sections:
[background]
color = ""
[visuals.clock]
color = ""
[visuals.input]
background_color = ""
border_color = ""
# and moreThe main config always wins over included files. Missing includes are skipped silently, so startup works even before a generator writes its first output. Existing include files must be valid TOML. If a generated file is invalid, auto reload ignores the update and keeps the last known good config.
Includes are intentionally non-recursive. theme and include keys inside included files are ignored, so generated fragments can only act as config overrides.
Background
Use Background to choose what appears behind the lock UI, either a wallpaper image or a generated color scene.
[background]
mode = "gradient"
color = "#202833"
scaling = "fill"
dim_strength = 54
[background.gradient]
top_left = "#A85BFF"
top_right = "#39B8FF"
bottom_left = "#6FE2FF"
bottom_right = "#6F4CFF"
[[background.outputs]]
name = "DP-1"
path = "/path/to/left.jpg"
[[background.outputs]]
name = "HDMI-A-1"
path = "/path/to/right.jpg"| Key | What it does | Default | Accepted values |
|---|---|---|---|
mode | Background source | "gradient" | "file", "gradient", "layered", "radial", "solid" |
path | Wallpaper image path | none | file path |
outputs | Optional per-monitor wallpaper overrides | [] | array of { name, path } entries |
color | Fallback or solid color | "#202833" | any color value |
scaling | How mode = "file" wallpapers are placed inside each output | "fill" | "fill", "fit", "center", "tile", "stretch" |
gradient | Optional corner colors used when mode = "gradient" | built-in four-corner palette | nested table |
layered | Optional base plus up to three soft blobs used when mode = "layered" | generated base with no blobs | nested table |
radial | Optional colors and position used when mode = "radial" | built-in center/edge palette | nested table |
blur_strength | Wallpaper blur strength | 0 | 0..255 (capped at 12 by renderer) |
dim_strength | Darkens the wallpaper | 54 | 0..100 percent |
tint | Optional color wash over the background | none | any color value |
slideshow | Optional lock-active wallpaper rotation for mode = "file" | none | nested table |
"gradient"- generate four-corner gradient using[background.gradient]"layered"- generate base plus up to three soft blobs using[background.layered]"radial"- generate radial bloom using[background.radial]"solid"- renders onlycolor, ignorespath"file"- scales the image per output with blur, dim, and tint applied
tint fully owns its alpha. Use rgba(...), #RRGGBBAA or another alpha-capable color format when you want a translucent wash.
For mode = "file":
"fill"covers the full output and crops overflow"fit"keeps the whole image visible and fills bars withbackground.color"center"keeps the original image size, centered, and clips only if it is larger than the output"tile"repeats the image across the full output"stretch"scales the image to the output size without preserving aspect ratio
Slideshow
Use Slideshow when you want to cycle through multiple wallpaper images while the screen is locked.
Set mode = "timed" to keep changing images during the same lock session. Set mode = "lock_only" when you only want one image picked each time the screen locks.
[background.slideshow]
enabled = true
directory = "~/Pictures/Wallpapers"
mode = "timed"
# files = [
# "~/Pictures/Wallpapers/01.jpg",
# "~/Pictures/Wallpapers/02.jpg"
# ]
order = "random"
change_every_seconds = 60| Key | What it does | Default | Accepted values |
|---|---|---|---|
enabled | Enable module | true | true, false |
directory | Scans for jpg, jpeg, png, and webp | none | directory path |
files | Explicit slideshow image list | [] | array of file paths |
order | Slide traversal order | "sequence" | "sequence", "random" |
mode | Rotating while locked or only change on each new lock. | "timed" | "timed", "lock_only" |
change_every_seconds | How long each slide stays visible while locked when mode = "timed" | 300 | integer seconds (min 1) |
Color Generated
Use Color Generated backgrounds when you want a clean, polished lock screen without choosing a wallpaper image. For more complete examples, see Color backgrounds.
Gradient
[background]
mode = "gradient"
blur_strength = 0
dim_strength = 0
[background.gradient]
top_left = "#A85BFF"
top_right = "#39B8FF"
bottom_left = "#6FE2FF"
bottom_right = "#6F4CFF"Radial
[background]
mode = "radial"
blur_strength = 0
dim_strength = 0
[background.radial]
center = "#6FE2FF"
edge = "#6F4CFF"
center_x = 50
center_y = 50
radius = 100Layered
[background]
mode = "layered"
blur_strength = 0
dim_strength = 0
[background.layered.base]
mode = "gradient"
[background.layered.base.gradient]
top_left = "#A85BFF"
top_right = "#39B8FF"
bottom_left = "#6FE2FF"
bottom_right = "#6F4CFF"
[[background.layered.blobs]]
color = "#FFFFFF"
opacity = 16
x = 18
y = 12
size = 42
[[background.layered.blobs]]
color = "#7C4DFF"
opacity = 22
x = 82
y = 78
size = 50Weather
Show the current forecast. After enabling weather, you can adjust how it looks in the Visuals weather settings
[weather]
enabled = true
location = "Riga"
refresh_minutes = 15
unit = "celsius"| Key | What it does | Default | Accepted values |
|---|---|---|---|
enabled | Enables weather refresh and the cached widget. | true | true, false |
location | Place name for display and geocoding. | "Riga" | string |
latitude | Explicit latitude in decimal degrees. | none | decimal number |
longitude | Explicit longitude in decimal degrees. | none | decimal number |
refresh_minutes | Daemon-side refresh interval. | 15 | 0..65535 (effective minimum 5) |
unit | Temperature unit. | "celsius" | "celsius", "fahrenheit" |
If latitude and longitude are both set, they are used directly and geocoding is skipped.
Battery
Show battery level and control how often it checks for updates. Mock values are available when you want predictable output for testing or screenshots
[battery]
enabled = true
refresh_seconds = 30| Key | What it does | Default | Accepted values |
|---|---|---|---|
enabled | Enables battery polling. | true | true, false |
refresh_seconds | Polling interval. | 30 | 0..65535 (effective minimum 15) |
mock_percent | Forces a fake battery percentage. | none | 0..100 |
mock_charging | Forces the mock charging state. | none | true, false |
On systems without a battery the widget stays hidden unless mock_percent is set. Mock values are intended for testing and theme screenshots only
Now Playing
Choose which media players can appear on the lock screen. For example, you can show music from Spotify or mpv while hiding browser players
After choosing which players are allowed here, you can adjust how the widget looks in the Visuals now-playing settings
[now_playing]
include_players = ["Spotify", "mpv"]
exclude_players = ["Firefox", "Chromium"]| Key | What it does | Default | Accepted values |
|---|---|---|---|
include_players | Shows MPRIS players. When empty, all players are eligible | [] | array of strings |
exclude_players | Hides matching MPRIS players from the now-playing | [] | array of strings |