component
Adom Machine Pins, Fusion Library + Sample Board
Public Made by Adomby adom
One Fusion 360 .lbr with all four Adom press-fit machine pins (working 3D), plus a sample board (2D/3D/silkscreen) ganging all four together. Fully documented and rebuildable.
← Commit history
Skill: rewrite the lead-GLB recipe with all this session's learnings (Draco decode, 1.6mm board, 1oz copper, hemisphere paste, 3D-text-not-texture, apex-on-target arrows, interference-fit not gas-tight, text-no-shadow via alpha-blend, no assembly rotation, native .fsch/.fbrd, viewer refreshRate PR, pup workflow)
2 files changed
+68−40
AdomMachinePins-complete.zip⋯ 1 unchanged line ⋯
SKILL.md+68−40@@ -175,43 +175,71 @@ for mesh in g.meshes: # decode each primitive Render at rest AND at the animation peak (lift the PIN_* nodes) and LOOK at both. Only push once the pins visibly seat in their own holes and the solder balls ring each pad. -## The reliable lead-GLB recipe that shipped (use the real Fusion board, do not hand-build the slab)--The user explicitly wanted the REAL Fusion board, not a hand-modeled slab. So: export the Fusion 3D-PCB to STEP, `step2glb` it (real holes, pads, pins, colors), then Draco-DECODE it and rebuild an-uncompressed GLB with `trimesh` so you can add what STEP drops and can render-verify it:- - board/soldermask meshes -> `alphaMode=BLEND` alpha ~0.45 (transparent FR4, see the tails through it);- - merge each pin's many sub-meshes (nodes named `MpinContact*` / `=>[0:1:1:*]`) into ONE node per pin- (`PIN_0..PIN_3`) so it animates as a unit;- - 300um solder-paste balls: a ring of small metallic spheres just outside each barrel base, on the- board top surface (auto-size the ring from each pin's detected barrel radius: ~9 balls medium, ~16 large);- - add a gentle 2 to 3mm insertion animation on the PIN_* nodes (see requirement 9);- - keep balls STATIC (paste stays on the pad; only the pin moves).-Scripts that shipped this: `/tmp/build_board_glb.py` (decode + rebuild + balls) and-`/tmp/add_anim_board.py` (4-pin animation).--## Recreate the lead GLB animation (all 4 pins, real holes, silk, solder balls)--The wiki lead 3D is a single hand-built GLB that the native Babylon viewer auto-plays. Build it with-`trimesh` + `pygltflib` (no Fusion export, so it can carry silk + animation):--1. **FR4 board with REAL holes:** `board = trimesh.creation.box([50,50,1.6])`, then for each pin- `board = board.difference(trimesh.creation.cylinder(radius=drill/2, height=5))` translated to the- pad center (needs `manifold3d`). Material: green, `alphaMode=BLEND`, `baseColorFactor` alpha 0.5,- `doubleSided` (transparent FR4 so you see the press-fit through it).-2. **Per pin:** the real STEP-derived pin mesh (Draco-decode the pin `.glb` with node-transform- composition, gold), annular copper pads top+bottom (`trimesh.creation.annulus(drill/2, pad/2)`), a- plated barrel in the hole, and a ring of 300um **hemisphere** solder domes top+bottom (manual lathe;- flat side on the copper). Reuse `adom-footprint/src/paste.rs` dot math (`DOT_DIA=0.30`).-3. **Silkscreen:** a flat textured quad on the board top per pin (PIL renders name/drill/ring as white- text on transparent; material `alphaMode=MASK`, doubleSided). Position beside each pad like the Fusion- silk.-4. **Animation:** one glTF translation animation with a sampler+channel per PIN node; keyframe the pin- up by `-zmin` (its seated depth), hold, press down, loop. Append the accessors to the binary blob- with the `add_anim.py` bytearray pattern (do NOT hand-splice bufferView offsets, it corrupts the GLB).-5. Assign PBR materials (FR4 transparent, gold pin, copper pads/barrel, teal paste, silk texture) with- `pygltflib` and drop `COLOR_0` so `baseColorFactor` wins. Put the GLB on the page as `model_3d`.--Known limitation: the native viewer's ground-plane shadows do not track animated meshes (they look-static as the pins move). That is a viewer behavior, not the GLB; a viewer/git-wiki tweak-(dynamic shadow caster or `showGround:false`) is the real fix.+## The lead-GLB recipe that shipped (authoritative, every step below was learned the hard way)++The lead 3D is ONE GLB the native Babylon viewer auto-plays. Base it on the REAL Fusion board (the+user insisted, no hand-modeled slab for the pins). Full builder: [`scripts/build_board_glb.py`];+animation: [`scripts/add_anim_board.py`]. The exact ordered recipe:++1. **Decode the real Fusion board.** Export the Fusion 3D PCB to STEP, `step2glb` it -> a **Draco**+ GLB. `trimesh` CANNOT read Draco (returns zero-area meshes). Use `DracoPy.decode` per primitive ++ compose node transforms yourself. Pins are the nodes named `MpinContact*` / `=>[0:1:1:*]`; cluster+ them by xy into 4, merge each into ONE node (`PIN_0..PIN_3`) so it animates as a unit.+2. **1.6mm FR4 board with REAL holes.** The Fusion 3D export is only ~0.3mm thick, REBUILD it: a+ `trimesh.creation.box([50,50,1.6])`, `.difference()` a drill-diameter cylinder per pad (needs+ `manifold3d`). Green, `alphaMode=BLEND` alpha ~0.46, **single-sided** (`doubleSided=False`) so the+ transparent slab does not show its own back-face triangulation.+3. **1oz copper (~35um), NOT buried in the FR4.** Per pad: a `trimesh.creation.annulus(drill/2, pad/2)`+ ring sitting PROUD on the top surface, another PROUD on the bottom, and a thin barrel+ (`annulus(drill/2-CU, drill/2)`) lining the hole, sticking out a hair top+bottom. Copper is real+ 1oz = a super-thin layer, do NOT make it thick.+4. **300um HEMISPHERE solder paste.** `icosphere` then `slice_plane([0,0,0],[0,0,1],cap=True)` = a dome+ with a flat bottom on the pad. Real 0.30mm dia (do NOT oversize), on the annular ring at ~0.45mm+ pitch. Keep balls STATIC (paste stays on the pad; only the pin moves).+5. **Silkscreen + callouts = 3D EXTRUDED TEXT, never a texture.** A flat texture on the board fights+ you forever: its UV + the GLB export's per-face mirror + any rotation keep DE-SYNCING the label+ positions from the pins (this caused a med<->large label swap that shipped). 3D text meshes+ (`text_mesh()` -> `extrude_polygon`) live in the same coordinate space as the pins, so labels stay+ glued to their pins. Cut-out letter counters via even-odd = full-polygon containment+ (`o.contains(other)`); a centroid point falls in the counter of O/D/e and misclassifies.+6. **Callout arrows: apex ON the target.** trimesh `cone` has its apex at +Z*height; after orienting+ the axis to the arrow direction, translate the BASE to `tip - height*dir` so the POINT lands on the+ target (ball / hole), not 1mm past it.+7. **Callout wording.** Show `hole Ø<drill> pin Ø<body>` and `pin <Δ>mm wider = interference fit`. Do+ NOT say "gas-tight" (press-fit marketing jargon, overstated, not everyday EE language). Snap the+ SOLDER-PASTE arrow tip to the ACTUAL nearest ball centre (balls are discrete 300um dots).+8. **Text must cast NO shadow, and this is GLB-only.** The viewer's ShadowGenerator has+ `transparencyShadow=false`, so it SKIPS alpha-blended meshes when building the shadow map. Give the+ silk/callout materials alpha ~0.98 (`alphaMode=BLEND`, still visually solid) => they render but cast+ no shadow. No viewer change, no `nocast` naming needed.+9. **Orientation: do NOT rotate the assembly.** 3D text in its natural orientation already reads+ left-to-right at the viewer's DEFAULT camera. Rotating the assembly 180 (a tempting "face the+ camera" fix) flips the text upside-down. Leave `ROT_CENTER=None`.+10. **Animation:** one glTF translation animation, a sampler+channel per `PIN_*` node, gentle **2-3mm**+ lift (a big lift makes the pins look like giant floating pins over tiny holes). Append accessors to+ the binary blob with the `add_anim.py` bytearray pattern (do NOT hand-splice bufferView offsets).+11. **VERIFY BEFORE PUSH, every time.** Headless-render (DracoPy + pyrender EGL, see the section above)+ AND load in the real Babylon viewer via pup. Confirm by MEASUREMENT that each label's nearest pin+ is the right SIZE (Ø1.6 medium vs Ø4.8 large) — the label swap was invisible in code.++## Native Fusion Electronics files to ship++Provide `fusion/AdomPinsBoard.fsch` (schematic) + `.fbrd` (board) + `.f3d` (3D design) + `.step`.+**Fusion Electronics IS EAGLE 9.x**, so `.fsch`/`.fbrd` are just the EAGLE XML (`<eagle version="9.6.2">`)+with Fusion's extensions — rename the EAGLE `.sch`/`.brd`, they open directly in Fusion (File > Open).+The `.f3d` is the 3D BREP design (NOT the ECAD design); it does not contain the schematic/board.++## The ONE thing that still needs a viewer PR (adom-3d-viewer-babylon9, Colby)++Real cast shadows do NOT animate: the viewer freezes the shadow map (`AdomStatics.refreshShadows()`+sets `refreshRate = REFRESHRATE_RENDER_ONCE`). Fix = keep `REFRESHRATE_RENDER_ONEVERYFRAME` when the+scene has `animationGroups`. That is a viewer-repo change (staged), send it as a PR to Colby; it cannot+be fixed from the GLB.++## pup / show-the-user workflow (do not make them hunt for the window)++- The pup window does NOT auto-update on a push. After each push, **re-navigate** it with a `?v=N`+ cache-bust (the viewer caches the GLB) so it shows the new model.+- Do NOT `location.reload(true)` — it wedges the CDP session and you have to reopen the window.+- REUSE one maximized window; show it on the machine the user is **physically** at (ask which if a VNC+ is in play — a window on the VNC'd host is on the wrong screen).