Download live.html from epoch14/fly-sim: direct link, hf CLI and curl.
- Browser
- Download file 6.04 kB
-
https://huggingface.co/spaces/epoch14/fly-sim/resolve/main/live.html
- Command line
-
hf download hf://spaces/epoch14/fly-sim/live.html
-
curl -L -o live.html https://huggingface.co/spaces/epoch14/fly-sim/resolve/main/live.html
6.04 kB
| <html lang="en"> | |
| <head> | |
| <meta charset="utf-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |
| <title>FlySim LIVE — feed the flies</title> | |
| <style> | |
| :root { color-scheme: dark; } | |
| * { box-sizing: border-box; } | |
| body { margin: 0; font: 16px/1.6 system-ui, sans-serif; background: #0d1117; color: #e6edf3; } | |
| main { max-width: 1080px; margin: 0 auto; padding: 32px 20px 80px; } | |
| h1 { font-size: 1.5rem; margin: 0 0 6px; display: flex; align-items: center; gap: 12px; } | |
| .badge { background: #da3633; color: #fff; font-weight: 700; font-size: .72rem; | |
| padding: 3px 12px; border-radius: 999px; letter-spacing: .1em; } | |
| p.sub { color: #8b949e; margin: 0 0 20px; max-width: 820px; } | |
| a { color: #58a6ff; text-decoration: none; } a:hover { text-decoration: underline; } | |
| #framebox { position: relative; border: 1px solid #30363d; border-radius: 10px; | |
| overflow: hidden; background: #000; aspect-ratio: 16/9.6; } | |
| #framebox iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; } | |
| #placeholder { position: absolute; inset: 0; display: flex; flex-direction: column; | |
| gap: 14px; align-items: center; justify-content: center; color: #8b949e; | |
| text-align: center; padding: 20px; } | |
| #placeholder b { color: #e6edf3; } | |
| .urlrow { display: flex; gap: 8px; margin: 14px 0; flex-wrap: wrap; } | |
| input[type=text] { flex: 1; min-width: 260px; background: #161b22; color: #e6edf3; | |
| border: 1px solid #30363d; border-radius: 8px; padding: 9px 12px; | |
| font-size: .9rem; } | |
| button { background: #238636; color: #fff; border: 1px solid #2ea043; border-radius: 8px; | |
| padding: 9px 18px; cursor: pointer; font-size: .9rem; font-weight: 600; } | |
| button.sec { background: #21262d; color: #e6edf3; border-color: #30363d; font-weight: 400; } | |
| button:hover { filter: brightness(1.15); } | |
| .how { background: #161b22; border: 1px solid #21262d; border-radius: 10px; | |
| padding: 14px 18px; margin-top: 18px; } | |
| .how h3 { margin: 0 0 8px; font-size: .85rem; color: #8b949e; text-transform: uppercase; | |
| letter-spacing: .06em; } | |
| code { background: #0d1117; border: 1px solid #21262d; padding: 2px 8px; border-radius: 6px; | |
| font-size: .85em; display: inline-block; margin: 2px 0; } | |
| .note { color: #8b949e; font-size: .88rem; } | |
| video { width: 100%; border-radius: 10px; background: #000; } | |
| </style> | |
| </head> | |
| <body> | |
| <main> | |
| <h1><span class="badge">LIVE</span> Feed the flies — the real simulator, running now</h1> | |
| <p class="sub">Two actual MuJoCo <i>Drosophila</i> walkers, streamed frame-by-frame from a | |
| running simulation. <b>Click the arena: the food patch moves there</b> and both flies | |
| re-orient with the M4-verified antennal chemotaxis, walk over, and feed. Energy drains, | |
| they get hungry again. You are the ecosystem's only food supply.</p> | |
| <div class="urlrow"> | |
| <input type="text" id="url" placeholder="paste a live sim URL — e.g. https://<job-id>--7860.hf.jobs" spellcheck="false"> | |
| <button id="go">Watch</button> | |
| <button class="sec" id="stop">Stop</button> | |
| </div> | |
| <div id="framebox"> | |
| <div id="placeholder"> | |
| <b>No live sim connected.</b> | |
| <span>Launch one below (about a minute to boot), paste the URL above, then click the arena to feed the flies.</span> | |
| <video controls muted loop preload="metadata" src="colony.mp4" style="max-width:520px"></video> | |
| <span class="note">…or watch the recorded colony while it boots.</span> | |
| </div> | |
| </div> | |
| <div class="how"> | |
| <h3>Launch a live sim</h3> | |
| <p class="note" style="margin-top:0"><b>Option A — your own machine (fastest, fully interactive):</b><br> | |
| <code>docker run --rm -p 7860:7860 -v $PWD/data:/app/data -e MUJOCO_GL=egl fly-sim:space python -m flysim.live_colony</code><br> | |
| then use <code>http://localhost:7860</code> above.</p> | |
| <p class="note"><b>Option B — Hugging Face compute (slow-motion, shareable):</b><br> | |
| <code>python -m flysim.jobs --live-colony --timeout 3600</code><br> | |
| prints <code>https://<job-id>--7860.hf.jobs</code> — paste it above. Note: HF job URLs | |
| require the viewer to be logged in to a Hugging Face account.</p> | |
| </div> | |
| <p class="note" style="margin-top:18px">What am I looking at? Real physics at 10 kHz (slowed | |
| to watchable speed), the same walkers, energy law (0.02/s drain, 0.25/s feeding) and odor | |
| sensing verified in milestones M1–M4. The flies cannot see the food — they smell the | |
| gradient across their two antennae and pulse-turn until aligned. Sated flies loiter in a | |
| slow orbit near the food; hunger pulls them back. Starvation is real: clicks farther than | |
| ~35 mm may cost a fly its life — the <b>reset colony</b> button in the viewer respawns | |
| them. Courtship encounters are logged when they cross paths. | |
| Back to the <a href="index.html">dashboard</a> · <a href="player.html">trajectory player</a>.</p> | |
| </main> | |
| <script> | |
| const box = document.getElementById("framebox"), ph = document.getElementById("placeholder"), | |
| urlIn = document.getElementById("url"); | |
| let saved = localStorage.getItem("flysim-live-url") || ""; | |
| urlIn.value = saved; | |
| function connect(u) { | |
| u = u.trim().replace(/\/+$/, ""); | |
| if (!u) return; | |
| if (!/^https?:\/\//.test(u)) u = "https://" + u; | |
| localStorage.setItem("flysim-live-url", u); | |
| urlIn.value = u; | |
| ph.style.display = "none"; | |
| const old = document.getElementById("liveframe"); | |
| if (old) old.remove(); | |
| const f = document.createElement("iframe"); | |
| f.id = "liveframe"; f.src = u; f.allow = "fullscreen"; | |
| box.appendChild(f); | |
| } | |
| document.getElementById("go").onclick = () => connect(urlIn.value); | |
| urlIn.addEventListener("keydown", e => { if (e.key === "Enter") connect(urlIn.value); }); | |
| document.getElementById("stop").onclick = () => { | |
| const old = document.getElementById("liveframe"); | |
| if (old) old.remove(); | |
| ph.style.display = ""; | |
| }; | |
| if (saved) connect(saved); | |
| </script> | |
| </body> | |
| </html> | |