# npnp
<p align="center">
<img src="assets/npnp.png" alt="npnp app logo" width="360">
</p>
<p align="center">
<a href="Cargo.toml"><img src="https://img.shields.io/badge/version-0.1.3-e05d44?style=flat-square" alt="version 0.1.3"></a>
<a href="LICENSE.md"><img src="https://img.shields.io/badge/license-PolyForm--NC%201.0-f08c5a?style=flat-square" alt="license PolyForm NC 1.0"></a>
<a href=".github/workflows/windows-release.yml"><img src="https://img.shields.io/badge/platform-Windows-2ea44f?style=flat-square" alt="platform Windows"></a>
<a href="https://www.rust-lang.org/"><img src="https://img.shields.io/badge/rust-edition%202024-f28d1a?style=flat-square" alt="rust edition 2024"></a>
</p>
Normalize Pin Net Pad (`npnp`) is an LCEDA/EasyEDA downloader and Altium library exporter written in pure Rust.
`npnp` searches LCEDA/LCSC components, downloads upstream EasyEDA source data and 3D models, and exports Altium-compatible schematic and PCB footprint libraries.
## Features
- Search LCEDA/LCSC components by keyword, part name, or LCSC ID.
- Download 3D models as STEP or OBJ/MTL.
- Export raw EasyEDA symbol and footprint JSON for inspection.
- Export Altium schematic libraries (`.SchLib`).
- Export Altium PCB footprint libraries (`.PcbLib`).
- Embed STEP models into PCB libraries when upstream STEP data is available.
- Batch export many LCSC IDs from a text file.
- Export either one file per component or merged library pairs.
- Append new components into an existing merged `npnp` library pair without duplicating existing LCSC IDs.
- Show live batch progress with counts, active workers, elapsed time, and the most recently processed component.
- Resume non-merged batch exports with checkpoint files.
- Retry transient LCEDA/EasyEDA request failures automatically.
## Requirements
- Rust toolchain for building from source.
- Network access to LCEDA/EasyEDA APIs when searching, downloading, or exporting.
- Altium Designer is recommended for final visual verification of generated `.SchLib` and `.PcbLib` files.
Install Rust from <https://rustup.rs/> if you do not already have it.
## Build From Source
Clone the repository:
```powershell
git clone https://github.com/linkyourbin/npnp.git npnp
cd npnp
```
Build a debug binary:
```powershell
cargo build
```
Build an optimized release binary:
```powershell
cargo build --release
```
Run the test suite:
```powershell
cargo test
```
Run formatting before publishing or sending a pull request:
```powershell
cargo fmt
```
Run a compile check without producing a release binary:
```powershell
cargo check
```
## Run From Source
When running through Cargo, put `--` before `npnp` arguments:
```powershell
cargo run --quiet --bin npnp -- --help
```
Show ready-to-run examples:
```powershell
cargo run --quiet --bin npnp -- --prompt
```
Show the package version:
```powershell
cargo run --quiet --bin npnp -- --version
```
Run any command from source:
```powershell
cargo run --quiet --bin npnp -- <COMMAND> [OPTIONS]
```
Example source-run search:
```powershell
cargo run --quiet --bin npnp -- search C2040 --limit 5
```
## Run As A Binary
After `cargo build --release`, the Windows binary is:
```powershell
.\target\release\npnp.exe
```
Show help from the built binary:
```powershell
.\target\release\npnp.exe --help
```
Show ready-to-run command examples:
```powershell
.\target\release\npnp.exe --prompt
```
Show the version:
```powershell
.\target\release\npnp.exe --version
```
Run a command with the built binary:
```powershell
.\target\release\npnp.exe <COMMAND> [OPTIONS]
```
If `npnp.exe` is on your `PATH`, use it directly:
```powershell
npnp --help
```
```powershell
npnp --prompt
```
```powershell
npnp search C2040 --limit 5
```
## Install Locally
Install the current checkout as a local Cargo binary:
```powershell
cargo install --path .
```
Verify the installed binary:
```powershell
npnp --version
```
Uninstall the local Cargo-installed binary:
```powershell
cargo uninstall npnp
```
The tool is published to crates.io. Users with a Rust development environment can install it with:
```powershell
cargo install npnp
```
## Command Overview
Top-level help:
```powershell
npnp --help
```
Ready-to-run examples:
```powershell
npnp --prompt
```
Help for a specific command:
```powershell
npnp <COMMAND> --help
```
Available commands:
- `search`
- `download-step`
- `download-obj`
- `export-source`
- `export-schlib`
- `export-pcblib`
- `bundle`
- `batch`
## Command: `search`
Search components by keyword, LCSC ID, manufacturer part, or broad text.
Usage:
```powershell
npnp search <KEYWORD> [--limit <LIMIT>]
```
Examples:
```powershell
npnp search C2040 --limit 5
```
```powershell
npnp search RP2040 --limit 10
```
```powershell
npnp search TYPE-C --limit 20
```
Options:
- `--limit <LIMIT>` controls how many search rows are printed. Default: `20`.
Output includes the search result index, display name, LCSC ID when available, manufacturer, and whether a 3D model is listed.
## Search Result Indexes
Most export/download commands accept `--index <INDEX>`. The default is `--index 1`.
Use this workflow for broad searches:
```powershell
npnp search TYPE-C --limit 20
```
Then export the exact row you want:
```powershell
npnp export-schlib TYPE-C --index 3 --output schlib --force
```
When `<KEYWORD>` is an exact LCSC ID like `C2040` and `--index` is left at `1`, `npnp` prefers the search result whose LCSC ID exactly matches the keyword. Explicit non-default indexes still select the requested search row.
## Command: `download-step`
Download a STEP file for the selected component result.
Usage:
```powershell
npnp download-step <KEYWORD> [--index <INDEX>] [--output <DIR>] [--force]
```
Examples:
```powershell
npnp download-step C2040 --output step --force
```
```powershell
npnp download-step RP2040 --index 1 --output models\step --force
```
Options:
- `--index <INDEX>` selects the search result row. Default: `1`.
- `--output <DIR>` sets the output directory. Default: `step`.
- `--force` overwrites an existing output file.
Typical output layout:
```text
step/
<footprint-or-component-name>.step
```
## Command: `download-obj`
Download OBJ and MTL files for the selected component result.
Usage:
```powershell
npnp download-obj <KEYWORD> [--index <INDEX>] [--output <DIR>] [--force]
```
Examples:
```powershell
npnp download-obj C2040 --output obj --force
```
```powershell
npnp download-obj RP2040 --index 1 --output models\obj --force
```
Options:
- `--index <INDEX>` selects the search result row. Default: `1`.
- `--output <DIR>` sets the output directory. Default: `obj`.
- `--force` overwrites existing OBJ/MTL files.
Typical output layout:
```text
obj/
<component-name>.obj
<component-name>.mtl
```
## Command: `export-source`
Export raw EasyEDA symbol and footprint source JSON files only.
Use this command when you want to inspect upstream payloads before generating Altium libraries.
Usage:
```powershell
npnp export-source <KEYWORD> [--index <INDEX>] [--output <DIR>] [--force]
```
Examples:
```powershell
npnp export-source C2040 --output easyeda_src --force
```
```powershell
npnp export-source RP2040 --index 1 --output debug\easyeda_src --force
```
Options:
- `--index <INDEX>` selects the search result row. Default: `1`.
- `--output <DIR>` sets the output directory. Default: `easyeda_src`.
- `--force` overwrites existing source JSON files.
Typical output layout:
```text
easyeda_src/
<component-name>_symbol_easyeda.json
<component-name>_footprint_easyeda.json
```
## Command: `export-schlib`
Export a pure Rust Altium schematic library (`.SchLib`).
Usage:
```powershell
npnp export-schlib <KEYWORD> [--index <INDEX>] [--output <DIR>] [--force]
```
Examples:
```powershell
npnp export-schlib C2040 --output schlib --force
```
```powershell
npnp export-schlib RP2040 --index 1 --output out\schlib --force
```
Options:
- `--index <INDEX>` selects the search result row. Default: `1`.
- `--output <DIR>` sets the output directory. Default: `schlib`.
- `--force` overwrites an existing `.SchLib` file.
Current schematic export includes:
- Symbol body and graphics.
- Pins.
- Multipart symbols when present in source data.
- Metadata records such as `Designator`, `Comment`, `Description`, and parameters.
- PCB footprint implementation links when footprint data is available.
Typical output layout:
```text
schlib/
<component-name>.SchLib
```
## Command: `export-pcblib`
Export a pure Rust Altium PCB footprint library (`.PcbLib`).
Usage:
```powershell
npnp export-pcblib <KEYWORD> [--index <INDEX>] [--output <DIR>] [--force]
```
Examples:
```powershell
npnp export-pcblib C2040 --output pcblib --force
```
```powershell
npnp export-pcblib RP2040 --index 1 --output out\pcblib --force
```
Options:
- `--index <INDEX>` selects the search result row. Default: `1`.
- `--output <DIR>` sets the output directory. Default: `pcblib`.
- `--force` overwrites an existing `.PcbLib` file.
Current PCB export includes:
- Pads.
- Tracks, arcs, regions, and footprint primitives mapped from EasyEDA data.
- 3D STEP model embedding when a usable upstream STEP model exists.
- Empty 3D body output when no usable STEP model is available.
Typical output layout:
```text
pcblib/
<component-name>.PcbLib
```
## Command: `bundle`
Export a source bundle for one selected component.
The bundle command writes EasyEDA source JSON files, a STEP file when available, and a manifest JSON file that records the selected component and generated artifacts.
Usage:
```powershell
npnp bundle <KEYWORD> [--index <INDEX>] [--output <DIR>] [--force]
```
Examples:
```powershell
npnp bundle C2040 --output bundle --force
```
```powershell
npnp bundle RP2040 --index 1 --output out\bundle --force
```
Options:
- `--index <INDEX>` selects the search result row. Default: `1`.
- `--output <DIR>` sets the output directory. Default: `bundle`.
- `--force` overwrites existing bundle files.
Typical output layout:
```text
bundle/
<component-name>_symbol_easyeda.json
<component-name>_footprint_easyeda.json
<footprint-or-component-name>.step
<component-name>_bundle.json
```
The STEP file appears only when the selected component has an upstream 3D model.
## Command: `batch`
Batch export Altium libraries from a text file containing LCSC IDs.
Usage:
```powershell
npnp batch --input <FILE> [--output <DIR>] [--schlib] [--pcblib] [--full] [--merge] [--append] [--library-name <NAME>] [--parallel <N>] [--continue-on-error] [--force]
```
Short input flag:
```powershell
npnp batch -i ids.txt --output batch_out --full --force
```
The input parser extracts IDs in the form `C<number>` from arbitrary text. It accepts lowercase IDs like `c2040`, deduplicates repeated IDs, and preserves first-seen order.
Example `ids.txt`:
```text
C2040
C12074
C569043
```
Export both schematic and PCB libraries, one file per component:
```powershell
npnp batch --input ids.txt --output batch_out --full --parallel 4 --continue-on-error --force
```
Export only schematic libraries:
```powershell
npnp batch --input ids.txt --output batch_schlib --schlib --parallel 4 --continue-on-error --force
```
Export only PCB libraries:
```powershell
npnp batch --input ids.txt --output batch_pcblib --pcblib --parallel 4 --continue-on-error --force
```
Export both targets using explicit flags instead of `--full`:
```powershell
npnp batch --input ids.txt --output batch_out --schlib --pcblib --parallel 4 --continue-on-error --force
```
Write one merged `.SchLib` and one merged `.PcbLib`:
```powershell
npnp batch --input ids.txt --output merged_out --merge --library-name MyLib --full --continue-on-error --force
```
Write only a merged schematic library:
```powershell
npnp batch --input ids.txt --output merged_schlib --merge --library-name MySchLib --schlib --continue-on-error --force
```
Write only a merged PCB library:
```powershell
npnp batch --input ids.txt --output merged_pcblib --merge --library-name MyPcbLib --pcblib --continue-on-error --force
```
Append only the missing parts into an existing merged library pair created by `npnp`:
```powershell
npnp batch --input new_ids.txt --output merged_out --merge --append --library-name MyLib --full --continue-on-error
```
Batch options:
- `--input <FILE>` or `-i <FILE>` is required.
- `--output <DIR>` sets the output directory. Default: `batch`.
- `--schlib` exports schematic libraries.
- `--pcblib` exports PCB libraries.
- `--full` exports both schematic and PCB libraries.
- `--merge` writes one merged library per selected target instead of one file per component.
- `--append` adds only missing components into an existing merged `npnp` library pair and skips duplicate LCSC IDs.
- `--library-name <NAME>` sets the merged output filename prefix.
- `--parallel <N>` sets concurrent jobs for non-merged batch export. Default: `4`.
- `--continue-on-error` keeps processing remaining IDs if one ID fails.
- `--force` ignores checkpoint skips and overwrites existing outputs.
Non-merged batch output layout:
```text
batch_out/
.checkpoint
schlib/
<component-a>.SchLib
<component-b>.SchLib
pcblib/
<component-a>.PcbLib
<component-b>.PcbLib
```
Merged batch output layout:
```text
merged_out/
MyLib.SchLib
MyLib.PcbLib
```
Checkpoint behavior:
- Non-merged batch exports create `.checkpoint` in the output directory.
- Completed IDs are written to `.checkpoint`.
- Later runs skip completed IDs unless `--force` is used.
- Merged batch exports rebuild the merged output and do not use the non-merged checkpoint layout.
- Merged `--append` runs reuse the existing merged `npnp` libraries, skip duplicate LCSC IDs, and write back one updated merged pair.
## Recommended Workflows
Exact LCSC ID workflow:
```powershell
npnp search C2040 --limit 5
npnp export-schlib C2040 --output out\schlib --force
npnp export-pcblib C2040 --output out\pcblib --force
```
Broad keyword workflow:
```powershell
npnp search TYPE-C --limit 20
npnp export-schlib TYPE-C --index 3 --output out\schlib --force
npnp export-pcblib TYPE-C --index 3 --output out\pcblib --force
```
Source inspection workflow:
```powershell
npnp export-source C2040 --output inspect\easyeda --force
npnp bundle C2040 --output inspect\bundle --force
```
Batch verification workflow:
```powershell
npnp batch --input ids.txt --output generated\check --full --force --continue-on-error
```
Merged library verification workflow:
```powershell
npnp batch --input ids.txt --output generated\merged_check --merge --library-name MyLib --full --force --continue-on-error
```
Merged append workflow:
```powershell
npnp batch --input more_ids.txt --output generated\merged_check --merge --append --library-name MyLib --full --continue-on-error
```
## Merge Output Screenshots
The `imgs/` directory stores screenshots generated from merged-library output produced by `npnp`.
These examples come from a merged export workflow such as:
```powershell
npnp batch --input ids.txt --output generated\merged_check --merge --library-name MyLib --full --force --continue-on-error
```
Overview:

Schematic library screenshots:
<p align="center">
<img src="imgs/sch_01.png" alt="Merged schematic screenshot 1" width="32%">
<img src="imgs/sch_02.png" alt="Merged schematic screenshot 2" width="32%">
<img src="imgs/sch_03.png" alt="Merged schematic screenshot 3" width="32%">
</p>
PCB library screenshots:
<p align="center">
<img src="imgs/pcb_01.png" alt="Merged PCB screenshot 1" width="32%">
<img src="imgs/pcb_02.png" alt="Merged PCB screenshot 2" width="32%">
<img src="imgs/pcb_03.png" alt="Merged PCB screenshot 3" width="32%">
</p>
## License
`npnp` now uses the closest standard license to the current project intent: `PolyForm-Noncommercial-1.0.0` in `LICENSE.md`.
- Non-commercial use, research, evaluation, and personal experimentation are allowed.
- Commercial use, paid redistribution, paid service use, or use inside a commercial workflow requires separate permission from the author.
- If you redistribute the project, keep the license text and required notices.
- The PolyForm license does not legally require pull requests. This project still asks anyone publishing modified versions to mention the original `npnp` project and, when possible, send changes back as a pull request.
- This is source-available and non-commercial, not an OSI open-source license.
## Notes On Generated Files
- Output filenames are sanitized for Windows-unsafe characters.
- Existing files are preserved unless `--force` is passed.
- STEP embedding depends on upstream LCEDA/EasyEDA model availability and payload quality.
- If a footprint opens without a 3D body, the upstream STEP model may be missing, invalid, or not linked from the selected component.
- The generated libraries should be opened in Altium Designer for final visual verification before production use.
## Troubleshooting
Batch terminal progress:
- `batch` shows a live progress line with `ok`, `skip`, `fail`, `active`, elapsed time, and the last processed component.
- `SKIP ...` and `FAILED ...` lines are printed as separate events during the run.
- Merged and append runs print extra stage lines when they load existing libraries or write the final merged outputs.
No valid IDs found in batch input:
```powershell
npnp batch --input ids.txt --output batch_out --full
```
Check that `ids.txt` contains values like:
```text
C2040
C12074
C569043
```
Wrong component exported from a broad keyword:
```powershell
npnp search <KEYWORD> --limit 20
```
Then pass the desired result row:
```powershell
npnp export-schlib <KEYWORD> --index <ROW> --output schlib --force
```
Existing output was not overwritten:
```powershell
npnp export-pcblib C2040 --output pcblib --force
```
Resume or rerun a non-merged batch export:
```powershell
npnp batch --input ids.txt --output batch_out --full --continue-on-error
```
Force a full non-merged batch rebuild:
```powershell
npnp batch --input ids.txt --output batch_out --full --force --continue-on-error
```
Network/API issues:
- Confirm that the machine can reach LCEDA/EasyEDA APIs.
- Retry later if LCEDA/EasyEDA is temporarily unavailable.
- `npnp` automatically retries transient request failures such as timeouts, connection failures, rate limiting, and server-side `5xx` responses.