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.46.0: heatsink vias ride inside the footprint on every lane; import-kicad HINT names the vias under the exposed pad or says they are missing (John, 2026-09-19)
5 files changed
+42−3
Cargo.toml+1−1@@ -1,6 +1,6 @@ [package] name = "adom-lbr"-version = "2.45.1"+version = "2.46.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+11@@ -67,6 +67,17 @@ read from `distributor_links.<dist>` as a string or an object with `pn` / `part_ 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>`. +**Heatsink vias ride inside the footprint (2.46.0).** A component page that defines heatsink+vias (`artwork/<MPN>-heatsink-via.json`: 0.3 mm drill, 0.8 mm pitch, 0.15 mm ring, tented)+carries them in the KiCad footprint as plated `thru_hole` pads numbered like the exposed pad+(KiCad `pad_prop_heatsink`; adom-footprint create `heatsinkVias` writes them, or the page's+build does). adom-lbr keeps them on every lane without any extra flag: `import-kicad` reads the+drill, the Altium PcbLib gets multi-layer pads with holes, `generate` writes EAGLE `<pad+drill=...>` with the same name (Fusion joins them to the exposed pad's net), so a user never+redraws thermal vias per tool. `import-kicad` prints a HINT naming the vias it found, or that+the largest SMD pad has none (John, 2026-09-19). The hero GLB shows the same vias as the+`Adom.HeatsinkVias` layer (65 % transparent copper through a 1.6 mm board).+ **Altium component Description (2.45.1).** The SchLib header's `ComponentDescription` (what Altium shows in Properties > General > Description and in the SCH Library panel list) is filled from the symbol's Description property; it is a different field from the Description
VERSION+1−1@@ -1 +1 @@-2.45.1+2.46.0
package.json+1−1@@ -1,6 +1,6 @@ { "slug": "adom-lbr",- "version": "2.45.1",+ "version": "2.46.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+28@@ -1938,6 +1938,33 @@ fn page_brief(path: &std::path::Path) -> Option<String> { /// 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.+/// Heatsink (thermal) vias travel INSIDE the footprint as plated through-hole pads that+/// carry the exposed pad's own number (0.3 mm drill, 0.8 mm pitch, 0.15 mm ring, tented+/// is the wiki's standard rule; adom-footprint create `heatsinkVias` writes them). Every+/// lane keeps them: KiCad as the pads themselves, Altium as multi-layer pads with holes,+/// EAGLE/Fusion as <pad drill=...> - so a user never redraws them per tool (John,+/// 2026-09-19). Say when a large SMD pad has none.+fn heatsink_hint(fp_txt: &str, mpn: &str) {+ let pad_re = regex_lite::Regex::new(r#"\(pad\s+"([^"]+)"\s+(smd|thru_hole|np_thru_hole)\b[^\n]*?\(size\s+([-\d.]+)\s+([-\d.]+)\)"#).unwrap();+ let mut smd_big: Vec<(String, f64)> = Vec::new();+ let mut th: std::collections::HashMap<String, usize> = std::collections::HashMap::new();+ for c in pad_re.captures_iter(fp_txt) {+ let (name, kind) = (c[1].to_string(), c[2].to_string());+ let area = c[3].parse::<f64>().unwrap_or(0.0) * c[4].parse::<f64>().unwrap_or(0.0);+ if kind == "smd" { smd_big.push((name, area)); } else if kind == "thru_hole" { *th.entry(name).or_insert(0) += 1; }+ }+ let Some(max_area) = smd_big.iter().map(|(_, a)| *a).fold(None, |m: Option<f64>, a| Some(m.map_or(a, |x| x.max(a)))) else { return };+ let median = { let mut v: Vec<f64> = smd_big.iter().map(|(_, a)| *a).collect(); v.sort_by(|a, b| a.partial_cmp(b).unwrap()); v[v.len() / 2] };+ for (name, area) in &smd_big {+ if *area >= 1.0 && *area >= 3.0 * median && *area == max_area {+ match th.get(name) {+ Some(n) => println!("HINT: {mpn} exposed pad {name} carries {n} heatsink via(s) as plated holes with its own number; they reach Altium (multi-layer pads) and Fusion (<pad drill>) unchanged."),+ None => println!("HINT: {mpn} exposed pad {name} ({area:.1} mm2) has NO heatsink vias in the footprint. A thermal pad without vias into the ground plane is a part that overheats; add them once in the KiCad footprint as thru_hole pads numbered {name} (adom-footprint create `heatsinkVias`, or the wiki page's artwork/<MPN>-heatsink-via.json rule: 0.3 mm drill, 0.8 mm pitch, 0.15 mm ring, tented) and every lane carries them."),+ }+ }+ }+}+ 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();@@ -3616,6 +3643,7 @@ The geometry is fine but a BOM cannot order this part - pass --part-metadata or let sym_txt = read_or_exit(&sym); let fp_txt = read_or_exit(&fp); sourcing_hint(&sym_txt, &mpn);+ heatsink_hint(&fp_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(|| {