Skip to content

3D-Printed Parts for the 32ESPecial🔗

Several of the parts for the 32ESPecial can be made using a 3D printer. To print these, you first need to create an STL file using OpenSCAD. Instructions for how to do this are here.

The source file for each of these parts is included below its description. These make use of would not be possible without the Belfry OpenScad Library, v2, licensed under the BSD 2-Clause "Simplified" License. That library is available on GitHub:

https://github.com/BelfrySCAD/BOSL2

Barrel Board Holder🔗

This holder works with the 2022A or 2024B barrel boards. It requires two (2) M3 x 10mm to fasten the PCBA to the holder. The holder is then fastened to the barrel using a zip tie.

Barrel Board Holder
Barrel Board Holder
OpenSCAD Source for the Barrel Board Holder
// This software is part of the KTag project, a DIY laser tag game
// with customizable features and wide interoperability.
//
// 🛡️ https://ktag.clubk.club 🃞
//
// Copyright © 2025 Joseph P. Kearney and the KTag developers.

// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
// details.
//
// There should be a copy of the GNU Affero General Public License in the LICENSE
// file in the root of this repository. If not, see http://www.gnu.org/licenses/.

// This software makes use of the Belfry OpenScad Library, v2,
// licensed under the BSD 2-Clause "Simplified" License.
// https://github.com/BelfrySCAD/BOSL2
include <BOSL2/std.scad>

/* [Options] */
// Please select a mounting option for the 2022A or 2024B PCB.
PCB_Mounting_Option = 0; // [0:M3 pilot hole, 1:M3 brass insert]

/* [Hidden] */

// Set the resolution compatible with 3d printing.
//
// $fa is the minimum angle for a fragment. Even a huge circle does not have
//     more fragments than 360 divided by this number. The default value is
//     12 (i.e. 30 fragments for a full circle). The minimum allowed value
//     is 0.01. Attempting to set a lower value causes a warning.
//
// $fs is the minimum size of a fragment. The default value is 2 so very small
//     circles have a smaller number of fragments than specified using $fa.
//     The minimum allowed value is 0.01. Attempting to set a lower value
//     causes a warning.
//
// $fn is number of fragments and usually has the default value of 0. When this
//     variable has a value greater than zero, the other two variables are
//     ignored, and a full circle is rendered using this number of fragments.
$fa = 1;
$fs = 0.5;
$fn = 0;

// Mounting Options (see above)
MOUNTING_PILOT_HOLE = 0;
MOUNTING_BRASS_INSERT = 1;


// Constants (in millimeters)
BOSS_X_OFFSET = 11.0;
BOSS_Y_OFFSET = 0.0;
BOSS_Z_HEIGHT = 2.0;
TOTAL_HEIGHT = 25;
PIPE_INNER_DIAMETER = 34.0;

ZIP_TIE_HEIGHT = 2.0;
ZIP_TIE_WIDTH = 5.0;
BOSS_HOLE_FOR_BRASS_INSERT = 4.0;
M3_PILOT_HOLE_DIAMETER = 2.8;
MOUNTING_Z_OFFSET = -TOTAL_HEIGHT/2;

function getMountingHoleDiameter(mounting_option) = 
    mounting_option == MOUNTING_PILOT_HOLE ? M3_PILOT_HOLE_DIAMETER :
    mounting_option == MOUNTING_BRASS_INSERT ? BOSS_HOLE_FOR_BRASS_INSERT :
    BOSS_HOLE_FOR_BRASS_INSERT; // Default value if no match

MOUNTING_HOLE_DIAMETER = getMountingHoleDiameter(PCB_Mounting_Option);

CONNECTOR_Y_OFFSET = 7.0;
CONNECTOR_CLEARANCE = 15.0;

EPSILON = 0.01;
PART_COLOR = "gray";

module M3_Mounting_Hole()
{
    HEIGHT = 12.0;

    translate([ 0, 0, -HEIGHT ])
    difference()
    {
        cylinder(HEIGHT + EPSILON, d = MOUNTING_HOLE_DIAMETER);
    }
}

module M3_Mounting_Boss()
{
    BOSS_OD = 9.8;
    HEIGHT = 12.0;

    difference()
    {
        translate([ 0, 0, -HEIGHT ]) cylinder(HEIGHT, d = BOSS_OD);
        M3_Mounting_Hole();
    }
}


color(PART_COLOR, 1)
difference()
{
    union()
    {
        cyl(l=TOTAL_HEIGHT, d=PIPE_INNER_DIAMETER, rounding=PIPE_INNER_DIAMETER/10);
        translate([ -BOSS_X_OFFSET, BOSS_Y_OFFSET, (TOTAL_HEIGHT / 2) + BOSS_Z_HEIGHT ]) M3_Mounting_Boss();
        translate([  BOSS_X_OFFSET, BOSS_Y_OFFSET, (TOTAL_HEIGHT / 2) + BOSS_Z_HEIGHT ]) M3_Mounting_Boss();
    }
    translate([ -BOSS_X_OFFSET, BOSS_Y_OFFSET, (TOTAL_HEIGHT / 2) + BOSS_Z_HEIGHT ]) M3_Mounting_Hole();
    translate([  BOSS_X_OFFSET, BOSS_Y_OFFSET, (TOTAL_HEIGHT / 2) + BOSS_Z_HEIGHT ]) M3_Mounting_Hole();

    // Zip Tie
    cuboid([PIPE_INNER_DIAMETER * 2,ZIP_TIE_HEIGHT, ZIP_TIE_WIDTH], rounding=ZIP_TIE_HEIGHT/10);

    // M3 Wood Screws
    //xcyl(PIPE_INNER_DIAMETER * 2, d=M3_PILOT_HOLE_DIAMETER);

    translate([ 0, -(TOTAL_HEIGHT/2)-CONNECTOR_Y_OFFSET, 0 ]) cuboid([CONNECTOR_CLEARANCE, TOTAL_HEIGHT, 2 * TOTAL_HEIGHT], rounding=TOTAL_HEIGHT/10);
}

Receiver Board Holder🔗

This holder works with the 2024C receiver board. It requires one (1) M3 x 10mm to fasten the PCBA to the holder. The holder is then attached to the body using a zip tie.

Receiver Board Holder
Receiver Board Holder
OpenSCAD Source for the Receiver Board Holder
// This software is part of the KTag project, a DIY laser tag game
// with customizable features and wide interoperability.
//
// 🛡️ https://ktag.clubk.club 🃞
//
// Copyright © 2025 Joseph P. Kearney and the KTag developers.

// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
// details.
//
// There should be a copy of the GNU Affero General Public License in the LICENSE
// file in the root of this repository. If not, see http://www.gnu.org/licenses/.

// This software makes use of the Belfry OpenScad Library, v2,
// licensed under the BSD 2-Clause "Simplified" License.
// https://github.com/BelfrySCAD/BOSL2
include <BOSL2/std.scad>

/* [Options] */
// Please select a mounting option for the 2024C PCB.
PCB_Mounting_Option = 0; // [0:M3 pilot hole, 1:M3 brass insert]

/* [Hidden] */

// Set the resolution compatible with 3d printing.
//
// $fa is the minimum angle for a fragment. Even a huge circle does not have
//     more fragments than 360 divided by this number. The default value is
//     12 (i.e. 30 fragments for a full circle). The minimum allowed value
//     is 0.01. Attempting to set a lower value causes a warning.
//
// $fs is the minimum size of a fragment. The default value is 2 so very small
//     circles have a smaller number of fragments than specified using $fa.
//     The minimum allowed value is 0.01. Attempting to set a lower value
//     causes a warning.
//
// $fn is number of fragments and usually has the default value of 0. When this
//     variable has a value greater than zero, the other two variables are
//     ignored, and a full circle is rendered using this number of fragments.
$fa = 1;
$fs = 0.5;
$fn = 0;

// Mounting Options (see above)
MOUNTING_PILOT_HOLE = 0;
MOUNTING_BRASS_INSERT = 1;


// Constants (in millimeters)
BOSS_X_OFFSET = 0.0;
BOSS_Y_OFFSET = 4.42;
BOSS_Z_HEIGHT = 2.0;

TOTAL_HEIGHT = 32.0;
DOME_INSERT_HEIGHT = 11.3 - BOSS_Z_HEIGHT;
TRANSITION_HEIGHT = 10.0;
BASE_HEIGHT = TOTAL_HEIGHT - DOME_INSERT_HEIGHT - TRANSITION_HEIGHT;

HOLDER_OD = 25.0;
SCH_40_ONEandaQUARTER_ID = 35.0;
SCH_40_ONEandaQUARTER_OD = 41.5;

ZIP_TIE_HEIGHT = 2.0;
ZIP_TIE_WIDTH = 5.0;
BOSS_HOLE_FOR_BRASS_INSERT = 4.0;
M3_PILOT_HOLE_DIAMETER = 2.8;
MOUNTING_Z_OFFSET = -TRANSITION_HEIGHT - BASE_HEIGHT/2;

function getMountingHoleDiameter(mounting_option) = 
    mounting_option == MOUNTING_PILOT_HOLE ? M3_PILOT_HOLE_DIAMETER :
    mounting_option == MOUNTING_BRASS_INSERT ? BOSS_HOLE_FOR_BRASS_INSERT :
    BOSS_HOLE_FOR_BRASS_INSERT; // Default value if no match

MOUNTING_HOLE_DIAMETER = getMountingHoleDiameter(PCB_Mounting_Option);

CONNECTOR_Y_OFFSET = 3.0;
CONNECTOR_CLEARANCE = 18.0;

EPSILON = 0.01;
PART_COLOR = "gray";

module M3_Mounting_Hole()
{
    HEIGHT = 12.0;

    translate([ 0, 0, -HEIGHT ])
    difference()
    {
        cylinder(HEIGHT + EPSILON, d = MOUNTING_HOLE_DIAMETER);
    }
}

module M3_Mounting_Boss()
{
    BOSS_OD = 9.8;
    HEIGHT = 12.0;

    difference()
    {
        translate([ 0, 0, -HEIGHT ]) cylinder(HEIGHT, d = BOSS_OD);
        M3_Mounting_Hole();
    }
}

difference()
{
    union()
    {
        color(PART_COLOR, 1)
        translate([0, 0, -TRANSITION_HEIGHT + 3.3])  // Why 3.3?
        tube(TOTAL_HEIGHT  , od=SCH_40_ONEandaQUARTER_OD, id=SCH_40_ONEandaQUARTER_ID);

        color(PART_COLOR, 1)
        difference()
        {
            union()
            {
                translate([0,0,DOME_INSERT_HEIGHT/2])
                cyl(l=DOME_INSERT_HEIGHT, d=HOLDER_OD, rounding2=HOLDER_OD/10);
                translate([  BOSS_X_OFFSET, BOSS_Y_OFFSET, DOME_INSERT_HEIGHT + BOSS_Z_HEIGHT ]) M3_Mounting_Boss();
                translate([0, 0, -TRANSITION_HEIGHT/2])
                cyl(h=TRANSITION_HEIGHT, d1=SCH_40_ONEandaQUARTER_OD, d2=HOLDER_OD);
                translate([0, 0, -TRANSITION_HEIGHT - BASE_HEIGHT/2])
                cyl(h=BASE_HEIGHT + EPSILON, d=SCH_40_ONEandaQUARTER_OD);
            }
            translate([BOSS_X_OFFSET, BOSS_Y_OFFSET, DOME_INSERT_HEIGHT + BOSS_Z_HEIGHT]) M3_Mounting_Hole();
            translate([ 0, -(TOTAL_HEIGHT/2)-CONNECTOR_Y_OFFSET, 0 ]) cuboid([CONNECTOR_CLEARANCE, TOTAL_HEIGHT, 2 * TOTAL_HEIGHT], rounding=TOTAL_HEIGHT/10);
        }
    }

    // Zip Tie
    translate([0, 0, MOUNTING_Z_OFFSET])
    cuboid([SCH_40_ONEandaQUARTER_OD * 2,ZIP_TIE_HEIGHT, ZIP_TIE_WIDTH], rounding=ZIP_TIE_HEIGHT/10);

    // M3 Wood Screws
    //translate([0, 0, MOUNTING_Z_OFFSET])
    //xcyl(SCH_40_ONEandaQUARTER_OD * 2, d=M3_PILOT_HOLE_DIAMETER);
}