Skip to content PULSAR
Docs Install
DocsThemesReleases Install Source on GitHub
Docs How theming works

Theming

pulsar theme set <name> recolors the whole desktop in one step; pulsar theme revert restores stock GNOME. The Pulsar theme is on by default. This is the map: what ships, what each piece writes, and what it leaves alone.

What ships

Piece Where
engine (python, stdlib only) /usr/libexec/pulsar/pulsar-theme, from scripts/pulsar-theme; pulsar theme ... execs it
picker (libadwaita) /usr/libexec/pulsar/pulsar-theme-picker, “Themes” in the app grid
20 themes: 14 dark + light; Dracula, Poimandres, Synthwave ’84, Phosphor and Amber dark only; Alucard light only /usr/share/pulsar/themes/<slug>/theme.toml + backgrounds/*.jxl
per-target templates /usr/share/pulsar/theme/templates/
Shell extension (+ glass and light) /usr/share/gnome-shell/extensions/pulsar-theme@arclight.digital, settings schema org.gnome.shell.extensions.pulsar-theme
image default zz1-pulsar-theme.gschema.override: enabled-extensions only
first-login units pulsar-theme-init.service, pulsar-theme-notice.service (user, --global)
GTK3 recoloring adw-gtk3-theme
agent skill for making themes /usr/share/pulsar/skills/pulsar-theme/SKILL.md, linked by pulsar agent add

Themes: Pulsar, Pulsar Holo, Catppuccin, Gruvbox, Tokyo Night, Nord, Rosé Pine, Everforest, Kanagawa, Solarized, Flexoki, Ayu, Dracula and Alucard (separate one-variant themes, as upstream ships them), Phosphor and Amber.

  • One-variant themes set Dark or Light Style when chosen and don’t change when it flips.
  • Phosphor and Amber (CRT terminals) pull every ANSI color toward the phosphor while keeping its meaning.
  • Order everywhere: the brand, then themes that follow Dark Style, then dark-only, then light-only.
  • The classics are generated by scripts/build-themes.py from the base16/base24 schemes in assets/themes/imports/. That file records each scheme, corrected slots (Tokyo Night’s base16 “red” is pale blue-white), and the contrast fit: text hues move in OKLab lightness only until they clear WCAG AA, keeping hue and chroma.
  • Pulsar and Pulsar Holo are hand-written from DESIGN.md.
  • pulsar theme audit re-checks all of it; the Containerfile refuses to build if any theme fails.

What one switch writes

All in the user’s own config, each file replaced with rename(2), in one transaction:

  • accent: the libadwaita accent nearest the theme accent’s hue (live everywhere, Flatpaks included, via the settings portal); slate only for a grey accent, and gnome_accent in theme.toml overrides it. A Dark Style flip re-sets it when the other variant’s differs. color-scheme is written only by a one-variant theme or --variant.
  • ~/.config/gtk-4.0/gtk.css: libadwaita color variables in a marked block appended to the user’s file, both variants under @media (prefers-color-scheme).
  • ~/.config/gtk-3.0/gtk.css + gtk-theme=adw-gtk3[-dark] for the current scheme (GTK3 has no media queries). On a Dark Style flip the extension runs pulsar-theme follow-scheme to redo it (open apps on their next window).
  • Ptyxis: a palette on every profile, following Dark Style.
  • GtkSourceView: a scheme pair; Text Editor recolors its window from it.
  • btop: a theme for the current scheme, redone by follow-scheme.
  • wallpaper: the pair.
  • Shell: two stylesheets in ~/.local/state/pulsar-theme/shell/, layered over the stock Shell theme by the extension and swapped on Dark Style.
  • terminal coding agents, where set up: Claude Code (~/.claude.json theme), Gemini CLI (~/.gemini/settings.json ui.theme) and opencode (~/.config/opencode/tui.json theme) draw with the terminal’s 16 colors. Light themes give Claude Code and Gemini their own light theme instead (their ANSI light modes use color 7, nearly the background). Redone on a Dark Style flip; revert takes back only that key. --without agents skips them.
  • Flatpak override: a read-only grant on ~/.config/gtk-4.0 and ~/.config/gtk-3.0 so Flatpak apps read the same gtk.css. --without flatpak turns it off until --with flatpak; revert removes exactly the two entries.

Fonts and icons are never touched.

  • follow-scheme never overwrites a choice: a btop, agent or GTK theme the user changed after theming stops following. A full set overwrites. First login keeps an agent theme the user already picked.
  • Dotfiles symlinked within the home folder (stow, chezmoi) are written through, on set and revert. Links outside home (Nix store, shared files) are skipped with a note. Files keep their permissions.

Revert

The first time the engine touches a file or key, the original goes into ~/.local/state/pulsar-theme/baseline/. Then:

  • engine-only files (palettes, schemes, the btop theme, the Shell sheets) are restored byte for byte, or removed if new;
  • shared files keep every user line, including later edits; only the engine’s part goes (the gtk.css block, the two btop.conf keys, the Text Editor key, the two Flatpak entries);
  • dconf keys return to their original value, unless the user changed them since;
  • Ptyxis profiles stay; only their palette key is reset.

Keys that showed the image default get GNOME’s upstream defaults (from the schema XML, not Fedora’s or Pulsar’s overrides). The extension is removed from enabled-extensions; other extensions stay. revert --to image resets to the image defaults. tests/theme-gate checks the round trip.

First login

  • zz1-pulsar-theme.gschema.override only enables the extension. Theme colors aren’t image defaults (they’d reach accounts init leaves alone); init writes them into a fresh account’s dconf before the Shell starts.
  • pulsar-theme-init.service runs pulsar-theme init once per account, before the Shell. A fresh account gets the full theme, plus the picker on Super+T if unused. An account with its own look (gtk.css, accent, wallpaper, GTK or Shell theme, terminal palette, editor scheme or btop theme) is left alone.
  • init writes ~/.local/state/pulsar-theme/init.json (the unit’s condition), so it runs once. A killed run leaves init.pending, and the next login finishes it without mistaking engine values for the user’s. revert writes it too, so a reverted account is never re-themed.
  • pulsar-theme-notice.service shows the one notification after the Shell starts, then deletes the queued notice.
  • Existing users meet this once, on the first login after the update. GDM’s greeter accounts are skipped: init, the notice and the welcome check pulsar-theme login-account.

Open apps

GTK reads gtk.css at startup. After a switch the engine lists open GTK apps and offers Restart / Later / Don’t ask again (a dialog in the picker, a terminal prompt, or a one-line note). Restart activates each app’s app.quit (Ctrl+Q), so unsaved work gets its save dialog; nothing is killed, and only apps that exited are relaunched. Don’t ask again sets restart-prompt = off in ~/.config/pulsar/theme.conf (pulsar theme config restart-prompt on undoes it).

Wallpapers

Pulsar has eight shader looks, one file each in assets/shaders/looks/ (looks.json gives their order, which is u_look). Every classic theme ships two of them rendered in its palette from assets/shaders/theme.frag, dark and light, for bg-next; the site’s hero can show any of the eight in any theme. Each look has its own light:

  • nebula: a domain-warped field; ion-trail filaments on its isolines, a faint lit circuit lattice. It was called silk until 2026-09-29: a render table that still says look = "silk" renders it, and the old wallpaper paths (pulsar-silk-*.png, backgrounds/silk-*.jxl) stay as links;
  • leak: soft beams with prismatic edges; god-rays, drifting motes, an anamorphic streak;
  • satin: a satin sheet piled up, lit with an anisotropic sheen along the threads;
  • holo: iridescent foil; thin-film fringes, a diffraction sheen, one faint scan band;
  • relief: a topographic map lit by one travelling light, the index lines glowing faintly;
  • tide: caustic light on a pool floor, each filament splitting a little into colour;
  • orbit: a ringed planet’s limb catching a low sun, ring particles glinting;
  • beacon: a pulsar’s two beams sweeping through dust.

A look a theme has no render table for takes its colours and light direction from the theme’s primary table. Light variants carry the looks in pearl or in the theme’s ink, low-contrast. Highlights roll off through a soft knee below the theme’s highlight color; no scanline raster (it moirés when GNOME scales). glow, signal, web and grain tune each render; the phosphor themes run stronger. The brand wallpapers and the site’s live hero sky compile assets/shaders/pulsar.frag (GLSL ES 1.0).

scripts/build.sh renders PNGs on the builder; the Containerfile converts them to JPEG XL at q99 (~1.2 MB each; lower qualities lose the film grain that also dithers dark gradients). Both shaders end with a ±1-step triangular dither. A --no-wallpapers build ships none, and every theme falls back to the brand pair.

docs/theming/wallpapers-before.jpg and wallpapers-after.jpg are contact sheets (regenerate with scripts/render-theme-wallpapers.py --sheet).

Glass and light

Shell extension effects, all on by default, each a switch in the Extensions app and on the Appearance page of Pulsar Settings (the gear in the theme picker opens it; org.gnome.shell.extensions.pulsar-theme), where Reset restores the defaults. They add material and light only; GNOME’s layout, radii, type and timing are unchanged.

Key What it does
glass Menus, the top bar, OSDs and notification banners go translucent over a live blur of what’s beneath, with a soft drop shadow. The dash gets the light and shadow without blur.
window-glass GTK window ground, header bars and sidebars go translucent (alpha in gtk.css) over a blur the extension draws inside each GTK window. Ptyxis’s background goes to 85% (unless you set your own opacity). Content (views, cards, dialogs, popovers) stays solid; cards go a step lighter with a hairline edge. The GTK half applies to apps opened after a change; the terminal changes live. Windows open when it’s switched off keep their blur until closed. Needs glass.
lighting The button that opened a menu glows; a shader lights the rim facing it, with spill, an inner glint, scatter and grain. OSDs are lit from the bottom, banners from the top. Low battery warms the edge (orange); critical battery or a critical banner turns it red. Phosphor and Amber (shell_glow in theme.toml) also glow the clock and headings.
power-on A surface’s rim traces out from the light as it appears (instant with animations off). Needs lighting.
glow Accent-filled things glow softly: a checked quick toggle (a split one as one pill), today in the calendar, the default button, switches, checked boxes, the active workspace, slider fills. Reach and strength scale with each element’s size (wider and stronger on big pills, tight and faint on bars); weaker on light schemes. In apps opened after a change: suggested buttons, switches, checks and radios (GTK4 and GTK3), plus scale fills and progress bars (GTK4 only). Nothing inside list cells, nothing disabled.
focus-brackets Four corner brackets follow the keyboard-focused control, beside the stock focus ring (not for pointer hover).
  • All effects are off on the lock screen and in high contrast.
  • window-glass and glow have engine halves (window_glass(), glow_on()): flipping them makes the extension run pulsar-theme window-glass, which rewrites the GTK and terminal halves.
  • The Shell sheet’s .pulsar-glass, .pulsar-lit and .pulsar-glow blocks (glow from gnome-shell-glow.css, appended to each scheme’s sheet) key off classes the extension puts on the UI group.
  • The blur: a half-size copy of the pixels beneath a surface, patched with what each frame redraws, run through a dual-filter (Kawase) pyramid and drawn through a full-resolution mask with rounded corners. It sits beside each menu, not inside it, because GNOME paints menus through an offscreen buffer (see glass.js). Glass window surfaces sit at opacity 254 so Mutter still paints what’s beneath their opaque parts.
  • The theme gate’s account has every effect off (they move the pixels it measures).

When GNOME changes

The Shell stylesheet is the only part built on GNOME internals. tests/theme-gate/gate.sh checks every selector against the new Shell’s stock stylesheet and every theme in a real headless Shell (see its README). The Containerfile refuses to build when the extension doesn’t declare the image’s Shell major; shell-version is bumped only after the gate passes.

Written with help from AI and reviewed by a person before publishing. Spotted a mistake? Let us know.

PULSAR

Your lighthouse in the sky.

Site

Machine

Arclight

Theme

Dark only Light only

Recolors the whole site, like pulsar theme set does your desktop.

Light and dark

One look picks light or dark for you

Saved in this browser Back to Pulsar