GODRICH

Crayon Web Design: 9 Hand-Drawn Landing Sections

Crayon web design draws thick, wobbly outlines around cards and buttons and runs an SVG filter on just those outlines, so they read as scribbled by hand rather

That's the crayon-box feel you can't fake with a font — the friendly kids'-studio or handmade-shop look you screenshot on Pinterest and then can't find the name for. Below is a full one-page landing built with it, live, not a mockup. Scroll it top to bottom once before we break it into parts.

Open the full page

Now the same page taken apart into nine reusable pieces, laid out in the order a visitor's eye actually moves through a landing — orient, browse features, check price, trust, act, sign up. Three of them (the scribble hero, the double-line cards, the speech-bubble testimonial) share one trick: the wobble filter sits on a separate SVG layer that draws only the border, never the one wrapping the text.

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

The whole kit runs on seven colors. Text always stays on the one ink color at the bottom of this table — that's what keeps a hand-drawn look legible.

Role Color Used for
Paper #fff8ef Page background
Ink #33261c All text (contrast 12.1–13.9:1)
Crayon red #ff5a5f Hand-drawn strokes, accent borders
Crayon yellow #ffcd3c Buttons, stars, underline
Crayon blue #4fa3e3 Double lines, blooming ring accent
Crayon green #6dbe6d Checkmarks, avatars
Crayon purple #a685e2 CTA background tint

01Crayon-scribble hero

The card's border is a separate SVG rect layer, and only that layer carries a feTurbulence wobble filter, so the dashed outline reads as hand-drawn while the headline stays crisp. The yellow underline below the title draws itself on and off with stroke-dashoffset.

stroke-dashoffset 밑줄손그림 border-radiusradius 24
<svg width="0" height="0" style="position:absolute">
  <filter id="rough" x="-30%" y="-30%" width="160%" height="160%">
    <feTurbulence type="fractalNoise" baseFrequency="0.045" numOctaves="2" seed="4" result="n"/>
    <feDisplacementMap in="SourceGraphic" in2="n" scale="7"
      xChannelSelector="R" yChannelSelector="G"/>
  </filter>
</svg>
<svg class="frame" viewBox="0 0 300 190" preserveAspectRatio="none">
  <rect x="6" y="6" width="288" height="178" rx="20"
        stroke="#33261c" stroke-width="5" stroke-dasharray="16 11"
        fill="none" filter="url(#rough)" />
</svg>

02Hand-drawn circle nav

A red crayon loop circles the active tab's label — not a clean ring but a double loop where one end overshoots the other, the way a real hand circles something twice. stroke-dasharray draws it on, holds, then draws it off in reverse.

stroke-dashoffset 재생겹쳐 그린 원radius pill
<li class="relative px-2 py-1">
  <span class="relative z-10 text-xs font-semibold">Home</span>
  <svg class="loop" viewBox="0 0 56 30">
    <path fill="none" stroke="#ff5a5f" stroke-width="3.5"
          stroke-linecap="round" stroke-linejoin="round"
          stroke-dasharray="110"
          d="M28 4 C 13 2, 4 11, 7 17 C 9 25, 20 28, 29 26
             C 41 24, 50 17, 47 10 C 45 4, 33 2, 25 5" />
  </svg>
</li>

03Wobbly sticker card grid

Each card layers a red and a blue outline offset by 1–2px, the look of a crayon line drawn twice. The four cards tilt in sequence with each one's animation delayed 140ms after the last.

비대칭 border-radius이중선 오프셋2열→1열
<svg class="frame" viewBox="0 0 100 78" preserveAspectRatio="none">
  <rect x="5" y="5" width="90" height="68" rx="12"
        fill="none" stroke="#ff5a5f" stroke-width="2.4" />
  <rect x="3" y="3" width="90" height="68" rx="12"
        fill="none" stroke="#4fa3e3" stroke-width="2.4" opacity=".8" />
</svg>

04Hand-drawn checklist

Each checkmark is one SVG stroke drawing left to right, not an icon font glyph. Every row gets its own color and start delay, so the checks land on their own beat instead of all at once.

stroke-dashoffset 체크어긋난 시작 시각radius 12
<svg class="check" viewBox="0 0 20 16">
  <path fill="none" stroke="#ff5a5f" stroke-width="3"
        stroke-linecap="round" stroke-linejoin="round"
        stroke-dasharray="26"
        d="M2 9 C 3 8, 4 10, 7 13 C 10 10, 14 6, 18 2" />
</svg>
<style>
  .check path { animation: checkDraw 2s ease-out infinite; }
  @keyframes checkDraw {
    0%   { stroke-dashoffset: 26; opacity: 0; }
    45%  { stroke-dashoffset: 0; opacity: 1; }
    100% { stroke-dashoffset: -26; opacity: 0; }
  }
</style>

05Star-and-circle pricing

Three plan cards each sit in a different crayon tone, and only the recommended plan's price gets a hand-drawn circle that loops itself while two small stars twinkle out of sync beside it. No table needed — color and the circle alone say which plan to pick.

stroke-dashoffset 원반짝이는 별radius 24
.ring-path {
  fill: none;
  stroke: #ff5a5f;
  stroke-width: 3.2;
  stroke-dasharray: 190;
  animation: ringDraw 2s ease-out infinite;
}
@keyframes ringDraw {
  0%   { stroke-dashoffset: 190; }
  50%  { stroke-dashoffset: 0; }
  100% { stroke-dashoffset: -190; }
}

06Crayon speech-bubble testimonial

The quote sits inside an SVG path with a bumpy outline instead of a clean rectangle, and the tail is two crooked line segments instead of a neat triangle. The star rating fills five widths at 100/100/100/80/40% so it reads like a real, slightly-mixed review score.

울퉁불퉁 테두리부분 채움 별점radius 16
<svg class="frame" viewBox="0 0 260 110" preserveAspectRatio="none">
  <path fill="#fff8ef" stroke="#33261c" stroke-width="3" stroke-linejoin="round"
    d="M18 10 L242 10 C250 10 252 18 252 26 L252 78 C252 88 248 96 238 96
       L48 96 L30 110 L34 94 L18 92 C10 90 8 82 8 74
       L8 26 C8 16 10 10 18 10 Z" />
</svg>

07Crayon-hatch CTA band

The band's background is one repeating-linear-gradient line — no image — drawn as tight crayon hatching, and the button on top wears a dashed red frame that keeps marching, as if it's being redrawn in a loop. It reads like a button sitting on a page from a coloring book.

repeating-linear-gradient 해칭이중선 재생radius pill
.band {
  background:
    repeating-linear-gradient(45deg, rgba(51,38,28,.08) 0 2px, transparent 2px 9px),
    #efe6fb;
}
.btn-rect {
  fill: none; stroke: #ff5a5f; stroke-width: 3;
  stroke-dasharray: 14 8;
  animation: march 2s linear infinite;
}
@keyframes march { to { stroke-dashoffset: -440; } }

08Scissor-cut zigzag footer

The footer's top edge is one clip-path: polygon() with teeth of uneven height — not one element per notch — so it reads like a kid's rough scissor cut instead of a machine-perfect zigzag. Uneven height at each point is what sells the illusion.

clip-path 지그재그3열→1열반짝임 점
.zigzag {
  height: 14px;
  background: #33261c;
  clip-path: polygon(
    0% 100%, 0% 30%, 6% 85%, 12% 15%, 18% 90%, 24% 20%,
    30% 88%, 36% 12%, 42% 92%, 48% 18%, 54% 85%, 60% 22%,
    66% 90%, 72% 15%, 78% 88%, 84% 20%, 90% 92%, 96% 14%,
    100% 30%, 100% 100%
  );
}

09Double-line crayon buttons & inputs

The button carries a red-and-blue double outline that drifts slightly out of register on a loop, and the input grows a loosely hand-drawn blue circle that blooms outward and fades on its own repeating cycle.

이중선 어긋남focus 손그림 원radius 12
.btn-rect-a { stroke: #ff5a5f; animation: shiftA 2s infinite; }
.btn-rect-b { stroke: #4fa3e3; opacity: .85; animation: shiftB 2s infinite; }
@keyframes shiftA { 50% { transform: translate(-2px, 1px); } }
@keyframes shiftB { 50% { transform: translate(2px, -1px); } }
.ring-rect { animation: bloom 2s infinite; }
@keyframes bloom {
  0%, 100% { opacity: 0; transform: scale(.9); }
  50%      { opacity: 1; transform: scale(1); }
}

Custom tailwind.config

Keep the seven crayon colors and three radii in this one place and both the one-pager and all nine parts stay in sync. The wobble filter's id should also stay singular across a project — reuse it, don't redeclare it.

theme: {
  extend: {
    colors: {
      paper: "#fff8ef", ink: "#33261c", red: "#ff5a5f",
      yellow: "#ffcd3c", blue: "#4fa3e3", green: "#6dbe6d", purple: "#a685e2",
    },
    borderRadius: { crayon: "20px", control: "12px", pill: "999px" },
    spacing: { gutter: "16px" },
  },
},

Vibe-Coding Prompt

Once the config is in your project, the instruction to Claude Code or Cursor comes down to where you do and don't attach the wobble filter. The full prompt text lives in the zip's prompt.md.

Keep the background a single paper color (#fff8ef). Every bordered box gets a
wobbly hand-drawn outline (SVG feTurbulence + feDisplacementMap) on its own
layer — never on the element wrapping the text itself. Round corners to
rounded-crayon or rounded-pill only. For double lines, offset a red and a
blue stroke by 1-2px.

Here's what that prompt produced when applied to page/index.html, captured as a full 1280px screenshot.

result

Where it breaks (the trap)

The first real trap was where the wobble filter gets attached. Wrapping the whole card — border and headline together — in filter: url(#rough) pushed every pixel through the same displacement map, so the title text warped along with the border and got hard to read at small sizes. Pulling the border into its own SVG rect/path layer and filtering only that layer fixed it — the text stayed sharp, only the outline wobbled.

The second trap showed up in the actual motion measurement. With just two 14px stars blinking in the footer, the measured changed-pixel area came out to 0.07%, under this site's 0.08% floor — visually indistinguishable from a static frame. Growing the stars to 20px and widening the scale range from 0.7–1.2x to 0.5–1.7x pushed it to 0.35%, which passed. The third trap was the size of the circle around the active nav tab: a 92×50 viewBox let the loop spill into the next tab's label, and shrinking it to 56×30 made it hug only the intended word. All three fixes are in the zip behind the password r6qyfm69.

All nine demos detect MDN's prefers-reduced-motion media query and stop the line-draw and card-tilt animations, freezing every element in its finished state — a completed checkmark, a closed circle — instead of hiding it.

Accessibility

The most common way a hand-drawn kit fails accessibility is running the wobble filter on the text itself. feDisplacementMap pushes every pixel of the source graphic by the noise map's value, letter strokes included, and at small sizes that blurs glyphs into illegibility. This kit keeps the filter on a border-only SVG layer at all times and never touches text elements. Text stays on one dark ink (#33261c), reaching 13.9:1 against the paper background and 12.1:1 against the darkest tint in the kit (the purple card tint) — well past the WCAG 2.1 minimum contrast of 4.5:1. The red and blue accent strokes are decorative borders and aren't held to text contrast rules, but keyboard focus on every button and input is drawn with its own :focus-visible outline, not left to depend on a colored line.

If pastel is more your brand's speed than crayon, the pastel candy landing kit covers that ground, and the full design trends category and this site's about page round out where else to look.

FAQ

How is crayon web design different from just using a sketch font?

A sketch font reshapes the letters themselves to look handwritten; this kit keeps letters in a clean typeface and only wobbles the decorative lines — borders, underlines, checkmarks — with an SVG filter. Wobbling text hurts readability; wobbling only the border keeps the charm without losing it.

Can this style work for a dark-themed brand?

Yes, but swapping paper (#fff8ef) for a dark background means flipping the ink text color to something light too, or contrast collapses. The saturated crayon reds and yellows still read fine on dark backgrounds; the card tints need a darker version of themselves to stay in balance.

Is the feTurbulence filter slow to render?

It's applied to one small SVG layer per border and its values are fixed, so it isn't recomputed every frame — the motion you see comes from stroke-dashoffset and transform, not from re-running the filter. Filtering a whole card or the full page would be the slow version; keep it scoped to small border layers like this kit does.

Enter the archive password

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