This is an interactive browser simulation of the BFF primordial soup experiment described in Computational Life: How Well-formed, Self-replicating Programs Emerge from Simple Interaction by Blaise Agüera y Arcas, Jyrki Alakuijala, James Evans, Ben Laurie, Alexander Mordvintsev, Eyvind Niklasson, Ettore Randazzo, and Luca Versari (Google / University of Chicago, 2024).
The central question: can self-replicating programs arise spontaneously from a soup of random, non-self-replicating programs, with no fitness function, no goal, no designer? The answer, demonstrated across multiple computational substrates, is yes.
The paper draws an analogy to the Origin of Life. Biology has the RNA world hypothesis: at some point in prebiotic chemistry, self-replicating molecules arose from a soup of random organic compounds. The authors ask whether this transition from pre-life to life is a general property of any sufficiently expressive computational substrate, not just biochemistry.
They show that when random programs interact and modify each other, self-replication emerges as an attractor state. The mechanism is primarily self-modification, not random initialization or background mutation. Once a replicator arises, it rapidly colonizes the soup. This is a phase transition: a sudden, irreversible change in the dynamics.
[[{.>]-]]-]>.{[[ as a full-tape genome: the 64-byte tape is filled with [ padding, with the replicator in the last 16 bytes. This matters because the replicator always copies to position 48 of the target tape -- the [ prefix ensures the outer loop guard fires on the next generation. Several copies are seeded at once. Crank the speed up and watch the cyan spread.BFF (Brainfuck+) extends the original Brainfuck language by replacing I/O streams with two independent heads operating on a single unified instruction+data tape. This allows programs to read and write to each other's code, enabling self-modification and, eventually, self-replication.
head0 is the read/data head. head1 is the write head. Both move independently over the same tape. All head positions wrap modulo tape length.
| OP | ACTION | NOTES |
|---|---|---|
| < | head0 -= 1 | Move read head left (wraps) |
| > | head0 += 1 | Move read head right (wraps) |
| { | head1 -= 1 | Move write head left (wraps) |
| } | head1 += 1 | Move write head right (wraps) |
| + | tape[head0] += 1 | Increment byte at read head (mod 256) |
| - | tape[head0] -= 1 | Decrement byte at read head (mod 256) |
| . | tape[head1] = tape[head0] | Copy: read head → write head position |
| , | tape[head0] = tape[head1] | Copy: write head → read head position |
| [ | if tape[head0] == 0: jump past ] | Loop start (conditioned on read head) |
| ] | if tape[head0] != 0: jump to [ | Loop end |
| (other) | no-op | All 246 other byte values do nothing |
A program terminates when the instruction pointer reaches the end of the tape, or after 213 = 8,192 IP reads (the paper's exact limit). Unmatched brackets also terminate. This prevents infinite loops from stalling the simulation.
The paper's example emergent replicator (from Figure 4) is:
When this program runs with its write head positioned at the left edge of the adjacent tape:
tape[head0] != 0. copies read→write{), the read head moves right (>)The inspector panel shows OP-PALINDROME: YES when a tape's BF operator subsequence reads the same forwards and backwards. This is one fingerprint of a replicator family.
The simulation follows the paper's "Turing gas" variant (after Fontana 1990). Parameters faithful to the paper:
[,}<] structure: its loop breaks when head0 sees a zero byte. It can copy zeros but cannot write over them. Zeros accumulate in the soup (up to ~14% of all bytes at peak), stalling replication. Complexity temporarily degrades. This is the red spike visible in the metrics chart.[<,}] structure emerges that can overwrite zeros. It rapidly displaces the first replicator and its zero-sensitive kin. The soup becomes a "very busy place" with multiple replicator variants overwriting each other. Complexity rises sharply then steadily.The paper shows through ablation that self-modification is the primary cause of replicator emergence, not random initialization or background mutation. Runs with zero mutation still produce replicators. Runs with only 128 epochs (too short for self-modification to accumulate) produce replicators only 0.3% of the time. The "long-no-noise" condition (no mutation, fixed interaction order) still produces replicators ~50% of the time.
[ ] in BFF is conditioned on tape[head0] == 0. The zero-poisoning phase is visually distinct: a spike in this metric coincides with the first replicator generation's vulnerability to zero bytes. Watch the grid turn red during this phase.. or ,). This is a proxy; the paper uses proper token-tracer analysis to identify true replicators, which is computationally intractable here. But the signal is clear: this metric rises sharply at the state transition and plateaus at the attractor.Written in vanilla HTML5/JS with no dependencies. Runs in any modern browser. The simulation is single-threaded; the paper used CUDA with parallel execution across all 131k tapes simultaneously. A JS WebWorker port would be the natural next step for matching paper-scale performance.
The paper notes that the first emergent replicator was a palindrome. The key insight: if a loop copies the tape in reverse (write head moving opposite to read head), and the source sequence is a palindrome, then the reversed copy is identical to the original, enabling faithful self-replication without needing to know the direction of copying.
The inspector computes palindrome status by extracting the BF operator subsequence of a tape (ignoring data bytes) and checking if it reads the same forwards and backwards. This is a necessary but not sufficient condition for replicator status; many palindromes are not replicators.
The paper computes high-order entropy using brotli compression as a Kolmogorov complexity proxy. We use a bigram repetition ratio (fraction of consecutive byte pairs that are equal) combined with Shannon entropy. This is cheaper to compute and captures the same qualitative signal: the state transition is detectable as the structured repetition of replicator sequences overwhelms the random background.
The steps/frame slider controls how many soup interactions execute per animation frame (~60fps):
At high speeds, stats recording and rendering are throttled to avoid blocking the JS thread. The simulation itself is never throttled; all steps run.
This is a single self-contained HTML file. Open in any browser, or host on GitHub Pages with zero configuration.
Agüera y Arcas B, Alakuijala J, Evans J, Laurie B, Mordvintsev A, Niklasson E, Randazzo E, Versari L.
Computational Life: How Well-formed, Self-replicating Programs Emerge from Simple Interaction.
arXiv:2406.19108v2, 2 August 2024.
arxiv.org/abs/2406.19108 | github: cubff
The original Brainfuck was created by Urban Müller in 1993 as a minimalist Turing-complete language with 8 commands. BFF replaces its I/O commands (. ,) with copy operations between two independent heads on a unified tape, eliminating external I/O and making the language entirely self-contained. This is the key modification that enables self-interaction and replication.