diff --git a/docs/design/Helder IDE.dc.html b/docs/design/Helder IDE.dc.html new file mode 100644 index 0000000..e536ab7 --- /dev/null +++ b/docs/design/Helder IDE.dc.html @@ -0,0 +1,873 @@ + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
[ 00 ] design canvas · helder
+

helder.

+

An editor for working with Claude Code. One slate shell, one amber accent, IBM Plex Mono for everything that is code or label. Every layer below uses the same four surfaces, the same 24px row height and the same selection marker: 2px amber on the left, fill one step deeper.

+
+ workspace + overlays + menus + foundations +
+
+ + +
+
+ [ 01 ] + Workspace + Four columns: source control · explorer · editor · agent. 1760 × 1000 +
+ +
+ + +
+
+ + + +
+
+ helder. + odynt + · + main +
+
+ resourcesviewsadminvaults + form.blade.php +
+
+ Search ⌘F + Auto-fit ⌘A + Hidden ⌘. + Note ⌘N + Git ⌘G + ? +
+
+ +
+ + +
+
+
Shift+Enter to commit
+
+
+
+ staged changes4 +
+
+
Mphpcategory.blade.php
+
Mphpform.blade.php
+
Mphpsubcategory.blade.php
+
Mphpdeclined-names.blade.php
+
+
+
+ changes1 +
+
Mphpdeclined-names.blade.php
+
+
4 staged · 1 unstaged
+
+ + +
+
explorerodynt
+
+
app
+
blueprints
+
bootstrap
+
config
+
database
+
docs
+
lang
+
public
+
resources
+
css
+
js
+
markdown
+
views
+
admin
+
vaults
+
_partials
+
phpcategory.blade.phpM
+
phpform.blade.phpM
+
phpindex.blade.php
+
phpsubcategory.blade.phpM
+
components
+
conversation
+
help
+
settings
+
routes
+
tests
+
mdAGENTS.md
+
mdCLAUDE.md
+
jsvite.config.js
+
+
+ + +
+
+ modified + +1 + −1 + +
+ Actual + Original + Diff + Split +
+
+
+ 1{{-- + 24B — the Vault editor. `$vault === null` means create. + 3--}} + 4 + 5@php + 6$isCreate = $vault === null; + 7$teamClass = \App\Models\Team::class; + 8$userClass = \App\Models\User::class; + 9@endphp + 10 + 11<x-layouts.app :title="$vault?->name"> + 12 + 13<style> + 14.vlt-head { + 15display: flex; + 16align-items: flex-end; + 17gap: 20px; + 18} + 19 + 20.vlt-card { + 21background: var(--color-surface-raised); + 22border: 1px solid var(--color-border-default); + 23border-radius: 4px; + 24padding: 22px 24px; + 25} + 26 + 27.vlt-group-label { + 28font-family: 'IBM Plex Mono', monospace; + 29letter-spacing: .14em; + 30text-transform: uppercase; + 31} + 32</style> +
+
+ + +
+
+
+
+ Claude Code v2.1.259 + Opus 5 (1M context) · Claude Max + ~/code/odynt +
+
+
+ [ ! ] + 1 MCP server needs authentication — run /mcp +
+
+
+ + Implement the vault admin screens from docs/design_handoff_vaults/README.md. +
+
+ + I read the handoff and the existing policies. Then I write the tests first. +
+
+ Read docs/design_handoff_vaults/README.md · 412 lines + Grep "VaultPolicy" · 7 hits + Edit app/Policies/VaultPolicy.php +
+
+
+ + test the round trip with Playwright + +
+
+ [Opus 5 · 1M] + odynt + main + + ▸▸ auto mode + /rc +
+
+
[main][~/code/odynt]$ php artisan test --filter=Vault
+
PASS Tests\Feature\VaultAdminTest · 14 assertions
+
[main][~/code/odynt]$
+
+
+
+ + +
+ ⑂ main + +16−12 + + resources/views/admin/vaults/form.blade.php + ·Ln 20, Col 12·UTF-8·LF·Blade +
+
+
+ + +
+
+ [ 02 ] + Overlays + One rule: ink scrim, panel on slate-2, 8px radius, esc top right. +
+ +
+ + +
+
2a · search ⌘f
+
+
+
+ + config( + + + php + md + js + 0 here · 226 hits · 0 files +
+
+
+
this file
+
phpConfigSyncCommand.php
+
No matches in this file.
+
+
+
project226
+
phpcypress/e2e/Conversation/ConversationWelcome.php4
+
+ 80function conversationSeedConfig(): void + 99conversationSeedConfig(); + 163conversationSeedConfig(); +
+
phpdatabase/seeders/DatabaseSeeder.php3
+
+ 230* This row is consumed by AppData::resolveDefaultThemeConfig() + 245'config' => self::guestThemeConfig(), + 257private static function guestThemeConfig(): array +
+
jscypress/e2e/blueprint-038-conversation-menu.cy.js1
+
+ 163cy.url().should('eq', Cypress.config('baseUrl') + '/conversation'); +
+
mdblueprints/done/012-dialog-page/blueprint.md1
+
+ 162— `config/ai.php` — providers.anthropic.api_key +
+
+
+
files0
+
No file names match.
+
+
+
+ ⌘← / ⌘→ column + ⌘↑ / ⌘↓ row + open + + esc +
+
+
+
+ + +
+
2b · shortcuts ?
+
+
+
+ + Keyboard shortcuts + + esc +
+
+
navigate
+
+ FSearch contents and names + ↑↓Move through a list + Open the selected item + ←→Column left or right +
+
agent
+
+ Pass the selection to the agent + NOpen the project note + PPass on the whole note +
+
git
+
+ CFocus the commit message + Commit the staged files + GSource Control column on or off + MCycle Actual · Original · Diff · Split +
+
file
+
+ SSave this file + WClose this file + .Hidden files on or off +
+
+
+
+
+ + +
+
2c · project note ⌘n
+
+
+
+ + Note + .notes.txt + + To the agent ⌘P + esc +
+
+

I've created a design for the admin screens that manage the vaults, vault_categories and the vault_subcategories.

+

Implement them. Let them respect the admin policies just like agents, teams and companies have their own policies.

+

The design can be found here: docs/design_handoff_vaults/README.md

+

The vaults index page replaces /crud/vaults. Remove that code and place this feature on /admin/vaults.

+
+
+ saved on focus loss·412 characters +
+
+
+
+ + +
+
2d · open a project
+
+
+ + + +
+
+
+
+ + + helder. + Open a project to begin + +
+
+ + + Open new project… + + +
+
recent
+
+
odynt~/code/odynt
+
stedt~/code/stedt
+
loopt~/code/loopt
+
doen-r~/code/doen-r
+
vakwerk~/code/vakwerk
+
diagram~/code/diagram
+
marketingtools~/code/marketingtools
+
+
+ ⌘↑↓ navigate open +
+
+
+
+
+
+
+ + +
+
+ [ 03 ] + Diff + Added is teal, removed is amber-deep. No green, no red. +
+ +
+
+
+ + + +
+ resources/views/help/vault/declined-names.blade.php + modified + +1 + −1 + staged → actual + + Collapse esc +
+
+
+
originalbefore
+
+ 18{{ __('A merge writes a declined row…') }} + 19</p> + 20</section> + 21 + 22<section class="odynt-help__section"> + 23<h2>{{ __('The reason a row can carry') }}</h2> + 24 + 25<p> + 26{{ __('A row can carry one of eleven reason codes…') }} + 27</p> + 28</section> +
+
+
+
updatedafter
+
+ 18{{ __('A merge writes a declined row…') }} + 19</p> + 20</section> + 21 + 22<section class="odynt-help__section is-reasons"> + 23<h2>{{ __('The reason a row can carry') }}</h2> + 24 + 25<p> + 26{{ __('A row can carry one of eleven reason codes…') }} + 27</p> + 28</section> +
+
+
+
+
+ + +
+
+ [ 04 ] + Details + Menus, prompts, tooltips and the markdown switch. All on 24px rows. +
+ +
+ +
+
4a · explorer menu
+
+
tests/Unit/ExampleTest.php
+
Pass on reference
+
Copy reference
+
Pass on file name
+
Copy file name
+
+
Rename file
+
Show in Finder
+
Delete file
+
+
+ +
+
4b · source control menu
+
+
resources/views/help/vault/declined-names.blade.php
+
Pass on reference
+
Copy reference
+
+
+Stage changes
+
Open diff
+
Discard changes
+
+
+ +
+
4c · pass on to agent
+
+
+ + Pass on to agent + + esc +
+
+ write the test for this + +
+
+ inserts + write the test for this ⇒ tests/Unit/ExampleTest.php +
+
insert into agent · esc cancel
+
+
+ +
+
4d · toolbar + tooltip
+
+
+ Search ⌘F + Auto-fit ⌘A + Hidden ⌘. + Note ⌘N + Git ⌘G +
+ +
+
Hidden files: hidden — dotfiles excluded from the tree and the search. Click to show.
+
Auto-fit panels: on — columns re-fit on resize and focus. Click to lock the current sizes.
+
Project note (.notes.txt) — kept next to this project.
+
+
+
Tooltip: slate-3 surface, 1px border, no arrow, no shadow. The state is amber inside the sentence.
+
+
+ +
+
4e · markdown actual · preview
+
+
+
+ markdown + + + Actual + Preview + +
+
+ 1You write the handover record for a + 2conversation that is about to be cut. + 3 + 4The reader is a model with no access to + 5the original messages. + 6 + 7## Sources + 8 + 9Use only the messages, the tool results + 10and the previous summary. +
+
+
+
+ markdown + + + Actual + Preview + +
+
+

You write the handover record for a conversation that is about to be cut.

+

The reader is a model with no access to the original messages. Your record is the only input it gets.

+

Sources

+

Use only the messages, the tool results and the previous summary. If you cannot point to that source, delete the line.

+
+
+
+
+
+
+ + +
+
+ [ 05 ] + Foundations + Four surfaces, one accent, six syntax colours. +
+ +
+ +
+
surfaces and accent
+
+
#101720editor · terminal
+
#18202Bpanels · chrome
+
#232C39selection · border
+
#E8913Aaction · state · cursor
+
+

Amber is a reservation: active toggle, selection marker, cursor, the blinking period and the counts in the status bar. Never an amber surface as decoration.

+
+ +
+
syntax
+
+ text · #E4E7E6 + variable · #BAC0C0 + comment · #6C7783 + keyword · #C3A6CE + string · #8FBFB4 + number · tag · #F0B476 +
+
+ + added — #8FBFB4 op rgba(143,191,180,.12) + − removed — #C4741F op rgba(196,116,31,.14) +
+

Six colours, all muted. No green for good and no red for bad — the diff reads on shape and on the 2px rule, not on alarm.

+
+ +
+
type and rhythm
+
+ IBM Plex Mono 700 + titles, labels, paths, code, shortcuts + IBM Plex Sans 400 · 500 + rows, menu items, tooltips, running text +
+
+ row height · 24pxchrome · 44px + code line · 20pxstatus bar · 28px + radius control · 2pxradius overlay · 8px + border · 1pxmarker · 2px amber +
+
+ +
+
row states
+
+
rest
+
hover — fill one step deeper
+
selected — 2px amber on the left
+
not available — 40%
+
+

No movement, no shadow, no scale. Colour only, 160ms. The only animation in the whole editor is the blinking cursor and the period in the mark.

+
+
+
+ + +
+
+ [ 06 ] + Code colours + The same six colours across every language. Nothing bold, nothing italic — weight stays 400 so the column reads flat. +
+ +
+ +
+
6a · javascript
+
+
+ js + resources/js/symbols-service.js + + javascript +
+
+ 1// One request per file. The tree keeps the last answer. + 2 + 3import { cache } from './cache.js'; + 4 + 5const ENDPOINT = '/api/symbols'; + 6const TIMEOUT = 2500; + 7 + 8export async function readSymbols(path, signal) { + 9if (cache.has(path)) return cache.get(path); + 10 + 11const res = await fetch(`${ENDPOINT}?p=${path}`, { signal }); + 12 + 13if (!res.ok) { + 14throw new Error(`symbols: ${res.status}`); + 15} + 16 + 17const rows = await res.json(); + 18cache.set(path, rows); + 19 + 20return rows; + 21} +
+
+
+ +
+
6b · php
+
+
+ php + app/Console/Commands/ConfigSyncCommand.php + + php +
+
+ 1<?php + 2 + 3declare(strict_types=1); + 4 + 5namespace App\Console\Commands; + 6 + 7use App\Models\Config; + 8 + 9/** Writes one row per config group. */ + 10final class ConfigSyncCommand extends Command + 11{ + 12protected $signature = 'config:sync'; + 13 + 14public function handle(): int + 15{ + 16$created = 0; + 17 + 18foreach ($this->registry() as $key => $class) { + 19$row = Config::query()->find($key); + 20 + 21if ($row === null) { + 22$created++; + 23} + 24} + 25 + 26return self::SUCCESS; + 27} + 28} +
+
+
+ +
+
6c · css
+
+
+ css + resources/css/panels.css + + css +
+
+ 1/* Four surfaces, one accent. Nothing else. */ + 2 + 3:root { + 4--editor: #101720; + 5--panel: #18202B; + 6--accent: #E8913A; + 7} + 8 + 9.row { + 10display: flex; + 11gap: 8px; + 12height: 24px; + 13border-left: 2px solid transparent; + 14transition: background 160ms ease-out; + 15} + 16 + 17.row:hover { + 18background: #1E2733; + 19} + 20 + 21.row[aria-selected='true'] { + 22background: #232C39; + 23border-left-color: var(--accent); + 24} +
+
+
+ +
+
6d · markdown preview
+
+
+ md + blueprints/046-symbols/blueprint.md + + + Actual + Preview + +
+
+ blueprint · 046 +

Symbols in the tree

+

The explorer shows classes and functions under a file once the file is open. The list comes from one request per file and it is cached for the session.

+

What it changes

+
+
A row gains one child level. Nothing else in the tree moves.
+
The endpoint answers in under 250ms for a file of 2000 lines.
+
A parse error leaves the file row untouched and logs once.
+
+
A symbol list nobody asked for is a symbol list nobody reads. Open the file first.
+
+ // the shape one row returns + { rel: 'class', line: 42, kind: 'php' } +
+
+
+ stepfilestate +
+
+ Endpointroutes/api.phpdone +
+
+ Tree levelexplorer.jsopen +
+
+

Full contract in docs/symbols.md

+
+
+
+
+
+ +
+ + +
+ + + diff --git a/docs/design/README.md b/docs/design/README.md new file mode 100644 index 0000000..e052c2a --- /dev/null +++ b/docs/design/README.md @@ -0,0 +1,386 @@ +# 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. diff --git a/docs/design/screenshots/Screenshot 2026-09-03 at 09.34.16.png b/docs/design/screenshots/Screenshot 2026-09-03 at 09.34.16.png new file mode 100644 index 0000000..af059cd Binary files /dev/null and b/docs/design/screenshots/Screenshot 2026-09-03 at 09.34.16.png differ diff --git a/docs/design/screenshots/Screenshot 2026-09-03 at 09.34.21.png b/docs/design/screenshots/Screenshot 2026-09-03 at 09.34.21.png new file mode 100644 index 0000000..16f5aa9 Binary files /dev/null and b/docs/design/screenshots/Screenshot 2026-09-03 at 09.34.21.png differ diff --git a/docs/design/screenshots/Screenshot 2026-09-03 at 09.34.26.png b/docs/design/screenshots/Screenshot 2026-09-03 at 09.34.26.png new file mode 100644 index 0000000..bf4fdd2 Binary files /dev/null and b/docs/design/screenshots/Screenshot 2026-09-03 at 09.34.26.png differ diff --git a/docs/design/screenshots/Screenshot 2026-09-03 at 09.34.30.png b/docs/design/screenshots/Screenshot 2026-09-03 at 09.34.30.png new file mode 100644 index 0000000..bb25924 Binary files /dev/null and b/docs/design/screenshots/Screenshot 2026-09-03 at 09.34.30.png differ diff --git a/docs/design/screenshots/Screenshot 2026-09-03 at 09.34.36.png b/docs/design/screenshots/Screenshot 2026-09-03 at 09.34.36.png new file mode 100644 index 0000000..f8ed92d Binary files /dev/null and b/docs/design/screenshots/Screenshot 2026-09-03 at 09.34.36.png differ diff --git a/docs/design/screenshots/Screenshot 2026-09-03 at 09.34.41.png b/docs/design/screenshots/Screenshot 2026-09-03 at 09.34.41.png new file mode 100644 index 0000000..a394413 Binary files /dev/null and b/docs/design/screenshots/Screenshot 2026-09-03 at 09.34.41.png differ diff --git a/docs/design/screenshots/Screenshot 2026-09-03 at 09.34.45.png b/docs/design/screenshots/Screenshot 2026-09-03 at 09.34.45.png new file mode 100644 index 0000000..71cbd33 Binary files /dev/null and b/docs/design/screenshots/Screenshot 2026-09-03 at 09.34.45.png differ diff --git a/docs/design/screenshots/Screenshot 2026-09-03 at 09.34.49.png b/docs/design/screenshots/Screenshot 2026-09-03 at 09.34.49.png new file mode 100644 index 0000000..8cc4f35 Binary files /dev/null and b/docs/design/screenshots/Screenshot 2026-09-03 at 09.34.49.png differ diff --git a/docs/design/styles.css b/docs/design/styles.css new file mode 100644 index 0000000..b444b4c --- /dev/null +++ b/docs/design/styles.css @@ -0,0 +1,8 @@ +@import url("tokens/fonts.css"); +@import url("tokens/colors.css"); +@import url("tokens/typography.css"); +@import url("tokens/spacing.css"); +@import url("tokens/radius.css"); +@import url("tokens/elevation.css"); +@import url("tokens/motion.css"); +@import url("tokens/base.css"); diff --git a/docs/design/tokens/base.css b/docs/design/tokens/base.css new file mode 100644 index 0000000..f3df35f --- /dev/null +++ b/docs/design/tokens/base.css @@ -0,0 +1,23 @@ +*, +*::before, +*::after { box-sizing: border-box; } + +body { + margin: 0; + background: var(--color-stone); + color: var(--color-ink-body); + font-family: var(--font-body); + font-size: var(--text-base); + font-weight: var(--weight-body); + line-height: var(--leading-normal); + -webkit-font-smoothing: antialiased; +} + +a { color: var(--color-amber-deep); text-decoration-color: var(--color-stone-rule); text-underline-offset: 3px; transition: var(--transition-color); } +a:hover { color: var(--color-ink-body); text-decoration-color: var(--color-ink-dim); } +[data-surface="slate"] a { color: var(--color-amber); } +[data-surface="slate"] a:hover { color: var(--color-neutral-1); } + +::selection { background: var(--color-amber-ring); color: var(--color-ink-body); } + +:focus-visible { outline: 2px solid var(--color-amber); outline-offset: 2px; } diff --git a/docs/design/tokens/colors.css b/docs/design/tokens/colors.css new file mode 100644 index 0000000..d5be354 --- /dev/null +++ b/docs/design/tokens/colors.css @@ -0,0 +1,66 @@ +/* Kade palette — cool stone paper, slate-ink dark punctuation, amber as the only accent. */ +:root { + /* Stone — the default canvas. Cool, quarried, never white. */ + --color-stone: #EFF0EE; + --color-stone-2: #E5E7E4; + --color-stone-3: #D8DBD7; + --color-stone-rule: #CDD1CD; + + /* Ink ramp — text on stone. */ + --color-ink-body: #171C22; + --color-ink-muted: #3A424C; + --color-ink-dim: #6B7480; + + /* Slate — the sparing dark surface. One or two blocks per page. */ + --color-slate: #101720; + --color-slate-2: #18202B; + --color-slate-3: #232C39; + + /* Neutral ramp — text on slate. Pure white does not exist in this system. */ + --color-neutral-1: #F4F5F4; + --color-neutral-2: #E4E7E6; + --color-neutral-3: #BAC0C0; + --color-neutral-4: #6C7783; + + /* Amber — the single accent. Reserved for action, state and signal. */ + --color-amber: #E8913A; + --color-amber-deep: #C4741F; + --color-amber-soft: #F0B476; + --color-amber-tint: rgba(232, 145, 58, 0.10); + --color-amber-ring: rgba(232, 145, 58, 0.22); + + /* Semantic aliases — prefer these in component code. */ + --surface-page: var(--color-stone); + --surface-card: var(--color-stone-2); + --surface-card-hover: var(--color-stone-3); + --surface-dark: var(--color-slate); + --surface-dark-card: var(--color-slate-2); + + --text-body: var(--color-ink-body); + --text-muted: var(--color-ink-muted); + --text-dim: var(--color-ink-dim); + --text-accent: var(--color-amber-deep); + --text-on-accent: var(--color-ink-body); + + --border-hairline: var(--color-stone-rule); + --border-strong: var(--color-ink-muted); + + --action-fill: var(--color-amber); + --action-fill-hover: var(--color-amber-deep); + --focus-ring: var(--color-amber-ring); + --focus-border: var(--color-amber); + --signal-error: var(--color-amber-deep); +} + +/* Slate scope — inside a dark block the ramps invert. Apply to the block, not the page. */ +[data-surface="slate"] { + --surface-page: var(--color-slate); + --surface-card: var(--color-slate-2); + --surface-card-hover: var(--color-slate-3); + --text-body: var(--color-neutral-1); + --text-muted: var(--color-neutral-2); + --text-dim: var(--color-neutral-4); + --text-accent: var(--color-amber); + --border-hairline: var(--color-slate-3); + --border-strong: var(--color-neutral-3); +} diff --git a/docs/design/tokens/elevation.css b/docs/design/tokens/elevation.css new file mode 100644 index 0000000..e7a45df --- /dev/null +++ b/docs/design/tokens/elevation.css @@ -0,0 +1,8 @@ +/* Elevation is carried by the stone ramp, not by shadow. Shadows exist only for layers that + cross the page plane (dropdown, modal) and for the amber focus ring. */ +:root { + --shadow-none: none; + --shadow-dropdown: 0 4px 16px rgba(23, 28, 34, 0.10); + --shadow-modal: 0 16px 48px rgba(23, 28, 34, 0.18); + --ring-focus: 0 0 0 2px var(--color-amber-ring); +} diff --git a/docs/design/tokens/fonts.css b/docs/design/tokens/fonts.css new file mode 100644 index 0000000..4979a2a --- /dev/null +++ b/docs/design/tokens/fonts.css @@ -0,0 +1,10 @@ +/* Kade type stack — IBM Plex Mono (display + labels) and IBM Plex Sans (body + UI). + No licensed binaries shipped with the source skills, so the families load from Google Fonts. + Replace this @import with local @font-face rules once real woff2 files are supplied. */ +@import url("https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital,wght@0,400;0,500;0,600;0,700;1,400&family=IBM+Plex+Sans:ital,wght@0,400;0,500;0,600;0,700;1,400;1,500&display=swap"); + +:root { + --font-display: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; + --font-mono: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; + --font-body: "IBM Plex Sans", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif; +} diff --git a/docs/design/tokens/motion.css b/docs/design/tokens/motion.css new file mode 100644 index 0000000..ad143ff --- /dev/null +++ b/docs/design/tokens/motion.css @@ -0,0 +1,10 @@ +/* Colour shifts only. Kade never translates, lifts, or scales on hover. */ +:root { + --ease-out: cubic-bezier(0.22, 1, 0.36, 1); /* @kind other */ + --duration-fast: 120ms; /* @kind other */ + --duration-base: 160ms; /* @kind other */ + --duration-slow: 260ms; /* @kind other */ + --transition-color: color var(--duration-base) var(--ease-out), + background-color var(--duration-base) var(--ease-out), + border-color var(--duration-base) var(--ease-out); +} diff --git a/docs/design/tokens/radius.css b/docs/design/tokens/radius.css new file mode 100644 index 0000000..214201d --- /dev/null +++ b/docs/design/tokens/radius.css @@ -0,0 +1,11 @@ +/* Kade is rectangular. A rounded card is an antipattern. */ +:root { + --radius-none: 0px; + --radius-sm: 2px; + --radius-md: 4px; + --radius-lg: 8px; + --radius-full: 9999px; + + --border-width: 1px; + --border-width-accent: 2px; +} diff --git a/docs/design/tokens/spacing.css b/docs/design/tokens/spacing.css new file mode 100644 index 0000000..3a4dc82 --- /dev/null +++ b/docs/design/tokens/spacing.css @@ -0,0 +1,21 @@ +/* 4px base step. Section rhythm is deliberately generous; the calm comes from air, not decoration. */ +:root { + --space-1: 4px; + --space-2: 8px; + --space-3: 12px; + --space-4: 16px; + --space-5: 20px; + --space-6: 24px; + --space-8: 32px; + --space-10: 40px; + --space-12: 48px; + --space-16: 64px; + --space-20: 80px; + --space-24: 96px; + + --gutter: var(--space-6); + --section-y: var(--space-24); + --section-y-tight: var(--space-16); + --container: 1140px; + --measure: 68ch; +} diff --git a/docs/design/tokens/typography.css b/docs/design/tokens/typography.css new file mode 100644 index 0000000..f690b37 --- /dev/null +++ b/docs/design/tokens/typography.css @@ -0,0 +1,31 @@ +/* One scale for display (Plex Mono 700) and body (Plex Sans). Line-height tightens as size grows. */ +:root { + --text-2xs: 10px; + --text-xs: 11px; + --text-sm: 13px; + --text-base: 15px; + --text-md: 17px; + --text-lg: 20px; + --text-xl: 24px; + --text-2xl: 32px; + --text-4xl: 44px; + --text-6xl: 58px; + --text-7xl: 76px; + + --leading-display: 1.02; + --leading-tight: 1.15; + --leading-snug: 1.3; + --leading-normal: 1.6; + --leading-loose: 1.7; + + /* Plex Mono display tracking is negative; label tracking is wide. */ + --tracking-display: -0.04em; + --tracking-heading: -0.02em; + --tracking-normal: 0; + --tracking-label: 0.14em; + + --weight-body: 400; + --weight-medium: 500; + --weight-semibold: 600; + --weight-display: 700; +}