Ovvi

Theme and accessibility

Appearance, interface style, status colors, VoiceOver, keyboard paths, text size and the keyboard shortcuts

Appearance and interface style

Two settings decide the look (D44). Both are in View ▸ Appearance, View ▸ Interface Style, Settings ▸ Appearance and the palette.

  • Appearance: Auto (follows macOS), Light or Dark. Dark is the default.
  • Interface style: Glass or Classic. Glass is the default.
    • Glass: the window background is a behind-window blur under a tint, so the desktop shows through softly. The selected tab and space row are Liquid Glass capsules.
    • A bright window behind a dark Glass window shows only as a soft, even light, as in Rex: no text or edges of it come through. The blur and a dark tint hide them. Light Glass's white tint hides a dark window behind it. Text stays at 4.5:1 or more in both cases.
    • An inactive window looks the same as the active one: the blur stays active, and the tints are plain colors.
    • Liquid Glass goes only on small or short-lived parts: the selected tab and space row, buttons, keycaps, the chat's reply box, and the panels below. It costs the GPU more than the classic blur, more the larger it is, and macOS turns it grey in an inactive window. Over the whole window it costs WindowServer about a quarter more GPU time while a terminal scrolls.
    • Classic: an opaque window with no blur. The selected tab and row are plain raised pills.
  • In both styles the sidebar sits flat on the window background, and pane cards are translucent fills with thin edges, never glass. Popovers, the palette, the hover card, the find bar and notices use the system glass over the system's regular material, so a terminal behind them is only a soft blur (on a small panel Liquid Glass alone lets its text read through). Tooltips are the system's.
  • Pane cards have a 10 pt radius. The 8 pt gap between cards is the one fixed layout size.

One token table in Style.swift holds every color the views draw, per style and appearance, with values measured from Rex and tuned by eye. In short:

TokenGlassClassic
Window backgroundbehind-window blur (hudWindow) + a tint. Dark: black 0.6 blended overlay darkens the blur, then #1d1d1d at 0.845 on top. Light: white at 0.7opaque #1e1e1e dark, #f6f6f6 light
Card fillwhite 0.03 dark, 0.6 light, a step brighter than the window; the keyboard card only a little brighter (white 0.02 more in dark, 0.25 in light, so it ends at 0.7)white 0.018 dark (#222 on #1e1e1e), 0.6 light; a step apart on the keyboard card (black 0.1 more in dark; white 0.5 more in light, so it ends at 0.8)
Card edgesRex's rim, plusLighter: a 0.7 pt inner rim (white 0.06 dark, 0.04 light) and over it along the top a 1 pt line (white 0.09 dark, 0.3 light) that fades out round the corners over 14 pt, with a glow under it (8 pt, about half); then a 1 pt outer stroke (black 0.5 dark, 0.1 light, the same on every card); in light a shadow (black 0.1, blur 5, 2 pt down)a hairline outer stroke, so each card stands apart from the window: light black 0.14 at 0.7 pt (black 0.18 at 0.8 pt on the keyboard card); dark white 0.1 at 0.7 pt (white 0.16 at 0.8 pt on the keyboard card); no shadow and no rim
Selected tab and rowLiquid Glass capsulea flat pill in dark (white 0.07, with a 1 pt edge at white 0.12); white with a fine stroke and a shadow in light
Tab trackthe primary color at 0.05 (0.1 with Increase Contrast)the same
Title row and sidebar text and glyphswhite 0.65 dark, black 0.65 light (0.85 with Increase Contrast); the selected tab's and row's title white 0.9 / black 0.9 (1 with Increase Contrast)the same
Tab dividerswhite 0.17 dark, black 0.14 light, as in Rex (0.3 and 0.28 with Increase Contrast)the same
Card header buttons and the divider gripwhite 0.42 dark, black 0.45 light (0.6 and 0.65 with Increase Contrast): at least 3:1 on the card and the windowthe same

The hover and pressed fills (rows, tabs, buttons) are the same in both styles: the primary color at 0.05 and 0.08, which follows the appearance by itself, so they are not tokens. The hover fill fades in and out over 0.14 s; a menu's highlight (the palette, the space menu, Open Session) moves at once.

Terminals keep a transparent background, so the card shows through. Their text uses libghostty's defaults: Alabaster in light, Afterglow in dark. They follow the appearance. A change updates every terminal without opening its stream again. Selected text takes the theme's text color over a blue, as Ghostty's own Alabaster and Afterglow themes draw it: #000000 on #BFDBFE in light (Ghostty's Alabaster), #D0D0D0 on #1B3A58 in dark (Ghostty's Afterglow selects on #303030, which hardly shows on a card). So a program's colors never hide selected text. There are no other themes.

The text draws as Ghostty draws it by default: no font-thicken, alpha-blending = native, 13 pt, in the JetBrains Mono that libghostty carries, Ghostty's own default font (Settings).

Status

The status words and colors are the same everywhere (tabs, space rows, the agent rows, the hover card, notifications):

Shown asWordDarkLightherdr status
a dashed circle (lucide's circle-dashed) and "Working"working#60a5fa#3b82f6working
a circle with an exclamation mark (circle-alert) and "Needs you"needs you#fb923c#ea580cblocked
a circle with a check (circle-check) and "Done"finished#34d399#10b981finished and not yet seen by this device
↓behind on a space row, the error tone of a notice; an alert circle and "Error" on a chat carderror#f85149#cf222e—
  • Icons. The icons and colors are t3code's: lucide's round shapes, drawn by the app with strokes of 2 units in 24 and round ends, in the status color. No state icon moves: no spinner and no dots for a state. They are 12 pt everywhere: a space row, a tab, an agent row's box, the hover card, a state label, a menu row and the chat's loader.
  • Priority. A tab or a space with several agents shows one icon, its strongest: Needs you, then Done (not seen), then Working. It shows nothing when all are idle.
  • State label. The agent card's header and the overview's tiles show a state as its icon and word, 11 pt medium in the status color, with no fill. A chat's Error is the alert circle in the error color.
  • State box. An agent row (Agent rows) shows its icon in a box in the status color, and for Working its time.
  • An idle agent shows no icon, no label, no box and no time.
  • A row that calls for the user (needs you, or done and not seen) has its name in medium weight; other rows are regular.

Accessibility

  • Status is never color alone. Every icon carries its word, and VoiceOver reads, for example, "codex, needs you" on a tab. A space row adds the word to its value.
  • The tab row makes only the capsules in and near its view, so VoiceOver reads those. ⌘1–9, ⇧⌘[ and ⇧⌘], and the palette reach the others; a space row's value has the strongest state of all its tabs.
  • A terminal card gives VoiceOver only its grid size, not its text.
  • ⌥⌘ and an arrow moves the keyboard between cards. Keyboard focus in the chrome follows Full Keyboard Access. A terminal keeps Tab for itself.
  • VoiceOver's actions on a card are its menu's items, with Move Pane to Tab's New Tab (when the pane shares its tab) and New Space only. With any accessibility client running (BetterTouchTool, Raycast, a test), SwiftUI builds a card's actions with the card: with one per tab, a switch to a session of 300 tabs takes three times as long. VO-Shift-M on a card opens its menu, with every tab; the palette lists them too.
  • Every card action can be reached from the keyboard, through the menu bar and the palette (D48). Every swipe has a keyboard path, a menu path and a button. Hover controls are also in context menus and the menu bar.
  • Each divider is an adjustable element: "Divider between ‹a› and ‹b›", with the ratio as a percent (Dividers).
  • The terminal font size is the app's text size (Settings).
  • Reduce Motion makes the sidebar's session pages jump, and turns off the icon bounce, the layout motion, the reorder slides, the tab bar's slide to a new tab, the spring-load pulse, the sidebar's slide, the plugins' sidebar slide, a plugin card's toast slide, the panels' scale-in, the chat's first-message motion and its fades (the rows as they show, a message the agent takes).
  • Reduce Transparency is handled by the system: its blurs and glass turn opaque. Classic is an opaque window for users who want no blur at all.
  • Increase Contrast makes the app's own dim colors stronger (the table above: the title row's text, tab dividers, the tab track, card header buttons and the grip). The system's colors follow it by themselves.
  • The card header buttons and the divider grip have a contrast of at least 3:1 against what is behind them, in both styles and both appearances (measured 3.3:1 to 4.1:1 on CI's desktop; in Glass it depends on the desktop).

Keyboard shortcuts

Every key lives in one registry: each action has an id (tab.new), a group, its default keys and the key the user set in Settings ▸ Keyboard Shortcuts. The menu bar, the palette, the Keyboard Shortcuts panel, the tooltips, the text that names a key, the terminal's line keys and the plugin cards' Back and Forward all read it, and a plugin's command keys join it from its manifest (Commands). The tables below are the defaults.

The palette and the menu bar come from one command list. A command with two default keys shows the first in the menu; a key monitor runs the first's command for the second (⇧⌘P, ⌃⇥, ⌃⇧⇥, ⌘=), always on the key window's own command list. It takes ⌃⇥ and ⌃⇧⇥ in every card and text field (a chat's composer, a browser's address), so they never move the keyboard to the next terminal instead. A key the user records is the action's only key.

One pattern for every level: the key says the action, the modifier says the level. T makes, W closes, [ and ] step, 1 to 9 jump. ⌘ is the pane (and the tab for New Tab and the jumps), ⇧⌘ the tab, ⌃⌘ the space, ⌥⌘ the session. Arrows mean panes, except ⇧⌘← and ⇧⌘→ (Move Tab) and ⌃⌘← and ⌃⌘→ (Go Back and Go Forward through the tabs shown, Xcode's keys).

PaneTabSpaceSession
New⌘D right, ⇧⌘D down⌘T⌃⌘T⌥⌘T (Open Session)
Close⌘W (the tab too when it is the last pane)⇧⌘W⌃⌘W⌥⌘W (Detach Session)
Previous, next⌘[ ⌘]⇧⌘[ ⇧⌘], ⌃⇧⇥ ⌃⇥⌃⌘[ ⌃⌘]⌥⌘[ ⌥⌘]
Jump to 1–9⌘1–9⌃⌘1–9⌥⌘1–9
Swipe⌥ + swipe up or down⌥ + swipe sideways, or sideways on the sidebar

Pane steps follow the split tree, as in Ghostty: left before right, top before bottom, round the ends. Tab and space steps go round the ends too, spaces in herdr's order, pinned ones first, less the hidden ones (the sidebar's in Manual); session steps stop at the first and last page. A split gives the keyboard to the new pane. A tab, space or session shown, however it comes into view, gives the keyboard to its keyboard card.

Keyboard Shortcuts panel. ⌘/ (Help ▸ Keyboard Shortcuts, also in the palette) opens a glass panel over the window, like the palette. It lists the important keys, as set, in two columns grouped as Panes, Tabs, Spaces, Sessions, App and Edit, and Customize… under them opens Settings ▸ Keyboard Shortcuts, which has every key. Each modifier and key is its own keycap. An action's second key follows after "or". A set of actions that differ only by the key shows as one row with one keycap for the keys while each keeps its default: "Select Pane ⌥ ⌘ ←→↑↓", "Show Tab 1–9 ⌘ 1–9"; one changed, each shows on its own row. Esc, ⌘/ or a click outside closes it.

KeysActionMenu
⌘NNew Window, which lists every machine's sessions to pick fromFile
⌘Tnew tab, in the keyboard card's folderFile
⌃⌘Tnew spaceFile
⌥⌘TOpen Session (the panel)File
⇧⌘GGo to Directory (in a card on This Mac that runs only its shell); over a File, Markdown or tree page or a Git diff, Find PreviousFile, Edit
⌘SSave, on a File or Markdown pageFile
⌘RReload Page, on a browser cardView
⌥⌘RRedraw Terminal: the program in a terminal pane paints its screen again (a one-column size change and back); over a plugin card, Reload Plugin. Terminal's Soft Reset keyFile; Reload Plugin: View ▸ Pane
⇧⌘RReplace Pane: a fresh shell in the pane's place, size and folder, with the keyboard (asks first unless the pane runs only its shell); on an agent, browser or plugin pane the new shell shows the New pane chooserFile
⌘Wclose the pane (asks first unless the pane runs only its shell)File
⇧⌘Wclose the tab (asks first when a program runs in it)File
⌃⌘Wclose the space (asks first when a program runs in it)File
⌥⌘WDetach Session: the page leaves the window, the session keeps runningFile
⇧⌘IInsert PathEdit
⌘LOpen Location: the address field of a browser cardEdit
⌥⌘IShow Web Inspector, on a browser cardEdit
⌘Ffind in the keyboard card; on a File or Markdown page, the editor's find bar; on File Explorer's tree and a Git diff, its find bar (a filter of the files)Edit
⌘G, or Enter in the find barnext match (⇧Enter: previous match); in a Git diff, Next ChangeEdit
⌘ELock Editing: locks and unlocks a Markdown pageView
⇧⌘ESwitch Between Tree and File: the keyboard between a file and the tree beside it, in a File Explorer cardView
⌘Kthe command palette; ⇧⌘P also opens it (Rex's key)View
⌃⌘Sshow or hide the sidebarView
⌃⌘OShow Overview: the overview on or offView
⌘D, ⇧⌘Dsplit right, split downView ▸ Pane
⇧⌘↩zoom or restore the cardView ▸ Pane
⌥⌘=Balance Splits: even out the splits of the tabView ▸ Pane
⌥⌘ + arrowSelect Pane Left, Right, Up, Down: the keyboard goes to the next card that way (as in Ghostty and iTerm2)View ▸ Pane
⌘[ and ⌘]Select Previous Pane, Select Next Pane, over every cardView ▸ Pane
⌃- and ⌃⇧-, ⌘← and ⌘→over a plugin card, Back and Forward (VS Code's Go Back and Go Forward), ahead of the page's own keys; an arrow key in a text field still moves the caret
⌘← ⌘→, ⌘⌫, ⌥← ⌥→in a terminal: to the line's start and end, delete to the line's start, back and forward a word (⌃A, ⌃E, ⌃U, ⌥B, ⌥F to the program)
⌥⇧⌘ + arrowMove Pane: swap the keyboard card with the card that wayView ▸ Pane
⌘+ (and ⌘=), ⌘-, ⌘0Increase, Decrease, Reset Font Size: the text size; on a browser card that has the keyboard, the page's zoom (⌘0 also undoes a pinch)View
⌃⌘Ffull screen (the macOS key)View
⌘/Keyboard Shortcuts (the panel)Help
⌘1 … ⌘9switch tabsWindow
⇧⌘[ and ⌃⇧⇥, ⇧⌘] and ⌃⇥previous and next tabWindow
⌃⌘← and ⌃⌘→Go Back and Go Forward through the tabs shown before, across spaces (History). Xcode's keys: VS Code's ⌃- and ⌃⇧- are a plugin card's Back and Forward, a browser's ⌘[ ⌘] the pane stepsWindow
⇧⌘←, ⇧⌘→move the tab left, right (as iTerm2; in a text field they still select to the line's start or end)Window
⌃⌘[ and ⌃⌘]previous and next spaceWindow
⌃⌘1 … ⌃⌘9switch spaces, in herdr's order, pinned ones first, less the hidden ones (the sidebar's in Manual)Window
⌥⌘[ and ⌥⌘]previous and next sessionWindow
⌥⌘1 … ⌥⌘9switch sessions, in the window's orderWindow

Close Window (File), Float Pane and Resize Pane (View ▸ Pane), all in the palette too, have no shortcut (⌘W is Close Window when no main window has the keyboard): the window's close button closes it, the card header's button floats a pane, and the dividers and Balance Splits cover resizing. Open Terminal Here, Start Agent Here, Open Browser Here, Open File Explorer Here and Open Git Here (File, the card's menu, the palette) have none either (New pane). In the palette: ↩ runs, ⎋ goes back or closes, ⌫ on an empty field goes back.

The menu bar redraws whenever a command's title, key, or enabled state changes: SwiftUI rebuilds the menu bar only when the window's command list changes, and a stale disabled item would swallow its key (⇧⌘↩ after a split).

Rex shortcuts not taken, and why:

  • ⌘K stays the palette (D48), so Change Session (⌘K in Rex) is not taken; sessions open with Open Session (⌥⌘T).
  • ⌘/ (sidebar) is Keyboard Shortcuts instead: ⌃⌘S is the macOS sidebar key.
  • ⌘R reloads only a browser card's page: the snapshot is live, so nothing else needs a refresh. Replace Pane is ⇧⌘R, Redraw Terminal ⌥⌘R: no card has both Redraw Terminal and Reload Plugin, and ⌃L stays the program's own (a shell clears its screen with it).
  • Find Previous has a shortcut only over a File or Markdown page: elsewhere ⇧⌘G is Go to Directory. ⌘S and ⌘E have their key only over the cards that use them, because a disabled menu item swallows its key (File Explorer and Git).
  • ⇧⌘← and ⇧⌘↑ (Split Left, Split Up) would steal select-to-line-start from text fields.

How it works: Platform and code, Agents and notifications.

On this page