Handoff: Helder — in-pane diff (screen 3b)
Overview
Helder is a desktop editor for working with Claude Code. This handoff covers one screen: the workspace with a modified file open in the editor pane, in Actual view.
The idea behind the screen: the user always reads the current version of the file. A changed
line is marked in place with a teal rule and a teal tint — nothing else moves, no split view, no
+/− line pairs. When the user hovers a changed line, the whole original file slides in over
the right-hand column (agent + terminal) at the same scroll position, so the two versions can be
compared line by line. The overlay disappears on mouse-out. There is no mode to enter and no mode to
leave.
About the design files
03b-in-pane-diff.html in this folder is a design reference created in HTML — a prototype that
shows the intended look and behaviour. It is not production code to copy.
The task is to recreate this design in the target codebase's own environment (Electron + React, Tauri, SwiftUI, whatever Helder already uses) with that codebase's established patterns, components and styling layer. If no environment exists yet, choose the framework that fits the product and implement the design there.
The HTML uses inline styles throughout because of how the design tool works. Do not treat that as a styling instruction — move the values into the codebase's own token/theme layer.
Fidelity
High fidelity. Colours, type, spacing, row heights and states below are final and exact. Recreate the UI pixel-perfectly. The only intentionally loose part is the file-tree and source-control content, which is sample data.
Screen
Name: Workspace — file modified, Actual view Canvas: 1760 × 1000 px (design size; the real window is resizable — see Responsive behaviour) Purpose: read and edit a file that has uncommitted changes, while Claude Code works in the right column; check what any changed line used to be without leaving the file.
Column layout (left → right)
| Region | Width | Background | Divider |
|---|---|---|---|
| Source control | 300 px, fixed | #18202B |
1 px #232C39 right |
| Explorer | 288 px, fixed | #18202B |
1 px #232C39 right |
| Editor | flexible (692 px at 1760) | #101720 |
— |
| Agent + terminal | 480 px, fixed | #101720 |
1 px #232C39 left |
Vertical stack: title bar 44 px → body row (flex: 1) → status bar 28 px.
Title bar — 44 px, #18202B, 1 px #232C39 bottom
- Traffic lights: three 12 px circles,
#E8913A/#6C7783/#3A424C, 8 px gap, 14 px from left. - Wordmark
helder.— IBM Plex Mono 700 13 px#F4F5F4; the period is#E8913Aand blinks (see Animation). - Repo · worktree:
bob#6C7783·bob2#E8913A500, Plex Mono 12 px. - Breadcrumb: Plex Mono 12 px
#6C7783,›separators, last crumb#F4F5F4600. - Right cluster, each 6 px 9 px padding, Plex Sans 12 px label + Plex Mono 12 px 600 shortcut chip
(1 px
#232C39, radius 2, padding 4 px 6 px): Search ⌘F · Fluid ⌘L · Hidden ⌘. (label and chip#6C7783— the off state) · Note ⌘N · Git ⌘G active: backgroundrgba(232,145,58,.10), label#F4F5F4, chip borderrgba(232,145,58,.35). Then a 26 × 26?button, 1 px#232C39.
The 46 px header row
All three panel headers sit on one 46 px row with their 1 px #232C39 bottom borders on the
same line. This alignment is deliberate — do not let any one of them grow.
- Source control commit row — 46 px, padding 0 12 px, flex, 8 px gap, centred.
Commit field: flex 1, height 30 px,
#101720, 1 px#232C39, radius 2, padding 0 9 px, Plex Sans 12 px#E4E7E6. Sample value:runs mail check once an hour. Push button: 30 × 30, 1 px#232C39, radius 2, glyph↑Plex Mono 15 px#BAC0C0. - Explorer header — 46 px, padding 0 12 px, space-between, Plex Mono 700 10 px, tracking
.14em, uppercase,#6C7783:EXPLORER…BOB. - Editor header — 46 px. A 46 px-wide agent-rail cell first (centred
BOB, same label style), then:MODIFIED(Plex Mono 700 10 px uppercase#6C7783),+2#8FBFB4,−2#C4741F(both Plex Mono 500 12 px), spacer, then the view switch.
View switch — a single bordered group, 1 px #232C39, radius 2, overflow: hidden, each item
5 px 12 px, Plex Sans 11 px, dividers 1 px #232C39 between items:
Actual (active: #E8913A fill, #171C22 text, weight 500) · Original · Preview · Diff
(inactive: #BAC0C0). Actual is the default and stays the default.
Source control panel
Section header: padding 14 px 12 px 6 px, Plex Mono 700 10 px tracking .14em uppercase #6C7783,
count on the right in #E8913A.
Folder line: 22 px, ▤ + path, Plex Mono 11 px #6C7783, ellipsis on overflow.
File row: 26 px, 8 px gap — status letter (Plex Mono 600 10 px, 12 px wide; staged #8FBFB4,
unstaged #F0B476), file-type chip (Plex Mono 600 10 px, #101720 text, radius 2, padding 4 px
5 px; md #BAC0C0, yml #F8C793, tsv #A8D6CB, sh #EFBCB0, json/php #C3A6CE,
js #F0B476), then the file name Plex Sans 12 px #BAC0C0.
Selected row: background #232C39, 2 px #E8913A left border, left padding reduced by 2 px so
the text does not shift, name #F4F5F4 500. Unselected rows carry border-left: 2px solid transparent so nothing moves on selection.
Footer: 12 px padding, 1 px #232C39 top, Plex Mono 11 px #6C7783, 3 staged · 3 unstaged.
Explorer
Rows are 24 px. Folder: 8 px-wide chevron (⌄ open #E8913A, › closed #6C7783), ▤
#828D9A, name Plex Sans 13 px (#F4F5F4 when open, #BAC0C0 when closed). Indent = 12 px + 16 px
per level. Files use the same type chips as source control; a modified file shows a trailing M
(Plex Mono 600 10 px #8FBFB4). Selected file: #232C39, 2 px #E8913A left border, name 500
#F4F5F4.
Editor pane
- Agent rail — 46 px, 1 px
#232C39right. Holds per-blockMmarkers aligned to the changed region: a marker is Plex Mono 600 10 px, 20 px tall, centred; the active block is#8FBFB4on#232C39, an unstaged block is#C4741Fon transparent. - Code grid —
grid-template-columns: 44px 1fr,align-content: start, padding 8 px 0, Plex Mono 400 13 px / 20 px. Line numbers: right-aligned, padding-right 12 px,#5A6472. Line text: padding-right 18 px,#BAC0C0; markdown headings#F4F5F4; fenced-code markers#6C7783; inline code and links#F0B476; a markdown link target#A8D6CB. Long lines wrap (text-wrap: pretty) and keep their single line number — wrapped rows are how the pane behaves at any width. - Changed line (the core of this screen) — line number
#8FBFB4onrgba(143,191,180,.12)with a 2 px#8FBFB4left border; the text cell has the samergba(143,191,180,.12)tint and text#F4F5F4. No+glyph, no second row, no strikethrough. This is the current content, simply marked as changed. - Minimap strip — 16 px, 1 px
#232C39left, 4 × 4 px marks:#6C7783normal,#8FBFB4staged change,#C4741Funstaged change.
Agent + terminal column (480 px)
Conversation body: padding 14 px 16 px, 12 px gap, Plex Sans 13 px / 1.6 #BAC0C0; tool output and
metadata in Plex Mono 12 px / 1.6 #6C7783; file paths and identifiers inline in Plex Mono #F0B476;
lead-ins (Why it was there.) #F4F5F4 600.
Prompt field: 44 px, #101720, 2 px #E8913A border + 0 0 0 2px rgba(232,145,58,.22) ring
(the house focus state), radius 2, › #E8913A, 1 × 16 px #E8913A caret that blinks.
Status lines: Plex Mono 11 px #6C7783; bob chip = #E8913A fill, #171C22 text, radius 2;
⑂ bob2 #A8D6CB; ▸▸ auto mode on #E8913A.
Terminal: 150 px, 1 px #232C39 top, Plex Mono 12 px / 1.7; prompt [bob2] #A8D6CB,
[~/code/bob]$ #828D9A, 7 × 14 px #E8913A blinking block cursor.
Status bar — 28 px, #18202B, 1 px #232C39 top
Plex Mono 11 px #6C7783, 16 px gap, 0 14 px padding: ⑂ bob2 #E8913A · +22 #A8D6CB ·
−66 #C4741F · spacer · file path · · · Ln 1, Col 1 · UTF-8 · LF · language #D4D9D8.
Interactions & behaviour
The hover reveal (the one behaviour to get right)
- Trigger:
mouseenteranywhere on a changed line's text cell. Dismiss:mouseleave. No click, no pin, no delay in the prototype. If you add a delay, keep it under 120 ms in and 0 ms out — the gesture must feel like looking, not like opening something. - What appears: a panel pinned to the top, right and bottom of the body row, 496 px wide, so
it covers the whole agent + terminal column and nothing else.
#101720, 2 px#C4741Fleft border,box-shadow: 0 4px 16px rgba(23,28,34,.10),overflow: hidden,z-indexabove the agent column. - Panel header: 46 px (the same 46 px as the editor header, so the first code line of both panes
starts at the same y),
#18202B, 1 px#232C39bottom:ORIGINALPlex Mono 700 10 px tracking.14em#C4741F, thenbefore this change · same scrollPlex Mono 11 px#6C7783, thenhold hoverright-aligned in the same muted style. - Panel body: the whole original file, not a hunk — same lines, same order, same wrap points
and the same vertical position for every line as in the editor pane. In the prototype this is
achieved by scaling the type to the narrower column:
grid-template-columns: 35px 1fr, font400 10.3px/20pxPlex Mono, gutter padding-right 9 px, text padding-right 11 px. The line-height stays 20 px, so line n sits at the same y in both panes. In the real implementation, do it properly: render the original text into the same layout the editor uses and synchronise scroll offsets, so line n of the original is always level with line n of the current file. The rule to satisfy: the changed line and its previous version are on the same horizontal line of the screen. - The old line inside the panel: line number
#C4741Fonrgba(196,116,31,.14)with a 2 px#C4741Fleft border; text cell same tint, text#E4E7E6. So: teal = what is there now, amber = what was there before. Never green/red. - The editor keeps its own scroll while the overlay is open; the overlay follows it.
Other states
- Hover on any list row (source control, explorer, menus): fill deepens one step
(
#18202B→#232C39). No lift, no shadow, no opacity change, no scale on press. - Focus on a text field: 2 px
#E8913Aborder + 2 pxrgba(232,145,58,.22)ring. - Disabled: 40 % opacity,
cursor: not-allowed.
Animation
Only two things move:
- The blinking period / caret —
@keyframes blink { 0%,49% { opacity:1 } 50%,100% { opacity:0 } },1.1s steps(1, end) infinite. Used on the wordmark period, the prompt caret and the terminal cursor. Freeze underprefers-reduced-motion. - Colour transitions — 160 ms
cubic-bezier(0.22, 1, 0.36, 1); 120 ms on small controls.
No entrance animation, no slide, no fade for the overlay — it is there or it is not. No scroll reveal, no parallax.
Responsive behaviour
Source control (300) and explorer (288) and the agent column (480) are fixed; the editor takes the rest. Below roughly 1400 px the design has not been specified — ask before inventing collapse behaviour. The hover panel is always 496 px and always anchored right.
State
| State | Type | Notes |
|---|---|---|
activeView |
'actual' | 'original' | 'preview' | 'diff' |
Default 'actual'. Persist per file. |
hoveredChangedLine |
lineNumber | null |
Drives the overlay. Cleared on mouse-out and on scroll-end if the pointer leaves. |
changedLines |
Map<lineNumber, { current: string, previous: string, staged: boolean }> |
From the VCS diff of working tree vs HEAD/index. |
originalText |
string |
Full HEAD/index version of the open file, needed for the overlay. |
editorScrollTop |
number |
Mirrored into the overlay so the two panes stay in register. |
selectedFile, stagedFiles, unstagedFiles |
— | Source control and explorer content. |
Data needed: the file's working-tree content, its original content, and a line-level diff mapping current line numbers to previous content. The overlay must be able to render the original file immediately — pre-fetch it when a modified file is opened, not on hover.
Design tokens
Surfaces #101720 base · #18202B raised · #232C39 selected/hover · #3A424C rule-strong
Text #F4F5F4 strong · #E4E7E6 body-strong · #BAC0C0 body · #828D9A dim · #6C7783 muted ·
#5A6472 line numbers
Accent #E8913A amber · #C4741F amber-deep (previous state) · #F0B476 amber-soft (inline code)
Change #8FBFB4 current/changed, tint rgba(143,191,180,.12) · #C4741F previous, tint
rgba(196,116,31,.14)
Syntax / chips #A8D6CB string · #F8C793 number-keyword · #C3A6CE structural · #D8BEE4
directive · #EFBCB0 selector · #D4D9D8 property
Radius 0 default · 2 px controls, chips, panels · 4 px window
Borders 1 px #232C39 hairline · 2 px accent, used only for the selection marker, the changed-line
rule and a focused field
Shadow dropdown 0 4px 16px rgba(23,28,34,.10); modal 0 16px 48px rgba(23,28,34,.18). Nothing else
casts a shadow.
Row heights 22 px meta · 24 px explorer · 26 px source-control file · 28 px status bar · 30 px menu ·
34/38 px fields · 44 px title bar · 46 px panel headers
Type IBM Plex Mono 400/500/600/700 — code, labels, all numbers; IBM Plex Sans 400/500/600 — UI
text and prose. Code 13 px / 20 px. Labels 10 px, tracking .14em, uppercase. UI text 12–13 px.
Do not use green or red for change, gradients, blur, emoji, white or pure black.
Assets
None. No images, icons or fonts ship with this handoff. Both faces load from Google Fonts (IBM Plex
Mono, IBM Plex Sans) — swap in the licensed binaries in the app. Every glyph in the design is a
Unicode mark set in Plex Mono (› ⌄ ▤ ↑ ⑂ · → ▸▸ ✳ └); if the app already uses
Lucide at stroke width 1.75, those are the sanctioned replacements for the folder and arrow marks.
Files
03b-in-pane-diff.html— the screen, standalone. Hover the teal line 31 (- The scheduler fires it. Job \mail-checker-ronde`, every hour, on the hour.`) to see the original overlay.- Source of truth in the design project:
Helder IDE.dc.html, section [ 03 ] Diff, screen 3b. Section 3a in the same file shows the older full-screen side-by-side diff, kept for reference; 3b replaces it for in-pane use.