// Face-Down Oval Zipper Pull Template // Designed for face-down printing: text and border are channels in blue layer (printed first), // then white backing fills the channels and covers the back. // When flipped over, shows white text/border on blue background. // Parameters - these can be overridden from command line name = "NAME"; // Text to display on zipper pull oval_width = 96; // Width of blue oval (mm) - total with border will be 100mm (96 + 2*2) oval_height = 30; // Height of blue oval (mm) - total with border will be 34mm (30 + 2*2) blue_thickness = 1; // Thickness of blue layer (mm) - this is the "show" side white_thickness = 1.5; // Thickness of white backing layer (mm) base_text_size = 13; // Base font size for medium names // Dynamic font sizing based on name length (mimics Ford oval proportions) // "Fred" (4 chars) at 13mm gives ~20% coverage - our target name_length = len(name); text_size = name_length <= 3 ? 18 : // Short names (Zoe, Sam, Al) - larger (~21% coverage) name_length <= 5 ? 13 : // Medium names (Fred, John, Mary) - standard (~20% coverage) name_length <= 8 ? 11 : // Longer names (Michael, Jessica) - smaller (~25% coverage) 11; // Very long names (Christopher) - increased to 11mm (~35% coverage) // Border parameters border_width = 2; // Width of the white border around the oval (mm) // Hole parameters for zipper pull hole_diameter = 4; // Diameter of the hole (mm) hole_clearance = 4; // Minimum clearance from edge of outer border (mm) // Total dimensions total_width = oval_width + border_width*2; // 100mm total_height = oval_height + border_width*2; // 34mm // Hole position - on LEFT side when viewed from show side // Since we print face-down, hole appears on RIGHT during printing // When flipped, it will be on the left as expected hole_x = -(total_width/2) + (hole_diameter/2) + hole_clearance; // Module to create an oval (ellipse) module oval(width, height, depth) { scale([width/2, height/2, 1]) cylinder(h=depth, r=1, $fn=100); } // Module for text with fake bold effect module bold_text() { for (x = [-0.3, 0, 0.3]) { for (y = [-0.3, 0, 0.3]) { translate([x, y, 0]) linear_extrude(height=blue_thickness + 0.1) text(name, size=text_size, font="Fordscript", halign="center", valign="center"); } } } // Blue layer with channels for text and border (prints first, face-down) // The channels will be filled with white when the white layer is printed module blue_layer() { color("RoyalBlue") difference() { // Full blue oval oval(total_width, total_height, blue_thickness); // Cut out the border ring channel (will be filled with white) translate([0, 0, -0.05]) difference() { oval(total_width, total_height, blue_thickness + 0.1); oval(oval_width, oval_height, blue_thickness + 0.2); } // Cut out text channels (will be filled with white) translate([0, 0, -0.05]) bold_text(); // Cut out hole translate([hole_x, 0, -0.05]) cylinder(h=blue_thickness + 0.1, d=hole_diameter, $fn=50); } } // White backing layer (prints second, on top of blue) // Also fills the text and border channels module white_layer() { color("white") difference() { union() { // Main backing layer on top of blue translate([0, 0, blue_thickness]) oval(total_width, total_height, white_thickness); // Fill the border channel difference() { oval(total_width, total_height, blue_thickness); oval(oval_width, oval_height, blue_thickness + 0.1); } // Fill the text channels bold_text(); } // Cut out hole through entire white layer translate([hole_x, 0, -0.05]) cylinder(h=blue_thickness + white_thickness + 0.2, d=hole_diameter, $fn=50); } } // Main zipper pull assembly module zipper_pull() { blue_layer(); white_layer(); } // Generate the zipper pull zipper_pull();