World Cup Mascot Trio
Three tiny mascot-inspired heads line up like a sticker sheet — eagle, moose, and jaguar — while a little soccer ball hops across the front. It is a cozy fan-art study drawn during the tournament, all hand-drawn shapes and no official marks.
This coded drawing is a fan-art practice example created for educational purposes only. Clutch, Maple, and Zayu are trademarked mascot characters of FIFA and the FIFA World Cup 26. CoDoodle is not affiliated with, endorsed by, or sponsored by FIFA. No official logos or marks are depicted.
← you, in 40 minutes.
what you'll build
Here's the plan
A friendly sticker row of three chibi mascot-inspired heads — a white-headed eagle, a warm-brown moose, and a golden jaguar — with a tiny classic soccer ball hopping across the front. The heads are drawn as separate SVG groups so they can bob on staggered beats, blink at different sleepy rhythms, and still stay readable at tiny gallery size.
You’ll learn
- Composing three small character heads so they overlap clearly without turning into a pile of shapes
- Using bare silhouettes first: antlers, ears, beak, snout, and head masses before any facial details
- Keeping face details in matching per-character groups so they can bob in sync with their heads
- Hiding a looping ball-hop restart with opacity so the arc feels continuous instead of snappy
- Skill level
- Intermediate
- Time
- ~40 min
- Tools
- Just a browser
- Code type
- SVG + CSS
- Lines
- ~108
the steps
Build it, one change at a time
Set the sticker stage
Start with warm paper, one wide soft shadow for the whole row, a few tiny sticker props, and the generic soccer ball resting near the front. The ball gets its own wc-ball group now so it can hop later without disturbing the animals.
<rect x="0" y="0" width="200" height="200" rx="18" fill="#FBF2E5" stroke="none"/> <ellipse class="wc-shadow" cx="101" cy="154" rx="74" ry="10" fill="#2B3A55" opacity="0.15" stroke="none"/> <!-- little sticker props around the row --> <path class="wc-spark wc-spark1" d="M26 48 L30 57 L26 66 L22 57 Z" fill="#FFD84D" stroke="#2B3A55" stroke-width="2" stroke-linejoin="round"/> <path class="wc-spark wc-spark2" d="M170 42 L173 49 L170 56 L167 49 Z" fill="#FF6B5E" stroke="none"/> <path class="wc-spark wc-spark3" d="M42 138 C38 134 32 137 34 142 C36 148 44 149 44 149 C44 149 50 143 48 138 C46 134 42 134 42 138 Z" fill="#FF8FA3" stroke="none" opacity="0.78"/> <path class="wc-spark wc-spark4" d="M161 135 C158 131 153 133 154 138 C155 143 162 145 162 145 C162 145 168 140 167 136 C166 132 162 132 161 135 Z" fill="#FFD84D" stroke="#2B3A55" stroke-width="2" stroke-linejoin="round"/> <!-- a generic soccer ball: no crest, no logo, just a classic pentagon pattern --> <g class="wc-ball" stroke="#2B3A55" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <circle cx="84" cy="151" r="9" fill="#FFFDF7"/> <path d="M84 145 L89 149 L87 155 L81 155 L79 149 Z" fill="#2B3A55"/> <path d="M84 145 L84 142 M89 149 L93 147 M87 155 L90 159 M81 155 L78 159 M79 149 L75 147" fill="none"/> </g>warm paper, soft shadow, sparkles, hearts, and one tiny soccer ball waiting its turn.
Block in the three heads
Draw the trio as bare silhouettes first: eagle on the left with a sunshine beak mass, moose in the middle with rounded antlers and the biggest head, jaguar on the right with soft ears and a golden muzzle. Each character sits in its own bob group, and the tilt lives one level deeper so the animation can move cleanly from the base.
<g class="wc-trio"> <g class="wc-head wc-eagle-bob"> <g transform="rotate(-7 57 113)"> <!-- eagle: white head plus a sunshine beak mass, no face yet --> <path d="M36 115 C35 94 45 80 60 78 C76 76 89 90 87 113 C85 134 72 145 58 145 C44 145 37 133 36 115 Z" fill="#FFFDF7" stroke="#2B3A55" stroke-width="3.6" stroke-linecap="round" stroke-linejoin="round"/> <path d="M49 103 C54 98 63 98 69 103 L73 115 C67 121 55 121 48 114 Z" fill="#FFD84D" stroke="#2B3A55" stroke-width="3" stroke-linejoin="round"/> </g> </g> <g class="wc-head wc-moose-bob"> <g transform="rotate(2 101 110)"> <!-- moose: antlers first, ears second, big head last --> <g fill="#D9B184" stroke="#2B3A55" stroke-width="3.4" stroke-linecap="round" stroke-linejoin="round"> <path d="M80 82 C73 72 76 63 84 67 C91 70 90 80 84 86 Z"/> <path d="M122 82 C129 72 126 63 118 67 C111 70 112 80 118 86 Z"/> </g> <path d="M76 103 C69 95 61 98 62 108 C63 118 72 119 78 113 Z" fill="#B98A5F" stroke="#2B3A55" stroke-width="3.4" stroke-linejoin="round"/> <path d="M126 103 C133 95 141 98 140 108 C139 118 130 119 124 113 Z" fill="#B98A5F" stroke="#2B3A55" stroke-width="3.4" stroke-linejoin="round"/> <ellipse cx="101" cy="114" rx="32" ry="36" fill="#B98A5F" stroke="#2B3A55" stroke-width="4"/> <ellipse cx="101" cy="128" rx="22" ry="16" fill="#D9B184" stroke="#2B3A55" stroke-width="3"/> </g> </g> <g class="wc-head wc-jaguar-bob"> <g transform="rotate(8 146 115)"> <!-- jaguar: rounded ears and a golden head, spots come later --> <path d="M126 92 C125 82 134 78 140 86 C145 82 154 82 160 87 C167 80 176 85 174 95 C181 105 180 129 168 139 C156 150 135 147 126 133 C119 122 119 103 126 92 Z" fill="#E8B54A" stroke="#2B3A55" stroke-width="3.8" stroke-linecap="round" stroke-linejoin="round"/> <ellipse cx="148" cy="126" rx="17" ry="14" fill="#F6CF78" stroke="#2B3A55" stroke-width="3"/> </g> </g> </g>three readable silhouettes — eagle, moose, jaguar — before the cuteness switch flips on.
Add faces, blush, and spots
Now add the sweet parts in a separate detail layer that mirrors the three head groups. Dot eyes stay inside per-character eye groups for blinking, blush stays soft, eagle feather tufts finish the left silhouette, and the jaguar gets loose rosette strokes instead of fussy tiny circles.
<g class="wc-details"> <g class="wc-eagle-detail-bob"> <g transform="rotate(-7 57 113)"> <!-- feather tufts finish the eagle head outline --> <g fill="#FFFDF7" stroke="#2B3A55" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"> <path d="M43 86 l-7 -8 l1 12"/> <path d="M52 80 l-3 -10 l8 9"/> <path d="M69 82 l7 -8 l-2 11"/> </g> <g class="wc-eyes wc-eagle-eyes" fill="#2B3A55" stroke="none"> <circle cx="52" cy="108" r="2.8"/> <circle cx="69" cy="108" r="2.8"/> </g> <path d="M57 116 C61 119 66 119 69 116" fill="none" stroke="#2B3A55" stroke-width="2.2" stroke-linecap="round"/> <ellipse cx="45" cy="117" rx="5" ry="3.2" fill="#FF8FA3" stroke="none" opacity="0.66"/> <ellipse cx="76" cy="117" rx="5" ry="3.2" fill="#FF8FA3" stroke="none" opacity="0.66"/> </g> </g> <g class="wc-moose-detail-bob"> <g transform="rotate(2 101 110)"> <g class="wc-eyes wc-moose-eyes" fill="#2B3A55" stroke="none"> <circle cx="91" cy="113" r="3"/> <circle cx="111" cy="113" r="3"/> </g> <path d="M98 126 C101 129 106 129 109 126" fill="none" stroke="#2B3A55" stroke-width="2.4" stroke-linecap="round"/> <ellipse cx="82" cy="123" rx="5.5" ry="3.5" fill="#FF8FA3" stroke="none" opacity="0.68"/> <ellipse cx="120" cy="123" rx="5.5" ry="3.5" fill="#FF8FA3" stroke="none" opacity="0.68"/> <path d="M96 127 C98 125 101 125 102 128 M106 128 C108 125 111 125 113 127" fill="none" stroke="#2B3A55" stroke-width="1.7" stroke-linecap="round" opacity="0.7"/> </g> </g> <g class="wc-jaguar-detail-bob"> <g transform="rotate(8 146 115)"> <!-- loose rosette strokes read better than tiny dots at gallery size --> <g fill="none" stroke="#9F6F2E" stroke-width="2.3" stroke-linecap="round"> <path d="M133 105 c-3 -3 -7 1 -4 4"/> <path d="M163 106 c4 -3 7 2 4 5"/> <path d="M135 133 c-3 1 -4 5 0 6"/> <path d="M163 132 c4 1 4 5 0 7"/> <path d="M148 98 c-3 -2 -6 0 -5 4"/> </g> <g class="wc-eyes wc-jaguar-eyes" fill="#2B3A55" stroke="none"> <circle cx="139" cy="119" r="2.8"/> <circle cx="156" cy="119" r="2.8"/> </g> <path d="M143 128 C146 131 151 131 154 128" fill="none" stroke="#2B3A55" stroke-width="2.2" stroke-linecap="round"/> <ellipse cx="131" cy="128" rx="5" ry="3.2" fill="#FF8FA3" stroke="none" opacity="0.66"/> <ellipse cx="166" cy="128" rx="5" ry="3.2" fill="#FF8FA3" stroke="none" opacity="0.66"/> </g> </g> </g>the static trio: sleepy dot eyes, tiny smiles, blush, eagle tufts, and jaguar rosettes.
Bob, blink, and hop the ball
The three heads share one bob keyframe but start on staggered delays, so they feel like friends bouncing to the same chant. Each eye group uses the same blink keyframe at a different duration, and the soccer ball hops forward in a small arc — then fades out before the loop restarts and fades back in at the beginning so you never see a snap.
@media (prefers-reduced-motion: no-preference) { .wc .wc-eagle-bob, .wc .wc-eagle-detail-bob { transform-origin: 57px 149px; animation: wc-bob 2.8s ease-in-out infinite; } .wc .wc-moose-bob, .wc .wc-moose-detail-bob { transform-origin: 101px 151px; animation: wc-bob 2.8s ease-in-out 0.28s infinite; } .wc .wc-jaguar-bob, .wc .wc-jaguar-detail-bob { transform-origin: 148px 149px; animation: wc-bob 2.8s ease-in-out 0.56s infinite; } .wc .wc-shadow { transform-box: fill-box; transform-origin: center; animation: wc-shadow 2.8s ease-in-out infinite; } .wc .wc-eyes { transform-box: fill-box; transform-origin: center; } .wc .wc-eagle-eyes { animation: wc-blink 5.2s ease-in-out infinite; } .wc .wc-moose-eyes { animation: wc-blink 6.4s ease-in-out 1.1s infinite; } .wc .wc-jaguar-eyes { animation: wc-blink 4.8s ease-in-out 0.6s infinite; } /* fade at both ends so the looping ball never visibly jumps back */ .wc .wc-ball { transform-origin: 84px 151px; animation: wc-ball-hop 3.4s cubic-bezier(0.4, 0, 0.2, 1) infinite; } .wc .wc-spark { transform-box: fill-box; transform-origin: center; } .wc .wc-spark1 { animation: wc-twinkle 2.7s ease-in-out infinite; } .wc .wc-spark2 { animation: wc-twinkle 2.7s ease-in-out 0.7s infinite; } .wc .wc-spark3 { animation: wc-twinkle 3.1s ease-in-out 1.2s infinite; } .wc .wc-spark4 { animation: wc-twinkle 3.1s ease-in-out 1.8s infinite; } } @keyframes wc-bob { 0%, 100% { transform: translateY(0) scale(1.02, 0.98); } 50% { transform: translateY(-5px) scale(0.98, 1.03); } } @keyframes wc-shadow { 0%, 100% { transform: scaleX(1); opacity: 0.15; } 50% { transform: scaleX(0.9); opacity: 0.1; } } @keyframes wc-blink { 0%, 42%, 49%, 100% { transform: scaleY(1); } 45%, 47% { transform: scaleY(0.1); } } @keyframes wc-ball-hop { 0% { opacity: 0; transform: translate(-8px, 0); } 8% { opacity: 1; transform: translate(-5px, 0); } 35% { opacity: 1; transform: translate(10px, -18px); } 68% { opacity: 1; transform: translate(28px, 0); } 84%, 100% { opacity: 0; transform: translate(36px, 0); } } @keyframes wc-twinkle { 0%, 100% { opacity: 0.35; transform: scale(0.82); } 45% { opacity: 1; transform: scale(1.12); } }three sleepy heads bobbing in staggered rhythm while the ball hops across the sticker row.
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="wc" viewBox="0 0 200 200" width="200" height="200" role="img" aria-label="Three chibi fan-art mascot heads bobbing on staggered beats while a generic soccer ball hops across the front">
<rect x="0" y="0" width="200" height="200" rx="18" fill="#FBF2E5" stroke="none"/>
<ellipse class="wc-shadow" cx="101" cy="154" rx="74" ry="10" fill="#2B3A55" opacity="0.15" stroke="none"/>
<path class="wc-spark wc-spark1" d="M26 48 L30 57 L26 66 L22 57 Z" fill="#FFD84D" stroke="#2B3A55" stroke-width="2" stroke-linejoin="round"/>
<path class="wc-spark wc-spark2" d="M170 42 L173 49 L170 56 L167 49 Z" fill="#FF6B5E" stroke="none"/>
<path class="wc-spark wc-spark3" d="M42 138 C38 134 32 137 34 142 C36 148 44 149 44 149 C44 149 50 143 48 138 C46 134 42 134 42 138 Z" fill="#FF8FA3" stroke="none" opacity="0.78"/>
<path class="wc-spark wc-spark4" d="M161 135 C158 131 153 133 154 138 C155 143 162 145 162 145 C162 145 168 140 167 136 C166 132 162 132 161 135 Z" fill="#FFD84D" stroke="#2B3A55" stroke-width="2" stroke-linejoin="round"/>
<g class="wc-ball" stroke="#2B3A55" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="84" cy="151" r="9" fill="#FFFDF7"/>
<path d="M84 145 L89 149 L87 155 L81 155 L79 149 Z" fill="#2B3A55"/>
<path d="M84 145 L84 142 M89 149 L93 147 M87 155 L90 159 M81 155 L78 159 M79 149 L75 147" fill="none"/>
</g>
<g class="wc-trio">
<g class="wc-head wc-eagle-bob">
<g transform="translate(-15 -4) rotate(-7 57 113)">
<path d="M36 115 C35 94 45 80 60 78 C76 76 89 90 87 113 C85 134 72 145 58 145 C44 145 37 133 36 115 Z" fill="#FFFDF7" stroke="#2B3A55" stroke-width="3.6" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M49 103 C54 98 63 98 69 103 L73 115 C67 121 55 121 48 114 Z" fill="#FFD84D" stroke="#2B3A55" stroke-width="3" stroke-linejoin="round"/>
</g>
</g>
<g class="wc-head wc-moose-bob">
<g transform="rotate(2 101 110)">
<g fill="#D9B184" stroke="#2B3A55" stroke-width="3.4" stroke-linecap="round" stroke-linejoin="round">
<path d="M80 82 C73 72 76 63 84 67 C91 70 90 80 84 86 Z"/>
<path d="M122 82 C129 72 126 63 118 67 C111 70 112 80 118 86 Z"/>
</g>
<path d="M76 103 C69 95 61 98 62 108 C63 118 72 119 78 113 Z" fill="#B98A5F" stroke="#2B3A55" stroke-width="3.4" stroke-linejoin="round"/>
<path d="M126 103 C133 95 141 98 140 108 C139 118 130 119 124 113 Z" fill="#B98A5F" stroke="#2B3A55" stroke-width="3.4" stroke-linejoin="round"/>
<ellipse cx="101" cy="114" rx="32" ry="36" fill="#B98A5F" stroke="#2B3A55" stroke-width="4"/>
<ellipse cx="101" cy="128" rx="22" ry="16" fill="#D9B184" stroke="#2B3A55" stroke-width="3"/>
</g>
</g>
<g class="wc-head wc-jaguar-bob">
<g transform="rotate(8 146 115)">
<path d="M126 92 C125 82 134 78 140 86 C145 82 154 82 160 87 C167 80 176 85 174 95 C181 105 180 129 168 139 C156 150 135 147 126 133 C119 122 119 103 126 92 Z" fill="#E8B54A" stroke="#2B3A55" stroke-width="3.8" stroke-linecap="round" stroke-linejoin="round"/>
<ellipse cx="148" cy="126" rx="17" ry="14" fill="#F6CF78" stroke="#2B3A55" stroke-width="3"/>
</g>
</g>
</g>
<g class="wc-details">
<g class="wc-eagle-detail-bob">
<g transform="translate(-15 -4) rotate(-7 57 113)">
<g fill="#FFFDF7" stroke="#2B3A55" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round">
<path d="M43 86 l-7 -8 l1 12"/>
<path d="M52 80 l-3 -10 l8 9"/>
<path d="M69 82 l7 -8 l-2 11"/>
</g>
<g class="wc-eyes wc-eagle-eyes" fill="#2B3A55" stroke="none">
<circle cx="52" cy="95" r="2.8"/>
<circle cx="68" cy="95" r="2.8"/>
</g>
<ellipse cx="44" cy="112" rx="5" ry="3.2" fill="#FF8FA3" stroke="none" opacity="0.66"/>
<ellipse cx="75" cy="112" rx="5" ry="3.2" fill="#FF8FA3" stroke="none" opacity="0.66"/>
</g>
</g>
<g class="wc-moose-detail-bob">
<g transform="rotate(2 101 110)">
<g class="wc-eyes wc-moose-eyes" fill="#2B3A55" stroke="none">
<circle cx="91" cy="104" r="3"/>
<circle cx="111" cy="104" r="3"/>
</g>
<path d="M98 126 C101 129 106 129 109 126" fill="none" stroke="#2B3A55" stroke-width="2.4" stroke-linecap="round"/>
<ellipse cx="82" cy="123" rx="5.5" ry="3.5" fill="#FF8FA3" stroke="none" opacity="0.68"/>
<ellipse cx="120" cy="123" rx="5.5" ry="3.5" fill="#FF8FA3" stroke="none" opacity="0.68"/>
<path d="M96 127 C98 125 101 125 102 128 M106 128 C108 125 111 125 113 127" fill="none" stroke="#2B3A55" stroke-width="1.7" stroke-linecap="round" opacity="0.7"/>
</g>
</g>
<g class="wc-jaguar-detail-bob">
<g transform="rotate(8 146 115)">
<g fill="none" stroke="#9F6F2E" stroke-width="2.3" stroke-linecap="round">
<path d="M133 105 c-3 -3 -7 1 -4 4"/>
<path d="M163 106 c4 -3 7 2 4 5"/>
<path d="M148 98 c-3 -2 -6 0 -5 4"/>
</g>
<g class="wc-eyes wc-jaguar-eyes" fill="#2B3A55" stroke="none">
<circle cx="139" cy="119" r="2.8"/>
<circle cx="156" cy="119" r="2.8"/>
</g>
<path d="M143 128 C146 131 151 131 154 128" fill="none" stroke="#2B3A55" stroke-width="2.2" stroke-linecap="round"/>
<ellipse cx="131" cy="128" rx="5" ry="3.2" fill="#FF8FA3" stroke="none" opacity="0.66"/>
<ellipse cx="166" cy="128" rx="5" ry="3.2" fill="#FF8FA3" stroke="none" opacity="0.66"/>
</g>
</g>
</g>
</svg>
tips & gotchas
Mistakes we actually made
I keep the moose slightly larger than the side heads — otherwise the antlers disappear and the whole row reads flat.
I draw the details in matching bob groups, not loose on top of the SVG, because a face that stays still while the head bounces feels instantly off.
I use a few jaguar rosette strokes instead of many tiny spots — at 200px, restraint reads more like design and less like confetti.
I fade the soccer ball before the loop resets. The movement is still simple, but your eye forgives the restart because there is no visible teleport.
make it yours
Remix it
- New sticker propseasy
Swap the hearts for stars, tiny flags, or confetti dots — keep them generic and hand-drawn.
- Different moodseasy
Turn one tiny smile into an o-mouth, a wink, or sleepy closed eyes for a more expressive trio.
- Team colourseasy
Recolour the blush, sparkles, or background using your own palette while keeping the navy outlines.
- Ball bounce pathmedium
Make the ball hop behind the moose, then reappear in front of the jaguar by combining opacity with layer order.
challenge extension
Add one tiny scarf or pennant per head using only generic stripes and shapes — no crests, no wordmarks — then make each accessory wiggle with the same staggered timing as its head.