.claude/skills/ux-principles/SKILL.md
Flutter UX/UI principles for the assistant app. Covers dark-theme colour tokens, responsive breakpoints (Flutter adaptive layouts), accessibility, Riverpod state patterns for loading/error/empty states, and platform conventions for web and macOS. Use when building or reviewing any Flutter screen or widget in app/.
npx skillsauth add cedricziel/assistant ux-principlesInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
The frontend is a Flutter 3.x application (app/) targeting web and macOS.
State is managed with Riverpod 3.x. Navigation uses go_router 17.x.
The Rust backend serves the compiled Flutter web app embedded in the binary.
The app uses a consistent dark palette. Apply these values via a ThemeData
extension or a shared AppColors class — never hard-code hex literals in
widgets.
| Token | Value | Usage |
| -------------------- | ---------------------- | ----------------------------- |
| Background (body) | #020611 | Scaffold background |
| Surface | #0a1628 | Cards, panels, dialogs |
| Surface border | #0b1b32 | Card/container borders |
| Text primary | #e5e9f0 | Headings, body text |
| Text secondary | #8aa5d8 | Labels, metadata, hints |
| Accent blue | #6ec6ff | Links, focus rings |
| Accent brand | #7aa2ff | Brand text, active indicators |
| Primary button | #2563eb | CTA buttons |
| Primary button hover | #1d4ed8 | Button hover/pressed state |
| Error background | rgba(239,68,68,0.15) | Error banners |
| Error border | rgba(239,68,68,0.3) | Error container borders |
| Error text | #fca5a5 | Error message text |
| Success | #4ade80 | Status badges, confirmations |
| Warning | #fbbf24 | Warning indicators |
Rules:
Colors.white for text — use the #e5e9f0 token.Colors.black for backgrounds — use #020611.Color.fromRGBO() or Color(0xFFrrggbb) notation for custom tokens.Three adaptive layout tiers, matching the Playwright viewport sizes:
| Tier | Width | Flutter pattern |
| ------- | ---------- | ------------------------------------------- |
| Desktop | >= 900 px | NavigationRail (left) + wide content area |
| Tablet | 640–899 px | Drawer (hamburger) + medium content |
| Mobile | < 640 px | NavigationBar (bottom tabs) + full-width |
Use LayoutBuilder or MediaQuery.of(context).size.width to switch layouts:
Widget build(BuildContext context) {
final width = MediaQuery.of(context).size.width;
if (width >= 900) return _DesktopLayout();
if (width >= 640) return _TabletLayout();
return _MobileLayout();
}
Rules:
MediaQuery.SingleChildScrollView or ListView so they work at any height.ElevatedButton, TextButton) over raw GestureDetector.Semantics labels for icon-only buttons and custom widgets.FocusNode ordering unless required.Tooltip for icon-only actions.Every async screen must handle all three states. Pattern using Riverpod:
@override
Widget build(BuildContext context, WidgetRef ref) {
final state = ref.watch(myProvider);
return state.when(
loading: () => const Center(child: CircularProgressIndicator()),
error: (err, _) => Center(child: Text('Error: $err')),
data: (items) => items.isEmpty
? const _EmptyState()
: _ContentList(items: items),
);
}
Empty state widget rules:
TextFormField inside a Form with a GlobalKey<FormState> for validation.autovalidateMode: AutovalidateMode.onUserInteraction.validator return value (not a separate overlay).ElevatedButton(
onPressed: isLoading ? null : _submit,
child: isLoading
? const SizedBox.square(dimension: 16, child: CircularProgressIndicator(strokeWidth: 2))
: const Text('Save'),
)
/ (Flutter web build).flutter_secure_storage (falls back to localStorage on web).go_router; the Rust SPA handler serves index.html for any unmatched path.⌘W, ⌘R), system font.macos_ui or native CupertinoX widgets where platform behaviour is expected (scroll physics, context menus).macos/Runner/DebugProfile.entitlements must include com.apple.security.network.client for API calls.tools
Enforces OpenAPI spec discipline when working on REST API endpoints in this project. Triggers whenever adding, modifying, or removing HTTP routes, request/response types, or API handlers in the Rust web-ui crate (`crates/web-ui`). Reminds the agent to (1) update the committed `openapi.json` spec, (2) run `make dump-openapi` to re-export the spec from the running server, and (3) run `make generate-flutter-client` to regenerate the Dart/dio client in `app/packages/assistant_api/`. Also applies when changing route parameters, status codes, or authentication on existing endpoints.
tools
Browser automation via @playwright/mcp (Microsoft). Use this when the user wants to navigate websites, fill forms, take screenshots, scrape web content, test web apps, or run any multi-step browser workflow. Requires no display (headless mode supported).
testing
A minimal example WASM skill that returns a greeting. Use to verify that the WASM execution tier is working correctly.
development
Run coding agents (Claude Code, Codex, OpenCode, or others) as background processes for programmatic control. Use when you need non-blocking execution, parallel agents, PR reviews, or long-running coding tasks. Prefer this over direct bash for any task that takes more than ~20 seconds.