Undecided design ships as defaults

The AI look is not a skill problem. It is a decision problem. This skill forces the decisions, in order.

npx designpaca

Node 20.11+ · detects and preselects your install targets

Six stages

From one line of brief to a page that passed its own audit

Every stage has a pass condition. Fail it and you do not move on. Below is what one brief became at each stage.

The brief that came in

Build a subscription landing page for a small-batch coffee roastery

  1. Brief gate

    Compress the brief into three lines: what, for whom, constraints. Pick a path by scope.

    For whom: home baristas of 3+ years who can taste the roast profile

  2. Reference research

    Pick three real sites at three different layers: structure, tone, detail.

    R2 = an independent literary publisher. Tone comes from outside the category

  3. Direction

    Synthesize the references into one axis. Choose exactly one risk worth taking.

    Sentiment stays in the name. The screen carries numbers.

  4. Design tokens

    Decide the numbers before writing code. The performance budget is fixed here too.

    --measure: 65ch / --leading-normal: 1.55 / JS budget 0KB

  5. Build

    Layout, surface, depth, motion. It must be finished with every effect switched off.

    <h1>Acidity 8.5 · Body 6.0 · Light roast</h1>

  6. Preflight

    Read your own work as a stranger's. All twelve gates must answer no.

    12/12 gates passed · 0 slop fingerprints · 31px overflow at 320px fixed

SVG filters

Four things you fix without opening an image editor

There is no shortage of filter demos that make texture. The places where filters actually save you work are elsewhere. In all four below, the left is what you used to hand-tune every time and the right is the same material with one declaration added. The numbers come from capturing this screen and measuring it.

  1. A scrim shaped like the letters

    산미 8.5 · 로스팅 2일차
    just placed on top
    산미 8.5 · 로스팅 2일차
    filter: url(#scrim)

    A caption over a photo fails 4.5:1. Every photo has a different brightness, so the translucent box gets hand-tuned each time.

    feMorphology fattens the glyph alpha, a blur softens it, and feFlood fills only that shape. It follows the letters instead of covering the photo with a box.

    white-on-photo contrast 1.70:1 → 4.79:1 · swap the photo, nothing to re-tune

  2. Colour-vision simulation

    통과주의실패
    what you see
    통과주의실패
    deuteranopia

    State encoded in colour alone becomes one badge for 1 in 12 men. No amount of looking at your own screen catches it.

    A single feColorMatrix. This is the one filter that must not run in sRGB — colour-vision transforms are physical mixing, so linearRGB is correct here.

    minimum colour distance across the three badges 82 → 2 · warning and failure become one colour

  3. Separate shapes fusing into one

    no filter · 3 circles
    filter: url(#goo)

    Getting pieces to melt together usually means reaching for canvas or a physics library. It comes up in loaders, merging menus, indicator transitions.

    Blur hard, then stand the alpha up 18× with feColorMatrix. Whether they fuse is arithmetic, not taste — the blurred alpha midway between two circles has to clear the threshold (7÷18 ≒ 0.39). At 18px apart with a blur of 7 it sat near 0.2 and never merged; 12px and 10 clears it.

    counted across the middle row: 3 blobs → 1 · 0 lines of JS

  4. An overlay that bends the backdrop

    산미 8.5
    backdrop-filter: blur
    산미 8.5
    blur + url(#lens)

    A translucent panel only blurs what is behind it. Real glass bends light — that difference puts the panel inside the picture instead of on top of it.

    Hand a displacement map to backdrop-filter. R is the X offset, G is the Y offset, 128 is neutral. Build the map with feTurbulence and every value collapses toward 128, so nothing moves — the map has to be a gradient you draw, pushing inward from the edges.

    the grid compresses at the edges · size the map wrong and nothing happens, silently · Chromium only

Your language is probably not Latin

Latin defaults break Korean in three places

Western design tools carry no Korean typesetting rules. Leave the defaults in place and all three of these fail at once. Left is the default, right is what this skill sets. Same text, same width, same font.

Line breaking

default

스페셜티커피의 로스팅프로파일을 구분하려면 산미와 바디를 수치로 봐야 한다.

word-break: keep-all

스페셜티커피의 로스팅프로파일을 구분하려면 산미와 바디를 수치로 봐야 한다.

The default breaks mid-word. Look at the last line on the left — one word straddles two lines.

Leading

line-height 1.45

스페셜티커피의 로스팅프로파일을 구분하려면 산미와 바디를 수치로 봐야 한다.

line-height 1.75

스페셜티커피의 로스팅프로파일을 구분하려면 산미와 바디를 수치로 봐야 한다.

The Latin standard of 1.4-1.5 is tight for syllable blocks with a final consonant.

Size

11px

스페셜티커피의 로스팅프로파일을 구분하려면 산미와 바디를 수치로 봐야 한다.

15px

스페셜티커피의 로스팅프로파일을 구분하려면 산미와 바디를 수치로 봐야 한다.

11px is a label size in Latin. Korean glyphs carry more strokes and smear at it.

This page, measured

Fixing the copy does not remove the slop

Polishing sentences fixes sentences. The radius vocabulary, the translucent panels, the number of type steps all stay. So here are this page's own form metrics. If a number comes back badly, it ships as it is.

0.6% JS to first paint of the 50KB budget actually spent
12/12 hard gates static checks plus real renders at 320px and 1440px
three.js payload
184KB
fetched only when the inspection frame enters view. Never in the initial bundle
slop fingerprints
0
9 patterns grepped
radius vocabulary
2
3px and 14px. The pill shape is gone
translucent panels
2
grew to 29 before being pulled back. Glass stayed only on frames that hold something
type scale steps
6
as defined in tokens. Display sits outside the scale, and the largest type is 6x the body
font families
2
each language loads only its own
accent colours
1
light and dark are the same colour
time to interactive
not yet
measured with Lighthouse after deploy

Measured on the production build. Unmeasured entries stay empty. A hole is more honest than an invented number. This page is a product demo, so the JS budget was raised to carry three.js. Saying so here is the rule.

What this page actually got caught on

Not the result of auditing someone else. The result of auditing itself.

Text width jumped 13% at the moment the font swapped

Before the web font arrives the system font draws instead, and Malgun Gothic runs 13% wider than Pretendard, so line breaks are recalculated on swap. Matched the fallback with size-adjust. Measured difference is now 0.0%. System fonts differ per OS, so each gets its own fallback.

29 glass cards. Only the material had changed. The structure was still a row of cards

Our own rule says cards are for when elevation carries real hierarchy. Figures became typography, rules became an offset list, the audit became a log. Five panels of glass remain.

We wrote down that Chrome drops backdrop-filter with SVG. It does not

Attach url() to backdrop-filter and Chrome reports true through CSS.supports while discarding the whole declaration at render time. The computed value becomes none. Refraction is demonstrated for real by the SVG tiles in the materials section, and the panels build thickness from blur and edge light instead.

444px of horizontal overflow. The entire layout was off its rails

The grid class had gone missing from main. Subgrid only works when the parent is a grid, so every section had lost its alignment. It merely looked slightly off until the width was actually measured.

Scrolling to the very bottom still left the last 3 of 6 pipeline stages invisible

Elements near the page bottom never reach the end of a scroll-driven animation range. Visible with effects off but missing with them on is not the same as having a fallback. Rebuilt so that once revealed, it stays revealed.

The button inside the dark band sat at 2.88:1. The threshold is 4.5:1

The band inverted the accent colour but left the text on it white. Added an inverted counterpart token and switched both together.

13px of horizontal overflow at 320px, even with the table inside a scroll container

A grid item's default min-width is auto, so content pushes the parent wider. Overflow only works once min-width:0 is set.

6 eyebrow labels. The count rule caps them at 3

Kept three, dropped the rest. Sections read fine without a label above the heading.

The text column was 960px. The measure we had just set was 561px

Bound the grid's main column to the token. The skill's own example code was wrong too, so that got fixed as well.

We skipped this skill's own stage 1 when the direction changed

Switching the material to glass is a stage-2 decision, and that means going back to references first. We jumped straight to implementation instead. The result was glass painted onto the previous direction's skeleton, while design.md still described the old decisions. We re-ran the whole path from stage 0.

The glass panes faced the camera head-on, so Fresnel was structurally zero

When a flat plane faces the camera, the dot product of normal and view is 1, so no edge reflection is computed. The one signal that makes a surface read as glass was dead, which is why six panes looked like blurry rectangles. We bend the normal slightly and derive the rim light from the UV edge instead.

The pipeline, the spine of this page, used only 43% of the viewport

625px out of 1440. Narrowest of the nine sections while being the tallest at 1637px. Opening each stage into two columns brought it to 1113px.

The contrast script treated translucent backgrounds as opaque

It reported "English 1.15:1", which was wrong. Compositing alpha bottom-up gave zero failures. A checker that is wrong makes both its passes and its failures meaningless.

All thirteen were caught while building this page, and fixed after being caught. Three came from a person rather than a checker: the cards look generic, the typography is not handled well, and did we actually use our own skill.

Every rule states why

A prohibition without a reason does not survive contact with a brief. If the user asks for it explicitly, the user wins.

Never start without references
Starting from memory produces the category average.
One accent colour
Wanting a second one means the hierarchy failed.
Be bold in exactly one place
Shout in two places and both go unheard.
Spectacle ranks fourth
Judging weights are Design 40 / Usability 30 / Creativity 20 / Content 10.
Never invent a number
A number-shaped hole is honest. An invented number costs trust.
It must be finished with every effect off
That state is the basis of every fallback. If it collapses, the effects were doing the structure's job.

One line

Targets are detected and preselected. If you edit a skill file yourself, updates leave it alone.

npx designpaca
  • Claude Code ~/.claude/skills/designpaca/
  • Codex CLI ~/.codex/skills/designpaca/
  • Cursor ~/.cursor/skills/designpaca/
  • ZCode ~/.zcode/skills/designpaca/
  • Neutral path ~/.agents/skills/designpaca/ · any harness
  • Antigravity ~/.gemini/antigravity-cli/skills/designpaca/
  • Gemini CLI ~/.gemini/skills/designpaca/
  • Windsurf ~/.codeium/windsurf/skills/designpaca/
  • Copilot ~/.copilot/skills/designpaca/
  • AGENTS.md block injection, agent agnostic
npx designpaca update
Pull the latest skill. Files you edited are skipped
npx designpaca doctor
Diagnose install state and drift
npx designpaca uninstall
Exact removal, driven by the manifest