Metadata-Version: 2.4
Name: alloy-engine
Version: 0.1.0rc2
Summary: Alloy: a multi-material, parallel physics engine for robot learning, built on Newton and MuJoCo Warp
License-Expression: Apache-2.0
Requires-Python: <3.13,>=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
License-File: NOTICE
Requires-Dist: mujoco==3.17.0
Requires-Dist: warp-lang==1.18.0
Requires-Dist: numpy
Requires-Dist: scipy
Requires-Dist: pyyaml
Requires-Dist: absl-py
Requires-Dist: etils[epath]
Provides-Extra: mesh
Requires-Dist: pytetwild==0.2.3; extra == "mesh"
Requires-Dist: coacd; extra == "mesh"
Provides-Extra: import
Requires-Dist: trimesh; extra == "import"
Requires-Dist: manifold3d; extra == "import"
Requires-Dist: coacd; extra == "import"
Requires-Dist: pillow; extra == "import"
Requires-Dist: huggingface_hub; extra == "import"
Requires-Dist: scikit-image==0.25.2; extra == "import"
Provides-Extra: barcode
Requires-Dist: zxing-cpp==3.1.1; extra == "barcode"
Provides-Extra: envs
Requires-Dist: torch; extra == "envs"
Requires-Dist: huggingface_hub; extra == "envs"
Provides-Extra: usd
Requires-Dist: usd-core<26.9,>=25.5; platform_machine != "aarch64" and extra == "usd"
Requires-Dist: usd-exchange<4,>=2.3.0; platform_machine == "aarch64" and extra == "usd"
Requires-Dist: newton-usd-schemas<0.7,>=0.6.0; extra == "usd"
Provides-Extra: il
Requires-Dist: h5py; extra == "il"
Provides-Extra: viewer
Requires-Dist: viser>=1.1.1; extra == "viewer"
Requires-Dist: pyglet<3,>=2.1.6; extra == "viewer"
Requires-Dist: imgui_bundle>=1.92.0; extra == "viewer"
Dynamic: license-file

# Alloy

**Install:** `git clone https://github.com/argonrobotics-ai/alloy && cd alloy && bash install.sh` (Linux x86_64,
or macOS on Apple silicon; it brings its own Python 3.12 if needed), then the quick start below. Inside a Python
3.11 or 3.12 virtual environment, `pip install alloy-engine` works too.

Alloy is a physics engine for robot learning, built on [Newton](https://github.com/newton-physics/newton),
[MuJoCo Warp](https://github.com/google-deepmind/mujoco_warp) and [Warp](https://github.com/NVIDIA/warp): rigid
bodies and robots step in MuJoCo Warp (MuJoCo C on the CPU), cloth and soft bodies in Newton's VBD, sand and pastes
in Newton's MPM, liquids in Alloy's own DFSPH. One scene can hold rigid robots (sub-millimetre contact for declared
precision fits such as pegs and threads), cloth and soft bodies, liquids, granular material, cables and objects that
cut or tear, stepped together in parallel worlds on one NVIDIA GPU: thousands for free rigid bodies, hundreds for a
robot arm, tens to hundreds with cloth or liquid (`docs/guide/worlds.md` has the measured rows). Without a GPU
everything runs on the CPU, slowly.

The guide names the scene, hardware and run behind each number; rows and commands ship for some. Known engine
limits, each with its size and workaround, are listed in `docs/known_gaps/` (`docs/guide/known_limits.md`).

Objects are described once as **cards** (YAML: shape plus material values with their sources); a router picks the
solver for
each (MuJoCo Warp for rigid bodies, VBD for cloth and soft bodies, DFSPH for liquids, ...), and one `Simulation`
loop steps them together.

> Status: early public release (0.x). APIs may change between minor versions.

## Install

Linux x86_64 (CPU or NVIDIA GPU) or macOS on Apple silicon (CPU). Linux aarch64 installs the same way but is not
tested yet. Newton and MuJoCo Warp come inside Alloy; Warp, MuJoCo and the rest come from PyPI.

The surest way is a clone and `install.sh`. It makes a fresh `.venv` with Python 3.12 (fetched with
[uv](https://docs.astral.sh/uv/) if the machine has none, without changing your PATH), installs Alloy's wheel from
this repository's GitHub Release (checksum checked) and runs the quick start below as a check. On a machine where
it finds an NVIDIA GPU it also adds PyTorch (the `envs` extra, about 3 GB; `--no-torch` skips it):

```bash
git clone https://github.com/argonrobotics-ai/alloy && cd alloy
bash install.sh                 # --extras import,mesh adds the extras below; --cpu checks on the CPU; --help
source .venv/bin/activate
```

Or with pip, inside a Python 3.11 or 3.12 virtual environment you made (`python3 -m venv .venv && source
.venv/bin/activate`). A stock Ubuntu 24.04 refuses pip outside a virtual environment (PEP 668,
"externally-managed-environment"), and its `python3 -m venv` fails until `sudo apt install python3-venv`;
`install.sh` needs neither:

```bash
pip install alloy-engine                       # the import name is alloy
python -c "import alloy; print(alloy.__version__)"
pip install "alloy-engine[import,mesh]"        # optional extras (below)
```

Extras: `import` (the object library below, mesh import, `collision="decompose"`), `mesh` (soft bodies from
meshes), `envs` (PyTorch and `huggingface_hub`, for the Gym envs and torch camera images) and `barcode`. In a clone
set up with `install.sh`, add them with `bash install.sh --extras import,mesh` (it keeps the pinned packages).

**NVIDIA GPU:** the pinned Warp (`warp-lang` 1.18.0) needs an R580-series or newer NVIDIA driver and a Turing
(`sm_75`: T4, RTX 20 series) or newer GPU (Warp's install notes). Stock cloud images often ship without a driver:
install one first (`nvidia-smi` then lists the GPU). Without a GPU it can use, Alloy runs on the CPU (`install.sh`
says which device it found, and what to do when the GPU has no driver). On a fresh Ubuntu machine with an NVIDIA
GPU:

```bash
sudo ubuntu-drivers install && sudo reboot     # the NVIDIA driver (or start from a CUDA image instead)
nvidia-smi                                     # after the reboot: lists the GPU
git clone https://github.com/argonrobotics-ai/alloy && cd alloy
bash install.sh                                # finds the GPU and adds PyTorch; --no-torch skips it
```

A C compiler lets CPU robot scenes use MuJoCo's C step (gcc on Linux; on a Mac, Apple's command line tools:
`xcode-select --install`); without one they run on a slower fallback, and Alloy says so.

Developer install from a clone (nothing is built: the engine is Python and Warp kernels):

```bash
python3.12 -m venv .venv
.venv/bin/pip install -e ".[dev]"
```

The first run compiles Warp kernels (1-3 minutes on a CPU, about 2 minutes on a GPU); they are cached in
`~/.cache/warp`, so later runs start in seconds.

AI agents: start with [AGENTS.md](AGENTS.md) (quick start); index of all docs in [llms.txt](llms.txt).

## Quick start

Drop a box onto a table and save its trajectory (`size` is full edge lengths in metres; under a minute on a CPU
once kernels are cached):

```python
import alloy

scene = alloy.Scene(dt=0.005)                       # control period: 5 ms per step
scene.add_ground()
scene.add_box("table", size=(0.8, 0.8, 0.70), pos=(0, 0, 0.35), static=True)   # top at z = 0.70 m
scene.add_box("box", size=(0.08, 0.08, 0.08), pos=(0, 0, 0.90), mass=0.5)     # kg
sim = alloy.build(scene)                            # GPU if there is one, else CPU
traj = sim.run(1.5, record=["box"])                 # traj["box.pos"]: (frames, worlds, 3)
traj.world(0).save("drop.npz")                      # t, box.pos, box.quat_wxyz, ...
z = float(traj.world(0)["box.pos"][-1, 2])
print(f"box rests at z = {z:.3f} m, health ok: {sim.check()['ok']}")   # 0.740: table top + half the box
assert abs(z - 0.74) < 0.005
```

More: `examples/api/` (a gripper lift, many parallel worlds, cloth, liquid) and `AGENTS.md`.

## Object library

The starter library in `library/` (materials, contact pairs, 118 objects, demo scenes, robot models) ships with
Alloy. About 5,400 more object cards, with collision hulls and estimated mass and friction, are a public Hugging
Face dataset, `argonrobotics-ai/alloy-library`, kept outside this repository: 1,111 YCB and Google Scanned Objects
scans; 1,989 Objaverse objects; 1,900 kitchen objects and fixtures made by Lightwheel (NVIDIA's
PhysicalAI-Robotics-Manipulation-Objects-Kitchen-MJCF dataset, CC BY 4.0, as packaged by RoboCasa, with our
collision hulls, estimated masses and materials; no RoboCasa kitchens or tasks); and 393 cards from Gym-Anything,
one per rigid part of its articulated objects. 263 of the kitchen cards carry a flag for a failed mass, size or
physics check. The cards record where each mass comes from: measured or from a catalogue for 64 of the YCB and
Google Scanned objects, an estimate from the object's category or mesh volume for more than 9 in 10 (the note says
ESTIMATE); friction is that of the library material the card names, not measured per object. Each one has its
card, meshes, convex hulls, textures and a thumbnail. Alloy downloads only the objects you ask for, into
`~/.cache/alloy/imports/<library>/`; no account or login is needed. Fetching needs the `import` extra (it brings
`huggingface_hub`): `bash install.sh --extras import` in a clone set up with `install.sh`, or
`pip install "alloy-engine[import]"`. With the extra, a build also fetches a Hub object you name that is not on
disk yet; without it, `add_object` raises `SceneError` for any object not on disk, its fix naming the extra and
`alloy fetch <name>`. To fetch ahead of time:

```bash
alloy fetch --list --library ycb_gso                 # what there is; nothing is downloaded
alloy fetch ycb_025_mug ycb_024_bowl                 # objects by name; files you already have are not downloaded again
alloy fetch --library robocasa --category blenders   # one category; --library alone fetches a whole library (GBs)
```

Then use them by card name: `scene.add_object("mug", "ycb_025_mug", pos=(0, 0, 0.1))`, or
`alloy compose "a mug and a bowl on a table"`. `ALLOY_CACHE` moves the download folder. Each object's card records
the licence its source declares (CC BY 4.0, MIT, CC0 1.0 or Apache-2.0) and, in the comment at its top, the credit
to give (the dataset's `ATTRIBUTION.md` collects them); check both before you share an object or an image of it, or
use it commercially. More: `docs/guide/fetch.md`.

## What is in the box

| Path | What |
|---|---|
| `alloy/` | the engine package: cards, scene assembly, solvers, contact, coupling, precision, parallel worlds |
| `library/` | the starter card library: materials (values with their sources), contact pairs, objects, scenes, robots |
| `tests/` | unit, law and integration tests (`pytest`) |
| `bench/` | the benchmark harness: analytic laws, scenarios, goldens and the scoreboard |
| `docs/guide/` | one page per topic |
| `examples/` | runnable scripts (index: `examples/README.md`) |

## Tests

```bash
scripts/ci_cpu.sh                                  # warms the Warp cache, then the CPU suite
.venv/bin/python -m pytest tests -m "not gpu and not slow" -q
```

GPU tests (`-m gpu`) need an NVIDIA GPU and skip cleanly without one.

## Built on

Alloy's physics core is built on [Newton](https://github.com/newton-physics/newton) and
[MuJoCo Warp](https://github.com/google-deepmind/mujoco_warp) (both Apache-2.0), on
[Warp](https://github.com/NVIDIA/warp). Rigid bodies and robots step in MuJoCo Warp through Newton's `SolverMuJoCo`
(in MuJoCo C on the CPU), cloth and soft bodies in Newton's `SolverVBD`, sand and pastes in Newton's implicit MPM
solver, and liquids in Alloy's own DFSPH solver. Newton and MuJoCo Warp ship inside Alloy as `alloy/_vendor/newton`
(with our fixes) and `alloy/_vendor/mujoco_warp` (files unchanged), with their own names, licences and copyright
headers; [alloy/_vendor/VENDORED.md](alloy/_vendor/VENDORED.md) lists the upstream commit each starts from and every
change we made. By default Alloy replaces some of MuJoCo Warp's solver and collision steps at run time (listed in
the same file).

Installing Alloy does not install or replace a `newton` or `mujoco-warp` package of your own, but it pins
`mujoco==3.17.0` and `warp-lang==1.18.0` (from PyPI) and replaces other versions of those two in the
environment. A `newton` or `mujoco-warp` of your own can share the environment only if it accepts exactly those
versions; otherwise keep it in its own virtual environment.

## Licence

Apache-2.0 (see `LICENSE`). Third-party code, robot models and data keep their own licences; see `NOTICE`.
Contributions: `CONTRIBUTING.md`. Security reports: `SECURITY.md`.
