The room demo
samples/DotFly.Sample.Godot3D is a Godot 4 (.NET) scene: a fly flies around a sunlit living room
and looks for sugar, with the whole MaleCNS connectome (166,700 neurons, 24.9 M synapses) running
in real time on dotFly as the only thing between her senses and her actions. The left third of
the screen shows what the network is doing; the bottom-right map shows the room, the odor streams
and her flight path.
The loop
world ─► senses (encoders, hand-written) inputs: 7,524 neurons
two eye cameras, 32×32 luminance, 45° left / right ─ Retina.cs
per eye: dark fraction & growth ──────────────────► LC4 looming
horizontal shift outward / inward ───────► T4a / T4b front-to-back / back-to-front motion
vertical shift up / down ────────────────► T4c / T4d
odor concentration at the two antennae ─ Odor.cs ─────► ORN_DM1 L/R smell (one glomerulus)
wind on the antennae (the side it comes from) ────────► JO-C/E L/R Johnston's organ
sugar contact when landed ─────────────────────────────► claw_tpGRN, LB3 tarsal / labellar taste
MaleCNS v1.0, Shiu et al. dynamics, gain 1.0, 4,225 neurons silenced for stability
measured circuits: LC4 → DNp04 L/R, DNp01 (Giant Fiber) escape
T4a → HS, T4b → H2, T4c → VS optic flow
ORN_DM1 → DM1_lPN odor amount
JO-C/E → AMMC012 (one per antenna) wind direction, lateralized
claw_tpGRN & LB3 → MN9 the Shiu et al. feeding pathway
readouts: 38 neurons in 13 groups
decoder (Behaviour.cs + decoders/dn_fixed_3d.json, hand-written, labelled Fixed)
yaw = 1.2·(DNp04_L − DNp04_R) + 0.2·((HS_R + H2_L) − (HS_L + H2_R)) − 0.3·(HS_R − HS_L)
escape away · optomotor counter-turn · centering along walls
odor : DM1_lPN > 110 Hz → surge upwind (yaw −= 0.6·(wind_L − wind_R)); tumble when it falls;
lost → U-turn, then casts; > 270 Hz and sugar below → land
climb : random vertical drift (no altimeter); in odor ±12 BL/s, reversed when the readout falls
speed : 120 body lengths/s cruise (a real fly: 100–170), 80 while tracking, 35 while casting
taste : MN9 (0.3 s smoothed) > 15 Hz → feed; take off when it stops
Speeds are in body lengths per second and scale with DOTFLY_BODY_LENGTH (default 0.03 m — ten
times a real fly; the room, at 24 × 18 × 5 m, is at its own scale).
What the brain does and what the decoder does
The brain supplies five graded, lateralized signals — looming side, optic-flow pattern, odor
amount, wind side, taste — through circuits that are all in the checkpoint and were found with
the CLI (dotfly inspect --upstream-of, dotfly run --stimulate), not assumed. The decision of
where to go (surge, tumble, cast, height search, landing) is the decoder's: the fly's own
navigation circuit — wind and odor meeting in the fan-shaped body, compared with the compass and
turned into a steering command by PFL3 → DNa02 — is silent in this uniform-LIF model (see
Findings). The panels print the decoder's rules beside the readouts they use.
The panels
- eyes — the two 32×32 luminance images the retina encoder receives (the motion/looming photoreceptors R1–R6 are achromatic; the eye cameras never see the odor rendering or the fly's own body), the channel rates per eye, and the smell/taste/wind input rates.
- brain — every neuron's recent spikes at its real soma position (dark → red → yellow → white), input populations in blue, readout groups as rate-sized discs; the brain to scale, the VNC compressed into the remaining width.
- traces — 10 s time-graphs of the readout groups in three panels (escape; optic flow; smell/taste/wind), each captioned with the decoder rule it feeds, plus the decoded actions as live bars and the behaviour state.
- room — an isometric map: furniture, columns, sugar, wind, the odor cones' centrelines, the flight path coloured by age with feeding stops marked, the fly with a drop line; other flies as grey dots.
- HUD — the checkpoint, neural time vs wall time (RTF, "behind"), spikes/s, the gain and the stability control, the causal switches, the camera mode, the state, odor at the antennae.
The world and the rendering
- Forward+ with SDFGI, SSR, SSAO/SSIL, soft sun shadows through real window openings, a physical sky, procedural PBR materials — no downloaded assets except the fly.
- The odor field is the demo's physics (
Odor.cs): three cones from the sugar, narrow at the source and broad downwind, buoyant (rising to the ceiling), meandering in 3-D, ending before walls; the wind turns once per 15 minutes.odor_raymarch.gdshaderevaluates the same function per pixel — the gold haze with glitter is exactly what the antennae sample (the glitter and wisps are visual only) — and never draws between the camera and the fly. - The fly: a 6,654-triangle rigged Drosophila (
models/fly.glb, loaded at runtime), leg clips driven by the behaviour state (flight, landing reach, standing, takeoff), wings rowed fore–aft with a pitch flip at each stroke reversal as in high-speed video of real flies, at 14 Hz so the eye can follow (a real fly: ~200 Hz). - Cameras (
C): chase — third-person with inertia, 13.5 body lengths back, orbits to her front when she lands; follow — a trail camera sliding along the path she flew, 7.8 body lengths behind, never her front. Both keep her centred in the visible area by a lens shift, and anything between her and the camera turns translucent.
Keys and switches
R recurrent transmission (off = the network is a pass-through of its inputs), E external
input, V vision, O smell/taste, S silence DNp04 + HS (they still spike, they no longer
transmit), Space pause, C camera.
Environment: DOTFLY_BODY_LENGTH (m), DOTFLY_QUALITY=high|medium|low, DOTFLY_ODOR_RENDER=0,
DOTFLY_CAMERA=follow, DOTFLY_FLIES=N (or -- --flies N: each extra fly is a full independent
simulation, cores split evenly), DOTFLY_SCREENSHOT_FRAME=n, DOTFLY_SCREENSHOT_STATE=Feeding|Landed|Faded|Odor.
Performance (8-core Ryzen laptop, 1280×720)
| quality | odor | frame |
|---|---|---|
low — no screen-space effects |
off | 8.8 ms |
medium (default) — SSR + SSAO + soft shadows |
on | 10.3 ms (~98 FPS) |
high — + SDFGI + SSIL + shadowed lamps |
on | 12.8 ms (~78 FPS) |
The network keeps RTF 1.00 throughout (its own threads; ~20–35 % busy for one fly). Four flies: 2 threads each, every fly at RTF 1.00, ~90 % busy — the practical limit on 8 cores.