Skip to content

Instantly share code, notes, and snippets.

@kevinkhill
Last active December 12, 2025 04:55
Show Gist options
  • Select an option

  • Save kevinkhill/2b85cbe86fad153ba0788f8eaae5e81d to your computer and use it in GitHub Desktop.

Select an option

Save kevinkhill/2b85cbe86fad153ba0788f8eaae5e81d to your computer and use it in GitHub Desktop.
Giants Causeway Generator
// Number of rows in the tessellation
rows = 20;
// Number of columns in the tessellation
cols = 100;
// Width of each hexagonal pillar (circumradius)
hex_size = 4;
// Minimum height of each pillar
height_min = 2;
// Maximum height of each pillar
height_max = 20;
// Desired number of sine wave periods across the grid width
num_periods = 1.5;
// Randomness to add to the height of the pillars
jitter_factor = 5;
// This determines where along the wave the heights start
angle_tweak = -45;
// Dynamically calculated amplitude
wave_amplitude = (height_max - height_min); // Full range of heights
// Function to calculate pillar height based on a sine wave (horizontal wave)
function sine_height(col) = //
let( //
angle = col * PI * num_periods, // Map column to sine wave angle
sine_value = sin(angle + angle_tweak), // Sine value (-1 to 1)
scaled_sine = (sine_value * wave_amplitude) // Scale sine to desired amplitude
) //
height_min
+ wave_amplitude + scaled_sine; // Offset to ensure range is height_min to height_max
// Function to calculate row-based height factor (linear ramp from max to min)
function row_factor(row) = 1 - row / (rows - 1);
// Module for creating a hexagonal pillar
module hexagon_pillar(width = 5, height = 3)
{
linear_extrude(height)
{
polygon(points = [[width * cos(0), width * sin(0)], //
[width * cos(60), width * sin(60)], //
[width * cos(120), width * sin(120)], //
[width * cos(180), width * sin(180)], //
[width * cos(240), width * sin(240)], //
[width * cos(300), width * sin(300)]]);
}
}
// Generate the tessellation
for (row = [0:rows - 1])
{
for (col = [0:cols - 1])
{
// Calculate the x and y offsets for the hexagonal grid
x_offset = col * 1.5 * hex_size; // Horizontal distance
y_offset = row * sqrt(3) * hex_size + (col % 2) * (sqrt(3) * hex_size / 2); // Staggered rows
// Calculate the combined height based on sine function and row factor
height = sine_height(col) * row_factor(rows - row);
// Add jitter for randomness
jitter = rands(1, jitter_factor, 1)[0];
translate([ x_offset, y_offset, 0 ])
{
hexagon_pillar(width = hex_size, height = (height_min + height + jitter));
}
}
}
@K-Francis-H
Copy link

Really cool! But right now the jitter_factor var is being ignored. Change line 61 to jitter = rands(0, jitter_factor, 1)[0]; to incorporate it. Would be cool to try and make it use any 3D surface function instead of only a sin wave of linear increasing amplitude across the y dimension. Thanks for sharing!

@kevinkhill
Copy link
Author

Good catch, thank you :)

@kevinkhill
Copy link
Author

Would be cool to try and make it use any 3D surface function instead of only a sin wave of linear increasing amplitude across the y dimension.

YES! ...... how?

@mjparme
Copy link

mjparme commented Dec 25, 2024

Just want to point out that you can make a hexagon like this:

circle(d = hex_size, $fn = 6);

@kevinkhill
Copy link
Author

Someone on reddit shared this with me too. I had no idea, and that's cool.

@Wol
Copy link

Wol commented Mar 31, 2025

Is the sin call takes in degrees, rather than radians, what's the point of multiplying by PI on line 24?

Changing it to be angle = col / cols * num_periods and then doing sin(360 * angle + angle_tweak would mean you get definite control over the number of periods over the whole thing.

@kevinkhill
Copy link
Author

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment