web-design
Penguin visual language for generated web pages and app UIs — GitHub-style simplicity with a single blue accent, light and pure-black dark themes, design tokens, component and chat-interface recipes, plus an opt-in warm paper editorial theme.
git clone --depth 1 https://github.com/Prism-Shadow/penguin-harness /tmp/web-design && cp -r /tmp/web-design/packages/skills/skills/web-design ~/.claude/skills/web-designSKILL.md
# Web Design
Default visual language for every web page or frontend you generate, distilled from the Penguin Harness landing page and web app. The idea is **GitHub-style simplicity**: solid backgrounds, 1px borders instead of shadows, system fonts, one blue accent used sparingly. Depth comes from hairline borders, not shadows or gradients; dark mode is pure black, not navy. Apply these defaults unless the user explicitly asks for another style. One packaged alternative exists — the **paper editorial** theme below, for requests that call for a warm, print-like feel; pick one language per product and never mix them. The typography discipline, language, motion, IME, citation and responsiveness rules apply under both. Treat the user's one-line request as the whole spec: this skill fills every unstated gap, so the result is a finished page — never a wireframe that waits for styling feedback.
## Before you start
If the user's message only invokes this skill (e.g. "use web-design skill") without a concrete page or interface to build, ask what they want to build. When a concrete build is already requested (an app UI, a landing page, a RAG chat interface), do **not** ask about styling — colors, fonts, spacing, radii and layout are all decided by the defaults below; the only question ever worth asking is *what to build*, never *how it should look*. Route by request shape: conversational or docs-QA → the chat/RAG layout; product or marketing → the page layout; tool-like apps → a sticky nav + panels composed from the components.
Non-negotiable for ANY text input that sends on Enter: **never send while an IME composition is in progress** (check `event.isComposing`, falling back to `event.keyCode === 229`, on keydown). For Chinese/Japanese/Korean input methods, that Enter only confirms the composed text — auto-sending on it fires half-typed messages. Details in the composer recipe below.
## Ship complete
Every delivery, even from a one-line request, includes all of this unasked:
- `<html lang>` matching the UI language; `<meta name="viewport" content="width=device-width, initial-scale=1">`; a real `<title>`.
- Dark mode wired and persisted when using the default language (the paper theme is light-only); single column under 640px; no horizontal scroll.
- Every async surface has designed loading, empty, error and success states — never a blank region or a silent failure.
- A working keyboard path: visible `:focus-visible`, Esc closes overlays (focus returning to the trigger), Enter submits (IME-safe as above).
- `alt` text on images, `aria-label` on icon-only buttons; tap targets ≥ 40px.
- Zero external requests: system fonts, inline or local CSS/JS, inline SVG icons — no CDN, no icon font, no analytics.
## Design tokens
```css
:root {
color-scheme: light;
/* Brand blue — the only accent family. Use sparingly: links, eyebrows, tiny dots, tints. */
--brand-50: #e8f0fe; --brand-100: #d2e3fc; --brand-300: #8ab4f8; --brand-500: #4285f4;
--brand-600: #1a73e8; /* accent text/icons in light mode */ --brand-700: #0b57d0; /* links on white */
/* Neutrals (Tailwind gray) */
--gray-50: #f9fafb; --gray-100: #f3f4f6; --gray-200: #e5e7eb; --gray-300: #d1d5db;
--gray-400: #9ca3af; --gray-500: #6b7280; --gray-600: #4b5563; --gray-900: #111827;
--bg: #ffffff; --surface: #ffffff; --border: var(--gray-200); --control-border: var(--gray-300);
--fg: var(--gray-900); --fg-muted: var(--gray-600); --fg-faint: var(--gray-500);
--accent-bg: #111827; --accent-fg: #ffffff; /* primary buttons are near-black, not blue */
--radius-control: 6px; /* buttons, inputs, chips */ --radius-card: 12px; /* cards, panels */
--ease: cubic-bezier(0.2, 0.7, 0.3, 1);
}
.dark {
color-scheme: dark; /* pure black, no blue tint */
--bg: #000000; --surface: #0d0d0d; --border: #1f1f1f; --control-border: #303030;
--fg: #f3f4f6; --fg-muted: #9ca3af; --fg-faint: #6b7280;
--accent-bg: #f3f4f6; --accent-fg: #111827; /* primary button inverts to light */
--brand-600: #8ab4f8; --brand-700: #8ab4f8; /* brand text flips to the 300 tone */
}
```
- Toggle dark mode with a `dark` class on `<html>` (persist the choice; default to `prefers-color-scheme`).
- Primary buttons are **neutral black/white**, never blue fills. Brand blue is reserved for accents: links, section eyebrows, small status dots, `--brand-50` tinted chips.
- Pills, badges and dots use `border-radius: 9999px`; everything else uses the two radii above. No gradients or elevation shadows on content (modals excepted; flat focus rings drawn with `box-shadow` are fine).
## Typography
System fonts only — no CDN fonts, no @font-face. The CJK entries matter (bilingual product):
```css
body { font-family: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto,
"PingFang SC", "Microsoft YaHei", sans-serif; -webkit-font-smoothing: antialiased; }
code, pre, kbd { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
```
Headings are always `font-weight: 600` with `letter-spacing: -0.025em` — nothing heavier, no thin weights. Scale: page/hero title 30–36px; section title 24–30px; card title 16–18px; body 14px / line-height 1.5; captions 12px in `--fg-faint`; code 13px / line-height 1.85. Hierarchy comes from weight, size, spacing and hairlines — never from colored blocks.
## Language
Write the page's UI copy in the language the user's request was made in — a Chinese request gets a Chinese interface, an English request an English one — and set `<html lang>` to match. Code identifiers, CSS class names and code comments stay English.
## Components
- **Primary button** — `background: var(--accent-bg); color: var(--accent-fg); border-radius: 6px; padding: 6px 12px; font-size: 14px; font-weight: 500;` hover: `opacity: .9`. Large CTA variant: height 44px, radius 8px, padding 0 20px.
- **Secondary button** — white/`--surface` bg, `1px solid var(--control-border)`, same paddings; hover swaps bg to `--gray-100`/dark `#1f1f1f`.
- **Card** — `bUse when developing PenguinHarness itself — changing packages/{core,server,web,cli,desktop,landing,docs,skills}, the built-in model catalog, the installers or the release workflow; writing or auditing changelog entries; writing a blog post or capturing release screenshots; deciding what to do about data already on disk; or auditing prose that reads like a leaked authoring session. Covers the two-repo symlink layout, the CI-parity verification chain, the record-and-ship contract, where blog media is hosted, and the seams that are intentional.
Use when changing the PenguinHarness Web App (`packages/web`) — adding or restyling any UI, picking a status colour, adding an icon, laying out a row or a form field, writing user-facing copy, or building a popup. Covers the semantic tone tokens, the icon size/stroke/gap scale, the semantic-versus-formatting rule for explanatory text, the two-dictionary i18n contract, and the portal-panel pattern with its Esc and scroll caveats.
Run one specified Test Agent on one specified Benchmark Case exactly once, privately score that execution, and return one protocol result.
Initialize an Agent's settings from a user requirement by writing AGENTS.md, setting identity metadata, and installing only needed Skills.