InkForge Design System
A code-truthful spec for a native macOS drawing app. The art direction is Studio Slate — a monochromatic dark workspace where the user's artwork is the only saturated thing on screen. Every token here maps to a constant in Sources/InkForge/UI/Theme.swift; when code and this doc disagree, code wins.
The canvas is the brand.
A drawing app for artists, not a productivity app for managers. Three principles hold the whole thing together — break any one and it stops feeling like InkForge.
Five greys, one accent, nothing else.
The surface hierarchy is built from five near-neutral greys, each ~4 percentage points lighter than the last. When panels nest, the inner one is always one step lighter than its parent. Steel blue is the single accent — it appears in four specific contexts only.
Surfaces — five-stop grey
Text — three-tier on dark
The single accent
System font throughout — mono digits where values tick.
Inter (–apple-system / SF Pro) everywhere. Use monospacedDigitSystemFont anywhere a numeric value changes (knob readouts, slider labels) so digits don't jitter sideways. JetBrains Mono for eyebrows, hex inputs, and spec labels.
A tight scale — drawing apps fight for canvas space.
Six steps from a 2px row gap to a 24px status-bar rhythm. Tight by design — every pixel of chrome is a pixel not given to the artwork.
Tight corners — precision tool, not consumer app.
Four steps, all small. Large rounded corners signal "friendly app"; these signal "instrument". Pill is reserved for color swatches and small tags only.
Every shadow is pure black — never warm grey.
On a dark background, coloured shadows add noise. All shadows use black alpha. The steel-blue glow is the one exception — reserved exclusively for the active tool button.
Two recipes: raised pad and recessed groove.
The load-bearing design idea. Every interactive surface is either a raised pad (pressable) or a recessed groove (readout/track). No hover state — this is a tablet-first app. The active tool gets the steel-blue glow as its one reward.
Raised pad — toolbar buttons
Recessed groove — vertical sliders & knob
Six primitives compose every screen.
All components in Sources/InkForge/UI/. Representative samples rendered on the dark canvas stage:
Layer panel rows
Toolbar buttons (Pen · AI · Selection · Eraser)
Color swatches (recent colors)
Feedback, not decoration.
Short and purposeful. All animations respect prefers-reduced-motion — they collapse to a plain opacity transition. The steel-blue glow is the most visible motion in the system.
SF Symbols at system stroke weight — OS-continuous chrome.
All in-product glyphs use SF Symbols line icons at the system default stroke weight, matched to SF Pro text. No custom icon set — this keeps the app feeling native and eliminates a design maintenance surface. The app icon is the one exception: a custom pen nib with a steel-blue AI sparkle, on a dark canvas-matching background.
Precise, plain, and deferential to the artist.
The app never congratulates itself. Copy is label-grade brief in the toolbar, a full sentence only when something needs context. The AI feature is presented as a collaborator, not a magic shortcut.
"Inpaint — describe what to fill"
"Result added as new layer"
"Hold stroke end to snap to shape"
"Magic AI will perfect your art!"
"Replaced by AI — amazing!"
"Auto-beautified your stroke ✨"
Five ways to break the feel.
If a new screen does any of these, it isn't InkForge anymore.
- Don't use colour in the chrome. The user's artwork is the only saturated thing on screen. A coloured toolbar button competes with a warm neutral the artist just chose for their painting.
- Don't use coloured shadows. All shadows are pure black alpha. Coloured shadows on a dark background read as light leaks, not depth.
- Don't bake AI results into the canvas. Results always land as new layers — the artist makes the final call on blending. No destructive operations without a clear undo path.
- Don't rely on hover-only feedback. This is a Wacom tablet app. If an affordance only reveals itself on mouse hover, a stylus user never sees it. States must be readable from form, not cursor.
- Don't use proportional-width digits in readouts. Use
monospacedDigitSystemFontwherever a value ticks — the label must not jitter sideways as it changes.
Where every token actually lives.
This page documents the system; the code defines it. When they disagree, the code wins.