A CLI, library, and local server for interacting with the Tektonian backend.
Project description
Simulac
⚡️ Full-stack robot framework
Simulac is a full-stack robot framework for robotics engineers who want a unified API for robot simulation, scene building, and hosted robot benchmarks.
Simulac supports:
- Integrated physics engines
- Simulac provides an abstraction layer over industry-standard physics engines
- Mujoco is default local runtime. Mujoco Warp, Newton and Genesis will be added in the future
- Digital twin building
- Simulac provides fully curated assets for digital twin
- Use assets with simple entity constructors
Stuff("Robocasa/mug/mug_01") - Export and load environment definitions as JSON for reuse, review, and experiment setup
- Robot benchmark
- Run hosted robot benchmarks without manually reproducing benchmark infrastructure
- Reduce setup frictions and speed up iteration
Contents
- Installation
- Robot Framework
- Local World Building
- Runtime API
- Randomization and Constraints
- Hosted Benchmark
- CLI
- Authentication
- Configuration
- Development
- Project Status
- License
Installation
Simulac requires Python 3.12 or later.
Install with pip:
pip install simulac
Or install with uv:
uv add simulac
Robot Framework
Simulac's local Environment API separates scene definition from runtime
mutation:
- Create an
Environment. - Add entities such as
Stuff,Robot,Camera, and lights. - Mutate build-time properties before creating a runner.
- Create a
Runner, which freezes the scene definition. - Use runtime handles for live simulation changes.
from simulac import Camera, Environment, Robot, Runner, Stuff
env = Environment(default_engine="mujoco")
table = env.add_entity(
Stuff("path/to/table.xml"),
entity_id="table",
pos=(0.0, 0.0, 0.0),
fixed=True,
)
cube = env.add_entity(
Stuff("path/to/cube.xml"),
entity_id="cube",
pos=(0.4, 0.0, 0.8),
)
robot = env.add_entity(
Robot("path/to/franka_panda.xml"),
entity_id="panda",
)
camera = env.add_entity(
Camera(type="rgb"),
entity_id="front_rgb",
pos=(0.8, -0.8, 1.2),
)
cube.set_mass(0.12)
cube.set_friction(1.0)
runner = Runner(env, 0, 5, runtime_engine="mujoco")
state = runner.reset(seed=0)
Build-time object handles include:
| Handle | Common operations |
|---|---|
StuffObject |
set_pos, set_rot, set_size, set_mass, set_fixed, set_friction, collider, joint, anchor |
RobotObject |
set_pos, set_rot, set_joint_pos, collider, joint, anchor |
CameraObject |
set_pos, set_rot, set_fov, look_at, attach_to, follow |
Save a scene
env.save_env("scene.json", overwrite=True)
Load a scene
loaded_env = Environment("scene.json", default_engine="mujoco")
Local World Building
Local world building uses entity definitions and object handles.
from simulac import AreaLight, Camera, Environment, Robot, Stuff
env = Environment(default_engine="mujoco")
table = env.add_entity(Stuff("path/to/table.xml"), entity_id="table", fixed=True)
robot = env.add_entity(Robot("path/to/robot.xml"), entity_id="robot")
camera = env.add_entity(Camera(type="rgb"), entity_id="front_rgb")
light = env.add_entity(AreaLight(intensity=0.8), entity_id="main_light")
camera.look_at(table.anchor("workspace_center"))
camera.attach_to(robot.anchor("camera_mount"))
Objects can expose named references for placement, constraints, and runtime lookup:
top = table.collider("top")
mount = table.anchor("robot_mount")
joint = robot.joint("joint1")
Environment definitions can be exported as JSON:
scene_json = env.dump_env_json(indent=2)
env.save_env("scene.json", overwrite=True)
Runtime API
After a runner is created, use runtime handles for live simulation state.
cube_rt = runner.get_runtime_object(cube)
robot_rt = runner.get_runtime_object(robot)
camera_rt = runner.get_runtime_object(camera)
cube_rt.change_pos((0.42, 0.05, 0.82))
cube_rt.change_mass(0.20)
cube_rt.change_friction(0.9)
robot_rt.change_joint_pos([0.0] * 7)
robot_rt.set_control([0.0] * 7)
livcamera_rte_camera.change_fov(60.0)
state = runner.tick()
image = runner.render(camera, width=640, height=480)
Runtime robot handles expose robot state by joint, site, link, and sensor name:
joint = robot_rt.joint("joint1")
site = robot_rt.site("gripper")
link = robot_rt.link("link7")
sensor = robot_rt.sensor("force_sensor")
For engine-specific work, access the native context:
ctx = runner.context("mujoco")
model = ctx.model
data = ctx.data
Randomization and Constraints
Randomization specs are sampled during reset. Constraints are used to reject invalid reset candidates.
from simulac import Constraint, Environment, Randomize, Stuff
env = Environment(default_engine="mujoco")
block = env.add_entity(Stuff("path/to/block.xml"), entity_id="block")
goal = env.add_entity(
Stuff("path/to/goal_marker.xml"),
entity_id="goal",
fixed=True,
)
block.set_pos(
Randomize.uniform(
(0.25, -0.20, 0.80),
(0.55, 0.20, 0.80),
constraints=[
Constraint.distance("block", "goal", min=0.15, max=0.50),
],
)
)
block.set_mass(Randomize.choice(0.08, 0.12, 0.16))
Randomization helpers:
Randomize.uniform(min, max)Randomize.normal(mean, std, clip_min=None, clip_max=None)Randomize.choice(*values)
Constraint helpers:
Constraint.distance(a, b, min=None, max=None)Constraint.bbox(target, lower, upper, mode="inside")Constraint.nonpenetration(*between)
Hosted Benchmark
Run a Benchmark
from simulac.gym_style import init_bench
env = init_bench(
"Tektonian/Libero",
"libero_90/KITCHEN_SCENE2_put_the_black_bowl_at_the_back_on_the_plate",
0,
{"control_mode": "OSC_POSE"},
)
obs, info = env.reset(seed=0)
obs, reward, done, info = env.step([0.0] * 7)
env.close()
init_bench() accepts:
| Parameter | Description |
|---|---|
benchmark_id |
Benchmark owner and name, for example Tektonian/Libero |
env_id |
Benchmark scene or task id |
seed |
Initial seed used to build the remote environment |
benchmark_specific |
Benchmark-specific options such as controller mode |
Visit our website to see all available benchmarks
Authentication
Remote benchmark execution requires a Tektonian API key.
Go to our website and get an API key.
Store your API key with CLI command:
simulac auth login
You can also provide the key through an environment variable:
export SIMULAC_API_KEY=<your_api_key>
Note: API keys can only be viewed once when created
Check the active credential:
simulac auth whoami
Remove the locally stored API key:
simulac auth logout
List Available Environments
simulac benchmark list Tektonian/Libero
from simulac.gym_style import get_env_list
env_ids = get_env_list("Tektonian/Libero")
Visit the Tektonian benchmark page to see available benchmarks:
https://tektonian.com/benchmark
Step Multiple Environments
make_vec() steps multiple hosted environments concurrently and returns results
in the same order as the input environment list.
from simulac.gym_style import init_bench, make_vec
args = (
"Tektonian/Libero",
"libero_90/KITCHEN_SCENE2_put_the_black_bowl_at_the_back_on_the_plate",
0,
)
options = {"benchmark_specific": {"control_mode": "OSC_POSE"}}
envs = [init_bench(*args, **options) for _ in range(3)]
vec_env = make_vec(envs)
reset_results = vec_env.reset([0, 1, 2])
step_results = vec_env.step([[0.0] * 7 for _ in envs])
vec_env.close()
CLI
Configuration
Simulac reads configuration from environment variables when present:
SIMULAC_API_KEY: use an API key without runningsimulac auth loginSIMULAC_BASE_URL: override the default Tektonian API endpointSIMULAC_LOG_LEVEL: set log verbosity. choose one ofoff, trace, debug, info, warning, errorSIMULAC_TELEMETRY=off: disable telemetry
Development
For development, start with:
- See
CONTRIBUTING.md - Read
docs/README.md - Read docs in
docs/internal
Project Status
Simulac is currently alpha software.
- -
The remote benchmark client is the most complete public surface.(with version 0.1.0 at 01-06-2026 ) - -
Local world-building and runner APIs are still evolving.(with version 0.1.0 at 01-06-2026) - - Support parallel
Runner - - GUI for build
Environment - - Add more physics engine adapters
- - Mujoco Warp
- - Newton
- - Genesis
License
Apache-2.0
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
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 simulac-0.1.0.tar.gz.
File metadata
- Download URL: simulac-0.1.0.tar.gz
- Upload date:
- Size: 114.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.11 {"installer":{"name":"uv","version":"0.10.11","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2d0603dfeeb09cd5a9e4598cd947b80bfdf0661618a95e3bf5b854b804f18159
|
|
| MD5 |
8a8bd0257a53d788081b469b91ed8da1
|
|
| BLAKE2b-256 |
80ffde0501008dd75c7e3168bd6eef858bda81ef9fc05b25e5a6697469406a02
|
File details
Details for the file simulac-0.1.0-py3-none-any.whl.
File metadata
- Download URL: simulac-0.1.0-py3-none-any.whl
- Upload date:
- Size: 154.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.11 {"installer":{"name":"uv","version":"0.10.11","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9d37b33553cfc3b828afa1685eac90c520c34fd5e6b32e90d2cfb2bee46ba0ee
|
|
| MD5 |
a53c56a7ca43b7ec2af4e48fed816ddc
|
|
| BLAKE2b-256 |
dca797bf9223a069b49f7a8fe0a00082b460234cae955699d84229b08592d978
|