SVG Power-Up

March 18, 2021

I wanted to learn more about SVG. So I decided to try to draw a power-up mushroom without using any graphic design tools.

I had been using SVG icons and graphing tools for a while, but I was a little intimidated by SVG for some reason and had never taken a close look at how it works.

Scaled Vector Graphics (SVG) are an XML format for describing 2D images. An <svg> element can hold a set of shapes. I started off my mushroom picture with a black rectangle (rect) inside of a 1000 x 1000 viewBox.

<svg version='1.1' baseProfile='full' xmlns='http://www.w3.org/2000/svg'
     viewBox='0 0 1000 1000'>

  <!-- Black Rectangle -->
  <rect width="100%" height="100%" fill="#000000" />
</svg>

SVG uses a grid with points specified in the format x y. 0 0 is the upper left corner.

As shapes are added, they are stacked on top of each other. To draw a red mushroom cap on top of the black rectangle, I started to draw a path.

The data (d) for a path takes a set of commands. The commands I need are:

For my path I wanted to:

  • Move to just below the middle of the left side (M 0 550)
  • Draw a curve upward and then back down to the middle of the right side (C 0 -175, 1000 -175, 1000 550)

To determine the control points for for the Bézier curve, I experimented with different values for a few minutes until it looked right.

I added fill to color in the area of the path in red. Since I hadn't yet made a complete loop, a straight line connected the end of the path back to the beginning.

<svg version='1.1' baseProfile='full' xmlns='http://www.w3.org/2000/svg'
     viewBox='0 0 1000 1000'>

  <!-- Black Rectangle -->
  <rect width="100%" height="100%" fill="#000000" />

  <!-- Mushroom Cap -->
  <path d='M 0 550
           C 0 -175, 1000 -175, 1000 550' fill='#eb3434' />
</svg>

To complete the bottom side of the cap, I added a curve from 1000 550 back to 0 550.

<svg version='1.1' baseProfile='full' xmlns='http://www.w3.org/2000/svg'
     viewBox='0 0 1000 1000'>

  <!-- Black Rectangle -->
  <rect width="100%" height="100%" fill="#000000" />

  <!-- Mushroom Cap -->
  <path d='M 0 550
           C 0 -175, 1000 -175, 1000 550
           C 1000 1000, 0 1000, 0 550' fill='#eb3434' />
</svg>

Next, I needed to add the white dots to the cap. So I added a circle, choosing a position for the center (cx and cy) and a length for the radius (r).

<svg version='1.1' baseProfile='full' xmlns='http://www.w3.org/2000/svg'
     viewBox='0 0 1000 1000'>

  <!-- Black Rectangle -->
  <rect width="100%" height="100%" fill="#000000" />

  <!-- Mushroom Cap -->
  <path d='M 0 550
           C 0 -175, 1000 -175, 1000 550
           C 1000 1000, 0 1000, 0 550' fill='#eb3434' />

  <!-- White Dots -->
  <circle cx='500' cy='300' r='225' fill='#ffffff' />
</svg>

This next step was the hardest part. I needed to draw a white dot on the left side of the cap.

First, I temporarily added a circle where I wanted the dot to go. I started a path and matched its curve with the circle. Then I removed the circle and adjusted the curve to follow the left side of the cap. This took a bit of fiddling. I was determined to figure out how to draw this from scratch, but in the future I'll definitely invest some time in learning a graphic design tool like Inkscape.

After the left dot was ready, I mirrored it on the right.

<svg version='1.1' baseProfile='full' xmlns='http://www.w3.org/2000/svg'
     viewBox='0 0 1000 1000'>

  <!-- Black Rectangle -->
  <rect width="100%" height="100%" fill="#000000" />

  <!-- Mushroom Cap -->
  <path d='M 0 550
           C 0 -175, 1000 -175, 1000 550
           C 1000 1000, 0 1000, 0 550' fill='#eb3434' />

  <!-- White Dots -->
  <circle cx='500' cy='300' r='225' fill='#ffffff' />
  <path d='M 78.5 240
           C 210 340, 200 560, 11.5 630
           C -12 585, -6 350, 78.5 240' fill='#ffffff' />
  <path d='M 921.5 240
           C 790 340, 800 560, 988.5 630
           C 1012 585, 1006 350, 921.5 240' fill='#ffffff' />
</svg>

To draw the face, I needed one more command to use in the path: L to draw a straight line. The full path was:

  • Move to the bottom left quadrant (M 200 770)
  • Draw a curve from left to right (C 250 550, 750 550, 800 770)
  • Draw a straight line down (L 800 830)
  • Draw a curve from right to left (C 800 1050, 200 1050, 200 830)
  • Draw a line upward (L 200 770)
<svg version='1.1' baseProfile='full' xmlns='http://www.w3.org/2000/svg'
     viewBox='0 0 1000 1000'>

  <!-- Black Rectangle -->
  <rect width="100%" height="100%" fill="#000000" />

  <!-- Mushroom Cap -->
  <path d='M 0 550
           C 0 -175, 1000 -175, 1000 550
           C 1000 1000, 0 1000, 0 550' fill='#eb3434' />

  <!-- White Dots -->
  <circle cx='500' cy='300' r='225' fill='#ffffff' />
  <path d='M 78.5 240
           C 210 340, 200 560, 11.5 630
           C -12 585, -6 350, 78.5 240' fill='#ffffff' />
  <path d='M 921.5 240
           C 790 340, 800 560, 988.5 630
           C 1012 585, 1006 350, 921.5 240' fill='#ffffff' />

  <!-- Face -->
  <path d='M 200 770
           C 250 550, 750 550, 800 770
           L 800 830
           C 800 1050, 200 1050, 200 830
           L 200 770' fill='#ffd7b3' />
</svg>

Next, I added some eyes quick using rect and defining an x-axis radius (rx) to round the edges.

<svg version='1.1' baseProfile='full' xmlns='http://www.w3.org/2000/svg'
     viewBox='0 0 1000 1000'>

  <!-- Black Rectangle -->
  <rect width="100%" height="100%" fill="#000000" />

  <!-- Mushroom Cap -->
  <path d='M 0 550
           C 0 -175, 1000 -175, 1000 550
           C 1000 1000, 0 1000, 0 550' fill='#eb3434' />

  <!-- White Dots -->
  <circle cx='500' cy='300' r='225' fill='#ffffff' />
  <path d='M 78.5 240
           C 210 340, 200 560, 11.5 630
           C -12 585, -6 350, 78.5 240' fill='#ffffff' />
  <path d='M 921.5 240
           C 790 340, 800 560, 988.5 630
           C 1012 585, 1006 350, 921.5 240' fill='#ffffff' />

  <!-- Face -->
  <path d='M 200 770
           C 250 550, 750 550, 800 770
           L 800 830
           C 800 1050, 200 1050, 200 830
           L 200 770' fill='#ffd7b3' />

  <!-- Eyes -->
  <rect x='380' y='680' width='55' height='150' rx='55' fill='#000000' />
  <rect x='398' y='700' width='20' height='50' rx='20' fill='#ffffff' />
  <rect x='565' y='680' width='55' height='150' rx='55' fill='#000000' />
  <rect x='582' y='700' width='20' height='50' rx='20' fill='#ffffff' />
</svg>

At this point, I realized that the picture was squished against the left and right side. I hadn't meant to do this and had wanted a little bit of a black border there. This mistake led to a good lesson in how to adjust the viewBox to reposition its contents. I changed the starting coordinates from 0 0 to -10 -10 and added 20 to the width and height. Then I anchored the black rect at -10 -10.

To finish it off, I tossed in a few gradients to provide some depth. The final version is:

<svg version='1.1' baseProfile='full' xmlns='http://www.w3.org/2000/svg'
     viewBox='-10 -10 1020 1020'>
  <defs>
    <linearGradient id='cap' x1='0%' y1='50%' x2='0%' y2='80%'>
      <stop offset='0%' style='stop-color:#eb3434;' />
      <stop offset='100%' style='stop-color:#8b0e0e;' />
    </linearGradient>
    <linearGradient id='face' x1='0%' y1='0%' x2='0%' y2='55%'>
      <stop offset='0%' style='stop-color:#ffb066;' />
      <stop offset='100%' style='stop-color:#ffd7b3;' />
    </linearGradient>
  </defs>

  <!-- Black Rectangle -->
  <rect x='-10' y='-10' width="100%" height="100%" fill="#000000" />

  <!-- Mushroom Cap -->
  <path d='M 0 550
           C 0 -175, 1000 -175, 1000 550
           C 1000 1000, 0 1000, 0 550' fill='url(#cap)' />

  <!-- White Dots -->
  <circle cx='500' cy='300' r='225' fill='#ffffff' />
  <path d='M 78.5 240
           C 210 340, 200 560, 11.5 630
           C -12 585, -6 350, 78.5 240' fill='#ffffff' />
  <path d='M 921.5 240
           C 790 340, 800 560, 988.5 630
           C 1012 585, 1006 350, 921.5 240' fill='#ffffff' />

  <!-- Face -->
  <path d='M 200 770
           C 250 550, 750 550, 800 770
           L 800 830
           C 800 1050, 200 1050, 200 830
           L 200 770' fill='url(#face)' />

  <!-- Eyes -->
  <rect x='380' y='680' width='55' height='150' rx='55' fill='#000000' />
  <rect x='398' y='700' width='20' height='50' rx='20' fill='#ffffff' />
  <rect x='565' y='680' width='55' height='150' rx='55' fill='#000000' />
  <rect x='582' y='700' width='20' height='50' rx='20' fill='#ffffff' />
</svg>

References