A Windows port (C# / .NET 8 / Win32 + Direct3D11) of desktop-vibe-fly — a 3D fruit fly that lives on your desktop, driven by a live spiking simulation of the real FlyWire connectome, with a "vibecode" nose that sniffs out AI-agent activity on your machine. That macOS project is itself a fork of DenisSergeevitch/desktop-fly, the original FlyWire-connectome fly. Same brain, same data, same behavior — a from-scratch reimplementation for Win32 + Direct3D11 of everything both upstream projects do.
Grab the latest build from Releases — two flavors, pick one:
| variant | size | needs installed on your PC | when to use it |
|---|---|---|---|
DesktopVibeFly-win-x64-selfcontained.zip |
~29 MB | nothing | just want to run it, don't have .NET installed |
DesktopVibeFly-win-x64-framework-dependent.zip |
~1.5 MB | .NET 8 Desktop Runtime | already have .NET 8 installed / prefer a small download |
Unzip, run DesktopFly.exe. A 🪰 appears in the system tray.
The original is a Swift/Cocoa/SceneKit app. Nothing about the neuroscience sim, the behavior state machine, or the "smell for vibecode" file-system scanner is Apple-specific, so this port keeps all of that bit-for-bit identical — same constants, same thresholds, same order of operations — and only replaces the parts that were genuinely macOS-only:
| piece | macOS original | this port |
|---|---|---|
| overlay window | NSWindow (borderless, ignoresMouseEvents) |
one small layered/click-through HWND per fly, following it via UpdateLayeredWindow, re-nested into the real Win32 z-order behind whatever window currently covers her |
| brain window | NSPanel (titled, opaque) |
ordinary floating HWND with its own D3D11 swap chain, MSAA + a D3D-drawn HUD, a fly-selector tab strip when more than one fly is alive |
| scene units | points (NSScreen.frame is DPI-independent) |
logical points too — Sense/ScreenSpace.cs divides out each monitor's DPI |
| 3D rendering | SceneKit | Direct3D11 via Vortice.Windows, procedural meshes, hand-written HLSL |
| tray icon | NSStatusItem |
Shell_NotifyIcon + a native popup menu (no WinForms/WPF) |
| window terrain / senses | CGWindowListCopyWindowInfo, CGEventSource |
EnumWindows, GetLastInputInfo, low-level input hooks |
| thermal "temperature" | ProcessInfo.thermalState |
CPU-load proxy (Windows has no permission-free thermal sensor API) |
| desktop icon / Explorer-row smell | AXUIElement (Accessibility) | cross-process SysListView32 reads |
| live agent smell | — | new: process census + agent/editor project registries + transcript watchers |
| brain(s) | one shared connectome sim | new: one independent 668-neuron LIFSim per fly, all live at once, watched one at a time |
| window "terrain" | a walkable 2D edge | new: every window is a real 3D platform — footprint, height, z-order-stacked, occlusion-honest |
| thermal odor | — | new: a window whose process is burning real CPU pulls the fly toward it |
data (brain_points.json, circuit.json), etl.py |
— | unchanged — already cross-platform |
Requirements: Windows 10/11 (x64), .NET 8 SDK.
No extra runtime install needed for Direct3D11/HLSL compilation —
d3dcompiler_47.dll ships with Windows.
cd DesktopFly
dotnet restore
dotnet build -c Release
dotnet run -c ReleaseA 🪰 icon appears in the system tray; right-click (or left-click) it for the menu. The fly wanders a transparent, click-through overlay on top of your desktop — it never intercepts your mouse or keyboard.
dotnet run -- --simtest # circuit invariants: GF silent at rest, loom latency, ...
dotnet run -- --behaviortest # 19 end-to-end checks: stimulate neurons -> body reacts
dotnet run -- --vibetest # what the fly's nose can smell on this machine
dotnet run -- --vibetest --deep # ...forcing a fresh whole-disk project hunt first
dotnet run -- --snapshot f.png # offscreen fly render
dotnet run -- --brainshot b.png # offscreen brain render--simtest and --behaviortest are the ground truth for whether a change
to Sim/LIFSim.cs or Behavior/Fly.cs broke anything — same invariants
CLAUDE.md documented for the Swift version (GF silent over 4s of rest,
fires within ~10ms of an abrupt loom, walk-drive duty 20-50%, etc.).
--vibetest prints the scanned roots, the projects found and the
window-title tokens they produce — the fastest way to answer "why is the
fly ignoring my code".
The marker table (AGENTS.md, CLAUDE.md, .cursor/rules, and ~40 more)
and all the odor math are the original's, unchanged. What is different is
where it looks, and that it also smells what is running.
Where the projects are. The Swift version scans a fixed handful of
~/ folders; on Windows that reliably finds nothing, because projects
live in Downloads, on a second drive, or anywhere else. So the port
reads the registries that agents and editors already keep
(VibeSense/RecentProjects.cs): ~/.claude/projects/ names every folder
a Claude Code session ran in (the folder name is the slugified absolute
path — resolved back against the real filesystem, because - is
ambiguous), ~/.codex/sessions/ carries each rollout's cwd, and the
whole VS Code family — Code, Insiders, VSCodium, Cursor, Windsurf, Trae,
Kiro, Antigravity, Positron — keeps workspaceStorage\*\workspace.json
with a file:/// folder URI, as does JetBrains' recentProjects.xml.
That is ~100 ms and it names real paths, including the ones on D:,
with a timestamp. A folder an agent actually ran in counts as a project
even with no marker file in it.
The first-run whole-disk walk (depth 10, budgeted by folder count and
wall clock, junctions/system trees pruned, cached in
%USERPROFILE%\.desktopfly-vibe-roots.json) is still there, but it is
now the fallback for a machine whose agents have no history yet — and the
tray's Full Disk Rescan when you want it anyway. Every later launch
does the original's cheap depth-4 scan over the cached roots, the typical
ones (real Desktop/Documents even when OneDrive has redirected them,
Downloads, source\repos, …) and the discovered ones.
What is running (Sense/ProcessSense.cs, VibeSense/LiveVibe.cs) is
a second, live source of smell, so a window reeks even when nothing on
disk gives it away:
- a process census every 2 s on a background thread — one
NtQuerySystemInformationcall, ~7 ms for 300 processes (measured), so ~0.3% of one core; it backs off ×3 while the machine is idle, and falls back toCreateToolhelp32Snapshotif the fast path ever looks wrong; - agentic editors are recognised by process name (Cursor, Windsurf, Trae,
Kiro, Antigravity, Zed, Warp…), plain editors only count when this
machine's copy has AI extensions installed (
~/.vscode/extensionsand friends), so a bare Notepad never reeks; - headless agents (
claude,codex,aider,gemini,amp,cursor-agent, …) have no window, so they are pinned onto the window of their nearest window-owning ancestor — on the machine this was written on, 24 of 25Code.exeprocesses have no window at all, so matching by pid alone finds nothing; - an agent shipped as a node/python script is identified by its command
line, read via
NtQueryInformationProcess(ProcessCommandLineInformation)— noPROCESS_VM_READ— only for newly seen host processes, and never stored or logged: only the agent name it matched; - freshness: file watchers on the transcript folders mean the fly can
tell an idle agent from a thinking one. (Note the folder's own mtime is
useless for this — NTFS only bumps it when an entry is added, not when
an existing
.jsonlgrows.)
The three intensities that produces, all tunable in
%USERPROFILE%\.desktopfly.json:
| situation | source weight | what the fly does |
|---|---|---|
| app minimized to the taskbar | ×0.2 → ~0.5–2 | faint; the fly has to be near the taskbar button to notice |
| window open, agent alive but quiet | ~7–14 | pulls from across the desk |
| agent writing right now | ~22–30 (×2.2, decaying over 45 s) | pulls from anywhere on screen |
Nothing here injects extra arousal into the circuit: the drive is still
Clamp(concentration / odorFull) from the original's odor math, so
"reeking" only ever means smelt from further away and preferred over
everything else. The tray's What the Fly Smells… and
--vibetest both report the live half — which agents are running, in
whose window, how long ago they moved, and what every window on screen is
currently worth.
| item | effect |
|---|---|
| Pause / Resume | freeze the world |
| Show/Hide Brain | toggle the live brain window |
| Escape Test (loom) | inject a looming stimulus into every fly's own circuit, watch the GF fire |
| Move to Next Display | hop the fly across monitors (shown when >1 display) |
| Add / Remove Fly | extra flies, each with its own independent 668-neuron brain |
| Scare Flies | startle everyone, for real — every fly's own escape circuit reacts |
| What the Fly Smells… | projects found, odor tokens, live source count, agents running right now, recent projects from agent history |
| Rescan Vibe Now / Full Disk Rescan | re-run the quick or the deep scan |
One window, one brain shown at a time — a tab strip appears across the top once there is more than one fly, so you can watch any of them think.
All 668 circuit neurons glow in real time as they actually spike —
brightness and size track a per-neuron activity trace, not a sampled
subset — while the Giant Fiber still gets its own dramatic flash on an
escape spike. Resizing the window shows more scene, not a bigger brain:
the field of view widens with the window so the brain keeps a constant
on-screen size. Rendering is 4× MSAA into an offscreen target that is
resolved into the swap chain, and the labels/legend/hints are drawn by the
window's own D3D HUD layer (Render/HudRenderer.cs).
Every window on screen is a flying platform — a footprint plus a real height, stacked in the same front-to-back order Windows itself uses, so a fly can stand on one, fly over or around one, or walk underneath one on the bare desktop. She never clips through a window's slab in either direction, and her own sprite is nested into the real Win32 z-order behind whatever currently covers her — genuinely hidden, not just drawn underneath a mask. A soft ground shadow (offset to stay visible under a straight-down camera, since a shadow drawn exactly beneath her would be perfectly hidden by her own sprite) shows how high she's flying and onto which surface. She also drifts toward windows whose process is genuinely burning CPU — a build, a render, a game — a separate, independent draw from the vibecode smell above.
Builds clean on .NET 8 SDK + Vortice.Windows 3.8.3 / Vortice.Mathematics
2.1.1 (the versions pinned in DesktopFly.csproj), and both --simtest
and --behaviortest pass. The no-args tray+overlay app, --vibetest,
--snapshot, and --brainshot have all been run and verified on real
Windows hardware.
One caveat on --simtest: it is stochastic and fails roughly one run in
ten. The marginal assertion is arousalOn > 0.50 in Tests/SimTests.cs,
and the measured value lands in 0.50–0.55 — i.e. the threshold sits on the
edge of the quantity's own distribution rather than clear of it. This is
inherited from the Swift original (same threshold, same unseeded noise);
re-run before concluding a change broke something. See NOTES_FOR_BUILDING.md for the handful of small API-drift
fixes (mostly int→uint signature changes in the Vortice.Windows
version currently on nuget.org) that were needed to get here, in case a
future package upgrade reintroduces similar drift.
Sim/LIFSim.cs and the core of Behavior/Fly.cs (every threshold, gain,
and the per-millisecond order of operations) are a faithful, line-for-line
port — no shortcuts there, and nothing in the 3D-terrain/multi-brain work
below touches them. Behavior/Fly.cs itself has grown real, new
capabilities beyond the original — a per-fly LIFSim instead of one shared
brain, and windows as real 3D platforms with height, occlusion, and
altitude physics — layered additively on top of that untouched core (see
CLAUDE.md's "What must stay byte-for-byte identical" for exactly where
that line is drawn). Sense//VibeSense/'s vibecode-smelling logic
remains a faithful port; its additions are Windows-shaped rather than
different-in-kind: the first-run whole-disk project hunt described above,
Sense/ScreenSpace.cs restoring the original's DPI-independent point
space, and the CPU-heat odor source. The rendering layer took a few real
simplifications:
- The ground shadow is a stylized offset blob, not shadow-mapping.
SHADOWS_ENABLEDin the original drove a deferred shadow map; this port draws a soft ellipse displaced along the same light direction the body is shaded with, damped so it stays inside the fly's own small sprite window rather than drifting out of frame at altitude — a straight-down orthographic camera has no parallax, so a shadow placed directly beneath her would be perfectly hidden behind her own sprite regardless of height. (Everything else about her geometry — procedural spheres/capsules/cone for the body, an ellipse for the wings, all the same measurements asbuildFlyModel()— is intact.) - Abdomen stripes are a flat color, not the procedurally-drawn striped texture the original painted at runtime.
--snapshotuses the overlay's straight-on orthographic camera instead of the original's angled perspective hero shot — still useful to sanity-check the body/gait, just from a different angle.- Thermal tempo is a CPU-load proxy, documented above.
- Desktop-icon/Explorer-row smelling (
ShellIconSense.cs) is best-effort, same as the original's AX-based Finder scanning being gated behind a permission the person could decline — here it's just wrapped defensively so a failure degrades to "no icon targets" instead of a crash, never blocking the window-title-based smelling that's the primary version of the feature.
DenisSergeevitch/desktop-fly original macOS app: the LIF connectome sim + fly body
│ (Swift, Cocoa, SceneKit)
▼
kulikov0/desktop-vibe-fly + the "vibecode" nose: smells AGENTS.md/CLAUDE.md
│ markers and running AI agents, steers the fly toward them
▼
this repo (Windows port) same sim, same behavior, same nose — reimplemented for
Win32 + Direct3D11, plus a live process/window census in
place of the fixed-folder disk scan (see below)
Code is MIT — see LICENSE, copyright retained from the
original author, unchanged through both forks. data/ is derived from
FlyWire (FAFB v783) and is CC BY-NC 4.0 — see
DesktopFly/data/DATA_LICENSE.md. If you use this, cite:
- Dorkenwald, S. et al. Neuronal wiring diagram of an adult brain. Nature 634, 124–138 (2024).
- Schlegel, P. et al. Whole-brain annotation and multi-connectome cell typing of Drosophila. Nature 634, 139–152 (2024).

