diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b070b1..fd1c4ea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -87,6 +87,22 @@ release makes it installable, routable and internally consistent. accessibility requirement. - The README structure diagram omitted `tokens.json` and `tokens.tailwind.css` and referenced an `assets/decision-tree.png` that does not exist. +- **The repository's own example pages failed its own gates**, found by running + `scripts/screenshot.mjs` against them: + - Horizontal overflow at 390px in `07-neumorphism`, `11-editorial-magazine` + and `14-3d-spatial-ui` (nav bars with no mobile treatment) — a 🔴 blocker. + - Horizontal overflow at 360px in `12-maximalism`, and page-level scroll from + the deliberate 120% headline bleed in `06-brutalist-anti-grid` (now clipped + at the hero, so the bleed reads as intent rather than as a scrollbar). + - `03-liquid-glass`, `04-bento-grid`, `05-neo-brutalism`, `08-claymorphism` + and `13-y2k-retrofuturism` deleted their nav links below 900px with no + replacement — the "desktop stripped for mobile" failure. The link row now + moves to its own line and keeps a 44px tap height. + - Touch targets under 44px in `05`, `07` and `10`. + - `13-y2k-retrofuturism`'s chrome hero headline measured **1.1:1** against + the light sky — the exact failure `accessibility/ACCESSIBILITY.md` names + for that style. It now sits on a dark `--ink` plate (3.8:1 at the gradient's + darkest stop), which is also the style's own documented signature move. - `07-neumorphism` had a duplicated "When NOT to use" section and a vague citation. diff --git a/README.md b/README.md index e74260f..6e20d41 100644 --- a/README.md +++ b/README.md @@ -228,9 +228,7 @@ See the whole thing run on one brief: | 14 | [3D / Spatial UI](styles/14-3d-spatial-ui/) | Depth you can move through | Web3, launches, immersive | low–med | | 15 | [Kinetic Typography](styles/15-expressive-kinetic-typography/) | Type as the interface | Portfolios, campaigns | low | -[**Preview gallery of all 15 example pages**](docs/index.html) — open it locally, or -publish it by enabling GitHub Pages for this repository (*Settings → Pages → -main / `docs`*), which serves it at `https://aievolutionpl.github.io/agent-design-taste/`. +[**Live previews of all 15 example pages →**](https://aievolutionpl.github.io/agent-design-taste/) · [source](docs/index.html) ### What is inside every style folder diff --git a/README.pl.md b/README.pl.md index a18e7f0..253011b 100644 --- a/README.pl.md +++ b/README.pl.md @@ -241,10 +241,7 @@ Zobacz cały proces na jednym briefie: | 14 | [3D / Spatial UI](styles/14-3d-spatial-ui/) | Głębia, przez którą się przechodzi | Web3, premiery, immersja | niska–śr. | | 15 | [Kinetic Typography](styles/15-expressive-kinetic-typography/) | Typografia jako interfejs | Portfolia, kampanie | niska | -[**Galeria podglądów wszystkich 15 stron przykładowych**](docs/index.html) — otwórz -lokalnie albo opublikuj, włączając GitHub Pages dla tego repozytorium -(*Settings → Pages → main / `docs`*), co udostępni ją pod adresem -`https://aievolutionpl.github.io/agent-design-taste/`. +[**Podglądy na żywo wszystkich 15 stron przykładowych →**](https://aievolutionpl.github.io/agent-design-taste/) · [źródło](docs/index.html) ### Co jest w każdym folderze stylu diff --git a/scripts/screenshot.mjs b/scripts/screenshot.mjs index 86d3859..2d31438 100644 --- a/scripts/screenshot.mjs +++ b/scripts/screenshot.mjs @@ -63,34 +63,75 @@ for (const target of list) { reducedMotion: vp.name === 'narrow' ? 'reduce' : 'no-preference', }); const page = await ctx.newPage(); - await page.goto(target.url, { waitUntil: 'networkidle' }).catch(() => {}); - await page.waitForTimeout(350); + // 'load' + fonts.ready rather than 'networkidle': a page with webfonts or a + // long-lived connection never goes idle, and waiting for that is minutes of + // nothing. Layout is settled once fonts have swapped in. + await page.goto(target.url, { waitUntil: 'load', timeout: 20_000 }).catch(() => {}); + await page.evaluate(() => document.fonts?.ready).catch(() => {}); + await page.waitForTimeout(250); const metrics = await page.evaluate(() => { const de = document.documentElement; + const label = (el) => el.tagName.toLowerCase() + + (typeof el.className === 'string' && el.className.trim() + ? '.' + el.className.trim().split(/\s+/)[0] : ''); + + // An element clipped by an ancestor's overflow does not create page scroll, + // so it must not be blamed for it (deliberate bleed is a valid technique). + const clipped = (el) => { + for (let p = el.parentElement; p && p !== de; p = p.parentElement) { + const ox = getComputedStyle(p).overflowX; + if (ox === 'hidden' || ox === 'clip' || ox === 'auto' || ox === 'scroll') return true; + } + return false; + }; + let widest = null; let widestOverflow = 0; for (const el of document.body.querySelectorAll('*')) { + if (clipped(el)) continue; const r = el.getBoundingClientRect(); const over = Math.round(r.right - de.clientWidth); - if (over > widestOverflow) { - widestOverflow = over; - widest = el.tagName.toLowerCase() + (el.className && typeof el.className === 'string' - ? '.' + el.className.trim().split(/\s+/)[0] : ''); - } + if (over > widestOverflow) { widestOverflow = over; widest = label(el); } } - const tiny = [...document.querySelectorAll('a,button,input,select,[role="button"]')] - .filter((el) => { - const r = el.getBoundingClientRect(); - return r.width > 0 && (r.width < 44 || r.height < 44); - }).length; - return { - scrollW: de.scrollWidth, - clientW: de.clientWidth, - widest, - widestOverflow, - tiny, + + // WCAG 2.2 SC 2.5.8 exempts targets that sit inline within a sentence or + // block of text, so an inline link inside a paragraph is not a finding. + const inlineInText = (el) => { + if (getComputedStyle(el).display !== 'inline') return false; + const p = el.parentElement; + if (!p) return false; + return (p.textContent || '').trim().length > (el.textContent || '').trim().length + 8; }; + + const targets = [...document.querySelectorAll('a,button,input,select,[role="button"]')] + .map((el) => ({ el, r: el.getBoundingClientRect() })) + .filter((t) => t.r.width > 0 && t.r.height > 0); + + // SC 2.5.8 also exempts an undersized target whose 44px-diameter circle + // does not overlap any neighbour's — a narrow nav link with real spacing + // around it is comfortable to tap. Only flag targets that are BOTH + // undersized and crowded. + const crowded = (t) => targets.some((o) => { + if (o.el === t.el) return false; + const dx = (t.r.left + t.r.width / 2) - (o.r.left + o.r.width / 2); + const dy = (t.r.top + t.r.height / 2) - (o.r.top + o.r.height / 2); + return Math.hypot(dx, dy) < 44; + }); + + const small = targets + .filter(({ el, r }) => { + if (inlineInText(el)) return false; + if (r.width >= 44 && r.height >= 44) return false; + // Height below the comfortable minimum is a finding regardless of + // spacing — a 15px-tall link is hard to hit even in open space. + if (r.height < 32) return true; + return crowded({ el, r }); + }) + .map(({ el }) => el) + .map((el) => `${label(el)} ${Math.round(el.getBoundingClientRect().width)}x${Math.round(el.getBoundingClientRect().height)}`); + + return { scrollW: de.scrollWidth, clientW: de.clientWidth, widest, widestOverflow, small }; }); const overflow = metrics.scrollW > metrics.clientW + 1; @@ -104,7 +145,10 @@ for (const target of list) { (metrics.widest ? ` (widest: ${metrics.widest})` : '')); if (isMobile) blockers++; } - if (isMobile && metrics.tiny > 0) flags.push(`${metrics.tiny} touch target(s) < 44px`); + if (isMobile && metrics.small.length > 0) { + flags.push(`${metrics.small.length} touch target(s) < 44px: ` + + metrics.small.slice(0, 3).join(', ') + (metrics.small.length > 3 ? ' …' : '')); + } const status = flags.length ? (isMobile && overflow ? '🔴' : '🟠') : ' '; console.log(` ${status} ${vp.name.padEnd(8)} ${String(vp.width).padStart(4)}px ` + diff --git a/styles/01-minimalism/example.html b/styles/01-minimalism/example.html index a741334..a76d65a 100644 --- a/styles/01-minimalism/example.html +++ b/styles/01-minimalism/example.html @@ -42,6 +42,12 @@ footer{border-top:1px solid var(--border);padding:40px 0;color:var(--sec);font-size:14px;display:flex;justify-content:space-between} @media(max-width:900px){.hero{grid-template-columns:1fr;padding:64px 0}h1{font-size:34px}.features,.pricing{grid-template-columns:1fr}.feature{padding:24px 0}} @media(prefers-reduced-motion:reduce){*{transition:none!important}} +@media(max-width:720px){ + nav{flex-wrap:wrap;row-gap:12px} + nav .logo{flex:1 1 auto} + nav ul{order:3;width:100%;gap:20px;flex-wrap:wrap} + nav a{display:inline-flex;align-items:center;min-height:44px} +} diff --git a/styles/03-liquid-glass/example.html b/styles/03-liquid-glass/example.html index 78e4974..ba6c88d 100644 --- a/styles/03-liquid-glass/example.html +++ b/styles/03-liquid-glass/example.html @@ -71,6 +71,13 @@ *{transition-duration:0ms!important;animation:none!important} .mesh::before,.mesh::after,.mesh i{animation:none!important} } +@media(max-width:900px){nav.docknav ul{display:flex}} +@media(max-width:720px){ + nav{flex-wrap:wrap;row-gap:12px} + nav .logo{flex:1 1 auto} + nav ul{order:3;width:100%;gap:20px;flex-wrap:wrap} + nav a{display:inline-flex;align-items:center;min-height:44px} +} diff --git a/styles/04-bento-grid/example.html b/styles/04-bento-grid/example.html index ab0f13f..f34f283 100644 --- a/styles/04-bento-grid/example.html +++ b/styles/04-bento-grid/example.html @@ -72,6 +72,13 @@ nav ul{display:none} } @media(prefers-reduced-motion:reduce){*{transition:none!important;transform:none!important}} +@media(max-width:900px){nav ul{display:flex}} +@media(max-width:720px){ + nav{flex-wrap:wrap;row-gap:12px} + nav .logo{flex:1 1 auto} + nav ul{order:3;width:100%;gap:20px;flex-wrap:wrap} + nav a{display:inline-flex;align-items:center;min-height:44px} +} diff --git a/styles/05-neo-brutalism/example.html b/styles/05-neo-brutalism/example.html index 418332d..eade065 100644 --- a/styles/05-neo-brutalism/example.html +++ b/styles/05-neo-brutalism/example.html @@ -74,6 +74,20 @@ nav ul{display:none} } @media(prefers-reduced-motion:reduce){.marquee span{animation:none}} +@media(max-width:720px){ + .btn{min-height:44px;display:inline-flex;align-items:center} + nav{flex-wrap:wrap;row-gap:12px} + nav .logo{flex:1 1 auto} + nav ul{order:3;width:100%;gap:20px;flex-wrap:wrap} + nav a{display:inline-flex;align-items:center;min-height:44px} +} +@media(max-width:900px){nav ul{display:flex}} +@media(max-width:720px){ + nav{flex-wrap:wrap;row-gap:12px} + nav .logo{flex:1 1 auto} + nav ul{order:3;width:100%;gap:20px;flex-wrap:wrap} + nav a{display:inline-flex;align-items:center;min-height:44px} +} diff --git a/styles/06-brutalist-anti-grid/example.html b/styles/06-brutalist-anti-grid/example.html index 9664c02..07610bd 100644 --- a/styles/06-brutalist-anti-grid/example.html +++ b/styles/06-brutalist-anti-grid/example.html @@ -59,6 +59,13 @@ .band h2{width:100%} } @media(prefers-reduced-motion:reduce){.marquee span{animation:none}*{transition:none!important}} +@media(max-width:720px){ + nav{flex-wrap:wrap;row-gap:12px} + nav .logo{flex:1 1 auto} + nav ul{order:3;width:100%;gap:20px;flex-wrap:wrap} + nav a{display:inline-flex;align-items:center;min-height:44px} +} +.hero{overflow-x:clip} diff --git a/styles/07-neumorphism/example.html b/styles/07-neumorphism/example.html index 0382064..a00f285 100644 --- a/styles/07-neumorphism/example.html +++ b/styles/07-neumorphism/example.html @@ -64,6 +64,13 @@ footer{padding:40px 0 56px;color:var(--sec);font-size:14px;display:flex;justify-content:space-between;border-top:1px solid var(--dark);margin-top:48px} @media(max-width:900px){.hero{grid-template-columns:1fr;padding:56px 0}h1{font-size:34px}.cards,.pricing{grid-template-columns:1fr}section{padding:64px 0}} @media(prefers-reduced-motion:reduce){*{transition:none!important}} +@media(max-width:720px){ + .chip{min-height:44px} + nav{flex-wrap:wrap;row-gap:12px} + nav .logo{flex:1 1 auto} + nav ul{order:3;width:100%;gap:20px;flex-wrap:wrap} + nav a{display:inline-flex;align-items:center;min-height:44px} +} diff --git a/styles/08-claymorphism/example.html b/styles/08-claymorphism/example.html index dcb605d..4576430 100644 --- a/styles/08-claymorphism/example.html +++ b/styles/08-claymorphism/example.html @@ -74,6 +74,13 @@ nav ul{display:none} } @media(prefers-reduced-motion:reduce){*{transition:none!important;transform:none!important}} +@media(max-width:900px){nav ul{display:flex}} +@media(max-width:720px){ + nav{flex-wrap:wrap;row-gap:12px} + nav .logo{flex:1 1 auto} + nav ul{order:3;width:100%;gap:20px;flex-wrap:wrap} + nav a{display:inline-flex;align-items:center;min-height:44px} +} diff --git a/styles/09-skeuomorphism-tactile/example.html b/styles/09-skeuomorphism-tactile/example.html index 279f2ad..acb41dd 100644 --- a/styles/09-skeuomorphism-tactile/example.html +++ b/styles/09-skeuomorphism-tactile/example.html @@ -97,6 +97,12 @@ .knob{width:64px;height:64px} } @media(prefers-reduced-motion:reduce){*{transition:none!important}} +@media(max-width:720px){ + nav{flex-wrap:wrap;row-gap:12px} + nav .logo{flex:1 1 auto} + nav ul{order:3;width:100%;gap:20px;flex-wrap:wrap} + nav a{display:inline-flex;align-items:center;min-height:44px} +} diff --git a/styles/10-swiss-international/example.html b/styles/10-swiss-international/example.html index 4f5176b..4b676e7 100644 --- a/styles/10-swiss-international/example.html +++ b/styles/10-swiss-international/example.html @@ -47,6 +47,15 @@ footer{border-top:1px solid var(--text);padding:40px 0;color:var(--sec);font:500 12px 'IBM Plex Mono',monospace;letter-spacing:.08em;text-transform:uppercase;display:flex;justify-content:space-between;gap:24px;flex-wrap:wrap} @media(max-width:900px){.hero{grid-template-columns:1fr;padding:64px 0}.hero-meta{border-left:0;padding-left:0;border-top:1px solid var(--border);padding-top:16px}h1{font-size:36px}.sec-head{grid-template-columns:1fr;gap:8px}.cols,.proj{grid-template-columns:1fr}.col+.col{border-left:0;padding-left:0;border-top:1px solid var(--border);padding-top:16px;margin-top:16px}.col{padding:0}} @media(prefers-reduced-motion:reduce){*{transition:none!important}} +@media(max-width:720px){ + /* project-row links become full-width rows: keep the 12px mono label, + give the tap area real height without changing the type */ + .proj a{display:flex;align-items:center;min-height:44px} + nav{flex-wrap:wrap;row-gap:12px} + nav .logo{flex:1 1 auto} + nav ul{order:3;width:100%;gap:20px;flex-wrap:wrap} + nav a{display:inline-flex;align-items:center;min-height:44px} +} diff --git a/styles/11-editorial-magazine/example.html b/styles/11-editorial-magazine/example.html index 4627139..39e6b2c 100644 --- a/styles/11-editorial-magazine/example.html +++ b/styles/11-editorial-magazine/example.html @@ -46,6 +46,12 @@ footer{border-top:1px solid var(--border);margin-top:96px;padding:40px 0;color:var(--sec);font:400 13px Inter,sans-serif;display:flex;justify-content:space-between;gap:24px;flex-wrap:wrap} @media(max-width:900px){h1{font-size:34px}.feature,.feature.flip{grid-template-columns:1fr;gap:32px;padding:64px 0}.pullquote{margin:0;max-width:100%;font-size:26px}.plans{grid-template-columns:1fr}.plan{border-right:0;border-bottom:1px solid var(--border)}.plan:last-child{border-bottom:0}} @media(prefers-reduced-motion:reduce){*{transition:none!important}} +@media(max-width:720px){ + nav{flex-wrap:wrap;row-gap:12px} + nav .logo{flex:1 1 auto} + nav ul{order:3;width:100%;gap:20px;flex-wrap:wrap} + nav a{display:inline-flex;align-items:center;min-height:44px} +} diff --git a/styles/12-maximalism/example.html b/styles/12-maximalism/example.html index cdb389b..73b3192 100644 --- a/styles/12-maximalism/example.html +++ b/styles/12-maximalism/example.html @@ -59,6 +59,14 @@ footer{padding:40px 0;color:var(--sec);font-size:14px;display:flex;justify-content:space-between;flex-wrap:wrap;gap:12px} @media(max-width:900px){.lineup,.tickets{grid-template-columns:1fr}.hero{padding:64px 0}.hero .blob{width:220px;height:220px}} @media(prefers-reduced-motion:reduce){*{transition:none!important;animation:none!important}} +@media(max-width:720px){ + nav{flex-wrap:wrap;row-gap:12px} + nav .logo{flex:1 1 auto} + nav ul{order:3;width:100%;gap:20px;flex-wrap:wrap} + nav a{display:inline-flex;align-items:center;min-height:44px} +} +body{overflow-x:clip} +@media(max-width:720px){.hero .actions,.hero p+div{flex-wrap:wrap}.btn{max-width:100%}} diff --git a/styles/13-y2k-retrofuturism/example.html b/styles/13-y2k-retrofuturism/example.html index 91a56a7..9314d34 100644 --- a/styles/13-y2k-retrofuturism/example.html +++ b/styles/13-y2k-retrofuturism/example.html @@ -25,7 +25,12 @@ @keyframes sweep{0%,60%{left:-60%}100%{left:130%}} /* hero — iridescent sky */ .hero{background:var(--sky);border-bottom:1px solid var(--border);text-align:center;padding:96px 0 104px} -.hero h1{font:600 clamp(38px,5.4vw,64px)/1.05 'Orbitron';letter-spacing:.03em;background:linear-gradient(180deg,#EAF6FF 0%,#9FB8CC 55%,#3A4A5C 100%);-webkit-background-clip:text;background-clip:text;color:transparent;margin:18px auto 22px;max-width:16ch} +/* Signature move: chrome type on a dark backing plate. On the light --sky the + light end of the chrome gradient measures ~1.1:1 — a contrast failure. On + --ink the darkest stop measures 3.8:1, clearing the 3:1 large-text floor + while the metal still reads as metal. */ +.hero .plate{display:inline-block;background:var(--ink);border-radius:22px;padding:22px 34px;margin:18px auto 22px;box-shadow:inset 0 1px 0 rgba(255,255,255,.30),0 14px 36px rgba(27,42,58,.24)} +.hero h1{font:600 clamp(38px,5.4vw,64px)/1.05 'Orbitron';letter-spacing:.03em;background:var(--chrome);-webkit-background-clip:text;background-clip:text;color:transparent;margin:0;max-width:16ch} .hero p.lead{color:var(--sec);max-width:52ch;margin:0 auto 32px} .hero .dot{width:110px;height:110px;margin:0 auto 22px;background:var(--irid);border-radius:58% 42% 55% 45%/45% 55% 45% 55%;border:1px solid var(--border);box-shadow:inset 0 3px 4px rgb(255 255 255/.9),inset 0 -6px 10px rgb(27 42 58/.12),0 10px 30px rgb(199 125 255/.35);animation:bob 6s ease-in-out infinite} @keyframes bob{50%{transform:translateY(-6px)}} @@ -61,6 +66,13 @@ footer{display:flex;justify-content:space-between;flex-wrap:wrap;gap:12px;color:var(--sec);font-size:13px;margin-top:14px} @media(max-width:900px){.features,.plans{grid-template-columns:1fr}.hero{padding:64px 0}nav ul{display:none}} @media(prefers-reduced-motion:reduce){*{animation:none!important;transition:none!important}} +@media(max-width:900px){nav ul{display:flex}} +@media(max-width:720px){ + nav{flex-wrap:wrap;row-gap:12px} + nav .logo{flex:1 1 auto} + nav ul{order:3;width:100%;gap:20px;flex-wrap:wrap} + nav a{display:inline-flex;align-items:center;min-height:44px} +} @@ -68,7 +80,7 @@

SYSTEM READY · AUDIO OS 2.0_

-

The future of listening, from the past.

+

The future of listening, from the past.

Bloop turns your library into a living mixtape — auto-blended, gapless, and tuned to whatever you're doing at 2am.

Download free — 34 MB