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
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.
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.
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.
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>
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.