noita_gish — Mechanics Status Report

Honest accounting of which physics features are working, which are partially working, and which have known issues. Updated as features land or break.

Branch: claude/wizardly-ardinghelli-2f45e3 · Last updated: 2026-04-25

New companion page: Mechanics Relationship Map explains how the solvers, fields, thermal effects, magnetics, automata, and debug views fit together, with compact illustrations.

New companion page: The Explosive Lab reads the shared pressure-vessel state machine behind FIRECRACKER, REACTIVE_BURN and SEALED_CHARGE out of the shader, with the ignition ladder that makes chain reactions work.

New companion page: Solver Internals opens the MPM step itself — the transfer stencil and its weights, the MLS-MPM shortcut, the fixed-point boundary, and the one-substep lag on every force applied after the gather.

New companion page: Why This Version traces the multi-generation mechanics — ferrofluid backends, living material, fracture, stiffness, blast, contact heat, burn front, coupling — naming what each older generation got wrong and why the current one was judged good enough.

solidVerified working as intended in test scenes caveatWorks but has known caveats / non-physical edge cases partialImplemented but some sub-feature disabled or unverified brokenCurrently producing wrong results stubMaterial registered but real behavior is a placeholder
Contents · Solvers · Magnetic family · Charged family · Fluids · Solids / structural · Granular & fracture · Thermal coupling · Open issues & known limitations

Solvers

SolverStatusNotes
MPM (MLS-MPM) solid Affine particle-in-cell with SVD-based per-material constitutive branches. Supports ~80 material types. The G2P pass had a regression in the recent additions — fixed in commit da9bf86 after a GLSL reserved-word collision and SSBO cap overflow caused silent shader-link failure.
SPH solid Continuous surface force (CSF), thermal coupling, codimensional thin-film. Stable.
Eulerian Air solid MAC-grid Navier-Stokes + Boussinesq buoyancy + airtight cavity pressure + Gray-Scott reaction-diffusion automata. Multiple sub-solvers all working.
SDF Field solid Rigid kinematic geometry (boxes, segments). Materials carry magnetic mode/strength/dir, thermal coupling, friction. SDF objects are kinematic only — they don't feel forces back from particles (no two-way coupling).
Magnetic Poisson caveat Jacobi-relaxation Poisson solver, ~52-72 iterations per frame. Solves ∇²φ = -∇·M and produces H = -∇φ. Core math is correct. Caveats below in the magnetic section.
Electrostatic Poisson caveat Reuses the magnetic Jacobi + field shaders (Poisson is Poisson). Coulomb force F = qE applied in a dedicated post-MPM compute pass. Solver math is correct; behavior verified for ambient-E-driven ion streaming. Triboelectric contact charging is a stub.
XPBD constraints partial Distance-constraint Jacobi solver with int fixed-point accumulators. Rope material (80) wired up; press Y to spawn. Cloth bend constraints + graph-coloring for stiffness are TODO.

Magnetic family

Resolved (April 2026): ferrofluid was forming lumps even with NO external field. Root cause: langevin_response() used max(α·H, 1e-4) to dodge the 1/tanh(0) singularity, which made every particle emit a tiny non-zero M (~saturation/30000) even when H was truly zero. Rasterized over thousands of particles, this self-amplified into the observed clumping. Fixed in commit on this branch: hard zero below x=1e-6, only the high-x branch keeps the divisor protection. Now: with no external source, ferrofluid is just a viscous fluid (correct, matches real physics). With ambient/cursor/scene source, it magnetizes and forms patterns.
Remaining caveat: ferro tends to compact more than physical when a strong external source is present. Multiple stacked fixes now mitigate this: Use the Mechanic Toggles panel (Advanced → Magnetics) to A/B which sub-mechanic is most active in your scene.

Ferrofluid liquids

IDMaterialStatusNotes
31Ferrofluid solid Baseline ferro-liquid via Tait EOS + Langevin magnetization. Climbs to a held cursor, forms spikes. Susceptibility 0.22, max force 14 m/s².
67Heavy Ferrofluid caveat High saturation (14) + alpha (3.0) + susceptibility (0.90). Climbs gravity strongly, taller spikes than baseline. Caveat: prone to over-collapse when source is strong.
68Diamagnetic Fluid solid Negative chi (-0.55), polarity = -1 in Langevin. Particles repelled from high-|H| regions; pools at edge of magnets. Visually distinct from paramagnetic ferros.
69Paramagnetic Mist solid Light aerosol (density_scale 0.25), chi 0.08. Drifts along field lines without clumping. No surface tension to make it pool.
70Sticky Ferrofluid caveat Heavy damping (0.35/s velocity decay) + chi 0.55. Forms compact globules instead of tall spikes. Same self-collapse caveat as Heavy Ferrofluid.

Thermal-magnetic solids

IDMaterialStatusNotes
57Soft Iron (MPM particles) solid Susceptibility raised 0.0018 → 0.22 in commit e15ec57. Now visibly responds to scene magnets.
58Magnetic Rubber solid Soft magnetizable solid that bends under field. Long-tested.
71Superconductor caveat Meissner effect via stateless χ = -1.8 below T_c=180K. Field expulsion shows visibly in overlay. Levitation is geometry-dependent — works as a "field cushion" pushing the block away from the magnet, but doesn't always produce the dramatic float we want. Persistent M_prev would help (replace stateless gate with hysteresis).
72Curie Ferromagnet solid Hard magnet below T_Curie ~680K, paramagnetic above. Sharp transition (smoothstep window 50K). Heat with G to demagnetize visibly.
73Eddy Copper solid Non-magnetic conductor heated by |v|² · |H|² · k. 2D approximation of Joule heating from eddy currents. Drag through a field to redden.
74Hard Magnet caveat Persistent magnetization via per-particle M_prev SSBO. Relaxation rate 0.3/s — exposure → ~3s remanence. Caveat: the relaxation lerp toward Langevin target means the "permanent" magnetization decays over a few seconds even when the bar stays cool. Real hard magnets have effectively infinite remanence below T_Curie. Long-term fix: switch to Preisach hysteresis loop.

Mechanics inside the magnetic Kelvin-force path

grid / field state particle state sampled coupling caveat field solve · grid ∇²φ = −∇·M 52–72 Jacobi H = −∇φ particles M, x, v raster demag feedback external-drive gate hf_suppress both damp the force, not the field Kelvin (χ/2)∇|H|² isotropic chain ∇(M·H) anisotropic surface spikes M_prev carried across frames, per-material relaxation the field solve is correct; every flagged caveat sits between the field and the force
grid / field state particle state sampled coupling
The magnetic force chain. The field solve itself is sound; every mechanic the table below flags as a caveat sits between the field and the force — the two damping gates, and the isotropic Kelvin term. Drawn dashed and desaturated for that reason.
MechanicStatusNotes
External-drive gate caveat Damps Kelvin force unless ambient_H, cursor (proximity-weighted), or a scene magnet is present. Cursor gate is positional as of 4450a86. Scene gate is still binary global — if a scene magnet exists anywhere, the gate is fully open everywhere. Result: ferro far from a magnet still gets self-feedback unclamped.
hf_suppress (sharpness damp) caveat Damps Kelvin force when the local field is much sharper than the bulk. Sharpness coefficient bumped 2.1 → 4.5 in 4450a86. Effective for individual-particle spikes; medium-sized clumps still slip through somewhat.
Kelvin body force caveat F = (χ/2) ∇|H|² applied to magnetic particles. Math is correct but ISOTROPIC — pulls particles toward any high-|H| region, including ones created by their own clustering (this is the dipole-dipole self-feedback issue).
Anisotropic chain force F = ∇(M·H) solid Restored as a dedicated post-MPM compute pass (ferro_chain_force.comp) following the same pattern as the Coulomb force pass. Reads M_prev + drive_field, scatters head-to-tail-attractive / side-by-side-repulsive corrections to particle velocities. With the Langevin seeding fix, M_prev is exactly zero without an external source so chains naturally only form when ferrofluid is actually magnetized. Toggleable via the Mechanic Toggles panel.
ferro_surface_force solid Capillary-style spike formation for fluid ferro materials. Active for FERRO_FLUID, HEAVY_FERRO, STICKY_FERRO. Long-tested.
Demag feedback (particle M rasterized into drive field) solid Rasterized on the final induction iteration so particles see each other's contribution self-consistently. Drives the Kelvin force gradient computation, NOT the Langevin response (which uses the scene-only field below).
Scene-only field for Langevin response solid The principled fix for the bistable trigger bug. Particles compute Langevin magnetization against a separate field texture that excludes their own rastered M (scene magnets + cursor + soft iron only). Without this, a clump of magnetized ferro saw its own field, magnetized further, sustained itself indefinitely — touching ferro once magnetized it permanently. Now: the only way to keep ferro magnetized is a continuous external source. Cost: one extra Poisson solve per frame (~2-3 ms).
M_prev cleared on particle spawn solid spawn_from_positions calls MagneticField::clear_m_prev_range for fresh particles. Without this, deleting + respawning ferro inherited stale magnetization from whatever previously occupied the same global indices — the user-reported "respawn still has field" half of the trigger bug.
Persistent M_prev SSBO + relaxation solid Per-particle vec2 magnetization carried across frames with per-material relaxation rate. Enables hysteresis, Curie memory, Meissner thermal lag.
Per-material thermal decay solid M_prev *= exp(-decay·dt) per frame, drives M to zero in absence of external field. Per-material rates: HARD_MAGNET 0.02/s (~35s half-life), FERRO 1.5/s, SUPERCONDUCTOR 30/s. Combined with scene-only Langevin, this is what cleanly demagnetizes ferro after the source is removed.
Demag pressure in fluid stress solid Magnetized fluid regions get an extra positive pressure k·|H|² added to the Tait pressure (mpm_p2g.comp ferro branch). Approximates the ½μ₀M² demag energy density that resists further compaction. Stops particles from packing arbitrarily densely under a strong field.
Per-cell M tanh-cap solid In magnetic_compose.comp, per-cell |M| saturated to CELL_M_CAP=28 via M̂ = M̂_max·tanh(|M|/M̂_max). Approximates demag-energy saturation that prevents arbitrary M density per cell. Smooth saturation (not hard clip) keeps the field gradient continuous.
Ambient field (uniform background H) solid Earth-analog uniform contribution added in magnetic_field.comp. Drives ferrofluid to self-organize without any scene magnet. Works correctly.

Charged / electrostatic family

IDMaterialStatusNotes
77Positive Ion Cloud solid q = +1, Tait fluid EOS. Streams along ambient E direction. Coulomb force runs via a dedicated post-MPM compute pass.
78Negative Ion Cloud solid Mirror of positive — q = -1, streams against E.
79Triboelectric Rubber stub Material registered with q = 0. Charges via contact friction is not yet implemented — the per-particle charge stays at zero. Currently behaves as a neutral rubber-like solid.

Mechanics

MechanicStatusNotes
Poisson solver (∇²φ = -ρ/ε₀) solid Reuses the magnetic Jacobi + field shaders unchanged. Convergence verified.
Charge rasterization solid Bilinear-weighted fixed-point atomic deposit, identical pattern to magnetic.
Coulomb force F = qE solid Dedicated post-MPM compute pass (electrostatic_force.comp). 28 m/s² per-frame cap on acceleration to prevent integrator blowup.
Triboelectric contact charging stub Not implemented. Need contact-detection + charge-transfer rules. ~150 LOC follow-up.
Ambient E-field solid Uniform background E contribution, mirror of ambient_H.

Fluids

SPH and MPM-fluid materials. Most have been long-tested.

IDMaterialStatusNotes
SPHSPH Water / Oil / etc. solid CSF surface tension, viscosity, thermal coupling. Long-stable.
15MPM Fluid (Tait) solid Weakly-compressible Tait EOS. Used as base for ferro variants.
16Flammable Fluid solid Tait + ignition + burn-rate chemistry. Long-stable.

Solids / structural

Standard MPM constitutive: elastic, fracture, hardening, ceramic, composite, etc. All long-tested. See technique_guide.html for details on each.

Granular & fracture

IDMaterialStatusNotes
75Granular Sand solid Drucker-Prager elastoplasticity (Klar 2016 simplified) with 35° friction cone. Forms angle-of-repose pile correctly when given enough material — needs ≥1m³ of sand to make a visible cone, the original showcase scene was too narrow.
76Phase-Field Brittle caveat Historical description: energy-driven damage growth + (1-d)² stress degradation, with a Laplacian upgrade proposed. Updated 2026-09-19: the selectable AnisoMPM path now has a nonlocal damage term for three enrolled materials; other branches retain their own laws. Scope and remaining resolution caveat.

Thermal coupling

Long-tested. SPH-MPM-Air-SDF cross-coupling all working. New magnetic-thermal couplings (Curie, Meissner, Eddy) are wired through and respond to heat sources.

Open issues & known limitations

Roadmap (priority order)

  1. Per-mechanic toggle panels — add to magnetic first, then electrostatic / MPM constitutive. Lets you isolate which sub-mechanic is producing wrong behavior. ~150-200 LOC per solver. This will dramatically improve our debugging cadence.
  2. Restore anisotropic chain force as a dedicated post-MPM pass.
  3. Per-cell M density cap in the particle rasterization to prevent runaway clumping.
  4. SDF spawn from creation menu — discoverability fix for scene magnets, soft iron blocks.
  5. Two-way SDF rigid-body dynamics — biggest single change remaining; magnets feel forces from particles.
  6. Scientific validation of showcase scenes — once toggle panels exist, walk through each scene with toggles to verify the documented "expected" behavior matches reality.

This file is generated by hand and updated when features land or break. When the magnetic mechanics toggle panel ships, this report should be expanded with per-toggle behavior notes.