387 lines
18 KiB
Markdown
387 lines
18 KiB
Markdown
# Handoff: Helder — editor for working with Claude Code
|
||
|
||
## Overview
|
||
|
||
Helder is a desktop code editor built around one job: work on a codebase together with
|
||
Claude Code. It replaces a general IDE with four columns — source control, explorer,
|
||
editor, agent — plus five overlays (search, keyboard shortcuts, project note, project
|
||
launcher, expanded diff) and a set of small surfaces (context menus, a pass-on-to-agent
|
||
prompt, tooltips, a markdown preview).
|
||
|
||
This handoff describes one consistent visual system for all of those screens.
|
||
|
||
## About the design files
|
||
|
||
The files in this bundle are **design references written in HTML**. They show the
|
||
intended look, spacing and states. They are not production code to copy.
|
||
|
||
The task is to **recreate these screens in the target codebase's own environment**
|
||
(Electron + React, Tauri + Svelte, SwiftUI, whatever the app already uses) with its
|
||
established patterns. If no environment exists yet, pick the framework that fits a
|
||
desktop editor and implement the design there.
|
||
|
||
`Helder IDE.dc.html` is a single-canvas board: every screen sits on one page, side by
|
||
side, at real pixel sizes. Open it in a browser to inspect any value with devtools.
|
||
|
||
## Fidelity
|
||
|
||
**High fidelity.** Colours, type, row heights, paddings, radii and states are final and
|
||
exact. Recreate them pixel-for-pixel. Everything is authored with inline styles so any
|
||
element's computed value can be read directly from the file.
|
||
|
||
Two things are deliberately *not* final:
|
||
- The code shown inside the editor panes is sample content, not a spec.
|
||
- Icons are Unicode stand-ins (`⌕ ▤ ◇ ⧉ ✎ ↺ ⇄ ⑂ ◆ →`). Ship them as Lucide glyphs at
|
||
stroke width 1.75, 16px inline / 18px standalone.
|
||
|
||
---
|
||
|
||
## Design tokens
|
||
|
||
### Surfaces (four, no more)
|
||
|
||
| Token | Hex | Use |
|
||
|---|---|---|
|
||
| `editor` | `#101720` | Editor canvas, terminal, launcher backdrop, code blocks |
|
||
| `panel` | `#18202B` | Title bar, side panels, status bar, overlays, menus, tooltip host |
|
||
| `raised` | `#232C39` | Selected row, hairline borders, tooltip surface, keycap borders |
|
||
| `hover` | `#1E2733` | Row hover fill only |
|
||
|
||
### Text on dark
|
||
|
||
| Token | Hex | Use |
|
||
|---|---|---|
|
||
| `text-1` | `#F4F5F4` | Active file, dialog titles, selected row |
|
||
| `text-2` | `#E4E7E6` | Body copy, code plain text |
|
||
| `text-3` | `#BAC0C0` | Inactive rows, identifiers, secondary copy |
|
||
| `text-4` | `#6C7783` | Labels, paths, meta, comments |
|
||
| `text-5` | `#3A424C` | Line numbers, disabled |
|
||
|
||
### Accent — amber, reserved
|
||
|
||
`#E8913A` primary · `#C4741F` deep · `#F0B476` soft · `rgba(232,145,58,.10)` tint ·
|
||
`rgba(232,145,58,.22)` focus ring.
|
||
|
||
Amber is allowed **only** for: the active toolbar toggle (tint fill), the 2px selection
|
||
rule, the caret, keycap glyphs, the blinking period in the wordmark, the primary button
|
||
fill (ink text on amber, never white), the search-hit highlight, section markers, list
|
||
markers, links, and counts in the status bar. Never an amber panel, never an amber
|
||
heading.
|
||
|
||
### Light canvas (this board only)
|
||
|
||
`#EFF0EE` page · `#E5E7E4` spec card · `#CDD1CD` hairline · `#171C22` ink ·
|
||
`#3A424C` ink muted · `#6B7480` ink dim. The application itself is dark only.
|
||
|
||
### Syntax — six colours, all muted
|
||
|
||
| Role | Hex |
|
||
|---|---|
|
||
| plain / function name | `#E4E7E6` |
|
||
| variable / property | `#BAC0C0` |
|
||
| comment | `#6C7783` |
|
||
| keyword / operator / pseudo-class | `#C3A6CE` |
|
||
| string / value / type path | `#8FBFB4` |
|
||
| number / tag / hex literal | `#F0B476` |
|
||
|
||
No bold, no italic in code. Weight stays 400 so the column reads flat.
|
||
|
||
### Diff
|
||
|
||
- added: text `#8FBFB4`, fill `rgba(143,191,180,.12)`, 2px left rule `#8FBFB4`
|
||
- removed: text `#C4741F`, fill `rgba(196,116,31,.14)`, 2px left rule `#C4741F`
|
||
- counts in headers: `+1` in `#8FBFB4`, `−1` in `#C4741F` (real minus sign U+2212)
|
||
|
||
No green, no red anywhere. The diff reads on shape and on the 2px rule.
|
||
|
||
### Type
|
||
|
||
- `IBM Plex Mono` — 400/500/600/700. All labels, paths, code, keycaps, titles, numbers.
|
||
- `IBM Plex Sans` — 400/500. Rows, menu items, tooltips, buttons, running text.
|
||
|
||
| Role | Spec |
|
||
|---|---|
|
||
| Board display | Mono 700, 58px/1.02, `-0.04em` |
|
||
| Section title | Mono 700, 20px/1.2, `-0.02em` |
|
||
| Dialog title | Mono 700, 14px/1 |
|
||
| Section/panel label | Mono 700, 10px, `0.14em`, uppercase, `#6C7783` |
|
||
| Board label | Mono 700, 10–11px, `0.14em`, uppercase, `#6B7480` |
|
||
| Code | Mono 400, 13px / 20px line box |
|
||
| Search hit line | Mono 400, 12px / 24px line box |
|
||
| Path / meta / status bar | Mono 400, 11–12px |
|
||
| Keycap | Mono 600, 12px, padding 4px 6px, 1px `#232C39`, radius 2px, glyph `#E8913A` |
|
||
| Row label | Sans 400 13px (500 when selected) |
|
||
| Body copy | Sans 400, 14px/1.7, max 68ch |
|
||
| Tooltip | Sans 400, 12px/1.5 |
|
||
|
||
### Geometry
|
||
|
||
| Value | Where |
|
||
|---|---|
|
||
| 24px | Explorer / launcher-adjacent row height |
|
||
| 26px | Source-control row height |
|
||
| 28px | Status bar, state-specimen rows |
|
||
| 30px | Context-menu item height |
|
||
| 34px | Editor tab strip, markdown/code panel header |
|
||
| 44px | Title bar and toolbar |
|
||
| 20px | Code line box (13px type) |
|
||
| 2px | Radius: buttons, inputs, tags, keycaps, menus' inner rows, code blocks |
|
||
| 4px | Radius: panels, cards, menus |
|
||
| 8px | Radius: overlays (modals) only |
|
||
| 1px | Every hairline (`#232C39` on dark, `#CDD1CD` on light) |
|
||
| 2px | Accent rule: selection, focus border, pull-quote |
|
||
| 9999px | Traffic-light dots and avatars only |
|
||
|
||
Column widths in the workspace: source control 236 · explorer 288 · editor flex ·
|
||
agent 480. Agent terminal block 190px tall. Full frame 1760 × 1000.
|
||
|
||
### Elevation
|
||
|
||
Only two shadows exist:
|
||
- dropdown / context menu: `0 4px 16px rgba(23,28,34,.10)`
|
||
- overlay: `0 16px 48px rgba(23,28,34,.18)`
|
||
|
||
No ambient card shadow, no glow.
|
||
|
||
### Motion
|
||
|
||
Colour transitions only, 160ms `cubic-bezier(0.22,1,0.36,1)` (120ms on small controls).
|
||
The single exception is `blink`: a stepped 1.1s on/off (no fade) used for the caret, the
|
||
terminal block cursor and the amber period in the wordmark. No entrance animation, no
|
||
lift, no scale, no parallax.
|
||
|
||
---
|
||
|
||
## Screens
|
||
|
||
### 01 · Workspace (1760 × 1000)
|
||
|
||
Vertical stack: title bar 44px → body (flex row) → status bar 28px.
|
||
|
||
**Title bar** (`#18202B`, 1px bottom `#232C39`, padding 0 14px, gap 18px)
|
||
Traffic lights 12px (`#E8913A`, `#6C7783`, `#3A424C`, gap 8px) · wordmark
|
||
`helder` Mono 700 13px `#F4F5F4` with a blinking `.` in `#E8913A` · project `odynt`
|
||
Mono 12px `#6C7783` · `·` · branch `main` Mono 500 12px `#E8913A` · breadcrumb of the
|
||
open path in Mono 12px `#6C7783`, last segment `#F4F5F4` 600, `›` separators · then the
|
||
toolbar, right-aligned, gap 4px.
|
||
|
||
Toolbar toggle: label Sans 12px + keycap. Off = label `#BAC0C0`, no fill. On = fill
|
||
`rgba(232,145,58,.10)`, label `#F4F5F4` 500, keycap border `rgba(232,145,58,.35)`.
|
||
Hidden-files-off is the muted case: label and keycap both `#6C7783`. Toggles:
|
||
Search ⌘F · Auto-fit ⌘A · Hidden ⌘. · Note ⌘N · Git ⌘G · `?` (26px square, 1px border).
|
||
|
||
**Source control column** (236px, `#18202B`, 1px right border)
|
||
Commit box: 52px `#101720` field, 1px `#232C39`, radius 2, placeholder
|
||
"Shift+Enter to commit" `#6C7783`; 34px push button `↑` beside it, same border.
|
||
Group header: Mono 700 10px `0.14em` uppercase `#6C7783`, count right in `#E8913A`
|
||
("STAGED CHANGES 4", "CHANGES 1"). Rows 26px: status letter (Mono 600 10px — staged
|
||
`#8FBFB4`, unstaged `#F0B476`) · 8px type badge · file name Sans 12px, ellipsised.
|
||
Footer line "4 staged · 1 unstaged" Mono 11px `#6C7783`.
|
||
|
||
**Explorer** (288px, `#18202B`) — 30px header ("EXPLORER" / project name), then 24px
|
||
rows. Indent 16px per level (12 · 28 · 44 · 60 · 76 padding-left). Collapsed `›`
|
||
`#6C7783`; expanded `⌄` `#E8913A`, its label `#F4F5F4`. File rows carry an 8px type
|
||
badge and, when dirty, a trailing `M` in `#8FBFB4`.
|
||
|
||
Type badge: Mono 600 8px, ink text `#101720` on a per-extension fill, radius 2,
|
||
padding 3px 4px — php `#C3A6CE` · md `#BAC0C0` · js `#F0B476` · css `#8FBFB4`.
|
||
|
||
**Editor** (flex, `#101720`) — 34px strip: "MODIFIED" label, `+1` / `−1` counts, then a
|
||
right-aligned segmented control (1px `#232C39`, radius 2, dividers 1px): Actual ·
|
||
Original · Diff · Split. Active segment = amber fill with `#171C22` text.
|
||
Code area: CSS grid `56px 1fr`, line box 20px, numbers right-aligned `#3A424C` with
|
||
14px right padding. **Indentation is padding-left on the code cell** (7.82px per space:
|
||
31.3 / 62.6 / 93.8 / 125.1) — do not ship non-breaking spaces.
|
||
|
||
**Agent panel** (480px, `#18202B`, 1px left border)
|
||
Header: 60px `#232C39` square (mark), then `Claude Code` Mono 700 14px + version in
|
||
`#6C7783`, model line Sans 12px `#BAC0C0`, cwd Mono 12px `#6C7783`.
|
||
Notice strip: fill `rgba(232,145,58,.10)`, `[ ! ]` Mono 600 12px `#E8913A`, sentence
|
||
Sans 12px, inline command in Mono `#F0B476`.
|
||
Transcript: user turn prefixed `›` in `#E8913A`, agent turn `◆` in `#6C7783`, text
|
||
Sans 13px/1.6. Tool calls sit in a `#101720` block, 1px `#232C39`: verb in `#8FBFB4`
|
||
(read) or `#F0B476` (write), target and counts `#6C7783`.
|
||
Prompt field: 44px, `#101720`, **2px `#E8913A` border + `0 0 0 2px rgba(232,145,58,.22)`
|
||
ring** (this is the focus treatment everywhere), `›` prefix, blinking 1px caret.
|
||
Status line: Mono 11px `#6C7783`; project chip = amber fill with `#171C22` text;
|
||
`▸▸ auto mode` in `#E8913A`; slash hint right.
|
||
Terminal: 190px, `#101720`, Mono 12px/1.7 — `[main]` `#8FBFB4`, `[~/path]$` `#6C7783`,
|
||
output `#6C7783`, 7×14px blinking amber block cursor.
|
||
|
||
**Status bar** (28px, `#18202B`) — `⑂ main` in `#E8913A`, `+16` `#8FBFB4`, `−12`
|
||
`#C4741F`, then right-aligned path · Ln/Col · UTF-8 · LF · language (`#BAC0C0`).
|
||
|
||
### 02a · Search (⌘F)
|
||
|
||
Overlay: flat ink scrim `rgba(16,23,32,.72)` (no blur), 34px inset, panel `#18202B`,
|
||
1px `#232C39`, radius 8, overlay shadow.
|
||
|
||
- Query bar 54px: `⌕` `#E8913A`, query Mono 500 16px `#F4F5F4`, blinking caret; right
|
||
side = extension filters (active = amber fill + ink text; inactive = 1px border,
|
||
`#BAC0C0`) and a Mono 11px result summary `#6C7783` behind a 1px left divider.
|
||
- Three columns: **this file** (230px) · **project** (flex) · **files** (250px), split by
|
||
1px borders. Column headers are the standard 10px mono labels; the focused column's
|
||
header is `#E8913A` with a count chip (amber fill, ink text).
|
||
- Result group header: type badge + path Mono 12px `#BAC0C0`, hit count right `#6C7783`.
|
||
- Hit lines: grid `64px 1fr`, line box 24px. Match run = amber fill with `#171C22` text
|
||
on the selected row, `#F0B476` text elsewhere. Selected row: `#232C39` fill, 2px amber
|
||
left rule, and the line number lifts to `#E8913A` (never leave it at `#3A424C`).
|
||
- Empty column state: one plain sentence, Sans 12px `#6C7783` ("No matches in this
|
||
file." / "No file names match."). No illustration.
|
||
- Footer 38px: key hints (`⌘←`/`⌘→` column, `⌘↑`/`⌘↓` row, `↵` open) with amber glyphs,
|
||
`esc` chip right.
|
||
|
||
### 02b · Keyboard shortcuts (`?`)
|
||
|
||
Same overlay shell. 50px header with `◇` `#E8913A` + "Keyboard shortcuts" + `esc` chip.
|
||
Body groups (`NAVIGATE`, `AGENT`, `GIT`, `FILE`) each a 10px mono label, then a
|
||
`92px 1fr` grid: keycap cluster left (gap 4px), description Sans 13px `#E4E7E6` right,
|
||
6px vertical padding per row.
|
||
|
||
### 02c · Project note (⌘N)
|
||
|
||
Same shell. Header: `▤` amber, "Note", filename `.notes.txt` Mono 12px `#6C7783`, then
|
||
the primary button — amber fill, `#171C22` text, Sans 500 12px, radius 2, padding
|
||
6px 10px, with a `⌘P` keycap at Mono 600 11px — then the `esc` chip.
|
||
Body: Mono 400 14px/1.7 `#E4E7E6`, max 68ch, 18px between paragraphs, blinking caret at
|
||
the end of the text. Footer 34px: "saved on focus loss · 412 characters".
|
||
|
||
The note is plain text and it is the agent's input: ⌘P sends the whole note.
|
||
|
||
### 02d · Project launcher
|
||
|
||
Window `#101720` with only traffic lights (34px), no title bar. Centred panel on
|
||
`#18202B`, radius 8, overlay shadow, top-aligned with 20px/40px padding.
|
||
Header: `◆` amber + wordmark with blinking period + "Open a project to begin" Sans 12px
|
||
`#6C7783`. Then a 46px "Open new project…" row with `+` amber and an `↵` chip.
|
||
`RECENT` label, then 38px rows: `▤` icon, name Sans 500 13px, path Mono 11px `#6C7783`.
|
||
Selected row: `#232C39`, 2px amber left rule, icon and path lift one step.
|
||
Footer 36px: `⌘↑↓ navigate · ↵ open`.
|
||
|
||
### 03 · Expanded diff (1760 × 620)
|
||
|
||
Own window: 42px title bar (traffic lights, path Mono 500 12px `#F4F5F4`, "MODIFIED",
|
||
`+1` / `−1`, "staged → actual" Mono 11px `#6C7783`, and a right-aligned
|
||
"Collapse `esc`" button with 1px border).
|
||
Two panes split by a 1px border; each has a 30px header — left `ORIGINAL` + "before"
|
||
`#3A424C`, right `UPDATED` in `#E8913A` + "after".
|
||
Panes are grids `52px 1fr`, line box 22px, indentation as padding-left, and **identical
|
||
line numbering in both panes** so the eye can travel across. Changed row gets the fill,
|
||
the 2px left rule and a lifted number colour.
|
||
|
||
### 04 · Small surfaces
|
||
|
||
**Context menu** (explorer and source control) — 320px, `#18202B`, 1px `#232C39`,
|
||
radius 4, dropdown shadow, 8px vertical padding. First a path header (Mono 11px
|
||
`#6C7783`, 1px bottom border). Items 30px, Sans 13px `#BAC0C0`, icon `#6C7783`.
|
||
Highlighted item: `#232C39` fill, 2px amber left rule, label `#F4F5F4` 500, icon amber.
|
||
Destructive item ("Delete file", "Discard changes"): `#C4741F` label. Groups separated
|
||
by a 1px rule with 6px margins.
|
||
|
||
Explorer items: Pass on reference · Copy reference · Pass on file name · Copy file name
|
||
| Rename file · Show in Finder · Delete file.
|
||
Source-control items: Pass on reference · Copy reference | Stage changes · Open diff ·
|
||
Discard changes.
|
||
|
||
**Pass on to agent** — 460px panel, 14px padding, gap 12. Title row (`◇` amber +
|
||
Mono 700 13px + `esc` chip), a focused 38px input (2px amber border + ring, blinking
|
||
caret), then an INSERTS preview: 10px mono label + the composed string on an amber fill
|
||
with `#171C22` text, radius 2, ellipsised. Footer hint `↵ insert into agent · esc cancel`
|
||
with amber glyphs.
|
||
|
||
**Tooltip** — `#232C39` surface, 1px `#3A424C`, radius 2, padding 8px 10px, max 300px,
|
||
Sans 12px/1.5 `#E4E7E6`. No arrow, no shadow. The current state is named inside the
|
||
sentence in amber ("Hidden files: *hidden* — …", "Auto-fit panels: *on* — …"), then one
|
||
sentence saying what a click does.
|
||
|
||
**Markdown Actual / Preview** — same 34px header on both halves; the segmented control's
|
||
active side is the amber fill. Actual = the code grid (`44px 1fr`, line box 20px) with
|
||
`##` headings in `#F0B476`. Preview: 18px/20px padding, max 68ch, Sans 13px/1.7 body,
|
||
Mono 700 headings with a 1px `#232C39` underline.
|
||
|
||
### 06 · Code colours and markdown preview
|
||
|
||
Four specimens at 620px: a JS module, a PHP class, a CSS file and the full markdown
|
||
preview. Each panel: 34px header with type badge, path Mono 500 12px, and a right
|
||
language label (or the Actual/Preview control).
|
||
|
||
The markdown preview is the reading surface, so it is the one place where Sans body copy
|
||
gets room:
|
||
- eyebrow: 10px mono label `#6C7783`
|
||
- h2: Mono 700 24px/1.1, `-0.03em`, `#F4F5F4`
|
||
- h3: Mono 700 17px/1.2 with a 1px `#232C39` underline, 8px below the text
|
||
- paragraph: Sans 14px/1.7 `#E4E7E6`, max 68ch, `text-wrap: pretty`
|
||
- list: flex rows, gap 10, `—` marker in `#E8913A` (never a bullet, never an emoji)
|
||
- inline code: Mono 13px `#F0B476` on `#18202B`, 1px `#232C39`, radius 2, padding 1px 5px
|
||
- block quote: 2px amber left rule, 16px left padding, Sans *italic* 15px `#F0B476`
|
||
- code block: `#18202B`, 1px `#232C39`, radius 2, padding 14px 16px, Mono 13px/20px,
|
||
syntax palette as above
|
||
- table: 1px `#232C39` container, radius 2; header row on `#18202B` with 10px mono
|
||
labels; body rows Sans 13px `#BAC0C0`, cells 10px 14px, 1px row rules; state words use
|
||
`#8FBFB4` (done) and `#E8913A` (open)
|
||
- link: `#E8913A` with a 1px `#232C39` bottom border; hover lifts the text to `#F4F5F4`
|
||
and the border to `#E8913A`. `→` marks forward action.
|
||
|
||
---
|
||
|
||
## Interactions and behaviour
|
||
|
||
| Trigger | Result |
|
||
|---|---|
|
||
| `⌘F` | Search overlay, query seeded from the editor selection |
|
||
| `⌘↑` / `⌘↓` | Move the row cursor in the focused list |
|
||
| `⌘←` / `⌘→` | Move focus between search columns |
|
||
| `↵` | Open the selected row (search hit, file, recent project) |
|
||
| `⌘→` (editor) | Pass the current selection to the agent |
|
||
| `⌘M` | Cycle Actual · Original · Diff · Split |
|
||
| `⌘C` / `⌘↵` / `⌘P` (git) | Focus commit message / commit staged / push branch |
|
||
| `⌘A` | Toggle auto-fit panels (columns re-fit on resize and focus) |
|
||
| `⌘.` | Toggle hidden dotfiles in tree and search |
|
||
| `⌘G` | Show or hide the source-control column |
|
||
| `⌘S` / `⌘W` / `⌘D` | Save / close / delete (confirm) the current file |
|
||
| `⌘N` | Open the project note; it saves on focus loss |
|
||
| `⌘P` (note open) | Send the whole note to the agent |
|
||
| right-click a row | Context menu, anchored to the pointer, first item pre-highlighted |
|
||
| `esc` | Close the top overlay, menu or prompt; never more than one |
|
||
|
||
Rules that hold everywhere:
|
||
- Exactly one overlay at a time, on a flat ink scrim. Overlays never stack.
|
||
- Hover changes fill one step and nothing else. No lift, no scale, no shadow, no opacity.
|
||
- Press holds the hover colour. Nothing shrinks.
|
||
- Focus is always the 2px amber border plus the 2px 22% ring. Never remove it.
|
||
- Disabled is 40% opacity plus `cursor: not-allowed`, no recolouring.
|
||
- Empty and error states are one plain sentence starting with an em dash. No icon, no
|
||
apology, no exclamation mark.
|
||
|
||
## State
|
||
|
||
- `project` — path, branch, recent list (persisted)
|
||
- `openFile` — path, language, dirty flag, cursor line/col, view mode
|
||
(`actual|original|diff|split`)
|
||
- `tree` — expanded paths, selected path, `showHidden`
|
||
- `git` — staged[], unstaged[], commit message draft, ahead/behind counts
|
||
- `agent` — model, session, transcript, prompt draft, pending tool calls, auth notices
|
||
- `overlay` — `null | search | shortcuts | note | diff | launcher | menu | passOn`
|
||
- `panels` — column widths, `autoFit`, `gitVisible`
|
||
- `note` — text, dirty flag (write on blur)
|
||
|
||
Search runs per keystroke against three indexes (open file, project contents, file
|
||
names) and reports counts per column; a query with no hits leaves the columns in their
|
||
empty state rather than collapsing them.
|
||
|
||
## Assets
|
||
|
||
None. No images, no illustrations, no photography. Icons come from Lucide
|
||
(`lucide@0.544.0`, stroke width 1.75); the Unicode glyphs in the mock are placeholders.
|
||
Fonts are IBM Plex Mono and IBM Plex Sans (currently from Google Fonts — swap in local
|
||
woff2 for a desktop build).
|
||
|
||
## Files
|
||
|
||
- `Helder IDE.dc.html` — the design board: all screens, one canvas, real sizes
|
||
- `tokens/*.css` — the Kade token files the board is built on (colour, type, spacing,
|
||
radius, elevation, motion, fonts)
|
||
- `styles.css` — the token entry point
|
||
|
||
Open `Helder IDE.dc.html` in a browser; the board is inert (no interaction) by design.
|