The small details that make an interface feel finished

jubayer-ui gives Claude exact values for the details people feel but rarely name: nested corners, optical centring, shadows, icon swaps and press feedback, in both directions.

  • Free, MIT License
  • 10 files, 23 KB zip

Updated 28 October 2026

When Claude uses it

Claude reads this description from the skill's SKILL.md and loads the skill when your request matches it.

Reviews and polishes interface details with exact values, covering concentric border radius, optical alignment, shadows versus borders, image outlines, icon stroke and states, press feedback, enter and exit motion, icon cross-fades and theme-switch transitions, plus right-to-left rules for Arabic/English products (which icons mirror and which never do, flipping optical nudges, drawers, swipes, carousels, logical corner radii and x-offset shadows) and a bilingual check. Use when a component or screen looks slightly off, when adding or reviewing hover, press, icon or entrance motion, when choosing radius, shadow or icon values, or when building or reviewing an RTL or bilingual interface.

What it covers

  • Concentric radius

    The outer radius is the inner radius plus the padding, so nested corners look parallel.

  • Optical alignment

    Nudge play icons and icon buttons by eye where geometric centring looks off.

  • Shadows for depth, borders for structure

    Layered transparent shadows replace borders that only fake depth; dividers and focus states keep theirs.

  • Icon and press motion

    Icon swaps with scale, opacity and blur at fixed values, and scale(0.96) on press.

  • Motion restraint

    Name the properties that transition, skip animation on first load and on theme switch, and use will-change sparingly.

  • Icons that match the text

    Stroke width follows the weight of the text beside it; one SVG, recoloured per state.

  • Right to left

    Mirror only directional icons, never logos, media controls or digits; negate horizontal motion and use logical corners.

What this version adds

A reference on RTL icons and motion: which icons mirror and which never do, how to flip them, which optical nudges change sides, drawers, swipes and carousels in RTL, logical corner radii and shadows with an x offset.

Try it with a prompt like this

The Arabic version of my dashboard feels off: the drawer slides in from the wrong side and some icons point backwards. Can you polish it?

Or run it by name in Claude Code: type /jubayer-ui and what you want checked.

View SKILL.md

The skill's main file, as it is in the zip. The reference files it links to are listed below it.

jubayer-ui/SKILL.md · Show the full file
---
name: jubayer-ui
description: Reviews and polishes interface details with exact values, covering concentric border radius, optical alignment, shadows versus borders, image outlines, icon stroke and states, press feedback, enter and exit motion, icon cross-fades and theme-switch transitions, plus right-to-left rules for Arabic/English products (which icons mirror and which never do, flipping optical nudges, drawers, swipes, carousels, logical corner radii and x-offset shadows) and a bilingual check. Use when a component or screen looks slightly off, when adding or reviewing hover, press, icon or entrance motion, when choosing radius, shadow or icon values, or when building or reviewing an RTL or bilingual interface.
---

# UI polish

An interface rarely feels unfinished because of one big mistake. It feels unfinished because of a dozen small ones: radii that do not nest, an icon a pixel off-center, a border doing a shadow's job, a transition that cannot be interrupted. This skill lists the details worth fixing and gives the exact value for each, including the ones that break when the same screen runs right to left.

When reviewing, slow the interface down. What feels off at 10% speed is what is subtly wrong at full speed.

Keep the project's component library, tokens and density, and match its motion language except where a rule below prescribes an exact interaction.

Every duration, curve, scale and blur below is a specific value, not a range to approximate. `cubic-bezier(0.2, 0, 0, 1)` is not `cubic-bezier(0.4, 0, 0.2, 1)`, and `0.96` is not `0.95`. Use what is written.

Text wrapping, font rendering, tabular numbers and text spacing belong to `jubayer-typography`. Hit areas, focus, keyboard support, ARIA and reduced motion belong to `jubayer-accessibility`. Grouping, section spacing, breakpoints and spatial RTL belong to `jubayer-layout`.

## Concentric border radius

Outer radius = inner radius + padding. Mismatched radii on nested elements is the most common thing that makes an interface feel off. Radius, shadow and outline recipes are in [surfaces.md](surfaces.md).

## Optical over geometric alignment

When geometric centering looks off, align optically. Buttons with icons, play triangles and asymmetric icons all need a manual nudge.

## Shadows for elevation, borders for structure

Where a border exists only to create depth, prefer layered transparent `box-shadow` values. Keep borders that communicate structure or state: dividers, separators and selected or focus states.

## Interruptible animations

Use CSS transitions for interactive state changes, because they can be interrupted mid-animation. Reserve keyframes for staged sequences that run once.

## Split and stagger enter animations

For an infrequent staged entrance where sequence communicates hierarchy, break the content into semantic chunks and stagger them by ~100ms. Animating one container gets you less for the same cost. Leave high-frequency interactions unstaggered. See [enter-exit.md](enter-exit.md).

## Subtle exit animations

Use a small fixed `translateY` rather than full height. Exits should be softer than enters. Use `ease-out` for both directions.

## Contextual icon animations

Animate icons with `opacity`, `scale` and `blur` rather than toggling visibility. Use exactly these values: scale `0.25` to `1`, opacity `0` to `1`, blur `4px` to `0px`.

With a motion library (`motion` or `framer-motion` in `package.json`), match that package's import path, or nearby imports where both exist. Use `transition: { type: "spring", duration: 0.3, bounce: 0 }`. Bounce is always `0`.

Without one, keep both icons in the DOM with one absolutely positioned, and cross-fade with `cubic-bezier(0.2, 0, 0, 1)`. That gives you enter and exit with no dependency. Both recipes are in [icon-transitions.md](icon-transitions.md).

## Image outlines

Give images a `1px` outline at low opacity for consistent depth. Pure black in light mode (`oklch(0 0 0 / 0.1)`), pure white in dark (`oklch(1 0 0 / 0.1)`). Never a near-black like slate or zinc and never a tinted neutral. A tinted outline picks up the surface underneath and reads as dirt on the image edge.

## Scale on press

A `scale(0.96)` on click gives a button tactile feedback. Always `0.96`; anything below `0.95` feels exaggerated. Add a `static` prop to switch it off where motion would distract. See [recipes for CSS, Tailwind and Motion](animations.md#scale-on-press).

## Skip animation on page load

Use `initial={false}` on `AnimatePresence` to keep enter animations off the first render. Check that it leaves intentional page entrances intact.

## Suppress transitions on theme switch

A theme flip changes color, background, border and shadow on nearly every element at once. Every transition on those properties fires together and the switch smears instead of snapping. Inject `*,*::before,*::after{transition:none !important}`, force a reflow, then remove it on the next frame. See the [recipe](animations.md#suppress-transitions-on-theme-switch).

## Transition only what changes

Always name the exact properties: `transition-property: scale, opacity`. Tailwind's `transition-transform` covers `transform, translate, scale, rotate`.

## Use `will-change` sparingly

Only for `transform`, `opacity` and `filter`, which the GPU can composite. Never `will-change: all`. Add it when you see first-frame stutter, not before. See [performance.md](performance.md).

## Match icon stroke to text weight

An icon next to text carries the text's optical weight: `1.5px` stroke beside regular (400) text, `2px` beside semibold (600). One stroke weight per icon set and one icon library per surface. Sizing and RTL flipping are in [icons.md](icons.md), with the full RTL rules in [rtl-icons-and-motion.md](rtl-icons-and-motion.md).

## One SVG, recolored per state

Icons use `currentColor` and take hover, selected and disabled states from CSS color and opacity, never from separate assets. Outline is the default variant; fill marks the active state.

## Motion restraint

Give high-frequency interactions instant feedback, or a transition of `150ms` or less on opacity and color. A custom animation there charges its attention cost on every trigger.

Every animated state change also needs a static cue: color, an icon, or a label. Motion is never the only feedback channel.

## Right to left: icons, motion and corners

Logical properties flip layout; they do not flip icons, transforms, shadows or gestures. Set `dir` in markup (`<html lang="ar" dir="rtl">`) and key every override off `:dir(rtl)` or `[dir="rtl"]`.

- **Mirror only directional icons**: back/forward arrows, navigation chevrons, reading-direction progress, sliders, text and list icons, a composer's send arrow. Never mirror media controls or the scrub bar, clockwise clocks and circular arrows, logos, photos, digits, code, phone numbers or checkmarks.
- **Flip with `scale: -1 1`** (or `transform: scaleX(-1)`) under `:dir(rtl)`. For a glyph with Latin letters or numbers, ship a drawn RTL variant instead.
- **Nudges follow the glyph.** Put padding nudges on logical sides; negate `translate` nudges on mirrored icons; leave the play triangle's nudge physical.
- **Negate horizontal motion.** `translateX()` and Motion's `x` keep their sign. Navigation drawers enter from the inline start, side sheets from the inline end, and carousels, swipe thresholds and edge-swipe back follow the reading direction. JS reading `scrollLeft` must handle negative values.
- **Asymmetric corners use logical properties** (`border-start-start-radius`, `rounded-s-*`); the concentric rule is unchanged.
- **x-offset shadows and directional gradients** need an RTL override; a `--dir: 1 / -1` multiplier keeps each value written once.

Bangla is left to right, so a Bangla/English product mirrors nothing. Recipes and the bilingual checklist are in [rtl-icons-and-motion.md](rtl-icons-and-motion.md).

## Before you finish

| Mistake | Fix |
| --- | --- |
| Icons look off-center | Nudge optically with padding, or fix the SVG |
| Jarring staged entrance or exit | Stagger infrequent entrances; keep exits subtle |
| Theme toggle crossfades the whole page | Disable transitions for the swap, force a reflow, restore on the next frame |
| `transition: all` on elements | Specify exact properties |
| First-frame animation stutter | Add `will-change: transform` (sparingly) |
| Hairline icon beside bold text | Match the stroke width to the text weight |
| Every icon mirrors in RTL, or none do | Mirror only directional icons; play, clocks, logos, digits and checkmarks stay |
| Flipped icon with letters or numbers | Ship a drawn RTL variant |
| Open chevron points up in RTL | Negate the rotation angle under `:dir(rtl)` |
| Drawer, carousel or swipe moves the wrong way in RTL | Anchor with `inset-inline-*` and negate the x value with a direction sign |
| Rounded corner on the wrong side in RTL | Use `border-start-start-radius` and the other logical corners |
| Shadow or fade points the wrong way in RTL | Override the x offset or gradient direction under `:dir(rtl)` |

## Reporting

**Severity.** `HIGH` breaks an interaction, makes motion unusable, or leaves a state change visible only while the animation runs. `MEDIUM` is a visible inconsistency in surfaces, icons, or motion. `LOW` is isolated polish.

**Verification.** Without a browser: every state the component defines, meaning hover, focus, active, loading and empty, plus motion durations and easings read from the code. With one: walk each state, and replay motion at 10% speed in the browser's Animations panel. For a bilingual product, repeat the walk with `dir="rtl"` on `<html>` and real Arabic content, and run the checklist in [rtl-icons-and-motion.md](rtl-icons-and-motion.md#bilingual-checklist). Report every check you could not run as `Not verified`.

**Format.** Group findings under the principle each violates, ordered by severity, one row per root cause listing every location it appears in:

| Severity | Location | Before | After | Why |
| --- | --- | --- | --- | --- |

`Location` is `path/to/file:line`. `Why` names the principle and the user impact.

End with `Block` when any `HIGH` remains, `Approve` otherwise, leaving the rest in the table as work to do. Never `Approve` coverage you did not inspect. With nothing to report, state "No actionable UI-polish findings" and report verification.

## Origin

Based on Jakub Krehel's `better-ui` skill (MIT License), renamed and edited by Maniruzzaman Jubayer, with added right-to-left and bilingual rules. See LICENSE.

Files in the zip

  • jubayer-ui/LICENSE1 KB
  • jubayer-ui/SKILL.md10 KB
  • jubayer-ui/agents/openai.yaml1 KB
  • jubayer-ui/animations.md7 KB
  • jubayer-ui/enter-exit.md4 KB
  • jubayer-ui/icon-transitions.md4 KB
  • jubayer-ui/icons.md5 KB
  • jubayer-ui/performance.md3 KB
  • jubayer-ui/rtl-icons-and-motion.md11 KB
  • jubayer-ui/surfaces.md7 KB

Based on Jakub Krehel's better-* skills, MIT License. The LICENSE in the zip keeps his copyright and mine.

Install jubayer-ui in 3 steps

Pick where you use Claude. The same zip works in both places.

In the Claude app or on Claude.ai

  1. Step 1:

    Open Settings › Capabilities. Under Code execution and file creation, switch on Run code in the cloud. Skills need it.

    Claude settings at Capabilities, showing Code execution and file creation with the Run code in the cloud switch turned on, noted as required for skills
    Settings › Capabilities: Run code in the cloud, on
  2. Step 2:

    Open Settings › Customize › Skills, choose + Add, then Upload skill.

    The Skills section of Customize in Claude with the + Add menu open, showing Create a skill, Create with Claude and Upload skill, with Upload skill outlined
    Customize › Skills › + Add › Upload skill
  3. Step 3:

    Drop the skill's zip, as it downloads from here, on Upload a skill and choose Upload. Claude scans it, then lists it under Skills, where you switch it on or off.

    The Upload a skill page in Claude with its drop zone outlined, which takes a .zip or .skill file that includes a SKILL.md and runs a security scan on upload
    Upload a skill: drop the .zip, then Upload

In Claude Code

  1. Step 1:

    Unzip the skill into your skills folder: ~/.claude/skills/ for every project, or .claude/skills/ in one project.

    A terminal running mkdir -p ~/.claude/skills and unzip jubayer-ui.zip -d ~/.claude/skills
    Unzip into ~/.claude/skills
  2. Step 2:

    Check the folder is there. Each skill is a folder with a SKILL.md inside.

    A terminal listing ~/.claude/skills with the jubayer skill folders and the files inside one of them
    Each skill is its own folder
  3. Step 3:

    Ask Claude for the job in plain words, or type the skill's name as a command, such as /jubayer-ui.

    A terminal starting Claude Code in a project folder, with /jubayer-ui polish the settings page typed as the request
    Run it by name or just ask

Want the polish built in from the start?

I design interfaces and build them in production code, so details like these never wait for a cleanup pass.

Questions people ask

  • Both. The rules are design decisions written as code: CSS, Tailwind or Motion values Claude can apply in your components.
  • No. It keeps your components, tokens and density, and only prescribes exact values where a detail needs one, such as the press scale.
  • Arrows, chevrons, back and forward, and icons that show the direction of text. Not logos, media playback controls, clocks, checkmarks, digits or code.

Want this level of detail in your product?

I design and build products with these rules from the first flow, in English, Arabic or both. Start with a free 30 minute call, then get one written scope and one fixed quote.

Book a free intro call