qualia-framework 3.2.0 → 3.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +3 -4
- package/README.md +10 -5
- package/agents/planner.md +52 -0
- package/agents/verifier.md +180 -32
- package/bin/cli.js +403 -9
- package/bin/install.js +118 -65
- package/bin/qualia-ui.js +11 -11
- package/bin/state.js +200 -6
- package/bin/statusline.js +4 -4
- package/docs/erp-contract.md +161 -0
- package/hooks/branch-guard.js +23 -2
- package/hooks/migration-guard.js +23 -0
- package/hooks/pre-compact.js +20 -0
- package/hooks/pre-deploy-gate.js +39 -0
- package/hooks/pre-push.js +20 -0
- package/hooks/session-start.js +16 -43
- package/package.json +5 -4
- package/rules/infrastructure.md +87 -0
- package/skills/qualia/SKILL.md +1 -0
- package/skills/qualia-build/SKILL.md +18 -0
- package/skills/qualia-design/SKILL.md +14 -8
- package/skills/qualia-help/SKILL.md +60 -0
- package/skills/qualia-learn/SKILL.md +27 -4
- package/skills/qualia-polish/SKILL.md +167 -117
- package/skills/qualia-report/SKILL.md +17 -8
- package/skills/qualia-review/SKILL.md +126 -41
- package/skills/qualia-test/SKILL.md +134 -0
- package/skills/qualia-verify/SKILL.md +1 -1
- package/templates/DESIGN.md +440 -102
- package/templates/help.html +476 -0
- package/templates/plan.md +14 -0
- package/tests/bin.test.sh +20 -6
- package/tests/hooks.test.sh +76 -7
- package/tests/runner.js +1915 -0
- package/tests/state.test.sh +189 -11
|
@@ -25,7 +25,7 @@ node ~/.claude/bin/qualia-ui.js banner design
|
|
|
25
25
|
cat .planning/DESIGN.md 2>/dev/null || echo "NO_DESIGN"
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
-
If DESIGN.md exists →
|
|
28
|
+
If DESIGN.md exists → it is law. Use exact values from sections 1-9 (Visual Theme, Color Palette, Typography, Components, Layout, Depth, Do's/Don'ts, Responsive, Agent Prompt Guide). If not → use Qualia defaults from `rules/frontend.md`: distinctive fonts, sharp accents, layered backgrounds, no card grids, no blue-purple gradients, full-width layouts.
|
|
29
29
|
|
|
30
30
|
### 2. Find Target Files
|
|
31
31
|
|
|
@@ -41,19 +41,25 @@ Evaluate each file on: AI slop detection, visual hierarchy, typography, color, s
|
|
|
41
41
|
|
|
42
42
|
### 4. Fix Everything
|
|
43
43
|
|
|
44
|
-
|
|
44
|
+
Use exact values from DESIGN.md when available. Sections map to fixes:
|
|
45
45
|
|
|
46
|
-
**
|
|
46
|
+
**Typography (§3):** Apply fonts from hierarchy table. Replace any generic fonts (Inter, Arial) with project fonts. Use exact weights, sizes, letter-spacing from the table. Body line-height 1.5-1.7.
|
|
47
47
|
|
|
48
|
-
**
|
|
48
|
+
**Color (§2):** Apply palette from CSS variables. Replace scattered hex values with `var(--color-*)`. Verify contrast ratios listed in DESIGN.md.
|
|
49
49
|
|
|
50
|
-
**
|
|
50
|
+
**Components (§4):** Match button, card, input, badge specs exactly — padding, radius, shadow, hover states.
|
|
51
51
|
|
|
52
|
-
**
|
|
52
|
+
**Layout (§5):** Full-width with fluid padding `clamp(1rem, 5vw, 4rem)`. Apply spacing scale. NO hardcoded max-width caps. Prose gets `max-width: 65ch`.
|
|
53
53
|
|
|
54
|
-
**
|
|
54
|
+
**Depth (§6):** Apply shadow levels from elevation table. Use brand-tinted shadows, not neutral gray.
|
|
55
55
|
|
|
56
|
-
**
|
|
56
|
+
**Motion (§Motion):** CSS transitions 200-300ms on hover/focus. Staggered entrance animations. `prefers-reduced-motion` respected.
|
|
57
|
+
|
|
58
|
+
**States:** Loading skeleton/spinner on async ops. Error states on data fetches. Empty states on lists. Hover/focus/active/disabled on every interactive element.
|
|
59
|
+
|
|
60
|
+
**Responsive (§8):** Apply collapsing strategy from table. Mobile-first. Touch targets 44x44px min. No horizontal scroll.
|
|
61
|
+
|
|
62
|
+
**Anti-Slop (§12):** Run grep patterns from the detection table. Every match = mandatory fix.
|
|
57
63
|
|
|
58
64
|
**Kill:** Card grids → varied layouts. Generic heroes → distinctive. Blue-purple gradients → brand colors. Static pages → purposeful motion. Fixed widths → fluid.
|
|
59
65
|
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: qualia-help
|
|
3
|
+
description: "Open the Qualia Framework reference guide in the browser. A beautiful themed HTML page with all commands, rules, services, and the road. Trigger on 'help', 'how does this work', 'show me the commands', 'qualia help', 'reference'."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# /qualia-help — Framework Reference
|
|
7
|
+
|
|
8
|
+
Opens a Qualia-themed HTML reference guide in your default browser.
|
|
9
|
+
|
|
10
|
+
## Process
|
|
11
|
+
|
|
12
|
+
### 1. Generate the HTML
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
# Read the template and inject the current version
|
|
16
|
+
VERSION=$(node -e "console.log(require(require('os').homedir() + '/.claude/.qualia-config.json').version || 'v3')" 2>/dev/null || echo "v3")
|
|
17
|
+
TEMPLATE="$HOME/.claude/qualia-templates/help.html"
|
|
18
|
+
OUTPUT="/tmp/qualia-help.html"
|
|
19
|
+
|
|
20
|
+
# If template doesn't exist, check the framework install
|
|
21
|
+
if [ ! -f "$TEMPLATE" ]; then
|
|
22
|
+
TEMPLATE="$(dirname "$(dirname "$(which qualia-framework 2>/dev/null || echo '')")")/templates/help.html"
|
|
23
|
+
fi
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### 2. Inject version and open
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
# Replace {{VERSION}} placeholder with actual version
|
|
30
|
+
sed "s/{{VERSION}}/$VERSION/g" "$TEMPLATE" > "$OUTPUT"
|
|
31
|
+
|
|
32
|
+
# Open in default browser (cross-platform)
|
|
33
|
+
if command -v xdg-open &>/dev/null; then
|
|
34
|
+
xdg-open "$OUTPUT" # Linux
|
|
35
|
+
elif command -v open &>/dev/null; then
|
|
36
|
+
open "$OUTPUT" # macOS
|
|
37
|
+
elif command -v start &>/dev/null; then
|
|
38
|
+
start "$OUTPUT" # Windows (Git Bash)
|
|
39
|
+
else
|
|
40
|
+
echo "Open this file in your browser: $OUTPUT"
|
|
41
|
+
fi
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### 3. Confirm
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
node ~/.claude/bin/qualia-ui.js banner router
|
|
48
|
+
node ~/.claude/bin/qualia-ui.js ok "Reference guide opened in browser"
|
|
49
|
+
node ~/.claude/bin/qualia-ui.js info "File: /tmp/qualia-help.html"
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
If the browser does not open automatically, tell the user the file path so they can open it manually.
|
|
53
|
+
|
|
54
|
+
## Notes
|
|
55
|
+
|
|
56
|
+
- The HTML file is self-contained — no external dependencies except Google Fonts
|
|
57
|
+
- Works offline after first load (fonts cache)
|
|
58
|
+
- Qualia-themed: dark background, teal accents, Outfit + Inter fonts
|
|
59
|
+
- Shows: The Road, all commands grouped, verification scoring, rules, stack, GitHub orgs
|
|
60
|
+
- Version is injected dynamically from .qualia-config.json
|
|
@@ -46,17 +46,40 @@ What did you learn?
|
|
|
46
46
|
3. Client preference — client-specific requirement
|
|
47
47
|
```
|
|
48
48
|
|
|
49
|
-
### 2.
|
|
49
|
+
### 2. Check for Duplicates
|
|
50
|
+
|
|
51
|
+
Before saving, check if a similar entry already exists:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
# Search for the title (case-insensitive substring match)
|
|
55
|
+
grep -i "{title keywords}" ~/.claude/knowledge/{type}.md 2>/dev/null
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
If a near-match exists (title is similar to an existing entry):
|
|
59
|
+
- Show the existing entry to the user
|
|
60
|
+
- Ask: "A similar entry exists. Update it, create a new one, or skip?"
|
|
61
|
+
- If update: replace the existing entry. If new: append. If skip: done.
|
|
62
|
+
|
|
63
|
+
### 3. Format Entry
|
|
64
|
+
|
|
65
|
+
Each entry gets a unique ID and ISO timestamp for dedup and ordering:
|
|
50
66
|
|
|
51
67
|
```markdown
|
|
52
|
-
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
### {Title}
|
|
72
|
+
**ID:** {random 8-char hex, e.g. a3f7c1e9}
|
|
73
|
+
**Date:** {ISO 8601, e.g. 2026-04-11}
|
|
53
74
|
**Project:** {current project name or "general"}
|
|
54
75
|
**Context:** {brief context — what you were building when you learned this}
|
|
55
76
|
|
|
56
77
|
{The learning — be specific enough that future-you understands without context}
|
|
57
78
|
```
|
|
58
79
|
|
|
59
|
-
###
|
|
80
|
+
### 4. Append to Knowledge File
|
|
81
|
+
|
|
82
|
+
Append-only — never overwrite the file, always add at the end:
|
|
60
83
|
|
|
61
84
|
```bash
|
|
62
85
|
# Append to the right file
|
|
@@ -67,7 +90,7 @@ echo "{formatted entry}" >> ~/.claude/knowledge/{type}.md
|
|
|
67
90
|
- Fix → `~/.claude/knowledge/common-fixes.md`
|
|
68
91
|
- Client pref → `~/.claude/knowledge/client-prefs.md`
|
|
69
92
|
|
|
70
|
-
###
|
|
93
|
+
### 5. Confirm
|
|
71
94
|
|
|
72
95
|
```
|
|
73
96
|
⬢ Saved to {file}
|
|
@@ -1,11 +1,24 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: qualia-polish
|
|
3
|
-
description: "Design and UX pass —
|
|
3
|
+
description: "Design and UX pass — anti-AI-slop, genuine craft, responsive, accessible. Run after all phases are verified."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# /qualia-polish — Design Pass
|
|
7
7
|
|
|
8
|
-
Run after all feature phases are verified.
|
|
8
|
+
Makes it look like a human designer built it. Kills AI slop. Run after all feature phases are verified.
|
|
9
|
+
|
|
10
|
+
## The Standard
|
|
11
|
+
|
|
12
|
+
Every site Qualia ships must feel **designed, not generated.** AI-generated sites have tells:
|
|
13
|
+
- Identical card grids with rounded corners and soft shadows
|
|
14
|
+
- Blue-purple gradients on everything
|
|
15
|
+
- Inter/system-ui font with no hierarchy
|
|
16
|
+
- Generic hero with centered text and a stock gradient background
|
|
17
|
+
- Fixed-width containers leaving dead space on wide screens
|
|
18
|
+
- No motion, no personality, no opinion
|
|
19
|
+
- Perfect symmetry everywhere (real design has tension)
|
|
20
|
+
|
|
21
|
+
**Kill all of these.** A Qualia site should make someone ask "who designed this?" — not "which template is this?"
|
|
9
22
|
|
|
10
23
|
## Process
|
|
11
24
|
|
|
@@ -19,139 +32,176 @@ node ~/.claude/bin/qualia-ui.js banner polish
|
|
|
19
32
|
cat .planning/DESIGN.md 2>/dev/null || echo "NO_DESIGN"
|
|
20
33
|
```
|
|
21
34
|
|
|
22
|
-
If DESIGN.md exists →
|
|
35
|
+
If DESIGN.md exists → it's the standard. Read ALL 12 sections. Key sections for polish:
|
|
36
|
+
- §1 Visual Theme — the feel and signature details
|
|
37
|
+
- §2 Color Palette — exact hex values, CSS variables, contrast ratios
|
|
38
|
+
- §3 Typography — hierarchy table with exact sizes/weights/spacing
|
|
39
|
+
- §4 Components — exact button/card/input/badge specs
|
|
40
|
+
- §5 Layout — spacing scale, grid strategy
|
|
41
|
+
- §6 Depth & Elevation — shadow levels with exact rgba values
|
|
42
|
+
- §7 Do's/Don'ts — brand-specific guardrails
|
|
43
|
+
- §9 Agent Prompt Guide — quick reference for common patterns
|
|
44
|
+
- §10 Accessibility — WCAG checklist
|
|
45
|
+
- §11 Hardening — stress-test criteria
|
|
46
|
+
- §12 Anti-Slop Detection — grep patterns for automated checks
|
|
47
|
+
|
|
48
|
+
If no DESIGN.md → use `rules/frontend.md` defaults.
|
|
23
49
|
|
|
24
50
|
Read EVERY frontend file before modifying. No blind edits.
|
|
25
51
|
|
|
26
|
-
### 1.
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
**Typography:**
|
|
31
|
-
- [ ] No generic fonts (Inter, Roboto, Arial, system-ui, Space Grotesk)
|
|
32
|
-
- [ ] Proper type scale with clear hierarchy (display → heading → body → caption)
|
|
33
|
-
- [ ] Body text: 16px+, line-height 1.5–1.7
|
|
34
|
-
- [ ] Headings: tighter line-height (1.1–1.3), negative letter-spacing for large sizes
|
|
35
|
-
- [ ] Prose max-width: 65ch
|
|
36
|
-
- [ ] Font weights used for hierarchy (Regular, Medium, Semibold, Bold)
|
|
37
|
-
|
|
38
|
-
**Color & Contrast:**
|
|
39
|
-
- [ ] Cohesive palette via CSS variables (not scattered hex values)
|
|
40
|
-
- [ ] All text passes WCAG AA contrast (4.5:1 normal, 3:1 large)
|
|
41
|
-
- [ ] CTA buttons use accent color — stand out from the page
|
|
42
|
-
- [ ] No blue-purple gradients, no rainbow palettes
|
|
43
|
-
- [ ] Dark mode: rethought surfaces (not just inverted)
|
|
44
|
-
- [ ] Semantic colors used consistently (success=green, error=red, warning=amber)
|
|
45
|
-
|
|
46
|
-
**Layout & Spacing:**
|
|
47
|
-
- [ ] Full-width fluid layouts — no hardcoded max-width caps
|
|
48
|
-
- [ ] 8px spacing grid followed consistently
|
|
49
|
-
- [ ] Tight spacing within groups, generous between sections
|
|
50
|
-
- [ ] Fluid padding: `clamp(1rem, 5vw, 4rem)` horizontal
|
|
51
|
-
- [ ] No identical card grids — varied visual hierarchy
|
|
52
|
-
- [ ] No generic heroes — purposeful, distinctive
|
|
53
|
-
|
|
54
|
-
**Interactive States:**
|
|
55
|
-
- [ ] Every button/link: hover (color shift, 150ms), focus (visible ring), active (press feedback), disabled
|
|
56
|
-
- [ ] Loading: skeleton or spinner on all async operations
|
|
57
|
-
- [ ] Empty: helpful message + action on empty lists/data
|
|
58
|
-
- [ ] Error: user-friendly message + recovery action on failed fetches
|
|
59
|
-
- [ ] Form validation: inline errors with `aria-describedby`
|
|
60
|
-
|
|
61
|
-
**Motion:**
|
|
62
|
-
- [ ] Hover/focus: 150–200ms transitions
|
|
63
|
-
- [ ] Page load: staggered entrance animations (50–80ms delay)
|
|
64
|
-
- [ ] Expand/collapse: 250ms ease-in-out
|
|
65
|
-
- [ ] `prefers-reduced-motion` respected (no animation for users who opt out)
|
|
66
|
-
- [ ] No jank: transforms and opacity only for animated properties
|
|
67
|
-
|
|
68
|
-
**Accessibility:**
|
|
69
|
-
- [ ] Semantic HTML: `nav`, `main`, `section`, `article`, `header`, `footer`
|
|
70
|
-
- [ ] One `h1` per page, sequential heading hierarchy
|
|
71
|
-
- [ ] All images: descriptive `alt` (or `alt=""` + `aria-hidden` if decorative)
|
|
72
|
-
- [ ] All form inputs: visible `<label>` with `htmlFor` — not placeholder-only
|
|
73
|
-
- [ ] All interactive elements: keyboard accessible (Tab/Enter/Escape)
|
|
74
|
-
- [ ] Touch targets: 44px minimum
|
|
75
|
-
- [ ] Skip link: `<a href="#main">` as first focusable element
|
|
76
|
-
- [ ] No `outline: none` without focus replacement
|
|
77
|
-
- [ ] `<html lang="en">` set
|
|
78
|
-
- [ ] Color not sole information carrier — icons/text as supplements
|
|
79
|
-
|
|
80
|
-
**Responsive:**
|
|
81
|
-
- [ ] Mobile-first approach (base styles for mobile, min-width breakpoints for larger)
|
|
82
|
-
- [ ] No horizontal scroll at 320px
|
|
83
|
-
- [ ] Navigation: hamburger on mobile, expanded on desktop
|
|
84
|
-
- [ ] Touch targets adequate on mobile (44px min)
|
|
85
|
-
- [ ] Fluid typography with `clamp()`
|
|
86
|
-
- [ ] Images: `max-width: 100%`, responsive srcset where needed
|
|
87
|
-
- [ ] Tables: card view or horizontal scroll on mobile
|
|
88
|
-
|
|
89
|
-
**Performance:**
|
|
90
|
-
- [ ] Server Components by default — `'use client'` only when needed
|
|
91
|
-
- [ ] Images via `next/image` with width/height
|
|
92
|
-
- [ ] No barrel file imports — direct imports from source
|
|
93
|
-
- [ ] Heavy components lazy-loaded with `next/dynamic`
|
|
94
|
-
- [ ] Data fetched in parallel, not sequentially
|
|
95
|
-
|
|
96
|
-
### 2. Fix Everything
|
|
97
|
-
|
|
98
|
-
Work through violations from the critique. Fix each category:
|
|
99
|
-
|
|
100
|
-
1. Typography first (sets the visual foundation)
|
|
101
|
-
2. Color & contrast (palette coherence)
|
|
102
|
-
3. Layout & spacing (structural fixes)
|
|
103
|
-
4. Interactive states (loading, empty, error, hover, focus)
|
|
104
|
-
5. Motion (transitions, entrance animations, reduced-motion)
|
|
105
|
-
6. Accessibility (semantic HTML, ARIA, keyboard, labels)
|
|
106
|
-
7. Responsive (mobile breakpoints, fluid sizing)
|
|
107
|
-
8. Performance (quick wins — image optimization, dynamic imports)
|
|
108
|
-
|
|
109
|
-
### 3. Harden
|
|
110
|
-
|
|
111
|
-
After polish, stress-test edge cases:
|
|
112
|
-
- Long text content (overflow, truncation, word-break)
|
|
113
|
-
- Extremely long usernames or email addresses
|
|
114
|
-
- Empty data everywhere simultaneously
|
|
115
|
-
- Error state on every fetch simultaneously
|
|
116
|
-
- 320px viewport width
|
|
117
|
-
- Keyboard-only navigation through entire flow
|
|
118
|
-
- Screen reader landmarks check (semantic HTML)
|
|
119
|
-
- Right-to-left text (if i18n is planned)
|
|
120
|
-
- Slow network (loading states visible, no flash of empty content)
|
|
121
|
-
|
|
122
|
-
### 4. Verify
|
|
52
|
+
### 1. AI Slop Detector
|
|
53
|
+
|
|
54
|
+
Run these checks first. Any hits = mandatory fixes.
|
|
123
55
|
|
|
124
56
|
```bash
|
|
125
|
-
|
|
57
|
+
# Generic fonts (the #1 AI tell)
|
|
58
|
+
grep -rn "Inter\|Roboto\|Arial\|Helvetica\|system-ui\|Space.Grotesk" --include="*.tsx" --include="*.css" --include="*.scss" --include="tailwind*" app/ components/ src/ 2>/dev/null | grep -v node_modules
|
|
59
|
+
|
|
60
|
+
# Hardcoded max-width containers (screams template)
|
|
61
|
+
grep -rn "max-w-7xl\|max-w-\[1200\|max-w-\[1280\|max-width.*1200\|max-width.*1280" --include="*.tsx" --include="*.css" app/ components/ src/ 2>/dev/null
|
|
62
|
+
|
|
63
|
+
# Blue-purple gradients
|
|
64
|
+
grep -rn "from-blue.*to-purple\|from-purple.*to-blue\|linear-gradient.*blue.*purple\|linear-gradient.*purple.*blue\|from-indigo.*to-violet" --include="*.tsx" --include="*.css" app/ components/ src/ 2>/dev/null
|
|
65
|
+
|
|
66
|
+
# Card grid monotony (same card component repeated in a grid)
|
|
67
|
+
grep -rn "grid-cols-3\|grid-cols-4" --include="*.tsx" app/ components/ src/ 2>/dev/null | head -5
|
|
68
|
+
|
|
69
|
+
# Generic hero patterns
|
|
70
|
+
grep -rn "text-center.*mx-auto\|Hero\|hero" --include="*.tsx" app/ components/ src/ 2>/dev/null | head -5
|
|
71
|
+
|
|
72
|
+
# Scattered hardcoded colors (no design system)
|
|
73
|
+
grep -rn "text-\[#\|bg-\[#\|border-\[#\|color:.*#\|background:.*#" --include="*.tsx" app/ components/ src/ 2>/dev/null | wc -l
|
|
126
74
|
```
|
|
127
75
|
|
|
128
|
-
|
|
76
|
+
**Every hit gets fixed.** Not flagged — fixed.
|
|
77
|
+
|
|
78
|
+
### 2. Typography Pass
|
|
79
|
+
|
|
80
|
+
**Goal:** A reader should feel the type was chosen, not defaulted.
|
|
81
|
+
|
|
82
|
+
- Pick a distinctive display font. Not Inter, not Roboto, not system. Something with character: Clash Display, Cabinet Grotesk, General Sans, Satoshi, Plus Jakarta Sans, Outfit, Sora, Manrope. Pair with a clean body font.
|
|
83
|
+
- Establish clear hierarchy: display (hero text) → h1 → h2 → h3 → body → caption
|
|
84
|
+
- Body: 16px minimum, line-height 1.5-1.7
|
|
85
|
+
- Headings: tighter line-height (1.1-1.3), negative letter-spacing (-0.02em) for display sizes
|
|
86
|
+
- Weight hierarchy: Regular (400) for body, Medium (500) for labels, Semibold (600) for headings, Bold (700) for display
|
|
87
|
+
- Prose content: `max-width: 65ch`. Everything else: fluid full-width.
|
|
88
|
+
- Use `clamp()` for fluid sizing: `clamp(2rem, 1rem + 3vw, 3.75rem)` for h1
|
|
89
|
+
|
|
90
|
+
### 3. Color & Surfaces
|
|
91
|
+
|
|
92
|
+
**Goal:** A palette that looks intentional, not random.
|
|
93
|
+
|
|
94
|
+
- Define all colors as CSS variables or Tailwind config — zero scattered hex values
|
|
95
|
+
- One dominant brand color. One sharp accent for CTAs that pops against the page.
|
|
96
|
+
- Surfaces: layer them. Background → card → elevated card. Use subtle shade differences, not just white-on-white.
|
|
97
|
+
- Dark mode (if present): rethink surfaces, don't just invert. Slightly reduce contrast. Use darker brand colors, not just white→black swap.
|
|
98
|
+
- Semantic colors with non-color indicators: success (green + checkmark), error (red + icon), warning (amber + triangle)
|
|
99
|
+
- Verify WCAG AA: 4.5:1 for normal text, 3:1 for large text (18px+ bold or 24px+)
|
|
100
|
+
|
|
101
|
+
### 4. Layout & Spacing
|
|
102
|
+
|
|
103
|
+
**Goal:** Full-width, fluid, generous. No dead space gutters.
|
|
104
|
+
|
|
105
|
+
- Full-width layouts with fluid padding: `clamp(1rem, 5vw, 4rem)` horizontal
|
|
106
|
+
- 8px spacing grid: 4, 8, 12, 16, 24, 32, 48, 64, 96
|
|
107
|
+
- Tight spacing within groups (related items). Generous spacing between sections.
|
|
108
|
+
- Break symmetry where it serves the design — offset grids, overlapping elements, diagonal flow
|
|
109
|
+
- Varied layouts: not every section should be a centered-text-with-cards-below. Use side-by-side, staggered, asymmetric, full-bleed.
|
|
110
|
+
- Section spacing: `clamp(2rem, 8vw, 6rem)` vertical padding
|
|
111
|
+
|
|
112
|
+
### 5. Interactive States
|
|
129
113
|
|
|
130
|
-
|
|
114
|
+
**Goal:** Every clickable thing responds. Every async operation shows progress.
|
|
115
|
+
|
|
116
|
+
- **Hover:** color shift or underline within 150ms ease-out. `cursor: pointer` on ALL clickables.
|
|
117
|
+
- **Focus:** visible ring (2px+ offset, contrasting color). Never `outline: none` without replacement.
|
|
118
|
+
- **Active/pressed:** subtle scale down (`transform: scale(0.98)`) or color shift.
|
|
119
|
+
- **Disabled:** opacity 0.5 + `cursor: not-allowed` + `aria-disabled="true"`
|
|
120
|
+
- **Loading:** skeleton shimmer or spinner on every async operation. Never a blank void.
|
|
121
|
+
- **Empty:** helpful message + CTA on empty lists/tables. Not just "No results."
|
|
122
|
+
- **Error:** user-friendly message + recovery action. Not raw error text. Use `aria-live="assertive"`.
|
|
123
|
+
|
|
124
|
+
### 6. Motion & Personality
|
|
125
|
+
|
|
126
|
+
**Goal:** The site feels alive, not static. But tasteful — not a circus.
|
|
127
|
+
|
|
128
|
+
- Page load: stagger children entrance (50-80ms delay between items, `fadeUp` animation, 300ms)
|
|
129
|
+
- Hover transitions: 150-200ms ease-out
|
|
130
|
+
- Section transitions: 300-500ms with `cubic-bezier(0.4, 0, 0.2, 1)`
|
|
131
|
+
- One signature motion that gives the site personality (parallax, scroll-triggered reveal, magnetic buttons, morphing shapes)
|
|
132
|
+
- **Always** `prefers-reduced-motion: reduce` — disable non-essential animation
|
|
133
|
+
- CSS-only for static sites, `motion/react` (formerly Framer Motion) for React
|
|
134
|
+
|
|
135
|
+
### 7. Accessibility (Non-Negotiable)
|
|
136
|
+
|
|
137
|
+
- Semantic HTML: `nav`, `main`, `section`, `article`, `header`, `footer` — not div soup
|
|
138
|
+
- One `h1` per page, sequential heading order (no h1 → h3 skip)
|
|
139
|
+
- All images: descriptive `alt` (or `alt=""` + `aria-hidden` if decorative)
|
|
140
|
+
- All form inputs: visible `<label>` with `htmlFor` — not placeholder-only
|
|
141
|
+
- All interactive elements: keyboard accessible (Tab, Enter, Escape, Arrow keys)
|
|
142
|
+
- Touch targets: 44x44px minimum
|
|
143
|
+
- Skip link: `<a href="#main" class="sr-only focus:not-sr-only">` as first focusable element
|
|
144
|
+
- `<html lang="en">` set
|
|
145
|
+
- Color never the sole information carrier — icons, text, patterns as supplements
|
|
146
|
+
- `aria-live="polite"` for toast notifications and dynamic content updates
|
|
147
|
+
|
|
148
|
+
### 8. Responsive (Mobile-First)
|
|
149
|
+
|
|
150
|
+
- Base styles for mobile (320px), scale up with `min-width` breakpoints
|
|
151
|
+
- Test at: 320px (small phone), 375px (iPhone), 768px (iPad), 1024px (laptop), 1440px (desktop)
|
|
152
|
+
- No horizontal scroll at any viewport
|
|
153
|
+
- Navigation: hamburger/drawer on mobile, full horizontal on desktop
|
|
154
|
+
- Stack on mobile, expand on desktop
|
|
155
|
+
- Fluid typography with `clamp()`
|
|
156
|
+
- Images: `max-width: 100%`, responsive `srcset`, `next/image` with width/height
|
|
157
|
+
- Tables: card layout or horizontal scroll on mobile
|
|
158
|
+
|
|
159
|
+
### 9. Harden (Edge Cases)
|
|
160
|
+
|
|
161
|
+
After all visual work, stress-test:
|
|
162
|
+
- Long text: does a 200-character username break the layout?
|
|
163
|
+
- Empty everywhere: all lists empty, all data missing — does it still make sense?
|
|
164
|
+
- Error everywhere: every fetch fails — are error states visible and helpful?
|
|
165
|
+
- 320px viewport: nothing overflows, nothing clips, nothing overlaps
|
|
166
|
+
- Keyboard only: Tab through the entire app — can you reach everything? Is focus visible?
|
|
167
|
+
- Slow network: are loading states visible? Does content stream in or flash?
|
|
168
|
+
|
|
169
|
+
### 10. Verify & Ship
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
npx tsc --noEmit 2>&1 | head -20
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Fix any TypeScript errors.
|
|
131
176
|
|
|
132
177
|
```bash
|
|
133
178
|
git add {changed files}
|
|
134
|
-
git commit -m "polish: design
|
|
179
|
+
git commit -m "polish: design pass — typography, color, states, motion, responsive, a11y"
|
|
135
180
|
```
|
|
136
181
|
|
|
137
182
|
```bash
|
|
138
183
|
node ~/.claude/bin/state.js transition --to polished
|
|
139
184
|
```
|
|
140
|
-
Do NOT manually edit STATE.md or tracking.json — state.js handles both.
|
|
141
|
-
|
|
142
|
-
### 6. Report
|
|
143
185
|
|
|
144
186
|
```bash
|
|
145
187
|
node ~/.claude/bin/qualia-ui.js divider
|
|
146
|
-
node ~/.claude/bin/qualia-ui.js
|
|
147
|
-
node ~/.claude/bin/qualia-ui.js ok "Typography
|
|
148
|
-
node ~/.claude/bin/qualia-ui.js ok "Color
|
|
149
|
-
node ~/.claude/bin/qualia-ui.js ok "Layout
|
|
150
|
-
node ~/.claude/bin/qualia-ui.js ok "States
|
|
151
|
-
node ~/.claude/bin/qualia-ui.js ok "Motion
|
|
152
|
-
node ~/.claude/bin/qualia-ui.js ok "Accessibility
|
|
153
|
-
node ~/.claude/bin/qualia-ui.js ok "Responsive
|
|
154
|
-
node ~/.claude/bin/qualia-ui.js ok "
|
|
155
|
-
node ~/.claude/bin/qualia-ui.js ok "Hardening — {brief}"
|
|
188
|
+
node ~/.claude/bin/qualia-ui.js ok "AI slop: killed"
|
|
189
|
+
node ~/.claude/bin/qualia-ui.js ok "Typography: {brief}"
|
|
190
|
+
node ~/.claude/bin/qualia-ui.js ok "Color: {brief}"
|
|
191
|
+
node ~/.claude/bin/qualia-ui.js ok "Layout: {brief}"
|
|
192
|
+
node ~/.claude/bin/qualia-ui.js ok "States: {brief}"
|
|
193
|
+
node ~/.claude/bin/qualia-ui.js ok "Motion: {brief}"
|
|
194
|
+
node ~/.claude/bin/qualia-ui.js ok "Accessibility: {brief}"
|
|
195
|
+
node ~/.claude/bin/qualia-ui.js ok "Responsive: {brief}"
|
|
196
|
+
node ~/.claude/bin/qualia-ui.js ok "Hardened: {brief}"
|
|
156
197
|
node ~/.claude/bin/qualia-ui.js end "POLISHED" "/qualia-ship"
|
|
157
198
|
```
|
|
199
|
+
|
|
200
|
+
## Rules
|
|
201
|
+
|
|
202
|
+
1. **Read before write.** Understand every file before changing it.
|
|
203
|
+
2. **DESIGN.md is law.** If it exists, follow it. Don't override client decisions.
|
|
204
|
+
3. **Don't break functionality.** Only change styling, never logic.
|
|
205
|
+
4. **AI slop is a bug.** Generic fonts, card grids, blue-purple gradients, centered-everything — treat these as defects, not preferences.
|
|
206
|
+
5. **TypeScript must pass** after every change.
|
|
207
|
+
6. **One commit** at the end — not per category.
|
|
@@ -73,26 +73,35 @@ git commit -m "report: session {YYYY-MM-DD}"
|
|
|
73
73
|
git push
|
|
74
74
|
```
|
|
75
75
|
|
|
76
|
-
### 5. Upload to ERP
|
|
76
|
+
### 5. Upload to ERP (if enabled)
|
|
77
77
|
|
|
78
|
-
|
|
78
|
+
Read `~/.claude/.qualia-config.json` and check the `erp` object:
|
|
79
|
+
- If `erp.enabled` is `false`, skip this step and print: "ERP upload skipped (disabled in config)."
|
|
80
|
+
- If `erp.enabled` is `true` (default) or the `erp` field is missing (backward compatibility), proceed with the upload.
|
|
79
81
|
|
|
80
82
|
```bash
|
|
81
|
-
|
|
83
|
+
# Read ERP config
|
|
84
|
+
ERP_URL=$(node -e "try{const c=JSON.parse(require('fs').readFileSync(require('os').homedir()+'/.claude/.qualia-config.json','utf8'));console.log(c.erp?.url||'https://portal.qualiasolutions.net')}catch{console.log('https://portal.qualiasolutions.net')}")
|
|
85
|
+
ERP_ENABLED=$(node -e "try{const c=JSON.parse(require('fs').readFileSync(require('os').homedir()+'/.claude/.qualia-config.json','utf8'));console.log(c.erp?.enabled!==false)}catch{console.log('true')}")
|
|
86
|
+
|
|
82
87
|
API_KEY=$(cat ~/.claude/.erp-api-key 2>/dev/null)
|
|
83
88
|
REPORT_FILE=".planning/reports/report-{date}.md"
|
|
84
89
|
EMAIL=$(git config user.email)
|
|
85
90
|
PROJECT=$(basename $(pwd))
|
|
86
91
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
+
# Only upload if ERP is enabled
|
|
93
|
+
if [ "$ERP_ENABLED" = "true" ]; then
|
|
94
|
+
curl -s -X POST "$ERP_URL/api/claude/report-upload" \
|
|
95
|
+
-H "X-API-Key: $API_KEY" \
|
|
96
|
+
-F "file=@$REPORT_FILE" \
|
|
97
|
+
-F "employee_email=$EMAIL" \
|
|
98
|
+
-F "project_name=$PROJECT"
|
|
99
|
+
fi
|
|
92
100
|
```
|
|
93
101
|
|
|
94
102
|
If the upload succeeds, print: "Report uploaded to ERP. You can now clock out."
|
|
95
103
|
If it fails (no API key, network error), print the error and tell the employee to ask Fawzi.
|
|
104
|
+
If ERP is disabled, print: "ERP upload skipped (disabled in config)."
|
|
96
105
|
|
|
97
106
|
### 6. Update State
|
|
98
107
|
|