Interface Craft
Infer the mode from the request; do not present a menu:
- Review: report actionable issues; do not edit.
- Improve: review, implement scoped fixes, verify.
- Create: build the screen or component with these principles from the start. Before code, name the surface (operate / persuade / read) and write the short direction in generic tells; build the real states, not only the happy path.
Scope the scan to the request. Broad requests ("review this screen", "improve this flow"): scan all seven dimensions below. Narrow requests ("only microcopy", "just the error states", "keep the layout"): check only those dimensions plus states directly affected by your change (e.g. a longer label must still fit and stay accessible). In both cases change only what has a real problem.
Theme consistency is always in scope when the product supports light and dark appearances and the task touches UI colors, surfaces, overlays or a screen review. Invisible or low-contrast text in one theme is a priority-1 accessibility issue. Use the theming reference.
Workflow
- Inspect the interface, relevant code, design tokens, existing components, user-facing text, and the main task. For screenshots, separate what is visible from behavior you cannot see. Ask only when missing information blocks the work.
Web UI that can be opened in a browser (URL, dev server, .html): render and measure before judging. Run
node scripts/render_audit.mjs <url> --out ui-audit, then do the region scan in visual scan: every tile, every lens, in both themes. Add--stressfor broad reviews (longer Turkish text and 2× text expose breaks the sample data hides) and--states …when states are reachable by URL (stress and states). For a screenshot the user sent, tile it with--tile-imageand do the same scan. A visual review is not finished until every tile has been opened. For broad reviews, finish with the fresh-eyes/persona pass (visual scan, Pass D). Skip this only for narrow copy-only or code-only requests. - Scan the in-scope dimensions (all seven for broad work): task/flow, information & decision load, microcopy, interaction, visual craft, system states (empty/loading/error/success), accessibility. For broad reviews, walk all ten Nielsen heuristics (interaction reference).
- Diagnose: each issue = observed trigger → user consequence → concrete fix. Mark hypotheses as hypotheses. Never claim conversion gains or user testing from an expert review.
- Prioritize: (1) task blockers and accessibility, (2) errors, ambiguity, decision burden, (3) wording, hierarchy, consistency, (4) decorative polish. Merge overlapping findings into one fix.
High on sight, whatever else is going on: content clipped or overlapping at 320px or 200% text; text or a control invisible in one theme; a control covered by another layer; state shown only by color or only by motion; the danger color on a non-destructive action (or a safe color on a destructive one); success claimed before it is confirmed; focus lost or invisible; a layout that breaks only with real-length data.
Static lead-finders (paths relative to this skill; confirm every hit visually or in code):
python3 scripts/theme_audit.py <ui-source-dir>when the product has light and dark appearances.python3 scripts/token_audit.py <ui-source-dir>on broad reviews or "inconsistent spacing/fonts" complaints: it finds literal font sizes, off-grid spacing, one-off radii and fonts that ignore Dynamic Type.python3 scripts/hit_area_audit.py <ui-source-dir>on broad reviews and whenever a control "does nothing" or a tap opens the wrong thing: it finds clipped fill-scaled media whose invisible overflow still takes taps, tap targets under 44 pt / 48 dp, near-invisible layers that catch taps and full-cover web overlays.
- Implement the cheapest fix that solves the problem, in this order: delete something → use the platform's native behavior → reuse an existing token or component → correct a value → add something new. Work with the existing design language, tokens, components and dependencies. Before using a platform or library API, check the project's deployment target / dependency versions and confirm availability in current docs; use a compatible alternative or an availability guard when needed. When advice conflicts: user intent > accessibility > platform conventions > existing system > aesthetics. Do not add a library just for polish.
- Verify proportionally. Use preview/browser/simulator and project checks when available; never claim a check you did not run. Web: re-run
render_audit.mjswith the same arguments and compare counts per rule across all runs; a fix must not add hits elsewhere (often dark or 375px). Visual work: narrow + wide layouts, long text, and both light and dark, including overlays (sheets, menus, alerts) and every chip/button state. For layout and loading (see layout resilience): smallest and largest widths, landscape/iPad where supported, keyboard open on forms, largest text size, slow network and a failed image load. For repeated content, render the shortest and longest real items side by side. Comparable cards in the same row, carousel or grid row should share one height (reserved text lines, fixed media ratio). Vertical lists may keep natural row heights; check that media size and alignment stay consistent there. Never change simulator or device appearance on a shared device without recording and restoring the previous value. Interaction work: keyboard/focus, loading/success/error, recovery paths. Tap-test (see layout resilience, Hit areas): on the widest supported layout, tap every control that sits directly above or below media or a card, and tap just outside each card edge; a control that does nothing or a tap that opens the neighbour means a hit area does not match what is drawn.
Platform routing
- Web (HTML/CSS/React/Tailwind): visual-craft values are the starting point; existing tokens and observed rendering win.
- Native iOS (SwiftUI/UIKit) / Android (Compose): use the SwiftUI/Compose column in visual-craft; follow HIG/Material 3 over web values. For component-level platform compliance, also load
ui-complianceif available; otherwise apply HIG/Material 3 directly. - If
make-interfaces-feel-betteris installed and the task is heavy on web animation/surface code, load its reference files for full code samples.
Reference routing (load only what the task needs)
- Visual scan: web render audit (
scripts/render_audit.mjs: overflow, clipping, overlap, real contrast, near-miss alignment, uneven gaps, unequal cards, covered/small targets, focus, images, token inventory) + region-by-region tile scan. Default for any visual review of web UI. - Stress and states:
--stressruns, break harness with worst-case content, state workbench (?__state=), variants on one axis. Use when reviewing components/flows and when building. - Generic tells: surface types (operate/persuade/read), direction before code, generic-look tells and copy tells (EN/TR). Use for Create, redesigns and "looks generic" complaints.
- Visual craft: design-token consistency (
scripts/token_audit.py), surface separation (tone / line / shadow), radius, typography and spacing values, motion (frequency gate, easing tokens, durations, gestures), hit areas, performance - web and native. - Interaction and feedback: ten Nielsen heuristics, forms, navigation, states, recovery, help.
- Cognitive principles: Laws of UX - choice, memory, grouping, progress, attention.
- Microcopy: labels, buttons, helper text, errors, empty states, confirmations, localization (incl. Turkish).
- Theming: light/dark consistency - fixed vs adaptive color pairing, overlays, assets, audit procedure,
scripts/theme_audit.py. - Layout resilience: safe areas, keyboard, narrow/wide/iPad/landscape, large text, clipped controls, extreme data; loading states, skeleton parity, layout shift, image fallbacks.
- Accessibility: semantics, keyboard, focus, contrast, targets, reduced motion, screen readers.
Hard rules
- Every change must solve a named problem.
- Never: fake progress, false urgency, guilt-based opt-outs, hidden costs, hover-only actions, placeholder-as-label, arbitrary "max 7 items" menus, animating everything.
- Don't ship a fixed/adaptive color pairing (e.g.
Color.whitebackground with a dynamic text token,bg-whitewithtext-foreground) unless its contrast is verified in both themes. The default is a background and foreground from the same theme source. - Motion: no animation on high-frequency or keyboard-driven actions; never
ease-inin UI (exits use a strong ease-out, shorter than the enter); never start fromscale(0). - Surfaces: tone separates regions, lines mark boundaries people must find (inputs need 3:1), shadows mean elevation. No resting decorative shadows, no border + wide shadow on one element.
- Never trade readable labels, discoverability, user control or accessibility for decoration.
- Preserve product claims, prices and business behavior unless changing them is in scope.
- For library/framework API details, use the environment's documentation workflow (e.g. Context7); do not rely on remembered syntax.
Output
Lead with the outcome in one or two sentences. Respond in the user's language; keep the interface's existing locale unless asked.
For substantial reviews or edits, one table sorted by priority. Omit dimensions with no findings - never pad. Give each visual finding its run (viewport + theme, state, stress) so it can be found again. Then:
- Verification performed: runs, states, tiles and checks actually done. Mark anything you could not check as "Not verified".
- Considered and rejected: audit hits or ideas you dropped, one line each with the reason.
- Verdict for reviews: Block / Needs changes / Approve. Do not approve a screen that has an open "high on sight" finding.
Example (review of a sign-up form):
| # | Priority | Location | Before | After | User impact |
|---|---|---|---|---|---|
| 1 | Blocker | SignUp.tsx:42 | Submit stays enabled while pending; repeated taps send repeated requests | Disable during request, show spinner + "Hesap oluşturuluyor…" | Reduces repeat submissions while pending; visible status. Not verified: whether the backend deduplicates (idempotency) - flag for follow-up |
| 2 | A11y | SignUp.tsx:18 | Email field has placeholder only, no label | Persistent <label> "E-posta"; placeholder ornek@alanadi.com | Label stays visible while typing; screen readers announce it |
| 3 | Error | validation.ts:9 | "Invalid input" | "E-posta adresinde @ işareti eksik." next to the field | User knows exactly what to fix |
| 4 | A11y (Dark) | FilterSheet.swift:120 | Sheet uses Color(hex: "F8FAFC") and chips Color.white, but text uses the adaptive ink token → white on white in dark mode | Surface and chip backgrounds use adaptive surface tokens; verified in both themes | Chip labels and section titles readable in dark mode |
| 5 | Polish | Card.tsx:7 | rounded-xl on card and inner button with p-2 | Card rounded-2xl (8 + 8), button rounded-lg | Nested corners look concentric |
For a small copy edit: the revised text plus one line of reasoning is enough.


