DEV Community

Cover image for Branding logo in SVG
Maxime HEBRARD
Maxime HEBRARD

Posted on

Branding logo in SVG

Inspired by the logo of the Hacktoberfest 2016 seen below, I will create an image with my initials (MH) with a similar typography and decoration than the logo. Then customize the colors to produce the cover image of this post.

What is Hacktoberfest?

Hacktoberfest is a contest organized by Digital Ocean every years to promote opensource. By contributing to multiple projects hosted on GitHub or GitLab during the month of October, one can earn perks like T-shirt and stickers.

Hacktoberfest 2020 perks

Why this image?

Hacktoberfest 2016

2016 is the year I first joined the contest and I like this T-shirt very much. The fill of the letter represent lines of code and the background pictures circuit board or git branching history. That correspond to my interest. Also, H is the first letter of my family name, so If I could reproduce the H and add a M with the same look and feel, that would become a nice wallpaper for future content.

Setup

Git repo

I always start a new project by creating a repository on GitHub. You can follow along from there: mhebrard/mh-logo.

vsCode

I use Visual Studio Code as my text editor, with few extentions installed:

  • Emmet: Built-in extention that help write HTML. For example, type ! then enter to obtain a pre-filled index.html template.
  • Live Server: Serve your current project. Come with hot reload.
  • Prettier: Automatically correct indentation on save.
  • Git Graph: Easy to use interface to manage git repo from within vsCode.

Initial files

  • Hacktoberfest-2016.png: Image to replicate.
  • index.html: Display the PNG and the SVG image.
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="./style.css" />
    <title>Document</title>
  </head>
  <body>
    <img src="./Hacktoberfest-2016.png" alt="hack" class="wallpaper" />
    <img src="./MH.svg" alt="MH" class="svg" />
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode
  • style.css: Position the PNG to display the H near the top-left corner of the screen and the SVG on top of it.
/* CSS variables 
 * Define color scheme
 */
:root {
  --background: #3a3937;
  --primary: #ce873d;
  --secondary: #949494;
}
/* Remove margin
 * Set background
 */
body {
  margin: 0;
  background-color: var(--background);
}

/* Move and resize the wallpaper 
 * to place the H conveniently 
 */
.wallpaper {
  position: absolute;
  left: -340px;
  top: -40px;
  height: 700px;
}

/* Place the SVG on top of the wallpaper */
.svg {
  position: absolute;
}
Enter fullscreen mode Exit fullscreen mode
  • MH.svg: SVG in which to replicate the logo
<svg version="1.1"
  width="1920" height="1080"
  xmlns="http://www.w3.org/2000/svg"
  ><!-- Size the SVG as a HD wallpaper -->

  <!-- Show SVG contour -->
  <rect width="100%" height="100%" fill="none" stroke="red" />

</svg>
Enter fullscreen mode Exit fullscreen mode

With those files created we can trigger live server by right-click on index.html and select "Open with Live Server". That will open the web browser and display the wallpaper and the SVG live.

Redraw of H

In MH.svg, I add a group <g> that will contain the H letter. In this group, I add a <path> that will draw the H contours. I specify no fill, a stroke color and a stroke width for the path. The main attribute of the path is d that contain a string defining each anchor point of the path. This string is composed as a sequence of one letter that indicate the drawing instruction (M: move, L: line, H: horizontal, V: vertical), and X and Y coordinates. Note that is SVG, the origin (0,0) is the top-left corner of the image. Also, upper-case letters refer to absolute coordinates and lower-case letters refers to relative coordinates from the previous anchor point.

<!-- in MH.svg -->
<g id="H">
  <path fill="none" stroke="pink" stroke-width="5"
    d="M220 550 l-30 -30 v-370
    l-10 -10 -50 50 -20 -20 90 -90 50 50
    v170 l80 -80 v-70
    l-30 -30 40 -40 50 50 v340
    l10 10 50 -50 20 20 -90 90 -50 -50
    v-170 l-80 80 v120 z
    "
  />
</g>
Enter fullscreen mode Exit fullscreen mode
  • The first line in the 'd' attribute means "move -without drawing- to (220, 550), then draw a line from the current point to 30px on the left and 30px on top, then draw a vertical line of 370px on top".
  • The next line draw the top-left shape of the H -the serif.
  • The next line draw the top of the horizontal bar of the H. 
  • The next line draw the top-right shape of the H -the sans-serif.
  • The next line is a copy of the serif but with all signs inverted.
  • The next line finishes the shape and closes the path.

Creation of M

Now let's move the H away and draw an M.

<g id="M" transform="translate(0, 0)">
  <path fill="none" stroke="pink" stroke-width="5"
    d="M220 550 l-30 -30 v-370
    l-10 -10 -50 50 -20 -20 90 -90 50 50
    l80 80 60 -60
    l-30 -30 40 -40 50 50 v340
    l10 10 50 -50 20 20 -90 90 -50 -50
    v-170 -60 l-60 60 -80 -80 
    v280 z
    "
  />
</g>

<g id="H" transform="translate(400, 0)">
<!-- [...] -->
Enter fullscreen mode Exit fullscreen mode
  • First two lines are a copy of the H that draw the start and the top left serif.
  • Next line continue the serif until it "hit" the right bar of the H, then move up to draw the top of the M. The line stop when reaching the Y coordinate where the sans-serif shape start.
  • Next 2 lines are a copy of the sans-serif and the botom-right serif of the H.
  • Next line ensure that the M shape has same width as the horizontal bar of the H.
  • Last line close the path.

At this point we have our two letters MH.
MH contours

Fill

Let's add to the SVG the code representation as fill of the main letters. First I overlap the M and the H and give it some fill to highlight which part of the image I need to cover with code. I also create a new group that will contain the code representation.

<g id="M" transform="translate(0, 0)">
  <path fill="rgba(255, 255, 255, 0.3)" stroke="pink" stroke-width="5" d="[...]"/>
<!-- [...] -->

<g id="H" transform="translate(0, 0)">
  <path fill="rgba(255, 255, 255, 0.3)" stroke="pink" stroke-width="5" d="[...]" />
<!-- [...] -->

<g id="Fill" transform="translate(0, 0)">
  <path fill="none" stroke="lime" stroke-width="5" d="[...]"/>
<!-- [...] -->
Enter fullscreen mode Exit fullscreen mode

The fill itself is representing 2 columns of text, starting at 190px and 330px on x axis. It is composed of horizontal lines of random length with a constant spacing of 10px. Note that the tabulation are 20px. Each line is separated by 10px, with few blank lines. Path lines are rounded using stroke-linecap attribute.

<g id="Fill" transform="translate(0, 0)">
    <path fill="none" stroke="lime" stroke-width="5"  stroke-linecap="round"
      d="M120 90 h20 m10 0 h30 m10 0 h60 M330 90 h50
      M120 100 h20 m10 0 h60 M330 100 h120
      M120 110 h20 m10 0 h40 m10 0 h30 M330 110 h30 m10 0 h60
      M120 120 h20 m10 0 h40 m10 0 h50 M330 120 h30 m10 0 h30 m10 0 h30
      M120 130 h20 m10 0 h10 m10 0 h20
      M120 150 h10 m10 0 h70 m10 0 h40 M330 150 h10
      M120 160 h10 m10 0 h30 m10 0 h30 M330 160 m20 0 h20 m10 0 h30 m10 0 h60
      M190 170 m20 0 h20 m10 0 h20 m10 0 h20 M330 170 m20 0 h10 m10 0 h30 m10 0 h10 m10 0 h30
      M190 180 m20 0 h40 m10 0 h40 M330 180 m20 0 h30 m10 0 h30 m10 0 h20
      M190 190 m20 0 h10
      M190 200 m20 0 h10
      M190 210 m20 0 h20 m10 0 h20 M330 210 h10
      M190 220 h10 M330 220 m20 0 h10 m10 0 h20
      M190 230 h10 m10 0 h60 m10 0 h30 M330 230 m20 0 h10 m10 0 h30 m10 0 h10 m10 0 h20
      M190 240 h100
      M190 260 h10 M330 260 h10 m10 0 h100
      M190 270 m20 0 h20 m10 0 h30 M330 270 h30 m10 0 h30 m10 0 h50
      M190 280 m20 0 h10 m10 0 h20 m10 0 h20 m10 0 h20
      M190 290 m20 0 h10 m10 0 h30 m10 0 h30
      M190 300 m20 0 h10 m10 0 h30 m10 0 h30 M330 300 h10
      M190 310 m20 0 h10 m10 0 h30 m10 0 h30 M330 310 m20 0 h20 m10 0 h40
      M190 320 m20 0 h10 m10 0 h20 m10 0 h50 M330 320 m20 0 h20 m10 0 h40
      M190 330 h10 m10 0 h20 M330 330 m20 0 h30 m10 0 h30 m10 0 h40
      M190 350 h20 m10 0 h40 m10 0 h10 m10 0 h20
      M190 360 h30 m10 0 h10 m10 0 h50 M330 360 h20 m10 0 h30 m10 0 h60
      M190 370 h10 m10 0 h40 M330 370 h10 m10 0 h40 m10 0 h20
      M190 390 h10
      M190 400 m20 0 h20 m10 0 h30 M330 400 h10
      M190 410 m20 0 h10 m10 0 h20 M330 410 m20 0 h20 m10 0 h30
      M190 420 m20 0 h10 m10 0 h20 M330 420 m20 0 h20 m10 0 h30
      M190 430 m20 0 h20 m10 0 h20 M330 430 m20 0 h20 m10 0 h30
      M190 440 h10 M330 440 m20 0 h40 m10 0 h30 m10 0 h20
      M190 460 h10
      M190 470 m20 0 h30 M330 470 h10 m10 0 h60 m10 0 h10 m10 0 h20 m10 0 h30
      M190 480 m20 0 h10 m10 0 h20 M330 480 h20 m10 0 h50 m10 0 h20 m10 0 h60
      M190 490 m20 0 h20 m10 0 h20 M330 490 h10 m10 0 h20 m10 0 h30 m10 0 h40
      M190 500 m20 0 h10 m10 0 h30 M330 500 h30 m10 0 h20 m10 0 h40 m10 0 h20
      M190 510 m20 0 h30 m10 0 h20
      M190 520 h10
      M190 530 M330 530 m30 0 h100
      M190 540 h30
      "
    />
  </g> 
Enter fullscreen mode Exit fullscreen mode

Now we want the fill to appears only within the letters. For that we encapsulate the letters paths in clipPath objects and assign an id to each clipPath. The clipPaths are move into a defs section. Like the header for HTML, the defs of SVG define objects without rendering them.

<defs>
  <clipPath id="clipM">
    <path id="shapeM" fill="none" stroke="#ce873d" stroke-width="5" d="[...]" />
  </clipPath>

  <clipPath id="clipH">
    <path id="shapeH" fill="none" stroke="#ce873d" stroke-width="5" d="[...]" />
  </clipPath>

  <g id="Fill">
    <path fill="none" stroke="#949494" stroke-width="5" d="[...]" />
  </g>

</defs>
Enter fullscreen mode Exit fullscreen mode

Then in the body of the SVG (anything outside the defs), we can specify what to render and use the objects defined in the defs section. Note that we first use the fill object that is clipped using the clipPath containing the letter contour. Then we use the letter contour itself that will be render on top of the fill.

<g id="M">
  <use href="#Fill" clip-path="url(#clipM)" />
  <use href="#shapeM"/>
</g>

<g id="H" transform="translate(400, 0)">
  <use href="#Fill" clip-path="url(#clipH)" />
  <use href="#shapeH"/>
</g>
Enter fullscreen mode Exit fullscreen mode

MH with fill

Branches

Time to focus on the mother board branches. Similar as the fill, I define objects in the defs section that I can reuse for both letters. Starting with re-draw of the base image and more precisely the left part of the branches. The group is composed of a unique path that draw the grey banches and a sub-group for the orange circles

<defs>
<!-- [...] -->
  <g id="branchLeft">
    <path fill="none" stroke="#949494" stroke-width="3" stroke-linecap="round" 
      d="
      M170 170 v330
      M170 170 l-140 140
      M170 170 m-40 40 h-30 l-30 30
      M170 170 m-80 80 v30 l-30 30
      M170 170 v80 l-30 30 v180
      M170 170 v80 l-30 30 v40 l-60 60
      M170 170 v80 l-30 30 v100 l-40 40 v30
      " />
    <g fill="#3a3937" stroke="#ce873d" stroke-width="3">
      <circle cx="170" cy="500" r="4"/>
      <circle cx="30" cy="310" r="4"/>
      <circle cx="70" cy="240" r="4"/>
      <circle cx="60" cy="310" r="4"/>
      <circle cx="140" cy="460" r="4"/>
      <circle cx="80" cy="380" r="4"/>
      <circle cx="100" cy="450" r="4"/>
    </g>
  </g>
</defs>
<!-- [...] -->
<g id="H" transform="translate(0, 0)">
  <use href="#branchLeft" />
  <use href="#Fill" clip-path="url(#clipH)" />
  <use href="#shapeH"/>
</g>
Enter fullscreen mode Exit fullscreen mode

The branches on the right are a copy of the left object with the path coordinates inverted. Note that we have to re-position each circle as they used absolute coordinate

<defs>
<!-- [...] -->
  <g id="branchRight">
    <path fill="none" stroke="#949494" stroke-width="3" stroke-linecap="round" 
      d="
      M410 440 v-360
      M410 440 v-320 l-50 -50
      M410 440 l140 -140
      M410 440 m40 -40 h30 l30 -30
      M410 440 m80 -80 v-30 l30 -30
      M410 440 v-80 l30 -30 v-180
      M410 440 v-80 l30 -30 v-40 l60 -60
      M410 440 v-80 l30 -30 v-100 l40 -40 v-30
      " />
    <g fill="#3a3937" stroke="#ce873d" stroke-width="3">
      <circle cx="360" cy="70" r="4"/>
      <circle cx="410" cy="80" r="4"/>
      <circle cx="440" cy="150" r="4"/>
      <circle cx="480" cy="160" r="4"/>
      <circle cx="500" cy="230" r="4"/>
      <circle cx="520" cy="300" r="4"/>
      <circle cx="550" cy="300" r="4"/>
      <circle cx="510" cy="370" r="4"/>
    </g>
  </g>
</defs>
<!-- [...] -->
<g id="H" transform="translate(0, 0)">
  <use href="#branchLeft" />
  <use href="#branchRight" />
  <use href="#Fill" clip-path="url(#clipH)" />
  <use href="#shapeH"/>
</g>
Enter fullscreen mode Exit fullscreen mode

Those two objects branchLeft and branchRight will be reused with the M, but first let's create another object for the top and bottom branches of the H.

<defs>
<!-- [...] -->
  <g id="branchH">
    <path fill="none" stroke="#949494" stroke-width="3" stroke-linecap="round" 
      d="
      M270 250 v-190
      M270 250 v-140 l-40 -40
      M270 250 l30 -30
      M310 370 v190
      M310 370 v140 l40 40
      M310 370 l-30 30
      " />
    <g fill="#3a3937" stroke="#ce873d" stroke-width="3">
      <circle cx="270" cy="60" r="4"/>
      <circle cx="230" cy="70" r="4"/>
      <circle cx="300" cy="220" r="4"/>
      <circle cx="310" cy="560" r="4"/>
      <circle cx="350" cy="550" r="4"/>
      <circle cx="280" cy="400" r="4"/>
    </g>
  </g>
</defs>
<!-- [...] -->
<g id="H" transform="translate(0, 0)">
  <use href="#branchLeft" />
  <use href="#branchH" />
  <use href="#branchRight" />
  <use href="#Fill" clip-path="url(#clipH)" />
  <use href="#shapeH"/>
</g>
Enter fullscreen mode Exit fullscreen mode

Now let's move the H aside and focus on the M. We can reuse branchLeft as is. branchRight need to be move to the right to fit the different letter width.

<g id="M" transform="translate(0, 0)">
  <use href="#branchLeft" />
  <use href="#branchRight" transform="translate(60,0)"/>
  <use href="#Fill" clip-path="url(#clipM)" />
  <use href="#shapeM"/>
</g> 

<g id="H" transform="translate(700, 0)">
<!-- [...] -->
Enter fullscreen mode Exit fullscreen mode

Then create a new object to draw some branches at the top and bottom of the M.

<defs>
<!--[...]-->
  <g id="branchM">
    <path fill="none" stroke="#949494" stroke-width="3" stroke-linecap="round" 
      d="
      M330 180 v-40
      M330 180 l-100 -100
      M370 310 v240
      M370 310 l-30 30
      M370 310 v40 l-60 60
      M370 310 v40 l-30 30 v30 l-60 60
      M370 310 v120 l-70 70
      M370 310 v120 l-30 30 v60
      M370 310 v180 l40 40
      " />
    <g fill="#3a3937" stroke="#ce873d" stroke-width="3">
      <circle cx="330" cy="140" r="4"/>
      <circle cx="230" cy="80" r="4"/>
      <circle cx="370" cy="550" r="4"/>
      <circle cx="340" cy="340" r="4"/>
      <circle cx="310" cy="410" r="4"/>
      <circle cx="280" cy="470" r="4"/>
      <circle cx="300" cy="500" r="4"/>
      <circle cx="340" cy="520" r="4"/>
      <circle cx="410" cy="530" r="4"/>    
    </g>
  </g>
</defs>
<!-- [...] -->
<g id="M" transform="translate(0, 0)">
  <use href="#branchLeft" />
  <use href="#branchM" />
  <use href="#branchRight" transform="translate(60,0)"/>
  <use href="#Fill" clip-path="url(#clipM)" />
  <use href="#shapeM"/>
</g>
Enter fullscreen mode Exit fullscreen mode

MH with fill and background

Style

I am a big fan of the movie Tron (both original and legacy), so let's change the colors of the image and add some glow !

The image is composed of two colors that are currently hard coded in each SVG object. To control the fill and stroke of an object, we can use the keyword currentColor in place of the color code itself. That will refer to the color attribute of the current style. In order to define two colors, we need to use a dedicated class for the accent color.
A style section can be added directly in the SVG to define CSS statements.

<style>
  svg {
    color: #949494;
  }
  .accent {
    color: #ce873d;
  }
</style>

<defs>
  <clipPath id="clipM">
    <path id="shapeM" class="accent" fill="none" stroke="currentColor" stroke-width="5" d="[...]"/>
  </clipPath>

  <clipPath id="clipH">
    <path id="shapeH" class="accent" fill="none" stroke="currentColor" stroke-width="5" d="[...]"/>
  </clipPath>

  <g id="Fill">
    <path fill="none" stroke="currentColor" stroke-width="5" stroke-linecap="round" d="[...]" />
  </g>

  <g id="branchLeft">
    <path fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" d="[...]" />
    <g class="accent" fill="currentColor" stroke="currentColor" stroke-width="3">
<!-- [...] -->

  <g id="branchRight">
    <path fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" d="[...]" />
    <g class="accent" fill="currentColor" stroke="currentColor" stroke-width="3">
<!-- [...] -->

  <g id="branchH">
    <path fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" d="[...]" />
    <g class="accent" fill="currentColor" stroke="currentColor" stroke-width="3">
<!-- [...] -->

  <g id="branchM">
    <path fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" d="[...]" />
    <g class="accent" fill="currentColor" stroke="currentColor" stroke-width="3">
<!-- [...] -->
Enter fullscreen mode Exit fullscreen mode

Next, let's add a glow effect on the accent color objects. For that we define a filter object that produce the glow and we assign it to each object as we did with the clipPath.

<defs>
<!-- [...] -->
  <g id="branchLeft">
    <!-- [...] -->
    <g class="accent" fill="currentColor" stroke="currentColor" stroke-width="3" filter="url(#accent-glow)">
<!-- [...] -->

  <g id="branchRight">
    <!-- [...] -->
    <g class="accent" fill="currentColor" stroke="currentColor" stroke-width="3" filter="url(#accent-glow)">
<!-- [...] -->

  <g id="branchH">
    <!-- [...] -->
    <g class="accent" fill="currentColor" stroke="currentColor" stroke-width="3" filter="url(#accent-glow)">
<!-- [...] -->

  <g id="branchM">
    <!-- [...] -->
    <g class="accent" fill="currentColor" stroke="currentColor" stroke-width="3" filter="url(#accent-glow)">
<!-- [...] -->

  <filter id="accent-glow" class="accent" x="-50%" y="-50%" width="200%" height="200%">
    <feFlood result="flood" flood-color="currentColor" flood-opacity="1"></feFlood>
    <feComposite in="flood" result="mask" in2="SourceGraphic" operator="in"></feComposite>
    <feMorphology in="mask" result="dilated" operator="dilate" radius="3"></feMorphology>
    <feGaussianBlur in="dilated" result="blurred" stdDeviation="6"></feGaussianBlur>
    <feMerge>
      <feMergeNode in="blurred"></feMergeNode>
      <feMergeNode in="SourceGraphic"></feMergeNode>
    </feMerge>
  </filter>
</defs>
<!-- [...] -->

<g id="M" transform="translate(0, 0)">
  <!-- [...] -->
  <use href="#shapeM" filter="url(#accent-glow)"/>
<!-- [...] -->

<g id="H" transform="translate(700, 0)">
  <!-- [...] -->
  <use href="#shapeH" filter="url(#accent-glow)"/>
<!-- [...] -->
Enter fullscreen mode Exit fullscreen mode

Now we can easily change the colors of the SVG to be a variant of cyan. Note that I also turn the background color to black using the rectangle that take 100% of the SVG space.

<style>
  svg {
    color: #ccffff;
  }
  .accent {
    color: #55ffff;
  }
</style>
<!-- [...] -->
<rect width="100%" height="100%" fill="#000" stroke="red" />
Enter fullscreen mode Exit fullscreen mode

Tron style MH

Positioning

Finally we can find the center of each letter, their dimentions, and move them to be evenly distributed on the wallpaper.

Traces

In the image above, the pink trace identify the center of each letter and draw a circle of 600px diameter around them. The red trace heighlight the center of the wallpaper. The green trace notify even spacing to place the two items of 600x600 on the wallpaper.

The final translation of the letter is as below:

<g id="M" transform="translate(220,230)">
<!-- [...]--->

<g id="H" transform="translate(1090, 230)">
Enter fullscreen mode Exit fullscreen mode

Save

Last step is to remove the traces, and save the image as PNG. We can do that using the web browser, right-click on the image and select "Copy image", then paste the result in your favorite image editor (Photoshop...) and save as PNG.

Top comments (0)