Displays
Resolution, brightness, rotation and input source for every display
palupdated 2026-09-29SystemComes with palMenu bar: Brightness7 deep links
Comes with pal, so a new install already has it; the button finds it in pal again if you removed it. This page can't see what your pal has installed.





What it does
Every display with its mode and brightness: change resolution, scaling, rotation and mirroring, set an external monitor's brightness and input source, and save arrangements to switch between.
- One row per display with its resolution, refresh rate, rotation and brightness
- Brightness, contrast and volume as sliders, for external monitors too (over DDC)
- Switch the input source of an external monitor
- Change the resolution with an easy undo, rotate, mirror or make a display the main one
- Save the arrangement under a name and apply it again from the list, the bar or a link
- Each tool it uses is optional; a row says what to install when one is missing
Palettes 1
-
Displays
displaysliveEvery display with its mode and brightness, the arrangement presets, Night Shift and Sleep displays; Enter drills into a display's controls.
- ↵Open the display, apply a preset, run a row
- ⌘BSet the brightness to the percent typed in the bar
- ⌘⇧MMake the display the main one
- ⌘CCopy the display's id, for links
- ⌘RRename a preset
- ⌘⌫Delete a preset
Actions
- OpenDrills into the display: its controls, modes and arrangement.↵
- Set brightnessThe percent typed in the bar (or +10 / -10).⌘B
- Make mainMoves the arrangement so this display is at (0,0).⌘⇧M
Links 7
Displays answers these pal:// routes from a web page, a script or a keybind; pal call is the same route from a terminal. A link from a page asks first unless you trust the extension. How links work.
-
Set a display's brightness
brightnesspal call displays/brightness value=<value>value*A percent (50), or a step (+10, -5)displaymain, external, builtin, a display id or a name; the bar item's display otherwise
-
Set an external monitor's contrast over DDC
contrastpal call displays/contrast value=<value>value*A percent (50), or a step (+10, -5)displayexternal, a display id or a name; the first external otherwise
-
Set an external monitor's speaker volume over DDC
volumepal call displays/volume value=<value>value*A percent (50), or a step (+10, -5)displayexternal, a display id or a name; the first external otherwise
-
Switch an external monitor's input source over DDC
inputpal call displays/input source=<source>source*hdmi1, hdmi2, dp1, dp2, usbc, or a raw VCP 60 codedisplayexternal, a display id or a name; the first external otherwise
-
Set a display's resolution (displayplacer, or the compositor on Linux)
modepal call displays/mode mode=<mode>mode*A mode number from the palette, or 1800x1169, 1800x1169@60, 2560x1440 hidpi, 3024x1964 nativedisplaymain, external, builtin, a display id or a name; the main display otherwise
-
Apply a saved arrangement preset
presetpal call displays/preset name=<name>name*The preset's name
-
Night Shift on, off or toggled (the nightlight CLI)
night-shiftpal call displays/night-shiftstateon, off or toggle; toggle otherwise
Settings
Extension, [extensions.displays]
stepWhat one press of the arrow keys, a scroll on the bar item or a `+10`-style link moves a level by, in percent. Shift with an arrow always moves 1%.
input_altMost monitors take the standard VCP 60 codes for their inputs (DisplayPort 1 is 15, HDMI 1 is 17). LG's take 208 and 144 instead; turn this on if switching the input does nothing.
Defaults shown. Change them in pal's settings window or in the config file.
The README
Everything Displays does, key by key, from the extension's own README.md
Displays
Every display with its mode and brightness; Enter drills into one for its
controls (brightness, contrast, volume as sliders, the input source), its
modes (resolution, refresh rate, HiDPI scaling), rotation, mirroring and
Make main; arrangement presets; a bar item with a slider per display
(mark several cards, cmd-click or shift+↓, and the brightness keys
move them all). The
palette's full description, keys and settings are in docs/palettes.md
("Displays").
What runs where
Nothing is built in: every fact comes from a tool, each optional, and a Setup row says what to install for the displays that are connected (Enter copies the command). The listing itself needs no tool on macOS.
| macOS | Linux | |
|---|---|---|
| the displays, names, current mode, main, mirror | system_profiler SPDisplaysDataType -json (~150 ms) |
hyprctl monitors -j, else wlr-randr --json, else xrandr --query |
| modes, rotation, mirroring, main, presets | displayplacer (brew install displayplacer, ~300 ms a listing) |
the same compositor tool |
| built-in brightness | brightness CLI, the HEAD build (brew install --HEAD brightness) |
brightnessctl |
| external brightness, contrast, volume, input | m1ddc on Apple Silicon, ddcctl on Intel, over DDC/CI |
ddcutil |
| Night Shift | nightlight (brew install smudge/smudge/nightlight) |
not offered |
The displays are joined on the CoreGraphics display id on macOS, which is
what windows.displays() in the SDK reports, displayplacer calls the
"contextual" id and m1ddc the "Display ID"; on Linux on the output name
(DP-1). Routes take that id, or main / external / builtin / a name.
Notes per tool:
- The
brightnesson PATH is validated (-lmust list displays) and Homebrew's prefixes are tried when it is something else by that name. The bottled 1.2 cannot read or set an Apple Silicon panel (it answerskIOReturnUnsupported); the HEAD build goes through DisplayServices and can. It also reads Apple displays (Studio Display) the same way. m1ddcsets the input source but cannot read which is active, so the Input row carries nocurrenttag with it;ddcctlandddcutilread it. Volume is offered only when the monitor answers a volume read.displayplacer's reproduce line (the last line oflist) is what a preset stores and what Undo restores; every change is that line with one field moved, so a mode change never touches the other displays. Rotating the built-in screen asks first, with displayplacer's own warning.- The built-in panel never goes below 5 % from pal (
BUILTIN_FLOORintools.ts): a screen you cannot see is one you cannot fix from. - On Linux, Make main exists only under xrandr (
--primary); Wayland compositors have no primary output.
Caching
displayplacer list plus system_profiler cost a few hundred ms, so one
snapshot of the displays stands for 20 s (SNAPSHOT_TTL_MS), and a level
reading for 3 s (brightness moves under the keyboard's keys too). ⌘R,
a write and the bar item's wake refresh drop both. Tools are re-detected
every minute, so a brew install lands without a restart.
Files
model.ts is pure: the parsers of every tool's output and the placement
maths (a mode, the main display, a mirror set, a rotation as the next
displayplacer command), fixture-tested in
host/test/extensions/displays.test.ts. tools.ts runs the tools and
keeps the caches. view.ts draws the slider level and the bar popover.
index.ts is the palette, the picks, the bar item and the routes.







