73 lines
16 KiB
HTML
73 lines
16 KiB
HTML
|
|
<!DOCTYPE html>
|
||
|
|
<html lang="en">
|
||
|
|
<head>
|
||
|
|
<meta charset="UTF-8">
|
||
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
|
|
<title>Circuit Bloom in Static — exploration</title>
|
||
|
|
<style>
|
||
|
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||
|
|
body { background: #0a0a0f; color: #3a3a4a; font-family: ui-monospace, monospace; overflow: hidden; }
|
||
|
|
#grid { padding: 20px; font-size: 12px; line-height: 1.4; white-space: pre; }
|
||
|
|
.c { display: inline-block; transition: all 0.3s; }
|
||
|
|
.c.active { color: #fde68a; text-shadow: 0 0 6px rgba(253,230,138,0.5); }
|
||
|
|
.c.strong { color: #34d399; text-shadow: 0 0 10px rgba(52,211,153,0.6); font-weight: bold; }
|
||
|
|
.c.dead { color: #1a1a2a; }
|
||
|
|
#info { position: fixed; bottom: 10px; left: 20px; color: #3a3a4a; font-size: 11px; }
|
||
|
|
#controls { position: fixed; top: 10px; right: 20px; color: #666; font-size: 11px; }
|
||
|
|
#controls span { cursor: pointer; margin-left: 12px; color: #fde68a; }
|
||
|
|
</style>
|
||
|
|
</head>
|
||
|
|
<body>
|
||
|
|
<div id="grid"></div>
|
||
|
|
<div id="info">neurameba · physarum exploration</div>
|
||
|
|
<div id="controls"><span id="play-btn">play</span><span id="reset-btn">reset</span></div>
|
||
|
|
<script>
|
||
|
|
const text = "# Command Reference\n\nEverything in motd happens through commands. Type them in the input bar at the bottom of the terminal.\n\n---\n\n## Shell\n\n### /help\nShow all available commands grouped by category.\n```\n> /help\n```\n\n### /menu\nToggle the sidebar. Shows motd branding, commands, doc links, and footer. Click any command to run it.\n```\n> /menu\n```\n\n### /clear\nClear the terminal output.\n```\n> /clear\n```\n\n### /terminal --width [value]\nSet the terminal width. Accepts px, %, or `reset`.\n```\n> /terminal --width 1000\n Terminal width set to 1000px.\n\n> /terminal --width 80%\n Terminal width set to 80%.\n\n> /terminal --width reset\n Terminal width reset to default (800px).\n```\n\nWidth is stored in localStorage and restored on next visit. On mobile, the terminal is always 100% width.\n\n### /close\nClose the left panel.\n```\n> /close\n```\n\n### /settings cli [position]\nMove the terminal input line. Positions: bottom (default), top, right, left, middle.\n```\n> /settings cli top\n CLI position set to top.\n\n> /settings cli\n CLI position: top\n```\n\nPosition persists across sessions. On mobile, always bottom.\n\n### /config export\nDownload your current config as a JSON file.\n```\n> /config export\n Config downloaded.\n```\n\n### /config import\nLoad config from a JSON file. Opens a file picker.\n```\n> /config import\n [file picker opens]\n Config imported.\n```\n\n### /config reset\nReset all client-side config overrides to server defaults.\n```\n> /config reset\n Config reset to defaults.\n```\n\nThe config system merges localStorage overrides with server defaults. Export/import lets you back up or transfer your settings.\n\n### /read [path]\nRead a documentation file. Renders markdown inline in the terminal.\n```\n> /read about\n> /read api\n> /read commands\n```\n\nWithout arguments, lists all available docs.\n```\n> /read\n```\n\n### /tree -cat\nBrowse categories and their tags. Click a tag to search for posts with it.\n```\n> /tree -cat\n\n coding/\n [rust] [python] [wasm] [js] [frontend] [backend]\n creative/\n [music] [art] [writing] [gamedev]\n meta/\n [motd] [bugs] [ideas] [feedback]\n general/\n [offtopic] [introductions] [showcase]\n```\n\n### /link [target]\nUniversal navigation. Resolves the target and takes you there.\n```\n> /link @alice → opens alice's profile\n> /link rust → searches for [rust] posts\n> /link a3kf9x → shows a specific post\n> /link docs/api → reads the API doc\n```\n\nResolution order: user > tag > post > doc.\n\n---\n\n## Auth\n\n### /register\nCreate an account. Interactive prompts for username and password.\n```\n> /register\n username: alice\n password: ********\n Registered as alice.\n```\n- Username: 3-20 characters, letters/numbers/underscore\n- Password: minimum 8 characters\n\n### /login\nLog in. Session lasts until you close the tab.\n```\n> /login\n username: alice\n password: ********\n Logged in as alice.\n```\n\n### /login-permanently\nLog in with a persistent session. Survives tab closes and browser restarts.\n```\n> /login-permanently\n username: alice\n password: ********\n Logged in as alice (persistent).\n```\n\n### /logout\nEnd your session.\n```\n> /logout\n Logged out.\n```\n\n---\n\n## Profile\n\n### /profile\nView your own profile.\n```\n> /profile\n\n ████ ████\n ████████\n ████████████\n ████████\n ██ ████ ██\n\n @alice (Alice)\n building things\n Posts: 42\n Joined: 2026-03-15\n```\n\n### /profile @user\nView another user's profile.\n```\n> /profile @bob\n```\n\n### /settings\nEdit your display name and bio. Interactive prompts.\n```\n> /settings\n display_name (Alice): Alice W.\n bio (building things): shipping code\n Settings updated.\n```\n\n---\n\n## Posts\n\n### /post [text]\nPublish a post. Max 500 characters. Tags use [brackets].\n```\n> /post just shipped the wasm compiler [rust] [wasm]\n\n @alice · just shipped the was
|
||
|
|
const passes = [{"t":0,"r":316,"c":7,"a":"hold","s":0.18735667095626896,"ps":9,"e":100.14885336765015,"pr":1.1},{"t":0,"r":285,"c":69,"a":"extend","s":0.30809761159341226,"ps":9,"e":70.78034662492311,"pr":1.1},{"t":0,"r":393,"c":4,"a":"hold","s":0.17295510912411766,"ps":9,"e":100.03364087299295,"pr":1.1},{"t":0,"r":16,"c":1,"a":"extend","s":0.3434941901040408,"ps":9,"e":70.97856746458262,"pr":1.1},{"t":0,"r":356,"c":4,"a":"hold","s":0.15811929875060635,"ps":9,"e":99.91495439000485,"pr":1.1},{"t":1,"r":316,"c":7,"a":"hold","s":0.19231770059620323,"ps":8,"e":100.48739497241978,"pr":1.05},{"t":1,"r":285,"c":69,"a":"hold","s":0.2999667714434493,"ps":8,"e":71.9800807964707,"pr":1.05},{"t":1,"r":393,"c":4,"a":"hold","s":0.1844822129378177,"ps":8,"e":100.30949857649549,"pr":1.05},{"t":1,"r":16,"c":1,"a":"extend","s":0.37596963636734954,"ps":9,"e":50.845427188864996,"pr":1.1},{"t":1,"r":356,"c":4,"a":"hold","s":0.20412643493847937,"ps":9,"e":100.19796586951269,"pr":1.1},{"t":1,"r":16,"c":2,"a":"extend","s":0.36229770354582275,"ps":5,"e":22.797437379231393,"pr":1.2000000000000002},{"t":1,"r":15,"c":1,"a":"hold","s":0.2522155519514593,"ps":5,"e":31.687110471861374,"pr":1.2000000000000002},{"t":2,"r":316,"c":7,"a":"retracted","s":0.18196815090401597,"ps":7,"e":100.89314017965191,"pr":1},{"t":2,"r":285,"c":69,"a":"hold","s":0.30809761159341226,"ps":7,"e":73.394861689218,"pr":1},{"t":2,"r":393,"c":4,"a":"retracted","s":0.17295510912411766,"ps":7,"e":100.64313944948843,"pr":1},{"t":2,"r":16,"c":1,"a":"extend","s":0.37596963636734954,"ps":8,"e":36.85722899586265,"pr":1.05},{"t":2,"r":356,"c":4,"a":"retracted","s":0.2013726135922446,"ps":8,"e":100.60894677825064,"pr":1.05},{"t":2,"r":16,"c":2,"a":"hold","s":0.2363487969192705,"ps":5,"e":23.938227754585558,"pr":1.2000000000000002},{"t":2,"r":15,"c":1,"a":"hold","s":0.21240522940773485,"ps":5,"e":32.63635230712325,"pr":1.2000000000000002},{"t":2,"r":17,"c":1,"a":"hold","s":0.34912852672756667,"ps":5,"e":23.83392558047696,"pr":1.2000000000000002},{"t":2,"r":15,"c":2,"a":"hold","s":0.07155840080467106,"ps":5,"e":9.592797511822251,"pr":1.3000000000000003},{"t":3,"r":285,"c":69,"a":"retracted","s":0.30947893761440404,"ps":6,"e":74.97069319013323,"pr":0.95},{"t":3,"r":16,"c":1,"a":"hold","s":0.3434941901040408,"ps":8,"e":38.40518251669498,"pr":1.05},{"t":3,"r":16,"c":2,"a":"hold","s":0.2363487969192705,"ps":4,"e":25.22901812993972,"pr":1.1500000000000001},{"t":3,"r":15,"c":1,"a":"retracted","s":0.20891134321522534,"ps":4,"e":33.70764305284506,"pr":1.1500000000000001},{"t":3,"r":17,"c":1,"a":"hold","s":0.3346772661569516,"ps":4,"e":25.911343709732574,"pr":1.1500000000000001},{"t":3,"r":15,"c":2,"a":"hold","s":0.10824993453267848,"ps":5,"e":9.708796988083678,"pr":1.3000000000000003},{"t":3,"r":16,"c":0,"a":"hold","s":0.18748914649167336,"ps":5,"e":16.545868455874523,"pr":1.1500000000000001},{"t":4,"r":16,"c":1,"a":"hold","s":0.3434941901040408,"ps":7,"e":40.10313603752731,"pr":1},{"t":4,"r":16,"c":2,"a":"retracted","s":0.36229770354582275,"ps":4,"e":27.527399758306302,"pr":1.1500000000000001},{"t":4,"r":17,"c":1,"a":"retracted","s":0.34912852672756667,"ps":4,"e":28.104371923553106,"pr":1.1},{"t":4,"r":15,"c":2,"a":"retracted","s":0.10735494506484615,"ps":4,"e":9.967636548602448,"pr":1.2500000000000002},{"t":4,"r":16,"c":0,"a":"hold","s":0.20701218821321257,"ps":5,"e":17.451965961580225,"pr":1.1500000000000001},{"t":5,"r":16,"c":1,"a":"retracted","s":0.32695910626811864,"ps":7,"e":41.668808887672256,"pr":1},{"t":5,"r":16,"c":0,"a":"retracted","s":0.20701218821321257,"ps":4,"e":18.508063467285925,"pr":1.1}];
|
||
|
|
const lines = text.split('\n');
|
||
|
|
const gridEl = document.getElementById('grid');
|
||
|
|
const charEls = [];
|
||
|
|
for (let r = 0; r < lines.length; r++) {
|
||
|
|
const row = [];
|
||
|
|
for (let c = 0; c < lines[r].length; c++) {
|
||
|
|
const s = document.createElement('span');
|
||
|
|
s.className = 'c';
|
||
|
|
s.textContent = lines[r][c];
|
||
|
|
row.push(s);
|
||
|
|
gridEl.appendChild(s);
|
||
|
|
}
|
||
|
|
charEls.push(row);
|
||
|
|
gridEl.appendChild(document.createTextNode('\n'));
|
||
|
|
}
|
||
|
|
let tick = -1, playing = false, iv;
|
||
|
|
function apply(t) {
|
||
|
|
for (const r of charEls) for (const e of r) e.className = 'c';
|
||
|
|
const active = new Map();
|
||
|
|
for (const p of passes) {
|
||
|
|
if (p.t > t) break;
|
||
|
|
const k = p.r+','+p.c;
|
||
|
|
if (p.a === 'died' || p.a === 'retracted') active.set(k, 'dead');
|
||
|
|
else if (p.ps > 16) active.set(k, 'strong');
|
||
|
|
else active.set(k, 'active');
|
||
|
|
}
|
||
|
|
for (const [k, cls] of active) {
|
||
|
|
const [r, c] = k.split(',').map(Number);
|
||
|
|
if (charEls[r]?.[c]) charEls[r][c].className = 'c ' + cls;
|
||
|
|
}
|
||
|
|
document.getElementById('info').textContent = 'tick ' + t + ' · ' + [...active.values()].filter(v=>v!=='dead').length + ' alive';
|
||
|
|
}
|
||
|
|
function play() {
|
||
|
|
if (playing) return;
|
||
|
|
playing = true;
|
||
|
|
document.getElementById('play-btn').textContent = 'pause';
|
||
|
|
const max = passes.length > 0 ? passes[passes.length-1].t : 0;
|
||
|
|
iv = setInterval(() => { tick++; if (tick > max) { pause(); return; } apply(tick); }, 900);
|
||
|
|
}
|
||
|
|
function pause() { playing = false; clearInterval(iv); document.getElementById('play-btn').textContent = 'play'; }
|
||
|
|
function reset() { pause(); tick = -1; for (const r of charEls) for (const e of r) e.className = 'c'; document.getElementById('info').textContent = 'neurameba'; }
|
||
|
|
document.getElementById('play-btn').addEventListener('click', () => playing ? pause() : play());
|
||
|
|
document.getElementById('reset-btn').addEventListener('click', reset);
|
||
|
|
setTimeout(play, 1000);
|
||
|
|
</script>
|
||
|
|
</body>
|
||
|
|
</html>
|