← Back to Models
Soap dish v1

Soap dish v1

by Mach3 ·

Sports neat spherical cut out for a piece of soap, and bestagon ribs (of course!). Optional water collector tray.

Interactive Preview & Customizer

3D STL viewer with browser-based OpenSCAD rendering on parameter changes.

Loading previewLoading preview...

Which part to preview or export

Vertical gap between tray and dish in assembly preview (mm)

step 0.5

Outer frame width (mm)

step 1

Outer frame height (mm)

step 1

Total frame thickness (mm)

step 0.5

Border wall thickness (mm)

step 0.1

Outer corner radius (mm)

step 0.5

Size of individual honeycomb cells (mm)

step 0.5

Thickness of honeycomb ribs (mm)

step 0.1

Radius for the spherical soap scoop (mm)

step 1

Depth of scoop into the frame (mm)

step 0.5

Clearance around dish footprint inside tray (mm)

step 0.1

Tray wall and floor thickness (mm)

step 0.1

Total tray height (mm)

step 0.5

Curve smoothness

step 1
WASM compiler loads on first parameter change.
Download current STL

Prompt

I want to turn this into soap holder.
1. make sure the hex structures are originating from the center of the shape;
2. I want to have a negative cut of huge sphere from the center of the shape

OpenSCAD Code

// Honeycomb Soap Dish + Optional Drip Tray
// Dimensions: 175mm x 175mm

/* [Output] */
// Which part to preview or export
part = "assembly";               // [dish,tray,assembly]
// Vertical gap between tray and dish in assembly preview (mm)
assembly_gap = 1.0;          // [0:0.5:8]

/* [Frame] */
// Outer frame width (mm)
frame_width = 135;           // [90:1:220]
// Outer frame height (mm)
frame_height = 135;          // [90:1:220]
// Total frame thickness (mm)
frame_depth = 24;            // [8:0.5:60]
// Border wall thickness (mm)
frame_border = 1.6;          // [1:0.1:6]
// Outer corner radius (mm)
corner_radius = 35;          // [8:0.5:70]

/* [Honeycomb] */
// Size of individual honeycomb cells (mm)
hex_radius = 20;             // [6:0.5:40]
// Thickness of honeycomb ribs (mm)
hex_wall = 1.6;              // [0.8:0.1:6]

/* [Bowl] */
// Radius for the spherical soap scoop (mm)
dish_radius = 220;           // [120:1:420]
// Depth of scoop into the frame (mm)
dish_depth = 16;             // [4:0.5:36]

/* [Tray] */
// Clearance around dish footprint inside tray (mm)
tray_tolerance = 1.0;        // [0:0.1:3]
// Tray wall and floor thickness (mm)
tray_wall_thickness = 2.0;   // [0.8:0.1:8]
// Total tray height (mm)
tray_height = 8;             // [2:0.5:30]

/* [Quality] */
// Curve smoothness
$fn = 80;                    // [48:1:180]

// --- Render selection ---
if (part == "dish") {
    soap_dish_body();
} else if (part == "tray") {
    drip_tray();
} else if (part == "assembly") {
    drip_tray();
    translate([0, 0, tray_height + assembly_gap]) soap_dish_body();
}

// --- Modules ---

module soap_dish_body() {
    // Position sphere so its bottom reaches the desired depth
    sphere_z_offset = (frame_depth - dish_depth) + dish_radius;

    difference() {
        union() {
            // 1. Outer border frame
            difference() {
                rounded_square(frame_width, frame_height, frame_depth, corner_radius);

                // Interior cutout
                translate([0, 0, -1])
                    rounded_square(
                        frame_width - frame_border * 2,
                        frame_height - frame_border * 2,
                        frame_depth + 2,
                        corner_radius - frame_border
                    );
            }

            // 2. Honeycomb fill
            intersection() {
                rounded_square(frame_width - frame_border, frame_height - frame_border, frame_depth, corner_radius - frame_border / 2);

                // Pattern centered at 0,0
                honeycomb_grid(frame_width, frame_height, frame_depth, hex_radius, hex_wall);
            }
        }

        // 3. Concave soap bowl cut
        translate([0, 0, sphere_z_offset])
            sphere(r = dish_radius);
    }
}

module drip_tray() {
    // Fit tray to soap dish outer footprint
    tray_inner_w = frame_width + (tray_tolerance * 2);
    tray_inner_h = frame_height + (tray_tolerance * 2);
    tray_inner_r = corner_radius + tray_tolerance;

    tray_outer_w = tray_inner_w + (tray_wall_thickness * 2);
    tray_outer_h = tray_inner_h + (tray_wall_thickness * 2);
    tray_outer_r = tray_inner_r + tray_wall_thickness;

    difference() {
        // Outer tray body
        rounded_square(tray_outer_w, tray_outer_h, tray_height, tray_outer_r);

        // Inner cavity; shifted up to keep floor thickness
        translate([0, 0, tray_wall_thickness])
            rounded_square(tray_inner_w, tray_inner_h, tray_height, tray_inner_r);
    }
}

module rounded_square(w, h, z, r) {
    translate([-w / 2 + r, -h / 2 + r, 0])
    hull() {
        cylinder(h = z, r = r);
        translate([w - 2 * r, 0, 0]) cylinder(h = z, r = r);
        translate([0, h - 2 * r, 0]) cylinder(h = z, r = r);
        translate([w - 2 * r, h - 2 * r, 0]) cylinder(h = z, r = r);
    }
}

module honeycomb_grid(width, height, depth, r, wall) {
    x_spacing = r * 1.5;
    y_spacing = r * sqrt(3);

    // Calculate number of cells needed to cover area
    cols = ceil(width / x_spacing) + 1;
    rows = ceil(height / y_spacing) + 1;

    translate([0, 0, 0])
    for (i = [-cols / 2 : cols / 2]) {
        for (j = [-rows / 2 : rows / 2]) {
            x_pos = i * x_spacing;
            y_offset = (abs(i) % 2 == 1) ? y_spacing / 2 : 0;
            y_pos = j * y_spacing + y_offset;

            translate([x_pos, y_pos, 0])
            difference() {
                cylinder(h = depth, r = r, $fn = 6);
                translate([0, 0, -0.5])
                    cylinder(h = depth + 1, r = r - wall, $fn = 6);
            }
        }
    }
}