Iron Law: Never hardcode colors, spacing, or typography — always use design tokens; run /lint-design-system before declaring any UI change complete.
Design System — Unified Routing Hub
Single entry point for all design system enforcement across Flutter and Angular.
When to use: Any UI task — building screens, reviewing components, auditing design drift, or running design lint.
Routing Table
Determine the stack from file context, then load the correct references:
What are you working on?
|
+-- Flutter (lib/**/*.dart, pubspec.yaml)
| |
| +-- Tokens (colors, spacing, typography, radius)
| | → Read: .claude/skills/ui-standards-tokens/reference/ui-design-tokens.md
| |
| +-- Accessibility (semantics, focus, contrast)
| | → Read: .claude/skills/ui-standards-tokens/reference/ui-accessibility-patterns.md
| |
| +-- Polish (animations, glassmorphism, theme extensions)
| → Read: .claude/skills/flutter-mobile/reference/flutter-design-polish.md
|
+-- Angular (src/app/**/*.ts|html|scss)
| |
| +-- Component styling (daisyUI classes, semantic tokens)
| | → Read: .claude/skills/angular-spa/reference/daisyui-v5-components.md
| |
| +-- Tailwind config (spacing, breakpoints, CSS vars)
| | → Read: .claude/skills/angular-spa/reference/tailwind-v4-config.md
| |
| +-- Conventions (design principles, form patterns)
| | → Read: .claude/skills/angular-spa/reference/angular-conventions.md
| |
| +-- Animations (timing, keyframes, reduced motion)
| → Read: .claude/skills/angular-spa/reference/animations.md
|
+-- Cross-stack (interaction contracts, visual direction)
|
+-- Surface/interaction contracts (modals, forms, lists, errors)
| → Read: .claude/skills/design-system/reference/interaction-contracts.md
|
+-- Visual design direction (anti-patterns, typography philosophy)
→ Read: .claude/skills/frontend-design/reference/frontend-design-principles.md
Design Rules — Hard Policy (Both Stacks)
These are non-negotiable. Violations are caught by hookify rules at write-time.
Colors
- NEVER hardcode hex values (
#3b82f6, Color(0xFF...))
- NEVER use
rgb(), rgba(), hsl(), hsla() literals
- Flutter: Use
Theme.of(context).colorScheme.*
- Angular: Use daisyUI semantic tokens (
bg-primary, text-base-content)
Spacing
- NEVER use raw numeric spacing (
EdgeInsets.all(16), mt-3)
- Flutter: Use
AppSpacing.xs/sm/md/lg/xl/xxl
- Angular: Use Tailwind semantic scale or daisyUI component spacing
Typography
- NEVER use raw font sizes (
TextStyle(fontSize: 14), text-[14px])
- Flutter: Use
Theme.of(context).textTheme.*
- Angular: Use Tailwind typography scale (
text-sm, text-lg, text-xl)
Forms
- NEVER use bare
<input>, <select>, <textarea> without framework bindings
- Angular: Use daisyUI form classes + reactive form
formControlName
- Flutter: Use shared form field wrapper widgets
Touch Targets
- Minimum 48dp (Flutter) / 44px (Angular) for all interactive elements
Inline Styles
- NEVER use
style="..." in Angular templates — use Tailwind utilities or SCSS
- NEVER use inline
Style widgets in Flutter — use theme extensions
Machine Enforcement
Hookify Rules (fire on every Write/Edit by Claude)
| Rule |
Stack |
What It Catches |
hookify.design-no-hardcoded-colors-dart |
Flutter |
Color(0xFF...), Colors.blue |
hookify.design-no-raw-spacing-dart |
Flutter |
EdgeInsets.all(16), SizedBox(height: 8) |
hookify.design-no-raw-textstyle-dart |
Flutter |
TextStyle(fontSize: N) |
hookify.design-no-hex-angular |
Angular |
bg-[#...], color: #..., rgb(), hsl() |
hookify.design-no-raw-spacing-angular |
Angular |
mt-3, px-4, gap-2 |
hookify.design-no-raw-typography-angular |
Angular |
text-[14px], font-[...], font-size: N |
hookify.design-no-raw-form-inputs |
Angular |
bare <input>, <select> without formControl |
All rules respect // ignore-design: [reason] exception markers.
Lint Commands
| Command |
Scope |
/lint-design-system |
Orchestrator — runs all checks for detected stack(s) |
dart analyze |
Flutter static analysis |
ng lint |
Angular static analysis |
Quality Gate
Before declaring any UI work done, these must pass (from verification-and-reporting.md):
Exception Policy
When a design rule must be violated intentionally:
- Add inline marker:
// ignore-design: [short reason] or <!-- ignore-design: [reason] -->
- Reason must explain WHY (e.g., "platform-specific iOS styling", "third-party widget constraint")
- Exceptions are reviewed like code debt
- Periodically audit: search for
ignore-design and remove stale exceptions
- If 5+ exceptions accumulate in one file → the design system may need extending, flag it
Scope & Rationale
What We Enforce
| Surface |
Status |
Rationale |
| Logged-in app screens (Flutter + Angular) |
ENFORCED |
Primary user experience — consistency here drives retention and trust |
| Shared/reusable components |
ENFORCED |
Foundation — drift here cascades everywhere |
| Theme definitions |
ENFORCED |
Single source of truth for tokens |
What We Defer
| Surface |
Status |
Rationale |
| Admin panels / internal tools |
DEFERRED |
Lower user impact — enforce when dedicated redesign pass happens |
| Legacy/migration pages |
DEFERRED |
Will be replaced — enforce on new version only |
| Marketing / landing pages |
DEFERRED |
Often need custom creative direction that conflicts with app tokens |
| Test files |
EXCLUDED |
Test code can use raw values for assertion clarity |
Generated code (*.g.dart, *.freezed.dart) |
EXCLUDED |
Machine-generated — not human-authored |
File Path Scope
| Stack |
Included |
Excluded |
| Flutter |
lib/ |
test/, *.g.dart, *.freezed.dart, build output |
| Angular |
src/app/ |
node_modules/, *.spec.ts, config files |
Visual Audit — 10-Dimension Scoring
Score the current UI across these 10 dimensions (0–10 each). For each dimension provide: score, specific file:line example, and a concrete fix.
- Color consistency — Are colors using theme tokens (
bg-primary, colorScheme.primary) or hardcoded hex values (Color(0xFF3b82f6), #3b82f6 in SCSS)?
- Typography hierarchy — Clear h1 > h2 > h3 > body > caption scale using
Theme.of(context).textTheme.* (Flutter) or Tailwind typography scale (text-sm, text-lg, text-xl) (Angular)? Or raw TextStyle(fontSize: N) / text-[14px] scattered throughout?
- Spacing rhythm — Consistent 4px/8px/16px scale via
AppSpacing.* (Flutter) or Tailwind semantic scale (Angular)? Or arbitrary EdgeInsets.all(16) / mt-3 / px-4 that break the grid?
- Component consistency — Do similar elements (buttons, cards, list items, form fields) use the same widget/component patterns, or are there one-off inline implementations?
- Responsive behavior — Fluid across breakpoints? Angular: Tailwind
sm:/md:/lg: breakpoints applied? Flutter: LayoutBuilder / MediaQuery used for adaptive layouts?
- Dark mode — Complete theme coverage using
colorScheme (Flutter) / daisyUI semantic tokens (Angular)? Or half-done with hardcoded light values that break in dark mode?
- Animation — Purposeful (entrance transitions, state changes, feedback)? Or gratuitous scroll-triggered animations on every section that distract rather than guide?
- Accessibility — Color contrast ≥ 4.5:1 for normal text / ≥ 3:1 for large text, focus states present, touch targets ≥ 48dp (Flutter) / 44px (Angular), semantic labels on interactive elements?
- Information density — Cluttered (too many competing elements) or too sparse (wasted space)? Empty states handled with meaningful UI rather than blank screens or raw
null renders?
- Polish — Hover states (Angular), loading states (
CircularProgressIndicator / skeleton screens), error states (user-visible feedback), and micro-transitions present and consistent?
Total score / 100.
- ≥ 80 — Ship-ready. Minor issues only.
- 60–79 — Polish pass needed before release.
- < 60 — Redesign required. Do not ship.
For each dimension scored below 7: file the specific file:line violation and state the concrete fix using the correct token or pattern for the stack.
AI Slop Detection
Flag these patterns immediately — they signal generic AI-generated UI with no design intention. Each flag requires the exact file:line and the replacement pattern.
| Pattern |
Signal |
Replacement |
Purple-to-blue gradient as primary background (from-purple-500 to-blue-500, LinearGradient([Color(0xFF...purple), Color(0xFF...blue)])) |
Generic AI hero aesthetic |
Use brand color tokens from colorScheme (Flutter) or daisyUI semantic bg-primary (Angular); gradients only for deliberate decorative surfaces |
Glass morphism cards with no semantic purpose (backdrop-blur, bg-white/10, BackdropFilter on every card) |
Trendy filler masking weak content hierarchy |
Use solid surface tokens (colorScheme.surface, bg-base-100); reserve blur effects for modal overlays where focus isolation is the intent |
Excessive border-radius on everything including data tables and code blocks (rounded-2xl on <table>, BorderRadius.circular(24) on list tiles) |
Indiscriminate softening |
Apply radius intentionally: cards and buttons use AppRadius.* tokens; data-dense surfaces (tables, code) use rounded-none or rounded-sm |
Scroll-triggered animations on every section (IntersectionObserver on 10+ elements, AnimationController firing on every scroll event) |
Cargo-culted engagement pattern |
Use entrance animations only for primary hero or key CTAs; all other content renders immediately; see flutter-design-polish.md and animations.md for approved patterns |
Generic centered hero: [Big Title] [Subtitle] [Primary Button] [Secondary Button] over gradient background |
Uncustomized template output |
Differentiate with brand-specific layout, real imagery or illustration, and a single focused CTA |
| Inter / Roboto / Space Grotesk as the only fonts with no display personality (same weight, same size hierarchy everywhere) |
Default font stack, zero typographic intention |
Add a display typeface for headings that matches brand tone; establish a deliberate type scale with size AND weight contrast between levels |
Symmetrical 3-column feature card grid: icon + title + body, all equal height, all centered (grid-cols-3, Column(children: [Icon, Text, Text]) × N) |
The AI feature section template |
Vary layout rhythm — mix wide + narrow cards, use real screenshots or illustrations instead of icons, break the grid for emphasis |
Shadow stacking — shadow-lg on a container that already has shadow-md, nested inside shadow-sm (BoxShadow arrays with 3+ layers on the same widget) |
Depth miscalculation, not intentional elevation |
Use a single elevation token per surface level; Flutter: one BoxShadow per widget matching colorScheme.shadow; Angular: one daisyUI shadow utility per element |
1---2name: design-system3description: Unified design system enforcement for Flutter and Angular. Routes all UI tasks through the correct stack-specific tokens, rules, and interaction contracts. Use when auditing UI compliance, reviewing design consistency, or building any user-facing surface.4---56**Iron Law:** Never hardcode colors, spacing, or typography — always use design tokens; run /lint-design-system before declaring any UI change complete.78# Design System — Unified Routing Hub910Single entry point for all design system enforcement across Flutter and Angular.1112**When to use:** Any UI task — building screens, reviewing components, auditing design drift, or running design lint.1314## Routing Table1516Determine the stack from file context, then load the correct references:1718```19What are you working on?20 |21 +-- Flutter (lib/**/*.dart, pubspec.yaml)22 | |23 | +-- Tokens (colors, spacing, typography, radius)24 | | → Read: .claude/skills/ui-standards-tokens/reference/ui-design-tokens.md25 | |26 | +-- Accessibility (semantics, focus, contrast)27 | | → Read: .claude/skills/ui-standards-tokens/reference/ui-accessibility-patterns.md28 | |29 | +-- Polish (animations, glassmorphism, theme extensions)30 | → Read: .claude/skills/flutter-mobile/reference/flutter-design-polish.md31 |32 +-- Angular (src/app/**/*.ts|html|scss)33 | |34 | +-- Component styling (daisyUI classes, semantic tokens)35 | | → Read: .claude/skills/angular-spa/reference/daisyui-v5-components.md36 | |37 | +-- Tailwind config (spacing, breakpoints, CSS vars)38 | | → Read: .claude/skills/angular-spa/reference/tailwind-v4-config.md39 | |40 | +-- Conventions (design principles, form patterns)41 | | → Read: .claude/skills/angular-spa/reference/angular-conventions.md42 | |43 | +-- Animations (timing, keyframes, reduced motion)44 | → Read: .claude/skills/angular-spa/reference/animations.md45 |46 +-- Cross-stack (interaction contracts, visual direction)47 |48 +-- Surface/interaction contracts (modals, forms, lists, errors)49 | → Read: .claude/skills/design-system/reference/interaction-contracts.md50 |51 +-- Visual design direction (anti-patterns, typography philosophy)52 → Read: .claude/skills/frontend-design/reference/frontend-design-principles.md53```5455## Design Rules — Hard Policy (Both Stacks)5657These are non-negotiable. Violations are caught by hookify rules at write-time.5859### Colors60- **NEVER** hardcode hex values (`#3b82f6`, `Color(0xFF...)`)61- **NEVER** use `rgb()`, `rgba()`, `hsl()`, `hsla()` literals62- **Flutter:** Use `Theme.of(context).colorScheme.*`63- **Angular:** Use daisyUI semantic tokens (`bg-primary`, `text-base-content`)6465### Spacing66- **NEVER** use raw numeric spacing (`EdgeInsets.all(16)`, `mt-3`)67- **Flutter:** Use `AppSpacing.xs/sm/md/lg/xl/xxl`68- **Angular:** Use Tailwind semantic scale or daisyUI component spacing6970### Typography71- **NEVER** use raw font sizes (`TextStyle(fontSize: 14)`, `text-[14px]`)72- **Flutter:** Use `Theme.of(context).textTheme.*`73- **Angular:** Use Tailwind typography scale (`text-sm`, `text-lg`, `text-xl`)7475### Forms76- **NEVER** use bare `<input>`, `<select>`, `<textarea>` without framework bindings77- **Angular:** Use daisyUI form classes + reactive form `formControlName`78- **Flutter:** Use shared form field wrapper widgets7980### Touch Targets81- **Minimum 48dp** (Flutter) / **44px** (Angular) for all interactive elements8283### Inline Styles84- **NEVER** use `style="..."` in Angular templates — use Tailwind utilities or SCSS85- **NEVER** use inline `Style` widgets in Flutter — use theme extensions8687## Machine Enforcement8889### Hookify Rules (fire on every Write/Edit by Claude)9091| Rule | Stack | What It Catches |92|------|-------|-----------------|93| `hookify.design-no-hardcoded-colors-dart` | Flutter | `Color(0xFF...)`, `Colors.blue` |94| `hookify.design-no-raw-spacing-dart` | Flutter | `EdgeInsets.all(16)`, `SizedBox(height: 8)` |95| `hookify.design-no-raw-textstyle-dart` | Flutter | `TextStyle(fontSize: N)` |96| `hookify.design-no-hex-angular` | Angular | `bg-[#...]`, `color: #...`, `rgb()`, `hsl()` |97| `hookify.design-no-raw-spacing-angular` | Angular | `mt-3`, `px-4`, `gap-2` |98| `hookify.design-no-raw-typography-angular` | Angular | `text-[14px]`, `font-[...]`, `font-size: N` |99| `hookify.design-no-raw-form-inputs` | Angular | bare `<input>`, `<select>` without `formControl` |100101All rules respect `// ignore-design: [reason]` exception markers.102103### Lint Commands104105| Command | Scope |106|---------|-------|107| `/lint-design-system` | Orchestrator — runs all checks for detected stack(s) |108| `dart analyze` | Flutter static analysis |109| `ng lint` | Angular static analysis |110111### Quality Gate112113Before declaring any UI work done, these must pass (from `verification-and-reporting.md`):114115- [ ] No hardcoded colors — all colors use theme tokens116- [ ] No raw spacing values — all spacing uses semantic tokens117- [ ] No inline TextStyles — all typography uses theme text styles118- [ ] Touch targets >= 48dp (Flutter) / 44px (Angular)119- [ ] `/lint-design-system` run with zero violations120- [ ] Exception markers (`// ignore-design: [reason]`) reviewed and justified121122## Exception Policy123124When a design rule must be violated intentionally:1251261. Add inline marker: `// ignore-design: [short reason]` or `<!-- ignore-design: [reason] -->`1272. Reason must explain WHY (e.g., "platform-specific iOS styling", "third-party widget constraint")1283. Exceptions are reviewed like code debt1294. Periodically audit: search for `ignore-design` and remove stale exceptions1305. If 5+ exceptions accumulate in one file → the design system may need extending, flag it131132## Scope & Rationale133134### What We Enforce135136| Surface | Status | Rationale |137|---------|--------|-----------|138| **Logged-in app screens** (Flutter + Angular) | ENFORCED | Primary user experience — consistency here drives retention and trust |139| **Shared/reusable components** | ENFORCED | Foundation — drift here cascades everywhere |140| **Theme definitions** | ENFORCED | Single source of truth for tokens |141142### What We Defer143144| Surface | Status | Rationale |145|---------|--------|-----------|146| **Admin panels / internal tools** | DEFERRED | Lower user impact — enforce when dedicated redesign pass happens |147| **Legacy/migration pages** | DEFERRED | Will be replaced — enforce on new version only |148| **Marketing / landing pages** | DEFERRED | Often need custom creative direction that conflicts with app tokens |149| **Test files** | EXCLUDED | Test code can use raw values for assertion clarity |150| **Generated code** (`*.g.dart`, `*.freezed.dart`) | EXCLUDED | Machine-generated — not human-authored |151152### File Path Scope153154| Stack | Included | Excluded |155|-------|----------|----------|156| Flutter | `lib/` | `test/`, `*.g.dart`, `*.freezed.dart`, build output |157| Angular | `src/app/` | `node_modules/`, `*.spec.ts`, config files |158159## Visual Audit — 10-Dimension Scoring160161Score the current UI across these 10 dimensions (0–10 each). For each dimension provide: score, specific file:line example, and a concrete fix.1621631. **Color consistency** — Are colors using theme tokens (`bg-primary`, `colorScheme.primary`) or hardcoded hex values (`Color(0xFF3b82f6)`, `#3b82f6` in SCSS)?1642. **Typography hierarchy** — Clear h1 > h2 > h3 > body > caption scale using `Theme.of(context).textTheme.*` (Flutter) or Tailwind typography scale (`text-sm`, `text-lg`, `text-xl`) (Angular)? Or raw `TextStyle(fontSize: N)` / `text-[14px]` scattered throughout?1653. **Spacing rhythm** — Consistent 4px/8px/16px scale via `AppSpacing.*` (Flutter) or Tailwind semantic scale (Angular)? Or arbitrary `EdgeInsets.all(16)` / `mt-3` / `px-4` that break the grid?1664. **Component consistency** — Do similar elements (buttons, cards, list items, form fields) use the same widget/component patterns, or are there one-off inline implementations?1675. **Responsive behavior** — Fluid across breakpoints? Angular: Tailwind `sm:`/`md:`/`lg:` breakpoints applied? Flutter: `LayoutBuilder` / `MediaQuery` used for adaptive layouts?1686. **Dark mode** — Complete theme coverage using `colorScheme` (Flutter) / daisyUI semantic tokens (Angular)? Or half-done with hardcoded light values that break in dark mode?1697. **Animation** — Purposeful (entrance transitions, state changes, feedback)? Or gratuitous scroll-triggered animations on every section that distract rather than guide?1708. **Accessibility** — Color contrast ≥ 4.5:1 for normal text / ≥ 3:1 for large text, focus states present, touch targets ≥ 48dp (Flutter) / 44px (Angular), semantic labels on interactive elements?1719. **Information density** — Cluttered (too many competing elements) or too sparse (wasted space)? Empty states handled with meaningful UI rather than blank screens or raw `null` renders?17210. **Polish** — Hover states (Angular), loading states (`CircularProgressIndicator` / skeleton screens), error states (user-visible feedback), and micro-transitions present and consistent?173174**Total score / 100.**175- **≥ 80** — Ship-ready. Minor issues only.176- **60–79** — Polish pass needed before release.177- **< 60** — Redesign required. Do not ship.178179For each dimension scored below 7: file the specific file:line violation and state the concrete fix using the correct token or pattern for the stack.180181## AI Slop Detection182183Flag these patterns immediately — they signal generic AI-generated UI with no design intention. Each flag requires the exact file:line and the replacement pattern.184185| Pattern | Signal | Replacement |186|---------|--------|-------------|187| Purple-to-blue gradient as primary background (`from-purple-500 to-blue-500`, `LinearGradient([Color(0xFF...purple), Color(0xFF...blue)])`) | Generic AI hero aesthetic | Use brand color tokens from `colorScheme` (Flutter) or daisyUI semantic `bg-primary` (Angular); gradients only for deliberate decorative surfaces |188| Glass morphism cards with no semantic purpose (`backdrop-blur`, `bg-white/10`, `BackdropFilter` on every card) | Trendy filler masking weak content hierarchy | Use solid surface tokens (`colorScheme.surface`, `bg-base-100`); reserve blur effects for modal overlays where focus isolation is the intent |189| Excessive border-radius on everything including data tables and code blocks (`rounded-2xl` on `<table>`, `BorderRadius.circular(24)` on list tiles) | Indiscriminate softening | Apply radius intentionally: cards and buttons use `AppRadius.*` tokens; data-dense surfaces (tables, code) use `rounded-none` or `rounded-sm` |190| Scroll-triggered animations on every section (`IntersectionObserver` on 10+ elements, `AnimationController` firing on every scroll event) | Cargo-culted engagement pattern | Use entrance animations only for primary hero or key CTAs; all other content renders immediately; see `flutter-design-polish.md` and `animations.md` for approved patterns |191| Generic centered hero: `[Big Title] [Subtitle] [Primary Button] [Secondary Button]` over gradient background | Uncustomized template output | Differentiate with brand-specific layout, real imagery or illustration, and a single focused CTA |192| Inter / Roboto / Space Grotesk as the only fonts with no display personality (same weight, same size hierarchy everywhere) | Default font stack, zero typographic intention | Add a display typeface for headings that matches brand tone; establish a deliberate type scale with size AND weight contrast between levels |193| Symmetrical 3-column feature card grid: icon + title + body, all equal height, all centered (`grid-cols-3`, `Column(children: [Icon, Text, Text])` × N) | The AI feature section template | Vary layout rhythm — mix wide + narrow cards, use real screenshots or illustrations instead of icons, break the grid for emphasis |194| Shadow stacking — `shadow-lg` on a container that already has `shadow-md`, nested inside `shadow-sm` (`BoxShadow` arrays with 3+ layers on the same widget) | Depth miscalculation, not intentional elevation | Use a single elevation token per surface level; Flutter: one `BoxShadow` per widget matching `colorScheme.shadow`; Angular: one daisyUI shadow utility per element |