stolinski/s-stack/design-engineering

Trust tier 3
  • community
Source check pending

Checking that the SKILL.md file is still in the repository.

Use when designing, building, reviewing, or polishing user interfaces, motion, component behavior, interaction details, and product-feel across any frontend stack. Generalized from Emil Kowalski-style design engineering principles; framework-neutral, implementation-first.

Install

npx vskill@latest install stolinski/s-stack/design-engineering

SKILL.md

Design Engineering

Purpose

Use this skill to make interfaces feel intentional, fast, and physically believable — not merely functional. It is framework-neutral: apply it to HTML/CSS, Svelte, React, Vue, native apps, Web Components, canvas/WebGL, or design specs.

The goal is not decoration. The goal is product feel: the compounding effect of layout, motion, responsiveness, accessibility, and tiny interaction details that users rarely notice consciously but absolutely feel.

When to Use

Use for:

  • UI polish passes
  • Interaction design and component behavior
  • Motion design, transitions, gestures, and microinteractions
  • Reviewing frontend code for feel, responsiveness, and accessibility
  • Turning a rough UI into something crisp and shippable
  • Designing component APIs where behavior and styling must stay coherent
  • Diagnosing why an interface feels slow, awkward, cheap, or janky

Do not use for:

  • Pure backend work with no user-facing behavior
  • Brand strategy without UI execution
  • Large design-system governance unless the task includes concrete UI behavior

Core Philosophy

Taste is trained

Good taste is not vibes. It is pattern recognition built by studying great interfaces, reverse-engineering why they feel good, inspecting tiny details, and practicing until the defaults become sharp.

Do not stop at “it works.” Ask what the user feels in the first 100ms after they act.

Invisible details compound

The best UI details disappear. A popover opens from the trigger. A button visibly responds to pressure. A list reorders without losing spatial continuity. A destructive action feels serious without feeling dramatic.

Users may not name these details, but their nervous system does.

Beauty is leverage

Most software is good enough. Taste is a differentiator. Strong defaults, precise motion, and coherent interaction details make tools feel more trustworthy and more desirable.

Operating Loop

  1. Identify the user action.
  2. Identify the expected physical response.
  3. Decide whether motion helps or hurts.
  4. Make the first frame responsive.
  5. Preserve spatial continuity.
  6. Implement with the least fragile primitive.
  7. Test slowly, quickly, interrupted, repeated, keyboard-only, touch, and reduced-motion.
  8. Remove anything that feels ornamental under repetition.

Review Output Contract

When reviewing UI or code, prefer a compact table:

BeforeAfterWhy
transition: all 300mstransition: transform 180ms var(--ease-out), opacity 180ms var(--ease-out)Exact properties avoid accidental slow/janky animations
Element appears from scale(0)Start at scale(.96) + opacity: 0Real objects do not appear from mathematical nothing
Popover scales from centerPopover scales from trigger edge/originMotion should explain where the surface came from
Keyboard command opens animated paletteKeyboard command opens instantlyFrequent keyboard actions must feel immediate

If making changes, also report:

  • Changed: files/areas touched
  • Verified: exact command/browser/device checks run
  • Remaining: only if something material is still unresolved

Animation Decision Framework

1. Should this animate?

Ask how often the user sees it.

FrequencyDecision
Hundreds of times/day: command palette, keyboard nav, shortcut-driven actionsNo animation, or effectively instant
Tens of times/day: hover, row focus, common navigationMinimal feedback only
Occasional: dialogs, drawers, toasts, settings panelsStandard motion is useful
Rare: onboarding, empty-state celebration, marketing demoDelight is allowed

Rule: keyboard-initiated actions should generally not animate. Keyboard users are asking for speed.

2. What is the purpose?

Valid purposes:

  • Feedback: confirms an input was received
  • Spatial continuity: explains where something came from or went
  • State indication: connects previous state to next state
  • Jarring-change prevention: avoids a broken-looking jump
  • Education: demonstrates behavior or hierarchy
  • Delight: only when rare enough not to become tax

If the purpose is only “looks cool,” cut it unless the moment is rare and intentionally expressive.

3. What easing should it use?

Default decisions:

  • Entering/exiting surfaces: strong ease-out
  • Moving objects already on screen: ease-in-out
  • Hover/color/soft property changes: standard ease or tokenized curve
  • Constant looping motion: linear
  • Drag/release, physics, interrupts: spring/inertia model when available

Useful CSS curves:

css
:root {
--ease-out: cubic-bezier(0.23, 1, 0.32, 1);
--ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);
--ease-drawer: cubic-bezier(0.32, 0.72, 0, 1);
}

Avoid ease-in for most UI entrances. It withholds motion at the moment the user is watching, so it feels sluggish.

4. How fast should it be?
InteractionDuration
Press feedback80–160ms
Hover/focus feedback100–180ms
Tooltip100–160ms, often no delay after first hover
Popover/menu140–220ms
Toast enter180–260ms
Dialog/drawer200–320ms
Page/route transition200–400ms, only if it preserves orientation
Exit of temporary UIUsually faster than enter

Perceived performance matters more than raw duration. The first visual response should happen immediately, even if the full transition takes longer.

Motion Rules with Teeth

Never animate all

Bad:

css
.card { transition: all 300ms ease; }

Good:

css
.card {
transition:
transform 180ms var(--ease-out),
opacity 180ms var(--ease-out),
border-color 140ms ease;
}
Prefer transform and opacity

Animate transform and opacity by default. Treat layout properties (height, width, top, left, margin) as expensive and suspicious unless the element count is small and you have tested it.

If animating layout is necessary, isolate the damage:

  • Limit the animated subtree
  • Use containment where appropriate
  • Avoid animating large lists
  • Test under CPU throttling or real low-end devices
Do not appear from scale(0)

Bad:

css
.popover[data-state='open'] { transform: scale(1); }
.popover[data-state='closed'] { transform: scale(0); }

Good:

css
.popover {
transform-origin: var(--surface-origin, top center);
transition: transform 160ms var(--ease-out), opacity 120ms ease;
}
.popover[data-state='closed'] {
transform: scale(.96) translateY(-2px);
opacity: 0;
}

Objects should feel like they enter the world, not spawn from zero dimension.

Origin matters
  • Popovers, dropdowns, menus: scale/slide from the trigger or attachment edge.
  • Modals: stay centered; do not pretend they came from a random button unless the design is explicitly morphing.
  • Tooltips: small offset from anchor; fast and calm.
  • Drawers/sheets: move from their physical screen edge.
Make press states physical

Buttons and pressable controls need a visible response.

Good patterns:

css
.button {
transition: transform 120ms var(--ease-out), background-color 120ms ease;
}
.button:active {
transform: scale(.97);
}

For dense professional tools, reduce the scale change: .99 or a color/brightness response can be enough.

Prefer interruptible motion

Users change their mind mid-transition. UI should survive interruption.

Prefer:

  • CSS transitions for simple state changes
  • Web Animations API for controllable imperative animation
  • Spring/inertia libraries for gestures
  • Timeline libraries only when sequencing is truly needed

Avoid brittle keyframe choreography for basic UI state changes.

Use @starting-style for enter transitions when supported

For native CSS enter animations without mounting hacks:

css
.panel {
opacity: 1;
transform: translateY(0);
transition: opacity 160ms ease, transform 160ms var(--ease-out);
@starting-style {
opacity: 0;
transform: translateY(4px);
}
}

Use progressive enhancement. Do not make the component depend on unsupported behavior without a fallback.

Component Design Principles

Components own behavior, not just pixels

A polished component defines:

  • States: idle, hover, focus, active, loading, disabled, selected, invalid
  • Input modes: mouse, touch, keyboard, screen reader
  • Timing: how it enters, exits, interrupts, and repeats
  • Layout behavior: overflow, wrapping, density, container constraints
  • Accessibility: roles, names, focus movement, reduced motion

A component that only defines colors and border radius is not done.

Design APIs around intent

Prefer component props/options that encode product intent over raw styling knobs.

Better:

ts
variant: 'primary' | 'secondary' | 'danger'
density: 'comfortable' | 'compact'
emphasis: 'strong' | 'subtle'

Worse:

ts
borderColor: string
paddingX: number
animationDuration: number

Expose escape hatches only when real use cases demand them.

Empty, loading, and error states are part of the component

Do not bolt them on later. A component should know how it behaves when:

  • Data has not loaded
  • Data is empty
  • Data failed
  • Data is stale while refetching
  • The user lacks permission
  • The viewport is cramped
Focus is a design material

Keyboard focus should be visible, tasteful, and predictable. Never remove outlines without replacing them. Focus movement must match user intent.

Checklist:

  • Tab order follows visual/task order
  • Escape closes temporary surfaces
  • Focus returns to the trigger after dismissal
  • Dialogs trap focus only while modal
  • Roving focus is used for composite widgets when appropriate

Gestures and Drag Interactions

Dismiss by intent, not distance alone

Use a combination of distance and velocity. A quick confident flick should dismiss even if distance is short; a slow accidental drag should recover.

Boundaries should damp, not brick-wall

When dragging past a limit, apply resistance/friction instead of hard stopping. Hard stops feel cheap and broken.

Capture the pointer

For web drag interactions, use pointer events and pointer capture so dragging remains coherent even if the pointer leaves the element.

ts
function onPointerDown(event: PointerEvent): void {
event.currentTarget.setPointerCapture(event.pointerId);
}

Guard multi-touch if the gesture is single-pointer.

Release must settle somewhere believable

On release, animate to the nearest intentional state: closed, open, dismissed, snapped, reordered. Do not leave fractional awkward states unless the UI is truly continuous.

Layout and Visual Polish

Alignment beats decoration

Before adding effects, fix:

  • Uneven spacing
  • Optical alignment
  • Baseline rhythm
  • Hit target size
  • Text contrast
  • Icon/text balance
  • Ragged wrapping in common widths
Use hierarchy before chrome

If a screen feels confusing, do not add borders everywhere. Clarify hierarchy with grouping, spacing, type scale, and content order first.

Defaults should be opinionated

A high-quality component should look good with minimal configuration. If every usage needs five props/classes to look acceptable, the abstraction is weak.

Responsive behavior is not just breakpoints

Check:

  • Long labels
  • Narrow containers
  • Tall content
  • Touch targets
  • Safe areas / notches
  • Reduced pointer precision
  • Text zoom
  • OS/browser font rendering differences

Accessibility and User Preferences

Reduced motion is not optional

Implement prefers-reduced-motion. Reduced does not always mean zero; it means remove vestibular motion and long transitions.

css
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
scroll-behavior: auto !important;
}
.animated-surface {
transition-duration: 1ms;
animation-duration: 1ms;
}
}

Prefer component-scoped reductions when possible so you do not destroy useful non-motion affordances globally.

This is the start of the file. Read the full SKILL.md on GitHub.

Security

  • Security scanPassed, 95 of 100Pattern checks on the skill's files.
  • Model reviewPassed

Quality evaluation

  • Task evaluationNot runNo evaluation yet. Run one in Skill Studio.

Source

Popularity

Repository stars
59
Repository forks
2
7-day trend score
20

Stars and forks are for the whole GitHub repository, not this skill alone. Not refreshed yet.

Works with

Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.

  • Claude Code
  • Cursor
  • GitHub Copilot
  • Windsurf
  • Codex
  • Gemini CLI
  • Cline
  • Amp
  • Roo Code
  • Goose
  • Continue
  • Kilo Code
  • Junie
  • Trae
  • OpenHands
  • Qwen Code
  • AI Agent
  • Tabnine Chat
  • Sourcegraph Cody
  • Amazon Q
  • Firebase Genkit
  • Sweep
  • Devin
  • Phind
  • Mentat
  • Claude Desktop
  • Aider
  • GPT Pilot
  • Plandex
  • bolt.new
  • v0
  • Replit Agent
  • Anse
  • TypingMind
  • BetterChatGPT
  • LibreChat
  • Warp AI
  • Pieces
  • Fig AI
Embed badge
vskill VERIFIED badge
[![vskill VERIFIED](https://verified-skill.com/api/v1/skills/stolinski/s-stack/design-engineering/badge)](https://verified-skill.com/skills/stolinski/s-stack/design-engineering)

Something wrong with this skill or its page? Tell us.