Field Notes

Rotation Math Will Humble You

Three wrong attempts to cut through-hole text into a tube face in OpenSCAD. The rotation math feels tractable. It is not. Here's what broke each time and what the working version actually looks like.

What YETI Did

There's a YETI cooler tray insert where "YETI" is cut completely through the material — actual holes in the shape of the letters, not a deboss or an emboss. Light comes through. The shape is clean. It looks expensive.

That's the spec: cut "Sorted3D" through the 4mm tube wall on each side face of the tip-up holder. In OpenSCAD, you do that with linear_extrude inside a difference(). The hard part is getting the text facing the right direction on the right face.


Attempt 1: Wrong Depth, Looked Right in Preview

The first version used 1.6mm for the extrude depth — shallow deboss instead of through-cut. In the OpenSCAD preview, the cutter geometry was visible as a ghost on the surface, which looked like raised text. It was not. It was the preview showing the cutting volume.

Rendered to STL: the cutter was going in the wrong direction, entirely outside the tube. No cut at all.


Attempt 2: Cutting In, Text Mirrored

Fixed the direction. Now the cutter actually intersected the tube wall. Characters were debossed. Progress.

Text read: ɔ8bəɹɹoƧ

That's "Sorted3D" mirrored. Every letter was backwards. The rotation was mapping the face correctly but the text was readable only from behind the wall — like looking at a window sign from outside when it was hung facing in.


Attempt 3: Different Wrong Mirror

Added mirror([1,0,0]) to flip the text. Left tube: correct. Right tube: now mirrored instead. Two tubes, one wrong each time.


What Actually Worked

The fix was changing methodology, not just the rotation values. Instead of reasoning about 3D rotation in the main file and guessing, the approach was:

The correct rotation for the left face (readable from the left, cutting in +X):

translate([-0.1, TU_OD_Y/2, TU_H/2])
    rotate([0, 90, 0])
        rotate([0, 0, 90])
            linear_extrude(TU_WALL + 0.2)
                mirror([1, 0, 0])
                    text("Sorted3D", ...);

The correct rotation for the right face (readable from the right, cutting in -X):

translate([TOTAL_W + 0.1, TU_OD_Y/2, TU_H/2])
    rotate([0, -90, 0])
        rotate([0, 0, -90])
            linear_extrude(TU_WALL + 0.2)
                mirror([1, 0, 0])
                    text("Sorted3D", ...);

Both faces use mirror([1,0,0]). The inner rotate([0,0,90]) / rotate([0,0,-90]) are mirror images of each other. The outer rotate([0,90,0]) / rotate([0,-90,0]) control which direction the extrude cuts — into +X for the left face, into -X for the right face.


The Rule

When placing extruded text on a face in OpenSCAD, do not reason about 3D rotations in your head. It feels like it should be tractable. It is not. Build an isolated test file with just the cutter geometry and a representative box. Render from the exact camera angle a real viewer would use. Read the image yourself before applying it to the real file.

The two-minute test file saves thirty minutes of wrong guesses. It also saves you from asking someone else to tell you if the text looks right only to find out it doesn't and you're right back where you started.

Tips
rotate([0,90,0]) maps local +Z to world +X. rotate([0,-90,0]) maps local +Z to world -X.

This is the key for placing text cutters on YZ-plane faces. Get the extrude direction right first, then fix the text orientation. The extrude direction is controlled by the outer rotation. The text orientation is controlled by the inner rotation and mirror.

The mirror([1,0,0]) is not optional — and both faces need it.

Without it, text rendered on a face is readable only from behind the wall. Both the left and right faces need the mirror despite appearing to be mirror images of each other — the inner rotation handles the orientation flip; the mirror handles the character reversal.

Test with a box, not with the real part.

The real part has 10 boolean operations. A test box has one. Render time is faster, failure is cheaper, and you're not putting bad edits into a file with a dozen other things that could be accidentally broken while you're debugging.