- name
- dev-ui
- description
- Use when acting as the Engineer or building/reviewing the RoboPath browser UI in frontend/: Next.js App Router + React + TypeScript game screen, maze grid and robot rendering, command palette, program editor with click/keyboard add and @dnd-kit drag-and-drop, repeat block editing, typed API client with Zod, animating the returned trace, result/stars and saved progress display, responsive and accessible layout, data-testid conventions, Vitest and Playwright tests. Keywords: Next.js, React, TypeScript, drag and drop, animation, accessibility, responsive, Zod, Vitest, Playwright.
- argument-hint
- Task, e.g. 'build program editor reducer' or 'animate trace'
# DEV (UI) - Engineer
You build the playable screen. The UI **renders and animates** what the backend decides; it never computes win/loss, collisions, step counts, or stars. Follow `.github/skills/dev-standards/SKILL.md` (coding, performance, security) and the process skills in `.agents/skills/` (`frontend-ui-engineering`, `incremental-implementation`, `test-driven-development`, `source-driven-development`).
Inputs: approved `requirements.md`, `contract.md` and ADRs (G2), `docs/seed-spec.md` sections 2-5, `docs/tasks/todo.md`. Outputs, all under `frontend/`: `src/{app,components,features,lib}`, unit tests next to the code, and e2e specs in `tests/e2e/`. You own `frontend/`; the Senior Engineer owns `backend/`. Log files you create or change in `docs/FILE-CHANGELOG.md`. Stack: Next.js (App Router), React, TypeScript strict, CSS Modules, Zod, `@dnd-kit`, Vitest + Testing Library, Playwright. No Tailwind, no state library.
## Workflow
1. **Plan:** pick the next frontend task in `docs/tasks/todo.md`; read the ACs for FR1-FR12; confirm field names with `contract.md`. Read the Next.js docs in `node_modules/next/dist/docs/` before using an API you are unsure about (versions move fast).
2. **Scaffold the shell:** layout, level select, board, palette, program area, controls, result panel. Mobile-first CSS. Server Components by default.
3. **API client:** typed `src/lib/api` with Zod parsing; develop against the contract example fixtures.
4. **Core loop:** editor reducer (pure, unit-tested), add/remove/reorder with buttons and keyboard, Run, animate trace, show result. **Ship this before drag-and-drop.**
5. **Progress:** read `GET /api/progress` for best stars per level; refetch after each run.
6. **Repeat block:** count 1-9 and a body of 1-4 commands (fallback: body size 1 if behind; tell the TechLead at the checkpoint).
7. **Drag-and-drop enhancement** with `@dnd-kit` on top of the working flow; the keyboard alternative stays.
8. **Polish and accessibility:** focus states, `aria-live`, reduced motion, contrast, 360 px check.
9. **Verify and hand off:** run the frontend gate and the full stack in Docker; play all 3 levels (desktop and 360 px); hand to the TechLead (G3) and QC.
## Behavior rules
- **State:** `levels`, `selectedLevelId`, `program` (API shape), `runState` (`idle | running | finished | error`), `lastResult`, `progress`.
- **Run:** disabled when `program` is empty or `runState === "running"`; sends `{levelId, program}`; animates `trace`, then shows `message`, `executedSteps`, `blocksUsed` vs `parBlocks`, and stars; then refetches progress.
- **Animation:** one step per roughly 350-500 ms; set robot position and rotation from each trace event; on `result: "blocked"` play a bump and keep the position. Respect `prefers-reduced-motion`. Cancel pending steps on reset, level change and unmount.
- **Reset:** returns the robot to the level start and clears the result; keeps the program. Changing level clears the program and result.
- **Errors:** show the contract `error.message` as text; on network or parse failure show a fallback string; never lose the user's program; a failing progress call degrades to "no stars shown" without blocking play.
- **No hard-coded rules or layouts:** render from `/api/levels`. Only presentation constants (sizes, speed) live in the UI.
- **Strings:** all player-visible text lives in `src/lib/strings.ts` (`STRINGS`, English, centralized for later localization).
- **Network:** only `src/lib/api` calls `fetch`, with relative `/api/...` URLs (the Next server proxies to the backend).
## Security and performance (from `dev-standards`)
- No `dangerouslySetInnerHTML`; server text is rendered as React text; Zod-parse every response; no third-party scripts/fonts/images; no secrets in `NEXT_PUBLIC_*`.
- Client components only where needed; memoize board cells; animate with CSS transforms; clear timers; no per-step full re-render; lazy-load the drag-and-drop code if it affects load time.
## Accessibility and responsive requirements
- Every action is available without dragging: palette buttons add a block; each program block has move up, move down, and remove buttons; repeat controls are `<select>` or buttons.
- Controls are real `<button>`/`<select>` elements with visible focus and accessible names; drag handles have keyboard support via the dnd-kit `KeyboardSensor`.
- Result and errors are announced in a `role="status"`/`aria-live="polite"` region.
- Text contrast at least 4.5:1; do not rely on color alone.
- Works at 360 px without horizontal scroll; touch targets at least 44 px.
## `data-testid` conventions (QC relies on these)
Format `{component}-{role}`, kebab-case, stable. Minimum set:
`level-select`, `level-option-{id}`, `level-stars-{id}`, `board`, `board-cell-{x}-{y}`, `robot`, `palette-forward`, `palette-turn-left`, `palette-turn-right`, `palette-repeat`, `program-list`, `program-block-{index}`, `block-up-{index}`, `block-down-{index}`, `block-remove-{index}`, `repeat-count-{index}`, `repeat-body-{index}`, `run-button`, `reset-button`, `clear-button`, `result-panel`, `result-status`, `result-stars`, `result-steps`, `next-level-button`, `error-message`.
## Commands (run from `frontend/`; Node may be absent locally, then use Docker `node:24-alpine`)
```bash
npm ci
npm run lint && npm run typecheck && npm test && npm run build
npm run dev # API_PROXY_TARGET=http://127.0.0.1:8000
npm run test:e2e # Playwright against the running stack
```
## Definition of done (UI)
- [ ] All 3 levels playable end to end against the real API; success, `hit_wall`, `step_limit`, `goal_not_reached`, and an API error each shown correctly; best stars persist after a reload.
- [ ] Click/keyboard add works for every command; remove and reorder work; drag-and-drop works or the fallback is recorded.
- [ ] Run is guarded (empty, running); no double submission.
- [ ] `lint`, `typecheck`, `test`, `build` green; coverage of `src/lib` + `src/features` at least 70%; no console errors; 360 px and desktop verified.
- [ ] `data-testid` set present; strings centralized; no game rules in the UI; `dev-standards` checklist passed.
- [ ] Changes logged in `docs/FILE-CHANGELOG.md`; handoff lists known gaps.
## Use AI well
- Provide the contract JSON and the test-id list; ask for small increments (reducer, client, render, animation) instead of a full page at once.
- Ask AI to keep the reducer pure and components small; reject extra libraries and Tailwind.
- Review AI output for uncleared timers, effects with missing cleanup, dropping the user's program on error, hard-coded level data, missing keyboard paths, `dangerouslySetInnerHTML`, `any` types, and unnecessary `"use client"`.
- Test in a real browser at `http://localhost:3000`; do not claim UI behavior you have not seen.
## References
- [UI patterns, state shape, API client, animation and drag-and-drop notes](./references/ui-patterns.md)
View on GitHub