// CyberDeck case — TYPEWRITER // Angled-riser aesthetic: keyboard sits low and forward, display is // propped up and back at a fixed 35 degree typing angle on two side // pylons (classic "cyberdeck" convention borrowed from portable // typewriter proportions). Pi + LoRa board live in the riser base under // the display, ahead of the keyboard well. // Fits: Raspberry Pi 4/5, Meshtastic-class LoRa board, 5-7" DSI/HDMI display, // BB Q10/Q20-class keyboard. See ../bom.json for source hardware. // // Print settings: 0.2mm layer height, 30% infill (the display pylons carry // load and want more infill than the base tray), supports ON under the // overhanging display shelf. PLA is fine; this design has no exposed hinge. // // Compile: openscad -o typewriter.stl typewriter.scad pi_w = 85; pi_d = 56; pi_h = 17; lora_w = 51; lora_d = 26; lora_h = 14; disp_w = 194; disp_d = 110; disp_h = 20; kb_w = 116; kb_d = 43; kb_h = 10; wall = 3; gap = 3; tilt = 35; // display angle, degrees off horizontal pylon_h = 70; // pylon height at the back base_w = max_(kb_w, disp_w) + 2*(wall+gap); base_d = kb_d + pi_d + lora_d + 4*(wall+gap); base_h = pi_h + wall + 6; function max_(a,b) = a > b ? a : b; module base_tray() { difference(){ cube([base_w, base_d, base_h]); translate([wall, wall, wall]) cube([base_w-2*wall, base_d-2*wall, base_h]); // keyboard well, front translate([(base_w-kb_w)/2, wall+gap, wall]) cube([kb_w, kb_d, kb_h+2]); } // Pi standoffs behind the keyboard well py = wall+gap+kb_d+gap; for (p=[[wall+8,py+8],[wall+8+58,py+8],[wall+8,py+8+49],[wall+8+58,py+8+49]]) translate([p[0], p[1], wall]) cylinder(r=2.5, h=6, $fn=24); // LoRa mount ledge, rear strip translate([wall+6, base_d-wall-lora_d-6, wall]) cube([lora_w, lora_d, 4]); // front lip badge (embossed) — visible to the typist translate([base_w/2, wall+1, base_h]) linear_extrude(height=0.6) text("PWP CYBERDECK", size=5, halign="center", valign="center", font="Liberation Sans:style=Bold"); } module pylon(mirror_x=false) { // right-triangle side wall that carries the display shelf at `tilt` x = mirror_x ? -1 : 1; points = [[0,0],[0,pylon_h],[pylon_h/tan(90-tilt),0]]; linear_extrude(height=wall) polygon(points=[[0,0],[0,pylon_h], [pylon_h*cos(tilt)/sin(tilt),0]]); } module display_shelf() { // angled shelf the display sits on, between the two pylons shelf_w = disp_w + 2*gap; translate([0,0,0]) rotate([tilt-90,0,0]) difference(){ cube([shelf_w, disp_d+2*wall, wall]); translate([wall, wall, -1]) cube([shelf_w-2*wall, disp_d, wall+2]); } } // assemble: base, then pylons + shelf offset behind it in the layout translate([0,0,0]) base_tray(); translate([base_w+20, 0, 0]) { pylon(); translate([0, base_d-wall, 0]) mirror([1,0,0]) translate([-wall,0,0]) pylon(); } translate([base_w+20, base_d/2 - (disp_d+2*wall)/2, pylon_h*0.9]) display_shelf(); // wordmark engraved into the display shelf underside — visible when the // deck is folded flat for transport translate([base_w+20+ (disp_w+2*gap)/2, base_d/2, 0.5]) rotate([tilt-90,0,0]) linear_extrude(height=0.5) text("PERFECT WORLD PROJECT", size=4, halign="center", valign="center", font="Liberation Sans:style=Bold");