//----------------------------------------------------------------------- // Speaker enclosure - 4cm x 5cm x 10cm exterior, 4.5cm speaker opening // Built with YAPP_Box (YAPPgenerator_v3.scad) //----------------------------------------------------------------------- include <./YAPPgenerator_v3.scad> printBaseShell = true; printLidShell = true; // Reference "PCB" - there's no real PCB here, this block just defines // the box's internal footprint. Exterior = pcbLength/pcbWidth + 2*wallThickness // (padding = 0), so: 36 + 2*2 = 40mm, 46 + 2*2 = 50mm. pcbLength = 40; // X axis (front-to-back) -> 4cm exterior pcbWidth = 50; // Y axis (side-to-side) -> 5cm exterior pcbThickness = 1.6; standoffHeight = 0; standoffDiameter = 0; standoffPinDiameter = 0; pcb = [ ["Main", pcbLength, pcbWidth, 0, 0, pcbThickness, standoffHeight, standoffDiameter, standoffPinDiameter, 0.4] ]; paddingFront = 0; paddingBack = 0; paddingRight = 0; paddingLeft = 0; wallThickness = 2.0; basePlaneThickness = 2.0; lidPlaneThickness = 2.0; // Total exterior height = basePlaneThickness + baseWallHeight // + lidWallHeight + lidPlaneThickness // = 2 + 86 + 10 + 2 = 100mm (10cm) baseWallHeight = 86; lidWallHeight = 10; ridgeHeight = 5.0; roundRadius = 3.0; //--------------------------------------------------------------- // Speaker cutout - centered on the Front face (the 5cm x 10cm face) // Front face local coords (yappCoordBox, corner-referenced): // p(0) = position from the Left edge (Y axis) // p(1) = position from the Bottom edge (Z axis) // A 45mm circle centered at Y=25, Z=50 has its bounding-box corner at: // p1 = 50 - 22.5 = 27.5 //--------------------------------------------------------------- cutoutsFront = [ [2.5, 2.5, 0, 0, 22.5, yappCircle] ]; cutoutsLid = [ [22, 10, 0, 0, 0.5*25.4/2, yappCircle], [2, 35, 0, 0, 0.5*25.4/2, yappCircle], ]; snapJoins = [ [10,5,yappFront,yappBack,yappSymmetric] ]; //--------------------------------------------------------------- // Angled speaker-retaining wall // A near-vertical rib that rises 30mm from the front-bottom of // the base and leans slightly back toward the box centre. Its // speaker-facing surface sits 15mm behind the front (speaker) // wall at the floor and 17.5mm behind it at the top, so it // backstops the speaker and holds it against the speaker hole. //--------------------------------------------------------------- frontInnerX = shellInsideLength + wallThickness; // X of inner front-wall face retainGapBot = 15; // mm behind the front wall at the floor retainGapTop = 17.5; // mm behind the front wall at the top retainHeight = 30; // rib height above the base floor retainThick = 2.4; // rib wall thickness retainWidth = 40; // Y span (a little wider than the speaker) retainYc = 27; // Y centre (matches the speaker cutout) retainFoot = 10; // how far the base flares back toward centre retainFootH = 14; // height over which the flare tapers back in module speakerRetainer() { xBot = frontInnerX - retainGapBot; xTop = frontInnerX - retainGapTop; zBot = basePlaneThickness; zTop = basePlaneThickness + retainHeight; // hookBaseInside() origin sits at the inner corner: // global = hookCoord + [wallThickness, wallThickness, basePlaneThickness] // X grows toward the speaker hole; the flared foot extends the other // way (toward box centre) so it never touches the speaker. Each layer // sits fully on the one below it, so it prints without support. translate([-wallThickness, -wallThickness, -basePlaneThickness]) translate([0, retainYc + retainWidth/2, 0]) rotate([90, 0, 0]) linear_extrude(height = retainWidth) polygon([[xBot + retainThick, zBot], // front face, floor [xBot - retainFoot, zBot], // flared foot toe [xTop, zBot + retainFootH], // foot tapers into back face [xTop, zTop], // back face, top [xTop + retainThick, zTop]]); // front face, top } module hookBaseInside() { speakerRetainer(); } //--------------------------------------------------------------- // Skull faceplate / grille // A round faceplate, raised proud of the front face, that fully // overlaps the 45mm speaker opening and fuses to the solid front // wall around it. A skull face is cut through it as the speaker // grille - eye sockets and nasal opening come straight from the // icon, plus a row of added tooth slots in the jaw. // skull.svg: "death-skull" by sbed / game-icons.net - CC BY 3.0 // https://game-icons.net/1x1/sbed/death-skull.html //--------------------------------------------------------------- plateDia = 50; // faceplate diameter (> 45mm opening -> fused rim) plateRaise = 1; // mm proud of the front face plateEmbed = 5; // mm the plate sinks into the front wall (weld) skullFaceW = 46; // skull width across the plate skullMaskD = 44; // opened-up disc around the skull -> the grille voids frontOuterX = shellInsideLength + 2*wallThickness; // X of the outer front face speakerYc = 27; // speaker opening centre (Y) speakerZc = 28.6; // speaker opening centre (Z) // skull.svg imports at ~180.6mm wide (512-unit viewBox at 72dpi) skullImportW = 180.6; module skullArt() { import("skull-2.svg", center = true); } // The faceplate is a solid disc. The grille is the skull's negative // space: inside a centre disc, everything that is NOT skull bone is // opened up - eye sockets, nasal opening and the crescent gaps around // the cranium and jaw. The bone itself stays as plate material, so the // disc is never cut through and the skull reads by its voids. module grille2D() { difference() { circle(d = plateDia, $fn = 160); difference() { circle(d = skullMaskD, $fn = 150); scale(skullFaceW / skullImportW) skullArt(); } // teeth: a row of slots cut into the jaw for extra grille area //for (i = [-2 : 2]) //translate([i * 4.4, -15.5]) square([2.2, 7], center = true); } } module skullFaceplate() { // hookBaseOutside() shares the inner-corner origin: // global = hookCoord + [wallThickness, wallThickness, basePlaneThickness] translate([-wallThickness, -wallThickness, -basePlaneThickness]) translate([frontOuterX - plateEmbed, speakerYc, speakerZc]) rotate([90, 0, 90]) // 2D x->Y, 2D y->Z, extrude->+X linear_extrude(plateRaise + plateEmbed) grille2D(); } module hookBaseOutside() { skullFaceplate(); } showOrientation = true; YAPPgenerate();