This site is being designed in public. Please excuse placeholder content, broken design, etc.!

Tom Callahan’s Blog

In my first test I just used varying border-radius values to generate pseudo-random blob shapes for the backgrounds of my "cards":

&:nth-child(3n) .inner {
border-radius: 50% 25% 75% 33%;
background-color: $color-yellow;
}
&:nth-child(3n + 1) .inner {
border-radius: 25% 75% 50% 33%;
background-color: $color-red;
}
&:nth-child(3n + 2) .inner {
border-radius: 75% 50% 25% 33%;
background-color: $color-blue;
}

That kind of worked, but it doesn't create very organic shapes, leaves some sharp corners, and requires a lot of code to make enough shapes to feel fully random.

So I read up on the SVG format itself (specifically the path element) and am going to use it to draw truly random shapes directly in the SVG using React.

I started with a diamond to get the basics of shape drawing down:

<svg className={styles.corners} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" preserveAspectRatio="none" > <path d="M 0,50 L 50,0 L 100,50 L 50,100 z" /></svg>

The "corners" class positions the SVG absolutely inside the containiner <li>, with top and left set to zero and width and height set to 100%. The "preserveAspectRatio" attribute causes the SVG to scale like an image so that it stretches to fit the shape. The "viewBox" uses values from 0 to 100 so that the math is easy. Then it moves the pointer and draws four lines to the midpoint of each side, making a diamond:

Next, I changes the straight lines to curves, with the control points in the corners. Using the "C" operator for the first curve, then S for the remainders to avoid having to specify the first control point repeatedly:

<svg className={styles.corners} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" preserveAspectRatio="none" ><path d="M 0,50 C 0 0, 0 0, 50 0 S 100 0, 100 50 S 100 100, 50 100 S 0 100, 0 50" /></svg>

This gives you rectangles with rounded corners, kind of like a squircle:

Finally, by offsetting the four midpoints a little I can introduce some randomness into it. First I set a random value for each point by generating a random number from 0 to 20, then subtracting 10 to shift that to -10 to +10, then add 50 to bring it to the center of the side length for a final number between 40 and 60.

const rp1 = Math.random() * 20 - 10 + 50;

Yes it could be written more concisely but since this only gets executed once per component I'm more concerned with being able to follow my own logic later, at least for now. Do that four times then convert the "d" attribute in the SVG to a reactive value and use a template literal to insert the random values whereever there's a "50" in the original code:

<path d={`M 0,${rp1} C 0 0, 0 0, ${rp2} 0 S 100 0, 100 ${rp3} S 100 100, ${rp4} 100 S 0 100, 0 ${rp1}`} />

Later, I'll refine this by also randomizing the control points, and it will need a lot of tweaking until it feels right, but this is the proof of concept. The final result for now is:

One note, I had to set overflow: visible on the SVG since some of those curves leave the original viewport, probably due to where the random points ended up. Pulling the control points in some will help avoid that but I'll leave that CSS property in place just in case.

Socials