ada-agent 0.2.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 -263
- package/bench/README.md +88 -88
- package/bench/swebench.mjs +242 -242
- package/docs/architecture.md +163 -163
- package/docs/architecture.svg +73 -73
- package/docs/cloudflare.md +81 -81
- package/docs/connectors.md +49 -49
- package/docs/integrations.md +62 -62
- package/package.json +66 -65
- 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 -1
- package/src/client/cli.ts +1275 -1262
- package/src/client/models-dev.ts +106 -106
- package/src/selfcheck.ts +404 -390
- package/src/server/config.ts +65 -65
- package/src/server/providers/openai-compat.ts +78 -78
- package/src/server/providers/registry.ts +32 -32
- package/src/server/router.ts +33 -33
- package/src/shared/types.ts +21 -21
|
@@ -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.
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
// Auto-start the ada backend if it isn't reachable. So new users running `ada` for the first time
|
|
2
|
+
// don't have to also remember "start ada-server in another terminal." If the configured backend URL
|
|
3
|
+
// is remote (not localhost), we DON'T spawn anything — the user clearly meant to point at a remote.
|
|
4
|
+
// The spawned child is killed when this process exits.
|
|
5
|
+
|
|
6
|
+
import { spawn } from "node:child_process";
|
|
7
|
+
import { resolve } from "node:path";
|
|
8
|
+
import { fileURLToPath } from "node:url";
|
|
9
|
+
|
|
10
|
+
const LOCAL_HOSTS = new Set(["localhost", "127.0.0.1", "0.0.0.0", "::1", "[::1]"]);
|
|
11
|
+
|
|
12
|
+
/** True if the backend URL points at this machine — the only case we auto-spawn for. */
|
|
13
|
+
export function isLocalBackend(backendUrl: string): boolean {
|
|
14
|
+
try {
|
|
15
|
+
return LOCAL_HOSTS.has(new URL(backendUrl).hostname);
|
|
16
|
+
} catch {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** Probe the backend's /health. The URL passed in is `<base>/v1`; /health is at the base, not /v1. */
|
|
22
|
+
export function healthUrl(backendUrl: string): string {
|
|
23
|
+
try {
|
|
24
|
+
const u = new URL(backendUrl);
|
|
25
|
+
u.pathname = "/health";
|
|
26
|
+
u.search = "";
|
|
27
|
+
return u.toString();
|
|
28
|
+
} catch {
|
|
29
|
+
return `${backendUrl.replace(/\/+$/, "").replace(/\/v\d+$/, "")}/health`;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async function probe(url: string, timeoutMs = 800): Promise<boolean> {
|
|
34
|
+
try {
|
|
35
|
+
const res = await fetch(url, { signal: AbortSignal.timeout(timeoutMs) });
|
|
36
|
+
return res.ok;
|
|
37
|
+
} catch {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** Resolved path to bin/ada-server.mjs (sibling of bin/ada.mjs, packaged in the npm tarball). */
|
|
43
|
+
function serverBin(): string {
|
|
44
|
+
return resolve(fileURLToPath(import.meta.url), "..", "..", "..", "bin", "ada-server.mjs");
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* If the backend isn't responding (and the URL is local), spawn `ada-server` as a child process and
|
|
49
|
+
* wait up to `waitMs` for /health to come up. Returns `"running"` if already alive, `"started"` if
|
|
50
|
+
* we spawned it, `"remote"` if the URL is remote (skipped), or `"failed"` if it didn't come up in
|
|
51
|
+
* time. Sets `process.on(...)` handlers so the child dies with us.
|
|
52
|
+
*/
|
|
53
|
+
export async function ensureBackend(backendUrl: string, opts?: { quiet?: boolean; waitMs?: number }): Promise<"running" | "started" | "remote" | "failed"> {
|
|
54
|
+
const probeUrl = healthUrl(backendUrl);
|
|
55
|
+
if (await probe(probeUrl)) return "running";
|
|
56
|
+
if (!isLocalBackend(backendUrl)) return "remote";
|
|
57
|
+
|
|
58
|
+
if (!opts?.quiet) process.stderr.write("\x1b[2mstarting ada-server…\x1b[0m ");
|
|
59
|
+
const child = spawn(process.execPath, [serverBin()], { stdio: ["ignore", "ignore", "ignore"], detached: false });
|
|
60
|
+
child.unref(); // don't keep parent alive once parent's own work finishes
|
|
61
|
+
const killChild = (): void => {
|
|
62
|
+
try {
|
|
63
|
+
if (!child.killed) child.kill();
|
|
64
|
+
} catch {
|
|
65
|
+
/* ignore */
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
process.once("exit", killChild);
|
|
69
|
+
process.once("SIGINT", () => {
|
|
70
|
+
killChild();
|
|
71
|
+
process.exit(130);
|
|
72
|
+
});
|
|
73
|
+
process.once("SIGTERM", () => {
|
|
74
|
+
killChild();
|
|
75
|
+
process.exit(143);
|
|
76
|
+
});
|
|
77
|
+
child.once("error", () => {
|
|
78
|
+
/* surfaced via the probe loop's timeout */
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
const deadline = Date.now() + (opts?.waitMs ?? 5000);
|
|
82
|
+
while (Date.now() < deadline) {
|
|
83
|
+
await new Promise((r) => setTimeout(r, 150));
|
|
84
|
+
if (await probe(probeUrl, 400)) {
|
|
85
|
+
if (!opts?.quiet) process.stderr.write("\x1b[32mok\x1b[0m\n");
|
|
86
|
+
return "started";
|
|
87
|
+
}
|
|
88
|
+
if (child.exitCode != null) break; // child died — no point waiting more
|
|
89
|
+
}
|
|
90
|
+
if (!opts?.quiet) process.stderr.write("\x1b[31mfailed\x1b[0m\n");
|
|
91
|
+
killChild();
|
|
92
|
+
return "failed";
|
|
93
|
+
}
|