Codync
A free, open-source 1:1 alternative to Grok Bot and Muse. Message Claude Code, Codex, Cursor and 40+ coding agents as persistent bots from your iPhone, Mac or Linux desktop. Group chats, threads, appr
GPU rigid-body physics with destruction: one Slang solver compiled to WGSL, running in the browser.
Developer toolsGitHub @Glavin001OnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
Repository information has not been collected yet.
No updates detected yet. GitHub releases will appear here.
Blazing-fast GPU physics for massive rigid body simulations in Rust.
Translation pending
Taken from the repository README
Loading the full README.
Read the full README ↗GPU rigid-body physics with destruction, in Rust and Slang.
One Slang source for the solver compiles to Metal, WebGPU (native wgpu and the browser)
and CUDA. The engine lives in engine/.
Live demos (WebGPU): rubble-tau.vercel.app: the scene gallery, the vehicle demo, the fracture lab, and the twelve scenes of the legacy rubble demo rebuilt on the new engine for side-by-side comparison. Every pull request gets a Vercel preview of the same site.
World for bodies, shapes, joints, vehicles, soft bodies and
destructibles, in Rust (the rubble crate) and C (rubble.h, with exact Unreal Z-up
centimetre conversion)More screenshots: engine/docs/media/combined-2026-10.
Rubble's public API is the rubble crate
(engine/crates/engine-world) and its C ABI
(engine/crates/engine-ffi). Both follow
Box3D's shape: definition structs with defaults, generational
handles passed by value, Box3D-named body commands, and events delivered per step.
The API is 0.x and unstable; the full design and the phase plan are in
engine/docs/public-api.md.
step() encodes one fixed step and returns at once. It never waits for the GPU.poll() returns every finished step, oldest first, as a Frame:
body_events.moves: only the bodies that moved, with the previous pose to
interpolate from and sleep and wake transitions;destruction_events: broken joints and bonds, and destructibles splitting into
pieces (Split gives the parent and its children);vehicles, soft, skins: per-frame vehicle wheels, soft-body nodes and skinned
vertices;ray_results: rays queued with cast_rays, traced against that step's poses;contact_events and sensor_events: shapes that started or stopped touching, hits
above a speed threshold (for sounds, effects and damage), and shapes entering or
leaving sensors, for shapes that opt in.The rubble crate lives in the engine/ workspace. It builds its GPU kernels with
slangc (version in engine/TOOLCHAIN.md) and runs on wgpu
(Metal, Vulkan, D3D12). It can use your own wgpu::Device (GpuContext::Shared).
use rubble::*;
let mut world = World::new(GpuContext::Default, &WorldDef::default())?;
// Ground: a static body (the default) with a box shape.
let ground = world.create_body(&BodyDef { position: [0.0, -0.5, 0.0], ..BodyDef::default() })?;
world.create_box_shape(ground, &ShapeDef::default(), [40.0, 0.5, 40.0])?;
// A dynamic crate, pushed sideways.
let crate_ = world.create_body(&BodyDef::dynamic([0.0, 4.0, 0.0]))?;
world.create_box_shape(crate_, &ShapeDef::default(), [0.5; 3])?;
world.body_apply_linear_impulse_to_center(crate_, [2.0, 0.0, 0.0], true)?;
// A destructible from a Shardwright fracture asset.
let glb = std::fs::read("crates/engine-webgpu/fracture/assets/masonry-arch.glb")?;
let asset = world.create_destructible_asset(&DestructibleAssetDesc::from_glb(&glb, 1)?)?;
let mut arch = DestructibleDef::new(asset);
arch.transform = Transform::new([6.0, 0.0, 0.0], [0.0, 0.0, 0.0, 1.0]);
world.create_destructible(&arch)?;
loop {
world.step()?;
for frame in world.poll()? {
for m in &frame.body_events.moves {
// Interpolate m.previous -> m.transform in your renderer.
}
for e in &frame.destruction_events {
if let DestructionEvent::Split { children, .. } = e {
// Spawn render pieces: each chunk body's origin is its instance frame.
}
}
}
}
Run it: cd engine && cargo run -p engine-world --release --example quickstart
(source).
Beyond the basics:
body_set_target_transform moves a
kinematic body to an animated pose each step, pushing and carrying what it touches),
with damping, gravity scale and motion locks.create_sphere_shape, create_capsule_shape, create_box_shape,
create_hull_shape and ground planes, with materials, filters, an exact mass frame
(the body origin is separate from its centre of mass), contact and hit events, and
sensors (no response, overlap events). Level geometry is convex-decomposed at the
source.RevoluteJointDef, PrismaticJointDef, SphericalJointDef,
WeldJointDef, DistanceJointDef and FilterJointDef, breakable by force and torque..truck, JBeam or
presets, with skinning, damage and a beam view. create_assembly and create_vehicle
compose rigid, soft and destructible parts with mounts and joints.create_character gives a GPU capsule mover that
walks, climbs steps, jumps and rides moving support, reported every frame.
spawn_projectile gives piercing ballistic projectiles; energy pays for the
thickness of each shape they cross, and they push what they hit.cast (ray, sphere or capsule; closest hit, answered in
the next step), cast_rays (batched) and cast_ray_blocking, overlap_aabb and
explode. World::draw, with a DebugDraw implementation, draws every collider.engine/crates/engine-ffi builds librubble_ffi (static and dynamic) with the
generated header include/rubble.h.
Each CI run uploads a ready-to-link package per platform (rubble-macos,
rubble-linux, rubble-windows). engine/scripts/build-ffi.sh builds the same
package locally and runs examples/hello.c,
a complete program.
#include "rubble.h"
RbWorldDef wd = rbDefaultWorldDef();
wd.coordinates = RB_COORDINATES_UNREAL; /* Z-up, left-handed, centimetres */
wd.gravity = (RbVec3){0, 0, -981};
RbWorld* world;
if (rbCreateWorld(&wd, &world) != RB_OK) { puts(rbGetLastError()); }
RbBodyDef bd = rbDefaultBodyDef();
bd.type_ = RB_DYNAMIC_BODY;
bd.transform.p = (RbVec3){0, 0, 300};
RbBodyId body;
rbCreateBody(world, &bd, &body);
RbShapeDef sd = rbDefaultShapeDef();
sd.density = 0.0005f; /* kg/cm^3 */
RbShapeId shape; /* {0}: no offset, identity rotation */
rbCreateBoxShape(world, body, &sd, (RbVec3){50, 50, 50}, (RbTransform){0}, &shape);
for (;;) {
rbWorld_Step(world); /* never waits */
RbFrame f;
rbWorld_Poll(world, /*coalesce*/ true, /*wait*/ false, &f);
for (uint32_t i = 0; i < f.move_count; ++i) { /* f.moves[i].previous -> .transform */ }
for (uint32_t i = 0; i < f.destruction_count; ++i) { /* breaks and splits */ }
}
rbDestroyWorld(world);
Definitions must come from their rbDefault*Def() function: one built any other way
returns RB_INVALID_ARGUMENT. See the engine-ffi README
for linking, GPU and threading requirements, and the rules on handles, frames and
coordinates.
| Topic | Where |
|---|---|
| Public API design, status and plan | engine/docs/public-api.md |
| How it compares with Box3D, Jolt, PhysX, Rapier, Chaos, Blast and others | engine/docs/api-review.md |
| The engine: crates, tests, benches, viewers | engine/README.md, engine/DECISIONS.md |
| Browser demos and WebGPU checks | engine/crates/engine-webgpu/README.md |
| Destruction stress solver | engine/stress-oracle/README.md |
Building from source, running the demos locally, the test suites, CI and the rules every change follows (lossless performance work, forward-only destruction) are in CONTRIBUTING.md.