code wiki / _hdl_build / nx_wasm_physlab_html.nx
nx_wasm_physlab_html.nx source
↩ module page · 27 lines · 4247 B
1// nx_wasm_physlab_html.nx -- SOVEREIGN packager for PHYSLAB (the visible phys3d+softjiggle surface). Emits a
2// self-contained .html whose JS is LOGIC-FREE (operator law): the wasm owns physics/jiggle/render; the page
3// only passes raw mouse state (canvas-scaled coords + button bits) and blits the framebuffer per rAF.
4// usage: nx_wasm_physlab_html <in.wasm> <out.html>. license_tier: ORIGINAL
5import "nx_syscalls.nx"
6import "nx_base64.nx"
7
8func hw(fd: i64, s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(fd, s, n); return 0 }
9
10func main(argc: i64, argv: *i64) -> i64 {
11 if argc < 3 { hw(2, "usage: nx_wasm_physlab_html <in.wasm> <out.html>\n" as *u8); return 2 }
12 let wlen_p: *i64 = sys_mmap(8) as *i64
13 let wbytes: *u8 = sys_read_file(argv[1] as *u8, wlen_p)
14 if (wbytes as i64) == 0 { hw(2, "read wasm failed\n" as *u8); return 3 }
15 let wlen: i64 = wlen_p[0]
16 let b64: *u8 = sys_mmap(wlen * 2 + 64) as *u8
17 let b64len: i64 = b64_encode(wbytes, wlen, b64)
18 let fd: i64 = sys_openat_wr(argv[2] as *u8, 0x1a4)
19 if fd < 0 { hw(2, "open html failed\n" as *u8); return 4 }
20 hw(fd, "<!doctype html><html><head><meta charset='utf-8'><title>Nishi PhysLab -- the sovereign physics core, live</title><style>html,body{background:#000;margin:0;height:100%;overflow:hidden;font-family:sans-serif;color:#cdd}#wrap{display:flex;align-items:center;justify-content:center;height:100vh;width:100vw}canvas{image-rendering:pixelated;width:100vw;height:100vh;object-fit:contain;background:#20242e;cursor:crosshair}#hud{position:fixed;top:10px;left:0;right:0;text-align:center;font-size:13px;color:#aef;text-shadow:0 1px 2px #000;pointer-events:none}</style></head><body><div id='wrap'><canvas id='c'></canvas></div><div id='hud'>move mouse = swing the jiggle chain (it collides with the pillar) · CLICK = drop a crate · R = reset · G = fullscreen — rigid bodies STACK and SLEEP (dimmed), spheres BOUNCE; the ENTIRE sim is sovereign wasm (nx_phys3d + nx_softjiggle), zero JS logic, deterministic</div><script>\n" as *u8)
21 hw(fd, "const B='" as *u8)
22 sys_write(fd, b64, b64len)
23 hw(fd, "';\nconst hud=document.getElementById('hud');function diag(m){hud.textContent=m;}window.onerror=(m,s,l)=>{diag('JS ERROR: '+m+' @line '+l);};\nconst bytes=Uint8Array.from(atob(B),c=>c.charCodeAt(0));\nWebAssembly.instantiate(bytes).then(r=>{const ex=r.instance.exports;const W=Number(ex.ww()),H=Number(ex.hh()),off=Number(ex.fb_off());const cv=document.getElementById('c');cv.width=W;cv.height=H;const ctx=cv.getContext('2d');const img=ctx.createImageData(W,H);const mem=new Uint8Array(ex.memory.buffer);ex.start();let mx=160,my=60,btn=0,frames=0;const t0=performance.now();function pos(e){const r=cv.getBoundingClientRect();mx=Math.max(0,Math.min(W-1,Math.round((e.clientX-r.left)*W/r.width)));my=Math.max(0,Math.min(H-1,Math.round((e.clientY-r.top)*H/r.height)));}addEventListener('mousemove',pos);cv.addEventListener('mousedown',e=>{e.preventDefault();pos(e);btn|=1;});addEventListener('mouseup',()=>{btn&=~1;});cv.addEventListener('contextmenu',e=>e.preventDefault());addEventListener('keydown',e=>{if(e.code=='KeyR')btn|=2;if(e.code=='KeyG'){if(document.fullscreenElement)document.exitFullscreen();else document.documentElement.requestFullscreen();}});addEventListener('keyup',e=>{if(e.code=='KeyR')btn&=~2;});function frame(){try{ex.tick(BigInt(mx),BigInt(my),BigInt(btn));ex.render();for(let i=0;i<W*H;i++){const b=off+i*8;img.data[i*4]=mem[b];img.data[i*4+1]=mem[b+1];img.data[i*4+2]=mem[b+2];img.data[i*4+3]=255;}ctx.putImageData(img,0,0);frames++;if(frames===1){diag('PHYSLAB ok -- move the mouse: the chain jiggles; click: drop crates; watch them stack then DIM (sleep). bodies='+Number(ex.body_count()));}if(frames%240===0){diag('PHYSLAB '+Math.round(frames*1000/(performance.now()-t0))+' fps - bodies '+Number(ex.body_count())+' asleep '+Number(ex.asleep_count())+' - click drops a crate, R resets');}}catch(e){diag('SIM ERROR: '+e);return;}requestAnimationFrame(frame);}frame();}).catch(e=>{diag('WASM LOAD ERROR: '+e);});\n</script></body></html>\n" as *u8)
24 sys_close(fd)
25 hw(1, "nx_wasm_physlab_html: wrote html (logic-free JS)\n" as *u8)
26 return 0
27}