Whole-brain dynamics on your desktop.
This page pairs a live whole-brain simulation with an account of how it works, how it was built, and where AI was used. You can explore brain states, apply a treatment, and trace every number back to the source code. The equations run on your machine, with no cloud service behind them.
Whole-brain simulation: 85 Wilson–Cowan regions on a synthetic connectome
The simulation page shows a model that couples 85 brain areas across roughly twelve hundred synthetic pathways. Each area is described by two numbers that change in time: how active its excitatory cells are, and how active the inhibitory cells that curb them are. Excitation feeds itself and drives inhibition, inhibition pushes excitation back down, and each responds to its input through a curve that rises and then saturates, the way a population of cells does. That pair of equations per region is the Wilson–Cowan model, and we work at this population level because rhythms, synchrony and seizure discharges are things whole populations do, not single spikes. You can choose a preset and adjust its controls; pressing run integrates the equations forward in time and nothing else. Try the generalised seizure preset, then open the knobs and raise inhibition toward 1 to watch the discharge stop.
Open the simulation ↗ in another app window and keep this page beside it.
The computational chain: from parameter knobs to regional readout
The simulation steps deterministically from six top-level controls down to the activity of every region, half a millisecond at a time. A small seeded random-number generator supplies every random nudge along the way, so identical settings and the same seed produce the same trace to the last decimal, in the desktop worker or in the test runner. That is what makes a run a fact rather than an event: a difference between two runs is a difference in settings, never in luck. You can check it yourself by running any condition twice with the seed held constant.
- Derive base parameters. The engine translates the six knobs and five neuromodulators into the coefficients the equations actually use: how strongly a region excites itself, how hard its inhibition pushes back, its resting drive, and its coupling to the rest of the network. A treatment multiplies those values afterwards, and a preset can override individual ones. This mapping is one function, called derive, and it runs before the integration begins.
- Couple the network. A signal takes time to travel along an axon, so an area experiences what its neighbours were doing several milliseconds earlier. The synthetic connectome weights these delayed interactions by the distance between region centroids: nearer regions are more strongly connected, with a handful of known long-range pathways added by hand. A damaged region has the activity it can reach scaled down by the fraction of its tissue that survives.
- Integrate population rates. Excitatory and inhibitory activity relax toward their saturating response curves across discrete half-millisecond steps. Cells that have been firing for a while tire: an adaptation variable builds up gradually and damps ongoing activity, which is what generates slow waves. The engine discards an initial four-hundred-millisecond warm-up so the model's start-up transient never appears in your run.
- Apply seeded noise. Fluctuations enter the equations through a seeded pseudo-random sequence. Because the generator, mulberry32, produces exactly the same sequence from the same starting integer, identical inputs yield identical traces on the desktop worker and in the test runner alike. You can reproduce any trace anywhere by keeping its seed.
- Sample and analyse. The engine samples every region's excitatory activity every four milliseconds to assemble the frames the brain plays back. From those frames the same routines compute the mean field, which is all 85 regions averaged into one number at each moment, its amplitude, how much of the regions' variation is shared, and the split of its power across the frequency bands. The picture on the page and the text Cajal reads come from the very same analysis functions.
The equations, as the engine steps them
for every region i, every 0.5 ms, after a 400 ms warm-up that is never recorded: net_i = Σ_j w_ij · E_j(t − delay_ij) the connectome, delayed x_E = c1·E_i − c2·I_i − k_adapt·A_i + P_i + G·net_i + stim_i + σ·ξ x_I = c3·E_i − c4·I_i + Q + ½σ·ξ ξ: seeded Gaussian noise E_i ← E_i + (dt/τ_E)·(−E_i + alive_i · S(x_E; a_E, θ_E)) I_i ← I_i + (dt/τ_I)·(−I_i + alive_i · S(x_I; a_I, θ_I)) A_i ← A_i + (dt/τ_A)·(−A_i + E_i) slow adaptation S(x; a, θ) = 1 / (1 + e^(−a(x−θ))) − 1 / (1 + e^(aθ)) the response curve alive_i = 1 − lesion severity (1 intact, 0 destroyed) the six knobs become the parameters (every knob 1 = the awake baseline): c1 = 16 · excitability · (1.1 − 0.1·ACh) c2 = 12 · inhibition · (0.95 + 0.05·DA) P = 1.25 · excitability · (0.6 + 0.4·arousal) · (0.9 + 0.1·NA) · (1.1 − 0.1·ADO) G = 2.5 · coupling · (1.15 − 0.15·5HT) σ = 0.45 · noise · (0.9 + 0.1·NA)(0.85 + 0.15·5HT)(1.1 − 0.1·DA) k_adapt = 2.6 · adaptation · (0.7 + 0.3·ADO) · (1.2 − 0.2·ACh) · (1.3 − 0.3·min(arousal, 1)) a_E = 1.3 · (0.85 + 0.15·DA) a_I = 2 c3 = 15 c4 = 3 Q = 0 τ_E = 8 ms τ_I = 9 ms τ_A = 300 ms θ_E = 4 θ_I = 3.7 ACh, DA, NA, 5HT, ADO: the five modulators, each 1 at baseline a treatment multiplies these parameters last; a preset's overrides replace them E is sampled every 4 ms (250 Hz) into the frames the brain plays back. The readout is computed from those frames: the mean field (E averaged over regions), its RMS amplitude, synchrony = var(mean field) / mean var(E_i), and a Hann-windowed FFT of the mean field split into delta, theta, alpha, beta and gamma.
The letter of this is service/engine/wholeBrain.ts (the loop and derive()) and service/engine/analysis.ts (the readout). Where this page and that file disagree, the file is right.
Scalp projection: synthetic forward mapping to nineteen channels
An electroencephalogram, or EEG, is a set of small voltages recorded by sensors resting on the scalp, nineteen of them here. To produce those nineteen traces from a run, the model projects each cortical region's activity outward to every sensor, weighted by a decay that falls off with distance, and only the cortex contributes because the deep nuclei do not reach the scalp. It runs in the direction the physics does, from sources to sensors, which is why it is called a forward model, and it omits the skull, the head geometry and the orientation of the sources, keeping only the rhythms, the amplitudes and the synchrony. We rely on this crude projection because it carries exactly what the benchmark tests and nothing that could flatter the simulation.
- what it keeps
- rhythm, amplitude and synchrony — the three things the benchmark turns on.
- what it is not
- a lead field. There is no head model, no skull and no source orientation; every electrode is a distance-weighted sum of the cortical regions under it.
- where it runs
- in the Python service (
models/cajal_models/synth.py), not in this page. The projection is deterministic under its seed, like the run it reads.
Engineering provenance: collaborative development under architectural discipline
This feature came together through coordinated work between human judgment and two kinds of artificial intelligence. A coding agent, Claude Code, implemented the software under strict written rules, while Gemini drafted this explanatory prose from structured technical briefs; the person guided the scientific design, evaluated every change, and made every architectural commitment. The rules exist for a reason each: a coding agent that reads them before every change does not drift the architecture, and a model that writes prose will state a plausible thing the code does not do unless every sentence is checked. Development began with the mathematics, then pinned its behaviour with tests, and only then spent its effort on whether a reader can understand and trust what they see. You can read the rules and the tests yourself; the repository guide below says where they are.
- Consult the manual. The repository keeps a manual that describes how the system works right now, one document per subsystem, and the coding agent read it before writing code. The manual lists thirteen invariants, rules that must stay true through every change, such as the engine taking no outside dependencies because two programs run it. Reading first is what kept the architecture from drifting as features were added.
- Isolate the mathematics. The equations that move the brain, the wiring, and the analysis live in one folder of plain TypeScript with no outside libraries, because two programs run them: the desktop worker and the test runner. One copy means the run you watch and the run the assistant describes are the same numbers, and there is no second version to fall out of step.
- Pin with tests. A regime is a pattern the model can be in, such as desynchronised waking rhythms or a hypersynchronous seizure, and a regime test runs a preset and asserts the pattern it claims, so a change that moves the pattern fails on purpose. Before any preset value is altered, a sweep runs the model across one parameter with everything else held still, to find where the response turns and how sharply. A tuned number is then a measurement of the model, not a guess.
- Verify every claim. Every sentence of technical copy, including this page, was checked against the code before it was committed. A drafted assertion the implementation does not support was deleted, not softened. That audit is what lets the page say how the model works without a hedge on every line.
Active roles: machine learning systems operating within the studio
The separate full Cajal studio adds learned models; the offline desktop app runs only the mathematical engine. In the full studio, models work each in one bounded role, and none of them touches the equations. They describe, interpret or draft; every simulated trace, every treatment effect and every spectral number comes from the deterministic mathematics above. The roles are bounded on purpose, so that you can always tell a number the equations produced from a sentence a model wrote.
- AI Cajal the assistant
- A language model at a desk with fifteen tools. When you ask it a question, it runs the simulation tools and explains the numbers they returned, never inventing one. When you describe a state in words, it drafts the settings as a proposal for you to confirm, and nothing is computed until you do.
- AI LaBraM EEG benchmark
- LaBraM is a network trained on about 2,500 hours of real human EEG to produce a compact description of any recording it is shown, without ever being taught to name a state; that kind of network is called a foundation model. In the benchmark it reads the nineteen-channel projections of four simulated states and returns a description of each. A separate, blind instance of the language model reads only the classical analysis of each recording, never LaBraM's numbers, and names the state, which tests whether the simulated rhythms carry a signature a reader of real EEG can recognise.
- AI The scribe
- Gemini, called at authoring time with a curated context pack, drafted this explanatory text. It runs during the build of the page and never during a simulation. Its job is to make the ideas clear without inventing a capability the code does not have.
The three rules it works under
- never a measurement
- a simulation is never presented as a measurement of anyone's brain, and a recording is described, never diagnosed.
- grounded in the run
- every number the assistant quotes comes from a tool result in that turn; if it was not run, it is not known.
- provenance on every panel
- every panel in the studio carries a badge saying whether it is mathematics or AI, and a fallback never looks like the model it stood in for.
Repository guide: structure and local verification
This repository holds the mathematical engine, the interface, and the Electron desktop shell. The installed app contains its runtime and assets. The assistant and foundation-model benchmark belong to the separate full Cajal studio.
- Open the index. Begin with README.md and desktop/README.md for the build commands and desktop boundaries.
- Inspect the engine. Read service/engine/wholeBrain.ts, the whole-brain integration file. You will see the complete Wilson–Cowan implementation and the knob-to-parameter mapping, with no outside library in sight.
- Run the tests. Run npm test from your terminal. The regime tests assert the rhythm, synchrony and activity each preset claims, so you can see what the model is held to.
- Launch the bench. Run npm run desktop to open the application. You can adjust the knobs, change the seed, and watch the model move between states yourself.
Where things are
desktop/- the offline Electron shell, bundle path checks, and desktop smoke test.
service/engine/- the simulation engine: whole brain, connectome, atlas, analysis, presets, treatments, sweeps, microcircuit, single neuron. Pure TypeScript, no dependencies. Start here. The same files as the full studio's, so a run is the same numbers in both.
service/tests/- the regime tests that pin what every preset claims.
src/lib/- the page: sim.ts (the seam to the worker), gl.ts and render.ts (the brain), colormap.ts (the one activation scale), client.ts (the bench and this page).
src/lib/copy.ts- the prose, authored by the scribe in the full studio and checked against the code.
src/pages/- the two routes: index.astro, the simulation; how-it-works.astro, this page.
public/brain/- the baked brain: mesh.bin (the FreeSurfer fsaverage6 pial surface) and volume.bin (the MNI152 brain mask), built once in the full studio and committed.
Running it
npm ci && npm run desktop # build and open the desktop app npm test # the engine's regime tests npm run package # an installer under release/ # the assistant, the recordings and the benchmark are the full studio's, and need its local services
Scope and limits
This simulation demonstrates the kinds of dynamics a cortex can have; it does not record or diagnose any person's brain. The thresholds where the model tips between states are properties of these equations on a synthetic wiring, not constants of biology.
Every word this page uses is defined on the Glossary of the full studio ↗.