Night Light is an easy-to-use applet for the COSMIC desktop (Pop!_OS) that warms your screen's color temperature to cut blue light. It lives as an icon on your panel or dock: click it for a simple popup with an on/off toggle and a temperature slider, and open Settings for a custom schedule (warm between any two times you choose, to the minute), the night temperature, and brightness. It's built entirely with native COSMIC/libcosmic widgets, so it looks and behaves like a first-party part of the desktop rather than a bolted-on tool.
It exists because COSMIC's compositor does not yet expose a color/gamma
protocol, so the usual tools (redshift, gammastep, wlsunset) can't adjust
the screen — see How it works.
Panel applet popup — on/off toggle and temperature slider |
Settings window — night temperature, brightness, and a to-the-minute schedule |
These images are theme-aware: GitHub shows the light screenshots in light mode and the dark screenshots in dark mode.
The easy way — install the .deb from the COSMIC Store:
- Download the latest
cosmic-nightlight_*.debfrom the Releases page. - Open the downloaded file with the COSMIC Store and click Install.
(Or from a terminal:
sudo apt install ./cosmic-nightlight_*.deb.) - Add the applet to your bar: COSMIC Settings → Desktop → Panel (or Dock) → Configure applets → Add applet → Night Light.
That's it — click the Night Light icon to toggle the tint or open its settings.
Flatpak is not an option for this tool: the sandbox cannot grant the root / DRM-master / VT-switch capabilities the workaround needs. That is also why the
.debinstalls a smallpkexechelper and a polkit rule (so the tint can be applied without a password prompt forwheel/sudomembers).
The scripts/install.sh / scripts/uninstall.sh helpers build and install
locally from a checkout — handy for hacking on the app, and usable as an
alternative to the .deb. They need a Rust toolchain and libdrm headers
(libdrm-dev):
./scripts/install.sh --gui # build + install the helper, polkit rule, and GUI
./scripts/uninstall.sh # remove everything install.sh addedTo build the .deb yourself, see PACKAGING.md.
The applet. The Night Light icon opens a popup with the on/off toggle, the temperature slider, and a Night Light Settings… button.
Settings. The settings window covers the schedule (Off, or a Custom
Schedule with From/To times), the night temperature, and brightness —
which dims the screen while the night light is on. Open it from the popup, from the Night Light Settings launcher
entry, or with cosmic-nightlight --settings.
The schedule. From and To each pick an exact time — hour, minute,
and AM/PM (or a 24-hour clock, following your COSMIC time setting) — and the
Schedule row summarizes the result, e.g. Warm from 9:37PM to 5:22AM. A
window that ends earlier in the day than it starts runs overnight; one
that ends later runs within the day, so 9:00AM→5:00PM warms the screen for
office hours only.
Toggling the tint against the schedule sets a manual override that lasts until
the next scheduled transition, after which automatic scheduling resumes.
Settings live in ~/.config/cosmic/io.github.cosmic_nightlight/ and sync live
across the applet, the settings window, and the background scheduler.
What applies the schedule. The applet does, as long as it is on your panel or dock: it re-checks the clock every 15 seconds and warms or clears the screen when a boundary passes. The settings window does the same while it is open. No background service is required, and there is nothing to enable — the applet is part of your panel, so it comes up with your session and picks the schedule up from there.
Running without the applet. If you'd rather not keep the applet on your panel, enable the headless scheduler as a systemd user service instead:
systemctl --user enable --now cosmic-nightlight.serviceThe .deb ships that unit; from a source install, copy
systemd/cosmic-nightlight.service into ~/.config/systemd/user/ first. It is
off by default and adds no behavior of its own — it just keeps a process around
to do what the applet would have. Running it alongside the applet is harmless:
they share a record of what is on screen and lock against each other, so a
boundary still costs a single flicker.
Advanced: drive the helper directly
The privileged helper can be called by hand. Each call briefly flickers the screen:
pkexec /usr/bin/cosmic-nightlight-helper --temp 3500 # warm tint
pkexec /usr/bin/cosmic-nightlight-helper --temp 4000 --brightness 0.9
pkexec /usr/bin/cosmic-nightlight-helper --off # reset(Use /usr/local/bin/... if you installed via scripts/install.sh.)
- Flicker on every change — inherent to the VT-bounce workaround.
- A modeset can clear the tint — resolution/monitor-hotplug/DPMS-wake events make the compositor reprogram the CRTC, dropping the LUT. A suspend/resume is detected and re-applied automatically; for the others, re-apply by hand (or wait for the next schedule boundary).
- The schedule uses fixed clock times you pick (From/To, defaulting to 18:00 → 06:00), not your location's real sunset/sunrise. Tying it to your location (geoclue / an astronomical calc) is a clear next step.
- Requires
pkexec/polkit and membership inwheelorsudo.
COSMIC's cosmic-comp does not implement
wlr-gamma-control-unstable-v1 (cosmic-comp#764), so wlsunset,
gammastep, and redshift cannot adjust the screen through Wayland. Native
Night Light is only planned for COSMIC Epoch 3 (cosmic-comp#2059,
cosmic-epoch#2498) and has not shipped.
So we go around Wayland and write the gamma ramp straight to the kernel's
DRM/KMS layer — the same thing redshift does on a bare TTY. There is one
real obstacle:
While COSMIC is the foreground session it holds the DRM master lock, so any other process that calls
drmModeCrtcSetGammagetsEACCES.
The workaround (proven by jjo/drm-colortemp): when the session switches to a
spare virtual terminal, logind revokes the compositor's DRM master. During
that window a root process can grab master, write the gamma LUTs, and — because
the compositor doesn't reset them — the tint persists after switching back.
This project automates that VT bounce so it happens on a schedule. The cost is a brief (~1–2 s) screen flicker each time the tint changes. This is inherent to the workaround; it goes away once COSMIC ships a real gamma protocol.
A Cargo workspace with three crates so the privileged, security-sensitive code stays tiny and independent of the heavy GUI:
| Crate | Runs as | Responsibility |
|---|---|---|
nightlight-core |
library | Gamma math (gamma.rs), DRM apply (drm.rs), VT bounce (vt.rs) |
nightlight-helper |
root (via pkexec) |
Thin CLI: parse --temp/--brightness, call core |
cosmic-nightlight |
your user | libcosmic panel applet + --settings window + optional --daemon scheduler; shells out to the helper |
All three modes keep to the schedule themselves, so any one of them running is
enough. They coordinate through a record of what is on screen plus an advisory
lock, both in $XDG_RUNTIME_DIR, so several noticing the same boundary at once
still apply it once.
Flow on a tint change:
daemon/GUI ──pkexec──▶ cosmic-nightlight-helper (root)
│ 1. VT_ACTIVATE a spare VT (compositor drops DRM master)
│ 2. drmSetMaster + drmModeCrtcSetGamma on every active CRTC
│ 3. drmDropMaster
└ 4. VT_ACTIVATE back to your session (tint persists)
The gamma curve is Tanner Helland's black-body white-point fit: 6500 K is an identity ramp (no tint); lower temperatures cut green/blue to warm the image — far finer than the 3 coarse presets a DDC/CI approach can offer, and it works on laptop internal panels (which usually have no DDC/CI).
This whole approach is a stopgap. The proper solution is COSMIC implementing a gamma-control protocol; track cosmic-comp#764 and cosmic-comp#2059. Once that lands, the DRM/VT machinery here can be replaced with a normal Wayland client.



