Although I’d put the same knob on the half-triangle end piece template as on the equilateral triangle template for piecing hexagons into strips, Mary decided a flat chip would be easier to use:

Bonus: you can now flip it over to cut the other half-triangles, if you haven’t already figured out how to cut two layers of fabric folded wrong sides together.
While I was at it, the knob on the triangle became optional, too. Flipping that one doesn’t buy you much, though.
The OpenSCAD source as a GitHub Gist has been ever so slightly tweaked:
// Quilting - Hexagon Templates | |
// Ed Nisley KE4ZNU - July 2020 | |
// Reverse-engineered to repair a not-quite-standard hexagon quilt | |
// Useful geometry: | |
// https://en.wikipedia.org/wiki/Hexagon | |
/* [Layout Options] */ | |
Layout = "Build"; // [Build, HexBuild, HexPlate, TriBuild, TriPlate, EndBuild, EndPlate] | |
//------- | |
//- Extrusion parameters must match reality! | |
// Print with 2 shells | |
/* [Hidden] */ | |
ThreadThick = 0.25; | |
ThreadWidth = 0.40; | |
HoleFinagle = 0.2; | |
HoleFudge = 1.00; | |
function HoleAdjust(Diameter) = HoleFudge*Diameter + HoleFinagle; | |
Protrusion = 0.1; // make holes end cleanly | |
function IntegerMultiple(Size,Unit) = Unit * ceil(Size / Unit); | |
inch = 25.4; | |
//------- | |
// Dimensions | |
/* [Layout Options] */ | |
FinishedWidthInch = 2.75; | |
FinishedWidth = FinishedWidthInch * inch; | |
SeamAllowanceInch = 0.25; | |
SeamAllowance = SeamAllowanceInch * inch; | |
TemplateThick = 3.0; | |
TriKnob = true; | |
EndKnob = false; | |
/* [Hidden] */ | |
FinishedSideInch = FinishedWidthInch/sqrt(3); | |
FinishedSide = FinishedSideInch * inch; | |
echo(str("Finished side: ",FinishedSideInch," inch")); | |
CutWidth = FinishedWidth + 2*SeamAllowance; | |
CutSide = CutWidth/sqrt(3); | |
echo(str("Cut side: ",CutSide / inch," inch")); | |
// Make polygon-circles circumscribe the target widths | |
TemplateID = FinishedWidth / cos(180/6); | |
TemplateOD = CutWidth / cos(180/6); | |
/* [Hidden] */ | |
TriRadius = FinishedSide/sqrt(3); | |
TriPoints = [[TriRadius,0], | |
[TriRadius*cos(120),TriRadius*sin(120)], | |
[TriRadius*cos(240),TriRadius*sin(240)] | |
]; | |
echo(str("TriPoints: ",TriPoints)); | |
EndPoints = [[TriRadius,0], | |
[TriRadius*cos(120),TriRadius*sin(120)], | |
[TriRadius*cos(120),0] | |
]; | |
echo(str("EndPoints: ",EndPoints)); | |
TipCutRadius = 2*(TriRadius + SeamAllowance); // circumscribing radius of tip cutter | |
TipPoints = [[TipCutRadius,0], | |
[TipCutRadius*cos(120),TipCutRadius*sin(120)], | |
[TipCutRadius*cos(240),TipCutRadius*sin(240)] | |
]; | |
HandleHeight = 1 * inch; | |
HandleLength = (TemplateID + TemplateOD)/2; | |
HandleThick = IntegerMultiple(3.0,ThreadWidth); | |
HandleSides = 12*4; | |
StringDia = 4.0; | |
StringHeight = 0.6*HandleHeight; | |
DentDepth = HandleThick/4; | |
DentDia = 15 * DentDepth; | |
DentSphereRadius = (pow(DentDepth,2) + pow(DentDia,2)/4)/(2*DentDepth); | |
KnobOD = 15.0; // Triangle handle | |
KnobHeight = 20.0; | |
//------- | |
module PolyCyl(Dia,Height,ForceSides=0) { // based on nophead's polyholes | |
Sides = (ForceSides != 0) ? ForceSides : (ceil(Dia) + 2); | |
FixDia = Dia / cos(180/Sides); | |
cylinder(r=HoleAdjust(FixDia)/2,h=Height,$fn=Sides); | |
} | |
//------- | |
// Hex template | |
module HexPlate() { | |
difference() { | |
cylinder(r=TemplateOD/2,h=TemplateThick,$fn=6); | |
translate([0,0,-Protrusion]) | |
cylinder(r=TemplateID/2,h=(TemplateThick + 2*Protrusion),$fn=6); | |
} | |
for (i=[1:6/2]) | |
rotate(i*60) | |
translate([0,0,TemplateThick/2]) | |
cube([HandleLength,HandleThick,TemplateThick],center=true); | |
} | |
module HexHandle() { | |
difference() { | |
rotate([90,0,0]) | |
scale([1,HandleHeight/(TemplateOD/2),1]) | |
rotate(180/HandleSides) | |
cylinder(d=HandleLength,h=HandleThick,center=true,$fn=HandleSides); | |
translate([0,0,-HandleHeight]) | |
cube([2*TemplateOD,2*TemplateOD,2*HandleHeight],center=true); | |
translate([0,HandleThick,StringHeight]) | |
rotate([90,090,0]) | |
rotate(180/8) | |
PolyCyl(StringDia,2*HandleThick,8); | |
for (j=[-1,1]) { | |
translate([0,j*(DentSphereRadius + HandleThick/2 - DentDepth),StringHeight]) | |
rotate(180/48) | |
sphere(r=DentSphereRadius,$fn=48); | |
} | |
} | |
} | |
module HexTemplate() { | |
HexPlate(); | |
HexHandle(); | |
} | |
//------- | |
// Triangle template | |
module TriPlate() { | |
linear_extrude(height=TemplateThick) | |
intersection() { | |
offset(delta=SeamAllowance) // basic cutting outline | |
polygon(points=TriPoints); | |
rotate(180) | |
polygon(points=TipPoints); | |
} | |
} | |
module TriTemplate() { | |
union() { | |
if (TriKnob) | |
cylinder(d=KnobOD,h=KnobHeight,$fn=HandleSides); | |
TriPlate(); | |
} | |
} | |
//------- | |
// End piece template | |
module EndPlate() { | |
linear_extrude(height=TemplateThick) | |
intersection() { | |
offset(delta=SeamAllowance) // basic cutting outline | |
polygon(points=EndPoints); | |
rotate(180) | |
polygon(points=TipPoints); | |
} | |
} | |
module EndTemplate() { | |
union() { | |
if (EndKnob) | |
translate([0,(TriRadius/2)*sin(30),0]) | |
cylinder(d=KnobOD,h=KnobHeight,$fn=HandleSides); | |
EndPlate(); | |
} | |
} | |
//------- | |
// Build it! | |
if (Layout == "HexPlate") | |
HexPlate(); | |
if (Layout == "HexBuild") | |
HexTemplate(); | |
if (Layout == "TriPlate") | |
TriPlate(); | |
if (Layout == "TriBuild") | |
TriTemplate(); | |
if (Layout == "EndPlate") | |
EndPlate(); | |
if (Layout == "EndBuild") | |
EndTemplate(); | |
if (Layout == "Build") { | |
translate([1.5*TriRadius,-TriRadius,0]) | |
rotate(180/6) | |
TriTemplate(); | |
translate([-1.5*TriRadius,-TriRadius,0]) | |
rotate(180/6) | |
EndTemplate(); | |
translate([0,TemplateOD/2,0]) | |
HexTemplate(); | |
} |