cube3D (Moreno et al.) is a research platform of physical smart bricks — ESP32-powered cubes you snap together into an artefact. The trick: the assembled artefact classifies itself. No camera, no server, no cube with a global view. Each cube runs an identical ~26k-parameter network, exchanges a small state vector with its face-neighbours, and after a few dozen rounds of gossip every cube independently concludes "we are a chair." Break the chair and the surviving cubes re-converge on whatever they still resemble — decentralized damage recovery.
This bench is a faithful browser port. The Python/TensorFlow repo needs Colab to even look at; here the same system runs in your pocket. The weights are not retrained or approximated — they're lifted verbatim from neural_network.h, the C header flashed onto the real cubes, and the 487 voxelised ShapeNet shapes are the repo's actual dataset (ShapeData/xdata_7class.npy).
This bench grew a sequel: golem.mino.mobi — a Minecraft-like builder world where you assemble the swarm yourself, and once it decides what it is, it acts like it: cars drive, boats sail, houses refuse to move.
It's a neural cellular automaton (NCA). Each cube holds a 28-channel state: 1 structure bit (am I here?), 20 hidden channels — scratch space the gossip protocol invents for itself during training — and 7 class-belief channels, one per ShapeNet class (plane · chair · car · table · house · guitar · boat). One tick:
relu(Σ W_dir · state_dir + b) → 84 features. A missing neighbour reads as zeros — silence.84 → relu → 84 → 27.tanh, and only with probability fire rate — cubes are asynchronous, like real hardware with unsynchronised clocks. Only the 27 non-structure channels move; a cube can't talk itself out of existing.A cube's vote is the argmax of its 7 belief channels; its colour here is that vote, saturating with softmax confidence (grey = undecided). The bars in the panel are the live vote histogram — watch a minority opinion collapse as consensus spreads through the lattice like a phase change.
Chop a slab off a house and the survivors re-classify almost perfectly — that's the paper's headline result, and it reproduces here (it's asserted in this bench's selftest). But knock 15% of cubes out at random and accuracy genuinely degrades: a swiss-cheese chair is legitimately ambiguous to agents that can only see their neighbours. The bench doesn't hide that; degradation under scattered damage is the honest behaviour of the real system.
The physical cube is a 240 MHz microcontroller doing ~26k multiply-accumulates per tick; fifteen-cubed of worst case is ~10M MACs per swarm-tick, which plain JavaScript on Float32Arrays does in a few milliseconds. Rust/WASM would be justified at maybe 50× this scale; here it would only add a build step to a workbench that deliberately has none. The engine (nca.js) is a pure, DOM-free module in the house style: struct-of-arrays state, synchronous step(fireRate, rand), seedable mulberry32 — the same portable-kernel shape as swarm3d.js, ready for a compute-shader port if it ever earns one.
Rendering is one THREE.InstancedMesh — 3,375 potential cubes, one draw call, per-instance colour written from the belief channels each tick. Smashed cubes become ballistic debris on a second instanced mesh; they're pure theatre, but the theatre is the point of running this in a browser.
The port is checked against a NumPy reference implementation of the original TF graph: after 20 deterministic ticks the mean belief logits agree to <5×10⁻⁶, and over the repo's dataset the per-cube classification accuracy is 99.8% (90 stochastic ticks, fire rate 0.5) — matching the paper's training protocol. Run it yourself: node tjs/cube/nca.selftest.mjs. Direction-to-kernel mapping (which weight matrix is "north") was recovered from the firmware export cell in BIGCUBE_V2.ipynb, the same code that generated the flashed header.