Add latches to the lid
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
SCAD = wargame_box.scad
|
SCAD = wargame_box.scad
|
||||||
PARTS = box lid insert
|
PARTS = box lid insert latch
|
||||||
STLS = $(addprefix stl/,$(addsuffix .stl,$(PARTS)))
|
STLS = $(addprefix stl/,$(addsuffix .stl,$(PARTS)))
|
||||||
|
|
||||||
all: $(STLS)
|
all: $(STLS)
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
# Wargame Accessory Box & Dice Tray
|
# Wargame Accessory Box & Dice Tray
|
||||||
|
|
||||||
A parametric OpenSCAD box for carrying tabletop wargaming accessories.
|
A parametric OpenSCAD box for carrying tabletop wargaming accessories.
|
||||||
Three printable parts:
|
Four printable parts:
|
||||||
|
|
||||||
| Part | Purpose |
|
| Part | Purpose |
|
||||||
|----------|--------------------------------------------------------------------|
|
|----------|--------------------------------------------------------------------|
|
||||||
| `box` | Open tray. With the insert removed it doubles as a dice tray. |
|
| `box` | Open tray. With the insert removed it doubles as a dice tray. |
|
||||||
| `lid` | Fully detachable friction-fit lid (no hinge to get in the way). |
|
| `lid` | Fully detachable lid, held shut by snap latches hinged on filament pins (or a classic friction fit). |
|
||||||
|
| `latch` | One-piece snap latch — print two per latch position. |
|
||||||
| `insert` | Removable compartment tray for tokens, measuring tapes, etc. |
|
| `insert` | Removable compartment tray for tokens, measuring tapes, etc. |
|
||||||
|
|
||||||

|

|
||||||
@@ -19,14 +20,50 @@ the free space in your backpack — they are **outer** dimensions and
|
|||||||
measured space exactly.
|
measured space exactly.
|
||||||
|
|
||||||
Pick what to render with the `part` variable (or the customizer):
|
Pick what to render with the `part` variable (or the customizer):
|
||||||
`assembly` (exploded preview), `box`, `lid`, `insert`, `print`.
|
`assembly` (exploded preview), `box`, `lid`, `insert`, `latch`, `print`.
|
||||||
|
|
||||||
Or export everything from the command line:
|
Or export everything from the command line:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
make # exports stl/box.stl, stl/lid.stl, stl/insert.stl
|
make # exports stl/box.stl, stl/lid.stl, stl/insert.stl, stl/latch.stl
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## The latch lid
|
||||||
|
|
||||||
|
By default (`lid_style = "latch"`) the lid is held shut by snap
|
||||||
|
latches that hinge on short pieces of filament:
|
||||||
|
|
||||||
|
* The **lid** carries pairs of lugs along its front and back edges.
|
||||||
|
* Each **latch** is a single printed part with a pivot barrel that
|
||||||
|
fits between a lug pair. Its window snaps over a chamfered catch
|
||||||
|
bar on the box wall; pull the flared tip outward to open.
|
||||||
|
* To assemble one latch: cut a ~23 mm piece of 1.75 mm filament,
|
||||||
|
slide it through lug → latch barrel → lug, and fix it with a drop
|
||||||
|
of glue **on the outer lug holes only** — the lug holes are sized
|
||||||
|
tight and the barrel hole loose, so the latch keeps pivoting
|
||||||
|
freely. Trim the pin flush.
|
||||||
|
|
||||||
|
Tuning knobs (all per side unless noted):
|
||||||
|
|
||||||
|
* `latches_per_side` — how many latches on each long wall
|
||||||
|
(default 2, evenly spread).
|
||||||
|
* `catch_proud` — how far the catch bar sticks out = how hard the
|
||||||
|
snap is (default 1.4 mm).
|
||||||
|
* `latch_play` — vertical play between latch and catch bar
|
||||||
|
(default 0.1 mm). Use a small negative value to preload the lid
|
||||||
|
shut.
|
||||||
|
* `filament_d` — hinge pin diameter, in case you want to use
|
||||||
|
2.85 mm filament or a piece of wire instead.
|
||||||
|
|
||||||
|
Note: lugs and latches stick out about 7 mm beyond the box on the
|
||||||
|
front and back, so allow `total_y + 14` of space in the backpack.
|
||||||
|
With latches doing the holding, a looser lip (`lid_clearance` around
|
||||||
|
0.3–0.4) makes the lid pleasant to take off.
|
||||||
|
|
||||||
|
Prefer the original hinge-free push-fit lid? Set
|
||||||
|
`lid_style = "friction"` and you get the old behaviour, including
|
||||||
|
the thumb grooves for prying the lid off.
|
||||||
|
|
||||||
## Configuring the insert layout
|
## Configuring the insert layout
|
||||||
|
|
||||||
Compartments are defined by the `layout` list, one entry per row
|
Compartments are defined by the `layout` list, one entry per row
|
||||||
@@ -55,10 +92,13 @@ of the automatic height and print two with different layouts.
|
|||||||
## How the parts work together
|
## How the parts work together
|
||||||
|
|
||||||
* The **lid** is a flat plate with a lip that plugs into the box opening.
|
* The **lid** is a flat plate with a lip that plugs into the box opening.
|
||||||
`lid_clearance` (default 0.2 mm per side) controls the friction fit —
|
With the latch lid the lip just aligns the lid (and keeps tokens in
|
||||||
print a test fit and adjust for your printer/material. Shallow thumb
|
their compartments); with `lid_style = "friction"` it carries the
|
||||||
grooves on the box's front and back walls let you pry the lid off; they
|
whole fit. `lid_clearance` (default 0.2 mm per side) controls how
|
||||||
do **not** pierce the wall, so the dice tray stays fully closed.
|
snug it is — print a test fit and adjust for your printer/material.
|
||||||
|
In friction mode, shallow thumb grooves on the box's front and back
|
||||||
|
walls let you pry the lid off; they do **not** pierce the wall, so
|
||||||
|
the dice tray stays fully closed.
|
||||||
* The **insert** sits below the lid's lip, so the lip also keeps loose
|
* The **insert** sits below the lid's lip, so the lip also keeps loose
|
||||||
tokens from jumping compartments in the bag. Finger notches on its
|
tokens from jumping compartments in the bag. Finger notches on its
|
||||||
short walls let you lift it straight out; then the empty box is your
|
short walls let you lift it straight out; then the empty box is your
|
||||||
@@ -68,7 +108,9 @@ of the automatic height and print two with different layouts.
|
|||||||
## Printing notes
|
## Printing notes
|
||||||
|
|
||||||
* No supports needed for any part. Print all parts flat side down
|
* No supports needed for any part. Print all parts flat side down
|
||||||
(the lid prints plate-down, lip up).
|
(the lid prints plate-down, lip and lugs up). The latch prints
|
||||||
|
standing on its flat side — that gives a clean pivot hole and puts
|
||||||
|
the layer lines along the strip, where the snap stress is.
|
||||||
* PLA or PETG, 2–3 perimeters, ~10 % infill (the parts are mostly walls).
|
* PLA or PETG, 2–3 perimeters, ~10 % infill (the parts are mostly walls).
|
||||||
* If the lid is too tight/loose, tune `lid_clearance` in steps of 0.05 mm.
|
* If the lid is too tight/loose, tune `lid_clearance` in steps of 0.05 mm.
|
||||||
Same for the insert with `insert_clearance` (looser is fine there —
|
Same for the insert with `insert_clearance` (looser is fine there —
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 41 KiB |
+166
-6
@@ -1,9 +1,11 @@
|
|||||||
// ============================================================
|
// ============================================================
|
||||||
// Wargame Accessory Box & Dice Tray
|
// Wargame Accessory Box & Dice Tray
|
||||||
// ------------------------------------------------------------
|
// ------------------------------------------------------------
|
||||||
// Three printable parts:
|
// Printable parts:
|
||||||
// * box - open tray, doubles as a dice tray
|
// * box - open tray, doubles as a dice tray
|
||||||
// * lid - fully detachable friction-fit lid
|
// * lid - fully detachable lid, held shut by snap latches
|
||||||
|
// hinged on filament pins (or classic friction fit)
|
||||||
|
// * latch - one-piece snap latch (print 2 per latch position)
|
||||||
// * insert - removable compartment tray (configurable layout)
|
// * insert - removable compartment tray (configurable layout)
|
||||||
//
|
//
|
||||||
// Set `part` below (or via customizer / -D on the CLI) to
|
// Set `part` below (or via customizer / -D on the CLI) to
|
||||||
@@ -12,7 +14,7 @@
|
|||||||
// ============================================================
|
// ============================================================
|
||||||
|
|
||||||
/* [What to render] */
|
/* [What to render] */
|
||||||
part = "assembly"; // [assembly, box, lid, insert, print]
|
part = "assembly"; // [assembly, box, lid, insert, latch, print]
|
||||||
|
|
||||||
/* [Outer dimensions (must fit the backpack)] */
|
/* [Outer dimensions (must fit the backpack)] */
|
||||||
// Total outer width (X), including walls
|
// Total outer width (X), including walls
|
||||||
@@ -39,16 +41,39 @@ tray_chamfer = 6;
|
|||||||
// Thickness of the flat lid plate
|
// Thickness of the flat lid plate
|
||||||
lid_top = 2.4;
|
lid_top = 2.4;
|
||||||
// Height of the lip that plugs into the box opening
|
// Height of the lip that plugs into the box opening
|
||||||
lip_h = 10;
|
lip_h = 5;
|
||||||
// Lip wall thickness
|
// Lip wall thickness
|
||||||
lip_t = 2.0;
|
lip_t = 2.0;
|
||||||
// Gap per side between lip and box wall.
|
// Gap per side between lip and box wall.
|
||||||
// Tune for your printer: smaller = tighter friction fit.
|
// Tune for your printer: smaller = tighter friction fit.
|
||||||
|
// With lid_style = "latch" the latches do the holding, so a
|
||||||
|
// looser 0.3 - 0.4 makes the lid easy to take off.
|
||||||
lid_clearance = 0.20;
|
lid_clearance = 0.20;
|
||||||
// Thumb groove on the box's outer walls to pry the lid off
|
// Thumb groove on the box's outer walls to pry the lid off
|
||||||
// (does NOT pierce the wall, dice tray stays closed)
|
// (friction lid only; latches replace it)
|
||||||
thumb_grooves = true;
|
thumb_grooves = true;
|
||||||
|
|
||||||
|
/* [Latches] */
|
||||||
|
// How the lid is held shut. "latch": snap latches hinged on
|
||||||
|
// short pieces of filament (see README). "friction": original
|
||||||
|
// push fit.
|
||||||
|
lid_style = "latch"; // [latch, friction]
|
||||||
|
// Latches per long (front/back) wall, spread out evenly
|
||||||
|
latches_per_side = 2;
|
||||||
|
// Diameter of the filament used as hinge pin
|
||||||
|
filament_d = 1.75;
|
||||||
|
// Latch strip width
|
||||||
|
latch_w = 12;
|
||||||
|
// Latch strip thickness (thinner = softer snap)
|
||||||
|
latch_t = 2.0;
|
||||||
|
// Catch bar distance below the box rim
|
||||||
|
catch_drop = 14;
|
||||||
|
// Catch bar protrusion from the wall = snap engagement
|
||||||
|
catch_proud = 1.4;
|
||||||
|
// Vertical play between latch window and catch bar.
|
||||||
|
// Negative values preload the lid shut.
|
||||||
|
latch_play = 0.1;
|
||||||
|
|
||||||
/* [Insert] */
|
/* [Insert] */
|
||||||
// Gap per side between insert and box wall
|
// Gap per side between insert and box wall
|
||||||
insert_clearance = 0.40;
|
insert_clearance = 0.40;
|
||||||
@@ -103,6 +128,36 @@ ins_h = insert_h_override > 0
|
|||||||
lip_x = inner_x - 2 * lid_clearance; // lid lip outer size
|
lip_x = inner_x - 2 * lid_clearance; // lid lip outer size
|
||||||
lip_y = inner_y - 2 * lid_clearance;
|
lip_y = inner_y - 2 * lid_clearance;
|
||||||
|
|
||||||
|
// --- latch hinge internals ---
|
||||||
|
lug_w = 5; // lid lug width (each side)
|
||||||
|
hinge_gap = 0.4; // side play lug <-> latch
|
||||||
|
pin_boss_r = filament_d / 2 + 2.3; // lug / barrel outer radius
|
||||||
|
pin_standoff = pin_boss_r + 0.4; // pin axis to wall face
|
||||||
|
lug_hole_d = filament_d + 0.15; // tight: pin glued into lugs
|
||||||
|
barrel_hole_d = filament_d + 0.35; // loose: latch pivots freely
|
||||||
|
latch_gap = 0.4; // latch strip to wall face
|
||||||
|
bar_h = 2.8; // catch bar height
|
||||||
|
bar_rise = 1.2; // straight part below chamfer
|
||||||
|
window_rail = 3; // strip rails beside window
|
||||||
|
window_w = latch_w - 2 * window_rail;
|
||||||
|
bar_len = window_w - 0.8;
|
||||||
|
grip_l = 6; // thumb flare below window
|
||||||
|
|
||||||
|
z_pin = box_h + lid_top - pin_boss_r; // hinge axis, lid closed
|
||||||
|
z_bar_top = box_h - catch_drop;
|
||||||
|
// latch window, measured down the strip from the pin axis
|
||||||
|
win_t1 = z_pin - z_bar_top - 0.4;
|
||||||
|
win_t2 = z_pin - z_bar_top + bar_h + latch_play;
|
||||||
|
latch_len = win_t2 + 4 + grip_l; // pin axis to latch tip
|
||||||
|
|
||||||
|
function latch_pos_x() =
|
||||||
|
latches_per_side <= 0 ? []
|
||||||
|
: [for (i = [1 : latches_per_side])
|
||||||
|
total_x * i / (latches_per_side + 1)];
|
||||||
|
|
||||||
|
assert(lid_style != "latch" || z_pin - latch_len > 2,
|
||||||
|
"box too shallow for the latch: reduce catch_drop");
|
||||||
|
|
||||||
// ------------------------------------------------------------
|
// ------------------------------------------------------------
|
||||||
// Helpers
|
// Helpers
|
||||||
// ------------------------------------------------------------
|
// ------------------------------------------------------------
|
||||||
@@ -141,7 +196,7 @@ module box() {
|
|||||||
}
|
}
|
||||||
if (tray_chamfer > 0) tray_chamfers();
|
if (tray_chamfer > 0) tray_chamfers();
|
||||||
}
|
}
|
||||||
if (thumb_grooves)
|
if (thumb_grooves && lid_style == "friction")
|
||||||
for (m = [0, 1])
|
for (m = [0, 1])
|
||||||
translate([total_x / 2,
|
translate([total_x / 2,
|
||||||
m == 0 ? -(14 - groove_depth)
|
m == 0 ? -(14 - groove_depth)
|
||||||
@@ -149,6 +204,25 @@ module box() {
|
|||||||
box_h - 16])
|
box_h - 16])
|
||||||
cylinder(h = 20, d = 28, $fn = 48);
|
cylinder(h = 20, d = 28, $fn = 48);
|
||||||
}
|
}
|
||||||
|
if (lid_style == "latch")
|
||||||
|
for (x0 = latch_pos_x()) {
|
||||||
|
translate([x0, 0, z_bar_top]) catch_bar();
|
||||||
|
translate([x0, total_y, z_bar_top])
|
||||||
|
mirror([0, 1, 0]) catch_bar();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// catch bar on the outer wall: origin on the wall face with the
|
||||||
|
// bar top at z = 0, protruding in -y. Chamfered on top so the
|
||||||
|
// latch rides over it, flat below so the latch can't cam out.
|
||||||
|
module catch_bar() {
|
||||||
|
translate([-bar_len / 2, 0, 0])
|
||||||
|
rotate([90, 0, 90])
|
||||||
|
linear_extrude(bar_len)
|
||||||
|
polygon([[0, 0],
|
||||||
|
[-catch_proud, -bar_h + bar_rise],
|
||||||
|
[-catch_proud, -bar_h],
|
||||||
|
[0, -bar_h]]);
|
||||||
}
|
}
|
||||||
|
|
||||||
module tray_chamfers() {
|
module tray_chamfers() {
|
||||||
@@ -203,6 +277,77 @@ module lid() {
|
|||||||
rbox(lip_x - 2 * lip_t, lip_y - 2 * lip_t,
|
rbox(lip_x - 2 * lip_t, lip_y - 2 * lip_t,
|
||||||
lip_h + 1, max(inner_r - lip_t, 0.1));
|
lip_h + 1, max(inner_r - lip_t, 0.1));
|
||||||
}
|
}
|
||||||
|
if (lid_style == "latch")
|
||||||
|
for (x0 = latch_pos_x()) {
|
||||||
|
translate([x0, 0, 0]) lug_pair();
|
||||||
|
translate([x0, total_y, 0]) mirror([0, 1, 0]) lug_pair();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------
|
||||||
|
// Latch hardware
|
||||||
|
// ------------------------------------------------------------
|
||||||
|
// One-piece snap latch hinged on a short piece of filament: the
|
||||||
|
// lid carries two lugs, the latch barrel sits between them, and
|
||||||
|
// the filament pin is glued into the (tighter) lug holes only,
|
||||||
|
// so the latch pivots freely. The window in the strip snaps
|
||||||
|
// over the catch bar on the box wall.
|
||||||
|
|
||||||
|
// one lid lug, centered on x = 0 at the lid edge y = 0, hanging
|
||||||
|
// outward in -y. Modeled in lid print orientation, so the pin
|
||||||
|
// boss rests flat on the bed.
|
||||||
|
module lid_lug() {
|
||||||
|
difference() {
|
||||||
|
hull() {
|
||||||
|
translate([-lug_w / 2, -pin_standoff, pin_boss_r])
|
||||||
|
rotate([0, 90, 0]) cylinder(r = pin_boss_r, h = lug_w);
|
||||||
|
translate([-lug_w / 2, 0, 0]) cube([lug_w, 2, lid_top]);
|
||||||
|
}
|
||||||
|
translate([-lug_w / 2 - 1, -pin_standoff, pin_boss_r])
|
||||||
|
rotate([0, 90, 0]) cylinder(d = lug_hole_d, h = lug_w + 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module lug_pair() {
|
||||||
|
off = latch_w / 2 + hinge_gap + lug_w / 2;
|
||||||
|
for (sx = [-1, 1]) translate([sx * off, 0, 0]) lid_lug();
|
||||||
|
}
|
||||||
|
|
||||||
|
// modeled flat: x = down the strip from the pin axis, y = away
|
||||||
|
// from the box wall, z = width. Prints standing on that flat
|
||||||
|
// face -> clean pivot hole and layer lines along the strip.
|
||||||
|
module latch() {
|
||||||
|
u0 = latch_gap; // inner face (toward the wall)
|
||||||
|
u1 = latch_gap + latch_t; // outer face
|
||||||
|
flare = 2.5;
|
||||||
|
difference() {
|
||||||
|
linear_extrude(latch_w) {
|
||||||
|
// pivot barrel
|
||||||
|
translate([0, pin_standoff]) circle(r = pin_boss_r);
|
||||||
|
polygon([
|
||||||
|
[0, u0],
|
||||||
|
[latch_len - 2, u0],
|
||||||
|
[latch_len, u0 + 1.4], // tip chamfer, rides
|
||||||
|
[latch_len, u1 + flare], // over the catch bar
|
||||||
|
[latch_len - 2, u1 + flare], // thumb flare to open
|
||||||
|
[win_t2 + 4, u1],
|
||||||
|
[0, u1]
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
// pivot hole
|
||||||
|
translate([0, pin_standoff, -1])
|
||||||
|
cylinder(d = barrel_hole_d, h = latch_w + 2);
|
||||||
|
// window that snaps over the catch bar
|
||||||
|
translate([win_t1, -1, window_rail])
|
||||||
|
cube([win_t2 - win_t1, u1 + flare + 2, window_w]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// latch in closed/engaged position on the front wall (y = 0)
|
||||||
|
module placed_latch(x0) {
|
||||||
|
translate([x0, 0, z_pin])
|
||||||
|
rotate([0, 0, 180]) rotate([0, 90, 0])
|
||||||
|
translate([0, 0, -latch_w / 2]) latch();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------
|
// ------------------------------------------------------------
|
||||||
@@ -263,14 +408,29 @@ module assembly() {
|
|||||||
color("LightGreen", 0.7)
|
color("LightGreen", 0.7)
|
||||||
translate([0, total_y, box_h + ins_h + 25])
|
translate([0, total_y, box_h + ins_h + 25])
|
||||||
rotate([180, 0, 0]) translate([0, 0, -lid_top]) lid();
|
rotate([180, 0, 0]) translate([0, 0, -lid_top]) lid();
|
||||||
|
// latches hang from the floating lid's lugs
|
||||||
|
if (lid_style == "latch")
|
||||||
|
color("Tomato")
|
||||||
|
translate([0, 0, ins_h + 25])
|
||||||
|
for (x0 = latch_pos_x()) {
|
||||||
|
placed_latch(x0);
|
||||||
|
translate([0, total_y, 0])
|
||||||
|
mirror([0, 1, 0]) placed_latch(x0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (part == "box") box();
|
if (part == "box") box();
|
||||||
else if (part == "lid") lid();
|
else if (part == "lid") lid();
|
||||||
else if (part == "insert") insert();
|
else if (part == "insert") insert();
|
||||||
|
else if (part == "latch") latch();
|
||||||
else if (part == "print") {
|
else if (part == "print") {
|
||||||
box();
|
box();
|
||||||
translate([total_x + 15, 0, 0]) lid();
|
translate([total_x + 15, 0, 0]) lid();
|
||||||
translate([0, total_y + 15, 0]) insert();
|
translate([0, total_y + 15, 0]) insert();
|
||||||
|
if (lid_style == "latch" && latches_per_side > 0)
|
||||||
|
for (i = [0 : 2 * latches_per_side - 1])
|
||||||
|
translate([total_x + 15 + pin_boss_r,
|
||||||
|
total_y + 15 + i * (2 * pin_boss_r + 4), 0])
|
||||||
|
latch();
|
||||||
}
|
}
|
||||||
else assembly();
|
else assembly();
|
||||||
|
|||||||
Reference in New Issue
Block a user