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.
- Find the code related to this project on GitHub @ mhebrard/mh-logo.
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.
Why this image?
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
!
thenenter
to obtain a pre-filledindex.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>
-
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;
}
-
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>
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>
- 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)">
<!-- [...] -->
- 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.
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="[...]"/>
<!-- [...] -->
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>
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>
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>
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>
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>
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>
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)">
<!-- [...] -->
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>
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">
<!-- [...] -->
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)"/>
<!-- [...] -->
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" />
Positioning
Finally we can find the center of each letter, their dimentions, and move them to be evenly distributed on the wallpaper.
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)">
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)