# ZOZO's Contact Solver: a GPU contact engine for cloth, solids, rods and sand

> st-tech/ppf-contact-solver is an Apache-2.0 FEM physics engine from ZOZO, Inc. that runs contact and elasticity on the GPU and ships a Blender add-on. Here is how it installs, what it refuses to do, and who should wait.

**st-tech/ppf-contact-solver** — A contact solver for physics-based simulations involving 👚 shells, 🪵 solids, 🪢 rods, 🧱 rigid bodies and ⏳ sand.

- Repository: https://github.com/st-tech/ppf-contact-solver
- Stars: 4,512 · Forks: 336
- Language: Python
- License: Apache-2.0
- Published: 2026-09-23 · Updated: 2026-09-23 · Language: en
- Canonical page: https://hysenlabs.com/projects/st-tech-ppf-contact-solver

## What ZOZO's Contact Solver actually solves

The project began as an in-house physics engine at ZOZO, Inc., a Japanese fashion e-commerce company, and the README describes it as now evolving with the community. The problem it targets is the one that shows up when simulated objects touch: cloth draped over a body, a rod tied in a knot, rigid blocks stacked on sand. The README lists shells, solids, rods, rigid bodies and sand as the supported object types, and the headline claim is that on success the result is 100% penetration-free, meaning no snagging intersections between surfaces.

The intended audience is narrow. This is not a game engine and not a real-time tool. The README's own disclaimer says it is offline, not real time, and that other recent work reports faster results. The people who get value from it are technical artists and researchers who already work in Blender or JupyterLab, who can accept an offline solve, and who care more about intersection-free contact than about frame rate. The fabric presets are calibrated against real measurements, which points at garment and textile work as the original motivation.

## Rust crates, a CUDA driver and a PyO3 extension: how the pieces fit

The repository is a Cargo workspace. Cargo.toml lists six members: ppf-cts-formats, ppf-cts-compute, ppf-cts-core, ppf-cts-py, ppf-cts-server and ppf-cts-solver. A release build at the workspace root produces three artifacts, all landing in target/release/: the CUDA solver driver binary named ppf-contact-solver, the tokio-based host ppf-cts-server, and a PyO3 cdylib called _ppf_cts_py. The first two are libraries built transitively.

The Python side is unusual. ppf-cts-py is built as a plain cargo cdylib, and the Cargo.toml comments state there is no maturin wheel step. Instead, frontend/__init__.py loads target/<profile>/lib_ppf_cts_py.so or .dylib, or _ppf_cts_py.dll on Windows, directly through importlib, so the extension is never installed into a venv or site-packages. That means the Python API is bound to the build tree you compiled, not to a pip package.

Backend selection is decided at compile time. On macOS, cargo build --release selects Metal; on a host with no GPU toolkit the build hard-errors and names what it looked for. The comments are explicit that there is no fallback build, so a tree either holds a real backend or holds nothing. The Dockerfile adds a CPU backend beside the CUDA one deliberately, because the runtime stage is plain ubuntu:24.04 and starts without --gpus, and a container that ships only the CUDA backend would come up and then fail at its first solve. With both present, the frontend's automatic rule answers with the CPU backend and prints why.

## Installing ZOZO's Contact Solver and running a first example

The README gives four native paths (macOS, Windows, Linux, Docker) plus a Blender add-on. On macOS and Linux the local entry point is the launcher script at the repository root, which brings up JupyterLab in the browser.

```bash
./ppf-contact-solver
```

On Windows the README says to double click start.bat instead. Either way you should end up with a JupyterLab session; the README's quick-look section shows clicking the printed URL and exploring the shipped examples.

For a container, the Dockerfile is built from nvidia/cuda:12.8.0-devel-ubuntu24.04, installs python3 and python3-venv, runs warmup.py with --skip-confirmation, and then builds with cargo. The README puts the image at roughly 1GB and says Docker covers Linux and Windows.

```bash
docker build -t ppf-contact-solver .
docker run -it ppf-contact-solver
```

The examples directory is the fastest way to see whether the solver is right for you: curtain.ipynb, drape.ipynb, fitting.ipynb, fishingknot.ipynb, domino.ipynb, stack.ipynb and others sit alongside a headless.py script and a fail-examples directory. Open one notebook, run its cells, and watch the solver output. If you want the Blender route instead, the README points at install-blender-addon.sh, install-blender-addon.ps1 and install-blender.sh in the repository root, and warns that add-on setup is not one click because the solver backend is deployed separately, locally or remotely.

## Where ZOZO's Contact Solver is the wrong tool

The README's disclaimer section is unusually blunt, and it is the most useful part of the page. Four limitations decide adoption on their own.

First, the solver is not differentiable. There are no gradients, so inverse design and learning are out of scope. If your workflow needs to backpropagate through a contact simulation, this project cannot help you and no amount of GPU speed changes that.

Second, it is not production ready. The README states that many bugs remain, including undiscovered ones, and points at the Issues page for known ones. That is a fair description of a research-grade engine.

Third, hardware support is uneven in a way that is easy to miss. CPU and Metal backends are described as slow and meant for evaluation, learning and small examples, with larger scenes needing a powerful GPU. The ROCm backend for AMD GPUs has, in the README's words, never run on real AMD hardware; the project relies on community bug reports. Treat any AMD path as unverified.

Fourth, the pacing. The README says the project is maintained by Ryoichi Ando alone, with limited time. The last push was on 2026-09-22 and releases landed the same day, so the code is moving, but a single maintainer is a real constraint on how fast your issue gets answered.

## How it differs from Blender's own cloth and collision system

The obvious alternative for anyone reading this is Blender's built-in cloth and collision simulation, which is already in the application, needs no separate backend, and runs interactively enough for look-development. The difference is the solver underneath. Blender's system is designed around artist iteration inside the DCC; ZOZO's Contact Solver is a finite element method engine with symbolic force Jacobians, and it runs both the contact and elasticity solvers on the GPU.

The practical consequence is the guarantee. The README's headline is 100% penetration-free upon success, and a separate claim says any single triangle never extends beyond strict upper bounds such as 1%. Blender's cloth solver makes no such promise, and self-intersection is a familiar problem there. The trade is workflow: with ZOZO's solver the backend is deployed separately, locally or remotely, and the Blender add-on simulates remotely and fetches results back, which the README notes works even on macOS. You give up the single-application convenience and get a contact formulation that is the point of the project.

The other difference is scale. The README cites an extreme case beyond 180M contacts, and the examples directory includes large-twist.ipynb, large-woven.ipynb and large-animals.ipynb alongside their smaller counterparts. That class of scene is not what an in-DCC cloth solver is built for.

## Conclusion

Adopt it if you need penetration-free FEM contact between shells, solids, rods and rigid bodies, and you have an NVIDIA GPU or are willing to treat CPU and Metal backends as evaluation-only. Do not adopt it if you need gradients for inverse design or learning, if you expect a one-click Blender install, or if you plan to run it on AMD hardware, since the README states the ROCm backend has never run on real AMD hardware. Before committing, run one example notebook such as examples/curtain.ipynb end to end and check whether the documented single-maintainer pace and the open bug list match what you need.

## FAQ

### Does ZOZO's Contact Solver run on AMD GPUs?

A ROCm backend exists in the tree, but the README states plainly that it has never run on real AMD hardware and that the project relies on community bug reports. Treat AMD support as unverified until that changes.

### Can I use ZOZO's Contact Solver inside Blender without installing anything else?

No. The README says add-on setup takes effort and is not one click, because the solver backend is deployed separately, locally or remotely. The add-on simulates remotely and fetches the results back to Blender.

### Is ZOZO's Contact Solver differentiable, so I can use it for inverse design?

It is not. The README's limitations list states there are no gradients, so inverse design and learning are out of scope.

### What licence does ZOZO's Contact Solver use, and can I use it commercially?

The repository is licensed Apache-2.0, and the README describes it as a permissive license that allows commercial and proprietary use. Confirm the terms against the LICENSE file yourself before relying on them.

## Sources

- [Issues](https://github.com/st-tech/ppf-contact-solver/issues)
- [License: Apache-2.0](https://github.com/st-tech/ppf-contact-solver/blob/main/LICENSE)
- [README](https://github.com/st-tech/ppf-contact-solver/blob/main/README.md)
- [Releases](https://github.com/st-tech/ppf-contact-solver/releases)
- [st-tech/ppf-contact-solver on GitHub](https://github.com/st-tech/ppf-contact-solver)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/st-tech-ppf-contact-solver
