Skip to content

Instantly share code, notes, and snippets.

@pnkfelix
Created March 17, 2026 14:13
Show Gist options
  • Select an option

  • Save pnkfelix/2fac6da2f9f462c187680842fa7ef989 to your computer and use it in GitHub Desktop.

Select an option

Save pnkfelix/2fac6da2f9f462c187680842fa7ef989 to your computer and use it in GitHub Desktop.
botc token tiles
// Blood on the Clocktower - Token Storage Tile (Square)
// Parametric single-piece layered holder for 3D printing
// Printer: Snapmaker U1, Slicer: Snapmaker Orca
/* ── Token dimensions (official + tolerance) ── */
role_token_dia = 44.5;
reminder_token_dia = 25.5;
token_tolerance = 0.8; // ~0.4mm clearance per side
role_cavity_dia = role_token_dia + token_tolerance; // 45.3mm
reminder_cavity_dia = reminder_token_dia + token_tolerance; // 26.3mm
role_r = role_cavity_dia / 2; // 22.65
reminder_r = reminder_cavity_dia / 2; // 13.15
/* ── Layer thicknesses ── */
base_thickness = 1.25; // 0.25 first layer + 5×0.2
reminder_depth = 1.8; // 9×0.2
role_depth = 2.0; // 10×0.2
total_height = base_thickness + reminder_depth + role_depth; // 5.2mm
/* ── Structural ── */
wall_min = 1.2; // min wall from cavity to tile edge
cavity_wall_min = 0.8; // min wall between adjacent reminder cavities
finger_scoop_dia = 10; // finger notch between reminder cavities
/* ── Reminder layout ── */
num_reminders = 2;
corner_r = 2.0; // outer edge rounding
// Two reminders along the diagonal of the square.
// Center-to-center distance must be >= reminder_cavity_dia + cavity_wall_min.
min_center_dist = reminder_cavity_dia + cavity_wall_min; // 27.1mm
half_dist = min_center_dist / 2; // 13.55mm
// Each reminder center is at (±half_dist/sqrt(2), ±half_dist/sqrt(2))
diag_offset = half_dist / sqrt(2); // ~9.58mm
// Tile half-size: must contain reminders AND role cavity
tile_half_for_reminders = diag_offset + reminder_r + wall_min; // ~23.93
tile_half_for_role = role_r + wall_min; // ~23.85
tile_half = max(tile_half_for_reminders, tile_half_for_role);
tile_size = 2 * tile_half;
// Reminder positions along the diagonal
reminder_pos = [[ diag_offset, diag_offset], // top-right
[-diag_offset, -diag_offset]]; // bottom-left
/* ── Rounded square helper ── */
module rounded_square(size, height, r) {
linear_extrude(height)
offset(r = r)
square([size - 2*r, size - 2*r], center = true);
}
/* ── Main geometry ── */
module tile() {
difference() {
// Solid body: rounded square
rounded_square(tile_size, total_height, corner_r);
// Role token cavity: centered, top layer
translate([0, 0, base_thickness + reminder_depth])
cylinder(d = role_cavity_dia, h = role_depth + 0.01, $fn = 80);
// Reminder token cavities: bottom layer, along diagonal
for (pos = reminder_pos) {
translate([pos[0], pos[1], base_thickness])
cylinder(d = reminder_cavity_dia, h = reminder_depth + 0.01, $fn = 60);
}
// Pass-through holes: cut through role layer above each reminder
for (pos = reminder_pos) {
translate([pos[0], pos[1], base_thickness + reminder_depth - 0.01])
cylinder(d = reminder_cavity_dia, h = role_depth + 0.02, $fn = 60);
}
// Finger scoop: small notch at the midpoint between the two
// reminder cavities, cut from base through the full height,
// so you can get a fingertip under a token edge
translate([0, 0, base_thickness])
cylinder(d = finger_scoop_dia, h = total_height, $fn = 40);
}
}
tile();
// ── Console diagnostics ──
echo(str("Tile size: ", tile_size, "mm square"));
echo(str("Total height: ", total_height, "mm"));
echo(str("Diagonal offset: ", diag_offset, "mm per axis"));
echo(str("Reminder center-to-center: ", min_center_dist, "mm"));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment