@ctxr/skill-frontend-excellence 0.1.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.
@@ -0,0 +1,342 @@
1
+ # Pre-Launch Checklist
2
+
3
+ The final verification gate before any public-visible page or interface is declared complete. Run every item on every change. Treat any failure as a blocking defect.
4
+
5
+ ## How to Use This Checklist
6
+
7
+ 1. Print or pin in your editor.
8
+ 2. Walk top to bottom on every page that changed.
9
+ 3. For shared components, walk every page that consumes them.
10
+ 4. Don't skip items because "they passed last time"; regressions hide in unchanged areas.
11
+ 5. If a page genuinely doesn't apply (e.g., no forms), mark "n/a"; don't silently skip.
12
+
13
+ ## 1. Lighthouse (Production Build)
14
+
15
+ Run against the production build, not the dev server. Run mobile and desktop separately. Run at least 3 times; take the median.
16
+
17
+ ```
18
+ <framework-build>
19
+ <framework-start-prod-server> -p 3001 &
20
+ export CHROME_PATH="$(find ~/Library/Caches/ms-playwright -name 'Google Chrome for Testing' -type f 2>/dev/null | head -1)"
21
+
22
+ # Mobile
23
+ npx lighthouse "http://localhost:3001/<path>" \
24
+ --output=json --output-path=/tmp/lh-mob.json \
25
+ --chrome-flags="--headless=new --no-sandbox --disable-gpu" \
26
+ --only-categories=performance,accessibility,best-practices,seo --quiet
27
+
28
+ # Desktop
29
+ npx lighthouse "http://localhost:3001/<path>" \
30
+ --output=json --output-path=/tmp/lh-desk.json \
31
+ --preset=desktop \
32
+ --chrome-flags="--headless=new --no-sandbox --disable-gpu" \
33
+ --only-categories=performance,accessibility,best-practices,seo --quiet
34
+ ```
35
+
36
+ | Score | Mobile | Desktop |
37
+ |-------|--------|---------|
38
+ | Performance | >= 95 | >= 99 |
39
+ | Accessibility | 100 | 100 |
40
+ | Best Practices | 100 | 100 |
41
+ | SEO | 100 (or n/a for noindex pages) | 100 (or n/a for noindex pages) |
42
+
43
+ Verify each category. If any score drops below the bar, identify the failing audit and fix per [lighthouse.md](lighthouse.md).
44
+
45
+ ## 2. Core Web Vitals (Lab)
46
+
47
+ From the same Lighthouse run, verify each metric:
48
+
49
+ - [ ] LCP < 2.5s mobile, < 2.0s desktop
50
+ - [ ] CLS < 0.1 mobile, < 0.05 desktop
51
+ - [ ] TBT < 200ms mobile, < 100ms desktop
52
+ - [ ] FCP < 1.8s mobile, < 1.0s desktop
53
+ - [ ] TTFB < 800ms mobile, < 600ms desktop
54
+
55
+ INP is not in lab Lighthouse; verify in the field via `web-vitals` JS instrumentation.
56
+
57
+ ## 3. Asset Budgets
58
+
59
+ - [ ] Initial JS payload (gzipped) < budget (default 90 KB mobile / 130 KB desktop)
60
+ - [ ] Initial CSS payload (gzipped) < budget (default 25 KB mobile / 35 KB desktop)
61
+ - [ ] Above-the-fold image budget met
62
+ - [ ] <= 2 font families, <= 4 weights total
63
+ - [ ] Third-party scripts within count and main-thread time budget
64
+
65
+ If your tooling supports `bundlesize`, `size-limit`, or a custom CI check, run it. Treat budget violations as blocking.
66
+
67
+ ## 4. Accessibility
68
+
69
+ ### Automated
70
+
71
+ - [ ] Lighthouse Accessibility = 100
72
+ - [ ] axe DevTools (or `@axe-core/playwright`) shows zero violations
73
+ - [ ] HTML validates (no broken markup)
74
+
75
+ ### Manual
76
+
77
+ - [ ] Tab through the entire page in document order
78
+ - [ ] Every interactive element shows a visible focus ring with 3:1 contrast against surface and resting state
79
+ - [ ] Esc closes any open modal, popover, dropdown
80
+ - [ ] Forms: labels visible, required marked, error inline + announced, focus moves to first invalid
81
+ - [ ] Modals: focus moves in on open, trapped while open, restored to trigger on close
82
+ - [ ] Screen reader pass on the primary user flow (VoiceOver or NVDA)
83
+ - [ ] Reading order matches visual order
84
+ - [ ] Headings: one H1, sequential, no skipped levels
85
+ - [ ] Images: every meaningful image has descriptive alt; decorative images have alt=""
86
+ - [ ] Links: descriptive text (not "click here")
87
+ - [ ] Skip-to-content link present and working
88
+
89
+ ### Visual accessibility
90
+
91
+ - [ ] Body text contrast >= 4.5:1 in both light and dark mode (verified independently, not by inversion)
92
+ - [ ] Large text and meaningful UI graphics >= 3:1
93
+ - [ ] Color is never the only signal (status, error, success paired with icon or text)
94
+ - [ ] Page usable at 200% browser zoom with no horizontal scroll
95
+ - [ ] Page usable at largest system text size
96
+
97
+ ## 5. Responsive
98
+
99
+ Test at every breakpoint and orientation.
100
+
101
+ - [ ] 320px (smallest supported phone)
102
+ - [ ] 375px (typical phone)
103
+ - [ ] 768px (tablet portrait)
104
+ - [ ] 1024px (tablet landscape, small laptop)
105
+ - [ ] 1280px (desktop)
106
+ - [ ] 1920px (large desktop)
107
+ - [ ] Phone landscape (short height)
108
+ - [ ] Tablet landscape
109
+
110
+ Per breakpoint:
111
+
112
+ - [ ] No horizontal scroll
113
+ - [ ] No clipped content
114
+ - [ ] Layout is intentional, not just fluid
115
+ - [ ] Touch targets >= 44x44 with 8px gaps (mobile/tablet)
116
+ - [ ] Body text >= 16px on mobile (avoids iOS auto-zoom)
117
+ - [ ] Tables either fit, scroll horizontally, or transform to cards
118
+ - [ ] Sidebar / nav transforms appropriately
119
+ - [ ] Modals fit smallest viewport
120
+ - [ ] Safe areas respected (notch, dynamic island, gesture bar)
121
+ - [ ] `100dvh` (not `100vh`) for full-height mobile sections
122
+
123
+ ## 6. Theme
124
+
125
+ - [ ] Light mode designed and tested independently
126
+ - [ ] Dark mode designed and tested independently (not just inverted)
127
+ - [ ] All semantic tokens work in both modes
128
+ - [ ] Borders and dividers visible in both modes
129
+ - [ ] Focus rings visible in both modes
130
+ - [ ] Imagery looks correct in both modes (may need separate dark variants)
131
+ - [ ] Theme toggle (if present) works without flicker
132
+ - [ ] Default theme respects `prefers-color-scheme`
133
+ - [ ] User-selected theme persists across navigation
134
+
135
+ ## 7. Motion
136
+
137
+ - [ ] All animations use `transform` and/or `opacity` (no `width`, `height`, `top`, `left`, `margin`)
138
+ - [ ] Durations 100-500ms (no animations longer than 500ms in routine UI)
139
+ - [ ] Exit faster than entrance (60-70%)
140
+ - [ ] `prefers-reduced-motion: reduce` removes or shortens non-essential animation
141
+ - [ ] Loading: skeleton at 300ms+, spinner before, progress for determinate
142
+ - [ ] Spinner / skeleton has accessible name or `aria-busy`
143
+ - [ ] Animations don't block input
144
+ - [ ] Animations don't cause layout shift (CLS)
145
+ - [ ] Continuous animations pause when off-screen and tab is inactive
146
+
147
+ ## 8. Visual Quality
148
+
149
+ ### Typography
150
+
151
+ - [ ] Maximum 2 font families, 4 weights total
152
+ - [ ] Distinctive choices (not just Inter on white)
153
+ - [ ] Type scale is consistent (multiplicative, not random)
154
+ - [ ] Body text 16px+ on mobile
155
+ - [ ] Line height 1.5-1.75 for body
156
+ - [ ] Line length 60-75 characters for prose
157
+ - [ ] Tabular figures for numeric columns
158
+
159
+ ### Color
160
+
161
+ - [ ] Semantic tokens used (no raw hex in components)
162
+ - [ ] Dominant + 1-2 accents (not evenly distributed)
163
+ - [ ] Brand color contrasts properly in both modes
164
+ - [ ] Neutral scale used consistently for surfaces and text
165
+
166
+ ### Spacing
167
+
168
+ - [ ] Spacing scale chosen (4-pt or 8-pt)
169
+ - [ ] No random spacing values
170
+ - [ ] Visual rhythm consistent
171
+
172
+ ### Iconography
173
+
174
+ - [ ] One icon set throughout
175
+ - [ ] Consistent stroke width
176
+ - [ ] Consistent sizes per hierarchy level
177
+ - [ ] No emoji as structural icons (only as accents where intentional)
178
+ - [ ] SVG only (no PNG icons)
179
+
180
+ ### Composition
181
+
182
+ - [ ] At least one section breaks the safe centered three-card layout (where appropriate to the brand)
183
+ - [ ] Visual hierarchy: scan the page; the most important element is the largest/boldest
184
+ - [ ] Whitespace intentional; not just residual
185
+ - [ ] One primary CTA per screen
186
+
187
+ ## 9. SEO (public-visible pages)
188
+
189
+ - [ ] Unique `<title>` 50-60 chars
190
+ - [ ] Unique `<meta name="description">` 140-160 chars
191
+ - [ ] One `<h1>` matching primary intent
192
+ - [ ] Sequential headings, no skipped levels
193
+ - [ ] Self-referencing `<link rel="canonical">`
194
+ - [ ] `<meta name="robots" content="index, follow">` (or `noindex` if not indexable)
195
+ - [ ] Open Graph tags (og:title, og:description, og:image 1200x630, og:url, og:type)
196
+ - [ ] Twitter card tags
197
+ - [ ] `<html lang="...">`
198
+ - [ ] Structured data validated via Rich Results Test (where applicable)
199
+ - [ ] Image alt text on every meaningful image
200
+ - [ ] Internal links use descriptive anchor text (not "click here")
201
+ - [ ] Page reachable from home in <= 3 clicks
202
+ - [ ] Listed in sitemap.xml (if indexable)
203
+ - [ ] HTTPS, no mixed content
204
+ - [ ] No render-blocking content critical to indexing
205
+
206
+ ## 10. State Coverage
207
+
208
+ Every screen and component has intentional designs for:
209
+
210
+ - [ ] Empty (with message and action, not blank)
211
+ - [ ] Loading (skeleton matching layout, or spinner)
212
+ - [ ] Success (brief feedback)
213
+ - [ ] Error (cause + fix + recovery action)
214
+ - [ ] Disabled (visually distinct, programmatically disabled)
215
+ - [ ] Initial / first-run (where applicable)
216
+ - [ ] Offline (network-dependent actions disabled, message shown)
217
+ - [ ] Limit reached (where applicable)
218
+
219
+ ## 11. Forms (if forms changed)
220
+
221
+ - [ ] Every input has a visible, programmatic label
222
+ - [ ] Right `type` and `inputmode` for the data
223
+ - [ ] `autocomplete` per WHATWG spec (especially for username/password/address/payment)
224
+ - [ ] Required fields marked visually + `aria-required`
225
+ - [ ] Validation on blur (not on every keystroke)
226
+ - [ ] Errors inline, near the field, with cause + fix
227
+ - [ ] Errors announced via `role="alert"` or `aria-live`
228
+ - [ ] On submit error, focus moves to first invalid field
229
+ - [ ] Submit button has loading state, disabled during submission, specific verb-noun label
230
+ - [ ] Helper text for complex fields
231
+ - [ ] Long forms autosave; "Saved" indicator visible
232
+ - [ ] Multi-step forms show progress and allow back navigation
233
+ - [ ] Destructive actions confirm or provide undo
234
+ - [ ] Tested with password manager / autofill
235
+
236
+ ## 12. Charts and Tables (if data viz changed)
237
+
238
+ - [ ] Right chart for the data
239
+ - [ ] Axes labeled with units
240
+ - [ ] Colorblind-safe palette
241
+ - [ ] Color paired with shape/pattern/label
242
+ - [ ] Tooltip works on hover AND tap
243
+ - [ ] Text alternative (summary or accessible data table)
244
+ - [ ] Interactive elements keyboard-accessible
245
+ - [ ] Touch targets >= 44x44
246
+ - [ ] Responsive: simplifies on small screens
247
+ - [ ] Loading skeleton matches layout
248
+ - [ ] Empty state with message and action
249
+ - [ ] Error state with retry
250
+ - [ ] Numbers locale-formatted
251
+ - [ ] Tables: sorting, sticky header, mobile-adaptive
252
+
253
+ ## 13. Cross-Browser
254
+
255
+ Test on at least:
256
+
257
+ - [ ] Latest Chrome (Chromium engine, what most users have)
258
+ - [ ] Latest Safari (WebKit, all iOS users + many macOS users)
259
+ - [ ] Latest Firefox (Gecko, smaller share but valuable diversity)
260
+
261
+ For supported older browsers (per browserslist), spot-check key flows.
262
+
263
+ For Safari:
264
+
265
+ - `:has()` (now widely supported, but verify on older iOS)
266
+ - `<dialog>` (added in Safari 15.4)
267
+ - `view-transition` API (Safari 18+)
268
+ - Container queries (Safari 16+)
269
+ - Backdrop filter (use prefixed `-webkit-backdrop-filter`)
270
+
271
+ ## 14. Real-User Monitoring
272
+
273
+ If RUM is set up:
274
+
275
+ - [ ] `web-vitals` library ships LCP, INP, CLS, FCP, TTFB to your pipeline
276
+ - [ ] Monitoring view shows p75 over rolling 28 days
277
+ - [ ] Alerts fire when p75 crosses thresholds
278
+ - [ ] Source maps uploaded for production error symbolication
279
+
280
+ ## 15. Documentation
281
+
282
+ - [ ] Component docs updated (if applicable)
283
+ - [ ] Storybook / playground stories cover new states
284
+ - [ ] Design system tokens updated (if new tokens introduced)
285
+ - [ ] README / CHANGELOG updated (if significant change)
286
+
287
+ ## 16. Git and Review
288
+
289
+ - [ ] Branch is up to date with main
290
+ - [ ] All changes are intentional (review the diff)
291
+ - [ ] No leftover console.log, debugger, TODO, FIXME without owner
292
+ - [ ] No leftover commented-out code
293
+ - [ ] Tests pass (unit, integration, e2e if applicable)
294
+ - [ ] Lint and format pass
295
+ - [ ] Type check passes
296
+ - [ ] Build succeeds for production target
297
+
298
+ ## 17. Multi-Page Polish Gate
299
+
300
+ If the change affects multiple pages or shared widgets, the polish gate must pass before launch. The full procedure lives in [audit-workflow.md](audit-workflow.md) Phase 19. The launch-relevant subset is:
301
+
302
+ - [ ] Widget inventory exists for the affected widget families
303
+ - [ ] Same-purpose widgets are extracted to one source of truth or normalized to one contract
304
+ - [ ] Drift collector returns no unexplained differences across pages for shared widgets
305
+ - [ ] Geometry sweep returns zero issues on every affected route at `1440x900` and `375x812`
306
+ - [ ] Before-and-after screenshots captured at both viewports for every affected route
307
+ - [ ] Reference comparison heuristics in [design.md](design.md) pass
308
+ - [ ] No same-purpose widget looks different on two routes without a named, intentional variant
309
+
310
+ Treat any failure as blocking. The full Phase 19 acceptance list in [audit-workflow.md](audit-workflow.md) is authoritative when both gates apply; this section is the launch-time subset.
311
+
312
+ ## 18. Final Smell Test
313
+
314
+ Open the page in a fresh browser (incognito to avoid cached assets). Walk through it as a new user would. Ask yourself:
315
+
316
+ - Is the primary action obvious within 2 seconds?
317
+ - Does the surface feel like a single product, or a collection of unrelated pieces?
318
+ - Does it look distinctive, or could it be any other product's equivalent screen?
319
+ - Would I be proud to share this URL?
320
+
321
+ If "no" to any, address it before declaring complete.
322
+
323
+ ## When the Checklist Fails
324
+
325
+ Don't move on. The checklist exists because every item on it has, at some point, been the regression that shipped to production.
326
+
327
+ For each failure:
328
+
329
+ 1. Identify the specific cause.
330
+ 2. Fix at the right layer (component, page, system, or design token).
331
+ 3. Re-run the relevant section of the checklist (not the whole thing).
332
+ 4. Once green, run a final full pass to verify nothing else regressed.
333
+
334
+ ## See Also
335
+
336
+ - [lighthouse.md](lighthouse.md) for score-driven audit fixes
337
+ - [accessibility.md](accessibility.md) for a11y deep dive
338
+ - [seo.md](seo.md) for SEO requirements
339
+ - [responsive.md](responsive.md) for layout testing
340
+ - [audit-workflow.md](audit-workflow.md) for multi-page polish work
341
+ - [components.md](components.md) for component contracts and drift detection
342
+ - [defects.md](defects.md) for symptom-to-fix lookup and geometry sweep