Skip to content

Instantly share code, notes, and snippets.

@theosanderson
Created February 12, 2026 19:43
Show Gist options
  • Select an option

  • Save theosanderson/3e7f81c22079954e0a6c3962a6575513 to your computer and use it in GitHub Desktop.

Select an option

Save theosanderson/3e7f81c22079954e0a6c3962a6575513 to your computer and use it in GitHub Desktop.
// ==========================================
// AFRICAN WATERING HOLE DIORAMA
// Features: Elephant, Hippo, Crocodile, and Scenery
// Best viewed with OpenSCAD Preview (F5) to see transparency and colors!
// ==========================================
$fn = $preview ? 40 : 80; // Adaptive resolution for smooth rendering
// Render the assembled scene
scene();
// ==========================================
// MAIN SCENE ASSEMBLY
// ==========================================
module scene() {
// 1. Terrain and Water
landscape();
// 2. Elephant (Approaching from the grassy bank, trunk dipping in)
translate([-35, 10, 0.5]) rotate([0, 0, -30]) scale(0.8) elephant();
// 3. Hippo (Wading deep in the pond, looking up)
translate([15, -15, -8]) rotate([0, -10, 130]) scale(0.7) hippo();
// Tiny oxpecker bird riding the hippo
translate([15, -15, -8]) rotate([0, -10, 130]) scale(0.7) translate([-2, 0, 16.5]) bird();
// 4. Crocodile (Basking on the shore, sliding its snout into the water)
translate([40, 20, 0.5]) rotate([0, 10, -135]) scale(0.7) crocodile();
// 5. Environment Flora & Rocks
// Acacia Trees
translate([-45, -35, 0.5]) acacia();
translate([-5, 50, 0.5]) scale(0.8) acacia();
// Scattered Rock Clusters
translate([-20, 30, 0.5]) rock_cluster();
translate([45, -10, 0.5]) rotate([0, 0, 45]) rock_cluster();
translate([-20, -25, 0.5]) scale(0.6) rock_cluster();
// Reeds growing on the water's edge
translate([35, -30, -1.5]) reeds();
translate([-10, -35, -1.5]) reeds();
translate([30, 20, -1.5]) reeds();
// Lilypads floating on the surface
translate([15, 5, -0.4]) rotate([0, 0, 30]) lilypad();
translate([5, -20, -0.4]) rotate([0, 0, 110]) lilypad();
translate([25, -20, -0.4]) rotate([0, 0, 210]) lilypad();
translate([8, 2, -0.4]) scale(0.7) rotate([0, 0, 50]) lilypad();
// Grass Tufts
translate([30, 25, 0.5]) grass_clump();
translate([35, 15, 0.5]) grass_clump();
translate([-15, -30, 0.5]) grass_clump();
translate([-25, -20, 0.5]) grass_clump();
translate([15, 40, 0.5]) grass_clump();
translate([-5, 45, 0.5]) grass_clump();
// 6. Dynamic Water Ripples
// Radiating from the submerged hippo
translate([15, -15, -0.45]) { ripple(10); ripple(14); }
// Radiating exactly where the elephant's trunk touches the surface
translate([-5.9, -6.8, -0.45]) { ripple(3); ripple(5); }
}
// ==========================================
// ENVIRONMENT & SCENERY MODULES
// ==========================================
module landscape() {
// Dirt Sub-terrain Base
color("#8B4513") // SaddleBrown
difference() {
translate([0, 0, -15]) cylinder(r=75, h=15, center=false);
// Deep sloped basin cut out for the watering hole
translate([10, -10, -10]) cylinder(r1=20, r2=40, h=10.1, center=false);
}
// Overgrown Grass Top Layer
color("#6B8E23") // OliveDrab
difference() {
translate([0, 0, 0]) cylinder(r=75, h=0.5, center=false);
// Hole outlining the dirt banks perfectly
translate([10, -10, -0.1]) cylinder(r1=40, r2=41.5, h=0.7, center=false);
}
// Semi-Transparent Water Volume
color([0.1, 0.5, 0.8, 0.75])
translate([10, -10, -9.5]) cylinder(r1=21, r2=38.5, h=9, center=false);
}
module acacia() {
// Trunk and Branches
color("#5C4033") {
cylinder(r1=3, r2=1.5, h=35);
translate([0, 0, 18]) rotate([0, 40, 45]) cylinder(r1=1.5, r2=0.8, h=15);
translate([0, 0, 22]) rotate([0, 50, -60]) cylinder(r1=1.2, r2=0.5, h=12);
translate([0, 0, 28]) rotate([0, 30, 180]) cylinder(r1=1, r2=0.4, h=10);
translate([0, 0, 12]) rotate([0, 60, 120]) cylinder(r1=1.8, r2=0.6, h=14);
}
// Wide African Canopy
color("#228B22") {
translate([0, 0, 35]) scale([2.5, 2.5, 0.5]) sphere(r=8);
translate([9, 9, 28]) scale([2, 2, 0.5]) sphere(r=6);
translate([-8, -6, 28]) scale([2, 2, 0.5]) sphere(r=5);
translate([-2, 8, 33]) scale([2, 2, 0.5]) sphere(r=4);
translate([-3, 10, 20]) scale([2, 2, 0.5]) sphere(r=4);
}
}
module rock_cluster() {
color("#708090") { // SlateGray
scale([1.5, 1, 1]) sphere(r=4);
translate([4, 2, 0]) scale([1, 1.2, 0.8]) sphere(r=3);
translate([-3, 4, -1]) scale([1.2, 1, 1]) sphere(r=2.5);
}
}
module reeds() {
color("#556B2F") {
for(i=[0:8]) rotate([0, 5+i*2, i*45]) cylinder(r=0.4, h=12+(i%4)*2);
}
}
module lilypad() {
color("#32CD32") // Pad
difference() {
cylinder(r=2.5, h=0.2);
translate([0, 0, -0.1]) cube([2.5, 0.8, 0.4]);
}
color("#FF69B4") // Blossom
translate([0, 0, 0.2]) {
for(a=[0:45:315])
rotate([0, 0, a]) translate([0.5, 0, 0]) scale([1, 0.5, 0.5]) sphere(r=0.8);
}
}
module grass_clump() {
color("#4F7942") {
for(i=[0:6]) rotate([0, 15, i*60]) cylinder(r1=0.3, r2=0, h=3+i%2);
}
}
module ripple(r) {
color([0.8, 0.9, 1.0, 0.6])
difference() {
cylinder(r=r, h=0.1);
translate([0, 0, -0.1]) cylinder(r=r-0.4, h=0.3);
}
}
// ==========================================
// ANIMAL MODULES
// ==========================================
module elephant() {
color("#708090") { // Gray
// Torso
hull() {
translate([-10, 0, 16]) sphere(r=11);
translate([10, 0, 18]) sphere(r=13);
}
// Head
translate([19, 0, 19]) sphere(r=9);
// Dynamic Sweeping Trunk (curved using sine waves + alternating radius for wrinkles)
for(i=[0:20]) {
translate([26 + i*0.8, 0, 17 - i*0.9 + sin(i*9)*2.5])
sphere(r=3 - i*0.1 + (i%2)*0.2);
}
// Massive Flapping Ears
translate([17, 8, 20]) rotate([10, 15, 30]) scale([0.3, 1.5, 1.5]) sphere(r=8);
translate([17, -8, 20]) rotate([10, 15, -30]) scale([0.3, 1.5, 1.5]) sphere(r=8);
// Sturdy Legs
translate([10, 7, 0]) cylinder(r1=3.5, r2=4, h=16);
translate([10, -7, 0]) cylinder(r1=3.5, r2=4, h=16);
translate([-8, 7, 0]) cylinder(r1=3.5, r2=4, h=16);
translate([-8, -7, 0]) cylinder(r1=3.5, r2=4, h=16);
// Tail
for(i=[0:12]) translate([-18 - i*0.6, 0, 16 - i*1.2]) sphere(r=1.2 - i*0.08);
}
// Toes
color("#E0E0E0") {
for(dx=[10, -8]) {
for(dy=[7, -7]) {
translate([dx+3.2, dy, 0.5]) sphere(r=0.8);
translate([dx+2.2, dy+2.2, 0.5]) sphere(r=0.8);
translate([dx+2.2, dy-2.2, 0.5]) sphere(r=0.8);
}
}
}
// Curved Ivory Tusks
color("#FFFFF0") {
for(i=[0:18]) {
translate([24 + i*1.0, 5 - i*0.1, 14 + sin(i*7)*2.5]) sphere(r=1.2 - i*0.06);
translate([24 + i*1.0, -5 + i*0.1, 14 + sin(i*7)*2.5]) sphere(r=1.2 - i*0.06);
}
}
// Eyes
color("black") {
translate([24, 6, 23]) sphere(r=0.8);
translate([24, -6, 23]) sphere(r=0.8);
}
}
module hippo() {
color("#606060") {
// Thick Barrel Body
hull() {
translate([-7, 0, 6]) sphere(r=9);
translate([7, 0, 7]) sphere(r=10);
}
// Base of Head
hull() {
translate([13, 0, 11]) sphere(r=7);
translate([16, 0, 10]) sphere(r=6);
}
// Very Wide Snout with Horizontal Mouth Slit
difference() {
hull() {
translate([18, 0, 9]) sphere(r=5);
translate([22, 0, 8]) scale([1, 1.6, 0.8]) sphere(r=5.5);
}
translate([24, 0, 7]) rotate([0, 10, 0]) cube([10, 15, 0.8], center=true);
}
// Tiny Submerged Ears
translate([11, 4.5, 16.5]) sphere(r=1.2);
translate([11, -4.5, 16.5]) sphere(r=1.2);
// Short Stout Legs
translate([6, 6, -3]) cylinder(r=3, h=10);
translate([6, -6, -3]) cylinder(r=3, h=10);
translate([-6, 6, -3]) cylinder(r=3, h=10);
translate([-6, -6, -3]) cylinder(r=3, h=10);
}
// Water Webbed Toes
color("#E0E0E0") {
for(dx=[6, -6]) {
for(dy=[6, -6]) {
translate([dx+2.8, dy+1, -2.5]) sphere(r=0.6);
translate([dx+2.8, dy-1, -2.5]) sphere(r=0.6);
translate([dx+2.2, dy+2.5, -2.5]) sphere(r=0.6);
translate([dx+2.2, dy-2.5, -2.5]) sphere(r=0.6);
}
}
}
// Nostrils set high
color("#111111") {
translate([25, 4, 10.5]) sphere(r=1);
translate([25, -4, 10.5]) sphere(r=1);
}
// Deep-set Eyes
color("black") {
translate([14, 5, 14.5]) sphere(r=0.8);
translate([14, -5, 14.5]) sphere(r=0.8);
}
// Protruding Jaw Tusks
color("#FFFFF0") {
translate([26, 3.5, 5]) rotate([0, 30, 0]) cylinder(r1=1, r2=0.2, h=4);
translate([26, -3.5, 5]) rotate([0, 30, 0]) cylinder(r1=1, r2=0.2, h=4);
}
}
module crocodile() {
color("#2E8B57") { // SeaGreen
// Segmented Flat Torso
hull() {
translate([3, 0, 2.5]) scale([1, 1.3, 0.5]) sphere(r=4.5);
translate([-5, 0, 2.5]) scale([1, 1.1, 0.5]) sphere(r=4);
}
// Head
hull() {
translate([8, 0, 2.5]) scale([1, 1.2, 0.5]) sphere(r=3.5);
translate([12, 0, 2]) scale([1, 0.9, 0.4]) sphere(r=3);
}
// Snout with Mouth Line
difference() {
hull() {
translate([12, 0, 2]) scale([1, 0.9, 0.4]) sphere(r=3);
translate([17, 0, 1.5]) scale([1, 0.7, 0.3]) sphere(r=2.5);
}
translate([16, 0, 1.5]) cube([8, 5, 0.2], center=true);
}
// Wavy S-Curve Tail
for(i=[0:22]) {
translate([-8 - i*1.8, sin(i*18)*3, 2.5 - i*0.08])
scale([1, 0.8, 0.5]) sphere(r=3.8 - i*0.16);
}
// Sprawled Crocodilian Legs
translate([4, 3, 1.5]) rotate([0, 75, 50]) cylinder(r=0.9, h=6);
translate([4, -3, 1.5]) rotate([0, 75, -50]) cylinder(r=0.9, h=6);
translate([-4, 3, 1.5]) rotate([0, 75, 130]) cylinder(r=0.9, h=6);
translate([-4, -3, 1.5]) rotate([0, 75, -130]) cylinder(r=0.9, h=6);
// Ridged Dorsal Scutes
for(i=[-10:1.5:6]) {
translate([i, 1.2, 4.2 - abs(i-2)*0.05]) scale([1, 0.5, 1]) cylinder(r1=0.8, r2=0, h=1.5, $fn=4);
translate([i, -1.2, 4.2 - abs(i-2)*0.05]) scale([1, 0.5, 1]) cylinder(r1=0.8, r2=0, h=1.5, $fn=4);
}
// Center Tail Scutes
for(i=[1:16]) {
translate([-8 - i*1.8, sin(i*18)*3, 4 - i*0.12])
scale([1, 0.5, 1]) cylinder(r1=0.7 - i*0.03, r2=0, h=1.2 - i*0.05, $fn=4);
}
}
// Slit Reptilian Eyes
color("#FFD700") {
translate([9.5, 2, 3.5]) sphere(r=0.7);
translate([9.5, -2, 3.5]) sphere(r=0.7);
}
color("black") {
translate([9.8, 2, 3.8]) sphere(r=0.35);
translate([9.8, -2, 3.8]) sphere(r=0.35);
}
// Sharp Teeth Lining the Jaw
color("white") {
for(i=[11:1.5:16]) {
translate([i, 1.8 - (i-11)*0.1, 1.2]) cylinder(r1=0.25, r2=0, h=1);
translate([i, -1.8 + (i-11)*0.1, 1.2]) cylinder(r1=0.25, r2=0, h=1);
}
}
}
module bird() { // A hitchhiking Oxpecker
color("white") hull() { sphere(r=1); translate([1.5, 0, 0.5]) sphere(r=0.6); }
color("#FF4500") translate([2, 0, 0.5]) rotate([0, 20, 0]) cylinder(r1=0.3, r2=0, h=1);
color("white") { // Tiny wings folded
translate([0.5, 1, 0.2]) rotate([-20, 0, 0]) scale([1, 1.5, 0.2]) sphere(r=0.8);
translate([0.5, -1, 0.2]) rotate([20, 0, 0]) scale([1, 1.5, 0.2]) sphere(r=0.8);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment