Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="utf-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"> | |
| <title>NEURAL DRIVE — a world model you can steer</title> | |
| <link rel="preconnect" href="https://fonts.googleapis.com"> | |
| <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> | |
| <link href="https://fonts.googleapis.com/css2?family=Chakra+Petch:wght@400;500;600;700&family=Azeret+Mono:wght@400;500;600&display=swap" rel="stylesheet"> | |
| <style> | |
| :root{ | |
| --bg:#08090c; --bg2:#0d0f14; --panel:#111319; --line:#1d212b; | |
| --amber:#ffb020; --amber-hot:#ff6a00; --cyan:#57e6d4; --ink:#eceae4; | |
| --dim:#727a88; --dimmer:#3a404c; --red:#ff5566; | |
| --grid:rgba(255,255,255,.028); | |
| } | |
| *{box-sizing:border-box;margin:0;padding:0} | |
| html,body{height:100%} | |
| body{ | |
| background:var(--bg); color:var(--ink); | |
| font-family:'Chakra Petch',sans-serif; letter-spacing:.02em; | |
| min-height:100%; overflow-x:hidden; | |
| background-image: | |
| radial-gradient(1200px 600px at 70% -10%, rgba(255,176,32,.06), transparent 60%), | |
| radial-gradient(900px 500px at 10% 110%, rgba(87,230,212,.05), transparent 60%), | |
| linear-gradient(var(--grid) 1px, transparent 1px), | |
| linear-gradient(90deg, var(--grid) 1px, transparent 1px); | |
| background-size:auto,auto,44px 44px,44px 44px; | |
| } | |
| /* film grain */ | |
| body::after{ | |
| content:""; position:fixed; inset:0; pointer-events:none; z-index:99; opacity:.05; | |
| background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='2'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E"); | |
| mix-blend-mode:overlay; | |
| } | |
| .wrap{max-width:980px; margin:0 auto; padding:34px 22px 60px; position:relative; z-index:1} | |
| /* header */ | |
| header{margin-bottom:24px} | |
| .brand{display:flex; flex-direction:column; gap:6px; width:100%} | |
| .lede{font-family:'Azeret Mono',monospace; font-size:13px; color:var(--dim); line-height:1.55; margin-top:12px; max-width:none; width:100%} | |
| .lede b{color:var(--ink); font-weight:500} | |
| .mlink{color:var(--amber); text-decoration:none; white-space:nowrap; border-bottom:1px solid rgba(255,176,32,.35); transition:border-color .15s} | |
| .mlink:hover{border-color:var(--amber)} | |
| .kicker{font-family:'Azeret Mono',monospace; font-size:11px; letter-spacing:.42em; color:var(--amber); text-transform:uppercase} | |
| h1{font-size:clamp(30px,6vw,54px); font-weight:700; line-height:.92; letter-spacing:-.01em} | |
| h1 .slash{color:var(--dimmer); font-weight:400} | |
| h1 em{color:var(--cyan); font-style:normal} | |
| .sub{font-family:'Azeret Mono',monospace; font-size:12px; color:var(--dim); max-width:42ch; line-height:1.5; margin-top:8px} | |
| .spec{font-family:'Azeret Mono',monospace; font-size:11px; color:var(--dim); text-align:right; line-height:1.9; white-space:nowrap} | |
| .spec b{color:var(--ink); font-weight:500} | |
| /* console */ | |
| .console{ | |
| border:1px solid var(--line); background:linear-gradient(180deg,var(--panel),#0b0d12); | |
| border-radius:14px; padding:16px; position:relative; | |
| box-shadow:0 40px 80px -40px rgba(0,0,0,.9), inset 0 1px 0 rgba(255,255,255,.03); | |
| } | |
| .viewport{position:relative; border-radius:9px; overflow:hidden; background:#000; aspect-ratio:2/1; | |
| outline:1px solid var(--line); box-shadow:inset 0 0 0 1px rgba(0,0,0,.6), 0 0 60px -20px rgba(255,176,32,.25);} | |
| #screen{width:100%; height:100%; display:block; image-rendering:pixelated; filter:saturate(1.06) contrast(1.03)} | |
| /* scanlines + vignette + glow overlays on the viewport */ | |
| .viewport::before{content:""; position:absolute; inset:0; pointer-events:none; z-index:3; | |
| background:repeating-linear-gradient(0deg, rgba(0,0,0,.16) 0 1px, transparent 1px 3px); mix-blend-mode:multiply; opacity:.5;} | |
| .viewport::after{content:""; position:absolute; inset:0; pointer-events:none; z-index:4; | |
| box-shadow:inset 0 0 120px 6px rgba(0,0,0,.6); background:radial-gradient(120% 120% at 50% 40%, transparent 60%, rgba(0,0,0,.35));} | |
| /* HUD corner brackets */ | |
| .bkt{position:absolute; width:20px; height:20px; border:2px solid var(--amber); opacity:.55; z-index:5; pointer-events:none} | |
| .bkt.tl{top:9px;left:9px;border-right:0;border-bottom:0}.bkt.tr{top:9px;right:9px;border-left:0;border-bottom:0} | |
| .bkt.bl{bottom:9px;left:9px;border-right:0;border-top:0}.bkt.br{bottom:9px;right:9px;border-left:0;border-top:0} | |
| /* boot overlay */ | |
| .boot{position:absolute; inset:0; z-index:8; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:18px; | |
| background:radial-gradient(120% 120% at 50% 30%, #10131a, #06070a); text-align:center; padding:24px} | |
| .boot.hide{opacity:0; visibility:hidden; transition:opacity .5s ease, visibility .5s} | |
| .boot .big{font-size:clamp(18px,3.5vw,26px); font-weight:600; letter-spacing:.06em} | |
| .boot-claim{font-family:'Azeret Mono',monospace; font-size:12px; letter-spacing:.16em; text-transform:uppercase; color:var(--amber); text-align:center; opacity:.92; margin-top:-6px} | |
| .boot .status{font-family:'Azeret Mono',monospace; font-size:12px; color:var(--dim); min-height:1.4em; letter-spacing:.05em} | |
| .bar{width:min(70%,360px); height:6px; border:1px solid var(--line); border-radius:6px; overflow:hidden; background:#0a0c11} | |
| .bar i{display:block; height:100%; width:0%; background:linear-gradient(90deg,var(--amber-hot),var(--amber)); box-shadow:0 0 14px var(--amber); transition:width .2s} | |
| .ignite{font-family:'Chakra Petch'; font-weight:700; letter-spacing:.28em; text-transform:uppercase; font-size:15px; | |
| color:#0a0a0a; background:linear-gradient(180deg,var(--amber),var(--amber-hot)); border:0; padding:14px 30px; border-radius:8px; cursor:pointer; | |
| box-shadow:0 0 34px -6px var(--amber); animation:pulse 1.8s ease-in-out infinite; display:none} | |
| .ignite:hover{filter:brightness(1.08)} | |
| @keyframes pulse{0%,100%{box-shadow:0 0 20px -6px var(--amber)}50%{box-shadow:0 0 40px 2px var(--amber)}} | |
| /* telemetry strip */ | |
| .telem{display:grid; grid-template-columns:repeat(4,1fr); gap:10px; margin-top:14px} | |
| .cell{border:1px solid var(--line); border-radius:8px; padding:10px 12px; background:#0b0d12} | |
| .cell .l{font-family:'Azeret Mono',monospace; font-size:9.5px; letter-spacing:.24em; color:var(--dim); text-transform:uppercase} | |
| .cell .v{font-family:'Azeret Mono',monospace; font-size:19px; font-weight:600; color:var(--ink); margin-top:3px} | |
| .cell .v small{font-size:11px; color:var(--dim); font-weight:400} | |
| .cell .v.hot{color:var(--amber)} .cell .v.cool{color:var(--cyan)} | |
| /* controls */ | |
| .controls{display:flex; align-items:center; justify-content:space-between; gap:18px; flex-wrap:wrap; margin-top:20px} | |
| .keys{display:flex; gap:8px; align-items:center; flex-wrap:wrap} | |
| .kc{font-family:'Azeret Mono',monospace; font-size:12px; min-width:34px; height:34px; padding:0 9px; display:flex; align-items:center; justify-content:center; | |
| border:1px solid var(--line); border-bottom-width:3px; border-radius:7px; background:#0e1016; color:var(--dim); transition:all .08s} | |
| .kc.on{background:var(--amber); color:#0a0a0a; border-color:var(--amber-hot); box-shadow:0 0 18px -3px var(--amber); transform:translateY(1px)} | |
| .kc small{font-size:9px; opacity:.7; margin-left:5px} | |
| .btns{display:flex; gap:10px} | |
| .btn{font-family:'Chakra Petch'; font-weight:600; letter-spacing:.14em; text-transform:uppercase; font-size:12px; cursor:pointer; | |
| border:1px solid var(--line); background:#0e1016; color:var(--ink); padding:11px 18px; border-radius:8px; transition:all .12s} | |
| .btn:hover{border-color:var(--amber); color:var(--amber)} | |
| .btn.ghost{color:var(--dim)} | |
| footer{margin-top:26px; font-family:'Azeret Mono',monospace; font-size:11px; color:var(--dimmer); line-height:1.7} | |
| footer a{color:var(--dim); text-decoration:none; border-bottom:1px solid var(--dimmer)} | |
| .warn{color:var(--red)} | |
| @media(max-width:620px){ .telem{grid-template-columns:repeat(2,1fr)} .spec{text-align:left} } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="wrap"> | |
| <header> | |
| <div class="brand"> | |
| <h1>NEURAL<span class="slash">/</span><em>DRIVE</em></h1> | |
| <p class="lede">A <a class="mlink" href="https://huggingface.co/codelion/neural-drive-model" target="_blank" rel="noopener">world model</a> trained automatically on SuperTuxKart gameplay videos, running entirely inside your browser.</p> | |
| </div> | |
| </header> | |
| <div class="console"> | |
| <div class="viewport"> | |
| <canvas id="screen" width="384" height="192"></canvas> | |
| <span class="bkt tl"></span><span class="bkt tr"></span><span class="bkt bl"></span><span class="bkt br"></span> | |
| <div class="boot" id="boot"> | |
| <div class="big" id="bootBig">IGNITION SEQUENCE</div> | |
| <div class="boot-claim">The world's first in-browser world model</div> | |
| <div class="bar"><i id="bar"></i></div> | |
| <div class="status" id="bootStatus">initializing…</div> | |
| <button class="ignite" id="ignite">▶ Ignition</button> | |
| </div> | |
| </div> | |
| <div class="telem"> | |
| <div class="cell"><div class="l">Framerate</div><div class="v hot" id="tFps">— <small>fps</small></div></div> | |
| <div class="cell"><div class="l">Frame time</div><div class="v" id="tMs">— <small>ms</small></div></div> | |
| <div class="cell"><div class="l">Compute</div><div class="v cool" id="tDev">—</div></div> | |
| <div class="cell"><div class="l">Inputs</div><div class="v" id="tAct">—</div></div> | |
| </div> | |
| </div> | |
| <div class="controls"> | |
| <div class="keys" id="keys"> | |
| <span class="kc" data-k="ArrowUp">↑<small>accel</small></span> | |
| <span class="kc" data-k="ArrowLeft">←<small>left</small></span> | |
| <span class="kc" data-k="ArrowDown">↓<small>brake</small></span> | |
| <span class="kc" data-k="ArrowRight">→<small>right</small></span> | |
| <span class="kc" data-k="KeyD">D<small>drift</small></span> | |
| </div> | |
| <div class="btns"> | |
| <button class="btn" id="respawn">⟲ Respawn</button> | |
| <button class="btn ghost" id="pause">Ⅱ Pause</button> | |
| </div> | |
| </div> | |
| </div> | |
| <script src="https://cdn.jsdelivr.net/npm/onnxruntime-web@1.20.1/dist/ort.webgpu.min.js"></script> | |
| <script> | |
| const $=id=>document.getElementById(id); | |
| const bar=$("bar"), bootStatus=$("bootStatus"), boot=$("boot"), bootBig=$("bootBig"), ignite=$("ignite"); | |
| let META, SEEDS, dit, vae, ctx=[], acts=[], running=false, DEV="—"; | |
| let N, ROW, K; | |
| const key={ArrowUp:0,ArrowDown:0,ArrowLeft:0,ArrowRight:0,KeyD:0}; | |
| function setStatus(t){bootStatus.textContent=t} | |
| function setBar(p){bar.style.width=(p*100).toFixed(0)+"%"} | |
| async function fetchProgress(url, label){ | |
| const res=await fetch(url); | |
| const total=+res.headers.get("content-length")||0; | |
| const reader=res.body.getReader(); let recd=0; const chunks=[]; | |
| while(true){const{done,value}=await reader.read(); if(done)break; chunks.push(value); recd+=value.length; | |
| if(total) setStatus(label+" "+(recd/1e6|0)+" / "+(total/1e6|0)+" MB"); } | |
| const buf=new Uint8Array(recd); let o=0; for(const c of chunks){buf.set(c,o); o+=c.length;} | |
| return buf; | |
| } | |
| // Box–Muller gaussian noise | |
| function randn(n){const a=new Float32Array(n); for(let i=0;i<n;i+=2){ | |
| let u=0,v=0; while(u===0)u=Math.random(); while(v===0)v=Math.random(); | |
| const m=Math.sqrt(-2*Math.log(u)); a[i]=m*Math.cos(2*Math.PI*v); if(i+1<n)a[i+1]=m*Math.sin(2*Math.PI*v);} return a;} | |
| async function boot_(){ | |
| try{ | |
| setStatus("loading manifest…"); | |
| META=await (await fetch("meta.json")).json(); | |
| N=META.z_ch*META.hz*META.wz; ROW=META.action_dim; K=META.k; | |
| setStatus("loading seed states…"); | |
| const sb=await fetchProgress("seeds.bin","seed states"); | |
| SEEDS=new Float32Array(sb.buffer); | |
| const hasGPU = !!navigator.gpu; | |
| DEV = hasGPU ? "WebGPU" : "WASM"; | |
| ort.env.wasm.wasmPaths="https://cdn.jsdelivr.net/npm/onnxruntime-web@1.20.1/dist/"; | |
| if(!hasGPU) ort.env.wasm.numThreads = Math.min(4, navigator.hardwareConcurrency||4); | |
| const eps = hasGPU ? ["webgpu","wasm"] : ["wasm"]; | |
| setBar(.05); | |
| setStatus("downloading dynamics model…"); | |
| const ditBuf=await fetchProgress("genframe_fp16.onnx","dynamics"); setBar(.7); | |
| setStatus("compiling dynamics on "+DEV+"…"); | |
| dit=await ort.InferenceSession.create(ditBuf,{executionProviders:eps, graphOptimizationLevel:"all"}); setBar(.85); | |
| setStatus("downloading decoder…"); | |
| const vaeBuf=await fetchProgress("vae.onnx","decoder"); | |
| vae=await ort.InferenceSession.create(vaeBuf,{executionProviders:eps, graphOptimizationLevel:"all"}); setBar(1); | |
| $("tDev").textContent=DEV; | |
| spawn((Math.random()*META.seeds_shape[0])|0); | |
| await warm(); | |
| bootBig.textContent = hasGPU ? "NEURAL ENGINE READY" : "READY (CPU — will be slow)"; | |
| if(!hasGPU) bootBig.classList.add("warn"); | |
| setStatus("arrow keys to drive · D drift"); | |
| ignite.style.display="inline-block"; | |
| }catch(e){ | |
| bootBig.textContent="INITIALIZATION FAILED"; bootBig.classList.add("warn"); | |
| setStatus(String(e).slice(0,140)); | |
| console.error(e); | |
| } | |
| } | |
| function spawn(i){ | |
| const per=META.ctx*N; const base=i*per; | |
| ctx=[]; acts=[]; | |
| for(let f=0;f<META.ctx;f++){ ctx.push(SEEDS.subarray(base+f*N, base+(f+1)*N).slice()); acts.push(new Float32Array(ROW)); } | |
| } | |
| function curAction(){ | |
| // [accel, brake, left, right, nitro, drift] | |
| return Float32Array.from([key.ArrowUp,key.ArrowDown,key.ArrowLeft,key.ArrowRight,0,key.KeyD]); | |
| } | |
| async function genFrame(act){ | |
| // single graph does prefill(7 ctx frames) once + k decode steps internally (KV-cache) | |
| const czbuf=new Float32Array(7*N); | |
| for(let f=0;f<7;f++) czbuf.set(ctx[f], f*N); | |
| const cabuf=new Float32Array(7*ROW); | |
| for(let f=0;f<7;f++) cabuf.set(acts[f], f*ROW); | |
| const out=await dit.run({ | |
| ctx_z:new ort.Tensor("float32",czbuf,[1,7,META.z_ch,META.hz,META.wz]), | |
| ctx_a:new ort.Tensor("float32",cabuf,[1,7,ROW]), | |
| cur_a:new ort.Tensor("float32",act,[1,ROW]), | |
| noise:new ort.Tensor("float32",randn(N),[1,META.z_ch,META.hz,META.wz]) | |
| }); | |
| return out.cur.data; | |
| } | |
| const oc=$("screen").getContext("2d"); const IMG=oc.createImageData(384,192); | |
| async function decode(lat){ | |
| const zT=new ort.Tensor("float32",lat,[1,META.z_ch,META.hz,META.wz]); | |
| const out=await vae.run({zin:zT}); const p=out.img.data; // [1,3,192,384] CHW | |
| const HW=192*384, d=IMG.data; | |
| for(let i=0;i<HW;i++){ | |
| let r=p[i], g=p[HW+i], b=p[2*HW+i]; | |
| r=r>=0&&r<=1?r:(r<0?0:(r>1?1:0)); g=g>=0&&g<=1?g:(g<0?0:(g>1?1:0)); b=b>=0&&b<=1?b:(b<0?0:(b>1?1:0)); | |
| d[i*4]=r*255; d[i*4+1]=g*255; d[i*4+2]=b*255; d[i*4+3]=255; | |
| } | |
| oc.putImageData(IMG,0,0); | |
| } | |
| async function warm(){ const c=await genFrame(new Float32Array(ROW)); await decode(c); } | |
| let ema=0; | |
| async function loop(){ | |
| if(!running) return; | |
| const t0=performance.now(); | |
| const act=curAction(); | |
| const cur=await genFrame(act); | |
| ctx.push(cur); if(ctx.length>7)ctx.shift(); | |
| acts.push(act); if(acts.length>7)acts.shift(); | |
| await decode(cur); | |
| const dt=performance.now()-t0; ema=ema?ema*.85+dt*.15:dt; | |
| $("tMs").innerHTML=(ema|0)+" <small>ms</small>"; | |
| $("tFps").innerHTML=(1000/ema).toFixed(1)+" <small>fps</small>"; | |
| const names=["ACCEL","BRAKE","LEFT","RIGHT","NITRO","DRIFT"]; | |
| const on=[...act].map((v,i)=>v?names[i]:null).filter(Boolean); | |
| $("tAct").textContent=on.length?on.join(" · "):"—"; | |
| requestAnimationFrame(loop); | |
| } | |
| function start(){ if(running)return; running=true; boot.classList.add("hide"); loop(); } | |
| // keyboard | |
| const codes=Object.keys(key); | |
| addEventListener("keydown",e=>{ if(codes.includes(e.code)){key[e.code]=1; paint(); if(["ArrowUp","ArrowDown","ArrowLeft","ArrowRight"].includes(e.code))e.preventDefault();}}); | |
| addEventListener("keyup",e=>{ if(codes.includes(e.code)){key[e.code]=0; paint();}}); | |
| function paint(){ document.querySelectorAll(".kc").forEach(el=>el.classList.toggle("on", !!key[el.dataset.k])); } | |
| // pointer support for the on-screen keycaps | |
| document.querySelectorAll(".kc").forEach(el=>{ | |
| const k=el.dataset.k, dn=e=>{e.preventDefault();key[k]=1;paint()}, up=e=>{e.preventDefault();key[k]=0;paint()}; | |
| el.addEventListener("pointerdown",dn); el.addEventListener("pointerup",up); el.addEventListener("pointerleave",up); | |
| }); | |
| $("ignite").onclick=start; | |
| $("respawn").onclick=()=>{ spawn((Math.random()*META.seeds_shape[0])|0); if(!running){decode(ctx[6]);} }; | |
| $("pause").onclick=()=>{ running=!running; $("pause").textContent=running?"Ⅱ Pause":"▶ Resume"; if(running)loop(); }; | |
| boot_(); | |
| </script> | |
| </body> | |
| </html> | |