@designesy/score
v0.9.3
Published
Design quality gate for AI-generated UI: score any URL on 45 deterministic checks, A–F grade. Runs locally; browser checks return MANUAL. No required dependencies.
Maintainers
Readme
@designesy/score
Design quality gate for AI-generated UI: score any URL on 45 deterministic checks, A–F grade. This is the standalone engine: it fetches a URL, extracts CSS + :root tokens, and runs every check that needs no browser locally, with no Designesy server required; the browser checks return MANUAL. No required dependencies.
Install
npm install --save-dev @designesy/score
# or
npx @designesy/score <url>CLI
# Score a site (prints formatted report)
npx @designesy/score designesy.org
# CI gate: fail if below threshold
npx @designesy/score linear.app --min-score 70 --min-grade B
# JSON output for pipelines
npx @designesy/score vercel.com --json
# Markdown review format (jakubkrehel-compatible)
npx @designesy/score stripe.com --format review
# Scoring scope: contract (strict, all checks penalize absence) or universal (fair to external sites)
npx @designesy/score designesy.org --scope contractOptions
| Flag | Description |
|---|---|
| --format <f> | Emission format: designesy (default), canonical, review, google |
| --scope <s> | Scoring scope: contract (strict) or universal (fair, default auto-detect) |
| --min-score <n> | Exit 1 if score < n |
| --min-grade <g> | Exit 1 if grade worse than g (A/B/C/D/F) |
| --json | Output raw JSON (no formatted report) |
| --quiet | Only output on failure (CI noise reduction) |
| --help, -h | Show help |
Library
import { scoreUrl } from '@designesy/score';
const result = await scoreUrl('https://linear.app');
console.log(result.score); // 72.5
console.log(result.grade); // 'C'
console.log(result.pass); // 28
console.log(result.fail); // 3
console.log(result.checks); // [{ id: 'v01', status: 'PASS', detail: '...' }, ...]The 45 checks
| Category | Checks | Weight | |---|---|---| | cadence | v14, v15, v16, v17, v18, v19, v20, v26, v28, x01, x02, x03 | 18 | | accessibility | v06, v22, v24, v25, v27, v35, v44 | 15 | | semantic | v42, v43 | 12 | | motion | v05, v11, v12, v23, v45 | 10 | | tokens | v01, v29 | 9 | | takt | v10, v13 | 8 | | copywriting | v38, v39, v40, v41 | 8 | | poise | v04, v08, v09 | 7 | | identity | v07, v34 | 6 | | interaction | v03 | 6 | | performance | v21 | 6 | | security | v36 | 5 | | spec | v37 | 4 | | responsive | v02 | 3 |
Plus 12 anti-slop deductions (S1 to S12) and 7 originality lifts (O1 to O7).
Scoring
- Weighted per-category scoring (PASS = 1.0, WARN = 0.5, FAIL = 0, SKIP/MANUAL excluded)
- Anti-slop deductions (up to -20pts for generic AI patterns)
- Originality lifts (up to +8pts for bespoke craft signals)
- Accessibility floor (score capped at C/70 when any a11y FAIL exists)
- Hard-fail ceilings (critical issues cap the score further)
Scope system
- contract (default for designesy.org): All 45 checks active. Absence = WARN/FAIL.
- universal (default for external sites): Optional features SKIP on absence instead of penalizing.
Auto-detect: designesy.org → contract, everything else → universal.
Dependencies
The engine uses only Node.js built-ins:
node:httpsfor URL fetching (avoids the Windows libuv/undici crash)node:dnsfor SSRF guard (DNS resolution validation)- No
ipaddr.js, noundici, nofetch()
One optional dependency: Google's @google/design.md linter (Apache-2.0), the version the hosted engine runs. v37 uses it to lint a site's /DESIGN.md. npm installs it by default, npx included. Installed without it (npm install --omit=optional), v37 reports MANUAL (not run, weight 0) for a site that serves a DESIGN.md, and every other check is unchanged.
SSRF guard
Built-in SSRF protection rejects:
- Private IP ranges (10.x, 127.x, 169.254.x, 172.16-31.x, 192.168.x)
- Cloud metadata endpoints (169.254.169.254)
- All IPv6 addresses
- Encoded IP bypasses (decimal, octal, hex)
- Redirect chains to internal addresses
License
MIT © Designesy
