# Frontend Design Review

> Quality gate for produced frontend designs. 6-dimension audit (typography hierarchy + motion coherence + shader perf-budget + accessibility WCAG AA + brand conformance + responsive fidelity). Scored rubric. Solo-invokable.

- Skill: `jokerman89/frontend-design-review` (Agent Skill)
- Install (CLI): `npx skillmds@latest add jokerman89/frontend-design-review`
- Raw SKILL.md: https://api.skillmd.com/api/skills/jokerman89/frontend-design-review/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Design & Media
- Author: jokerman89 (https://skillmd.com/u/jokerman89)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/jokerman89/frontend-design-review

---


You are the `frontend-design-review` skill — quality gate for the v3.7 frontend-* family (Phase A2 — resolves /plan-eng-review M-3 reviewer-concern #3).

## What this skill does

Reads a produced frontend artifact (HTML file, Next.js project, screenshots, or live URL) → DesignSystemAuditor agent runs **6-dimension audit** with explicit scoring rubric → writes `design-review.json` with per-dimension scores (0-100) + verdict (green/yellow/red) per dimension + overall verdict.

Solo-invokable for audit or chained from `/li:frontend-design` Workflow Step 7 (if enabled).

**Scoring rubric (resolves M-3 from /plan-eng-review):**
- Per dimension: **≥80 = green**, **60-79 = yellow**, **<60 = red**
- Overall verdict: ALL dimensions green → GREEN. Any red → RED. Otherwise YELLOW.
- Customer-share runs: any yellow or red → BLOCKED until operator addresses

L-001-discipline: skill body is the contract (the 6 dimensions). Agent at invocation does the actual scoring against the produced artifact. Don't pre-bake what "good" looks like.

## When to use

- Pre-customer-share artifact-validation
- Auto-invoked by `/li:frontend-design` Workflow Step 7 (if not skipped)
- Standalone audit of operator-built site
- Diff-mode: compare produced output vs vault baseline

## When NOT to use

- Pre-implementation review (no artifact to score yet) — use `/plan-eng-review` instead
- A/B test scoring (different bar) — out of scope for this skill
- Purely typographic-only review — use `/li:frontend-typography` direct

## Inputs

- Required `<artifact>` — path to HTML file, Next.js project dir, screenshot, OR live URL
- Optional `--baseline <vault-name>` — compare against `~/.lintel/brand/design-patterns/<name>/` baseline
- Optional `--dimensions <comma-list>` — subset audit (default: all 6)
- Optional `--out <path>` — output path (default: `<artifact-dir>/design-review.json`)
- Optional `--customer-share` — strict-mode: yellow → BLOCKED
- Optional `--include-screenshots` — capture artifact rendering for audit-log (Playwright headless)

## Workflow

### Step 1 — Parse + validate artifact

```bash
artifact="${1:-}"
baseline="${BASELINE:-}"
dimensions="${DIMENSIONS:-all}"
customer_share="${CUSTOMER_SHARE:-}"

[ -z "$artifact" ] && { echo "Usage: /li:frontend-design-review <artifact>"; exit 2; }

# Detect artifact type
if [[ "$artifact" =~ ^https?:// ]]; then
  artifact_type="url"
elif [ -d "$artifact" ]; then
  artifact_type="project-dir"
elif [[ "$artifact" =~ \.(html|htm)$ ]]; then
  artifact_type="single-html"
elif [[ "$artifact" =~ \.(png|jpg|jpeg|webp)$ ]]; then
  artifact_type="screenshot"
else
  echo "Unknown artifact type: $artifact"; exit 2
fi
```

### Step 1.5 — Mechanical validator pre-pass (ADR-0015)

Before any agent judgment, run the cheap hard gate on HTML artifacts:

```bash
dna="${LINTEL_SKILLS_DIR:-skills}/design-dna"
python3 "$dna/scripts/validate_design.py" "$artifact" \
  --profile "$dna/profiles/<active-profile>.yaml"
```

Exit 1 → the run is **RED** regardless of dimension scores (the violations are objective:
zoom-disable, killed focus, emoji icons, off-palette drift). Surface the validator output as
findings; the 6-dimension audit still runs so the operator gets the full picture. python3 absent
→ the agent checks the design-dna non-negotiables list manually as part of dimension 4.

### Step 2 — DesignSystemAuditor agent dispatch

Hand off to `agents/frontend/DesignSystemAuditor.md`. Agent loads artifact + (optional) baseline + dimension-list + the active design profile (`skills/design-dna/profiles/`, default anthropic-default) as the brand-conformance reference when no vault baseline is given.

### Step 3 — Run 6-dimension audit

**Dimension 1: Typography hierarchy (0-100)**
- Heading scale-ratio applied consistently (1.25/1.333/1.618)
- Line-height bands: tight for display, normal for body, relaxed for long-form
- Letter-spacing applied at scale (tight for large, wide for small uppercase)
- Font-loading: preload critical, swap-strategy declared
- Variable-axes used (if font supports)
- **Red flags (subtract):** heading-soup (>4 size-levels in fold), font-loading FOIT >100ms, no fallback-stack

**Dimension 2: Motion coherence (0-100)**
- Single motion-language thesis (not GSAP-here, Framer-Motion-there for same role)
- Scroll-trigger animations respect viewport budgets (no >5 concurrent scroll-tracked anims)
- prefers-reduced-motion fallback present + tested
- Mobile-strategy declared + visibly differentiated
- **Red flags:** scroll-jank >16ms, no prefers-reduced-motion fallback, mixed-library overlap

**Dimension 3: Shader perf-budget (0-100)**
- WebGL initialization gated by viewport-intersection
- Fragment-shader complexity within mid-tier-mobile budget
- Fallback for no-WebGL contexts
- IntersectionObserver pause for off-screen
- **Red flags:** fps drops below 30 on mid-tier mobile, no fallback, WebGL crashes leak

**Dimension 4: Accessibility WCAG AA (0-100)**
- Color-contrast ≥4.5:1 for normal text, ≥3:1 for large text
- All interactive elements keyboard-reachable
- Focus-rings visible + meet contrast
- Aria-labels on icon-buttons
- prefers-reduced-motion + prefers-color-scheme respected
- **Red flags:** contrast <3:1 on critical text, no keyboard nav, focus-rings stripped without replacement

**Dimension 5: Brand conformance (0-100)**
- Palette tokens match `~/.lintel/brand/palettes/<active>.json` (if customer-share)
- Logo placement matches brand guidelines
- Typography family matches brand spec (if operator-licensed)
- Voice-tier compliance (internal vs customer-share copy)
- **Red flags:** off-palette colors >20% of accents, logo missing or misused, voice-tier mismatch

**Dimension 6: Responsive fidelity (0-100)**
- Breakpoints: mobile (<640px), tablet (640-1024px), desktop (>1024px) all valid
- Container queries used where component-context varies
- Touch-targets ≥44px on mobile
- Hero scales appropriately (no horizontal scroll, no clipped content)
- Mobile-motion-strategy applied
- **Red flags:** horizontal scroll on mobile, touch-targets <32px, hero broken on iPhone-SE

### Step 4 — Compute scores + verdict

```bash
# Per-dimension: agent emits {score: N, findings: [...]}
# Skill computes verdict per dimension + overall

for dim in typography motion shader accessibility brand responsive; do
  score=$(jq -r ".dimensions.$dim.score" "$out")
  if [ "$score" -ge 80 ]; then verdict="green"
  elif [ "$score" -ge 60 ]; then verdict="yellow"
  else verdict="red"; fi
  jq --arg d "$dim" --arg v "$verdict" '.dimensions[$d].verdict = $v' "$out" > "$out.tmp" && mv "$out.tmp" "$out"
done

# Overall
red_count=$(jq '[.dimensions[] | select(.verdict == "red")] | length' "$out")
yellow_count=$(jq '[.dimensions[] | select(.verdict == "yellow")] | length' "$out")

if [ "$red_count" -gt 0 ]; then overall="red"
elif [ "$yellow_count" -gt 0 ]; then overall="yellow"
else overall="green"; fi

jq --arg v "$overall" '.overall_verdict = $v' "$out" > "$out.tmp" && mv "$out.tmp" "$out"
```

### Step 5 — Customer-share strict gate

```bash
if [ -n "${CUSTOMER_SHARE:-}" ] && [ "$overall" != "green" ]; then
  echo "BLOCKED: customer-share strict-mode requires GREEN. Current: $overall"
  echo "Top concerns:"
  jq -r '.dimensions[] | select(.verdict != "green") | "- " + .name + " (score: " + (.score|tostring) + "): " + (.findings[0] // "see report")' "$out"
  exit 1
fi
```

### Step 6 — Output report

```
FRONTEND DESIGN REVIEW — <artifact>
══════════════════════════════════════════════════════════════════

Overall verdict:    <GREEN | YELLOW | RED>

Per-dimension:
  Typography hierarchy:   <score>/100  <verdict>
  Motion coherence:       <score>/100  <verdict>
  Shader perf-budget:     <score>/100  <verdict>
  Accessibility (WCAG):   <score>/100  <verdict>
  Brand conformance:      <score>/100  <verdict>
  Responsive fidelity:    <score>/100  <verdict>

Top findings (yellow + red):
  • <dimension>: <finding>
  • <dimension>: <finding>

Recommendation:
  GREEN  → ship as-is
  YELLOW → address findings before customer-share
  RED    → BLOCKED for customer-share; must fix before re-review

Full report: $out
```

## Schema

`design-review.json`:

```json
{
  "schema_version": 1,
  "generated_at": "<iso-8601>",
  "artifact": "<path or URL>",
  "artifact_type": "url | project-dir | single-html | screenshot",
  "baseline_compared": "<vault-name or null>",
  "overall_verdict": "green | yellow | red",
  "dimensions": {
    "typography_hierarchy": {
      "name": "Typography hierarchy",
      "score": 85,
      "verdict": "green",
      "findings": ["heading-scale 1.25 applied consistently", "preload tag missing for Fraunces"]
    },
    "motion_coherence": { "name": "Motion coherence", "score": 70, "verdict": "yellow", "findings": [...] },
    "shader_perf_budget": { ... },
    "accessibility_wcag": { ... },
    "brand_conformance": { ... },
    "responsive_fidelity": { ... }
  },
  "customer_share_strict": false
}
```

## Status protocol

- **DONE** — review complete, design-review.json emitted, overall green
- **DONE_WITH_CONCERNS** — review complete, overall yellow (non-customer-share)
- **BLOCKED** — review red, OR customer-share strict-mode with yellow/red
- **NEEDS_CONTEXT** — artifact unreadable, OR dimension-list invalid

## Pause-points

- Customer-share + yellow/red: BLOCKED + surface top findings + ask "address now or override?"
- Red dimension: hard-block for customer-share regardless of overall

## Integration

**Reads:**
- `<artifact>` (URL, file, dir, screenshot)
- `~/.lintel/brand/design-patterns/<baseline>/` (if --baseline)
- `~/.lintel/brand/palettes/<active>.json` (for brand-conformance dimension)

**Writes:**
- `<artifact-dir>/design-review.json` (or $OUT-path)
- Audit-log: `.claude/runtime/audit/frontend-design-review-runs.jsonl`

**Calls into:**
- `agents/frontend/DesignSystemAuditor.md` (primary)
- `/li:compliance-gate` (if --customer-share + red dimension)

**Consumed by:**
- `/li:frontend-design` Workflow Step 7 (Phase A2-onwards integration)
- Operator standalone audit
- Pre-customer-share gate-check

## Anti-patterns

- **Scoring without rubric** — pre-A2 design-doc concern #3. Skill body documents rubric explicitly.
- **Treating all dimensions equal-weight** — accessibility + brand-conformance are gating for customer-share. Don't average them in.
- **Skipping baseline comparison when vault has match** — operator-invested patterns. Use them.
- **Producing review.json without `schema_version`** — M-5 compliance.

## Failure recovery

- Artifact unreadable: BLOCKED with diagnostic ("file not found", "URL 404", "directory not a project")
- Headless-browser screenshot fails: degrade to static-audit + flag in review
- Baseline-vault missing: warn + fall back

## Recommended next steps after invocation

- GREEN → ship
- YELLOW → address findings + re-run review
- RED → hard-block + investigate per-dimension findings
- Use design-review.json as input to `/li:context-save` for session-handoff

