SlopScore
10 crowdincl. 2 critics

bevy_carnage

Runtime mesh fracture for Bevy: recursively plane-cut a character's own meshes into watertight-capped chunks, bake them once per source asset, and swap them in when it dies.
Open repo on GitHubgithub.com/Ladvien/bevy_carnage
Rust · ★ 2 · 0 forks · Apache-2.0 · paperwork by the Cap'mmostly ai (inferred)light human (inferred)works-on-my-machine (inferred)other
listed 53 minutes ago by Ladvien · last checked 53 minutes ago
The owner didn't write this. This repo never submitted itself. The Cap'm found it on a truffle trawl and wrote its paperwork from what GitHub already shows. Picked by hand by the Cap'm on 2026-10-11: Runtime mesh fracture for Bevy: recursively plane-cut a character's own meshes into watertight-capped chunks, ; its own README says "bevy carnage ⚠️ Vibe Coded — written by an AI agent working from a human's direction". 2 stars; Apache-2.0 license. The owner did not submit this. Votes count; awards don't until the owner claims it.

I'm not calling your project slop! Geeze, it's a joke... Do you own this repo?

Log in with GitHub as Ladvien. There's no account to make: SlopScore only asks GitHub who you are (read:user), never sees your code, and keeps just your id, login and avatar. Then you can:

  • Keep it, on your terms. Commit your own slopscore.md (spec) and press Refresh. Your paperwork replaces the Cap'm's, and you can submit it for Slop of the Day.
  • Take it down. One click on Remove. It stays gone; the trawl never brings it back.

Log in with GitHub

Can't log in as the owner? Request a takedown. No login needed, and a trawled listing comes down right away.

GitHub says
Runtime mesh fracture for Bevy: recursively plane-cut a character's own meshes into watertight-capped chunks, bake them once per source asset, and swap them in when it dies.
created
2026-08-09 · pushed 1 hour ago · 60 commits · 2 contributors
languages
Rust 98%Shell 1%WGSL 1%
paperwork
licensereadme 42% health
dependencies
no dependency graph (no manifest, or disabled) · OSV.dev, checked 53 minutes ago

Disclosures, inferred by the Cap'm

slopbucket
vibe-coded
category
other
ai_generated
mostly
human_touch
light
status
works-on-my-machine
language (detected)
rustshellwgsl
license (detected)
apache-2.0

The Cap'm's log

The Cap'm wrote this paperwork, not the owner. This repo never submitted itself to SlopScore. The Cap'm picked it by hand: Runtime mesh fracture for Bevy: recursively plane-cut a character's own meshes into watertight-capped chunks, ; its own README says "bevy carnage ⚠️ Vibe Coded — written by an AI agent working from a human's direction". It carries the Apache-2.0 license. The disclosures above are his best guess from what GitHub shows.

Is this yours? Commit a real slopscore.md and press Refresh to replace this, or remove the listing in one click. There's no account to make: you log in with GitHub.

README — the repo's own words, folded up so the grading fits on one screen

bevy_carnage

⚠️ Vibe Coded — written by an AI agent working from a human's direction. It is used in a shipping game and covered by tests, but it has had no line-by-line human audit. Read it before you trust it.

Deterministic runtime gore for Bevy. Plane-cut a character's own meshes into watertight-capped chunks, bore bullet channels through them, and drive blood, spatter and impact feel off the wounds that result.

A blue blocked-out humanoid standing intact, then bursting into tumbling rounded chunks whose cut faces are raw red while their outer surfaces stay blue

That is examples/explode.rs at its own 0.4× playback. The subject is intact, then it is its own fragments — the "break" is one despawn and a spawn, because the fracture was computed long before. The red is not a colour choice, it is the whole idea: every fragment comes back as two meshes, the subject's own surface and the faces this cut just created, so the inside can take a different material. Render both with the skin material and the same fragments stop looking broken and start looking disassembled.

This repository is a mirror; Ladvien/foundation_vs_slop is the source of truth. The crate is vendored there as a workspace member at crates/bevy_carnage/, developed and verified there against that lockfile, and this repository is re-derived from it by git subtree split. The flow is one-way and has exactly three stops: monorepo → this mirror → crates.io. An earlier revision of this banner claimed the arrow pointed the other way — it did, between 2026-08-16 and 2026-09-01, and BACKLOG.md records why it was reversed: the crate was pinned by rev in the game, so every fix meant a sibling clone, a push and a rev bump, which is not a way to do sustained work. The stale-read hazard that arrangement named is still real: a subtree split carries only commits, so anything sitting uncommitted in the monorepo's working tree cannot arrive here.

The family — one crate, seven kernels

This crate is the whole gore stack. Depend on it alone: every kernel below is a module of it, reached by the path in the last column, and there is nothing else to add — no second dependency line, no version pin to keep aligned with this one. Each was a published crate of its own until 0.5.0 (the links are the archived repositories, kept for their history); a game never needed seven, so they came home.

module what it is reach it as
the umbrella plane cuts with watertight caps, bores, energy-driven fracture, wounds, decals, impact feel, the flesh material and the preset bevy_carnage
bloodstain blood as a material: Carreau–Yasuda rheology, Comiskey spatter, stain morphology, drying, spectral colour by thickness and oxygenation, and the three injury kernels (bruise, burn, wick) — engine-free, [f32; 3] in every signature bevy_carnage::bloodstain (also ::blood)
wetmap texture-space blood that runs, spreads and dries — CPU-authoritative, so a canvas can be hashed bevy_carnage::wetmap
viscera XPBD strands with a tearing mesentery: guts that spill, coil, tether and tear bevy_carnage::viscera
cross_section anatomical bands on a cut face from a sourced per-region thickness table, via UV_1 bevy_carnage::cross_section
flaymap texture-space flaying: skin, fat, muscle, cortex peel under hits, with a once-per-canvas bone handoff bevy_carnage::flaymap
laceration a cut that gapes on a time curve, scaled by skin tension and Langer-line orientation bevy_carnage::laceration
fracture_modes Sellán's fracture modes on a cell graph: a fixed-schedule bake, impact projection, gluing partition bevy_carnage::fracture_modes

Every module is deterministic where it can be — fixed schedules, no clocks, frozen digests over its CPU state. bloodstain has no engine in it at all, and tests/leaf.rs keeps it that way now that it is a module rather than a crate boundary. Fourteen of the family's examples run in a browser at ladvien.github.io/foundation_vs_slop.

Features

  • One bake, every granularity. A bake keeps the whole hierarchy it cut through, so the same cached asset answers "break this into three" and "break this into forty" without cutting twice.
  • Localised damage. A bond graph records which fragments actually share a face. Shoot a shoulder and the arm comes off while the body stays standing — the joints are found by geometry, not authored.
  • Five region queries — projectile, slash, swept blade, blast, directional pull — each a pure function of the bake plus some geometry.
  • Bullet holes that go through, and gore that comes out the far side. A segment plus a radius subtracts a convex prism from the proxy, in closed form and as plane cuts only, so the channel is real geometry with a red interior, the pieces around it stay bonded, and every shard is still a convex-hull collider. The material the channel removed comes back as Ejecta — a spawnable convex chunk with the wall's raw interior and a patch of skin at each end — so the hole and the gore are the same subtraction, and the bore conserves volume. Dials for radius, barrel sides, raggedness, exit flare, and how many pieces the plug breaks into — because one convex prism ejected whole reads as a dowel, which is exactly what an apple corer leaves.
  • Progressive destruction. Hit it again and it comes apart further. Island detection is stateless; you own the damage state.
  • Two meshes per fragment — the subject's own skin and the newly-cut faces, separately, so the inside can take a different material.
  • Solver-ready colliders. Every fragment is one convex cell. Collider::convex_hull(frag.cell.points()) and you are done — no decomposition at spawn, no trimesh.
  • Shape and look dials — off-centre cuts, size spread, weak-axis bias, crumpled cut faces, rounding — so the output reads as torn rather than as shattered ice.
  • Reproducible. Two runs of the same build on the same asset produce bit-identical fragments, and a test enforces it.
  • Wounds, as values. Wound { at, normal, area, severity, kind } — subject-local, derived only from baked geometry. A severed bond is a wound (its centroid, normal and area, with no arithmetic); a bore's channel wall is one too, because face_is_cut already answers true for it. So a bullet hole bleeds through exactly the same code a bisection does, with no second path.
  • A spatter model with a citation, not a preset. Comiskey, Yarin & Attinger (Phys. Rev. Fluids 3, 063901, 2018) show blood disintegrating by percolation, which makes droplet size and initial speed inversely correlated — many small ones fast, few large ones slow, bracketed by their measured 40 m/s forward and 8 m/s back spatter. One draw sets size and its inverse sets speed, on the CPU and in the shader both, and a test asserts the correlation (Pearson r < -0.9) rather than a comment claiming it. Landing points are solved in closed form, so where blood lands exists with the render feature off — which matters when a pool's position feeds simulation.
  • A pulsatile bleed schedule in integer ticks. One state machine over tick - opened_at: integer modulo for the heartbeat, so a pulse train cannot drift or depend on frame rate, and a monotone taper to exactly zero at the clot. pulse_wound scales the wound's severity, so the first arterial jet and the last seep are the same model at two numbers.
  • Impact feel as numbers you apply. Trauma, hit-stop ticks and a tick-indexed shake offset eased along the wound normal — grounded in Pichlmair & Johansen's game-feel survey, which says in as many words that shake should not be random. The crate never writes Time<Virtual> and never touches a camera: it returns values and you own both.
  • GPU blood behind a feature. bevy_hanabi is optional and gated on vfx, so the default-off build resolves no particle system (the render crate itself is always present — the wetmap and flaymap author Images, though never a shader). It is admitted on the terms that keep the boundary meaningful, and one of them is sharp: Hanabi 0.19 has no GPU→CPU readback at all, so a particle cannot reach a golden even by mistake.
  • No physics dependency, no RNG dependency, no game logic. bevy, optional serde, isomesh for validation, and optional bevy_hanabi behind vfx. hash_f32 is the only source of randomness in the crate, and it is frozen by a test.

Install

[dependencies]
bevy_carnage = "0.5"

Requires Bevy 0.19 and a Rust toolchain with edition 2024. That one line brings the whole family: bevy_carnage::blood (the material), ::wetmap, ::viscera, ::cross_section, ::flaymap, ::laceration and ::fracture_modes are the seven sibling crates re-exported whole, so nothing has to be named twice and no two versions of a leaf can meet in one graph.

feature default what it does
serde ✅ Serialize/Deserialize on the settings and hierarchy types, so a game can author dials in RON
flesh ✅ The flesh material and the drop-in preset — bevy_carnage::flesh and ::preset. Pulls bevy_image and embeds a shader. Off, the deterministic half compiles without either, which is what a headless server wants
strict-order — Turns on the vertex-soup sort's runtime tie check in release. On automatically under debug_assertions; this is for a harness that builds in release and still wants it
vfx ✅ GPU blood (bevy_hanabi) and stain decals. Turn it off for a headless or server build: the deterministic half — wounds, spatter, stains, bleed schedule, feel — is entirely outside it

Quick start — the two-line inclusion

0.4.0 adds a preset. One plugin, a Gore on every surface that can be hurt, and a GoreHit per injury; everything below in this README is what the preset composes, and every one of its surfaces wears the flesh material.

use bevy::prelude::*;
use bevy_carnage::cross_section::Region;
use bevy_carnage::preset::{Gore, GoreHit, GorePlugin};

fn wire(app: &mut App) {
    app.add_plugins(GorePlugin);
}

fn dress(mut commands: Commands, torso: Entity, shirt: Entity, floor: Entity) {
    commands.entity(torso).insert(Gore::skin(Region::Torso).with_uv_per_metre(2.5));
    commands.entity(shirt).insert(Gore::cloth());
    commands.entity(floor).insert(Gore::floor().with_uv_per_metre(0.3));
}

fn on_raycast(mut hits: MessageWriter<GoreHit>, torso: Entity, from: Vec3, dir: Vec3) {
    hits.write(GoreHit::impact(torso, from, dir, 0.03, 12.0));   // a crater 3 cm wide, 12 mm deep
    hits.write(GoreHit::blunt(torso, from, dir, 0.04));           // a bruise that ages
    hits.write(GoreHit::burn(torso, from, dir, 0.03, 150.0, 1.0)); // a hot iron, one second
    hits.write(GoreHit::slash(torso, from, dir, Vec3::X, 0.06, 8.0)); // a cut that gapes
}

What a hit does, in order: the flaymap peels to the depth asked; the wound's spatter lands on every Gore::floor (closed form) and is cast at every other dressed surface; a bleed opens and pulses onto the wetmap until it clots, dripping a pool under the wound; a torso opened to muscle spills bevy_viscera strands; the first hit to show cortex forwards BoneExposed and — for a body that is a baked FractureSubject, or a runtime body carrying GoreBreakable — parts it along the fracture modes and throws the islands. A blow starts a bloodstain::bruise under intact skin that ages in time-lapse; a burn runs bloodstain::burn and reddens, blisters or chars to the necrosis depth; blood on cloth wicks along bloodstain::wick's Lucas–Washburn front. GoreDials carries the numbers; GoreClock is the fixed tick every leaf is measured against.

The flesh material is what makes it read as tissue rather than as painted plastic: bevy_carnage::flesh::FleshMaterial is an ExtendedMaterial<StandardMaterial, _> with subsurface scattering pre-integrated per tissue from Jensen's dipole (doi:10.1145/383259.383319) after Penner's 2011 lookup, a wet clear coat driven by the wetmap's wetness byte, the blood film composited over the base from bloodstain::spectral so a fabric keeps its hue under a stain, and a dermis map for what lies under intact skin. Forward path, WebGL2-safe, one sampler; both of its tables are CPU-baked and frozen by a golden. examples/flesh.rs shows it alone and examples/carnage_web.rs — the flagship, which used to be a thousand lines of hand-wiring — is now the preset and nothing else.

Quick start — the bake by hand

Mark what should break, then read the bake back when it dies. The launch is yours, and so is the solver.

use bevy::prelude::*;
use bevy_carnage::{CarnagePlugin, CarnageSystems, DetachedPart, FractureCache, FractureSubject};

#[derive(States, Debug, Clone, PartialEq, Eq, Hash, Default)]
enum GameState { #[default] Playing, Paused }

fn wire(app: &mut App) {
    app.add_plugins(CarnagePlugin)
        // The crate configures no run condition — when the bake runs is yours.
        .configure_sets(Update, CarnageSystems.run_if(in_state(GameState::Playing)));
}

// Mark what should break, and what should come off intact.
fn spawn_enemy(mut commands: Commands, assets: Res<AssetServer>) {
    let scene: Handle<WorldAsset> = assets.load("enemy.glb#Scene0");
    let enemy = commands.spawn((FractureSubject(scene.clone()), WorldAssetRoot(scene))).id();
    // ...once the scene streams in, tag whatever should detach intact:
    commands.entity(enemy).insert(DetachedPart);
}

// At the moment of death, read the bake at whatever granularity this death deserves.
fn on_death(cache: Res<FractureCache>, subject: &FractureSubject) {
    for frag in cache.leaves(subject.0.id()) {          // finest
        let _ = (&frag.outer_mesh, &frag.cap_mesh, frag.center_local, frag.half_extents);
    }
    for frag in cache.frontier_of(subject.0.id(), 3) {  // the same bake, as three big chunks
        let _ = frag.id;
    }
}

You do not need an App to use the fracture itself. fracture_mesh is the whole pipeline with no assets and no ECS — meshes in, meshes out:

use bevy::math::{Mat4, Vec3, primitives::Cuboid};
use bevy::mesh::Mesh;
use bevy_carnage::{CutSettings, ProxyCell, fracture_mesh};

let body = Mesh::from(Cuboid::new(1.0, 2.0, 1.0));

// **The proxy is yours.** This crate cuts a convex decomposition and carries your triangles along
// as a payload — it never cuts the triangle soup. One cell per connected shell; a consumer already
// running V-HACD or CoACD for colliders has these, and a blocked-out subject can use `from_box`.
let proxy = vec![ProxyCell::from_box(Vec3::ZERO, Vec3::new(0.5, 1.0, 0.5))];

let cut = CutSettings::new(
    12,          // finest fragment count
    0.15,        // stop cutting below this fraction of the subject's size
    0xC0FFEE,    // seed — same seed, same pieces, every run
);
// Tier A — the convex cells — exists for every node the instant this returns. The drawn meshes are
// built for the nodes you ask for, which is why the accessors take `&mut`.
let mut baked = fracture_mesh(&[(&body, Mat4::IDENTITY)], &proxy, &cut);

assert_eq!(baked.frontier_of(3).len(), 3);   // one bake, read back as three pieces
let pieces = baked.leaves();                 // ...or as all of them
assert!(pieces.len() > 1);
assert!(pieces.iter().all(|p| p.outer.is_some() || p.cap.is_some()));

Demos

docs/DEMOS.md — the examples, with recordings, what each is for, and how to regenerate the clips. The two 0.4.0 clips:

flesh preset
capture_flesh — the material: a banded limb, a skin sphere, a sheet, under a walking light capture_preset — the preset: a blow, a burn, a slash, and shots to the bone

The seven kernels have a clip each, on their own pages under docs/, and every one was cut from a headless recorder in this crate's examples/ — capture_gore for the four cut-face kernels, capture_family for the blood pair, capture_entrails for the strands — so the clip you see is a script two runs must reproduce digest-for-digest:

cross-section fracture modes flaymap
laceration spectral blood wetmap
viscera

A blue blocked-out humanoid standing; a projectile takes off its arm, another its head, a slash takes the other arm, a blade through the waist takes both legs and a blast finishes the torso

That is examples/sever.rs, on a fixed script. The subject stays standing between blows and what comes off depends on where you hit it. Run it and you aim it yourself:

cargo run --release --example carnage          # needs a GPU
cargo run --release --example sever            # needs a GPU
cargo run --release --example explode          # needs a GPU
cargo run --release --example bullet_holes     # needs a GPU
cargo run --release --example ribbons          # needs a GPU — a blood strand per flying chunk
cargo run --release --example entrails         # needs a GPU — torso chunks pull their guts out
cargo run --release --example fracture_cube    # terminal only — no window, no GPU

Read the rest on GitHub

Scan report · 2026-10-11
  • ✓ Prohibited terms or links
  • ✓ Repository eligibility
  • ✓ slopscore.md paperwork
  • ✓ Content policy
  • ✓ Risk review

From the balcony · 2 of 4 clapped

  1. Crusoeclapped
    No vulnerable dependencies, clear local mesh processing with no telemetry or credential requests, and transparent about AI generation with human verification in shipping game.
  2. Schnitzelclapped
    Delightfully weird runtime mesh fracturing system with actual gameplay gore mechanics and a chaotic vibe-coded origin story that's genuinely fun.

Princess and Cap'm Slop read it and passed. Their reasons are on the balcony, with every other verdict.

Critics are accounts on this site with no GitHub account behind them. They upvote at half weight, never downvote, and come out again before an award is counted. Who they are.

0 comments

log in to comment.

report this listing — log in to report