From 93d5b0f102da1873d9f0186706f687d450d740ec Mon Sep 17 00:00:00 2001 From: Cal Corum Date: Sat, 20 Dec 2025 17:42:15 -0600 Subject: [PATCH] Add parametric light switch plate models MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Converted STL files to parametric OpenSCAD: - blank.scad: Blank cover plate - switch.scad: Single toggle switch - outlet.scad: Duplex outlet - switch-switch.scad: Double toggle (2-gang) - gfci-paddle-switch.scad: Decora/GFCI paddle switch - gfci-paddle-switch-extended.scad: Custom 153x230mm oversized plate All plates feature: - Print-optimized orientation (front face at Z=0, no overhangs) - Beveled edges matching original design - Back recess for electrical box fit - Round screw holes - BOSL2 library for clean geometry Includes 2D template (SVG) for paper test-fit printing. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- light-switches/blank.scad | 92 ++++++++++++ .../gfci-paddle-switch-extended-2d.scad | 26 ++++ .../gfci-paddle-switch-extended-template.svg | 53 +++++++ .../gfci-paddle-switch-extended.scad | 114 ++++++++++++++ light-switches/gfci-paddle-switch.scad | 141 ++++++++++++++++++ light-switches/outlet.scad | 117 +++++++++++++++ light-switches/switch-switch.scad | 119 +++++++++++++++ light-switches/switch.scad | 109 ++++++++++++++ 8 files changed, 771 insertions(+) create mode 100644 light-switches/blank.scad create mode 100644 light-switches/gfci-paddle-switch-extended-2d.scad create mode 100644 light-switches/gfci-paddle-switch-extended-template.svg create mode 100644 light-switches/gfci-paddle-switch-extended.scad create mode 100644 light-switches/gfci-paddle-switch.scad create mode 100644 light-switches/outlet.scad create mode 100644 light-switches/switch-switch.scad create mode 100644 light-switches/switch.scad diff --git a/light-switches/blank.scad b/light-switches/blank.scad new file mode 100644 index 0000000..7b2bb5f --- /dev/null +++ b/light-switches/blank.scad @@ -0,0 +1,92 @@ +// Blank Wall Plate (No Openings) +// Standard single-gang blank cover plate +// Parametric OpenSCAD model + +include + +/* [Plate Dimensions] */ +plate_width = 83.64; // mm - X dimension +plate_height = 126.64; // mm - Y dimension +plate_thickness = 5.0; // mm - Z dimension + +/* [Bevel Settings] */ +bevel_inset = 1.82; // mm - how much smaller bottom is per side + +/* [Recess Settings] */ +recess_enabled = true; +recess_depth = 2.0; // mm - depth of recess (from bottom) +recess_inset = 8.0; // mm - inset from outer edge + +/* [Screw Holes] */ +screw_holes_enabled = true; +screw_hole_diameter = 5.0; // mm - diameter of screw hole +screw_hole_spacing = 100.0; // mm - distance between hole centers + +/* [Corner Rounding] */ +plate_corner_radius = 3.0; // mm + +/* [Resolution] */ +$fn = 64; + +// ============================================ +// CALCULATED VALUES +// ============================================ + +bottom_width = plate_width - (bevel_inset * 2); +bottom_height = plate_height - (bevel_inset * 2); +recess_width = plate_width - (recess_inset * 2); +recess_height = plate_height - (recess_inset * 2); + +// ============================================ +// MODULES +// ============================================ + +module plate_body() { + // Flipped for printing: front face (larger) at Z=0, back (smaller) at Z=5 + // This eliminates overhang on beveled edges + prismoid( + size1 = [plate_width, plate_height], // front face (larger) at bottom + size2 = [bottom_width, bottom_height], // back face (smaller) at top + h = plate_thickness, + rounding = plate_corner_radius, + anchor = BOTTOM + ); +} + +module back_recess() { + if (recess_enabled) { + recess_rounding = max(0.5, plate_corner_radius - recess_inset/4); + // Recess now at top (Z=5) since plate is flipped for printing + translate([0, 0, plate_thickness - recess_depth - 0.01]) + prismoid( + size1 = [recess_width, recess_height], + size2 = [recess_width, recess_height], + h = recess_depth + 0.02, + rounding = recess_rounding, + anchor = BOTTOM + ); + } +} + +module screw_holes() { + if (screw_holes_enabled) { + for (y_pos = [screw_hole_spacing/2, -screw_hole_spacing/2]) { + translate([0, y_pos, -0.1]) + cylinder(h = plate_thickness + 0.2, d = screw_hole_diameter); + } + } +} + +// ============================================ +// MAIN ASSEMBLY +// ============================================ + +module blank_plate() { + difference() { + plate_body(); + back_recess(); + screw_holes(); + } +} + +blank_plate(); diff --git a/light-switches/gfci-paddle-switch-extended-2d.scad b/light-switches/gfci-paddle-switch-extended-2d.scad new file mode 100644 index 0000000..ba13bf5 --- /dev/null +++ b/light-switches/gfci-paddle-switch-extended-2d.scad @@ -0,0 +1,26 @@ +// 2D projection for paper test fit +// Print this at 100% scale (no scaling) + +include + +plate_width = 153.0; +plate_height = 230.0; +plate_corner_radius = 3.0; +opening_width = 34.0; +opening_height = 67.0; +opening_corner_radius = 2.0; + +// Screw holes - same spacing as original +screw_hole_diameter = 5.0; +screw_hole_spacing = 83.3; + +$fn = 64; + +difference() { + rect([plate_width, plate_height], rounding=plate_corner_radius); + rect([opening_width, opening_height], rounding=opening_corner_radius); + translate([0, screw_hole_spacing/2]) + circle(d=screw_hole_diameter); + translate([0, -screw_hole_spacing/2]) + circle(d=screw_hole_diameter); +} diff --git a/light-switches/gfci-paddle-switch-extended-template.svg b/light-switches/gfci-paddle-switch-extended-template.svg new file mode 100644 index 0000000..7a45e07 --- /dev/null +++ b/light-switches/gfci-paddle-switch-extended-template.svg @@ -0,0 +1,53 @@ + + + +OpenSCAD Model + + diff --git a/light-switches/gfci-paddle-switch-extended.scad b/light-switches/gfci-paddle-switch-extended.scad new file mode 100644 index 0000000..1b8e91e --- /dev/null +++ b/light-switches/gfci-paddle-switch-extended.scad @@ -0,0 +1,114 @@ +// GFCI Paddle Switch Plate - Extended Size +// Custom oversized plate with centered paddle opening +// Opening and screw holes remain in original position + +include + +/* [Plate Dimensions] */ +// Extended plate dimensions +plate_width = 153.0; // mm - X dimension (was 83.64) +plate_height = 230.0; // mm - Y dimension (was 126.64) +plate_thickness = 5.0; // mm - Z dimension + +/* [Bevel Settings] */ +bevel_inset = 1.82; // mm - how much smaller bottom is per side + +/* [Recess Settings] */ +recess_enabled = true; +recess_depth = 2.0; // mm - depth of recess (from bottom) +recess_inset = 8.0; // mm - inset from outer edge + +/* [Paddle Opening] */ +// Rectangular opening for paddle switch (same as standard plate) +opening_width = 34.0; // mm - width of opening +opening_height = 67.0; // mm - height of opening + +/* [Corner Rounding] */ +plate_corner_radius = 3.0; // mm +opening_corner_radius = 2.0; // mm + +/* [Screw Holes] */ +screw_holes_enabled = true; +screw_hole_diameter = 4.0; // mm +screw_hole_spacing = 83.3; // mm - distance between screw holes (unchanged) + +/* [Resolution] */ +$fn = 64; + +// ============================================ +// CALCULATED VALUES +// ============================================ + +bottom_width = plate_width - (bevel_inset * 2); +bottom_height = plate_height - (bevel_inset * 2); +recess_width = plate_width - (recess_inset * 2); +recess_height = plate_height - (recess_inset * 2); + +// ============================================ +// MODULES +// ============================================ + +module plate_body() { + // Flipped for printing: front face (larger) at Z=0, back (smaller) at Z=5 + // This eliminates overhang on beveled edges + prismoid( + size1 = [plate_width, plate_height], // front face (larger) at bottom + size2 = [bottom_width, bottom_height], // back face (smaller) at top + h = plate_thickness, + rounding = plate_corner_radius, + anchor = BOTTOM + ); +} + +module back_recess() { + if (recess_enabled) { + recess_rounding = max(0.5, plate_corner_radius - recess_inset/4); + // Recess now at top (Z=5) since plate is flipped for printing + translate([0, 0, plate_thickness - recess_depth - 0.01]) + prismoid( + size1 = [recess_width, recess_height], + size2 = [recess_width, recess_height], + h = recess_depth + 0.02, + rounding = recess_rounding, + anchor = BOTTOM + ); + } +} + +// 2D paddle opening shape (simple rectangle with rounded corners) +module paddle_opening_2d() { + rect([opening_width, opening_height], rounding=opening_corner_radius); +} + +module paddle_opening_3d() { + translate([0, 0, -0.1]) + linear_extrude(height = plate_thickness + 0.2) + paddle_opening_2d(); +} + +module screw_holes() { + if (screw_holes_enabled) { + // Top screw hole + translate([0, screw_hole_spacing/2, -0.1]) + cylinder(h = plate_thickness + 0.2, d = screw_hole_diameter); + + // Bottom screw hole + translate([0, -screw_hole_spacing/2, -0.1]) + cylinder(h = plate_thickness + 0.2, d = screw_hole_diameter); + } +} + +// ============================================ +// MAIN ASSEMBLY +// ============================================ + +module gfci_paddle_plate_extended() { + difference() { + plate_body(); + back_recess(); + paddle_opening_3d(); + screw_holes(); + } +} + +gfci_paddle_plate_extended(); diff --git a/light-switches/gfci-paddle-switch.scad b/light-switches/gfci-paddle-switch.scad new file mode 100644 index 0000000..650a669 --- /dev/null +++ b/light-switches/gfci-paddle-switch.scad @@ -0,0 +1,141 @@ +// GFCI Paddle Switch Plate +// Parametric recreation of standard Decora/GFCI wall plate +// Rebuilt from STL analysis - fully editable + +include + +/* [Plate Dimensions] */ +// Overall plate dimensions (at top surface) +plate_width = 83.64; // mm - X dimension +plate_height = 126.64; // mm - Y dimension +plate_thickness = 5.0; // mm - Z dimension + +/* [Bevel Settings] */ +// Bevel creates the tapered edge (top wider than bottom) +bevel_inset = 1.82; // mm - how much smaller bottom is per side +bevel_height = 3.0; // mm - height of beveled section (from top) + +/* [Recess Settings] */ +// Back recess that fits over electrical box +recess_enabled = true; +recess_depth = 2.0; // mm - depth of recess (from bottom) +recess_inset = 8.0; // mm - inset from outer edge on each side + +/* [Paddle Opening] */ +// Rectangular opening for paddle switch +opening_width = 34.0; // mm - width of opening +opening_height = 67.0; // mm - height of opening + +/* [Corner Rounding] */ +plate_corner_radius = 3.0; // mm - outer corner radius +opening_corner_radius = 2.0; // mm - opening corner radius + +/* [Screw Holes] */ +screw_holes_enabled = true; +screw_hole_diameter = 4.0; // mm +screw_hole_spacing = 83.3; // mm - distance between screw holes (center to center) + +/* [Resolution] */ +$fn = 64; // smoothness for curves + +// ============================================ +// CALCULATED VALUES +// ============================================ + +// Bottom dimensions (smaller due to bevel) +bottom_width = plate_width - (bevel_inset * 2); +bottom_height = plate_height - (bevel_inset * 2); + +// Recess dimensions +recess_width = plate_width - (recess_inset * 2); +recess_height = plate_height - (recess_inset * 2); + +// ============================================ +// MODULES +// ============================================ + +// Main plate body with beveled edges +module plate_body() { + // Flipped for printing: front face (larger) at Z=0, back (smaller) at Z=5 + // This eliminates overhang on beveled edges + prismoid( + size1 = [plate_width, plate_height], // front face (larger) at bottom + size2 = [bottom_width, bottom_height], // back face (smaller) at top + h = plate_thickness, + rounding = plate_corner_radius, + anchor = BOTTOM + ); +} + +// Back recess for electrical box fit +module back_recess() { + if (recess_enabled) { + recess_rounding = max(0.5, plate_corner_radius - recess_inset/4); + // Recess now at top (Z=5) since plate is flipped for printing + translate([0, 0, plate_thickness - recess_depth - 0.01]) + prismoid( + size1 = [recess_width, recess_height], + size2 = [recess_width, recess_height], + h = recess_depth + 0.02, + rounding = recess_rounding, + anchor = BOTTOM + ); + } +} + +// 2D paddle opening shape (simple rectangle with rounded corners) +module paddle_opening_2d() { + rect([opening_width, opening_height], rounding=opening_corner_radius); +} + +// 3D paddle opening (for subtraction) +module paddle_opening_3d() { + translate([0, 0, -0.1]) + linear_extrude(height = plate_thickness + 0.2) + paddle_opening_2d(); +} + +// Screw holes +module screw_holes() { + if (screw_holes_enabled) { + // Top screw hole + translate([0, screw_hole_spacing/2, -0.1]) + cylinder(h = plate_thickness + 0.2, d = screw_hole_diameter); + + // Bottom screw hole + translate([0, -screw_hole_spacing/2, -0.1]) + cylinder(h = plate_thickness + 0.2, d = screw_hole_diameter); + } +} + +// ============================================ +// MAIN ASSEMBLY +// ============================================ + +module gfci_paddle_plate() { + difference() { + plate_body(); + back_recess(); + paddle_opening_3d(); + screw_holes(); + } +} + +// Render the plate +gfci_paddle_plate(); + +// ============================================ +// PREVIEW HELPERS (uncomment to debug) +// ============================================ + +// Preview just the 2D opening shape: +// paddle_opening_2d(); + +// Preview the opening position: +// #paddle_opening_3d(); + +// Preview cross-section (cut in half): +// difference() { +// gfci_paddle_plate(); +// translate([0, -100, -1]) cube([200, 200, 20]); +// } diff --git a/light-switches/outlet.scad b/light-switches/outlet.scad new file mode 100644 index 0000000..b0fd154 --- /dev/null +++ b/light-switches/outlet.scad @@ -0,0 +1,117 @@ +// Duplex Outlet Wall Plate +// Standard single-gang duplex receptacle cover +// Parametric OpenSCAD model + +include + +/* [Plate Dimensions] */ +plate_width = 83.64; // mm - X dimension +plate_height = 126.64; // mm - Y dimension +plate_thickness = 5.0; // mm - Z dimension + +/* [Bevel Settings] */ +bevel_inset = 1.82; // mm - how much smaller bottom is per side + +/* [Recess Settings] */ +recess_enabled = true; +recess_depth = 2.0; // mm - depth of recess (from bottom) +recess_inset = 8.0; // mm - inset from outer edge + +/* [Outlet Opening] */ +// Each outlet receptacle opening (oval/rounded rectangle) +outlet_width = 34.0; // mm - width of each outlet opening +outlet_height = 26.0; // mm - height of each outlet opening +outlet_corner_radius = 10.0; // mm - creates rounded/oval shape +outlet_spacing = 39.5; // mm - vertical distance between outlet centers + +/* [Screw Hole] */ +// Center screw hole between outlets +screw_hole_enabled = true; +screw_hole_diameter = 5.0; // mm + +/* [Corner Rounding] */ +plate_corner_radius = 3.0; // mm + +/* [Resolution] */ +$fn = 64; + +// ============================================ +// CALCULATED VALUES +// ============================================ + +bottom_width = plate_width - (bevel_inset * 2); +bottom_height = plate_height - (bevel_inset * 2); +recess_width = plate_width - (recess_inset * 2); +recess_height = plate_height - (recess_inset * 2); + +// ============================================ +// MODULES +// ============================================ + +module plate_body() { + // Flipped for printing: front face (larger) at Z=0, back (smaller) at Z=5 + // This eliminates overhang on beveled edges + prismoid( + size1 = [plate_width, plate_height], // front face (larger) at bottom + size2 = [bottom_width, bottom_height], // back face (smaller) at top + h = plate_thickness, + rounding = plate_corner_radius, + anchor = BOTTOM + ); +} + +module back_recess() { + if (recess_enabled) { + recess_rounding = max(0.5, plate_corner_radius - recess_inset/4); + // Recess now at top (Z=5) since plate is flipped for printing + translate([0, 0, plate_thickness - recess_depth - 0.01]) + prismoid( + size1 = [recess_width, recess_height], + size2 = [recess_width, recess_height], + h = recess_depth + 0.02, + rounding = recess_rounding, + anchor = BOTTOM + ); + } +} + +// Single outlet opening (rounded rectangle / oval) +module outlet_opening_2d() { + rect([outlet_width, outlet_height], rounding=outlet_corner_radius); +} + +// Both outlet openings +module outlet_openings_3d() { + translate([0, 0, -0.1]) + linear_extrude(height = plate_thickness + 0.2) { + // Top outlet + translate([0, outlet_spacing/2, 0]) + outlet_opening_2d(); + // Bottom outlet + translate([0, -outlet_spacing/2, 0]) + outlet_opening_2d(); + } +} + +// Center screw hole +module center_screw_hole() { + if (screw_hole_enabled) { + translate([0, 0, -0.1]) + cylinder(h = plate_thickness + 0.2, d = screw_hole_diameter); + } +} + +// ============================================ +// MAIN ASSEMBLY +// ============================================ + +module outlet_plate() { + difference() { + plate_body(); + back_recess(); + outlet_openings_3d(); + center_screw_hole(); + } +} + +outlet_plate(); diff --git a/light-switches/switch-switch.scad b/light-switches/switch-switch.scad new file mode 100644 index 0000000..d87f94c --- /dev/null +++ b/light-switches/switch-switch.scad @@ -0,0 +1,119 @@ +// Double Toggle Switch Wall Plate +// Standard 2-gang toggle switch cover +// Parametric OpenSCAD model + +include + +/* [Plate Dimensions] */ +// 2-gang plate is wider than single-gang +plate_width = 126.64; // mm - X dimension (2-gang width) +plate_height = 126.64; // mm - Y dimension +plate_thickness = 5.0; // mm - Z dimension + +/* [Bevel Settings] */ +bevel_inset = 1.82; // mm - how much smaller bottom is per side + +/* [Recess Settings] */ +recess_enabled = true; +recess_depth = 2.0; // mm - depth of recess (from bottom) +recess_inset = 8.0; // mm - inset from outer edge + +/* [Switch Openings] */ +switch_width = 11.0; // mm - width of each toggle slot +switch_height = 67.0; // mm - height of each toggle slot +switch_corner_radius = 4.0; // mm - rounding at ends +switch_spacing = 45.0; // mm - horizontal distance between switch centers + +/* [Screw Holes] */ +screw_holes_enabled = true; +screw_hole_diameter = 5.0; // mm - diameter of screw hole +screw_hole_spacing = 96.0; // mm - distance between hole centers + +/* [Corner Rounding] */ +plate_corner_radius = 3.0; // mm + +/* [Resolution] */ +$fn = 64; + +// ============================================ +// CALCULATED VALUES +// ============================================ + +bottom_width = plate_width - (bevel_inset * 2); +bottom_height = plate_height - (bevel_inset * 2); +recess_width = plate_width - (recess_inset * 2); +recess_height = plate_height - (recess_inset * 2); + +// ============================================ +// MODULES +// ============================================ + +module plate_body() { + // Flipped for printing: front face (larger) at Z=0, back (smaller) at Z=5 + // This eliminates overhang on beveled edges + prismoid( + size1 = [plate_width, plate_height], // front face (larger) at bottom + size2 = [bottom_width, bottom_height], // back face (smaller) at top + h = plate_thickness, + rounding = plate_corner_radius, + anchor = BOTTOM + ); +} + +module back_recess() { + if (recess_enabled) { + recess_rounding = max(0.5, plate_corner_radius - recess_inset/4); + // Recess now at top (Z=5) since plate is flipped for printing + translate([0, 0, plate_thickness - recess_depth - 0.01]) + prismoid( + size1 = [recess_width, recess_height], + size2 = [recess_width, recess_height], + h = recess_depth + 0.02, + rounding = recess_rounding, + anchor = BOTTOM + ); + } +} + +// Single toggle switch slot +module switch_opening_2d() { + rect([switch_width, switch_height], rounding=switch_corner_radius); +} + +// Both switch openings +module switch_openings_3d() { + translate([0, 0, -0.1]) + linear_extrude(height = plate_thickness + 0.2) { + // Left switch + translate([-switch_spacing/2, 0, 0]) + switch_opening_2d(); + // Right switch + translate([switch_spacing/2, 0, 0]) + switch_opening_2d(); + } +} + +// Screw holes (top and bottom) +module screw_holes() { + if (screw_holes_enabled) { + for (y_pos = [screw_hole_spacing/2, -screw_hole_spacing/2]) { + translate([0, y_pos, -0.1]) + cylinder(h = plate_thickness + 0.2, d = screw_hole_diameter); + } + } +} + +// ============================================ +// MAIN ASSEMBLY +// ============================================ + +module switch_switch_plate() { + difference() { + plate_body(); + back_recess(); + switch_openings_3d(); + screw_holes(); + } +} + +switch_switch_plate(); diff --git a/light-switches/switch.scad b/light-switches/switch.scad new file mode 100644 index 0000000..9d2f8a1 --- /dev/null +++ b/light-switches/switch.scad @@ -0,0 +1,109 @@ +// Toggle Switch Wall Plate +// Standard single-gang toggle switch cover +// Parametric OpenSCAD model + +include + +/* [Plate Dimensions] */ +plate_width = 83.64; // mm - X dimension +plate_height = 126.64; // mm - Y dimension +plate_thickness = 5.0; // mm - Z dimension + +/* [Bevel Settings] */ +bevel_inset = 1.82; // mm - how much smaller bottom is per side + +/* [Recess Settings] */ +recess_enabled = true; +recess_depth = 2.0; // mm - depth of recess (from bottom) +recess_inset = 8.0; // mm - inset from outer edge + +/* [Switch Opening] */ +switch_width = 11.0; // mm - width of toggle slot +switch_height = 67.0; // mm - height of toggle slot +switch_corner_radius = 4.0; // mm - rounding at ends + +/* [Screw Holes] */ +screw_holes_enabled = true; +screw_hole_diameter = 5.0; // mm - diameter of screw hole +screw_hole_spacing = 100.0; // mm - distance between hole centers + +/* [Corner Rounding] */ +plate_corner_radius = 3.0; // mm + +/* [Resolution] */ +$fn = 64; + +// ============================================ +// CALCULATED VALUES +// ============================================ + +bottom_width = plate_width - (bevel_inset * 2); +bottom_height = plate_height - (bevel_inset * 2); +recess_width = plate_width - (recess_inset * 2); +recess_height = plate_height - (recess_inset * 2); + +// ============================================ +// MODULES +// ============================================ + +module plate_body() { + // Flipped for printing: front face (larger) at Z=0, back (smaller) at Z=5 + // This eliminates overhang on beveled edges + prismoid( + size1 = [plate_width, plate_height], // front face (larger) at bottom + size2 = [bottom_width, bottom_height], // back face (smaller) at top + h = plate_thickness, + rounding = plate_corner_radius, + anchor = BOTTOM + ); +} + +module back_recess() { + if (recess_enabled) { + recess_rounding = max(0.5, plate_corner_radius - recess_inset/4); + // Recess now at top (Z=5) since plate is flipped for printing + translate([0, 0, plate_thickness - recess_depth - 0.01]) + prismoid( + size1 = [recess_width, recess_height], + size2 = [recess_width, recess_height], + h = recess_depth + 0.02, + rounding = recess_rounding, + anchor = BOTTOM + ); + } +} + +// Toggle switch slot (rounded rectangle / stadium shape) +module switch_opening_2d() { + rect([switch_width, switch_height], rounding=switch_corner_radius); +} + +module switch_opening_3d() { + translate([0, 0, -0.1]) + linear_extrude(height = plate_thickness + 0.2) + switch_opening_2d(); +} + +module screw_holes() { + if (screw_holes_enabled) { + for (y_pos = [screw_hole_spacing/2, -screw_hole_spacing/2]) { + translate([0, y_pos, -0.1]) + cylinder(h = plate_thickness + 0.2, d = screw_hole_diameter); + } + } +} + +// ============================================ +// MAIN ASSEMBLY +// ============================================ + +module switch_plate() { + difference() { + plate_body(); + back_recess(); + switch_opening_3d(); + screw_holes(); + } +} + +switch_plate();