# DESIGN.md · dara/icarus

[View on GitCafe](https://git.cafe/dara/icarus/blob/refs%2Fheads%2Ffeature%2Fagent-firearms/DESIGN.md)

Repository: [dara/icarus](https://git.cafe/dara/icarus)

Visibility: public

Requested revision: refs/heads/feature/agent-firearms

Commit: 388ad5edbccee832351e236aae392376a110a36f

Blob: 57fcfa51b59dd6d77acb055f1a79bd034036a01c

Size: 2676 bytes

[Immutable source](https://git.cafe/dara/icarus/blob/388ad5edbccee832351e236aae392376a110a36f/DESIGN.md?format=markdown)

```
# Design: Icarus

Icarus is a tactical workbench: dark, dense, map-first. The canvas and the tactical objects on it stay visually dominant; everything else is hardware around the bench. Polish comes from order, not ornament.

The palette, theme, and sizing constants live in `lib/const/settings.dart`, with `Settings.tacticalVioletTheme` as the ShadColorScheme. That file is the only source of truth for values. This file holds the rules for using them.

## Building UI

- shadcn_ui is the component library. Reach for `Shad*` widgets first (`ShadDialog`, `ShadButton`, `ShadIconButton`, `ShadInput`, `ShadSelect`, `ShadTooltip`, `ShadContextMenu*`, `ShadPopover`) before Material equivalents or custom widgets. Read theme values through `ShadTheme.of(context)`.
- `ShadDialog` does not provide a `Material` ancestor. Material-dependent children (`TextField`, `InkWell`, `LinearProgressIndicator`, `Slider`) throw "No Material widget found" inside one. Wrap the dialog's `child` in `Material(color: Colors.transparent, child: ...)`; see `lib/widgets/dialogs/export_video_dialog.dart` for the idiom.
- Never hardcode a hex that already has a name in `lib/const/settings.dart`. If a color is new, name it there first.
- Spacing steps are 8/10/12/16/24px. Radii: 8px controls, 12px panels, 16px cards, 22px dialogs.
- Type roles, all in the system sans stack: headline 20px/500, title 16px/600, body 14px/400, label 12px/600, micro 10px/600. Hierarchy comes from these five roles, not from display fonts or hero-scale type.
- Transitions run 150-250ms and must communicate a state change (hover, selection, reveal, loading). No motion for its own sake.

## Things I would like to remain consistent

**The One Command Color** Violet marks current action, selection, focus, and primary commands, and nothing else. If violet appears somewhere that isn't actionable or active, it's wrong.

**The Tactical Semantics** Ally green, enemy red, defender blue, favorite amber, and the map ember hues carry game meaning. Never reuse them for unrelated UI emphasis.

**The Tonal First** Depth comes from surface steps (background, panel, raised) and 1px zinc borders. A shadow is only allowed where it explains stacking: drag previews, floating menus, card foreground details (`0 4px 12px rgba(0,0,0,0.54)` / `0 8px 24px rgba(0,0,0,0.28)`).

**Every control earns its position.** If you can't say why a control sits where it sits, it isn't done. Never fill spare space with a feature.

## Some general rules
These steer us in the right direction. They are not hard-set, but default to following them; if you think one should be ignored, be very loud about it and get approval from us first.

```
