#league-of-legends #format #editing #texture #mesh #serialization #wad

league-toolkit

Toolkit library for serializing and editing various League of Legends formats

17 releases

new 0.2.17 Feb 8, 2026
0.2.16 Feb 1, 2026
0.2.15 Jan 18, 2026
0.2.14 Dec 27, 2025
0.1.1 Oct 17, 2021

#926 in Parser implementations

MIT/Apache

12KB

πŸ› οΈ League Toolkit

Rust library for parsing, editing, and writing League of Legends file formats

CI Crates.io Docs License

Documentation β€’ Crates.io β€’ Changelog


✨ Features

  • πŸ“¦ WAD Archives β€” Read and write .wad.client asset containers
  • 🎨 Textures β€” Decode/encode .tex and .dds formats
  • 🧍 Meshes β€” Parse skinned (.skn) and static (.scb/.sco) meshes
  • 🦴 Animation β€” Load skeletons (.skl) and animations (.anm)
  • πŸ“‹ Property Bins β€” Read/write .bin configuration files
  • πŸ—ΊοΈ Map Geometry β€” Parse .mapgeo environment assets
  • πŸ”§ Modular β€” Use individual crates or the umbrella crate

πŸ“¦ Installation

Add the umbrella crate to your project:

[dependencies]
league-toolkit = { version = "0.2", features = ["wad", "mesh", "texture"] }

Or use individual crates for a smaller dependency footprint:

[dependencies]
ltk_wad = "0.2"
ltk_texture = "0.4"
ltk_mesh = "0.3"

πŸš€ Quick Start

Reading a WAD Archive

use std::fs::File;
use ltk_wad::Wad;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let file = File::open("assets.wad.client")?;
    let mut wad = Wad::mount(file)?;
    
    println!("Archive contains {} files", wad.chunks().len());
    
    // Decode a specific chunk
    let (mut decoder, chunks) = wad.decode();
    for chunk in chunks.values().take(5) {
        let data = decoder.load_chunk_decompressed(chunk)?;
        println!("Chunk {:016x}: {} bytes", chunk.path_hash(), data.len());
    }
    
    Ok(())
}

Decoding a Texture

use ltk_texture::Tex;
use std::io::Cursor;

let tex = Tex::from_reader(&mut cursor)?;
let surface = tex.decode_mipmap(0)?;
let image = surface.into_rgba_image()?;
image.save("output.png")?;

Parsing a Skinned Mesh

use ltk_mesh::SkinnedMesh;
use std::fs::File;

let mesh = SkinnedMesh::from_reader(&mut File::open("champion.skn")?)?;
println!("Vertices: {}", mesh.vertex_buffer().vertex_count());
println!("Submeshes: {}", mesh.ranges().len());

Working with Property Bins

use ltk_meta::{BinTree, BinTreeObject, value::*};

// Read
let tree = BinTree::from_reader(&mut file)?;
for (hash, object) in &tree.objects {
    println!("Object 0x{:08x}", hash);
}

// Create
let tree = BinTree::builder()
    .dependency("shared/data.bin")
    .object(
        BinTreeObject::builder(0x12345678, 0xABCDEF00)
            .property(0x1111, I32Value(42))
            .build()
    )
    .build();

πŸ“š Crates

Crate Description Formats
league-toolkit Umbrella crate (feature-gated re-exports) β€”
ltk_wad WAD archive reading/writing .wad.client
ltk_texture Texture decoding/encoding .tex, .dds
ltk_mesh Skinned & static mesh parsing .skn, .scb, .sco
ltk_anim Skeleton & animation formats .skl, .anm
ltk_meta Property bin files .bin
ltk_ritobin Human-readable bin format ritobin text
ltk_mapgeo Map environment geometry .mapgeo
ltk_file File type detection β€”
ltk_hash Hash functions (FNV-1a, ELF) β€”
ltk_shader Shader path utilities β€”
ltk_primitives Geometric primitives β€”
ltk_io_ext I/O extensions (internal) β€”

Each crate lives under crates/<name>.


βš™οΈ Feature Flags

The league-toolkit umbrella crate uses feature flags to control which subsystems are included:

Feature Enables Default
anim ltk_anim βœ…
file ltk_file βœ…
mesh ltk_mesh βœ…
meta ltk_meta βœ…
primitives ltk_primitives βœ…
texture ltk_texture βœ…
wad ltk_wad βœ…
hash ltk_hash βœ…
serde Serde support (where available) ❌

For a minimal build, disable defaults and opt-in selectively:

[dependencies]
league-toolkit = { version = "0.2", default-features = false, features = ["wad"] }

Texture Encoding with intel-tex

BC1/BC3 texture encoding requires the optional intel-tex feature on ltk_texture:

[dependencies]
league-toolkit = { version = "0.2", features = ["texture"] }
ltk_texture = { version = "0.4", features = ["intel-tex"] }

πŸ“– Documentation


πŸ› οΈ Development

Prerequisites: Rust stable toolchain

# Build all crates
cargo build

# Run tests
cargo test

# Build documentation
cargo doc --open

Project Structure

league-toolkit/
β”œβ”€β”€ crates/
β”‚   β”œβ”€β”€ league-toolkit/    # Umbrella crate
β”‚   β”œβ”€β”€ ltk_wad/           # WAD archives
β”‚   β”œβ”€β”€ ltk_texture/       # Textures
β”‚   β”œβ”€β”€ ltk_mesh/          # Meshes
β”‚   β”œβ”€β”€ ltk_anim/          # Animation
β”‚   β”œβ”€β”€ ltk_meta/          # Property bins
β”‚   β”œβ”€β”€ ltk_ritobin/       # Ritobin text format
β”‚   β”œβ”€β”€ ltk_mapgeo/        # Map geometry
β”‚   β”œβ”€β”€ ltk_file/          # File detection
β”‚   β”œβ”€β”€ ltk_hash/          # Hashing
β”‚   β”œβ”€β”€ ltk_shader/        # Shader utilities
β”‚   β”œβ”€β”€ ltk_primitives/    # Primitives
β”‚   └── ltk_io_ext/        # I/O extensions
└── docs/
    └── LTK_GUIDE.md       # Usage guide

πŸ“‹ Releasing

This repository uses Release-plz for automated versioning and publishing:

  1. Pushes to main trigger Release-plz to open a release PR
  2. Merging the release PR publishes updated crates to crates.io

πŸ“„ License

Licensed under either of:

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.


Made with ❀️ by the LeagueToolkit community

Dependencies

~0–3.5MB
~77K SLoC