Rust library for working with Visual Pinball VPX files
Find it on crates.io: https://crates.io/crates/vpin
Also available on npm as WASM package: https://www.npmjs.com/package/@francisdb/vpin-wasm
Join #vpxtool on "Virtual Pinball Chat" discord for support and questions.
The library provides several optional features that can be enabled:
parallel(default): Enables parallel processing using rayon for better performancewasm: Enables WebAssembly bindings for browser/Node.js usage
To use only VPX functionality without parallel support:
[dependencies]
vpin = { version = "0.20", default-features = false }To enable specific features:
[dependencies]
vpin = { version = "0.20", default-features = false, features = ["wasm"] }Check the examples folder
The library supports extracting VPX files to an expanded directory format for easier editing and version control.
For primitive mesh data, you can choose between two formats:
- OBJ format (default) - Text-based Wavefront OBJ, human-readable and widely supported
- GLB format (optional) - Binary GLTF, significantly faster I/O for large meshes and animation frames
Use write_with_format() to specify the format. Both formats are supported for reading, with OBJ checked first for
backward compatibility.
When extracting VPX files, the library can optionally generate mesh files for game items that don't store explicit mesh
data but are defined by drag points (walls, ramps, rubbers, flashers). Use ExpandOptions to enable this:
use vpin::vpx::expanded::{ExpandOptions, PrimitiveMeshFormat};
let options = ExpandOptions::new()
.mesh_format(PrimitiveMeshFormat::Glb)
.generate_derived_meshes(true);VPinball uses a left-handed coordinate system:
(0,0)───────────────→ +X (right)
│ ┌───────────┐
│ │ │
│ │ Playfield │
│ │ │
↓ └───────────┘
+Y (towards player)
+Z points up (towards the cabinet top glass)
- Origin: Top-left corner of the playfield (near the back of the cabinet)
- X-axis: Positive to the right (across the playfield)
- Y-axis: Positive towards the player (down the playfield)
- Z-axis: Positive upward (towards the glass)
Due to the Y-axis pointing down, winding order appears reversed compared to standard mathematical conventions:
- A polygon whose vertices go clockwise on screen has a positive orientation determinant
- A polygon whose vertices go counter-clockwise on screen has a negative orientation determinant
VPinball's triangulation algorithm (used for flashers, walls, etc.) normalizes all polygons to counter-clockwise order before processing. This library matches that behavior.
https://github.com/francisdb/vpxtool https://github.com/jsm174/vpx-editor
- Visual Pinball https://github.com/vpinball/vpinball
- VPUniverse https://vpuniverse.com/
- VPForums https://www.vpforums.org/
- Virtual Pinball Chat on Discord https://discord.com/invite/YHcBrtT
We expect a folder ~/vpinball/tables to exist that contains a lot of vpx files. The tests will
recursively search for these files and run the tests on them.
cargo test --release -- --ignored --nocapture# Install the target and wasmtime (do this only once)
rustup target add wasm32-wasip1
cargo install wasmtime-cli
# Run tests
cargo test --target wasm32-wasip1 --features wasm# Install the target and wasm-bindgen-test (do this only once)
rustup target add wasm32-unknown-unknown
cargo install wasm-bindgen-cli
# Run tests
cargo test --target wasm32-unknown-unknownWe use https://github.com/MarcoIeni/release-plz which creates a release pr on every commit to master