component
Wurth 61300411121 (WR-PHD 1x04 2.54 mm pin header)
Public Made by Adomby adom
Wurth Elektronik WR-PHD 61300411121: 4-pin, 2.54 mm, single-row THT vertical pin header, gold, 3 A. KiCad symbol, footprint at the datasheet's 1.10 mm hole, and KiCad's generic 1x04 header 3D model checked against the drawing.
← Commit history
Add datasheet, figures, hero card, provenance, verification log and README
19 files changed
+1740−2
README.md+103−2docs/61300411121-datasheet.pdfdocs/figures/61300411121-ds-p1.pngdocs/figures/61300411121-ds-p2.pngdocs/hero.pngpackage.json+214provenance/etch/61300411121-etched.check.json+140provenance/etch/61300411121-etched.check.pngprovenance/etch/61300411121-etched.mark-plan.json+172provenance/evidence/footprint-vs-datasheet.pngprovenance/evidence/model-views.pngprovenance/footprint-vs-datasheet.json+104provenance/model-vs-datasheet.json+116provenance/provenance.json+399provenance/tools/check_footprint.py+77provenance/tools/hero_glb-single-row.patch+53provenance/tools/make_cad.py+102provenance/tools/measure_model.py+133verification.json+127README.md+103−2@@ -1,3 +1,104 @@-# Wurth 61300411121 (WR-PHD 1x04 2.54 mm pin header)+# Wurth Elektronik 61300411121 -Wurth Elektronik WR-PHD 61300411121: 4-pin, 2.54 mm, single-row THT vertical pin header, gold, 3 A. KiCad symbol, footprint at the datasheet's 1.10 mm hole, and KiCad's generic 1x04 header 3D model checked against the drawing.+::adom-verified{src="/adom/61300411121/render/verification.json"}++**Wurth Elektronik** · WR-PHD pin header · 1x04, 2.54 mm pitch, THT vertical, gold++61300411121 is a 4-position, single-row, straight through-hole pin header from Wurth Elektronik's WR-PHD series: 0.64 mm square gold-plated copper-alloy pins on a black PA6T insulator, rated 3 A and 250 V AC. Each pin is 11.54 mm long: 6.0 mm mating length above a 2.54 mm insulator and a 3.0 mm solder tail. It mates with standard 2.54 mm female sockets and jumper housings for 0.64 mm square posts.++This page carries a KiCad symbol and footprint, a Fusion/EAGLE library, STEP and GLB 3D models, the datasheet, and the order numbers. The footprint follows the datasheet's recommended hole; the 3D model is **KiCad's generic 1x04 2.54 mm header model**, not Wurth Elektronik's own CAD (see 3D model below).++## Key specifications++| Parameter | Value | Source |+|---|---|---|+| Positions | 4, single row | datasheet p.1 |+| Pitch | 2.54 +-0.05 mm | p.1 |+| Pin | 0.64 +-0.15 mm square | p.1 |+| Pin length | 11.54 +-0.2 mm total: 6.0 mating, 2.54 insulator, 3.0 tail | p.1 |+| Insulator | 10.16 +-0.35 x 2.54 +-0.15 mm, 2.54 +-0.15 mm high | p.1 |+| Recommended hole | 1.10 +-0.15 mm, pl (pin 1 to End) 7.62 +-0.1 mm | p.1 |+| Rated current | 3 A | p.2 |+| Working voltage | 250 V AC | p.2 |+| Withstanding voltage | 500 V AC, 1 min | p.2 |+| Contact resistance | 20 mOhm max | p.2 |+| Insulation resistance | 1000 MOhm min | p.2 |+| Insulator material | PA6T, black, UL94 V-0 | p.2 |+| Contacts | copper alloy, gold plated, stamped | p.2 |+| Operating temperature | -40 to +105 C | p.2 |+| Durability | 25 mating cycles | p.2 |+| Approvals | RoHS, REACH, UL E323964 | p.2 |+| Soldering | wave, peak 250 to 260 C, 10 s max (EN 61760-1) | p.4 |+| Packaging | bag of 1000 | p.3 |++## Pinout++| Pin | Name | Type | Function |+|---|---|---|---|+| 1 | Pin_1 | passive | Contact 1 of 4, the end the datasheet labels "1"; square pad 1 |+| 2 | Pin_2 | passive | Contact 2 of 4 |+| 3 | Pin_3 | passive | Contact 3 of 4 |+| 4 | Pin_4 | passive | Contact 4 of 4, the end the datasheet labels "End" |++The datasheet prints no signal names, only the end labels 1 and End (p.1). The header itself is symmetric; contact 1 is whichever end is soldered into the square pad. Pin_1 to Pin_4 is KiCad's connector naming, kept so the symbol matches KiCad's Conn_01x04.++## Ordering++| Distributor | Part number | Stock (2026-11-10) | Price |+|---|---|---|---|+| Mouser | [710-61300411121](https://www.mouser.com/ProductDetail/Wurth-Elektronik/61300411121?qs=PhR8RmCirEYQcLLqXD8rAA%3D%3D) | 115,305 | $0.19 (1), $0.102 (100) |+| DigiKey | [732-5317-ND](https://www.digikey.com/en/products/detail/w%C3%BCrth-elektronik/61300411121/4846827) | 120,886 | $0.18 (1), $0.1047 (100) |+| JLCPCB / LCSC | [C5184785](https://jlcpcb.com/parts/componentSearch?searchTxt=C5184785) (extended part) | 1,544 | $0.2216 (1) |++Stock and prices are a snapshot from Adom Parts Search on the date shown.++## CAD files++| File | What it is |+|---|---|+| `61300411121.kicad_sym` | KiCad symbol: KiCad's Conn_01x04, renamed, with MPN, manufacturer, datasheet, Mouser, DigiKey, LCSC and wiki fields |+| `61300411121.kicad_mod` | KiCad footprint: KiCad's PinHeader_1x04_P2.54mm_Vertical with the datasheet's 1.10 mm hole and 1.80 mm pads; pad 1 square at the origin, pads along +Y |+| `61300411121.step` | 3D model the footprint binds (`${KIPRJMOD}/61300411121.step`): KiCad 10.0's PinHeader_1x04_P2.54mm_Vertical.step, byte-identical |+| `61300411121-etched.step`, `61300411121-etched.glb` | The same model with a virtual part-number mark on the insulator side wall |+| `61300411121.glb` | GLB of the plain model |+| `61300411121-hero.glb` | The wiki's 3D view: the etched model with the footprint's pad outlines, silkscreen, pin 1 dot and pin names as separate reference layers |+| `61300411121.lbr` | Fusion 360 / EAGLE library with MPN and order attributes |+| `61300411121.adom-lbr.json` | adom-lbr hub file, for Altium export (`adom-lbr export-altium`) |+| `docs/61300411121-datasheet.pdf` | Wurth Elektronik datasheet, rev 003.000 (2023-01-08) |++## Footprint++++The datasheet's hole-pattern view (p.1) is the WR-PHD **series** drawing: it shows ten holes from 1 to End with the length as the symbol pl. The value for this 4-pin part is in the Pattern Properties table: pl = 7.62 mm. The drawing also gives only the hole, 1.10 +-0.15 mm, not a copper pad. Read from the table, the pattern is four 1.10 mm holes at 2.54 mm; the 1.80 mm pad keeps the 0.35 mm annular ring of KiCad's own 2.54 mm header (1.0 mm drill, 1.7 mm pad). A nominal 0.64 mm square pin has a 0.905 mm diagonal, leaving about 0.2 mm in the hole. Every check is in `provenance/footprint-vs-datasheet.json`.++## 3D model++++The model is KiCad's generic `PinHeader_1x04_P2.54mm_Vertical.step` (kicad StepUp, KiCad 10.0 library), unmodified. It was measured against every dimension the datasheet prints and all are inside the tolerances: pins 0.64 mm square at 2.54 mm, 11.54 mm long with 6.0 mm above and 3.0 mm below a 2.54 x 2.54 x 10.16 mm insulator (`provenance/model-vs-datasheet.json`). It is Z up, the insulator seated on z = 0 with the tails below, contact 1 on pad 1 at the origin, so the footprint binds it with no offset or rotation.++Wurth Elektronik's own STEP for this part was **not** obtained: we-online.com refuses automated downloads. Details the drawing does not dimension (the insulator's chamfers and notches) may differ from the real part. Anyone who downloads Wurth's model through a browser is welcome to compare and add it.++The part number on the etched copy (61300 / 411121 on the pin-1 end of the side wall) is a virtual identification mark drawn by Adom. The real header carries no printed part number.++## Provenance++| Data | Source | Reference | Evidence |+|---|---|---|---|+| Identity, dimensions, hole pattern, end labels | Wurth Elektronik datasheet 61300411121 | rev 003.000, 2023-01-08, p.1 | [datasheet p.1](/adom/61300411121/render/docs/figures/61300411121-ds-p1.png) |+| Materials, electrical ratings, approvals | same datasheet | p.2 | [datasheet p.2](/adom/61300411121/render/docs/figures/61300411121-ds-p2.png) |+| Symbol | KiCad 10.0 Connector_Generic:Conn_01x04 | CC-BY-SA-4.0, KiCad library exception | `provenance/provenance.json` |+| Footprint | KiCad 10.0 PinHeader_1x04_P2.54mm_Vertical, hole and pad changed to the datasheet | datasheet p.1 | `provenance/footprint-vs-datasheet.json` |+| 3D model | KiCad 10.0 PinHeader_1x04_P2.54mm_Vertical.step, unmodified | sha256 a74079b8d06b... | `provenance/model-vs-datasheet.json` |+| Order numbers, stock, prices | Mouser, DigiKey, JLCPCB through Adom Parts Search | 2026-11-10 | this page |++`provenance/provenance.json` lists every file on this page with its sha256, source, authoring class (manufacturer original, KiCad library verbatim, KiCad library derived, Adom derived, Adom authored), tool and license. The tools that made and checked the files are in `provenance/tools/`.++The Adom parts factory declined to build this part on its own because its two readings of the land pattern disagreed; the series drawing above, with the part's value only in a table, is the likely reason. This page was built and checked by hand instead.++## License++The KiCad symbol, footprint and 3D model are derived from the KiCad libraries and stay under CC-BY-SA-4.0 with the KiCad library exception: boards that use them are not bound by the license. Adom's own files on this page are CC-BY-SA-4.0. The datasheet is Wurth Elektronik's and is included unmodified. See `LICENSE`.++[Datasheet PDF](docs/61300411121-datasheet.pdf)
docs/61300411121-datasheet.pdfadded⋯ 1 unchanged line ⋯
docs/figures/61300411121-ds-p1.pngadded⋯ 1 unchanged line ⋯
docs/figures/61300411121-ds-p2.pngadded⋯ 1 unchanged line ⋯
docs/hero.pngadded⋯ 1 unchanged line ⋯
package.jsonadded+214@@ -0,0 +1,214 @@+{+ "slug": "61300411121",+ "version": "0.1.0",+ "type": "component",+ "title": "Wurth 61300411121 (WR-PHD 1x04 2.54 mm pin header)",+ "brief": "Wurth Elektronik WR-PHD 61300411121: 4-pin, 2.54 mm, single-row THT vertical pin header, gold, 3 A. KiCad symbol, footprint at the datasheet's 1.10 mm hole, and KiCad's generic 1x04 header 3D model checked against the drawing.",+ "tags": [+ "component",+ "connectors",+ "pin-header",+ "wurth-elektronik",+ "wr-phd",+ "2-54mm",+ "tht",+ "61300411121"+ ],+ "dependencies": {},+ "hero": {+ "type": "image",+ "path": "docs/hero.png"+ },+ "files": [+ "page.json",+ "README.md",+ "LICENSE",+ "verification.json",+ "61300411121.kicad_sym",+ "61300411121.kicad_mod",+ "61300411121.lbr",+ "61300411121.adom-lbr.json",+ "61300411121.step",+ "61300411121.glb",+ "61300411121-etched.step",+ "61300411121-etched.glb",+ "61300411121-hero.glb",+ "61300411121-hero.overlay.json",+ "docs/hero.png",+ "docs/61300411121-datasheet.pdf",+ "docs/figures/61300411121-ds-p1.png",+ "docs/figures/61300411121-ds-p2.png",+ "provenance/provenance.json",+ "provenance/model-vs-datasheet.json",+ "provenance/footprint-vs-datasheet.json",+ "provenance/etch/61300411121-etched.mark-plan.json",+ "provenance/etch/61300411121-etched.check.json",+ "provenance/etch/61300411121-etched.check.png",+ "provenance/evidence/footprint-vs-datasheet.png",+ "provenance/evidence/model-views.png",+ "provenance/tools/make_cad.py",+ "provenance/tools/measure_model.py",+ "provenance/tools/check_footprint.py",+ "provenance/tools/hero_glb-single-row.patch"+ ],+ "component": {+ "mpn": "61300411121",+ "manufacturer": "Wurth Elektronik",+ "series": "WR-PHD",+ "package": "WR-PHD 1x04 THT vertical pin header, 2.54 mm pitch",+ "pin_count": 4,+ "category": "Connectors",+ "subcategory": "Pin header, 2.54 mm, single row, straight (WR-PHD)",+ "lifecycle": "Active (DigiKey, 2026-11-10)",+ "body_size": {+ "x_mm": 2.54,+ "y_mm": 10.16,+ "z_mm": 2.54,+ "pitch_mm": 2.54+ },+ "datasheet": "https://www.we-online.com/components/products/datasheet/61300411121.pdf",+ "parts": {+ "symbol": "61300411121.kicad_sym",+ "footprint": "61300411121.kicad_mod",+ "model_3d": "61300411121-hero.glb",+ "model_3d_plain": "61300411121-etched.glb",+ "model_3d_step": "61300411121-etched.step",+ "model_3d_step_plain": "61300411121.step",+ "lbr": "61300411121.lbr",+ "datasheet": "docs/61300411121-datasheet.pdf"+ },+ "distributor_links": {+ "mouser": {+ "part": "710-61300411121",+ "url": "https://www.mouser.com/ProductDetail/Wurth-Elektronik/61300411121?qs=PhR8RmCirEYQcLLqXD8rAA%3D%3D"+ },+ "digikey": {+ "part": "732-5317-ND",+ "url": "https://www.digikey.com/en/products/detail/w%C3%BCrth-elektronik/61300411121/4846827"+ },+ "lcsc": {+ "part": "C5184785",+ "url": "https://jlcpcb.com/parts/componentSearch?searchTxt=C5184785"+ }+ },+ "pins": [+ {+ "number": "1",+ "name": "Pin_1",+ "type": "passive",+ "description": "Contact 1 of 4: 0.64 mm square gold-plated pin at 2.54 mm pitch. The datasheet labels the end positions \"1\" and \"End\" and prints no signal names; the header is symmetric, so contact 1 is the end soldered into the square pad 1. Pin_1 is KiCad's connector naming. [datasheet p.1]"+ },+ {+ "number": "2",+ "name": "Pin_2",+ "type": "passive",+ "description": "Contact 2 of 4: 0.64 mm square gold-plated pin at 2.54 mm pitch. The datasheet labels the end positions \"1\" and \"End\" and prints no signal names; the header is symmetric, so contact 1 is the end soldered into the square pad 1. Pin_2 is KiCad's connector naming. [datasheet p.1]"+ },+ {+ "number": "3",+ "name": "Pin_3",+ "type": "passive",+ "description": "Contact 3 of 4: 0.64 mm square gold-plated pin at 2.54 mm pitch. The datasheet labels the end positions \"1\" and \"End\" and prints no signal names; the header is symmetric, so contact 1 is the end soldered into the square pad 1. Pin_3 is KiCad's connector naming. [datasheet p.1]"+ },+ {+ "number": "4",+ "name": "Pin_4",+ "type": "passive",+ "description": "Contact 4 of 4: 0.64 mm square gold-plated pin at 2.54 mm pitch. The datasheet labels the end positions \"1\" and \"End\" and prints no signal names; the header is symmetric, so contact 1 is the end soldered into the square pad 1. Pin_4 is KiCad's connector naming. [datasheet p.1]"+ }+ ],+ "provenance": {+ "datasheet": {+ "url": "https://www.we-online.com/components/products/datasheet/61300411121.pdf",+ "pages": 6,+ "sha256": "ce759fb8caee2fd0c3167f6925010f6703aa4f939ded51aae7ead334c38c0d7d",+ "source_tier": "mfr",+ "retrieved": "2026-11-10",+ "edition": "WR-PHD Pin Header 61300411121, revision 003.000, 2023-01-08, 6 pages"+ },+ "cad": "Symbol: KiCad Connector_Generic:Conn_01x04 (KiCad 10.0), renamed, with MPN, manufacturer and order fields. Footprint: KiCad Connector_PinHeader_2.54mm:PinHeader_1x04_P2.54mm_Vertical (KiCad 10.0) with the drill set to the datasheet's recommended 1.10 mm hole and the pads to 1.80 mm. 3D: KiCad 10.0's generic PinHeader_1x04_P2.54mm_Vertical.step, byte-identical, checked against every dimension the datasheet prints; not Wurth Elektronik's own model. KiCad library content is CC-BY-SA-4.0 with the KiCad library exception.",+ "pins": {+ "total": 4,+ "described": 4,+ "cites_pages": true,+ "refuses_to_fabricate": true+ },+ "build": {+ "tool": "hand-built by Claude in Noah's Adom workspace (provenance/tools/make_cad.py, measure_model.py); the Adom parts factory declined this part (request zxdLcgwLNNZq9JLWpcX44hJGj1SiM_dz: its two land-pattern readings disagreed)",+ "at": "2026-11-10"+ },+ "file": "provenance/provenance.json"+ },+ "models_3d": [+ {+ "file": "61300411121.step",+ "role": "plain",+ "up": "Z",+ "units": "mm",+ "origin": "footprint origin = pad 1 (KiCad pin-header convention); pads run along footprint +Y",+ "seat": "insulator underside on z = 0, through-hole tails 3.0 mm below",+ "extents_mm": [+ 2.54,+ 10.16,+ 11.54+ ],+ "zmin_mm": -3.0,+ "zmax_mm": 8.54,+ "centre_offset_mm": 0.0,+ "footprint_binding": "identity",+ "sha256": "a74079b8d06bda78847623b39ee1855ffd1d9a8c1e896b349e4f1dc2056d44d9",+ "checked": "2026-11-10",+ "checked_by": "step2glb features (service-step2glb 1.9.6) + provenance/tools/measure_model.py",+ "notes": [+ "body centre on the pad-pattern centre (0, 3.81 mm in footprint coordinates)",+ "every dimension the datasheet prints is inside its tolerance: provenance/model-vs-datasheet.json"+ ],+ "source": {+ "kind": "kicad-library",+ "library": "KiCad 10.0 packages3D, Connector_PinHeader_2.54mm.3dshapes/PinHeader_1x04_P2.54mm_Vertical.step",+ "author": "kicad StepUp (FreeCAD), 2017-12-09",+ "license": "CC-BY-SA-4.0 with the KiCad library exception",+ "sha256": "a74079b8d06bda78847623b39ee1855ffd1d9a8c1e896b349e4f1dc2056d44d9",+ "bytes_identical_to_source": true,+ "note": "generic 1x04 2.54 mm vertical header model, not Wurth Elektronik's own CAD"+ }+ },+ {+ "file": "61300411121-etched.step",+ "role": "eda",+ "up": "Z",+ "units": "mm",+ "origin": "footprint origin = pad 1",+ "seat": "insulator underside on z = 0, tails below",+ "extents_mm": [+ 2.545,+ 10.16,+ 11.54+ ],+ "zmin_mm": -3.0,+ "zmax_mm": 8.54,+ "footprint_binding": "identity",+ "sha256": "696be90475532efa33b75f335b21d3ec370b3d0ea7473b92c823c08b996b3567",+ "checked": "2026-11-10",+ "checked_by": "adom-aiflow-etch check (adom-aiflow 0.2.56) + step2glb features",+ "notes": [+ "the plain model plus a virtual MPN mark (Adom.LaserEtch, light grey, flat, 5 um proud) on the pin-1 flat of the -X insulator wall",+ "the mark is an identification aid drawn by Adom; the real WR-PHD header carries no printed part number"+ ]+ }+ ]+ },+ "description": "Wurth Elektronik WR-PHD 61300411121: 4-pin, 2.54 mm, single-row THT vertical pin header, gold, 3 A. KiCad symbol, footprint at the datasheet's 1.10 mm hole, and KiCad's generic 1x04 header 3D model checked against the drawing.",+ "discovery_triggers": [+ "61300411121",+ "Wurth 61300411121",+ "WR-PHD 1x4 pin header",+ "Wurth Elektronik 2.54 mm 4 pin header",+ "4 pin 2.54 mm male header gold",+ "1x04 pin header THT vertical",+ "710-61300411121",+ "732-5317-ND",+ "C5184785"+ ],+ "license": "CC-BY-SA-4.0"+}
provenance/etch/61300411121-etched.check.jsonadded+140@@ -0,0 +1,140 @@+{+ "schema": "adom/mark-check@1",+ "step": "61300411121-etched.step",+ "mpn": "61300411121",+ "status": "WARN",+ "checks": [+ {+ "check": "axis",+ "status": "PASS",+ "detail": "text along the 2.03 mm axis",+ "angleDeg": 0+ },+ {+ "check": "upright",+ "status": "PASS",+ "detail": "upright, left to right, pin 1 left middle"+ },+ {+ "check": "size",+ "status": "PASS",+ "detail": "text height 0.316 mm, 97% of what fits (0.326 mm), block fills 29% of the 2.54 mm band height",+ "capMm": 0.3158,+ "fitMm": 0.3258+ },+ {+ "check": "band",+ "status": "PASS",+ "detail": "inside the usable band"+ },+ {+ "check": "flat",+ "status": "PASS",+ "detail": "flat, coplanar with the face (+5 um)"+ },+ {+ "check": "group",+ "status": "PASS",+ "detail": "Adom.LaserEtch group"+ },+ {+ "check": "colour",+ "status": "PASS",+ "detail": "light mark (sRGB 0.90, 0.90, 0.89)",+ "rgb": [+ 0.896243869286,+ 0.896243869286,+ 0.886003966688+ ]+ },+ {+ "check": "widget",+ "status": "WARN",+ "detail": "5.7 px caps with the outline 320 px wide: too small to read in the widget; use two lines or a shorter mark (the user must agree)",+ "capHeightPx320": 5.7+ }+ ],+ "frame": {+ "reference": "normalized pose: footprint frame, X right, Y up, Z up off the board (after the stand-up turns); the marked side wall turned to face +Z",+ "sourceToNormalized": {+ "turns": [+ {+ "axis": "y",+ "quarterTurns": 1+ }+ ],+ "text": "90 deg about Y",+ "source": "as-is (Z up)"+ },+ "normalizedToOutput": {+ "checkImage": {+ "turns": [+ {+ "axis": "z",+ "quarterTurns": 1+ }+ ],+ "text": "90 deg about Z",+ "pose": "standard reading pose: reading direction to +X, text up +Y, pin 1 lower left"+ },+ "outline": {+ "turns": [+ {+ "axis": "z",+ "quarterTurns": 2+ }+ ],+ "text": "180 deg about Z",+ "pose": "iso outline from +X+Y+Z"+ }+ },+ "modelUp": {+ "supplied": false,+ "source": "as-is (Z up)"+ },+ "packageFront": {+ "supplied": true,+ "face": "side",+ "source": "--face side"+ },+ "textUp": {+ "supplied": false,+ "vector": [+ 1.0,+ -0.0,+ 0.0+ ],+ "source": "inferred from pin 1: footprint pad 1"+ },+ "mountedPose": false,+ "summary": "frame: normalized pose (source -> normalized: 90 deg about Y, as-is (Z up); normalized -> check image: 90 deg about Z, -> outline: 180 deg about Z); model up inferred, face side supplied, text up inferred from pin 1; not a mounted-pose check"+ },+ "plan": {+ "summary": "Mark along the 2.03 mm axis (-Y), 0.33 mm text (2 lines), upright with pin 1 left middle, outline rot 90 after a 180 deg pose turn; ~6 px caps at 320 px",+ "band": [+ -0.0,+ -1.016,+ 2.54,+ 1.016+ ],+ "readingDirection": [+ -0.0,+ -1.0,+ 0.0+ ],+ "lines": [+ "61300",+ "411121"+ ]+ },+ "thresholds": {+ "sizePass": 0.8,+ "sizeFail": 0.6,+ "widgetPxPass": 6.0,+ "widgetPxFail": 4.0,+ "outlineOffsetMax": 0.15,+ "coplanarMaxMm": 0.02+ },+ "image": "61300411121-etched.check.png",+ "reportPath": "61300411121-etched.check.json"+}
provenance/etch/61300411121-etched.check.pngadded⋯ 1 unchanged line ⋯
provenance/etch/61300411121-etched.mark-plan.jsonadded+172@@ -0,0 +1,172 @@+{+ "plan": {+ "schema": "adom/mark-plan@1",+ "mpn": "61300411121",+ "step": "61300411121.step",+ "footprint": "61300411121.kicad_mod",+ "standUp": [],+ "standUpSource": "as-is (Z up)",+ "inputs": {+ "up": "auto",+ "face": "side",+ "along": null,+ "upSupplied": false,+ "faceSupplied": true,+ "faceSource": "--face side"+ },+ "face": "side",+ "pin1": {+ "source": "footprint pad 1",+ "xyMm": [+ 0.0,+ -0.0+ ],+ "corner": "left/middle"+ },+ "existingMarks": [],+ "vendorMarking": {+ "present": false,+ "glyphFaces": 0,+ "faces": []+ },+ "faceNormal": [+ -1.0,+ 0.0,+ 0.0+ ],+ "longAxis": {+ "axis": "y",+ "vector": [+ 0.0,+ 1.0,+ 0.0+ ],+ "why": "long side wall (10.16 mm)",+ "source": "side-wall",+ "override": null,+ "pinRows": null+ },+ "readingDirection": {+ "vector": [+ -0.0,+ -1.0,+ 0.0+ ],+ "angleDeg": 270,+ "textUp": [+ 1.0,+ -0.0,+ 0.0+ ],+ "rule": "pin 1 / pad 1 at the start (left) of the text, and below it when it sits on a side"+ },+ "band": {+ "regionMm": [+ -0.0,+ -1.016,+ 2.54,+ 1.016+ ],+ "zMm": 1.27,+ "lengthMm": 2.032,+ "heightMm": 2.54,+ "why": "flat high band of the side wall",+ "terminationsExcludedBy": null,+ "trimmedEnds": [],+ "keepouts": [],+ "sideTurn": {+ "axis": "y",+ "quarterTurns": 1,+ "textUpInTurnedFrame": [+ 1,+ 0,+ 0+ ],+ "baselineInTurnedFrame": [+ 0.0,+ -1.0,+ 0.0+ ]+ },+ "margins": {+ "lengthEachSide": 0.12,+ "heightEachSide": 0.15+ }+ },+ "text": {+ "lines": [+ "61300",+ "411121"+ ],+ "chars": 11,+ "capHeightMm": 0.3258,+ "smallestLineMm": 0.3258,+ "heightPctOfBand": 29.5,+ "why": "two lines: the smaller line (0.326 mm) beats one line (0.175 mm) by 1.86x",+ "alternative": {+ "lines": [+ "61300411121"+ ],+ "capHeightMm": 0.1747,+ "smallestLineMm": 0.1747+ },+ "font": "service-step2glb /laser-etch (single-stroke outline font)"+ },+ "etch": {+ "poseQuarterTurnsZ": 1,+ "service": "/laser-etch?mode=flat",+ "note": "turn so the reading direction is +X, etch, fit the mark into the band, turn back"+ },+ "outline": {+ "upAxis": "z",+ "poseRotZDeg": 180,+ "rot": 90,+ "recipe": "adom-aiflow-etch outline <part.step> --footprint <part.kicad_mod> --mpn 61300411121 (stands the STEP up (as-is (Z up)), turns it 180 deg about Z and draws 61300 / 411121 on the planned band, rot 90)",+ "why": "iso camera looks from +X+Y+Z: text along +Y (rot 90) or -X (rot 180) reads left to right with pin 1 toward the viewer"+ },+ "widget": {+ "px": 320,+ "pxPerMm": 22.06,+ "capHeightPx": 5.9+ },+ "hints": [+ "LED: the top window stays clear; the mark goes on the front long wall"+ ],+ "warnings": [],+ "summary": "Mark along the 2.03 mm axis (-Y), 0.33 mm text (2 lines), upright with pin 1 left middle, outline rot 90 after a 180 deg pose turn; ~6 px caps at 320 px"+ },+ "etch": {+ "out": "61300411121-etched.step",+ "mpn": "61300411121",+ "lines": [+ "61300",+ "411121"+ ],+ "removedOldMarks": [],+ "turns": [+ {+ "axis": "y",+ "quarterTurns": 1+ },+ {+ "axis": "z",+ "quarterTurns": 1+ }+ ],+ "serviceMarkTurnedQuarter": 3,+ "line2Scaled": true,+ "fit": {+ "scale": 0.5518,+ "capMm": 0.3158,+ "markMm": [+ 1.5443,+ 0.7326+ ],+ "bandMm": [+ 2.032,+ 2.54+ ],+ "zMm": 1.275+ }+ }+}
provenance/evidence/footprint-vs-datasheet.pngadded⋯ 1 unchanged line ⋯
provenance/evidence/model-views.pngadded⋯ 1 unchanged line ⋯
provenance/footprint-vs-datasheet.jsonadded+104@@ -0,0 +1,104 @@+{+ "footprint": "61300411121.kicad_mod",+ "datasheet": "Wurth Elektronik 61300411121 rev 003.000 (2023-01-08), p.1 Recommended Hole Pattern + Pattern Properties",+ "pads": [+ {+ "number": "1",+ "kind": "thru_hole",+ "shape": "rect",+ "x": 0.0,+ "y": 0.0,+ "w": 1.8,+ "h": 1.8,+ "drill": 1.1+ },+ {+ "number": "2",+ "kind": "thru_hole",+ "shape": "circle",+ "x": 0.0,+ "y": 2.54,+ "w": 1.8,+ "h": 1.8,+ "drill": 1.1+ },+ {+ "number": "3",+ "kind": "thru_hole",+ "shape": "circle",+ "x": 0.0,+ "y": 5.08,+ "w": 1.8,+ "h": 1.8,+ "drill": 1.1+ },+ {+ "number": "4",+ "kind": "thru_hole",+ "shape": "circle",+ "x": 0.0,+ "y": 7.62,+ "w": 1.8,+ "h": 1.8,+ "drill": 1.1+ }+ ],+ "rows": [+ {+ "item": "Positions",+ "datasheet": "4 (Article Properties: Pins 4; the drawing itself shows a generic 10-position row, 1 to End)",+ "footprint": 4,+ "result": "pass"+ },+ {+ "item": "Pitch",+ "datasheet": "2.54 +-0.05 mm",+ "footprint": [+ 2.54,+ 2.54,+ 2.54+ ],+ "result": "pass"+ },+ {+ "item": "pl, pin 1 to End",+ "datasheet": "7.62 +-0.1 mm (Pattern Properties)",+ "footprint": 7.62,+ "result": "pass"+ },+ {+ "item": "Finished hole",+ "datasheet": "1.10 +-0.15 mm",+ "footprint": [+ 1.1+ ],+ "result": "pass"+ },+ {+ "item": "Single row",+ "datasheet": "one row",+ "footprint": "all pads at x = 0, along +Y",+ "result": "pass"+ },+ {+ "item": "Pin 1",+ "datasheet": "the end labelled 1",+ "footprint": "pad 1 rect at (0.0, 0.0)",+ "result": "pass"+ },+ {+ "item": "Copper pad",+ "datasheet": "not specified (the drawing gives the hole only)",+ "footprint": "1.8 mm (0.35 mm annular ring, the same ring KiCad uses on its 1.0 mm drill / 1.7 mm pad header)",+ "result": "note"+ },+ {+ "item": "Pin in hole",+ "datasheet": "0.64 +-0.15 mm square pin",+ "footprint": "nominal pin diagonal 0.905 mm in a 1.10 mm hole: 0.195 mm diametral clearance",+ "result": "pass"+ }+ ],+ "all_pass": true,+ "why_the_factory_disagreed": "The hole-pattern view is the series drawing: it shows ten holes from 1 to End with pl as a symbol; the 4-position value pl = 7.62 mm is only in the Pattern Properties table, and the copper pad size is not given at all. A reader that counts the drawn holes or invents a pad gets a different land pattern from one that reads the table, which fits the factory's refusal (two readings did not agree). Read from the table, the pattern is unambiguous."+}
provenance/model-vs-datasheet.jsonadded+116@@ -0,0 +1,116 @@+{+ "model": "61300411121.glb",+ "units": "mm",+ "source": "Wurth Elektronik 61300411121 datasheet rev 003.000 (2023-01-08), page 1",+ "method": "vertices of the step2glb GLB per material (insulator, contacts); pin section from the shaft vertices between the insulator top (+0.5 mm) and the tip chamfer",+ "measured": {+ "up_axis": "Z",+ "body_len": 10.159,+ "body_wid": 2.54,+ "body_bottom": 0.0,+ "body_top": 2.54,+ "insulator_h": 2.539,+ "pin_bottom": -3.0,+ "pin_top": 8.54,+ "pin_total": 11.54,+ "mating": 6.0,+ "tail": 3.0,+ "pins": [+ {+ "centre": -7.62,+ "w_long": 0.64,+ "w_short": 0.64+ },+ {+ "centre": -5.08,+ "w_long": 0.64,+ "w_short": 0.64+ },+ {+ "centre": -2.54,+ "w_long": 0.64,+ "w_short": 0.64+ },+ {+ "centre": -0.0,+ "w_long": 0.64,+ "w_short": 0.64+ }+ ],+ "pitch": [+ 2.54,+ 2.54,+ 2.54+ ]+ },+ "rows": [+ {+ "dimension": "Pin square",+ "datasheet": "0.64 +-0.15",+ "model": [+ 0.64,+ 0.64,+ 0.64,+ 0.64,+ 0.64,+ 0.64,+ 0.64,+ 0.64+ ],+ "result": "pass"+ },+ {+ "dimension": "Pitch",+ "datasheet": "2.54 +-0.05",+ "model": [+ 2.54,+ 2.54,+ 2.54+ ],+ "result": "pass"+ },+ {+ "dimension": "Total pin length",+ "datasheet": "11.54 +-0.2",+ "model": 11.54,+ "result": "pass"+ },+ {+ "dimension": "Mating length above insulator",+ "datasheet": "6.0 +-0.2",+ "model": 6.0,+ "result": "pass"+ },+ {+ "dimension": "Tail length below insulator",+ "datasheet": "3.0 +-0.2",+ "model": 3.0,+ "result": "pass"+ },+ {+ "dimension": "Insulator height",+ "datasheet": "2.54 +-0.15",+ "model": 2.539,+ "result": "pass"+ },+ {+ "dimension": "Insulator width",+ "datasheet": "2.54 +-0.15",+ "model": 2.54,+ "result": "pass"+ },+ {+ "dimension": "Insulator length L (4 pins)",+ "datasheet": "10.16 +-0.35",+ "model": 10.159,+ "result": "pass"+ },+ {+ "dimension": "Pin to pin pl (1 to 4)",+ "datasheet": "7.62 +-0.15",+ "model": 7.62,+ "result": "pass"+ }+ ],+ "all_pass": true+}
provenance/provenance.jsonadded+399@@ -0,0 +1,399 @@+{+ "schema": "adom/component-provenance@1",+ "mpn": "61300411121",+ "manufacturer": "Wurth Elektronik",+ "series": "WR-PHD",+ "built": "2026-11-10",+ "built_by": "Claude in Noah's Adom workspace, at Noah's request",+ "why": "The Adom parts factory declined this part (request zxdLcgwLNNZq9JLWpcX44hJGj1SiM_dz, state cannot_build: \"Two independent readings of the datasheet's land pattern didn't agree\"). The datasheet's hole-pattern view is the WR-PHD series drawing (ten holes, 1 to End); the 4-position pl = 7.62 mm is only in the Pattern Properties table and no copper pad size is printed. This page reads the table and takes the pad from KiCad's own header (0.35 mm annular ring).",+ "sources": {+ "datasheet": {+ "url": "https://www.we-online.com/components/products/datasheet/61300411121.pdf",+ "revision": "003.000",+ "date": "2023-01-08",+ "sha256": "ce759fb8caee2fd0c3167f6925010f6703aa4f939ded51aae7ead334c38c0d7d"+ },+ "kicad": {+ "version": "10.0",+ "symbol": "Connector_Generic:Conn_01x04",+ "footprint": "Connector_PinHeader_2.54mm:PinHeader_1x04_P2.54mm_Vertical",+ "model": "Connector_PinHeader_2.54mm.3dshapes/PinHeader_1x04_P2.54mm_Vertical.step",+ "license": "CC-BY-SA-4.0 with the KiCad library exception (designs that use the library are not bound by it)",+ "license_url": "https://www.kicad.org/libraries/license/"+ },+ "wurth_cad": {+ "obtained": false,+ "note": "Wurth Elektronik's own STEP for 61300411121 was not obtained: we-online.com answers automated requests with HTTP 403 or a bot check, and the remaining lanes (a browser, or the distributor CAD links behind a login) were out of scope for this headless build. The page therefore uses KiCad's generic 1x04 header model and says so."+ },+ "stock_checked": {+ "date": "2026-11-10",+ "tool": "adom-parts-search 2.1.5",+ "mouser": {+ "part": "710-61300411121",+ "stock": 115305,+ "price_1": "$0.19",+ "price_100": "$0.102",+ "lead_time": "112 days"+ },+ "digikey": {+ "part": "732-5317-ND",+ "stock": 120886,+ "price_1": "$0.18",+ "price_100": "$0.1047",+ "status": "Active"+ },+ "jlcpcb_lcsc": {+ "part": "C5184785",+ "stock": 1544,+ "price_1": "$0.2216",+ "library": "extended"+ }+ }+ },+ "checks": {+ "footprint": {+ "file": "provenance/footprint-vs-datasheet.json",+ "all_pass": true+ },+ "model": {+ "file": "provenance/model-vs-datasheet.json",+ "all_pass": true+ },+ "etch": {+ "file": "provenance/etch/61300411121-etched.check.json",+ "status": "WARN",+ "warn": "widget: 5.7 px caps when the outline is drawn 320 px wide (an 11-character mark on a 2.03 mm flat)"+ },+ "hero": {+ "align_ok": true,+ "centre_offset_mm": 0.0+ }+ },+ "licenses": {+ "page": "CC-BY-SA-4.0",+ "kicad_derived": "CC-BY-SA-4.0 with the KiCad library exception (designs that use the library are not bound by it)",+ "datasheet": "Wurth Elektronik eiSos copyright, unmodified"+ },+ "files": [+ {+ "path": "docs/61300411121-datasheet.pdf",+ "sha256": "ce759fb8caee2fd0c3167f6925010f6703aa4f939ded51aae7ead334c38c0d7d",+ "bytes": 383660,+ "authoring": "manufacturer-original",+ "license": "Wurth Elektronik eiSos copyright; redistributed unmodified as the manufacturer's published datasheet",+ "source": {+ "url": "https://www.we-online.com/components/products/datasheet/61300411121.pdf",+ "revision": "003.000",+ "date": "2023-01-08",+ "pages": 6,+ "retrieved": "2026-11-10",+ "note": "fetched with WebFetch on 2026-11-10; we-online.com answers plain curl with HTTP 403"+ },+ "cites": "identity, pinout end labels, dimensions, hole pattern (p.1); materials, electrical, certification (p.2); packaging (p.3); wave soldering profile (p.4); cautions (p.5-6)"+ },+ {+ "path": "docs/figures/61300411121-ds-p1.png",+ "sha256": "55599f0990d8b6537fe6ea4c429c2a36fd57d5085fa43fffdfe23ba9a4fd7f9d",+ "bytes": 181663,+ "authoring": "manufacturer-original (rendered)",+ "license": "Wurth Elektronik eiSos copyright (page image of the datasheet)",+ "source": {+ "derived_from": "docs/61300411121-datasheet.pdf",+ "tool": "pdftoppm -r 150 -f 1 -l 1"+ }+ },+ {+ "path": "docs/figures/61300411121-ds-p2.png",+ "sha256": "4fa49461f21cc7ad89387986d2b35a12ceb9120450bc485a57ae4bf656f22e0a",+ "bytes": 186188,+ "authoring": "manufacturer-original (rendered)",+ "license": "Wurth Elektronik eiSos copyright (page image of the datasheet)",+ "source": {+ "derived_from": "docs/61300411121-datasheet.pdf",+ "tool": "pdftoppm -r 150 -f 2 -l 2"+ }+ },+ {+ "path": "61300411121.step",+ "sha256": "a74079b8d06bda78847623b39ee1855ffd1d9a8c1e896b349e4f1dc2056d44d9",+ "bytes": 145684,+ "authoring": "kicad-library-verbatim",+ "license": "CC-BY-SA-4.0 with the KiCad library exception (designs that use the library are not bound by it)",+ "source": {+ "library": "KiCad 10.0 packages3D",+ "file": "Connector_PinHeader_2.54mm.3dshapes/PinHeader_1x04_P2.54mm_Vertical.step",+ "author": "kicad StepUp (FreeCAD), 2017-12-09",+ "source_sha256": "a74079b8d06bda78847623b39ee1855ffd1d9a8c1e896b349e4f1dc2056d44d9",+ "byte_identical": true,+ "board_copy": "fc-f405-stack design/projectlib/3dmodels/WE_61300411121.step (same sha256)"+ },+ "note": "generic 1x04 2.54 mm vertical header model, not Wurth Elektronik's own CAD; every printed datasheet dimension is inside its tolerance (provenance/model-vs-datasheet.json)"+ },+ {+ "path": "61300411121.kicad_sym",+ "sha256": "2bc7fb8efd75861b850fb237ac4ae63c66345226671074855403c3ffd96be1e8",+ "bytes": 4461,+ "authoring": "kicad-library-derived",+ "license": "CC-BY-SA-4.0 with the KiCad library exception (designs that use the library are not bound by it)",+ "source": {+ "library": "KiCad 10.0 Connector_Generic.kicad_sym",+ "symbol": "Conn_01x04",+ "via": {+ "file": "fc-f405-stack design/projectlib/fc_local.kicad_sym, symbol 61300411121",+ "sha256": "713394b6228763ca28c9f07450a9fc4c28e09d551cc9275ce87de00bf72f8bc7"+ },+ "tool": "provenance/tools/make_cad.py"+ },+ "changes_from_kicad": [+ "symbol renamed 61300411121; Value 61300411121",+ "Datasheet set to the Wurth PDF URL; MPN, Manufacturer added (board symbol)",+ "Footprint 61300411121:61300411121 (board symbol: fc_local:WE_61300411121_1x04_P2.54mm_Vertical)",+ "Description generic (board symbol carried a project note)",+ "Mouser, DigiKey, LCSC and Adom Wiki properties added for this page"+ ],+ "unchanged": "pins (numbers 1 to 4, names Pin_1 to Pin_4, passive, positions, lengths) and graphics, identical to KiCad's Conn_01x04 and to the board symbol"+ },+ {+ "path": "61300411121.kicad_mod",+ "sha256": "0aee3b319aae2fd7e3b0a4d29d5a05170edccfd6dc6a76a3c61a8394a3489d6e",+ "bytes": 3154,+ "authoring": "kicad-library-derived",+ "license": "CC-BY-SA-4.0 with the KiCad library exception (designs that use the library are not bound by it)",+ "source": {+ "library": "KiCad 10.0 Connector_PinHeader_2.54mm.pretty",+ "footprint": "PinHeader_1x04_P2.54mm_Vertical",+ "source_sha256_crlf": "8952158347d7b7cc13924c62dccb0c48911af892bb009a0de27cb4d3c25cc1bb",+ "via": {+ "file": "fc-f405-stack design/projectlib/fc_local.pretty/WE_61300411121_1x04_P2.54mm_Vertical.kicad_mod",+ "sha256": "034181bbd7b0c940eec8077dae075586247aaaa368edc0ad241bff2b2433bac9"+ },+ "tool": "provenance/tools/make_cad.py"+ },+ "changes_from_kicad": [+ "pads 1.7 to 1.8 mm and drill 1.0 to 1.1 mm (the datasheet's recommended 1.10 +-0.15 mm hole, same 0.35 mm annular ring); made for the board",+ "descr and Value name the Wurth part; made for the board",+ "footprint name 61300411121 and model path ${KIPRJMOD}/61300411121.step; made for this page (board: WE_61300411121_1x04_P2.54mm_Vertical, ${KIPRJMOD}/lib/fc_local.3dshapes/WE_61300411121.step)"+ ],+ "unchanged": "pads, drills, silkscreen, fab, courtyard identical to the board footprint (only the name and model path lines differ)",+ "check": "provenance/footprint-vs-datasheet.json"+ },+ {+ "path": "61300411121.glb",+ "sha256": "a72b4d0a33e7066094136aae48f64a5ef8321f694ae2e8f3e8582ac81eadc8df",+ "bytes": 39976,+ "authoring": "adom-derived",+ "license": "CC-BY-SA-4.0 with the KiCad library exception (designs that use the library are not bound by it)",+ "source": {+ "derived_from": "61300411121.step",+ "tool": "step2glb convert (adom-step2glb 1.3.4, service-step2glb 1.9.6)"+ },+ "note": "Z-up metres, KHR_mesh_quantization; colours from the STEP (black insulator, gold pins)"+ },+ {+ "path": "61300411121-etched.step",+ "sha256": "696be90475532efa33b75f335b21d3ec370b3d0ea7473b92c823c08b996b3567",+ "bytes": 360324,+ "authoring": "adom-derived",+ "license": "CC-BY-SA-4.0 with the KiCad library exception (designs that use the library are not bound by it)",+ "source": {+ "derived_from": "61300411121.step",+ "tool": "adom-aiflow-etch --face side (adom-aiflow 0.2.56), /laser-etch on service-step2glb"+ },+ "marking": {+ "text": "61300 / 411121",+ "virtual": true,+ "surface": "pin-1 flat of the -X insulator wall",+ "cap_height_mm": 0.3158,+ "group": "Adom.LaserEtch",+ "note": "identification aid drawn by Adom; the real part carries no printed part number"+ },+ "gate": {+ "status": "WARN",+ "report": "provenance/etch/61300411121-etched.check.json"+ }+ },+ {+ "path": "61300411121-etched.glb",+ "sha256": "d3023a6158d4a3740daea315a3eeefac4da547fc460a6e2b0f98731eb2287d17",+ "bytes": 52452,+ "authoring": "adom-derived",+ "license": "CC-BY-SA-4.0 with the KiCad library exception (designs that use the library are not bound by it)",+ "source": {+ "derived_from": "61300411121-etched.step",+ "tool": "step2glb convert (adom-step2glb 1.3.4, service-step2glb 1.9.6)"+ }+ },+ {+ "path": "61300411121-hero.glb",+ "sha256": "6a67a6407e529c4d725442b62f12f6d5a23a4590b1c5371e9824ecbb474ea58e",+ "bytes": 104280,+ "authoring": "adom-derived",+ "license": "CC-BY-SA-4.0 with the KiCad library exception (designs that use the library are not bound by it)",+ "source": {+ "derived_from": [+ "61300411121-etched.glb",+ "61300411121.kicad_mod",+ "page.json component.pins"+ ],+ "tool": "component-hero 0.1.2 scripts/hero_glb.py with provenance/tools/hero_glb-single-row.patch (labels of a single pad column on one side)"+ },+ "standard": "adom-hero 1.4",+ "align": true,+ "pin1": "added dot (AI)"+ },+ {+ "path": "61300411121-hero.overlay.json",+ "sha256": "39495c77bca44ac4607151b692ea130d9130fb1f588e317394d67d6b8cb53ae2",+ "bytes": 2777,+ "authoring": "adom-derived",+ "license": "CC-BY-SA-4.0",+ "source": {+ "tool": "component-hero hero_glb.py sidecar"+ }+ },+ {+ "path": "61300411121.lbr",+ "sha256": "d7dfee70796c895d96fc804bac2a862516a13d1b230df5a5fb32a3c8f4e5bbd3",+ "bytes": 8824,+ "authoring": "adom-derived",+ "license": "CC-BY-SA-4.0 with the KiCad library exception (designs that use the library are not bound by it)",+ "source": {+ "derived_from": [+ "61300411121.kicad_sym",+ "61300411121.kicad_mod",+ "page.json"+ ],+ "tool": "adom-lbr 2.47.9 generate --symbol-layout keep"+ },+ "check": "adom-lbr validate: valid EAGLE .lbr with complete deviceset; lint 0 errors 0 warnings"+ },+ {+ "path": "61300411121.adom-lbr.json",+ "sha256": "12b9aaa0e02a0d418db3c784e0a6b299eab0a3bcbf83e1821575e65261077d9d",+ "bytes": 7949,+ "authoring": "adom-derived",+ "license": "CC-BY-SA-4.0 with the KiCad library exception (designs that use the library are not bound by it)",+ "source": {+ "derived_from": [+ "61300411121.kicad_sym",+ "61300411121.kicad_mod"+ ],+ "tool": "adom-lbr 2.47.9 import-kicad"+ }+ },+ {+ "path": "docs/hero.png",+ "sha256": "5c74d16aadc2a78e9387974cc1baa6fa44f3309245384d0c001fc3765155c117",+ "bytes": 146525,+ "authoring": "adom-authored",+ "license": "CC-BY-SA-4.0",+ "source": {+ "tool": "step2glb thumbnail (iso2) of the etched STEP, composed with PIL; fonts Familjen Grotesk, Satoshi, JetBrains Mono"+ }+ },+ {+ "path": "provenance/evidence/footprint-vs-datasheet.png",+ "sha256": "3373a65e91f3ba6d641bc23c1385d8a13fd9d437e9900aeb3925d9b25a8413d3",+ "bytes": 119827,+ "authoring": "adom-authored (contains a datasheet crop)",+ "license": "CC-BY-SA-4.0 (the datasheet crop stays Wurth's)",+ "source": {+ "tool": "provenance/tools/check_footprint.py"+ }+ },+ {+ "path": "provenance/evidence/model-views.png",+ "sha256": "60b31d308eb5ca107afff7f89f6de8cb468feeea3bb9ff0cce01adada5180254",+ "bytes": 96930,+ "authoring": "adom-authored",+ "license": "CC-BY-SA-4.0 (renders of the KiCad model)",+ "source": {+ "tool": "step2glb thumbnail, 6 views"+ }+ },+ {+ "path": "provenance/footprint-vs-datasheet.json",+ "sha256": "f78e63e192055e892f103bb7d3dc11517181e81cd3f47d340bc250ad95921bb9",+ "bytes": 2525,+ "authoring": "adom-authored",+ "license": "CC-BY-SA-4.0",+ "source": {+ "tool": "provenance/tools/check_footprint.py"+ }+ },+ {+ "path": "provenance/model-vs-datasheet.json",+ "sha256": "831d9dece26239dfe458d65ccbf6713f5a27f128dd57d3e1f273d0534c0d1f01",+ "bytes": 2083,+ "authoring": "adom-authored",+ "license": "CC-BY-SA-4.0",+ "source": {+ "tool": "provenance/tools/measure_model.py"+ }+ },+ {+ "path": "provenance/etch/61300411121-etched.mark-plan.json",+ "sha256": "5a1d6140f8441c05a265ff68a99862764aebf192972e27f33ebebfed68b92393",+ "bytes": 3455,+ "authoring": "adom-derived",+ "license": "CC-BY-SA-4.0",+ "source": {+ "tool": "adom-aiflow-etch"+ }+ },+ {+ "path": "provenance/etch/61300411121-etched.check.json",+ "sha256": "df3a4dd25f010284f11f47c523404a242e4fbbe0e62b36d87ed05aad356ecaf2",+ "bytes": 3146,+ "authoring": "adom-derived",+ "license": "CC-BY-SA-4.0",+ "source": {+ "tool": "adom-aiflow-etch check"+ }+ },+ {+ "path": "provenance/etch/61300411121-etched.check.png",+ "sha256": "e2a15282987aa752574741509c4549049221ed0cd5cec3a2b20c00929f45a38b",+ "bytes": 7883,+ "authoring": "adom-derived",+ "license": "CC-BY-SA-4.0",+ "source": {+ "tool": "adom-aiflow-etch check"+ }+ },+ {+ "path": "provenance/tools/make_cad.py",+ "sha256": "46953856c6cb9e53a17385078709d9173635998e27efe0f472bd3a1d4c6e9b1a",+ "bytes": 4157,+ "authoring": "adom-authored",+ "license": "CC-BY-SA-4.0",+ "source": {}+ },+ {+ "path": "provenance/tools/measure_model.py",+ "sha256": "08bd2d351831d3cbd968374935addb3bf8003226f9750e82cd3db4643e7cd629",+ "bytes": 6367,+ "authoring": "adom-authored",+ "license": "CC-BY-SA-4.0",+ "source": {}+ },+ {+ "path": "provenance/tools/check_footprint.py",+ "sha256": "829ee406bc40011ff8add6405dedce8e712ca51e0d5736c97475430ad1e4014f",+ "bytes": 5612,+ "authoring": "adom-authored",+ "license": "CC-BY-SA-4.0",+ "source": {}+ },+ {+ "path": "provenance/tools/hero_glb-single-row.patch",+ "sha256": "eb6a9f4477bb622c75331b5fd22ae706ace108b9b70075abfddf1a4db0debe3a",+ "bytes": 3595,+ "authoring": "adom-authored",+ "license": "CC-BY-SA-4.0",+ "source": {+ "applies_to": "adom/component-hero 0.1.2 scripts/hero_glb.py (sha256 429e437a3f2e5f1dc3544fe65843ea4e019637f0a6163060cda2ae210f3af7bc)"+ }+ }+ ]+}
provenance/tools/check_footprint.pyadded+77@@ -0,0 +1,77 @@+#!/usr/bin/env python3+"""Check the 61300411121 footprint against the Wurth datasheet's recommended hole pattern (rev 003.000, p.1) and+draw the evidence image: the datasheet's hole-pattern view beside the footprint drawn to scale in the same pose.++ check_footprint.py <61300411121.kicad_mod> <datasheet hole-pattern crop.png> <out.json> <out.png>+"""+import json, math, re, sys++kmod, crop, out_json, out_png = sys.argv[1:5]+text = open(kmod).read()+pads = []+for m in re.finditer(r'\(pad "([^"]+)" (\w+) (\w+)\s*\(at ([-\d.]+) ([-\d.]+)\)\s*\(size ([-\d.]+) ([-\d.]+)\)\s*\(drill ([-\d.]+)\)', text):+ num, kind, shape, x, y, w, h, d = m.groups()+ pads.append(dict(number=num, kind=kind, shape=shape, x=float(x), y=float(y), w=float(w), h=float(h), drill=float(d)))+pads.sort(key=lambda p: int(p["number"]))+pitches = [round(math.hypot(b["x"] - a["x"], b["y"] - a["y"]), 4) for a, b in zip(pads, pads[1:])]+pl = round(math.hypot(pads[-1]["x"] - pads[0]["x"], pads[-1]["y"] - pads[0]["y"]), 4)+ring = round(min((p["w"] - p["drill"]) / 2 for p in pads), 3)+pin_diag = round(0.64 * math.sqrt(2), 3)+rows = [+ dict(item="Positions", datasheet="4 (Article Properties: Pins 4; the drawing itself shows a generic 10-position row, 1 to End)",+ footprint=len(pads), result="pass" if len(pads) == 4 else "fail"),+ dict(item="Pitch", datasheet="2.54 +-0.05 mm", footprint=pitches, result="pass" if all(abs(v - 2.54) <= 0.05 for v in pitches) else "fail"),+ dict(item="pl, pin 1 to End", datasheet="7.62 +-0.1 mm (Pattern Properties)", footprint=pl, result="pass" if abs(pl - 7.62) <= 0.1 else "fail"),+ dict(item="Finished hole", datasheet="1.10 +-0.15 mm", footprint=sorted({p["drill"] for p in pads}),+ result="pass" if all(abs(p["drill"] - 1.10) <= 1e-6 for p in pads) else "fail"),+ dict(item="Single row", datasheet="one row", footprint="all pads at x = 0, along +Y",+ result="pass" if all(abs(p["x"]) < 1e-6 for p in pads) else "fail"),+ dict(item="Pin 1", datasheet="the end labelled 1", footprint=f"pad {pads[0]['number']} {pads[0]['shape']} at ({pads[0]['x']}, {pads[0]['y']})",+ result="pass" if pads[0]["shape"] == "rect" and pads[0]["x"] == 0 and pads[0]["y"] == 0 else "fail"),+ dict(item="Copper pad", datasheet="not specified (the drawing gives the hole only)",+ footprint=f"{pads[0]['w']} mm ({ring} mm annular ring, the same ring KiCad uses on its 1.0 mm drill / 1.7 mm pad header)",+ result="note"),+ dict(item="Pin in hole", datasheet="0.64 +-0.15 mm square pin",+ footprint=f"nominal pin diagonal {pin_diag} mm in a 1.10 mm hole: {round(1.10 - pin_diag, 3)} mm diametral clearance",+ result="pass" if pin_diag < 1.10 else "fail"),+]+res = dict(footprint=kmod, datasheet="Wurth Elektronik 61300411121 rev 003.000 (2023-01-08), p.1 Recommended Hole Pattern + Pattern Properties",+ pads=pads, rows=rows, all_pass=all(r["result"] in ("pass", "note") for r in rows),+ why_the_factory_disagreed=("The hole-pattern view is the series drawing: it shows ten holes from 1 to End with pl as a symbol; "+ "the 4-position value pl = 7.62 mm is only in the Pattern Properties table, and the copper pad size is not given at all. "+ "A reader that counts the drawn holes or invents a pad gets a different land pattern from one that reads the table, "+ "which fits the factory's refusal (two readings did not agree). Read from the table, the pattern is unambiguous."))+json.dump(res, open(out_json, "w"), indent=1)++# evidence image+import matplotlib+matplotlib.use("Agg")+import matplotlib.pyplot as plt+from matplotlib.patches import Circle, Rectangle+from PIL import Image++fig = plt.figure(figsize=(16, 7.2), dpi=110, facecolor="white")+ax1 = fig.add_axes([0.01, 0.06, 0.46, 0.86]); ax1.imshow(Image.open(crop)); ax1.axis("off")+ax1.set_title("Datasheet p.1: Recommended Hole Pattern (series drawing) and Pattern Properties", fontsize=11)+ax2 = fig.add_axes([0.52, 0.12, 0.46, 0.78]); ax2.set_aspect("equal")+# draw horizontally like the datasheet: footprint +Y (pad 1 -> 4) becomes +X+for p in pads:+ cx = p["y"]; cy = 0.0+ if p["shape"] == "rect":+ ax2.add_patch(Rectangle((cx - p["w"] / 2, cy - p["h"] / 2), p["w"], p["h"], color="#c8962c", alpha=0.85))+ else:+ ax2.add_patch(Circle((cx, cy), p["w"] / 2, color="#c8962c", alpha=0.85))+ ax2.add_patch(Circle((cx, cy), p["drill"] / 2, color="white"))+ ax2.add_patch(Rectangle((cx - 0.32, cy - 0.32), 0.64, 0.64, fill=False, ec="#333333", lw=1.0, ls="--"))+ ax2.text(cx, -1.35, p["number"], ha="center", va="top", fontsize=12)+ax2.annotate("", xy=(0, 1.7), xytext=(7.62, 1.7), arrowprops=dict(arrowstyle="<->", lw=1))+ax2.text(3.81, 1.85, f"pl = {pl} mm (table: 7.62 +-0.1)", ha="center", va="bottom", fontsize=11)+ax2.annotate("", xy=(5.08, 1.15), xytext=(7.62, 1.15), arrowprops=dict(arrowstyle="<->", lw=1))+ax2.text(6.35, 1.25, f"{pitches[-1]} (2.54 +-0.05)", ha="center", va="bottom", fontsize=10)+ax2.text(0, -2.3, f"drill {pads[0]['drill']} mm (1.10 +-0.15)\npad {pads[0]['w']} mm, pad 1 square\ndashed: 0.64 mm pin", ha="left", va="top", fontsize=10)+ax2.set_xlim(-1.6, 9.3); ax2.set_ylim(-4.2, 2.8)+ax2.set_xlabel("mm (footprint +Y drawn to the right, as the datasheet draws pin 1 to End)")+ax2.set_title("Page footprint 61300411121.kicad_mod, to scale", fontsize=11)+ax2.grid(True, lw=0.3, alpha=0.5)+fig.savefig(out_png)+print(json.dumps(dict(rows=rows, all_pass=res["all_pass"]), indent=1))
provenance/tools/hero_glb-single-row.patchadded+53@@ -0,0 +1,53 @@+--- a/scripts/hero_glb.py+@@ -328,12 +328,18 @@+ cx, cy = (min(xs) + max(xs)) / 2, (min(ys) + max(ys)) / 2+ hx, hy = (max(xs) - min(xs)) / 2 or 1e-6, (max(ys) - min(ys)) / 2 or 1e-6+ plan, seen = [], set()++ # a single column (or row) of more than two pads (1xN pin header, SIP): every pad is on the one line, so the++ # extreme-based split below would push interior labels into the gaps between pads. Label them all on one side.++ one_col = len(sig) > 2 and max(xs) - min(xs) < 0.3++ one_row = len(sig) > 2 and not one_col and max(ys) - min(ys) < 0.3+ for p in sig:+ if p['number'] in seen: continue # multi-pad numbers (split EP, shield legs) labelled once+ seen.add(p['number'])+ # side = the extreme it sits closest to (normalised), so a 2-row part splits left/right or top/bottom+ dxn, dyn = (p['x'] - cx) / hx, (p['y'] - cy) / hy+- if len(sig) == 2 or abs(dxn) >= abs(dyn): side = 'R' if p['x'] >= cx else 'L'++ if one_col: side = 'R'++ elif one_row: side = 'B'++ elif len(sig) == 2 or abs(dxn) >= abs(dyn): side = 'R' if p['x'] >= cx else 'L'+ else: side = 'B' if p['y'] >= cy else 'T'+ same = [q for q in sig if q is not p and ((side in 'LR' and abs(q['x'] - p['x']) < 0.3) or (side in 'TB' and abs(q['y'] - p['y']) < 0.3))]+ pitch = min([abs((q['y'] - p['y']) if side in 'LR' else (q['x'] - p['x'])) for q in same] or [99])+@@ -355,6 +361,12 @@+ if side == 'R': lb['x'] = hit[1] + gap+ if side == 'T': lb['y'] = hit[2] - gap+ if side == 'B': lb['y'] = hit[3] + gap++ if plan and one_col: # one column: every label starts on the same line, clear of whatever pushed any of them out++ mx = max(lb['x'] for lb in plan)++ for lb in plan: lb['x'] = mx++ if plan and one_row:++ my = max(lb['y'] for lb in plan)++ for lb in plan: lb['y'] = my+ return plan, None+ + +@@ -530,7 +542,7 @@+ x, y, r, _ = dot+ ring = [(x + r * math.cos(t), y + r * math.sin(t)) for t in np.linspace(0, 2 * math.pi, 33)[:-1]]+ silk_tris += fill_tris([ring])+- obstacles = [(min(q[0] for q in pts), max(q[0] for q in pts), min(q[1] for q in pts), max(q[1] for q in pts)) for kind, pts, _ in silk if kind == 'fill']++ obstacles = [(min(q[0] for q in pts) - w / 2, max(q[0] for q in pts) + w / 2, min(q[1] for q in pts) - w / 2, max(q[1] for q in pts) + w / 2) for kind, pts, w in silk]+ if dot and not existing_mark: obstacles.append((dot[0] - dot[2], dot[0] + dot[2], dot[1] - dot[2], dot[1] + dot[2]))+ plan, why_no_labels = label_plan(pads, names, obstacles)+ name_up, name_down = [], []+@@ -563,7 +575,7 @@+ omitted=why_no_labels, fallback_to_pad_number=sum(1 for lb in plan if lb['text'] == lb['pad'])))+ hero = dict(spec=SPEC, mpn=mpn, kind='component + footprint reference art', board_use=False, plane_z_mm=Z, units='metre', upAxis='Z',+ layers=layers, align=chk, sources=dict(glb=os.path.basename(src_glb), glb_sha256=sha(src_glb),+- footprint=os.path.basename(kmod), footprint_sha256=sha(kmod), pins='page.json component.pins'), generator='factory/hero_glb.py')++ footprint=os.path.basename(kmod), footprint_sha256=sha(kmod), pins='page.json component.pins'), generator='factory/hero_glb.py + single-row label patch')+ ex = g.asset.extras if isinstance(g.asset.extras, dict) else {}+ ex['adomHero'] = hero; g.asset.extras = ex+ g.save_binary(out)
provenance/tools/make_cad.pyadded+102@@ -0,0 +1,102 @@+#!/usr/bin/env python3+"""Derive the wiki page's KiCad symbol and footprint for Wurth Elektronik 61300411121 from the project+library files the board uses, changing only identity text (names, model path, generic description, order+numbers). Geometry, pads, drills, graphics and pins are copied unchanged; compare_cad() proves it.++ make_cad.py <board .kicad_sym> <board .kicad_mod> <out dir>+"""+import hashlib, json, re, sys++MPN = "61300411121"+FIELDS = [ # added after Manufacturer, in this order, hidden+ ("Mouser", "710-61300411121"),+ ("DigiKey", "732-5317-ND"),+ ("LCSC", "C5184785"),+ ("Adom Wiki", "https://wiki.adom.inc/adom/61300411121"),+]+DESC = ("Wurth Elektronik WR-PHD 61300411121 pin header, 2.54 mm pitch, 1x04, THT vertical, "+ "gold-plated 0.64 mm square pins, 3 A, 250 VAC")+++def block(text, head):+ i = text.find(head)+ if i < 0:+ raise SystemExit(f"not found: {head}")+ d = 0+ for j in range(i, len(text)):+ if text[j] == "(":+ d += 1+ elif text[j] == ")":+ d -= 1+ if d == 0:+ return text[i:j + 1]+ raise SystemExit("unbalanced")+++def prop(name, value, indent="\t\t"):+ return (f'{indent}(property "{name}" "{value}"\n'+ f'{indent}\t(at 0 0 0)\n{indent}\t(show_name no)\n{indent}\t(do_not_autoplace no)\n'+ f'{indent}\t(hide yes)\n{indent}\t(effects\n{indent}\t\t(font\n{indent}\t\t\t(size 1.27 1.27)\n'+ f'{indent}\t\t)\n{indent}\t)\n{indent})\n')+++def make_symbol(src):+ s = open(src).read()+ sym = block(s, f'(symbol "{MPN}"')+ sym = sym.replace('(property "Footprint" "fc_local:WE_61300411121_1x04_P2.54mm_Vertical"',+ f'(property "Footprint" "{MPN}:{MPN}"', 1)+ sym, n = re.subn(r'\(property "Description" "[^"]*"', f'(property "Description" "{DESC}"', sym, count=1)+ assert n == 1+ # insert the order fields after the Manufacturer property block+ m = re.search(r'\t\t\(property "Manufacturer" "[^"]*"\n(?:.*\n)*?\t\t\)\n', "\t" + sym)+ assert m, "Manufacturer property not found"+ ins = "".join(prop(k, v) for k, v in FIELDS)+ sym = ("\t" + sym)[:m.end()] + ins + ("\t" + sym)[m.end():]+ head = ('(kicad_symbol_lib\n\t(version 20251024)\n\t(generator "kicad_symbol_editor")\n'+ '\t(generator_version "10.0")\n')+ return head + sym + "\n)\n"+++def make_footprint(src):+ f = open(src).read()+ f = f.replace('(footprint "WE_61300411121_1x04_P2.54mm_Vertical"', f'(footprint "{MPN}"', 1)+ f = f.replace('(model "${KIPRJMOD}/lib/fc_local.3dshapes/WE_61300411121.step"',+ '(model "${KIPRJMOD}/' + MPN + '.step"', 1)+ return f+++def geometry(text):+ """Everything that is not identity text: pads, graphics, pins, layers."""+ out = []+ for line in text.splitlines():+ t = line.strip()+ if re.match(r'\((footprint|symbol|property|descr|model|kicad_symbol_lib|version|generator)\b', t):+ out.append("<id>")+ continue+ out.append(t)+ return out+++def main():+ sym_src, fp_src, out = sys.argv[1:4]+ sym = make_symbol(sym_src)+ fp = make_footprint(fp_src)+ open(f"{out}/{MPN}.kicad_sym", "w").write(sym)+ open(f"{out}/{MPN}.kicad_mod", "w").write(fp)+ # pads and graphics unchanged? compare the footprint line by line outside identity lines+ fsrc = open(fp_src).read()+ same_fp = [a for a in zip(fsrc.splitlines(), fp.splitlines()) if a[0] != a[1]]+ print(json.dumps({+ "footprint_lines_changed": [{"board": a, "page": b} for a, b in same_fp],+ "symbol_pins": re.findall(r'\(pin (\w+) line\s*\n\s*\(at ([^)]*)\)\s*\n\s*\(length ([^)]*)\)\s*\n\s*\(name "([^"]*)"(?:.|\n)*?\(number "([^"]*)"', sym),+ "sha256": {+ "board_symbol_lib": hashlib.sha256(open(sym_src, "rb").read()).hexdigest(),+ "board_footprint": hashlib.sha256(open(fp_src, "rb").read()).hexdigest(),+ "page_symbol": hashlib.sha256(sym.encode()).hexdigest(),+ "page_footprint": hashlib.sha256(fp.encode()).hexdigest(),+ },+ }, indent=1))+++if __name__ == "__main__":+ main()
provenance/tools/measure_model.pyadded+133@@ -0,0 +1,133 @@+#!/usr/bin/env python3+"""Measure the 61300411121 3D model (step2glb GLB of the STEP) against the Wurth datasheet drawing.++ measure_model.py <model.glb> <out.json>++The GLB from step2glb is in metres. The two materials are the insulator (dark) and the contacts (gold). Every+dimension the datasheet prints is compared with its tolerance; the verdict per row is pass or fail.+"""+import json, sys+import numpy as np+from pygltflib import GLTF2++glb, out = sys.argv[1], sys.argv[2]+g = GLTF2().load(glb)+blob = g.binary_blob()+++def acc(i):+ a = g.accessors[i]+ bv = g.bufferViews[a.bufferView]+ n = {"SCALAR": 1, "VEC2": 2, "VEC3": 3, "VEC4": 4}[a.type]+ dt = {5126: np.float32, 5125: np.uint32, 5123: np.uint16, 5122: np.int16, 5121: np.uint8, 5120: np.int8}[a.componentType]+ off = (bv.byteOffset or 0) + (a.byteOffset or 0)+ size = n * np.dtype(dt).itemsize+ stride = bv.byteStride or size+ raw = np.frombuffer(blob, np.uint8, stride * (a.count - 1) + size, off)+ out = np.lib.stride_tricks.as_strided(raw, (a.count, size), (stride, 1)).copy().view(dt).reshape(a.count, n).astype(float)+ if a.normalized: # KHR_mesh_quantization: normalized integers+ out /= {5122: 32767.0, 5120: 127.0, 5123: 65535.0, 5121: 255.0}[a.componentType]+ return out+++def world(node_idx, parent=np.eye(4)):+ n = g.nodes[node_idx]+ m = np.eye(4)+ if n.matrix:+ m = np.array(n.matrix).reshape(4, 4).T+ else:+ t = np.eye(4); r = np.eye(4); s = np.eye(4)+ if n.translation: t[:3, 3] = n.translation+ if n.rotation:+ x, y, z, w = n.rotation+ r[:3, :3] = [[1 - 2 * (y * y + z * z), 2 * (x * y - z * w), 2 * (x * z + y * w)],+ [2 * (x * y + z * w), 1 - 2 * (x * x + z * z), 2 * (y * z - x * w)],+ [2 * (x * z - y * w), 2 * (y * z + x * w), 1 - 2 * (x * x + y * y)]]+ if n.scale: s[0, 0], s[1, 1], s[2, 2] = n.scale+ m = t @ r @ s+ m = parent @ m+ res = []+ if n.mesh is not None:+ res.append((n.mesh, m))+ for c in n.children or []:+ res += world(c, m)+ return res+++pts = {}+for root in g.scenes[g.scene or 0].nodes:+ for mesh_i, m in world(root):+ for p in g.meshes[mesh_i].primitives:+ v = acc(p.attributes.POSITION).astype(float)+ v = (np.c_[v, np.ones(len(v))] @ m.T)[:, :3] * 1000.0 # mm+ name = g.materials[p.material].name if p.material is not None else "none"+ col = g.materials[p.material].pbrMetallicRoughness.baseColorFactor if p.material is not None else None+ pts.setdefault((name, tuple(round(c, 3) for c in col[:3]) if col else None), []).append(v)++groups = {}+for (name, col), vs in pts.items():+ v = np.vstack(vs)+ groups[name] = dict(colour=col, n=len(v), min=v.min(0).round(3).tolist(), max=v.max(0).round(3).tolist(), pts=v)++# which axis is up? the longest extent of the gold pins is the pin axis+gold = [k for k, d in groups.items() if d["colour"] and d["colour"][0] > 0.4]+body = [k for k, d in groups.items() if k not in gold]+P = groups[gold[0]]["pts"]; B = groups[body[0]]["pts"]+ext = P.max(0) - P.min(0)+up = int(np.argmax(ext))+axes = "XYZ"+# pin cross-section: vertices in the middle of the mating length (well above the insulator), cluster by position+hi = P[:, up].max()+top_of_body = B[:, up].max()+band = P[(P[:, up] > top_of_body + 0.5) & (P[:, up] < hi - 0.05)] # full square section, below the tip chamfer+others = [i for i in range(3) if i != up]+# cluster pins along the longer of the two horizontal axes+long_ax = others[int(np.argmax([ext[i] for i in others]))]+short_ax = [i for i in others if i != long_ax][0]+order = np.sort(band[:, long_ax])+splits = np.where(np.diff(order) > 1.0)[0]+edges = [order[0]] + [order[s + 1] for s in splits]+pins = []+for k, e0 in enumerate(edges):+ e1 = order[splits[k]] if k < len(splits) else order[-1]+ sel = band[(band[:, long_ax] >= e0 - 1e-6) & (band[:, long_ax] <= e1 + 1e-6)]+ pins.append(dict(centre=round(float((sel[:, long_ax].min() + sel[:, long_ax].max()) / 2), 3),+ w_long=round(float(sel[:, long_ax].max() - sel[:, long_ax].min()), 3),+ w_short=round(float(sel[:, short_ax].max() - sel[:, short_ax].min()), 3)))+centres = [p["centre"] for p in pins]+pitch = [round(abs(b - a), 3) for a, b in zip(centres, centres[1:])]++zb0, zb1 = B[:, up].min(), B[:, up].max()+zp0, zp1 = P[:, up].min(), P[:, up].max()+m = dict(+ up_axis=axes[up],+ body_len=round(float(B[:, long_ax].max() - B[:, long_ax].min()), 3),+ body_wid=round(float(B[:, short_ax].max() - B[:, short_ax].min()), 3),+ body_bottom=round(float(zb0), 3), body_top=round(float(zb1), 3),+ insulator_h=round(float(zb1 - zb0), 3),+ pin_bottom=round(float(zp0), 3), pin_top=round(float(zp1), 3),+ pin_total=round(float(zp1 - zp0), 3),+ mating=round(float(zp1 - zb1), 3), tail=round(float(zb0 - zp0), 3),+ pins=pins, pitch=pitch,+)+DS = [ # (what, datasheet nominal, tol, measured key) from 61300411121 rev 003.000 p.1+ ("Pin square", 0.64, 0.15, [p["w_long"] for p in pins] + [p["w_short"] for p in pins]),+ ("Pitch", 2.54, 0.05, pitch),+ ("Total pin length", 11.54, 0.2, [m["pin_total"]]),+ ("Mating length above insulator", 6.0, 0.2, [m["mating"]]),+ ("Tail length below insulator", 3.0, 0.2, [m["tail"]]),+ ("Insulator height", 2.54, 0.15, [m["insulator_h"]]),+ ("Insulator width", 2.54, 0.15, [m["body_wid"]]),+ ("Insulator length L (4 pins)", 10.16, 0.35, [m["body_len"]]),+ ("Pin to pin pl (1 to 4)", 7.62, 0.15, [round(abs(centres[-1] - centres[0]), 3)]),+]+rows = []+for what, nom, tol, vals in DS:+ ok = all(abs(v - nom) <= tol + 1e-6 for v in vals)+ rows.append(dict(dimension=what, datasheet=f"{nom} +-{tol}", model=vals if len(vals) > 1 else vals[0],+ result="pass" if ok else "fail"))+res = dict(model=glb, units="mm", source="Wurth Elektronik 61300411121 datasheet rev 003.000 (2023-01-08), page 1",+ method="vertices of the step2glb GLB per material (insulator, contacts); pin section from the shaft vertices between the insulator top (+0.5 mm) and the tip chamfer",+ measured=m, rows=rows, all_pass=all(r["result"] == "pass" for r in rows))+json.dump(res, open(out, "w"), indent=1)+print(json.dumps(res, indent=1))
verification.jsonadded+127@@ -0,0 +1,127 @@+{+ "schema": "adom/verification@1",+ "part": "61300411121",+ "variants": [],+ "entries": [+ {+ "date": "2026-11-10",+ "by": {+ "name": "Claude, at Noah's request",+ "handle": "claude"+ },+ "status": "verified",+ "title": "Checked against Wurth datasheet 61300411121 rev 003.000: hole pattern, pin 1, and every printed dimension of the 3D model",+ "scope": [+ "symbol",+ "footprint",+ "3d",+ "pins"+ ],+ "variants": [+ "*"+ ],+ "checks": [+ {+ "text": "Datasheet 61300411121 rev 003.000 (2023-01-08), 6 pages, sha256 ce759fb8caee; Article Properties: 4 pins, pl 7.62 mm, L 10.16 mm.",+ "result": "pass"+ },+ {+ "text": "Footprint: 4 plated holes 1.10 mm (datasheet 1.10 +-0.15) at 2.54 mm (2.54 +-0.05), pl 7.62 mm (Pattern Properties 7.62 +-0.1), single row, pad 1 square at the origin, pads along +Y (provenance/footprint-vs-datasheet.json, provenance/evidence/footprint-vs-datasheet.png).",+ "result": "pass"+ },+ {+ "text": "Copper pad 1.80 mm: the datasheet prints the hole only; the pad keeps KiCad's 0.35 mm annular ring from its 1.0 mm drill / 1.7 mm pad header.",+ "result": "note"+ },+ {+ "text": "KiCad 10.0 parses the symbol and footprint (kicad-cli 10.0.6 sym/fp export svg; pcbnew FootprintLoad: 4 pads, 1.8 mm, drill 1.1, pad 1 rect).",+ "result": "pass"+ },+ {+ "text": "Pins: 4 passive contacts numbered 1 to 4; the datasheet labels the ends 1 and End and prints no signal names; symbol pins equal page.json pins (Pin_1 to Pin_4, KiCad naming).",+ "result": "pass"+ },+ {+ "text": "3D model (KiCad 10.0 PinHeader_1x04_P2.54mm_Vertical.step, byte-identical): pins 0.64 square (0.64 +-0.15), pitch 2.54, total 11.54 (11.54 +-0.2), mating 6.0 (6.0 +-0.2), tail 3.0 (3.0 +-0.2), insulator 2.54 high and wide (+-0.15), L 10.16 (10.16 +-0.35): all inside the drawing tolerances (provenance/model-vs-datasheet.json).",+ "result": "pass"+ },+ {+ "text": "Pose: Z up, insulator seated on z = 0, tails to z = -3.0, pin 1 contact on pad 1 at the origin, body centred on the pad pattern, footprint binding identity (step2glb features; hero generator align OK, offset 0.0 mm).",+ "result": "pass"+ },+ {+ "text": "Pin-1 orientation chain: footprint pad 1 square at the origin with the silkscreen corner mark; model contact 1 at the origin; header symmetric, so contact 1 is the end on pad 1.",+ "result": "pass"+ },+ {+ "text": "Etched copy: virtual MPN mark 61300 / 411121 on the pin-1 flat of the -X wall, flat, light, inside the band (adom-aiflow-etch check WARN only on the 320 px widget size).",+ "result": "pass"+ },+ {+ "text": "Fusion/EAGLE .lbr: adom-lbr validate OK, lint 0/0; MPN, manufacturer, Mouser, DigiKey, LCSC and Adom Wiki attributes present.",+ "result": "pass"+ }+ ],+ "evidence": [+ {+ "label": "datasheet",+ "href": "docs/61300411121-datasheet.pdf"+ },+ {+ "label": "datasheet p.1",+ "href": "docs/figures/61300411121-ds-p1.png"+ },+ {+ "label": "footprint vs datasheet",+ "href": "provenance/evidence/footprint-vs-datasheet.png"+ },+ {+ "label": "model views",+ "href": "provenance/evidence/model-views.png"+ },+ {+ "label": "provenance",+ "href": "provenance/provenance.json"+ }+ ],+ "files": {+ "61300411121.kicad_sym": "2bc7fb8efd75861b850fb237ac4ae63c66345226671074855403c3ffd96be1e8",+ "61300411121.kicad_mod": "0aee3b319aae2fd7e3b0a4d29d5a05170edccfd6dc6a76a3c61a8394a3489d6e",+ "61300411121.step": "a74079b8d06bda78847623b39ee1855ffd1d9a8c1e896b349e4f1dc2056d44d9",+ "61300411121-etched.step": "696be90475532efa33b75f335b21d3ec370b3d0ea7473b92c823c08b996b3567",+ "61300411121-hero.glb": "6a67a6407e529c4d725442b62f12f6d5a23a4590b1c5371e9824ecbb474ea58e",+ "docs/61300411121-datasheet.pdf": "ce759fb8caee2fd0c3167f6925010f6703aa4f939ded51aae7ead334c38c0d7d"+ }+ },+ {+ "date": "2026-11-10",+ "by": {+ "name": "Claude, at Noah's request",+ "handle": "claude"+ },+ "status": "open",+ "title": "3D model is KiCad's generic 1x04 header, not Wurth Elektronik's own CAD",+ "scope": [+ "3d"+ ],+ "variants": [+ "*"+ ],+ "checks": [+ {+ "text": "Wurth's STEP for 61300411121 was not obtained (we-online.com refuses automated downloads). The KiCad model fits every printed dimension; insulator details the drawing does not dimension (chamfers, notches) may differ from the real part. Compare with Wurth's model when someone downloads it through a browser.",+ "result": "note"+ }+ ],+ "evidence": [+ {+ "label": "provenance",+ "href": "provenance/provenance.json"+ }+ ],+ "files": {+ "61300411121.step": "a74079b8d06bda78847623b39ee1855ffd1d9a8c1e896b349e4f1dc2056d44d9"+ }+ }+ ]+}