osmontero/opencode-skills

designing-frontend-interfaces

Use when building or restyling any web interface — landing pages, dashboards, marketing sites, web apps, React/Vue components, HTML/CSS layouts, artifacts, posters — or when asked to make a UI look better, more polished, more distinctive, less generic, or less "AI-generated".

Trending #9345 First seen May 31, 2026

Installation

$ npx skills add osmontero/opencode-skills --skill designing-frontend-interfaces

Summary

  • Use when building or restyling any web interface — landing pages, dashboards, marketing sites, web apps, React/Vue components, HTML/CSS layouts, artifacts, posters — or when asked to make a UI look better, more polished, more distinctive, less generic, or less "AI-generated".
  • Also use when a design brief, art direction, visual identity, type scale, or color system is needed before implementation.

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from osmontero/opencode-skills · top by installs.

npx skills add osmontero/opencode-skills

Browse all from osmontero/opencode-skills

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Declared

Repository health

Stars 9
License LICENSE
Default branch main
Open issues 0
Status Active

Skill metadata

Parsed from SKILL.md frontmatter.

LicenseComplete terms in LICENSE.txt
Declared agents opencode

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 13,092 B
  • docs SUMMARY.md 440 B

History

  1. First seen on skills.sh
  2. First recorded snapshot · 217 installs

SKILL.md

Designing Frontend Interfaces

Overview

Distinctive interfaces come from committing to one aesthetic direction and executing it with a locked system of values. Generic interfaces come from picking each value ad hoc at the moment it is needed.

Core principle: Decide the system before you write the components. Every number in the finished CSS should trace back to a scale you chose deliberately.

This skill covers visual craft. Two companion skills cover the rest of interface quality:

  • REQUIRED SUB-SKILL for anything with flows, forms, or non-trivial state: use designing-user-experience
  • REQUIRED SUB-SKILL before shipping: use building-accessible-interfaces
  • To critique a finished UI, use reviewing-interface-quality

The Iron Law

NO COMPONENT CODE BEFORE THE DESIGN BRIEF AND TOKEN BLOCK EXIST

The brief is 8 lines. The token block is one CSS block. Together they cost about ninety seconds and they are what separates a designed interface from a decorated one.

Wrote components first? The values are already arbitrary. Extract them into a real scale before continuing — do not rationalize the numbers you happened to type.

Checklist

Create a task for each item and complete them in order:

  1. Write the design brief — 8 lines, in your response, before any file is created
  2. Choose an aesthetic direction — from references/aesthetic-directions.md, or invent one, and name it
  3. Lock the token block — type scale, color ramp, space scale, radius, shadow, motion. One CSS block.
  4. Build the layout skeleton — structure and spacing, no decoration yet
  5. Build components — every interactive element gets all five states
  6. Add the one memorable moment — the single thing someone will remember
  7. Self-review against the rubric — see Self-Review below; fix what fails
  8. Verify visually — render it and actually look at it

Step 1: The Design Brief

Write this out before creating any file. It is 8 lines of plain text in your response — not a document, not a file.

Purpose:    What job does this interface do?
Audience:   Who uses it, in what context, on what device?
Tone:       One named direction (see references/aesthetic-directions.md)
Reference:  A real-world visual analogue — a magazine, a era, a discipline
Palette:    Base / surface / ink / one accent — as hue intentions, not hex yet
Type:       Display face + text face, and why this pairing
Memorable:  The one thing someone will describe to a friend
Restraint:  What this design deliberately does NOT do

The Restraint line matters most. A design with no stated restraint becomes a design with every effect applied at once.

Worked example:

Purpose:    Changelog for a developer infrastructure tool
Audience:   Engineers skimming on a wide monitor, 30 seconds per visit
Tone:       Technical Broadsheet — newspaper density meets terminal precision
Reference:  Financial Times print edition, 1990s man pages
Palette:    Warm newsprint base, near-black ink, one signal red for breaking changes
Type:       Instrument Serif display / IBM Plex Mono text — editorial authority, machine detail
Memorable:  Version numbers set enormous in the left margin, hanging outside the text column
Restraint:  No cards. No shadows. No rounded corners. Rules and space only.

Step 2: Lock the Token Block

Every value the interface uses comes from here. If a number is not in this block, it does not belong in a component.

:root {
  /* TYPE — one ratio, applied consistently. 1.200 minor third (dense UI),
     1.250 major third (general), 1.333 perfect fourth (marketing),
     1.500 perfect fifth (editorial/poster). Pick ONE. */
  --font-display: "Instrument Serif", Georgia, serif;
  --font-text:    "IBM Plex Mono", ui-monospace, monospace;
  --step--1: 0.833rem;  --step-0: 1rem;     --step-1: 1.25rem;
  --step-2:  1.563rem;  --step-3: 1.953rem; --step-4: 2.441rem;
  --step-5:  3.052rem;  --step-6: 3.815rem;

  /* SPACE — one base unit and its multiples. Never a value in between. */
  --space-3xs: 0.25rem; --space-2xs: 0.5rem; --space-xs: 0.75rem;
  --space-s:   1rem;    --space-m:   1.5rem; --space-l:  2rem;
  --space-xl:  3rem;    --space-2xl: 4.5rem; --space-3xl: 7rem;

  /* COLOR — a ramp, not a set of one-offs. One accent, used sparingly. */
  --base:    #f4f1ea;   /* page */
  --surface: #ffffff;   /* raised */
  --ink:     #12100e;   /* primary text */
  --ink-2:   #55504a;   /* secondary text */
  --ink-3:   #8b857c;   /* tertiary / meta */
  --line:    #ddd7cc;   /* borders, rules */
  --accent:  #c1362f;   /* <10% of visible surface */

  /* FORM */
  --radius: 0;          /* commit: 0, or 2-4px, or a full 999px pill. Not "some of each". */
  --border: 1px solid var(--line);
  --shadow: none;       /* if using shadows, define 2 — near and far. Never 5. */

  /* MOTION */
  --dur-fast: 120ms; --dur: 220ms; --dur-slow: 420ms;
  --ease:     cubic-bezier(0.2, 0, 0, 1);
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
}

Rules for the block:

Token Rule
Type scale One ratio for the whole page. Deriving sizes by eye produces muddy hierarchy.
Space scale Every margin/padding/gap is a --space-* token. No 13px. No 0.85rem.
Color ramp Three ink levels is enough. A fourth means the hierarchy is unclear.
Accent Exactly one, unless the direction is explicitly maximalist. Under 10% of surface.
Radius One value. Mixed radii is the single loudest amateur signal.
Shadow Zero or two. Two shadows = one tight contact shadow + one wide ambient.
Motion Three durations, two easings. That covers every transition an interface needs.

Step 3: Hierarchy

Vary one dimension at a time. Amateur hierarchy changes size and weight and color and spacing simultaneously; everything shouts and nothing leads.

Need Change Keep fixed
Section heading vs. body Size (2+ steps) Weight, color
Emphasis inside a paragraph Weight Size, color
Metadata / captions Color (to --ink-3) Size, weight
Grouping Space (a full step) Everything else

Space groups more reliably than lines or boxes. Before adding a border or a card, try doubling the gap between groups and halving it within them. Most "needs a card" instincts are actually "needs correct spacing."

Step 4: Anti-Slop

Generic AI interface output has a specific, enumerable signature. These are not stylistic preferences — they are the exact defaults that make output identifiable on sight.

Never Instead
Inter, Roboto, Arial, system-ui as the display face A face with an opinion — see references/typography.md
Purple/violet → blue gradient on white Commit to a real palette from a real reference
rounded-lg / rounded-xl on everything One radius, chosen; or zero radius
A shadow-md on every surface Shadows only where something genuinely floats
Hero → 3 feature cards → CTA Let the content decide the structure
A centered max-w-4xl column for the whole page Vary measure by content type; break the grid at least once
text-gray-500 body text on white Real ink colors with intent; body text at full contrast
Emoji standing in for icons A real icon set, or no icons
Six weights of one neutral sans Two faces, three weights, maximum
Every section the same vertical rhythm Vary section spacing to express importance

The convergence trap: across separate generations, do not keep reaching for the same "safe distinctive" choices. Space Grotesk, a dark slate background, and a lime-green accent is now its own cliché. Vary light and dark, serif and sans and mono, dense and airy, across designs. Check references/aesthetic-directions.md and pick one you did not pick last time.

Rationalization table:

Thought Reality
"The user didn't specify a style, so neutral is safest" Unspecified means you choose. Neutral is a choice, and it is the worst one.
"It's just a quick demo" Demos are what people look at. The brief takes ninety seconds.
"Inter is genuinely a good typeface" It is. It is also the single strongest generic-AI signal. Use it for body text at most, never for display.
"A card grid is the clearest way to show features" It is the most common way. Try a table, a list with rules, a stepped layout, an editorial spread.
"I'll add the distinctive touches at the end" Distinctiveness is structural. Bolted on at the end it reads as decoration.
"Tailwind defaults are a design system" They are a palette of defaults. Configure them, or you ship the defaults everyone ships.

Step 5: Component States

Every interactive element gets all five. Missing states are the most common gap in generated UI.

.btn              { /* rest */ }
.btn:hover        { /* pointer only — must not be the sole affordance */ }
.btn:active       { /* pressed — a real transform, not just a color shift */ }
.btn:focus-visible{ outline: 2px solid var(--accent); outline-offset: 2px; }
.btn:disabled     { /* visibly inert, and still readable */ }
.btn[aria-busy]   { /* loading — reserve the space, don't collapse the layout */ }

Never remove focus outlines. If the default outline is ugly, restyle it — do not set outline: none. See building-accessible-interfaces.

Step 6: Verify Visually

Rendering code and reading it back is not verification. Look at the actual pixels.

# Static HTML
python3 -c "
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
    b = p.chromium.launch()
    pg = b.new_page(viewport={'width':1440,'height':900})
    pg.goto('file:///abs/path/index.html'); pg.wait_for_timeout(600)
    pg.screenshot(path='/tmp/desktop.png', full_page=True)
    pg.set_viewport_size({'width':390,'height':844})
    pg.screenshot(path='/tmp/mobile.png', full_page=True)
    b.close()"

Then read both PNGs and check them against the rubric. For dev servers, use the testing-webapps skill's with_server.py helper.

What to look for that only shows in the render: text overflowing containers, collapsed layouts at 390px, invisible low-contrast text, elements touching viewport edges, a heading that wraps to one orphaned word, images without dimensions causing layout shift.

Self-Review

Score each line honestly. Any no means fix it, not explain it.

  • Every spacing value in the CSS is a token from the block
  • The type scale is one ratio; no size was chosen by eye
  • Exactly one accent color, under 10% of visible surface
  • One radius value throughout
  • A stranger could name the aesthetic direction from a screenshot
  • The Memorable line from the brief is actually present in the build
  • The Restraint line was actually respected
  • Nothing from the Anti-Slop table appears
  • All five states exist on every interactive element
  • Focus is visible and never suppressed
  • Verified at 1440px and 390px by looking at screenshots
  • Body text passes 4.5:1; large text passes 3:1

Reference Files

Load these when you reach the relevant decision — not upfront.

File Load when
references/aesthetic-directions.md Step 1 — choosing and parameterizing a direction
references/typography.md Choosing faces, building the scale, setting text
references/color-and-theme.md Building the ramp, dark mode, contrast math
references/layout-and-composition.md Grids, breakpoints, breaking the grid, z-index
references/motion.md Any animation beyond a hover color change

Common Mistakes

Tokens declared, then ignored. The :root block exists but components use padding: 14px. Grep your CSS for raw px values before finishing.

Distinctive typeface, default everything else. Swapping Inter for a display face while keeping the card grid, the uniform radius, and the gray body text produces generic output in a costume.

Maximalism as an excuse for incoherence. Maximalist directions still need one type scale, one space scale, one palette. More elements, same system.

The brief describes a design the build does not deliver. Re-read the brief at Step 7. If Restraint: no shadows and the build has shadows, the build is wrong.

Complexity mismatched to the vision. A refined-minimal direction implemented with elaborate scroll animations reads as confused. Match implementation effort to the stated tone.