ada-agent 0.1.0 → 0.3.0
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/README.md +262 -256
- package/docs/architecture.md +38 -14
- package/docs/cloudflare.md +81 -0
- package/docs/connectors.md +2 -1
- package/docs/integrations.md +4 -1
- package/package.json +4 -2
- package/skills/aesthetic-direction/SKILL.md +24 -24
- package/skills/color-palette/SKILL.md +24 -24
- package/skills/component-library/SKILL.md +23 -23
- package/skills/dark-mode/SKILL.md +24 -24
- package/skills/dashboard-ui/SKILL.md +23 -23
- package/skills/design-system/SKILL.md +24 -24
- package/skills/design-tokens/SKILL.md +24 -24
- package/skills/empty-states/SKILL.md +23 -23
- package/skills/hero-section/SKILL.md +23 -23
- package/skills/micro-interactions/SKILL.md +23 -23
- package/skills/motion-design/SKILL.md +23 -23
- package/skills/page-transitions/SKILL.md +23 -23
- package/skills/pricing-page/SKILL.md +23 -23
- package/skills/scroll-animation/SKILL.md +23 -23
- package/skills/skeleton-loader/SKILL.md +23 -23
- package/skills/tailwind-theme/SKILL.md +24 -24
- package/skills/typography/SKILL.md +24 -24
- package/skills/ui-polish/SKILL.md +24 -24
- package/skills/ui-review/SKILL.md +24 -24
- package/skills/web-fonts/SKILL.md +24 -24
- package/src/client/autostart.ts +93 -0
- package/src/client/catalog.json +1 -0
- package/src/client/cli.ts +23 -1
- package/src/client/models-dev.ts +57 -3
- package/src/selfcheck.ts +404 -364
- package/src/server/config.ts +7 -0
- package/src/server/providers/openai-compat.ts +4 -2
- package/src/server/providers/registry.ts +1 -0
- package/src/server/router.ts +5 -1
- package/src/shared/types.ts +1 -0
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: micro-interactions
|
|
3
|
-
description: Add tasteful hover/press/focus micro-interactions and feedback that feel responsive without distracting.
|
|
4
|
-
category: ui-design
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# Micro-Interactions
|
|
8
|
-
|
|
9
|
-
Reach for this when a UI feels static or unresponsive — buttons, toggles, cards, and inputs should acknowledge every interaction within ~100ms.
|
|
10
|
-
|
|
11
|
-
1. Map the three states for each interactive element: rest, hover, active/press, plus a `:focus-visible` ring for keyboard users — never style all four identically.
|
|
12
|
-
2. Set durations by intent: 80–120ms for press/feedback, 150–200ms for hover, and pair with `transition-timing-function: cubic-bezier(0.2, 0, 0, 1)` (ease-out) so motion settles fast.
|
|
13
|
-
3. On press, apply a subtle `transform: scale(0.97)` or 1px translate — physical, not bouncy. Reserve a gentle overshoot spring only for playful toggles/likes.
|
|
14
|
-
4. Telegraph intent with secondary cues: shift `background`, lift with `box-shadow`, or nudge an icon — change 2 properties max so it reads as one motion.
|
|
15
|
-
5. Confirm async actions inline: swap label → spinner → checkmark, then settle. Use optimistic UI where the success rate is high.
|
|
16
|
-
6. Respect `@media (prefers-reduced-motion: reduce)` — drop transforms, keep instant color/opacity feedback so the cue survives.
|
|
17
|
-
|
|
18
|
-
## Rules
|
|
19
|
-
- Hover effects are progressive enhancement; the element must be fully usable and legible without them (touch + keyboard).
|
|
20
|
-
- Animate `transform` and `opacity` only on the hot path — never `width`, `top`, or `box-shadow` in tight loops (they trigger layout/paint).
|
|
21
|
-
- Keep focus rings visible and ≥3:1 contrast against the adjacent surface; never `outline: none` without a replacement.
|
|
22
|
-
- One signature interaction per surface — if everything wiggles, nothing reads as special.
|
|
23
|
-
- Feedback latency budget is 100ms; beyond that, show a loading state instead of a delayed jump.
|
|
1
|
+
---
|
|
2
|
+
name: micro-interactions
|
|
3
|
+
description: Add tasteful hover/press/focus micro-interactions and feedback that feel responsive without distracting.
|
|
4
|
+
category: ui-design
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Micro-Interactions
|
|
8
|
+
|
|
9
|
+
Reach for this when a UI feels static or unresponsive — buttons, toggles, cards, and inputs should acknowledge every interaction within ~100ms.
|
|
10
|
+
|
|
11
|
+
1. Map the three states for each interactive element: rest, hover, active/press, plus a `:focus-visible` ring for keyboard users — never style all four identically.
|
|
12
|
+
2. Set durations by intent: 80–120ms for press/feedback, 150–200ms for hover, and pair with `transition-timing-function: cubic-bezier(0.2, 0, 0, 1)` (ease-out) so motion settles fast.
|
|
13
|
+
3. On press, apply a subtle `transform: scale(0.97)` or 1px translate — physical, not bouncy. Reserve a gentle overshoot spring only for playful toggles/likes.
|
|
14
|
+
4. Telegraph intent with secondary cues: shift `background`, lift with `box-shadow`, or nudge an icon — change 2 properties max so it reads as one motion.
|
|
15
|
+
5. Confirm async actions inline: swap label → spinner → checkmark, then settle. Use optimistic UI where the success rate is high.
|
|
16
|
+
6. Respect `@media (prefers-reduced-motion: reduce)` — drop transforms, keep instant color/opacity feedback so the cue survives.
|
|
17
|
+
|
|
18
|
+
## Rules
|
|
19
|
+
- Hover effects are progressive enhancement; the element must be fully usable and legible without them (touch + keyboard).
|
|
20
|
+
- Animate `transform` and `opacity` only on the hot path — never `width`, `top`, or `box-shadow` in tight loops (they trigger layout/paint).
|
|
21
|
+
- Keep focus rings visible and ≥3:1 contrast against the adjacent surface; never `outline: none` without a replacement.
|
|
22
|
+
- One signature interaction per surface — if everything wiggles, nothing reads as special.
|
|
23
|
+
- Feedback latency budget is 100ms; beyond that, show a loading state instead of a delayed jump.
|
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: motion-design
|
|
3
|
-
description: Define a coherent motion system — duration tokens, easing curves, and clear rules for when to animate.
|
|
4
|
-
category: ui-design
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# Motion Design
|
|
8
|
-
|
|
9
|
-
Reach for this before adding any animation to a product, so motion is a designed system with tokens rather than one-off magic numbers scattered across components.
|
|
10
|
-
|
|
11
|
-
1. Define a duration scale as CSS custom properties: `--dur-1: 100ms` (micro), `--dur-2: 200ms` (UI), `--dur-3: 320ms` (entrances), `--dur-4: 500ms` (large/page). Scale duration with travel distance and element size.
|
|
12
|
-
2. Define an easing token set: `--ease-out: cubic-bezier(0.2, 0, 0, 1)` for enters, `--ease-in: cubic-bezier(0.4, 0, 1, 1)` for exits, `--ease-spring` for emphasis. Default to ease-out — elements decelerate into place.
|
|
13
|
-
3. Assign each animation a role: arrival (fade+rise), exit (fade+fall), state change, or attention. Different roles get different curves/durations — don't reuse one transition everywhere.
|
|
14
|
-
4. Orchestrate groups with a stagger of 30–60ms per item so lists cascade; cap total sequence length near 500ms so it never feels slow.
|
|
15
|
-
5. Prefer transform-driven motion (translate/scale) and physics-based springs (Framer Motion `type: "spring"`, sensible stiffness/damping) over linear tweens for anything interactive.
|
|
16
|
-
6. Provide a global `prefers-reduced-motion` fallback that collapses movement to opacity-only, and document the tokens so the team reuses them.
|
|
17
|
-
|
|
18
|
-
## Rules
|
|
19
|
-
- Motion must communicate (where did this come from, what changed), never decorate for its own sake.
|
|
20
|
-
- Never use `ease-in-out` for entrances — it starts slow and feels sluggish; reserve it for looping/ambient motion.
|
|
21
|
-
- Exits are faster than entrances (~0.7×); users have already decided, so get out of the way.
|
|
22
|
-
- No transition longer than ~500ms on an interaction the user is waiting on.
|
|
23
|
-
- One token set, imported everywhere — a stray `transition: all 0.3s` is a bug, not a shortcut.
|
|
1
|
+
---
|
|
2
|
+
name: motion-design
|
|
3
|
+
description: Define a coherent motion system — duration tokens, easing curves, and clear rules for when to animate.
|
|
4
|
+
category: ui-design
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Motion Design
|
|
8
|
+
|
|
9
|
+
Reach for this before adding any animation to a product, so motion is a designed system with tokens rather than one-off magic numbers scattered across components.
|
|
10
|
+
|
|
11
|
+
1. Define a duration scale as CSS custom properties: `--dur-1: 100ms` (micro), `--dur-2: 200ms` (UI), `--dur-3: 320ms` (entrances), `--dur-4: 500ms` (large/page). Scale duration with travel distance and element size.
|
|
12
|
+
2. Define an easing token set: `--ease-out: cubic-bezier(0.2, 0, 0, 1)` for enters, `--ease-in: cubic-bezier(0.4, 0, 1, 1)` for exits, `--ease-spring` for emphasis. Default to ease-out — elements decelerate into place.
|
|
13
|
+
3. Assign each animation a role: arrival (fade+rise), exit (fade+fall), state change, or attention. Different roles get different curves/durations — don't reuse one transition everywhere.
|
|
14
|
+
4. Orchestrate groups with a stagger of 30–60ms per item so lists cascade; cap total sequence length near 500ms so it never feels slow.
|
|
15
|
+
5. Prefer transform-driven motion (translate/scale) and physics-based springs (Framer Motion `type: "spring"`, sensible stiffness/damping) over linear tweens for anything interactive.
|
|
16
|
+
6. Provide a global `prefers-reduced-motion` fallback that collapses movement to opacity-only, and document the tokens so the team reuses them.
|
|
17
|
+
|
|
18
|
+
## Rules
|
|
19
|
+
- Motion must communicate (where did this come from, what changed), never decorate for its own sake.
|
|
20
|
+
- Never use `ease-in-out` for entrances — it starts slow and feels sluggish; reserve it for looping/ambient motion.
|
|
21
|
+
- Exits are faster than entrances (~0.7×); users have already decided, so get out of the way.
|
|
22
|
+
- No transition longer than ~500ms on an interaction the user is waiting on.
|
|
23
|
+
- One token set, imported everywhere — a stray `transition: all 0.3s` is a bug, not a shortcut.
|
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: page-transitions
|
|
3
|
-
description: Add smooth route/page transitions with the View Transitions API or Framer that preserve context.
|
|
4
|
-
category: ui-design
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# Page Transitions
|
|
8
|
-
|
|
9
|
-
Reach for this when route changes feel abrupt — a well-crafted transition maintains spatial continuity so users keep their place between views.
|
|
10
|
-
|
|
11
|
-
1. Pick the mechanism: native View Transitions API (`document.startViewTransition`, or `@view-transition { navigation: auto }` for MPAs) where supported; Framer Motion `AnimatePresence` with `mode="wait"` for React SPAs.
|
|
12
|
-
2. Default to a fast crossfade (~200–300ms) for unrelated routes; it's invisible-but-smooth and the safest baseline.
|
|
13
|
-
3. For shared elements (a card → its detail page), give both a matching `view-transition-name` (or Framer `layoutId`) so the element morphs in place — this is the high-value move.
|
|
14
|
-
4. Tune the generated pseudo-elements: style `::view-transition-old(root)` / `::view-transition-new(root)` with your easing tokens; clip-path or slide for directional hierarchy (forward = in from right, back = out to right).
|
|
15
|
-
5. Avoid layout shift mid-transition: hold scroll position or restore it explicitly, and ensure the incoming page's above-fold content is ready (Suspense/loaded data) before revealing.
|
|
16
|
-
6. Always ship a no-transition fallback for unsupported browsers (feature-detect `startViewTransition`) and honor `prefers-reduced-motion` with an instant swap.
|
|
17
|
-
|
|
18
|
-
## Rules
|
|
19
|
-
- A transition must orient the user, not entertain — if it makes navigation feel slower, shorten or cut it.
|
|
20
|
-
- Keep durations ≤300ms; users navigate constantly and a flashy 600ms transition becomes friction by the tenth click.
|
|
21
|
-
- Shared-element transitions need stable, unique names — duplicated `view-transition-name` on one page throws and breaks the animation.
|
|
22
|
-
- Never animate during the transition something that also triggers data fetching — wait for the new view's critical content first.
|
|
23
|
-
- Test back/forward and rapid navigation; transitions must be interruptible and not queue/stack.
|
|
1
|
+
---
|
|
2
|
+
name: page-transitions
|
|
3
|
+
description: Add smooth route/page transitions with the View Transitions API or Framer that preserve context.
|
|
4
|
+
category: ui-design
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Page Transitions
|
|
8
|
+
|
|
9
|
+
Reach for this when route changes feel abrupt — a well-crafted transition maintains spatial continuity so users keep their place between views.
|
|
10
|
+
|
|
11
|
+
1. Pick the mechanism: native View Transitions API (`document.startViewTransition`, or `@view-transition { navigation: auto }` for MPAs) where supported; Framer Motion `AnimatePresence` with `mode="wait"` for React SPAs.
|
|
12
|
+
2. Default to a fast crossfade (~200–300ms) for unrelated routes; it's invisible-but-smooth and the safest baseline.
|
|
13
|
+
3. For shared elements (a card → its detail page), give both a matching `view-transition-name` (or Framer `layoutId`) so the element morphs in place — this is the high-value move.
|
|
14
|
+
4. Tune the generated pseudo-elements: style `::view-transition-old(root)` / `::view-transition-new(root)` with your easing tokens; clip-path or slide for directional hierarchy (forward = in from right, back = out to right).
|
|
15
|
+
5. Avoid layout shift mid-transition: hold scroll position or restore it explicitly, and ensure the incoming page's above-fold content is ready (Suspense/loaded data) before revealing.
|
|
16
|
+
6. Always ship a no-transition fallback for unsupported browsers (feature-detect `startViewTransition`) and honor `prefers-reduced-motion` with an instant swap.
|
|
17
|
+
|
|
18
|
+
## Rules
|
|
19
|
+
- A transition must orient the user, not entertain — if it makes navigation feel slower, shorten or cut it.
|
|
20
|
+
- Keep durations ≤300ms; users navigate constantly and a flashy 600ms transition becomes friction by the tenth click.
|
|
21
|
+
- Shared-element transitions need stable, unique names — duplicated `view-transition-name` on one page throws and breaks the animation.
|
|
22
|
+
- Never animate during the transition something that also triggers data fetching — wait for the new view's critical content first.
|
|
23
|
+
- Test back/forward and rapid navigation; transitions must be interruptible and not queue/stack.
|
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: pricing-page
|
|
3
|
-
description: Design a clear, persuasive pricing page that steers users to the right plan and reduces decision anxiety.
|
|
4
|
-
category: ui-design
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# Pricing Page
|
|
8
|
-
|
|
9
|
-
Reach for this when designing or fixing a pricing page — clarity converts, and confusion kills more deals than price does.
|
|
10
|
-
|
|
11
|
-
1. Limit to 3–4 tiers and anchor with one recommended plan, visually elevated (border accent, "Most popular" badge, slight scale) — the decoy/anchor frames the others.
|
|
12
|
-
2. Make the price unmissable: large tabular number, `/mo` qualifier muted beside it, and a monthly↔annual toggle that shows the savings ("2 months free") to nudge annual.
|
|
13
|
-
3. Build a feature comparison that scales by inclusion, not repetition: list the delta each tier adds, use a clean check matrix for full comparison, and put the highest-value differentiator first.
|
|
14
|
-
4. Give each tier one CTA with consistent verbs; the recommended plan gets the solid primary button, others get quieter ghost buttons. Keep button widths and card heights aligned on the grid.
|
|
15
|
-
5. Defuse risk near the buttons: "no credit card", "cancel anytime", money-back guarantee, and a short FAQ for the predictable objections (overage, downgrades, taxes).
|
|
16
|
-
6. Polish hierarchy and motion: 8px rhythm, equal-height cards, a subtle hover lift on the recommended tier, and `prefers-reduced-motion` respected.
|
|
17
|
-
|
|
18
|
-
## Rules
|
|
19
|
-
- One recommended plan, clearly signaled — an undifferentiated row of equal cards makes users bounce.
|
|
20
|
-
- Show the real total: surface annual-vs-monthly math and any per-seat/usage cost; hidden pricing erodes trust fast.
|
|
21
|
-
- CTA verbs match commitment ("Start free trial" vs "Contact sales"), never a generic "Submit" everywhere.
|
|
22
|
-
- Lead each tier with value/outcomes, not a feature dump; the comparison table is for buyers who already want detail.
|
|
23
|
-
- Keep contrast and legibility on badges/accents ≥4.5:1 — the "popular" highlight must not sacrifice readability.
|
|
1
|
+
---
|
|
2
|
+
name: pricing-page
|
|
3
|
+
description: Design a clear, persuasive pricing page that steers users to the right plan and reduces decision anxiety.
|
|
4
|
+
category: ui-design
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Pricing Page
|
|
8
|
+
|
|
9
|
+
Reach for this when designing or fixing a pricing page — clarity converts, and confusion kills more deals than price does.
|
|
10
|
+
|
|
11
|
+
1. Limit to 3–4 tiers and anchor with one recommended plan, visually elevated (border accent, "Most popular" badge, slight scale) — the decoy/anchor frames the others.
|
|
12
|
+
2. Make the price unmissable: large tabular number, `/mo` qualifier muted beside it, and a monthly↔annual toggle that shows the savings ("2 months free") to nudge annual.
|
|
13
|
+
3. Build a feature comparison that scales by inclusion, not repetition: list the delta each tier adds, use a clean check matrix for full comparison, and put the highest-value differentiator first.
|
|
14
|
+
4. Give each tier one CTA with consistent verbs; the recommended plan gets the solid primary button, others get quieter ghost buttons. Keep button widths and card heights aligned on the grid.
|
|
15
|
+
5. Defuse risk near the buttons: "no credit card", "cancel anytime", money-back guarantee, and a short FAQ for the predictable objections (overage, downgrades, taxes).
|
|
16
|
+
6. Polish hierarchy and motion: 8px rhythm, equal-height cards, a subtle hover lift on the recommended tier, and `prefers-reduced-motion` respected.
|
|
17
|
+
|
|
18
|
+
## Rules
|
|
19
|
+
- One recommended plan, clearly signaled — an undifferentiated row of equal cards makes users bounce.
|
|
20
|
+
- Show the real total: surface annual-vs-monthly math and any per-seat/usage cost; hidden pricing erodes trust fast.
|
|
21
|
+
- CTA verbs match commitment ("Start free trial" vs "Contact sales"), never a generic "Submit" everywhere.
|
|
22
|
+
- Lead each tier with value/outcomes, not a feature dump; the comparison table is for buyers who already want detail.
|
|
23
|
+
- Keep contrast and legibility on badges/accents ≥4.5:1 — the "popular" highlight must not sacrifice readability.
|
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: scroll-animation
|
|
3
|
-
description: Build scroll-triggered and scroll-linked animations (GSAP/Framer Motion) that stay smooth and jank-free.
|
|
4
|
-
category: ui-design
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# Scroll Animation
|
|
8
|
-
|
|
9
|
-
Reach for this when content should reveal, pin, or parallax as the user scrolls — done well it adds depth; done badly it stutters and hijacks the page.
|
|
10
|
-
|
|
11
|
-
1. Decide trigger vs. scrub: reveal-on-enter (fire once when in view) vs. scroll-linked (progress tied to scroll position). Most sections want reveal; reserve scrubbing for hero/storytelling.
|
|
12
|
-
2. For reveals, prefer the native `IntersectionObserver` (or Framer Motion `whileInView` with `viewport={{ once: true }}`) — cheap and battery-friendly. Add a `rootMargin` so it triggers slightly before the element hits the fold.
|
|
13
|
-
3. For scrubbed/pinned sequences use GSAP ScrollTrigger with `scrub: true` (or a small smoothing number); animate only `transform`/`opacity` and let GSAP batch reads/writes.
|
|
14
|
-
4. Build the parallax/depth illusion with differential `translateY` on layers via transform — never animate `background-position` or `top` during scroll.
|
|
15
|
-
5. Stagger grouped reveals (40–80ms) and keep per-element distance small (16–40px rise) — large travel reads as laggy and forces reflow into view.
|
|
16
|
-
6. Disable scroll effects (or make them instant) under `prefers-reduced-motion`, and lazy-init heavy ScrollTriggers below the fold so first paint stays fast.
|
|
17
|
-
|
|
18
|
-
## Rules
|
|
19
|
-
- Never block or rubber-band native scroll; smooth-scroll libraries (Lenis) are opt-in and must respect reduced-motion.
|
|
20
|
-
- Keep work off the scroll thread: no layout-triggering properties, no `getBoundingClientRect` per frame in your own handlers — let IO/ScrollTrigger do it.
|
|
21
|
-
- Content must be fully readable with JS disabled or before the observer fires — start visible, animate enhancement, never hide-until-scripted as the only path.
|
|
22
|
-
- Test on a mid-tier phone at 60fps; if you see dropped frames, reduce simultaneous animated elements before tweaking easing.
|
|
23
|
-
- `will-change: transform` only on elements actively animating, and remove it after — leaving it on bloats the compositor.
|
|
1
|
+
---
|
|
2
|
+
name: scroll-animation
|
|
3
|
+
description: Build scroll-triggered and scroll-linked animations (GSAP/Framer Motion) that stay smooth and jank-free.
|
|
4
|
+
category: ui-design
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Scroll Animation
|
|
8
|
+
|
|
9
|
+
Reach for this when content should reveal, pin, or parallax as the user scrolls — done well it adds depth; done badly it stutters and hijacks the page.
|
|
10
|
+
|
|
11
|
+
1. Decide trigger vs. scrub: reveal-on-enter (fire once when in view) vs. scroll-linked (progress tied to scroll position). Most sections want reveal; reserve scrubbing for hero/storytelling.
|
|
12
|
+
2. For reveals, prefer the native `IntersectionObserver` (or Framer Motion `whileInView` with `viewport={{ once: true }}`) — cheap and battery-friendly. Add a `rootMargin` so it triggers slightly before the element hits the fold.
|
|
13
|
+
3. For scrubbed/pinned sequences use GSAP ScrollTrigger with `scrub: true` (or a small smoothing number); animate only `transform`/`opacity` and let GSAP batch reads/writes.
|
|
14
|
+
4. Build the parallax/depth illusion with differential `translateY` on layers via transform — never animate `background-position` or `top` during scroll.
|
|
15
|
+
5. Stagger grouped reveals (40–80ms) and keep per-element distance small (16–40px rise) — large travel reads as laggy and forces reflow into view.
|
|
16
|
+
6. Disable scroll effects (or make them instant) under `prefers-reduced-motion`, and lazy-init heavy ScrollTriggers below the fold so first paint stays fast.
|
|
17
|
+
|
|
18
|
+
## Rules
|
|
19
|
+
- Never block or rubber-band native scroll; smooth-scroll libraries (Lenis) are opt-in and must respect reduced-motion.
|
|
20
|
+
- Keep work off the scroll thread: no layout-triggering properties, no `getBoundingClientRect` per frame in your own handlers — let IO/ScrollTrigger do it.
|
|
21
|
+
- Content must be fully readable with JS disabled or before the observer fires — start visible, animate enhancement, never hide-until-scripted as the only path.
|
|
22
|
+
- Test on a mid-tier phone at 60fps; if you see dropped frames, reduce simultaneous animated elements before tweaking easing.
|
|
23
|
+
- `will-change: transform` only on elements actively animating, and remove it after — leaving it on bloats the compositor.
|
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: skeleton-loader
|
|
3
|
-
description: Build loading skeletons and shimmer that mirror the final layout to reduce perceived wait and CLS.
|
|
4
|
-
category: ui-design
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# Skeleton Loader
|
|
8
|
-
|
|
9
|
-
Reach for this when content takes a beat to load and a spinner would feel slow or cause layout shift — skeletons preview structure so the page feels fast and stable.
|
|
10
|
-
|
|
11
|
-
1. Mirror the real layout: build the skeleton from the same component with placeholder blocks at the actual sizes/positions, so swapping in data causes zero shift (protects CLS).
|
|
12
|
-
2. Skeleton-ize structure, not pixels: a few grey rounded blocks for title/avatar/lines — vary line widths (last line ~60%) so it reads as text, not a wireframe of every glyph.
|
|
13
|
-
3. Animate with a restrained shimmer: a slow gradient sweep (~1.5–2s linear, looping) or a gentle opacity pulse — subtle, low-contrast, never a strobing distraction.
|
|
14
|
-
4. Use the skeleton only past a perception threshold: render instantly when content is likely <~200ms? show nothing or the cached value; show the skeleton when you expect a real wait, and avoid flash-of-skeleton for sub-100ms loads.
|
|
15
|
-
5. Transition out smoothly: crossfade skeleton → content (~150ms) rather than a hard pop, and stagger if many items resolve together.
|
|
16
|
-
6. Honor `prefers-reduced-motion` by replacing the sweep with a static muted block, and keep the skeleton color derived from your surface/muted tokens for theme + dark-mode correctness.
|
|
17
|
-
|
|
18
|
-
## Rules
|
|
19
|
-
- Skeleton dimensions must equal final dimensions — if the content reflows on load, the skeleton failed its one job.
|
|
20
|
-
- Keep shimmer low-contrast and slow; a fast, high-contrast sweep is more annoying than a spinner.
|
|
21
|
-
- Don't skeleton a whole page when only one region is async — load shell + chrome instantly, skeleton just the pending part.
|
|
22
|
-
- Avoid skeleton flicker: gate on a short delay so fast responses never flash a placeholder.
|
|
23
|
-
- Build from muted/surface tokens so it adapts to light/dark automatically — no hard-coded greys.
|
|
1
|
+
---
|
|
2
|
+
name: skeleton-loader
|
|
3
|
+
description: Build loading skeletons and shimmer that mirror the final layout to reduce perceived wait and CLS.
|
|
4
|
+
category: ui-design
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Skeleton Loader
|
|
8
|
+
|
|
9
|
+
Reach for this when content takes a beat to load and a spinner would feel slow or cause layout shift — skeletons preview structure so the page feels fast and stable.
|
|
10
|
+
|
|
11
|
+
1. Mirror the real layout: build the skeleton from the same component with placeholder blocks at the actual sizes/positions, so swapping in data causes zero shift (protects CLS).
|
|
12
|
+
2. Skeleton-ize structure, not pixels: a few grey rounded blocks for title/avatar/lines — vary line widths (last line ~60%) so it reads as text, not a wireframe of every glyph.
|
|
13
|
+
3. Animate with a restrained shimmer: a slow gradient sweep (~1.5–2s linear, looping) or a gentle opacity pulse — subtle, low-contrast, never a strobing distraction.
|
|
14
|
+
4. Use the skeleton only past a perception threshold: render instantly when content is likely <~200ms? show nothing or the cached value; show the skeleton when you expect a real wait, and avoid flash-of-skeleton for sub-100ms loads.
|
|
15
|
+
5. Transition out smoothly: crossfade skeleton → content (~150ms) rather than a hard pop, and stagger if many items resolve together.
|
|
16
|
+
6. Honor `prefers-reduced-motion` by replacing the sweep with a static muted block, and keep the skeleton color derived from your surface/muted tokens for theme + dark-mode correctness.
|
|
17
|
+
|
|
18
|
+
## Rules
|
|
19
|
+
- Skeleton dimensions must equal final dimensions — if the content reflows on load, the skeleton failed its one job.
|
|
20
|
+
- Keep shimmer low-contrast and slow; a fast, high-contrast sweep is more annoying than a spinner.
|
|
21
|
+
- Don't skeleton a whole page when only one region is async — load shell + chrome instantly, skeleton just the pending part.
|
|
22
|
+
- Avoid skeleton flicker: gate on a short delay so fast responses never flash a placeholder.
|
|
23
|
+
- Build from muted/surface tokens so it adapts to light/dark automatically — no hard-coded greys.
|
|
@@ -1,24 +1,24 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: tailwind-theme
|
|
3
|
-
description: Set up Tailwind with a custom token-driven theme so utilities map to your design system, not defaults
|
|
4
|
-
category: ui-design
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# Tailwind Theme
|
|
8
|
-
|
|
9
|
-
Use this when a Tailwind project still looks like stock Tailwind — default grays, `blue-500`, `shadow-md` everywhere. The fix is wiring Tailwind to your tokens so utility classes carry your brand.
|
|
10
|
-
|
|
11
|
-
1. Define your palette/space/type/radius as CSS custom properties on `:root` (and a dark override), then point Tailwind at them. In v4, do this in CSS via `@theme { --color-accent: …; --radius-lg: …; }`.
|
|
12
|
-
2. Map semantic names into the theme: `bg-surface`, `text-muted`, `border-subtle`, `bg-accent` — so markup reads by role and a re-theme is a token edit, not a find-replace across components.
|
|
13
|
-
3. Replace, don't extend-and-ignore, the defaults you won't use: prune the stock gray ramp and arbitrary blues so nobody reaches for `text-gray-500` and bypasses your system.
|
|
14
|
-
4. Set a real type scale and `fontFamily` from your fonts; configure `--leading-*` and `--tracking-*` so `text-2xl` etc. carry intentional line-height, not Tailwind's generic defaults.
|
|
15
|
-
5. Build repeated patterns as components (React/Astro/Svelte) or `@apply` recipes for true primitives (`.btn`), not by copy-pasting 14 utility classes per button.
|
|
16
|
-
6. Lean on Tailwind's modern features intentionally: container queries (`@container`), `data-*`/`aria-*` variants for state, and the `dark:` variant driven by your `[data-theme]` strategy.
|
|
17
|
-
7. Add `prettier-plugin-tailwindcss` for canonical class order and an ESLint rule to flag arbitrary values (`w-[13px]`) that signal an off-system value.
|
|
18
|
-
|
|
19
|
-
## Rules
|
|
20
|
-
- Utilities must resolve to your tokens; if `bg-accent` doesn't exist, the theme isn't wired up.
|
|
21
|
-
- Prune unused default colors so the stock palette can't be used by accident.
|
|
22
|
-
- Extract a component or `@apply` recipe once a class string repeats; don't shotgun utilities.
|
|
23
|
-
- Arbitrary values (`p-[13px]`, `text-[#3a3a3a]`) are escape hatches — flag and minimize them.
|
|
24
|
-
- Drive `dark:` from the same token strategy as the rest of the system, not a separate color set.
|
|
1
|
+
---
|
|
2
|
+
name: tailwind-theme
|
|
3
|
+
description: Set up Tailwind with a custom token-driven theme so utilities map to your design system, not defaults
|
|
4
|
+
category: ui-design
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Tailwind Theme
|
|
8
|
+
|
|
9
|
+
Use this when a Tailwind project still looks like stock Tailwind — default grays, `blue-500`, `shadow-md` everywhere. The fix is wiring Tailwind to your tokens so utility classes carry your brand.
|
|
10
|
+
|
|
11
|
+
1. Define your palette/space/type/radius as CSS custom properties on `:root` (and a dark override), then point Tailwind at them. In v4, do this in CSS via `@theme { --color-accent: …; --radius-lg: …; }`.
|
|
12
|
+
2. Map semantic names into the theme: `bg-surface`, `text-muted`, `border-subtle`, `bg-accent` — so markup reads by role and a re-theme is a token edit, not a find-replace across components.
|
|
13
|
+
3. Replace, don't extend-and-ignore, the defaults you won't use: prune the stock gray ramp and arbitrary blues so nobody reaches for `text-gray-500` and bypasses your system.
|
|
14
|
+
4. Set a real type scale and `fontFamily` from your fonts; configure `--leading-*` and `--tracking-*` so `text-2xl` etc. carry intentional line-height, not Tailwind's generic defaults.
|
|
15
|
+
5. Build repeated patterns as components (React/Astro/Svelte) or `@apply` recipes for true primitives (`.btn`), not by copy-pasting 14 utility classes per button.
|
|
16
|
+
6. Lean on Tailwind's modern features intentionally: container queries (`@container`), `data-*`/`aria-*` variants for state, and the `dark:` variant driven by your `[data-theme]` strategy.
|
|
17
|
+
7. Add `prettier-plugin-tailwindcss` for canonical class order and an ESLint rule to flag arbitrary values (`w-[13px]`) that signal an off-system value.
|
|
18
|
+
|
|
19
|
+
## Rules
|
|
20
|
+
- Utilities must resolve to your tokens; if `bg-accent` doesn't exist, the theme isn't wired up.
|
|
21
|
+
- Prune unused default colors so the stock palette can't be used by accident.
|
|
22
|
+
- Extract a component or `@apply` recipe once a class string repeats; don't shotgun utilities.
|
|
23
|
+
- Arbitrary values (`p-[13px]`, `text-[#3a3a3a]`) are escape hatches — flag and minimize them.
|
|
24
|
+
- Drive `dark:` from the same token strategy as the rest of the system, not a separate color set.
|
|
@@ -1,24 +1,24 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: typography
|
|
3
|
-
description: Set an intentional modular type scale and font pairing with deliberate rhythm, measure, and hierarchy
|
|
4
|
-
category: ui-design
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# Typography
|
|
8
|
-
|
|
9
|
-
Reach for this when text feels flat or noisy — everything the same weight, headings barely larger than body, lines too long to read. Typography carries most of a UI's perceived quality.
|
|
10
|
-
|
|
11
|
-
1. Pick a scale ratio and generate sizes from one base: 1.2 (minor third) for dense product UI, 1.25–1.333 for marketing. Use `clamp()` for fluid headings: `clamp(2rem, 1.2rem + 3vw, 3.5rem)`.
|
|
12
|
-
2. Pair at most two families with real contrast in role — e.g. a characterful display serif (Fraunces) over a neutral workhorse sans (Inter), or one superfamily across weights. More than two fonts reads as chaos.
|
|
13
|
-
3. Set body deliberately: 15–18px, `line-height` 1.5–1.65, and constrain measure to 60–75ch with `max-width: 65ch`. Long lines are the most common readability failure.
|
|
14
|
-
4. Build hierarchy with weight and size and color together — not size alone. A muted `--text-muted` for captions, a heavier 600–700 for headings, tight tracking (`-0.02em`) on large display text.
|
|
15
|
-
5. Tighten leading as size grows (headings 1.1–1.2, body 1.5) and add `text-wrap: balance` on headings, `pretty` on paragraphs to kill orphans.
|
|
16
|
-
6. Enable OpenType features that fit the context: `font-feature-settings` for tabular numerals in tables/dashboards, ligatures for prose; `font-variant-numeric: tabular-nums` stops number jitter.
|
|
17
|
-
7. Verify the rendered rhythm at real sizes and viewports, not in the abstract — print a paragraph plus h1–h4 and adjust.
|
|
18
|
-
|
|
19
|
-
## Rules
|
|
20
|
-
- Two type families maximum; if you need a third role, change weight, not font.
|
|
21
|
-
- Body measure 60–75ch; never let prose run the full container width.
|
|
22
|
-
- Pair every font-size with an intentional line-height — don't inherit a global 1.5 onto display text.
|
|
23
|
-
- Use tabular numerals anywhere numbers align in columns or update live.
|
|
24
|
-
- Establish scale steps as tokens; reaching for an off-scale `font-size: 19px` is a smell.
|
|
1
|
+
---
|
|
2
|
+
name: typography
|
|
3
|
+
description: Set an intentional modular type scale and font pairing with deliberate rhythm, measure, and hierarchy
|
|
4
|
+
category: ui-design
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Typography
|
|
8
|
+
|
|
9
|
+
Reach for this when text feels flat or noisy — everything the same weight, headings barely larger than body, lines too long to read. Typography carries most of a UI's perceived quality.
|
|
10
|
+
|
|
11
|
+
1. Pick a scale ratio and generate sizes from one base: 1.2 (minor third) for dense product UI, 1.25–1.333 for marketing. Use `clamp()` for fluid headings: `clamp(2rem, 1.2rem + 3vw, 3.5rem)`.
|
|
12
|
+
2. Pair at most two families with real contrast in role — e.g. a characterful display serif (Fraunces) over a neutral workhorse sans (Inter), or one superfamily across weights. More than two fonts reads as chaos.
|
|
13
|
+
3. Set body deliberately: 15–18px, `line-height` 1.5–1.65, and constrain measure to 60–75ch with `max-width: 65ch`. Long lines are the most common readability failure.
|
|
14
|
+
4. Build hierarchy with weight and size and color together — not size alone. A muted `--text-muted` for captions, a heavier 600–700 for headings, tight tracking (`-0.02em`) on large display text.
|
|
15
|
+
5. Tighten leading as size grows (headings 1.1–1.2, body 1.5) and add `text-wrap: balance` on headings, `pretty` on paragraphs to kill orphans.
|
|
16
|
+
6. Enable OpenType features that fit the context: `font-feature-settings` for tabular numerals in tables/dashboards, ligatures for prose; `font-variant-numeric: tabular-nums` stops number jitter.
|
|
17
|
+
7. Verify the rendered rhythm at real sizes and viewports, not in the abstract — print a paragraph plus h1–h4 and adjust.
|
|
18
|
+
|
|
19
|
+
## Rules
|
|
20
|
+
- Two type families maximum; if you need a third role, change weight, not font.
|
|
21
|
+
- Body measure 60–75ch; never let prose run the full container width.
|
|
22
|
+
- Pair every font-size with an intentional line-height — don't inherit a global 1.5 onto display text.
|
|
23
|
+
- Use tabular numerals anywhere numbers align in columns or update live.
|
|
24
|
+
- Establish scale steps as tokens; reaching for an off-scale `font-size: 19px` is a smell.
|
|
@@ -1,24 +1,24 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: ui-polish
|
|
3
|
-
description: Elevate a rough but working UI — fix spacing, alignment, hierarchy, and the small details that read as quality
|
|
4
|
-
category: ui-design
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# UI Polish
|
|
8
|
-
|
|
9
|
-
Reach for this on a UI that functions but feels amateur — cramped, misaligned, flat. Polish is mostly subtraction and precision, not adding more.
|
|
10
|
-
|
|
11
|
-
1. Establish a spacing rhythm: snap every margin/padding/gap to the 4px (or 8px) scale, and make whitespace intentional — generous around groups, tight within them. Inconsistent gaps are the #1 tell.
|
|
12
|
-
2. Fix alignment to an actual grid: align edges and baselines, give content a `max-width` and consistent gutters, and make optical adjustments (icons often need a nudge to look centered).
|
|
13
|
-
3. Sharpen hierarchy: there should be an obvious first, second, and third thing on every screen. Use size, weight, and `--text-muted` color to demote secondary text instead of cramming everything at one level.
|
|
14
|
-
4. Tame the details: soften pure-black text to a near-black, swap harsh `0 1px 2px #000` shadows for layered low-alpha ones, align radii across siblings, and ensure border colors are subtle (low-contrast neutrals).
|
|
15
|
-
5. Polish interaction: add `:focus-visible` rings, hover/active feedback, and tasteful transitions (120–200ms, `ease-out`) on color and transform — never on `width`/`height` (use `transform`).
|
|
16
|
-
6. Handle the real states: empty, loading (skeletons over spinners), error, and long-content overflow. Unpolished UIs only ever show the happy path.
|
|
17
|
-
7. Do a final squint test and a 50%-zoom pass — blurred vision exposes weak hierarchy and ragged alignment instantly.
|
|
18
|
-
|
|
19
|
-
## Rules
|
|
20
|
-
- Every spacing value is on the scale; an unexplained `padding: 13px` is a defect.
|
|
21
|
-
- Increase contrast in hierarchy, decrease it in chrome — borders and shadows should whisper.
|
|
22
|
-
- Animate `transform`/`opacity` only; transitions 120–250ms with `ease-out`/custom cubic-bezier.
|
|
23
|
-
- Never ship without focus-visible, hover, empty, and loading states.
|
|
24
|
-
- When in doubt, remove an element or add whitespace before adding decoration.
|
|
1
|
+
---
|
|
2
|
+
name: ui-polish
|
|
3
|
+
description: Elevate a rough but working UI — fix spacing, alignment, hierarchy, and the small details that read as quality
|
|
4
|
+
category: ui-design
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# UI Polish
|
|
8
|
+
|
|
9
|
+
Reach for this on a UI that functions but feels amateur — cramped, misaligned, flat. Polish is mostly subtraction and precision, not adding more.
|
|
10
|
+
|
|
11
|
+
1. Establish a spacing rhythm: snap every margin/padding/gap to the 4px (or 8px) scale, and make whitespace intentional — generous around groups, tight within them. Inconsistent gaps are the #1 tell.
|
|
12
|
+
2. Fix alignment to an actual grid: align edges and baselines, give content a `max-width` and consistent gutters, and make optical adjustments (icons often need a nudge to look centered).
|
|
13
|
+
3. Sharpen hierarchy: there should be an obvious first, second, and third thing on every screen. Use size, weight, and `--text-muted` color to demote secondary text instead of cramming everything at one level.
|
|
14
|
+
4. Tame the details: soften pure-black text to a near-black, swap harsh `0 1px 2px #000` shadows for layered low-alpha ones, align radii across siblings, and ensure border colors are subtle (low-contrast neutrals).
|
|
15
|
+
5. Polish interaction: add `:focus-visible` rings, hover/active feedback, and tasteful transitions (120–200ms, `ease-out`) on color and transform — never on `width`/`height` (use `transform`).
|
|
16
|
+
6. Handle the real states: empty, loading (skeletons over spinners), error, and long-content overflow. Unpolished UIs only ever show the happy path.
|
|
17
|
+
7. Do a final squint test and a 50%-zoom pass — blurred vision exposes weak hierarchy and ragged alignment instantly.
|
|
18
|
+
|
|
19
|
+
## Rules
|
|
20
|
+
- Every spacing value is on the scale; an unexplained `padding: 13px` is a defect.
|
|
21
|
+
- Increase contrast in hierarchy, decrease it in chrome — borders and shadows should whisper.
|
|
22
|
+
- Animate `transform`/`opacity` only; transitions 120–250ms with `ease-out`/custom cubic-bezier.
|
|
23
|
+
- Never ship without focus-visible, hover, empty, and loading states.
|
|
24
|
+
- When in doubt, remove an element or add whitespace before adding decoration.
|
|
@@ -1,24 +1,24 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: ui-review
|
|
3
|
-
description: Critique a UI for visual quality, consistency, and hierarchy, returning specific, prioritized fixes
|
|
4
|
-
category: ui-design
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# UI Review
|
|
8
|
-
|
|
9
|
-
Use this to evaluate an existing screen with a senior designer's eye and produce concrete, actionable critique — not "looks good" but "the h2 and body are too close in size; bump the scale ratio to 1.25."
|
|
10
|
-
|
|
11
|
-
1. Read intent first: what is this screen for, what's the one primary action? Judge everything against whether the design serves that goal and points the eye to it.
|
|
12
|
-
2. Check hierarchy with the squint test: blur your vision (or zoom to 50%) and confirm the most important element dominates. If everything competes, that's finding #1.
|
|
13
|
-
3. Audit consistency: collect the distinct spacings, font sizes, colors, radii, and shadows in play. Off-scale or near-duplicate values (15px vs 16px, two almost-equal grays) are concrete defects to list.
|
|
14
|
-
4. Measure the fundamentals: contrast ratios on text (AA 4.5:1), body measure (60–75ch), alignment to a grid, and spacing rhythm. Flag exact violations with the failing value.
|
|
15
|
-
5. Inspect states and motion: are focus-visible, hover, empty, loading, and error handled? Are transitions tasteful (120–250ms, eased) or janky/missing?
|
|
16
|
-
6. Assess the aesthetic: is there a point of view, or does it read templated? Name the one change that would most raise perceived quality.
|
|
17
|
-
7. Return findings ranked by impact, each as observation → why it hurts → specific fix, separating must-fix from nice-to-have.
|
|
18
|
-
|
|
19
|
-
## Rules
|
|
20
|
-
- Every critique is specific and actionable — name the element, the failing value, and the fix.
|
|
21
|
-
- Lead with hierarchy and consistency; they drive perceived quality more than color choice.
|
|
22
|
-
- Cite measurable thresholds (contrast, measure, spacing scale) instead of vibes.
|
|
23
|
-
- Prioritize: 3 high-impact fixes beat 30 nitpicks.
|
|
24
|
-
- Acknowledge what works so good decisions survive the next iteration.
|
|
1
|
+
---
|
|
2
|
+
name: ui-review
|
|
3
|
+
description: Critique a UI for visual quality, consistency, and hierarchy, returning specific, prioritized fixes
|
|
4
|
+
category: ui-design
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# UI Review
|
|
8
|
+
|
|
9
|
+
Use this to evaluate an existing screen with a senior designer's eye and produce concrete, actionable critique — not "looks good" but "the h2 and body are too close in size; bump the scale ratio to 1.25."
|
|
10
|
+
|
|
11
|
+
1. Read intent first: what is this screen for, what's the one primary action? Judge everything against whether the design serves that goal and points the eye to it.
|
|
12
|
+
2. Check hierarchy with the squint test: blur your vision (or zoom to 50%) and confirm the most important element dominates. If everything competes, that's finding #1.
|
|
13
|
+
3. Audit consistency: collect the distinct spacings, font sizes, colors, radii, and shadows in play. Off-scale or near-duplicate values (15px vs 16px, two almost-equal grays) are concrete defects to list.
|
|
14
|
+
4. Measure the fundamentals: contrast ratios on text (AA 4.5:1), body measure (60–75ch), alignment to a grid, and spacing rhythm. Flag exact violations with the failing value.
|
|
15
|
+
5. Inspect states and motion: are focus-visible, hover, empty, loading, and error handled? Are transitions tasteful (120–250ms, eased) or janky/missing?
|
|
16
|
+
6. Assess the aesthetic: is there a point of view, or does it read templated? Name the one change that would most raise perceived quality.
|
|
17
|
+
7. Return findings ranked by impact, each as observation → why it hurts → specific fix, separating must-fix from nice-to-have.
|
|
18
|
+
|
|
19
|
+
## Rules
|
|
20
|
+
- Every critique is specific and actionable — name the element, the failing value, and the fix.
|
|
21
|
+
- Lead with hierarchy and consistency; they drive perceived quality more than color choice.
|
|
22
|
+
- Cite measurable thresholds (contrast, measure, spacing scale) instead of vibes.
|
|
23
|
+
- Prioritize: 3 high-impact fixes beat 30 nitpicks.
|
|
24
|
+
- Acknowledge what works so good decisions survive the next iteration.
|
|
@@ -1,24 +1,24 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: web-fonts
|
|
3
|
-
description: Load and pair web fonts performantly — subset, preload, self-host, and avoid FOUT/FOIT and layout shift
|
|
4
|
-
category: ui-design
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# Web Fonts
|
|
8
|
-
|
|
9
|
-
Use this when adding or fixing custom fonts so they look right *and* load fast. Fonts are often a page's heaviest render-blocking asset and a top cause of layout shift.
|
|
10
|
-
|
|
11
|
-
1. Prefer variable fonts in `woff2` only — one file covers all weights, drops requests, and `woff2` is the smallest format every modern browser supports.
|
|
12
|
-
2. Self-host instead of linking Google Fonts: it removes a third-party round-trip and the privacy/consent overhead, and lets you control caching and `font-display`.
|
|
13
|
-
3. Subset aggressively — strip to the scripts/glyphs you use (e.g. latin + latin-ext) with `glyphhanger`/`fonttools`; a full font can shrink 70%+, cutting first paint.
|
|
14
|
-
4. `preload` the one or two critical fonts (the body and primary heading face) with `<link rel="preload" as="font" type="font/woff2" crossorigin>`; don't preload every weight.
|
|
15
|
-
5. Set `font-display: swap` to render text immediately in a fallback, then tune the fallback metrics with `size-adjust`, `ascent-override`, and `descent-override` (or Next/Fontsource defaults) so the swap causes near-zero CLS.
|
|
16
|
-
6. Define a real fallback stack matched in metrics to the web font (`"Inter", system-ui, sans-serif`) so the pre-swap render already looks close.
|
|
17
|
-
7. Measure: confirm in DevTools that fonts are `woff2`, preloaded, swapped, and that the layout-shift score stays near zero after they load.
|
|
18
|
-
|
|
19
|
-
## Rules
|
|
20
|
-
- `woff2` only, variable font when available; never serve `ttf`/`otf`/multiple static weights.
|
|
21
|
-
- Self-host critical fonts; reserve external CDNs for non-critical or fallback cases.
|
|
22
|
-
- Preload only the 1–2 above-the-fold faces — preloading everything defeats the purpose.
|
|
23
|
-
- `font-display: swap` plus metric-overridden fallbacks to keep CLS ≈ 0.
|
|
24
|
-
- Subset to the glyphs you actually render; ship no unused scripts.
|
|
1
|
+
---
|
|
2
|
+
name: web-fonts
|
|
3
|
+
description: Load and pair web fonts performantly — subset, preload, self-host, and avoid FOUT/FOIT and layout shift
|
|
4
|
+
category: ui-design
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Web Fonts
|
|
8
|
+
|
|
9
|
+
Use this when adding or fixing custom fonts so they look right *and* load fast. Fonts are often a page's heaviest render-blocking asset and a top cause of layout shift.
|
|
10
|
+
|
|
11
|
+
1. Prefer variable fonts in `woff2` only — one file covers all weights, drops requests, and `woff2` is the smallest format every modern browser supports.
|
|
12
|
+
2. Self-host instead of linking Google Fonts: it removes a third-party round-trip and the privacy/consent overhead, and lets you control caching and `font-display`.
|
|
13
|
+
3. Subset aggressively — strip to the scripts/glyphs you use (e.g. latin + latin-ext) with `glyphhanger`/`fonttools`; a full font can shrink 70%+, cutting first paint.
|
|
14
|
+
4. `preload` the one or two critical fonts (the body and primary heading face) with `<link rel="preload" as="font" type="font/woff2" crossorigin>`; don't preload every weight.
|
|
15
|
+
5. Set `font-display: swap` to render text immediately in a fallback, then tune the fallback metrics with `size-adjust`, `ascent-override`, and `descent-override` (or Next/Fontsource defaults) so the swap causes near-zero CLS.
|
|
16
|
+
6. Define a real fallback stack matched in metrics to the web font (`"Inter", system-ui, sans-serif`) so the pre-swap render already looks close.
|
|
17
|
+
7. Measure: confirm in DevTools that fonts are `woff2`, preloaded, swapped, and that the layout-shift score stays near zero after they load.
|
|
18
|
+
|
|
19
|
+
## Rules
|
|
20
|
+
- `woff2` only, variable font when available; never serve `ttf`/`otf`/multiple static weights.
|
|
21
|
+
- Self-host critical fonts; reserve external CDNs for non-critical or fallback cases.
|
|
22
|
+
- Preload only the 1–2 above-the-fold faces — preloading everything defeats the purpose.
|
|
23
|
+
- `font-display: swap` plus metric-overridden fallbacks to keep CLS ≈ 0.
|
|
24
|
+
- Subset to the glyphs you actually render; ship no unused scripts.
|