GODRICH

Memphis Design Patterns: 9 Bold Landing Sections

Memphis design patterns repeat dots, squiggles, zigzags, and bold geometry across bright color fields.

Most screens saved on Pinterest as "memphis pattern" are illustration exports. They weigh down the page and force a re-export every time a color changes. Here each pattern is a single line of gradient code, so changing one hex value repaints the whole pattern. Scroll the one-page demo below and try to spot where each texture begins.

Open the full page

The nine parts that build that page are laid out in the grid below. The order follows how the pattern seeps into a screen: the background becomes a sea of pattern, shapes pick their spots, the pattern starts flowing, cards carry it as a headband, stickers testify, prices wear it, a sawtooth cuts the boundary, a strip scrolls it away, and a wave pushes you over the edge.

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

01Pattern-sea hero

The stage itself is a field of concentric ripples drawn by one repeating-radial-gradient. The white message panel stays still while a half circle, a triangle, a cross, and a zigzag strip drift around it. Every shape shares the same 2s period; only the negative delays stagger their phases. Mixing periods would leave one shape mid-cycle when the 2s loop restarts, so the frame would jump. Measurement: 2.831% cumulative area, 23 of 23 frames moving.

repeating-radial-gradientclip-pathanimation-delay
// Concentric ripples — one radial gradient, repeated from a single origin
.stage {
  background-image: repeating-radial-gradient(circle at 14px 14px, rgba(36, 31, 38, .1) 0 2.5px, transparent 3.5px 28px);
}
// Four shapes, one period, four phases
.herom__shape       { animation: shapeFloat 2s ease-out infinite; }
.herom__shape--half { animation-delay: -.5s; }
.herom__shape--tri  { animation-delay: -1s; }
@keyframes shapeFloat {
  0%, 100% { transform: translateY(0) rotate(-3deg); }
  50%      { transform: translateY(-12px) rotate(4deg); }
}

02Shape-badge nav

Three menu items wear circle, half-circle, and triangle badges, and they take turns being active. The swap uses steps(1, end) so it cuts in a single frame; a cross-fade would leave ghost frames where two tints overlap at half opacity. The only moving part is the badge, which pops upward on transform alone. The cut is why this demo logs only 9 of 23 frames with changes, while area and intensity stay comfortable.

steps(1, end)translateY:focus-visible
.navm__tab {
  --on: #ff5c47;                     // each tab owns a color
  animation: tabFill 2s steps(1, end) infinite;
}
.navm__tab:nth-child(2) { animation-delay: -.6667s; }
.navm__tab:nth-child(3) { animation-delay: -1.3333s; }
@keyframes tabFill {
  0%, 33.32%   { background: var(--on); }   // hold the color through the active window
  33.33%, 100% { background: transparent; }
}
@keyframes badgePop {
  0%           { transform: translateY(0); }
  6%, 28%      { transform: translateY(-7px); }
  33.33%, 100% { transform: translateY(0); }
}

03Repeating pattern band

Dot, wave, and cross panels stand side by side while each panel's pattern floor slides sideways. The pattern layer is exactly ten 24px tiles wide (240px) and shifts by translateX(-120px) — five whole tiles. Because 120 is a multiple of 24, the floor at the end of the move is pixel-identical to the start, so no seam ever shows. The three panels lift 0.22s apart. At 33.613% cumulative area this is the biggest mover of the nine.

background-sizetranslateXanimation-delay
.bandm__fill {
  position: absolute; inset: 0 auto 0 0;
  width: 240px;                       // 24px tile x 10 — half of it is exactly 5 tiles
  animation: fillFlow 2s linear infinite;
}
// Wave ribbon — inside one 24x40 tile: the band (y 8-28) plus edge semicircles
.bandm__fill--wave {
  background-image:
    linear-gradient(to bottom, transparent 8px, #241f26 8px 28px, transparent 28px),
    radial-gradient(circle 10px at 12px 8px, #241f26 0 9.5px, transparent 10px),
    radial-gradient(circle 10px at 0 28px, #241f26 0 9.5px, transparent 10px);
  background-size: 24px 40px;
}
@keyframes fillFlow { from { transform: translateX(0); } to { transform: translateX(-120px); } }

04Bold-outline card grid

Each white card pairs a 3px ink border with a zero-blur shadow 0 6px 0. The pairing is close to neo-brutalism, but here the border is only the frame — the pattern headband is the subject. The three cards carry dot, cross, and sawtooth headbands and rise 0.22s apart, and while a card is up, its shadow grows from 6px to 10px. Cumulative area 24.302%.

box-shadowtranslateYrotate
.gridm__card {
  border: 3px solid #241f26;
  box-shadow: 0 6px 0 #241f26;         // attached shadow = thickness
  animation: cardRise 2s cubic-bezier(.2, .8, .2, 1) infinite;
}
.gridm__card:nth-child(2) { animation-delay: -.22s; }
.gridm__card:nth-child(3) { animation-delay: -.44s; }
@keyframes cardRise {
  0%, 100% { transform: translateY(0) rotate(0);           box-shadow: 0 6px 0 #241f26; }
  45%      { transform: translateY(-12px) rotate(-1.5deg); box-shadow: 0 10px 0 #241f26; }
}

05Sticker testimonial stack

Three testimonial stickers overlap at a tilt and take turns coming to the front. The card whose turn it is straightens to 0deg and rises 8px, then settles back to its own angle. The stacking order (z-index) stays fixed; coming forward is expressed only through lift and angle, because animating z-index makes the value jump in discrete steps and the cards flicker. Frames with changes: 11 of 23.

rotatetranslateYz-index
.stickm__card {
  --tilt: -7deg;                       // resting angle
  animation: toFront 2s ease-out infinite;
}
.stickm__card--two   { animation-delay: -.6667s; }
.stickm__card--three { animation-delay: -1.3333s; }
@keyframes toFront {
  0%        { transform: rotate(var(--tilt)) translateY(0); }
  6%, 28%   { transform: rotate(0deg) translateY(-8px); }
  34%, 100% { transform: rotate(var(--tilt)) translateY(0); }
}

06Pattern-banded pricing

Only the middle plan wears the polka-dot headband and the badge. The plan floats 6px up and down while the badge pulses half a period out of phase: when the plan is highest, the badge is smallest, and when the plan settles, the badge swells. Counter-phase motion feels more alive than a single moving card. Cumulative area 4.699%, 23 of 23 frames.

translateYscaleradial-gradient
.pricem__plan--best { animation: bestFloat 2s ease-out infinite; }
.pricem__badge {
  animation: badgePulse 2s ease-out infinite;
  animation-delay: -1s;                // half a period = counter-phase
}
@keyframes bestFloat { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-6px); } }
@keyframes badgePulse { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.12); } }

07Zigzag divider

Two sawtooth strips run between sections in opposite directions and mesh like a zipper. Each tooth is a conic-gradient wedge: a downward tooth puts its apex on the bottom edge with from 315deg, an upward tooth puts it on the top edge with from 135deg plus a half-tile (8px) offset. The flow moves exactly two tiles (32px), and since the pattern is periodic, the wrap point is invisible. Both strips must share the same 16px tile for the mesh to hold.

conic-gradienttranslateXrepeat-x
.zzm__teeth--down {
  height: 32px;
  background: conic-gradient(from 315deg at 50% 100%, #ffcf33 0 90deg, transparent 90deg 360deg);
  background-size: 16px 16px; background-repeat: repeat-x;
  animation: teethFlow 2s linear infinite;
}
.zzm__teeth--up {
  top: 16px;
  background: conic-gradient(from 135deg at 50% 0%, #2ec4a6 0 90deg, transparent 90deg 360deg);
  background-size: 16px 16px; background-repeat: repeat-x; background-position: 8px 0;
  animation: teethFlow 2s linear infinite reverse;   // opposite direction
}
@keyframes teethFlow { from { transform: translateX(0); } to { transform: translateX(-32px); } }

08Pattern marquee strip

Five tokens — dot, squiggle, cross, half circle, triangle — form one set, laid down twice. The measured track is 460px wide and one set (five tokens plus five right margins) is exactly 230px, so translateX(-50%) equals a 230px push and the last frame matches the first. Spacing between tokens uses margin-right, not flex gap: with 2N items, gap leaves only 2N−1 gaps, so -50% drifts 8px per loop.

translateX(-50%)margin-rightmax-content
.marqm__track {
  display: flex;
  width: max-content;          // measured 460px = one 230px set x 2
  animation: trackFlow 2s linear infinite;
}
.marqm__tok { margin-right: 16px; }   // gap leaves 2N-1 gaps across 2N items, breaking -50%
@keyframes trackFlow {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}

09Wavy CTA band

The coral band's top edge is a row of semicircle crests. Each crest is a 12px-radius circle seated on the top edge of a 24px tile, and the crest layer is twenty tiles wide (480px), so translateX(-24px) slides it exactly one tile. Inside, the button floats 8px and lands while its attached shadow shrinks from 13px to 5px. Cumulative area 5.556%.

radial-gradienttranslateXtranslateY
.ctam__wave {
  width: 480px; height: 20px;   // 24px tile x 20
  background: radial-gradient(circle 12px at 12px 0, #ff5c47 0 11.5px, transparent 12px);
  background-size: 24px 24px; background-repeat: repeat-x;
  animation: waveDrift 2s linear infinite;
}
@keyframes waveDrift { from { transform: translateX(0); } to { transform: translateX(-24px); } }
@keyframes btnFloat {
  0%, 100% { transform: translateY(-8px); box-shadow: 0 13px 0 #241f26; }
  50%      { transform: translateY(0);    box-shadow: 0 5px 0 #241f26; }
}

Custom tailwind.config

What needs a single home in this trend is not the palette but the pattern tile and the thickness. If every part picks its own tile width, the seamless travel distance no longer adds up; if the shadow gains blur, the flat punch of Memphis dies.

theme: {
  extend: {
    colors: {
      base: "#fdf4ec", sheet: "#ffffff", ink: "#241f26", stone: "#5d5560",
      coral: "#ff5c47", lemon: "#ffcf33", sky: "#2fa3dd",
      mint: "#2ec4a6", pink: "#ff8fab",
    },
    borderRadius: { card: "16px", control: "12px", chip: "4px", pill: "999px" },
    boxShadow: {
      hard: "0 6px 0 #241f26",      // attached shadow = thickness
      "hard-sm": "0 4px 0 #241f26",
      lift: "0 10px 0 #241f26",     // thicker while lifted
    },
  },
},
Role Token When
Thickness shadow-hard Cards and bands resting on the floor
Lift shadow-lift Only while a card is up
Border border 3px ink Every shape and card — the two travel as a set

Vibe-Coding Prompt

Once the config is in place, the instruction below is all you hand to Claude Code or Cursor. Notice that pattern recipes come before the color list — that order matters. The full text and three variants live in prompt.md inside the zip.

Build every pattern as a CSS gradient tile. Do not use any images. Dots:
radial-gradient(circle at 12px 16px, #241f26 0 3px, transparent 3.5px) repeated on a
24px tile. Sawtooth: conic-gradient(from 315deg at 50% 100%, color 0 90deg,
transparent 90deg) repeated-x on a 24px tile. When a pattern flows, move it only by
whole multiples of the tile width, so the loop ends pixel-identical to where it
started. Give cards and shapes a 3px ink border together with a 0 6px 0 #241f26
shadow.

Rendering page/index.html from that instruction at 1280, 768, and 390px produced the shot below, with zero horizontal overflow measured at all three widths.

Result

Where it breaks (the trap)

The cross pattern cost the most time. Two stacked bars should make a plus, so I wrote linear-gradient(#241f26, #241f26) twice with background-size: 5px 17px — and the third panel rendered as a slab of solid ink instead of sky blue. A solid bar gradient repeats at its own bar width, every 5px, tiling the whole panel with vertical ink strips. A plus needs the 24px tile defined first, then the bar positioned inside it with transparent 9.5px, ink 9.5px 14.5px, transparent 14.5px. The same bug hid in a card headband, so both were fixed together.

The second trap was tooth direction. A conic gradient with its apex at at 50% 100% and from 135deg opens downward — outside the tile — so nothing paints. A tooth pointing down needs from 315deg so the wedge opens upward from the bottom apex. The mistake fails silently: no compile error, no console line, just an empty band on the first render. Third, before trusting the marquee, I measured the track with Playwright offsetWidth: 460px, exactly twice the 230px set. The parts tuned through all three traps, plus the whole one-page build, are in the zip that opens with the password yqayt28g.

Accessibility (accessibility)

None of the bright Memphis colors can carry white text. Computed with the WCAG 2.1 contrast formula, even the darkest accent — coral #ff5c47 — reaches only 3.06:1 against white, under the 4.5:1 body-text minimum. So this kit fixes the text color instead of choosing colors per surface: ink (#241f26) passes everywhere.

Foreground Background Measured ratio Body minimum
Ink #241f26 Sheet #ffffff 16.17:1 Pass
Ink #241f26 Base #fdf4ec 14.88:1 Pass
Ink #241f26 Lemon #ffcf33 10.95:1 Pass
Ink #241f26 Mint #2ec4a6 7.36:1 Pass
Ink #241f26 Sky #2fa3dd 5.7:1 Pass
Ink #241f26 Coral #ff5c47 5.29:1 Pass
White text Coral #ff5c47 3.06:1 Fails — never used

Text never sits directly on a pattern. A white panel goes down first, then ink on top, which locks the contrast regardless of which tile a letter lands on. Every one of the nine parts ships the MDN prefers-reduced-motion query; with reduced motion on, visitors see the finished static patterns, and the shape-badge nav keeps a static rule showing the second tab as active. A frozen marquee is not a bug — it is a finished strip of wallpaper.

If the style clicks for you, browse the design trend collection for neighboring styles, and the about page explains what this site hands out.

FAQ

How is Memphis different from neo-brutalism?

Both use thick black outlines, but the star differs. Neo-brutalism is defined by the border and the offset shadow itself — two or three colors are enough. Memphis treats the border as a frame and puts pattern fills first: repeating dots, waves, zigzags, and geometric shapes. Remove the headband pattern from card 04 in this kit and it stops being Memphis — that is the test.

Isn't a patterned background hard to read over?

Only if text sits directly on the pattern. Every paragraph in this kit is ink on a white panel, and patterns live outside the panels — on the stage, the headbands, and the boundaries. The numbers in the contrast table were measured under exactly that rule. Drop the panel and the ratio depends on whichever tile each letter happens to cover.

Is it too playful for a serious brand?

Cut the palette to ink and cream and the structure survives while the playfulness drains — that is the mono variant inside the zip. Shrinking the shapes and widening the tile gaps settles the pattern into background noise, so one or two bright accents can survive inside a corporate tone.

Enter the archive password

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