mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-18 17:16:46 +03:00
Rework the landing page proof, steering demo, feature grid, slop catalog, detector coverage, theming, Live workflow, and responsive behavior.\n\nAI-assisted implementation by OpenAI Codex.
707 lines
47 KiB
Plaintext
707 lines
47 KiB
Plaintext
---
|
||
import Base from '../layouts/Base.astro';
|
||
import Testimonials from '../components/Testimonials.astro';
|
||
import HeroProof from '../components/HeroProof.astro';
|
||
import LiveSteeringDemo from '../components/LiveSteeringDemo.astro';
|
||
import SlopPatternPreview from '../components/SlopPatternPreview.astro';
|
||
import '../styles/main.css';
|
||
import '../styles/sub-pages.css';
|
||
import '../styles/home-kinpaku.css';
|
||
import '../styles/home-rebuild.css';
|
||
import '../styles/home-refresh.css';
|
||
import '../styles/testimonials.css';
|
||
|
||
// Hero background is the locked /design-system finalist referenced from CSS:
|
||
// /assets/neo-kinpaku/candidates/finalists/m-01-v2-01.png.
|
||
// Previous hero: /assets/neo-kinpaku/kintsugi-hero-v3.png
|
||
---
|
||
|
||
<Base
|
||
title="Impeccable: The missing upgrade to Anthropic's impeccable skill"
|
||
description="1 skill, 23 commands, and curated anti-patterns for impeccable frontend design. Works with Cursor, Claude Code, GitHub Copilot, Gemini CLI, and Codex CLI."
|
||
activeNav="home"
|
||
canonicalPath="/"
|
||
bodyClass="home-kinpaku kinpaku-chrome"
|
||
mainId="main-content"
|
||
mainClass="site-content"
|
||
ogTitle="Impeccable: Design skills for AI harnesses"
|
||
ogDescription="1 skill, 23 commands, and curated anti-patterns for impeccable frontend design. Works with Cursor, Claude Code, GitHub Copilot, Gemini CLI, and Codex CLI."
|
||
ogImage="https://impeccable.style/og-image-v2.jpg"
|
||
twitterSite="@pbakaus"
|
||
twitterCreator="@pbakaus"
|
||
>
|
||
|
||
<Fragment slot="head">
|
||
<script is:inline async src="https://www.googletagmanager.com/gtag/js?id=G-TEXGHC7V34"></script>
|
||
<script is:inline>
|
||
window.dataLayer = window.dataLayer || [];
|
||
function gtag(){dataLayer.push(arguments);}
|
||
gtag('js', new Date());
|
||
gtag('config', 'G-TEXGHC7V34');
|
||
</script>
|
||
<link rel="apple-touch-icon" href="/apple-touch-icon.png">
|
||
<meta name="theme-color" content="#070604">
|
||
</Fragment>
|
||
|
||
<Fragment slot="before-header">
|
||
<div class="grain-overlay" aria-hidden="true"></div>
|
||
</Fragment>
|
||
|
||
<Fragment slot="after-header">
|
||
<!-- 1. HERO -->
|
||
<section id="hero" class="hero-rebuild">
|
||
<div class="hero-rebuild-art" aria-hidden="true"></div>
|
||
<div class="hero-rebuild-container">
|
||
<div class="hero-rebuild-left">
|
||
<h1 class="hero-rebuild-title">The missing design vocabulary for agents.</h1>
|
||
|
||
<p class="hero-rebuild-body">
|
||
Impeccable stops AI-generated interfaces from collapsing into the same tells. It teaches
|
||
your agent what to avoid, gives you precise commands to steer it, and audits the result
|
||
in your production codebase.
|
||
</p>
|
||
|
||
<div class="hero-rebuild-actions">
|
||
<a href="#downloads" class="ks-button ks-button-primary">
|
||
Get started
|
||
<span class="ks-button-arrow" aria-hidden="true">
|
||
<svg viewBox="0 0 16 8" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="square">
|
||
<path d="M0 4h14M10 0l4 4-4 4"/>
|
||
</svg>
|
||
</span>
|
||
</a>
|
||
<a href="/designing" class="ks-button ks-button-ghost">How it works</a>
|
||
</div>
|
||
|
||
<div class="hero-rebuild-logos" aria-label="AI coding harnesses Impeccable works with">
|
||
<span class="hero-rebuild-logo has-tooltip" data-tooltip="Codex CLI"><img src="assets/openai-logo.png" alt="Codex CLI" width="20" height="20" loading="lazy"></span>
|
||
<span class="hero-rebuild-logo has-tooltip" data-tooltip="Claude Code"><img src="assets/claude-logo.png" alt="Claude Code" width="22" height="22" loading="lazy"></span>
|
||
<span class="hero-rebuild-logo has-tooltip" data-tooltip="GitHub Copilot"><img src="assets/github-copilot-logo.svg" alt="GitHub Copilot" width="20" height="20" loading="lazy"></span>
|
||
<span class="hero-rebuild-logo has-tooltip" data-tooltip="Cursor"><img src="assets/cursor-logo.png" alt="Cursor" width="22" height="22" loading="lazy"></span>
|
||
<span class="hero-rebuild-logo has-tooltip" data-tooltip="Gemini CLI"><img src="assets/gemini-logo.png" alt="Gemini CLI" width="20" height="20" loading="lazy"></span>
|
||
<span class="hero-rebuild-logo has-tooltip" data-tooltip="Antigravity"><img src="assets/antigravity-logo.png" alt="Antigravity" width="20" height="20" loading="lazy"></span>
|
||
<span class="hero-rebuild-logo has-tooltip" data-tooltip="OpenCode"><img src="assets/opencode-logo.png" alt="OpenCode" width="20" height="20" loading="lazy"></span>
|
||
<span class="hero-rebuild-logo has-tooltip" data-tooltip="Pi"><img src="assets/pi-logo.svg" alt="Pi" width="20" height="20" loading="lazy"></span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="hero-rebuild-right">
|
||
<HeroProof />
|
||
</div>
|
||
</div>
|
||
</section>
|
||
</Fragment>
|
||
|
||
<!-- 01b. TESTIMONIALS: five-variant section, switcher in the bottom-right
|
||
floating panel. Sits between the hero and the slop teaser. The dot-grid
|
||
divider that used to open the slop section now opens this one. -->
|
||
<Testimonials />
|
||
|
||
|
||
<SlopPatternPreview />
|
||
|
||
<!-- 02. THE LANGUAGE - Commands vocabulary + two steering surfaces -->
|
||
<section class="language-section" id="language">
|
||
<div id="solution" style="height:0;overflow:hidden;visibility:hidden"></div>
|
||
<div class="section-header" data-reveal>
|
||
<h2 class="section-title">The Language</h2>
|
||
</div>
|
||
<div class="language-content">
|
||
<div class="language-intro-row" data-reveal>
|
||
<p class="section-lead">23 commands give you a shared design vocabulary with your AI. Each names one kind of intervention: <code>/typeset</code> for type, <code>/distill</code> for complexity, <code>/audit</code> for production quality. Pick any to see it in action, or <a href="/docs" class="cheatsheet-link">browse the full reference →</a></p>
|
||
<div class="language-view-toggle" role="tablist" aria-label="Commands view">
|
||
<button type="button" role="tab" class="language-view-tab is-active" data-view="palette" aria-selected="true">Palette</button>
|
||
<button type="button" role="tab" class="language-view-tab" data-view="periodic" aria-selected="false">Periodic</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="commands-section" style="height:0;overflow:hidden;visibility:hidden"></div>
|
||
|
||
<div class="language-view language-view--palette is-active" data-view-panel="palette">
|
||
<div class="commands-subsection">
|
||
<div class="commands-gallery">
|
||
<!-- Rendered by JS -->
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="language-view language-view--periodic" data-view-panel="periodic" hidden>
|
||
<div class="solution-visual-interactive" id="framework-viz-container" data-reveal>
|
||
<!-- Periodic table generated by JS -->
|
||
</div>
|
||
</div>
|
||
|
||
<section class="language-steering" aria-labelledby="language-steering-title">
|
||
<header class="language-steering-head">
|
||
<h3 id="language-steering-title">Give direction in chat. Refine the result on the page.</h3>
|
||
<p>Every change lands in your source.</p>
|
||
</header>
|
||
|
||
<div class="steering-desktop" data-steering-desktop data-mobile-pane="agent">
|
||
<div class="steering-desktop-bar">
|
||
<span class="steering-window-controls" aria-hidden="true"><i></i><i></i><i></i></span>
|
||
<span class="steering-desktop-context">main</span>
|
||
<span class="steering-desktop-brand"><i aria-hidden="true"></i> Claudex Cocursor</span>
|
||
</div>
|
||
|
||
<div class="steering-mobile-tabs" role="tablist" aria-label="Steering demo view">
|
||
<button type="button" role="tab" class="is-active" data-steering-mobile-tab="agent" aria-selected="true">Agent thread</button>
|
||
<button type="button" role="tab" data-steering-mobile-tab="browser" aria-selected="false">In-app browser</button>
|
||
</div>
|
||
|
||
<div class="steering-desktop-panes">
|
||
<article class="steering-pane steering-agent" tabindex="0" data-steering-pane="agent">
|
||
<header class="steering-pane-head">
|
||
<span class="steering-pane-title"><i aria-hidden="true"></i> Agent thread</span>
|
||
<span class="steering-pane-meta">Working tree</span>
|
||
</header>
|
||
|
||
<div class="steering-thread" data-steering-thread aria-label="Example Impeccable agent thread">
|
||
<div class="steering-thread-scene" data-steering-thread-scene="polish">
|
||
<div class="steering-thread-user">
|
||
<span>You</span>
|
||
<p><code>/impeccable <span data-steering-active-command>polish</span></code> the pricing page. Keep our sharp corners and sober palette. Remove the AI tells.</p>
|
||
</div>
|
||
|
||
<div class="steering-thread-agent" aria-live="polite">
|
||
<span>Agent</span>
|
||
<p data-steering-agent-copy>I’ll polish the page within its existing design system, then run the detector before I hand it back.</p>
|
||
<div class="steering-hook-log">
|
||
<p><i aria-hidden="true">↳</i><strong>DESIGN.md loaded</strong><small>Existing system preserved</small></p>
|
||
<p><i aria-hidden="true">↳</i><strong>4 tells found</strong><small>AI beige · italic serif · side-tab · pulsing dot</small></p>
|
||
<p><i aria-hidden="true">✓</i><strong>Written to source</strong><small>0 detector findings</small></p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="steering-thread-scene steering-thread-scene--live" data-steering-thread-scene="live">
|
||
<div class="steering-thread-user">
|
||
<span>You</span>
|
||
<p><code>/impeccable live</code></p>
|
||
</div>
|
||
|
||
<div class="steering-thread-agent">
|
||
<span>Agent</span>
|
||
<p>Starting Live Mode against the running app. I’ll open the page, then wait for element picks and page-level steering.</p>
|
||
<div class="steering-hook-log">
|
||
<p><i aria-hidden="true">↳</i><strong>Live helper started</strong><small>Picker injected into the app</small></p>
|
||
<p><i aria-hidden="true">↳</i><strong>localhost:3000 opened</strong><small>Production source connected</small></p>
|
||
<p><i aria-hidden="true">●</i><strong>Waiting for input</strong><small>Pick an element or steer the whole page</small></p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="steering-composer-wrap">
|
||
<div class="steering-command-menu" aria-label="Impeccable commands">
|
||
<div class="steering-command-query"><span>/impeccable</span><small>Choose a command</small></div>
|
||
<button type="button" class="is-active" data-steering-command="polish" data-agent-copy="I’ll polish the page within its existing design system, then run the detector before I hand it back." aria-pressed="true"><strong>polish</strong><span>Final quality pass</span><kbd>↵</kbd></button>
|
||
<button type="button" data-steering-command="audit" data-agent-copy="I’ll audit the page for accessibility, responsive behavior, and production quality." aria-pressed="false"><strong>audit</strong><span>Production quality</span><kbd>↵</kbd></button>
|
||
<button type="button" data-steering-command="typeset" data-agent-copy="I’ll clarify the type hierarchy while preserving the project’s existing fonts and tokens." aria-pressed="false"><strong>typeset</strong><span>Typography hierarchy</span><kbd>↵</kbd></button>
|
||
<button type="button" data-steering-command="distill" data-agent-copy="I’ll remove nonessential UI and make the primary task unmistakable." aria-pressed="false"><strong>distill</strong><span>Strip to the essence</span><kbd>↵</kbd></button>
|
||
</div>
|
||
<button type="button" class="steering-composer" aria-label="Choose an Impeccable command">
|
||
<span class="steering-composer-plus" aria-hidden="true">+</span>
|
||
<p><code>/impeccable <span data-steering-active-command data-steering-composer-command>polish</span></code><span class="steering-composer-caret" aria-hidden="true"></span></p>
|
||
<span class="steering-composer-send" aria-hidden="true">↑</span>
|
||
</button>
|
||
</div>
|
||
</article>
|
||
|
||
<article class="steering-pane steering-browser" tabindex="0" data-steering-pane="browser">
|
||
<header class="steering-pane-head">
|
||
<span class="steering-pane-title"><i aria-hidden="true"></i> Browser</span>
|
||
<span class="steering-pane-meta">Live preview</span>
|
||
</header>
|
||
<div class="steering-browser-toolbar" aria-hidden="true">
|
||
<span class="steering-browser-nav">
|
||
<i><svg viewBox="0 0 16 16"><path d="m9.75 3.5-4.5 4.5 4.5 4.5M5.5 8h6.25" /></svg></i>
|
||
<i><svg viewBox="0 0 16 16"><path d="m6.25 3.5 4.5 4.5-4.5 4.5M10.5 8H4.25" /></svg></i>
|
||
<i><svg viewBox="0 0 16 16"><path d="M12.5 6A5 5 0 1 0 13 9M12.5 3.5V6H10" /></svg></i>
|
||
</span>
|
||
<span class="steering-browser-address"><i></i> localhost:3000</span>
|
||
<span class="steering-browser-open"><svg viewBox="0 0 16 16"><path d="M9 3h4v4M13 3 7.5 8.5M12 9.5V13H3V4h3.5" /></svg></span>
|
||
</div>
|
||
<LiveSteeringDemo />
|
||
</article>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
</div>
|
||
</section>
|
||
|
||
|
||
<!-- 05. READY TO DROP IN: bento grid with six tiles. Replaces the
|
||
carousel (initWhyTabs in app.js returns early when .why-layout is
|
||
missing, so leaving that JS in place is harmless). Tiles share
|
||
inner content classes (.why-panel-title, .why-panel-body,
|
||
.why-visual--*) with the old carousel; only the outer chrome
|
||
changed. -->
|
||
<section class="why-section" id="why">
|
||
<div class="why-content" data-reveal>
|
||
<div class="section-header">
|
||
<h2 class="section-title">Ready to drop in</h2>
|
||
</div>
|
||
|
||
<div class="ks-bento why-bento">
|
||
<!-- T1: hero, wide. Respects your design system. -->
|
||
<article class="ks-bento-tile ks-bento-tile--span-8" id="why-respects">
|
||
<span class="ks-bento-num" data-color="kinpaku">01</span>
|
||
<h3 class="why-panel-title">Respects your design system.</h3>
|
||
<p class="why-panel-body">Inherits your tokens, components, and conventions instead of overwriting them. New work fits the system, not the model's defaults.</p>
|
||
<div class="why-visual why-visual--terminal">
|
||
<div class="why-terminal">
|
||
<div class="why-terminal-header">
|
||
<span class="why-terminal-dot"></span>
|
||
<span class="why-terminal-dot"></span>
|
||
<span class="why-terminal-dot"></span>
|
||
<span class="why-terminal-title">/impeccable polish : scanning codebase</span>
|
||
</div>
|
||
<div class="why-terminal-body">
|
||
<div class="why-terminal-line why-terminal-line--prompt"><span class="why-terminal-prompt">›</span> Walking src/…</div>
|
||
<div class="why-terminal-line"> <span class="why-terminal-ok">✓</span> <span class="why-terminal-path">src/styles/tokens.css</span> <span class="why-terminal-meta">14 colors, 6 font sizes, 7 spacing steps</span></div>
|
||
<div class="why-terminal-line"> <span class="why-terminal-ok">✓</span> <span class="why-terminal-path">tailwind.config.ts</span> <span class="why-terminal-meta">theme.extend merged</span></div>
|
||
<div class="why-terminal-line"> <span class="why-terminal-ok">✓</span> <span class="why-terminal-path">src/components/</span> <span class="why-terminal-meta">34 components</span></div>
|
||
<div class="why-terminal-line"> <span class="why-terminal-meta">· Button: primary, secondary, ghost, destructive</span></div>
|
||
<div class="why-terminal-line"> <span class="why-terminal-meta">· Card: 3 variants, 8px / 16px radii</span></div>
|
||
<div class="why-terminal-line"> <span class="why-terminal-meta">· Input, Select, Dialog, Toast, Table…</span></div>
|
||
<div class="why-terminal-line"> <span class="why-terminal-ok">✓</span> <span class="why-terminal-path">DESIGN.md</span> <span class="why-terminal-meta">brand rules loaded</span></div>
|
||
<div class="why-terminal-line why-terminal-line--hint"><span class="why-terminal-arrow">→</span> Matching your system. Not inventing one.</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</article>
|
||
|
||
<!-- T2: narrow. Real product context. -->
|
||
<article class="ks-bento-tile ks-bento-tile--span-4" id="why-product">
|
||
<span class="ks-bento-num" data-color="patina">02</span>
|
||
<h3 class="why-panel-title">Real product context.</h3>
|
||
<p class="why-panel-body">Captures the brief once, in <code>PRODUCT.md</code>. Every command reads it before designing.</p>
|
||
<div class="why-visual why-visual--productmd">
|
||
<div class="why-productmd-file">
|
||
<div class="why-productmd-header">
|
||
<span class="why-productmd-filename">PRODUCT.md</span>
|
||
<span class="why-productmd-status">Loaded on every command</span>
|
||
</div>
|
||
<div class="why-productmd-body">
|
||
<div class="why-productmd-field">
|
||
<span class="why-productmd-k">Users</span>
|
||
<span class="why-productmd-v">SREs on call, reading fast, often in the dark.</span>
|
||
</div>
|
||
<div class="why-productmd-field">
|
||
<span class="why-productmd-k">Mode</span>
|
||
<span class="why-productmd-v">Operate. Design serves the task.</span>
|
||
</div>
|
||
<div class="why-productmd-field">
|
||
<span class="why-productmd-k">Brand voice</span>
|
||
<span class="why-productmd-v">Calm, clinical, no hype.</span>
|
||
</div>
|
||
<div class="why-productmd-field">
|
||
<span class="why-productmd-k">Anti-references</span>
|
||
<span class="why-productmd-v">Purple gradients. Glassmorphism. "Boost your productivity."</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</article>
|
||
|
||
<!-- T3: narrow. DESIGN.md travels. Restored from the parked panel
|
||
at site/_parked/the-case.astro. -->
|
||
<article class="ks-bento-tile ks-bento-tile--span-4" id="why-designmd">
|
||
<span class="ks-bento-num" data-color="kinpaku">03</span>
|
||
<h3 class="why-panel-title">Travels as DESIGN.md.</h3>
|
||
<p class="why-panel-body"><code>/impeccable document</code> writes one in the <a href="https://stitch.withgoogle.com/docs/design-md/overview/" target="_blank" rel="noopener">Google Stitch format</a>. Your visual system becomes portable.</p>
|
||
<div class="why-visual why-visual--designmd-v2">
|
||
<div class="why-dm-header">
|
||
<span class="why-dm-filename">DESIGN.md</span>
|
||
<span class="why-dm-badge">Google Stitch spec</span>
|
||
</div>
|
||
<div class="why-dm-grid">
|
||
<div class="why-dm-tile why-dm-tile--color" style="--c: var(--ks-kinpaku);">
|
||
<div class="why-dm-tile-meta"><span>Primary</span><span>oklch(78% .12 82)</span></div>
|
||
<div class="why-dm-color-hero"></div>
|
||
<div class="why-dm-color-ramp">
|
||
<span style="background: oklch(22% .04 78)"></span>
|
||
<span style="background: oklch(34% .06 78)"></span>
|
||
<span style="background: oklch(48% .08 78)"></span>
|
||
<span style="background: oklch(61% .085 78)"></span>
|
||
<span style="background: oklch(72% .105 82)"></span>
|
||
<span style="background: oklch(78% .12 82)"></span>
|
||
<span style="background: oklch(84% .075 84)"></span>
|
||
<span style="background: oklch(89% .055 84)"></span>
|
||
</div>
|
||
</div>
|
||
<div class="why-dm-tile why-dm-tile--type">
|
||
<div class="why-dm-tile-meta"><span>Wordmark</span><span>Spaced 400</span></div>
|
||
<div class="why-dm-type-specimen">IM</div>
|
||
<div class="why-dm-type-family">Avenir Next</div>
|
||
</div>
|
||
<div class="why-dm-tile why-dm-tile--type">
|
||
<div class="why-dm-tile-meta"><span>Body</span><span>Regular 400</span></div>
|
||
<div class="why-dm-type-specimen why-dm-type-specimen--sans">Aa</div>
|
||
<div class="why-dm-type-family">Avenir Next</div>
|
||
</div>
|
||
<div class="why-dm-tile why-dm-tile--components">
|
||
<div class="why-dm-tile-meta"><span>Components</span><span>34</span></div>
|
||
<div class="why-dm-comp-row">
|
||
<span class="why-dm-comp-chip why-dm-comp-chip--primary">Primary</span>
|
||
<span class="why-dm-comp-chip">Ghost</span>
|
||
</div>
|
||
<div class="why-dm-comp-input">Email address</div>
|
||
</div>
|
||
</div>
|
||
<div class="why-dm-foot">Readable by every DESIGN.md-aware tool.</div>
|
||
</div>
|
||
</article>
|
||
|
||
<!-- T4: wide. V4 creative direction, shown through a real case. -->
|
||
<article class="ks-bento-tile ks-bento-tile--span-8 why-panel--vizfirst" id="why-tuned">
|
||
<span class="ks-bento-num" data-color="patina">04</span>
|
||
<h3 class="why-panel-title">Gives capable models a point of view.</h3>
|
||
<p class="why-panel-body">V4 turns real project material into an ownable surface concept, then holds the build to it. Below: the Neo Mirai case.</p>
|
||
<div class="why-visual why-visual--vizfirst">
|
||
<div class="why-direction-rail">
|
||
<span><i>Mode</i> Persuade</span>
|
||
<span><i>Concept</i> A cultural dispatch from the near future</span>
|
||
<span class="why-direction-locked"><i>Direction contract</i> Locked</span>
|
||
</div>
|
||
<figure class="why-vz-plate why-vz-plate--hifi">
|
||
<span class="why-vz-plate-kind">01 · Visual probe</span>
|
||
<a class="why-vz-plate-frame" href="/cases/neo-mirai" aria-label="Read the Neo Mirai case study">
|
||
<img src="assets/openai_image_2_hifi.jpg" alt="Auto-generated hi-fi landing-page mock in editorial warm-paper style." loading="lazy" width="864" height="1821" />
|
||
</a>
|
||
</figure>
|
||
<figure class="why-vz-plate why-vz-plate--brand">
|
||
<span class="why-vz-plate-kind">02 · Direction</span>
|
||
<a class="why-vz-plate-frame" href="/cases/neo-mirai" aria-label="Read the Neo Mirai case study">
|
||
<img src="assets/openai_image_2_brand.jpg" alt="Auto-generated brand toolkit: identity lockups, palette, type, icon system, and application mocks for a fictional AI design conference." loading="lazy" width="1536" height="1024" />
|
||
</a>
|
||
</figure>
|
||
<figure class="why-vz-plate why-vz-plate--live">
|
||
<span class="why-vz-plate-kind">03 · Shipped surface</span>
|
||
<a class="why-vz-plate-frame" href="/neo-mirai/" aria-label="Open the Neo Mirai live build">
|
||
<img src="assets/cases/neo-mirai/live-fold.png" alt="Finished Neo Mirai website hero and agenda, implemented from the generated conference mock." loading="lazy" width="1440" height="1100" />
|
||
</a>
|
||
</figure>
|
||
</div>
|
||
<p class="why-panel-meta"><a href="/cases/neo-mirai">Read the case →</a> · <a href="/neo-mirai/">Open the live build →</a></p>
|
||
</article>
|
||
|
||
<!-- T5: medium. Surface modes replace the old brand/product registers. -->
|
||
<article class="ks-bento-tile ks-bento-tile--span-6" id="why-modes">
|
||
<span class="ks-bento-num" data-color="kinpaku">05</span>
|
||
<h3 class="why-panel-title">Knows what the surface is for.</h3>
|
||
<p class="why-panel-body">A landing page should persuade. A dashboard should help someone work. Impeccable names the mode before it designs.</p>
|
||
|
||
<div class="why-visual why-visual--modes">
|
||
<div class="why-mode-card why-mode-card--persuade">
|
||
<div class="why-mode-head"><strong>Persuade</strong><span>Win attention</span></div>
|
||
<div class="why-mode-preview" aria-hidden="true">
|
||
<span class="why-mode-kicker">A sharp idea</span>
|
||
<b>Make it<br />unmissable.</b>
|
||
<i>See the story</i>
|
||
</div>
|
||
</div>
|
||
<div class="why-mode-card why-mode-card--operate">
|
||
<div class="why-mode-head"><strong>Operate</strong><span>Complete a task</span></div>
|
||
<div class="why-mode-preview" aria-hidden="true">
|
||
<span class="why-mode-toolbar"></span>
|
||
<span class="why-mode-data"><i></i><i></i><i></i></span>
|
||
<span class="why-mode-action">Resolve</span>
|
||
</div>
|
||
</div>
|
||
<div class="why-mode-card why-mode-card--read">
|
||
<div class="why-mode-head"><strong>Read</strong><span>Build understanding</span></div>
|
||
<div class="why-mode-preview" aria-hidden="true">
|
||
<b>A clear argument.</b>
|
||
<span class="why-mode-copy"><i></i><i></i><i></i><i></i></span>
|
||
</div>
|
||
</div>
|
||
<div class="why-mode-card why-mode-card--experience">
|
||
<div class="why-mode-head"><strong>Experience</strong><span>Let the work lead</span></div>
|
||
<div class="why-mode-preview" aria-hidden="true">
|
||
<span class="why-mode-art"></span>
|
||
<b>NEO<br />MIRAI</b>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
</article>
|
||
|
||
<!-- T6: medium. Hooks keep the detector in the agent loop; CI is
|
||
the final gate rather than the whole story. -->
|
||
<article class="ks-bento-tile ks-bento-tile--span-6" id="why-ci">
|
||
<span class="ks-bento-num" data-color="patina">06</span>
|
||
<h3 class="why-panel-title">Block slop before it ships.</h3>
|
||
<p class="why-panel-body">Hooks inspect each UI edit and send findings straight back to the agent. The same detector can fail a PR.</p>
|
||
<div class="why-visual why-visual--ci">
|
||
<div class="why-ci-window">
|
||
<div class="why-ci-header">
|
||
<span class="why-ci-branch">Edit · Hero.tsx</span>
|
||
<span class="why-ci-status why-ci-status--hook">hook active</span>
|
||
</div>
|
||
<div class="why-ci-body why-hook-loop">
|
||
<div class="why-hook-step">
|
||
<span class="why-hook-mark">1</span>
|
||
<span><strong>Edit lands</strong><small>Agent updates the hero.</small></span>
|
||
</div>
|
||
<div class="why-hook-step why-hook-step--found">
|
||
<span class="why-hook-mark">2</span>
|
||
<span><strong>Hook returns two findings</strong><small>AI beige · clipped label</small></span>
|
||
</div>
|
||
<div class="why-hook-step why-hook-step--clean">
|
||
<span class="why-hook-mark">✓</span>
|
||
<span><strong>Agent corrects the file</strong><small>Second pass: clean</small></span>
|
||
</div>
|
||
<div class="why-ci-summary"><span>Deep stop audit</span><strong>0 findings · PR ready</strong></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p class="why-panel-meta"><a href="/detector">Explore the detector lab →</a></p>
|
||
</article>
|
||
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- 06. GET STARTED -->
|
||
<section class="downloads-rebuild" id="downloads" aria-labelledby="downloads-title">
|
||
<div class="downloads-rebuild-card">
|
||
<div class="downloads-rebuild-head">
|
||
<h2 id="downloads-title" class="downloads-rebuild-title">Get started</h2>
|
||
</div>
|
||
|
||
<div class="downloads-rebuild-install" data-install-tabs>
|
||
<div class="downloads-rebuild-cmd-group">
|
||
<div class="downloads-rebuild-tabs" role="tablist" aria-label="Install method">
|
||
<span class="downloads-rebuild-tabs-label">Install via</span>
|
||
<button class="downloads-rebuild-tab" type="button" role="tab" id="install-tab-impeccable" aria-controls="install-panel-impeccable update-panel-impeccable" aria-selected="true" data-method="impeccable" title="Recommended">impeccable<svg class="downloads-rebuild-tab-rec" width="11" height="11" viewBox="0 0 24 24" role="img" aria-label="Recommended"><title>Recommended</title><path d="M12 .587l3.668 7.431 8.2 1.193-5.934 5.787 1.401 8.169L12 18.896l-7.335 3.871 1.401-8.169L.132 9.211l8.2-1.193z"/></svg></button>
|
||
<button class="downloads-rebuild-tab" type="button" role="tab" id="install-tab-marketplace" aria-controls="install-panel-marketplace update-panel-marketplace" aria-selected="false" tabindex="-1" data-method="marketplace"><img class="downloads-rebuild-tab-logo" src="assets/claude-mark.png" alt="" width="13" height="13" loading="lazy" aria-hidden="true">marketplace</button> <button class="downloads-rebuild-tab" type="button" role="tab" id="install-tab-skills" aria-controls="install-panel-skills update-panel-skills" aria-selected="false" tabindex="-1" data-method="skills">skills.sh</button>
|
||
</div>
|
||
|
||
<p class="downloads-rebuild-copilot-note">
|
||
<svg class="downloads-rebuild-copilot-note-logo" width="15" height="15" viewBox="0 0 24 24" aria-hidden="true"><path d="M23.922 16.992c-.861 1.495-5.859 5.023-11.922 5.023-6.063 0-11.061-3.528-11.922-5.023A.641.641 0 0 1 0 16.736v-2.869a.841.841 0 0 1 .053-.22c.372-.935 1.347-2.292 2.605-2.656.167-.429.414-1.055.644-1.517a10.195 10.195 0 0 1-.052-1.086c0-1.331.282-2.499 1.132-3.368.397-.406.89-.717 1.474-.952 1.399-1.136 3.392-2.093 6.122-2.093 2.731 0 4.767.957 6.166 2.093.584.235 1.077.546 1.474.952.85.869 1.132 2.037 1.132 3.368 0 .368-.014.733-.052 1.086.23.462.477 1.088.644 1.517 1.258.364 2.233 1.721 2.605 2.656a.832.832 0 0 1 .053.22v2.869a.641.641 0 0 1-.078.256ZM12.172 11h-.344a4.323 4.323 0 0 1-.355.508C10.703 12.455 9.555 13 7.965 13c-1.725 0-2.989-.359-3.782-1.259a2.005 2.005 0 0 1-.085-.104L4 11.741v6.585c1.435.779 4.514 2.179 8 2.179 3.486 0 6.565-1.4 8-2.179v-6.585l-.098-.104s-.033.045-.085.104c-.793.9-2.057 1.259-3.782 1.259-1.59 0-2.738-.545-3.508-1.492a4.323 4.323 0 0 1-.355-.508h-.016.016Zm.641-2.935c.136 1.057.403 1.913.878 2.497.442.544 1.134.938 2.344.938 1.573 0 2.292-.337 2.657-.751.384-.435.558-1.15.558-2.361 0-1.14-.243-1.847-.705-2.319-.477-.488-1.319-.862-2.824-1.025-1.487-.161-2.192.138-2.533.529-.269.307-.437.808-.438 1.578v.021c0 .265.021.562.063.893Zm-1.626 0c.042-.331.063-.628.063-.894v-.02c-.001-.77-.169-1.271-.438-1.578-.341-.391-1.046-.69-2.533-.529-1.505.163-2.347.537-2.824 1.025-.462.472-.705 1.179-.705 2.319 0 1.211.175 1.926.558 2.361.365.414 1.084.751 2.657.751 1.21 0 1.902-.394 2.344-.938.475-.584.742-1.44.878-2.497Z"/><path d="M14.5 14.25a1 1 0 0 1 1 1v2a1 1 0 0 1-2 0v-2a1 1 0 0 1 1-1Zm-5 0a1 1 0 0 1 1 1v2a1 1 0 0 1-2 0v-2a1 1 0 0 1 1-1Z"/></svg>
|
||
<span>On the GitHub Copilot app? Impeccable is <strong>built in</strong>. Skip the install and enable it under <strong>Settings → Experimental</strong>.</span>
|
||
</p>
|
||
|
||
<div class="downloads-rebuild-method-panel" id="install-panel-impeccable" role="tabpanel" aria-labelledby="install-tab-impeccable" data-method-panel="impeccable">
|
||
<div class="downloads-rebuild-cmd">
|
||
<span class="downloads-rebuild-prompt" aria-hidden="true">$</span>
|
||
<code>npx impeccable install</code>
|
||
<button class="downloads-rebuild-copy" type="button" aria-label="Copy install command" data-copy="npx impeccable install">
|
||
<svg class="downloads-rebuild-copy-icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" aria-hidden="true">
|
||
<rect x="9" y="9" width="13" height="13" rx="2"/>
|
||
<path d="M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1"/>
|
||
</svg>
|
||
<svg class="downloads-rebuild-check-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.1" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
||
<path d="M20 6 9 17l-5-5"/>
|
||
</svg>
|
||
<span>Copy</span>
|
||
</button>
|
||
</div>
|
||
<p class="downloads-rebuild-method-note">Installs the build tailored to your harness and model. Requires <strong title="Node 22.12+ keeps npx on the current CLI instead of falling back to outdated releases.">Node 22.12+</strong>.</p>
|
||
|
||
<details class="downloads-rebuild-branch">
|
||
<summary class="downloads-rebuild-branch-summary">
|
||
<svg class="downloads-rebuild-branch-arrow" width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" aria-hidden="true"><path d="M9 6l6 6-6 6"/></svg>
|
||
<span>Why one command, many builds</span>
|
||
</summary>
|
||
<div class="downloads-rebuild-branch-body">
|
||
<svg class="downloads-rebuild-branch-diagram" viewBox="0 0 430 210" role="img" aria-label="The impeccable source branches into a build tailored per harness. The Gemini and Codex builds carry extra model-specific slop rules that ban that model's known tells; every build also gets its native hook wiring and subagent where supported.">
|
||
<path class="downloads-rebuild-branch-line" d="M104 105 C150 105 150 36 186 36"/>
|
||
<path class="downloads-rebuild-branch-line" d="M104 105 C150 105 150 82 186 82"/>
|
||
<path class="downloads-rebuild-branch-line" d="M104 105 C150 105 150 128 186 128"/>
|
||
<path class="downloads-rebuild-branch-line" d="M104 105 C150 105 150 174 186 174"/>
|
||
|
||
<rect class="downloads-rebuild-branch-root-box" x="6" y="83" width="96" height="44" rx="3"/>
|
||
<text class="downloads-rebuild-branch-root-text" x="54" y="109" text-anchor="middle">impeccable</text>
|
||
|
||
<g class="downloads-rebuild-branch-target">
|
||
<circle class="downloads-rebuild-branch-dot" cx="188" cy="36" r="3"/>
|
||
<text class="downloads-rebuild-branch-name" x="200" y="33">Claude Code</text>
|
||
<text class="downloads-rebuild-branch-tags" x="200" y="46">hooks + subagent</text>
|
||
</g>
|
||
<g class="downloads-rebuild-branch-target">
|
||
<circle class="downloads-rebuild-branch-dot" cx="188" cy="82" r="3"/>
|
||
<text class="downloads-rebuild-branch-name" x="200" y="79">Cursor</text>
|
||
<text class="downloads-rebuild-branch-tags" x="200" y="92">pre-edit hook</text>
|
||
</g>
|
||
<g class="downloads-rebuild-branch-target">
|
||
<circle class="downloads-rebuild-branch-dot" cx="188" cy="128" r="3"/>
|
||
<text class="downloads-rebuild-branch-name" x="200" y="125">Gemini CLI</text>
|
||
<text class="downloads-rebuild-branch-tags downloads-rebuild-branch-tags--slop" x="200" y="138">+ Gemini-tuned slop rules</text>
|
||
</g>
|
||
<g class="downloads-rebuild-branch-target">
|
||
<circle class="downloads-rebuild-branch-dot" cx="188" cy="174" r="3"/>
|
||
<text class="downloads-rebuild-branch-name" x="200" y="171">Codex CLI</text>
|
||
<text class="downloads-rebuild-branch-tags downloads-rebuild-branch-tags--slop" x="200" y="184">+ Codex-tuned slop rules</text>
|
||
</g>
|
||
</svg>
|
||
<p class="downloads-rebuild-branch-caption">Same skill, recompiled per target. The part that matters: builds for models with known tells carry extra slop rules banning that model's habits. The Gemini build kills its image-on-hover motion; the Codex build refuses ghost-cards and over-rounding. Native hook wiring and a subagent ship too, where the tool supports them.</p>
|
||
</div>
|
||
</details>
|
||
</div>
|
||
|
||
<div class="downloads-rebuild-method-panel" id="install-panel-marketplace" role="tabpanel" aria-labelledby="install-tab-marketplace" data-method-panel="marketplace" hidden>
|
||
<div class="downloads-rebuild-cmd">
|
||
<span class="downloads-rebuild-prompt" aria-hidden="true">$</span>
|
||
<code>/plugin marketplace add pbakaus/impeccable</code>
|
||
<button class="downloads-rebuild-copy" type="button" aria-label="Copy Claude Code plugin command" data-copy="/plugin marketplace add pbakaus/impeccable">
|
||
<svg class="downloads-rebuild-copy-icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" aria-hidden="true">
|
||
<rect x="9" y="9" width="13" height="13" rx="2"/>
|
||
<path d="M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1"/>
|
||
</svg>
|
||
<svg class="downloads-rebuild-check-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.1" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
||
<path d="M20 6 9 17l-5-5"/>
|
||
</svg>
|
||
<span>Copy</span>
|
||
</button>
|
||
</div>
|
||
<p class="downloads-rebuild-method-note">Claude Code only. After adding the marketplace, open <code>/plugin</code> and install Impeccable from the list.</p>
|
||
</div>
|
||
|
||
<div class="downloads-rebuild-method-panel" id="install-panel-skills" role="tabpanel" aria-labelledby="install-tab-skills" data-method-panel="skills" hidden>
|
||
<div class="downloads-rebuild-cmd">
|
||
<span class="downloads-rebuild-prompt" aria-hidden="true">$</span>
|
||
<code>npx skills add pbakaus/impeccable</code>
|
||
<button class="downloads-rebuild-copy" type="button" aria-label="Copy npx skills command" data-copy="npx skills add pbakaus/impeccable">
|
||
<svg class="downloads-rebuild-copy-icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" aria-hidden="true">
|
||
<rect x="9" y="9" width="13" height="13" rx="2"/>
|
||
<path d="M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1"/>
|
||
</svg>
|
||
<svg class="downloads-rebuild-check-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.1" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
||
<path d="M20 6 9 17l-5-5"/>
|
||
</svg>
|
||
<span>Copy</span>
|
||
</button>
|
||
</div>
|
||
<p class="downloads-rebuild-method-note">The general-purpose skills installer. It installs one shared build for every harness rather than the one compiled for yours, so you give up the provider-native command files and paths tuned to your tool. Functionally complete, just not tailored.</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="downloads-rebuild-cmd-group">
|
||
<span class="downloads-rebuild-cmd-label">First run</span>
|
||
<div class="downloads-rebuild-cmd">
|
||
<span class="downloads-rebuild-prompt" aria-hidden="true">$</span>
|
||
<code>/impeccable init</code>
|
||
<button class="downloads-rebuild-copy" type="button" aria-label="Copy first run command" data-copy="/impeccable init">
|
||
<svg class="downloads-rebuild-copy-icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" aria-hidden="true">
|
||
<rect x="9" y="9" width="13" height="13" rx="2"/>
|
||
<path d="M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1"/>
|
||
</svg>
|
||
<svg class="downloads-rebuild-check-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.1" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
||
<path d="M20 6 9 17l-5-5"/>
|
||
</svg>
|
||
<span>Copy</span>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="downloads-rebuild-cmd-group">
|
||
<span class="downloads-rebuild-cmd-label downloads-rebuild-cmd-label--update">Update</span>
|
||
|
||
<div class="downloads-rebuild-method-panel" id="update-panel-impeccable" role="tabpanel" aria-labelledby="install-tab-impeccable" data-method-panel="impeccable">
|
||
<div class="downloads-rebuild-cmd downloads-rebuild-cmd--update">
|
||
<span class="downloads-rebuild-prompt" aria-hidden="true">$</span>
|
||
<code>npx impeccable update</code>
|
||
<button class="downloads-rebuild-copy" type="button" aria-label="Copy update command" data-copy="npx impeccable update">
|
||
<svg class="downloads-rebuild-copy-icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" aria-hidden="true">
|
||
<rect x="9" y="9" width="13" height="13" rx="2"/>
|
||
<path d="M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1"/>
|
||
</svg>
|
||
<svg class="downloads-rebuild-check-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.1" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
||
<path d="M20 6 9 17l-5-5"/>
|
||
</svg>
|
||
<span>Copy</span>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="downloads-rebuild-method-panel" id="update-panel-marketplace" role="tabpanel" aria-labelledby="install-tab-marketplace" data-method-panel="marketplace" hidden>
|
||
<p class="downloads-rebuild-update-menu">Update from the <code>/plugin</code> menu inside Claude Code.</p>
|
||
</div>
|
||
|
||
<div class="downloads-rebuild-method-panel" id="update-panel-skills" role="tabpanel" aria-labelledby="install-tab-skills" data-method-panel="skills" hidden>
|
||
<div class="downloads-rebuild-cmd downloads-rebuild-cmd--update">
|
||
<span class="downloads-rebuild-prompt" aria-hidden="true">$</span>
|
||
<code>npx skills update</code>
|
||
<button class="downloads-rebuild-copy" type="button" aria-label="Copy npx skills update command" data-copy="npx skills update">
|
||
<svg class="downloads-rebuild-copy-icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" aria-hidden="true">
|
||
<rect x="9" y="9" width="13" height="13" rx="2"/>
|
||
<path d="M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1"/>
|
||
</svg>
|
||
<svg class="downloads-rebuild-check-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.1" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
||
<path d="M20 6 9 17l-5-5"/>
|
||
</svg>
|
||
<span>Copy</span>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<p class="downloads-rebuild-note">Works with Cursor, Claude Code, GitHub Copilot, Gemini CLI, Codex CLI, and every other major AI coding harness.</p>
|
||
|
||
<p class="downloads-rebuild-secondary"><a href="/tutorials/getting-started">Read the setup guide</a> · <a href="/changelog">See what's new</a> · <a href="/faq">Got questions?</a></p>
|
||
</div>
|
||
|
||
|
||
<ul class="downloads-rebuild-extras">
|
||
<li>
|
||
<strong>Chrome extension</strong>
|
||
<span>Run the detector overlay on any page: your staging, a competitor, anything in the browser.</span>
|
||
<a href="https://chromewebstore.google.com/detail/impeccable/bdkgmiklpdmaojlpflclinlofgjfpabf" target="_blank" rel="noopener">Install from the Chrome Web Store →</a>
|
||
</li>
|
||
<li>
|
||
<strong>CLI for CI</strong>
|
||
<span><code>npx impeccable detect src/</code> in a PR check. 59 deterministic rules. JSON output, exit codes for build gates.</span>
|
||
<a href="https://www.npmjs.com/package/impeccable" target="_blank" rel="noopener">View on npm →</a>
|
||
</li>
|
||
<li>
|
||
<strong>Follow along</strong>
|
||
<span>The design thinking behind new commands and anti-patterns, in long form. Read the newsletter, or catch the shorter notes on X.</span>
|
||
<a href="https://impeccablestyle.substack.com" target="_blank" rel="noopener" class="downloads-rebuild-link-primary">Read the newsletter →</a>
|
||
<a href="https://x.com/impeccable_ai" target="_blank" rel="noopener" class="downloads-rebuild-link-secondary">Follow @impeccable_ai on X →</a>
|
||
</li>
|
||
</ul>
|
||
|
||
<p class="downloads-rebuild-more">Learn more: <a href="/tutorials/getting-started">Getting started</a> · <a href="/designing">Designing with Impeccable</a> · <a href="/docs">command docs</a></p>
|
||
</div>
|
||
</section>
|
||
|
||
<Fragment slot="scripts">
|
||
<script is:inline>
|
||
(function () {
|
||
const root = document.querySelector('[data-install-tabs]');
|
||
if (!root) return;
|
||
const tabs = Array.from(root.querySelectorAll('[role="tab"][data-method]'));
|
||
const panels = Array.from(root.querySelectorAll('[data-method-panel]'));
|
||
function select(method, focus) {
|
||
tabs.forEach((tab) => {
|
||
const on = tab.dataset.method === method;
|
||
tab.setAttribute('aria-selected', String(on));
|
||
tab.tabIndex = on ? 0 : -1;
|
||
if (on && focus) tab.focus();
|
||
});
|
||
panels.forEach((panel) => {
|
||
panel.hidden = panel.dataset.methodPanel !== method;
|
||
});
|
||
}
|
||
tabs.forEach((tab, i) => {
|
||
tab.addEventListener('click', () => select(tab.dataset.method));
|
||
tab.addEventListener('keydown', (event) => {
|
||
if (event.key !== 'ArrowRight' && event.key !== 'ArrowLeft') return;
|
||
event.preventDefault();
|
||
const step = event.key === 'ArrowRight' ? 1 : tabs.length - 1;
|
||
select(tabs[(i + step) % tabs.length].dataset.method, true);
|
||
});
|
||
});
|
||
})();
|
||
</script>
|
||
|
||
<script>
|
||
import '../scripts/app.js';
|
||
</script>
|
||
</Fragment>
|
||
|
||
</Base>
|