blast-stress-solver
Rust bindings for the Blast stress solver, packaged for straightforward native and WebAssembly consumption from Cargo.
This crate gives you two main layers:
ExtStressSolverfor Blast-only stress, bond failure, and split handlingblast_stress_solver::rapier::DestructionRuntimefor plugging destructibles into an existing Rapier app while keepingPhysicsPipeline::step(...)in the consumer
DestructibleSet still exists as the lower-level escape hatch for advanced
integration and explicit non-contact force injection.
If you want to auto-generate bonds from arbitrary pre-fractured piece meshes,
enable the authoring feature and use blast_stress_solver::authoring.
Installation
Core solver only:
[]
= "0.4.1"
With built-in scenario builders:
[]
= { = "0.4.1", = ["scenarios"] }
With Rapier integration and scenario builders:
[]
= { = "0.4.1", = ["rapier", "scenarios"] }
= { = "0.30", = false, = ["dim3", "f32"] }
With auto-bond authoring helpers:
[]
= { = "0.4.1", = ["authoring"] }
Target support
The published crate currently ships packaged backends for:
aarch64-apple-darwinwasm32-unknown-unknown
For other Apple/Linux native targets, the published crate falls back to compiling the bundled Blast C++ sources on the consumer machine with a normal C++17 toolchain. That removes the need to vendor the PhysX monorepo just to support x86_64 macOS or Linux consumers.
The packaged native and wasm32-unknown-unknown backends both include the
public authoring API.
wasm32-unknown-unknown intentionally stays prepackaged: downstream Rust wasm
builds do not need Emscripten, wasi-sdk, or a second Blast-side loader.
For other Apple/Linux native targets, authoring still works through the same
bundled C++17 source-build fallback used by the core solver.
Advanced overrides:
BLAST_STRESS_SOLVER_STATIC_LIB_PATH=/abs/path/to/libblast_stress_solver_ffi.aBLAST_STRESS_SOLVER_LIB_DIR=/abs/path/to/lib/dirBLAST_STRESS_SOLVER_FORCE_SOURCE_BUILD=1for the bundled Apple/Linux native fallback
Quick Start
The easiest way to understand the API is in two steps:
- Build a destructible wall and drive the Blast solver directly.
- Take the same wall and let
DestructionRuntimeintegrate it into an existing Rapier world.
The examples below are intentionally explicit about which code belongs to your
application and which code is specific to blast-stress-solver.
1. Blast-only example: build and collapse a simple wall
This version does not use Rapier yet. It shows the minimum Blast-side workflow:
- Build a wall scenario.
- Create
ExtStressSolverfrom its nodes and bonds. - Apply gravity and an impact force.
- Ask Blast for fracture commands and apply them.
use ;
use ;
What to notice:
build_wall_scenario(...)is optional convenience. If you already have your own nodes and bonds, you can skip thescenariosfeature and buildNodeDesc/BondDescdirectly.- The bottom row of the built-in wall is automatically marked as support
(
mass == 0.0), so the wall has something fixed to break away from. ExtStressSolverowns the Blast family/actor state. After fractures are applied,actor_count()grows as disconnected pieces split apart.
Authoring quick start
authoring is the Rust-side equivalent of the JS package's triangle-based
auto-bonding path. The intended flow is:
- collect one triangle soup per piece
- mark whether each piece is bondable
- call
create_bonds_from_triangles(...)orbuild_scenario_from_pieces(...)
Runnable example:
The full copy-pasteable source lives in
examples/auto_bond_wall.rs. It builds two touching cuboids, runs the public
auto-bonding API, and prints the resulting bond.
Notes:
- triangle vertices must already be expressed in the target scenario space
bondablemeans "participates in bond generation", not "fixed to the world"- a fixed support is still represented by
ScenarioNode { mass: 0.0, .. } build_scenario_from_pieces(...)is the highest-level convenience APIcreate_bonds_from_triangles(...)is the lower-level API when you already manageScenarioDescassembly yourself- the packaged Bevy demo in
blast-stress-demo-rsnow rebuilds its embedded fractured scene packs through this same public authoring API at load time
2. Rapier example: the same wall, now integrated into an existing Rapier app
This version shows the recommended runtime for real consumers.
DestructionRuntime does not replace Rapier. Your app still owns the Rapier
world, the physics pipeline, and the frame loop. blast-stress-solver handles
the destruction-specific part:
- keep a Blast stress graph for the structure
- derive accepted impacts from Rapier contacts
- detect failed bonds and split Blast actors
- create/update/destroy the corresponding Rapier bodies and colliders
- resimulate the same frame when topology changes
use ;
use ;
use ;
use *;
What to notice:
- Your app still owns
RigidBodySet,ColliderSet, the Rapier pipeline, and the main frame loop. DestructionRuntime::initialize(...)is the point where Blast’s initial actor graph becomes actual Rapier bodies and colliders.DestructionRuntime::step_frame(...)is the recommended integration point. That is where this crate inspects Rapier contacts, injects accepted impacts, applies fractures, rewrites Rapier body/collider topology, and requests same-frame resimulation when needed.physics_pipeline.step(...)is still your responsibility. This crate integrates into Rapier instead of hiding it.
WebAssembly
This crate supports downstream Rust applications that build for
wasm32-unknown-unknown.
The intended model is:
- your application depends on
blast-stress-solveras a normal Rust dependency - your application builds one final wasm output
- no Blast-specific sidecar wasm or JS loader is required
Downstream wasm-bindgen example
[]
= ["cdylib"]
[]
= "0.4.1"
= "0.2"
use ;
use *;
That build still emits one final application wasm file. There is no extra Blast runtime bundle to host or load manually.
Features
rapier: enables Rapier3D integration helpersscenarios: enables built-in wall, tower, and bridge scenario builders
Publishing
Do not run cargo publish directly against
blast/blast-stress-solver-rs/Cargo.toml. The source crate is marked
publish = false on purpose so local publishes cannot accidentally ship the
monorepo build layout.
Local crates.io preflight:
Local publish:
Tag-driven GitHub Actions release:
- bump
versioninblast/blast-stress-solver-rs/Cargo.toml - commit and push the branch
- push a matching tag such as:
That workflow stages the crate, runs the packaged native/wasm/demo-consumer proofs, dry-runs publish, publishes to crates.io, and creates a GitHub release.
Notes
- Local publish-style proof:
scripts/assemble-blast-stress-solver-package.sh --verify-demo-consumerstages the crate, verifies the packaged native and wasm smoke consumers, and runs the realblast/blast-stress-demo-rsheadless fracture test against the staged package. - The published crate is distributed as packaged Rust source plus:
- prebuilt backend artifacts for
aarch64-apple-darwinandwasm32-unknown-unknown - bundled native C++ sources for the Apple/Linux source-build fallback
- prebuilt backend artifacts for
- The monorepo development setup can still build the backend from source, but consumers no longer need to vendor the monorepo to get that native fallback.