Last active
October 5, 2025 14:06
-
-
Save erdesigns-eu/fe2d1f56a0f76a9df42ae1bd7e245aa9 to your computer and use it in GitHub Desktop.
Through Desk Nintendo Connector SCAD
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| * Integrated Round Through-Desk Dual NES/SNES Classic Panel (One-Piece) | |
| * - Circular cover (flush with desktop) + cylindrical sleeve; printed as a single piece | |
| * - Two NES/SNES Classic female cutouts in the cover (notch-safe) | |
| * - Structural underside: connector lip (downward continuation of the female opening) + optional rings | |
| * - Optional labels above each connector (emboss or inset) | |
| * - No fasteners | |
| * | |
| * Author: ERDesigns — License: MIT | |
| */ | |
| $fn = 128; // rendering quality | |
| //============================== Global scale =================================// | |
| /** | |
| * /// <summary> | |
| * /// Global export scale to compensate slicer/CAD unit mismatch. | |
| * /// Example: if slicer shows 76 mm where 80 mm is expected, set export_scale = 80/76. | |
| * /// </summary> | |
| */ | |
| export_scale = 1.0; | |
| /** /// <summary>Render helper applying export_scale only.</summary> */ | |
| module scaled(){ scale([export_scale, export_scale, export_scale]) children(); } | |
| //============================== Public parameters ============================// | |
| /** /// <summary>Cover (top plate) parameters.</summary> */ | |
| cover_od = 80.0; // visible outer diameter of the cover | |
| cover_thickness = 3.0; // cover thickness (defines flush depth) | |
| cover_roundover_r = 5.0; // top outer-edge roundover radius (real fillet on top rim) | |
| /** /// <summary>Sleeve (tube) parameters.</summary> */ | |
| sleeve_od = 60.0; // sleeve outer diameter (independent from cover_od) | |
| sleeve_wall = 1.0; // sleeve wall thickness | |
| sleeve_extra_below = 40.0; // extra length below the desktop (print length under the cover) | |
| /** /// <summary>NES/SNES connector configuration and placement.</summary> */ | |
| connector_cfg = make_connector( | |
| w=16.5, h=11.5, r=1.0, bezel_extra=0.30, | |
| left_notch_w=2.2, left_notch_h=1.8, left_notch_y=0.0, | |
| right_notch_w=2.2, right_notch_h=1.8, right_notch_y=0.0, | |
| notch_r=0.6, | |
| chamfer=0.6, | |
| bottom_slot_w=3.1, | |
| bottom_slot_h=2.5, | |
| bottom_slot_r=0.6 | |
| ); | |
| connector_cc = 25.0; // center-to-center spacing along X (mm) | |
| connector_y_offset = 0.0; // vertical offset of the pair (mm) | |
| /** /// <summary>Optional shallow bezel recess on top face.</summary> */ | |
| front_bezel_depth = 1.0; // 0 disables | |
| front_bezel_w = 1.8; | |
| /** /// <summary>Optional legacy stiffening rings (set to 0 to disable).</summary> */ | |
| boss_ring_w = 0.0; | |
| boss_ring_h = 0.0; | |
| rear_collar_w = 0.0; | |
| rear_collar_h = 0.0; | |
| /** /// <summary>Downward connector lip (notch-safe), like the Gira plate.</summary> */ | |
| connector_lip_w = 2.0; // radial thickness of the lip (mm) | |
| connector_lip_h = 4.0; // downward height of the lip (mm) | |
| /** /// <summary>Label settings (text above each connector on the top surface).</summary> */ | |
| label_enable = true; | |
| label_left = "Player 1"; | |
| label_right = "Player 2"; | |
| label_font = "DejaVu Sans:style=Bold"; | |
| label_size = 4.0; | |
| label_mode = "inset"; // "emboss" | "inset" | |
| label_height = 0.8; // used when label_mode="emboss" | |
| label_depth = 0.6; // used when label_mode="inset" | |
| label_gap = 3.5; // distance from opening to text baseline (mm) | |
| label_dx_left = 0.0; // fine X offset left label | |
| label_dx_right = 0.0; // fine X offset right label | |
| label_track_center = true; // keep centered above each connector, then add dx | |
| //============================== Derived values ===============================// | |
| sleeve_id = sleeve_od - 2*sleeve_wall; | |
| sleeve_len = sleeve_extra_below; // sleeve extends downwards (z negative) | |
| // Opening height incl. bezel clearance (for label baseline) | |
| h_open = get(connector_cfg,"h") + 2*get(connector_cfg,"bezel_extra"); | |
| label_baseline_y = connector_y_offset + (h_open/2) + label_gap; | |
| //============================== Top-level render =============================// | |
| scaled() unit_onepiece(); | |
| /** | |
| * /// <summary> | |
| * /// Integrated one-piece panel with: cover, sleeve, downward connector lips, optional rings, labels. | |
| * /// </summary> | |
| */ | |
| module unit_onepiece(){ | |
| difference(){ | |
| // ----- SOLID UNION: cover + sleeve + underside features + (emboss labels) ----- | |
| union(){ | |
| // (A) cover with real top roundover | |
| cover_with_roundover(cover_od, cover_thickness, cover_roundover_r); | |
| // (B) sleeve downwards from cover underside (z = [-sleeve_len, 0]) | |
| translate([0,0,-sleeve_len]) | |
| cylinder(h=sleeve_len, d=sleeve_od, center=false); | |
| // (C) downward connector lips (notch-safe) | |
| if (connector_lip_h > 0 && connector_lip_w > 0){ | |
| connector_lip_at(-connector_cc/2, connector_y_offset, connector_lip_w, connector_lip_h); | |
| connector_lip_at(+connector_cc/2, connector_y_offset, connector_lip_w, connector_lip_h); | |
| } | |
| // (D) optional legacy stiffening rings | |
| if (boss_ring_h > 0 && boss_ring_w > 0){ | |
| translate([-connector_cc/2, connector_y_offset, -boss_ring_h]) | |
| linear_extrude(height=boss_ring_h) | |
| connector_ring_annulus_2d(connector_cfg, boss_ring_w); | |
| translate([+connector_cc/2, connector_y_offset, -boss_ring_h]) | |
| linear_extrude(height=boss_ring_h) | |
| connector_ring_annulus_2d(connector_cfg, boss_ring_w); | |
| } | |
| if (rear_collar_h > 0 && rear_collar_w > 0){ | |
| translate([-connector_cc/2, connector_y_offset, -rear_collar_h]) | |
| linear_extrude(height=rear_collar_h) | |
| connector_ring_annulus_2d(connector_cfg, rear_collar_w); | |
| translate([+connector_cc/2, connector_y_offset, -rear_collar_h]) | |
| linear_extrude(height=rear_collar_h) | |
| connector_ring_annulus_2d(connector_cfg, rear_collar_w); | |
| } | |
| // (E) Emboss labels (add material) if selected | |
| if (label_enable && label_size > 0 && label_mode == "emboss" && label_height > 0){ | |
| // compute X positions using let() to avoid assignments | |
| let( | |
| xL = -connector_cc/2 + (label_track_center ? 0 : label_dx_left) + (label_track_center ? label_dx_left : 0), | |
| xR = +connector_cc/2 + (label_track_center ? 0 : label_dx_right) + (label_track_center ? label_dx_right : 0) | |
| ){ | |
| embossed_label(label_left, xL, label_baseline_y, cover_thickness, label_size, label_height, label_font); | |
| embossed_label(label_right, xR, label_baseline_y, cover_thickness, label_size, label_height, label_font); | |
| } | |
| } | |
| } | |
| // ----- CENTRAL BORE: through the SLEEVE ONLY (stops at cover underside) ----- | |
| translate([0,0,-sleeve_len-0.05]) | |
| cylinder(h=sleeve_len + 0.1, d=sleeve_id, center=false); | |
| // ----- CONNECTOR CUTOUTS: through the cover thickness only ----- | |
| translate([-connector_cc/2, connector_y_offset, 0]) | |
| connector_cutout(connector_cfg, cover_thickness + 0.06, false); | |
| translate([+connector_cc/2, connector_y_offset, 0]) | |
| connector_cutout(connector_cfg, cover_thickness + 0.06, false); | |
| // ----- OPTIONAL BEZEL RECESS (shallow) on top face ----- | |
| if (front_bezel_depth > 0 && front_bezel_w > 0){ | |
| let(bezel_h = min(front_bezel_depth, cover_thickness - 0.3)) | |
| if (bezel_h > 0){ | |
| front_bezel_at(connector_cfg, -connector_cc/2, connector_y_offset, cover_thickness, front_bezel_w, bezel_h, 1.0, notch_safe=true); | |
| front_bezel_at(connector_cfg, +connector_cc/2, connector_y_offset, cover_thickness, front_bezel_w, bezel_h, 1.0, notch_safe=true); | |
| } | |
| } | |
| // ----- INSET LABELS (engraved) if selected ----- | |
| if (label_enable && label_size > 0 && label_mode == "inset" && label_depth > 0){ | |
| let(engr_h = min(label_depth, max(cover_thickness - 0.2, 0.01))) | |
| if (engr_h > 0){ | |
| let( | |
| xL2 = -connector_cc/2 + (label_track_center ? 0 : label_dx_left) + (label_track_center ? label_dx_left : 0), | |
| xR2 = +connector_cc/2 + (label_track_center ? 0 : label_dx_right) + (label_track_center ? label_dx_right : 0) | |
| ){ | |
| engraved_label(label_left, xL2, label_baseline_y, cover_thickness, label_size, engr_h, label_font); | |
| engraved_label(label_right, xR2, label_baseline_y, cover_thickness, label_size, engr_h, label_font); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| //============================== Cover geometry ===============================// | |
| /** | |
| * /// <summary> | |
| * /// Disk-shaped cover with a TRUE top outer-edge roundover of radius r. | |
| * /// Uses minkowski() and intersection to avoid rounding the bottom edge. | |
| * /// </summary> | |
| */ | |
| module cover_with_roundover(d, t, r){ | |
| r_eff = max(0, min(r, t - 0.1)); // keep a small straight section | |
| if (r_eff <= 0){ | |
| cylinder(h=t, d=d, center=false); | |
| } else { | |
| intersection(){ | |
| // Clip to exact height t so only the TOP edge is rounded | |
| translate([0,0,t/2]) cube([d*2, d*2, t], center=true); | |
| minkowski(){ | |
| // inner core (reduced diameter so minkowski restores 'd') | |
| linear_extrude(height=max(t - r_eff, 0.01)) | |
| circle(d=max(d - 2*r_eff, 0.1)); | |
| sphere(r=r_eff); | |
| } | |
| } | |
| } | |
| } | |
| //============================== NEW: Connector lip ===========================// | |
| /** | |
| * /// <summary> | |
| * /// Downward connector lip (notch-safe) built as a true tube wall: | |
| * /// outer wall = offset(+lip_w) of the real opening; inner wall = exact opening. | |
| * /// This guarantees the inner aperture is unchanged and all material grows outward. | |
| * /// </summary> | |
| * /// <param name="xc">X center</param> | |
| * /// <param name="yc">Y center</param> | |
| * /// <param name="lip_w">Radial wall thickness (mm)</param> | |
| * /// <param name="lip_h">Downward height (mm)</param> | |
| */ | |
| module connector_lip_at(xc, yc, lip_w, lip_h){ | |
| if (lip_w > 0 && lip_h > 0){ | |
| translate([xc, yc, -lip_h]) | |
| difference(){ | |
| // Outer shell: expanded (offset outward) real opening | |
| linear_extrude(height=lip_h) | |
| offset(delta=lip_w) | |
| connector_profile_with_notch_2d(connector_cfg); | |
| // Hollow core: exact real opening (same as cover hole), ensures no inward shrink | |
| linear_extrude(height=lip_h + 0.02) | |
| connector_profile_with_notch_2d(connector_cfg); | |
| } | |
| } | |
| } | |
| //============================== Labels =======================================// | |
| /** /// <summary>Adds raised text on the top surface (emboss).</summary> */ | |
| module embossed_label(txt, xc, y_base, top_z, size, height, font_name){ | |
| if (txt != "" && height > 0 && size > 0) | |
| translate([xc, y_base, top_z]) | |
| linear_extrude(height=height) | |
| text(text=txt, size=size, font=font_name, halign="center", valign="baseline", $fn=64); | |
| } | |
| /** /// <summary>Engraves text into the top surface (inset).</summary> */ | |
| module engraved_label(txt, xc, y_base, top_z, size, depth, font_name){ | |
| if (txt != "" && depth > 0 && size > 0) | |
| translate([xc, y_base, top_z - depth]) | |
| linear_extrude(height=depth + 0.02) | |
| text(text=txt, size=size, font=font_name, halign="center", valign="baseline", $fn=64); | |
| } | |
| //============================== Connector profile reuse ======================// | |
| /** /// <summary>NES/SNES Classic connector opening config (struct-like vector).</summary> */ | |
| function make_connector( | |
| w=15.5, h=10.5, r=1.0, bezel_extra=0.30, | |
| left_notch_w=2.2, left_notch_h=1.8, left_notch_y=0.0, | |
| right_notch_w=2.2, right_notch_h=1.8, right_notch_y=0.0, | |
| notch_r=0.6, | |
| chamfer=0.6, | |
| bottom_slot_w=3.1, | |
| bottom_slot_h=2.5, | |
| bottom_slot_r=0.6 | |
| ) = [ | |
| ["w", w], ["h", h], ["r", r], ["bezel_extra", bezel_extra], | |
| ["left_notch_w", left_notch_w], ["left_notch_h", left_notch_h], ["left_notch_y", left_notch_y], | |
| ["right_notch_w", right_notch_w], ["right_notch_h", right_notch_h], ["right_notch_y", right_notch_y], | |
| ["notch_r", notch_r], | |
| ["chamfer", chamfer], | |
| ["bottom_slot_w", bottom_slot_w], | |
| ["bottom_slot_h", bottom_slot_h], | |
| ["bottom_slot_r", bottom_slot_r] | |
| ]; | |
| /** /// <summary>Tiny key-value getter for our struct-like vectors.</summary> */ | |
| function get(cfg, key, default_val=0) = | |
| let(idx = search([key], [ for (i=[0:len(cfg)-1]) cfg[i][0] ])[0]) | |
| (idx==[]) ? default_val : cfg[idx][1]; | |
| /** /// <summary>2D union of the connector opening WITHOUT the bottom inset notch.</summary> */ | |
| module connector_profile_2d(cfg){ | |
| w = get(cfg,"w"); h = get(cfg,"h"); rr = get(cfg,"r"); | |
| bezel = get(cfg,"bezel_extra"); | |
| lnw = get(cfg,"left_notch_w"); lnh = get(cfg,"left_notch_h"); lny = get(cfg,"left_notch_y"); | |
| rnw = get(cfg,"right_notch_w"); rnh = get(cfg,"right_notch_h"); rny = get(cfg,"right_notch_y"); | |
| nr = get(cfg,"notch_r"); | |
| union(){ | |
| rounded_rect2d(w + 2*bezel, h + 2*bezel, rr); | |
| if (lnw > 0 && lnh > 0) | |
| translate([-(w/2 + bezel - 0.01), lny]) | |
| translate([-lnw/2, 0]) | |
| rounded_rect2d(lnw, lnh, nr); | |
| if (rnw > 0 && rnh > 0) | |
| translate([(w/2 + bezel - 0.01), rny]) | |
| translate([+rnw/2, 0]) | |
| rounded_rect2d(rnw, rnh, nr); | |
| } | |
| } | |
| /** | |
| * /// <summary> | |
| * /// 2D union of the REAL connector opening INCLUDING the bottom inset notch | |
| * /// (matches the true through-hole outline at the top surface). | |
| * /// </summary> | |
| */ | |
| module connector_profile_with_notch_2d(cfg){ | |
| w = get(cfg,"w"); h = get(cfg,"h"); rr = get(cfg,"r"); | |
| bezel = get(cfg,"bezel_extra"); | |
| lnw = get(cfg,"left_notch_w"); lnh = get(cfg,"left_notch_h"); lny = get(cfg,"left_notch_y"); | |
| rnw = get(cfg,"right_notch_w"); rnh = get(cfg,"right_notch_h"); rny = get(cfg,"right_notch_y"); | |
| nr = get(cfg,"notch_r"); | |
| bsw = get(cfg,"bottom_slot_w"); | |
| bsh = get(cfg,"bottom_slot_h"); | |
| bsr = get(cfg,"bottom_slot_r"); | |
| difference(){ | |
| union(){ | |
| rounded_rect2d(w + 2*bezel, h + 2*bezel, rr); | |
| if (lnw > 0 && lnh > 0) | |
| translate([-(w/2 + bezel - 0.01), lny]) | |
| translate([-lnw/2, 0]) | |
| rounded_rect2d(lnw, lnh, nr); | |
| if (rnw > 0 && rnh > 0) | |
| translate([(w/2 + bezel - 0.01), rny]) | |
| translate([+rnw/2, 0]) | |
| rounded_rect2d(rnw, rnh, nr); | |
| } | |
| if (bsw > 0 && bsh > 0) | |
| translate([0, -(h/2 + bezel) + bsh/2]) | |
| rounded_rect2d(bsw, bsh, bsr); | |
| } | |
| } | |
| /** | |
| * /// <summary> | |
| * /// Subtracts the connector profile with an INSET bottom notch (true through-hole). | |
| * /// Use 'depth = cover_thickness + epsilon' for cover-only subtraction. | |
| * /// </summary> | |
| */ | |
| module connector_cutout(cfg, depth, pilots=false){ | |
| w = get(cfg,"w"); h = get(cfg,"h"); rr = get(cfg,"r"); | |
| bezel = get(cfg,"bezel_extra"); | |
| lnw = get(cfg,"left_notch_w"); lnh = get(cfg,"left_notch_h"); lny = get(cfg,"left_notch_y"); | |
| rnw = get(cfg,"right_notch_w"); rnh = get(cfg,"right_notch_h"); rny = get(cfg,"right_notch_y"); | |
| nr = get(cfg,"notch_r"); | |
| chamfer = get(cfg,"chamfer"); | |
| bsw = get(cfg,"bottom_slot_w"); | |
| bsh = get(cfg,"bottom_slot_h"); | |
| bsr = get(cfg,"bottom_slot_r"); | |
| difference(){ | |
| linear_extrude(height=depth) | |
| difference(){ | |
| union(){ | |
| rounded_rect2d(w + 2*bezel, h + 2*bezel, rr); | |
| if (lnw > 0 && lnh > 0) | |
| translate([-(w/2 + bezel - 0.01), lny]) | |
| translate([-lnw/2, 0]) | |
| rounded_rect2d(lnw, lnh, nr); | |
| if (rnw > 0 && rnh > 0) | |
| translate([(w/2 + bezel - 0.01), rny]) | |
| translate([+rnw/2, 0]) | |
| rounded_rect2d(rnw, rnh, nr); | |
| } | |
| if (bsw > 0 && bsh > 0) | |
| translate([0, -(h/2 + bezel) + bsh/2]) | |
| rounded_rect2d(bsw, bsh, bsr); | |
| } | |
| if (pilots){ | |
| linear_extrude(height=depth) square([w, 0.2], center=true); | |
| linear_extrude(height=depth) square([0.2, h], center=true); | |
| } | |
| } | |
| // Cosmetic micro-chamfer at the very front edge | |
| if (chamfer > 0){ | |
| translate([0,0,-0.01]) | |
| linear_extrude(height=chamfer) | |
| offset(delta=+chamfer) | |
| rounded_rect2d(w + 2*bezel, h + 2*bezel, rr); | |
| } | |
| } | |
| /** /// <summary>Front bezel recess generator (notch-safe annulus).</summary> */ | |
| module front_bezel_at(cfg, xc, yc, front_top_z, bezel_w, bezel_h, scale_factor=1.0, notch_safe=true){ | |
| translate([xc, yc, front_top_z - bezel_h]) | |
| linear_extrude(height=bezel_h + 0.02, scale=scale_factor) | |
| if (notch_safe) | |
| connector_ring_annulus_with_notch_2d(cfg, bezel_w); | |
| else | |
| connector_ring_annulus_2d(cfg, bezel_w); | |
| } | |
| /** /// <summary>Annulus helper without notch.</summary> */ | |
| module connector_ring_annulus_2d(cfg, ring_w){ | |
| difference(){ | |
| offset(delta=ring_w) connector_profile_2d(cfg); | |
| connector_profile_2d(cfg); | |
| } | |
| } | |
| /** /// <summary>Annulus helper with real notch outline.</summary> */ | |
| module connector_ring_annulus_with_notch_2d(cfg, ring_w){ | |
| difference(){ | |
| offset(delta=ring_w) connector_profile_with_notch_2d(cfg); | |
| connector_profile_with_notch_2d(cfg); | |
| } | |
| } | |
| //============================== Utility geometry =============================// | |
| /** /// <summary>2D rounded rectangle helper.</summary> */ | |
| module rounded_rect2d(w, h, r){ | |
| offset(r=r) offset(r=-r) square([w-2*r, h-2*r], center=true); | |
| } |
Comments are disabled for this gist.