app
Adom Library
Public Made by Adomby adom
adom-lbr — the EDA library translator. Bring a component in from any supported EDA tool and convert it to any other (KiCad ⇄ Altium ⇄ EAGLE/Fusion) through one canonical adom-lbr JSON — symbol + footprint + 3D + pin↔pad map. Altium is written natively (no Altium needed). Includes the adom-lbr Manager: browse wiki components and view symbol/footprint/3D + the per-EDA layer stackup.
← Commit history
2.45.0: orderable identity on every lane - Supplier N links + Manufacturer Part Number for Altium, ADOM_WIKI + DATASHEET attributes for Fusion, distributor part numbers read from the wiki page's {part} shape, hub manufacturer from the symbol, HINT when MPN/Mouser/DigiKey/LCSC/Adom Wiki are missing (John, 2026-09-19)
6 files changed
+74−6
Cargo.toml+1−1@@ -1,6 +1,6 @@ [package] name = "adom-lbr"-version = "2.44.0"+version = "2.45.0" edition = "2021" description = "adom-lbr generator / EDA translator: the canonical adom-lbr JSON is the hub, with native converters to Altium (.SchLib/.PcbLib/.IntLib), EAGLE/Fusion (.lbr), and KiCad. Altium output is written natively — no Altium needed at conversion time."
SKILL.md+13@@ -54,6 +54,19 @@ keeps one footprint PER PART even when land patterns match, so each part carries own STEP body and its symbol links its own footprint name (the ToF trio VL53L5CX / L7CX / L8CX share a pattern but not a body). +**Orderable identity on every lane (2.45.0).** A KiCad symbol made by adom-symbol 1.2.4++carries MPN / Manufacturer / Datasheet / Description / Mouser / DigiKey / LCSC / "Adom Wiki"+as properties. `import-kicad` keeps every one of them as an Altium parameter, adds+`Supplier N` / `Supplier Part Number N` pairs (Mouser, Digi-Key, LCSC) for ActiveBOM and+`Manufacturer Part Number`, and fills the hub's `manufacturer`; it prints a HINT naming any+that are missing. `generate --part-metadata page.json` writes the EAGLE attributes MPN,+MANUFACTURER, DATASHEET, ADOM_WIKI (https://wiki.adom.inc/<owner>/<slug>, from+component.wiki_url or the page slug), MOUSER_PN, DIGIKEY_PN, LCSC_PN; distributor numbers are+read from `distributor_links.<dist>` as a string or an object with `pn` / `part_number` /+`part` / `sku`. Why (John, 2026-09-19): the BOM and CPL that go to the fab with the gerbers+are built from these fields, and the wiki link is how the next EE finds the reviewed data.+One lookup fills the numbers: `adom-parts-search search <MPN>`.+ **Fusion/EAGLE symbols, same rule (2.44.0).** `generate` carries each `.kicad_sym` polyline's stroke width into the `.lbr`: a stroke at or under 0.2 mm (the chip-thumbnailer outline is 0.167 mm) becomes a 0.0254 mm hairline wire, which Fusion draws one pixel wide at any zoom;
VERSION+1−1@@ -1 +1 @@-2.44.0+2.45.0
crates/altium-codec/src/kicad.rs+24−1@@ -595,10 +595,33 @@ pub fn import_kicad_with_pin_map( } } + // The hub's identity comes from the symbol's own sourcing properties when it has+ // them: the orderable MPN (VL53L5CXV0GC/1, not the family name VL53L5CX) and the+ // manufacturer. The caller's --mpn stays the library name.+ let prop = |n: &str| -> Option<String> { symbol.parameters.iter().find(|p| p.name == n).map(|p| p.value.clone()).filter(|v| !v.trim().is_empty()) };+ let manufacturer = prop("Manufacturer").unwrap_or_default();+ let supplier_vals: Vec<(&str, Option<String>)> = [("Mouser", "Mouser"), ("DigiKey", "Digi-Key"), ("LCSC", "LCSC")]+ .into_iter().map(|(name, supplier)| (supplier, prop(name))).collect();+ let mpn_prop = prop("MPN");+ // Altium's ActiveBOM / supplier links read numbered Supplier pairs; add them+ // beside the plain Mouser / DigiKey / LCSC parameters the KiCad symbol carries.+ let mut n = 0;+ for (supplier, val) in supplier_vals {+ if let Some(v) = val {+ n += 1;+ symbol.parameters.push(crate::model::Parameter { name: format!("Supplier {n}"), value: supplier.to_string(), visible: false });+ symbol.parameters.push(crate::model::Parameter { name: format!("Supplier Part Number {n}"), value: v, visible: false });+ }+ }+ if let Some(v) = mpn_prop {+ if !symbol.parameters.iter().any(|p| p.name == "Manufacturer Part Number") {+ symbol.parameters.push(crate::model::Parameter { name: "Manufacturer Part Number".into(), value: v, visible: false });+ }+ } Ok((AdomLbrPart { schema_version: 2, mpn: mpn.to_string(),- manufacturer: String::new(),+ manufacturer, package: String::new(), value: String::new(), category: String::new(),
package.json+1−1@@ -1,6 +1,6 @@ { "slug": "adom-lbr",- "version": "2.44.0",+ "version": "2.45.0", "type": "app", "description": "adom-lbr \u2014 the EDA library translator. Bring a component in from any supported EDA tool and convert it to any other (KiCad \u21c4 Altium \u21c4 EAGLE/Fusion) through one canonical adom-lbr JSON \u2014 symbol + footprint + 3D + pin\u2194pad map. Altium is written natively (no Altium needed). Includes the adom-lbr Manager: browse wiki components and view symbol/footprint/3D + the per-EDA layer stackup.", "dependencies": {},
src/main.rs+34−2@@ -1926,9 +1926,28 @@ fn page_brief(path: &std::path::Path) -> Option<String> { /// Accepts a wiki component `page.json` (fields under `component`) or a bare JSON /// object with the same keys. Distributor part numbers may be written either flat /// (`"mouser_pn": "584-..."`) or under `distributor_links` as a string or as an-/// object carrying `pn` / `part_number`, because both shapes are already in use.+/// object carrying `pn` / `part_number` / `part` / `sku` (the wiki component pages+/// write `part`), because all of those shapes are in use. /// An absent or unreadable file is not an error - a part with no metadata still /// generates, it just generates without attributes, exactly as before.+/// Every EE attaches the orderable part numbers to a library part before it reaches a+/// design: the manufacturer part number and the Mouser, DigiKey and LCSC/JLCPCB numbers+/// are what the BOM and CPL carry to the fab with the gerbers (John, 2026-09-19). A+/// KiCad symbol carries them as properties (MPN, Manufacturer, Mouser, DigiKey, LCSC;+/// adom-symbol writes them from `mpn` + `distributors` in its create JSON); import-kicad+/// turns them into Altium parameters (plus Supplier N / Supplier Part Number N pairs)+/// and generate writes them as EAGLE attributes. Say so when any are missing, and say+/// where to get them: `adom-parts-search search <MPN>` looks all three up at once.+fn sourcing_hint(sym_txt: &str, mpn: &str) {+ let has = |n: &str| sym_txt.contains(&format!("(property \"{n}\""));+ let missing: Vec<&str> = ["MPN", "Manufacturer", "Datasheet", "Description", "Mouser", "DigiKey", "LCSC", "Adom Wiki"].into_iter().filter(|n| !has(n)).collect();+ if missing.is_empty() {+ println!("HINT: identity complete (MPN, Manufacturer, Datasheet, Description, Mouser, DigiKey, LCSC, Adom Wiki) - they become Altium parameters + Supplier links and EAGLE attributes.");+ } else {+ println!("HINT: {mpn} symbol has no {} property. A part without its MPN and Mouser/DigiKey/LCSC numbers cannot be ordered from the BOM/CPL the fab gets with the gerbers. Look them up with `adom-parts-search search {mpn}` and put them in the symbol (adom-symbol create: `mpn` + `distributors` in the create JSON) or the wiki page.json (component.distributor_links) before converting; LCSC may honestly be absent (say so on the page). The Adom Wiki property is the link to the part's component page (https://wiki.adom.inc/<owner>/<slug>), the one place an EE goes for the reviewed symbol, footprint, 3D, datasheet and provenance.", missing.join(" / "));+ }+}+ fn part_attributes(path: &std::path::Path) -> Vec<(String, String)> { let Ok(raw) = fs::read_to_string(path) else { return Vec::new() }; let Ok(doc) = serde_json::from_str::<serde_json::Value>(&raw) else { return Vec::new() };@@ -1939,12 +1958,24 @@ fn part_attributes(path: &std::path::Path) -> Vec<(String, String)> { let mut out = Vec::new(); if let Some(v) = clean(c.get("mpn")) { out.push(("MPN".to_string(), v)); } if let Some(v) = clean(c.get("manufacturer")) { out.push(("MANUFACTURER".to_string(), v)); }+ // The datasheet and the Adom wiki page ride along as attributes too: the wiki page is+ // the one place that holds the reviewed symbol/footprint/3D/datasheet/provenance for+ // the part, so every tool carries the link back to it (John, 2026-09-19).+ if let Some(v) = clean(c.get("datasheet")).or_else(|| clean(c.get("datasheet_url"))).or_else(|| clean(doc.get("datasheet"))) {+ out.push(("DATASHEET".to_string(), v));+ }+ let wiki = clean(c.get("wiki_url")).or_else(|| clean(doc.get("wiki_url"))).or_else(|| clean(doc.get("url"))).or_else(|| {+ let slug = clean(doc.get("slug"))?;+ let owner = clean(doc.get("owner")).or_else(|| clean(doc.get("org"))).unwrap_or_else(|| "adom".to_string());+ Some(format!("https://wiki.adom.inc/{owner}/{slug}"))+ });+ if let Some(v) = wiki { out.push(("ADOM_WIKI".to_string(), v)); } let links = c.get("distributor_links"); for (key, attr) in [("mouser", "MOUSER_PN"), ("digikey", "DIGIKEY_PN"), ("lcsc", "LCSC_PN")] { let flat = clean(c.get(&format!("{key}_pn"))); let nested = links.and_then(|d| d.get(key)).and_then(|e| match e { serde_json::Value::String(t) => Some(serde_json::Value::String(t.clone())),- other => other.get("pn").or_else(|| other.get("part_number")).cloned(),+ other => other.get("pn").or_else(|| other.get("part_number")).or_else(|| other.get("part")).or_else(|| other.get("sku")).cloned(), }); if let Some(v) = flat.or_else(|| clean(nested.as_ref())) { out.push((attr.to_string(), v));@@ -3584,6 +3615,7 @@ The geometry is fine but a BOM cannot order this part - pass --part-metadata or Commands::ImportKicad { sym, fp, mpn, out, pin_map } => { let sym_txt = read_or_exit(&sym); let fp_txt = read_or_exit(&fp);+ sourcing_hint(&sym_txt, &mpn); // Same pin-map convention as generate: explicit --pin-map wins, else // a pinmap.json sidecar beside the symbol just works. let pin_map_path = pin_map.or_else(|| {