// ============================================ // 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); } }