Skip to content
CoDdleCoDoodle home
Food DoodlesBeginnerSVG + CSS

Pancake Stack

A fluffy stack of pancakes with butter, syrup, and tiny garnish — with a cozy morning bob and rising steam.

← you, in 30 minutes.

what you'll build

Here's the plan

A cozy breakfast stack of three fluffy pancakes on a plate, topped with butter, amber syrup, berries, a tiny face, rising steam, and a gentle morning bob.

You’ll learn

  • Stack ellipses to build layered pancakes with depth
  • Layer syrup, butter, and garnish on top without crowding the scene
  • Add simple steam wisps and animate them upward
  • Combine a group bob with independent steam and glisten animations
Skill level
Beginner
Time
~30 min
Tools
Just a browser
Code type
SVG + CSS
Lines
~60

the steps

Build it, one change at a time

  1. Table, plate, and pancake stack

    Start with a warm breakfast table, a soft plate shadow, and a cream plate. Then stack three golden ellipses — each slightly smaller and higher — to build the pancake body.

    <!-- warm breakfast table -->
    <rect x="0" y="0" width="230" height="210" fill="#FFF8ED" stroke="none"/>
    
    <!-- soft plate shadow -->
    <ellipse cx="115" cy="182" rx="88" ry="9" fill="#2B3A55" stroke="none" opacity="0.12"/>
    
    <!-- cream plate -->
    <ellipse cx="115" cy="178" rx="92" ry="13" fill="#FFFDF7" stroke="#2B3A55" stroke-width="5"/>
    
    <!-- pancake stack -->
    <g class="stack" fill="#F6C14A" stroke="#2B3A55" stroke-width="5.5" stroke-linecap="round" stroke-linejoin="round">
      <ellipse cx="115" cy="156" rx="72" ry="20"/>
      <ellipse cx="115" cy="136" rx="70" ry="20"/>
      <ellipse cx="115" cy="116" rx="68" ry="20"/>
    </g>
    

    a warm plate with three fluffy pancake layers — ready for toppings.

  2. Butter, syrup, and garnish

    Add a melting butter pat, an amber syrup pool with two drips, a few blueberries, and a small strawberry. The syrup sits on top of the pancakes but behind the butter so the butter reads as on top.

    <!-- butter pat with a little melt -->
    <rect x="107" y="102" width="26" height="16" rx="4" fill="#FFEB7A" stroke="#2B3A55" stroke-width="4"/>
    <path d="M112 118 Q118 124 124 118" fill="none" stroke="#2B3A55" stroke-width="3" stroke-linecap="round"/>
    
    <!-- syrup pool and drips -->
    <g class="syrup" fill="#D98E04" stroke="#2B3A55" stroke-width="3.5" stroke-linejoin="round" stroke-linecap="round">
      <path d="M70 108 Q115 92 160 108 Q150 120 115 122 Q80 120 70 108 Z"/>
      <path d="M94 120 Q92 140 96 152 Q104 156 108 146 Q106 132 108 120 Z"/>
      <path d="M130 120 Q128 136 130 148 Q136 154 142 146 Q140 130 142 120 Z"/>
      <ellipse cx="115" cy="176" rx="30" ry="5"/>
    </g>
    
    <!-- blueberries -->
    <g fill="#3A4A68" stroke="#2B3A55" stroke-width="3">
      <circle cx="92" cy="112" r="5"/>
      <circle cx="84" cy="118" r="5"/>
      <circle cx="96" cy="122" r="5"/>
    </g>
    
    <!-- strawberry -->
    <g fill="#FF6B5E" stroke="#2B3A55" stroke-width="3.5" stroke-linejoin="round">
      <path d="M144 108 Q156 106 162 114 Q158 126 146 128 Q134 126 132 114 Q136 108 144 108 Z"/>
      <path d="M148 108 Q152 102 156 108 Z" fill="#7BC47E" stroke-width="2.5"/>
      <circle cx="140" cy="116" r="1" fill="#2B3A55" stroke="none"/>
      <circle cx="150" cy="112" r="1" fill="#2B3A55" stroke="none"/>
      <circle cx="154" cy="120" r="1" fill="#2B3A55" stroke="none"/>
    </g>
    

    butter, syrup, blueberries, and a strawberry — the stack is fully dressed.

  3. Tiny face and steam wisps

    Give the top pancake a tiny face with blush dots, then add two lazy steam wisps above the stack. The steam paths are simple curves that will rise and fade in the next step.

    <!-- tiny face on the top pancake -->
    <g class="face">
      <circle cx="110" cy="124" r="3.5" fill="#2B3A55"/>
      <circle cx="120" cy="124" r="3.5" fill="#2B3A55"/>
      <circle cx="105" cy="129" r="3" fill="#FFB3AD"/>
      <circle cx="125" cy="129" r="3" fill="#FFB3AD"/>
      <path d="M112 128 Q115 131 118 128" fill="none" stroke="#2B3A55" stroke-width="2.5" stroke-linecap="round"/>
    </g>
    
    <!-- lazy steam wisps -->
    <g class="steam-group">
      <path class="steam" d="M95 92 Q100 74 95 56" fill="none" stroke="#2B3A55" stroke-width="3" stroke-linecap="round" opacity="0.35"/>
      <path class="steam" d="M135 92 Q130 74 135 56" fill="none" stroke="#2B3A55" stroke-width="3" stroke-linecap="round" opacity="0.35"/>
    </g>
    

    a sleepy happy face and rising steam — breakfast is served.

  4. Bob, steam, and glisten

    Gently bob the whole pancake stack, animate the steam wisps upward with staggered delays, and add syrup highlight ellipses that pulse softly. Everything respects prefers-reduced-motion.

    /* syrup highlights that pulse */
    <g class="syrup-glisten">
      <ellipse cx="105" cy="108" rx="6" ry="2.5" fill="#FFFDF7" opacity="0.7"/>
      <ellipse cx="130" cy="112" rx="5" ry="2" fill="#FFE773" opacity="0.8"/>
      <ellipse cx="100" cy="136" rx="4" ry="1.8" fill="#FFFDF7" opacity="0.6"/>
      <ellipse cx="136" cy="138" rx="4" ry="1.8" fill="#FFFDF7" opacity="0.6"/>
      <ellipse cx="115" cy="174" rx="5" ry="1.5" fill="#FFFDF7" opacity="0.5"/>
    </g>
    
    .pancake-stack .stack {
      transform-box: fill-box;
      transform-origin: center;
      animation: stack-bob 3s ease-in-out infinite;
    }
    .pancake-stack .steam {
      transform-box: fill-box;
      transform-origin: bottom center;
      animation: steam-rise 2.5s ease-out infinite;
    }
    .pancake-stack .steam:nth-of-type(2) { animation-delay: 1.2s; }
    .pancake-stack .syrup-glisten { animation: glisten 2.2s ease-in-out infinite; }
    
    @media (prefers-reduced-motion: reduce) {
      .pancake-stack .stack,
      .pancake-stack .steam,
      .pancake-stack .syrup-glisten { animation: none; }
    }
    @keyframes stack-bob {
      0%, 100% { transform: translateY(0); }
      50% { transform: translateY(-3px); }
    }
    @keyframes steam-rise {
      0% { transform: translateY(0) scaleY(0.85); opacity: 0.25; }
      50% { opacity: 0.5; }
      100% { transform: translateY(-24px) scaleY(1.15); opacity: 0; }
    }
    @keyframes glisten {
      0%, 100% { opacity: 0.35; }
      50% { opacity: 1; }
    }
    

    the finished pancake stack bobs gently while steam rises and syrup glistens.

the complete code

Everything, in one place

Skipped straight to the end? Welcome. Copy the whole thing, download it, or open it in the Playground to start remixing.

<svg class="pancake-stack" viewBox="0 0 230 210" width="230" height="210" role="img" aria-label="Animated pancake stack doodle">
  <!-- warm breakfast table -->
  <rect x="0" y="0" width="230" height="210" fill="#FFF8ED" stroke="none"/>
  <!-- soft plate shadow -->
  <ellipse cx="115" cy="182" rx="88" ry="9" fill="#2B3A55" stroke="none" opacity="0.12"/>
  <!-- cream plate -->
  <ellipse cx="115" cy="178" rx="92" ry="13" fill="#FFFDF7" stroke="#2B3A55" stroke-width="5"/>
  <!-- pancake stack: bottom, middle, top -->
  <g class="stack" fill="#F6C14A" stroke="#2B3A55" stroke-width="5.5" stroke-linecap="round" stroke-linejoin="round">
    <ellipse cx="115" cy="156" rx="72" ry="20"/>
    <ellipse cx="115" cy="136" rx="70" ry="20"/>
    <ellipse cx="115" cy="116" rx="68" ry="20"/>
  </g>
  <!-- butter pat with a little melt -->
  <rect x="107" y="102" width="26" height="16" rx="4" fill="#FFEB7A" stroke="#2B3A55" stroke-width="4"/>
  <path d="M112 118 Q118 124 124 118" fill="none" stroke="#2B3A55" stroke-width="3" stroke-linecap="round"/>
  <!-- syrup pool and drips -->
  <g class="syrup" fill="#D98E04" stroke="#2B3A55" stroke-width="3.5" stroke-linejoin="round" stroke-linecap="round">
    <path d="M70 108 Q115 92 160 108 Q150 120 115 122 Q80 120 70 108 Z"/>
    <path d="M94 120 Q92 140 96 152 Q104 156 108 146 Q106 132 108 120 Z"/>
    <path d="M130 120 Q128 136 130 148 Q136 154 142 146 Q140 130 142 120 Z"/>
    <ellipse cx="115" cy="176" rx="30" ry="5"/>
  </g>
  <!-- blueberries -->
  <g fill="#3A4A68" stroke="#2B3A55" stroke-width="3">
    <circle cx="92" cy="112" r="5"/>
    <circle cx="84" cy="118" r="5"/>
    <circle cx="96" cy="122" r="5"/>
  </g>
  <!-- strawberry -->
  <g fill="#FF6B5E" stroke="#2B3A55" stroke-width="3.5" stroke-linejoin="round">
    <path d="M144 108 Q156 106 162 114 Q158 126 146 128 Q134 126 132 114 Q136 108 144 108 Z"/>
    <path d="M148 108 Q152 102 156 108 Z" fill="#7BC47E" stroke-width="2.5"/>
    <circle cx="140" cy="116" r="1" fill="#2B3A55" stroke="none"/>
    <circle cx="150" cy="112" r="1" fill="#2B3A55" stroke="none"/>
    <circle cx="154" cy="120" r="1" fill="#2B3A55" stroke="none"/>
  </g>
  <!-- tiny face on the top pancake -->
  <g class="face">
    <circle cx="110" cy="124" r="3.5" fill="#2B3A55"/>
    <circle cx="120" cy="124" r="3.5" fill="#2B3A55"/>
    <circle cx="105" cy="129" r="3" fill="#FFB3AD"/>
    <circle cx="125" cy="129" r="3" fill="#FFB3AD"/>
    <path d="M112 128 Q115 131 118 128" fill="none" stroke="#2B3A55" stroke-width="2.5" stroke-linecap="round"/>
  </g>
  <!-- lazy steam wisps -->
  <g class="steam-group">
    <path class="steam" d="M95 92 Q100 74 95 56" fill="none" stroke="#2B3A55" stroke-width="3" stroke-linecap="round" opacity="0.35"/>
    <path class="steam" d="M135 92 Q130 74 135 56" fill="none" stroke="#2B3A55" stroke-width="3" stroke-linecap="round" opacity="0.35"/>
  </g>
  <!-- syrup highlights that pulse -->
  <g class="syrup-glisten">
    <ellipse cx="105" cy="108" rx="6" ry="2.5" fill="#FFFDF7" opacity="0.7"/>
    <ellipse cx="130" cy="112" rx="5" ry="2" fill="#FFE773" opacity="0.8"/>
    <ellipse cx="100" cy="136" rx="4" ry="1.8" fill="#FFFDF7" opacity="0.6"/>
    <ellipse cx="136" cy="138" rx="4" ry="1.8" fill="#FFFDF7" opacity="0.6"/>
    <ellipse cx="115" cy="174" rx="5" ry="1.5" fill="#FFFDF7" opacity="0.5"/>
  </g>
</svg>
Open in Playground

tips & gotchas

Mistakes we actually made

Stack the pancakes bottom-to-top with decreasing width so the lower ones peek out like a real stack.

Draw syrup drips as simple paths that start wide at the top and narrow as they fall — the shape does most of the work.

Steam opacity should be low (0.25–0.5) so it doesn't overpower the food.

Use transform-box: fill-box on SVG groups when animating transforms so the origin behaves like a CSS box.

Glistening highlights pulse opacity, not scale — subtle is the goal.

make it yours

Remix it

  • New toppingseasy

    Replace berries with banana slices, whipped cream, or a sprinkle of chocolate chips.

  • Syrup coloreasy

    Change the syrup fill from amber to maple brown or berry pink.

  • Butter slidemedium

    Animate the butter melting down the side with a slow translateY keyframe.

  • Hungry forkmedium

    Add a tiny fork leaning on the plate and animate it tapping once every few seconds.

challenge extension

Same breakfast stack idea, new topper: replace the berries with a slice of banana and add a tiny fork leaning on the plate.