3d-printing/simple-hook/hook.scad
Felipe M. 4f2641e80f
Update simple-hook base plate to have flat back and rounded front edges
Make the back face a full-size flat rectangle flush against the wall,
while keeping rounded edges on all four sides of the front face.
2026-04-03 19:37:00 +02:00

150 lines
5.5 KiB
OpenSCAD

// ============================================
// Parametrizable Wall Hook
// ============================================
// A simple wall hook with a rectangular base plate
// and a cylindrical peg extending outward.
// Designed for 3D printing.
// ============================================
// CUSTOMIZABLE PARAMETERS
// ============================================
// Length of the hook cylinder (how far it extends from the wall)
hook_cylinder_length = 20; // [10:1:100]
// Upward angle of the hook cylinder in degrees
hook_angle = 0; // [0:1:45]
// Overall scale multiplier (1.0 = default size)
overall_scale = 1.0; // [0.25:0.05:3.0]
// Enable a retaining dent near the tip of the hook (prevents items from sliding off at 0° angle)
hook_dent_enabled = true; // [true, false]
// Width of the retaining dent in mm
hook_dent_width = 10; // [1:0.5:10]
// ============================================
// BASE PARAMETERS
// ============================================
// Base plate dimensions
base_width = 20; // Width (vertical dimension when mounted)
base_height = 40; // Height (vertical dimension when mounted)
base_depth = 3; // Thickness/depth of base plate
// Hook cylinder properties
hook_diameter = 5; // Diameter of the hook cylinder
fillet_radius = 2; // Radius for smooth junction between hook and base
// Rendering quality
cylinder_resolution = 50; // Number of facets for cylinders
// ============================================
// PARAMETER VALIDATION
// ============================================
assert(hook_cylinder_length > 0, "Hook cylinder length must be positive");
assert(hook_angle >= 0 && hook_angle <= 45, "Hook angle should be between 0 and 45 degrees");
assert(overall_scale > 0, "Overall scale must be positive");
assert(base_depth >= 3, "Base depth should be at least 3mm for strength");
assert(hook_diameter >= 4, "Hook diameter should be at least 4mm for printability");
assert(hook_dent_width > 0, "Hook dent width must be positive");
// ============================================
// MAIN ASSEMBLY
// ============================================
scale([overall_scale, overall_scale, overall_scale]) {
difference() {
union() {
base_plate();
hook_cylinder();
}
// Cut away anything extending behind the base
translate([-100, -50, -50])
cube([100, 100, 200]);
}
}
// ============================================
// COMPONENT MODULES
// ============================================
// Rectangular base plate, flat back (wall side), rounded front edges on all four sides
module base_plate() {
corner_radius = 2;
hull() {
// Back - full flat rectangle (wall side, sharp edges)
translate([0, -base_width/2, 0])
cube([1, base_width, base_height]);
// Front four corner spheres (create rounded edges on all sides)
translate([base_depth, -base_width/2 + corner_radius, corner_radius])
sphere(r=corner_radius, $fn=cylinder_resolution);
translate([base_depth, base_width/2 - corner_radius, corner_radius])
sphere(r=corner_radius, $fn=cylinder_resolution);
translate([base_depth, -base_width/2 + corner_radius, base_height - corner_radius])
sphere(r=corner_radius, $fn=cylinder_resolution);
translate([base_depth, base_width/2 - corner_radius, base_height - corner_radius])
sphere(r=corner_radius, $fn=cylinder_resolution);
}
}
// Hook cylinder extending from base with upward angle
module hook_cylinder() {
translate([0, 0, base_height/5])
rotate([0, 90 + hook_angle*-1, 0]) {
difference() {
union() {
// Main cylinder body
cylinder(h=hook_cylinder_length, d=hook_diameter, $fn=cylinder_resolution);
// Rounded cap at the end
translate([0, 0, hook_cylinder_length])
sphere(d=hook_diameter, $fn=cylinder_resolution);
}
// Pill-shaped retaining dent on top of the cylinder near the tip
if (hook_dent_enabled) {
dent_position = hook_cylinder_length - hook_diameter/2 - hook_dent_width/2;
translate([0, 0, dent_position])
retaining_dent(hook_dent_width, hook_diameter);
}
}
}
}
// Pill-shaped dent cut into the top of the hook cylinder
// Creates a \__/ profile when viewed from the side
module retaining_dent(width, diameter) {
pill_r = diameter/2;
half_spread = max(0, width/2 - pill_r);
// -X in local frame = "up" in world frame (after the 90° Y rotation)
translate([-diameter/2, 0, 0])
hull() {
translate([0, 0, -half_spread])
sphere(r=pill_r, $fn=cylinder_resolution);
translate([0, 0, half_spread])
sphere(r=pill_r, $fn=cylinder_resolution);
}
}
// Fillet at the junction between hook and base for strength
module fillet_junction() {
translate([base_depth - 1, 0, base_height/3])
rotate([0, 90 + hook_angle*-1, 0])
hull() {
// Cylinder at the start position
cylinder(h=0.1, d=hook_diameter, $fn=cylinder_resolution);
// Larger cylinder slightly behind to create smooth blend with base
translate([0, 0, -fillet_radius])
cylinder(h=0.1, d=hook_diameter + fillet_radius*2, $fn=cylinder_resolution);
}
}