# Desktop UI Domain Components

> Use whenever designing a component that doesn't have an off-the-shelf UI pattern — an audio waveform/timeline editor, a 3D viewport and its gizmos, a code/diff viewer, a node graph, an asset preview pane, or any other domain-specific tool surface. Depends on desktop-ui-foundations, desktop-ui-color-system, and desktop-ui-motion. Trigger on "waveform editor," "timeline," "3D viewport," "diff viewer," "node graph," or "there's no standard pattern for this."

- Skill: `simply-ehis/desktop-ui-domain-components` (Agent Skill)
- Install (CLI): `npx skillmds@latest add simply-ehis/desktop-ui-domain-components`
- Raw SKILL.md: https://api.skillmd.com/api/skills/simply-ehis/desktop-ui-domain-components/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Web & Frontend
- Author: simply-ehis (https://skillmd.com/u/simply-ehis)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/simply-ehis/desktop-ui-domain-components

---


# Domain-Specific Component Design (Desktop)

Most UI has a known pattern (a button is a button everywhere). Domain-specific surfaces don't — a waveform editor, a 3D viewport, or a node graph has to invent its own interaction language. This skill is a **process** for doing that well, since the specific components can't all be enumerated in advance.

## The process

1. **Identify the nearest established domain convention and start there, not from a blank canvas.** Almost every domain-specific surface has a category of professional tool that already solved the core interaction problem:
   - Audio editing/timeline → DAW conventions (Ableton, Logic, Reaper): waveform rendering, playhead behavior, zoom/scroll linkage, region selection and trim handles.
   - 3D manipulation → CAD/3D-tool conventions (Blender, Godot's own editor): gizmo design (move/rotate/scale handles), viewport navigation (orbit/pan/zoom), selection outlining.
   - Code/diff → IDE/diff-tool conventions (VS Code, GitHub): line-level add/remove coloring, gutter markers, syntax highlighting restraint.
   - Node/graph editing → node-based tool conventions (Blender's shader editor, game-engine visual scripting): port shapes signaling type/direction, connection curves, zoom-to-fit.

   Borrowing the convention isn't lack of originality — it's respecting that users bring muscle memory from other tools in the same domain, and fighting that expectation for no reason creates friction without benefit.

2. **Reconcile the borrowed convention with this skill family's token system.** The domain convention tells you the *interaction shape* (how a waveform selection handle behaves); the token system from `desktop-ui-foundations` and `desktop-ui-color-system` tells you the *visual language* (what color, what elevation, what corner radius) it should be rendered in so it still feels like the rest of the app, not a bolted-on third-party widget.

3. **Design the states explicitly** — domain-specific components are especially easy to leave half-finished because the "happy path" (a waveform mid-playback, a 3D object mid-manipulation) is the only state that gets built during a demo. At minimum, cover:
   - Empty (no audio loaded / no object selected / no diff to show)
   - Loading (waveform still decoding, model still loading)
   - Active/selected (a region selected, an object selected, a node selected) — with a clear, consistent selection treatment reused from `desktop-ui-color-system`'s active-state logic
   - Hover-preview vs. committed-selection, if the tool distinguishes them (hovering a region to preview it vs. actually selecting it)
   - Error (corrupt file, unsupported format, a broken node connection)

4. **Performance-check it against the hardware target.** Domain-specific surfaces are disproportionately likely to be the most expensive thing on screen (real-time waveform rendering, a live 3D viewport, syntax highlighting a huge file) — apply the same `transform`/`opacity`-only, avoid-real-time-blur discipline from `desktop-ui-motion`, and consider whether the surface needs to re-render on every frame or only when its underlying data actually changes.

## Interaction language within the component

- **Zoom and scroll should stay linked and predictable** — in a timeline or viewport, scrolling shouldn't unexpectedly change zoom level or vice versa unless a modifier key is deliberately used for that (a common, learnable convention: scroll to pan, Ctrl/Cmd+scroll to zoom).
- **Selection should always be visually unambiguous** — a selected region, node, or object needs a treatment strong enough to spot at a glance (an accent-colored outline or fill, consistent with the rest of the app's active-state color) even against a busy, colorful background like a waveform or a 3D scene.
- **Direct manipulation handles** (trim handles, resize gizmos, connection anchors) need a hit target larger than their visible size, exactly like the button hit-target rule in `desktop-ui-buttons-controls` — precision tools are exactly where an undersized hit target causes the most frustration.
- **Give real-time feedback during drag operations** (a numeric readout while dragging a trim handle, a live preview while scrubbing a timeline) — domain-specific tools are where users most need to know exactly what they're about to commit to before releasing the mouse.

## Accessibility

Custom-drawn components (canvas, WebGL, node graphs, waveform/timeline editors) render nothing to the platform's accessibility tree by default — this is the hardest category in the whole family to get right, which is exactly why it needs planning up front rather than being skipped:

- Design a parallel, simplified accessible representation alongside the visual one (e.g. a keyboard-navigable list of nodes/regions/track items that mirrors what's on the canvas) rather than treating the component as unsolvable for keyboard and screen reader users.
- Give the component a full keyboard interaction model — arrow keys to move a selection, `Enter`/`Space` to activate, a documented way to reach every action the mouse can reach — before calling it done. See `desktop-ui-accessibility-i18n` for the baseline patterns to adapt.

## Review format

| Before | After | Why |
|---|---|---|
| Waveform selection handles are the same visible width as their hit target (4px) | Visible handle stays thin, but the hit/drag target is padded to at least 12–16px | Precision editing needs a forgiving hit target, not a pixel-perfect one |
| 3D viewport gizmo colors don't match the app's own accent/semantic colors | Gizmo axis colors follow domain convention (X/Y/Z standard colors) but selection highlighting uses the app's own accent color | Respects domain muscle memory for axes while still feeling like part of this app for anything app-specific |
| Node graph only has a "connected" and "not connected" visual state | Adds a distinct hover-preview state before a connection is committed, and an error state for a type-mismatched connection | Domain components are the easiest place to skip states beyond the happy path |

