mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-17 16:46:31 +03:00
The public repo keeps the OSS promise surface: skill, CLI, extension, tests, and the provider build. The site, labs, concept/composition catalogs, image pipeline, Cloudflare functions, and authoring guide move to pbakaus/impeccable-site. concept-seed tests run against a synthetic fixture catalog; the plugin icon and skill categories moved in-repo; build validation narrows to README prose and non-site counts; release notes read from a sibling impeccable-site checkout. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
491 lines
26 KiB
HTML
491 lines
26 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>/impeccable distill | Impeccable</title>
|
|
<meta name="description" content="Ruthless subtraction. Strip designs to their essence.">
|
|
<meta name="theme-color" content="#fafafa">
|
|
<link rel="canonical" href="https://impeccable.style/docs/distill">
|
|
<link rel="icon" type="image/svg+xml" href="../favicon.svg">
|
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
<link href="https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,400;0,600;1,400&family=Instrument+Sans:wght@400;500;600;700&family=Space+Grotesk:wght@400;500;600&display=swap" rel="stylesheet">
|
|
<link rel="stylesheet" href="../css/sub-pages.css">
|
|
|
|
</head>
|
|
<body class="sub-page skills-layout-page">
|
|
<a href="#main" class="skip-link">Skip to content</a>
|
|
<!-- site-header v1 -->
|
|
<header class="site-header" data-site-header>
|
|
<a href="/" class="site-header-brand" aria-label="Impeccable home">
|
|
<svg class="site-header-brand-logo" viewBox="0 0 32 32" aria-hidden="true"><rect width="32" height="32" rx="6" fill="#1a1a1a"/><text x="16" y="24" font-family="system-ui, -apple-system, sans-serif" font-size="22" font-weight="500" fill="#f5f3ef" text-anchor="middle">/</text></svg>
|
|
<span class="site-header-brand-name">Impeccable</span>
|
|
</a>
|
|
<div class="site-header-right">
|
|
<nav class="site-header-nav" aria-label="Primary">
|
|
<a href="/" data-nav="home">Home</a>
|
|
<a href="/designing" data-nav="designing">Designing</a>
|
|
<a href="/docs" data-nav="docs" aria-current="page">Docs</a>
|
|
<a href="/slop" data-nav="slop">Slop</a>
|
|
<a href="/live-mode" data-nav="live">Live</a>
|
|
</nav>
|
|
<a href="https://github.com/pbakaus/impeccable" class="site-header-github" target="_blank" rel="noopener" aria-label="Impeccable on GitHub, 21k stars">
|
|
<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z"/></svg>
|
|
<span class="site-header-github-label">21k</span>
|
|
<svg class="site-header-github-star" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M12 2l2.76 6.36L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l7.24-.91L12 2z"/></svg>
|
|
</a>
|
|
</div>
|
|
</header>
|
|
<main id="main">
|
|
|
|
<div class="skills-layout">
|
|
|
|
<aside class="skills-sidebar" aria-label="Documentation">
|
|
<button class="skills-sidebar-toggle" type="button" aria-expanded="false" aria-controls="skills-sidebar-inner">
|
|
<span class="skills-sidebar-toggle-label">/distill</span>
|
|
<svg class="skills-sidebar-toggle-chevron" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" aria-hidden="true"><path d="M6 9l6 6 6-6"/></svg>
|
|
</button>
|
|
<div class="skills-sidebar-inner" id="skills-sidebar-inner">
|
|
<p class="skills-sidebar-label">Docs</p>
|
|
|
|
<div class="skills-sidebar-group" data-category="tutorials">
|
|
<p class="skills-sidebar-group-title">Tutorials</p>
|
|
<ul class="skills-sidebar-list">
|
|
<li><a href="/tutorials/getting-started">Getting started</a></li>
|
|
<li><a href="/tutorials/iterate-live">Iterate on UI with Live Mode</a></li>
|
|
<li><a href="/tutorials/brand-vs-product">Brand vs product, pick a register</a></li>
|
|
<li><a href="/tutorials/critique-with-overlay">Critique with the visual overlay</a></li>
|
|
</ul>
|
|
</div>
|
|
<hr class="skills-sidebar-divider">
|
|
|
|
<div class="skills-sidebar-group" data-category="create">
|
|
<p class="skills-sidebar-group-title">Create</p>
|
|
<ul class="skills-sidebar-list">
|
|
<li><a href="/docs/impeccable">/impeccable</a></li>
|
|
<li><a href="/docs/craft">craft</a></li>
|
|
<li><a href="/docs/shape">shape</a></li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div class="skills-sidebar-group" data-category="evaluate">
|
|
<p class="skills-sidebar-group-title">Evaluate</p>
|
|
<ul class="skills-sidebar-list">
|
|
<li><a href="/docs/audit">audit</a></li>
|
|
<li><a href="/docs/critique">critique</a></li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div class="skills-sidebar-group" data-category="refine">
|
|
<p class="skills-sidebar-group-title">Refine</p>
|
|
<ul class="skills-sidebar-list">
|
|
<li><a href="/docs/animate">animate</a></li>
|
|
<li><a href="/docs/bolder">bolder</a></li>
|
|
<li><a href="/docs/colorize">colorize</a></li>
|
|
<li><a href="/docs/delight">delight</a></li>
|
|
<li><a href="/docs/layout">layout</a></li>
|
|
<li><a href="/docs/overdrive">overdrive</a></li>
|
|
<li><a href="/docs/quieter">quieter</a></li>
|
|
<li><a href="/docs/typeset">typeset</a></li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div class="skills-sidebar-group" data-category="simplify">
|
|
<p class="skills-sidebar-group-title">Simplify</p>
|
|
<ul class="skills-sidebar-list">
|
|
<li><a href="/docs/adapt">adapt</a></li>
|
|
<li><a href="/docs/clarify">clarify</a></li>
|
|
<li><a href="/docs/distill" aria-current="page">distill</a></li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div class="skills-sidebar-group" data-category="harden">
|
|
<p class="skills-sidebar-group-title">Harden</p>
|
|
<ul class="skills-sidebar-list">
|
|
<li><a href="/docs/harden">harden</a></li>
|
|
<li><a href="/docs/onboard">onboard</a></li>
|
|
<li><a href="/docs/optimize">optimize</a></li>
|
|
<li><a href="/docs/polish">polish</a></li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div class="skills-sidebar-group" data-category="system">
|
|
<p class="skills-sidebar-group-title">System</p>
|
|
<ul class="skills-sidebar-list">
|
|
<li><a href="/docs/document">document</a></li>
|
|
<li><a href="/docs/extract">extract</a></li>
|
|
<li><a href="/docs/live">live</a></li>
|
|
<li><a href="/docs/teach">teach</a></li>
|
|
</ul>
|
|
</div>
|
|
|
|
</div>
|
|
</aside>
|
|
<div class="skills-main">
|
|
|
|
<article class="skill-detail">
|
|
<div class="skill-detail-hero skill-detail-hero--has-demo">
|
|
<header class="skill-detail-header">
|
|
<p class="skill-detail-eyebrow"><a href="/docs">Docs</a> / Simplify</p>
|
|
<h1 class="skill-detail-title"><span class="skill-detail-title-namespace"><span class="skill-detail-title-slash">/</span>impeccable</span>distill</h1>
|
|
<p class="skill-detail-tagline">Ruthless subtraction. Strip designs to their essence.</p>
|
|
|
|
<div class="skill-meta-strip">
|
|
<span class="skill-meta-chip skill-meta-category" data-category="simplify">Simplify</span>
|
|
<span class="skill-meta-chip">User-invocable</span>
|
|
<span class="skill-meta-chip skill-meta-args">[target]</span>
|
|
</div>
|
|
</header>
|
|
|
|
<section class="skill-demo" aria-label="Before and after demo">
|
|
<div class="split-comparison" data-demo="skill-distill">
|
|
<p class="skill-demo-eyebrow">Drag or hover to compare</p>
|
|
<div class="split-container">
|
|
<div class="split-before">
|
|
<div class="split-content">
|
|
<div style="width: 100%; max-width: 280px; padding: 12px; background: #f5f5f5; border: 1px solid #ddd; border-radius: 6px;">
|
|
<div style="display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; padding-bottom: 8px; border-bottom: 1px solid #ddd;">
|
|
<span style="font-size: 12px; color: #666;">Dashboard</span>
|
|
<div style="display: flex; gap: 4px;">
|
|
<button style="padding: 2px 6px; font-size: 10px; background: #e0e0e0; border: none; border-radius: 2px;">⚙️</button>
|
|
<button style="padding: 2px 6px; font-size: 10px; background: #e0e0e0; border: none; border-radius: 2px;">🔔</button>
|
|
<button style="padding: 2px 6px; font-size: 10px; background: #e0e0e0; border: none; border-radius: 2px;">❓</button>
|
|
<button style="padding: 2px 6px; font-size: 10px; background: #e0e0e0; border: none; border-radius: 2px;">⋮</button>
|
|
</div>
|
|
</div>
|
|
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 6px;">
|
|
<div style="padding: 8px; background: white; border: 1px solid #e0e0e0; border-radius: 4px; font-size: 10px; color: #666;">Revenue<br><b>$12,345</b></div>
|
|
<div style="padding: 8px; background: white; border: 1px solid #e0e0e0; border-radius: 4px; font-size: 10px; color: #666;">Users<br><b>1,234</b></div>
|
|
<div style="padding: 8px; background: white; border: 1px solid #e0e0e0; border-radius: 4px; font-size: 10px; color: #666;">Growth<br><b>+12%</b></div>
|
|
<div style="padding: 8px; background: white; border: 1px solid #e0e0e0; border-radius: 4px; font-size: 10px; color: #666;">Bounce<br><b>32%</b></div>
|
|
</div>
|
|
<div style="margin-top: 8px; padding: 8px; background: #e3f2fd; border-radius: 4px; font-size: 10px; color: #1976d2;">📊 View detailed analytics →</div>
|
|
<div style="margin-top: 4px; padding: 8px; background: #fff3e0; border-radius: 4px; font-size: 10px; color: #e65100;">🎯 Set up goals →</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="split-after">
|
|
<div class="split-content">
|
|
<div style="width: 100%; max-width: 260px; padding: 20px; background: var(--color-paper); border: 1px solid var(--color-mist); border-radius: 8px;">
|
|
<div style="font-size: 0.6875rem; text-transform: uppercase; letter-spacing: 0.1em; color: var(--color-ash); margin-bottom: 16px;">This Month</div>
|
|
<div style="margin-bottom: 20px;">
|
|
<div style="font-family: var(--font-display); font-size: 2.5rem; font-weight: 300; color: var(--color-ink); line-height: 1;">$12,345</div>
|
|
<div style="font-size: 0.8125rem; color: #22c55e; margin-top: 4px;">↑ 12% from last month</div>
|
|
</div>
|
|
<div style="display: flex; gap: 24px;">
|
|
<div>
|
|
<div style="font-size: 1.25rem; font-weight: 500; color: var(--color-ink);">1,234</div>
|
|
<div style="font-size: 0.6875rem; color: var(--color-ash);">Active users</div>
|
|
</div>
|
|
<div>
|
|
<div style="font-size: 1.25rem; font-weight: 500; color: var(--color-ink);">68%</div>
|
|
<div style="font-size: 0.6875rem; color: var(--color-ash);">Retention</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="split-divider"></div>
|
|
</div>
|
|
<div class="split-labels">
|
|
<span class="split-label-item" data-point="before">Before</span>
|
|
<p class="skill-demo-caption">Cluttered interface → Essential elements only</p>
|
|
<span class="split-label-item" data-point="after">After</span>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</div>
|
|
|
|
<section class="skill-detail-editorial prose">
|
|
<h2 id="when-to-use-it">When to use it</h2>
|
|
<p><code>/impeccable distill</code> removes what should not be there. Competing buttons, redundant information, decorative borders, three fonts where one works, six navigation items where three belong. Use it when an interface feels cluttered, busy, or like it is trying to do too much at once.</p>
|
|
<p>Reach for it after <code>/impeccable critique</code> flags "cognitive load" or "visual noise", or any time a page has grown by accretion and no one has done the editing.</p>
|
|
<h2 id="how-it-works">How it works</h2>
|
|
<p>The skill starts from one question: what is the single job this interface is trying to do? Everything that does not help that job is on the chopping block.</p>
|
|
<p>It works in two passes:</p>
|
|
<ol>
|
|
<li><strong>Assess the complexity sources</strong>. Too many elements, excessive variation, information overload, visual noise, confusing hierarchy, feature creep. Name each one.</li>
|
|
<li><strong>Edit ruthlessly</strong>. Remove what is not essential. Combine what can be combined. Hide what can wait. Consolidate variation into a single treatment. Commit to a single visual language.</li>
|
|
</ol>
|
|
<p>The principle: simplicity is not about fewer features. It is about fewer obstacles between users and their goals. Every element on the page has to justify its existence.</p>
|
|
<h2 id="try-it">Try it</h2>
|
|
<div class="code-block-wrap"><pre class="code-block"><code>/impeccable distill this dashboard</code></pre><button class="code-block-copy" type="button" data-copy="/impeccable distill this dashboard" aria-label="Copy to clipboard"></button></div>
|
|
<p>Before: four card styles, three button variants, two header treatments, a sidebar with 14 items grouped into 5 sections.</p>
|
|
<p>After a <code>/distill</code> pass, typical changes:</p>
|
|
<ul>
|
|
<li>Collapse the four card styles into one</li>
|
|
<li>Pick one button variant, demote the others to text links</li>
|
|
<li>Unify the headers</li>
|
|
<li>Group the sidebar into 3 sections, not 5</li>
|
|
<li>Hide advanced options behind a disclosure</li>
|
|
</ul>
|
|
<p>Fewer things. Each one clearer.</p>
|
|
<h2 id="pitfalls">Pitfalls</h2>
|
|
<ul>
|
|
<li><strong>Confusing distill with delete.</strong> Distill removes obstacles. It does not remove features users need. If a user relies on something daily, find a way to keep it quietly, not a way to cut it.</li>
|
|
<li><strong>Running it too early.</strong> If the feature is still growing, distilling it now means distilling the same thing again next week. Wait until the shape is stable.</li>
|
|
<li><strong>Expecting it to replace hierarchy work.</strong> Sometimes the right fix is not removing things, it is arranging them. Reach for <code>/impeccable layout</code> when the problem is layout, not quantity.</li>
|
|
</ul>
|
|
|
|
</section>
|
|
|
|
|
|
|
|
<section class="skill-source-card">
|
|
<header class="skill-source-card-header">
|
|
<span class="skill-source-card-label">reference/distill.md</span>
|
|
<span class="skill-source-card-subtitle">Loaded when the impeccable skill routes to this command.</span>
|
|
</header>
|
|
<div class="skill-source-card-body prose">
|
|
<p>Remove unnecessary complexity from designs, revealing the essential elements and creating clarity through ruthless simplification.</p>
|
|
<hr>
|
|
<h2 id="assess-current-state">Assess Current State</h2>
|
|
<p>Analyze what makes the design feel complex or cluttered:</p>
|
|
<ol>
|
|
<li><p><strong>Identify complexity sources</strong>:</p>
|
|
<ul>
|
|
<li><strong>Too many elements</strong>: Competing buttons, redundant information, visual clutter</li>
|
|
<li><strong>Excessive variation</strong>: Too many colors, fonts, sizes, styles without purpose</li>
|
|
<li><strong>Information overload</strong>: Everything visible at once, no progressive disclosure</li>
|
|
<li><strong>Visual noise</strong>: Unnecessary borders, shadows, backgrounds, decorations</li>
|
|
<li><strong>Confusing hierarchy</strong>: Unclear what matters most</li>
|
|
<li><strong>Feature creep</strong>: Too many options, actions, or paths forward</li>
|
|
</ul>
|
|
</li>
|
|
<li><p><strong>Find the essence</strong>:</p>
|
|
<ul>
|
|
<li>What's the primary user goal? (There should be ONE)</li>
|
|
<li>What's actually necessary vs nice-to-have?</li>
|
|
<li>What can be removed, hidden, or combined?</li>
|
|
<li>What's the 20% that delivers 80% of value?</li>
|
|
</ul>
|
|
</li>
|
|
</ol>
|
|
<p>If any of these are unclear from the codebase, STOP and call the AskUserQuestion tool to clarify.</p>
|
|
<p><strong>CRITICAL</strong>: Simplicity is not about removing features - it's about removing obstacles between users and their goals. Every element should justify its existence.</p>
|
|
<h2 id="plan-simplification">Plan Simplification</h2>
|
|
<p>Create a ruthless editing strategy:</p>
|
|
<ul>
|
|
<li><strong>Core purpose</strong>: What's the ONE thing this should accomplish?</li>
|
|
<li><strong>Essential elements</strong>: What's truly necessary to achieve that purpose?</li>
|
|
<li><strong>Progressive disclosure</strong>: What can be hidden until needed?</li>
|
|
<li><strong>Consolidation opportunities</strong>: What can be combined or integrated?</li>
|
|
</ul>
|
|
<p><strong>IMPORTANT</strong>: Simplification is hard. It requires saying no to good ideas to make room for great execution. Be ruthless.</p>
|
|
<h2 id="simplify-the-design">Simplify the Design</h2>
|
|
<p>Systematically remove complexity across these dimensions:</p>
|
|
<h3 id="information-architecture">Information Architecture</h3>
|
|
<ul>
|
|
<li><strong>Reduce scope</strong>: Remove secondary actions, optional features, redundant information</li>
|
|
<li><strong>Progressive disclosure</strong>: Hide complexity behind clear entry points (accordions, modals, step-through flows)</li>
|
|
<li><strong>Combine related actions</strong>: Merge similar buttons, consolidate forms, group related content</li>
|
|
<li><strong>Clear hierarchy</strong>: ONE primary action, few secondary actions, everything else tertiary or hidden</li>
|
|
<li><strong>Remove redundancy</strong>: If it's said elsewhere, don't repeat it here</li>
|
|
</ul>
|
|
<h3 id="visual-simplification">Visual Simplification</h3>
|
|
<ul>
|
|
<li><strong>Reduce color palette</strong>: Use 1-2 colors plus neutrals, not 5-7 colors</li>
|
|
<li><strong>Limit typography</strong>: One font family, 3-4 sizes maximum, 2-3 weights</li>
|
|
<li><strong>Remove decorations</strong>: Eliminate borders, shadows, backgrounds that don't serve hierarchy or function</li>
|
|
<li><strong>Flatten structure</strong>: Reduce nesting, remove unnecessary containers—never nest cards inside cards</li>
|
|
<li><strong>Remove unnecessary cards</strong>: Cards aren't needed for basic layout; use spacing and alignment instead</li>
|
|
<li><strong>Consistent spacing</strong>: Use one spacing scale, remove arbitrary gaps</li>
|
|
</ul>
|
|
<h3 id="layout-simplification">Layout Simplification</h3>
|
|
<ul>
|
|
<li><strong>Linear flow</strong>: Replace complex grids with simple vertical flow where possible</li>
|
|
<li><strong>Remove sidebars</strong>: Move secondary content inline or hide it</li>
|
|
<li><strong>Full-width</strong>: Use available space generously instead of complex multi-column layouts</li>
|
|
<li><strong>Consistent alignment</strong>: Pick left or center, stick with it</li>
|
|
<li><strong>Generous white space</strong>: Let content breathe, don't pack everything tight</li>
|
|
</ul>
|
|
<h3 id="interaction-simplification">Interaction Simplification</h3>
|
|
<ul>
|
|
<li><strong>Reduce choices</strong>: Fewer buttons, fewer options, clearer path forward (paradox of choice is real)</li>
|
|
<li><strong>Smart defaults</strong>: Make common choices automatic, only ask when necessary</li>
|
|
<li><strong>Inline actions</strong>: Replace modal flows with inline editing where possible</li>
|
|
<li><strong>Remove steps</strong>: Can signup be one step instead of three? Can checkout be simplified?</li>
|
|
<li><strong>Clear CTAs</strong>: ONE obvious next step, not five competing actions</li>
|
|
</ul>
|
|
<h3 id="content-simplification">Content Simplification</h3>
|
|
<ul>
|
|
<li><strong>Shorter copy</strong>: Cut every sentence in half, then do it again</li>
|
|
<li><strong>Active voice</strong>: "Save changes" not "Changes will be saved"</li>
|
|
<li><strong>Remove jargon</strong>: Plain language always wins</li>
|
|
<li><strong>Scannable structure</strong>: Short paragraphs, bullet points, clear headings</li>
|
|
<li><strong>Essential information only</strong>: Remove marketing fluff, legalese, hedging</li>
|
|
<li><strong>Remove redundant copy</strong>: No headers restating intros, no repeated explanations, say it once</li>
|
|
</ul>
|
|
<h3 id="code-simplification">Code Simplification</h3>
|
|
<ul>
|
|
<li><strong>Remove unused code</strong>: Dead CSS, unused components, orphaned files</li>
|
|
<li><strong>Flatten component trees</strong>: Reduce nesting depth</li>
|
|
<li><strong>Consolidate styles</strong>: Merge similar styles, use utilities consistently</li>
|
|
<li><strong>Reduce variants</strong>: Does that component need 12 variations, or can 3 cover 90% of cases?</li>
|
|
</ul>
|
|
<p><strong>NEVER</strong>:</p>
|
|
<ul>
|
|
<li>Remove necessary functionality (simplicity ≠ feature-less)</li>
|
|
<li>Sacrifice accessibility for simplicity (clear labels and ARIA still required)</li>
|
|
<li>Make things so simple they're unclear (mystery ≠ minimalism)</li>
|
|
<li>Remove information users need to make decisions</li>
|
|
<li>Eliminate hierarchy completely (some things should stand out)</li>
|
|
<li>Oversimplify complex domains (match complexity to actual task complexity)</li>
|
|
</ul>
|
|
<h2 id="verify-simplification">Verify Simplification</h2>
|
|
<p>Ensure simplification improves usability:</p>
|
|
<ul>
|
|
<li><strong>Faster task completion</strong>: Can users accomplish goals more quickly?</li>
|
|
<li><strong>Reduced cognitive load</strong>: Is it easier to understand what to do?</li>
|
|
<li><strong>Still complete</strong>: Are all necessary features still accessible?</li>
|
|
<li><strong>Clearer hierarchy</strong>: Is it obvious what matters most?</li>
|
|
<li><strong>Better performance</strong>: Does simpler design load faster?</li>
|
|
</ul>
|
|
<h2 id="document-removed-complexity">Document Removed Complexity</h2>
|
|
<p>If you removed features or options:</p>
|
|
<ul>
|
|
<li>Document why they were removed</li>
|
|
<li>Consider if they need alternative access points</li>
|
|
<li>Note any user feedback to monitor</li>
|
|
</ul>
|
|
<p>Remember: You have great taste and judgment. Simplification is an act of confidence - knowing what to keep and courage to remove the rest. As Antoine de Saint-Exupéry said: "Perfection is achieved not when there is nothing more to add, but when there is nothing left to take away."</p>
|
|
|
|
</div>
|
|
</section>
|
|
|
|
|
|
</article>
|
|
|
|
</div>
|
|
</div>
|
|
</main>
|
|
<script>
|
|
// Copy buttons on rendered code blocks
|
|
document.addEventListener('click', (e) => {
|
|
const btn = e.target.closest('[data-copy]');
|
|
if (!btn) return;
|
|
const text = btn.getAttribute('data-copy');
|
|
if (!text) return;
|
|
navigator.clipboard.writeText(text).then(() => {
|
|
btn.classList.add('is-copied');
|
|
setTimeout(() => btn.classList.remove('is-copied'), 1500);
|
|
}).catch(() => {});
|
|
});
|
|
|
|
// Mobile sidebar toggle (shown on narrow viewports, hidden on desktop).
|
|
document.addEventListener('click', (e) => {
|
|
const toggle = e.target.closest('.skills-sidebar-toggle');
|
|
if (!toggle) return;
|
|
const expanded = toggle.getAttribute('aria-expanded') === 'true';
|
|
toggle.setAttribute('aria-expanded', String(!expanded));
|
|
});
|
|
|
|
// Before/after split-compare: drag on touch, hover OR drag on mouse.
|
|
// Pointer events attach to the padded .split-comparison wrapper so
|
|
// there is a ~20px invisible buffer around the visible box. The
|
|
// divider only snaps back when the pointer leaves that outer buffer.
|
|
(function initSplitCompare() {
|
|
const wrappers = document.querySelectorAll('.split-comparison');
|
|
if (wrappers.length === 0) return;
|
|
const hasHover = matchMedia('(hover: hover)').matches;
|
|
const DEFAULT_POSITION = 50;
|
|
|
|
for (const wrapper of wrappers) {
|
|
const container = wrapper.querySelector('.split-container');
|
|
const splitAfter = wrapper.querySelector('.split-after');
|
|
const splitDivider = wrapper.querySelector('.split-divider');
|
|
if (!container || !splitAfter || !splitDivider) continue;
|
|
|
|
const tanAngle = Math.tan(10 * Math.PI / 180);
|
|
let skewOffset = 8;
|
|
const recalcSkew = () => {
|
|
const r = container.getBoundingClientRect();
|
|
if (r.width > 0 && r.height > 0) {
|
|
skewOffset = 50 * r.height * tanAngle / r.width;
|
|
}
|
|
};
|
|
recalcSkew();
|
|
window.addEventListener('resize', recalcSkew, { passive: true });
|
|
|
|
let targetX = DEFAULT_POSITION;
|
|
let currentX = DEFAULT_POSITION;
|
|
let rafId = null;
|
|
|
|
const paint = (pct) => {
|
|
const x = Math.max(-skewOffset, Math.min(100 + skewOffset, pct));
|
|
splitAfter.style.clipPath =
|
|
`polygon(${x + skewOffset}% 0%, 100% 0%, 100% 100%, ${x - skewOffset}% 100%)`;
|
|
splitDivider.style.left = `${x}%`;
|
|
};
|
|
|
|
const step = () => {
|
|
currentX += (targetX - currentX) * 0.2;
|
|
if (Math.abs(targetX - currentX) < 0.1) {
|
|
currentX = targetX;
|
|
rafId = null;
|
|
} else {
|
|
rafId = requestAnimationFrame(step);
|
|
}
|
|
paint(currentX);
|
|
};
|
|
|
|
const setTarget = (pct) => {
|
|
targetX = pct;
|
|
if (rafId === null) rafId = requestAnimationFrame(step);
|
|
};
|
|
|
|
paint(DEFAULT_POSITION);
|
|
|
|
// Percentage is always relative to the VISIBLE .split-container,
|
|
// not the padded .split-comparison wrapper. The pointer event
|
|
// target is the wrapper but the clip-path math uses the inner box.
|
|
const pctFromClientX = (clientX) => {
|
|
const rect = container.getBoundingClientRect();
|
|
return ((clientX - rect.left) / rect.width) * 100;
|
|
};
|
|
|
|
let hovering = false;
|
|
let dragging = false;
|
|
|
|
wrapper.addEventListener('pointerenter', (e) => {
|
|
if (hasHover && e.pointerType === 'mouse') {
|
|
hovering = true;
|
|
}
|
|
});
|
|
|
|
wrapper.addEventListener('pointerdown', (e) => {
|
|
dragging = true;
|
|
wrapper.setPointerCapture(e.pointerId);
|
|
setTarget(pctFromClientX(e.clientX));
|
|
});
|
|
|
|
wrapper.addEventListener('pointermove', (e) => {
|
|
if (dragging || hovering) {
|
|
setTarget(pctFromClientX(e.clientX));
|
|
}
|
|
});
|
|
|
|
const endDrag = (e) => {
|
|
if (dragging) {
|
|
dragging = false;
|
|
try { wrapper.releasePointerCapture(e.pointerId); } catch {}
|
|
}
|
|
};
|
|
|
|
wrapper.addEventListener('pointerup', endDrag);
|
|
wrapper.addEventListener('pointercancel', endDrag);
|
|
|
|
wrapper.addEventListener('pointerleave', (e) => {
|
|
endDrag(e);
|
|
if (hovering) {
|
|
hovering = false;
|
|
setTarget(DEFAULT_POSITION);
|
|
}
|
|
});
|
|
}
|
|
})();
|
|
</script>
|
|
</body>
|
|
</html>
|