InsightsInside the program

Inside the program

This program is billions of characters long, and every one of them is one of the eight commands of brainfuck. Together they run a chat model. Nearly all of those characters do one small thing: they put a number into memory. A short stretch at the end uses those numbers to turn your question into an answer.

Two very unequal parts

The program is one line of text, and it runs from its first character to its last [1]. The strip below is that line drawn to scale. It has two parts, and the second is so short that it is the sliver at the right end. Under the strip, the eight commands are counted. Press the buttons to count one part at a time:

The writing part: charactersThe engine: characters

Counted in the program itself, character by character.

Watch the bar for “step right” when you switch. In the long part it is all but gone, and the plus and minus signs make up more than half of the text. In the short part, left and right are nearly in balance and the plus and minus signs are few. So the two parts are not only unequal in length. They are different kinds of text.

The long part is the writing part: characters, the first of the program. It moves through memory in one direction. It steps one place to the left, adds or takes off a little, and steps on, from its beginning to its end. It reads nothing and prints nothing. When it is done, the numbers of the model are in memory.

The last characters, of the program, are the engine. It reads your question, calculates with the numbers the writing part left behind, and prints the answer. It writes little and walks a lot, back and forth between those numbers. It can be short because it works in loops. The commands [ and ] repeat whatever stands between them, so a calculation that is written once runs for thousands of numbers, and again for every piece of the answer. How long a part is says nothing about how long it runs.

Look at the last two bars with the whole program chosen. The read command , and the print command . each occur once. Both stand inside loops, so each is used for every letter that goes in or comes out. The , is character , about characters into the engine, and everything before it runs the same way whatever you ask. That is why the chatbot can keep a copy of the memory and skip the writing part the next time.That is why the chatbot runs the writing part only once: for the next question it puts back the 1.6 million places in memory that an answer changes.Whatever runs this program carries out the whole writing part again for every question: it cannot yet put back the places in memory that an answer changes.Whatever runs this program has to carry out the whole writing part once before it can read a question.

The mix of commands from the first character to the last

The same count, taken along the program instead of over a whole part. The writing part looks the same from start to end; the mix changes only in the engine, at the far right. Drag along the strip, or use the slider, to read one slice.

character 1

measured

The order of the writing part

The writing part fills memory from one end to the other, in the order in which the engine wants to find things. It starts with the table the engine uses last, the output table, then writes layer down to layer 1, then the table of word pieces and the vocabulary. The next section shows where each of these lies. On the program map each one is a field of its own colour.

In this program the output table and the table of word pieces hold the same numbers: the model uses one table for both jobs. The program writes it twice, in two orders, because the engine walks over it in two ways. Together the two copies are of the program. At the edges of every layer lie thin strips of constants, a few thousand characters each.

How much is characters?

estimated from a measured count

Printed, the program fills a library. Below, every book is drawn: a paperback of 300 pages with 1,800 characters on a page, coloured by what its characters write into memory. Point at a book, or press it, to see what is in it.

    measured

    Both parts work on the same thing, the program's memory. What does that memory look like?

    A row of numbers

    Start with a very small one. The machine below has a row of boxes that all hold 0, and five of the eight commands as keys. Press , then + then . and watch the first box:

    Printed—

    Press , then + then .

    The box went to 65, then to 66, and the machine printed B. Brainfuck has no letters, only numbers: 65 is the number computers use for A, and 66 is the one for B. So , read a letter as a number, + added one to it, and . printed the result as a letter again.

    Now press > and then +. A different box changes. The filled box with the small mark under it is where the machine is working, and > and < move that place one box at a time. The row of boxes is called the tape, one box is a cell, and the mark is the pointer. That is all the memory brainfuck has. There are no names for things and no way to jump to a cell: to use a number, the pointer has to walk to it.

    I'm showing nine cells here, and each holds a number from 0 to 255. The tape of this program has cells, and each holds a number up to about four billion (0.70 GiB of your computer's memory) (2.45 GiB of your computer's memory) (3.98 GiB of your computer's memory, just under the 4 GiB a browser tab can address in the usual way) (6.81 GiB of your computer's memory, more than the 4 GiB a browser tab can address in the usual way). The commands are the same ones you just pressed.

    What is in all those cells? The bar below is the real tape after the writing part has run, drawn to scale, with cell 0 at the left. Each colour is one kind of content. Press a colour to read what lies there, or drag along the bar, or use the slider under it, to move a marker over the tape. A press on a layer zooms in to it:

    cell 0

      Read from the tape the program writes. Pale stretches are cells with nothing in them. measured

      Almost the whole bar is filled, and almost all of the filling is of one kind: weights. A weight is one of the numbers the model learned when it was trained. A model is a very long list of them plus a fixed recipe for multiplying and adding them, so a tape full of weights is the model.

      The model does not read letters. It reads word pieces: a word piece is a word or a part of a word, such as “capital” or “ing” (elsewhere it is called a token). The stretch marked W, at the right, is the table of word pieces. It has one row of numbers for each of the word pieces the model knows. The stretch marked O, at the far left, is the output table, which is used at the very end to choose the next word piece.

      Between those two lie stretches. Each is a layer: one round of the model's calculation, with weights of its own. Every word piece goes through all . They are of two kinds and come in groups of four; press Four layers to see one group. In three of every four, the DeltaNet layers, the weights marked D mix in what came before. Such a layer does not look back at the earlier word pieces. It keeps tables of numbers, marked M, writes every word piece into them and reads from them; press One table to see one. The fourth layer of a group looks back, as all layers of brnfck-smollm2-135m, brnfck-qwen2.5-0.5b and brnfck-qwen2.5-1.5b do: the weights marked A are for that, and between them lie 256 memory slots, one for each word piece of the conversation. That is why a conversation here ends after 256 word pieces. The weights marked F, in every layer, are for the part that works on the current word piece alone. All of this memory is empty before you ask anything.

      Between those two lie stretches that look alike. Each is a layer: one round of the model's calculation, with weights of its own. Every word piece goes through all . If you pressed One layer you saw that a layer has weights of two kinds. The ones marked A are for attention, the part of a layer that looks back at the earlier word pieces. The ones marked F are for the part that works on the current word piece alone. Between them, marked M, lie 256 memory slots, one for each word piece of the conversation. That is where the model keeps what it has read, and it is why a conversation here ends after 256 word pieces. The first 24 slots are filled before you ask anything: they hold the fixed opening lines that tell the model to be a helpful assistant.

      The table of word pieces is on this tape twice: once at the right, and once more at the far left as the output table, in parts. Together the two copies take of the tape.

      The parts of the tape, in cells

      What lies in the stretch the bar shows now. Zoom the bar and this table follows it. The thin strips of constants are too narrow to see in the bar; with one layer in view they are listed here.

      What lies in the part of the tape that the bar shows

      Before the engine can start, of these cells must hold exactly the right number. How does a language that can only add one and take one away write that many numbers?

      Writing a number without typing it

      Brainfuck has no command that means “put 513 here”. From zero, 513 takes 513 plus signs. Written that way, the numbers on this tape would take characters, about times the length of the writing part as it is.

      The writing part does something shorter. It is cut into blocks, and each block fills a run of neighbouring cells, at most 8,192 of them [4]. The figure below holds one real block. The box shows the commands that run next, and your browser carries them out. Each row of the table is one cell: what it holds now, and what it must hold when the block is done. Press Step, or drag the slider under the table forwards and back, and watch the column “In the cell now”. Keep going until the line under the table says every cell is right:

      The ten cells the commands reach first: their digits, what they hold now and what they must hold

      More controls

      Jump to a part of the block

      The commands are the real text of the program; the numbers they must produce were read from the tape. The table shows ten of the block's cells, the ten the commands reach first. The bar under it stands for all of them. measured

      The cells did not get their numbers in one go. The first press gave every cell the same small start value. After that, two kinds of press took turns. One kind walked along the block and gave each cell a few plus or minus signs: those are the columns of signs in the table. The other kind was a single short loop that multiplied every cell by one small number, the ×5, ×7 or ×3 in the headings of the table, and shifted the whole block one cell to the left.

      That is how we write numbers ourselves. 513 is a 5, times ten, plus 1, times ten, plus 3: three small digits instead of 513 strokes. The block does the same with every one of its cells at once. A pass of plus and minus signs writes one digit into each cell, and the shared loop does the multiplying for all of them. The loop is written once, however many cells the block has.

      The digits here can be negative. Where the loop multiplies by 5 they run from −2 to 2, so such a digit never costs more than two characters. A digit of 0 costs none: the commands just step past that cell.

      Two details keep this working. The shared loop stops at the first cell that holds zero, so no cell may be zero on the way: that is what the start value is for. And the digits count from a middle value of the block, not from zero, which keeps them small. The last loop takes the start value off again and puts the middle value back.

      brnfck-smollm2-135m, brnfck-qwen2.5-0.5b, brnfck-qwen2.5-1.5b and brnfck-qwen3.5-0.8b were all written by the same encoder, so a block of this program is built like a block of brnfck-smollm2-135m. What differs is what is in the cells: these weights have 8 bits where brnfck-smollm2-135m's have 10, and there are strips of larger constants. Choose one under More controls to see a block with many more digits per cell.

      brnfck-smollm2-135m, brnfck-qwen2.5-0.5b, brnfck-qwen2.5-1.5b and brnfck-qwen3.5-0.8b were all written by the same encoder, so a block of this program is built like a block of brnfck-smollm2-135m. Its weights have 10 bits, as brnfck-smollm2-135m's do, and between them lie strips of larger constants. Choose one under More controls to see a block with more digits per cell.

      The block above needed only a few signs per cell. Is that luck? The next figure counts every weight on the tape by its value. Choose a part of the model to see its weights alone, and slide the marker along the values to read how many weights have each:

      Whichever part you choose, the bars pile up in the middle. Most weights are close to zero. (The tape stores a weight as the weight plus , so that a stored weight is never zero; the chart shows the weights themselves.) Numbers that lie close together are a small distance from the middle value of their block, and a small distance has small digits. Here is every digit the writing part wrote after the first one of a cell, counted:

      measured

      Most digits are 0, 1 or −1, the three cheapest. That brings the writing part to about characters for each of the cells it fills.

      What one cell costs, and how close that is to the shortest possible

      Characters per cell

      Three ways to write the same tape

      How far is this from the best possible? The numbers on the tape carry bits of information per cell. A brainfuck character can carry at most 3 bits, because there are 8 commands. So no way of writing this tape can be much shorter than characters. The writing part uses : times that floor. The floor is estimated: the information on the tape, counted per million cells, divided by 3.

      In Qwen2.5 every row of a table of weights has its own scale. Before the weights were stored, each row was multiplied by a power of two of its own, as large as it could be while the largest weight of the row still fits in 8 bits. That is why these values spread wider than those of brnfck-smollm2-135m, and why a cell costs a little more.

      In Qwen3.5-0.8B every row of a table of weights has its own scale. Before the weights were stored, each row was multiplied by a power of two of its own, as large as it could be while the largest weight of the row still fits in 10 bits. The values spread wider than those of brnfck-smollm2-135m, which also has 10 bits per weight: a typical weight lies about twice as far from zero (a standard deviation of 55.9 against 27.3), only 16% of them lie between −8 and 8 against 39%, and a cell costs 7.39 characters against 6.14.

      When the writing part ends, the tape holds the whole model and nothing has been read yet. What happens when you ask something?

      The engine

      The bar below is the engine alone, characters to , drawn to scale [5]. Each coloured stretch is one section of it, and the list under the bar names them in the order in which they run. Press a stretch of the bar or a row of the list to read what that section does, or drag along the bar:

      character the engine, to scale
      The sections of the engine, in the order of the program

      Read its commands

      The real commands of the program, one loop level per indent; a run of the same command is written as a count. The notes on the right are worked out from the shape of each loop.

      Show this section on the program map

      Read from top to bottom, the list is a recipe. Read the question and cut it into word pieces. Then, for one word piece at a time: fetch its row of numbers from the table, take those numbers through the layers, give every word piece the model knows a score, and keep the one with the highest. Print that word piece. It then becomes the next one to go through, and so the answer grows a word piece at a time, until the model picks a word piece that means “end” or the 256 slots are full.

      Look at the four headings that begin “The first layer of a group of 4” to “The fourth”. The sections under them stand in the program once: three DeltaNet layers and one attention layer. One loop runs the four of them times, and each time the pointer has moved on to the next four layers' weights. This works because the engine never names a place. Its commands only say “so many cells to the left”, and every group of four is laid out like the others, so the same commands fit every one of them.

      Look at the heading “In each of the layers”. The sections under it stand in the program once. One loop runs them times, and each time the pointer has moved on to the next layer's weights. This works because the engine never names a place. Its commands only say “so many cells to the left”, and the layers are laid out alike, so the same commands fit every one of them.

      If you opened Read its commands you saw mostly long runs of < and >. Most of the engine is walking; its longest single walk is cells. The arithmetic is done by a few small patterns that return everywhere. The one to remember is the bit peel, which reads a number one binary digit at a time. Dividing, rounding, comparing and multiplying two numbers are all built on it.

      The five patterns the engine is built from
      Move and copy
      [->+<] empties one cell into another. A cell can only be read by emptying it, so a copy empties it into two cells and moves one back.
      Multiply by a fixed number
      [->+++++<] adds five times the cell to its neighbour.
      Bit peel
      Doubling a cell pushes its highest binary digit out. By doubling the right number of times, “is this cell zero?” becomes “is this digit a one?”. That reads a number digit by digit, in about 4 steps each.
      Table lookup
      A tree of such tests, with a different fixed number added at the end of every branch. This is how the engine takes an exponential or one divided by a number: it looks the answer up.
      The walk over slots
      A loop whose commands end a fixed number of cells further than they began. The same commands then run on the next slot. This is how the engine visits every earlier word piece.
      How this engine differs from those of brnfck-smollm2-135m and the Qwen2.5 programs

      Qwen3.5-0.8B is of a newer make than Qwen2.5, and its engine was written for it [5]. It uses the building blocks of the Qwen2.5 engine for the feed-forward part, the scaling, the output table and the walk home. The rest is new:

      • Two kinds of layer. DeltaNet layers and attention layers, in groups of four: three of one, one of the other. The text of a group is written once and runs times.
      • A memory that does not grow. A DeltaNet layer has heads, and each keeps one table of numbers. For every word piece the engine makes three passes over the columns of a table: what it already says for the key, the difference written in, and what it says for the query. There are no memory slots in these layers.
      • A table that fades without being touched. A DeltaNet head forgets a little of its past with every word piece. Instead of multiplying the whole table, the engine multiplies one scale number of the head, and halves the table only when that number gets small.
      • The three word pieces before. A short convolution adds the inputs of the last three word pieces to those of this one. They stay on the tape between word pieces.
      • Gates. In both kinds of layer the output is multiplied by a gate the layer makes itself, bent by a curve.
      • No bias, gains per head. The attention layers have no bias. Every head of the questions and keys is brought to a common size with gains of its own, and only the first of its numbers are turned by position.
      • A scale for every row, as in the Qwen2.5 programs, with 10 bits per weight instead of their 8.
      • Nothing worked out beforehand. brnfck-smollm2-135m, brnfck-qwen2.5-0.5b and brnfck-qwen2.5-1.5b keep the opening lines of every conversation in memory. This one starts from an empty memory and runs every word piece, from the first.
      • One table, used twice, as in Qwen2.5: word pieces, and the output table in parts of rows.
      How this engine differs from brnfck-smollm2-135m's

      The two Qwen2.5 models are of another make, and their engine was written again for them [5]. It has the same 23 sections as brnfck-smollm2-135m's, but most of them work differently:

      • A scale for every row. Weights are 8 bits here. Each row of a table of weights has its own number of doublings, kept in a strip next to the place where the totals are rounded.
      • A bias. The totals of the first table of a layer get a constant added, one for each of its rows.
      • Gains kept apart. Every scaling multiplies each of the running numbers by a gain of its own, from a strip of constants, and rounds again.
      • The running numbers travel as a strip. With a scale for every row they cannot be put into the totals beforehand. They ride along and are added when the totals are rounded.
      • Shared keys. The model looks back with heads but stores only keys and values per word piece: heads share one.
      • One table, used twice. There is no separate output table. The scores come from the table of word pieces itself, which lies on the tape a second time, cut into parts of rows.
      • A bigger vocabulary, stored smaller. word pieces. The text of a word piece is not stored: three cells say which two smaller word pieces it is made of, and printing follows those rules down to single bytes.

      Since the engine can only walk, one word piece is one long trip. The next figure is a recording of such a trip. Across is the tape, as in the bar of the previous section. Down is time. The dot is the pointer. Press Play, drag the slider (or the picture), or jump from section to section:

      A recording of one word piece of one question. The line has the colour of the section that is running. measured

      The dot began at the right end of the tape, where the number of the word piece is kept. It ran through the table of word pieces to fetch one row. Then it worked its way to the left, layer after layer. At the far left it went through the output table and found the best next word piece. And then it walked all the way home.

      The weights do not stand still either. To multiply, the engine moves a column of weights across a small gap of free cells and adds it to running totals on the way. After a layer, its weights lie one gap further along. The walk home puts every column back where it was, so that the next word piece finds the same tape.

      One word piece is one crossing of the whole tape and back. How much work is that, and which part of it costs the most?

      Where the time goes

      An interpreter is a program that carries out brainfuck commands, and a step is one thing this one does. A step is not always one command: a run of plus signs is one addition, and a short loop that only moves or multiplies a number is done at once (exactly what counts). So what follows are counts of steps. They are not seconds, and they are not single commands.

      Each bar below is one section of the engine with the steps it took for one word piece. The strip above the bars adds them up by part of the model. Press a bar to see that section layer by layer, and slide along the layers to read each one:

      • Feed-forward
      • Attention
      • DeltaNet
      • Output table
      • Table of word pieces
      • Memory of earlier pieces
      • Walking

      In every layer

      measured

      The bars are very unequal. A few carry nearly the whole word piece, and they share a name: “Weights × numbers”. Those are the sections in which every weight of a table is multiplied by a number that is passing through. Press one of them and the chart underneath is almost flat: every layer costs about the same.

      That was one word piece. The next chart has one bar for every word piece of a recorded run, coloured by part of the model as before. Drag the slider along them, or drag across the bars. The figure above follows it:

      measured

      These counts come from two questions. The trip of the pointer and the chart by layer show one word piece of the first one.

      Steps differ in what they cost a computer, so a share of the steps is not the same as a share of the seconds. The seconds that were measured are in the table under How it was checked.

      What kind of step, over the whole run
      SmolLM2, Qwen2.5 and Qwen3.5 side by side

      brnfck-smollm2-135m, brnfck-qwen2.5-0.5b, brnfck-qwen2.5-1.5b and brnfck-qwen3.5-0.8b were made in the same way, and their models differ by a factor of eleven in size. This comparison is the same whichever program is chosen at the top. brnfck-smollm2-135m was counted to its last position, brnfck-qwen2.5-0.5b, brnfck-qwen2.5-1.5b and brnfck-qwen3.5-0.8b for one short question each; the table says for every number where it comes from.

      The program: writing part, and the engine as the dark end

      The tape: what the cells hold

      The share of each command in the whole program

        The tick marks the program chosen at the top. measured

        Steps for one word piece at position 24, by part of the model

        How much larger than in brnfck-smollm2-135m (each doubling is the same length)

        In brnfck-smollm2-135m, brnfck-qwen2.5-0.5b and brnfck-qwen2.5-1.5b position 24 is the first word piece after the fixed opening lines; brnfck-qwen3.5-0.8b keeps none in memory and runs every position from 0, so its position 24 is the 25th word piece of the run. Position 24 was counted in all four. measured

        brnfck-smollm2-135m, brnfck-qwen2.5-0.5b, brnfck-qwen2.5-1.5b and brnfck-qwen3.5-0.8b in numbers. Counts are counted in the programs. Times come from the project's logs, on one desktop computer. measured from the project's log

        Billions of steps for one word piece cannot be checked by reading along. How do we know the program calculates what the model calculates?

        How it was checked

        Three things were checked separately [2]. Is the program what it claims to be: nothing but the eight commands, brackets that match, one read command? Does the writing part leave exactly the right numbers on the tape? And does the whole program print the right text?

        The second check is one you can look at. The tape that this program writes was compared with a tape made in another way, by an earlier version that read its weights from a data file. Both tapes were cut into pieces of 1,048,576 cells, and each piece was given a checksum: a short fingerprint that comes out different if a single cell differs. Each square below is one piece of the tape. Drag the slider to walk along it:

        A marked square means both tapes gave the same SHA-256 checksum there. from the project's log

        Every square is marked. All checksums are equal, over all cells: the writing part writes the tape it should.

        For the third check the whole program was given questions, and what it printed was compared, letter for letter, with a plain version of the same model that calculates in whole numbers. Each row of this table is one of those runs:

        Seconds are per word piece, on one desktop computer. from the project's log

        What these checks do not show

        The right text is not a right answer. The program follows a version of the model in which every number was rounded to a whole number, because brainfuck has no others. That version picks the same next word piece as the original model in 94.8% of the tested cases (345 of 364).That version does not always pick the same next word piece as the original model. And the original is a small model that is often wrong.

        Only the questions in the table were compared. And the whole program has never been run one command at a time: it was run by interpreters that do simple loops at once. Running one command at a time, with a check on every move of the pointer, was done for small test models only.

        Every limit of these measurements
        • Only ten questions were compared. The engine has no known difference with the reference, on these ten and on 279 generated word pieces over 5 prompts. Other questions were not compared.
        • Only one question was compared. The program printed the reference text for it, and the check stopped the run after 30 word pieces. Other questions were not compared.
        • Only a few questions were compared. The program printed the reference text for questions. Some of those runs were stopped by the check after 30 word pieces. Other questions were not compared.
        • Never run one command at a time. For this program it would take far too long.
        • Steps were counted, not seconds. The seconds in the tables come from the faster interpreter that the project's checks use.
        • Measured from the command line. The tape of this program is 6.81 GiB, more than a 32-bit memory can hold. Everything here about it was measured with command-line tools on 64-bit memory. Your browser only reads the results.
        • No meaning of single weights. It is known which table a block belongs to, not what its numbers stand for.
        • Reading the commands needs a server that can send part of a file. The block and the pieces of the engine are read out of the program itself. Where a server cannot send a part of a file, only the pieces stored beside the figures are shown.
        • Measured unevenly. Everything about brnfck-smollm2-135m, brnfck-qwen2.5-0.5b, brnfck-qwen2.5-1.5b and brnfck-qwen3.5-0.8b and their tapes was measured in the same way for all four. The step counts were not: brnfck-smollm2-135m was run to its last position, brnfck-qwen2.5-0.5b, brnfck-qwen2.5-1.5b and brnfck-qwen3.5-0.8b for one short question each.
        • One computer, one browser. The figures and the chatbot were tried in one desktop Chromium browser.
        Every check of the program, the tape and the answers

          From the log of the project's own checks. from the project's log

          How the figures above were checked

            Where to go next

            The program map shows the same parts as a picture, down to single commands. The lessons start from programs of a few characters and build up to the patterns used here.

            1. Program mapThis programSee every character of it in one picture, and zoom in to the block or the section you read about here.
            2. LearnTwo coursesStart from the eight commands, then build the copy, the multiplication and the bit peel yourself.
            3. How it worksArticleFollow one question from your keyboard to the first printed word piece.
            4. Ask brnfck-smollm2-135mChatbotRun this program on a question of your own.
            5. Ask brnfck-qwen2.5-0.5bChatbotRun this program on a question of your own.
            6. Ask brnfck-qwen2.5-1.5bChatbotRun this program on a question of your own.
            7. Ask brnfck-qwen3.5-0.8bChatbotRun this program on a question of your own.
            8. Compare the modelsArticleWhat Qwen3.5-0.8B keeps instead of looking back, next to the models that look back in every layer.

            Details and sources

            What counts as a step

            One operation of the project's compile step (compiler/core/bf.js). It turns a run of + and − into one addition, joins a walk to the command that follows it, and does a loop that only adds and moves as one multiplication. Each of those leaves the tape as running the commands one at a time would. The chatbot uses a faster interpreter, which turns the same operations into machine code.

            The program file

            The whole program is one file. This is the one shown now.

            Sources

            1. The program: () and its description , which holds the sizes, the SHA-256 and the checksums of the tape.
            2. The project's checks: compiler/smollm/pure/verify.js and its log compiler/smollm/pure/out/verify.log.compiler/qwen/program/verify_pure.js and its log .compiler/qwen3.5/program/verify_pure.js and its log .
            3. What wrote the writing part: compiler/smollm/pure/encode.js (the encoder of brnfck-smollm2-135m, brnfck-qwen2.5-0.5b, brnfck-qwen2.5-1.5b and brnfck-qwen3.5-0.8b) and compiler/smollm/pure/build.js.compiler/qwen/program/build_pure.js.compiler/qwen3.5/program/build_pure.js.
            4. The generators of the engine: compiler/smollm/engine/gen.js, compiler/smollm/engine/stations.js, compiler/smollm/tokenizer/gen.js, compiler/smollm/program/gen.jscompiler/qwen/engine/gen.js, compiler/qwen/engine/stations.js, compiler/qwen/tokenizer/gen.js, compiler/qwen/program/gen.js, with the arithmetic they reproduce in compiler/qwen/engine/spec.js,compiler/qwen3.5/engine/gen.js with its two layer kinds compiler/qwen3.5/engine/mixers/deltanet.js and compiler/qwen3.5/engine/mixers/attention.js, compiler/qwen3.5/tokenizer/gen.js, compiler/qwen3.5/program/gen.js, the parts of the Qwen2.5 engine they use, and the arithmetic they reproduce in compiler/qwen3.5/engine/spec.js, and the building blocks in patterns.js.
            5. The model: SmolLM2-135M-Instruct by Hugging Face, published under the Apache 2.0 licence. 30 layers, 576 numbers per word piece, 49,152 word pieces.The model: Qwen2.5-0.5B-Instruct by Alibaba Cloud, published under the Apache 2.0 licence. 24 layers, 896 numbers per word piece, a vocabulary table of 151,936 rows.The model: Qwen2.5-1.5B-Instruct by Alibaba Cloud, published under the Apache 2.0 licence. 28 layers, 1,536 numbers per word piece, a vocabulary table of 151,936 rows.The model: Qwen3.5-0.8B by the Qwen team of Alibaba Cloud, published under the Apache 2.0 licence. 24 layers, 18 of them Gated DeltaNet, 1,024 numbers per word piece, a vocabulary table of 248,320 rows. Its new kind of layer is explained on Compare the models.
            6. The folded line of the program map: D. Hilbert, 1891, on a continuous line that passes through every point of a square.
            7. The colours of the figures follow the palette of M. Okabe and K. Ito (2008), made to stay apart for people with colour-blindness.
            8. Brainfuck: a language designed by Urban Müller in 1993.
            How the numbers behind the figures were made

            The scripts in tools/map-data/ read the real programs and the project's logs and write the data the figures load, one folder for each program. None of them changes a program. The eight below make the data of this page; beside them are their helpers (models.js, interp.js, instrument.js, regions.js), lens.js for what every layer would say on How it works, and train.js for the four programs that train a network.

            Each script takes the program as its first word: small, 0.5b, 1.5b or 0.8b.
            ScriptWhat it doesUsed for
            writer.jsRuns the writing part to get the tape. Runs the project's encoder again on that tape while noting every block, and checks that its output, with the engine behind it, has the SHA-256 of the program. Counts commands, weight values, digits, and the information on the tape.The two parts, the tape, the block, the digits
            sections.jsRuns the engine's generator again while noting where every named section lands. Compares the result with the end of the program, character for character.The sections of the engine, the program map
            tiles.jsReads the program once and makes the pictures of the program map and the pieces of text behind it.The program map
            depth.jsReads the program once and notes how deep its loops are nested along it.The program map, the layout "Skyline"
            stops.jsReads the engine and finds its only comma and its only full stop: the section of each, how many loops are open there, the characters around it, and the mix of commands along the way.The figure "Once, in more than a billion characters" on How it works
            trace.jsRuns the real program on a question with an interpreter that counts every step by section, layer and word piece and notes where the pointer is. The printed answer must equal the reference. It can stop after a number of positions.The trip of the pointer, the step counts
            checks.jsReads the logs of the project's own checks. It runs nothing.The checksums, the checks, the questions
            compare.jsGathers the main numbers of brnfck-smollm2-135m, brnfck-qwen2.5-0.5b, brnfck-qwen2.5-1.5b and brnfck-qwen3.5-0.8b from what the other scripts wrote.SmolLM2, Qwen2.5 and Qwen3.5 side by side
            
                
            The words used here, in one line each
            Command
            One of the eight characters brainfuck understands. Each does one small thing.
            Tape
            The program's memory: one long row of cells.
            Cell
            One place on the tape. It holds one whole number.
            Pointer
            The cell the program is at. The commands < and > move it one cell.
            Weight
            One of the numbers the model learned in training.
            Word piece
            A word or a part of a word. The model reads and writes text one word piece at a time. Elsewhere it is called a token.
            Layer
            One round of the model's calculation, with weights of its own. has of them.
            Writing part
            The long first part of the program. It puts the model on the tape and neither reads nor prints.
            Engine
            The short last part. It reads the question, calculates with the weights and prints the answer.
            Interpreter
            The software that carries out a brainfuck program.
            Step
            One operation of the interpreter. See what counts as a step.