Open general

Silkscreen bake times out on complex boards + corrupts the GLB (fix: bake after optimize)

John Lauer · 6d ago

Silkscreen bake times out (60s) on complex boards and then corrupts the whole GLB

cc Drew, Colby (silkscreen overlay + molecule pipeline).

Two live wiki pages show it exactly

  • Works (simple board, 6 meshes): https://wiki.adom.inc/adom/controlpanel-mpin-connector POST /convert?molecule=true with STEP + registered silk PNGs -> silkscreen_applied: true, both sides, anchored, 196 KB. Silk (SIDE A, RUD+/-, SDA, pad outlines) is perfectly registered.
  • Fails (complex board, ~174 meshes): https://wiki.adom.inc/adom/bq25792-charger Same call -> silkscreen subprocess times out at 60s, and the killed process leaves out.glb truncated, so unit-normalize, gold, compress, and provenance then all fail with "not a GLB" / "Unexpected end of JSON input". silkscreen_applied: false. (The silk you see on that page is a local hack I had to apply on the optimized GLB as a fallback; it is slightly mis-registered because the raw board bbox included an overhanging connector. Not the service's fault - just proof of what we lose without the in-pipeline bake.)

Root cause

apply_silkscreen runs on out.glb = the raw OCCT tessellation (BQ board: ~16 MB / 174 meshes / 226k verts, pre-join). pygltflib parsing that + the per-node top-face search blows the 60s budget. PNG size is NOT the cause (retried at 15 KB / 793x415, still timed out).

Proof it's the stage, not the code: I ran your exact apply_silkscreen(glb, top, bot) unchanged on the post-optimize GLB (465 KB, 20 meshes) -> completed in 0.3 s, applied: true. Your algorithm is correct.

Fix (two parts)

  1. Run the silkscreen overlay AFTER optimize.mjs (on the small joined GLB, not the raw tessellation). ~0.3 s instead of >60 s, scales to any board.
  2. Make each post-step copy-in/copy-out (write to a temp, swap on success) so a timeout/crash in one step (silkscreen) can't corrupt the artifact and take down normalize/gold/compress/provenance.

Nice-to-have: bump the 60s subprocess timeout, but (1) makes it moot. I have the failing job ids + the registered silk PNGs if useful.

1 Reply

John Lauer · 6d ago

Follow-up: the board bbox needs to come from the FR4 body (stackup thinking), and there's a better trace/visibility approach than textures.

Measured live on the BQ25792 board (raw pre-optimize GLB, distinct bodies):

Layer Z (mm) Thickness
Top soldermask 1.516 - 1.582 65 um
Top copper (traces) 1.516 - 1.551 35 um
FR4 core 0.000 - 1.516 1.516 mm
Bottom copper -0.035 - 0.000 35 um
Bottom soldermask -0.065 - 0.000 65 um

Two _board_bbox bugs this exposes (silkscreen_overlay.py):

  1. XY from the whole assembly ("nothing overhangs a PCB edge") is false - the BQ board's edge-hanging switch inflates Y 26.4 -> 28.2mm and misregisters the silk. Take XY from the substrate body.
  2. Z from "board-footprint meshes" breaks after join - post-optimize, meshes merge by material, so a components-spanning merged mesh passes the 50%-area filter and z-max lands at COMPONENT height (a quad ends up floating above the parts, seen live). Identify the FR4/mask bodies in the RAW GLB (node names Board, 1-soldermask, ...) BEFORE join, or pick the z from a slab-thickness heuristic (0.4-3mm thick, board-size XY).

Also worth knowing: the copper traces are real 3D bodies in the export (35 um thick, so cheap) - they're invisible only because Fusion colors them identically to the FR4 and the mask exports opaque. Recoloring the *-copper bodies to a metallic copper + making *-soldermask translucent (alpha ~0.6) in the raw GLB, THEN optimizing (join preserves distinct materials), gives real visible routing with no texture at all: https://wiki.adom.inc/adom/bq25792-charger (19MB -> 822KB). Might be worth folding into molecule mode as an option.

Stackup source data is queryable too (EAGLE .brd designrules: layerSetup/mtCopper/mtIsolate) - we're now putting a stackup table on each exported board's wiki page.

Log in to reply.