@champpaba/claude-agent-kit 1.4.0 → 1.4.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.
@@ -94,16 +94,19 @@ Read: .changes/{change-id}/page-plan.md
94
94
  - Suggest: User should run `/designsetup` to generate style guide
95
95
 
96
96
  **If page-plan.md exists:**
97
- - ✅ Read and load page-plan.md (contains component reuse plan, content draft, assets)
97
+ - ✅ Read and load page-plan.md (contains component reuse plan, content draft, assets, **animation blueprint**)
98
98
  - Extract:
99
+ - **Section 2.6 - Animation Blueprint** (🆕 animation strategy for all components)
99
100
  - Component reuse list (which components already exist)
100
101
  - Component new list (which to create)
101
102
  - Content draft (headlines, descriptions, copy)
102
103
  - Asset paths (images, icons locations)
103
104
  - **OPTIMIZATION:** Skip STEP 3 (component search) - page-plan already did this!
105
+ - **CRITICAL:** If Section 2.6 exists, animations are **pre-designed** - follow blueprint exactly
104
106
 
105
107
  **If page-plan.md does NOT exist:**
106
108
  - ℹ️ No page plan - will search for components manually in STEP 3
109
+ - ⚠️ No animation blueprint - fallback to `.claude/contexts/patterns/animation-patterns.md`
107
110
 
108
111
  **Report when complete:**
109
112
  ```
@@ -122,8 +125,10 @@ Read: .changes/{change-id}/page-plan.md
122
125
 
123
126
  📋 Page Plan: ✅ page-plan.md loaded (3 reuse, 2 new, 4 assets)
124
127
  → Will skip component search (STEP 3)
128
+ 🎬 Animation Blueprint: ✅ Section 2.6 loaded (buttons, cards, inputs pre-designed)
125
129
  OR
126
130
  📋 Page Plan: ℹ️ Not found - will search components in STEP 3
131
+ 🎬 Animation Blueprint: ⚠️ Not found - using animation-patterns.md (fallback)
127
132
 
128
133
  🎯 Ready to create UI components!
129
134
  ```
@@ -198,10 +203,112 @@ const TOKENS = {
198
203
  spacing: { padding: '[value]', gap: '[value]' },
199
204
  colors: { bg: '[token]', text: '[token]' },
200
205
  shadows: '[value]',
201
- radius: '[value]'
206
+ radius: '[value]',
207
+ // 🆕 Animation tokens (MANDATORY - v1.4.0)
208
+ animation: {
209
+ hover: '[classes]', // e.g., hover:scale-105 hover:shadow-lg
210
+ focus: '[classes]', // e.g., focus:ring-2 focus:ring-primary
211
+ active: '[classes]', // e.g., active:scale-95
212
+ transition: '[value]', // e.g., transition-all duration-150
213
+ duration: '[token]', // e.g., 150ms, 300ms, 500ms (from STYLE_TOKENS.json)
214
+ easing: '[token]', // e.g., ease-in-out
215
+ description: '[rationale]' // Why this animation pattern?
216
+ }
202
217
  }
203
218
  ```
204
219
 
220
+ **Animation Token Extraction Rules:**
221
+ 1. ✅ Extract from reference component (STEP 3 search results)
222
+ 2. ✅ Fallback to page-plan.md Section 2.6 (if exists)
223
+ 3. ✅ Fallback to animation-patterns.md (component patterns)
224
+ 4. ✅ Use durations from STYLE_TOKENS.json (150ms, 300ms, 500ms)
225
+ 5. ❌ NO random durations (200ms, 250ms, 400ms)
226
+ 6. ❌ NO random patterns (button A scales, button B changes color)
227
+
228
+ ### 📋 Step 4.5: Performance Optimization Checklist (MANDATORY)
229
+
230
+ **→ See:** `.claude/contexts/patterns/performance-optimization.md` for complete guide
231
+
232
+ **Before implementing ANY component, apply these optimizations:**
233
+
234
+ #### **Images (Primary Focus)**
235
+
236
+ - [ ] **Format:** Use WebP with fallback (NOT JPEG/PNG only)
237
+ ```tsx
238
+ // ✅ CORRECT
239
+ <picture>
240
+ <source srcset="hero.webp" type="image/webp">
241
+ <img src="hero.jpg" alt="Hero" loading="lazy" />
242
+ </picture>
243
+
244
+ // ❌ WRONG
245
+ <img src="hero.jpg" alt="Hero" />
246
+ ```
247
+
248
+ - [ ] **Lazy Loading:** `loading="lazy"` for below-fold images
249
+ ```tsx
250
+ // ✅ Below fold (most images)
251
+ <img src="product.webp" alt="Product" loading="lazy" width={400} height={300} />
252
+
253
+ // ✅ Above fold (hero only)
254
+ <img src="hero.webp" alt="Hero" loading="eager" width={1920} height={1080} />
255
+ ```
256
+
257
+ - [ ] **Dimensions:** ALWAYS specify width/height (prevent layout shift)
258
+ ```tsx
259
+ // ✅ CORRECT (prevents CLS)
260
+ <img src="product.webp" alt="Product" width={400} height={300} />
261
+
262
+ // ❌ WRONG (causes layout shift)
263
+ <img src="product.webp" alt="Product" />
264
+ ```
265
+
266
+ - [ ] **Responsive Images:** Generate 3 sizes for images > 400px width
267
+ ```tsx
268
+ // ✅ CORRECT (mobile saves bandwidth)
269
+ <img
270
+ src="hero-1920.webp"
271
+ srcset="hero-768.webp 768w, hero-1024.webp 1024w, hero-1920.webp 1920w"
272
+ sizes="(max-width: 768px) 100vw, 1920px"
273
+ alt="Hero"
274
+ width={1920}
275
+ height={1080}
276
+ />
277
+ ```
278
+
279
+ #### **Code (Secondary Focus)**
280
+
281
+ - [ ] **Lazy Load Heavy Components:** Use dynamic imports for charts, modals, editors
282
+ ```tsx
283
+ // ✅ CORRECT (only load when needed)
284
+ const HeavyChart = dynamic(() => import('./HeavyChart'), {
285
+ loading: () => <div>Loading...</div>,
286
+ ssr: false
287
+ })
288
+ ```
289
+
290
+ - [ ] **Use React.memo() for expensive components:** Prevent unnecessary re-renders
291
+ ```tsx
292
+ // ✅ CORRECT (memoize expensive list)
293
+ export const ProductList = memo(function ProductList({ products }) {
294
+ return products.map(product => <ProductCard key={product.id} {...product} />)
295
+ })
296
+ ```
297
+
298
+ #### **Quick Validation**
299
+
300
+ **Before committing code, verify:**
301
+ 1. All images have `width` and `height` attributes ✓
302
+ 2. Below-fold images have `loading="lazy"` ✓
303
+ 3. Hero images use `loading="eager"` ✓
304
+ 4. Using WebP format (with fallback) ✓
305
+ 5. No arbitrary spacing values (use spacing scale) ✓
306
+
307
+ **Performance Impact:**
308
+ - LCP: -50-60% (faster hero image load)
309
+ - Bundle size: -30-40% (code splitting)
310
+ - Image size: -80% (WebP + compression)
311
+
205
312
  ### 📋 Step 5: Pre-Implementation Report (REQUIRED)
206
313
 
207
314
  Provide complete analysis covering steps 1-4 BEFORE writing code.
@@ -230,6 +337,8 @@ Provide complete analysis covering steps 1-4 BEFORE writing code.
230
337
  - @.claude/contexts/design/accessibility.md
231
338
  - @.claude/contexts/patterns/ui-component-consistency.md (CRITICAL!)
232
339
  - @.claude/contexts/patterns/frontend-component-strategy.md
340
+ - @.claude/contexts/patterns/animation-patterns.md (Animations & micro-interactions)
341
+ - @.claude/contexts/patterns/performance-optimization.md (Image optimization, lazy loading)
233
342
 
234
343
  ### Project-Specific (If Exists)
235
344
  - `design-system/STYLE_GUIDE.md` (Priority #1 - loaded in STEP 0.5)
@@ -163,20 +163,380 @@ Based on context + found components, generate:
163
163
  </Layout>
164
164
  \`\`\`
165
165
 
166
- ## 3. 📦 Assets to Prepare (คุณต้องเตรียม)
166
+ ## 2.5. 📐 Layout Wireframe (Visual Blueprint)
167
167
 
168
- ### Images
169
- - [ ] \`filename.jpg\` (widthxheight, format)
170
- Place at: \`/public/images/filename.jpg\`
171
- → Purpose: [description]
168
+ > **Purpose:** Visual representation of page layout for user review BEFORE implementation
169
+
170
+ ### Desktop View (>1024px)
171
+ \`\`\`
172
+ ┌────────────────────────────────────────────────────┐
173
+ │ [Logo] [Nav Menu] [CTA Button] │ ← Navbar (h-16, sticky)
174
+ ├────────────────────────────────────────────────────┤
175
+ │ │
176
+ │ Hero Section │ ← Full viewport (h-screen)
177
+ │ [Large Headline] │ Background image
178
+ │ [Subheadline text] │ Centered content
179
+ │ [Primary CTA] │
180
+ │ │
181
+ ├────────────────────────────────────────────────────┤
182
+ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
183
+ │ │ Card 1 │ │ Card 2 │ │ Card 3 │ │ ← Feature Grid
184
+ │ │ [Icon] │ │ [Icon] │ │ [Icon] │ │ (grid-cols-3, gap-6)
185
+ │ │ Title │ │ Title │ │ Title │ │ Container: max-w-7xl
186
+ │ │ Desc │ │ Desc │ │ Desc │ │ Padding: py-24
187
+ │ └──────────┘ └──────────┘ └──────────┘ │
188
+ ├────────────────────────────────────────────────────┤
189
+ │ [Footer Links] [Social Icons] │ ← Footer (h-20)
190
+ └────────────────────────────────────────────────────┘
191
+ \`\`\`
192
+
193
+ ### Tablet View (768-1023px)
194
+ \`\`\`
195
+ ┌──────────────────────────────┐
196
+ │ [Logo] [Nav] [☰] │ ← Navbar (collapsed nav)
197
+ ├──────────────────────────────┤
198
+ │ Hero Section │ ← h-[600px]
199
+ │ [Headline] │ Same layout, smaller
200
+ │ [CTA] │
201
+ ├──────────────────────────────┤
202
+ │ ┌──────────┐ ┌──────────┐ │
203
+ │ │ Card 1 │ │ Card 2 │ │ ← Feature Grid
204
+ │ └──────────┘ └──────────┘ │ (grid-cols-2, gap-4)
205
+ │ ┌──────────┐ │
206
+ │ │ Card 3 │ │
207
+ │ └──────────┘ │
208
+ ├──────────────────────────────┤
209
+ │ Footer (stacked) │
210
+ └──────────────────────────────┘
211
+ \`\`\`
212
+
213
+ ### Mobile View (<768px)
214
+ \`\`\`
215
+ ┌────────────────┐
216
+ │ [Logo] [☰] │ ← Navbar (hamburger)
217
+ ├────────────────┤
218
+ │ Hero │ ← h-[500px]
219
+ │ [Headline] │ Smaller text
220
+ │ [CTA] │ Full-width button
221
+ ├────────────────┤
222
+ │ ┌────────────┐ │
223
+ │ │ Card 1 │ │ ← Feature Grid
224
+ │ │ [Icon] │ │ (grid-cols-1, gap-4)
225
+ │ │ Title │ │ Full-width cards
226
+ │ └────────────┘ │
227
+ │ ┌────────────┐ │
228
+ │ │ Card 2 │ │
229
+ │ └────────────┘ │
230
+ │ ┌────────────┐ │
231
+ │ │ Card 3 │ │
232
+ │ └────────────┘ │
233
+ ├────────────────┤
234
+ │ Footer │
235
+ │ (stacked) │
236
+ └────────────────┘
237
+ \`\`\`
238
+
239
+ ### Spacing & Sizing Details
240
+
241
+ **Containers:**
242
+ - Hero: Full viewport height (h-screen desktop, h-[600px] tablet, h-[500px] mobile)
243
+ - Features: max-w-7xl, px-6, py-24 (desktop) → py-16 (tablet) → py-12 (mobile)
244
+ - Cards: Equal height, p-6 (desktop) → p-4 (mobile)
245
+
246
+ **Grid Breakpoints:**
247
+ - Desktop (>1024px): 3 columns (grid-cols-3)
248
+ - Tablet (768-1023px): 2 columns (grid-cols-2)
249
+ - Mobile (<768px): 1 column (grid-cols-1)
250
+
251
+ **Gaps:**
252
+ - Section gaps: gap-24 (desktop) → gap-16 (tablet) → gap-12 (mobile)
253
+ - Card gaps: gap-6 (desktop) → gap-4 (mobile)
254
+
255
+ ### Responsive Behavior
256
+
257
+ | Element | Desktop | Tablet | Mobile |
258
+ |---------|---------|--------|--------|
259
+ | **Navbar** | Full menu | Collapsed | Hamburger |
260
+ | **Hero** | h-screen | h-[600px] | h-[500px] |
261
+ | **Feature Grid** | 3 cols | 2 cols | 1 col (stack) |
262
+ | **Cards** | Side-by-side | Wrap to 2 cols | Full-width stack |
263
+ | **Footer** | Horizontal | Stacked | Stacked |
264
+
265
+ ---
266
+
267
+ ## 2.6. 🎬 Animation Blueprint (Micro-interactions)
268
+
269
+ > **Purpose:** Define animation strategy BEFORE implementation to ensure consistency and polish
270
+ > **Source:** `design-system/STYLE_TOKENS.json` (animation tokens)
271
+ > **Philosophy:** Match Flow Engineer Step 3 - Design animations systematically, not randomly
272
+
273
+ ### Animation Principles
274
+
275
+ **From STYLE_TOKENS.json:**
276
+ - **Durations:** 150ms (quick), 300ms (normal), 500ms (slow)
277
+ - **Easing:** ease-in-out (default), cubic-bezier for custom
278
+ - **Properties:** GPU-accelerated ONLY (transform, opacity) - NOT width, height, top, left
279
+ - **Consistency:** Same component type = same animation pattern
280
+
281
+ ---
282
+
283
+ ### Button Animations
284
+
285
+ #### Primary CTA Button
286
+ **Hover State:**
287
+ - Properties: `transform` (scale 1.05) + `box-shadow` (md → lg)
288
+ - Duration: 150ms (fast, responsive feel)
289
+ - Easing: ease-in-out
290
+ - Code: `transition-all duration-150 hover:scale-105 hover:shadow-lg`
291
+
292
+ **Active State:**
293
+ - Properties: `transform` (scale 0.95)
294
+ - Duration: 100ms (immediate feedback)
295
+ - Code: `active:scale-95`
296
+
297
+ **Loading State:**
298
+ - Properties: `opacity` (text → 70%), spinner fade-in
299
+ - Duration: 300ms
300
+ - Code: `disabled:opacity-70` + spinner component
301
+
302
+ **Full Example:**
303
+ ```tsx
304
+ <button className="px-6 py-3 bg-primary text-primary-foreground rounded-md
305
+ transition-all duration-150
306
+ hover:scale-105 hover:shadow-lg
307
+ active:scale-95
308
+ disabled:opacity-70">
309
+ Get Started
310
+ </button>
311
+ ```
312
+
313
+ #### Secondary Button
314
+ **Hover State:**
315
+ - Properties: `background-color` shift, `border-color` shift
316
+ - Duration: 150ms
317
+ - Code: `transition-colors duration-150 hover:bg-secondary/80`
318
+
319
+ ---
320
+
321
+ ### Card Animations
322
+
323
+ #### Feature Card / Product Card
324
+ **Hover State:**
325
+ - Properties: `box-shadow` elevation (sm → xl)
326
+ - Duration: 300ms (smooth, elegant)
327
+ - Easing: ease-in-out
328
+ - Code: `transition-shadow duration-300 hover:shadow-xl`
329
+
330
+ **Border Glow (Optional):**
331
+ - Properties: `border-color` subtle shift
332
+ - Duration: 300ms
333
+ - Code: `hover:border-primary/50`
334
+
335
+ **Full Example:**
336
+ ```tsx
337
+ <div className="p-6 bg-card border border-border rounded-lg
338
+ transition-shadow duration-300
339
+ hover:shadow-xl hover:border-primary/50">
340
+ {/* Card content */}
341
+ </div>
342
+ ```
343
+
344
+ #### Interactive Card (Clickable)
345
+ **Hover State:**
346
+ - Same as feature card + cursor pointer
347
+ - Code: `cursor-pointer transition-shadow duration-300 hover:shadow-xl`
348
+
349
+ **Active State:**
350
+ - Properties: `transform` (scale 0.98) - subtle press feedback
351
+ - Duration: 100ms
352
+ - Code: `active:scale-98`
353
+
354
+ ---
355
+
356
+ ### Input & Form Animations
357
+
358
+ #### Text Input / Select / Combobox
359
+ **Focus State:**
360
+ - Properties: `box-shadow` (ring-2 appears), `border-color` shift
361
+ - Duration: 200ms (balanced - not too fast, not slow)
362
+ - Easing: ease-in-out
363
+ - Code: `transition-all duration-200 focus:ring-2 focus:ring-primary focus:border-primary`
364
+
365
+ **Error State:**
366
+ - Properties: `border-color` (→ destructive), optional shake
367
+ - Duration: 300ms
368
+ - Code: `border-destructive` (static) or `animate-shake` (if shake defined)
369
+
370
+ **Full Example:**
371
+ ```tsx
372
+ <input className="w-full px-3 py-2 border border-input rounded-md
373
+ transition-all duration-200
374
+ focus:ring-2 focus:ring-primary focus:border-primary
375
+ placeholder:text-muted-foreground" />
376
+ ```
377
+
378
+ ---
379
+
380
+ ### Navigation Animations
381
+
382
+ #### Desktop Menu Hover
383
+ **Menu Item Hover:**
384
+ - Properties: `background-color` subtle shift
385
+ - Duration: 150ms
386
+ - Code: `transition-colors duration-150 hover:bg-accent`
387
+
388
+ #### Mobile Menu (Slide-in)
389
+ **Hamburger → Sidebar:**
390
+ - Properties: `transform` (translateX -100% → 0)
391
+ - Duration: 300ms
392
+ - Easing: cubic-bezier(0.4, 0, 0.2, 1)
393
+ - Library: Framer Motion or Tailwind transition
394
+
395
+ **Example (Framer Motion):**
396
+ ```tsx
397
+ <motion.div
398
+ initial={{ x: "-100%" }}
399
+ animate={{ x: 0 }}
400
+ exit={{ x: "-100%" }}
401
+ transition={{ duration: 0.3, ease: [0.4, 0, 0.2, 1] }}>
402
+ {/* Sidebar content */}
403
+ </motion.div>
404
+ ```
405
+
406
+ ---
407
+
408
+ ### Icon Animations
409
+
410
+ #### Chevron / Arrow (Dropdown)
411
+ **Expand/Collapse:**
412
+ - Properties: `transform` (rotate 0deg → 180deg)
413
+ - Duration: 200ms
414
+ - Code: `transition-transform duration-200 [data-state=open]:rotate-180`
415
+
416
+ #### Loading Spinner
417
+ **Continuous Rotation:**
418
+ - Properties: `transform` (rotate 360deg)
419
+ - Duration: 1000ms (1s per rotation)
420
+ - Easing: linear (consistent speed)
421
+ - Code: `animate-spin` (Tailwind utility)
422
+
423
+ ---
424
+
425
+ ### Modal / Dialog Animations
426
+
427
+ #### Modal Entrance
428
+ **Background Overlay:**
429
+ - Properties: `opacity` (0 → 100%)
430
+ - Duration: 200ms
431
+ - Code: `transition-opacity duration-200`
432
+
433
+ **Dialog Content:**
434
+ - Properties: `opacity` + `transform` (scale 0.95 → 1)
435
+ - Duration: 300ms
436
+ - Easing: ease-in-out
437
+ - Library: Framer Motion or Radix UI (built-in)
438
+
439
+ ---
440
+
441
+ ### Performance Rules (CRITICAL!)
442
+
443
+ **✅ DO USE (GPU-accelerated):**
444
+ - `transform` (translate, scale, rotate)
445
+ - `opacity`
446
+ - `filter` (blur, brightness)
447
+
448
+ **❌ DON'T USE (CPU-intensive, causes reflow):**
449
+ - `width`, `height` (causes layout recalculation)
450
+ - `top`, `left`, `margin` (use `transform` instead)
451
+ - `font-size` (causes text reflow)
452
+
453
+ **Example:**
454
+ ```tsx
455
+ // ❌ WRONG (causes reflow)
456
+ className="hover:w-full hover:h-auto"
457
+
458
+ // ✅ CORRECT (GPU-accelerated)
459
+ className="hover:scale-105 transform"
460
+ ```
461
+
462
+ ---
463
+
464
+ ### Animation Consistency Checklist
465
+
466
+ **Before implementing components:**
467
+ - [ ] All buttons use scale + shadow pattern (150ms)
468
+ - [ ] All cards use shadow elevation pattern (300ms)
469
+ - [ ] All inputs use ring pattern (200ms)
470
+ - [ ] All durations from STYLE_TOKENS.json (150/300/500ms)
471
+ - [ ] All properties GPU-accelerated (transform, opacity)
472
+ - [ ] No random durations (e.g., 200ms, 400ms) unless intentional
473
+ - [ ] Tested on mobile (animations not janky)
474
+
475
+ ---
476
+
477
+ ### Design Rationale
478
+
479
+ **Why these patterns?**
480
+ 1. **Scale + Shadow (Buttons):** Creates depth, signals interactivity
481
+ 2. **Shadow Elevation (Cards):** Subtle, elegant, matches Material Design
482
+ 3. **Ring (Inputs):** Clear focus indicator, accessibility compliant
483
+ 4. **Short Durations (150-300ms):** Feels responsive, not sluggish
484
+ 5. **GPU Properties:** 60fps smooth animations, no jank
485
+
486
+ **Inspiration:** Based on extracted animations from reference sites + STYLE_TOKENS.json
487
+
488
+ ---
489
+
490
+ ## 3. 📦 Assets to Prepare (Performance-Optimized)
491
+
492
+ > **Performance Note:** Follow image optimization best practices for faster load times and better SEO.
493
+ > See: `.claude/contexts/patterns/performance-optimization.md`
494
+
495
+ ### Images (Apply Performance Checklist)
496
+
497
+ **For each image, provide:**
498
+
499
+ - [ ] **filename.webp** (1920x1080)
500
+ → **Source:** filename.jpg (compress to WebP, quality 85%)
501
+ → **Responsive sizes:** 768w, 1024w, 1920w (generate 3 sizes for responsive)
502
+ → **Loading strategy:**
503
+ - `loading="lazy"` (if below fold - most images)
504
+ - `loading="eager"` (if hero/above fold - rare)
505
+ → **Alt text:** Descriptive alt text for accessibility
506
+ → **Place at:** `/public/images/`
507
+ → **Purpose:** [description - where used on page]
508
+ → **Estimated size:** ~80KB WebP (was ~450KB JPEG) = **-82% reduction**
509
+ → **LCP impact:** Hero images affect LCP score - optimize first!
510
+
511
+ **Example:**
512
+ ```
513
+ - [ ] **hero-background.webp** (1920x1080)
514
+ → Source: hero-background.jpg (compress via TinyPNG/Squoosh)
515
+ → Sizes: hero-768.webp, hero-1024.webp, hero-1920.webp
516
+ → Loading: eager (hero image, above fold)
517
+ → Alt: "Students taking TOEIC exam in modern classroom"
518
+ → Place: /public/images/
519
+ → Purpose: Hero section background
520
+ → Size: 85KB WebP (was 520KB JPEG) = -84%
521
+ ```
172
522
 
173
523
  ### Icons
174
- - [ ] [description] (size, format)
175
- Place at: \`/public/icons/\`
176
- → Style: [match STYLE_GUIDE]
524
+
525
+ **Preferred format:** SVG (scalable, tiny file size)
526
+
527
+ - [ ] **[icon-name].svg** (24x24 viewBox)
528
+ → **Format:** SVG (preferred) or PNG sprite (if 10+ icons)
529
+ → **Optimization:** Remove unnecessary metadata (use SVGO)
530
+ → **Place at:** `/public/icons/` or inline in component
531
+ → **Style:** Match STYLE_GUIDE colors
532
+ → **Estimated size:** 1-3KB per icon
533
+
534
+ **If using 10+ icons:** Consider SVG sprite sheet (combine → 1 HTTP request)
177
535
 
178
536
  ### Other Assets
179
- [Fonts, videos, etc.]
537
+ - [ ] **Fonts:** Use `font-display: swap` to prevent FOIT (Flash of Invisible Text)
538
+ - [ ] **Videos:** Use lazy loading, provide poster image
539
+ - [ ] **Third-party scripts:** Load async/defer when possible
180
540
 
181
541
  ---
182
542