Browse Source

Initial import of e-paper door case CAD files

OpenSCAD source files and rendered STLs for the e-paper display door case
enclosure, including CPU case, EPD case, lid, and bottom components.
ZiB 4 months ago
commit
6ab6ebbbe1
10 changed files with 485 additions and 0 deletions
  1. 93 0
      GDEY0583T81.scad
  2. 8 0
      bottom.scad
  3. BIN
      bottom.stl
  4. 255 0
      cpu_case.scad
  5. 19 0
      ee04.scad
  6. BIN
      ee04.stl
  7. 100 0
      epd_case.scad
  8. BIN
      epd_case.stl
  9. 10 0
      lid.scad
  10. BIN
      lid.stl

+ 93 - 0
GDEY0583T81.scad

@@ -0,0 +1,93 @@
+// GDEY0583T81 mockup
+//
+// FPC dimensions from GDEY0583T81 mechanical drawing:
+//   right edge:   55.47 mm from display right  →  69.93 mm from display left
+//   stiffened section (at glass edge): 14.50 mm wide, 6.00 mm deep
+//   cable section (remainder):         12.50 mm wide, 18.00 mm long
+//   total extension: 24.00 mm from display Y+ face; thickness 0.30 mm
+//   contact zone at tip: 11.50 mm wide × 2.50 mm deep (24 pins, 0.5 mm pitch)
+//
+// Optional bend parameters (all default to flat/no-bend):
+//   fpc_bend_start  — mm from display Y+ face where bend begins (undef = flat)
+//   fpc_bend_r      — bend radius mm (default 4.0)
+//   fpc_bend_angle  — bend angle degrees (default 90; arc clip assumes ≤ 90°)
+//   fpc_post_clip   — truncate post-bend segment to this length in mm (undef = full)
+
+module GDEY0583T81(fpc_bend_start=undef, fpc_bend_r=4.0, fpc_bend_angle=90, fpc_post_clip=undef) {
+    dw = 125.4;   dd = 99.5;    dt = 1.2;    // overall body
+    aw = 118.78;  ad = 88.22;                 // active area
+    ax = (dw - aw) / 2;                       // active area X offset (symmetric)
+    ay = 3.30;                                // active area Y offset from Y- edge (per drawing)
+
+    fpc_right   = dw - 55.47;  // FPC right edge X (= 69.93 mm from display left)
+    fpc_w_wide  = 14.50;
+    fpc_w_cable = 12.50;
+    fpc_stiff   = 6.00;
+    fpc_len     = 24.00;
+    fpc_t       = 0.30;
+    contact_w   = 11.50;
+    contact_d   = 2.50;
+    fpc_xl      = fpc_right - fpc_w_cable;   // cable left edge X
+
+    color([0.32, 0.32, 0.32])
+        cube([dw, dd, dt]);
+
+    color([0.82, 0.82, 0.82])
+        translate([ax, ay, dt - 0.01])
+            cube([aw, ad, 0.1]);
+
+    color([0.65, 0.65, 0.65]) {
+        if (is_undef(fpc_bend_start)) {
+            // Flat cable (no bend)
+            translate([fpc_right - fpc_w_wide, dd, 0])
+                cube([fpc_w_wide, fpc_stiff, fpc_t]);
+            translate([fpc_xl, dd + fpc_stiff, 0])
+                cube([fpc_w_cable, fpc_len - fpc_stiff, fpc_t]);
+        } else {
+            _bs = fpc_bend_start;
+
+            // Pre-bend straight sections
+            if (_bs > 0)
+                translate([fpc_right - fpc_w_wide, dd, 0])
+                    cube([fpc_w_wide, min(fpc_stiff, _bs), fpc_t]);
+            if (_bs > fpc_stiff)
+                translate([fpc_xl, dd + fpc_stiff, 0])
+                    cube([fpc_w_cable, _bs - fpc_stiff, fpc_t]);
+
+            // Bend arc: quarter-annular tube sweeping in YZ plane, axis along X.
+            // rotate([0,90,0]) cylinder → axis X, cross-section circle in YZ at origin.
+            // Clip cube (Y≥0, Z≥0) selects the quadrant from (Y=0,Z=r) to (Y=r,Z=0),
+            // which is cable-entry (flat, at Z=0) to cable-exit (going -Z).
+            // Arc center placed at world (fpc_xl, dd+_bs, -fpc_bend_r).
+            translate([fpc_xl, dd + _bs, -fpc_bend_r])
+                intersection() {
+                    difference() {
+                        rotate([0, 90, 0])
+                            cylinder(r=fpc_bend_r + fpc_t, h=fpc_w_cable, $fn=32);
+                        rotate([0, 90, 0])
+                            cylinder(r=fpc_bend_r, h=fpc_w_cable, $fn=32);
+                    }
+                    cube([fpc_w_cable, fpc_bend_r + fpc_t + 1, fpc_bend_r + fpc_t + 1]);
+                }
+
+            // Post-bend straight segment: exits arc at (Y=dd+_bs+r, Z=-r), going -Z
+            _arc_len   = fpc_bend_r * fpc_bend_angle * PI / 180;
+            _post_len  = fpc_len - _bs - _arc_len;
+            _post_show = is_undef(fpc_post_clip) ? _post_len : min(fpc_post_clip, _post_len);
+            if (_post_show > 0)
+                translate([fpc_xl, dd + _bs + fpc_bend_r, -fpc_bend_r - _post_show])
+                    cube([fpc_w_cable, fpc_t, _post_show]);
+        }
+    }
+
+    // Contact pads shown only for flat cable (position undefined after bend)
+    if (is_undef(fpc_bend_start))
+        color([0.80, 0.70, 0.25])
+            translate([fpc_right - fpc_w_cable + (fpc_w_cable - contact_w) / 2,
+                       dd + fpc_len - contact_d,
+                       -0.01])
+                cube([contact_w, contact_d, fpc_t + 0.02]);
+}
+
+// Standalone render — runs only when this file is opened directly, not when use<>'d
+GDEY0583T81();

+ 8 - 0
bottom.scad

@@ -0,0 +1,8 @@
+include <cpu_case.scad>
+
+SHOW_BASE  = false;
+SHOW_BOARD = false;
+SHOW_LID   = false;
+
+// Base is already floor-down, cavity-up — correct print orientation at origin
+base();

BIN
bottom.stl


+ 255 - 0
cpu_case.scad

@@ -0,0 +1,255 @@
+// ============================================================
+//  XIAO ePaper Display Board EE04 — 3D-Printed Case
+//  OpenSCAD parametric model
+// ============================================================
+use <ee04.scad>
+
+/* [Preview] */
+SHOW_BOARD  = true;
+SHOW_LID    = true;
+SHOW_BASE   = true;
+EXPLODE     = 65;      // mm to pull lid out in Y- for inspection (try 40)
+
+/* [Board Dimensions — from EE04 STL] */
+PCB_L = 80.00;   // board length  (case_x axis)
+PCB_W = 41.22;   // board width   (case_y axis)
+PCB_T =  1.93;   // PCB thickness
+
+// Component heights measured from PCB bottom face:
+COMP_MAX_Z  = 7.29;   // tallest component (XIAO module)
+COMP_SIDE_Z = 3.82;   // tallest component on +Y wall (buttons, USB-C)
+
+/* [Cutout Positions — from STL geometry, PCB-origin-relative] */
+
+// ---- +Y wall: Sliding power switch ----
+PWR_CX      =  10.3;   // PCB-relative case_x centre
+PWR_W       =   5.0;   // slot width
+PWR_H       =   2.5;   // slot height
+PWR_CZ      =   3.8;   // height above PCB bottom
+
+// ---- +Y wall: USB-C port ----
+USBC_CX     =  65.65;
+USBC_W      =  11.5;
+USBC_H      =   4.8;
+USBC_CZ     =   4.4;
+
+// ---- +Y wall: 3× user buttons + 1× reset ----
+BTN_CX      = [48.4, 39.1, 29.8, 20.4];   // PCB-relative case_x centres
+BTN_D       =   4.5;
+BTN_CZ      =   3.7;
+
+/* [Case Parameters] */
+WALL          =  2.0;   // wall thickness
+FLOOR         =  2.0;   // base floor thickness (thicker for thread engagement)
+CORNER_R      =  2.5;   // XY corner fillet radius
+SCREW_D       =  3.2;   // M3 tap drill diameter
+BOSS_D        =  6.0;   // PCB standoff boss outer diameter
+BOSS_H        =  2.0;   // standoff boss height; PCB bottom sits flush on boss top
+
+/* [PCB Standoff Positions — relative to PCB origin] */
+PCB_BOSS_X1   =  2.5;
+PCB_BOSS_X2   =  PCB_L - 2.5;
+PCB_BOSS_Y1   =  2.5;
+PCB_BOSS_Y2   =  PCB_W - 2.5;
+
+/* [Interior Clearances — PCB edge to interior wall face] */
+CLR_XN   =   5.0;   // X- side
+CLR_XP   =  15.0;   // X+ side (JST cable routing)
+CLR_YN   =  15.0;   // Y- side (FPC routing; lid inserts from here)
+CLR_YP   =   0.5;   // Y+ side (snug against button/USB-C wall)
+CLR_LID  =   5.0;   // from tallest component top to lid underside
+
+/* [Sliding Lid] */
+LID_T       =  1.5;   // lid ceiling thickness
+FLANGE_H    =  3.0;   // Z height of retention flanges (base + lid); drives lid placement and Y- wall step
+FLANGE_W    =  FLANGE_H * tan(30);   // flange width — 30° from vertical (60° from horizontal), printable without support
+SLIDE_CLEAR =  0.40;  // clearance between flange/rib and groove/channel on all mating faces (0.4 mm suits typical FDM tolerances)
+
+/* [Computed] */
+PCB_Z    = FLOOR + BOSS_H;
+
+// Base inner height: floor to lid underside ≈ BASE_H (flange rests on groove floor)
+BASE_INNER_H = BOSS_H + COMP_MAX_Z + CLR_LID;
+BASE_H       = FLOOR + BASE_INNER_H;
+
+PCB_OX   = WALL + CLR_XN;
+PCB_OY   = WALL + CLR_YN;
+
+CAV_L    = CLR_XN + PCB_L + CLR_XP;
+CAV_W    = CLR_YN + PCB_W + CLR_YP;
+OUT_L    = CAV_L + 2*WALL;
+OUT_W    = CAV_W + 2*WALL;
+
+LID_H     = FLANGE_H + LID_T;
+LID_Y_LEN = CAV_W;   // flange length; lid Y+ end stops against Y+ interior wall
+
+// ============================================================
+//  HELPERS
+// ============================================================
+module rounded_box(l, w, h, r) {
+    hull()
+        for (dx = [r, l-r], dy = [r, w-r])
+            translate([dx, dy, 0]) cylinder(r=r, h=h, $fn=32);
+}
+
+// Standoff boss: solid cylinder with through-hole (hole continues into floor via base diff)
+module pcb_boss(px, py) {
+    translate([PCB_OX + px, PCB_OY + py, FLOOR])
+        difference() {
+            cylinder(d=BOSS_D, h=BOSS_H + 0.01, $fn=24);
+            translate([0, 0, -0.1])
+                cylinder(d=SCREW_D * 0.7, h=BOSS_H + 0.2, $fn=18);
+        }
+}
+
+// ============================================================
+//  BASE
+// ============================================================
+module base() {
+    color("#004B49") {
+        difference() {
+            rounded_box(OUT_L, OUT_W, BASE_H, CORNER_R);
+
+            // Interior cavity (open top)
+            translate([WALL, WALL, FLOOR])
+                cube([CAV_L, CAV_W, BASE_H]);
+
+            // ---- Boss screw holes through 50 % of floor ----
+            for (bx = [PCB_BOSS_X1, PCB_BOSS_X2])
+                for (by = [PCB_BOSS_Y1, PCB_BOSS_Y2])
+                    translate([PCB_OX + bx, PCB_OY + by, FLOOR * 0.5 - 0.1])
+                        cylinder(d=SCREW_D * 0.7, h=FLOOR * 0.5 + 0.2, $fn=18);
+
+            // ---- +Y wall cutouts ----
+
+            // Sliding power switch slot
+            translate([PCB_OX + PWR_CX - PWR_W/2,
+                       OUT_W - WALL - 0.1,
+                       PCB_Z + PWR_CZ - PWR_H/2])
+                cube([PWR_W, WALL + 0.2, PWR_H]);
+
+            // USB-C slot
+            translate([PCB_OX + USBC_CX - USBC_W/2,
+                       OUT_W - WALL - 0.1,
+                       PCB_Z + USBC_CZ - USBC_H/2])
+                cube([USBC_W, WALL + 0.2, USBC_H]);
+
+            // 4× button holes (3 user + 1 reset)
+            for (bcx = BTN_CX)
+                translate([PCB_OX + bcx,
+                           OUT_W + 0.1,
+                           PCB_Z + BTN_CZ])
+                    rotate([90, 0, 0])
+                        cylinder(d=BTN_D, h=WALL + 0.3, $fn=32);
+
+            // ---- Y- wall step for lid flange clearance ----
+            // Remove the full Y- wall above z=BASE_H-FLANGE_H-SLIDE_CLEAR so the lid
+            // flanges can enter freely from Y-.
+            translate([-0.1, -0.1, BASE_H - FLANGE_H - SLIDE_CLEAR])
+                cube([OUT_L + 0.2, WALL + 0.2, FLANGE_H + SLIDE_CLEAR + 0.1]);
+        }
+
+        // Standoff bosses (added outside diff so cavity doesn't subtract them)
+        pcb_boss(PCB_BOSS_X1, PCB_BOSS_Y1);
+        pcb_boss(PCB_BOSS_X2, PCB_BOSS_Y1);
+        pcb_boss(PCB_BOSS_X1, PCB_BOSS_Y2);
+        pcb_boss(PCB_BOSS_X2, PCB_BOSS_Y2);
+    }
+
+    // Lid-retention flanges — right triangles, wide face flush with case top (z=BASE_H),
+    // tip pointing down to (WALL, BASE_H-FLANGE_H). Hypotenuse faces down-into-cavity;
+    // lid flanges slide underneath it for Z retention.
+    color("#2C3863") {
+        hull() {
+            translate([WALL, WALL, BASE_H - 0.01])
+                cube([FLANGE_W, CAV_W, 0.01]);
+            translate([WALL, WALL, BASE_H - FLANGE_H])
+                cube([0.01, CAV_W, 0.01]);
+        }
+        hull() {
+            translate([OUT_L - WALL - FLANGE_W, WALL, BASE_H - 0.01])
+                cube([FLANGE_W, CAV_W, 0.01]);
+            translate([OUT_L - WALL - 0.01, WALL, BASE_H - FLANGE_H])
+                cube([0.01, CAV_W, 0.01]);
+        }
+    }
+}
+
+// ============================================================
+//  LID  (slide-on; enters from Y- face, closes toward Y+)
+//  Print upside-down (ceiling on build plate).
+//  z=0 = bottom of flanges; z=FLANGE_H = ceiling underside.
+//  Flanges sit inside cavity and ride on base retention flange hypotenuses.
+// ============================================================
+module lid() {
+    // Flanges: right triangles in XZ; hypotenuse at reciprocal angle to base retention flanges.
+    // Wide vertical face at x=WALL+FLANGE_W (inner), tip at bottom-wall-face — same
+    // (-FLANGE_W, -FLANGE_H) hypotenuse slope as base flanges so they mate when lid slides in.
+    color("#2C3863") {
+        // Left (X-) flange
+        hull() {
+            translate([WALL + FLANGE_W - SLIDE_CLEAR - 0.01, 0, 0])
+                cube([0.01, LID_Y_LEN, FLANGE_H - SLIDE_CLEAR]);
+            translate([WALL + SLIDE_CLEAR, 0, -0.005])
+                cube([0.01, LID_Y_LEN, 0.01]);
+        }
+        // Right (X+) flange
+        hull() {
+            translate([OUT_L - WALL - FLANGE_W + SLIDE_CLEAR, 0, 0])
+                cube([0.01, LID_Y_LEN, FLANGE_H - SLIDE_CLEAR]);
+            translate([OUT_L - WALL - SLIDE_CLEAR - 0.01, 0, -0.005])
+                cube([0.01, LID_Y_LEN, 0.01]);
+        }
+
+        // Interior ribs — 2 mm wide, on cavity face of each flange
+        translate([WALL + FLANGE_W - SLIDE_CLEAR, 0, 0])
+            cube([2.0, LID_Y_LEN, FLANGE_H]);
+        translate([OUT_L - WALL - FLANGE_W + SLIDE_CLEAR - 2.0, 0, 0])
+            cube([2.0, LID_Y_LEN, FLANGE_H]);
+
+        // Y+ stop tabs — two 10 mm tabs at 1/3 and 2/3 of OUT_L, press against Y+ interior wall
+        translate([OUT_L/4 - 5, LID_Y_LEN - 3, FLANGE_H - 3])
+            cube([10, 3, 3]);
+        translate([3*OUT_L/4 - 5, LID_Y_LEN - 3, FLANGE_H - 3])
+            cube([10, 3, 3]);
+    }
+
+    color("#004B49") {
+        // Ceiling plate — matches base footprint (OUT_L × OUT_W) with CORNER_R rounding
+        translate([0, -WALL, FLANGE_H])
+            rounded_box(OUT_L, OUT_W, LID_T, CORNER_R);
+
+        // Y- lip — same rounded_box profile clipped to the Y- wall zone so the
+        // lip corners match the base exterior corners
+        intersection() {
+            translate([0, -WALL, -SLIDE_CLEAR])
+                rounded_box(OUT_L, OUT_W, FLANGE_H + SLIDE_CLEAR, CORNER_R);
+            translate([-0.1, -WALL - 0.1, -SLIDE_CLEAR - 0.1])
+                cube([OUT_L + 0.2, WALL + 0.2, FLANGE_H + SLIDE_CLEAR + 0.2]);
+        }
+    }
+}
+
+// ============================================================
+//  BOARD PLACEMENT
+//  EE04() XY-normalises the STL (board left/front at origin).
+//  +1.925 corrects for STL native Z (PCB bottom at Z=−1.925) so
+//  the PCB bottom face lands exactly at PCB_Z.
+// ============================================================
+module stl_board() {
+    translate([PCB_OX, PCB_OY, PCB_Z])
+        EE04();
+}
+
+// ============================================================
+//  ASSEMBLY
+// ============================================================
+if (SHOW_BASE)  base();
+
+if (SHOW_LID)
+    translate([0,
+               WALL - EXPLODE,
+               BASE_H - FLANGE_H])
+        lid();
+
+if (SHOW_BOARD) stl_board();

+ 19 - 0
ee04.scad

@@ -0,0 +1,19 @@
+// EE04 XIAO ePaper display board — STL wrapper
+// Requires ee04.stl in the same directory (183k triangles; too large to inline as polyhedron).
+//
+// Board origin: PCB bottom face at Z=0, bottom-left corner at (0,0).
+// X: 0..80.00 mm (board length)
+// Y: 0..41.22 mm (board width)
+// Z: 0 = PCB bottom; components extend upward.
+//
+// STL native axes after rotate([0,0,270]): Y→X, −X→Y, Z→Z.
+// translate([40, 20.5, 0]) handles XY normalisation.
+
+module EE04() {
+    color("darkgray", 0.85)
+        translate([40, 20.5, 0])
+            rotate([0, 0, 270])
+                import("./ee04.stl");
+}
+
+EE04();

BIN
ee04.stl


+ 100 - 0
epd_case.scad

@@ -0,0 +1,100 @@
+// GDEY0583T81 — Waveshare 5.83" ePaper Display Case
+use <GDEY0583T81.scad>
+// Display slides in from Y-; no Y- side wall
+// FPC cable exits toward Y+ then bends 90° toward Z- through backplate slot
+
+// --- Display Dimensions ---
+DISP_W = 125.4;   // overall width  (X)
+DISP_D = 99.5;    // overall depth  (Y)
+DISP_T = 1.2;     // thickness      (Z)
+
+// --- Active (Visible) Area ---
+ACT_W  = 118.78;  // active area width (X)
+ACT_D  = 88.22;   // active area depth (Y)
+
+// --- Case Parameters ---
+WALL     = 2.0;   // wall and backplate thickness
+LIP      = 1.5;   // front bezel lip thickness (Z, sits on top of display)
+TOL      = 0.3;   // per-side clearance for display fit (0.3 mm suits FDM sliding tolerances)
+CHAM       = 1.0;   // chamfer Z height at window opening
+CHAM_ANGLE = 60;    // chamfer face angle from vertical (deg); 45 = equal bevel, lower = less overhang
+CORNER_R = 2.5;   // XY corner fillet radius (matches EE04 case)
+BEZEL_Y    = 2.5;   // extra Y- bezel beyond the display's natural 3.30 mm border
+EXPLODE    = 0;    // mm to pull display mockup toward Y- in preview
+SHOW_DISP  = true; // show GDEY0583T81 mockup in preview
+FPC_BEND_R = 4.0;  // FPC cable bend radius toward Z- (starting at display Y+ edge)
+CLIP_Z     = 0;     // preview-only: mm to remove from Z+ (0 = full model; LIP reveals cavity; LIP+DISP_T reveals floor)
+
+// --- Derived Dimensions ---
+cav_w    = DISP_W + TOL * 2;
+cav_d    = DISP_D + TOL;       // tolerance on Y+ side only; Y- is open
+case_w   = cav_w + WALL * 2;
+case_h   = WALL + DISP_T + LIP;
+
+// FPC slot geometry — cable dims from 583.scad (12.5 mm wide, 0.3 mm thick;
+//   right edge 55.47 mm from display right edge)
+_fpc_x1  = WALL + TOL + DISP_W - 55.47 - 12.50 - 2.5;  // slot left edge (2.5 mm wider each side)
+_fpc_xw  = 12.50 + 5.0;                                  // slot width (5 mm wider than cable)
+_fpc_ro  = FPC_BEND_R + 0.30 + TOL;               // outer clearance radius (bend_r + fpc_t + tol)
+// max Y reached by arc at Z=0 (backplate bottom); drives minimum case_d
+_bend_my = BEZEL_Y + DISP_D + sqrt(_fpc_ro*_fpc_ro - (FPC_BEND_R - WALL)*(FPC_BEND_R - WALL));
+case_d   = max(cav_d + WALL + BEZEL_Y, _bend_my + WALL);
+
+_cham_xy = CHAM * tan(CHAM_ANGLE);  // horizontal expansion derived from angle
+
+// Active window position in case coordinates
+// X: symmetric (3.31 mm border each side)
+// Y: offset per drawing — 3.30 mm from Y- entry edge, 7.98 mm from Y+ (FPC) edge
+win_x  = WALL + TOL + (DISP_W - ACT_W) / 2;
+win_y  = 3.30 + BEZEL_Y;
+
+module rounded_box(l, w, h, r) {
+    hull()
+        for (dx = [r, l-r], dy = [r, w-r])
+            translate([dx, dy, 0]) cylinder(r=r, h=h, $fn=32);
+}
+
+module epd_case() {
+    difference() {
+        // Solid case body — open at Y=0 (no Y- wall) by construction
+        rounded_box(case_w, case_d, case_h, CORNER_R);
+
+        // Display cavity: slides in from Y=0; BEZEL_Y extends depth so display seats at Y=BEZEL_Y
+        translate([WALL, -0.01, WALL])
+            cube([cav_w, BEZEL_Y + cav_d + 0.01, DISP_T + TOL]);
+
+        // Active area window: straight portion + chamfered top edges
+        // Extends 0.01 mm into the display cavity to avoid a coplanar face with the mockup
+        translate([win_x, win_y, WALL + DISP_T - 0.01])
+            cube([ACT_W, ACT_D, LIP - CHAM + 0.02]);
+        hull() {
+            translate([win_x, win_y, case_h - CHAM])
+                cube([ACT_W, ACT_D, 0.01]);
+            translate([win_x - _cham_xy, win_y - _cham_xy, case_h])
+                cube([ACT_W + 2*_cham_xy, ACT_D + 2*_cham_xy, 0.01]);
+        }
+
+        // FPC cable slot — quarter-cylinder swept volume of cable arc from horizontal to vertical.
+        // Arc center at (Y=DISP_D, Z=WALL−FPC_BEND_R); first-quadrant slice (Y≥DISP_D, Z≥arc_center_z).
+        // Creates opening through backplate floor and clears Y+ wall material for bend.
+        translate([_fpc_x1, BEZEL_Y + DISP_D, WALL - FPC_BEND_R])
+            intersection() {
+                rotate([0, 90, 0])
+                    cylinder(r=_fpc_ro, h=_fpc_xw, $fn=32);
+                cube([_fpc_xw, _fpc_ro + 1, _fpc_ro + 1]);
+            }
+    }
+
+}
+
+color("#004B49")
+    intersection() {
+        epd_case();
+        cube([case_w + 1, case_d + 1,
+              ($preview && CLIP_Z > 0) ? max(0.01, case_h - CLIP_Z) : case_h + 1]);
+    }
+
+// Display mockup — seated at case origin; EXPLODE pulls it toward Y-
+if ($preview && SHOW_DISP)
+    translate([WALL + TOL, BEZEL_Y - EXPLODE, WALL])
+        GDEY0583T81(fpc_bend_start=0, fpc_bend_r=FPC_BEND_R, fpc_post_clip=2);

BIN
epd_case.stl


+ 10 - 0
lid.scad

@@ -0,0 +1,10 @@
+include <cpu_case.scad>
+
+SHOW_BASE  = false;
+SHOW_BOARD = false;
+SHOW_LID   = false;
+
+// Ceiling on build plate, flanges pointing up — matches the "print upside-down" note in cpu_case.scad
+translate([0, LID_Y_LEN, LID_H])
+    rotate([180, 0, 0])
+        lid();

BIN
lid.stl