GODRICH
#css-animation#button#loader#transition#scroll#dashboard#ui#design-trends

Skeuomorphism Design Kit: 9 Tactile Landing Parts

Skeuomorphism design brings the feel of real materials — leather, metal, wood, glass — onto the screen.

The early-2010s version of this style wrapped whole apps in stitched leather and linen, and the weight of it is exactly why flat design took over. What returned is narrower and smarter: a bright, flat page with real material in only three places. Scroll the one-pager below and try to find those three spots before reading on.

Open the full page

The nine parts that page is built from are pulled out one by one into the grid below. The order follows how materials earn their weight: leather gets sewn, metal gets machined, paper gets stacked, a knob gets turned by hand, glass gets set, wood gets opened, a sticker gets pressed on, a key gets pressed down — and the ninth part puts all of it on one page without overdoing it. Most skeuomorphism design examples still show the 2010s version, which is why the three-spot rule matters more than any single material. The same nine slots filled with layered scraps and color live in collage maximalist landing sections, and the dot-and-squiggle version lives in Memphis pattern landing sections. Set the three kits side by side and you can see how far texture, overlap, and shape each carry a page on their own.

Auto-plays · click a tile to jump to its section · all nine in one zip

01Leather stitch pricing card

What you see

The leather card lands from 20px above, and the instant it touches down, the pale stitch ticks appear inside the double border as a single-frame cut.

Leather stitch pricing card
Open in a new tab

01 · Leather stitch pricing card — Measured area 23.101% · moving frames 15/23Original by GODRICH · SCSS and React ship in the zip · See the password

이중 테두리repeating-linear-gradientsteps(1, end)

Where to look in the code

The stitching is not an image: each of the four edges carries its own repeating-linear-gradient of thread marks.

.leather__stitch {
  position: absolute;
  top: 8px; left: 8px; right: 8px; bottom: 8px;
  border-radius: $r-control;
  opacity: 0;
  background:
    repeating-linear-gradient(90deg, $stitch 0 8px, transparent 8px 16px) top    / 100% 2px no-repeat,
    repeating-linear-gradient(90deg, $stitch 0 8px, transparent 8px 16px) bottom / 100% 2px no-repeat,
    repeating-linear-gradient(0deg,  $stitch 0 8px, transparent 8px 16px) left   / 2px 100% no-repeat,
    repeating-linear-gradient(0deg,  $stitch 0 8px, transparent 8px 16px) right  / 2px 100% no-repeat;
  animation: stitchCut $duration steps(1, end) infinite;
}
@keyframes stitchCut {
  0%, 36%  { opacity: 0; }
  38%, 86% { opacity: 1; }
  88%, 100% { opacity: 0; }
}

02Metal dial CTA

How a skeuomorphic ui design metal dial reads on screen

The dial swings 32 degrees each way, and because the whole disc rotates, the conic-gradient shading streams across its face and reads as machined metal.

Metal dial CTA
Open in a new tab

02 · Metal dial CTA — Measured area 17.386% · moving frames 18/23Original by GODRICH · SCSS and React ship in the zip · See the password

conic-gradient노치 테두리왕복 회전

How to read the code

The element is a real button — the disc itself is the conversion control.

.metaldial__dial {
  animation: dialSwing $duration $ease-spring infinite;
}
.metaldial__face {
  background:
    conic-gradient(from 210deg,
      $metal-hi 0deg, $metal-lo 70deg, $metal-mid 120deg,
      $metal-hi 180deg, $metal-edge 250deg, $metal-mid 300deg, $metal-hi 360deg);
  box-shadow: inset 0 2px 3px rgba(255, 255, 255, .65), inset 0 -3px 5px rgba(0, 0, 0, .4);
}
@keyframes dialSwing {
  0%, 6%    { transform: rotate(-32deg); }
  48%, 56%  { transform: rotate(32deg); }
  94%, 100% { transform: rotate(-32deg); }
}

03Paper grain feature card

What moves

Three grained sheets sit in a stack, and the top sheet slides 48px up to expose the grain of the one beneath.

Paper grain feature card
Open in a new tab

03 · Paper grain feature card — Measured area 34.744% · moving frames 17/23Original by GODRICH · SCSS and React ship in the zip · See the password

1px 결 겹침translateY 시트radius 16

What to change

The grain is three 1px repeating-linear-gradient layers set in different directions, so no noise image or base64 blob is ever needed.

.paperstack__sheet {
  background:
    repeating-linear-gradient(0deg,  $grain-a 0 1px, transparent 1px 3px),
    repeating-linear-gradient(90deg, $grain-b 0 1px, transparent 1px 4px),
    repeating-linear-gradient(48deg, $grain-c 0 1px, transparent 1px 7px),
    $paper-face;
}
@keyframes sheetSlide {
  0%, 10%   { transform: translateY(0); }
  46%, 58%  { transform: translateY(-48px); }
  88%, 100% { transform: translateY(0); }
}

04Volume knob widget

What you see

The knob sweeps 120 degrees each way between the low tick and the high one, its pale pointer line traveling across the dial marks.

Volume knob widget
Open in a new tab

04 · Volume knob widget — Measured area 8.684% · moving frames 18/23Original by GODRICH · SCSS and React ship in the zip · See the password

rotate 왕복지침 선radius 50%

Where to look in the code

Because the pointer stays inside the knob's circle, the knob never appears to grow as it turns.

.volknob__knob {
  background:
    radial-gradient(120% 120% at 34% 26%, rgba(255, 255, 255, .32), transparent 42%),
    conic-gradient(from 250deg, $knob-face, $knob-body 90deg, $knob-face 170deg,
      $knob-body 260deg, $knob-face 340deg);
  box-shadow: 0 6px 10px rgba(23, 20, 26, .35), inset 0 1px 2px rgba(255, 255, 255, .22);
  animation: knobSweep $duration $ease-out infinite;
}
@keyframes knobSweep {
  0%, 8%    { transform: rotate(-120deg); }
  46%, 56%  { transform: rotate(120deg); }
  92%, 100% { transform: rotate(-120deg); }
}

05Glass inlay badge

What happens on screen

The badge sits in a recess carved out of a brushed metal plate, and a slanted highlight bar sweeps across it from left to right.

Glass inlay badge
Open in a new tab

05 · Glass inlay badge — Measured area 10.794% · moving frames 11/23Original by GODRICH · SCSS and React ship in the zip · See the password

하이라이트 훑기translateX 광선inset 깊이

How to read the code

As the bar crosses the center, the mint core inside the glass brightens once — light passing through, not a glow effect.

.glassbadge__sheen {
  position: absolute;
  top: -20%; left: 0;
  width: 44%;
  height: 140%;
  transform: translateX(-140%) rotate(24deg);
  background: linear-gradient(100deg, transparent, rgba(255, 255, 255, .4) 45%,
    rgba(255, 255, 255, .55) 50%, rgba(255, 255, 255, .4) 55%, transparent);
  animation: sheenSweep $duration $ease-out infinite;
}
@keyframes flareUp {
  0%, 36%   { opacity: 0; }
  44%, 50%  { opacity: 1; }
  58%, 100% { opacity: 0; }
}

06Wood grain sliding panels

What moves

Two wood-grain leaves part to reveal a bright slot inside, stay open a beat, then close again.

Wood grain sliding panels
Open in a new tab

06 · Wood grain sliding panels — Measured area 38.896% · moving frames 15/23Original by GODRICH · SCSS and React ship in the zip · See the password

두 짝 분할나무 결 gradient대칭 이동

What to change

The grain is painted on the panels themselves, so when a leaf slides, the grain travels with it — the same thing a photo of wood would do, at none of the weight.

.wooddoors__leaf {
  background:
    radial-gradient(ellipse 14px 22px at 62% 30%, rgba(74, 44, 12, .55) 0 38%,
      rgba($wood-c, .5) 42% 52%, transparent 60%),
    repeating-linear-gradient(90deg,
      $wood-a 0 12px, $wood-b 12px 15px, $wood-c 15px 27px, $wood-d 27px 30px,
      $wood-a 30px 38px, $wood-lo 38px 41px);
}
@keyframes doorsOpenL {
  0%, 10%   { transform: translateX(0); }
  42%, 60%  { transform: translateX(-92%); }
  88%, 100% { transform: translateX(0); }
}

07Sticker emboss logo

What you see

The embossed sticker drops in tilted from 24px up and seats itself at minus three degrees.

Sticker emboss logo
Open in a new tab

07 · Sticker emboss logo — Measured area 20.042% · moving frames 16/23Original by GODRICH · SCSS and React ship in the zip · See the password

text-shadow 4겹스탬프 착지radius 16

Where to look in the code

The relief is four layers of text-shadow: a bright line below, a dark line above, and two side corrections — all four together make the letters read as carved rather than printed.

.emboss__brand {
  color: $emboss-ink;
  text-shadow:
    0 1px 0 $emboss-light,
    0 -1px 0 $emboss-dark,
    1px 0 0 rgba(255, 255, 255, .55),
    -1px 0 0 rgba(96, 74, 48, .35);
}
@keyframes stickerApply {
  0%        { transform: translateY(-24px) rotate(-8deg) scale(1.12); }
  40%       { transform: translateY(0) rotate(-3deg) scale(1); }
  50%       { transform: translateY(-2px) rotate(-3.6deg) scale(1.01); }
  60%, 88%  { transform: translateY(0) rotate(-3deg) scale(1); }
  100%      { transform: translateY(-24px) rotate(-8deg) scale(1.12); }
}

08Physically pressable button

What happens on screen

The keycap sinks 8px while the side wall beneath it shrinks to a quarter via scaleY.

Physically pressable button
Open in a new tab

08 · Physically pressable button — Measured area 7.858% · moving frames 12/23Original by GODRICH · SCSS and React ship in the zip · See the password

옆벽 scaleY8px 스트로크radius 12

How to read the code

The wall is its own element rather than a painted box-shadow, so the press stays a transform — cheap to animate, and it runs on the compositor.

.physkey__wall {
  height: 8px;
  transform-origin: 50% 0;
  animation: wallPress $duration $ease-spring infinite;
}
@keyframes capPress {
  0%, 12%   { transform: translateY(0); }
  32%, 46%  { transform: translateY(8px); }
  62%       { transform: translateY(-3px); }
  76%, 100% { transform: translateY(0); }
}
@keyframes wallPress {
  0%, 12%   { transform: scaleY(1); }
  32%, 46%  { transform: scaleY(.25); }
  62%       { transform: scaleY(1.1); }
  76%, 100% { transform: scaleY(1); }
}

09One page with three texture spots

What moves

A miniature landing page scrolls up and down through its own sections. Texture lives in exactly three places — the wood nav, the metal dial, the leather pricing card — and every other band stays bright and flat.

One page with three texture spots
Open in a new tab

09 · One page with three texture spots — Measured area 32.228% · moving frames 19/23Original by GODRICH · SCSS and React ship in the zip · See the password

질감 3곳핑퐁 스크롤translateY 프리뷰

What to change

The trick behind the preview is a track at exactly 200% of the viewport, so translateY(-50%) moves precisely one screen.

.minipage__track {
  display: flex;
  flex-direction: column;
  height: 200%;
  animation: pageScroll $duration $ease-out infinite;
}
@keyframes pageScroll {
  0%, 10%   { transform: translateY(0); }
  44%, 54%  { transform: translateY(-50%); }
  88%, 100% { transform: translateY(0); }
}

Custom tailwind.config

What has to live in one place here is not the palette but the thickness of a press. A physical key rests on an 8px wall and bottoms out at 2px — drift between those two numbers and the button stops feeling seated.

theme: {
  extend: {
    colors: {
      paper: "#fbf6ec", sheet: "#ffffff", ink: "#2a2320", stone: "#5c5048",
      brand: "#2f6df6", branddeep: "#1c48b8", mint: "#2f9e74",
      leather: "#7a4a2b", leatherdeep: "#5e3517", wood: "#a96f38",
    },
    borderRadius: { card: "16px", control: "12px", chip: "4px", pill: "999px" },
    boxShadow: {
      keyrest: "inset 0 2px 0 rgba(255,255,255,.4), inset 0 -2px 0 rgba(0,0,0,.25), 0 8px 0 #1a3fa0",
      keydown: "inset 0 2px 0 rgba(255,255,255,.4), inset 0 -2px 0 rgba(0,0,0,.25), 0 2px 0 #1a3fa0",
    },
  },
},
Role Token When
Key wall at rest shadow-keyrest While the button is idle (8px)
Pressed wall shadow-keydown Only in the active: state (2px)
Texture surface tex-leather and friends Three spots per page, maximum

Vibe-Coding Prompt

With the config planted, the instruction you hand Cursor or Claude Code is one block. The ordering matters: texture placement comes before any color list. The unabridged prompt ships as prompt.md in the zip.

Texture lives in exactly three places: the nav (wood), the CTA (metal dial), and the
recommended pricing plan (leather). Untextured area must be at least twice the textured
area. Wood is a vertical repeating-linear-gradient of grain bands; the metal dial is a
conic-gradient in four stops; leather is two overlapping repeating gradients plus a top
highlight. Stitch ticks wrap each of the four edges as a repeating-linear-gradient of
8px thread and 8px gap. A button rests on an 8px wall and drops to 2px when pressed —
the cap sinks by exactly the wall it loses.

Built from that instruction, page/index.html looks like this at a 1280px viewport.

Result

Where it breaks (the trap)

Text directly on wood was the trap that lasted longest. The nav first carried a white brand name on the raw grain — but the grain repeats through four band colors, and the same white type measured 5.14:1 on the dark band (#96622e) and 3.01:1 on the bright one (#c08a4e). No single color clears 4.5:1 across all four bands, so the type moved onto dark inlay chips and the wood stayed decorative. Measure contrast before seating body text on any texture.

The second trap was travel distance on the paper sheet. Raising the top sheet by 72 percent of its own height looked fine at 480px but clipped the sheet's top edge off the stage at 320px. Switching to a flat 48px — and down to 20px on narrow screens — kept the whole sheet visible at both widths. Trading a percentage for a flat pixel value when the width changes is the same habit that Outlook-safe newsletter templates ask for. The finished nine files are all inside the zip, which opens with the password 7dcfwy5m.

Accessibility

Texture is where contrast goes to die. Every text pairing in this kit was run through the relative-luminance formula from the WCAG 2.1 minimum contrast criterion and recorded below.

Text pairing Ratio Verdict
Leather body #f6e7cf / leather #7a4a2b 6.07:1 pass
Leather price #ffffff / leather #7a4a2b 7.39:1 pass
Paper body #574a38 / paper #fff7e6 8.07:1 pass
Paper secondary #7a6c56 / paper #fff7e6 4.80:1 pass, barely
Hero button #ffffff / brand #2f6df6 4.53:1 pass, barely
Leather body on a bright grain band #96613c 4.24:1 fail — no body text on bright bands

The last row is why the leather card keeps its copy on the dark grain side, and why the white icon idea on the mint core (1.86:1) became a deep-teal icon instead. Every one of the nine parts carries the MDN prefers-reduced-motion media query, so visitors who reduce motion get each part seated and still. The materials themselves are conic-gradient and text-shadow values, so an unsupported browser degrades to flat color, never to a broken layout.

Browse the design trends category for other styles making the rounds; what this site hands out is on the about page.

FAQ

How many texture spots can one skeuomorphic ui css page carry?

Three. This kit uses exactly that many — wood nav, metal dial, leather pricing card — and keeps everything else bright and flat. Past four spots the eye loses its resting place and the page slides back toward the heavy 2010s look.

Can I wrap the whole page in leather like the old apps?

For a single card, yes; for a whole landing, no. Dark texture forces you to re-measure contrast everywhere, and the brightest grain band cannot carry 4.5:1 body text at all. Texture earns its keep as a point of focus and becomes a cost as a background.

Does this drop straight into a React project?

The zip carries React versions (.tsx + .module.scss) of all nine parts alongside the vanilla files. Duration, easing, and the accent color arrive as props, and both flavors were verified against the same measured values. If you are still deciding where a texture part belongs above the fold, hero section design patterns settles that placement call faster.

Enter the archive password

The password is inside this article. You will find it as you read.