---
name: tv-ui-audit
description: "Iterative TV UI/UX audit and fix loop for Android TV Compose apps — audit → scorecard → Top 20 → OpenCode pass → verify → repeat."
version: 1.0.0
metadata:
  hermes:
    tags: [android-tv, compose, ui-audit, ux, opencode, deepseek]
    related: [tv-app-build, unspooled-tv-development]
---

# TV UI/UX Audit

## Overview

Iterative audit-and-fix loop for Android TV Compose apps. Each pass: audit → scorecard → Top 20 → OpenCode with DeepSeek Flash → verify → repeat. Score progression tracked across builds.

**Target score:** 90+/100 for production readiness.

## The Loop

### Phase 1: Audit

1. **Grep diagnostics** — scan for known anti-patterns:
   - `FocusRequester.Default` — should be 0
   - `moveFocus(` — should be 0
   - `clearFocus(force` — should be 0
   - `import androidx.compose.material3.MaterialTheme` — should be 0 (TV-first)
   - `import androidx.compose.material3.Text` — should be 0 (TV-first)
   - `tween(durationMillis = N)` — hardcoded durations
   - `spacedBy(N.dp)` — hardcoded spacing
   - `RoundedCornerShape(N.dp)` — hardcoded radius
   - `BorderStroke(N.dp)` — hardcoded borders
   - `fontSize = N.sp` — hardcoded typography
   - `.padding(N.dp)` — hardcoded padding
   - `Color(0x...)` — hardcoded colors

2. **Scorecard** — rate across 7 categories:
   - Visual Design: /20
   - TV Navigation: /20
   - Focus System: /20
   - Consistency: /15
   - Accessibility: /10
   - Performance: /10
   - Polish: /5
   - **Total: /100**

3. **Top 20 ranking** — rank all issues by severity (Critical > Major > Minor) and impact.

4. **Regressions** — list anything that became worse vs previous build.

5. **Competitor comparison** — benchmark against Netflix TV, Apple TV, Plex, Jellyfin, Stremio.

### Phase 2: OpenCode Plan

Write a plan file (`.hermes/opencode-fix-top20-<build>.md`) with:
- 20 numbered fixes, each with: issue number, file path, line number, problem description, fix description
- Constraints section: TV-first, no `moveFocus()`, use `requestFocusAfterFrames()`, use `UnifiedTokens`, no mobile MaterialTheme
- Verification section: build command + grep scans to run
- Bonus fixes section: additional improvements if time permits

### Phase 3: OpenCode Execution

```bash
opencode run --model deepseek/deepseek-v4-flash \
  --title "Fix Unspooled Build X Top 20 TV UI UX Audit" \
  --dangerously-skip-permissions \
  --thinking "Execute the attached plan fully..." \
  -f .hermes/opencode-fix-top20-<build>.md
```

Run in background with `notify_on_complete=true`.

### Phase 4: Verification

After OpenCode completes:
1. `git diff --stat` — see what changed
2. `./gradlew :app:assembleDebug` — build must pass
3. Run all grep scans — verify 0 violations for critical patterns
4. Compare scorecard vs previous build

### Phase 5: Commit & Push

```bash
git add -A && git commit -m "feat: complete UI/UX audit fixes — Build X"
git push origin master
```

Update `PROJECT_STATE.md` with audit progress section.

## Scoring Rubric

### Visual Design (/20)
- Typography consistency: 4 pts — all screens use `UnifiedTokens.Type`
- Spacing consistency: 4 pts — all screens use `UnifiedTokens.Space`
- Color usage: 4 pts — no hardcoded `Color(0x...)`, theme tokens used
- Card sizing: 4 pts — all cards use `metrics.posterColumns` / `UnifiedTokens.Layout`
- Empty/loading/error states: 4 pts — all screens use shared state components

### TV Navigation (/20)
- D-pad flow: 6 pts — no dead ends, no traps
- Focus movement: 6 pts — explicit `FocusLinks` where needed
- Focus visibility: 4 pts — consistent focus ring (white 2dp)
- Focus scaling: 4 pts — `graphicsLayer` scale, no springs on cards

### Focus System (/20)
- No `FocusRequester.Default`: 5 pts
- No `moveFocus()`: 5 pts
- No `clearFocus(force=true)`: 5 pts
- Stable requesters across data changes: 5 pts

### Consistency (/15)
- Animation durations: 4 pts — all use `UnifiedTokens.Motion`
- Corner radius: 4 pts — all use `UnifiedTokens.Radius`
- Border widths: 4 pts — all use `UnifiedTokens.Focus`
- Design system files: 3 pts — no duplicate component names across packages

### Accessibility (/10)
- `contentDescription` on interactive elements: 4 pts
- `Role` semantics on sidebar items: 3 pts
- Minimum 48dp touch targets: 3 pts

### Performance (/10)
- No O(n²) composition: 3 pts
- Animation throttling: 3 pts
- No `animateFloatAsState` on every tick: 2 pts
- `graphicsLayer` instead of `Modifier.scale()`: 2 pts

### Polish (/5)
- Shimmer/directional sweep: 2 pts
- Empty state icons: 2 pts
- Back button on SeeAll: 1 pt

## Pitfalls

### OpenCode Plan Writing
- **Be specific with file paths and line numbers.** OpenCode needs exact locations.
- **Include constraints section.** Without it, OpenCode may introduce mobile MaterialTheme imports or `moveFocus()` calls.
- **Group related fixes.** 20 individual fixes is too many for one OpenCode pass. Group by file (e.g., "Watched screen: 8 issues in 1 file").
- **Add bonus fixes section.** OpenCode often has time for extras — list them separately so they don't block the Top 20.

### Verification
- **Always run the build.** OpenCode's self-report of "build passes" is not evidence — run it yourself.
- **Run all grep scans.** A single scan is not enough — check all 10 anti-pattern categories.
- **Compare against previous build.** Note what improved, what regressed, what stayed the same.

### Scorecard
- **Be honest about scores.** Don't inflate scores because you want to ship. If a screen has 8 hardcoded `sp` values, it gets 0/4 for typography consistency.
- **Track progression across builds.** Each build should show clear improvement. If a build scores the same or lower, something went wrong.

## Reference Files

- `references/audit-methodology.md` — Full audit methodology with grep patterns, scoring rubric, and OpenCode plan template.
- `references/scorecard-template.md` — Scorecard template for each build pass.
- `references/competitor-benchmarks.md` — Netflix TV, Apple TV, Plex, Jellyfin, Stremio comparison notes.
