Veila
Configuration

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 window

veila 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 lock

Validate the active config before restarting or locking:

veila check-config

For a custom path:

veila --config=/path/to/config.toml init --theme default
veila check-config --config=/path/to/config.toml

The 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
KeyWhat it doesDefaultAccepted values
acquire_timeout_secondsTimeout for the session-lock handshake.5integer (min 1)
auto_reload_configAutomatically reload valid config changestruetrue, false
auto_reload_debounce_msDelay before applying config250integer ms (effective clamp 250..5000)
log_to_fileDaemon logging to a filefalsetrue, false
log_file_pathPath used when log_to_file = true-file path
auth_backoff_base_msBase delay after a failed auth attempt750integer ms
auth_backoff_max_secondsMaximum retry delay cap12integer seconds
hide_cursorHide the pointer cursor while it is over the lock surfacefalsetrue, false
allow_empty_passwordSubmit empty Enter presses to PAM, useful for U2F or fingerprint PAM flowstruetrue, false
screen_off_secondsPowers displays off while lockednoneinteger seconds
power_off_secondary_outputsPowers off background-only secondary monitors after lock readiness when [visuals.outputs].ui_mode = "single"falsetrue, false
suspend_secondsSuspend system while lockednoneinteger seconds
suspend_only_on_batterySuspend system only on battery powerfalsetrue, false
skip_suspend_while_media_playingSkip suspend on actively playing MPRIS mediafalsetrue, 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
KeyWhat it doesDefaultAccepted values
enabledStart native fprintd verification while lockedfalsetrue, 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 more

The 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"
KeyWhat it doesDefaultAccepted values
modeBackground source"gradient""file", "gradient", "layered", "radial", "solid"
pathWallpaper image pathnonefile path
outputsOptional per-monitor wallpaper overrides[]array of { name, path } entries
colorFallback or solid color"#202833"any color value
scalingHow mode = "file" wallpapers are placed inside each output"fill""fill", "fit", "center", "tile", "stretch"
gradientOptional corner colors used when mode = "gradient"built-in four-corner palettenested table
layeredOptional base plus up to three soft blobs used when mode = "layered"generated base with no blobsnested table
radialOptional colors and position used when mode = "radial"built-in center/edge palettenested table
blur_strengthWallpaper blur strength00..255 (capped at 12 by renderer)
dim_strengthDarkens the wallpaper540..100 percent
tintOptional color wash over the backgroundnoneany color value
slideshowOptional lock-active wallpaper rotation for mode = "file"nonenested 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 only color, ignores path
  • "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 with background.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
KeyWhat it doesDefaultAccepted values
enabledEnable moduletruetrue, false
directoryScans for jpg, jpeg, png, and webpnonedirectory path
filesExplicit slideshow image list[]array of file paths
orderSlide traversal order"sequence""sequence", "random"
modeRotating while locked or only change on each new lock."timed""timed", "lock_only"
change_every_secondsHow long each slide stays visible while locked when mode = "timed"300integer 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 = 100

Layered

[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 = 50

Weather

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"
KeyWhat it doesDefaultAccepted values
enabledEnables weather refresh and the cached widget.truetrue, false
locationPlace name for display and geocoding."Riga"string
latitudeExplicit latitude in decimal degrees.nonedecimal number
longitudeExplicit longitude in decimal degrees.nonedecimal number
refresh_minutesDaemon-side refresh interval.150..65535 (effective minimum 5)
unitTemperature 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
KeyWhat it doesDefaultAccepted values
enabledEnables battery polling.truetrue, false
refresh_secondsPolling interval.300..65535 (effective minimum 15)
mock_percentForces a fake battery percentage.none0..100
mock_chargingForces the mock charging state.nonetrue, 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"]
KeyWhat it doesDefaultAccepted values
include_playersShows MPRIS players. When empty, all players are eligible[]array of strings
exclude_playersHides matching MPRIS players from the now-playing[]array of strings

On this page