One app for how your Omarchy desktop looks.
Colours, text, windows, the bar, your apps — in one place, in plain words,
live as you change them.
Omarchy gives you a beautiful desktop and a hundred files to change it in. Lacquer is the other half: one window, 370 settings, everything named in everyday words, and nothing that needs a restart to see.
There is no Apply button. Move a slider and your windows move with it. Change
your mind and Ctrl+Z puts it back. Everything Lacquer writes goes into one
fenced block in your own config, so it stays yours, and lacquer-cleanup
takes every trace of it back out.
▶ Watch the three-minute tour — every page, in one take (MP4, 30 MB)
Home is a printed contents page: a live miniature of your own windows drawn from your real settings, what you have changed, and a search box that finds any setting by name from anywhere in the app.
Everything is live. Pick a shape and your windows take it immediately — and the miniature on Home carries it too, so you can see what you did without leaving the app.
Nothing here is a mistake. Undo walks back through every change, every page has its own way back to normal, and the first time Lacquer touches a file it keeps a copy of it.
| Main tab | Pages |
|---|---|
| Colours & wallpaper | Themes and their wallpapers · Shuffle (a new theme on a schedule or with the sun) · Make a theme from any wallpaper · Saved looks |
| Screen & text | Fonts & text size · How text is drawn · Size of everything · Light or dark & icons · Mouse pointer · Resolution & scale · Night light · Lock, start-up & screensaver |
| Windows | Shape & border · Corners & see-through · Glass & shadow · Screen frame · Spacing & layout · Grouped windows · Motion feel · Animations · Animation curves |
| Top bar & menus | Bar & menu style · What sits in the top bar · The app menu's own look |
| Apps | Terminal · System monitor & prompt · App list · Per-app window rules · Add-ons |
Every setting is named in everyday words. Rest on one and it explains itself, with the technical name in small print underneath for anyone following a guide online.
The 1.0 release hid each setting's description until you rested the pointer on it. That opened the row and pushed everything below it down, so scrolling with a mouse re-flowed the page under your own cursor. Three people reported it, one rolled back. Descriptions are simply there again, as they were in the beta: nothing opens, nothing moves.
Along with it:
- The wheel no longer changes values when you scroll past a slider. Plain wheel scrolls the page; Ctrl+wheel still steps, on purpose.
- The window can be resized by the grip in its bottom-right corner, and the size is remembered. A layer-shell surface cannot be dragged by the compositor, which is why it could not be resized before.
- The tab marker is an underline again, rather than a brush stroke that read, accurately, as half-drawn.
- The Windows tab is no longer a telephone.
U+F118Fismd-phone_bluetooth_outlinein the installed Nerd Font. - The paper grain is lighter and even, and the key hints say "key – what it does" rather than running the two together.
- Per-app rules can pin an app to a screen, for a game on the big monitor and everything else wherever you are.
One thing that cannot be fixed from inside the app: Super+W will not close
Lacquer. Hyprland binds it globally, so the compositor consumes the key before
any client sees it. Esc closes, as does the ✕.
What 1.0 means here. Every setting has been round-tripped: set it, unset it, and the config file is byte-for-byte what it was. Lacquer has been built and tested on one laptop (1080p, one screen, foot, Hyprland via Omarchy 4). If yours is different — several screens, fractional scaling, another terminal — please open an issue for anything that looks wrong, with the output of
lacquer-reportattached.
omarchy plugin add https://github.com/Deunnis/omarchy-lacquer --enable
Then open Omarchy Lacquer from the app launcher (Super + Space); the plugin
adds its own launcher entry. From a terminal or a keybinding:
omarchy-shell shell toggle io.github.deunnis.lacquer
omarchy-shell shell summon io.github.deunnis.lacquer '{"section":"cursor"}'
Update with omarchy plugin update io.github.deunnis.lacquer.
Lacquer also answers directly, whether or not the panel is open:
omarchy-shell lacquer open '{"section":"theme"}' # or close, toggle
omarchy-shell lacquer showSection borders
omarchy-shell lacquer currentTheme
omarchy-shell lacquer applyTheme gruvbox
omarchy-shell lacquer setWallpaper ~/.local/state/omarchy/current/theme/backgrounds/…
omarchy-shell lacquer shuffleStatus
A theme name that is not a theme, a section that is not a section and a
wallpaper outside the current theme are all refused, and say so instead of
answering ok. setWallpaper checks where the file is, not that it is there:
a name that does not exist inside the current theme's backgrounds folder is
handed to Omarchy and quietly does nothing.
What happens without you changing anything: enabling the plugin adds its
launcher entry and a theme-switch hook (which does nothing until you pin a GTK
or icon choice). The first time the app opens it copies looknfeel.lua,
shell.toml and shell.json to *.lacquer-backup-<time>. Beyond that, only
a change you make writes anything, and the theme shuffle is off until you
turn it on.
- Omarchy 4 (Quattro), with its Lua Hyprland config.
- Everything else Lacquer calls ships with Omarchy:
aether,jq,lua,python3,gsettings,hyprsunset, andimagemagickfor the boot unlock screen's logo (that one page says so and stops if it is missing; nothing else needs it).
Optional, for one section each:
| Plugin | Adds |
|---|---|
| Lacquer Shell | Screen frame (corners, frame, vignette, scanlines, grain), and an animated clone of the bar (Omarchy 4.0.4+). Lacquer offers to install it when you open the section. |
| lock-explorer | Lock & boot: lock designs, unlock animation, clock and its own boot screens. Without it the section still sets when the screen locks and the boot unlock screen. |
| OmaMenu with Menu Look IPC | Menu look. Without it the section is not shown. |
| OmaShuffle | Nothing extra: while it is installed, Lacquer's Shuffle stays out of its way. |
Lacquer's changes are ordinary config, so removing the plugin alone leaves them in effect. To undo them first:
~/.config/omarchy/plugins/io.github.deunnis.lacquer/lacquer-cleanup # shows what it would undo
~/.config/omarchy/plugins/io.github.deunnis.lacquer/lacquer-cleanup --yes # undoes it
omarchy plugin remove io.github.deunnis.lacquer
lacquer-cleanup removes Lacquer's blocks from looknfeel.lua, hyprland.lua
and autostart.lua, puts back Omarchy's hyprsunset.conf if Lacquer wrote
one, unpins GTK and icon choices, resets a saved cursor, and deletes its
text-drawing file, hook, launcher entry and state. It lists, and leaves alone, what are ordinary
settings elsewhere: shell.toml/shell.json values, fonts and text size,
terminal/btop/starship lines, lock-explorer and OmaMenu settings, and the
backups. Skipping it is fine too: the launcher entry goes when the plugin is
disabled, and the hook deletes itself at the next theme switch.
Lacquer writes almost nothing itself. Wherever a tool already owns a setting —
omarchy theme set, omarchy font set, gsettings, hyprctl, aether's CLI,
lock-explorer's IPC, omamenu's IPC — Lacquer calls that tool. The files it
does write, it edits line by line in their own format, and every write path
was checked to put a file back byte-for-byte when a value is set back.
Lacquer opens on Home (a section in the summon payload opens elsewhere):
- A live miniature of this desktop. Your wallpaper and bar, windows drawn
with your gaps, border width, rounding, opacity and theme accent, re-tiling
every few seconds on your own
windowsMovecurve and speed, with a pointer following focus. Change a setting and the miniature follows. - The theme's palette as soft discs drifting behind the page, and a swatch row that ripples.
- Search across every setting (355 today: look & feel rows, animation leaves, shell.toml tokens, and the groups of the Desktop, Screens and Apps views). Just start typing; Enter opens the section with the cursor on the match.
- Every section with what it is set to right now, in cards that rise in when Home opens.
Everything moving is paused whenever Home is not on screen. Measured on a Ryzen 5 4500U laptop, any animation that runs at the display rate without pause costs about 12 % of a core, whatever it draws, so the drift and ripple are stepped at ~15 frames a second, the caret blinks without fading, and the miniature rests a few seconds between re-tiles: Home costs about 7 % of one core while open.
Motion (under Theme) is one pick for how the whole desktop moves. A feel — Calm, Standard, Expressive or Snappy — carries four bezier curves and a duration for every family of movement, and setting one writes Hyprland's animation curves and speeds for windows, layers, fades, workspaces and borders, sets the pace of Lacquer's own pages, and (with the companion installed) the bar's. A speed multiplier scales the whole feel without changing its shape. The shape of this is borrowed from Material 3's motion scheme.
A feel is a starting point, not a mode: Animations and Curves still edit every value underneath, and the section says when they no longer match the feel.
Curves a feel writes are its own (lqEnter, lqExit, lqMove, lqEmphasis),
so a theme's curves are never overwritten.
Switching sections glides the page in from the direction you moved along the rail, with a fade and a small settle; the rail's accent marker slides and stretches to the new entry; rows and groups cascade in; sub-tabs slide in from the side.
Motion in the header (or Ctrl+M) turns every animation Lacquer draws on
or off: transitions, the rail marker, cascades, Home's live miniature, palette
and blinking caret, and the rows' fades. It is saved in
~/.local/state/omarchy/io.github.deunnis.lacquer/ui.json. With it off, Home costs no
more than a closed panel. Two things are not covered: the curve preview's Play
button (it is the feature), and the hover fades built into Omarchy's own
buttons, which Lacquer does not own.
Omaland also writes look and
feel into looknfeel.lua. When Lacquer finds Omaland's block it shows a banner
and does nothing else. Import settings (Ctrl+I) copies Omaland's values into
Lacquer's own block (on top of anything already set in Lacquer) and removes
Omaland's block. Uninstall Omaland asks again before running
omarchy plugin remove. Not now hides the banner for the session. Keeping
both installed works, but for a setting both of them change, whichever block
comes later in looknfeel.lua is the one Hyprland uses.
OmaShuffle: see Shuffle below.
Live, with undo. Nothing to press.
| during a drag | hyprctl eval only — nothing touches disk |
| on release | debounced write of the block, then hyprctl reload |
That split is why dragging a slider does not fire dozens of reloads. Every row has a reset-to-default and every section a reset.
Ctrl+Z covers looknfeel.lua and shell.toml — the two files Lacquer
owns outright. It deliberately does not cover shell.json: the bar layout
and plugin settings are also written by the omarchy CLIs and by the shell
itself, and replaying a whole-file snapshot over that would clobber changes
Lacquer never made. Undo a bar or plugin change by changing it back.
hyprctl keyword is not usable — Hyprland rejects it under the Lua parser
("keyword can't work with non-legacy parsers, use eval").
Live apply means a mistake reaches disk, so the first time Lacquer ever runs it snapshots the three files it rewrites outright:
~/.config/hypr/looknfeel.lua.lacquer-backup-<timestamp>
~/.config/omarchy/shell.toml.lacquer-backup-<timestamp>
~/.config/omarchy/shell.json.lacquer-backup-<timestamp>
The other files Lacquer writes — hyprland.lua, autostart.lua,
monitors.lua, and a tool's own config when you ask one to follow the theme —
are only ever added to between fences, and taking the fences out puts them back
exactly, so they are not copied.
Once only — a marker in ~/.local/state/omarchy/ — so the snapshot is of the
state before Lacquer, not of whatever it wrote yesterday. If a migration is
due, it waits for the backup to finish rather than racing it, so the snapshot
always shows the world as it was.
Every installed theme with a colors.toml (an empty folder such as a half-made
themes/aether would apply a broken theme, so it is hidden), with previews and
a palette strip, and the active theme's wallpapers. Picking applies through
omarchy theme set / omarchy theme bg set.
OmaShuffle's engine, carried over: a new theme on every real boot, or Day &
Night themes that follow sunrise and sunset. It runs in Service.qml, so it
works with Lacquer closed. State lives in
~/.local/state/omarchy/io.github.deunnis.lacquer/shuffle.json.
While io.github.omashuffle is installed, Lacquer's engine stays dormant
so the two never both switch the theme on the same boot or sunset. The
section's "Move to Lacquer" button removes OmaShuffle — only when pressed and
confirmed — and only then does the engine adopt its state, including the last
boot id, so the restart that follows is not counted as a boot. Uninstalling
OmaShuffle any other way does not switch the shuffle on in Lacquer. On a fresh
install the shuffle is off until you turn it on.
Two upstream quirks are fixed in the copy: a manual latitude of null no
longer becomes 0, and a theme applied from outside the engine now clears a
stale manual pick.
aether, driven by its CLI. Choose the source by clicking the preview or
All wallpapers… (w), which opens Omarchy's own image picker with every
installed theme's wallpapers, or Other image… (f), the desktop file
chooser. Lacquer closes while you pick and comes back on Generate with your
choice. The palette preview uses --extract-palette and changes nothing. Generate & apply runs aether --generate, which switches
the whole desktop to a theme called aether and, unless unticked, writes theme
files into Zed, VS Code and Neovim — so it asks twice. Saved blueprints apply
with --apply-blueprint; everything else is one click away in aether itself.
A look is the whole set under one name: the theme, the entire Hyprland block
(spacing, borders, corners, effects, motion, the desktop colour), the bar and
menu style as your own shell.toml text, fonts and text size, the pointer, the
GTK pins, and how text is drawn. Naming one keeps what is on the screen; picking
it puts all of it back.
Deliberately not in a look: window rules, monitor arrangement and launcher entries. Those describe a machine and its apps, and carrying them to another computer would do harm rather than good.
Applying always keeps a Just before first, so the way out never depends on
having thought of it beforehand. Write them to a file puts every look in
~/lacquer-looks.json — the same file Lacquer stores them in — so moving your
desktop to another machine is a copy rather than an export format of its own,
and Read a file in… merges one back. Anything read from a file is treated as
a stranger: only the shapes Lacquer writes survive, names and slugs are clipped,
and at most a hundred looks are taken.
The first time Lacquer opens it shows seven notes, about a minute, each pinned over the thing it is talking about. The sheet washes out around a ring, and the ring is a real hole — so where a note says to click, the click reaches the control underneath. Escape closes the notes rather than the app, Enter turns the page, and it puts you back on the page you started from.
Afterwards it lives behind the lamp in the header. Wiping Lacquer's state folder brings it back on the next opening.
| applied with | survives a theme switch | |
|---|---|---|
| Text size | omarchy display text size |
yes |
| Terminal font | omarchy font set (restarts the shell; Lacquer reopens where it was) |
yes |
| Interface font | gsettings font-name |
yes |
| Light/dark apps, GTK theme, icons | gsettings, pinned | only when pinned |
| Cursor | hyprctl setcursor + gsettings + Lacquer's block in hypr/autostart.lua |
yes |
| Nightlight | hypr/hyprsunset.conf + autostart |
yes |
| How text is drawn | ~/.config/fontconfig/conf.d/99-lacquer-rendering.conf |
yes |
| Pointer behaviour | Lacquer's block in hypr/looknfeel.lua (cursor:*) |
yes |
Every theme switch resets the GTK theme, colour scheme and icons to what the
theme asks for. A pick in GTK & icons is a pin: it is kept in pins.json
and put back by ~/.config/omarchy/hooks/theme-set.d/lacquer-reapply after
the switch. Anything not picked keeps following the theme; Del (or
Follow theme) unpins. The hook deletes itself if Lacquer is uninstalled.
Two Omarchy quirks are worked around, not changed:
omarchy font setsets foot back to 9 pt and its alacritty substitution is greedy, eatingstyle = "Bold"from one-line font tables. Lacquer restores foot's size and rewrites the family inside its quotes only.- Text size re-derives every terminal's size from the px value, so the section says what a step will set terminals to before you press it.
How text is drawn — smoothing, hinting and the screen's subpixel order — is
fontconfig's, not Hyprland's. Lacquer owns one file of its own for it so your
fonts.conf is never touched, and Back to normal leaves that file with
nothing in it, which is the same as not having it. What the page shows before
anything is set is measured with fc-match rather than guessed. Nothing here
previews: an app reads fontconfig when it starts.
Mouse pointer carries the style and size, and what the pointer does: hide it while you type, hide it when it has sat still, jump it to the window you land on, magnify around it, and who draws it.
Add a font and Add a cursor theme take a download straight from the
desktop file chooser: a .ttf/.otf, a theme folder, or a .zip/.tar.gz of
either. add-asset unpacks archives itself rather than calling tar/unzip,
so a member cannot escape the target folder (absolute paths, .., symlinks,
hard links and devices are refused) or fill the disk (member, size, count and
depth caps). Only files of the kind are taken: fonts land flattened in
~/.local/share/fonts/<name>/ and the font cache is rebuilt; a cursor theme
keeps its own folder name in ~/.local/share/icons/. Nothing outside the
picked path is read, and an existing folder is never overwritten — a second
copy becomes <name>-2.
The cursor and nightlight autostart share a second fenced block, in
~/.config/hypr/autostart.lua rather than hyprland.lua, so it never shares a
file with the window-rule block written from Lacquer's in-memory state.
Turning the nightlight schedule off puts Omarchy's shipped
hyprsunset.conf back exactly. A hand-written schedule is left alone unless
you choose to replace it (a backup is kept).
Boot unlock screen is the screen that asks for the disk password while the
laptop starts (Omarchy's Plymouth theme). Omarchy's own Style › Unlock only
offers themes that ship an unlock.png, so Aether themes and most community
themes can't be put there. Lacquer offers the current theme as well: it draws
the Omarchy logo in the theme's accent colour, the same way the stock themes'
logos are made (pixel for pixel), previews it, and bakes it with the theme's
background and foreground through omarchy plymouth set. Themes that do ship
an unlock screen go through omarchy plymouth set-by-theme, and Default
through omarchy plymouth reset, exactly like Omarchy's menu. All three
rebuild the boot image and ask for your password, so they run in Omarchy's
floating terminal (unlock-apply), never in the background. Nothing changes
the boot screen on its own after a theme switch; the section says when it no
longer matches. The drawn logos and previews live in Lacquer's state folder
(~/.local/state/omarchy/io.github.deunnis.lacquer/unlock/).
The lock screen itself needs nothing: Omarchy's lock screen already follows the
theme (wallpaper, blurred, and the [lock] colours), and those colours can be
tuned under Shell style › Lock screen.
Lock designs and lock-explorer's boot screens go through lock-explorer's IPC only
(omarchy-shell lock …). Its shell.json entry is never edited directly: its
in-memory settings win over the file and it rewrites the whole entry.
Choosing a boot screen only marks it; building it needs your password and
happens behind lock-explorer's own Apply button, which Lacquer opens rather
than re-implementing, so lock-explorer's record of what is baked stays true.
Idle timings (idle.screensaver, idle.lock) are set in shell.json from a
fresh read, touching only that key. Screensaver and About art use
omarchy branding.
OmaMenu's size, corners, border and transparency, set through an omamenu IPC
target (look, setLook, resetLook) in io.github.omamenu. The section only
appears when OmaMenu answers on it. The
menu keeps its own file and write guarantees; Lacquer only sends values. Menu
look's transparency replaces Shell style's [menu] background-alpha while it
is above 0 %.
Terminal padding, cursor and background opacity go to every installed terminal
(foot, alacritty, kitty, ghostty) in each file's own format; font and size stay
with Fonts & text. btop's drawing options reload a running btop with SIGUSR2;
color_theme is never touched. Starship's spacing and command timeout apply to
the next prompt. A theme switch never rewrites any of these files.
Borders & shape builds a gradient border that follows your theme. Lacquer
still pins no colour: its block asks Hyprland for the border colour the theme
just set (hl.get_config) and derives the second stop — lighter, darker,
towards the unfocused colour, or a hue turn — so a theme switch re-derives it
with nothing to re-apply. Hyprland can spin the angle on its own. Five shape
presets (Sharp, Soft, Pill, Neon, Paper) set rounding, border width, shadow,
glow and the gradient together, as one undo step.
Screen frame needs the optional companion, Lacquer Shell: rounded display corners or brackets, a frame in the theme's accent, and a vignette, scanlines or grain. It is input-transparent, so the desktop underneath behaves exactly as before, and it draws once and then holds still. Lacquer offers to install it with Omarchy's own installer, in a terminal you watch, after a confirmation. The same plugin ships an animated clone of Omarchy's bar, whose pace follows the motion feel.
Size moves text, cursor, gaps and the bar's height together (Small/Normal/Large/Huge), and sets how big Lacquer's own window opens.
Displays sets resolution, refresh rate, scale and rotation. A change is
applied live and reverts on its own within ten seconds unless you confirm it,
and only a confirmed change is written — to its own fenced block in
hypr/monitors.lua, through monitors-write.
App windows writes per-app rules — float or tile, floating size, centring,
workspace, opacity, and which effects to drop — as o.window("^class$", …)
lines in Lacquer's block, the same shape as Omarchy's own app rules. Apps on
screen are offered first.
App launcher renames an app, changes its icon or hides it, by copying the
packaged .desktop into ~/.local/share/applications/ and editing the copy.
Lacquer only ever edits a copy it wrote; Undo deletes it and the packaged entry
takes over again.
bat, delta and fzf can follow the theme too (under btop & prompt). Omarchy already retints terminals, btop, helix, tmux, VS Code, Obsidian and the browsers; these three it does not. Each gets a fenced block in its own config, rewritten by the theme-set hook.
Lacquer owns exactly what sits between its fences in
~/.config/hypr/looknfeel.lua:
-- >>> lacquer managed block >>>
-- <<< lacquer managed block <<<It re-reads the block every time it opens and only ever rewrites what is between the fences, so hand-editing is safe. If the block cannot be read — a syntax error, say — Lacquer says so and refuses to write, rather than treating it as empty and replacing your edit with nothing. Calls it does not recognise are no-ops, so adding a keybind or a launcher line to the block does not make it unreadable. Only values that differ from Omarchy's shipped defaults are written, and an empty block is removed rather than left as a husk.
Full opacity is the one setting that needs a second file. Omarchy tags every
window with opacity "0.985 0.96" in default/hypr/windows.lua, which
multiplies with the decoration:*_opacity globals and stops those sliders ever
reaching 1.0. Cancelling it means a window rule, and window rules belong in
~/.config/hypr/hyprland.lua — so Lacquer keeps a second managed block there.
That block also holds the per-app rules from App windows, and nothing else.
Both files are written before a single hyprctl reload, so Hyprland never
reads a half-written pair.
Two settings are written as Lua rather than as values, so they can follow the
theme without Lacquer running. The border gradient works its second colour
out from the theme's own border colour when Hyprland loads the block, and
Paint the desktop in your theme's colour reads the live theme's
colors.toml the same way. Both are wrapped in pcall, so a theme without the
colour they want changes nothing. The desktop-colour switch has no key of its
own in the file; it is read back from the marker line its chunk carries, since
the reader that measures a block is sandboxed and cannot open files.
Omarchy's defaults are read by running
$OMARCHY_PATH/default/hypr/looknfeel.lua through read.lua, a set of
recording stubs. Lua reading Lua, so there is no second grammar to keep in sync.
The Shell section edits ~/.config/omarchy/shell.toml — the surface that
restyles the bar, menus, popups, tooltips, notifications, the launcher, the
lock screen and every control in them. Omarchy ships no UI for any of it.
Four sub-tabs ([ and ] to move between them):
| Text | base size plus every per-token font pin |
| Spacing | the scale, and all 25 spacing tokens |
| Controls | border, fill and focus chrome in each state |
| Surfaces | the bar and all nine overlay surfaces |
These apply with no restart — the shell watches the file — and user keys
beat the active theme's own shell.toml, so they survive a theme switch.
Which is exactly why colour rows are marked. Pinning a colour means a theme
change can no longer move it, and colour belongs to the theme. A pinned colour shows a pins theme chip and a one-click clear;
structural rows carry no such tension and are unmarked.
A key the theme does not ship falls back to Omarchy's documented default from
shell.toml.tpl, not to the slider's minimum — many keys ship commented out,
and showing the minimum would be a number that is simply untrue.
Editing is line-based, not a TOML round-trip: comments, key order, alignment
and anything Lacquer does not understand survive untouched, because this file
is shared with omarchy display text size and with hand edits.
Position, transparency, and a layout editor for all three sections. Each widget shows its friendly name and id with controls to move it between sections, reorder it, or take it off the bar.
Bar height and colours are not here — they belong to shell.toml and live
under Shell → Surfaces, so there is one place for each thing rather than two.
A settings editor for every installed plugin, built from the schema block in
its own manifest. Omarchy 4.0.3 renders these nowhere: the shell carries
schema, defaults and settingsForm as registry metadata and every control
they imply exists in qs.Ui, but nothing joins the two.
| Schema type | Control |
|---|---|
boolean |
switch |
integer, number with min+max |
slider |
integer, number without bounds |
text field, refusing non-numbers |
string, path |
text field |
enum |
dropdown |
array, multiselect |
text field taking JSON, refusing invalid JSON |
Manifests are read straight off disk rather than from the host's registry snapshot, because that snapshot only covers bar widgets — panel, service and overlay plugins carry settings too.
A plugin may only write its own settings through the shell API: shell.qml's
_updateSettings requires pluginHasBarCapabilities(), which means declaring
kind: "bar" — replacing the user's entire bar. Lacquer does not do that. So:
| bar widgets, layout, position, transparency | the omarchy bar and omarchy plugin CLIs |
| plugins that are not on the bar | a guarded direct write to shell.json |
The direct write re-parses the file each time rather than holding a copy, so a change made by the shell or the CLI in between is never clobbered, and it serialises to the same shape already on disk so a write is not a reformat.
Every leaf Hyprland exposes, grouped the way its animation tree is shaped, with speed, curve and style. Speed is a duration in deciseconds — bigger is slower — and each row shows the millisecond equivalent.
A leaf Omarchy ships no value for inherits from its parent. Hyprland reports those as "not overridden" rather than resolving them, so Lacquer shows them as inherited instead of inventing a number; Override materialises the leaf from the nearest ancestor that has real values.
A cubic bezier with both endpoints pinned at (0,0) and (1,1), which is what
Hyprland's bezier is. Only the two control handles move. The unit square is
drawn square with room above and below, because curves legitimately overshoot.
The play strip runs the same four numbers through QML's Easing.Bezier for the
real duration of a leaf using that curve, so you can feel the timing without
opening a window.
Hyprland keeps a curve in its name table once defined, so a curve added at runtime lingers until Hyprland restarts. Lacquer only edits curves that already exist.
| type | on Home: search every setting |
↑ ↓ / k j |
move between rows (Desktop, Screens, Apps: between groups; Home: sections) |
← → / h l |
adjust the focused row |
Space |
toggle a switch |
Backspace |
reset the row to Omarchy's default; in Desktop, unpin |
Enter |
apply the chosen theme or choice |
l g o |
Generate: light/dark, generate (asks first), open aether |
Tab / Shift+Tab |
next / previous page, in the order of the tabs |
? |
show the keys for this page |
[ / ] |
change sub-tab, or pick a plugin |
P |
play the curve preview |
Ctrl+Z |
undo |
Ctrl+M |
app animations on/off |
Ctrl+I |
import Omaland's settings, while its banner is showing |
Esc |
close |
Hovering a row moves the keyboard cursor to it.
pkill hyprsunset returns before the old instance lets go of the display, and
a new one started in that window exits at once; the nightlight helper waits
for the old process to be gone and checks the new one stays up.
A plugin cannot ask the host where it lives: since 4.0.3 shell.qml's
publicPluginManifest() deletes __sourceDir from every third-party manifest,
so the plugin directory comes from Qt.resolvedUrl(".") instead.
manifest.json |
what the plugin is: its panel and service entry points |
lacquer.desktop |
the launcher entry the service installs |
Panel.qml |
the app: state, live preview, persistence, undo, Omaland import |
ConfigRow.qml |
one look-and-feel option |
LeafRow.qml |
one animation leaf |
CurveEditor.qml |
the bezier graph and play strip |
ShellRow.qml |
one shell.toml option, with the colour warning |
SettingRow.qml |
one plugin setting, control chosen from its schema type |
LookSchema.js |
the catalogue of look-and-feel options |
ShellSchema.js |
the catalogue of shell.toml options |
TomlEdit.js |
comment-preserving line editor for shell.toml |
scan-plugins.py |
reads every installed plugin manifest off disk |
AnimSchema.js |
the catalogue of animation leaves |
StyleLua.js |
renders and parses the managed block, the border gradient, the window rules and the monitor lines |
MotionTokens.js |
the motion feels: curve families, durations and the leaves each one drives |
read.lua |
recording stubs that report what a Lua chunk declares |
Service.qml |
launcher entry, theme-set hook, Shuffle engine, reopen after a font restart |
stores/ |
one non-visual store per area: Hypr, ShellToml, ShellJson, Theme, ShuffleEngine, Aether, Desktop, FontRender, Looks, Night, Screens, MenuLook, Apps, Motion, Borders, Monitors, Rules, Launcher, Tools, Companion |
sections/HomeSection.qml |
Home: miniature, palette, search index, summary cards |
sections/ |
one view per pane; ChoicePane.qml renders the chip, stepper, icon, font, art and card groups shared by Desktop, Screens and Apps |
ShuffleDeck.js, SunTimes.js |
OmaShuffle's deck and sunrise maths |
scan-themes, scan-wallpapers, scan-desktop, scan-screens |
read-only scanners |
desktop-block |
owns the fenced block in hypr/autostart.lua |
nightlight |
hyprsunset schedule and temperature |
app-config |
terminal, btop and starship line edits |
shell-json-set |
one top-level shell.json key from a fresh read |
lacquer-reapply.hook |
copied into hooks/theme-set.d/ |
lacquer-cleanup |
undoes Lacquer's changes before removal |
app-theme |
the fenced block that makes bat, delta and fzf follow the theme |
launcher-entry |
renames, re-icons or hides an app, in a copy of its .desktop |
monitors-write |
owns the fenced block in hypr/monitors.lua |
add-asset |
unpacks a picked font or cursor theme into place |
unlock-screen, unlock-apply |
build and install the boot unlock screen for any theme |
Contrast.js |
the readability maths behind Make a theme's reading |
ui/ |
Lacquer's own kit: the lithograph tokens in Design.qml, the ink controls, the mark, the tour |
read-state |
a bounded reader for Lacquer's own state files |
lacquer-report |
prints setup details and recent log lines for a bug report |
LookSchema.js, ConfigRow.qml and the hl.config rendering in StyleLua.js
are adapted from Omaland by Bobby Nicholas (MIT) —
https://github.com/bobby-nicholas/omaland. See LICENSE.
The Shuffle engine, ShuffleDeck.js, SunTimes.js and scan-themes come from
OmaShuffle (MIT, Deunnis).
The mark is the letter L of Courier Prime Bold by Alan Dague-Greene
(SIL Open Font License), printed twice out of register in the theme's own two
colours. Its outline is carried in ui/MarkPath.js, so no font has to be
installed for it to draw.
















