[Part 2] Building mountains: Building the first version
On the first part of this series, we learnt how we could create polygons using CSS’s clip-path. Now, on the second
part of this series we will explore how we can leverage clip-path to create polygons that resemble mountains
on a retro game.
Visualizing mountains
On a surface level, mountains can be described as
a large natural elevation of the earth’s surface rising abruptly from the surrounding level; a large steep hill.
— Oxford Languages
The idea is to use an algorithm that builds a shape step by step from left to right. These steps are then used
as input for clip-path, creating the visual effect of a mountain.
Now that we have broken down the first step we can start to manually code a polygon that resembles this very shape:
.polygon {
clip-path: polygon(
0% 100%,
0% 90%,
10% 90%,
10% 80%,
20% 80%,
20% 70%,
30% 70%,
30% 60%,
40% 60%,
40% 50%,
50% 50%,
50% 40%,
60% 40%,
60% 30%,
70% 30%,
70% 20%,
80% 20%,
80% 10%,
90% 10%,
90% 0%,
100% 0%,
100% 100%
);
}
Now it’s a matter of adjusting our percentages to create our very first mountain looking like shape:
Adjusting how many “pixels” are in a polygon
The shape above gives an impression of a mountain but looks more like steps than a mountain. The main reason for that is the “pixel density” we are packing in this polygon. The polygon above has 5 “pixels” horizontally. In order to make it look more like a mountain we need to be able to pack more “pixels” in it horizontally.
What we have done is essentially add more vertices to our polygon:
.polygon {
clip-path: polygon(0% 100%, 0% 90%, 4% 90%, 4% 86%, 8% 86%, 8% 82%, 12% 82%, 12% 78%, 16% 78%, 16% 74%, 20% 74%, 20% 70%, 24% 70%, 24% 66%, 28% 66%, 28% 62%, 32% 62%, 32% 58%, 36% 58%, 36% 54%, 40% 54%, 40% 50%, 44% 50%, 44% 46%, 48% 46%, 48% 42%, 52% 42%, 52% 46%, 56% 46%, 56% 50%, 60% 50%, 60% 54%, 64% 54%, 64% 58%, 68% 58%, 68% 62%, 72% 62%, 72% 66%, 76% 66%, 76% 70%, 80% 70%, 80% 74%, 84% 74%, 84% 78%, 88% 78%, 88% 82%, 92% 82%, 92% 86%, 96% 86%, 96% 90%, 100% 90%, 100% 94%, 100% 100%);
}
but you will quickly notice that this might be tedious and very prone to error to create this manually. Since this is a deterministic path we can create an algorithm to create such “steps”:
function generateZigZagPolygon(
elementWidth: number,
elementHeight: number,
pixelSize = 10,
): string {
const points: string[] = [];
const midX = elementWidth / 2;
let y = elementHeight;
points.push("0% 100%");
points.push(`0% ${(y / elementHeight) * 100}%`);
for (let x = 0; x < elementWidth; x += pixelSize) {
const nextX = x + pixelSize;
const yPercent = (y / elementHeight) * 100;
const xPercent = (nextX / elementWidth) * 100;
points.push(`${xPercent}% ${yPercent}%`);
if (nextX <= midX) {
y -= pixelSize;
} else {
y += pixelSize;
}
points.push(`${xPercent}% ${(y / elementHeight) * 100}%`);
}
points.push("100% 100%");
return `polygon(${points.join(", ")})`;
}
In this first version, we have understood what we understand by “mountains” and we could recreate a retro look mountain
using clip-path. On the first step we have created a simple version where we essentially create a “step” looking like
shape going from left to right. Then, we adapted this shape to create what it looks like a retro mountain. Then, we take
this concept and create an algorithm to generate the mountains dynamically based on the container’s width, height and desired
pixel size.
Next step will be to create a dynamically generated terrain with multiple mountains on it. You will notice that the terrain will look almost the same and have unnatural look to it, we will then introduce the concept of a random flatness to the terrain.