---
title: Motion & Polish (the app's visual flourishes)
---

# Motion & Polish (visual flourishes, on by default)

## What it is

**Settings → Appearance → Motion & Polish.** A master switch plus per-effect toggles for Omniscio's
visual flourishes. **Everything is ON by default since 2026-07-16** — the polish is part of the
first impression. The safety levers are unchanged: turning the master OFF still kills every effect
at once, a user's explicit opt-out (master or per-effect) is never overridden, and all motion
auto-quiets under the OS "reduce motion" setting and Omniscio's Low-Power mode. (Before 2026-07-16 the
master defaulted off and only the "Liveliness" tier lit up with it; the flip unified everything to
default-on.)

Mirrors the **Chat Depth** dial's plumbing: settings → Zod → a `data-polish-*` attribute on
`<html>` → gated CSS (or a component-level gate for motion that CSS can't express). Engineering
invariants + the tests that lock them: [motion-polish-contract.md](../../.claude/memory/contracts/motion-polish-contract.md).

## Where to find it

**Settings → Appearance → Motion & Polish** — the master switch and the per-effect toggles behind it.

## How it behaves

### How gating works

- `motionPolishEnabled` (master, **default on**) gates EVERYTHING. An explicit master-off renders
  nothing — the one-switch kill.
- Each effect has its own boolean, **all default on** (`?? true` at the gate mirrors the Zod
  `.default(true)`, so a config that predates a key still gets the polished default; an explicit
  per-effect `false` survives independently).
- The pure helper `computePolishAttributes(settings)` ([src/renderer/src/lib/motion-polish.ts](../../src/renderer/src/lib/motion-polish.ts))
  is the single source of truth; `isPolishEffectOn(settings, effect)` is its boolean form for
  component wiring. Both window roots (main + detached) apply the attributes.
- Persistent-mode effects use a `data-polish-*` attribute; transient/one-shot effects (Inbox Zero)
  gate via `isPolishEffectOn` in a hook (an attribute can't represent a one-shot event).
- Settings persist as DELTAS, so the default flip reaches every install that never touched the
  toggles; only a persisted `false` keeps an effect off.

### The effects (all default on under the master)

| Toggle                                     | What it does                                                                                                                                                                                                      |
| ------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Interactive surfaces (`polishInteractive`) | Buttons lift with a soft tinted shadow on hover.                                                                                                                                                                  |
| Dashboard motion (`polishDashboard`)       | Insights (codebase-stats) numbers count up from zero, and the stat cards cascade in when the panel opens.                                                                                                         |
| Ambient backgrounds (`polishAmbient`)      | A slow drifting accent gradient behind the big welcome ("No session selected") and "All clear" inbox screens.                                                                                                     |
| Depth & elevation (`polishDepth`)          | Panels and cards lift with a soft shadow.                                                                                                                                                                         |
| View crossfades (`polishViewCrossfade`)    | The Dashboard fades instead of hard-swapping on view change.                                                                                                                                                      |
| Glide on reorder (`polishGlideReorder`)    | Needs-You / Pinned sidebar rows slide into place and their sections collapse smoothly, so everything below (including the "Live Sessions" divider) re-settles in sync instead of snapping when the list re-sorts. |
| Inbox Zero celebration (`polishInboxZero`) | A calm "you're all caught up" moment (soft glow + self-drawing check) when you clear the last inbox item.                                                                                                         |

### Related: the always-on butter layer (not toggles)

Separate from these toggles, a base layer of one-shot interaction feedback is always on (like the
dialog entrance): the segmented-control active pill glides between options, inbox rows fade in on
arrival and height-collapse on dismiss, button loading spinners fade in, and count badges pop once
when their number changes. Same safety rules (one-shot, reduced-motion + low-power kills); detail:
[buttery-microinteractions-contract.md](../../.claude/memory/contracts/buttery-microinteractions-contract.md).

### Notes

- Accessibility / performance: every animated effect is killed by BOTH `prefers-reduced-motion`
  and `html.low-power`; effects animate transform/opacity only (60fps) and stay off the
  performance-critical chat-bubble surface (owned by Chat Depth) and the virtualized session list.
- Adding a new effect: follow the end-to-end chain in the contract (type + default → Zod → gate →
  both app roots → CSS/component → settings toggle → search keywords → `npm run settings:catalog`).
  A missing link = a dead toggle.
- History: [motion-polish-toggles-postmortem.md](../../.claude/memory/postmortems/motion-polish-toggles-postmortem.md).

## Related

- [chat-depth.md](chat-depth.md) — the sibling appearance dial whose plumbing this mirrors.
- [low-power-mode.md](low-power-mode.md) — the mode that quiets every animated effect.
- [perf-status.md](perf-status.md) — what the app does when the machine is under load.

