proxdex
The librarian for making Pokémon proxies. proxdex keeps every card's assets in
a predictable place keyed by its set + collector number (ex3-90), tracks
which pipeline stage each card has reached, corrects thin card frames, and
records what you've actually printed — so a growing collection stays easy to
search, and you never reprint a card you already have.
It uses cardbleed (border extension) and Upscayl (upscaling), and imposes the print sheet itself — so it owns the whole path to paper.
Think of it as author a master, then reproduce it: the four card stages
produce a device-independent, trim-size master (what the card should look
like); the sheet step reproduces it faithfully on a specific printer + medium
(colour-correct + add bleed outside the trim).
Pipeline
Each card's stored file is the actual trim-size card — no bleed. Four stages, one file per stage:
| # | stage | produced by | command |
|---|---|---|---|
| 1 | original |
downloaded from scrydex | search / fetch |
| 2 | bordered |
thin frame expanded to trim (optional) | border |
| 3 | upscaled |
Upscayl — after the border fix | upscale / import |
| 4 | edited |
normalize + uniform look — the master | grade |
build runs 2→4 in one go. Cut bleed and medium colour-correction are not
baked into the card — they're applied at sheet time, extended outside the
trim, so the master stays a clean, resizable, device-neutral card. Where do
effects go? Author the look in grade (after upscaling, WYSIWYG); frame
expansion goes before upscale in border; bleed + medium reproduction happen
in sheet. See uniform prints.
Layout on disk
<library>/
├── proxdex.toml # config + library marker
├── INDEX.md # generated: search hub + print status
├── back.png # shared card back (optional; trim-size)
├── cards/
│ └── ex3-dragon/
│ └── ex3-90_dragonite-ex/
│ ├── ex3-90_1_original.png
│ ├── ex3-90_2_bordered.png # only if the frame needed expanding
│ ├── ex3-90_3_upscaled.png
│ └── ex3-90_4_edited.png # trim-size master (no bleed)
└── print-batches/
└── 2026-07-18_dark-deck/
├── fronts.pdf
└── batch.toml # cards, printed?, paper/printer, notes
Install
uv tool install proxdex # global CLI in ~/.local/bin (or: pip install proxdex)
uv tool install . # from a local checkout
uv tool upgrade proxdex # later
cardbleed ships as a dependency, so it's bundled in proxdex's own venv — no
separate install, and proxdex finds it there even though it isn't on your PATH.
Library vs. tool
The tool is installed once; your library (cards, config, batches) is just a folder. proxdex locates it, git-style:
--root DIR, else- the nearest
proxdex.tomlsearching up from the current directory, else $PROXDEX_ROOT(set this in your shell profile to run from anywhere):
export PROXDEX_ROOT=~/Documents/Pokémon\ Proxies
proxdex where # confirm which library + config is active
Config lives in <library>/proxdex.toml (created by init), so it travels
with the data and each library can differ. New config keys added by a tool
upgrade fall back to defaults, so old libraries keep working. INDEX.md is
regenerated automatically after any command that changes state (no need to
run index by hand).
Usage
cd ~/Documents/Pokémon\ Proxies
proxdex init # one-time: create the library here
proxdex search entei ex # find a card by name, pick which print to fetch
proxdex fetch ex3-90 ex6-105 # or download directly by id
proxdex build # border → upscale → grade, for cards that need it
proxdex sheet dark-deck # colour-correct + bleed + impose → print PDF + batch
# ...print the PDF (colour management OFF), then:
proxdex printed dark-deck # mark the batch printed
proxdex ls # every card, stage progress, printed?
That's the whole loop: search → build → sheet → printed. The individual
stage commands (border, upscale, grade) exist for granular control, and
import files loose images (Upscayl-GUI output, or --id an arbitrary scan):
proxdex import ~/upscaled/*.png # ex*_upscayl_*.png → stage 2
proxdex import scan.png --id ex6-105 # arbitrary file → looks up + files it
Commands accept card ids to scope them (proxdex build ex6-105); with none,
they act on the whole library. proxdex searches up from the current
directory for proxdex.toml, or pass --root DIR.
Print sheet
proxdex sheet <name> [ids...] colour-corrects each master, extends cut bleed
outside the trim (cardbleed), imposes onto pages, and writes
print-batches/<date>_<name>/<faces>.pdf plus a manifest. proxdex renders the
PDF itself, so the print path is fully determined — print with your printer's
colour management OFF so a calibration holds.
- Any input size → exact card size. Whatever resolution a card is, it's
scaled to the configured card dimensions (
[card], default 63×88mm) at sheet DPI.fit = coverfills the card preserving aspect (matching-aspect cards lose nothing);containpads;stretchforces it. - Fronts, backs, or duplex (
--facesor[sheet] faces). Duplex emits a front page then a mirrored back page (duplex_flip = long|short), so double-siding lines up. Backs come from a shared[sheet] back_imageor a per-card<id>_back.png. - Offsets nudge the whole image (mm):
front_offset_*and, crucially for duplex registration,back_offset_*(e.g.0.4, 0.35). - Cut guides:
guide_style=full(grid lines) /corners(crop marks) /none, withplacement, length,color, width, and independentguides_front/guides_back(cut from the front, so backs default off). Optional printerreg_marks. All under[sheet].
The PDF is lossless (Flate-embedded, never JPEG) and rendered at
[sheet] dpi (default 1400, --dpi to override) so the printer never
upsamples; only one page raster is held in memory at a time.
Card backs
proxdex back sets the shared back used by sheet --faces backs|duplex:
proxdex back --tcg mtg # Scryfall's standard MTG back
proxdex back --file my-back.png # your own scan (any TCG)
proxdex back --url https://…/back.png
It runs the back through the same medium colour-correction as the fronts
and adds bleed with cardbleed, then saves back.png (auto-used by sheet).
Per-card backs: drop <id>_back.png in a card's folder. Note: there's no
reliable Pokémon-back API (the back is one image, owned by TPC) — supply your
own high-res scan via --file/--url; MTG has a clean source via Scryfall.
Finding cards
Don't know the id? proxdex search queries the TCG API by name — every word
must appear in the card name — and shows each match's set, release year,
collector number, rarity and artist so you can tell prints apart:
$ proxdex search entei ex
# ID Name Set Year No. Rarity Artist
1 ex4-91 Entei ex Team Magma vs Team Aqua 2004 91/95 Rare Holo EX Ryo Ueda
2 ex7-97 Rocket's Entei Team Rocket Returns 2004 97/109 Rare Holo EX Ryo Ueda
3 bw5-13 Entei-EX Dark Explorers 2012 13/108 Rare Holo EX Shizurow
Fetch which? [numbers/ranges/ids · 'all' · blank to cancel]: 1
Type 1, 1,3, 1-3, an id, or all. Narrow with --set base1,
--rarity holo, --year 2004; skip the prompt with --select 1,3 or
--fetch; add --open to preview result images in your browser.
Upscaling
proxdex upscale drives Upscayl's engine (upscayl-bin) directly — no GUI
round-trip — and mirrors the app's own options: any of the seven built-in
models, an output scale, and optional Double Upscayl (runs the model twice,
so 2× doubled = 4×, up to 16×). The command construction matches the app
exactly, including only passing -s when the scale differs from the model's
native 4×. On macOS the bundled binary and models are auto-detected inside
Upscayl.app; elsewhere set the paths under [tools].
Set defaults once in proxdex.toml:
[tools]
upscayl_model = "digital-art-4x" # + upscayl-standard-4x, upscayl-lite-4x, high-fidelity-4x,
# remacri-4x, ultramix-balanced-4x, ultrasharp-4x
upscayl_scale = 2 # 1, 2, 3, or 4
upscayl_double = true # run the model twice (default on → 2× becomes 4×)
Override per run: proxdex upscale --model ultrasharp-4x --scale 4 --double.
Prefer the GUI? Skip this step and proxdex import its output instead.
Border correction (frame expansion)
Real cards have a uniform frame on the top and both sides and a thicker
bottom (set symbol, ©). Some scrydex scans are cut into the frame, so the
card's own border is too thin. proxdex measure reports the top/side thickness
(the bottom is never measured); proxdex border expands a too-thin frame up to
the target — before upscaling — using cardbleed to continue the existing
pattern rather than smear pixels. Cards already at size are left untouched
(within tolerance_mm). This is frame correction, distinct from cut bleed
(which sheet adds outside the trim).
By default the target is symmetric (pad thin edges up to the sides). Once
you've eyeballed a known-good card, set a real-card ratio in proxdex.toml:
[border]
target_side_ratio = 0.045 # side frame ≈ 4.5% of card width
Uniform prints
A mixed collection — crisp digital art next to warm, flat scans — won't print
uniformly if you just apply the same multipliers to everything, because each
card starts from a different place. So grade works in two steps:
- normalize (per card, dynamic) — white-balances the shared card frame to one target colour and evens out black/white points, so every card lands on the same baseline regardless of how it was made. The target defaults to the library's own median frame colour, so the collection converges on its own consensus; pin it if you prefer.
- look (uniform) — one identical recipe on top. Because the baseline is now shared, your intended saturation lands the same way on every card.
[grade]
normalize = true # step 1
match_border_target = [] # [] = library median; or pin e.g. [252, 214, 46]
saturation = 1.10 # step 2 — the intended look
contrast = 1.06
brightness = 1.03 # printers + matte paper dull the image
Calibrate the look with a test strip: print one sheet, compare to screen, nudge
the numbers, reprint. Run proxdex grade --no-normalize to apply only the
recipe (skip step 1).
Printing media (washed-out foil)
Some media shift colour — transparent plastic foil especially, where the ink is
semi-transparent so prints come out lighter and less saturated than the
screen. sheet applies a media profile at print time to cancel that, while
your edited master stays neutral (switch media → just re-run sheet with a
different --profile, no regrade):
[print]
profile = "foil" # "none" | "paper" | "foil"
foil boosts saturation and ink density (saturation 1.38, contrast 1.16, brightness 0.95, gamma 0.88). These are a solid automatic starting point;
calibrate once with a test print and override any value:
[print]
profile = "foil"
saturation = 1.45 # push harder if prints still look washed out
gamma = 0.85
Override per run with proxdex sheet <name> --profile foil.
Calibrating to your printer (closed loop)
If you have a scanner, proxdex can measure a per-medium correction instead of
guessing at a preset — print a chart, scan it, and it fits the colour transform
that makes prints true to the original. Each medium is its own profile (e.g.
paper on white, foil-holo for foil on a holographic backing), so they can
carry different corrections.
proxdex calibrate target --profile foil-holo --pdf # emit a patch chart (as a PDF)
# → print it on that medium, scan it (auto-correction OFF), then:
proxdex calibrate fit --profile foil-holo --scan chart_scan.png
# → measures a degree-2 polynomial correction; `sheet` now applies it.
# verify / iterate:
proxdex calibrate target --profile foil-holo --corrected --pdf # chart with fix baked in
proxdex calibrate check --scan corrected_scan.png
# → prints the residual error; reprint & re-fit until it plateaus.
--pdf sends the chart through the same renderer as your card sheets, so the
correction is measured on the exact path it's applied to. Then proxdex sheet
applies the measured correction — it supersedes the manual foil preset for
that profile.
Honest limits: the scanner is the measuring device, so this makes prints true as your scanner sees them — excellent for proxies, but not colorimetric (that needs a reference target or a spectrophotometer). Some saturated colours are simply outside a medium's gamut and can't be fully reached. And you must turn off the scanner's auto colour/contrast, or it fights the loop.
License
MIT
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file proxdex-0.1.0.tar.gz.
File metadata
- Download URL: proxdex-0.1.0.tar.gz
- Upload date:
- Size: 39.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1721199c23e65bfefe8ad8520fbf7d7c925cbdec1e2eeec2043550df73970ee7
|
|
| MD5 |
589dba16c7bc598730b6921c04058e10
|
|
| BLAKE2b-256 |
0860f06593e5f377dd7ea205551476a2d6ba06d5ab14a55fd02df23a8b63f12c
|
Provenance
The following attestation bundles were made for proxdex-0.1.0.tar.gz:
Publisher:
release.yml on ErikBavenstrand/proxdex
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
proxdex-0.1.0.tar.gz -
Subject digest:
1721199c23e65bfefe8ad8520fbf7d7c925cbdec1e2eeec2043550df73970ee7 - Sigstore transparency entry: 2206686043
- Sigstore integration time:
-
Permalink:
ErikBavenstrand/proxdex@7aa858573a0dcc505ac52326ca6dc10967f2dffc -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/ErikBavenstrand
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@7aa858573a0dcc505ac52326ca6dc10967f2dffc -
Trigger Event:
push
-
Statement type:
File details
Details for the file proxdex-0.1.0-py3-none-any.whl.
File metadata
- Download URL: proxdex-0.1.0-py3-none-any.whl
- Upload date:
- Size: 44.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
028d25538c709130b8f4931cd7aac17d22a072d0b9605879b2fd463d5be1e8b3
|
|
| MD5 |
9d654c5a888450e6c2f520523b3d6137
|
|
| BLAKE2b-256 |
42ab5cbd0dea889a3cdeddefe2e770f55792a4b7e46555dbc76d7bc640cf37d9
|
Provenance
The following attestation bundles were made for proxdex-0.1.0-py3-none-any.whl:
Publisher:
release.yml on ErikBavenstrand/proxdex
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
proxdex-0.1.0-py3-none-any.whl -
Subject digest:
028d25538c709130b8f4931cd7aac17d22a072d0b9605879b2fd463d5be1e8b3 - Sigstore transparency entry: 2206686059
- Sigstore integration time:
-
Permalink:
ErikBavenstrand/proxdex@7aa858573a0dcc505ac52326ca6dc10967f2dffc -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/ErikBavenstrand
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@7aa858573a0dcc505ac52326ca6dc10967f2dffc -
Trigger Event:
push
-
Statement type: