A high-performance Rust library and CLI tool for rendering Hytale character skins and animations. Parses .blockymodel and .blockyanim files to produce PNG stills, animated GIFs, and WebM videos.
- Multiple Output Formats: PNG stills, animated GIFs, and WebM videos
- PlayerDB Integration: Fetch player skins directly using username or UUID
- Cosmetic Support: Full cosmetic registry with haircuts, clothing, accessories, and more
- Multiple Camera Presets: Headshot, full body, isometric, bust, and directional views
- Tint Gradients: Apply skin tones and color customization via tint gradient maps
- Multi-threaded Rendering: Parallel frame rendering with configurable worker threads
- Supersampling: Anti-aliasing through higher resolution rendering and downsampling
- Batch Processing: Render multiple animations from a directory
- GPU Acceleration: Optional GPU rendering backend (via
gpufeature)
- Rust 1.70+ (2021 edition)
- FFmpeg (required for GIF and WebM encoding)
# Clone the repository
git clone https://github.com/nodecraft/hytale-skin-renderer.git
cd hytale-skin-renderer
# Build release binary
cargo build --release
# Optional: Build with GPU support
cargo build --release --features gpuThe binary will be available at target/release/hytale-renderer.
# Show all available options
cargo run -- --help
# Render a still image (default pipeline)
cargo run -- --pipeline body --output player.png
# Render an animated GIF
cargo run -- --pipeline gif --output animation.gif
# Render a WebM video
cargo run -- --pipeline webm --output animation.webmThe CLI supports three rendering pipelines via the --pipeline flag:
| Pipeline | Description | Default Output |
|---|---|---|
body |
Static PNG renders with multiple camera views | all_views_render-{view}.png |
gif |
Animated GIF from blockyanim | animation.gif |
webm |
Animated WebM video from blockyanim | idle_animation.webm |
Use --camera to select a camera angle:
legacy- Original camera positionfull-body-front- Front-facing full body viewfront-right- Angled front-right viewback-right- Angled back-right viewfront-left- Angled front-left viewback-left- Angled back-left viewheadshot- Close-up head shotisometric-head- Isometric head viewplayer-bust- Upper body/bust shot
Render a player's skin directly by username or UUID:
cargo run -- --skin "PlayerName" --output player_render.png# Set output FPS (default: 30)
cargo run -- --pipeline gif --fps 60 --output smooth.gif
# Set animation duration in seconds
cargo run -- --pipeline webm --length-seconds 5.0 --output five_seconds.webm
# Set number of animation cycles
cargo run -- --pipeline gif --cycles 3 --output looped.gif
# Batch render all animations in a directory
cargo run -- --pipeline gif \
--animations-dir "assets/Common/Characters/Animations/Default" \
--recursive \
--output "output/{anim_name}.gif"# Set output size (width and height)
cargo run -- --size 1024 --output hd_render.png
# Enable supersampling (2x renders at 2048x2048, downsamples to 1024x1024)
cargo run -- --size 1024 --supersample 2 --output smooth_render.png
# Configure worker threads
cargo run -- --pipeline gif --workers 8 --encode-workers 4 --output animation.gifcargo run -- \
--pipeline webm \
--model "assets/Common/Characters/Player.blockymodel" \
--animation "assets/Common/Characters/Animations/Default/Idle.blockyanim" \
--texture "assets/Common/Characters/Player_Textures/Player_Greyscale.png" \
--skin "PlayerUsername" \
--camera full-body-front \
--size 512 \
--supersample 2 \
--fps 30 \
--cycles 2 \
--workers 4 \
--output "player_idle.webm"| Flag | Description | Default |
|---|---|---|
--pipeline |
Render pipeline (body, gif, webm) |
body |
--model, -m |
Path to .blockymodel file |
assets/Common/Characters/Player.blockymodel |
--animation, -a |
Path to .blockyanim file |
assets/.../Idle.blockyanim |
--animations-dir |
Directory of animations (batch mode) | - |
--recursive |
Recursively search animations directory | false |
--texture, -t |
Path to base texture PNG | assets/.../Player_Greyscale.png |
--output, -o |
Output file path (supports {anim_name}, {view} placeholders) |
varies by pipeline |
--skin |
PlayerDB username or UUID | - |
--skin-config |
Path to skin configuration JSON | skin.json |
--tint-gradients |
Path to tint gradients folder | assets/Common/TintGradients |
--fallbacks |
Path to haircut fallbacks JSON | assets/.../HaircutFallbacks.json |
--camera |
Camera preset | varies by pipeline |
--size, -s |
Output image size (width & height) | 1024 (body), 512 (gif/webm) |
--supersample |
Supersampling factor | 1 |
--fps |
Target frames per second | 30 |
--length-seconds |
Output duration in seconds | - |
--cycles, -c |
Number of animation cycles | 1 |
--workers |
Number of render worker threads (0 = auto) | 0 |
--encode-workers |
Number of encoder threads (0 = ffmpeg default) | 0 |
--backend |
Rendering backend (auto, cpu, gpu) |
auto |
Add to your Cargo.toml:
[dependencies]
hytale-skin-renderer = { path = "path/to/hytale-skin-renderer" }use hytale_skin_renderer::render_blockymodel_to_png;
use std::path::Path;
fn main() -> hytale_skin_renderer::Result<()> {
let model_path = Path::new("assets/Common/Characters/Player.blockymodel");
let texture_path = Path::new("assets/Common/Characters/Player_Textures/Player_Greyscale.png");
let image = render_blockymodel_to_png(
model_path,
Some(texture_path),
1024, // width
1024, // height
)?;
image.save("output.png")?;
Ok(())
}src/
├── main.rs # CLI entry point
├── lib.rs # Library exports
├── animation.rs # Animation parsing and playback
├── asset_provider.rs # Asset loading abstraction
├── camera.rs # Camera presets and projection
├── cosmetics.rs # Cosmetic registry and loading
├── cosmetic_attachment.rs
├── error.rs # Error types
├── geometry.rs # 3D geometry generation
├── math.rs # Math utilities
├── models.rs # Blockymodel/blockyanim parsing
├── output.rs # PNG/GIF/WebM export
├── playerdb.rs # PlayerDB API integration
├── render_pipeline.rs # High-level render orchestration
├── scene.rs # Scene graph management
├── skin.rs # Skin configuration
├── texture.rs # Texture loading and sampling
└── renderer/
├── mod.rs # Renderer core
├── clip.rs # Clipping utilities
├── config.rs # Render configuration
├── debug.rs # Debug utilities
├── face.rs # Face rendering
├── gpu.rs # GPU backend (optional)
├── math.rs # Renderer math
├── postprocess.rs # Post-processing effects
└── rasterizer.rs # CPU rasterization
tests/
├── integration.rs # Full pipeline tests
├── geometry_tests.rs # Geometry unit tests
├── lighting_tests.rs # Lighting unit tests
└── renderer_tests.rs # Renderer unit tests
assets/ # Game assets (models, textures, animations)
# Run all tests
cargo test
# Run specific test suite
cargo test --test integration
cargo test --test geometry_tests
cargo test --test lighting_tests
cargo test --test renderer_tests- serde / serde_json - JSON parsing for configs and model data
- image - Image loading and PNG/GIF encoding
- glam - Fast linear algebra (vectors, matrices)
- clap - CLI argument parsing
- reqwest - HTTP client for PlayerDB API
- zip - Asset archive handling
- wgpu (optional) - GPU rendering backend
- FFmpeg (external) - Video encoding for GIF/WebM
See LICENSE for details.