[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-78604":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":16,"subscribersCount":16,"size":16,"stars1d":17,"stars7d":18,"stars30d":19,"stars90d":16,"forks30d":16,"starsTrendScore":20,"compositeScore":21,"rankGlobal":10,"rankLanguage":10,"license":22,"archived":23,"fork":23,"defaultBranch":24,"hasWiki":23,"hasPages":25,"topics":26,"createdAt":10,"pushedAt":10,"updatedAt":32,"readmeContent":33,"aiSummary":34,"trendingCount":16,"starSnapshotCount":16,"syncStatus":35,"lastSyncTime":36,"discoverSource":37},78604,"ppf-contact-solver","st-tech\u002Fppf-contact-solver","st-tech","A contact solver for physics-based simulations involving 👚 shells, 🪵 solids and 🪢 rods.","",null,"Python",4023,295,33,41,0,40,157,1822,120,29.41,"Apache License 2.0",false,"main",true,[27,28,29,30,31],"cloth","collision","contact","physics","simulation","2026-06-12 02:03:47","# ZOZO's Contact Solver 🫶\n\nA contact solver for physics-based simulations\ninvolving 👚 shells, 🪵 solids and 🪢 rods. All made by [ZOZO, Inc.](https:\u002F\u002Fcorp.zozo.com\u002Fen\u002F), the largest fashion e-commerce company in Japan.\n\n[![Getting Started](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Fgetting-started.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Fgetting-started.yml)\n[![All Examples](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Frun-all-once.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Frun-all-once.yml)\n[![All Examples (Windows Native)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Frun-all-once-win.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Frun-all-once-win.yml)\n[![Python API Docs](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Fmake-docs.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Fmake-docs.yml)\n[![Docker Build](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Fbuild-docker.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Fbuild-docker.yml)\n[![Build Windows](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Frelease-win.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Frelease-win.yml)\n[![Blender CI](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Fblender.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Fblender.yml)\n![solver_logo](.\u002Fasset\u002Fimage\u002Fteaser-image.jpg)\n\n> 🤖 We **highly** respect that readers expect to hear the author's original voice and tone, which we work to retain throughout. Our use of LLMs is clarified in [(Markdown)](.\u002Farticles\u002Fllm_transparency.md).\n\n## 👀 Quick Look\n\n🎨 Simulate remotely from our [Blender add-on](https:\u002F\u002Fst-tech.github.io\u002Fppf-contact-solver) (screenshots taken on macOS; you can also run locally if you have a modern NVIDIA GPU on Windows or Linux)\n\n\u003Chttps:\u002F\u002Fgithub.com\u002Fuser-attachments\u002Fassets\u002Ff266111e-7380-428b-8a3c-25eac4f039e5>\n\n🚀 Or double click `start.bat` (Windows) or run a Docker command (Linux\u002FWindows) to get it running\n\n![glance-terminal](.\u002Fasset\u002Fimage\u002Fglance-terminal.webp)\n\n🌐 Click the URL and explore our examples\n\n![glance-jupyter](.\u002Fasset\u002Fimage\u002Fglance-jupyter.webp)\n\n## ✨ Highlights\n\n- **💪 Robust**: Contact resolutions are penetration-free. No snagging intersections.\n- **⏲ Scalable**: An extreme case includes beyond 180M contacts. Not just one million.\n- **🚲 Cache Efficient**: All on the GPU runs in single precision. No double precision.\n- **🥼 Not Rubbery**: Triangles never extend beyond strict upper bounds (e.g., 1%).\n- **📐 Finite Element Method**: We use FEM for deformables and symbolic force jacobians.\n- **⚔️ Highly Stressed**: We run GitHub Actions to run stress tests [10 times in a row](#️-ten-consecutive-runs).\n- **🚀 Massively Parallel**: Both contact and elasticity solvers are run on the GPU.\n- **🪟 Windows Executable**: No installation wizard shown. Just unzip and run [(Video)](https:\u002F\u002Fzozo.box.com\u002Fs\u002F9rthkw122fyss5qxuf5mie9xywg7jzdz).\n- **🐳 Docker Sealed**: All can be deployed fast. The image is ~1GB.\n- **🌐 JupyterLab Included**: Open your browser and run examples right away [(Video)](https:\u002F\u002Fzozo.box.com\u002Fs\u002Fjgd6ijfmwee04vvnnfzapq7m2eq7cxy8).\n- **🐍 Documented Python APIs**: Our Python code is fully [docstringed](https:\u002F\u002Fst-tech.github.io\u002Fppf-contact-solver\u002Fjupyterlab_api\u002Fmodule_reference.html) and lintable [(Video)](https:\u002F\u002Fzozo.box.com\u002Fs\u002F52atrfn70vn8u07iwzbyrrz5ameczo03).\n- **☁️ Cloud-Ready**: Our solver can be seamlessly deployed on major cloud platforms.\n- **🎨 Blender Add-on**: Simulate remotely and fetch results locally, even on macOS.\n- **🤖 MCP Support**: Let a LLM run simulations for you using natural language.\n- **✨ Stay Clean**: You can remove all traces after use.\n- **📜 Permissive License**: Apache 2.0 allows commercial and proprietary use.\n\n> ⚠️ Built for offline uses; not real time. Some examples may run at an interactive rate.\n\n## 🔖 Table of Contents\n\n- [📝 Change History](#-change-history)\n- [🎓 Technical Materials](#-technical-materials)\n- [⚡️ Requirements](#️-requirements)\n- [💨 Getting Started](#-getting-started)\n  - [🪟 Windows Native Executable](#-windows-native-executable)\n  - [🐳 Docker (Linux and Windows)](#-docker-linux-and-windows)\n- [🐍 How To Use](#-how-to-use)\n  - [🎨 Blender Add-on](#-blender-add-on)\n  - [🌐 JupyterLab](#-jupyterlab)\n    - [📚 Python APIs and Parameters](#-python-apis-and-parameters)\n- [🔍 Obtaining Logs](#-obtaining-logs)\n- [🖼️ Catalogue](#️-catalogue)\n  - [🎨 Blender Add-on Examples](#-blender-add-on-examples)\n  - [🌐 JupyterLab Examples](#-jupyterlab-examples)\n  - [💰 Budget Table on AWS](#-budget-table-on-aws)\n  - [🏗️ Large Scale Examples](#️-large-scale-examples)\n- [🚀 GitHub Actions](#-github-actions)\n  - [⚔️ Ten Consecutive Runs](#️-ten-consecutive-runs)\n  - [📦 Action Artifacts](#-action-artifacts)\n- [📡 Deploying on Cloud Services](#-deploying-on-cloud-services)\n  - [📦 Deploying on vast.ai](#-deploying-on-vastai)\n  - [📦 Deploying on Scaleway](#-deploying-on-scaleway)\n  - [📦 Deploying on Amazon Web Services](#-deploying-on-amazon-web-services)\n  - [📦 Deploying on Google Compute Engine](#-deploying-on-google-compute-engine)\n- [🤝 Community Works](#-community-works)\n  - [🧩 Blender Add-ons](#-blender-add-ons)\n  - [📺 Videos](#-videos)\n  - [📰 Articles](#-articles)\n  - [📣 Sharing Your Work](#-sharing-your-work)\n- [💼 Commercial Use and Beyond](#-commercial-use-and-beyond)\n- [📬 Contributing](#-contributing)\n- [💬 Participating Discussions](#-participating-discussions)\n- [📨 Reaching the Author](#-reaching-the-author)\n- [🙏 Acknowledgements](#-acknowledgements)\n\n### 📚 Advanced Contents\n\n- 🧑 Setting Up Your Development Environment [(Markdown)](.\u002Farticles\u002Fdevelop.md#-setting-up-your-development-environment)\n- 🐞 Bug Fixes and Updates [(Markdown)](.\u002Farticles\u002Fbug.md)\n\n## 📝 Change History\n\n- (2026.04.30) Added a Blender Add-on support. See the [documentation](https:\u002F\u002Fst-tech.github.io\u002Fppf-contact-solver).\n- (2025.12.18) Added native Windows standalone executable build support [(Video)](https:\u002F\u002Fzozo.box.com\u002Fs\u002F9rthkw122fyss5qxuf5mie9xywg7jzdz).\n- (2025.11.26) Added [large-woven.ipynb](.\u002Fexamples\u002Flarge-woven.ipynb) [(Video)](https:\u002F\u002Fzozo.box.com\u002Fs\u002Fkc81msjfo4yw9eozn8i8bean0gbph0pj) to [large scale examples](#️-large-scale-examples).\n- (2025.11.12) Added [five-twist.ipynb](.\u002Fexamples\u002Ffive-twist.ipynb) [(Video)](https:\u002F\u002Fzozo.box.com\u002Fs\u002F36h8jpu5vcgc5t4xln2l68afj7izsx4h) and [large-five-twist.ipynb](.\u002Fexamples\u002Flarge-five-twist.ipynb) [(Video)](https:\u002F\u002Fzozo.box.com\u002Fs\u002Fv62q7cbfnpl3hufwwy2nmewyes2w1iw6) showcasing over 180M count. See [large scale examples](#️-large-scale-examples).\n- (2025.10.03) Massive refactor of the codebase [(Markdown)](.\u002Farticles\u002Frefactor_202510.md). Note that this change includes breaking changes to our Python APIs.\n- (2025.08.09) Added a hindsight note in [eigensystem analysis](.\u002Farticles\u002Feigensys.md) to acknowledge prior work by [Poya et al. (2023)](https:\u002F\u002Fromeric.github.io\u002F).\n- (2025.05.01) Simulation states now can be saved and loaded [(Video)](https:\u002F\u002Fzozo.box.com\u002Fs\u002F7v0exrbptvfli4o4z91pqtmz0tehdn62).\n\n\u003Cdetails>\n\u003Csummary>More history records\u003C\u002Fsummary>\n- (2025.04.02) Added 9 examples. See the [catalogue](#️-catalogue).\n- (2025.03.03) Added a [budget table on AWS](#-budget-table-on-aws).\n- (2025.02.28) Added a [reference branch and a Docker image of our TOG paper](#-technical-materials).\n- (2025.02.26) Added Floating Point-Rounding Errors in ACCD in [hindsight](.\u002Farticles\u002Fhindsight.md).\n- (2025.02.07) Updated the [trapped example](.\u002Fexamples\u002Ftrapped.ipynb) [(Video)](https:\u002F\u002Fzozo.box.com\u002Fs\u002Flnnyeqrvm86rxnwyjxhojfj0jgm5nphn) with squishy balls.\n- (2025.03.03) Added a [budget table on AWS](#-budget-table-on-aws).\n- (2025.02.28) Added a [reference branch and a Docker image of our TOG paper](#-technical-materials).\n- (2025.02.26) Added Floating Point-Rounding Errors in ACCD in [hindsight](.\u002Farticles\u002Fhindsight.md).\n- (2025.02.07) Updated the [trapped example](.\u002Fexamples\u002Ftrapped.ipynb) [(Video)](https:\u002F\u002Fzozo.box.com\u002Fs\u002Flnnyeqrvm86rxnwyjxhojfj0jgm5nphn) with squishy balls.\n- (2025.1.8) Added a [domino example](.\u002Fexamples\u002Fdomino.ipynb) [(Video)](https:\u002F\u002Fzozo.box.com\u002Fs\u002Fp5ksfqja1ew3c6vntco5zq6g0kgf7xoo).\n- (2025.1.5) Added a [single twist example](.\u002Fexamples\u002Ftwist.ipynb) [(Video)](https:\u002F\u002Fzozo.box.com\u002Fs\u002F4phoyyeertd2mcfv436kp2ojmo1x0eio).\n- (2024.12.31) Added full documentation for Python APIs, parameters, and log files [(GitHub Pages)](https:\u002F\u002Fst-tech.github.io\u002Fppf-contact-solver).\n- (2024.12.27) Line search for strain limiting is improved [(Markdown)](.\u002Farticles\u002Fbug.md#new-strain-limiting-line-search)\n- (2024.12.23) Added [(Bug Fixes and Updates)](.\u002Farticles\u002Fbug.md)\n- (2024.12.21) Added a [house of cards example](.\u002Fexamples\u002Fcards.ipynb) [(Video)](https:\u002F\u002Fzozo.box.com\u002Fs\u002F7c114pua0107xkz4nc3bwfdzpkhgn1o9)\n- (2024.12.18) Added a [frictional contact example](.\u002Fexamples\u002Ffriction.ipynb): armadillo sliding on the slope [(Video)](https:\u002F\u002Fzozo.box.com\u002Fs\u002F15r5o7rrowwtbrsrjjpj35v8xt92ufhr)\n- (2024.12.18) Added a [hindsight](.\u002Farticles\u002Fhindsight.md) noting that the tilt angle was not $30^\\circ$, but rather $26.57^\\circ$\n- (2024.12.16) Removed thrust dependencies to fix runtime errors for the driver version `560.94` [(Issue Link)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Fissues\u002F1)\n\u003C\u002Fdetails>\n\n## 🎓 Technical Materials\n\n#### 📘 **A Cubic Barrier with Elasticity-Inclusive Dynamic Stiffness**\n\n\u003Chttps:\u002F\u002Fgithub.com\u002Fuser-attachments\u002Fassets\u002Fac104255-604e-4890-9fb1-59732f004f0a>\n\n- 📚 Published in [ACM Transactions on Graphics (TOG) Vol.43, No.6](https:\u002F\u002Fdl.acm.org\u002Fdoi\u002Fabs\u002F10.1145\u002F3687908)\n- 🎥 Main video [(Video)](https:\u002F\u002Fzozo.box.com\u002Fs\u002Fylyv8798ue38ra5vqo2dgjhx48edy6j9)\n- 🎥 Additional video examples [(Directory)](https:\u002F\u002Fzozo.box.com\u002Fs\u002Finyyosspazk7z79zf9yeikt4xxy641g3)\n- 🎥 Presentation videos [(Short)](https:\u002F\u002Fzozo.box.com\u002Fs\u002Ffv07obu61ajn8s8s6ub9i7j9id5h4l2v) [(Long)](\u003Chttps:\u002F\u002Fzozo.box.com\u002Fs\u002F3ewlqk47bss9v39g26nlsb99qhxsc50v>)\n- 📃 Main paper [(PDF)](https:\u002F\u002Fzozo.box.com\u002Fs\u002Fckss1ejz0lbw848pg1qo7eqtvujsogy5) ([Hindsight)](.\u002Farticles\u002Fhindsight.md)\n- 📊 Supplementary PDF [(PDF)](https:\u002F\u002Fzozo.box.com\u002Fs\u002Fylqjobig0bq55eox5evjt49u2tcyqljm)\n- 🤖 Supplementary scripts [(Directory)](https:\u002F\u002Fzozo.box.com\u002Fs\u002Fm6h1t5eykdsuynx7kqr3wqi9789pfl9n)\n- 🔍 Singular-value eigenanalysis [(Markdown)](.\u002Farticles\u002Feigensys.md)\n\n##### 📌 Reference Implementation\n\nThe main branch is undergoing frequent updates and will deviate from the paper.\nTo retain consistency with the paper, we have created a new branch ```sigasia-2024```.\n\n- 🛠️ Only maintenance updates are planned for this branch.\n- 🚫 General users *should not* use this branch as it is not optimized for best performance.\n- 🚫 All algorithmic changes listed in this [(Markdown)](.\u002Farticles\u002Fbug.md) are excluded from this branch.\n- 📦 We also provide a pre-compiled Docker image: ```ghcr.io\u002Fst-tech\u002Fppf-contact-solver-compiled-sigasia-2024:latest``` of this branch.\n- 🌐 [Template Link for vast.ai](https:\u002F\u002Fcloud.vast.ai?ref_id=85288&template_id=0c7544fb5eda5ac95bf945c6b1249175)\n\n## ⚡️ Requirements\n\n- 🔥 A modern NVIDIA GPU (CUDA 12.8 or newer)\n- 💻 x86 architecture (arm64 is not supported)\n- 🐳 A Docker environment (see [below](#-docker-linux-and-windows)) or 🪟 Windows 10\u002F11 for native executable (see [below](#-windows-native-executable))\n- 🎨 Blender 5+ (only if you intend to use the Blender add-on)\n\n## 💨 Getting Started\n\nWhether you plan to use the Blender add-on or the JupyterLab interface, the solver engine itself must first be deployed. The steps below apply to both.\n\n> ⚠️ Do not run `warmup.py` locally. If you do, you are very likely to hit failures and find it difficult to cleanup.\n\n#### 🪟 Windows Native Executable\n\nFor Windows 10\u002F11 users, a self-contained executable (~320MB) is available.\nNo Python, Docker, or CUDA Toolkit installation is needed.\nAll should simply work out of the box [(Video)](https:\u002F\u002Fzozo.box.com\u002Fs\u002F9rthkw122fyss5qxuf5mie9xywg7jzdz).\n\n> 🤔 If you are cautious, you can review the [build workflow](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Frelease-win.yml) to verify safety yourself.\nWe try to maximize transparency; **we never build locally and upload.**\n\n1. Install the latest NVIDIA driver [(Link)](https:\u002F\u002Fwww.nvidia.com\u002Fen-us\u002Fdrivers\u002F)\n2. Download the latest release from [GitHub Releases](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Freleases) and unzip\n3. Double click `start.bat`\n\nJupyterLab frontend will auto-start. You should be able to access it at \u003Chttp:\u002F\u002Flocalhost:8080>.\n\n#### 🐳 Docker (Linux and Windows)\n\nInstall a NVIDIA driver [(Link)](https:\u002F\u002Fwww.nvidia.com\u002Fen-us\u002Fdrivers\u002F) on your host system and follow the instructions below specific to the operating system to get a Docker running:\n\n🐧 Linux | 🪟 Windows\n----|----\nInstall the Docker engine from here [(Link)](https:\u002F\u002Fdocs.docker.com\u002Fengine\u002Finstall\u002F). Also, install the NVIDIA Container Toolkit [(Link)](https:\u002F\u002Fdocs.nvidia.com\u002Fdatacenter\u002Fcloud-native\u002Fcontainer-toolkit\u002Flatest\u002Finstall-guide.html). Just to make sure that the Container Toolkit is loaded, run `sudo service docker restart`. | Install the Docker Desktop [(Link)](https:\u002F\u002Fdocs.docker.com\u002Fdesktop\u002Fsetup\u002Finstall\u002Fwindows-install\u002F). You may need to log out or reboot after the installation. After logging back in, launch Docker Desktop to ensure that Docker is running.\n\nNext, run the following command to start the container. If no edits are needed, just copy and paste:\n\n##### 🪟 Windows (PowerShell)\n\n```bash\n$MY_WEB_PORT = 8080      # JupyterLab port on your side\n$MY_BLENDER_PORT = 9090  # Solver port for the Blender add-on\n$IMAGE_NAME = \"ghcr.io\u002Fst-tech\u002Fppf-contact-solver-compiled:latest\"\ndocker run --rm -it `\n  --name ppf-contact-solver `\n  --gpus all `\n  -p ${MY_WEB_PORT}:${MY_WEB_PORT} `\n  -p ${MY_BLENDER_PORT}:${MY_BLENDER_PORT} `\n  -e WEB_PORT=${MY_WEB_PORT} `\n  $IMAGE_NAME # Image size ~1GB\n```\n\n##### 🐧 Linux (Bash\u002FZsh)\n\n```bash\nMY_WEB_PORT=8080      # JupyterLab port on your side\nMY_BLENDER_PORT=9090  # Solver port for the Blender add-on\nIMAGE_NAME=ghcr.io\u002Fst-tech\u002Fppf-contact-solver-compiled:latest\ndocker run --rm -it \\\n  --name ppf-contact-solver \\\n  --gpus all \\\n  -p ${MY_WEB_PORT}:${MY_WEB_PORT} \\\n  -p ${MY_BLENDER_PORT}:${MY_BLENDER_PORT} \\\n  -e WEB_PORT=${MY_WEB_PORT} \\\n  $IMAGE_NAME # Image size ~1GB\n```\n\nThe image download shall be started.\nOur image is hosted on [GitHub Container Registry](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Fpkgs\u002Fcontainer\u002Fppf-contact-solver-compiled) (~1GB).\nJupyterLab will then auto-start.\nEventually you should be seeing:\n\n```\n==== JupyterLab Launched! 🚀 ====\n     http:\u002F\u002Flocalhost:8080\n    Press Ctrl+C to shutdown\n================================\n```\n\nNext, open your browser and navigate to \u003Chttp:\u002F\u002Flocalhost:8080>. The port `8080` can change if you change the `MY_WEB_PORT` variable.\nKeep your terminal window open.\nNow you are ready to go! 🎉\n\n#### 🛑 Shutting Down\n\nTo shut down the container, just press `Ctrl+C` in the terminal.\nThe container will be removed and all traces will be cleaned up. 🧹\n\n> If you wish to keep the container running in the background, replace `--rm` with `-d`. To shutdown the container and remove it, run `docker stop ppf-contact-solver && docker rm ppf-contact-solver`.\n\n#### 🔧 Advanced Installation\n\nIf you wish to build the docker image from scratch, please refer to the cleaner installation guide [(Markdown)](.\u002Farticles\u002Finstall.md).\n\n## 🐍 How To Use\n\nWe provide two frontends: a Blender add-on and a JupyterLab interface. The Blender add-on lets you build scenes and run simulations entirely within Blender's UI, while JupyterLab lets you script everything in Python from your browser. Both communicate with the same solver engine, so pick whichever you like.\n\nIn both cases, you can interact with the simulator on your laptop while the actual simulation runs on a remote headless server over the internet.\nThis means that **you don't have to own NVIDIA hardware**, but can rent it at [vast.ai](https:\u002F\u002Fvast.ai) for less than $0.5 per hour.\nThat said, if you do have a modern NVIDIA GPU on a local Windows or Linux machine, you can also run the solver directly on it.\nActually, this [(Video)](https:\u002F\u002Fzozo.box.com\u002Fs\u002Fjgd6ijfmwee04vvnnfzapq7m2eq7cxy8) was recorded on a [vast.ai](https:\u002F\u002Fvast.ai) instance.\nThe experience is good! 👍\n\n### 🎨 Blender Add-on\n\nOur Blender add-on aims to offer a familiar UI that best feels like everything works locally, but under the hood, it communicates with a remote server where **all** simulations run, and then the results are fetched back.\n\nThis provides a unique experience where users can leverage powerful **remote** GPUs while working seamlessly in their local Blender environment. Remarkably, our Blender add-on works even on **macOS** systems 😊, unlike other CUDA-based physics simulator add-ons that require local NVIDIA GPUs.\nMore importantly, **you can work on a laptop without worrying about draining the battery fast**. 🔋\n\nFollow this page [How to Install](https:\u002F\u002Fst-tech.github.io\u002Fppf-contact-solver\u002Fblender_addon\u002Fgetting_started\u002Finstall.html) to learn how to install the add-on. For a thorough walk through workflow, we refer to our documentation below:\n\n\u003Cp align=\"center\">\n  \u003Ca href=\"https:\u002F\u002Fst-tech.github.io\u002Fppf-contact-solver\">\u003Cimg src=\".\u002Fasset\u002Fimage\u002Fread-blender-addon-docs.svg\" alt=\"Read Blender Add-on Documentation\" height=\"35\">\u003C\u002Fa>\n\u003C\u002Fp>\n\nHere are some highlights:\n\n#### 📖 Docs Look\n\nWe maintain a [full docs site](https:\u002F\u002Fst-tech.github.io\u002Fppf-contact-solver) with workflow guides and recorded walkthroughs for the add-on:\n\n\u003Ctable>\n\u003Ctr>\n\u003Ctd width=\"50%\" valign=\"top\">\u003Cimg src=\".\u002Fdocs\u002Fblender_addon\u002Fimages\u002Fscreenshots\u002Fdocumentation-dark-small.png\" alt=\"Workflow documentation page on the docs site, showing the Blender \u002F solver coordinate system explanation.\">\u003C\u002Ftd>\n\u003Ctd width=\"50%\" valign=\"top\">\u003Cimg src=\".\u002Fdocs\u002Fblender_addon\u002Fimages\u002Fscreenshots\u002Fvideo-tutorials-dark-small.jpg\" alt=\"Video Tutorials page on the docs site, showing a grid of recorded walkthroughs.\">\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd valign=\"top\">Workflow documentation page. \u003Ca href=\"https:\u002F\u002Fst-tech.github.io\u002Fppf-contact-solver\u002Fblender_addon\u002Fworkflow\u002Findex.html\">(Link)\u003C\u002Fa>\u003C\u002Ftd>\n\u003Ctd valign=\"top\">Video tutorials page. \u003Ca href=\"https:\u002F\u002Fst-tech.github.io\u002Fppf-contact-solver\u002Fblender_addon\u002Ftutorial.html\">(Link)\u003C\u002Fa>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftable>\n\n#### 🖼️ UI Look\n\nHere are a couple of screenshots of the add-on running inside Blender:\n\n\u003Ctable>\n\u003Ctr>\n\u003Ctd width=\"50%\" valign=\"top\">\u003Cimg src=\".\u002Fdocs\u002Fblender_addon\u002Fimages\u002Fgallery\u002Fkite-ui-small.jpg\" alt=\"The kite scene set up inside Blender using the add-on.\">\u003C\u002Ftd>\n\u003Ctd width=\"50%\" valign=\"top\">\u003Cimg src=\".\u002Fdocs\u002Fblender_addon\u002Fimages\u002Fgallery\u002Fzebra-ui-small.jpg\" alt=\"The zebra scene set up inside Blender using the add-on.\">\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd valign=\"top\">Kite scene set up in Blender. \u003Ca href=\"https:\u002F\u002Fzozo.box.com\u002Fs\u002Fdbtktx71fd0gb4z2trnvew7l3t8fuwxu\">(full-size)\u003C\u002Fa>\u003C\u002Ftd>\n\u003Ctd valign=\"top\">Zebra scene set up in Blender. \u003Ca href=\"https:\u002F\u002Fzozo.box.com\u002Fs\u002Fbkt5uviyqx825os7r854xslurqpxcj2k\">(full-size)\u003C\u002Fa>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftable>\n\n![Blender add-on overview](.\u002Fdocs\u002Fblender_addon\u002Fimages\u002Fblender.webp)\n\n#### 🤖 From Natural Language to Simulation (via MCP)\n\nWe expose all of the add-on's tools through an MCP server, so any LLM (Claude, Codex, etc.) can drive the whole pipeline from a natural language prompt. Scene building, parameter tweaks, and running the simulation all happen without UI clicks. Here are two examples:\n\n\u003Ctable>\n\u003Ctr>\n\u003Ctd width=\"50%\" valign=\"top\">\u003Cimg src=\".\u002Fdocs\u002Fblender_addon\u002Fimages\u002Fgallery\u002Fmcp.webp\" alt=\"Codex terminal on the left driving Blender on the right through the MCP server, building a bowl-and-spheres scene from a natural language prompt.\">\u003C\u002Ftd>\n\u003Ctd width=\"50%\" valign=\"top\">\u003Cimg src=\".\u002Fdocs\u002Fblender_addon\u002Fimages\u002Fgallery\u002Fdrape-over-sphere.webp\" alt=\"A cloth sheet draped over a sphere, produced from a single natural language prompt through the MCP server.\">\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd valign=\"top\">Codex (left) driving Blender (right) through the add-on's MCP server.\u003C\u002Ftd>\n\u003Ctd valign=\"top\">A prompt: drape a sheet over a sphere and make an animation video mp4 render 300 frames.\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftable>\n\n#### 🐍 From a Python Script to Simulation\n\nYou can also drive the entire pipeline from a Python script inside Blender's scripting editor. This is handy for procedural scene setup and batch variant generation. Below is a full example that drapes a sheet over a sphere:\n\n```python\nimport addon_utils\nimport importlib\nimport bpy\n\n# Look up the add-on module under whichever extension repository Blender\n# installed it into and grab the public solver API.\naddon = next(m for m in addon_utils.modules() if m.__name__.endswith(\".ppf_contact_solver\"))\nsolver = importlib.import_module(f\"{addon.__name__}.ops.api\").solver\n\n# Reset any prior state.\nsolver.clear()\n\n# Create a sphere (the static collider) at the origin.\nbpy.ops.mesh.primitive_ico_sphere_add(subdivisions=4, radius=0.5, location=(0, 0, 0))\nbpy.context.object.name = \"Sphere\"\n\n# Create a 2x2 sheet just above the sphere as a 64x64 grid.\nbpy.ops.mesh.primitive_grid_add(x_subdivisions=64, y_subdivisions=64, size=2, location=(0, 0, 0.6))\nsheet = bpy.context.object\nsheet.name = \"Sheet\"\n\n# Pin the two corners on the -x edge via a vertex group.\nvg = sheet.vertex_groups.new(name=\"Corners\")\ncorner_indices = [\n    i for i, v in enumerate(sheet.data.vertices)\n    if v.co.x \u003C -0.99 and abs(abs(v.co.y) - 1.0) \u003C 0.01\n]\nvg.add(corner_indices, 1.0, \"REPLACE\")\n\n# Build solver groups.\ncloth = solver.create_group(\"Cloth\", type=\"SHELL\")\ncloth.add(\"Sheet\")\ncloth.param.enable_strain_limit = True\ncloth.param.strain_limit = 0.05\ncloth.param.bend = 1\n\nball = solver.create_group(\"Ball\", type=\"STATIC\")\nball.add(\"Sphere\")\n\n# Pin the two sheet corners.\ncloth.create_pin(\"Sheet\", \"Corners\")\n\n# Scene parameters.\nsolver.param.frame_count = 100\nsolver.param.step_size = 0.01\n```\n\nHere's how the script runs inside Blender [(full-size)](https:\u002F\u002Fzozo.box.com\u002Fs\u002Fm86w3jyprvz5dug2pr7k73bozdbgldfl):\n\n![python-scripting](.\u002Fdocs\u002Fblender_addon\u002Fimages\u002Fscreenshots\u002Fpython-scripting.jpg)\n\nFor the full `solver.*` surface, see the [Blender Python API guide](https:\u002F\u002Fst-tech.github.io\u002Fppf-contact-solver\u002Fblender_addon\u002Fintegrations\u002Fpython_api.html).\n\n### 🌐 JupyterLab\n\nOur frontend is accessible through a browser using our built-in JupyterLab interface.\nAll is set up when you open it for the first time.\nResults can be interactively viewed through the browser and exported as needed.\nOur Python interface is designed with the following principles in mind:\n\n- **🛠️ In-Pipeline Tri\u002FTet Creation**: Depending on external 3D\u002FCAD softwares for triangulation or tetrahedralization makes dynamic resolution changes cumbersome. We provide handy `.triangulate()` and `.tetrahedralize()` calls to keep everything in-pipeline, allowing users to skip explicit mesh exports to 3D\u002FCAD software.\n- **🚫 No Mesh Data Included**: Preparing mesh data using external tools can be cumbersome. Our frontend minimizes this effort by allowing meshes to be created on the fly or downloaded when needed.\n- **🔗 Method Chaining**: We adopt the method chaining style from JavaScript, making the API intuitive to understand and read smoothly.\n- **📦 Single Import for Everything**: All frontend features are accessible by simply importing with `from frontend import App`.\n\nHere's an example of draping five sheets over a sphere with two corners pinned.\nWe have more examples in the [examples](.\u002Fexamples\u002F) directory. Please take a look! 👀\n\n```python\n# import our frontend\nfrom frontend import App\n\n# make an app\napp = App.create(\"drape\")\n\n# create a square mesh resolution 128 spanning the xz plane\nV, F = app.mesh.square(res=128, ex=[1, 0, 0], ey=[0, 0, 1])\n\n# add to the asset and name it \"sheet\"\napp.asset.add.tri(\"sheet\", V, F)\n\n# create an icosphere mesh radius 0.5\nV, F = app.mesh.icosphere(r=0.5, subdiv_count=4)\n\n# add to the asset and name it \"sphere\"\napp.asset.add.tri(\"sphere\", V, F)\n\n# create a scene\nscene = app.scene.create()\n\n# define gap between sheets\ngap = 0.01\n\nfor i in range(5):\n\n    # add the sheet asset to the scene with an vertical offset\n    obj = scene.add(\"sheet\").at(0, gap * i, 0)\n\n    # pick two corners\n    corner = obj.grab([1, 0, -1]) + obj.grab([-1, 0, -1])\n\n    # pin the corners\n    obj.pin(corner)\n\n    # set the strict limit on maximum strain to 5% per triangle\n    obj.param.set(\"strain-limit\", 0.05)\n\n# add a sphere mesh at a lower position with jitter and set it static collider\nscene.add(\"sphere\").at(0, -0.5 - gap, 0).jitter().pin()\n\n# compile the scene and report stats\nscene = scene.build().report()\n\n# preview the initial scene, shows image left\nscene.preview()\n\n# create a new session with the compiled scene\nsession = app.session.create(scene)\n\n# set session params\nsession.param.set(\"frames\", 100).set(\"dt\", 0.01)\n\n# build this session\nsession = session.build()\n\n# start the simulation and live-preview the results, shows image right\nsession.start().preview()\n\n# also show streaming logs\nsession.stream()\n\n# or interactively view the animation sequences\nsession.animate()\n\n# export all simulated frames in (sequences of ply meshes + a video)\nsession.export.animation()\n```\n\n\u003Cimg src=\".\u002Fasset\u002Fimage\u002Fdrape-preview.webp\" alt=\"drape\">\n\n#### 📚 Python APIs and Parameters\n\n- Full API documentation is available on our [GitHub Pages](https:\u002F\u002Fst-tech.github.io\u002Fppf-contact-solver\u002Fjupyterlab_api\u002Fmodule_reference.html). The major APIs are documented using docstrings and compiled with [Sphinx](https:\u002F\u002Fwww.sphinx-doc.org\u002Fen\u002Fmaster\u002F)\nWe have also included [`jupyter-lsp`](https:\u002F\u002Fgithub.com\u002Fjupyter-lsp\u002Fjupyterlab-lsp) to provide interactive linting assistance and display docstrings as you type. See this video [(Video)](https:\u002F\u002Fzozo.box.com\u002Fs\u002F52atrfn70vn8u07iwzbyrrz5ameczo03) for an example.\nThe behaviors can be changed through the settings.\n\n- A list of parameters used in `param.set(key,value)` is documented here: [(Simulation Parameters)](https:\u002F\u002Fst-tech.github.io\u002Fppf-contact-solver\u002Fjupyterlab_api\u002Fsimulation_parameters.html) [(Material Parameters)](https:\u002F\u002Fst-tech.github.io\u002Fppf-contact-solver\u002Fjupyterlab_api\u002Fmaterial_parameters.html).\n\n> ⚠️ Please note that our Python APIs are subject to breaking changes as this repository undergoes frequent iterations. If you need APIs to be fixed, please fork.\n\n## 🔍 Obtaining Logs\n\nLogs for the simulation can also be queried through our Python APIs. Here's an example of how to get a list of recorded logs, fetch them, and compute the average.\n\n```python\n# get a list of log names\nlogs = session.get.log.names()\nprint(logs)\nassert \"time-per-frame\" in logs\nassert \"newton-steps\" in logs\n\n# get a list of time per video frame\nmsec_per_video = session.get.log.numbers(\"time-per-frame\")\n\n# compute the average time per video frame\nprint(\"avg per frame:\", sum([n for _, n in msec_per_video]) \u002F len(msec_per_video))\n\n# get a list of newton steps\nnewton_steps = session.get.log.numbers(\"newton-steps\")\n\n# compute the average of consumed newton steps\nprint(\"avg newton steps:\", sum([n for _, n in newton_steps]) \u002F len(newton_steps))\n\n# Last 8 lines. Omit for everything.\nprint(\"==== log stream ====\")\nfor line in session.get.log.stdout(n_lines=8):\n    print(line)\n```\n\nBelow are some representatives.\n`vid_time` refers to the video time in seconds and is recorded as `float`.\n`ms` refers to the consumed simulation time in milliseconds recorded as `int`.\n`vid_frame` is the video frame count recorded as `int`.\n\n| **Name** | **Description** | **Format**\n|---------------|----------------|------------\n| time-per-frame | Time per video frame | `list[(vid_frame,ms)]` |\n| matrix-assembly | Matrix assembly time | `list[(vid_time,ms)]` |\n| pcg-linsolve | Linear system solve time | `list[(vid_time,ms)]` |\n| line-search | Line search time | `list[(vid_time,ms)]` |\n| time-per-step | Time per step | `list[(vid_time,ms)]` |\n| newton-steps | Newton iterations per step | `list[(vid_time,count)]` |\n| num-contact | Contact count | `list[(vid_time,count)]` |\n| max-sigma | Max stretch | `list(vid_time,float)` |\n\nThe full list of log names and their descriptions is documented here: [(GitHub Pages)](https:\u002F\u002Fst-tech.github.io\u002Fppf-contact-solver\u002Fjupyterlab_api\u002Flog_channels.html).\n\nNote that some entries have multiple records at the same video time. This occurs because the same operation is executed multiple times within a single step during the inner Newton's iterations. For example, the linear system solve is performed at each Newton's step, so if multiple Newton's steps are executed, multiple linear system solve times appear in the record at the same video time.\n\nIf you would like to retrieve the raw log stream, you can do so by\n\n```python\n# Last 8 lines. Omit for everything.\nfor line in session.get.log.stdout(n_lines=8):\n    print(line)\n```\n\nThis will output something like:\n\n```text\n* dt: 1.000e-03\n* max_sigma: 1.045e+00\n* avg_sigma: 1.030e+00\n------ newton step 1 ------\n   ====== contact_matrix_assembly ======\n   > dry_pass...0 msec\n   > rebuild...7 msec\n   > fillin_pass...0 msec\n```\n\nIf you would like to read `stderr`, you can do so using `session.get.stderr()` (if it exists).\nThis returns `list[str]`.\nAll the log files are updated in real-time and can be fetched right after the simulation starts; you don't have to wait until it finishes.\n\n## 🖼️ Catalogue\n\n### 🎨 Blender Add-on Examples\n\nThese scenes are all built with our [add-on](#-blender-add-on). The simulation itself runs on a remote solver, or directly on your local machine if you have a modern NVIDIA GPU on Windows or Linux.\n\nYou set the geometry, constraints, and parameters from Blender's UI, and the saved `.blend` carries everything the add-on needs.\n\n||||\n|---|---|---|\n|[kite.blend](https:\u002F\u002Fzozo.box.com\u002Fs\u002Fj5tg9hy7nf1fdea1yg0s6holzwwus77t) [(Video)](https:\u002F\u002Fzozo.box.com\u002Fs\u002F7siwyp04s1vs48znwnt5vx1vhgodyr4h)|[crumple.blend](https:\u002F\u002Fzozo.box.com\u002Fs\u002F69ysygaqfud3bba8v3w33eqcbfn6l76u) [(Video)](https:\u002F\u002Fzozo.box.com\u002Fs\u002Fddrqqq87gpn0mekqx0yaukez87casten)|[puff.blend](https:\u002F\u002Fzozo.box.com\u002Fs\u002Fmfc64djyjyunuhnmn51rm4jexxenx0si) [(Video)](https:\u002F\u002Fzozo.box.com\u002Fs\u002F8dpuoqbg80vxvxwsga36nz1633vx4k6u)|\n|![](.\u002Fdocs\u002Fblender_addon\u002Fimages\u002Fgallery\u002Fkite.webp)|![](.\u002Fdocs\u002Fblender_addon\u002Fimages\u002Fgallery\u002Fcrumple.webp)|![](.\u002Fdocs\u002Fblender_addon\u002Fimages\u002Fgallery\u002Fpuff.webp)|\n|[press.blend](https:\u002F\u002Fzozo.box.com\u002Fs\u002Fn1upezi7j0eufmrsief4qh252of7g1nq) [(Video)](https:\u002F\u002Fzozo.box.com\u002Fs\u002Fnt8s46e6kke9poruvxmtxv5v56p2ysit)|[zebra.blend](https:\u002F\u002Fzozo.box.com\u002Fs\u002Fqcos081dolarpczz8mheegvwqalxcnu2) [(Video)](https:\u002F\u002Fzozo.box.com\u002Fs\u002Frvcqynftqk27fczplafm0wgt95xmhb1k)|[curtain.blend](https:\u002F\u002Fzozo.box.com\u002Fs\u002Ff8775589v2jd3nnmm7dzjrfy44xmbuhl) [(Video)](https:\u002F\u002Fzozo.box.com\u002Fs\u002Fe558genjdno7jz9m0svojte5eco6q7tm)|\n|![](.\u002Fdocs\u002Fblender_addon\u002Fimages\u002Fgallery\u002Fpress.webp)|![](.\u002Fdocs\u002Fblender_addon\u002Fimages\u002Fgallery\u002Fzebra.webp)|![](.\u002Fdocs\u002Fblender_addon\u002Fimages\u002Fgallery\u002Fcurtain.webp)|\n\nThe simulated portion (objects, groups, pins, and solver parameters) is generated by a script you drop into Blender's Scripting editor. Cameras, lighting, and any non-simulated props are still set up in Blender's UI. Each script is linked above its thumbnail.\n\n|||||\n|---|---|---|---|\n|[cards.py](.\u002Fexamples\u002Fblender\u002Fcards.py) [(Video)](https:\u002F\u002Fzozo.box.com\u002Fs\u002F3xihxxigc6atsoss4vrh72qppgdvihy5)|[five-twist.py](.\u002Fexamples\u002Fblender\u002Ffive-twist.py) [(Video)](https:\u002F\u002Fzozo.box.com\u002Fs\u002F71a22jxs5r68wk08j283p4fwj1q4543u)|[noodle.py](.\u002Fexamples\u002Fblender\u002Fnoodle.py) [(Video)](https:\u002F\u002Fzozo.box.com\u002Fs\u002Forx2xs715i15l4urmnxns8qs9djhntvs)|[woven.py](.\u002Fexamples\u002Fblender\u002Fwoven.py) [(Video)](https:\u002F\u002Fzozo.box.com\u002Fs\u002F16pmmgkpk6r18ae90cwjaknod6cd7y2w)|\n|![](.\u002Fdocs\u002Fblender_addon\u002Fimages\u002Fgallery\u002Fcards.webp)|![](.\u002Fdocs\u002Fblender_addon\u002Fimages\u002Fgallery\u002Ffive-twist.webp)|![](.\u002Fdocs\u002Fblender_addon\u002Fimages\u002Fgallery\u002Fnoodle.webp)|![](.\u002Fdocs\u002Fblender_addon\u002Fimages\u002Fgallery\u002Fwoven.webp)|\n\n### 🌐 JupyterLab Examples\n\nAll these examples run on our Python frontend through JupyterLab. Click any notebook to see how the scene is built, or click the video link to watch the result.\n\n|||||\n|---|---|---|---|\n|[woven.ipynb](.\u002Fexamples\u002Fwoven.ipynb) [(Video)](https:\u002F\u002Fzozo.box.com\u002Fs\u002F0kgqmurmahwpvufuplbse9f83lsd7cjs)|[stack.ipynb](.\u002Fexamples\u002Fstack.ipynb) [(Video)](https:\u002F\u002Fzozo.box.com\u002Fs\u002Fcy0pmlu5wwzmhri2qhrereqgobbv4eh6)|[trampoline.ipynb](.\u002Fexamples\u002Ftrampoline.ipynb) [(Video)](https:\u002F\u002Fzozo.box.com\u002Fs\u002Fsyi5q1ywgtwrqx1f9xcjgz5m4jzagdra)|[needle.ipynb](.\u002Fexamples\u002Fneedle.ipynb) [(Video)](https:\u002F\u002Fzozo.box.com\u002Fs\u002Fzlrb6xk4gg4yjm2tspyv6u2n8vlo3dyb)|\n|![](.\u002Fasset\u002Fimage\u002Fcatalogue\u002Fwoven.mp4.webp)|![](.\u002Fasset\u002Fimage\u002Fcatalogue\u002Fstack.mp4.webp)|![](.\u002Fasset\u002Fimage\u002Fcatalogue\u002Ftrampoline.mp4.webp)|![](.\u002Fasset\u002Fimage\u002Fcatalogue\u002Fneedle.mp4.webp)|\n|[cards.ipynb](.\u002Fexamples\u002Fcards.ipynb) [(Video)](https:\u002F\u002Fzozo.box.com\u002Fs\u002F7c114pua0107xkz4nc3bwfdzpkhgn1o9)|[codim.ipynb](.\u002Fexamples\u002Fcodim.ipynb) [(Video)](https:\u002F\u002Fzozo.box.com\u002Fs\u002Fo3en7lkzz2xhi0i9hzfdidau7pp7nco2)|[hang.ipynb](.\u002Fexamples\u002Fhang.ipynb) [(Video)](https:\u002F\u002Fzozo.box.com\u002Fs\u002Flcgnivq93ahvp1uccw91t13ht6qggopx)|[trapped.ipynb](.\u002Fexamples\u002Ftrapped.ipynb) [(Video)](https:\u002F\u002Fzozo.box.com\u002Fs\u002Flnnyeqrvm86rxnwyjxhojfj0jgm5nphn)|\n|![](.\u002Fasset\u002Fimage\u002Fcatalogue\u002Fcards.mp4.webp)|![](.\u002Fasset\u002Fimage\u002Fcatalogue\u002Fcodim.mp4.webp)|![](.\u002Fasset\u002Fimage\u002Fcatalogue\u002Fhang.mp4.webp)|![](.\u002Fasset\u002Fimage\u002Fcatalogue\u002Ftrapped.mp4.webp)|\n|[domino.ipynb](.\u002Fexamples\u002Fdomino.ipynb) [(Video)](https:\u002F\u002Fzozo.box.com\u002Fs\u002Fp5ksfqja1ew3c6vntco5zq6g0kgf7xoo)|[noodle.ipynb](.\u002Fexamples\u002Fnoodle.ipynb) [(Video)](https:\u002F\u002Fzozo.box.com\u002Fs\u002Fwvsn7byr4yv80wixi5cs8mgoubco6kp4)|[drape.ipynb](.\u002Fexamples\u002Fdrape.ipynb) [(Video)](https:\u002F\u002Fzozo.box.com\u002Fs\u002Ffuisqc3wpnynd46mvdc7z2gat7mkjw07)|[five-twist.ipynb](.\u002Fexamples\u002Ffive-twist.ipynb) [(Video)](https:\u002F\u002Fzozo.box.com\u002Fs\u002F36h8jpu5vcgc5t4xln2l68afj7izsx4h)|\n|![](.\u002Fasset\u002Fimage\u002Fcatalogue\u002Fdomino.mp4.webp)|![](.\u002Fasset\u002Fimage\u002Fcatalogue\u002Fnoodle.mp4.webp)|![](.\u002Fasset\u002Fimage\u002Fcatalogue\u002Fdrape.mp4.webp)|![](.\u002Fasset\u002Fimage\u002Fcatalogue\u002Fquintupletwist.mp4.webp)|\n|[ribbon.ipynb](.\u002Fexamples\u002Fribbon.ipynb) [(Video)](https:\u002F\u002Fzozo.box.com\u002Fs\u002Fqxsx2it6kvd6p5ufqtmge6pd63lmhcny)|[curtain.ipynb](.\u002Fexamples\u002Fcurtain.ipynb) [(Video)](https:\u002F\u002Fzozo.box.com\u002Fs\u002Fii938zyr4ytks5bnpbch3ystztuqq8mu)|[fishingknot.ipynb](.\u002Fexamples\u002Ffishingknot.ipynb) [(Video)](https:\u002F\u002Fzozo.box.com\u002Fs\u002F56dqf3fmnd0qr9pptqe8u8mw8vooh01p)|[friction.ipynb](.\u002Fexamples\u002Ffriction.ipynb) [(Video)](https:\u002F\u002Fzozo.box.com\u002Fs\u002F15r5o7rrowwtbrsrjjpj35v8xt92ufhr)|\n|![](.\u002Fasset\u002Fimage\u002Fcatalogue\u002Fribbon.mp4.webp)|![](.\u002Fasset\u002Fimage\u002Fcatalogue\u002Fcurtain.mp4.webp)|![](.\u002Fasset\u002Fimage\u002Fcatalogue\u002Ffishingknot.mp4.webp)|![](.\u002Fasset\u002Fimage\u002Fcatalogue\u002Ffriction.mp4.webp)|\n|[belt.ipynb](.\u002Fexamples\u002Fbelt.ipynb) [(Video)](https:\u002F\u002Fzozo.box.com\u002Fs\u002F7ovalnjrptprcib7z0hj85lvr3yuhroz)|[fitting.ipynb](.\u002Fexamples\u002Ffitting.ipynb) [(Video)](https:\u002F\u002Fzozo.box.com\u002Fs\u002Fpdcswk4ytzqgo98cjo91ensprgxz2umm)|[roller.ipynb](.\u002Fexamples\u002Froller.ipynb) [(Video)](https:\u002F\u002Fzozo.box.com\u002Fs\u002F5156ez3b7rsvldqbgxsd7irhwp7mo2nc)|[yarn.ipynb](.\u002Fexamples\u002Fyarn.ipynb) [(Video)](https:\u002F\u002Fzozo.box.com\u002Fs\u002F3ly6riq5id8y9ukvbpnfnlro3qttylxw)|\n|![](.\u002Fasset\u002Fimage\u002Fcatalogue\u002Fbelt.mp4.webp)|![](.\u002Fasset\u002Fimage\u002Fcatalogue\u002Ffitting.mp4.webp)|![](.\u002Fasset\u002Fimage\u002Fcatalogue\u002Froller.mp4.webp)|![](.\u002Fasset\u002Fimage\u002Fcatalogue\u002Fyarn.mp4.webp)|\n\n### 💰 Budget Table on AWS\n\nBelow is a table summarizing the estimated costs for running our examples on a NVIDIA L4 instance `g6.2xlarge` at Amazon Web Services US regions (`us-east-1` and `us-east-2`).\n\n- 💰 Uptime cost is approximately $1 per hour.\n- ⏳ Deployment time is approximately 8 minutes ($0.13). Instance loading takes 3 minutes, and Docker pull & load takes 5 minutes.\n- 🎮 The NVIDIA L4 delivers [30.3 TFLOPS for FP32](https:\u002F\u002Fwww.nvidia.com\u002Fen-us\u002Fdata-center\u002Fl4\u002F), offering approximately 36% of the [performance of an RTX 4090](https:\u002F\u002Fwww.nvidia.com\u002Fen-us\u002Fgeforce\u002Fgraphics-cards\u002F40-series\u002Frtx-4090\u002F).\n- 🎥 Video frame rate is 60fps.\n\n| **Example** | **Cost** | **Time** | **#Frame** | **#Vert** | **#Face** | **#Tet** | **#Rod** | **Max Strain** |\n|--------------|-------|-------|-----|--------|--------|--------|---------|-----|\n| trapped      | $0.37 | 22.6m | 300 | 263K   | 299K   | 885K   | ```N\u002FA```     | ```N\u002FA``` |\n| twist        | $0.91 | 55m   | 500 | 203K   | 406K   | ```N\u002FA```    | ```N\u002FA```     | ```N\u002FA``` |\n| stack        | $0.60 | 36.2m | 120 | 166.7K | 327.7K | 8.8K   | ```N\u002FA```     | 5%  |\n| trampoline   | $0.74 | 44.5m | 120 | 56.8K  | 62.2K  | 158.0K | ```N\u002FA```     | 1%  |\n| needle       | $0.31 | 18.4m | 120 | 86K    | 168.9K | 8.8K   | ```N\u002FA```     | 5%  |\n| cards        | $0.29 | 17.5m | 300 | 8.7K   | 13.8K  | 1.9K   | ```N\u002FA```     | 5%  |\n| domino       | $0.12 | 4.3m  | 250 | 0.5K   | 0.8K   | ```N\u002FA```    | ```N\u002FA```     | ```N\u002FA``` |\n| drape        | $0.10 | 3.5m  | 100 | 81.9K  | 161.3K | ```N\u002FA```    | ```N\u002FA```     | 5% |\n| curtain      | $0.33 | 19.6m | 300 | 64K    | 124K   | ```N\u002FA```    | ```N\u002FA```     | 5% |\n| friction     | $0.17 | 10m   | 700 | 1.1K   | ```N\u002FA```    | 1K     | ```N\u002FA```     | ```N\u002FA``` |\n| hang         | $0.12 | 7.5m  | 200 | 16.3K  | 32.2K  | ```N\u002FA```    | ```N\u002FA```     | 1%  |\n| belt         | $0.19 | 11.4m | 200 | 12.3K  | 23.3K  | ```N\u002FA```    | ```N\u002FA```     | 5%  |\n| codim        | $0.36 | 21.6m | 240 | 122.7K | 90K    | 474.1K | 1.3K    | ```N\u002FA``` |\n| fishingknot  | $0.38 | 22.5m | 830 | 19.6K  | 36.9K  | ```N\u002FA```    | ```N\u002FA```     | 5%  |\n| fitting      | $0.03 | 1.54m | 240 | 28.4K  | 54.9K  | ```N\u002FA```    | ```N\u002FA```     | 10% |\n| noodle       | $0.14 | 8.45m | 240 | 116.2K | ```N\u002FA```    | ```N\u002FA```    | 116.2K  | ```N\u002FA``` |\n| ribbon       | $0.23 | 13.9m | 480 | 34.9K  | 52.9K  | 8.8K   | ```N\u002FA```     | 5%  |\n| woven        | $0.58 | 34.6m | 450 | 115.6K | ```N\u002FA```    | ```N\u002FA```    | 115.4K  | ```N\u002FA``` |\n| yarn         | $0.01 | 0.24m | 120 | 28.5K  | ```N\u002FA```    | ```N\u002FA```    | 28.5K   | ```N\u002FA``` |\n| roller       | $0.03 | 2.08m | 240 | 21.4K  | 22.2K  | 61.0K  | ```N\u002FA```     | ```N\u002FA``` |\n\n#### 🏗️ Large Scale Examples\n\nLarge scale examples are run on a [vast.ai](https:\u002F\u002Fvast.ai) instance with an RTX 4090.\nThese examples are not included in GitHub Action tests since they can take days to finish.\n\n| | | |\n|---|---|---|\n| [large-twist.ipynb](.\u002Fexamples\u002Flarge-twist.ipynb) [(Video)](https:\u002F\u002Fzozo.box.com\u002Fs\u002Fawtqwo572t7ixuy04va478zn6f69djlr) | [large-five-twist.ipynb](.\u002Fexamples\u002Flarge-five-twist.ipynb) [(Video)](https:\u002F\u002Fzozo.box.com\u002Fs\u002Fv62q7cbfnpl3hufwwy2nmewyes2w1iw6) | [large-woven.ipynb](.\u002Fexamples\u002Flarge-woven.ipynb) [(Video)](https:\u002F\u002Fzozo.box.com\u002Fs\u002Fkc81msjfo4yw9eozn8i8bean0gbph0pj) |\n| ![twist](.\u002Fasset\u002Fimage\u002Flarge-scale\u002Ftwist.jpg) | ![five-twist](.\u002Fasset\u002Fimage\u002Flarge-scale\u002Ffive-twist.jpg) | ![woven](.\u002Fasset\u002Fimage\u002Flarge-scale\u002Fwoven.jpg) |\n\n| Example | Commit | #Vert | #Face | #Rod | #Contact | #Frame | Time\u002FFrame |\n|---|---|---|---|---|---|---|---|\n| large-twist | [cbafbd2](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Ftree\u002Fcbafbd2197fc7f28673386dfaf1e8d8a1be49937) | 3.2M | 6.4M | ```N\u002FA``` | 56.7M | 2,000 | 46.4s |\n| large-five-twist | [6ab6984](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Fcommit\u002F6ab6984d95f67673f1ebfdc996b0320123d88bed) | 8.2M | 16.4M | ```N\u002FA``` | 184.1M | 2,413 | 144.5s |\n| large-woven | [4c07b83](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Fcommit\u002F4c07b834b299e49bb08797940e9f0869789301b8) | 2.7M | ```N\u002FA``` | 2.7M | 8.9M | 946 | 436.8s |\n\n📝 Large scale examples take a very long time, and it's easy to lose connection or close the browser.\nOur frontend lets you close and reopen it at your convenience. Just recover your session after you reconnect.\nHere's an example cell how to recover:\n\n```python\n# In case you shutdown the server (or kernel) and still want\n# to restart, do this.\n# Do not run other cells used to create this scene.\n# You can also recover this way if you closed the browser.\n# Just directly run this in a new cell or in a new notebook.\n\nfrom frontend import App\n\n# recover the session\nsession = App.recover(\"app-name\")\n\n# resume if not currently running\nif not App.busy():\n    session.resume()\n\n# preview the current state\nsession.preview()\n\n# stream the logs\nsession.stream()\n```\n\n## 🚀 GitHub Actions\n\nWe implemented GitHub Actions that test all of our examples except for large scale ones, which take from days to weeks to finish.\nWe perform explicit intersection checks at the end of each step, which raises an error if an intersection is detected.\n**This ensures that all steps are confirmed to be penetration-free if tests pass.**\nThe runner types are described as follows:\n\n### [![Getting Started](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Fgetting-started.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Fgetting-started.yml)\n\nThe tested runner of this action is the Ubuntu NVIDIA GPU-Optimized Image for AI and HPC with an NVIDIA Tesla T4 (16 GB VRAM) with Driver version ``570.133.20``.\nThis is not a self-hosted runner, meaning that each time the runner launches, all environments are fresh. 🌱\n\n### [![All Examples](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Frun-all-once.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Frun-all-once.yml) [![All Examples (Windows Native)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Frun-all-once-win.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Frun-all-once-win.yml)\n\nWe use the GitHub-hosted runner, but the actual simulation runs on a `g6e.2xlarge` AWS instance.\nSince we start with a fresh instance, the environment is clean every time.\nWe take advantage of the ability to deploy on the cloud; this action is performed in parallel, which reduces the total action time.\n\n### [![Blender CI](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Fblender.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Fblender.yml)\n\nThis action exercises our [Blender add-on](#-blender-add-on) on free GitHub-hosted Linux and macOS runners in parallel. Blender 5.1.1 is installed from the official Blender Foundation mirror, the Rust solver is built in CPU-emulated mode (no CUDA required), and the add-on is installed as a Blender 5 extension. A headless test rig then runs the full scenario registry covering add-on UI flows.\n\n### 📦 Action Artifacts\n\nWe generate zipped action artifacts for each run. These artifacts include:\n\n- **📝 Logs**: Detailed logs of the simulation runs.\n- **📊 Metrics**: Performance metrics and statistics.\n- **📹 Videos**: Simulated animations.\n\nPlease note that these artifacts will be deleted after a month.\n\n### ⚔️ Ten Consecutive Runs\n\nWe know that you can't judge the reliability of contact resolution by simply watching a single success video example.\nTo ensure greater transparency, we implemented GitHub Actions to run many of our examples via automated GitHub Actions, not just once, but **10 times in a row** for both Docker and Windows.\nThis means that **a single failure out of 10 tests is considered a failure of the entire test suite!**\nAlso, we apply small jitters to the position of objects in the scene, so **at each run, the scene is slightly different.**\n\n##### 🪟 Windows Native\n\n[![drape.ipynb (Windows Native)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Fdrape-win.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Fdrape-win.yml)\n[![cards.ipynb (Windows Native)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Fcards-win.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Fcards-win.yml)\n[![curtain.ipynb (Windows Native)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Fcurtain-win.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Fcurtain-win.yml)\n[![friction.ipynb (Windows Native)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Ffriction-win.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Ffriction-win.yml)\n[![hang.ipynb (Windows Native)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Fhang-win.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Fhang-win.yml)\n[![needle.ipynb (Windows Native)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Fneedle-win.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Fneedle-win.yml)\n[![stack.ipynb (Windows Native)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Fstack-win.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Fstack-win.yml)\n[![trampoline.ipynb (Windows Native)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Ftrampoline-win.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Ftrampoline-win.yml)\n[![trapped.ipynb (Windows Native)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Ftrapped-win.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Ftrapped-win.yml)\n[![twist.ipynb (Windows Native)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Ftwist-win.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Ftwist-win.yml)\n[![five-twist.ipynb (Windows Native)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Ffive-twist-win.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Ffive-twist-win.yml)\n[![domino.ipynb (Windows Native)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Fdomino-win.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Fdomino-win.yml)\n[![belt.ipynb (Windows Native)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Fbelt-win.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Fbelt-win.yml)\n[![codim.ipynb (Windows Native)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Fcodim-win.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Fcodim-win.yml)\n[![fishingknot.ipynb (Windows Native)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Ffishingknot-win.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Ffishingknot-win.yml)\n[![fitting.ipynb (Windows Native)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Ffitting-win.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Ffitting-win.yml)\n[![noodle.ipynb (Windows Native)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Fnoodle-win.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Fnoodle-win.yml)\n[![ribbon.ipynb (Windows Native)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Fribbon-win.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Fribbon-win.yml)\n[![woven.ipynb (Windows Native)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Fwoven-win.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Fwoven-win.yml)\n[![yarn.ipynb (Windows Native)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Fyarn-win.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Fyarn-win.yml)\n[![roller.ipynb (Windows Native)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Froller-win.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Froller-win.yml)\n\n##### 🐧 Linux\n\n[![drape.ipynb](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Fdrape.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Fdrape.yml)\n[![cards.ipynb](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Fcards.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Fcards.yml)\n[![curtain.ipynb](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Fcurtain.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Fcurtain.yml)\n[![friction.ipynb](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Ffriction.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Ffriction.yml)\n[![hang.ipynb](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Fhang.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Fhang.yml)\n[![needle.ipynb](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Fneedle.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Fneedle.yml)\n[![stack.ipynb](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Fstack.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Fstack.yml)\n[![trampoline.ipynb](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Ftrampoline.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Ftrampoline.yml)\n[![trapped.ipynb](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Ftrapped.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Ftrapped.yml)\n[![twist.ipynb](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Ftwist.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Ftwist.yml)\n[![five-twist.ipynb](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Ffive-twist.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Ffive-twist.yml)\n[![domino.ipynb](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Fdomino.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Fdomino.yml)\n[![belt.ipynb](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Fbelt.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Fbelt.yml)\n[![codim.ipynb](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Fcodim.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Fcodim.yml)\n[![fishingknot.ipynb](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Ffishingknot.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Ffishingknot.yml)\n[![fitting.ipynb](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Ffitting.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Ffitting.yml)\n[![noodle.ipynb](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Fnoodle.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Fnoodle.yml)\n[![ribbon.ipynb](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Fribbon.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Fribbon.yml)\n[![woven.ipynb](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Fwoven.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Fwoven.yml)\n[![yarn.ipynb](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Fyarn.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Fyarn.yml)\n[![roller.ipynb](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Froller.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Factions\u002Fworkflows\u002Froller.yml)\n\n## 📡 Deploying on Cloud Services\n\nRunning our solver on the cloud has a few practical advantages:\n\n- **💰 Pay only when you use it**: Spin up an instance, run your experiment, and delete it when you're done. You pay for hours, not for a GPU sitting on your desk.\n- **📈 Scale on demand**: If you have a deadline, just launch multiple instances and run experiments in parallel. No waiting in a queue.\n- **🤝 Share with collaborators**: Send the JupyterLab link to a remote teammate and they can watch the simulation right alongside you.\n- **🔒 Cloud-grade security**: You inherit whatever security the provider gives you, which is usually a lot more than you'd set up yourself.\n- **🐛 Reproducible environments**: Users and developers share the same kernel and driver, making bug reproduction more reliable than across heterogeneous local setups.\n- **🛠️ No hardware maintenance**: No driver updates, no thermal management, and no replacement costs when hardware fails.\n\nBelow, we describe how to deploy our solver on major cloud services. These instructions are up to date as of late 2024 and are subject to change.\n\n> ⚠️ For all the services below, don't forget to delete the instance after use, or you'll be charged for nothing. 💸\n\n### 📦 Deploying on [vast.ai](https:\u002F\u002Fvast.ai)\n\n- Select our template [(Link)](https:\u002F\u002Fcloud.vast.ai?ref_id=85288&template_id=29158e5c91e1b4b9543b6a027a837979).\n- Create an instance and connect via SSH with port forwarding, e.g. `ssh -L 8080:localhost:8080 root@\u003Chost> -p \u003Cport>`, then open `http:\u002F\u002Flocalhost:8080` in your browser.\n\n### 📦 Deploying on [Scaleway](https:\u002F\u002Fwww.scaleway.com\u002Fen\u002F)\n\n- Set zone to `fr-par-2`\n- Select type `L4-1-24G` or `GPU-3070-S`\n- Choose `Ubuntu Jammy GPU OS 12`\n- *Do not skip* the Docker container creation in the installation process; it is required.\n- This setup costs approximately €0.76 per hour.\n- CLI instructions are described in [(Markdown)](.\u002Farticles\u002Fcloud.md#-scaleway).\n\n### 📦 Deploying on [Amazon Web Services](https:\u002F\u002Faws.amazon.com\u002Fen\u002F)\n\n- Amazon Machine Image (AMI): `Deep Learning Base AMI with Single CUDA (Ubuntu 22.04)`\n- Instance Type: `g6.2xlarge` (Recommended)\n- This setup costs around $1 per hour.\n- *Do not skip* the Docker container creation in the installation process; it is required.\n\n### 📦 Deploying on [Google Compute Engine](https:\u002F\u002Fcloud.google.com\u002Fproducts\u002Fcompute)\n\n- Select `GPUs`. We recommend the GPU type `NVIDIA L4` because it's affordable and accessible, as it does not require a high quota. You may select `T4` instead for testing purposes.\n- Do **not** check `Enable Virtual Workstation (NVIDIA GRID)`.\n- We recommend the machine type `g2-standard-8`.\n- Choose the OS type `Deep Learning VM with CUDA 12.4 M129` and set the disk size to `50GB`.\n- As of late 2024, this configuration costs approximately $0.86 per hour in `us-central1 (Iowa)` and $1.00 per hour in `asia-east1 (Taiwan)`.\n- Port number `8080` is reserved by the OS image. Set `$MY_WEB_PORT` to `8888`. When connecting via `gcloud`, use the following format:  `gcloud compute ssh --zone \"xxxx\" \"instance-name\" -- -L 8080:localhost:8888`.\n- *Do not skip* the Docker container creation in the installation process; it is required.\n- CLI instructions are described in [(Markdown)](.\u002Farticles\u002Fcloud.md#-google-compute-engine).\n\n## 🤝 Community Works\n\n### 🧩 Blender Add-ons\n\nAlongside our [official Blender add-on](#-blender-add-on), the following community add-ons are also available:\n\n- [AndoSim](https:\u002F\u002Fgithub.com\u002FSlaymish\u002FAndoSim)\n- [ArzteZ-PPF-solver](https:\u002F\u002Fgithub.com\u002Ftavcitavci-sys-tavci-ui\u002FArzteZ-PPF-solver)\n\n### 📺 Videos\n\n- [*The Worst Bug In Games Is Now Gone Forever*](https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=VOORiyip4_c) by [Two Minute Papers](https:\u002F\u002Fwww.youtube.com\u002F@TwoMinutePapers).\n- [*Visual Components - ZOZO's Contact Solver Handshanking*](https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=k000SaPXK4Q) by [idkfa](https:\u002F\u002Fwww.youtube.com\u002F@idkfa3).\n\n### 📰 Articles\n\n- [*A New Open-Source Physics Engine for Blender - ZOZO's Contact Solver*](https:\u002F\u002Fwww.reddit.com\u002Fr\u002Fblender\u002Fcomments\u002F1ti5bbh\u002Fa_new_opensource_physics_engine_for_blender_zozos\u002F) on [r\u002Fblender](https:\u002F\u002Fwww.reddit.com\u002Fr\u002Fblender\u002F).\n- [*New Simulation Method To Achieve Accuracy In Collision Physics*](https:\u002F\u002F80.lv\u002Farticles\u002Fnew-simulation-method-to-achieve-accuracy-in-collision-physics) by Amber Rutherford on [80 Level](https:\u002F\u002F80.lv\u002F).\n- [*New Research Might Have Finally Solved the Clipping Bug*](https:\u002F\u002Fwww.live-laugh-love.world\u002Fblog\u002Fgame-collision-bugs-solution\u002F) by LLL Inc.\n- [*New Open-Source Physics Engine For Blender Released*](https:\u002F\u002F80.lv\u002Farticles\u002Fnew-open-source-physics-engine-for-blender-released) on [80 Level](https:\u002F\u002F80.lv\u002F).\n- [*The Official Blender Add-on for ZOZO's Contact Solver - An Open-Source Physics Solver*](https:\u002F\u002Fwww.pixelsham.com\u002F2026\u002F05\u002F20\u002Fthe-official-blender-add-on-for-zozos-contact-solver-an-open-source-physics-solver\u002F) on [PixelSham](https:\u002F\u002Fwww.pixelsham.com\u002F).\n- [*ZOZO's Contact Solver Blender Add-on 2026*](https:\u002F\u002F3dnchu.com\u002Farchives\u002Fzozos-contact-solver-b3d\u002F) (Japanese article) on [3D人-3dnchu-](https:\u002F\u002F3dnchu.com\u002F).\n\n### 📣 Sharing Your Work\n\nOur work still needs many improvements, and our documentation and tutorial videos are not very sophisticated.\nThe author would greatly appreciate it if you made your own tutorial videos, write-ups, or blog posts about the solver, and posted them online on YouTube, your blog, social media, or anywhere else.\n\n## 💼 Commercial Use and Beyond\n\nThis project is released under the [Apache License 2.0](.\u002FLICENSE). In plain terms, you may use, modify, and redistribute the code in commercial products, including proprietary software, without paying royalties or open-sourcing your own code. You only need to preserve the license notice and the attribution required by the license.\n\nIf you build something on top of this solver, we would love to hear about it, but you are not obligated to disclose anything.\n\n## 📬 Contributing\n\nWe appreciate your interest in opening pull requests, but we are not ready to accept external pull requests because doing so involves resolving copyright and licensing matters with [ZOZO, Inc.](https:\u002F\u002Fcorp.zozo.com\u002Fen\u002F) For the time being, please open issues for bug reports under the terms described below. If you wish to extend the codebase, please fork the repository and work on it.\n\nBy submitting an Issue or suggestion to this repository, you agree that your contribution is provided under the terms of the [Apache License, Version 2.0](.\u002FLICENSE). Any bug reports or feature proposals you provide will be deemed to be licensed to us and the community on a royalty-free, unrestricted basis for the purpose of improving this software.\n\nSee [CONTRIBUTING.md](.\u002FCONTRIBUTING.md) for details.\nThank you!\n\n## 💬 Participating Discussions\n\nWe have opened [GitHub Discussions](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Fdiscussions) as a place for questions, ideas, and conversations about the solver. Feel free to drop by to ask questions, share your work, or chat with the community.\n\n## 📨 Reaching the Author\n\nThis project is owned by [ZOZO, Inc.](https:\u002F\u002Fcorp.zozo.com\u002Fen\u002F) and maintained by Ryoichi Ando.\n\nFor bug reports or feature requests, please open an issue on GitHub. For usage questions, [GitHub Discussions](https:\u002F\u002Fgithub.com\u002Fst-tech\u002Fppf-contact-solver\u002Fdiscussions) is the best place to ask. Either route is the fastest way to reach the author and keeps the conversation searchable for other users.\n\nIf you would prefer to reach out privately, you can also email the author at ryoichi.ando@zozo.com.\n\nPlease refrain from attaching code patches or other materials that would be considered contributions to this project. Anything you do send is treated under the terms of [CONTRIBUTING.md](.\u002FCONTRIBUTING.md): by sending it you agree it is licensed to us and the community under the [Apache License, Version 2.0](.\u002FLICENSE) on a royalty-free, unrestricted basis.\n\nIf you used this project in a public piece of work, whether a paper, a production credit, or a personal project, the author would like to feature it here. Please send a link to your article, project page, or website (rather than images or clips themselves, since hosting them here may run into licensing issues) and we will be glad to consider linking to it.\n\n## 🙏 Acknowledgements\n\nThe author thanks [ZOZO, Inc.](https:\u002F\u002Fcorp.zozo.com\u002Fen\u002F) for permitting the release of the code and the team members for assisting with the internal paperwork for this project.\nThis repository is owned by [ZOZO, Inc.](https:\u002F\u002Fcorp.zozo.com\u002Fen\u002F)\n","ppf-contact-solver 是一个用于物理模拟的接触求解器，支持衣物、固体和杆件的碰撞检测。该项目的核心功能包括无穿透的接触解析、大规模并行处理能力以及高效的缓存机制，能够在单精度下处理超过1.8亿个接触点。它采用有限元方法进行变形体模拟，并通过符号力雅可比矩阵提高计算效率。此外，项目还具备高度的鲁棒性和稳定性，经过了严格的测试验证。适用于需要高精度物理模拟的应用场景，如服装设计与仿真、游戏开发及工程力学分析等。",2,"2026-06-11 03:56:58","high_star"]