Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .impeccable/design.json
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@
},
"alarm": {
"role": "primary",
"displayName": "Alarm / Bell (terminal ANSI yellow, runtime-rotated per surface)",
"displayName": "Alarm (terminal ANSI yellow, runtime-rotated per surface)",
"canonical": "var(--vscode-terminal-ansiYellow)",
"tonalRamp": ["#4a3818", "#6e5424", "#917030", "#b58c45", "#d3a85c", "#f9d181", "#fbdda3", "#fee9b3"]
},
Expand Down Expand Up @@ -155,13 +155,13 @@
"motion": [
{ "name": "ease-quart-out", "value": "cubic-bezier(0.22, 1, 0.36, 1)", "purpose": "Default for pane spawn/kill and any layout-adjacent transition. Exponential ease-out, no bounce." },
{ "name": "spring-overshoot", "value": "cubic-bezier(0.34, 1.56, 0.64, 1)", "purpose": "Reserved for celebratory state-resolution: TODO check pop-in, kill-confirm letter flash, copy-confirm scale. Used only at 220–500ms; never on layout." },
{ "name": "ease-in-out-bell", "value": "ease-in-out", "purpose": "Bell ring continuous animation (800ms, infinite, alternating ±45deg rotation)." },
{ "name": "ease-in-out-alarm", "value": "ease-in-out", "purpose": "Alarm pulse (650ms, one bounded burst on arrival, infinite while speaking)." },
{ "name": "ease-out-shake", "value": "ease-out", "purpose": "Kill-overlay shake-x (400ms, x-axis only)." },
{ "name": "duration-pane", "value": "440ms", "purpose": "Pane spawn and kill choreography." },
{ "name": "duration-flourish", "value": "500ms", "purpose": "TODO pill dismiss sequence." },
{ "name": "duration-confirm", "value": "220ms", "purpose": "Kill-overlay confirm letter flash." },
{ "name": "duration-copy-flash", "value": "260ms", "purpose": "Selection popup copy-confirm scale flash." },
{ "name": "duration-bell-ring", "value": "800ms", "purpose": "One full ring cycle." },
{ "name": "duration-alarm-pulse","value": "650ms", "purpose": "One full alarm pulse cycle." },
{ "name": "duration-shake", "value": "400ms", "purpose": "Kill-cancel shake-x." }
],
"breakpoints": [
Expand All @@ -174,8 +174,8 @@
"kind": "custom",
"refersTo": "door",
"description": "Pane-header indicator on the baseboard. Top corners rounded, square bottom; the signature component of the system.",
"html": "<button class=\"ds-door\" type=\"button\" title=\"build\"><span class=\"ds-door__title\">build</span><span class=\"ds-door__badges\"><span class=\"ds-todo-pill\">TODO</span><svg class=\"ds-door__bell\" viewBox=\"0 0 256 256\" width=\"11\" height=\"11\" aria-hidden=\"true\"><path fill=\"currentColor\" d=\"M221.8 175.94C216.25 166.38 208 139.33 208 104a80 80 0 1 0-160 0c0 35.34-8.26 62.38-13.81 71.94A16 16 0 0 0 48 200h40.81a40 40 0 0 0 78.38 0H208a16 16 0 0 0 13.8-24.06ZM128 216a24 24 0 0 1-22.62-16h45.24A24 24 0 0 1 128 216Z\"/></svg></span></button>",
"css": ".ds-door { display: flex; align-items: center; gap: 8px; height: 24px; min-width: 68px; max-width: 220px; padding: 0 10px; overflow: hidden; border: none; border-radius: 8px 8px 0 0; background: var(--color-door-bg, #5e452e); color: var(--color-door-fg, #d3af86); font-family: var(--vscode-editor-font-family, ui-monospace, SFMono-Regular, Menlo, monospace); font-size: 0.75rem; line-height: 1rem; font-weight: 500; cursor: pointer; } .ds-door__title { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; text-align: left; } .ds-door__badges { display: flex; align-items: center; gap: 6px; flex-shrink: 0; } .ds-door__bell { color: var(--vscode-terminal-ansiYellow, #f9d181); }"
"html": "<button class=\"ds-door\" type=\"button\" title=\"build\"><span class=\"ds-door__title\">build</span><span class=\"ds-door__badges\"><span class=\"ds-todo-pill\">TODO</span></span></button>",
"css": ".ds-door { display: flex; align-items: center; gap: 8px; height: 24px; min-width: 68px; max-width: 220px; padding: 0 10px; overflow: hidden; border: none; border-radius: 8px 8px 0 0; background: var(--color-door-bg, #5e452e); color: var(--color-door-fg, #d3af86); font-family: var(--vscode-editor-font-family, ui-monospace, SFMono-Regular, Menlo, monospace); font-size: 0.75rem; line-height: 1rem; font-weight: 500; cursor: pointer; } .ds-door__title { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; text-align: left; } .ds-door__badges { display: flex; align-items: center; gap: 6px; flex-shrink: 0; }"
},
{
"name": "Pane Header (Active)",
Expand Down
12 changes: 6 additions & 6 deletions DESIGN.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ components:

Dormouse is a tenant in someone else's house. The house is VSCode. The user picked the furniture (their theme), the lighting (their mode), the typography (their editor font). Dormouse moves in, multiplies what the user can do with their terminals, and leaves the decor alone. The interface should be indistinguishable from a built-in panel: not because it imitates VSCode, but because it inherits from VSCode. Every color, every font, every surface is a passthrough of the host's tokens.

The system is intentionally minimal and bg-only. Chrome recedes; terminals are the content. Hierarchy is conveyed through background shifts between `header-active-bg` and `header-inactive-bg`, not through borders, shadows, or accent stripes. Status is conveyed through shape and position (a bell icon, a door's alert state) and through the active terminal palette's own ANSI red/green/yellow, not through a separate design-system palette.
The system is intentionally minimal and bg-only. Chrome recedes; terminals are the content. Hierarchy is conveyed through background shifts between `header-active-bg` and `header-inactive-bg`, not through borders, shadows, or accent stripes. Status is conveyed through shape and position (a door's alert state, a ringing Pane's outline) and through the active terminal palette's own ANSI red/green/yellow, not through a separate design-system palette.

The system explicitly rejects: rounded SaaS cards, gradient accents, hacker-aesthetic green-on-black, "Slack-style" Electron chrome bloat, decorative animations, and any token that hardcodes a color. If a user installs a high-contrast theme, the chrome can look flatter than usual: that is accepted, not "fixed" with overrides.

Expand Down Expand Up @@ -137,7 +137,7 @@ This system has no "primary" accent in the brand sense. The closest analogue is
- **Terminal Background / Foreground** (`var(--vscode-terminal-background)` / `var(--vscode-terminal-foreground)`): the terminal content surface and xterm default text. Orthogonal to the chrome.
- **Error** (`var(--vscode-terminal-ansiRed)`): destructive actions and kill-confirm letter flash.
- **Success** (`var(--vscode-terminal-ansiGreen)`): TODO check, theme-store install confirm.
- **Alarm** (`var(--vscode-terminal-ansiYellow)` baseline; runtime-overridden): alert tint. `computeDynamicPalette()` replaces each `--color-alarm-vs-*` token with plain white or black by the OKLab lightness of its background (active header, inactive header, Door, or terminal body), so ringing bells and the whole-Pane alarm treatment stay maximally legible on any surface.
- **Alarm** (`var(--vscode-terminal-ansiYellow)` baseline; runtime-overridden): alert tint. `computeDynamicPalette()` replaces each `--color-alarm-vs-*` token with plain white or black by the OKLab lightness of its background (active header, inactive header, Door, or terminal body), so every alarm inset and the whole-Pane alarm treatment stay maximally legible on any surface.

### Fixed Exceptions
Every literal color the Host-Theme-Only Rule below permits, in full. Each is here because the surface it paints is not read as part of the theme; a literal anywhere else is a bug.
Expand Down Expand Up @@ -198,18 +198,18 @@ Doors are the pane-header indicators on the baseboard. The most signature compon
- **Surface:** `bg-door-bg` + `text-door-fg`. These resolve at runtime via `computeDynamicPalette()` and may match either the inactive-header palette or the terminal palette, whichever has stronger separation from `app-bg`.
- **Dimensions:** `h-6` (24px), `min-w-[68px]`, `max-w-[220px]`; the title button pads `pl-2.5` (10px), `gap-2` between its glyph, title, and badges, ending `pr-2.5` alone or `pr-1` when the notepad button follows it. The notepad button carries the trailing inset itself (`pl-0.5 pr-2`).
- **Type:** `text-sm font-medium font-mono`.
- **Content:** leading browser-display icon cluster on a browser Surface (`size={12}` each, `gap-0.5` — a wide robot plus the presentation glyph, or the presentation glyph alone for `iframe`; named in the Door's accessible name, `docs/specs/dor-browser.md` → Browser Chrome); truncated title; optional TODO pill (`text-xs font-semibold tracking-[0.08em]`, success-tinted when flourishing); optional bell icon (`size={11}`, `weight="fill"`), `text-alarm-vs-door` when ringing; trailing notepad button (`size={12}`, `weight="fill"`) when the minimized Surface holds notes.
- **Alarm:** one 2px inset overlay (`--color-alarm-vs-door`) draws the edge for both the unlabelled ring, where it flashes once on arrival, and `SPOKEN`, which persists until the ring is attended and adds a speaker icon *beside* the TODO pill and bell instead of evicting them. `SPEAKING` instead inverts and pulses the whole Door and takes the badge slot for its speaker-plus-label, for one utterance. Both speech states carry a speaker icon (shape, not color); all three name the state in the accessible name. The row inventory is `docs/specs/layout.md` → Alarm overlay.
- **Content:** leading browser-display icon cluster on a browser Surface (`size={12}` each, `gap-0.5` — a wide robot plus the presentation glyph, or the presentation glyph alone for `iframe`; named in the Door's accessible name, `docs/specs/dor-browser.md` → Browser Chrome); truncated title; optional TODO pill (`text-xs font-semibold tracking-[0.08em]`, success-tinted when flourishing); trailing notepad button (`size={12}`, `weight="fill"`) when the minimized Surface holds notes.
- **Alarm:** one 2px inset overlay (`--color-alarm-vs-door`) draws the edge for both the unlabelled ring, where it flashes once on arrival, and `SPOKEN`, which persists until the ring is attended and adds a speaker icon *beside* the TODO pill instead of evicting it. `SPEAKING` instead inverts and pulses the whole Door and takes the badge slot for its speaker-plus-label, for one utterance. Both speech states carry a speaker icon (shape, not color); all three name the state in the accessible name. The row inventory is `docs/specs/layout.md` → Alarm overlay.
- **Hover/Focus:** no decorative hover on the door itself; the focus state is conveyed by the parent pane's selection ring, not by a per-door treatment. The door is a labelled `role="group"` wrapper holding one or two buttons rather than one button — the title button reattaches, the notepad button opens the popover and does not (`docs/specs/notepad.md` → Notepad UI) — and only the notepad button takes the standard `hover:bg-current/10` wash.

### Buttons

#### Header Action Button
The icon-and-tooltip button used inside pane headers (kill, alert toggle, todo, etc.).
The icon-and-tooltip button used inside pane headers (kill, minimize, notepad, etc.).
- **Shape:** `rounded` (4px) when icon-only, also `rounded` for labeled variants.
- **Color:** `text-inherit` — inherits the header's foreground, so it tints with the active/inactive header palette.
- **Hover:** `hover:bg-current/10` — a 10%-opacity wash of the current text color. Theme-agnostic, works light or dark.
- **Tooltip:** rendered through a portal as a `PopupButtonRow` 8px below the button, with `text-sm` primary line and an optional muted detail line. Keybindings inside the tooltip auto-render as `[bracketed]` shortcuts.
- **Tooltip:** rendered through a portal as a `PopupButtonRow` 8px below the button, one `text-sm` line right-aligned to its edge. Keybindings inside the tooltip auto-render as `[bracketed]` shortcuts.

#### Popup Button (`popupButton`)
The flat segments inside a `PopupButtonRow` — the row owns the border, background, shadow, and `text-sm`, so a segment contributes only padding and state. Every segment currently inherits the row's foreground; these rows offer rather than ask, so none of them carries an emphasized action.
Expand Down
10 changes: 5 additions & 5 deletions TUTORIAL_MOCKUP.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ Four beats. Beat 2 is the section; the rest is scaffolding around it.

1. **A rule, not a switch** — alerts belong to a command, not a tab.
2. **Attention** — three runs of the same task, three outcomes.
3. **Two more ways the bell rings** — neither needs a rule.
3. **Two more ways a pane rings** — neither needs a rule.
4. **Nothing gets lost** — the TODO receipt.

## Beat 1 — A rule, not a switch
Expand Down Expand Up @@ -64,13 +64,13 @@ Reference table (candidate for the section prose or the dialog, not a step):
| typing into it | hovering it |
| clicking a door, or `Enter` on a door | a door sitting in the baseboard |

## Beat 3 — Two more ways the bell rings
## Beat 3 — Two more ways a pane rings

Both are rule-free, and both obey the same attention rule as Beat 2.

| id | title | hint |
|---|---|---|
| `al-notif` | A program can ring the bell itself | Press `n` for a fake build that sends a notification. No rule needed — any program that asks for attention gets it, and its message rides along on the TODO tag. |
| `al-notif` | A program can ring on its own | Press `n` for a fake build that sends a notification. No rule needed — any program that asks for attention gets it, and its message rides along on the TODO tag. |
| `al-cmd-exit` | A long command finished while you were away | Dormouse noticed you watched this command start, then left. Anything that ran longer than 15 seconds and finished after you walked away is worth a word. |

## Beat 4 — Nothing gets lost
Expand All @@ -89,14 +89,14 @@ al-spreads One rule, every pane running it
al-quiet-attended Sit in the pane — it finishes silently
al-ring-switch Look away — the same task rings
al-ring-idle Stay put but idle — it rings anyway
al-notif A program can ring the bell itself
al-notif A program can ring on its own
al-cmd-exit A long command finished while you were away
al-todo-auto A dismissed ring leaves a TODO
al-todo-clear Press `Enter` in the pane to clear it
al-todo-manual Add a TODO by hand
```

Changes from today's nine: `al-busy` ("the bell tilts while the command works")
Changes from today's nine: `al-busy` (the pane's in-progress feedback)
is **cut** as a step — it is feedback, not a concept, and it is what the user is
already staring at during Beat 2. `al-ring` is **split into three** so each
attention mechanism gets its own line. Everything else keeps its id.
Comment on lines +99 to 102

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR cuts al-busy, so today's list is eight and the cut is no longer a pending change.

Suggested change
Changes from today's nine: `al-busy` (the pane's in-progress feedback)
is **cut** as a step — it is feedback, not a concept, and it is what the user is
already staring at during Beat 2. `al-ring` is **split into three** so each
attention mechanism gets its own line. Everything else keeps its id.
Changes from today's eight: `al-ring` is **split into three** so each
attention mechanism gets its own line. Everything else keeps its id.

Expand Down
Loading
Loading