Python-first native multibody simulation for reinforcement learning
Project description
LavenderSim
LavenderSim is a Python-first native robotics simulator for reinforcement learning. You describe bodies, joints, sensors, rewards, and interaction loops in Python; a compact C++17 engine runs the physics on macOS, Linux, and the web.
Documentation · Environment guide · Examples · Development guide
AI provenance: Almost the entire project was generated by GPT-5.6 Sol under human direction. Treat the implementation as AI-generated software: review it, test it for your application, and do not assume MuJoCo-level numerical validation or safety guarantees.
Why LavenderSim?
- Python-first worlds: create complete articulated scenes without XML.
- RL-ready API: seeded
reset, bounded spaces, flat observations, and Gymnasium-style five-valuestepresults without requiring Gymnasium. - 13 registered tasks: ten benchmark environments plus the walker, quadruped, and ball-pushing tasks developed with the simulator.
- Robotics features: revolute, prismatic, fixed, and spherical joints; effort, position, velocity, and impedance control; named sites; IMUs; tactile, range, force, and torque sensors; actuator dynamics; fixed tendons; heightfields; cameras; and contact materials.
- Deterministic branching: serialize
snapshot()state, try an action sequence, restore, and branch again. - CPU parallelism: the included vectorizer runs independent native simulators in separate processes; PPO defaults to 32 environments.
- Python-controlled web UI: stream authoritative native poses to a browser, receive direction/speed or floor-click targets, and control overlays from Python.
- One physics source:
engine/physics.cppbuilds as a macOS/Linux shared library and as WebAssembly.
Beginner quick start
Python 3.9 or newer is supported. Install the native package from PyPI:
python -m pip install lavendersim
The release includes native wheels for Linux x86-64, macOS Intel, and macOS arm64.
Create and step your first environment:
import numpy as np
from lavendersim.env import make
env = make("CartPoleBalance-v0", control_hz=60, horizon_seconds=3, seed=7)
observation, info = env.reset(seed=7)
for _ in range(180):
# Replace this with your policy. Every action component is in [-1, 1].
action = np.zeros(env.action_space.shape, dtype=np.float32)
observation, reward, terminated, truncated, info = env.step(action)
if terminated or truncated:
observation, info = env.reset()
env.close()
What the values mean:
observation: the flatfloat32policy input.reward: the task-specific learning signal.terminated: a physical success or failure condition occurred.truncated: the episode reached its time limit.info: diagnostics such as tracking error and contact counts.
List every environment or run an example:
python examples/envs/list_envs.py
python examples/envs/rover_waypoint.py --steps 300 --headless
python examples/envs/cartpole_balance.py --steps 600 --web
Environment catalog
| ID | Goal | Notable features |
|---|---|---|
CartPoleBalance-v0 |
Balance a pole on a moving cart | Effort actuator, activation dynamics, snapshots |
AcrobotSwingup-v0 |
Swing an underactuated arm upright | Named sites, actuator friction |
ReactionWheelCube-v0 |
Stabilize a cube with internal wheels | IMU, armature, delayed actuation |
TiltMaze-v0 |
Roll a ball to a target and settle | Low friction, goal dwell reward |
RoverWaypoint-v0 |
Drive to a randomized waypoint | Ray-fan lidar, heightfield terrain |
HopperCommand-v0 |
Track a requested planar speed | Fixed tendon, IMU, terrain probe |
QuadrupedTerrain-v0 |
Track randomized direction and speed | 12 joints, range probes, command input |
ArmReach-v0 |
Reach randomized 3-D targets | End-effector sites and velocities |
TactileGripperLift-v0 |
Grasp, lift, and hold a payload | Tactile arrays, coupled jaw tendon |
PegInsertion-v0 |
Align and seat a peg | Site errors, filtered force/torque sensing |
WalkerCommand-v0 |
Follow a body-relative motion command | IMU and joint proprioception |
QuadrupedCommand-v0 |
Follow planar commands | Randomized command-conditioned locomotion |
ManipulatorPush-v0 |
Push a ball to a clicked target and stop | Goal-conditioned interaction and web target UI |
Use an ID with lavendersim.env.make() or the PPO trainer. The short aliases
walker, quadruped, and manipulator remain supported.
Author a Python scene
from lavendersim import PD, Scene
from lavendersim.runtime import CodeSceneEnv
scene = Scene("Two-link robot")
base = scene.box("base", size=(0.3, 0.2, 0.3), position=(0, 0.1, 0), mass=0)
link = scene.capsule("link", radius=0.05, length=0.8, position=(0, 0.55, 0), mass=1)
joint = scene.revolute(
"shoulder", base, link,
anchor=(0, 0.2, 0), axis=(0, 0, 1),
limits=(-1.5, 1.5), pd=PD(kp=30, kd=2, max_torque=20),
)
tip = scene.site("tip", body=link, position=(0, 0.4, 0))
with CodeSceneEnv(scene, control_dt=1 / 60) as sim:
observation, info = sim.reset(seed=1)
observation, reward, terminated, truncated, info = sim.step({"shoulder": 0.4})
print(observation["sites"]["tip"])
Scenes support boxes, spheres, capsules, cylinders, convex bodies, articulated actors, collision exclusions, materials, cameras, motion generators, UI metadata, and the sensor/actuator features listed above.
PPO training on CPU
Install the RL extra from a checkout:
python -m pip install -e '.[dev,rl]'
./build_native.sh
python -m experiment.train_ppo \
--task QuadrupedTerrain-v0 \
--num-envs 32 \
--control-hz 60 \
--horizon-seconds 3 \
--rollout-steps 180 \
--output-dir experiment/runs/quadruped-terrain
The default geometry produces 5,760 transitions per PPO update. A tiny end-to-end smoke run is useful before a long experiment:
python -m experiment.train_ppo \
--task CartPoleBalance-v0 --num-envs 2 --rollout-steps 30 \
--updates 1 --epochs 1 --minibatch-size 60 \
--output-dir /tmp/lavendersim-smoke
Live browser visualization
The Python server remains authoritative: it steps the native environment, runs the policy, streams body poses to the browser, and receives UI commands.
./build_web.sh
python -m experiment.serve_quadruped \
--checkpoint experiment/runs/quadruped_ppo/checkpoint.pt
Open http://127.0.0.1:8765/?live=1. The quadruped page sends direction and
speed back to Python. The manipulator page sends a clicked floor target. Python
can also select visible bodies, colors, sites, contacts, joints, sensor rays,
tendons, heightfields, camera state, and metrics through LiveViewer.
Snapshots
state = env.snapshot()
first_branch = env.step(action_a)
env.restore(state)
second_branch = env.step(action_b)
encoded = state.to_bytes()
env.restore(encoded)
Snapshots validate the scene fingerprint and include body/joint state, actuator activation, sensor filters and delays, simulation time, and RNG state.
Development
git clone https://github.com/cloneofsimo/lavendersim.git
cd lavendersim
python3 -m venv .venv
.venv/bin/pip install -e '.[dev,rl]'
./build_native.sh
.venv/bin/pytest -q
The same CMake definition builds macOS and Linux wheels. CI also builds the
WebAssembly engine and tests isolated wheel installation. See
docs/development.md for release details.
Project status and scope
LavenderSim is experimental alpha software, not a drop-in MuJoCo replacement. It does not currently implement MJCF import, deformables, spatial tendon wrapping, fluids, general equality constraints, or GPU simulation. Validate physics behavior and learned policies before using them in consequential or real-world systems.
Released under the MIT License.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file lavendersim-0.2.0.tar.gz.
File metadata
- Download URL: lavendersim-0.2.0.tar.gz
- Upload date:
- Size: 229.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c15d8602e7375507774d854c064384743352c6a177df8a588f744658d386db1e
|
|
| MD5 |
48d53555bcfcb0872c11bb91cb7b1b7e
|
|
| BLAKE2b-256 |
1e10e39127483968ccd80153451a8540cb61d4b2a79f4fdb3ac7e30fed59330f
|
Provenance
The following attestation bundles were made for lavendersim-0.2.0.tar.gz:
Publisher:
publish.yml on cloneofsimo/lavendersim
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
lavendersim-0.2.0.tar.gz -
Subject digest:
c15d8602e7375507774d854c064384743352c6a177df8a588f744658d386db1e - Sigstore transparency entry: 2164714354
- Sigstore integration time:
-
Permalink:
cloneofsimo/lavendersim@b751f79434f8e5cfceae2beaac3332440880e18b -
Branch / Tag:
refs/heads/main - Owner: https://github.com/cloneofsimo
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@b751f79434f8e5cfceae2beaac3332440880e18b -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file lavendersim-0.2.0-py3-none-musllinux_1_2_x86_64.whl.
File metadata
- Download URL: lavendersim-0.2.0-py3-none-musllinux_1_2_x86_64.whl
- Upload date:
- Size: 126.4 kB
- Tags: Python 3, musllinux: musl 1.2+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
afb0b846666550d78f077b29ab1bd17f88d62574fcd9c3aabd5efb7457714658
|
|
| MD5 |
6b2075cfa45c515e92632c5144c6d390
|
|
| BLAKE2b-256 |
75190400f90d6335c6a6ce4db8caea8d6da36b3065b5c197ff983c528a5bfff8
|
Provenance
The following attestation bundles were made for lavendersim-0.2.0-py3-none-musllinux_1_2_x86_64.whl:
Publisher:
publish.yml on cloneofsimo/lavendersim
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
lavendersim-0.2.0-py3-none-musllinux_1_2_x86_64.whl -
Subject digest:
afb0b846666550d78f077b29ab1bd17f88d62574fcd9c3aabd5efb7457714658 - Sigstore transparency entry: 2164714980
- Sigstore integration time:
-
Permalink:
cloneofsimo/lavendersim@b751f79434f8e5cfceae2beaac3332440880e18b -
Branch / Tag:
refs/heads/main - Owner: https://github.com/cloneofsimo
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@b751f79434f8e5cfceae2beaac3332440880e18b -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file lavendersim-0.2.0-py3-none-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl.
File metadata
- Download URL: lavendersim-0.2.0-py3-none-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl
- Upload date:
- Size: 126.1 kB
- Tags: Python 3, manylinux: glibc 2.28+ x86-64, manylinux: glibc 2.5+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
380e154f82853b155622e116bbff426c1ebf4073a5ca43ea0c2e90360e39538a
|
|
| MD5 |
fce1e6fb7de57d3ae7366512b06d306c
|
|
| BLAKE2b-256 |
c8213da2aff06efbff309699ab91887fa9562aafd69891f5584b3bc4cf2fcda3
|
Provenance
The following attestation bundles were made for lavendersim-0.2.0-py3-none-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl:
Publisher:
publish.yml on cloneofsimo/lavendersim
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
lavendersim-0.2.0-py3-none-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl -
Subject digest:
380e154f82853b155622e116bbff426c1ebf4073a5ca43ea0c2e90360e39538a - Sigstore transparency entry: 2164714658
- Sigstore integration time:
-
Permalink:
cloneofsimo/lavendersim@b751f79434f8e5cfceae2beaac3332440880e18b -
Branch / Tag:
refs/heads/main - Owner: https://github.com/cloneofsimo
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@b751f79434f8e5cfceae2beaac3332440880e18b -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file lavendersim-0.2.0-py3-none-macosx_11_0_x86_64.whl.
File metadata
- Download URL: lavendersim-0.2.0-py3-none-macosx_11_0_x86_64.whl
- Upload date:
- Size: 135.0 kB
- Tags: Python 3, macOS 11.0+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
077698d1f173d9a48f310d6ac25bb8f565c7f0c7f76f033d46358608d49433a8
|
|
| MD5 |
bb6574da13fff83cce01e1a6cf9176e6
|
|
| BLAKE2b-256 |
fb379bf4899321a7cc027ebef3740d5b4ca708c3ecdc319abd149aab3a3ddb42
|
Provenance
The following attestation bundles were made for lavendersim-0.2.0-py3-none-macosx_11_0_x86_64.whl:
Publisher:
publish.yml on cloneofsimo/lavendersim
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
lavendersim-0.2.0-py3-none-macosx_11_0_x86_64.whl -
Subject digest:
077698d1f173d9a48f310d6ac25bb8f565c7f0c7f76f033d46358608d49433a8 - Sigstore transparency entry: 2164715197
- Sigstore integration time:
-
Permalink:
cloneofsimo/lavendersim@b751f79434f8e5cfceae2beaac3332440880e18b -
Branch / Tag:
refs/heads/main - Owner: https://github.com/cloneofsimo
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@b751f79434f8e5cfceae2beaac3332440880e18b -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file lavendersim-0.2.0-py3-none-macosx_11_0_arm64.whl.
File metadata
- Download URL: lavendersim-0.2.0-py3-none-macosx_11_0_arm64.whl
- Upload date:
- Size: 116.7 kB
- Tags: Python 3, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
55dffb3a4455d9d228e0a9486ba9d7e8d046f9d73a6d5365600aceab5185ba16
|
|
| MD5 |
c19c90494bddd7557fbc8311601409c7
|
|
| BLAKE2b-256 |
84756926847720877a2d1caf015b3b1f3e96871c76547d7ef0f7528f12c3d8c4
|
Provenance
The following attestation bundles were made for lavendersim-0.2.0-py3-none-macosx_11_0_arm64.whl:
Publisher:
publish.yml on cloneofsimo/lavendersim
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
lavendersim-0.2.0-py3-none-macosx_11_0_arm64.whl -
Subject digest:
55dffb3a4455d9d228e0a9486ba9d7e8d046f9d73a6d5365600aceab5185ba16 - Sigstore transparency entry: 2164715617
- Sigstore integration time:
-
Permalink:
cloneofsimo/lavendersim@b751f79434f8e5cfceae2beaac3332440880e18b -
Branch / Tag:
refs/heads/main - Owner: https://github.com/cloneofsimo
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@b751f79434f8e5cfceae2beaac3332440880e18b -
Trigger Event:
workflow_dispatch
-
Statement type: