Skip to content
CoDdleCoDoodle home
Fan Art PracticeBeginnerSVG + CSS

Hacipupu

A chibi Hacipupu snoozing upright in its bear-hood onesie — face peeking out, star hugged tight, ears bobbling on opposite beats. The coziest thing on the fridge.

This coded drawing is a fan-art practice example created for educational purposes only. HACIPUPU is a copyrighted character produced under license by POP MART. CoDoodle is not affiliated with, endorsed by, or sponsored by POP MART.

← you, in 30 minutes.

what you'll build

Here's the plan

A chibi Hacipupu in its bear-hood onesie — round hood with little ears, a soft face peeking out of the opening, a plump body hugging a tiny star — breathing slowly on warm cream paper. The whole trick is the hood: it's drawn as its OWN shape with an opening cut by a second path, so the face lives inside a costume instead of on a head.

You’ll learn

  • The hood-framing-a-face construction: hood shape first, opening path on top, face elements inside the opening
  • Drawing a costume that reads as a costume — stitch marks along the opening do more than any amount of shading
  • Keeping ears in their own groups with base-anchored transform-origins so they bobble instead of spinning
  • Making a character feel sleepy with animation: slow breathe from the feet, drowsy 6-second blinks, nothing bounces
Skill level
Beginner
Time
~30 min
Tools
Just a browser
Code type
SVG + CSS
Lines
~68

the steps

Build it, one change at a time

  1. Set the stage

    Warm paper, one soft ground shadow, and a scatter of stars and a sparkle — this character collects stars, so the props foreshadow the one it's about to hug. The shadow stays OUTSIDE the character group so it can flex on its own beat under the breathing.

    <rect x="0" y="0" width="200" height="200" rx="18" fill="#FBF2E5" stroke="none"/>
    <ellipse class="hp-shadow" cx="100" cy="176" rx="46" ry="9" fill="#2B3A55" opacity="0.15" stroke="none"/>
    <!-- four-point stars: two lines of symmetry make them easy to hand-place -->
    <path class="hp-prop hp-star1" d="M35 62 L38.2 69 L45 71 L38.2 73 L35 80 L31.8 73 L25 71 L31.8 69 Z" fill="#FFD84D" stroke="#2B3A55" stroke-width="2" stroke-linejoin="round"/>
    <path class="hp-prop hp-star2" d="M166 106 L168.4 111 L173 112.5 L168.4 114 L166 119 L163.6 114 L159 112.5 L163.6 111 Z" fill="#FF8FA3" stroke="none"/>
    <path class="hp-prop hp-spark1" d="M162 48 L165 55 L162 62 L159 55 Z" fill="#FF6B5E" stroke="#2B3A55" stroke-width="2" stroke-linejoin="round"/>
    

    an empty stage with a few stars waiting to be collected.

  2. Build the onesie silhouette

    Back-to-front: each little hood ear goes in its OWN group (they'll bobble separately later), then the plump body with stub arms and feet, then the big round hood LAST so it overlaps the ear bases and the body's shoulders — and finally the hood OPENING, a smaller pale shape sitting on the hood. No face yet: right now it's just an empty costume.

    <g class="hp-all">
      <!-- each ear is its own group so it can bobble on its own beat -->
      <g class="hp-ear hp-ear-l">
        <circle cx="67" cy="56" r="12" fill="#EED9C4" stroke="#2B3A55" stroke-width="4"/>
      </g>
      <g class="hp-ear hp-ear-r">
        <circle cx="133" cy="56" r="12" fill="#EED9C4" stroke="#2B3A55" stroke-width="4"/>
      </g>
      <g class="hp-body" stroke="#2B3A55" stroke-width="4" stroke-linecap="round" stroke-linejoin="round">
        <path d="M64 150 C55 153 51 162 56 168 C60 173 71 171 74 163 Z" fill="#EED9C4"/>
        <path d="M136 150 C145 153 149 162 144 168 C140 173 129 171 126 163 Z" fill="#EED9C4"/>
        <path d="M71 126 C67 148 72 170 100 170 C128 170 133 148 129 126 Z" fill="#EED9C4"/>
        <path d="M85 168 C77 170 73 176 78 179 C83 182 94 180 95 172 Z" fill="#EED9C4"/>
        <path d="M115 168 C123 170 127 176 122 179 C117 182 106 180 105 172 Z" fill="#EED9C4"/>
      </g>
      <!-- hood goes last so it overlaps the ear bases and shoulders -->
      <path class="hp-hood" d="M100 44 C130 44 149 65 149 92 C149 119 128 135 100 135 C72 135 51 119 51 92 C51 65 70 44 100 44 Z" fill="#EED9C4" stroke="#2B3A55" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
      <!-- the opening: a second, paler shape ON the hood — the face will live here -->
      <path class="hp-opening" d="M100 66 C119 66 130 79 130 96 C130 113 117 124 100 124 C83 124 70 113 70 96 C70 79 81 66 100 66 Z" fill="#FBF0DC" stroke="#2B3A55" stroke-width="3.5"/>
    </g>
    

    an empty bear onesie — somebody's about to be very cozy.

  3. Peek the face out (and hug the star)

    Pink inner-ear dots go INSIDE each ear's group so they ride the bobble. Stitch marks along the opening's rim are what make the hood read as a costume rather than a head. Then the face inside the opening — small glinted eyes, a tiny smile, big blush — a pale belly patch, and one sunshine star tucked under a stubby arm drawn OVER it.

    <!-- inner ears live inside each hp-ear group so they bobble too -->
    <circle cx="67" cy="56" r="5" fill="#FF8FA3" stroke="none" opacity="0.85"/>
    <!-- stitches along the opening rim: four short ticks sell the whole costume -->
    <g class="hp-stitches" fill="none" stroke="#2B3A55" stroke-width="2" stroke-linecap="round" opacity="0.45">
      <path d="M79 76 l4 3"/>
      <path d="M92 68.5 l1.5 4.5"/>
      <path d="M108 68.5 l-1.5 4.5"/>
      <path d="M121 76 l-4 3"/>
    </g>
    <ellipse class="hp-belly" cx="100" cy="150" rx="15" ry="11" fill="#FBF0DC" stroke="#2B3A55" stroke-width="2.5" opacity="0.9"/>
    <g class="hp-face">
      <g class="hp-eye hp-eye-l">
        <circle cx="89" cy="94" r="3.6" fill="#2B3A55" stroke="none"/>
        <circle cx="87.8" cy="92.6" r="1.2" fill="#FFFDF7" stroke="none"/>
      </g>
      <g class="hp-eye hp-eye-r">
        <circle cx="111" cy="94" r="3.6" fill="#2B3A55" stroke="none"/>
        <circle cx="109.8" cy="92.6" r="1.2" fill="#FFFDF7" stroke="none"/>
      </g>
      <path d="M95 103 Q100 107 105 103" fill="none" stroke="#2B3A55" stroke-width="2.8" stroke-linecap="round"/>
      <ellipse cx="80" cy="101" rx="5" ry="3.4" fill="#FF8FA3" stroke="none" opacity="0.72"/>
      <ellipse cx="120" cy="101" rx="5" ry="3.4" fill="#FF8FA3" stroke="none" opacity="0.72"/>
    </g>
    <!-- the hugged star, with the arm stroke drawn OVER it so it reads as held -->
    <g class="hp-hug">
      <path class="hp-star-held" d="M124 136 L127.4 143 L134.5 145 L127.4 147 L124 154 L120.6 147 L113.5 145 L120.6 143 Z" fill="#FFD84D" stroke="#2B3A55" stroke-width="2.6" stroke-linejoin="round"/>
      <path d="M112 146 C117 152 125 154 131 150" fill="none" stroke="#2B3A55" stroke-width="4" stroke-linecap="round"/>
    </g>
    

    the finished static Hacipupu — cozy, blushing, star secured.

  4. Breathe, bobble, blink

    Everything here is slow on purpose. The whole hp-all group breathes from its feet — a gentle squash trade, never a bounce — while the shadow flexes underneath. Both ears share ONE bobble animation with the right ear half a cycle late (animation-delay: -1.9s of 3.8s). Blinks come every 6.2 seconds, drowsy. The held star glows and tilts a little, the props twinkle staggered, and all of it sits inside @media (prefers-reduced-motion: no-preference).

    @media (prefers-reduced-motion: no-preference) {
      /* breathe from the feet: squash trades with stretch, nothing bounces */
      .hp .hp-all { transform-origin: 100px 172px; animation: hp-breathe 4.4s ease-in-out infinite; }
      .hp .hp-shadow { transform-box: fill-box; transform-origin: center; animation: hp-shadow 4.4s ease-in-out infinite; }
      /* same bobble on both ears — the right one starts half a cycle later */
      .hp .hp-ear-l { transform-origin: 70px 64px; animation: hp-ear-bobble 3.8s ease-in-out infinite; }
      .hp .hp-ear-r { transform-origin: 130px 64px; animation: hp-ear-bobble 3.8s ease-in-out -1.9s infinite; }
      .hp .hp-eye { transform-box: fill-box; transform-origin: center; animation: hp-blink 6.2s ease-in-out infinite; }
      .hp .hp-star-held { transform-box: fill-box; transform-origin: center; animation: hp-star-glow 4.4s ease-in-out infinite; }
    }
    @keyframes hp-breathe { 0%, 100% { transform: scale(1.015, 0.99); } 50% { transform: scale(0.995, 1.018) translateY(-1px); } }
    @keyframes hp-shadow { 0%, 100% { transform: scaleX(1); opacity: 0.15; } 50% { transform: scaleX(0.93); opacity: 0.12; } }
    @keyframes hp-ear-bobble { 0%, 100% { transform: rotate(0deg); } 40% { transform: rotate(-4deg); } 75% { transform: rotate(3deg); } }
    @keyframes hp-blink { 0%, 55%, 61%, 100% { transform: scaleY(1); } 58% { transform: scaleY(0.1); } }
    @keyframes hp-star-glow { 0%, 100% { transform: scale(1) rotate(0deg); opacity: 1; } 50% { transform: scale(1.12) rotate(8deg); opacity: 0.85; } }
    

    breathing, bobbling, barely blinking — professionally cozy, zero JavaScript.

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="hp" viewBox="0 0 200 200" width="200" height="200" role="img" aria-label="A chibi Hacipupu fan-art doodle breathing sleepily in its bear-hood onesie while its ears bobble and stars twinkle">
  <rect x="0" y="0" width="200" height="200" rx="18" fill="#FBF2E5" stroke="none"/>
  <ellipse class="hp-shadow" cx="100" cy="176" rx="46" ry="9" fill="#2B3A55" opacity="0.15" stroke="none"/>
  <path class="hp-prop hp-star1" d="M35 62 L38.2 69 L45 71 L38.2 73 L35 80 L31.8 73 L25 71 L31.8 69 Z" fill="#FFD84D" stroke="#2B3A55" stroke-width="2" stroke-linejoin="round"/>
  <path class="hp-prop hp-star2" d="M166 106 L168.4 111 L173 112.5 L168.4 114 L166 119 L163.6 114 L159 112.5 L163.6 111 Z" fill="#FF8FA3" stroke="none"/>
  <path class="hp-prop hp-spark1" d="M162 48 L165 55 L162 62 L159 55 Z" fill="#FF6B5E" stroke="#2B3A55" stroke-width="2" stroke-linejoin="round"/>
  <g class="hp-all">
    <g class="hp-ear hp-ear-l">
      <circle cx="67" cy="56" r="12" fill="#EED9C4" stroke="#2B3A55" stroke-width="4"/>
      <circle cx="67" cy="56" r="5" fill="#FF8FA3" stroke="none" opacity="0.85"/>
    </g>
    <g class="hp-ear hp-ear-r">
      <circle cx="133" cy="56" r="12" fill="#EED9C4" stroke="#2B3A55" stroke-width="4"/>
      <circle cx="133" cy="56" r="5" fill="#FF8FA3" stroke="none" opacity="0.85"/>
    </g>
    <g class="hp-body" stroke="#2B3A55" stroke-width="4" stroke-linecap="round" stroke-linejoin="round">
      <path d="M64 150 C55 153 51 162 56 168 C60 173 71 171 74 163 Z" fill="#EED9C4"/>
      <path d="M136 150 C145 153 149 162 144 168 C140 173 129 171 126 163 Z" fill="#EED9C4"/>
      <path d="M71 126 C67 148 72 170 100 170 C128 170 133 148 129 126 Z" fill="#EED9C4"/>
      <path d="M85 168 C77 170 73 176 78 179 C83 182 94 180 95 172 Z" fill="#EED9C4"/>
      <path d="M115 168 C123 170 127 176 122 179 C117 182 106 180 105 172 Z" fill="#EED9C4"/>
    </g>
    <path class="hp-hood" d="M100 44 C130 44 149 65 149 92 C149 119 128 135 100 135 C72 135 51 119 51 92 C51 65 70 44 100 44 Z" fill="#EED9C4" stroke="#2B3A55" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
    <path class="hp-opening" d="M100 66 C119 66 130 79 130 96 C130 113 117 124 100 124 C83 124 70 113 70 96 C70 79 81 66 100 66 Z" fill="#FBF0DC" stroke="#2B3A55" stroke-width="3.5"/>
    <g class="hp-stitches" fill="none" stroke="#2B3A55" stroke-width="2" stroke-linecap="round" opacity="0.45">
      <path d="M79 76 l4 3"/>
      <path d="M92 68.5 l1.5 4.5"/>
      <path d="M108 68.5 l-1.5 4.5"/>
      <path d="M121 76 l-4 3"/>
    </g>
    <ellipse class="hp-belly" cx="100" cy="150" rx="15" ry="11" fill="#FBF0DC" stroke="#2B3A55" stroke-width="2.5" opacity="0.9"/>
    <g class="hp-face">
      <g class="hp-eye hp-eye-l">
        <circle cx="89" cy="94" r="3.6" fill="#2B3A55" stroke="none"/>
        <circle cx="87.8" cy="92.6" r="1.2" fill="#FFFDF7" stroke="none"/>
      </g>
      <g class="hp-eye hp-eye-r">
        <circle cx="111" cy="94" r="3.6" fill="#2B3A55" stroke="none"/>
        <circle cx="109.8" cy="92.6" r="1.2" fill="#FFFDF7" stroke="none"/>
      </g>
      <path d="M95 103 Q100 107 105 103" fill="none" stroke="#2B3A55" stroke-width="2.8" stroke-linecap="round"/>
      <ellipse cx="80" cy="101" rx="5" ry="3.4" fill="#FF8FA3" stroke="none" opacity="0.72"/>
      <ellipse cx="120" cy="101" rx="5" ry="3.4" fill="#FF8FA3" stroke="none" opacity="0.72"/>
    </g>
    <g class="hp-hug">
      <path class="hp-star-held" d="M124 136 L127.4 143 L134.5 145 L127.4 147 L124 154 L120.6 147 L113.5 145 L120.6 143 Z" fill="#FFD84D" stroke="#2B3A55" stroke-width="2.6" stroke-linejoin="round"/>
      <path d="M112 146 C117 152 125 154 131 150" fill="none" stroke="#2B3A55" stroke-width="4" stroke-linecap="round"/>
    </g>
  </g>
</svg>
Open in Playground

tips & gotchas

Mistakes we actually made

My first hood opening was a perfect circle and the character looked like it was peering through a porthole. Squash the opening slightly taller than wide and drop it low on the hood — snug beats geometric.

The stitches are load-bearing. Without those four little ticks along the rim, the hood reads as a weird second head; with them, it's instantly a costume.

Anchor the ear bobbles at each ear's BASE where it meets the hood — with transform-box: fill-box centers they twirl like knobs instead of flopping.

Sleepy means slow AND small: a 4.4s breathe that only moves ~1.5% and a blink every 6.2s. Every time I sped something up 'a little', the nap turned into a workout.

make it yours

Remix it

  • New onesie coloureasy

    Recolour the #EED9C4 fills — a mint or sky onesie with the same navy outlines is a whole new drop.

  • Swap the hugeasy

    Replace the star with a tiny muffin (a rounded-rect base + a cloud-scallop top) tucked under the same arm stroke.

  • Naptimeeasy

    Swap each eye group for a single closed-eye arc and slow the breathe to 6s — fully asleep mode.

  • Bunny hoodmedium

    Stretch both ear circles into tall standing ovals, raise their transform-origins to the new bases, and retime the bobble so they sway rather than flick.

challenge extension

Give Hacipupu a floating dream: a tiny thought-bubble trail (three ascending circles) above the hood, each fading in and out on the SAME 4.4s clock as the breathe, timed so the biggest bubble blooms exactly at the top of the inhale.