Adom Chip Fetcher
Public Made by Adomby adom
Your whole parts library — manufacturer-grade chip CAD (symbol, footprint, 3D) one tap from your EDA tool.
Playbook: JST connectors (email-gated CAD)
Read this for any JST part (PHR-/XHP-/ZHR-/SHR-/EHR-/VHR-/PAP-/GHR-/NHR- housings, or B*B-/S*B-/BM*B-/SM*B- board/SMT headers). JST is the canonical example of a manufacturer that emails you the CAD instead of serving it as a download. Proven end-to-end on PHR-2, 2026-06-27.
One-line shape: native browser → jst-mfg.com download link → accept cookies → fill agreement form → JST emails the
.zip→ fetch the email attachment → import. There is no account login for CAD.
0. Why JST is special (don't skip)
- jst.com (USA) is Cloudflare-walled against pup. A pup navigation to any
deep product page returns a "Just a moment… / Performing security
verification" interstitial that never clears. You MUST use the
native-browser bridge (
nbrowser_*, the user's real signed-in Chrome viaadom-browser-extension) — it carries human-trust and passes Cloudflare. If the bridge is absent, tell the user to install it (https://wiki.adom.inc/adom/adom-browser-extension); pup will not work here. - jst.com is only marketing + spec tables + a "Distributor Login" (that login is for distributors, NOT a CAD gate). The actual CAD + catalogs live on the global site jst-mfg.com, which jst.com links to.
- No login is required to get CAD. The gate is a per-download License Agreement form whose submit triggers an email.
1. Resolve the part → series
JST CAD is organized by series, not by individual MPN. Each series has a numeric id (PH = 199, PH high-box = 200, SH = 231, …; ~600+ series).
- Master index ("Series Alphabet Search"):
https://www.jst-mfg.com/product/index.php?type=5— every series is anindex.php?series=<id>link. This page is also your scope list for a batch (one row per series). - Or keyword-search a known MPN:
https://www.jst-mfg.com/search/?q=<MPN>(sources::jst::search_url). Strip ordering suffixes first withsources::jst::base_part— drop(LF)(SN)and any(…)option group, and a trailing suction-capTon SMT headers (B10B-PH-K-S(LF)(SN)→B10B-PH-K-S).
2. Read the CAD columns on the series page
Open the series page in the native browser. Each part row has Download
buttons under format columns. Map them by reading the column header — the
doc= number is per-series, not universal:
| Common (PH, series=199) | doc= | format | inner file |
|---|---|---|---|
| IGES | 1 | 3D | <PART>.IGS |
| STEP | 2 | 3D | <PART>.STEP ← prefer this |
| 3D-PDF | 3 | 3D pdf | <PART>.pdf |
| 2D-PDF | 4 | drawing pdf | <PART>.pdf |
⚠️ Coverage varies: some older series offer only IGES (no STEP). If a
series has no STEP column, take IGES and convert with step2glb/service-kicad
downstream. Always read the header — never assume doc=2 is STEP.
The link itself is built by sources::jst::download_url(series, doc, filename):
…/product/index.php?type=10&series=<S>&doc=<D>&filename=<PART>.zip
3. The download link returns a FORM, not a file
GET-ing the download link does two things server-side:
- binds
(series, doc, filename)into the PHP session, and - returns a License Agreement HTML page (no file).
The page has required fields company, section, name, address, tel, email
(+ optional url) and an "I agree" button wired to a JS download()
function. download() collects every form value and POSTs them to
ajax_download.php (jsonp). The server reads the file to send from the
session set in step 1 — so the GET and the POST must share the browser
session (same native-browser window = automatic).
Accept cookies first. The cookie banner literally says "accept cookies in order to submit any of our forms." Click "Allow all cookies" before filling.
Driving it (native browser)
nbrowser_navigateto thedownload_url→ wait ~2.5s.nbrowser_eval: accept cookies, set the 7 fields by id (dispatchinput+change), then calldownload()(or click "I agree"). The success callback firesalert("The data has been sent to your email address")then navigates toindex.php?series=<S>— hookwindow.alertintosessionStoragefirst since navigation wipes globals, then read it back.
Use the user's real business profile for the fields (see
user_profile.md). For a batch, set the email to a plus-alias like
[email protected] with a Gmail filter/label so the inbox isn't buried (the
file still arrives; adom-google can still read it).
4. Retrieve the emailed file (the part most tools miss)
Since April 2025 JST sends the CAD as an email attachment (<PART>.zip,
inner <PART>.STEP/.IGS), from a JST send-only address, ~30-60s later. This
is where chip-fetcher needs an email-reading capability —
see jst-email-retrieval.md for the Gmail
(adom-google) path and the non-Gmail build-your-own path.
Gmail quick path (adom-google):
adom-google api "https://gmail.googleapis.com/gmail/v1/users/me/messages" \
-q q="JST newer_than:1d" -q maxResults=5 # strip leading "HTTP 200…" line before JSON
adom-google gmail attachments <messageId> # find <PART>.zip + its attId
adom-google gmail read <messageId> <attId> -o <PART>.zip
Pick the newest message whose inner file matches the format you requested
(IGES and STEP both arrive as <PART>.zip — distinguish by the inner
.STEP vs .IGS).
5. Datasheet = series catalog (DIRECT download, no gate)
JST has no per-part datasheet. Use the series catalog PDF, a plain direct
download: sources::jst::catalog_pdf_url("PH") →
https://www.jst-mfg.com/product/pdf/eng/ePH.pdf. Fetch with
nbrowser_fetch_url (returns base64 for binary — decode before writing) and
import as the part's .pdf. The 2D-PDF drawing (doc=4) is the per-part
mechanical print if you want it too.
6. Import + what JST does NOT give you
adom-chip-fetcher import <PART>.STEP --mpn <PART>
adom-chip-fetcher import <catalog>.pdf --mpn <PART>
JST supplies 3D (STEP/IGES) + drawings + catalog datasheet only. It does
NOT supply KiCad .kicad_sym / .kicad_mod. Those come from the ladder.
6z. Series-ID table + full connector component-page pipeline (proven 2026-06-28)
Series IDs (jst-mfg.com index.php?series=<id>): PH 199, XH 277,
SH 231, GH 105, ZH 287, VH 262, SH-high-box etc. via the
alphabet search (type=5). Per series the 2-circuit set:
| Series | Board header | Wire housing | Crimp contact (PDF only, no STEP) | Pitch |
|---|---|---|---|---|
| PH | B2B-PH-K-S |
PHR-2 |
SPH-002T-P0.5S/L (AWG 30-24) |
2.0 |
| XH | B2B-XH-A |
XHP-2 |
SXH-001T-P0.6N (AWG 30-22) |
2.5 |
| SH | SM02B-SRSS-TB |
SHR-02V-S-B |
SSH-003T-P0.2 (AWG 32-26) |
1.0 |
| GH | BM02B-GHS-TBT |
GHR-02V-S |
SSHL-002T-P0.2 (AWG 32-28) |
1.25 |
| ZH | B2B-ZR |
ZHR-2 |
SZH-002T-P0.5 (AWG 32-26) |
1.5 |
The component-page pipeline (the right way — JST 3D is always the part):
- 3D = JST manufacturer STEP via the email flow (§3-4) for BOTH the board header and the wire housing. This is the whole point — never ship a KiCad 3D as the deliverable. (License: don't rehost the STEP; the viewer uses a lossy GLB preview + "run the skill" to fetch the real STEP.)
- Symbol + footprint =
ds2sfrun on the JST datasheet (adom-ds2sf extract library/<MPN> --source-tier mfr). ds2sf works on connectors (2 pins, generic_connector_pin_function). Render its SVGs:adom-ds2sf svg <dir>(footprint) +adom-symbol render-ds2sf --file <MPN>-symbol.extracted.json --out <MPN>-symbol.ds2sf.svg. - KiCad sym/fp/3D = the comparison foil only, never the deliverable. Fetch
the KiCad footprint/symbol (GitLab raw, §6a) + KiCad 3D (
service-kicad model fetch). NOTE: KiCad has no ZH series (it ships ZE for 1.5 mm) — ZH is JST-only, footprint from ds2sf. - chip-fetcher layout: one project per mating system (
JST-<series>-system) holding 3 cards — wire housing, JST board (ds2sf+KiCad sym/fp via the source ▾; JST "Mfr direct" 3D), and<MPN>-KICAD(KiCad-only sym/fp + KiCad 3D). Housings = JST 3D + PDF only (wire parts have no PCB footprint). Tag provenance on import:--content-origin manufacturer --discovery-source jstfor JST files,--content-origin kicadfor KiCad. - Wiki component page (
adom/<mpn-slug>, type=component): the native 3D viewer'smodel_3dis a merged comparison GLB built with trimesh — KiCad model + JST model side by side, each oriented per the user's chip-fetcherchosen_up_axispick (JST headers = yUp; KiCad per-part, can differ e.g. SH-KICAD=z), a billboard label above each, and the footprint laid flat UNDER each model (KiCad fp under the KiCad part, ds2sf fp under the JST part) so the pad layout is visible. Plus a static ds2sf-vs-KiCad sym/fp grid + the mating BOM table.
GLB gotchas (critical): step2glb emits Draco-compressed GLBs; the wiki
Babylon viewer cannot fetch the Draco decoder (CSP-blocked → "Failed to load
model"), so decompress to plain GLB before publishing (gltf-transform:
mergeDocuments + unpartition + dispose the KHR_draco_mesh_compression
extension; trimesh can't read Draco). trimesh bakes label textures 180°-rotated
— pre-flop+flip the label PNGs. See discussion #18 on adom/wiki (decoder bug).
6a. Connectors: wire vs board, and the symbol/footprint source (proven 2026-06-27)
Wire side vs board side. A JST family has a wire-side crimp housing
(e.g. PHR-2) and a mating board-side header (e.g. B2B-PH-K-S). The
part that solders to the PCB — and the one a board design needs — is the
board-side header. If the user asks for "the connector for the board,"
they mean the header, not the housing. Housing-N mates the header-N (pin count
matches: PHR-2 ↔ B2B-PH-K-S).
Best symbol+footprint source for JST connectors = KiCad standard libraries (fast, no login — prefer over SnapMagic, which needs the user's password):
# Footprint (.kicad_mod) — KiCad footprints repo, Connector_JST.pretty
# names look like JST_PH_B2B-PH-K_1x02_P2.00mm_Vertical
curl -s "https://gitlab.com/api/v4/projects/kicad%2Flibraries%2Fkicad-footprints/repository/files/Connector_JST.pretty%2F<FPNAME>.kicad_mod/raw?ref=master" -o <MPN>.kicad_mod
# Symbol — connectors use the GENERIC N-pin symbol (correct + standard).
# kicad-symbols stores libs as DIRECTORIES: Connector_Generic.kicad_symdir/
curl -s "https://gitlab.com/api/v4/projects/kicad%2Flibraries%2Fkicad-symbols/repository/files/Connector_Generic.kicad_symdir%2FConn_01x0<N>.kicad_sym/raw?ref=master" -o <MPN>.kicad_sym
# Matched 3D STEP — read the (model ...) path from the .kicad_mod, then:
service-kicad model fetch "Connector_JST.3dshapes/<FPNAME>.step" --out <MPN>.step
Gotchas (all hit on 2026-06-27):
- KiCad ships ZE (not ZH) for the 1.5 mm series. ZH proper needs SnapMagic.
kicad-packages3Donly carries ~159 of the 500 footprints' models — many series (VH, etc.) have NO KiCad 3D. For those, get the STEP via the JST email flow (§3–4) and pair it with the KiCad footprint.- Import connectors with
--no-validate: thegate/validate step is chip-centric — it flags a connector's catalog PDF as "no pin-table, ds2sf can't extract a symbol" and marks the card incomplete. That's a false negative for connectors (the symbol is the generic N-pin one). A connector card with step+mod+sym+pdf IS complete; ignore that specific gate complaint.
Proven set (project JST-common): PH B2B-PH-K-S, XH B2B-XH-A,
SH SM02B-SRSS-TB, GH BM02B-GHS-TBT, VH B2P-VH (VH STEP via email).
7. Batch notes / hazards
- The full catalog is ~600 series × tens of thousands of parts = that many form submits + emails. Throttle hard (2-5s human-like delays, per critical rule #9) and expect JST to rate-limit. Do NOT blast the whole catalog without the user scoping it.
- One email per file, one file per
(series, doc, filename)GET→POST. STEP and IGES are separate requests/emails. - Heartbeat each stage:
adom-chip-fetcher heartbeat <PART> "probing jst-mfg.com"/"requested STEP — awaiting email"/"imported".
7a. Inbox hygiene — DEDUP before every request (mandatory)
Every JST request emails the user a file. Re-requesting spams their inbox.
Before submitting the agreement form for any (part, format):
- Skip if already in the library. If
library/<MPN>/<MPN>.stepexists (or the format you want), do NOT request it again. Check first, every time. - STEP only by default. Request
doc=2(STEP). Only fall back todoc=1(IGES) when the series has no STEP column. Never grab both "to be safe." - One submit per file, ever. Do not re-submit a part you already requested this session (track what you've sent). A double-click / retry = a second email. The form's success alert is your confirmation — don't resubmit to "make sure."
- Route to a filtered alias, not the raw inbox. Use the user's plus-alias
(e.g.
[email protected]) with a label/filter so the batch doesn't bury their inbox. Seejst-email-retrieval.md. - Clean up after a proof/demo. Test/demo runs that submit the form generate
real emails — trash the duplicates afterward
(
adom-google api -X POST .../messages/<id>/trash).
Skipping dedup is how a 5-part batch becomes a 12-email inbox flood (learned the hard way 2026-06-27: 6 emails for 3 unique parts due to IGES+STEP grabs, a demo re-submit, and a double-submit).
Source plugin
src/sources/jst.rs — series_index_url, series_url, search_url,
download_url, catalog_pdf_url, DocKind, FORM_FIELDS, base_part.
Building animated 3D mating component pages (wiki components)
This is the high-value deliverable: a wiki component page whose 3D viewer shows the connector assembling itself in a looping animation — board sliding into the PCB (THT pins passing through to the underside), then the wire housing mating into the board. KiCad sits beside it as a comparison foil. Learned end-to-end 2026-06-28.
Scene recipe (per system)
- Columns: left = KiCad library model (foil), right = JST manufacturer model.
If KiCad has no 3D model for the part (e.g. ZH
B2B-ZR→kicad-packages3d404s), make it a single JST column and say so on the page; KiCad sym/fp still compare below. - Colour = source: JST renders blue, KiCad renders tan/grey. Plus an opaque nameplate per column ("JST manufacturer" / "KiCad library"). Users WANT to know which model is which — never drop the labels.
- PCB: a thin floating slab (≈1.6 mm), footprint texture on top, no riser block underneath — a riser hides the pin tips poking through, which is the whole point. The footprint pads sit a few mm above the viewer's ground plane.
- THT vs SMT seating: THT parts (
B2B-*PH/XH/ZH) seat with pins through the PCB, protruding ≈2 mm out the bottom (the money shot — user checks pins line up with holes). SMT parts (SM02B/BM02BSH/GH) rest tabs on the pad surface (no through-pins — say so).
Mate orientation (which way the wire slides in)
Encoded in the JST part number AND drawn in the datasheet:
B…prefix (B2B, BM) = top entry → wire mates straight down (+Z).S…prefix (SM, S2B) = side entry / right-angle → wire mates horizontally (+Y). Confirm per part. Animate the wire along that axis.
Getting each model's orientation right
STEP frames are inconsistent. Don't guess from bbox (connectors are ~cubic). Use:
step2glb features <step>→ floor_z / longest-axis hints (treat as hints, verify).step2glb thumbnail <step|glb> --pose front|top|side→ read the pin axis directly.- KiCad models are reliably Z-up, pins -Z (identity). JST THT boards here needed R_x(+90) (pins along native -Y); each JST wire housing differs — check its orthos.
- Seat board so
bbox.min_z(pin tip) =PCB_bottom - protrude(THT) orPCB_top(SMT).
Authoring the animation (GLB node channels)
- Build the scene in trimesh, giving the board/wire their own named nodes
(
add_geometry(..., node_name="board1")), geometry baked at the seated pose so node base-translation = 0. (If a viewer ignores animation, it still looks correct.) - Add animation with @gltf-transform (
createAnimationSampler/createAnimationChannel, target pathtranslation, LINEAR). Each node lerps from a small retract offset back to 0 (seated). Keep lifts small (~board: clear the PCB top + ~2.5 mm; wire: ~its height + 4 mm) — big lifts waste the loop and bury the money shot. - Timeline: board drops, then wire mates, then dwell long on the fully-mated state, quick reset, loop. The wiki 3D viewer (Babylon) autoplays + loops embedded GLB animations — no play button needed.
CRITICAL gotchas
- Viewer grounds to the model's lowest geometry. So a footprint quad that is the lowest thing sits coplanar with the ground plane → z-fighting. Fix by giving the PCB real geometry and letting pins be the lowest element (also what we want).
- The 3D viewer is an
<iframe>(/viewer/3d/component/<slug>). Reloading the parent page does not refresh the iframe's cached GLB. To see an update: bump the GLB filename (-v5.glb) and/oriframe.src = src.split('?')[0]+'?cb=…'. Burned ~4 republishes chasing "my fix isn't showing" — it was always iframe cache. - Transparent label PNGs bleed through a back-to-back double-sided sign. Composite
the label onto an opaque background before texturing; put the normal image on the
front quad and a
ImageOps.mirrorcopy on the back quad, separated ~0.4 mm. - STEP→GLB emits Draco-compressed GLBs the merge tools can't read — decompress with
gltf-transform (
unpartition+ disposeKHR_draco_mesh_compression) first.
Pipeline & publish
step2glb convert (JST STEP + KiCad STEP) → gltf-transform decompress → trimesh merge
(merge_mate.py: pedestal + seat + nameplate, emits <out>.anim.json) → add_anim.mjs
→ component repo (parts.model_3d) → adompkg publish --org adom (components are
org-owned; publishing as your user 409s). ZH note: service-kicad fp fetch Connector_JST JST_ZH_B2B-ZR_1x02_P1.50mm_Vertical gives the footprint even though no 3D model exists.
Refinements learned the hard way (2026-06-28, v0.8.9)
- bbox-check every object; never eyeball the math. The merge prints each part's bbox and asserts: connector body_bottom == PCB_top (housing sits ON the PCB, not sunk into it), THT pin_tip < PCB_bottom (pins truly protrude), wire stays above the PCB. Detect the body bottom (not bbox-min, which is the pin tips) by walking z slices and finding where the cross-section widens to the body — seat THAT on the PCB. Seating by bbox-min sinks the housing into the board; this was a real bug.
- Insert the wire DEEP — ~80% of the board-body depth, not just touching. The user
needs to see it truly seat and see JST's contact-lock slots engage. (
INSERT=0.80.) - Float the PCB high (top ≈8 mm) with a tiny ground anchor. The viewer grounds to the lowest geometry, so drop a ~0.3 mm speck at z=0 under each column — the viewer's ground (and shadow) sit there, the PCB floats ~6 mm up, and you can angle the camera under the board to inspect the protruding pins. No riser block (it hides the pins).
- Shadows are viewer-side, already on: the Babylon viewer has a SpotLight + 1 shadowGenerator (that's the ground shadow). You can't toggle it from the GLB; raising the PCB is what makes the descending part's shadow read clearly. Richer per-part inter-shadowing would be a wiki-viewer change, not a GLB change.
- If KiCad has no 3D model for a JST part (e.g. ZH
B2B-ZR), don't silently drop the column — render a standing red placard ("KiCad: no 3D model — ships sym+fp only") in the KiCad slot so the user knows why it's absent. (Add a{"placeholder":true}column to the merge config.) - Animation dwell: keep lifts small and dwell long on the fully-mated state — that (pins through + wire seated) is the money shot, not the parts hovering far above.
# Playbook: JST connectors (email-gated CAD)
**Read this for any JST part** (PHR-/XHP-/ZHR-/SHR-/EHR-/VHR-/PAP-/GHR-/NHR-
housings, or B\*B-/S\*B-/BM\*B-/SM\*B- board/SMT headers). JST is the
canonical example of a **manufacturer that emails you the CAD** instead of
serving it as a download. Proven end-to-end on PHR-2, 2026-06-27.
> One-line shape: native browser → jst-mfg.com download link → accept cookies
> → fill agreement form → JST **emails** the `.zip` → fetch the email
> attachment → import. There is **no account login** for CAD.
---
## 0. Why JST is special (don't skip)
- **jst.com (USA) is Cloudflare-walled against pup.** A pup navigation to any
deep product page returns a "Just a moment… / Performing security
verification" interstitial that never clears. **You MUST use the
native-browser bridge** (`nbrowser_*`, the user's real signed-in Chrome via
`adom-browser-extension`) — it carries human-trust and passes Cloudflare.
If the bridge is absent, tell the user to install it
(https://wiki.adom.inc/adom/adom-browser-extension); pup will not work here.
- jst.com is only marketing + spec tables + a **"Distributor Login"** (that
login is for distributors, NOT a CAD gate). The actual CAD + catalogs live
on the **global site jst-mfg.com**, which jst.com links to.
- **No login is required to get CAD.** The gate is a per-download **License
Agreement form** whose submit triggers an **email**.
## 1. Resolve the part → series
JST CAD is organized by **series**, not by individual MPN. Each series has a
numeric id (PH = 199, PH high-box = 200, SH = 231, …; ~600+ series).
- Master index ("Series Alphabet Search"):
`https://www.jst-mfg.com/product/index.php?type=5` — every series is an
`index.php?series=<id>` link. This page is also your **scope list** for a
batch (one row per series).
- Or keyword-search a known MPN: `https://www.jst-mfg.com/search/?q=<MPN>`
(`sources::jst::search_url`). Strip ordering suffixes first with
`sources::jst::base_part` — drop `(LF)(SN)` and any `(…)` option group, and
a trailing suction-cap `T` on SMT headers
(`B10B-PH-K-S(LF)(SN)` → `B10B-PH-K-S`).
## 2. Read the CAD columns on the series page
Open the series page in the native browser. Each part row has **Download**
buttons under format columns. Map them by reading the **column header** — the
`doc=` number is **per-series**, not universal:
| Common (PH, series=199) | doc= | format | inner file |
|---|---|---|---|
| IGES | 1 | 3D | `<PART>.IGS` |
| STEP | 2 | 3D | `<PART>.STEP` ← **prefer this** |
| 3D-PDF| 3 | 3D pdf| `<PART>.pdf` |
| 2D-PDF| 4 | drawing pdf | `<PART>.pdf` |
⚠️ **Coverage varies**: some older series offer **only IGES** (no STEP). If a
series has no STEP column, take IGES and convert with `step2glb`/service-kicad
downstream. Always read the header — never assume `doc=2` is STEP.
The link itself is built by `sources::jst::download_url(series, doc, filename)`:
`…/product/index.php?type=10&series=<S>&doc=<D>&filename=<PART>.zip`
## 3. The download link returns a FORM, not a file
GET-ing the download link does two things server-side:
1. binds `(series, doc, filename)` into the **PHP session**, and
2. returns a **License Agreement** HTML page (no file).
The page has required fields **company, section, name, address, tel, email**
(+ optional **url**) and an **"I agree"** button wired to a JS `download()`
function. `download()` collects every form value and POSTs them to
`ajax_download.php` (jsonp). The server reads the file to send from the
**session set in step 1** — so the GET and the POST **must share the browser
session** (same native-browser window = automatic).
**Accept cookies first.** The cookie banner literally says *"accept cookies in
order to submit any of our forms."* Click "Allow all cookies" before filling.
### Driving it (native browser)
1. `nbrowser_navigate` to the `download_url` → wait ~2.5s.
2. `nbrowser_eval`: accept cookies, set the 7 fields by id (dispatch
`input`+`change`), then call `download()` (or click "I agree"). The success
callback fires `alert("The data has been sent to your email address")` then
navigates to `index.php?series=<S>` — hook `window.alert` into
`sessionStorage` first since navigation wipes globals, then read it back.
Use the user's real business profile for the fields (see
`user_profile.md`). For a **batch**, set the email to a plus-alias like
`[email protected]` with a Gmail filter/label so the inbox isn't buried (the
file still arrives; adom-google can still read it).
## 4. Retrieve the emailed file (the part most tools miss)
Since **April 2025** JST sends the CAD as an **email attachment** (`<PART>.zip`,
inner `<PART>.STEP`/`.IGS`), from a JST send-only address, ~30-60s later. This
is where chip-fetcher needs an **email-reading capability** —
see [`jst-email-retrieval.md`](jst-email-retrieval.md) for the Gmail
(adom-google) path and the **non-Gmail** build-your-own path.
Gmail quick path (adom-google):
```bash
adom-google api "https://gmail.googleapis.com/gmail/v1/users/me/messages" \
-q q="JST newer_than:1d" -q maxResults=5 # strip leading "HTTP 200…" line before JSON
adom-google gmail attachments <messageId> # find <PART>.zip + its attId
adom-google gmail read <messageId> <attId> -o <PART>.zip
```
Pick the **newest** message whose inner file matches the format you requested
(IGES and STEP both arrive as `<PART>.zip` — distinguish by the inner
`.STEP` vs `.IGS`).
## 5. Datasheet = series catalog (DIRECT download, no gate)
JST has no per-part datasheet. Use the **series catalog PDF**, a plain direct
download: `sources::jst::catalog_pdf_url("PH")` →
`https://www.jst-mfg.com/product/pdf/eng/ePH.pdf`. Fetch with
`nbrowser_fetch_url` (returns base64 for binary — decode before writing) and
import as the part's `.pdf`. The 2D-PDF drawing (doc=4) is the per-part
mechanical print if you want it too.
## 6. Import + what JST does NOT give you
```bash
adom-chip-fetcher import <PART>.STEP --mpn <PART>
adom-chip-fetcher import <catalog>.pdf --mpn <PART>
```
JST supplies **3D (STEP/IGES) + drawings + catalog datasheet only**. It does
**NOT** supply KiCad `.kicad_sym` / `.kicad_mod`. Those come from the ladder.
## 6z. Series-ID table + full connector component-page pipeline (proven 2026-06-28)
**Series IDs** (jst-mfg.com `index.php?series=<id>`): PH **199**, XH **277**,
SH **231**, GH **105**, ZH **287**, VH **262**, SH-high-box etc. via the
alphabet search (`type=5`). Per series the 2-circuit set:
| Series | Board header | Wire housing | Crimp contact (PDF only, no STEP) | Pitch |
|---|---|---|---|---|
| PH | `B2B-PH-K-S` | `PHR-2` | `SPH-002T-P0.5S/L` (AWG 30-24) | 2.0 |
| XH | `B2B-XH-A` | `XHP-2` | `SXH-001T-P0.6N` (AWG 30-22) | 2.5 |
| SH | `SM02B-SRSS-TB` | `SHR-02V-S-B` | `SSH-003T-P0.2` (AWG 32-26) | 1.0 |
| GH | `BM02B-GHS-TBT` | `GHR-02V-S` | `SSHL-002T-P0.2` (AWG 32-28) | 1.25 |
| ZH | `B2B-ZR` | `ZHR-2` | `SZH-002T-P0.5` (AWG 32-26) | 1.5 |
**The component-page pipeline (the right way — JST 3D is always the part):**
1. **3D = JST manufacturer STEP** via the email flow (§3-4) for BOTH the board
header and the wire housing. This is the whole point — never ship a KiCad 3D
as the deliverable. (License: don't rehost the STEP; the viewer uses a lossy
GLB preview + "run the skill" to fetch the real STEP.)
2. **Symbol + footprint = `ds2sf`** run on the JST datasheet
(`adom-ds2sf extract library/<MPN> --source-tier mfr`). ds2sf **works on
connectors** (2 pins, generic_connector_pin_function). Render its SVGs:
`adom-ds2sf svg <dir>` (footprint) + `adom-symbol render-ds2sf --file
<MPN>-symbol.extracted.json --out <MPN>-symbol.ds2sf.svg`.
3. **KiCad sym/fp/3D = the comparison foil only**, never the deliverable. Fetch
the KiCad footprint/symbol (GitLab raw, §6a) + KiCad 3D (`service-kicad model
fetch`). NOTE: KiCad has **no ZH series** (it ships ZE for 1.5 mm) — ZH is
JST-only, footprint from ds2sf.
4. **chip-fetcher layout:** one project per mating system (`JST-<series>-system`)
holding 3 cards — **wire housing**, **JST board** (ds2sf+KiCad sym/fp via the
source ▾; JST "Mfr direct" 3D), and **`<MPN>-KICAD`** (KiCad-only sym/fp +
KiCad 3D). Housings = JST 3D + PDF only (wire parts have no PCB footprint).
Tag provenance on import: `--content-origin manufacturer --discovery-source
jst` for JST files, `--content-origin kicad` for KiCad.
5. **Wiki component page** (`adom/<mpn-slug>`, type=component): the native 3D
viewer's `model_3d` is a **merged comparison GLB** built with trimesh —
KiCad model + JST model side by side, **each oriented per the user's
chip-fetcher `chosen_up_axis` pick** (JST headers = yUp; KiCad per-part, can
differ e.g. SH-KICAD=z), **a billboard label above each**, and **the
footprint laid flat UNDER each model** (KiCad fp under the KiCad part, ds2sf
fp under the JST part) so the pad layout is visible. Plus a static
ds2sf-vs-KiCad sym/fp grid + the mating BOM table.
**GLB gotchas (critical):** step2glb emits **Draco-compressed** GLBs; the wiki
Babylon viewer **cannot fetch the Draco decoder** (CSP-blocked → "Failed to load
model"), so **decompress to plain GLB before publishing** (gltf-transform:
`mergeDocuments` + `unpartition` + dispose the `KHR_draco_mesh_compression`
extension; trimesh can't read Draco). trimesh bakes label textures **180°-rotated**
— pre-flop+flip the label PNGs. See discussion #18 on `adom/wiki` (decoder bug).
## 6a. Connectors: wire vs board, and the symbol/footprint source (proven 2026-06-27)
**Wire side vs board side.** A JST family has a wire-side crimp **housing**
(e.g. `PHR-2`) and a mating board-side **header** (e.g. `B2B-PH-K-S`). The
part that solders to the PCB — and the one a board design needs — is the
**board-side header**. If the user asks for "the connector for the board,"
they mean the header, not the housing. Housing-N mates the header-N (pin count
matches: `PHR-2` ↔ `B2B-PH-K-S`).
**Best symbol+footprint source for JST connectors = KiCad standard libraries**
(fast, no login — prefer over SnapMagic, which needs the user's password):
```bash
# Footprint (.kicad_mod) — KiCad footprints repo, Connector_JST.pretty
# names look like JST_PH_B2B-PH-K_1x02_P2.00mm_Vertical
curl -s "https://gitlab.com/api/v4/projects/kicad%2Flibraries%2Fkicad-footprints/repository/files/Connector_JST.pretty%2F<FPNAME>.kicad_mod/raw?ref=master" -o <MPN>.kicad_mod
# Symbol — connectors use the GENERIC N-pin symbol (correct + standard).
# kicad-symbols stores libs as DIRECTORIES: Connector_Generic.kicad_symdir/
curl -s "https://gitlab.com/api/v4/projects/kicad%2Flibraries%2Fkicad-symbols/repository/files/Connector_Generic.kicad_symdir%2FConn_01x0<N>.kicad_sym/raw?ref=master" -o <MPN>.kicad_sym
# Matched 3D STEP — read the (model ...) path from the .kicad_mod, then:
service-kicad model fetch "Connector_JST.3dshapes/<FPNAME>.step" --out <MPN>.step
```
**Gotchas (all hit on 2026-06-27):**
- KiCad ships **ZE (not ZH)** for the 1.5 mm series. ZH proper needs SnapMagic.
- `kicad-packages3D` only carries ~159 of the 500 footprints' models — **many
series (VH, etc.) have NO KiCad 3D**. For those, get the STEP via the JST
**email flow** (§3–4) and pair it with the KiCad footprint.
- Import connectors with **`--no-validate`**: the `gate`/validate step is
chip-centric — it flags a connector's catalog PDF as "no pin-table, ds2sf
can't extract a symbol" and marks the card incomplete. That's a false
negative for connectors (the symbol is the generic N-pin one). A connector
card with step+mod+sym+pdf IS complete; ignore that specific gate complaint.
Proven set (project `JST-common`): PH `B2B-PH-K-S`, XH `B2B-XH-A`,
SH `SM02B-SRSS-TB`, GH `BM02B-GHS-TBT`, VH `B2P-VH` (VH STEP via email).
## 7. Batch notes / hazards
- **The full catalog is ~600 series × tens of thousands of parts** = that many
form submits + emails. Throttle hard (2-5s human-like delays, per critical
rule #9) and expect JST to rate-limit. Do NOT blast the whole catalog without
the user scoping it.
- One email per file, one file per `(series, doc, filename)` GET→POST. STEP and
IGES are separate requests/emails.
- Heartbeat each stage: `adom-chip-fetcher heartbeat <PART> "probing jst-mfg.com"`
/ `"requested STEP — awaiting email"` / `"imported"`.
### 7a. Inbox hygiene — DEDUP before every request (mandatory)
Every JST request emails the user a file. Re-requesting spams their inbox.
Before submitting the agreement form for any `(part, format)`:
1. **Skip if already in the library.** If `library/<MPN>/<MPN>.step` exists (or
the format you want), do NOT request it again. Check first, every time.
2. **STEP only by default.** Request `doc=2` (STEP). Only fall back to `doc=1`
(IGES) when the series has no STEP column. Never grab both "to be safe."
3. **One submit per file, ever.** Do not re-submit a part you already requested
this session (track what you've sent). A double-click / retry = a second
email. The form's success alert is your confirmation — don't resubmit to
"make sure."
4. **Route to a filtered alias, not the raw inbox.** Use the user's plus-alias
(e.g. `[email protected]`) with a label/filter so the batch doesn't bury
their inbox. See [`jst-email-retrieval.md`](jst-email-retrieval.md).
5. **Clean up after a proof/demo.** Test/demo runs that submit the form generate
real emails — trash the duplicates afterward
(`adom-google api -X POST .../messages/<id>/trash`).
Skipping dedup is how a 5-part batch becomes a 12-email inbox flood (learned the
hard way 2026-06-27: 6 emails for 3 unique parts due to IGES+STEP grabs, a
demo re-submit, and a double-submit).
## Source plugin
`src/sources/jst.rs` — `series_index_url`, `series_url`, `search_url`,
`download_url`, `catalog_pdf_url`, `DocKind`, `FORM_FIELDS`, `base_part`.
## Building animated 3D mating component pages (wiki components)
This is the high-value deliverable: a wiki **component page** whose 3D viewer shows
the connector **assembling itself in a looping animation** — board sliding into the
PCB (THT pins passing through to the underside), then the wire housing mating into
the board. KiCad sits beside it as a comparison foil. Learned end-to-end 2026-06-28.
### Scene recipe (per system)
- **Columns:** left = KiCad library model (foil), right = JST manufacturer model.
If KiCad has **no 3D model** for the part (e.g. ZH `B2B-ZR` → `kicad-packages3d`
404s), make it a **single JST column** and say so on the page; KiCad sym/fp still
compare below.
- **Colour = source:** JST renders blue, KiCad renders tan/grey. Plus an **opaque
nameplate** per column ("JST manufacturer" / "KiCad library"). Users WANT to know
which model is which — never drop the labels.
- **PCB:** a thin **floating** slab (≈1.6 mm), footprint texture on top, **no riser
block underneath** — a riser hides the pin tips poking through, which is the whole
point. The footprint pads sit a few mm above the viewer's ground plane.
- **THT vs SMT seating:** THT parts (`B2B-*` PH/XH/ZH) seat with **pins through the
PCB, protruding ≈2 mm out the bottom** (the money shot — user checks pins line up
with holes). SMT parts (`SM02B/BM02B` SH/GH) rest tabs on the pad surface (no
through-pins — say so).
### Mate orientation (which way the wire slides in)
Encoded in the JST part number AND drawn in the datasheet:
- `B…` prefix (B2B, BM) = **top entry** → wire mates **straight down (+Z)**.
- `S…` prefix (SM, S2B) = **side entry / right-angle** → wire mates **horizontally (+Y)**.
Confirm per part. Animate the wire along that axis.
### Getting each model's orientation right
STEP frames are inconsistent. Don't guess from bbox (connectors are ~cubic). Use:
- `step2glb features <step>` → floor_z / longest-axis hints (treat as hints, verify).
- `step2glb thumbnail <step|glb> --pose front|top|side` → read the pin axis directly.
- KiCad models are reliably **Z-up, pins -Z** (identity). JST THT boards here needed
**R_x(+90)** (pins along native -Y); each JST wire housing differs — check its orthos.
- Seat board so `bbox.min_z` (pin tip) = `PCB_bottom - protrude` (THT) or `PCB_top` (SMT).
### Authoring the animation (GLB node channels)
- Build the scene in **trimesh**, giving the board/wire their own **named nodes**
(`add_geometry(..., node_name="board1")`), geometry baked at the **seated** pose so
node base-translation = 0. (If a viewer ignores animation, it still looks correct.)
- Add animation with **@gltf-transform** (`createAnimationSampler` / `createAnimationChannel`,
target path `translation`, LINEAR). Each node lerps from a small **retract offset**
back to 0 (seated). Keep lifts **small** (~board: clear the PCB top + ~2.5 mm; wire:
~its height + 4 mm) — big lifts waste the loop and bury the money shot.
- Timeline: board drops, then wire mates, then **dwell long on the fully-mated state**,
quick reset, loop. The wiki 3D viewer (Babylon) **autoplays + loops** embedded GLB
animations — no play button needed.
### CRITICAL gotchas
- **Viewer grounds to the model's lowest geometry.** So a footprint quad that is the
lowest thing sits coplanar with the ground plane → **z-fighting**. Fix by giving the
PCB real geometry and letting **pins** be the lowest element (also what we want).
- **The 3D viewer is an `<iframe>`** (`/viewer/3d/component/<slug>`). Reloading the
parent page does **not** refresh the iframe's cached GLB. To see an update: bump the
GLB **filename** (`-v5.glb`) and/or `iframe.src = src.split('?')[0]+'?cb=…'`. Burned
~4 republishes chasing "my fix isn't showing" — it was always iframe cache.
- **Transparent label PNGs bleed through** a back-to-back double-sided sign. Composite
the label onto an **opaque** background before texturing; put the normal image on the
front quad and a `ImageOps.mirror` copy on the back quad, separated ~0.4 mm.
- **STEP→GLB emits Draco-compressed** GLBs the merge tools can't read — decompress with
gltf-transform (`unpartition` + dispose `KHR_draco_mesh_compression`) first.
### Pipeline & publish
`step2glb convert` (JST STEP + KiCad STEP) → gltf-transform decompress → trimesh merge
(`merge_mate.py`: pedestal + seat + nameplate, emits `<out>.anim.json`) → `add_anim.mjs`
→ component repo (`parts.model_3d`) → `adompkg publish --org adom` (components are
org-owned; publishing as your user 409s). ZH note: `service-kicad fp fetch Connector_JST
JST_ZH_B2B-ZR_1x02_P1.50mm_Vertical` gives the footprint even though no 3D model exists.
### Refinements learned the hard way (2026-06-28, v0.8.9)
- **bbox-check every object; never eyeball the math.** The merge prints each part's
bbox and asserts: connector **body_bottom == PCB_top** (housing sits ON the PCB, not
sunk into it), THT **pin_tip < PCB_bottom** (pins truly protrude), wire stays above
the PCB. Detect the **body bottom** (not bbox-min, which is the pin tips) by walking z
slices and finding where the cross-section widens to the body — seat THAT on the PCB.
Seating by bbox-min sinks the housing into the board; this was a real bug.
- **Insert the wire DEEP — ~80% of the board-body depth**, not just touching. The user
needs to see it truly seat and see JST's contact-lock slots engage. (`INSERT=0.80`.)
- **Float the PCB high (top ≈8 mm) with a tiny ground anchor.** The viewer grounds to
the lowest geometry, so drop a ~0.3 mm speck at z=0 under each column — the viewer's
ground (and shadow) sit there, the PCB floats ~6 mm up, and you can angle the camera
**under** the board to inspect the protruding pins. No riser block (it hides the pins).
- **Shadows are viewer-side, already on:** the Babylon viewer has a SpotLight + 1
shadowGenerator (that's the ground shadow). You can't toggle it from the GLB; raising
the PCB is what makes the descending part's shadow read clearly. Richer per-part
inter-shadowing would be a wiki-viewer change, not a GLB change.
- **If KiCad has no 3D model** for a JST part (e.g. ZH `B2B-ZR`), don't silently drop
the column — render a standing **red placard** ("KiCad: no 3D model — ships sym+fp only")
in the KiCad slot so the user knows *why* it's absent. (Add a `{"placeholder":true}`
column to the merge config.)
- **Animation dwell:** keep lifts small and dwell long on the fully-mated state — that
(pins through + wire seated) is the money shot, not the parts hovering far above.