fe-design · git:20260824.5e14e9f · 2026-08-24 · sha256 bc2e67a2bb91b4a1

fe-design git:20260824.5e14e9fA

Immutable. This exact content is served forever at /api/v1/blob/bc2e67a2bb91b4a1.

---
model_tier: medium
name: fe-design
description: "Frontend design heuristics — and, outside the ticket engine, the loop that applies them: audit, brief, inventory, build, review. Use when building or changing any UI, not only when planning one."
personas:
  - frontend-engineer
domain: engineering
workspaces:
  - engineering
packs:
  - engineering-base
---

# Frontend Design Skill

## Ad-hoc mode — outside the engine, YOU run this loop now

One question decides which mode you are in: **is a `/implement-ticket` run
dispatching this?**

| Situation | Who owns the UI write | This skill is |
|---|---|---|
| A ticketed run — the UI directive set is dispatching | `directives/ui/*` | a reference it cites |
| Anything else — "build me the page", "improve this form", "implement the approved design" | **you, in this turn** | the executor |
| A renderer axis is in play — WebGL / Three.js / canvas / scroll-scrubbed video | **still you** — the renderer is a grounding question, not a second executor | the executor, grounded via `search_stack` |

The third row is an **axis**, not an owner. Renderer selection resolves through
machinery that already exists: `search_stack` in
[`corpus-grounding`](../corpus-grounding/SKILL.md)
(`scripts/decision_engine.ts`), whose stack corpus carries `threejs.csv` among
its stacks, read beside the register in
[`design-intelligence`](../design-intelligence/references/context-and-registers.md)
§ Register. No second frontend executor is declared, and none is needed: a
renderer changes what you ground against, never who writes the UI.

Outside the engine, nothing else owns the design quality of a UI write. Reading
this skill and then writing the UI from priors is the failure it exists to
prevent — the loop below is not optional context, it is the work.

**Skip only when the change is `ui-trivial`, decidable off the diff:** ≤ 1 file,
≤ 5 changed lines, no new component, no new state, no new dependency. Anything
else runs the loop.

### The loop

1. **Audit first** — run [`existing-ui-audit`](../existing-ui-audit/SKILL.md).
   What already exists (components, tokens, layout conventions) outranks every
   heuristic below. Reinventing an existing component is the #1 failure mode.
2. **Brief** — cover the same five keys the engine requires before any code:
   `layout`, `components`, `states`, `microcopy`, `a11y`. `states` means all
   five of `empty`, `loading`, `error`, `success`, `disabled` — a brief missing
   one is unfinished, not concise.
3. **Inventory — only when an artifact was provided, and before you build.**
   List the artifact's **interactions, keyframes, and script includes** from its
   source (`design-fidelity-mechanics` § Data-basis ladder — read it, do not
   look at a picture of it). Then place **every** listed item in exactly one
   bucket, using the engine's own names (`apply.ts`, `COVERAGE_BUCKETS`) so the
   two surfaces read the same. **Nothing enforces that they stay the same** —
   this is a copied vocabulary, not a shared constant, and no test pins it;
   renaming a bucket in the engine leaves this list stale and silent:

   | Bucket | Meaning |
   |---|---|
   | `honoured` | carried over as-is |
   | `translated` | carried over in a different shape (a handler became a framework binding) |
   | `flagged` | **not** carried over — with the reason, in the output |

   Dropping a handler stays allowed; hiding one does not. An item in no bucket
   is the failure this step exists to catch — "missing JavaScript" is what it
   looks like from the user's side. Inside the engine this is enforced
   (`apply.ts`, `COVERAGE_BUCKETS`, an unaccounted item is a halt); out here it
   is a duty you carry, and nothing checks it for you. (fixture:
   `daf-adhoc-port-coverage`.)
4. **Build** — against the audit's primitives, in the project's stack. Where the
   artifact's own markup/CSS/JS is stack-compatible, adapt **that code**;
   re-deriving it from scratch is a deviation needing confirmation
   (`design-fidelity-mechanics` § Adopt the code).
5. **Review, then re-enter** — run [`design-review`](../design-review/SKILL.md)
   before calling it done, and scope the verdict honestly: render-scoped when
   you can render it, otherwise explicitly static-scoped, naming which checks
   actually ran. "Looks good" with neither scope named is a verdict without
   evidence. Findings → fix them and **re-enter step 5**, at most **2 rounds**,
   and **stop early on a null**: a round that produces **no new finding** ends
   the loop, and a round that produces only findings the provided artifact
   already covers produces no new finding. At the 2-round ceiling with findings
   still open, stop and hand the remaining list back — ship-as-is or abort is
   the user's call, never another silent pass. Judgement alone never buys a
   third round.

   The ceiling is **2**, the same number the engine enforces
   (`directives/ui/polish.ts`, `POLISH_CEILING`), so the ad-hoc path and the
   ticketed path bound the loop identically rather than by two conventions that
   can drift. Fixtures: `daf-adhoc-converges` (round 2 is a null, loop ends) and
   `daf-adhoc-ceiling` (findings remain at the ceiling, loop hands back).

### The floors — pulled immediately before the write

```
PULL references/craft-floor.md IMMEDIATELY BEFORE THE WRITE, NOT AT SKILL LOAD.
```

Twelve universal floors that do not vary by mode, register, intent or stack.
They were inline here until the delivery point moved: a floor read at skill-load
time can be a compaction away from the write it governs (`ADR-227`).

One precedence rule stays here because it is authority, not craft: **the audit
outranks every heuristic.** Say `[audit override]` when it does.

## Positioning — reference inside the engine, executor outside it

Inside a `/implement-ticket` run, `fe-design` is a **universal reference
skill**: it carries stack-agnostic heuristics the UI directive set cites, and
it does not own the flow. The ownership table below applies **to that mode**.
Outside the engine the table has no dispatcher behind it — the ad-hoc loop
above is the owner instead.

| Concern | Owner (engine-mediated runs) |
|---|---|
| Layout / states / microcopy lock | [`directives/ui/design.ts`](../../templates/scripts/work_engine/directives/ui/design.ts) |
| Stack-dispatched implementation | [`directives/ui/apply.ts`](../../templates/scripts/work_engine/directives/ui/apply.ts) → `blade-ui` / `livewire` / `flux` / `react-shadcn-ui` |
| Existing-component inventory + tokens | [`existing-ui-audit`](../existing-ui-audit/SKILL.md) (mandatory pre-step) |
| Grounded selection (style, color tokens, typography, pattern, anti-patterns) | [`design-intelligence`](../design-intelligence/SKILL.md) — corpus-grounded; this skill stays the heuristic layer and *invokes* it |
| Design-review polish loop | [`directives/ui/review.ts`](../../templates/scripts/work_engine/directives/ui/review.ts) + [`directives/ui/polish.ts`](../../templates/scripts/work_engine/directives/ui/polish.ts) |

## When to use

Cite this skill when:

- Planning a new page or feature UI before implementing
- Choosing between component patterns (modal vs. inline, table vs. cards)
- Designing forms with complex validation or multi-step flows
- Making responsive design decisions
- Reviewing UI for accessibility and usability

**Inside a ticketed run**, do NOT use this skill to:

- Implement components — that is the apply-step's stack-dispatched skill
- Audit an existing UI — that is `existing-ui-audit`
- Drive the full UI flow — that is the `directives/ui/` orchestrator

Outside a ticketed run, the first and third lines invert: no dispatcher is
running, so implementation quality and the flow are yours. The second holds in
both modes — the audit is always `existing-ui-audit`; you invoke it, you do not
replace it.

> **Resource-first, before taste.** Any request to recreate / redesign / mock /
> prototype / improve an existing UI runs the
> [resource-first context gate](../existing-ui-audit/SKILL.md#resource-first-context-gate-design-fidelity)
> FIRST — search the project's tokens/design-system/assets, hard-stop and ask
> when a referenced source is inaccessible (never invent from memory), and
> prefer code over screenshots for exact values. Planning here starts from that
> inventory, not from generic aesthetic memory (design-artifact lifecycle,
> Inspect stage).

## How the directive set cites this skill

`directives/ui/design.ts` produces the design brief (layout, components,
states, microcopy, a11y). Selection decisions (style, semantic color
tokens, typography pairing, layout pattern, anti-patterns) come **grounded**
from [`design-intelligence`](../design-intelligence/SKILL.md) — run its
corpus query first; fall back to the heuristics in this reference only
where the corpus reports an evidence gap or the audit already pins a
project pattern. Stack-specific choices come from the dispatched
implementation skill, not from here.

> **When the corpus is not installed.** `design-intelligence` ships in the
> `frontend-design` pack; this skill ships in `engineering-base`. A consumer
> who installed only `laravel` or only `react` therefore has this skill and
> **not** the corpus. Fall back to the heuristics here and say so in the
> result — "selected from heuristics; `frontend-design` not installed, so no
> corpus grounding". The evidence-gap fallback above is about a corpus that
> answered "nothing here"; this is about a corpus that is absent. Never
> present an ungrounded pick as grounded, and never record a missing pack as
> an evidence gap.

## Section index — load on demand

Load the reference file whose sections the task needs — never all of them by default:

- [`references/design-patterns.md`](references/design-patterns.md) — Component Architecture · Form Design · Table Design · Responsive Strategy · Accessibility (a11y) · Motion — decision-tree and rationale · UX Principles · Craft details — typography & imagery · Presenting variants
- [`references/design-read-and-memory.md`](references/design-read-and-memory.md) — Cross-task design memory — read DESIGN.md / PRODUCT.md first · Register — brand vs product · Design Read — articulate intent before generating · Aesthetic direction

## Procedure

When `directives/ui/design.ts` (or any caller) cites this skill:

1. **Inspect `state.ui_audit` first** — review the audit produced by [`existing-ui-audit`](../existing-ui-audit/SKILL.md); it is mandatory. Stop and request the audit if missing.
2. **Pick the smallest matching section** — Component Architecture, Form Design, Table Design, Responsive Strategy, Accessibility, or UX Principles. Cite by H2/H3 heading, never paste the whole skill.
3. **Defer to audit findings** — when the audit pins a project pattern (token, primitive, layout convention), use it. The heuristics here are fallbacks for gaps, not overrides.
4. **Defer to the stack apply skill** — Blade vs. Livewire vs. Flux vs. React-shadcn choices come from the dispatched implementation skill, never from this reference.
5. **Surface conflicts** — if a heuristic here contradicts an audit finding or stack convention, name both and let the caller decide; do not silently pick.

## Output format

When this skill's content is folded into a design brief or review:

1. Quote the cited heuristic verbatim, with the H2/H3 heading and a one-line "why this applies" tie-back to the request.
2. Map each heuristic to a concrete artifact in the brief (component, form section, table column, breakpoint rule, a11y check, UX state).
3. Keep stack-agnostic — never name Blade/Livewire/Flux/React primitives in the cited prose; the apply step adds those.
4. Mark anything overridden by audit findings as `[audit override]` and link to the audit entry.

## Related

- **Orchestrator:** [`directives/ui/`](../../templates/scripts/work_engine/directives/ui/) — owns the UI flow
- **Pre-step (mandatory):** [`existing-ui-audit`](../existing-ui-audit/SKILL.md) — inventory before design
- **Stack apply skills (dispatched, not standalone):**
  - [`blade-ui`](../blade-ui/SKILL.md) — Blade template implementation
  - [`livewire`](../livewire/SKILL.md) — Livewire component implementation
  - [`flux`](../flux/SKILL.md) — Flux component library usage
  - [`react-shadcn-ui`](../react-shadcn-ui/SKILL.md) — React + shadcn primitives
- **Adjacent reference:** [`dashboard-design`](../dashboard-design/SKILL.md) — monitoring dashboard design (different domain)

## Gotcha

- Don't design components without running `existing-ui-audit` first — the audit's component/token inventory is the canonical source for "what already exists in this project". Reinventing is the #1 failure mode.
- Heuristics in this reference apply across stacks; do not promote them to project rules without checking the audit.
- Mobile-first is not optional — every layout must work on 320px width.

## Read the authority object — never re-infer it

Read the resolved `ui_authority`
([contract](../../../docs/contracts/ui-authority.md)) before the loop:
`surface_mode`, `register`, `change_intent`, `reference_maturity`,
`constraints`. This skill is a **declared consumer** — a second decision table
beside the object is a drift surface, so do not re-derive any field.

`surface_mode` sets density, hierarchy and expressiveness only, per
[`design-modes`](../../../docs/guidelines/design-modes.md) § The second axis.

```
QUALITY FLOORS DO NOT VARY BY SURFACE MODE.
A FLOOR THAT MOVES WITH THE MODE IS A PREFERENCE WEARING A FLOOR'S NAME.
```

### The source-led path

`reference_maturity: runnable-artifact` → the artifact's own markup, CSS and JS
is the data basis; adapting it is the **default** and a from-scratch
re-derivation is a deviation. Sort every mechanic into `honoured` / `translated`
/ `flagged`; one present, absent and unflagged is a **silent drop**, target zero.
Procedure and the vanishing-mechanic classes:
[`references/source-led-port.md`](references/source-led-port.md).

Maturity is not decided here — it arrives on the authority object, and per-value
provenance belongs to `road-to-frontend-fidelity-calibration` Phases 0 and 2.

## Anti-slop discipline

Before proposing a direction, scan the Visual (V1–V7) and Layout (L1–L8)
sections of [`design-antipatterns`](../../../docs/guidelines/design-antipatterns.md).
On a match, choose differently or invoke the entry's own override condition in
the brief — every entry has one, and they are register-scoped. The Q* floors are
in [`references/craft-floor.md`](references/craft-floor.md) instead of here, so
they arrive at the write rather than at skill load.

## Do NOT

- Do NOT skip mobile viewport testing.
- Do NOT use fixed pixel widths for responsive layouts.
- Do NOT ignore accessibility requirements.
- Do NOT use this skill as an executor INSIDE a ticketed run — there the executor is `directives/ui/design.ts` and this is the reference it cites. Outside one, the ad-hoc loop at the top of this file IS the executor; do NOT read the reference and then write the UI from priors.