Read this model as text
A hinged travel case for a tiny whoop, its charger and a row of 1S batteries, designed for PETG. Seen from the front with the lid open behind, the whoop sits on the left in a cradle that follows its ducts, the charger on the right in a drop-in frame whose two springs press it into the front right corner. A window in the front wall in front of the charger takes its charging cable and closes with a slider that clicks open and shut. The lid holds the batteries standing on their side in snap clips. Two pin hinges at the rear, each on one M3 bolt, and a snap latch at the front. A drop-in whoop insert with four corner springs lets a smaller whoop ride in the same cradle.
The image shows the solid OpenSCAD renders at part assembly · test_print false · show_contents false · whoop_wheelbase 80 · duct_d 50 · whoop_h 40 · insert_wheelbase 65 · insert_duct_d 36 · charger_l 90 · charger_w 45 · charger_h 20 · port_x 0 · port_z 10 · battery_count 8 · battery_l 62 · battery_w 13.5 · battery_t 9 · color_case SteelBlue.
Tiny whoop case with sprung drop-in frames, port slider and 1S battery clips
mick/whoop-case@1.2.0
Report
For a legal or policy problem: a license violation, personal data, somebody else’s work republished as their own. A model that prints badly is a comment, not a report.
Parameters
from sourceDescription
What is this
A hinged travel case for a tiny whoop, its charger and a row of 1S batteries, designed for PETG. Seen from the front with the lid open behind, the whoop sits on the left in a cradle that follows its ducts, the charger on the right in a drop-in frame whose two springs press it into the front right corner. A window in the front wall in front of the charger takes its charging cable and closes with a slider that clicks open and shut. The lid holds the batteries standing on their side in snap clips. Two pin hinges at the rear, each on one M3 bolt, and a snap latch at the front. A drop-in whoop insert with four corner springs lets a smaller whoop ride in the same cradle.
What you use it for
Carrying a whoop with its charger and spare 1S batteries in one box. The default whoop, a Meteor75 Pro II (80 mm wheelbase), drops straight into the cradle without an insert. For another whoop, print the whoop insert set to its wheelbase and duct diameter: its springs centre the whoop and hold it, and one insert takes whoops from 1.5 mm smaller to about 4 mm larger in reach than set. The charger frame takes a charger from 1.5 mm smaller to about 3.5 mm larger than set in length and width; the springs catch over its top edge. A different charger only needs a new frame. Push the charger or whoop straight down: the ramps on the spring pads push the springs aside.
Design notes
Everything prints without supports and the floor of the case is closed. The springs live in the drop-in frames, which have no floor of their own, so every leaf stands free on the bed and joins its frame only at its root. Printed upright and bent sideways, a leaf is loaded along its layers, which is what lets PETG take several millimetres of travel again and again. The charger frame is a U open to the front, so the charger meets the front wall and its port lines up with the window; a low rib on the floor locates the frame. The whoop insert follows the cradle wall; its four leaves are mirrored about both axes so the whoop centres without turning, and each pad pushes along the diagonal of its duct. The window has chamfered top corners so its top is an 8 mm bridge. The slider prints flat and runs in two upright rails; a tongue cut into it, which bends along its layers, carries a bump that clicks into a V groove at the open and the closed position. Battery arms hang from the lid plate and bend across their layers, which PETG takes at their small deflection; there is 1.6 mm between neighbouring arms. The base prints upright, the lid upside down, the frames upright, the slider flat with the bump up. Each hinge is base, lid, base on an M3 x 30 with a nut. With the defaults the case is about 176 x 118 mm and fits a 180 mm bed. test_print renders a coupon set: one hinge and the latch in both halves, the slider with its rails, one charger spring and one battery clip.
Parameters
part picks the assembly or one part in print orientation, test_print swaps it for the coupon set, show_contents shows the whoop, charger and batteries as ghosts. whoop_wheelbase (motor to motor across the diagonal), duct_d (outer diameter of one duct) and whoop_h (total height with camera) set the cradle and the case. insert_wheelbase and insert_duct_d set the smaller whoop the whoop insert holds. charger_l, charger_w and charger_h set the charger frame. port_x moves the window from the middle of the charger toward the whoop, port_z sets the height of its centre above the floor. battery_count, battery_l (with the plug), battery_w (the height as it stands) and battery_t set the battery clips. color_case is display only.
Use with your agent
{
"mcpServers": {
"remixcad": {
"type": "http",
"url": "https://remix-cad.vercel.app/api/mcp"
}
}
}get_model("mick/whoop-case@1.2.0")Returns the manifest, the source, the import closure and the license obligations. Full MCP setup.
Parameter table
Parsed from the Customizer annotations in main.scad| Name | Default | Range | Unit | Description |
|---|---|---|---|---|
| part | "assembly" | assembly, base, lid, charger_insert, whoop_insert, slider | ||
| test_print | false | |||
| show_contents | false | |||
| whoop_wheelbase | 80 | 60 to 120 step 0.5 | ||
| duct_d | 50 | 30 to 70 step 0.5 | ||
| whoop_h | 40 | 20 to 60 step 1 | ||
| insert_wheelbase | 65 | 50 to 110 step 0.5 | ||
| insert_duct_d | 36 | 25 to 65 step 0.5 | ||
| charger_l | 90 | 40 to 140 step 1 | ||
| charger_w | 45 | 20 to 80 step 1 | ||
| charger_h | 20 | 8 to 40 step 1 | ||
| port_x | 0 | -30 to 30 step 0.5 | ||
| port_z | 10 | 9 to 30 step 0.5 | ||
| battery_count | 8 | 0 to 12 step 1 | ||
| battery_l | 62 | 40 to 80 step 1 | ||
| battery_w | 13.5 | 8 to 20 step 0.5 | ||
| battery_t | 9 | 5 to 14 step 0.5 | ||
| color_case | "SteelBlue" | SteelBlue, White, DimGray, Black, FireBrick, Goldenrod, ForestGreen, MediumPurple |
Lineage
0 models depend on this oneOnly what this model came from and what came from it.
License
Whoever downloads this takes these obligations along- mick/whoop-case@1.2.0 is MIT
Source
main.scad is the entrypointmain.scad
// Tiny whoop case: the whoop, its charger and a row of 1S batteries in one hinged box.
// Printed in PETG. Seen from the front with the lid open behind, the whoop sits on
// the left in a cradle that follows its ducts and the charger on the right in a
// drop-in frame whose springs press it into the front right corner. A slider closes
// the window for the charging cable. The lid holds the batteries on their side in
// snap clips. A drop-in insert with four corner springs takes a smaller whoop.
// The springs live in the drop-in frames, which have no floor, so the floor of the
// case stays closed. Every part prints without supports.
//
// Coordinates: y = 0 at the rear (hinges), y = Sy at the front (latch). Seen from
// the front, the viewer's right is low x. The lid is modelled closed and flipped
// for printing.
/* [Part] */
// The whole case with the lid open, or one part in print orientation.
part = "assembly"; // [assembly, base, lid, charger_insert, whoop_insert, slider]
// Print a coupon set instead: one hinge and the latch in base and lid halves, the
// slider with its rails, one charger spring and one battery clip.
test_print = false;
// Show the whoop, the charger and the batteries as ghosts in the assembly.
show_contents = false;
/* [Whoop] */
// The whoop the cradle fits without an insert. Motor to motor across the diagonal:
// 80 for a Meteor75 Pro II.
whoop_wheelbase = 80; // [60:0.5:120]
// Outer diameter of one duct.
duct_d = 50; // [30:0.5:70]
// Total height of the whoop, camera included.
whoop_h = 40; // [20:1:60]
/* [Whoop insert] */
// A smaller whoop held in the cradle by the whoop insert: wheelbase and duct diameter.
insert_wheelbase = 65; // [50:0.5:110]
insert_duct_d = 36; // [25:0.5:65]
/* [Charger] */
// Charger size, port end against the front wall. The frame takes a charger from
// 1.5 mm smaller to about 3.5 mm larger, in both directions.
charger_l = 90; // [40:1:140]
charger_w = 45; // [20:1:80]
// Height of the charger: the springs catch over its top edge.
charger_h = 20; // [8:1:40]
// Charging window: offset of its centre from the middle of the charger toward the
// whoop, and height of its centre above the floor.
port_x = 0; // [-30:0.5:30]
port_z = 10; // [9:0.5:30]
/* [Batteries] */
// 1S batteries in the lid, standing on their side. 0 for an empty lid.
battery_count = 8; // [0:1:12]
// Length with the plug, width (its height as it stands) and thickness.
battery_l = 62; // [40:1:80]
battery_w = 13.5; // [8:0.5:20]
battery_t = 9; // [5:0.5:14]
/* [Colour] */
// Display only, the STL carries no colour.
color_case = "SteelBlue"; // [SteelBlue, White, DimGray, Black, FireBrick, Goldenrod, ForestGreen, MediumPurple]
/* [Hidden] */
$fn = 48;
wall = 2.6;
floor_t = 2;
top_t = 2;
corner_r = 4;
// whoop cradle: clearance, wall, height
c_clr = 0.5;
cw = 1.6;
cradle_h = 12;
// whoop insert: clearance in the cradle, wall, leaf, pad depth, preload, pad width
i_clr = 0.25;
iw = 1.2;
wl_t = 1.2;
w_pad = 3;
w_pre = 1.5;
w_pad_w = 6;
// lip on the base rim, recess in the lid
lip_h = 2;
lip_t = 1.2;
lip_c = 0.25;
// charger frame: wall, clearance in the case, leaf, travel room behind it, preload,
// pad depth from the leaf face, pad width, gap behind the travel, root spoke
fw = 1.2;
f_clr = 0.2;
s_t = 1.6;
travel = 5;
preload = 1.5;
pad_d = 3;
pad_w = 6;
s_gap = 0.6;
spoke = 4;
rib_t = 1.2;
rib_h = 3;
// charging window and slider
sl_w = 30;
sl_h = 16;
sl_t = 1.6;
sl_gap = 0.15;
sl_travel = 13;
sl_lip = 1.5;
sl_rail = 2;
det = 0.5;
// battery clips
bat_clr = 0.25;
arm_t = 1.4;
arm_w = 6;
arm_gap = 1.6;
bump = 0.7;
// hinges: knuckle radius, axis behind the rear face, segment width and gap
bolt_d = 3.4;
rk = 4;
hk = rk + 0.5;
seg_w = 8;
seg_gap = 0.4;
hinge_in = 22;
// latch
latch_w = 20;
latch_drop = 8;
tongue_t = 1.6;
ridge_d = 1;
latch_gap = 0.3;
sq = whoop_wheelbase / sqrt(2);
whoop_span = sq + duct_d;
drone_need = whoop_span + 2 * (c_clr + cw) + 2;
// charger frame across x: outer wall, charger, spring room, inner wall, floor rib
cx0 = wall + f_clr + fw;
xi = cx0 + charger_w;
fiw = xi + (pad_d - preload) + s_t + travel + s_gap;
fx1 = fiw + fw;
rib_x = fx1 + f_clr;
charger_zone = rib_x + rib_t - wall;
bat_pitch = battery_t + 2 * (bat_clr + arm_t) + arm_gap;
Sx_in = max(charger_zone + drone_need, battery_count * bat_pitch + 8);
Sy_in = max(drone_need, charger_l + (pad_d - preload) + s_t + travel + s_gap + fw + f_clr, battery_l + 12);
Sx = Sx_in + 2 * wall;
Sy = Sy_in + 2 * wall;
fz = floor_t;
cav_h = max(whoop_h + 2, charger_h + 6, cradle_h + 2);
base_h = floor_t + cav_h;
zc = base_h;
lid_cav = max(battery_w + 2.5, 9);
lid_h = top_t + lid_cav;
pb = zc + lid_h - top_t;
// charger along y: front face on the front wall
yf = Sy - wall;
yr = yf - charger_l;
fy0 = wall + f_clr;
y1 = yf - f_clr;
la = min(0.6 * charger_w + 3, charger_w - 2);
lb = min(max(25, 0.55 * charger_l), charger_l - 10);
// underside of the catch lip on the charger spring pads, above the floor
zl0 = charger_h + 0.2;
frame_h = zl0 + pad_d + 2;
// whoop centre, in the zone right of the charger frame
dx = wall + charger_zone + (Sx_in - charger_zone) / 2;
dy = Sy / 2;
// charging window and slider
p_lim = max(0, charger_w / 2 - 9);
px = cx0 + charger_w / 2 + max(-p_lim, min(port_x, p_lim));
pz = fz + max(8.6, min(port_z, cav_h - 23));
rail_z0 = max(0.6, pz - 10);
rail_top = pz + sl_h / 2 + sl_travel + 1.5;
// latch ridge
zr = zc - latch_drop + 2.4;
// ---- 2D helpers ----
module outer2d() {
offset(r = corner_r) offset(delta = -corner_r) square([Sx, Sy]);
}
module inset2d(k) {
offset(r = -k) outer2d();
}
module ring2d(a, b) {
difference() { inset2d(a); inset2d(b); }
}
// Horizontal hole that prints without support: the tip points up in 2D y.
module teardrop2d(r) {
circle(r = r);
rotate(45) square(r);
}
// Whoop outline: four ducts on a square of side s, and the frame between them.
module whoop2d(s, d) {
for (sx = [-1, 1], sy = [-1, 1]) translate([sx * s / 2, sy * s / 2]) circle(d = d);
square(s, center = true);
}
// ---- Hinge ----
// Knuckle profile in (y, z) about the hinge axis, which sits hk behind the rear face
// at rim height. Its underside runs into the wall at 45 degrees. The lid mirrors it
// about the rim, so both halves print without support.
module knuckle_profile() {
difference() {
hull() {
translate([-hk, 0]) circle(r = rk);
translate([-0.01, -hk - 1.42 * rk]) square([1, hk + 1.42 * rk - 2]);
}
translate([-hk, 0]) teardrop2d(bolt_d / 2);
}
}
module knuckle2d(upper) {
translate([0, zc]) {
if (upper) mirror([0, 1]) knuckle_profile();
else knuckle_profile();
}
}
// Two hinges, each base-lid-base on one M3 x 30 bolt with a nut.
module knuckles(upper) {
for (gx = [hinge_in, Sx - hinge_in], k = upper ? [0] : [-1, 1])
translate([gx + k * (seg_w + seg_gap) - seg_w / 2, 0, 0])
rotate([90, 0, 90]) linear_extrude(seg_w) knuckle2d(upper);
}
// ---- Base ----
module base_shell() {
difference() {
union() {
hull() {
linear_extrude(0.01) inset2d(0.5);
translate([0, 0, 0.5]) linear_extrude(base_h - 0.5) outer2d();
}
// lip on the inner half of the rim, it locates the lid
translate([0, 0, base_h - 0.01]) linear_extrude(lip_h + 0.01) ring2d(wall - lip_t, wall);
}
translate([0, 0, floor_t]) linear_extrude(base_h + lip_h) inset2d(wall);
}
}
// Wall around the ducts of the default whoop: it drops in without an insert.
module cradle() {
translate([dx, dy, fz - 0.01]) linear_extrude(cradle_h + 0.01)
difference() {
offset(r = c_clr + cw) whoop2d(sq, duct_d);
offset(r = c_clr) whoop2d(sq, duct_d);
}
}
// Low rib that keeps the charger frame in its bay.
module divider() {
translate([rib_x, wall - 0.01, fz - 0.01]) cube([rib_t, Sy - 2 * wall + 0.02, rib_h + 0.01]);
}
// Ridge on the front wall that the latch hook catches; both faces at 45 degrees.
module latch_ridge() {
translate([Sx / 2 - (latch_w + 4) / 2, 0, 0]) rotate([90, 0, 90]) linear_extrude(latch_w + 4)
polygon([[Sy - 0.5, zr - 1.5], [Sy + ridge_d, zr], [Sy + ridge_d, zr + 0.6], [Sy - 0.5, zr + 2.1]]);
}
// Window for the charging cable. The top corners are chamfered at 45 degrees, so
// the top is an 8 mm bridge.
module port_cut() {
translate([0, Sy + 1, 0]) rotate([90, 0, 0]) linear_extrude(wall + 2)
translate([px, pz]) polygon([[-7, -4.5], [7, -4.5], [7, 1.5], [4, 4.5], [-4, 4.5], [-7, 1.5]]);
}
// Two upright rails on the outside of the front wall, with a stop under them. The
// slider goes in from the top. Their profile is the same all the way up, so they
// print without overhang.
module slider_rails() {
for (m = [0, 1]) translate([px, 0, 0]) mirror([m, 0, 0]) {
translate([sl_w / 2 + 0.2, Sy - 0.5, rail_z0]) cube([sl_rail, sl_t + 2 * sl_gap + 0.5 + 1.2, rail_top - rail_z0]);
translate([sl_w / 2 - sl_lip, Sy + sl_t + 2 * sl_gap, rail_z0]) cube([sl_lip + 0.21, 1.2, rail_top - rail_z0]);
}
translate([px - sl_w / 2 - 0.2, Sy - 0.5, rail_z0]) cube([sl_w + 0.4, sl_t + 2 * sl_gap + 1.7, pz - sl_h / 2 - rail_z0]);
}
// V grooves in the wall face where the slider bump clicks in: closed and open.
module detents() {
for (zg = [pz - 3, pz - 3 + sl_travel])
translate([px + 8.5, 0, 0]) rotate([90, 0, 90]) linear_extrude(5)
polygon([[Sy + 0.01, zg - det], [Sy - det, zg], [Sy + 0.01, zg + det]]);
}
module base() {
difference() {
union() {
base_shell();
knuckles(false);
cradle();
divider();
latch_ridge();
slider_rails();
}
port_cut();
detents();
}
}
// ---- Slider ----
// Prints flat, front face on the bed. A tongue cut into it beside the window bends
// along its layers and carries a bump on the back that clicks into the grooves.
// Local frame: x across, y up the wall, z from the front face to the back face.
module slider_flat() {
tx0 = sl_w / 2 + 9;
difference() {
cube([sl_w, sl_h, sl_t]);
translate([tx0 - 0.7, 3.3, -1]) cube([5.4, 9.7, sl_t + 2]);
}
translate([tx0, 4, 0]) cube([4, 9.01, sl_t]);
translate([tx0, 0, sl_t - 0.01]) rotate([90, 0, 90]) linear_extrude(4) polygon([[4, 0], [5, det], [6, 0]]);
}
module slider_placed() {
multmatrix([[1, 0, 0, px - sl_w / 2], [0, 0, -1, Sy + sl_gap + sl_t], [0, 1, 0, pz - sl_h / 2], [0, 0, 0, 1]])
slider_flat();
}
// ---- Charger frame ----
// A U open to the front, so the charger meets the front wall and its port lines up
// with the window. Two upright leaves hang from the frame and bend sideways, along
// their layers; the frame has no floor, so they stand free on the bed. One runs
// along the rear of the charger and pushes it forward, one along its inner side
// and pushes it against the outer wall. Each pad reaches preload into the charger;
// its top is a 45 degree ramp the charger edge pushes back on the way down, ending
// in a lip that catches over the charger.
// Local frame: u along the leaf from its root, v toward the charger, z up.
module spring(len) {
translate([-0.5, -s_t, 0]) cube([len + 0.5, s_t, zl0 + 2]);
translate([len - pad_w, 0, 0]) rotate([90, 0, 90]) linear_extrude(pad_w)
polygon([[-0.01, 0], [pad_d, 0], [pad_d, zl0], [pad_d + 1, zl0 + 1], [-0.01, zl0 + pad_d + 2.01]]);
}
module charger_insert() {
translate([0, 0, fz]) {
translate([fy0, fy0, 0]) cube([fw, y1 - fy0, frame_h]);
translate([fy0, fy0, 0]) cube([fx1 - fy0, fw, frame_h]);
translate([fiw, fy0, 0]) cube([fw, y1 - fy0, frame_h]);
translate([cx0, yr - (pad_d - preload), 0]) spring(la);
translate([xi + (pad_d - preload), y1 - spoke, 0]) {
mirror([1, 0, 0]) rotate(-90) spring(lb);
cube([fiw - (xi + pad_d - preload) + 0.01, spoke, frame_h]);
}
}
}
// ---- Whoop insert ----
// Follows the cradle wall and holds a smaller whoop with four leaves, one per duct,
// mirrored about both axes so the whoop centres without turning. Each leaf runs
// across its corner, square to the diagonal, from the insert wall to a pad on the
// diagonal that pushes the duct toward the centre. The pad top is a 45 degree ramp
// the duct pushes aside on the way down.
module whoop_insert() {
rpf = insert_wheelbase / 2 + insert_duct_d / 2 - w_pre;
rlf = rpf + w_pad;
rlb = rlf + wl_t;
a = rlb - whoop_wheelbase / 2;
r_in = duct_d / 2 + c_clr - i_clr - iw;
ok = a < r_in - 3;
s_root = ok ? sqrt(pow(r_in + 0.6, 2) - a * a) : 0;
if (!ok) echo("whoop insert: the insert whoop is too close in size to the cradle whoop, no room for the springs");
translate([dx, dy, fz]) {
linear_extrude(cradle_h) difference() {
offset(r = c_clr - i_clr) whoop2d(sq, duct_d);
offset(r = c_clr - i_clr - iw) whoop2d(sq, duct_d);
}
if (ok) for (sx = [-1, 1], sy = [-1, 1])
multmatrix([[sx / sqrt(2), sx / sqrt(2), 0, 0], [-sy / sqrt(2), sy / sqrt(2), 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
translate([-w_pad_w / 2, rlf, 0]) cube([s_root + w_pad_w / 2, wl_t, cradle_h]);
translate([-w_pad_w / 2, 0, 0]) rotate([90, 0, 90]) linear_extrude(w_pad_w)
polygon([[rlf + 0.01, 0], [rpf, 0], [rpf, cradle_h - w_pad], [rlf + 0.01, cradle_h + 0.01]]);
}
}
}
// ---- Lid ----
module lid_shell() {
difference() {
translate([0, 0, zc]) hull() {
linear_extrude(lid_h - 0.5) outer2d();
translate([0, 0, lid_h - 0.01]) linear_extrude(0.01) inset2d(0.5);
}
translate([0, 0, zc - 1]) linear_extrude(lid_cav + 1) inset2d(wall);
// recess for the lip of the base
translate([0, 0, zc - 1]) linear_extrude(lip_h + 0.3 + 1) ring2d(wall - lip_t - lip_c, wall + 0.01);
}
}
// Snap tongue on the front. Its hook catches under the ridge of the base; the lip
// at its end is for a fingernail.
module latch_tongue() {
yt = Sy + ridge_d + latch_gap;
zt = zc - latch_drop - 3;
translate([Sx / 2 - latch_w / 2, 0, 0]) rotate([90, 0, 90]) linear_extrude(latch_w) {
translate([Sy - 0.5, zc + 4]) square([yt + tongue_t - (Sy - 0.5), lid_h - 4]);
translate([yt, zt]) square([tongue_t, zc + 4.01 - zt]);
polygon([[yt + 0.01, zr + 0.2], [Sy + latch_gap, zr - 0.8], [Sy + latch_gap, zr - 1.4], [yt + 0.01, zr - 2.4]]);
polygon([[yt + tongue_t - 0.01, zt], [yt + tongue_t + 1.5, zt], [yt + tongue_t - 0.01, zt + 1.5]]);
}
}
function bat_x(i) = Sx / 2 + (i - (battery_count - 1) / 2) * bat_pitch;
// 1S batteries stand on their side, thickness across x, plug end along y. Two pairs
// of arms per battery, each with a 45 degree bump that snaps over its free edge.
// arm_gap between neighbouring arms leaves room for an arm to give while the next
// slot is full.
module bat_clips() {
if (battery_count > 0)
for (i = [0 : battery_count - 1], yc = [Sy / 2 - 0.28 * battery_l, Sy / 2 + 0.28 * battery_l], s = [-1, 1]) {
f = bat_x(i) + s * (battery_t / 2 + bat_clr);
zb = pb - battery_w - 0.15;
translate([0, yc + arm_w / 2, 0]) rotate([90, 0, 0]) linear_extrude(arm_w) {
translate([s < 0 ? f - arm_t : f, pb - battery_w - 1.6]) square([arm_t, battery_w + 1.6 + 0.01]);
polygon([[f + s * 0.01, zb], [f - s * bump, zb - bump], [f + s * 0.01, zb - 2 * bump]]);
}
}
}
module lid() {
lid_shell();
knuckles(true);
bat_clips();
latch_tongue();
}
module lid_print() {
translate([0, Sy, zc + lid_h]) rotate([180, 0, 0]) lid();
}
// ---- Ghost contents ----
module ghost_whoop() {
color("Gainsboro", 0.5) translate([dx, dy, fz]) {
for (sx = [-1, 1], sy = [-1, 1]) translate([sx * sq / 2, sy * sq / 2, 0])
difference() { cylinder(d = duct_d, h = 16); translate([0, 0, -1]) cylinder(d = duct_d - 2, h = 18); }
translate([-12, -16, 0]) cube([24, 32, whoop_h]);
}
}
module ghost_charger() {
color("OrangeRed", 0.5) translate([cx0, yr, fz]) cube([charger_w, charger_l, charger_h]);
}
module ghost_batteries() {
if (battery_count > 0)
color("DimGray", 0.6) for (i = [0 : battery_count - 1])
translate([bat_x(i) - battery_t / 2, Sy / 2 - battery_l / 2, pb - battery_w]) cube([battery_t, battery_l, battery_w]);
}
// ---- Test coupons ----
module coupon(lo, hi) {
translate(-lo) intersection() { children(); translate(lo) cube(hi - lo); }
}
module test_layout() {
g = 44;
// hinge, base and lid half
coupon([hinge_in - 16, -hk - rk - 1, zc - 14], [hinge_in + 16, 6, zc + lip_h + 1]) base();
translate([0, 22, 0]) coupon([hinge_in - 16, Sy - 6, 0], [hinge_in + 16, Sy + hk + rk + 1, lid_h + 12]) lid_print();
// latch, base and lid half
translate([g, 0, 0]) coupon([Sx / 2 - 16, Sy - 6, zc - 14], [Sx / 2 + 16, Sy + 5, zc + lip_h + 1]) base();
translate([g, 22, 0]) coupon([Sx / 2 - 16, -6, 0], [Sx / 2 + 16, 6, lid_h + latch_drop + 5]) lid_print();
// slider rails with the window, and the slider
translate([2 * g, 0, 0]) coupon([px - 19, Sy - 3, pz - 11], [px + 19, Sy + 4, rail_top + 1]) base();
translate([2 * g + 4, 12, 0]) slider_flat();
// the charger spring on the inner side, with its spoke and a strip of frame
translate([3 * g, 0, 0])
coupon([xi - 3, y1 - spoke - lb - 3, fz], [fx1 + 0.1, y1 + 0.1, fz + frame_h + 0.1]) charger_insert();
// one battery clip
if (battery_count > 0) {
yc = Sy / 2 - 0.28 * battery_l;
bx = bat_x(0);
translate([3 * g + 20, 0, 0])
coupon([bx - bat_pitch / 2 - 1, Sy - yc - arm_w / 2 - 4, 0], [bx + bat_pitch / 2 + 1, Sy - yc + arm_w / 2 + 4, lid_h + 1]) lid_print();
}
}
// ---- Layout ----
module assembly() {
color(color_case) base();
color(color_case) charger_insert();
color(color_case) slider_placed();
if (show_contents) { ghost_whoop(); ghost_charger(); }
// lid swung open flat behind the base
translate([0, -hk, zc]) rotate([180, 0, 0]) translate([0, hk, -zc]) {
color(color_case) lid();
if (show_contents) ghost_batteries();
}
}
if (test_print) color(color_case) test_layout();
else if (part == "base") color(color_case) base();
else if (part == "lid") color(color_case) lid_print();
else if (part == "charger_insert") color(color_case) translate([0, 0, -fz]) charger_insert();
else if (part == "whoop_insert") color(color_case) translate([-dx, -dy, -fz]) whoop_insert();
else if (part == "slider") color(color_case) slider_flat();
else assembly();
Comments
Context, not a score. Comments never move a model up or down the results.No comments yet
Printed it? A note about your material and the clearance you landed on saves the next person a failed print.
