Corn Soft Serve
A sunny corn ice cream cone with a tiny cob buddy — sweet, sleepy, and ready for the hottest sidewalk stroll.
← you, in 25 minutes.
what you'll build
Here's the plan
A happy corn soft serve sticker — butter-yellow swirl, criss-cross waffle cone, tiny drowsy face, and one small corn-cob buddy waving beside it. The lower scoop band becomes the star: you build a neat grid of rounded-rect kernels, then let a soft highlight shimmer across it like summer sun.
You’ll learn
- Setting up a warm sticker stage with a ground shadow and tiny prop shapes that can twinkle later
- Layering a waffle cone underneath a smooth soft-serve silhouette so the treat reads clearly before details arrive
- Turning repeated rounded rectangles into a corn-kernel grid — small, tidy, and easy to remix
- Animating only transform and opacity: a gentle cone bob, sleepy blinks, a shimmer pass, leaf waves, and twinkles
- Skill level
- Beginner
- Time
- ~25 min
- Tools
- Just a browser
- Code type
- SVG + CSS
- Lines
- ~95
the steps
Build it, one change at a time
Set the summer stage
Start with warm paper, one soft ground shadow, a few sparkle props, and tiny kernel specks. The shadow stays outside the cone group so it can flatten on the ground while the treat bobs above it.
<rect x="0" y="0" width="200" height="200" rx="18" fill="#FBF2E5" stroke="none"/> <ellipse class="cs-shadow" cx="103" cy="178" rx="53" ry="10" fill="#2B3A55" opacity="0.14" stroke="none"/> <!-- little props first — they become twinkles in the final step --> <path class="cs-twinkle cs-twinkle1" d="M30 47 L34 55 L30 63 L26 55 Z" fill="#FFD84D" stroke="#2B3A55" stroke-width="2" stroke-linejoin="round"/> <path class="cs-twinkle cs-twinkle2" d="M166 54 L169 61 L166 68 L163 61 Z" fill="#FF6B5E" stroke="none"/> <path class="cs-twinkle cs-twinkle3" d="M37 133 L40 138 L37 143 L34 138 Z" fill="#FF8FA3" stroke="none"/> <g class="cs-specks" fill="#FFD84D" stroke="#2B3A55" stroke-width="1.6" stroke-linejoin="round"> <rect x="49" y="78" width="7" height="5" rx="2"/> <rect x="151" y="107" width="7" height="5" rx="2"/> <rect x="42" y="157" width="6" height="4.5" rx="2"/> </g>paper, shadow, sparkles, and a few tiny corn clues.
Stack the cone and swirl
Draw the waffle cone first, then the soft-serve shape above it. The criss-cross lines sit inside the cone group, and the whole treat lives in cs-all so one gentle bob can move it as a single sticker.
<g class="cs-all"> <g class="cs-cone" stroke="#2B3A55" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"> <path d="M69 110 L131 110 L101 170 Z" fill="#E3B478"/> <!-- waffle lines: two diagonal sets crossing inside the cone --> <g class="cs-waffle" stroke="#2B3A55" stroke-width="2.4" opacity="0.58"> <path d="M78 122 L113 167"/> <path d="M91 111 L123 151"/> <path d="M108 111 L128 136"/> <path d="M123 122 L88 167"/> <path d="M110 111 L78 151"/> <path d="M93 111 L73 136"/> </g> </g> <g class="cs-serve" stroke="#2B3A55" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"> <path d="M69 109 C52 107 49 88 65 82 C58 69 67 58 82 60 C82 48 93 40 105 45 C110 34 124 32 132 43 C141 55 130 64 120 64 C139 66 148 80 139 93 C151 101 142 117 124 116 L78 116 C75 116 72 113 69 109 Z" fill="#FFD84D"/> <path d="M75 113 C80 100 121 96 134 107 C128 119 83 122 75 113 Z" fill="#FFFDF7" opacity="0.45" stroke="none"/> </g> </g>a plain corn-yellow swirl parked neatly in its waffle cone.
Add kernels, face, and buddy
Now the repeated-kernel trick shows up: small rounded rectangles in two loose rows across the lower band. Add the sleepy face, a curl at the swirl tip, and a tiny corn cob with husk leaves so the flavor joke lands instantly.
<!-- the curl sits on top of the swirl like a little soft-serve flourish --> <path class="cs-curl" d="M112 47 C119 38 132 41 132 51 C132 59 122 62 118 55" fill="none" stroke="#2B3A55" stroke-width="3.4" stroke-linecap="round"/> <g class="cs-kernels" fill="#FFFDF7" stroke="#2B3A55" stroke-width="1.4" stroke-linejoin="round" opacity="0.95"> <!-- repeat rounded rect kernels in rows — tiny grid, big flavor signal --> <rect x="76" y="95" width="7" height="6" rx="2"/> <rect x="87" y="93" width="7" height="6" rx="2"/> <rect x="98" y="92" width="7" height="6" rx="2"/> <rect x="109" y="93" width="7" height="6" rx="2"/> <rect x="120" y="96" width="7" height="6" rx="2"/> <rect x="80" y="104" width="7" height="6" rx="2"/> <rect x="91" y="103" width="7" height="6" rx="2"/> <rect x="102" y="102" width="7" height="6" rx="2"/> <rect x="113" y="103" width="7" height="6" rx="2"/> <rect x="124" y="105" width="7" height="6" rx="2"/> </g> <g class="cs-shimmer" fill="#FFFDF7" opacity="0" stroke="none"> <rect x="84" y="92" width="5" height="20" rx="2.5"/> <rect x="97" y="91" width="5" height="20" rx="2.5"/> <rect x="110" y="92" width="5" height="20" rx="2.5"/> </g> <g class="cs-face"> <g class="cs-eye cs-eye-l"> <path d="M86 77 C89 80 94 80 97 77" fill="none" stroke="#2B3A55" stroke-width="3" stroke-linecap="round"/> </g> <g class="cs-eye cs-eye-r"> <path d="M111 77 C114 80 119 80 122 77" fill="none" stroke="#2B3A55" stroke-width="3" stroke-linecap="round"/> </g> <path d="M100 86 C103 90 108 90 111 86" fill="none" stroke="#2B3A55" stroke-width="3" stroke-linecap="round"/> <ellipse cx="78" cy="86" rx="6.5" ry="4" fill="#FF8FA3" stroke="none" opacity="0.75"/> <ellipse cx="128" cy="86" rx="6.5" ry="4" fill="#FF8FA3" stroke="none" opacity="0.75"/> </g> <g class="cs-buddy" stroke="#2B3A55" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"> <path class="cs-leaf cs-leaf-l" d="M145 143 C136 139 133 128 138 122 C145 128 148 135 145 143 Z" fill="#A8C98A"/> <path class="cs-leaf cs-leaf-r" d="M162 143 C172 137 173 127 167 121 C159 128 157 136 162 143 Z" fill="#A8C98A"/> <rect x="143" y="105" width="24" height="43" rx="11" fill="#FFD84D"/> <g fill="#FFFDF7" stroke="none" opacity="0.78"> <rect x="148" y="111" width="5" height="6" rx="2"/> <rect x="157" y="111" width="5" height="6" rx="2"/> <rect x="148" y="122" width="5" height="6" rx="2"/> <rect x="157" y="122" width="5" height="6" rx="2"/> <rect x="148" y="133" width="5" height="6" rx="2"/> <rect x="157" y="133" width="5" height="6" rx="2"/> </g> <g class="cs-buddy-face" stroke="#2B3A55" stroke-width="2" fill="none"> <path d="M149 120 C150 122 152 122 153 120"/> <path d="M157 120 C158 122 160 122 161 120"/> <path d="M152 129 C154 131 157 131 159 129"/> </g> </g>corn ice cream, confirmed — kernels, sleepy smile, and a cob sidekick.
Make it bob and shimmer
Keep every motion polite and cheap: transform for bobbing, blinking, waving, and twinkling; opacity plus translateX for the shimmer group. Everything sits inside @media (prefers-reduced-motion: no-preference), so the sticker rests quietly when motion is reduced.
@media (prefers-reduced-motion: no-preference) { .cs .cs-all { transform-origin: 101px 170px; animation: cs-bob 3s ease-in-out infinite; } .cs .cs-shadow { transform-box: fill-box; transform-origin: center; animation: cs-shadow 3s ease-in-out infinite; } .cs .cs-eye { transform-box: fill-box; transform-origin: center; animation: cs-blink 5.2s ease-in-out infinite; } .cs .cs-shimmer { animation: cs-shimmer 2.8s ease-in-out infinite; } .cs .cs-leaf { transform-box: fill-box; transform-origin: bottom center; } .cs .cs-leaf-l { animation: cs-leaf-wave 2.7s ease-in-out infinite; } .cs .cs-leaf-r { animation: cs-leaf-wave 2.7s ease-in-out -1.35s infinite; } .cs .cs-twinkle { transform-box: fill-box; transform-origin: center; } .cs .cs-twinkle1 { animation: cs-twinkle 2.5s ease-in-out infinite; } .cs .cs-twinkle2 { animation: cs-twinkle 2.5s ease-in-out 0.7s infinite; } .cs .cs-twinkle3 { animation: cs-twinkle 2.5s ease-in-out 1.3s infinite; } @keyframes cs-bob { 0%, 100% { transform: translateY(0) rotate(0deg); } 50% { transform: translateY(-5px) rotate(-1deg); } } @keyframes cs-shadow { 0%, 100% { transform: scaleX(1); opacity: 0.14; } 50% { transform: scaleX(0.86); opacity: 0.09; } } @keyframes cs-blink { 0%, 42%, 48%, 90%, 100% { transform: scaleY(1); opacity: 1; } 45%, 93% { transform: scaleY(0.12); opacity: 0.8; } } @keyframes cs-shimmer { 0%, 100% { opacity: 0; transform: translateX(-7px); } 45% { opacity: 0.5; transform: translateX(7px); } } @keyframes cs-leaf-wave { 0%, 100% { transform: rotate(0deg); } 45% { transform: rotate(8deg); } 75% { transform: rotate(-5deg); } } @keyframes cs-twinkle { 0%, 100% { opacity: 0.32; transform: scale(0.82) rotate(0deg); } 50% { opacity: 1; transform: scale(1.12) rotate(8deg); } } }bobbing, blinking, shimmering, waving — tiny summer novelty achieved.
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="cs" viewBox="0 0 200 200" width="200" height="200" role="img" aria-label="A happy corn soft serve cone gently bobbing with blinking eyes, shimmering kernels, twinkles, and a waving corn-cob buddy">
<rect x="0" y="0" width="200" height="200" rx="18" fill="#FBF2E5" stroke="none"/>
<ellipse class="cs-shadow" cx="103" cy="178" rx="53" ry="10" fill="#2B3A55" opacity="0.14" stroke="none"/>
<path class="cs-twinkle cs-twinkle1" d="M30 47 L34 55 L30 63 L26 55 Z" fill="#FFD84D" stroke="#2B3A55" stroke-width="2" stroke-linejoin="round"/>
<path class="cs-twinkle cs-twinkle2" d="M166 54 L169 61 L166 68 L163 61 Z" fill="#FF6B5E" stroke="none"/>
<path class="cs-twinkle cs-twinkle3" d="M37 133 L40 138 L37 143 L34 138 Z" fill="#FF8FA3" stroke="none"/>
<g class="cs-specks" fill="#FFD84D" stroke="#2B3A55" stroke-width="1.6" stroke-linejoin="round">
<rect x="49" y="78" width="7" height="5" rx="2"/>
<rect x="151" y="107" width="7" height="5" rx="2"/>
<rect x="42" y="157" width="6" height="4.5" rx="2"/>
</g>
<g class="cs-all">
<g class="cs-cone" stroke="#2B3A55" stroke-width="4" stroke-linecap="round" stroke-linejoin="round">
<path d="M69 110 L131 110 L101 170 Z" fill="#E3B478"/>
<g class="cs-waffle" stroke="#2B3A55" stroke-width="2.4" opacity="0.58">
<path d="M78 122 L113 167"/>
<path d="M91 111 L123 151"/>
<path d="M108 111 L128 136"/>
<path d="M123 122 L88 167"/>
<path d="M110 111 L78 151"/>
<path d="M93 111 L73 136"/>
</g>
</g>
<g class="cs-serve" stroke="#2B3A55" stroke-width="4" stroke-linecap="round" stroke-linejoin="round">
<path d="M69 109 C52 107 49 88 65 82 C58 69 67 58 82 60 C82 48 93 40 105 45 C110 34 124 32 132 43 C141 55 130 64 120 64 C139 66 148 80 139 93 C151 101 142 117 124 116 L78 116 C75 116 72 113 69 109 Z" fill="#FFD84D"/>
<path d="M75 113 C80 100 121 96 134 107 C128 119 83 122 75 113 Z" fill="#FFFDF7" opacity="0.45" stroke="none"/>
<path class="cs-curl" d="M112 47 C119 38 132 41 132 51 C132 59 122 62 118 55" fill="none" stroke="#2B3A55" stroke-width="3.4" stroke-linecap="round"/>
<g class="cs-kernels" fill="#FFFDF7" stroke="#2B3A55" stroke-width="1.4" stroke-linejoin="round" opacity="0.95">
<rect x="76" y="95" width="7" height="6" rx="2"/>
<rect x="87" y="93" width="7" height="6" rx="2"/>
<rect x="98" y="92" width="7" height="6" rx="2"/>
<rect x="109" y="93" width="7" height="6" rx="2"/>
<rect x="120" y="96" width="7" height="6" rx="2"/>
<rect x="80" y="104" width="7" height="6" rx="2"/>
<rect x="91" y="103" width="7" height="6" rx="2"/>
<rect x="102" y="102" width="7" height="6" rx="2"/>
<rect x="113" y="103" width="7" height="6" rx="2"/>
<rect x="124" y="105" width="7" height="6" rx="2"/>
</g>
<g class="cs-shimmer" fill="#FFFDF7" opacity="0" stroke="none">
<rect x="84" y="92" width="5" height="20" rx="2.5"/>
<rect x="97" y="91" width="5" height="20" rx="2.5"/>
<rect x="110" y="92" width="5" height="20" rx="2.5"/>
</g>
<g class="cs-face">
<g class="cs-eye cs-eye-l">
<path d="M86 77 C89 80 94 80 97 77" fill="none" stroke="#2B3A55" stroke-width="3" stroke-linecap="round"/>
</g>
<g class="cs-eye cs-eye-r">
<path d="M111 77 C114 80 119 80 122 77" fill="none" stroke="#2B3A55" stroke-width="3" stroke-linecap="round"/>
</g>
<path d="M100 86 C103 90 108 90 111 86" fill="none" stroke="#2B3A55" stroke-width="3" stroke-linecap="round"/>
<ellipse cx="78" cy="86" rx="6.5" ry="4" fill="#FF8FA3" stroke="none" opacity="0.75"/>
<ellipse cx="128" cy="86" rx="6.5" ry="4" fill="#FF8FA3" stroke="none" opacity="0.75"/>
</g>
<g class="cs-buddy" stroke="#2B3A55" stroke-width="3" stroke-linecap="round" stroke-linejoin="round">
<path class="cs-leaf cs-leaf-l" d="M145 143 C136 139 133 128 138 122 C145 128 148 135 145 143 Z" fill="#A8C98A"/>
<path class="cs-leaf cs-leaf-r" d="M162 143 C172 137 173 127 167 121 C159 128 157 136 162 143 Z" fill="#A8C98A"/>
<rect x="143" y="105" width="24" height="43" rx="11" fill="#FFD84D"/>
<g fill="#FFFDF7" stroke="none" opacity="0.78">
<rect x="148" y="111" width="5" height="6" rx="2"/>
<rect x="157" y="111" width="5" height="6" rx="2"/>
<rect x="148" y="122" width="5" height="6" rx="2"/>
<rect x="157" y="122" width="5" height="6" rx="2"/>
<rect x="148" y="133" width="5" height="6" rx="2"/>
<rect x="157" y="133" width="5" height="6" rx="2"/>
</g>
<g class="cs-buddy-face" stroke="#2B3A55" stroke-width="2" fill="none">
<path d="M149 120 C150 122 152 122 153 120"/>
<path d="M157 120 C158 122 160 122 161 120"/>
<path d="M152 129 C154 131 157 131 159 129"/>
</g>
</g>
</g>
</g>
</svg>
tips & gotchas
Mistakes we actually made
I keep the kernel grid slightly uneven on purpose — the rows feel drawn by hand, but the repeated rects still teach the pattern clearly.
I put the shimmer in its own group above the kernels with opacity 0 at rest; that way the static stage stays clean, and the final animation only wakes it up.
I anchor the bob at the cone tip, not the center of the scoop — the treat feels like it is balancing on the waffle point instead of floating.
I keep the cob buddy smaller and off to the side so it reads as a sidekick, not a second main character stealing the cone's moment.
make it yours
Remix it
- Extra kernelseasy
Add a third row of rounded rects near the bottom band, then stagger the x positions so it still feels handmade.
- New syrup stripeeasy
Add a coral drizzle path over the swirl and keep it inside the cs-serve group so it bobs with the cone.
- Buddy blinkeasy
Wrap the cob buddy's eye paths in their own group and reuse cs-blink with a shorter delay.
- Melty summer modemedium
Add two small yellow drip paths under the lower swirl and animate them with a tiny translateY plus opacity fade.
challenge extension
Turn the kernel grid into a reusable mini pattern: make three rows, vary the kernel colors between cream and sunshine yellow, then send a shimmer over only the middle row so the flavor band feels extra glossy.