Hatsune Miku
A sticker-bright chibi Miku fan-art study with swaying teal twin-tails, a tiny headset, and music notes that bounce like they heard the beat first.
This coded drawing is a fan-art practice example created for educational purposes only. Hatsune Miku is a trademark and copyrighted character of Crypton Future Media, Inc. CoDoodle is not affiliated with, endorsed by, or sponsored by Crypton Future Media.
← you, in 40 minutes.
what you'll build
Here's the plan
A chibi Hatsune Miku fan-art doodle built from plain SVG shapes: warm cream paper, chunky navy outlines, long teal twin-tails, a tiny headset, and hand-drawn music notes. You'll build it in layers first, then add CSS that makes the tails sway on opposite phases while the notes bob and the eyes blink.
You’ll learn
- Layering a character back-to-front so hair, body, head, and details read cleanly
- Using simple paths and ellipses to suggest a recognizable character without tracing anatomy
- Drawing music notes as SVG shapes instead of relying on a font glyph
- Anchoring transform origins at believable hinge points so idle motion feels attached
- Skill level
- Intermediate
- Time
- ~40 min
- Tools
- Just a browser
- Code type
- SVG + CSS
- Lines
- ~98
the steps
Build it, one change at a time
Set the stage
Start with CoDoodle paper, a soft ground shadow, three handmade music notes, and two little sparkles. The notes are paths and ellipses instead of text, so the drawing doesn't depend on a font being available in the iframe.
<rect x="0" y="0" width="210" height="210" rx="18" fill="#FBF2E5" stroke="none"/> <ellipse class="hm-shadow" cx="105" cy="186" rx="48" ry="9" fill="#2B3A55" opacity="0.16" stroke="none"/> <g class="hm-notes" stroke="#2B3A55" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"> <g class="hm-note hm-note1" fill="#FF6B5E"> <ellipse cx="35" cy="86" rx="5.4" ry="4.2" transform="rotate(-20 35 86)" stroke="none"/> <path d="M40 84 L40 54" fill="none"/> <path d="M40 55 C51 58 53 66 46 71" fill="none"/> </g> <g class="hm-note hm-note2" fill="#FFD84D"> <ellipse cx="172" cy="63" rx="5.2" ry="4" transform="rotate(-18 172 63)" stroke="none"/> <path d="M177 61 L177 35" fill="none"/> <path d="M177 36 C187 39 190 47 183 52" fill="none"/> </g> <g class="hm-note hm-note3" fill="#2B3A55"> <ellipse cx="166" cy="138" rx="4.8" ry="3.8" transform="rotate(-18 166 138)" stroke="none"/> <path d="M171 136 L171 111" fill="none"/> <path d="M171 112 C181 115 183 123 177 128" fill="none"/> </g> </g> <path class="hm-spark hm-spark1" d="M54 38 L57 46 L54 54 L51 46 Z" fill="#FF8FA3" stroke="none"/> <path class="hm-spark hm-spark2" d="M151 34 L154 40 L151 46 L148 40 Z" fill="#2B3A55" stroke="none"/>paper, shadow, notes, sparkles: a tiny concert stage.
Block in the chibi
Build the main character inside one group so it can bob as a unit later. The twin-tails sit behind the body and head (each in its OWN group so it can sway on its own beat), the outfit stays tiny and graphic, and the bangs are chunky teal shapes instead of lots of thin strands.
<g class="hm-character"> <g class="hm-tail-left"> <path d="M64 72 C47 78 33 105 31 137 C29 169 42 189 63 184 C52 164 57 133 68 109 C75 94 78 80 64 72 Z" fill="#4EC9C9" stroke="#2B3A55" stroke-width="4" stroke-linejoin="round"/> <path d="M59 91 C48 111 44 146 51 170" fill="none" stroke="#2FA3A3" stroke-width="3" stroke-linecap="round"/> <path d="M72 93 C61 119 61 151 69 175" fill="none" stroke="#2FA3A3" stroke-width="2.4" stroke-linecap="round" opacity="0.75"/> </g> <g class="hm-tail-right"> <path d="M146 72 C163 78 177 105 179 137 C181 169 168 189 147 184 C158 164 153 133 142 109 C135 94 132 80 146 72 Z" fill="#4EC9C9" stroke="#2B3A55" stroke-width="4" stroke-linejoin="round"/> <path d="M151 91 C162 111 166 146 159 170" fill="none" stroke="#2FA3A3" stroke-width="3" stroke-linecap="round"/> <path d="M138 93 C149 119 149 151 141 175" fill="none" stroke="#2FA3A3" stroke-width="2.4" stroke-linecap="round" opacity="0.75"/> </g> <g class="hm-body" stroke="#2B3A55" stroke-width="3.5" stroke-linecap="round" stroke-linejoin="round"> <path d="M82 134 C75 140 73 151 78 158 C83 156 86 145 90 139 Z" fill="#FFF2DD"/> <path d="M128 139 C136 145 139 156 134 162 C128 160 125 148 122 140 Z" fill="#FFF2DD"/> <path d="M89 119 L121 119 L127 150 C121 158 91 158 84 150 Z" fill="#FFFDF7"/> <path d="M91 121 L105 135 L119 121" fill="#B7F2F2"/> <path d="M101 132 L109 132 L111 158 L99 158 Z" fill="#4EC9C9"/> <path d="M82 151 L128 151 L121 174 L89 174 Z" fill="#2B3A55"/> <path d="M94 174 L92 188 M116 174 L118 188" fill="none"/> <path d="M87 188 L99 188 M111 188 L123 188" fill="none"/> </g> <g class="hm-head"> <path d="M66 77 C66 45 82 27 105 27 C128 27 144 45 144 77 C144 104 128 121 105 121 C82 121 66 104 66 77 Z" fill="#FFF2DD" stroke="#2B3A55" stroke-width="4" stroke-linejoin="round"/> <path d="M67 69 C70 43 84 26 105 26 C126 26 140 43 143 69 C130 60 119 57 105 58 C91 57 80 60 67 69 Z" fill="#4EC9C9" stroke="#2B3A55" stroke-width="4" stroke-linejoin="round"/> <path d="M74 67 C81 78 91 80 97 61 C101 78 111 80 116 60 C122 78 133 78 139 68" fill="#4EC9C9" stroke="#2B3A55" stroke-width="3.2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M83 55 C94 49 116 48 128 55" fill="none" stroke="#2FA3A3" stroke-width="3" stroke-linecap="round"/> </g> </g>the chibi shape is there: tails, bangs, tiny outfit, no face yet.
Add the pop details
Now add the pieces that make the doodle feel alive: coral hair ties, navy eyes with teal shine, blush dots, a small smile, and a headset with a mic arm. Keep every detail chunky enough to survive at gallery-card size.
<g class="hm-tie-details" stroke="#2B3A55" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"> <rect x="55" y="68" width="15" height="15" rx="3" fill="#FF6B5E" transform="rotate(-9 62.5 75.5)"/> <rect x="140" y="68" width="15" height="15" rx="3" fill="#FF6B5E" transform="rotate(9 147.5 75.5)"/> <path d="M58 78 L47 84 L53 70 Z" fill="#FFD84D"/> <path d="M152 78 L163 84 L157 70 Z" fill="#FFD84D"/> </g> <g class="hm-face"> <g class="hm-eye hm-eye-left"> <ellipse cx="91" cy="83" rx="7.5" ry="10.5" fill="#2B3A55" stroke="none"/> <ellipse cx="93" cy="86" rx="3.4" ry="5.4" fill="#4EC9C9" stroke="none"/> <circle cx="88" cy="78" r="2.2" fill="#FFFDF7" stroke="none"/> </g> <g class="hm-eye hm-eye-right"> <ellipse cx="119" cy="83" rx="7.5" ry="10.5" fill="#2B3A55" stroke="none"/> <ellipse cx="121" cy="86" rx="3.4" ry="5.4" fill="#4EC9C9" stroke="none"/> <circle cx="116" cy="78" r="2.2" fill="#FFFDF7" stroke="none"/> </g> <path d="M99 101 C102 105 108 105 111 101" fill="none" stroke="#2B3A55" stroke-width="2.4" stroke-linecap="round"/> <circle cx="82" cy="97" r="4" fill="#FF8FA3" stroke="none" opacity="0.65"/> <circle cx="128" cy="97" r="4" fill="#FF8FA3" stroke="none" opacity="0.65"/> </g> <g class="hm-headset" stroke="#2B3A55" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" fill="none"> <path d="M78 50 C88 37 122 37 132 50"/> <rect x="72" y="57" width="11" height="18" rx="4" fill="#FFFDF7"/> <rect x="127" y="57" width="11" height="18" rx="4" fill="#FFFDF7"/> <path d="M133 72 C144 78 142 90 132 92"/> <circle cx="130" cy="92" r="2.8" fill="#FF6B5E" stroke="none"/> </g>face, headset, hair ties: now it reads as a finished sticker.
Animate the idle loop
Give the two tails the same sway keyframes, then offset the right tail by half the duration with a negative delay. The rest is tiny polish: the whole character breathes upward, the shadow softens, notes bob on staggered beats, and the eyes blink — all inside @media (prefers-reduced-motion: no-preference).
@media (prefers-reduced-motion: no-preference) { .hm .hm-character { transform-origin: 105px 188px; animation: hm-bob 4s ease-in-out infinite; } .hm .hm-shadow { transform-box: fill-box; transform-origin: center; animation: hm-shadow 4s ease-in-out infinite; } /* same sway on both tails — the right one just starts half a cycle later */ .hm .hm-tail-left { transform-origin: 55px 78px; animation: hm-sway 3.4s ease-in-out infinite; } .hm .hm-tail-right { transform-origin: 155px 78px; animation: hm-sway 3.4s ease-in-out -1.7s infinite; } .hm .hm-eye { transform-box: fill-box; transform-origin: center; animation: hm-blink 4.8s ease-in-out infinite; } .hm .hm-note { transform-box: fill-box; transform-origin: center; } .hm .hm-note1 { animation: hm-note-bob 3s ease-in-out infinite; } .hm .hm-note2 { animation: hm-note-bob 3s ease-in-out 0.7s infinite; } .hm .hm-note3 { animation: hm-note-bob 3s ease-in-out 1.3s infinite; } .hm .hm-spark { transform-box: fill-box; transform-origin: center; } .hm .hm-spark1 { animation: hm-twinkle 2.6s ease-in-out infinite; } .hm .hm-spark2 { animation: hm-twinkle 2.6s ease-in-out 0.9s infinite; } } @keyframes hm-bob { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-2px); } } @keyframes hm-shadow { 0%, 100% { transform: scaleX(1); opacity: 0.16; } 50% { transform: scaleX(0.92); opacity: 0.11; } } @keyframes hm-sway { 0%, 100% { transform: rotate(-3deg); } 50% { transform: rotate(4deg); } } @keyframes hm-blink { 0%, 44%, 50%, 92%, 100% { transform: scaleY(1); } 47%, 95% { transform: scaleY(0.1); } } @keyframes hm-note-bob { 0%, 100% { transform: translateY(0) rotate(0deg); opacity: 0.72; } 50% { transform: translateY(-6px) rotate(-5deg); opacity: 1; } } @keyframes hm-twinkle { 0%, 100% { opacity: 0.35; transform: scale(0.85); } 45% { opacity: 1; transform: scale(1.12); } }tails swaying, notes bobbing, eyes blinking: a quiet little loop.
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="hm" viewBox="0 0 210 210" width="210" height="210" role="img" aria-label="A chibi Hatsune Miku fan-art doodle with swaying twin-tails and bobbing music notes">
<rect x="0" y="0" width="210" height="210" rx="18" fill="#FBF2E5" stroke="none"/>
<ellipse class="hm-shadow" cx="105" cy="186" rx="48" ry="9" fill="#2B3A55" opacity="0.16" stroke="none"/>
<g class="hm-notes" stroke="#2B3A55" stroke-width="3" stroke-linecap="round" stroke-linejoin="round">
<g class="hm-note hm-note1" fill="#FF6B5E">
<ellipse cx="35" cy="86" rx="5.4" ry="4.2" transform="rotate(-20 35 86)" stroke="none"/>
<path d="M40 84 L40 54" fill="none"/>
<path d="M40 55 C51 58 53 66 46 71" fill="none"/>
</g>
<g class="hm-note hm-note2" fill="#FFD84D">
<ellipse cx="172" cy="63" rx="5.2" ry="4" transform="rotate(-18 172 63)" stroke="none"/>
<path d="M177 61 L177 35" fill="none"/>
<path d="M177 36 C187 39 190 47 183 52" fill="none"/>
</g>
<g class="hm-note hm-note3" fill="#2B3A55">
<ellipse cx="166" cy="138" rx="4.8" ry="3.8" transform="rotate(-18 166 138)" stroke="none"/>
<path d="M171 136 L171 111" fill="none"/>
<path d="M171 112 C181 115 183 123 177 128" fill="none"/>
</g>
</g>
<path class="hm-spark hm-spark1" d="M54 38 L57 46 L54 54 L51 46 Z" fill="#FF8FA3" stroke="none"/>
<path class="hm-spark hm-spark2" d="M151 34 L154 40 L151 46 L148 40 Z" fill="#2B3A55" stroke="none"/>
<g class="hm-character">
<g class="hm-tail-left">
<path d="M64 72 C47 78 33 105 31 137 C29 169 42 189 63 184 C52 164 57 133 68 109 C75 94 78 80 64 72 Z" fill="#4EC9C9" stroke="#2B3A55" stroke-width="4" stroke-linejoin="round"/>
<path d="M59 91 C48 111 44 146 51 170" fill="none" stroke="#2FA3A3" stroke-width="3" stroke-linecap="round"/>
<path d="M72 93 C61 119 61 151 69 175" fill="none" stroke="#2FA3A3" stroke-width="2.4" stroke-linecap="round" opacity="0.75"/>
</g>
<g class="hm-tail-right">
<path d="M146 72 C163 78 177 105 179 137 C181 169 168 189 147 184 C158 164 153 133 142 109 C135 94 132 80 146 72 Z" fill="#4EC9C9" stroke="#2B3A55" stroke-width="4" stroke-linejoin="round"/>
<path d="M151 91 C162 111 166 146 159 170" fill="none" stroke="#2FA3A3" stroke-width="3" stroke-linecap="round"/>
<path d="M138 93 C149 119 149 151 141 175" fill="none" stroke="#2FA3A3" stroke-width="2.4" stroke-linecap="round" opacity="0.75"/>
</g>
<g class="hm-body" stroke="#2B3A55" stroke-width="3.5" stroke-linecap="round" stroke-linejoin="round">
<path d="M82 134 C75 140 73 151 78 158 C83 156 86 145 90 139 Z" fill="#FFF2DD"/>
<path d="M128 139 C136 145 139 156 134 162 C128 160 125 148 122 140 Z" fill="#FFF2DD"/>
<path d="M89 119 L121 119 L127 150 C121 158 91 158 84 150 Z" fill="#FFFDF7"/>
<path d="M91 121 L105 135 L119 121" fill="#B7F2F2"/>
<path d="M101 132 L109 132 L111 158 L99 158 Z" fill="#4EC9C9"/>
<path d="M82 151 L128 151 L121 174 L89 174 Z" fill="#2B3A55"/>
<path d="M94 174 L92 188 M116 174 L118 188" fill="none"/>
<path d="M87 188 L99 188 M111 188 L123 188" fill="none"/>
</g>
<g class="hm-head">
<path d="M66 77 C66 45 82 27 105 27 C128 27 144 45 144 77 C144 104 128 121 105 121 C82 121 66 104 66 77 Z" fill="#FFF2DD" stroke="#2B3A55" stroke-width="4" stroke-linejoin="round"/>
<path d="M67 69 C70 43 84 26 105 26 C126 26 140 43 143 69 C130 60 119 57 105 58 C91 57 80 60 67 69 Z" fill="#4EC9C9" stroke="#2B3A55" stroke-width="4" stroke-linejoin="round"/>
<path d="M74 67 C81 78 91 80 97 61 C101 78 111 80 116 60 C122 78 133 78 139 68" fill="#4EC9C9" stroke="#2B3A55" stroke-width="3.2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M83 55 C94 49 116 48 128 55" fill="none" stroke="#2FA3A3" stroke-width="3" stroke-linecap="round"/>
</g>
<g class="hm-tie-details" stroke="#2B3A55" stroke-width="3" stroke-linecap="round" stroke-linejoin="round">
<rect x="55" y="68" width="15" height="15" rx="3" fill="#FF6B5E" transform="rotate(-9 62.5 75.5)"/>
<rect x="140" y="68" width="15" height="15" rx="3" fill="#FF6B5E" transform="rotate(9 147.5 75.5)"/>
<path d="M58 78 L47 84 L53 70 Z" fill="#FFD84D"/>
<path d="M152 78 L163 84 L157 70 Z" fill="#FFD84D"/>
</g>
<g class="hm-face">
<g class="hm-eye hm-eye-left">
<ellipse cx="91" cy="83" rx="7.5" ry="10.5" fill="#2B3A55" stroke="none"/>
<ellipse cx="93" cy="86" rx="3.4" ry="5.4" fill="#4EC9C9" stroke="none"/>
<circle cx="88" cy="78" r="2.2" fill="#FFFDF7" stroke="none"/>
</g>
<g class="hm-eye hm-eye-right">
<ellipse cx="119" cy="83" rx="7.5" ry="10.5" fill="#2B3A55" stroke="none"/>
<ellipse cx="121" cy="86" rx="3.4" ry="5.4" fill="#4EC9C9" stroke="none"/>
<circle cx="116" cy="78" r="2.2" fill="#FFFDF7" stroke="none"/>
</g>
<path d="M99 101 C102 105 108 105 111 101" fill="none" stroke="#2B3A55" stroke-width="2.4" stroke-linecap="round"/>
<circle cx="82" cy="97" r="4" fill="#FF8FA3" stroke="none" opacity="0.65"/>
<circle cx="128" cy="97" r="4" fill="#FF8FA3" stroke="none" opacity="0.65"/>
</g>
<g class="hm-headset" stroke="#2B3A55" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" fill="none">
<path d="M78 50 C88 37 122 37 132 50"/>
<rect x="72" y="57" width="11" height="18" rx="4" fill="#FFFDF7"/>
<rect x="127" y="57" width="11" height="18" rx="4" fill="#FFFDF7"/>
<path d="M133 72 C144 78 142 90 132 92"/>
<circle cx="130" cy="92" r="2.8" fill="#FF6B5E" stroke="none"/>
</g>
</g>
</svg>
tips & gotchas
Mistakes we actually made
I first made the tails too skinny, and they disappeared at thumbnail size. Big teal shapes with one or two darker strand lines read better than hair spaghetti.
The notes looked tempting as text, but shape-built notes are steadier because the sandbox can't surprise you with a different font.
The tail sway only feels attached when the transform-origin sits at the hair tie, not in the middle of the tail shape.
Blinking the whole eye group keeps the highlight and teal shine tucked inside the squish instead of floating in place.
make it yours
Remix it
- Swap the stage propseasy
Trade the notes for hearts, stars, or little equalizer bars while keeping the same bob animation.
- Try a concert paletteeasy
Push the tie and sparkles toward neon coral, sunshine, or lavender while leaving the navy outline intact.
- Add a tiny wavemedium
Split one arm into its own group and give it a slow rotate() around the shoulder.
challenge extension
Make a second fan-art chibi using the same recipe: one big recognizable silhouette, two or three signature details, and a gentle idle animation that moves from a believable anchor point instead of the center of the whole SVG.