Adom Step2GLB - The Adom STEP Engine
Public Made by Adomby adom
The Adom STEP engine: fully manage STEP files. Convert to color-preserving GLB, render thumbnails and vector outlines, laser-etch MPNs, create and edit STEP geometry, extract features, and run molecule mode. One name for the thin Rust CLI and the shared OCCT service. Formerly 'step2glb' + 'service-step2glb'.
Lasered part number lands on the +Z face for every up-axis, so down orientations render it mirrored
With --name, the lasered part number is always placed on the +Z face, whatever --up-axis says. On any down orientation (zDown, yDown, xDown) the marking therefore sits on the face pointing away from the camera, and because the glyphs are projected to 2D and drawn over the PNG without a depth test, they come out mirror-reversed across the part.
Split out of #12 (thumbnail zDown returned the top view). #12 is fixed and deployed; this one is independent and was not introduced by that fix.
Repro
step2glb thumbnail BSC016N06NS-ai-nominal.step --pose iso --up-axis zDown \
--name BSC016N06NS --width 640 --height 480 -o iso-zdown-name.png
The part number reads backwards, lying across the exposed drain pad on the underside — a face that carries no marking on the real part.
Same on the top pose now that --pose top --up-axis zDown correctly shows the underside:
step2glb thumbnail BSC016N06NS-ai-nominal.step --pose top --up-axis zDown \
--name BSC016N06NS --width 640 --height 480 -o top-zdown-name.png
Cause
_up_for_axis() in api/step_to_thumbnail.py maps the up-axis to a bare axis letter:
def _up_for_axis(up_axis):
a = (up_axis or "").lower()
if a in ("y", "yup", "ydown", "-y"):
return "y"
return "z"
zDown and asIs both return "z", yUp and yDown both return "y". The sign is dropped. _top_slice_inplane_bbox() and _name_world_polylines() then both take the max end of that axis as the top face, so a part authored upside-down gets its part number on its underside.
up_axis documents which source axis is the chip's up, so the chip's marked face is the one at the up end of it. For zDown that is zmin, not zmax.
xUp and xDown are worse than mirrored: neither is listed, so they fall through to "z" and the marking goes on a face 90 degrees away from the one they name.
Not a one-line change
Threading the sign through means _top_slice_inplane_bbox() has to slice from the other end, and _name_world_polylines() has to flip the in-plane basis to stay right-handed. It already carries a hand-correction for the y-up case, so getting the other five wrong would render the glyphs backwards on the correct face instead of forwards on the wrong one. The rule is that the basis (e_u, e_v, n) must be right-handed with n the outward normal of the marked face, which is a different flip for each of the six.
Correction to an earlier version of this issue: I first wrote that this sits in the laser-etch fitting code reworked in #13/#14/#15. It does not, and the separation is worth stating because it makes this safer to change than it first looked. /laser-etch goes through laser_etch.py to laser_fit.py, which takes no up-axis at all and finds the marked face geometrically via largest_planar_normal(). The thumbnail --name overlay is the older, independent path in step_to_thumbnail.py, last touched before that work landed. _up_for_axis() has exactly one caller. So the fit report is not at risk here; the verification this needs is a rendered check of all six orientations, not a re-run of the #13/#14/#15 fitting evidence.
Verified pre-existing: an iso/zDown render with --name is byte-identical before and after the #12 fix.
Ray is taking this one — it is next in the STEP-engine queue behind #17.

