@tangle-network/browser-agent-driver 0.12.1 → 0.14.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 +81 -0
- package/dist/brain/index.d.ts.map +1 -1
- package/dist/brain/index.js +88 -6
- package/dist/brain/index.js.map +1 -1
- package/dist/cli-design-audit.d.ts +2 -0
- package/dist/cli-design-audit.d.ts.map +1 -1
- package/dist/cli-design-audit.js +111 -303
- package/dist/cli-design-audit.js.map +1 -1
- package/dist/cli-view.d.ts +83 -0
- package/dist/cli-view.d.ts.map +1 -0
- package/dist/cli-view.js +397 -0
- package/dist/cli-view.js.map +1 -0
- package/dist/cli.js +32 -1
- package/dist/cli.js.map +1 -1
- package/dist/design/audit/classify.d.ts +20 -0
- package/dist/design/audit/classify.d.ts.map +1 -0
- package/dist/design/audit/classify.js +148 -0
- package/dist/design/audit/classify.js.map +1 -0
- package/dist/design/audit/evaluate.d.ts +49 -0
- package/dist/design/audit/evaluate.d.ts.map +1 -0
- package/dist/design/audit/evaluate.js +355 -0
- package/dist/design/audit/evaluate.js.map +1 -0
- package/dist/design/audit/measure/a11y.d.ts +25 -0
- package/dist/design/audit/measure/a11y.d.ts.map +1 -0
- package/dist/design/audit/measure/a11y.js +144 -0
- package/dist/design/audit/measure/a11y.js.map +1 -0
- package/dist/design/audit/measure/contrast.d.ts +18 -0
- package/dist/design/audit/measure/contrast.d.ts.map +1 -0
- package/dist/design/audit/measure/contrast.js +201 -0
- package/dist/design/audit/measure/contrast.js.map +1 -0
- package/dist/design/audit/measure/index.d.ts +14 -0
- package/dist/design/audit/measure/index.d.ts.map +1 -0
- package/dist/design/audit/measure/index.js +38 -0
- package/dist/design/audit/measure/index.js.map +1 -0
- package/dist/design/audit/pipeline.d.ts +33 -0
- package/dist/design/audit/pipeline.d.ts.map +1 -0
- package/dist/design/audit/pipeline.js +109 -0
- package/dist/design/audit/pipeline.js.map +1 -0
- package/dist/design/audit/roi.d.ts +49 -0
- package/dist/design/audit/roi.d.ts.map +1 -0
- package/dist/design/audit/roi.js +157 -0
- package/dist/design/audit/roi.js.map +1 -0
- package/dist/design/audit/rubric/fragments/domain-ai.md +19 -0
- package/dist/design/audit/rubric/fragments/domain-crypto.md +24 -0
- package/dist/design/audit/rubric/fragments/domain-devtools.md +21 -0
- package/dist/design/audit/rubric/fragments/domain-fintech.md +19 -0
- package/dist/design/audit/rubric/fragments/maturity-prototype.md +36 -0
- package/dist/design/audit/rubric/fragments/type-blog.md +22 -0
- package/dist/design/audit/rubric/fragments/type-docs.md +23 -0
- package/dist/design/audit/rubric/fragments/type-ecommerce.md +23 -0
- package/dist/design/audit/rubric/fragments/type-marketing.md +22 -0
- package/dist/design/audit/rubric/fragments/type-saas-app.md +20 -0
- package/dist/design/audit/rubric/fragments/universal-calibration.md +16 -0
- package/dist/design/audit/rubric/fragments/universal-effort-anchor.md +46 -0
- package/dist/design/audit/rubric/fragments/universal-foundation.md +49 -0
- package/dist/design/audit/rubric/loader.d.ts +49 -0
- package/dist/design/audit/rubric/loader.d.ts.map +1 -0
- package/dist/design/audit/rubric/loader.js +216 -0
- package/dist/design/audit/rubric/loader.js.map +1 -0
- package/dist/design/audit/types.d.ts +166 -0
- package/dist/design/audit/types.d.ts.map +1 -0
- package/dist/design/audit/types.js +8 -0
- package/dist/design/audit/types.js.map +1 -0
- package/dist/drivers/cursor-overlay.d.ts +26 -0
- package/dist/drivers/cursor-overlay.d.ts.map +1 -0
- package/dist/drivers/cursor-overlay.js +235 -0
- package/dist/drivers/cursor-overlay.js.map +1 -0
- package/dist/drivers/playwright.d.ts +32 -0
- package/dist/drivers/playwright.d.ts.map +1 -1
- package/dist/drivers/playwright.js +79 -0
- package/dist/drivers/playwright.js.map +1 -1
- package/dist/drivers/steel.d.ts +135 -0
- package/dist/drivers/steel.d.ts.map +1 -0
- package/dist/drivers/steel.js +236 -0
- package/dist/drivers/steel.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/provider-defaults.d.ts +19 -1
- package/dist/provider-defaults.d.ts.map +1 -1
- package/dist/provider-defaults.js +34 -0
- package/dist/provider-defaults.js.map +1 -1
- package/dist/test-runner.d.ts.map +1 -1
- package/dist/test-runner.js +51 -14
- package/dist/test-runner.js.map +1 -1
- package/dist/types.d.ts +10 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/viewer/viewer.html +940 -0
- package/package.json +3 -2
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: domain-ai
|
|
3
|
+
title: AI / ML Products
|
|
4
|
+
weight: high
|
|
5
|
+
applies-when:
|
|
6
|
+
domain: [ai, ml, llm, agents]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
AI / ML PRODUCT CRITERIA:
|
|
10
|
+
|
|
11
|
+
- Demo prominence: working live demo > screenshots
|
|
12
|
+
- Model differentiation: clear what makes this AI different (latency, quality, cost)
|
|
13
|
+
- Streaming UI quality (for chat/agent products): smooth, no layout shifts, cancelable
|
|
14
|
+
- Tool/function call visualization: when the agent uses tools, can the user see it?
|
|
15
|
+
- Error recovery: model timeouts, content filters, rate limits — all handled gracefully
|
|
16
|
+
- Conversation history: persistent, searchable, exportable
|
|
17
|
+
- Token/cost transparency for paid usage
|
|
18
|
+
- Safety messaging: where appropriate, present without being alarmist
|
|
19
|
+
- Avoid excessive AI cliches (matrix rain, robot illustrations, generic gradients)
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: domain-crypto
|
|
3
|
+
title: Crypto / DeFi
|
|
4
|
+
weight: high
|
|
5
|
+
dimension: trust-signals
|
|
6
|
+
applies-when:
|
|
7
|
+
domain: [crypto, defi, web3]
|
|
8
|
+
type: [marketing, saas-app, tool]
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
DeFi / CRYPTO CRITERIA — evaluate as a trader managing real money:
|
|
12
|
+
|
|
13
|
+
- Trust signals: does the UI feel safe to connect a wallet to? Professional or sketchy?
|
|
14
|
+
- Token displays: balances formatted correctly, right decimals, USD equivalents
|
|
15
|
+
- Transaction clarity: clear what you're signing — amount, fees, slippage shown
|
|
16
|
+
- Loading states: RPC calls are slow — proper indicators for balances, quotes, gas
|
|
17
|
+
- Mobile responsiveness: most DeFi usage is mobile
|
|
18
|
+
- Dark mode: most crypto apps use dark mode — sufficient contrast, visible borders
|
|
19
|
+
- Error handling: RPC fails, wallet rejects, insufficient balance — all handled
|
|
20
|
+
- Swap UX: token selection intuitive, address paste, price impact shown
|
|
21
|
+
- Wallet connection: smooth flow, supported wallets clearly shown
|
|
22
|
+
- Gas/fee transparency: estimates shown before confirmation
|
|
23
|
+
|
|
24
|
+
CALIBRATION: Uniswap v4 / Aave v3 = 8. Average DEX = 5. Rug-pull-looking sites = 2.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: domain-devtools
|
|
3
|
+
title: Developer Tools
|
|
4
|
+
weight: high
|
|
5
|
+
applies-when:
|
|
6
|
+
domain: [devtools, dev, infrastructure, api, sdk]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
DEVELOPER TOOLS CRITERIA:
|
|
10
|
+
|
|
11
|
+
- Code-first messaging: hero shows code, not abstract illustrations
|
|
12
|
+
- Quickstart prominent: "get started in N minutes" with copyable command
|
|
13
|
+
- API docs link visible
|
|
14
|
+
- SDK support transparency: which languages, badges/logos
|
|
15
|
+
- Pricing transparency: free tier clear, no "contact us"
|
|
16
|
+
- GitHub stars, npm downloads, or similar credibility markers
|
|
17
|
+
- Dark mode: developers prefer dark, must be excellent
|
|
18
|
+
- Terminal aesthetics done well, not gimmicky
|
|
19
|
+
- Real customer logos (other dev companies preferred)
|
|
20
|
+
|
|
21
|
+
CALIBRATION: Vercel / Linear / Cursor / Stripe = 9. Average dev tool landing = 6. "Enterprise blockchain" sites = 3.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: domain-fintech
|
|
3
|
+
title: Fintech / Financial Services
|
|
4
|
+
weight: high
|
|
5
|
+
dimension: trust-signals
|
|
6
|
+
applies-when:
|
|
7
|
+
domain: [fintech, finance, banking, payments]
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
FINTECH-SPECIFIC CRITERIA:
|
|
11
|
+
|
|
12
|
+
- Trust signals: security badges, compliance mentions (SOC2, PCI), institutional logos
|
|
13
|
+
- Numerical precision: amounts with correct decimals, currency symbols, no truncation
|
|
14
|
+
- Risk disclosure: fees, terms, warnings prominently shown
|
|
15
|
+
- Conservative aesthetic: financial sites should feel substantial, not playful
|
|
16
|
+
- Data tables: aligned columns, easy scanning, totals visible
|
|
17
|
+
- Form validation: especially strict for money inputs (max digits, format)
|
|
18
|
+
- Color use: green/red for money should follow market conventions (gain/loss)
|
|
19
|
+
- Audit trail visibility: transaction history, statements, exports
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: maturity-prototype
|
|
3
|
+
title: Prototype / Template Detection
|
|
4
|
+
weight: high
|
|
5
|
+
applies-when:
|
|
6
|
+
maturity: [prototype, mvp]
|
|
7
|
+
designSystem: [shadcn, mui, ant, chakra]
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
TEMPLATE-DETECTION CRITERIA — apply when this looks like an unmodified component-library app:
|
|
11
|
+
|
|
12
|
+
The #1 sin of vibecoded / AI-generated apps is shipping unmodified component library defaults:
|
|
13
|
+
- Default border-radius (6-8px shadcn, 4px MUI)
|
|
14
|
+
- Default color palette (zinc/slate grays, blue-600 primary)
|
|
15
|
+
- Default component spacing with no customization
|
|
16
|
+
- Standard card shadows, stock empty states
|
|
17
|
+
- "Looks like every other AI-generated app" = automatic 3-4 score
|
|
18
|
+
|
|
19
|
+
HIERARCHY & INFORMATION ARCHITECTURE:
|
|
20
|
+
- Is everything the same visual weight? (Common AI pattern: all cards same size)
|
|
21
|
+
- Clear primary/secondary/tertiary action distinction?
|
|
22
|
+
- Layout has purpose, or is it "centered column of cards"?
|
|
23
|
+
|
|
24
|
+
DESIGN SYSTEM COHERENCE:
|
|
25
|
+
- More than 3 distinct border-radius values = incoherent
|
|
26
|
+
- Color palette: intentional limited (4-6) vs random accumulation
|
|
27
|
+
- Spacing: 8px grid rhythm vs arbitrary per-component
|
|
28
|
+
- Typography: deliberate scale with 3-4 sizes vs every component picking its own
|
|
29
|
+
|
|
30
|
+
CRAFT SIGNALS (separates 7 from 9):
|
|
31
|
+
- Custom icons or generic Lucide/Heroicons dump?
|
|
32
|
+
- Micro-interactions: button feedback, page transitions, loading skeletons
|
|
33
|
+
- Empty states: designed illustrations or "No data found" text?
|
|
34
|
+
- Error states: helpful with recovery actions or raw error strings?
|
|
35
|
+
|
|
36
|
+
CEILING: Unmodified template apps cap at 4 regardless of functionality. State this in the score reasoning.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: type-blog
|
|
3
|
+
title: Blog / Article
|
|
4
|
+
weight: medium
|
|
5
|
+
applies-when:
|
|
6
|
+
type: [blog]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
BLOG / ARTICLE CRITERIA — evaluate as a reader scanning then committing:
|
|
10
|
+
|
|
11
|
+
- Reading line length: 65-75ch optimal
|
|
12
|
+
- Type pairing: serif body or excellent sans, clear heading distinction
|
|
13
|
+
- Line height: 1.5-1.7 for body text
|
|
14
|
+
- Image usage: meaningful, not stock filler
|
|
15
|
+
- Code blocks (if technical): syntax highlighting, copyable
|
|
16
|
+
- Author byline + date prominent
|
|
17
|
+
- Reading time estimate (helpful)
|
|
18
|
+
- TOC or section nav for long articles
|
|
19
|
+
- Related/next-article surface at the end
|
|
20
|
+
- No autoplay video, no aggressive CTAs interrupting reading
|
|
21
|
+
|
|
22
|
+
CALIBRATION: Stripe blog / Vercel blog / Substack flagships = 9. Medium = 6. WordPress defaults = 4.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: type-docs
|
|
3
|
+
title: Technical Documentation
|
|
4
|
+
weight: high
|
|
5
|
+
dimension: readability
|
|
6
|
+
applies-when:
|
|
7
|
+
type: [docs]
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
TECHNICAL DOCUMENTATION CRITERIA — evaluate as a developer trying to learn:
|
|
11
|
+
|
|
12
|
+
- Reading line length: prose 65-75ch, never wider
|
|
13
|
+
- Code blocks: syntax highlighting, copyable, language labels
|
|
14
|
+
- Information architecture: clear section navigation, breadcrumbs, in-page TOC
|
|
15
|
+
- Search affordance: prominent, fast, results relevant
|
|
16
|
+
- Type hierarchy: H1/H2/H3 visually distinct, scannable
|
|
17
|
+
- Inline code styling distinguishable from prose
|
|
18
|
+
- Anchor links on headings for sharing
|
|
19
|
+
- Dark mode toggle present and well-implemented
|
|
20
|
+
- Performance: doc pages should load instantly (no JS-heavy frameworks for static content)
|
|
21
|
+
- Cross-linking between related concepts
|
|
22
|
+
|
|
23
|
+
CALIBRATION: Stripe Docs / Tailwind Docs / Vercel Docs = 9. Average dev docs = 5. Wall-of-text wikis = 3.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: type-ecommerce
|
|
3
|
+
title: E-commerce / Storefront
|
|
4
|
+
weight: high
|
|
5
|
+
dimension: conversion
|
|
6
|
+
applies-when:
|
|
7
|
+
type: [ecommerce]
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
E-COMMERCE CRITERIA — evaluate as a shopper deciding to spend money:
|
|
11
|
+
|
|
12
|
+
- Product imagery: high-resolution, multiple angles, zoom support
|
|
13
|
+
- Price prominence and clarity (no hidden fees, currency obvious)
|
|
14
|
+
- Add-to-cart affordance: obvious, immediate feedback
|
|
15
|
+
- Trust signals: reviews, ratings, return policy, security badges
|
|
16
|
+
- Filters/sort: discoverable, fast, persistent state
|
|
17
|
+
- Cart accessibility: visible at all times, count badge
|
|
18
|
+
- Checkout flow: single-page or stepped, progress visible, guest checkout option
|
|
19
|
+
- Mobile-first: most ecommerce traffic is mobile
|
|
20
|
+
- Performance: every second of load = ~2% conversion lost
|
|
21
|
+
- Inventory state: clear "in stock" / "out of stock" / "limited"
|
|
22
|
+
|
|
23
|
+
CALIBRATION: Apple / Allbirds / Glossier = 9. Generic Shopify themes = 5. Broken cart flows = 2.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: type-marketing
|
|
3
|
+
title: Marketing / Landing Page
|
|
4
|
+
weight: high
|
|
5
|
+
applies-when:
|
|
6
|
+
type: [marketing]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
MARKETING / LANDING PAGE CRITERIA — evaluate as a potential customer deciding in 10 seconds:
|
|
10
|
+
|
|
11
|
+
- Hero clarity: in 5 seconds, can I tell what this product does and who it's for?
|
|
12
|
+
- Visual hierarchy: does the eye flow naturally from headline → subtext → CTA?
|
|
13
|
+
- CTA prominence: is the primary call-to-action obvious and compelling?
|
|
14
|
+
- Social proof: testimonials, logos, or metrics shown convincingly?
|
|
15
|
+
- Headline typography impactful? Body text readable?
|
|
16
|
+
- Imagery high quality and relevant, or stock-photo generic?
|
|
17
|
+
- Whitespace — does the page breathe or feel cramped?
|
|
18
|
+
- Mobile: hero and CTA work without scrolling on small viewports?
|
|
19
|
+
- Performance perception: feels fast? Images optimized? No layout shift?
|
|
20
|
+
- Footer: navigation complete, legal links present?
|
|
21
|
+
|
|
22
|
+
CALIBRATION: Stripe / Linear / Vercel = 9. Average startup landing = 5. Template sites = 3.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: type-saas-app
|
|
3
|
+
title: SaaS Application
|
|
4
|
+
weight: high
|
|
5
|
+
applies-when:
|
|
6
|
+
type: [saas-app, dashboard]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
SaaS APPLICATION CRITERIA — evaluate as a paying customer would:
|
|
10
|
+
|
|
11
|
+
- Information density: data presented efficiently without clutter?
|
|
12
|
+
- Navigation: features findable in <3 clicks? Sidebar/nav intuitive?
|
|
13
|
+
- Empty states: helpful onboarding prompts when there's no data?
|
|
14
|
+
- Loading states: skeleton screens or spinners, or does content pop in?
|
|
15
|
+
- Form design: inline validation, clear labels, logical tab order?
|
|
16
|
+
- Dashboard layout: most important data prominent, card hierarchy clear?
|
|
17
|
+
- Error states: actionable with clear recovery paths?
|
|
18
|
+
- Pattern consistency: do buttons, inputs, modals follow the same patterns throughout?
|
|
19
|
+
|
|
20
|
+
CALIBRATION: Linear / Notion / Figma = 9. Generic admin templates = 5. Broken CRUD = 3.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: universal-calibration
|
|
3
|
+
title: Universal Calibration Anchor
|
|
4
|
+
weight: critical
|
|
5
|
+
applies-when:
|
|
6
|
+
universal: true
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
CALIBRATION — be ruthlessly honest:
|
|
10
|
+
- 9-10: Only world-class design (Linear, Stripe, Vercel, Apple). Exceptional typography, spacing, micro-interactions. Coherent system, intentional decisions visible everywhere.
|
|
11
|
+
- 7-8: Professional and polished. Clear design system. Minor inconsistencies tolerated if the whole feels coherent.
|
|
12
|
+
- 5-6: Functional but generic. Default component libraries with light customization. Production-ready but uninspired.
|
|
13
|
+
- 3-4: Noticeably broken or amateurish. Inconsistent spacing, clashing colors, poor hierarchy. Default templates with no investment.
|
|
14
|
+
- 1-2: Unusable. Overlapping elements, unreadable text, broken layouts.
|
|
15
|
+
|
|
16
|
+
Most production apps score 5-7. Very few deserve 8+. Do NOT grade on a curve.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: universal-effort-anchor
|
|
3
|
+
title: Effort & ROI Calibration
|
|
4
|
+
weight: critical
|
|
5
|
+
applies-when:
|
|
6
|
+
universal: true
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
EFFORT SCALE — when scoring `effort` on a finding, use these anchors:
|
|
10
|
+
|
|
11
|
+
| Effort | Definition | Examples |
|
|
12
|
+
|---|---|---|
|
|
13
|
+
| 1 | Single CSS value change in a token or shared style | `--color-text: #4b5563`, `padding-bottom: 48px` |
|
|
14
|
+
| 2 | Single component file edit | Update `Button.tsx` to add focus ring |
|
|
15
|
+
| 3 | A few related component edits | Standardize 3 card components to one radius |
|
|
16
|
+
| 4 | New design token + propagation | Add `--space-section`, replace 12 hardcoded values |
|
|
17
|
+
| 5 | New shared component | Build a reusable `Stack` to fix layout drift |
|
|
18
|
+
| 6 | Significant component refactor | Restructure `Sidebar` to support responsive collapse |
|
|
19
|
+
| 7 | Section redesign | Hero rewrite with new copy hierarchy |
|
|
20
|
+
| 8 | Multi-page layout change | Apply new grid container across routes |
|
|
21
|
+
| 9 | Design system overhaul | New type scale + recolor + spacing rebuild |
|
|
22
|
+
| 10 | Full app redesign | Greenfield rebuild |
|
|
23
|
+
|
|
24
|
+
IMPACT SCALE — when scoring `impact` on a finding:
|
|
25
|
+
|
|
26
|
+
| Impact | Definition |
|
|
27
|
+
|---|---|
|
|
28
|
+
| 1-2 | Pure nitpick. Most users wouldn't notice. |
|
|
29
|
+
| 3-4 | Visible if you're looking. Polish detail. |
|
|
30
|
+
| 5-6 | Noticeable on first scan. Affects perceived quality. |
|
|
31
|
+
| 7-8 | Hurts trust or usability. Affects task success. |
|
|
32
|
+
| 9-10 | Breaks the experience. WCAG failures, broken layouts, unreadable text. |
|
|
33
|
+
|
|
34
|
+
BLAST SCALE — when assigning `blast`:
|
|
35
|
+
|
|
36
|
+
| Blast | When |
|
|
37
|
+
|---|---|
|
|
38
|
+
| `page` | Only this page benefits from the fix |
|
|
39
|
+
| `section` | A region of this page (hero, footer, sidebar) |
|
|
40
|
+
| `component` | A shared component (`Card`, `Button`) — multiple pages benefit |
|
|
41
|
+
| `system` | A design token, global style, or universal pattern — every page benefits |
|
|
42
|
+
|
|
43
|
+
RANKING DISCIPLINE — assign these honestly:
|
|
44
|
+
- A 5-second token change with system blast (e.g. fix the body text gray) should DOMINATE a 2-day visual polish refactor.
|
|
45
|
+
- Don't inflate impact to make minor findings sound important. The user fixes the top-5; everything below 5 may never get touched.
|
|
46
|
+
- A "small but everywhere" fix beats a "big but isolated" fix in ROI ranking — that's correct.
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: universal-foundation
|
|
3
|
+
title: Universal Design Foundation
|
|
4
|
+
weight: critical
|
|
5
|
+
applies-when:
|
|
6
|
+
universal: true
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
EVALUATION FRAMEWORK — score each area 1-10:
|
|
10
|
+
|
|
11
|
+
1. LAYOUT & GRID
|
|
12
|
+
- Consistent grid system? What unit? (4px, 8px, etc.)
|
|
13
|
+
- Column alignment: do content blocks align to consistent edges?
|
|
14
|
+
- Container widths appropriate (prose 65-75ch, app fluid)?
|
|
15
|
+
- Z-index layering — any stacking issues, overlapping elements?
|
|
16
|
+
- Orphaned elements floating outside the grid?
|
|
17
|
+
|
|
18
|
+
2. TYPOGRAPHY SYSTEM
|
|
19
|
+
- Type scale: count distinct font-size values. >5-6 suggests no scale.
|
|
20
|
+
- Line height: body 1.4-1.6, headings 1.1-1.3. Flag violations.
|
|
21
|
+
- Letter spacing: headings often need negative tracking (-0.01 to -0.03em).
|
|
22
|
+
- Font pairing: max 2 families. Flag 3+.
|
|
23
|
+
- Long-form text wider than 75ch harms readability.
|
|
24
|
+
|
|
25
|
+
3. SPACING & RHYTHM
|
|
26
|
+
- Grid adherence: % of spacing values that are multiples of the base unit
|
|
27
|
+
- Vertical rhythm: are section gaps consistent?
|
|
28
|
+
- Component internal spacing: consistent padding within similar components?
|
|
29
|
+
- Whitespace ratio: enough breathing room or cramped?
|
|
30
|
+
|
|
31
|
+
4. COMPONENT CONSISTENCY
|
|
32
|
+
- Button variants: how many distinct button styles? Intentional or accidental?
|
|
33
|
+
- Input styling: consistent border, focus ring, label position?
|
|
34
|
+
- Card patterns: same border-radius, shadow, padding?
|
|
35
|
+
- Border radius count: >3 distinct values = incoherent
|
|
36
|
+
- Shadow system: consistent elevation scale or random drops?
|
|
37
|
+
|
|
38
|
+
5. INTERACTION DESIGN
|
|
39
|
+
- Hover states present and meaningful?
|
|
40
|
+
- Visible focus indicators for keyboard nav?
|
|
41
|
+
- Active/pressed feedback?
|
|
42
|
+
- Transition timing 150-300ms with appropriate easing?
|
|
43
|
+
- Loading states: skeleton, spinner, or content pop-in?
|
|
44
|
+
|
|
45
|
+
6. VISUAL POLISH
|
|
46
|
+
- Pixel precision — anything off by 1px?
|
|
47
|
+
- Image quality on retina displays?
|
|
48
|
+
- Icon set consistency — all from one family or mixed?
|
|
49
|
+
- Empty/error states: designed or browser-default?
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rubric loader — reads markdown fragments with YAML frontmatter, composes
|
|
3
|
+
* a rubric from the set whose `applies-when` predicates match a classification.
|
|
4
|
+
*
|
|
5
|
+
* Adding a new rubric: drop a markdown file in `fragments/` (or in
|
|
6
|
+
* `~/.bad/rubrics/` for user fragments). No code changes required.
|
|
7
|
+
*/
|
|
8
|
+
import type { PageClassification, RubricFragment, ComposedRubric } from '../types.js';
|
|
9
|
+
/**
|
|
10
|
+
* Parse a markdown fragment file into a RubricFragment.
|
|
11
|
+
* Frontmatter format:
|
|
12
|
+
* ---
|
|
13
|
+
* id: foo
|
|
14
|
+
* title: Foo
|
|
15
|
+
* weight: high
|
|
16
|
+
* applies-when:
|
|
17
|
+
* type: [marketing]
|
|
18
|
+
* domain: [fintech]
|
|
19
|
+
* ---
|
|
20
|
+
* body markdown...
|
|
21
|
+
*/
|
|
22
|
+
export declare function parseFragment(filePath: string): RubricFragment;
|
|
23
|
+
/**
|
|
24
|
+
* Load all fragments from a directory. Recursive subdirs ignored — fragments are flat.
|
|
25
|
+
*/
|
|
26
|
+
export declare function loadFragments(dir?: string): RubricFragment[];
|
|
27
|
+
/**
|
|
28
|
+
* Predicate evaluator. Returns true if the fragment applies to the classification.
|
|
29
|
+
*
|
|
30
|
+
* Universal fragments always apply.
|
|
31
|
+
* Type/domain/maturity/designSystem predicates are AND-combined: all listed
|
|
32
|
+
* fields must match. Within a field, the classification value must be in the
|
|
33
|
+
* fragment's allowed set.
|
|
34
|
+
*/
|
|
35
|
+
export declare function fragmentApplies(fragment: RubricFragment, classification: PageClassification): boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Compose a rubric from a classification.
|
|
38
|
+
*
|
|
39
|
+
* @param classification - the page classification
|
|
40
|
+
* @param fragments - all loaded fragments (defaults to builtin)
|
|
41
|
+
* @param userFragmentsDir - optional path to user-supplied fragments
|
|
42
|
+
*/
|
|
43
|
+
export declare function composeRubric(classification: PageClassification, fragments?: RubricFragment[], userFragmentsDir?: string): ComposedRubric;
|
|
44
|
+
/**
|
|
45
|
+
* Compose a rubric from an explicit profile name (for `--profile` override).
|
|
46
|
+
* Loads only the matching type fragment + universal fragments.
|
|
47
|
+
*/
|
|
48
|
+
export declare function composeRubricFromProfile(profile: string, fragmentsOverride?: RubricFragment[]): ComposedRubric;
|
|
49
|
+
//# sourceMappingURL=loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../../../src/design/audit/rubric/loader.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,OAAO,KAAK,EACV,kBAAkB,EAClB,cAAc,EACd,cAAc,EAEf,MAAM,aAAa,CAAA;AAYpB;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,cAAc,CAiB9D;AAkED;;GAEG;AACH,wBAAgB,aAAa,CAAC,GAAG,GAAE,MAA8B,GAAG,cAAc,EAAE,CAMnF;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,cAAc,EACxB,cAAc,EAAE,kBAAkB,GACjC,OAAO,CA4BT;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAC3B,cAAc,EAAE,kBAAkB,EAClC,SAAS,CAAC,EAAE,cAAc,EAAE,EAC5B,gBAAgB,CAAC,EAAE,MAAM,GACxB,cAAc,CAgChB;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,MAAM,EACf,iBAAiB,CAAC,EAAE,cAAc,EAAE,GACnC,cAAc,CAsBhB"}
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rubric loader — reads markdown fragments with YAML frontmatter, composes
|
|
3
|
+
* a rubric from the set whose `applies-when` predicates match a classification.
|
|
4
|
+
*
|
|
5
|
+
* Adding a new rubric: drop a markdown file in `fragments/` (or in
|
|
6
|
+
* `~/.bad/rubrics/` for user fragments). No code changes required.
|
|
7
|
+
*/
|
|
8
|
+
import * as fs from 'node:fs';
|
|
9
|
+
import * as path from 'node:path';
|
|
10
|
+
import { fileURLToPath } from 'node:url';
|
|
11
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
12
|
+
const BUILTIN_FRAGMENTS_DIR = path.join(__dirname, 'fragments');
|
|
13
|
+
const WEIGHT_ORDER = {
|
|
14
|
+
critical: 0,
|
|
15
|
+
high: 1,
|
|
16
|
+
medium: 2,
|
|
17
|
+
low: 3,
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Parse a markdown fragment file into a RubricFragment.
|
|
21
|
+
* Frontmatter format:
|
|
22
|
+
* ---
|
|
23
|
+
* id: foo
|
|
24
|
+
* title: Foo
|
|
25
|
+
* weight: high
|
|
26
|
+
* applies-when:
|
|
27
|
+
* type: [marketing]
|
|
28
|
+
* domain: [fintech]
|
|
29
|
+
* ---
|
|
30
|
+
* body markdown...
|
|
31
|
+
*/
|
|
32
|
+
export function parseFragment(filePath) {
|
|
33
|
+
const raw = fs.readFileSync(filePath, 'utf-8');
|
|
34
|
+
const match = raw.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
|
|
35
|
+
if (!match) {
|
|
36
|
+
throw new Error(`fragment ${filePath} missing YAML frontmatter`);
|
|
37
|
+
}
|
|
38
|
+
const [, frontmatter, body] = match;
|
|
39
|
+
const meta = parseMinimalYaml(frontmatter);
|
|
40
|
+
return {
|
|
41
|
+
id: String(meta.id ?? path.basename(filePath, '.md')),
|
|
42
|
+
title: String(meta.title ?? meta.id ?? 'Untitled'),
|
|
43
|
+
weight: meta.weight ?? 'medium',
|
|
44
|
+
appliesWhen: meta['applies-when'] ?? {},
|
|
45
|
+
body: body.trim(),
|
|
46
|
+
...(meta.dimension ? { dimension: String(meta.dimension) } : {}),
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Minimal YAML parser — supports the subset our frontmatter uses:
|
|
51
|
+
* key: value
|
|
52
|
+
* key: [a, b, c]
|
|
53
|
+
* key:
|
|
54
|
+
* subkey: [a, b]
|
|
55
|
+
*
|
|
56
|
+
* Avoids pulling in a full YAML dep for ~50 lines of config.
|
|
57
|
+
*/
|
|
58
|
+
function parseMinimalYaml(text) {
|
|
59
|
+
const lines = text.split('\n');
|
|
60
|
+
const result = {};
|
|
61
|
+
let i = 0;
|
|
62
|
+
while (i < lines.length) {
|
|
63
|
+
const line = lines[i];
|
|
64
|
+
if (!line.trim() || line.trim().startsWith('#')) {
|
|
65
|
+
i++;
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
const topMatch = line.match(/^([a-zA-Z][\w-]*):\s*(.*)$/);
|
|
69
|
+
if (!topMatch) {
|
|
70
|
+
i++;
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
const [, key, valueRaw] = topMatch;
|
|
74
|
+
const value = valueRaw.trim();
|
|
75
|
+
if (value === '') {
|
|
76
|
+
// Nested object — collect indented lines
|
|
77
|
+
const nested = {};
|
|
78
|
+
i++;
|
|
79
|
+
while (i < lines.length && (lines[i].startsWith(' ') || lines[i].trim() === '')) {
|
|
80
|
+
if (!lines[i].trim()) {
|
|
81
|
+
i++;
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
const nm = lines[i].match(/^\s+([a-zA-Z][\w-]*):\s*(.*)$/);
|
|
85
|
+
if (nm) {
|
|
86
|
+
nested[nm[1]] = parseScalarOrList(nm[2].trim());
|
|
87
|
+
}
|
|
88
|
+
i++;
|
|
89
|
+
}
|
|
90
|
+
result[key] = nested;
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
result[key] = parseScalarOrList(value);
|
|
94
|
+
i++;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return result;
|
|
98
|
+
}
|
|
99
|
+
function parseScalarOrList(value) {
|
|
100
|
+
if (value.startsWith('[') && value.endsWith(']')) {
|
|
101
|
+
return value
|
|
102
|
+
.slice(1, -1)
|
|
103
|
+
.split(',')
|
|
104
|
+
.map(s => s.trim())
|
|
105
|
+
.filter(Boolean);
|
|
106
|
+
}
|
|
107
|
+
if (value === 'true')
|
|
108
|
+
return true;
|
|
109
|
+
if (value === 'false')
|
|
110
|
+
return false;
|
|
111
|
+
if (/^-?\d+(\.\d+)?$/.test(value))
|
|
112
|
+
return Number(value);
|
|
113
|
+
return value;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Load all fragments from a directory. Recursive subdirs ignored — fragments are flat.
|
|
117
|
+
*/
|
|
118
|
+
export function loadFragments(dir = BUILTIN_FRAGMENTS_DIR) {
|
|
119
|
+
if (!fs.existsSync(dir))
|
|
120
|
+
return [];
|
|
121
|
+
return fs
|
|
122
|
+
.readdirSync(dir)
|
|
123
|
+
.filter(f => f.endsWith('.md'))
|
|
124
|
+
.map(f => parseFragment(path.join(dir, f)));
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Predicate evaluator. Returns true if the fragment applies to the classification.
|
|
128
|
+
*
|
|
129
|
+
* Universal fragments always apply.
|
|
130
|
+
* Type/domain/maturity/designSystem predicates are AND-combined: all listed
|
|
131
|
+
* fields must match. Within a field, the classification value must be in the
|
|
132
|
+
* fragment's allowed set.
|
|
133
|
+
*/
|
|
134
|
+
export function fragmentApplies(fragment, classification) {
|
|
135
|
+
const w = fragment.appliesWhen;
|
|
136
|
+
if (w.universal)
|
|
137
|
+
return true;
|
|
138
|
+
if (w.type && w.type.length > 0) {
|
|
139
|
+
if (!w.type.includes(classification.type))
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
if (w.domain && w.domain.length > 0) {
|
|
143
|
+
const domainMatch = w.domain.some(d => classification.domain.toLowerCase().includes(d.toLowerCase()));
|
|
144
|
+
if (!domainMatch)
|
|
145
|
+
return false;
|
|
146
|
+
}
|
|
147
|
+
if (w.maturity && w.maturity.length > 0) {
|
|
148
|
+
if (!w.maturity.includes(classification.maturity))
|
|
149
|
+
return false;
|
|
150
|
+
}
|
|
151
|
+
if (w.designSystem && w.designSystem.length > 0) {
|
|
152
|
+
if (!w.designSystem.includes(classification.designSystem))
|
|
153
|
+
return false;
|
|
154
|
+
}
|
|
155
|
+
// If at least one predicate field was set and all matched, apply.
|
|
156
|
+
// If NO predicates were set and not universal, don't apply (be conservative).
|
|
157
|
+
const hasPredicate = !!w.type?.length ||
|
|
158
|
+
!!w.domain?.length ||
|
|
159
|
+
!!w.maturity?.length ||
|
|
160
|
+
!!w.designSystem?.length;
|
|
161
|
+
return hasPredicate;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Compose a rubric from a classification.
|
|
165
|
+
*
|
|
166
|
+
* @param classification - the page classification
|
|
167
|
+
* @param fragments - all loaded fragments (defaults to builtin)
|
|
168
|
+
* @param userFragmentsDir - optional path to user-supplied fragments
|
|
169
|
+
*/
|
|
170
|
+
export function composeRubric(classification, fragments, userFragmentsDir) {
|
|
171
|
+
const all = [
|
|
172
|
+
...(fragments ?? loadFragments(BUILTIN_FRAGMENTS_DIR)),
|
|
173
|
+
...(userFragmentsDir ? loadFragments(userFragmentsDir) : []),
|
|
174
|
+
];
|
|
175
|
+
const matched = all
|
|
176
|
+
.filter(f => fragmentApplies(f, classification))
|
|
177
|
+
.sort((a, b) => WEIGHT_ORDER[a.weight] - WEIGHT_ORDER[b.weight]);
|
|
178
|
+
const body = matched
|
|
179
|
+
.map(f => `## ${f.title}\n\n${f.body}`)
|
|
180
|
+
.join('\n\n---\n\n');
|
|
181
|
+
// Calibration is the universal-calibration fragment if loaded; otherwise
|
|
182
|
+
// a sensible default.
|
|
183
|
+
const calFragment = matched.find(f => f.id === 'universal-calibration');
|
|
184
|
+
const calibration = calFragment?.body ??
|
|
185
|
+
'Score 1-10. Most production apps score 5-7. Only world-class deserves 8+. Be honest.';
|
|
186
|
+
// Custom dimensions contributed by fragments (deduped, preserves order)
|
|
187
|
+
const dimensions = Array.from(new Set(matched.map(f => f.dimension).filter((d) => Boolean(d))));
|
|
188
|
+
return {
|
|
189
|
+
fragments: matched,
|
|
190
|
+
body,
|
|
191
|
+
calibration,
|
|
192
|
+
dimensions,
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Compose a rubric from an explicit profile name (for `--profile` override).
|
|
197
|
+
* Loads only the matching type fragment + universal fragments.
|
|
198
|
+
*/
|
|
199
|
+
export function composeRubricFromProfile(profile, fragmentsOverride) {
|
|
200
|
+
const all = fragmentsOverride ?? loadFragments(BUILTIN_FRAGMENTS_DIR);
|
|
201
|
+
const wanted = new Set([
|
|
202
|
+
`type-${profile}`,
|
|
203
|
+
'universal-foundation',
|
|
204
|
+
'universal-calibration',
|
|
205
|
+
]);
|
|
206
|
+
const matched = all
|
|
207
|
+
.filter(f => wanted.has(f.id))
|
|
208
|
+
.sort((a, b) => WEIGHT_ORDER[a.weight] - WEIGHT_ORDER[b.weight]);
|
|
209
|
+
const body = matched.map(f => `## ${f.title}\n\n${f.body}`).join('\n\n---\n\n');
|
|
210
|
+
const calFragment = matched.find(f => f.id === 'universal-calibration');
|
|
211
|
+
const calibration = calFragment?.body ??
|
|
212
|
+
'Score 1-10. Most production apps score 5-7. Only world-class deserves 8+. Be honest.';
|
|
213
|
+
const dimensions = Array.from(new Set(matched.map(f => f.dimension).filter((d) => Boolean(d))));
|
|
214
|
+
return { fragments: matched, body, calibration, dimensions };
|
|
215
|
+
}
|
|
216
|
+
//# sourceMappingURL=loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../../../src/design/audit/rubric/loader.ts"],"names":[],"mappings":"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"}
|