A command-line tool that downloads League of Legends champion skins from CommunityDragon and repackages them into installable .wad.client skin files.
by jinjutwo & nylish
What this was used for • How it works • Structure • Installation • Usage • Limitations
Important
This repository is archived. It is no longer maintained and is published for historical/reference purposes only. No support, updates, or pull request review should be expected. See Known limitations for what does and doesn't work if you plan to reuse the code.
League of Legends ships every skin's game data as a .bin file inside Riot's public CommunityDragon mirror, but that raw data is numbered for its original skin slot (e.g. skin23.bin), so it can't simply be dropped into a client-side skin-swapper, which expects the base-skin slot (skin0.bin).
This project automated the process of turning a raw CDragon skin into a drop-in replacement:
- Download the target champion's base skin and the desired skin variant directly from CommunityDragon.
- Renumber the extracted skin's internal properties (
SkinCharacterDataProperties,ResourceResolver) fromSkinXtoSkin0, using ritobin to round-trip the binary through JSON. - Repackage the patched files into a
.wad.clientarchive (viawad-make) and zip it up with the metadata layout expected by common skin-swapper tools.
It was built for personal/offline use — swapping a champion's own default skin for one of its alternate skins client-side. It does not modify anything server-side, does not affect other players, and does not touch paid content beyond what the account already owns.
Caution
This tool downloads and repackages Riot Games' assets and is intended strictly for personal, offline use in line with Riot's "Legal Jibber Jabber" policy on fan-made mods. It is not affiliated with or endorsed by Riot Games. Do not use it to distribute Riot's assets or to gain any in-game advantage.
flowchart LR
A["CommunityDragon\n(raw game data)"] -->|skin_fetcher.py| B["base_skinsfiles/\n(downloaded skin*.bin)"]
B -->|skin_extractor.py + ritobin| C["Renumbered skin0.bin\n(SkinX → Skin0)"]
C -->|wad-make| D["cdn/\n.wad.client + .zip package"]
B -.->|ritoskin_bridge.py, optional| E["lol-skins /\nlol-skins-developer format"]
The core pipeline (skin_fetcher.py → skin_extractor.py, driven by main.py) is self-contained and only depends on the two bundled executables in bin/. An optional second path (ritoskin_bridge.py) was added later to hand off processing to an external tool called ritoskin2.0-threads for extra output formats — see Known limitations.
CDragonSkinExtractor/
├── main.py # CLI entry point (start here)
├── skin_fetcher.py # Downloads skin .bin files from CommunityDragon
├── skin_extractor.py # Renumbers skins and builds the .wad.client/.zip output
├── ritoskin_bridge.py # Optional bridge to the external ritoskin2.0-threads tool
├── ritoskin_quick_workflow.py # Shortcut: download + bridge, skipping local extraction
├── bin/
│ ├── ritobin.exe # .bin <-> .json converter (github.com/moonshadow565/ritobin)
│ └── wad-make.exe # Packs a folder into a .wad.client archive
├── tools/
│ ├── check_progress.py # Inspects ritoskin_bridge processing state
│ ├── setup_integration.py # Verifies/creates the ritoskin2.0-threads folder layout
│ └── chroma_extractor.py # Standalone: bulk-downloads chroma preview images
├── tests/
│ ├── test_integration.py # Manual end-to-end smoke test
│ └── test_shaco.py # Manual smoke test using Shaco's skins
├── docs/
│ └── cli-usage.md # Full CLI reference and examples
└── requirements.txt
Running any script downloads/generates content into base_skinsfiles/, cdn/, output/, and lol-skins-output/ — these are gitignored, not part of the repo.
Requires Python 3.7+ and Windows (the bundled bin/*.exe tools are Win32 binaries; on other platforms they'd need to run under Wine, which the code has partial support for but was never fully tested).
git clone https://github.com/darkseal-org/CDragonSkinExtractor.git
cd CDragonSkinExtractor
pip install -r requirements.txt# Extract a single skin
python main.py --champion "Zed" --skins "23"
# Extract multiple skins for one champion
python main.py --champion "Yasuo" --skins "1" "2" "3"
# Extract skins for multiple champions in one run
python main.py --champions "Zed:23,48" "Sett:38,39" "Shaco:64,65,66"
# CDragon-only extraction, skipping the optional ritoskin bridge
python main.py --champion "Zed" --skins "23" --no-ritoskin
# List known champion names / see all flags
python main.py --list-champions
python main.py --helpSuccessful runs write the finished .wad.client and .zip package to cdn/<Champion>/<skin-number>/. See docs/cli-usage.md for the full flag reference, naming conventions for champions with special-cased names (e.g. Drmundo, AurelionSol), and troubleshooting notes.
tools/chroma_extractor.py is an unrelated, standalone helper that bulk-downloads a champion's chroma preview images from CommunityDragon, named and sorted by chroma ID:
python tools/chroma_extractor.py(Edit the champion name/ID at the bottom of the file — it has no CLI flags.)
- The
ritoskin_bridge.pypath is non-functional out of the box. It shells out to an external tool (ritoskin2.0-threads/ritoskin.exe) and hash files that were never part of this repository —tools/setup_integration.pycan scaffold the expected folder layout, but you must supply that tool and its hash files yourself. Without them,--no-ritoskinis the only reliable mode. ritoskin_quick_workflow.pyandtools/check_progress.pydepend on the same missing external tool.- The core download → renumber → repackage pipeline (
main.pywith--no-ritoskin) is the part that was actually exercised regularly.
- jinjutwo
- nylish
- Packaging relies on ritobin for
.bin/.jsonconversion.
Released under the MIT License.