# First movement — a minimal physical bridge

September 19, 2026. Open https://augmentedthinker.github.io/first-movement/. Press Play, then try Mouth close-up, Sugar + bitter, Actuator off, and Stiffer joint.

## Claim and boundary

Verified MN9 spike recordings from the complete Shiu/FlyWire v630 neural model drive a torque actuator in a modified NeuroMechFly body. MuJoCo integrates the physical response. The browser replays the recorded transforms and measurements; it does not run neural or physical simulation. This is an **open-loop engineering integration**, not a validated model of natural feeding, muscle 9, or a complete animal.

## What the primary sources support

- **Neural output:** [Shiu et al., Nature (2024)](https://www.nature.com/articles/s41586-024-07763-9) identifies MN9 with rostrum lifting and explicitly leaves its quantitative firing-rate-to-lifting relationship unknown. Our prior experiment reproduced sensory-to-MN9 computation; it did not identify muscle parameters.
- **Anatomical interpretation:** [McKellar et al., eLife (2020), Controlling motor neurons of every muscle for fly proboscis reaching](https://pmc.ncbi.nlm.nih.gov/articles/PMC7316511/) identifies muscle 9 as a rostrum protractor and reports effects beyond that joint. Our locked haustellum is a simplification and does not reproduce that natural coupling.
- **Body:** [NeuroMechFly v2, Nature Methods (2024)](https://doi.org/10.1038/s41592-024-02497-y) and the [current official source](https://github.com/NeLy-EPFL/flygym/tree/38c8ec61034cd59bc5ba0de20688d4a3c0000d60). Inspection used FlyGym 2.1.0 at the pinned commit, not old 1.x APIs. Its body geometry comes from micro-CT; this experiment uses the bundled simplified meshes.

The inspected `rigging.yaml` supplies `c_rostrum` and `c_haustellum`, their positions and masses. `anatomy.py` chains head → rostrum → haustellum. `BaseFly.add_joints` supports configurable hinges and passive mechanics; `add_actuators` supports generic controls. This is a general composition facility, not evidence that the defaults are a validated feeding mechanism. No separately articulated labellum or MN9 muscle-force calibration was identified in this model configuration. The archived implementation is not used.

## Exactly what was changed

`build_model.py` composes the upstream model and explicitly loads its `neutral` keyframe. It saves meshes and XML with static-body fusion disabled, then bakes that pose into the rigid body transforms. Every original geom's position and orientation is checked against the neutral source model before simulation.

All original joints are removed. One y-axis hinge is inserted at the supplied head–rostrum anchor; the haustellum remains a rigid child. Geometry, masses, supplied mesh scaling, mirroring and computed inertias are retained. The thorax, head, legs, wings and other parts stay fixed. This is equivalent to a tethered, immobilized preparation. The floor is only a visual reference; taste contact and collisions are not simulated.

The engineered hinge uses:

| Parameter | Value |
| --- | --- |
| Axis | local +y; negative torque rotates outward in the chosen sagittal plane |
| Range | −1.4 to +0.2 radians; engineering bounds, not anatomical measurements |
| Stiffness | 0.06 model torque units/radian |
| Damping | 0.002 model torque units/(radian/second) |
| Added armature | 0; segment inertia comes from supplied geometry/mass |
| Spring reference | 0 radians |
| Gravity | (0, 0, −9810) mm/s², retained from FlyGym |
| Timestep | 0.0001 seconds |
| Integrator | MuJoCo `implicitfast` |
| Pre-run settling | 0.4 seconds with zero actuator input |
| Recorded duration | 1 second of neural input plus 0.3 seconds of decay |

A passive, non-actuated rostrum sags under gravity before recording. Its settled baseline is about −0.5186 radians (−29.7°) in the standard apparatus. All reported motion is relative to this baseline, not a claim about a living fly's rest posture. The doubled-stiffness apparatus settles to its own baseline. Mechanical constants and torque scales are arbitrary engineering choices, not fits to feeding measurements. Torque is reported in model units without claiming a measured biological force.

## The bridge cannot read the condition

`solve(motor_spikes, coupling=1, stiffness_scale=1, timestep=None)` receives only two numerical arrays of spike times, plus explicitly named mechanical test settings. It does not accept a stimulus label, sensory population or desired trajectory.

For spike times `s`, define:

```
a(t) = sum(exp(-(t-s)/0.05)) over s <= t
activation(t) = 1 - exp(-a(t)/10)
torque(t) = -0.06 * activation(t) * coupling
```

Both MN9 spike trains are pooled; left/right mechanical differences are not represented. Parameters were fixed before the measured comparison runs. No search for a sugar-specific pose or outcome was performed. The control signal is a torque, not a prescribed angle. During each run, `mj_step` solves the motion; the runner never assigns `qpos` to a desired trajectory. Inertia, damping, gravity and spring resistance therefore affect the result.

The data flow is feed-forward and staged: previously completed full-network simulation → raw recorded MN9 spikes → local mechanical replay → browser replay of the mechanical result. It is not simultaneous live coupling and has no sensory feedback.

## Measurements and controls

Maximum absolute angular displacement from the settled baseline:

| Neural condition | Seed 1729 | Seed 1730 | Seed 1731 |
| --- | ---: | ---: | ---: |
| Sugar | 21.94° | 20.22° | 19.33° |
| Sugar + bitter | 3.94° | 8.76° | 10.32° |
| Bitter | ~0° | ~0° | ~0° |
| Wires off + sugar | ~0° | ~0° | ~0° |
| No taste | ~0° | ~0° | ~0° |

Additional checks with sugar seed 1729:

- **Actuator off:** all 132 neural spikes retained; zero active torque; motion matches no-input baseline.
- **Doubled stiffness:** exactly the same activation, torque and 132 spikes; maximum displacement falls to 14.49°. This also changes passive equilibrium; each run is compared to its own baseline.
- **Temporal causality:** sugar trajectory is identical to no-input trajectory before its first motor spike.
- **Numerical refinement:** halving the timestep changes the sugar trajectory by at most 0.0092°. This is a numerical check, not biological validation.
- **Data integrity:** incoming motor arrays are checked against the original raw neural NPZ recordings. Their hashes and the neural JSON hash are retained.
- **Solver:** all trajectories finite, no MuJoCo warnings, all zero-spike conditions exactly identical. Residual no-input baseline drift is about 1.2e-7 degrees, displayed as 0.0°.

The mixed-condition ordering need not match total spike counts: temporal structure, filtering and mechanics matter. These are descriptive comparisons from three existing neural seeds, not statistical claims about natural flies. They also do not establish that the selected connectome topology is uniquely necessary.

## Files, provenance and reproduction

- FlyGym is installed from pinned commit `38c8ec61034cd59bc5ba0de20688d4a3c0000d60`; its license is in `licenses/`.
- `.venv/`: isolated Python environment; exact versions in `requirements-lock.txt`.
- `build_model.py`: explicit body modifications and neutral-geometry validation.
- `model/upstream-posed/`: exported upstream geometry and original articulated composition.
- `model/embodied.xml`: actual one-DoF MuJoCo model used for trials.
- `run_physics.py`: label-blind mechanical solver, bridge, recorded trajectories and assertions.
- `results/*.npz`: full 0.1 ms recordings; `trace` columns are time (seconds), angle (radians), angular velocity, control torque, actuator force, activation, potential energy and kinetic energy. Each file also contains the settled baseline and both neural spike arrays.
- `results/summary.json`: measurements, hashes, versions, validation and resource observations.
- `results/playback.json`: actual 5 ms sampled states, measurements and moving geom transforms. Transform rows contain world xyz then a row-major 3×3 orientation matrix.
- `results/scene.json`: compiled MuJoCo mesh vertices/faces and fixed geom transforms. No artist-authored substitute fly is used.
- `source/main.js`, `build.mjs`, `package.json`, `package-lock.json`: Three.js display source and bundle tooling.
- Top-level `astra-fly-body.html/css/js`: local artifact and bundled assets. Colors, lighting, highlighted mouth, camera and grid are presentation only.
- Browser interaction and desktop/mobile layout were checked before publication; machine-specific test tooling is not included.

From the repository root, after installing the environment described in the top-level README:

```bash
artifacts/fly-embodiment/.venv/bin/python artifacts/fly-embodiment/build_model.py
artifacts/fly-embodiment/.venv/bin/python artifacts/fly-embodiment/run_physics.py
npm --prefix artifacts/fly-embodiment run build
```

Run sequentially; these commands replace the current records. The neural experiment does not need to run again. The original `artifacts/digital-fly/results/` must remain available for input verification.

To recreate Python dependencies, create `.venv` using Python 3.13 and install `requirements-lock.txt`. The FlyGym entry points to the exact upstream commit, not a floating release. Install viewer dependencies using `npm ci --prefix artifacts/fly-embodiment`. The generated viewer is served as a static page; no backend is needed.

The physical batch plus timestep check took about 13 seconds and peaked near 270 MiB here. This excludes one-time installation and model composition. Nothing runs in the background. The viewer draws on interaction or user-started playback, stops its animation frames on pause/finish, pauses while hidden and disposes the renderer on page exit.

## Credits and licenses

NeuroMechFly/FlyGym: EPFL Neuroengineering Laboratory and contributors; Apache-2.0 notice preserved in `licenses/FlyGym-APACHE-2.0.txt` and `THIRD-PARTY-NOTICES.md`. The scientific body is theirs; our contribution is the modified one-joint apparatus, spike-to-torque bridge, controlled replay and presentation. Original NeuroMechFly: [Lobato-Rios et al. (2022)](https://doi.org/10.1038/s41592-022-01466-7); modern framework: [Wang-Chen et al. (2024)](https://doi.org/10.1038/s41592-024-02497-y).

Neural model: Philip Shiu, Nico Spiller and collaborators; original MIT code notice remains in `licenses/Shiu-MIT.txt`. FlyWire/FAFB and its scientific contributors retain the data attribution and noncommercial requirements documented in [the official citation guidelines](https://home.flywire.ai/guidelines) and the First Taste public repository. Mesh/software licensing does not replace neural-data terms.

MuJoCo: Google DeepMind and contributors, Apache-2.0. Three.js: its authors, MIT; the notice is preserved beside this guide and in the generated bundle. This edition is publicly shared as a noncommercial educational integration experiment.

## Development checks and known limits

Visual inspection caught an initial composition-export mistake: MuJoCo had fused the static thorax, while our first transform rewrite assumed it still existed, and the neutral keyframe had not been applied. This was fixed before delivery by disabling fusion, loading the keyframe explicitly, and asserting that every geom frame matches the upstream posed source before the hinge is introduced. All final physical recordings and viewer bundles were regenerated from the corrected model. The mouth dynamics were numerically unchanged by the corrected whole-body placement.

The model does not reproduce natural muscles, bilateral control, haustellum coupling, labellar opening, physical food contact, ingestion or behavioral feedback. Greater visual detail would not remove those limitations. A defensible next experiment would isolate the proboscis mechanics and obtain better joint/force calibration before claiming natural feeding behavior.
