Skip to content
CoDdleCoDoodle home
Seasonal ArtBeginnerSVG + CSS

Hot Dog Summer

A plump little sausage living its best beach life — shades on, mustard freshly squiggled, not a single care left in the bun.

← you, in 25 minutes.

what you'll build

Here's the plan

A hot dog having the best day of its life — a plump sausage in rounded sunglasses, tucked into a golden bun on a coral beach towel, mustard squiggle styled on top. The sausage AND the mustard are drawn with the same two-stroke trick — a fat navy line under a thinner coloured one — and a doodled sun spins its stubby rays in the corner all afternoon.

You’ll learn

  • Drawing plump tube shapes as ONE thick stroke with round linecaps — the sausage is a single path, not twenty
  • Outlining without outlines: stacking a fat navy stroke underneath a thinner coloured copy of the same path
  • Clipping a glint inside sunglass lenses with clipPath, so the shine only exists where the lens is
  • Mixing timescales — a lazy 3.2s bob against a 26-second sun spin — so a scene feels warm instead of busy
Skill level
Beginner
Time
~25 min
Tools
Just a browser
Code type
SVG + CSS
Lines
~71

the steps

Build it, one change at a time

  1. Set the beach stage

    Warm paper, one soft shadow where the hot dog will land, a bare sun disc top-left, and three sparkle stickers. The shadow stays OUTSIDE the character group so it can flatten against the ground during the bob, and the sun gets its own group now because its rays will spin around it later.

    <rect x="0" y="0" width="200" height="200" rx="18" fill="#FBF2E5" stroke="none"/>
    <!-- shadow stays OUTSIDE the character group so it can flatten while the hot dog bobs -->
    <ellipse class="hd-shadow" cx="100" cy="176" rx="64" ry="9" fill="#2B3A55" opacity="0.16" stroke="none"/>
    <!-- the sun gets its own group — the rays arrive in step 3 and will spin around it -->
    <g class="hd-sun">
      <circle cx="36" cy="38" r="14" fill="#FFD84D" stroke="#2B3A55" stroke-width="3"/>
    </g>
    <path class="hd-spark hd-spark1" d="M164 40 L168 48 L164 56 L160 48 Z" fill="#FFD84D" stroke="#2B3A55" stroke-width="2" stroke-linejoin="round"/>
    <path class="hd-spark hd-spark2" d="M24 148 L27 155 L24 162 L21 155 Z" fill="#FF6B5E" stroke="none"/>
    <path class="hd-spark hd-spark3" d="M183 130 L186 137 L183 144 L180 137 Z" fill="#FF8FA3" stroke="none"/>
    

    an empty beach: one sun, one shadow, three sparkles.

  2. Tuck the sausage into the bun

    The whole sausage is ONE stroked path with round linecaps — a fat navy line drawn first, then a slightly thinner red-brown copy of the exact same path on top, so the caps draw both plump ends for free. Paint order does the tucking: back bun, sausage, then the front bun lip LAST so the sausage sits inside it with both ends poking out.

    <g class="hd-all">
      <!-- back bun first — it only peeks through the crease, but that sliver sells the depth -->
      <ellipse class="hd-bun-back" cx="100" cy="140" rx="50" ry="20" fill="#E3B478" stroke="#2B3A55" stroke-width="3.5"/>
      <!-- the sausage is ONE path drawn twice: fat navy stroke under, thinner colour stroke over.
           round linecaps give you both plump ends for free -->
      <path class="hd-sausage-ink" d="M44 112 Q100 97 156 112" fill="none" stroke="#2B3A55" stroke-width="40" stroke-linecap="round"/>
      <path class="hd-sausage" d="M44 112 Q100 97 156 112" fill="none" stroke="#D98A6A" stroke-width="33.5" stroke-linecap="round"/>
      <!-- front bun lip goes LAST so the sausage looks tucked in, ends overhanging both sides -->
      <path class="hd-bun-front" d="M50 118 C68 128 132 128 150 118 C158 124 161 144 154 156 C144 168 56 168 46 156 C39 144 42 124 50 118 Z" fill="#F0C98A" stroke="#2B3A55" stroke-width="3.5" stroke-linecap="round" stroke-linejoin="round"/>
    </g>
    

    a faceless hot dog — 80% of the silhouette from three shapes.

  3. Add mustard, shades, and towel swagger

    The sun's rays and the beach towel are drawn BEFORE the hd-all group — they belong to the beach, not the hot dog, so they must not bob with it. Then inside the group: stubby raised arms, the mustard squiggle (the same two-stroke trick again, with peaks poking proudly above the silhouette), blush and a smile, and rounded sunglasses whose lens shapes double as a clipPath — that's the window the glint will sweep through in the next step.

    <!-- rays + towel are drawn BEFORE the hd-all group: beach things don't bob -->
    <g class="hd-rays" stroke="#FFD84D" stroke-width="3.5" stroke-linecap="round">
      <line x1="56" y1="38" x2="63" y2="38"/>
      <line x1="50" y1="24" x2="55" y2="19"/>
      <line x1="36" y1="18" x2="36" y2="11"/>
      <line x1="22" y1="24" x2="17" y2="19"/>
      <line x1="16" y1="38" x2="9" y2="38"/>
      <line x1="22" y1="52" x2="17" y2="57"/>
      <line x1="36" y1="58" x2="36" y2="65"/>
      <line x1="50" y1="52" x2="55" y2="57"/>
    </g>
    <g class="hd-towel">
      <rect x="24" y="166" width="152" height="8" rx="4" fill="#FF6B5E" stroke="#2B3A55" stroke-width="2.5"/>
      <rect x="28" y="168.5" width="144" height="3" rx="1.5" fill="#FFFDF7" opacity="0.8" stroke="none"/>
    </g>
    <!-- everything below lives INSIDE hd-all, after the bun-front path -->
    <g class="hd-arms" fill="#D98A6A" stroke="#2B3A55" stroke-width="3" stroke-linecap="round" stroke-linejoin="round">
      <path d="M48 100 C36 96 28 84 32 75 C35 68 44 70 43 78 C42 86 48 92 55 95 Z"/>
      <path d="M152 100 C164 96 172 84 168 75 C165 68 156 70 157 78 C158 86 152 92 145 95 Z"/>
    </g>
    <!-- mustard: the sausage trick again — navy stroke under, sunshine stroke over -->
    <path class="hd-mustard-ink" d="M54 93 Q62 81 70 88 Q78 96 86 84 Q94 75 102 83 Q110 91 118 81 Q126 74 134 83 Q142 92 148 88" fill="none" stroke="#2B3A55" stroke-width="8.5" stroke-linecap="round" stroke-linejoin="round"/>
    <path class="hd-mustard" d="M54 93 Q62 81 70 88 Q78 96 86 84 Q94 75 102 83 Q110 91 118 81 Q126 74 134 83 Q142 92 148 88" fill="none" stroke="#FFD84D" stroke-width="5.5" stroke-linecap="round" stroke-linejoin="round"/>
    <g class="hd-face">
      <ellipse cx="62" cy="108" rx="6.5" ry="4" fill="#FF8FA3" opacity="0.72" stroke="none"/>
      <ellipse cx="138" cy="108" rx="6.5" ry="4" fill="#FF8FA3" opacity="0.72" stroke="none"/>
      <path d="M92 114 C95 121 105 121 108 114" fill="none" stroke="#2B3A55" stroke-width="3" stroke-linecap="round"/>
    </g>
    <g class="hd-shades">
      <path d="M73 100 L64 97" stroke="#2B3A55" stroke-width="3" stroke-linecap="round"/>
      <path d="M127 100 L136 97" stroke="#2B3A55" stroke-width="3" stroke-linecap="round"/>
      <path d="M94 100 C96 96 104 96 106 100" fill="none" stroke="#2B3A55" stroke-width="3.5" stroke-linecap="round"/>
      <rect x="73" y="94" width="21" height="16" rx="8" fill="#2B3A55" stroke="none"/>
      <rect x="106" y="94" width="21" height="16" rx="8" fill="#2B3A55" stroke="none"/>
      <!-- the lens shapes again, this time as a clipPath — the glint only exists inside them -->
      <clipPath id="hd-lens-clip"><rect x="73" y="94" width="21" height="16" rx="8"/><rect x="106" y="94" width="21" height="16" rx="8"/></clipPath>
      <g clip-path="url(#hd-lens-clip)">
        <!-- the rotated rect sits in its OWN group so the animation can move the group
             without overwriting the rotate() attribute -->
        <g class="hd-glint">
          <rect x="88" y="84" width="7" height="38" fill="#FFFDF7" opacity="0.7" transform="rotate(24 100 102)"/>
        </g>
      </g>
    </g>
    

    the finished static hot dog, fully committed to summer.

  4. Bob, spin, sweep

    The hd-all group does a tiny squash-and-stretch bob from the bun's base while the shadow flattens in sync. The rays turn once every 26 seconds — glacial on purpose, so the sun shimmers instead of spinning — and the glint slides ±46px along the shades, invisible except while it crosses the clipPath lenses. Everything sits inside @media (prefers-reduced-motion: no-preference) so it freezes politely when motion isn't wanted.

    @media (prefers-reduced-motion: no-preference) {
      /* bob pivots from the bun's base so the squash plants into the towel */
      .hd .hd-all { transform-origin: 100px 166px; animation: hd-bob 3.2s ease-in-out infinite; }
      .hd .hd-shadow { transform-box: fill-box; transform-origin: center; animation: hd-shadow 3.2s ease-in-out infinite; }
      /* 26 seconds per revolution — lazy summer pace */
      .hd .hd-rays { transform-origin: 36px 38px; animation: hd-rays-turn 26s linear infinite; }
      .hd .hd-sun { transform-box: fill-box; transform-origin: center; animation: hd-sun-pulse 3.2s ease-in-out infinite; }
      /* the glint slides sideways; the clipPath decides where it's visible */
      .hd .hd-glint { animation: hd-glint 5.2s ease-in-out infinite; }
      .hd .hd-spark { transform-box: fill-box; transform-origin: center; }
      .hd .hd-spark1 { animation: hd-twinkle 2.8s ease-in-out infinite; }
      .hd .hd-spark2 { animation: hd-twinkle 2.8s ease-in-out 0.9s infinite; }
      .hd .hd-spark3 { animation: hd-twinkle 3.4s ease-in-out 1.6s infinite; }
    }
    @keyframes hd-bob { 0%, 100% { transform: translateY(0) scale(1.02, 0.98); } 50% { transform: translateY(-4px) scale(0.99, 1.02); } }
    @keyframes hd-shadow { 0%, 100% { transform: scaleX(1); opacity: 0.16; } 50% { transform: scaleX(0.88); opacity: 0.11; } }
    @keyframes hd-rays-turn { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
    @keyframes hd-sun-pulse { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.06); } }
    @keyframes hd-glint { 0%, 55% { transform: translateX(-46px); } 80%, 100% { transform: translateX(46px); } }
    @keyframes hd-twinkle { 0%, 100% { opacity: 0.35; transform: scale(0.82); } 45% { opacity: 1; transform: scale(1.12); } }
    

    bobbing, spinning, glinting — hot dog summer, 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="hd" viewBox="0 0 200 200" width="200" height="200" role="img" aria-label="A smiling hot dog in sunglasses bobbing happily on a beach towel while sun rays turn and a glint sweeps across its shades">
  <rect x="0" y="0" width="200" height="200" rx="18" fill="#FBF2E5" stroke="none"/>
  <ellipse class="hd-shadow" cx="100" cy="176" rx="64" ry="9" fill="#2B3A55" opacity="0.16" stroke="none"/>
  <g class="hd-sun">
    <circle cx="36" cy="38" r="14" fill="#FFD84D" stroke="#2B3A55" stroke-width="3"/>
  </g>
  <path class="hd-spark hd-spark1" d="M164 40 L168 48 L164 56 L160 48 Z" fill="#FFD84D" stroke="#2B3A55" stroke-width="2" stroke-linejoin="round"/>
  <path class="hd-spark hd-spark2" d="M24 148 L27 155 L24 162 L21 155 Z" fill="#FF6B5E" stroke="none"/>
  <path class="hd-spark hd-spark3" d="M183 130 L186 137 L183 144 L180 137 Z" fill="#FF8FA3" stroke="none"/>
  <g class="hd-rays" stroke="#FFD84D" stroke-width="3.5" stroke-linecap="round">
    <line x1="56" y1="38" x2="63" y2="38"/>
    <line x1="50" y1="24" x2="55" y2="19"/>
    <line x1="36" y1="18" x2="36" y2="11"/>
    <line x1="22" y1="24" x2="17" y2="19"/>
    <line x1="16" y1="38" x2="9" y2="38"/>
    <line x1="22" y1="52" x2="17" y2="57"/>
    <line x1="36" y1="58" x2="36" y2="65"/>
    <line x1="50" y1="52" x2="55" y2="57"/>
  </g>
  <g class="hd-towel">
    <rect x="24" y="166" width="152" height="8" rx="4" fill="#FF6B5E" stroke="#2B3A55" stroke-width="2.5"/>
    <rect x="28" y="168.5" width="144" height="3" rx="1.5" fill="#FFFDF7" opacity="0.8" stroke="none"/>
  </g>
  <g class="hd-all">
    <ellipse class="hd-bun-back" cx="100" cy="140" rx="50" ry="20" fill="#E3B478" stroke="#2B3A55" stroke-width="3.5"/>
    <path class="hd-sausage-ink" d="M44 112 Q100 97 156 112" fill="none" stroke="#2B3A55" stroke-width="40" stroke-linecap="round"/>
    <path class="hd-sausage" d="M44 112 Q100 97 156 112" fill="none" stroke="#D98A6A" stroke-width="33.5" stroke-linecap="round"/>
    <path class="hd-bun-front" d="M50 118 C68 128 132 128 150 118 C158 124 161 144 154 156 C144 168 56 168 46 156 C39 144 42 124 50 118 Z" fill="#F0C98A" stroke="#2B3A55" stroke-width="3.5" stroke-linecap="round" stroke-linejoin="round"/>
    <g class="hd-arms" fill="#D98A6A" stroke="#2B3A55" stroke-width="3" stroke-linecap="round" stroke-linejoin="round">
      <path d="M48 100 C36 96 28 84 32 75 C35 68 44 70 43 78 C42 86 48 92 55 95 Z"/>
      <path d="M152 100 C164 96 172 84 168 75 C165 68 156 70 157 78 C158 86 152 92 145 95 Z"/>
    </g>
    <path class="hd-mustard-ink" d="M54 93 Q62 81 70 88 Q78 96 86 84 Q94 75 102 83 Q110 91 118 81 Q126 74 134 83 Q142 92 148 88" fill="none" stroke="#2B3A55" stroke-width="8.5" stroke-linecap="round" stroke-linejoin="round"/>
    <path class="hd-mustard" d="M54 93 Q62 81 70 88 Q78 96 86 84 Q94 75 102 83 Q110 91 118 81 Q126 74 134 83 Q142 92 148 88" fill="none" stroke="#FFD84D" stroke-width="5.5" stroke-linecap="round" stroke-linejoin="round"/>
    <g class="hd-face">
      <ellipse cx="62" cy="108" rx="6.5" ry="4" fill="#FF8FA3" opacity="0.72" stroke="none"/>
      <ellipse cx="138" cy="108" rx="6.5" ry="4" fill="#FF8FA3" opacity="0.72" stroke="none"/>
      <path d="M92 114 C95 121 105 121 108 114" fill="none" stroke="#2B3A55" stroke-width="3" stroke-linecap="round"/>
    </g>
    <g class="hd-shades">
      <path d="M73 100 L64 97" stroke="#2B3A55" stroke-width="3" stroke-linecap="round"/>
      <path d="M127 100 L136 97" stroke="#2B3A55" stroke-width="3" stroke-linecap="round"/>
      <path d="M94 100 C96 96 104 96 106 100" fill="none" stroke="#2B3A55" stroke-width="3.5" stroke-linecap="round"/>
      <rect x="73" y="94" width="21" height="16" rx="8" fill="#2B3A55" stroke="none"/>
      <rect x="106" y="94" width="21" height="16" rx="8" fill="#2B3A55" stroke="none"/>
      <clipPath id="hd-lens-clip"><rect x="73" y="94" width="21" height="16" rx="8"/><rect x="106" y="94" width="21" height="16" rx="8"/></clipPath>
      <g clip-path="url(#hd-lens-clip)">
        <g class="hd-glint">
          <rect x="88" y="84" width="7" height="38" fill="#FFFDF7" opacity="0.7" transform="rotate(24 100 102)"/>
        </g>
      </g>
    </g>
  </g>
</svg>
Open in Playground

tips & gotchas

Mistakes we actually made

I animated the glint rect directly at first — the CSS animation's transform replaced the SVG rotate() attribute and my diagonal shine snapped bolt upright. Wrap the rotated rect in its own <g> and animate the group; that way the attribute and the animation each keep their own transform.

My first mustard squiggle stayed politely inside the sausage outline and looked printed on. Letting the peaks poke a few pixels ABOVE the navy silhouette is what makes it read as a dollop sitting on top.

The front bun's top edge has to sag toward the middle. My first pass was a straight line and the sausage looked like it was sitting on a shelf — the dip is what turns a shape next to another shape into a cradle.

Keep the bob at -4px over 3.2s and the sun at a 26-second spin. This hot dog has nowhere to be — the moment I sped anything up, relaxed turned into nervous.

make it yours

Remix it

  • Ketchup doubleeasy

    Duplicate both mustard paths, nudge them down ~8px, and swap the sunshine for coral #FF6B5E — every good hot dog carries both condiments.

  • Sun with a faceeasy

    Give the sun two tiny navy dots and a smile arc — three extra lines and suddenly the whole beach has a witness.

  • Golden houreasy

    Warm the paper toward peach, deepen the sun to coral, and slow every animation by half for the sunset-nap version.

  • Shades upmedium

    Move the whole hd-shades group up onto the sausage's forehead, then draw two sleepy closed-eye arcs where the lenses used to be.

challenge extension

Sync the shine to the bob: retime hd-glint to the same 3.2s as the bounce and pick an animation-delay so the sweep crosses the lenses exactly at the top of each bob — then make spark1 pop at that same moment, like the hot dog is getting its photo taken.