Wraps the PolyTrack WASM physics engine in a safe, ergonomic API for deterministic, offline car simulation — no browser, no renderer, no game loop. Useful for TAS tooling, AI training, replay systems, and brute-force search.
  • Rust 95.3%
  • Python 4.7%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-07-20 12:35:08 -07:00
.cargo feat: move from github 2026-06-13 16:47:55 -07:00
benches feat: move from github 2026-06-13 16:47:55 -07:00
src feat: move from github 2026-06-13 16:47:55 -07:00
.gitignore feat: move from github 2026-06-13 16:47:55 -07:00
blob_to_json.py feat: move from github 2026-06-13 16:47:55 -07:00
Cargo.lock chore: bump dep versions 2026-07-20 12:35:04 -07:00
Cargo.toml Merge branch 'main' of https://git.polymodloader.com/SpideyZac/polysim 2026-07-20 12:35:08 -07:00
json_to_blob.py feat: move from github 2026-06-13 16:47:55 -07:00
LICENSE Initial commit 2026-06-14 01:40:06 +02:00
README.md chore: bump dep versions 2026-07-20 12:35:04 -07:00
rustfmt.toml feat: move from github 2026-06-13 16:47:55 -07:00
simulation_assets.bin feat: move from github 2026-06-13 16:47:55 -07:00

PolySim

Headless PolyTrack physics simulation in Rust.

Wraps the PolyTrack WASM physics engine in a safe, ergonomic API for deterministic, offline car simulation — no browser, no renderer, no game loop. Useful for TAS tooling, AI training, replay systems, and brute-force search.

Requirements

  • Rust 1.85+ (edition 2024 required by polytrack-codes and wasmtime 47.0.0)

Usage

[dependencies]
polysim = { git = "https://git.polymodloader.com/SpideyZac/polysim.git" }
wasmtime = "47.0.0"  # for Module when sharing across workers

Single car

use polysim::{
    physics::{PolyTrackPhysics, create_engine},
    simulation::{PlayerController, PreparedTrack, SimulationWorker},
};

let engine = create_engine();
let (physics, _module) = PolyTrackPhysics::from_file(&engine, "physics.wasm")?;

let prepared = PreparedTrack::from_export_string("PolyTrack24...")?;
let mut worker = SimulationWorker::new(physics, prepared)?;
worker.init()?;
worker.create_car(0)?;

loop {
    worker.set_car_controls(0, PlayerController { up: true, ..Default::default() })?;
    let state = worker.update_car(0)?;
    println!("frame {} speed {:.1} km/h", state.frames, state.speed_kmh);
    if state.finish_frames.is_some() {
        println!("finished at frame {}", state.finish_frames.unwrap());
        break;
    }
}

Multiple cars in one worker

Each car gets its own WASM-heap output buffer — updates never clobber each other:

worker.create_car(0)?;
worker.create_car(1)?;

worker.set_car_controls(0, PlayerController { up: true, ..Default::default() })?;
worker.set_car_controls(1, PlayerController { up: true, right: true, ..Default::default() })?;

let state0 = worker.update_car(0)?;
let state1 = worker.update_car(1)?;

Multiple parallel workers

Compile once, instantiate one PolyTrackPhysics per thread from the shared Module. Each worker owns its own WASM heap — no locking required:

use wasmtime::Module;

let engine = create_engine();
let module = Module::from_file(&engine, "physics.wasm")?;

std::thread::spawn({
    let engine = engine.clone();
    let module = module.clone();
    move || {
        let phys = PolyTrackPhysics::from_module(&engine, &module).unwrap();
        // ... create worker, run sim
    }
});

Key types

Type Description
[PreparedTrack] Decoded track — construct once, share across workers
[SimulationWorker] Drives one WASM instance; supports N simultaneous cars
[CarState] Full per-frame snapshot: position, speed, checkpoints, wheels
[PlayerController] Five binary inputs: up, right, down, left, reset
[PolyTrackPhysics] Low-level WASM wrapper; rarely needed directly

CarState fields

Field Description
frames Physics tick counter
speed_kmh Current speed in km/h
has_started Whether the timer is running
finish_frames Tick at which the car finished, if at all
next_checkpoint_index Index of the next checkpoint to hit
is_finishline_cp Whether the next target is the finish line
next_checkpoint_position World-space position of the next target
position Car world-space XYZ
quaternion Car orientation [x, y, z, w]
collision_impulses Magnitude of collisions this tick (up to 4)
wheel_contacts Per-wheel contact point and normal
wheel_suspension_lengths Current suspension compression
steering Steering angle in radians