When the predator strikes, your fly jumps on its own. The escape reflex is a small, pure, deterministic neural module modeled on the real fruit-fly connectome — the LC4 / LPLC2 → Giant Fiber looming-detection pathway.
The circuit
looming predator
├── angular velocity ──> LC4 (2,442 synapses)
├── angular size ──> LPLC2 (1,366 synapses)
│ │
│ weighted sum (real or swapped)
│ ↓
└───────────────> GF membrane potential (leaky integrate-and-fire)
│
potential ≥ threshold → READY
│
escape jump
In the MaleCNS v1.0 connectome the Giant Fiber is neuron DNp01, and LC4 + LPLC2 supply ~99.6% of its visual input (Ache et al. 2019, FAFB). The synapse counts are research references: they are used here only as relative weights between the two channels. They are not biophysical membrane parameters, conductance values, or firing rates, and this model does not simulate ion channels.
State
The whole neural state is one plain object. Field names are a compatibility surface — the HUD, window.FlyLabAPI and the saved-game format all read them.
| Field | Meaning |
|---|---|
| lc4 | LC4 activation in [0, 1] — driven by angular velocity |
| lplc2 | LPLC2 activation in [0, 1] — driven by angular size |
| pot | GF membrane potential, leaky-integrated toward its input |
| armed | true when pot is at/above threshold and outside the refractory window |
| lastFire | simulation time of the last escape fire |
| iframe | post-escape invulnerability window (consumed by the behavior layer) |
| prevTheta | previous angular size of the stimulus, held for finite-difference velocity |
Transitions
All transitions are pure functions of (state, input) — no DOM, no globals, no RNG. Same inputs, same state, every time.
Sensory layer
lc4 = clamp01(vel × 0.45) // LC4, leads lplc2 = 𝟙[size > 0.08] × exp(−(size − 1.4)² / (2 × 0.7²)) // LPLC2, lags
LPLC2 is tuned as a size-selective band around 1.4 rad — a looming object is most threatening at a particular apparent size, not the largest one.
Integration
real: (2442 × lc4 + 1366 × lplc2) / 3808 swapped: (2442 × lplc2 + 1366 × lc4) / 3808
real puts the large weight on the leading channel (velocity); swapped moves it onto the lagging channel (size). This is the comparison condition of the wiring check below.
Membrane
pot ← pot + (target − pot) × min(1, dt × leakRate) armed ← pot ≥ threshold AND (now − lastFire) > refractory
Leak rate is 10 s⁻¹ in the playable loop, 15 s⁻¹ in the fixed-seed assay. Threshold is 0.6 (the giant trait lowers it by 0.08).
Layer boundaries
- The game loop computes the environment input — predator distance to angular size/velocity — advances time, and calls
stepGF. - The neural module performs every state transition.
- The player is the escape decision. The circuit says READY; you (or your agent's brain) press Space.
fireGF(state, now)is called by the behavior layer when the escape actually happens: it resets the membrane to 0 and opens the refractory window. One stimulus crossing threshold arms the unit once; re-arming requires both a new integration and the refractory window to have passed.
Naming: the code identifier for the swapped condition is the string "shuffled" — a compatibility surface kept for saved runs and tests; in prose we call it what it is: two weights swapped.
The reproducible wiring check
A single-loom assay — one looming strike with seed-randomized initial distance, velocity and acceleration; escape succeeds only if the GF fires with ≥ 0.18 s of lead before contact. The only difference between arms is the connectivity condition. 200 trials per arm, pinned, reproducible:
| real wiring | swapped wiring | |
|---|---|---|
| escape rate | 100 % | 68 % |
| mean lead time | 0.2023 s | 0.1828 s |
Stated plainly: this is a demonstration of reproducibility and sensitivity to channel order within this model — the real condition is defined as the one that puts the large weight on the leading channel, so real-beats-swapped holds by construction; the escape rates are functions of the hand-set parameters (VEL_GAIN, SIZE_PEAK, THRESHOLD, leak rate). The exact values are asserted in the test suite — any change to the circuit that moves them fails the build. The assay itself is deterministic per seed: simEscapeTrial("real", 12345) always returns lead = 0.18333…. A parameter-sweep over how wide a range real beats swapped is not yet done; until it is, this check should not be quoted as a headline result.
Three models, one honest boundary
The world contains three models at different grains. They are related by theme, not shared code — pages and docs must not describe any two of them as "the same model":
| Model | Where | What it is |
|---|---|---|
| Playable GF escape circuit | gf-neuron.js + sim.js | The 2-channel → 1-unit reflex described here, running live in the game loop |
| Selectable brains | cx-circuit.js, brain-*.js | The 24-neuron spiking circuit and the judgment layer that can sit in the brain slot |
| Vial population prototype | server-side sim modules | Generational genetics (food, temperature, mating, inheritance) — no predator, no GF |
The unit contract, pinned by tests
- Identical inputs produce identical neural state (deterministic replay).
- Zero stimulus leaks the membrane monotonically to
< 0.01. - Threshold crossing arms once; firing resets the membrane and enforces the refractory window; the unit re-arms only after it.
- Real and swapped connectivity are distinguishable and reproducible.
- The assay and experiment numbers above stay pinned — any change that moves them fails the build.