An interactive, in-browser reproduction of the Computational Life experiment. Thousands of random programs collide, rewrite each other, and split apart again, with no fitness function and no goal. Sometimes, the soup crosses into life.
This is an independent reproduction of Agüera y Arcas et al., Computational Life: How Well-formed, Self-replicating Programs Emerge from Simple Interaction (2024), arXiv:2406.19108. The experiment, the language and the findings are theirs. What BRLabs built is the interactive browser version and the live species tracker described below.
BFF is a tiny programming language, ten instructions on a 64-byte tape, where code and data share the same memory, so a running program rewrites the very bytes it is being read from. Fill a soup with thousands of these tapes, each made of random bytes. Each step, pick two at random, concatenate them, run the result, then split them back. No selection, no fitness, no goal.
The paper's finding: self-replicators, programs that copy themselves, arise anyway, purely from programs modifying one another. The soup crosses from a “pre-life” phase into a “life” phase, and once a replicator appears it sweeps the population. Nothing was optimizing for it. It is about the closest thing there is to watching natural selection switch on from nothing.
A program is just a string of bytes. Of the 256 possible byte values, ten happen to be instructions; every other byte does nothing and is simply carried along as inert filler. Two heads point at positions on the tape, think of them as two fingers, one reading, one writing, and the instructions move those fingers and copy bytes between them.
When two programs are glued together into one tape and run, a program can end up reading its own bytes and writing them into its partner's half. That is the whole trick. Here is the smallest thing that copies, a five-instruction loop:
Read it left to right. Head 0 reads; head 1 writes.
[: start of a loop. It means: keep repeating everything inside me until the byte under head 0 is zero..: copy the byte under head 0 onto head 1. One byte of the program is written into its partner's half.>: move head 0 one step right, to the next byte to read.}: move head 1 one step right, to the next slot to write.]: end of the loop. If the byte under head 0 is not zero, jump back to the [ and do it all again.Each turn of the loop copies one byte and advances both fingers. Run it to the end and the partner's half now holds a byte-for-byte copy of the program. Split the pair back apart and there are two copies where there was one. The program has replicated. Nothing rewarded it; it simply contained a sequence that happens to copy.
Of course, no such tidy loop drops out of nowhere fully formed. The soup starts as pure chance: random bytes, not a single working program. What actually happens is messier, fragments of code that copy badly, or halfway, appear by accident; and because programs are constantly overwriting one another, those fragments get scattered and recombined across the soup all the time. Every so often, one of them copies itself faster than it is destroyed by the others, and that small imbalance is enough. From there it makes copies of itself, the copies make more copies, and the soup tips from noise into life. All of that order emerged from pure randomness, with no one designing it.
It is hard not to read this as a computational cartoon of a real transition in biology. A program is a string of symbols that is at once information and the thing acted upon, the way a strand of DNA both stores a sequence and is itself the molecule that gets copied. The copy loop, where one head reads a position and the other writes it forward, plays the part a polymerase plays in a cell: something that runs along a template and lays down a copy of it. And once a program manages to copy itself, you have replication carrying heritable information, which, together with variation, is the one ingredient Darwinian evolution actually needs. The instant the soup holds something that copies itself imperfectly, natural selection has a foothold, and it switches on with no one having designed it.
What the soup dramatizes most directly, though, is the step before evolution, the origin of life itself: the passage from stuff that does not reproduce to something that does. In the leading account of that passage, life's threshold was a molecule that could both carry information and drive its own copying; everything Darwinian came afterwards. The soup reaches that threshold starting from pure randomness, which is exactly what makes it worth watching. The analogy is deliberately loose, and it is worth being clear where it stops: there is no chemistry here, no base pairing, no complementary strand, no physical wear. A byte is copied because an instruction says so, not through molecular recognition. It isolates one idea, template-directed self-copying, and the selection that follows, and strips away the biochemistry that makes the real thing vastly harder. Take it as an intuition pump, not a model of a cell.
A version you can run and watch in the browser, on your own machine. It is fully deterministic: the same seed produces the same world, byte for byte, on every machine, so any run is reproducible from a single number. You can zoom from the whole soup down to a single instruction and read any program's code as it changes.
The part that is ours is a live species tracker. It groups programs by their sequence of opcodes, the active instructions, ignoring the inert filler between them, and catalogues every self-replicating lineage as it appears: when it was born, how far it spread, its peak size, when it died, and how much of it still carries the founder's exact code versus drifting into a cloud of variants. A lineage only enters the catalogue once it is shown to actually reproduce, so the table is a census of life, not of noise.
One honest note, and it doubles as the most interesting thing to try. The paper's canonical setup starts both data heads at position zero. In that configuration a replicator must first solve how to walk a head into its partner's half before it can copy anything, which costs most of a genome, and in this build emergence there is rare.
This build ships with the Second head starts at control pre-set to 64, the first byte of the partner program, so a newcomer meets the interesting case first. With the head there, the minimal replicator is only about five bytes and life emerges readily, in roughly a third of runs, close to the rate the paper reports. Set it back to zero and the same soup can run a long time with nothing happening. Watching that single parameter flip the system between “nothing ever happens” and “life within a few hundred generations” is the fastest way to feel why the position of a copying head is half of the replication problem, the same reason a real cell needs an origin of replication and a primer, and cannot simply start copying anywhere.
One difference from the paper is worth stating plainly, because it shapes what you will see. The paper runs a soup of about 131,000 programs; this one, running live in your browser on a single machine, runs a few thousand. Fewer programs means far fewer random encounters each generation, and emergence is a tail event, depending on a rare replicator being stumbled upon and then finding partners to spread into.
That is very likely why we do not see spontaneous emergence in the canonical 0/0 setup here, even though the paper does: the rare seed that configuration needs is simply unlikely to be hit in a soup this small before you stop watching. Offsetting the second head lowers the bar far enough that even a small soup clears it, which is why the shipped default finds life and the canonical one, here, usually does not. We say “likely” on purpose: it is the most parsimonious explanation and it fits both the paper's account of emergence as a rare event and what the tool shows, but we have not yet run the large-population sweep that would settle it. That sweep is one of the things the open-source Node version exists to do.
The science, the result, the BFF language, the primordial-soup model, is entirely from the paper cited above. BRLabs built the interactive reproduction, the zoomable renderer and the species tracker, and validated the interpreter against a Node reference so browser and command line agree byte for byte. Our own exploration on top of it is separate, and its findings appear below only as they hold up.
The reproduction turned a single control, the mutation rate, into a dial that walks the soup through three regimes. It is the same simulation each time; only the amount of outside noise changes, and that one number moves the system from the origin of life, to evolution, to collapse.
Mutation at zero: the origin of life. With no outside noise, self-replicators still emerge from pure randomness and sweep the soup, exactly the paper's result. Even here the tracker shows a mild quasispecies: a lineage can grow past half the soup while none of its members carry the founder's exact code any more. The original sequence goes extinct while the species, as a cloud of variants thrown off by programs overwriting themselves, thrives.
Mutation low: Darwinian evolution switches on. Nudge the rate up a few thousandths and the system gains the one thing it was missing, a steady source of variation. Now you are watching selection work: dozens of lineages appear at once, most of them corrupted copies that die within a few generations, and a minority persist as a mutant cloud around a conserved functional core, the tiny copy loop that every survivor keeps. Fertility and diversity climb together, a living, churning population instead of a monoculture. This is the quasispecies structure Eigen described in 1971, and the survivors tend to be the mutationally robust variants rather than the most efficient ones, the effect Wilke and colleagues named survival of the flattest in 2001.
Mutation high: the error catastrophe. Push the rate far enough and even the functional core cannot be held: replicators are corrupted faster than they can copy, and the soup dissolves back into noise. That collapse is the error threshold made tangible, the ceiling above which no amount of copying can outrun the damage. Real life sits below that ceiling; RNA viruses live close to it.
None of these phenomena is new. The origin result belongs to the paper cited above; the quasispecies and the error threshold are Eigen's, and digital-evolution systems such as Avida and Tierra have studied them for decades. What this build adds is showing all three regimes in one place, live, driven by a single slider, with a species tracker that makes the mutant cloud visible as it forms. Treat it as a clean demonstration of classic theory arising on its own here, not as a new result.
A quantitative write-up is next. Measuring where the error threshold actually sits in this language needs large populations, more than the browser runs comfortably, so that sweep runs on the open-source Node version. For now the tool is the place to see it: turn on lineage tracking and watch the “% original” column fall while a species holds its ground, then nudge the mutation rate up a notch and watch the number of species explode.
Everything the tool exposes, explained in full. In the simulation itself, hovering any control or metric shows a one-line version of these notes.
wrap: the tape is circular, a head leaving the right edge reappears on the left (a circular genome). invalidate: the program simply ends (no telomere). saturate: the head sticks at the last cell (a stalled fork). It changes the geometry replicators have to cope with, and different edges favour different copying strategies.0: the default, there is no external mutation at all: every variation you see is produced only by programs rewriting one another as they run. Raising it adds background noise, which can seed variety early but, past a point, corrupts replicators faster than they can copy, the error threshold made tangible.0: the paper's canonical setup, both heads start together, so a replicator must first evolve a way to walk a head into its partner's half before it can copy anything; that is expensive, and emergence is rare in a soup this small. Pre-set to 64 (the first byte of the partner program), copying can begin immediately and emergence becomes common. This one control flips the system between “nothing happens” and “life in a few hundred generations.”[ or ], does when it has no matching partner on the tape. ends program is the paper's specification. The program stops there. no-op is a lenient variant that ignores the stray bracket and keeps running. It sounds like a technicality, but it changes which almost-working fragments survive long enough to matter, so it is worth comparing.demo A and demo B are two different hand-found replicators; the “one of each” option lets you watch two strategies compete for the same soup.scan every sets how often that census runs, in generations (smaller is finer but slower). species at is how many living carriers a sequence needs before it earns a row, filtering out one-off flukes. dead after is how many generations a lineage must sit at zero carriers before it is marked dead rather than briefly absent.code is the lineage's opcode sequence, its identity. born is the epoch it was first admitted; status is alive or the epoch it died; lived is how many generations it has existed (or existed for). Hover a row to light up its members in the soup, and click to keep them lit while you scroll.now is how many carriers are alive as of the last scan; peak is the most it ever had at once. A lineage whose now has fallen far below its peak is on its way out.% orig is how many members still carry the founder's exact 64 bytes, versus the cloud of variants that have drifted away from it, watch it fall while a species stays alive and you are seeing a quasispecies form. % soup is the lineage's peak share of the entire soup; % rel is its peak share among only the replicating (fertile) programs, how much of the living population it accounted for.