nx_game_page_workbench_candidate_t342.nx source
↩ module page · 2160 lines · 262144 B
1// nx_game_page_emit.nx -- the SOVEREIGN game-page emitter. Until now the browser page for a wasm
2// game was assembled by printf blocks in _ops/nx_emit_game.sh -- real emission logic living in
3// SHELL, against the doctrine (shell only LAUNCHES sovereign ELFs). This organ owns it: reads the
4// .wasm, base64-encodes it (composes nx_base64 -- one encoder, not a coreutils dependency), and
5// emits the complete self-contained page (marker, shim, input forwarding, persistence bytes-mover).
6// usage: nx_game_page_emit <wasm> <out.html> <title> <native-client-name> <controls-html>
7//
8// RECOVERED 2026-08-02 from buildroot/_build/nx_craft_emit.s (the 14:07 build's data section)
9// after a failed in-place rewrite TRUNCATED this file to 0 bytes and the damage was copied to
10// both trees. Every emitted chunk below is the exact byte sequence that build shipped, so the
11// recovered emitter is byte-equivalent to the last one that passed both gates.
12// license_tier: ORIGINAL
13import "nx_syscalls.nx"
14import "nx_character_prepared_runtime.nx"
15import "nx_cast_shader_src.nx"
16import "nx_imported_body_page_t262.nx"
17import "nx_prepared_motion.nx"
18import "nx_base64.nx"
19import "nx_game_page_artifact_lib.nx"
20import "nx_game_shader_backend_selected_t55.nx"
21import "nx_game_asset_prepare_emit.nx"
22import "nx_game_rig_inspection_emit_t230.nx"
23import "nx_game_texture_mip_emit_t241.nx"
24import "nx_game_surface_prepare.nx"
25import "nx_game_normal_encoding_emit.nx"
26import "nx_json.nx"
27import "nx_utf8.nx"
28import "nx_gpu_choice_workspace_t48.nx"
29import "nx_site_chrome_search_t53.nx"
30// the ONE ruler for "does this module's framebuffer fit the memory it declares". This emitter used to
31// own that arithmetic; it now composes it, so the 16 shipped pages that never reach gpe_build_s can be
32// held to the same bound by the same code rather than by a second copy of it.
33import "nx_wasmfit.nx"
34import "nx_hairdyn_lib.nx"
35import "nx_audio_osc.nx"
36import "nx_atmosphere.nx"
37import "nx_glprobe_lib.nx"
38import "nx_tool_run.nx" // GP2 rk_webgpu_door: the kernel WGSL is CAPTURED from ./nx_wgsl.elf at emit time, never hand-written here
39import "nx_genp_allow_lib.nx" // THE ONE gen-time recipe allowlist (2026-09-04): the NXGP count and write passes compose it -- the engine and nx_world_snap read the same ruler
40import "nx_release_view_emit.nx"
41import "nx_release_recent_lib.nx" // GE52 gpe_release_block: the release delta (accept- + referee- planes, board land rows) rendered at every emit; pure, gated by nx_release_delta_gate
42import "nx_tier_ladder_lib.nx" // GP3/GE45 rk_tier_ladder: the render-door ladder is DATA (knowledge/tier_ladder.conf) -- emitted as window.__nx_ladder + nxDoorReport, walked natively by tl_pick, pinned by nx_tier_ladder_gate
43// GP3 / GE45 WATCH SYMBOL: the render-door ladder reaches every world page through this ONE door. It composes
44// tl_emit() (knowledge/tier_ladder.conf -> window.__nx_ladder + nxDoorId/nxDoor/nxDoorReport) and nothing else,
45// so the board's rk_tier_ladder cell flips on the same bytes nx_tier_ladder_gate pins.
46func rk_tier_ladder() -> *u8 { return tl_emit() }
47
48// ---- GE30 THE THREADED BOOT --------------------------------------------------------------------
49// A caller DECLARES a threaded twin by setting gpe_mt_pages/gpe_mt_max before calling the builder;
50// nx_craft_emit does it after its stage 3c has actually built and deployed one. ZERO means no
51// threading code is emitted at all and the page is byte-identical to the single-thread page it has
52// always been, so every other caller of this emitter is untouched BY CONSTRUCTION rather than by
53// review. The numbers are not the page's to invent: they must equal the twin's declared memory
54// import exactly or instantiation fails, so they travel from the organ that derived them.
55static gpe_mt_pages: i64
56static gpe_mt_max: i64
57static gpe_mt_sha: *u8
58static gpe_mt_url: *u8
59static gpe_mt_bytes: i64
60
61// The Worker body, as a STRING the page turns into a blob URL. It is deliberately tiny: it holds no
62// game logic, only instantiate-and-render-a-band, because the JS/HTML-interop law is that values
63// cross the boundary and logic does not. Every rule it obeys lives in the wasm both sides share.
64const GPE_MT_WSRC: *u8 = "const NXMT_WSRC=\"let ex=null;onmessage=async(e)=>{const d=e.data;try{if(d.t==='init'){const i=await WebAssembly.instantiate(d.mod,{env:{memory:d.mem}});ex=i.exports;postMessage({t:'ready'});}else if(d.t==='band'){ex.render_band(BigInt(d.y0),BigInt(d.y1),BigInt(d.wid));postMessage({t:'band'});}}catch(err){postMessage({t:'err',m:String(err)});}};\";\n"
65
66const GPE_WASM_CAP: i64 = 4194304
67// One declaration owns the shared identity tuple for all generator entry points.
68func gpe_mt_declare(twin:*u8,bytes:i64,url:*u8,pages:i64,maximum:i64)->i64 {
69 gpe_mt_pages=0;gpe_mt_max=0;gpe_mt_sha=0 as *u8;gpe_mt_url=0 as *u8;gpe_mt_bytes=0
70 if (twin as i64)<=0 || bytes<GPA_HEADER_BYTES || bytes>GPE_WASM_CAP {return 0}
71 if pages<1 || maximum<pages || maximum>65536 {return 0}
72 let digest:*u8=sys_mmap(GPA_SHA_HEX+1)
73 if (digest as i64)<=0 {return 0}
74 gpa_sha(twin,bytes,digest)
75 var selected:*u8=url
76 if (selected as i64)==0 {
77 let prefix:*u8="/releases/craft-mt-" as *u8;let suffix:*u8=".wasm" as *u8
78 selected=sys_mmap(gpe_slen(prefix)+GPA_SHA_HEX+gpe_slen(suffix)+1)
79 if (selected as i64)<=0 {return 0}
80 var p:i64=gpe_ap(selected,0,prefix);p=gpe_ap(selected,p,digest);p=gpe_ap(selected,p,suffix);selected[p]=0 as u8
81 }
82 let n:i64=gpe_slen(selected)
83 if n==0 {return 0}
84 var i:i64=0
85 while i<n {
86 let c:i64=selected[i] as i64
87 if c<33||c>126||c==34||c==39||c==92||c==60||c==62||c==96 {return 0}
88 i=i+1
89 }
90 gpe_mt_pages=pages;gpe_mt_max=maximum;gpe_mt_sha=digest;gpe_mt_url=selected;gpe_mt_bytes=bytes
91 return 1
92}
93
94func gpe_mt_boot(out: *u8, p0: i64) -> i64 {
95 var p: i64 = p0
96 p = gpe_ap(out, p, "// Shared by threaded and unthreaded doors; emit even when no twin exists.\nlet nxResidentStageHolds=0;\nlet nxResidentFailedWorkerEngine=null;\n// This owner is ONLY the resident cast loader. Independent visitor slots must\n// use separate owner objects and separate native banks before sharing this helper.\nconst nxResidentOwner={epoch:0};\nfunction nxResidentToken(owner=nxResidentOwner){return {owner,epoch:++owner.epoch,engine:ex};}\nfunction nxResidentCurrent(token){return token.epoch===token.owner.epoch&&token.engine===ex;}\nasync function nxResidentStage(token,operation){\n if(!nxResidentCurrent(token))throw Error('resident-stage-stale-asset');\n if(nxResidentFailedWorkerEngine===token.engine)throw Error('resident-stage-worker-failed-unjoined');\n nxResidentStageHolds++;\n try{\n const workerOwner=NXMT;\n if(workerOwner&&workerOwner.busy){\n if(!workerOwner.pending)throw Error('resident-stage-worker-join-unavailable');\n await workerOwner.pending;\n }\n if(!nxResidentCurrent(token))throw Error('resident-stage-stale-asset');\n if(nxResidentFailedWorkerEngine===token.engine)throw Error('resident-stage-worker-failed-unjoined');\n if(workerOwner&&NXMT!==workerOwner)throw Error('resident-stage-worker-owner-lost');\n // operation is internal and synchronous: stage/admit/grow/reacquire/bind.\n // No texture decode, network await or user callback belongs in this section.\n const result=operation();\n if(result&&typeof result.then==='function'){\n // Misuse cannot release the shared region while async work still runs.\n // Wait for settlement, then refuse; this does not roll back its side effects.\n let failure;\n try{await result;}catch(error){failure=error;}\n const refusal=Error('resident-stage-async-operation');refusal.cause=failure;throw refusal;\n }\n return result;\n }finally{nxResidentStageHolds--;}\n}\nfunction nxResidentBind(token,bytes,hasMorf,clipCode){\n const result={state:'unavailable',token:token.epoch,clipCode:clipCode};\n if(clipCode!==0){result.reason='clip-not-admitted';return result;}\n if(!hasMorf){result.state='absent';return result;}\n const engine=token.engine;\n for(const name of ['morf_stage_off','morf_stage_cap','morf_pages','morf_bind','morf_current']){\n if(typeof engine[name]!=='function'){result.reason='missing-export:'+name;return result;}\n }\n try{\n const offset=Number(engine.morf_stage_off()),capacity=Number(engine.morf_stage_cap());\n if(!Number.isSafeInteger(offset)||offset<0||!Number.isSafeInteger(capacity)||capacity<bytes.byteLength||offset>engine.memory.buffer.byteLength-bytes.byteLength)throw Error('resident-stage-capacity');\n new Uint8Array(engine.memory.buffer,offset,bytes.byteLength).set(bytes);\n const pages=Number(engine.morf_pages(BigInt(bytes.byteLength)));\n if(!Number.isSafeInteger(pages)||pages<=0)throw Error('resident-admit:'+pages);\n const before=engine.memory.buffer.byteLength/65536;\n if(pages>before)engine.memory.grow(pages-before);\n const code=Number(engine.morf_bind(BigInt(bytes.byteLength),BigInt(engine.memory.buffer.byteLength),BigInt(token.epoch)));\n if(code!==0)throw Error('resident-bind:'+code);\n result.state='admitted';result.pages=engine.memory.buffer.byteLength/65536;result.grew=result.pages-before;\n }catch(error){result.state='refused';result.reason=String(error);}\n return result;\n}\n" as *u8)
97 if gpe_mt_pages < 1 {
98 // NAMED ABSENCE, never a silent one: a page with no twin still publishes why, so a probe
99 // reading window.__nx_mt cannot confuse "this build has no twin" with "threading failed".
100 p = gpe_ap(out, p, "let NXMT=null;\nwindow.__nx_mt={n:1,shared:false,why:\"no-twin-built\"};\n" as *u8)
101 return p
102 }
103 p = gpe_ap(out, p, GPE_MT_WSRC)
104 if (gpe_mt_sha as i64)==0 || (gpe_mt_url as i64)==0 || gpe_mt_bytes<=0 {
105 gpe_puts("SHARED-IDENTITY refused: declared twin lacks artifact identity\n" as *u8)
106 return gpe_ap(out,p,"let NXMT=null;throw Error('shared-identity: missing declared artifact');\n" as *u8)
107 }
108 p=gpe_ap(out,p,"let NXMT=null;\nconst NXMT_URL=\"" as *u8)
109 p=gpe_ap(out,p,gpe_mt_url)
110 p=gpe_ap(out,p,"\";\nconst NXMT_SHA256=\"" as *u8)
111 p=gpe_ap(out,p,gpe_mt_sha)
112 p=gpe_ap(out,p,"\";\nconst NXMT_BYTES=" as *u8)
113 p=gpe_num(out,p,gpe_mt_bytes)
114 p=gpe_ap(out,p,";\nconst NXMT_PAGES=" as *u8)
115 p = gpe_num(out, p, gpe_mt_pages)
116 p = gpe_ap(out, p, ";\nconst NXMT_MAX=" as *u8)
117 p = gpe_num(out, p, gpe_mt_max)
118 // ★EVERY WORKER IS INSTANTIATED BEFORE THE FIRST init(). Each instantiation rewrites the module's
119 // data segments into the SHARED memory, so a Worker created mid-session would clobber live state.
120 // ★AND THE MAIN THREAD SWITCHES TO THE TWIN TOO. The inlined build owns a PRIVATE memory; if only
121 // the Workers held the twin, the bands would land in the shared memory while render_overlay,
122 // fb_digest and the blit all read the private one -- an empty frame with every check passing.
123 p = gpe_ap(out, p, ";\nif(self.crossOriginIsolated===true&&typeof SharedArrayBuffer!==\"undefined\"&&nxThreads()>1){\nconst _ws=[];let _wu=null;\ntry{\nconst _n=nxThreads();\nconst _rs=await fetch(NXMT_URL);\nif(_rs.ok!==true)throw new Error(\"twin-http-\"+_rs.status);\nconst _bf=await _rs.arrayBuffer();\nif(_bf.byteLength!==NXMT_BYTES)throw Error(\"twin-size-mismatch\");\nconst _digest=new Uint8Array(await crypto.subtle.digest(\"SHA-256\",_bf));\nconst _sha=Array.from(_digest,b=>b.toString(16).padStart(2,\"0\")).join(\"\");\nif(_sha!==NXMT_SHA256)throw Error(\"twin-sha256-mismatch\");\nconst _mm=new WebAssembly.Memory({initial:NXMT_PAGES,maximum:NXMT_MAX,shared:true});\nif((_mm.buffer instanceof SharedArrayBuffer)!==true)throw new Error(\"memory-not-shared\");\nconst _md=await WebAssembly.compile(_bf);\nconst _in=await WebAssembly.instantiate(_md,{env:{memory:_mm}});\nlet _dataInit=\"legacy-active\";\nif(typeof _in.exports._nx_data_init===\"function\"){const _state=_in.exports._nx_data_init();if(_state!==2n)throw new Error(\"shared-data-not-ready-state-\"+String(_state));_dataInit=\"owned-ready\";}\n_wu=URL.createObjectURL(new Blob([NXMT_WSRC],{type:\"text/javascript\"}));\nfor(let _i=0;_i<_n;_i++)_ws.push(new Worker(_wu));\nawait Promise.all(_ws.map((w,i)=>new Promise((res,rej)=>{w.onmessage=e=>{if(e.data&&e.data.t===\"ready\")res();else rej(new Error(\"worker-init-\"+i));};w.onerror=rej;w.postMessage({t:\"init\",mod:_md,mem:_mm,wid:i});})));\nex=_in.exports;\nnxIdentitySelect(_bf,\"shared\");\nNXMT={n:_n,ws:_ws,rows:0,busy:false};\nwindow.__nx_mt={n:_n,shared:true,pages:NXMT_PAGES,url:NXMT_URL,expectedSha256:NXMT_SHA256,actualSha256:_sha,bytes:_bf.byteLength,identity:\"verified\",dataInitialization:_dataInit};\n}catch(_e){nxMtStop(_ws);NXMT=null;window.__nx_mt={n:1,shared:false,why:\"threaded-boot-failed: \"+String(_e)};}finally{if(_wu!==null)URL.revokeObjectURL(_wu);}\n}else{window.__nx_mt={n:1,shared:false,why:nxThreadsWhy()};}\n" as *u8)
124 // The banded draw. A Worker join is ASYNCHRONOUS and the frame loop is synchronous, so the frame
125 // completes out of band and a busy flag drops frames rather than queueing them -- rAF will call
126 // again. render_overlay runs ONCE on the main thread after the join, because the mobs, the depth
127 // strip and the HUD are whole-frame passes that no band owns. Any worker failure demotes the page
128 // to one thread PERMANENTLY and says so: a threading fault must never cost a visitor the world.
129 p = gpe_ap(out, p, "function nxMtStop(ws){\nfor(const w of ws){w.onmessage=null;w.onerror=null;w.terminate();}\nws.length=0;\n}\nfunction nxMtDraw(_t0){\nconst owner=NXMT;if(owner===null||owner.busy||nxResidentStageHolds>0)return;\nconst engine=ex;\nowner.busy=true;\nif(owner.rows<1)owner.rows=Number(ex.render_rows());\nconst h=owner.rows,n=owner.n,per=Math.ceil(h/n),js=[];\nfor(let i=0;i<n;i++){const y0=i*per,y1=Math.min(h,(i+1)*per);if(y1<=y0)continue;\njs.push(new Promise((res,rej)=>{const w=owner.ws[i];w.onmessage=e=>{if(e.data&&e.data.t===\"band\")res();else rej(new Error(\"band\"));};w.onerror=rej;w.postMessage({t:\"band\",y0:y0,y1:y1,wid:i});}));}\nowner.pending=Promise.all(js).then(()=>{if(NXMT!==owner)return;if(!nxDemand.active){owner.busy=false;return;}ex.render_overlay();blit();if(ex.frame_ms)ex.frame_ms(BigInt(Math.round(performance.now()-_t0)));owner.busy=false;}).catch(()=>{nxResidentFailedWorkerEngine=engine;nxMtStop(owner.ws);if(NXMT!==owner)return;NXMT=null;window.__nx_mt={n:1,shared:false,why:\"worker-failed-demoted\"};});\n}\n" as *u8)
130 return p
131}
132
133// this file is a buffer builder and had no stdout path of its own; the fit guard needs one, because
134// a refusal that does not say WHICH number was wrong just moves the investigation somewhere else.
135func gpe_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
136func gpe_pn(v: i64) -> i64 {
137 var m: i64 = v
138 if m < 0 { gpe_puts("-" as *u8); m = 0 - m }
139 let t: *u8 = sys_mmap(24)
140 var k: i64 = 0
141 if m == 0 { t[0] = 48 as u8; k = 1 }
142 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
143 let o: *u8 = sys_mmap(24)
144 var i: i64 = 0
145 while i < k { o[i] = t[k-1-i]; i = i + 1 }
146 sys_write(1, o, k)
147 return 0
148}
149const GPE_MAGIC_20260728: i64 = 20260728
150
151// THE SOVEREIGN-RENDER SWITCH. 1 = the page ALSO carries the WebGL interop path; 0 = the emitted page
152// contains no GLSL and no WebGL setup at all and the NishiLang wasm rasteriser draws every pixel.
153//
154// ★SET BACK TO 1 ON 2026-08-14, AND THE REASON IS A SEQUENCING ERROR I MADE, NOT A CHANGE OF GOAL.
155// The sovereignty destination is unchanged: this path leaves the moment the native one can replace it.
156// What I did wrong was DELETE THE INCUMBENT BEFORE BUILDING THE REPLACEMENT. The WebGL path is not
157// merely "a renderer" -- it is the ONLY code that draws the skinned NXA characters (dual-quaternion
158// skinning, eyeball geometry, per-genome skin/outfit/hair), and it shades the whole voxel world at
159// canvas resolution. Turning it off replaced all of that with a 480x300 CPU raycast and coloured
160// billboards, which is exactly the "significantly worse graphics" and "lost the female models" the
161// operator reported -- three times, because I kept shipping forward instead of restoring.
162//
163// ★THE LAW THIS ENCODES: A SOVEREIGN REPLACEMENT IS EARNED BY BEING BUILT, NOT BY DELETING THE THING
164// IT MEANS TO REPLACE. The sovereign rasteriser still ships in the same page and still runs whenever
165// WebGL is unavailable -- it is the FALLBACK, which is the honest status of a path that cannot yet
166// draw a character. It becomes the only path when nx_wasm_craft grows wc_mob_mesh (the contract is
167// already on the compare board as _ABSENT_:wc_mob_mesh); nx_sovworld_gate holds that contract.
168//
169// ⚠ADJUDICATED 2026-08-15: wc_mob_mesh NOW EXISTS (11-bone LBS figure, gate 63/63, per-pixel terrain
170// occlusion) and the sentence above FIRED -- but existence is a NAME-KEYED completion signal, and the
171// paragraph one screen up records what shipping on that signal cost three times. The two contracts
172// disagree, and the NEWER, LIVED one controls: the sovereign figure's measured quality is figure-crop
173// CHARJUDGE 0 (flat regions narrower than a judge cell) against the character corpus mean of 138, so
174// flipping today would again replace richer characters with poorer ones. THE PARITY BAR IS PRE-DECLARED
175// AND ALREADY PUBLISHED, not taste: this flips to 0 when nx_world_snap char's figure-crop CHARJUDGE for
176// the sovereign figure MEETS OR BEATS THE CORPUS MEAN on the /compare/charsim board (138 at declaration
177// time; read the live board, not this comment). Until then nx_sovworld_gate's T5 stays RED as the
178// standing work-order -- a red that names real remaining work is worth more than a green bought by a
179// regression. The ?gl=0 sovereign path ships in every page and is now one visible click away.
180//
181// ★CONTRACT MET 2026-08-16, MEASURED: nx_world_snap char figure-crop CHARJUDGE = 251 (composition 673,
182// contour 1000, palette 251) against the declared bar of 138 -- after per-triangle sun lambert (gate T64)
183// and the DECLARED portrait-distance calibration (derived: torso must span >= 2 judge cells; the
184// calibration was announced on the board BEFORE it moved, and the flat-vs-lit delta was completed at the
185// old distance first so no history was lost). The rule was pre-declared before the experiment; honoring
186// it now is the same discipline as refusing the premature flip yesterday. The sovereign path today is
187// 1200x750 adaptive with lit, genome-distinct, per-pixel-occluded skinned figures -- not the 480x300
188// billboards of the 08-14 regression this guard was written against. If the lived result disappoints,
189// this is ONE flip back and every number that justified it is on the board.
190// FLIPPED 1 on 2026-08-18 BY OPERATOR ORDER (the delivery ask: "leverage in 3rd party through last
191// mile shims and natively... deliver anything the system is capable of instead of these shitty
192// graphics"). The 08-16 sovereign-only refusal stands for the CHARSIM QUALITY LADDER -- quality is
193// still measured and beaten on the sovereign path (?gl=0, always compiled in, auto-fallback on any
194// GL failure) -- but DELIVERY now takes the GPU when the visitor's device has one.
195const GPE_EMIT_WEBGL: i64 = 1
196// Shared module cap is declared beside its first consumer.
197// ---- cloth-solver constants, hoisted 2026-08-28 to clear the rule-11 ratchet -------------------
198// NOT invented here: every name below is taken from the sentence the emitter already prints beside
199// the value, so the const says what the comment said and the digits never have to be read twice.
200// (981 stays inline: it is 9.81 m/s^2 x100 and sits under the ratchet's bar, so hoisting it would
201// add a name nobody needs while changing nothing the detector can see.)
202const GPE_ALPHA_BEND_SOFT_Q12: i64 = 40960 // the gate-proven XG_ALPHA_BEND_SOFT_Q12 compliance
203const GPE_UNITS_PER_178CM: i64 = 171530 // the page's own 1.78m-to-world-unit pairing
204const GPE_G_DEN_60HZ: i64 = 640800 // that pairing carried to a per-tick accel at 60Hz
205const GPE_OUT_CAP: i64 = 16777216
206
207func gpe_slen(s: *u8) -> i64 { var k: i64 = 0; while s[k] != (0 as u8) { k = k + 1 } return k }
208func gpe_ap(out: *u8, pos: i64, s: *u8) -> i64 {
209 var k: i64 = 0
210 var p: i64 = pos
211 while s[k] != (0 as u8) { out[p] = s[k]; p = p + 1; k = k + 1 }
212 return p
213}
214func gpe_ap_n(out: *u8, pos: i64, s: *u8, n: i64) -> i64 {
215 var k: i64 = 0
216 var p: i64 = pos
217 while k < n { out[p] = s[k]; p = p + 1; k = k + 1 }
218 return p
219}
220
221// ---- GP2 / GE44: THE WEBGPU DOOR, FIRST BYTE (2026-09-02, /compare/gpu GP2 and gameengine GE44) --------------
222// rk_webgpu_door emits (1) the GE43 compute kernel's WGSL, CAPTURED from the deployed shader backend at emit
223// time (`nx_wgsl compute`, the same bytes nx_wgsl_compute_gate pins) -- never a hand-written copy, which is
224// the duplication nx_shader_ir exists to delete -- and (2) nxKernelProbe(dev): under ?gpu=1&kernel=1 it
225// dispatches that kernel through the page's WebGPU device over two storage buffers seeded from the same
226// hashes on both sides, reads the depth buffer back and diffs it against the CPU reference (the u32 minimum
227// of the two lanes). WebGPU CARRIES our bytes and computes nothing of ours: that is the "pure submission
228// pipe" door the gameengine board declares. The result lands on the HUD telemetry line (kernel OK n= diff=
229// ms=) and in window.__nx_kernel. If the backend cannot be forked or its output carries no WGSL section the
230// door emits KWGSL=null and a NAMED telemetry state instead of an empty shader -- an absent kernel must read
231// as absent, never as a page that quietly skipped the proof. The workgroup width is READ from the WGSL text
232// at run time (workgroup_size), so the dispatch geometry has one owner: the backend.
233// Retained legacy fixed-buffer wrapper ABI; active page capture uses owned buffers.
234const RK_WGSL_CAP: i64 = 65536
235const RK_WGSL_TMO_MS: i64 = 8000
236const RK_WGSL_ELF: *u8 = "./nx_wgsl.elf"
237const RK_WGSL_ELF_ABS: *u8 = "/volume1/homes/elderwesto/nishihost/nx_wgsl.elf" // the emitter's CWD is not always the serving root
238const RK_WGSL_BEGIN: *u8 = "--- WGSL ---\n"
239const RK_WGSL_END: *u8 = "\nwgsl_bytes="
240const RK_KERNEL_N: i64 = 65536 // u32 lanes per probe (1024 workgroups at the backend's width of 64)
241func rk_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
242func rk_err(s: *u8) -> i64 { sys_write(2, s, rk_slen(s)); return 0 }
243func rk_num(out: *u8, pos: i64, v: i64) -> i64 {
244 var p: i64 = pos
245 var x: i64 = v
246 if x == 0 { out[p] = 48 as u8; return p + 1 }
247 let t: *u8 = sys_mmap(32)
248 var k: i64 = 0
249 while x > 0 { t[k] = (48 + (x % 10)) as u8; x = x / 10; k = k + 1 }
250 while k > 0 { k = k - 1; out[p] = t[k]; p = p + 1 }
251 sys_munmap(t, 32)
252 return p
253}
254func rk_find(buf: *u8, n: i64, from: i64, needle: *u8) -> i64 {
255 let nl: i64 = rk_slen(needle)
256 var i: i64 = from
257 while i + nl <= n {
258 var k: i64 = 0
259 var hit: i64 = 1
260 while k < nl { if buf[i + k] != needle[k] { hit = 0; k = nl } else { k = k + 1 } }
261 if hit == 1 { return i }
262 i = i + 1
263 }
264 return 0 - 1
265}
266// a JS double-quoted string literal from bytes: backslash, quote and newline escaped, CR dropped; nothing else occurs in WGSL
267func rk_js_str(out: *u8, pos: i64, src: *u8, n: i64) -> i64 {
268 var p: i64 = pos
269 out[p] = 34 as u8; p = p + 1
270 var i: i64 = 0
271 while i < n {
272 let c: i64 = src[i] as i64
273 if c == 10 { out[p] = 92 as u8; out[p + 1] = 110 as u8; p = p + 2 }
274 else { if c == 34 { out[p] = 92 as u8; out[p + 1] = 34 as u8; p = p + 2 }
275 else { if c == 92 { out[p] = 92 as u8; out[p + 1] = 92 as u8; p = p + 2 }
276 else { if c == 13 { p = p } else { out[p] = c as u8; p = p + 1 } } } }
277 i = i + 1
278 }
279 out[p] = 34 as u8; p = p + 1
280 return p
281}
282// fork the deployed shader backend; relative path first (CWD = serving root), the absolute serving-root path second
283func rk_capture_wgsl(buf: *u8, ol: *i64) -> i64 {
284 return gsb_capture("compute" as *u8,buf,RK_WGSL_CAP,ol,RK_WGSL_TMO_MS)
285}
286// R-F (2026-09-04): THE UNIFORM LAYOUT IS CAPTURED FROM THE BACKEND AT EMIT, NEVER HAND-COUNTED HERE. The page
287// packs struct U by float index; until today those indices (28 = pal, 76 = palf, 96 floats) were typed beside a
288// hand-written struct declaration -- two copies of one shape. `nx_wgsl layout` derives every offset from the
289// declared IR by the WGSL memory-layout rules (nx_wgsl_gate holds the packer's own numbers as its KAT), so the
290// page now carries NXUO (name -> float index) and NXU_SIZE from that capture, and the struct U declaration is the
291// backend's own emission (WGSL_U). An absent capture is NAMED: NXUO=null makes the WebGPU claim throw
292// uniform-layout-absent-at-emit, the door refuses by name and the ladder falls to webgl2 -- never a page that
293// quietly packs by stale indices.
294const RK_LAYOUT_BEGIN: *u8 = "struct U{"
295const RK_LAYOUT_END: *u8 = "var<uniform> u:U;\n"
296const RK_LAYOUT_SIZE_KEY: *u8 = "layoutraw_rc="
297const RK_LAYOUT_NAMES: i64 = 18
298const RK_FLOAT_BYTES: i64 = 4
299func rk_capture_layout(buf: *u8, ol: *i64) -> i64 {
300 return gsb_capture("layout" as *u8,buf,RK_WGSL_CAP,ol,RK_WGSL_TMO_MS)
301}
302// the decimal after `needle` in buf, or -1 when absent
303func rk_int_after(buf: *u8, n: i64, needle: *u8) -> i64 {
304 let at: i64 = rk_find(buf, n, 0, needle)
305 if at < 0 { return 0 - 1 }
306 var i: i64 = at + rk_slen(needle)
307 var v: i64 = 0
308 var any: i64 = 0
309 var more: i64 = 1
310 while more == 1 {
311 if i >= n { more = 0 } else {
312 let c: i64 = buf[i] as i64
313 if c < 48 { more = 0 } else { if c > 57 { more = 0 } else { v = v * 10 + (c - 48); any = 1; i = i + 1 } }
314 }
315 }
316 if any == 0 { return 0 - 1 }
317 return v
318}
319// the byte offset of uniform `name` from the captured rows (`uniform|<name>|offset=<n>|`), or -1
320func rk_uniform_offset(buf: *u8, n: i64, name: *u8) -> i64 {
321 let key: *u8 = sys_mmap(128)
322 var q: i64 = 0
323 let pre: *u8 = "uniform|"
324 var k: i64 = 0
325 while pre[k] != (0 as u8) { key[q] = pre[k]; q = q + 1; k = k + 1 }
326 k = 0
327 while name[k] != (0 as u8) { key[q] = name[k]; q = q + 1; k = k + 1 }
328 let post: *u8 = "|offset="
329 k = 0
330 while post[k] != (0 as u8) { key[q] = post[k]; q = q + 1; k = k + 1 }
331 key[q] = 0 as u8
332 return rk_int_after(buf, n, key)
333}
334// emits `const NXUO={<name>:<float index>,...};` for the world pass's uniforms; -1 when a name is missing
335// The world pass uniform block (GE55, 2026-09-05): NXU_SIZE alone, captured from `nx_wgsl layoutraw` -- 160 B, the
336// sim's own UR_* word table -- because the page packs NOTHING: the bridge writeBuffers the sim's block from wasm memory
337// at uniform_off() and the kernel (nx_world_shader_src upk) derives every float. NXUO and WGSL_U were retired with the
338// JS packer they served; the named-absent shape when the capture fails.
339func rk_uniform_block(out: *u8, pos: i64) -> i64 {
340 var p: i64 = pos
341 let owned:*NxBufOwned=rk_owned_new();if (owned as i64)<=0{return pos}
342 let captured:i64=gsb_capture_owned("layout",owned,RK_WGSL_TMO_MS,0)
343 let buf:*u8=owned.buf;var n:i64=owned.len;if captured!=0{n=0}
344 var b: i64 = 0 - 1
345 var e: i64 = 0 - 1
346 var sz: i64 = 0 - 1
347 if n > 0 {
348 b = rk_find(buf, n, 0, RK_LAYOUT_BEGIN)
349 if b >= 0 { e = rk_find(buf, n, b, RK_LAYOUT_END); if e >= 0 { e = e + rk_slen(RK_LAYOUT_END) } }
350 sz = rk_int_after(buf, n, RK_LAYOUT_SIZE_KEY)
351 }
352 var q: i64 = 0 - 1
353 if sz > 0 { q = p }
354 if q < 0 {
355 rk_err("[gpe] GE55 raw uniform block: ABSENT AT EMIT -- nx_wgsl.elf layout gave no layoutraw_rc; the page carries NXU_SIZE=0 and the WebGPU claim refuses by name\n" as *u8)
356 p = gpe_ap(out, p, "const NXU_SIZE=0;\n" as *u8)
357 rk_owned_close(owned);return p
358 }
359 p = q
360 p = gpe_ap(out, p, "const NXU_SIZE=" as *u8)
361 p = rk_num(out, p, sz)
362 p = gpe_ap(out, p, ";\n" as *u8)
363 rk_err("[gpe] GE55 raw uniform block captured from nx_wgsl layoutraw (160 B, the sim UR_* table): NXU_SIZE=" as *u8)
364 let nb: *u8 = sys_mmap(32)
365 let qn: i64 = rk_num(nb, 0, sz)
366 sys_write(2, nb, qn)
367 rk_err("\n" as *u8)
368 rk_owned_close(owned)
369 return p
370}
371// R-G3 (2026-09-04): THE WORLD SHADER IS CAPTURED FROM THE BACKEND AT EMIT. `nx_wgsl world` prints the fragment module
372// (uniforms, the voxel texture, struct Hit, every function, the entry) and the fullscreen-triangle vertex stage, both
373// emitted from ONE NishiLang source (nx_world_shader_src). The page carries them as WGSL_IRF / WGSL_IRV and draws them
374// under the ?ir=1 lever through two shader modules (both entries are `main`); the hand WGSL stays the default until
375// the parity instrument (R-H) proves the frames equal. An absent capture is NAMED (WGSL_IRF=null, the ?ir=1 claim
376// throws world-ir-absent-at-emit) -- never a page that silently drew the hand shader while claiming the IR.
377const RK_WORLD_FS_BEGIN: *u8 = "--- world_wgsl WGSL ---\n"
378const RK_WORLD_FS_END: *u8 = "\nworld_wgsl_rc="
379const RK_WORLD_VS_BEGIN: *u8 = "--- worldvs_wgsl WGSL ---\n"
380const RK_WORLD_VS_END: *u8 = "\nworldvs_wgsl_rc="
381func rk_capture_world(buf: *u8, ol: *i64) -> i64 {
382 return gsb_capture("world" as *u8,buf,RK_WGSL_CAP,ol,RK_WGSL_TMO_MS)
383}
384// the [begin,end) span of one probe's emitted text in buf, written to bo[0]/bo[1]; 0 when absent or refused (rc<0)
385func rk_world_span(buf: *u8, n: i64, begin: *u8, end: *u8, bo: *i64) -> i64 {
386 bo[0] = 0 - 1; bo[1] = 0 - 1
387 let b: i64 = rk_find(buf, n, 0, begin)
388 if b < 0 { return 0 }
389 let s: i64 = b + rk_slen(begin)
390 let e: i64 = rk_find(buf, n, s, end)
391 if e <= s { return 0 }
392 // a refused probe prints its label_rc=-1 right after the header: the span is then the refusal, not a shader
393 if rk_find(buf, e + 1, s, "_rc=-1" as *u8) >= 0 { return 0 }
394 bo[0] = s; bo[1] = e
395 return 1
396}
397func rk_world_block(out: *u8, pos: i64) -> i64 {
398 var p: i64 = pos
399 let owned:*NxBufOwned=rk_owned_new();if (owned as i64)<=0{return pos}
400 let captured:i64=gsb_capture_owned("world",owned,RK_WGSL_TMO_MS,0)
401 let buf:*u8=owned.buf;var n:i64=owned.len;if captured!=0{n=0}
402 let fo: *i64 = sys_mmap(16) as *i64
403 let vo: *i64 = sys_mmap(16) as *i64
404 var okf: i64 = 0
405 var okv: i64 = 0
406 if n > 0 { okf = rk_world_span(buf, n, RK_WORLD_FS_BEGIN, RK_WORLD_FS_END, fo); okv = rk_world_span(buf, n, RK_WORLD_VS_BEGIN, RK_WORLD_VS_END, vo) }
407 if okf == 0 { rk_err("[gpe] R-G3 world shader: FRAGMENT MODULE ABSENT AT EMIT -- nx_wgsl.elf world gave no world_wgsl section or refused it; the page carries WGSL_IRF=null and the ?ir=1 claim refuses by name\n" as *u8) }
408 if okv == 0 { rk_err("[gpe] R-G3 world shader: VERTEX ENTRY ABSENT AT EMIT -- nx_wgsl.elf world gave no worldvs_wgsl section; WGSL_IRV=null\n" as *u8) }
409 if okf == 0 { p = gpe_ap(out, p, "const WGSL_IRF=null;" as *u8) } else {
410 rk_err("[gpe] R-G3 world shader captured from nx_wgsl world: fragment_bytes=" as *u8)
411 let nb: *u8 = sys_mmap(32)
412 let q: i64 = rk_num(nb, 0, fo[1] - fo[0])
413 sys_write(2, nb, q)
414 rk_err("\n" as *u8)
415 p = gpe_ap(out, p, "const WGSL_IRF=`" as *u8)
416 var i: i64 = fo[0]
417 while i < fo[1] { out[p] = buf[i]; p = p + 1; i = i + 1 }
418 p = gpe_ap(out, p, "`;" as *u8)
419 }
420 if okv == 0 { p = gpe_ap(out, p, "const WGSL_IRV=null;\n" as *u8) } else {
421 p = gpe_ap(out, p, "const WGSL_IRV=`" as *u8)
422 var i2: i64 = vo[0]
423 while i2 < vo[1] { out[p] = buf[i2]; p = p + 1; i2 = i2 + 1 }
424 p = gpe_ap(out, p, "`;\n" as *u8)
425 }
426 let depth:i64=rk_int_after(buf,n,"world_fragment_depth=" as *u8)
427 if depth==1&&okf==1&&okv==1 {
428 p=gpe_ap(out,p,"const NX_WORLD_DEPTH=true;\n" as *u8)
429 }else{
430 p=gpe_ap(out,p,"const NX_WORLD_DEPTH=false;\n" as *u8)
431 if depth==1 {gsb_failed=1}
432 }
433 rk_owned_close(owned)
434 return p
435}
436// S12 step 1 (2026-09-06): the CAST shaders (nx_cast_shader_src through the same nx_wgsl backend, IDENTICAL to the hand GLSL
437// under nx_glsl_tokdiff) are captured at emit time exactly as the world's are, and the page COMPILES them at boot through mkm
438// (createShaderModule + getCompilationInfo) with the outcome announced on window.__nx_cast_wgsl -- so the GPU-host compile
439// that is the WGSL validity oracle runs on every load of the page, on the operator's own device, and any authorised frame
440// check reads it. Nothing is drawn yet: the cast pipeline + instanced draw is the rest of S12. An absent capture is NAMED
441// (WGSL_CASTV=null / WGSL_CASTF=null), never a page that silently claims a cast twin it does not carry.
442const RK_CAST_VS_BEGIN: *u8 = "--- cast_wgsl WGSL ---\n"
443const RK_CAST_VS_END: *u8 = "\ncast_wgsl_rc="
444const RK_CAST_FS_BEGIN: *u8 = "--- castfs_wgsl WGSL ---\n"
445const RK_CAST_FS_END: *u8 = "\ncastfs_wgsl_rc="
446static gpe_cast_path:*u8
447static gpe_cast_expected:*u8
448static gpe_cast_expected_bytes:i64
449func rk_capture_cast(buf: *u8, ol: *i64) -> i64 {
450 ol[0]=0
451 if gpe_cast_path==(0 as *u8)||gpe_cast_expected==(0 as *u8) {gsb_failed=1;return -1}
452 let rc:i64=gsb_capture_selected(gpe_cast_path,gpe_cast_expected,gpe_cast_expected_bytes,"cast" as *u8,buf,RK_WGSL_CAP,ol,RK_WGSL_TMO_MS)
453 if rc!=0 {return -1}
454 let vo:*i64=sys_mmap(16) as *i64;let fo:*i64=sys_mmap(16) as *i64
455 let valid:i64=rk_world_span(buf,ol[0],RK_CAST_VS_BEGIN,RK_CAST_VS_END,vo)&rk_world_span(buf,ol[0],RK_CAST_FS_BEGIN,RK_CAST_FS_END,fo)
456 if valid!=1||rk_int_after(buf,ol[0],"castv_struct_size=" as *u8)<=0||rk_int_after(buf,ol[0],"castf_struct_size=" as *u8)<=0 {ol[0]=0;gsb_failed=1;return -1}
457 return 0
458}
459func gpe_cast_identity(out:*u8,pos:i64,buf:*u8,n:i64,vo:*i64,fo:*i64)->i64 {
460 var p:i64=pos;let capture:*u8=sys_mmap(65);let vertex:*u8=sys_mmap(65);let fragment:*u8=sys_mmap(65)
461 gpa_sha(buf,n,capture);gpa_sha((buf as i64+vo[0]) as *u8,vo[1]-vo[0],vertex);gpa_sha((buf as i64+fo[0]) as *u8,fo[1]-fo[0],fragment)
462 p=gpe_ap(out,p,"window.__nx_shader_identity={version:1,verification:'producer SHA256 before and after capture; GPU review pending',cast:{requested_producer_sha256:'" as *u8)
463 p=gpe_ap(out,p,gpe_cast_expected);p=gpe_ap(out,p,"',verified_producer_sha256:'" as *u8);p=gpe_ap(out,p,gpe_cast_expected)
464 p=gpe_ap(out,p,"',producer_bytes:" as *u8);p=rk_num(out,p,gpe_cast_expected_bytes)
465 p=gpe_ap(out,p,",capture_sha256:'" as *u8);p=gpe_ap(out,p,capture);p=gpe_ap(out,p,"',vertex_sha256:'" as *u8);p=gpe_ap(out,p,vertex)
466 p=gpe_ap(out,p,"',fragment_sha256:'" as *u8);p=gpe_ap(out,p,fragment);p=gpe_ap(out,p,"',vertex_layout_bytes:" as *u8);p=rk_num(out,p,rk_int_after(buf,n,"castv_struct_size=" as *u8))
467 p=gpe_ap(out,p,",fragment_layout_bytes:" as *u8);p=rk_num(out,p,rk_int_after(buf,n,"castf_struct_size=" as *u8))
468 p=gpe_ap(out,p,",layout_source:'same verified cast capture'},world:{producer_sha256:'" as *u8);p=gpe_ap(out,p,gsb_expected)
469 p=gpe_ap(out,p,"',producer_bytes:" as *u8);p=rk_num(out,p,gsb_expected_bytes)
470 p=gpe_ap(out,p,"},compute:{producer_sha256:'" as *u8);p=gpe_ap(out,p,gsb_expected);p=gpe_ap(out,p,"',producer_bytes:" as *u8);p=rk_num(out,p,gsb_expected_bytes)
471 p=gpe_ap(out,p,"}};\n" as *u8)
472 return p
473}
474
475// S12 step 2 (2026-09-06): `const <name>={<member>:<offset>,...};const <name>_SIZE=<bytes>;` from the rows `nx_wgsl cast`
476// prints after `<rowskey> rows:` -- one `uniform|<member>|offset=<N>|...` row per uniform member, ending at `<sizekey><N>` --
477// so the page packs each cast stage's struct U at the offsets the ONE layout ruler (wg_uniform_layout_k) derived from the
478// same IR the shader was emitted from. An absent block emits null + 0 and NAMES itself on stderr: the page then refuses
479// the cast draw by name instead of packing by a hand count (the R-F law the world block already keeps).
480// Preserve producer layout metadata; do not recompute WGSL packing in the page.
481// ECMAScript Number exact-integer representation boundary, not a resource budget.
482const RK_LM_JS_SAFE_INTEGER_MAX:i64=9007199254740991
483func rk_lm_decimal(b:*u8,s:i64,e:i64)->i64{
484 if s>=e{return -1};var v:i64=0;var i:i64=s
485 while i<e{let d:i64=(b[i] as i64)-48;if d<0||d>9||v>(RK_LM_JS_SAFE_INTEGER_MAX-d)/10{return -1};v=v*10+d;i=i+1};return v
486}
487func rk_lm_prop(b:*u8,s:i64,e:i64,key:*u8)->i64{
488 let at:i64=rk_find(b,e,s,key);if at<0{return -1}
489 let start:i64=at+rk_slen(key)
490 if rk_find(b,e,start,key)>=0{return -1}
491 var end:i64=start;while end<e&&b[end]!=(124 as u8){end=end+1}
492 return rk_lm_decimal(b,start,end)
493}
494func rk_lm_row(b:*u8,s:i64,e:i64,r:*i64)->i64{
495 if rk_find(b,e,s,"uniform|")!=s{return 0}
496 let ns:i64=s+rk_slen("uniform|");var ne:i64=ns
497 while ne<e&&b[ne]!=(124 as u8){
498 let c:i64=b[ne] as i64
499 if !((c>=65&&c<=90)||(c>=97&&c<=122)||c==95||(ne>ns&&c>=48&&c<=57)){return 0}
500 ne=ne+1
501 }
502 if ne==ns||ne>=e{return 0}
503 let off:i64=rk_lm_prop(b,ne,e,"|offset=")
504 let bytes:i64=rk_lm_prop(b,ne,e,"|size=")
505 let align:i64=rk_lm_prop(b,ne,e,"|align=")
506 if off<0||bytes<=0||align<=0{return 0}
507 if (align&(align-1))!=0||off%align!=0{return 0}
508 r[0]=ns;r[1]=ne-ns;r[2]=off;r[3]=bytes;r[4]=align;return 1
509}
510func rk_lm_null(out:*u8,pos:i64,name:*u8)->i64{
511 gsb_failed=1;var p:i64=gpe_ap(out,pos,"const ");p=gpe_ap(out,p,name)
512 p=gpe_ap(out,p,"=null;const ");p=gpe_ap(out,p,name);p=gpe_ap(out,p,"_SIZE=0;const ")
513 p=gpe_ap(out,p,name);p=gpe_ap(out,p,"_META=null;\n");return p
514}
515func rk_layout_obj(out:*u8,pos:i64,buf:*u8,n:i64,rowskey:*u8,sizekey:*u8,name:*u8)->i64{
516 if n<=0||(buf as i64)<=0{return rk_lm_null(out,pos,name)}
517 let at:i64=rk_find(buf,n,0,rowskey);let stop:i64=rk_find(buf,n,0,sizekey)
518 if at<0||stop<=at{return rk_lm_null(out,pos,name)}
519 if (at>0&&buf[at-1]!=(10 as u8))||buf[stop-1]!=(10 as u8){return rk_lm_null(out,pos,name)}
520 if rk_find(buf,n,at+rk_slen(rowskey),rowskey)>=0||rk_find(buf,n,stop+rk_slen(sizekey),sizekey)>=0{return rk_lm_null(out,pos,name)}
521 var header_end:i64=at;while header_end<stop&&buf[header_end]!=(10 as u8){header_end=header_end+1}
522 let marker:i64=rk_find(buf,header_end,at+rk_slen(rowskey)," rows:")
523 if marker<0||marker+rk_slen(" rows:")!=header_end{return rk_lm_null(out,pos,name)}
524 let declared:i64=rk_lm_decimal(buf,at+rk_slen(rowskey),marker)
525 var size_end:i64=stop;while size_end<n&&buf[size_end]!=(10 as u8){size_end=size_end+1}
526 let sz:i64=rk_lm_decimal(buf,stop+rk_slen(sizekey),size_end)
527 if sz<=0||sz!=declared{return rk_lm_null(out,pos,name)}
528 let r:*i64=sys_mmap_try(5*__size_of(i64)) as *i64
529 if (r as i64)<=0{return rk_lm_null(out,pos,name)}
530 let first:i64=header_end+1;var i:i64=first;var end_prev:i64=0;var max_align:i64=1;var valid:i64=1;var count:i64=0
531 while i<stop&&valid==1{
532 var e:i64=i;while e<stop&&buf[e]!=(10 as u8){e=e+1}
533 if e==stop||rk_lm_row(buf,i,e,r)!=1{valid=0}else{
534 if r[2]<end_prev||r[2]>sz||r[3]>sz-r[2]{valid=0}else{end_prev=r[2]+r[3]}
535 if r[4]>max_align{max_align=r[4]}
536 // Duplicate names cannot become silently overwritten object properties.
537 var prior:i64=first
538 while prior<i&&valid==1{
539 let ns:i64=prior+rk_slen("uniform|");var ne:i64=ns
540 while ne<i&&buf[ne]!=(124 as u8){ne=ne+1}
541 if ne-ns==r[1]{
542 var same:i64=1;var k:i64=0
543 while k<r[1]{if buf[ns+k]!=buf[r[0]+k]{same=0};k=k+1}
544 if same==1{valid=0}
545 }
546 while prior<i&&buf[prior]!=(10 as u8){prior=prior+1};prior=prior+1
547 }
548 count=count+1
549 };i=e+1
550 }
551 if count==0||sz%max_align!=0{valid=0}
552 if valid!=1{sys_munmap_direct(r as *u8,5*__size_of(i64));return rk_lm_null(out,pos,name)}
553 var p:i64=gpe_ap(out,pos,"const ");p=gpe_ap(out,p,name);p=gpe_ap(out,p,"={")
554 var pass:i64=0
555 while pass<2{
556 i=first
557 while i<stop{
558 var e:i64=i;while e<stop&&buf[e]!=(10 as u8){e=e+1}
559 rk_lm_row(buf,i,e,r)
560 p=gpe_ap(out,p,"[");p=rk_js_str(out,p,(buf as i64+r[0]) as *u8,r[1]);p=gpe_ap(out,p,"]:")
561 if pass==0{p=rk_num(out,p,r[2])}else{
562 p=gpe_ap(out,p,"{offset:");p=rk_num(out,p,r[2]);p=gpe_ap(out,p,",size:")
563 p=rk_num(out,p,r[3]);p=gpe_ap(out,p,",align:");p=rk_num(out,p,r[4]);p=gpe_ap(out,p,"}")
564 }
565 p=gpe_ap(out,p,",");i=e+1
566 }
567 p=gpe_ap(out,p,"};\n")
568 if pass==0{
569 p=gpe_ap(out,p,"const ");p=gpe_ap(out,p,name);p=gpe_ap(out,p,"_SIZE=");p=rk_num(out,p,sz)
570 p=gpe_ap(out,p,";const ");p=gpe_ap(out,p,name);p=gpe_ap(out,p,"_META={")
571 };pass=pass+1
572 }
573 sys_munmap_direct(r as *u8,5*__size_of(i64));return p
574}
575
576const RK_CAST_GLSL_VS_BEGIN: *u8 = "--- cast_glsl GLSL ---\n"
577const RK_CAST_GLSL_VS_END: *u8 = "\ncast_glsl_rc="
578const RK_CAST_GLSL_FS_BEGIN: *u8 = "--- castfs_glsl GLSL ---\n"
579const RK_CAST_GLSL_FS_END: *u8 = "\ncastfs_glsl_rc="
580func rk_cast_glsl(out:*u8,pos:i64,buf:*u8,n:i64)->i64 {
581 let vo:*i64=sys_mmap(16) as *i64;let fo:*i64=sys_mmap(16) as *i64
582 if rk_world_span(buf,n,RK_CAST_GLSL_VS_BEGIN,RK_CAST_GLSL_VS_END,vo)!=1||rk_world_span(buf,n,RK_CAST_GLSL_FS_BEGIN,RK_CAST_GLSL_FS_END,fo)!=1 {gsb_failed=1;return pos}
583 // wg_probe reports emitted byte count; rk_world_span excludes the final LF before its metadata.
584 if rk_int_after(buf,n,"cast_glsl_rc=" as *u8)!=vo[1]-vo[0]+1||rk_int_after(buf,n,"castfs_glsl_rc=" as *u8)!=fo[1]-fo[0]+1 {gsb_failed=1;return pos}
585 let vertex:*u8=sys_mmap(65);let fragment:*u8=sys_mmap(65)
586 gpa_sha((buf as i64+vo[0]) as *u8,vo[1]-vo[0],vertex);gpa_sha((buf as i64+fo[0]) as *u8,fo[1]-fo[0],fragment)
587 var p:i64=gpe_ap(out,pos,"const MVS=" as *u8)
588 p=rk_js_str(out,p,(buf as i64+vo[0]) as *u8,vo[1]-vo[0]);p=gpe_ap(out,p,";const MFS=" as *u8)
589 p=rk_js_str(out,p,(buf as i64+fo[0]) as *u8,fo[1]-fo[0]);p=gpe_ap(out,p,";\nwindow.__nx_shader_identity.cast.glsl={vertex_sha256:'" as *u8)
590 p=gpe_ap(out,p,vertex);p=gpe_ap(out,p,"',fragment_sha256:'" as *u8);p=gpe_ap(out,p,fragment)
591 p=gpe_ap(out,p,"',vertex_consumer:'MVS',fragment_consumer:'MFS',association:'selected capture emitted to WebGL program inputs; actual program review pending'};window.__nx_shader_identity.cast.wgsl={vertex_sha256:window.__nx_shader_identity.cast.vertex_sha256,fragment_sha256:window.__nx_shader_identity.cast.fragment_sha256,vertex_consumer:'WGSL_CASTV',fragment_consumer:'WGSL_CASTF',association:'same selected capture emitted to WebGPU pipeline inputs; actual pipeline review pending'};\n" as *u8)
592 sys_munmap(vo as *u8,16);sys_munmap(fo as *u8,16);sys_munmap(vertex,65);sys_munmap(fragment,65)
593 return p
594}
595
596static gpe_eye_path: *u8
597static gpe_eye_expected: *u8
598static gpe_eye_expected_bytes: i64
599func rk_eye_stage(out:*u8,pos:i64,buf:*u8,n:i64,begin:*u8,end:*u8,rc_key:*u8,name:*u8)->i64 {
600 let span:*i64=sys_mmap(16) as *i64
601 if (span as i64)<=0 {gsb_failed=1;return pos}
602 if rk_world_span(buf,n,begin,end,span)!=1||rk_int_after(buf,n,rc_key)!=span[1]-span[0]+1 {sys_munmap(span as *u8,16);gsb_failed=1;return pos}
603 var p:i64=gpe_ap(out,pos,"const " as *u8);p=gpe_ap(out,p,name);p=gpe_ap(out,p,"=" as *u8)
604 p=rk_js_str(out,p,(buf as i64+span[0]) as *u8,span[1]-span[0]);p=gpe_ap(out,p,";\n" as *u8)
605 sys_munmap(span as *u8,16);return p
606}
607func rk_eye_block(out:*u8,pos:i64)->i64 {
608 if gpe_eye_path==(0 as *u8)||gpe_eye_expected==(0 as *u8) {gsb_failed=1;return pos}
609 let owned:*NxBufOwned=rk_owned_new();if (owned as i64)<=0 {return pos}
610 var p:i64=pos
611 let rc:i64=gsb_capture_selected_owned(gpe_eye_path,gpe_eye_expected,gpe_eye_expected_bytes,"eye" as *u8,owned,RK_WGSL_TMO_MS,0)
612 let buf:*u8=owned.buf;let n:i64=owned.len
613 if rc!=0||n<=0 {gsb_failed=1} else {
614 if rk_find(buf,n,0,"eye_over=0\n" as *u8)<0||rk_find(buf,n,0,"eyefs_over=0\n" as *u8)<0||rk_find(buf,n,0,"eye_glsl_named=NONE" as *u8)<0||rk_find(buf,n,0,"eye_wgsl_named=NONE" as *u8)<0||rk_find(buf,n,0,"eyefs_glsl_named=NONE" as *u8)<0||rk_find(buf,n,0,"eyefs_wgsl_named=NONE" as *u8)<0 {gsb_failed=1} else {
615 let eye_capture_sha:*u8=sys_mmap(65)
616 if (eye_capture_sha as i64)<=0 {gsb_failed=1} else {
617 gpa_sha(buf,n,eye_capture_sha)
618 p=gpe_ap(out,p,"const NXEYE={producer_path:" as *u8);p=rk_js_str(out,p,gpe_eye_path,rk_slen(gpe_eye_path))
619 p=gpe_ap(out,p,",producer_sha256:" as *u8);p=rk_js_str(out,p,gpe_eye_expected,rk_slen(gpe_eye_expected))
620 p=gpe_ap(out,p,",producer_bytes:" as *u8);p=rk_num(out,p,gpe_eye_expected_bytes)
621 p=gpe_ap(out,p,",capture_sha256:" as *u8);p=rk_js_str(out,p,eye_capture_sha,64)
622 p=gpe_ap(out,p,",capture_bytes:" as *u8);p=rk_num(out,p,n)
623 p=gpe_ap(out,p,"};\n" as *u8);sys_munmap(eye_capture_sha,65)
624 }
625 p=rk_eye_stage(out,p,buf,n,"--- eye_glsl GLSL ---\n" as *u8,"\neye_glsl_rc=" as *u8,"eye_glsl_rc=" as *u8,"EYE_GLSL_VS" as *u8)
626 p=rk_eye_stage(out,p,buf,n,"--- eyefs_glsl GLSL ---\n" as *u8,"\neyefs_glsl_rc=" as *u8,"eyefs_glsl_rc=" as *u8,"EYE_GLSL_FS" as *u8)
627 p=rk_eye_stage(out,p,buf,n,"--- eye_wgsl WGSL ---\n" as *u8,"\neye_wgsl_rc=" as *u8,"eye_wgsl_rc=" as *u8,"EYE_WGSL_VS" as *u8)
628 p=rk_eye_stage(out,p,buf,n,"--- eyefs_wgsl WGSL ---\n" as *u8,"\neyefs_wgsl_rc=" as *u8,"eyefs_wgsl_rc=" as *u8,"EYE_WGSL_FS" as *u8)
629 p=rk_layout_obj(out,p,buf,n,"eyev_layout_rc=" as *u8,"eyev_struct_size=" as *u8,"NXEV" as *u8)
630 p=rk_layout_obj(out,p,buf,n,"eyef_layout_rc=" as *u8,"eyef_struct_size=" as *u8,"NXEF" as *u8)
631 if rk_int_after(buf,n,"eyev_struct_size=" as *u8)<=0||rk_int_after(buf,n,"eyef_struct_size=" as *u8)<=0 {gsb_failed=1}
632 }}
633 rk_owned_close(owned);return p
634}
635
636// Owned capture grows within actual allocation/deadline constraints; zero max means no caller byte ceiling.
637func rk_owned_new()->*NxBufOwned{
638 let b:*NxBufOwned=sys_mmap_try(NX_BO_BYTES) as *NxBufOwned;if (b as i64)<=0{gsb_failed=1;return 0 as *NxBufOwned}
639 b.buf=0 as *u8;b.len=0;b.cap=0;return b
640}
641func rk_owned_close(b:*NxBufOwned)->i64{
642 if (b as i64)<=0{return 0};let rc:i64=nx_bo_release(b);if rc!=0{gsb_failed=1;return rc}
643 let released:i64=sys_munmap_direct(b as *u8,NX_BO_BYTES);if released<0{gsb_failed=1};return released
644}
645func rk_capture_cast_owned(b:*NxBufOwned)->i64{
646 if gpe_cast_path==(0 as *u8)||gpe_cast_expected==(0 as *u8){gsb_failed=1;return -1}
647 let rc:i64=gsb_capture_selected_owned(gpe_cast_path,gpe_cast_expected,gpe_cast_expected_bytes,"cast",b,RK_WGSL_TMO_MS,0);if rc!=0{return rc}
648 let spans:*i64=sys_mmap_try(32) as *i64;if (spans as i64)<=0{gsb_failed=1;return -1}
649 let valid:i64=rk_world_span(b.buf,b.len,RK_CAST_VS_BEGIN,RK_CAST_VS_END,spans)&rk_world_span(b.buf,b.len,RK_CAST_FS_BEGIN,RK_CAST_FS_END,(spans as i64+16) as *i64)
650 sys_munmap_direct(spans as *u8,32)
651 if valid!=1||rk_int_after(b.buf,b.len,"castv_struct_size=")<=0||rk_int_after(b.buf,b.len,"castf_struct_size=")<=0{gsb_failed=1;return -1};return 0
652}
653func rk_cast_block(out: *u8, pos: i64) -> i64 {
654 var p: i64 = pos
655 let owned:*NxBufOwned=rk_owned_new();if (owned as i64)<=0{return pos}
656 let captured:i64=rk_capture_cast_owned(owned)
657 let buf:*u8=owned.buf;var n:i64=owned.len;if captured!=0{n=0}
658 let vo: *i64 = sys_mmap(16) as *i64
659 let fo: *i64 = sys_mmap(16) as *i64
660 var okv: i64 = 0
661 var okf: i64 = 0
662 if n > 0 { okv = rk_world_span(buf, n, RK_CAST_VS_BEGIN, RK_CAST_VS_END, vo); okf = rk_world_span(buf, n, RK_CAST_FS_BEGIN, RK_CAST_FS_END, fo) }
663 if okv==1&&okf==1&&gsb_expected!=(0 as *u8) {p=gpe_cast_identity(out,p,buf,n,vo,fo)} else {gsb_failed=1}
664 p = rk_cast_glsl(out, p, buf, n)
665 if okv == 0 { rk_err("[gpe] S12 cast shader: VERTEX MODULE ABSENT AT EMIT -- nx_wgsl.elf cast gave no cast_wgsl section or refused it; the page carries WGSL_CASTV=null\n" as *u8) }
666 if okf == 0 { rk_err("[gpe] S12 cast shader: FRAGMENT MODULE ABSENT AT EMIT -- nx_wgsl.elf cast gave no castfs_wgsl section or refused it; the page carries WGSL_CASTF=null\n" as *u8) }
667 if okv == 0 { p = gpe_ap(out, p, "const WGSL_CASTV=null;" as *u8) } else {
668 p = gpe_ap(out, p, "const WGSL_CASTV=`" as *u8)
669 var i: i64 = vo[0]
670 while i < vo[1] { out[p] = buf[i]; p = p + 1; i = i + 1 }
671 p = gpe_ap(out, p, "`;" as *u8)
672 }
673 if okf == 0 { p = gpe_ap(out, p, "const WGSL_CASTF=null;\n" as *u8) } else {
674 rk_err("[gpe] S12 cast shader captured from nx_wgsl cast: vertex_bytes=" as *u8)
675 let nb: *u8 = sys_mmap(32)
676 let q: i64 = rk_num(nb, 0, vo[1] - vo[0])
677 sys_write(2, nb, q)
678 rk_err(" fragment_bytes=" as *u8)
679 let q2: i64 = rk_num(nb, 0, fo[1] - fo[0])
680 sys_write(2, nb, q2)
681 rk_err("\n" as *u8)
682 p = gpe_ap(out, p, "const WGSL_CASTF=`" as *u8)
683 var i2: i64 = fo[0]
684 while i2 < fo[1] { out[p] = buf[i2]; p = p + 1; i2 = i2 + 1 }
685 p = gpe_ap(out, p, "`;\n" as *u8)
686 }
687 // S12 step 2: the two cast structs' derived layouts ride beside the modules as NXCV / NXCF (offset tables) + sizes
688 p = rk_layout_obj(out, p, buf, n, "castv_layout_rc=" as *u8, "castv_struct_size=" as *u8, "NXCV" as *u8)
689 p = rk_layout_obj(out, p, buf, n, "castf_layout_rc=" as *u8, "castf_struct_size=" as *u8, "NXCF" as *u8)
690 rk_owned_close(owned)
691 return p
692}
693func rk_webgpu_door(out: *u8, pos: i64) -> i64 {
694 var p: i64 = pos
695 let owned:*NxBufOwned=rk_owned_new();if (owned as i64)<=0{return pos}
696 let captured:i64=gsb_capture_owned("compute",owned,RK_WGSL_TMO_MS,0)
697 let buf:*u8=owned.buf;var n:i64=owned.len;if captured!=0{n=0}
698 var b: i64 = 0 - 1
699 var e: i64 = 0 - 1
700 if n > 0 {
701 b = rk_find(buf, n, 0, RK_WGSL_BEGIN)
702 if b >= 0 { b = b + rk_slen(RK_WGSL_BEGIN); e = rk_find(buf, n, b, RK_WGSL_END) }
703 }
704 if e <= b {
705 rk_err("[gpe] GP2 rk_webgpu_door: KERNEL WGSL ABSENT AT EMIT -- nx_wgsl.elf compute gave no WGSL section; the page carries KWGSL=null and its telemetry says so\n" as *u8)
706 p = gpe_ap(out, p, "const KWGSL=null;window.__nx_kernel={s:\"WGSL-ABSENT-AT-EMIT\"};\n" as *u8)
707 } else {
708 rk_err("[gpe] GP2 rk_webgpu_door: kernel WGSL captured from nx_wgsl compute, bytes=" as *u8)
709 let nb: *u8 = sys_mmap(32)
710 let q: i64 = rk_num(nb, 0, e - b)
711 sys_write(2, nb, q)
712 rk_err("\n" as *u8)
713 p = gpe_ap(out, p, "// GP2: the GE43 kernel, CAPTURED from nx_wgsl compute at emit time (the bytes nx_wgsl_compute_gate pins)\nconst KWGSL=" as *u8)
714 p = rk_js_str(out, p, ((buf as i64) + b) as *u8, e - b)
715 p = gpe_ap(out, p, ";\n" as *u8)
716 }
717 rk_owned_close(owned)
718 p = gpe_ap(out, p, "async function nxKernelProbe(dev){try{\nif(!KWGSL)throw \"kernel-wgsl-absent-at-emit\";\nconst N=" as *u8)
719 p = rk_num(out, p, RK_KERNEL_N)
720 p = gpe_ap(out, p, ",t0=performance.now();\nconst WGm=KWGSL.match(/workgroup_size\\((\\d+)\\)/);if(!WGm)throw \"kwgsl-has-no-workgroup_size\";const WG=parseInt(WGm[1],10);\nconst d0=new Uint32Array(N),z0=new Uint32Array(N);\nfor(let i=0;i<N;i++){d0[i]=(Math.imul(i,2654435761)^0x9e3779b9)>>>0;z0[i]=(Math.imul(i+7,40503)^0x7f4a7c15)>>>0;}\nconst mk=(a,u)=>{const b=dev.createBuffer({size:a.byteLength,usage:u,mappedAtCreation:true});new Uint32Array(b.getMappedRange()).set(a);b.unmap();return b;};\nconst depth=mk(d0,GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_SRC),zin=mk(z0,GPUBufferUsage.STORAGE);\nconst md=dev.createShaderModule({code:KWGSL});const inf=await md.getCompilationInfo();\nfor(const m of inf.messages){if(m.type===\"error\")throw \"kwgsl:\"+m.lineNum+\":\"+m.message;}\nconst pl=dev.createComputePipeline({layout:\"auto\",compute:{module:md,entryPoint:\"main\"}});\nconst bg=dev.createBindGroup({layout:pl.getBindGroupLayout(0),entries:[{binding:1,resource:{buffer:depth}},{binding:2,resource:{buffer:zin}}]});\nconst rb=dev.createBuffer({size:N*4,usage:GPUBufferUsage.MAP_READ|GPUBufferUsage.COPY_DST});\nconst enc=dev.createCommandEncoder();const ps=enc.beginComputePass();ps.setPipeline(pl);ps.setBindGroup(0,bg);ps.dispatchWorkgroups(Math.ceil(N/WG));ps.end();\nenc.copyBufferToBuffer(depth,0,rb,0,N*4);dev.queue.submit([enc.finish()]);\nawait rb.mapAsync(GPUMapMode.READ);const got=new Uint32Array(rb.getMappedRange().slice(0));rb.unmap();\nlet diff=0;for(let i=0;i<N;i++){const e=(d0[i]<z0[i])?d0[i]:z0[i];if(got[i]!==e)diff++;}\nconst ms=Math.round(performance.now()-t0);\nwindow.__nx_kernel={s:(diff===0?\"OK\":\"DIFF\")+\" n=\"+N+\" diff=\"+diff+\" ms=\"+ms+\" wg=\"+WG,n:N,diff:diff,ms:ms,wg:WG};\nconsole.log(\"nishi kernel door\",window.__nx_kernel.s);\n}catch(e){window.__nx_kernel={s:\"FAIL:\"+String(e)};console.log(\"nishi kernel door FAIL\",e);}}\n" as *u8)
721 return p
722}
723
724// gpe_emit_webgpu -- STAGE A of the WebGPU tier (2026-08-18, the /compare/graphics contract row;
725// operator order: GPU delivery through last-mile shims, everything above them Nishi-emitted).
726// Emits the WGSL world shader (a line-faithful transliteration of FSH: DDA march, face shading,
727// bump micro-relief, edge AO, one-bounce sun shadow, water two-hit blend, sky/clouds, rain,
728// crosshair, hotbar) plus the WebGPU init and per-frame draw. LEVERED: runs only under ?gpu=1 --
729// characters still render only in the GL tier (drawNPCs/drawEyes are GL programs), so WebGPU
730// must NOT be default until the NPC+eye passes reach parity; the lever keeps every ordinary
731// visitor on the proven ladder (GL -> sovereign wasm) while this tier is measured.
732// Known deltas vs FSH, all deliberate: the dead `ua` local was dropped; WebGPU's top-left
733// fragment origin is Y-flipped back to GL's bottom-left so every screen-space read matches.
734// The uniform struct is 384 bytes (WGSL std layout: five vec3f+f32 rows, one vec4f, one
735// vec2f+2*f32 row, one 4*f32 row, then pal[12]+palf[5] as vec4f arrays) -- the JS packs the
736// SAME 96 floats; change one side and the other MUST move (the wire-format law).
737// WebGPU timestamps are two u64 endpoints; each slot owns resolve and readback buffers.
738const GPE_GPU_TIMESTAMP_ENDPOINTS: i64 = 2
739const GPE_GPU_TIMESTAMP_BUFFERS: i64 = 2
740const GPE_GPU_SLOT_BUFFER_BYTES: i64 = GPE_GPU_TIMESTAMP_ENDPOINTS * GPE_GPU_TIMESTAMP_BUFFERS * __size_of(i64)
741// ECMAScript Number.MAX_SAFE_INTEGER: the policy is emitted as JavaScript numbers.
742const GPE_GPU_POLICY_MAX_INTEGER: i64 = 9007199254740991
743const GPE_GPU_POLICY_RADIX: i64 = 10
744const GPE_FACING_INTEGER_MAX: i64 = 2147483647
745const GPE_FACING_HALF_TURN_Q12: i64 = 12868
746// Facing policy v1 is data; tokenizer reuse keeps malformed/truncated inputs outside runtime.
747func gpe_facing_key(t: *NxJsonTok, key: *u8) -> i64 {
748 let n: i64 = gpe_slen(key)
749 if t.tok_len != n+2 { return 0 }
750 var i: i64 = 0
751 while i < n { if t.src[t.tok_off+1+i] != key[i] { return 0 } i=i+1 }
752 return 1
753}
754func gpe_facing_parse(raw: *u8, n: i64, values: *i64) -> i64 {
755 if n <= 0 { return -1 }
756 let t: *NxJsonTok = nx_json_new(raw,n)
757 if (t as i64) <= 0 { return -1 }
758 if nx_json_next(t) != NX_JSON_LBRACE { return -1 }
759 var seen: i64 = 0
760 var field: i64 = 0
761 while field < 3 {
762 if field > 0 { if nx_json_next(t) != NX_JSON_COMMA { return -1 } }
763 if nx_json_next(t) != NX_JSON_STRING { return -1 }
764 var slot: i64 = -1
765 if gpe_facing_key(t,"version" as *u8) == 1 { slot=0 }
766 if gpe_facing_key(t,"radius_q8" as *u8) == 1 { slot=1 }
767 if gpe_facing_key(t,"gain_q12_per_tick" as *u8) == 1 { slot=2 }
768 if slot < 0 { return -1 }
769 let bit: i64 = 1 << slot
770 if (seen & bit) != 0 { return -1 }
771 seen=seen | bit
772 if nx_json_next(t) != NX_JSON_COLON { return -1 }
773 if nx_json_next(t) != NX_JSON_NUMBER { return -1 }
774 var value: i64 = 0
775 var i: i64 = 0
776 while i < t.tok_len {
777 let digit: i64 = (raw[t.tok_off+i] as i64)-48
778 if digit < 0 || digit > 9 { return -1 }
779 if value > (GPE_FACING_INTEGER_MAX-digit)/10 { return -1 }
780 value=value*10+digit
781 i=i+1
782 }
783 values[slot]=value
784 field=field+1
785 }
786 if nx_json_next(t) != NX_JSON_RBRACE { return -1 }
787 if nx_json_next(t) != NX_JSON_EOF { return -1 }
788 if seen != 7 || values[0] != 1 { return -1 }
789 if values[1] < 1 || values[2] < 1 || values[2] > GPE_FACING_HALF_TURN_Q12 { return -1 }
790 return 0
791}
792func gpe_facing_policy(out: *u8, pos: i64) -> i64 {
793 let box: *i64 = sys_mmap(8) as *i64
794 let raw: *u8 = sys_read_file("/volume1/homes/elderwesto/nishihost/knowledge/facing.conf" as *u8,box)
795 let values: *i64 = sys_mmap(24) as *i64
796 var p: i64 = pos
797 if gpe_facing_parse(raw,box[0],values) != 0 {
798 gpe_puts("FACING-POLICY refused: missing or invalid knowledge/facing.conf\n" as *u8)
799 return gpe_ap(out,p,"throw Error('facing-policy: missing or invalid knowledge/facing.conf');\n" as *u8)
800 }
801 p=gpe_ap(out,p,"window.__nx_facing_policy={version:1,radius_q8:" as *u8)
802 p=gpe_num(out,p,values[1])
803 p=gpe_ap(out,p,",gain_q12_per_tick:" as *u8)
804 p=gpe_num(out,p,values[2])
805 return gpe_ap(out,p,"};\nif(typeof ex.mob_heading!=='function'||typeof ex.set_facing_policy!=='function')throw Error('facing-policy: incompatible native module');\nif(Number(ex.set_facing_policy(BigInt(window.__nx_facing_policy.radius_q8),BigInt(window.__nx_facing_policy.gain_q12_per_tick)))!==0)throw Error('facing-policy: native refused configuration');\n" as *u8)
806}
807
808func gpe_gpu_timing_policy(out: *u8, pos: i64) -> i64 {
809 let ln: *i64 = sys_mmap(__size_of(i64)) as *i64
810 let raw: *u8 = sys_read_file("knowledge/gpu_timing.conf" as *u8, ln)
811 var slots: i64 = 0
812 var budget: i64 = 0
813 var value: i64 = 0
814 var fields: i64 = 0
815 var digits: i64 = 0
816 var valid: i64 = 1
817 var i: i64 = 0
818 let zero: i64 = ("0" as *u8)[0] as i64
819 let nine: i64 = ("9" as *u8)[0] as i64
820 let whitespace: *u8 = "\t\n\r "
821 if ln[0] <= 0 { valid = 0 }
822 while i <= ln[0] {
823 var c: i64 = whitespace[1] as i64
824 if i < ln[0] { c = raw[i] as i64 }
825 if c >= zero && c <= nine {
826 let digit: i64 = c-zero
827 if value > (GPE_GPU_POLICY_MAX_INTEGER-digit)/GPE_GPU_POLICY_RADIX { valid = 0 }
828 if valid == 1 { value = value*GPE_GPU_POLICY_RADIX+digit }
829 digits = digits + 1
830 } else {
831 var separator: i64 = 0
832 var w: i64 = 0
833 while whitespace[w] != 0 as u8 {
834 if c == whitespace[w] as i64 { separator = 1 }
835 w = w+1
836 }
837 if separator == 0 { valid = 0 }
838 if digits > 0 {
839 if fields == 0 { slots = value }
840 if fields == 1 { budget = value }
841 fields = fields+1
842 value = 0
843 digits = 0
844 }
845 }
846 i = i+1
847 }
848 if fields != 2 { valid = 0 }
849 if slots < 1 || budget < 1 { valid = 0 }
850 if slots > budget/GPE_GPU_SLOT_BUFFER_BYTES { valid = 0 }
851 var p: i64 = pos
852 if valid == 0 {
853 gpe_puts("GPU-TIMING policy absent/invalid: profiling unavailable; rendering retained\n" as *u8)
854 return gpe_ap(out,p,"window.__nx_gpu_timing_policy=null;\n" as *u8)
855 }
856 p = gpe_ap(out,p,"window.__nx_gpu_timing_policy={slots:" as *u8)
857 p = gpe_num(out,p,slots)
858 p = gpe_ap(out,p,",buffer_budget_bytes:" as *u8)
859 p = gpe_num(out,p,budget)
860 return gpe_ap(out,p,"};\n" as *u8)
861}
862
863static gpe_prepared_path:*u8
864static gpe_prepared_sha:*u8
865static gpe_prepared_bytes:i64
866// Hash-bound UTF8 catalogue; script-safe quoting preserves data and exposes actual dependency references.
867func gpe_catalogue_string(out:*u8,pos:i64,src:*u8,n:i64)->i64{
868 if pos<0||n<0||pos>GPE_OUT_CAP-2||n>(GPE_OUT_CAP-pos-2)/6||utf8_validate(src,n)!=n{return -1}
869 var p:i64=pos;out[p]=34 as u8;p=p+1;var i:i64=0;let hex:*u8="0123456789abcdef"
870 while i<n{let c:i64=src[i] as i64
871 if c==34||c==92{out[p]=92 as u8;out[p+1]=c as u8;p=p+2}
872 else{if c<32||c==60{out[p]=92 as u8;out[p+1]=117 as u8;out[p+2]=48 as u8;out[p+3]=48 as u8;out[p+4]=hex[c/16];out[p+5]=hex[c%16];p=p+6}
873 else{if c==226&&i+2<n&&src[i+1]==128 as u8&&(src[i+2]==168 as u8||src[i+2]==169 as u8){out[p]=92 as u8;out[p+1]=117 as u8;out[p+2]=50 as u8;out[p+3]=48 as u8;out[p+4]=50 as u8;out[p+5]=hex[(src[i+2] as i64)-160];p=p+6;i=i+2}
874 else{out[p]=src[i];p=p+1}}};i=i+1
875 };out[p]=34 as u8;return p+1
876}
877func gpe_prepared_catalogue(out:*u8,pos:i64)->i64{
878 var p:i64=gpe_ap(out,pos,"const NXPREPARED=" as *u8)
879 if (gpe_prepared_path as i64)==0{return gpe_ap(out,p,"[];\n" as *u8)}
880 if gpe_prepared_bytes<=0||gpe_prepared_bytes>9223372036854775807/4||gsb_artifact_matches(gpe_prepared_path,gpe_prepared_sha,gpe_prepared_bytes)!=1{gsb_failed=1;return p}
881 let box:*i64=sys_mmap_try(8) as *i64;if (box as i64)==0{gsb_failed=1;return p};let data:*u8=sys_read_file(gpe_prepared_path,box)
882 if (data as i64)==0||box[0]!=gpe_prepared_bytes{if (data as i64)>0{sys_free_file(data,box[0])};sys_munmap_direct(box as *u8,8);gsb_failed=1;return p}
883 let digest:*u8=sys_mmap_try(GPA_SHA_HEX+1)
884 if (digest as i64)==0{sys_free_file(data,box[0]);sys_munmap_direct(box as *u8,8);gsb_failed=1;return p}
885 gpa_sha(data,box[0],digest);let identity:i64=fsx_seq(digest,gpe_prepared_sha);sys_munmap_direct(digest,GPA_SHA_HEX+1)
886 if identity!=1{sys_free_file(data,box[0]);sys_munmap_direct(box as *u8,8);gsb_failed=1;return p}
887 p=gpe_ap(out,p,"JSON.parse(" as *u8);let encoded:i64=gpe_catalogue_string(out,p,data,box[0]);if encoded<0{gsb_failed=1}else{p=gpe_ap(out,encoded,");\n" as *u8)}
888 sys_free_file(data,box[0]);sys_munmap_direct(box as *u8,8);return p
889}
890struct GpeSceneWriter { output:i64, capacity:i64, position:i64, failed:i64 }
891func gpe_scene_light_recipe_emit(out:*u8,pos:i64)->i64{
892 let extent:i64=__size_of(GpeSceneWriter)
893 let w:*i64=sys_mmap_try(extent) as *i64
894 if (w as i64)<=0{gsb_failed=1;return pos}
895 w[0]=0;w[1]=0;w[2]=0;w[3]=0
896 var p:i64=pos
897 var b:*u8=0 as *u8
898 var bytes:i64=0
899 if cs_scene_light_recipe_write(w)!=0||w[2]<=0||w[2]>=GLW_I64_MAX{gsb_failed=1}
900 if gsb_failed==0{
901 let n:i64=w[2];bytes=n+1;b=sys_mmap_try(bytes)
902 if (b as i64)<=0{gsb_failed=1}
903 if gsb_failed==0{
904 w[0]=b as i64;w[1]=n;w[2]=0;w[3]=0
905 if cs_scene_light_recipe_write(w)!=0||w[2]!=n{gsb_failed=1}
906 if gsb_failed==0{
907 b[n]=0 as u8
908 p=gpe_ap(out,pos,"const NX_SCENE_LIGHT_RECIPE=Object.freeze(")
909 p=gpe_ap(out,p,b);p=gpe_ap(out,p,");\n")
910 }
911 }
912 }
913 if (b as i64)>0{if sys_munmap_direct(b,bytes)!=0{gsb_failed=1}}
914 if sys_munmap_direct(w as *u8,extent)!=0{gsb_failed=1}
915 return p
916}
917
918func gpe_visitors_gpu(out: *u8,pos: i64) -> i64 {
919 let p:i64=gpe_ap(out,gpe_mip_emit(out,gpe_rig_inspection_emit(out,gpe_prepared_body_emit(out,gpe_prepared_catalogue(out,pos)))),nx_prepared_motion_js())
920 if gsb_failed!=0{return p}
921 let q:i64=gpe_scene_light_recipe_emit(out,p)
922 if gsb_failed!=0{return q}
923 return gpe_ap(out,q,nx_character_prepared_runtime_js())
924}
925
926func gpe_emit_webgpu(out: *u8, pos: i64) -> i64 {
927 var p: i64 = pos
928 p = rk_uniform_block(out, p)
929 p = rk_world_block(out, p)
930 p = rk_cast_block(out, p)
931 p = rk_eye_block(out, p)
932 p = gpe_visitors_gpu(out, p)
933 p = gpe_ap(out, p, "const NXTFIX=location.search.indexOf(\"tfix=1\")>=0;\n" as *u8)
934 // R-H (2026-09-04): the parity instrument. ?blocks=1 renders ONE extra pass of the world into a COPY_SRC texture,
935 // copies it to a mapped buffer and publishes 16x9 RGB block means as window.__nx_blocks -- read back from the GPU,
936 // never from the presented canvas (a headless drawImage of a WebGPU canvas is black, measured 2026-09-04).
937 p = gpe_ap(out, p, "const NXBLOCKS=location.search.indexOf(\"blocks=\")>=0;\nasync function nxReadBlocks(dev,G){dev.pushErrorScope('validation');try{const c9=G.gctx.canvas,W=c9.width,H=c9.height,fmt=navigator.gpu.getPreferredCanvasFormat(),bgra=fmt.indexOf(\"bgra\")===0;\nconst rt=dev.createTexture({size:[W,H],format:fmt,usage:GPUTextureUsage.RENDER_ATTACHMENT|GPUTextureUsage.COPY_SRC});const bpr=Math.ceil(W*4/256)*256;\nconst rb=dev.createBuffer({size:bpr*H,usage:GPUBufferUsage.COPY_DST|GPUBufferUsage.MAP_READ});const enc=dev.createCommandEncoder();\nconst dt9=dev.createTexture({size:[W,H],format:\"depth24plus\",usage:GPUTextureUsage.RENDER_ATTACHMENT});nxGpuCastPrepare(dev,G,enc);const rp=enc.beginRenderPass({colorAttachments:[{view:rt.createView(),loadOp:\"clear\",storeOp:\"store\",clearValue:{r:0,g:0,b:0,a:1}}],depthStencilAttachment:{view:dt9.createView(),depthClearValue:1.0,depthLoadOp:\"clear\",depthStoreOp:\"discard\"}});rp.setPipeline(G.pl);rp.setBindGroup(0,G.bg);rp.draw(3);nxGpuCast(dev,G,rp);nxGpuDrawVisitors(dev,G,rp);rp.end();\nenc.copyTextureToBuffer({texture:rt},{buffer:rb,bytesPerRow:bpr,rowsPerImage:H},[W,H]);dev.queue.submit([enc.finish()]);nxGpuCastPop(dev,G);await rb.mapAsync(GPUMapMode.READ);\nconst d=new Uint8Array(rb.getMappedRange());const _bn=(location.search.match(/blocks=(\\d+)/)||[])[1];const gx=(_bn&&+_bn>=4)?Math.min(512,+_bn):16,gy=Math.max(1,Math.round(gx*H/W)),o=[];let tot=0;\nfor(let by=0;by<gy;by++)for(let bx=0;bx<gx;bx++){let r=0,g=0,b=0,k=0;const x0=Math.floor(bx*W/gx),x1=Math.floor((bx+1)*W/gx),y0=Math.floor(by*H/gy),y1=Math.floor((by+1)*H/gy);\nfor(let y=y0;y<y1;y++)for(let x=x0;x<x1;x++){const i=y*bpr+x*4;r+=d[i+(bgra?2:0)];g+=d[i+1];b+=d[i+(bgra?0:2)];k++;}o.push(Math.round(r/k),Math.round(g/k),Math.round(b/k));tot+=r+g+b;}\nrb.unmap();window.__nx_blocks={w:W,h:H,fmt:fmt,src:window.__nx_world_src||null,mean:tot/(W*H*3),blocks:o};}catch(e){window.__nx_blocks={err:String(e)};}const re9=await dev.popErrorScope();if(re9){window.__nx_blocks={err:'validation:'+re9.message,mean:0};}}\n" as *u8)
938 // GE55 (2026-09-05): THE HAND WGSL WORLD PASS IS RETIRED. Its ten functions (vx, h21, h31, pal9, sky, struct Hit,
939 // march, shade, the fragment and vertex entries -- ~11 KB of hand-written WGSL, and the WGSL_U uniform struct it was
940 // concatenated with) are gone: the WebGPU door draws WGSL_IRF / WGSL_IRV, captured at emit time from the ONE
941 // NishiLang shader source (nx_world_shader_src through nx_shader_ir + nx_wgsl), and ?hand=1 now refuses by name
942 // rather than drawing anything. The page carries no hand-written shader bytes and no per-frame packer arithmetic
943 // (the sim packs its own raw uniform block, the kernel derives every float in upk). WGSL stays declared null so the
944 // IR?WGSL_IRV:WGSL ternary keeps a defined else-branch. Pre-retirement source: knowledge/library/nx_game_page_emit.nx.pre-retire-20260905.
945 p = gpe_ap(out, p, "const WGSL=null;\n" as *u8)
946 p = gpe_gpu_timing_policy(out, p)
947 p = gpe_ap(out, p, ngc_source())
948 p = gpe_ap(out, p, "async function nxGpuTimingDevice(ad){\nconst requested=ad.features.has('timestamp-query');\nwindow.__nx_gpu_timing_request={requested:requested,fallback:false,error:null};\ntry{return await ad.requestDevice({requiredFeatures:requested?['timestamp-query']:[]});}\ncatch(e){if(!requested)throw e;window.__nx_gpu_timing_request.fallback=true;window.__nx_gpu_timing_request.error=String(e);return await ad.requestDevice();}\n}\nasync function nxGpuTimerChecked(dev,operation){\nlet opened=0,value,failure=null;const pending=[];\ntry{for(const kind of ['validation','out-of-memory','internal']){dev.pushErrorScope(kind);opened++;}value=operation();}\ncatch(e){failure=e;}\nfinally{while(opened>0){opened--;try{pending.push(dev.popErrorScope());}catch(e){if(!failure)failure=e;}}}\nconst results=await Promise.allSettled(pending);\nfor(const result of results){if(result.status==='rejected'){if(!failure)failure=result.reason;}else if(result.value&&!failure){failure=Error(result.value.message);}}\nif(failure)throw failure;return value;\n}\nasync function nxGpuTimerInit(dev){\nconst T={state:'unsupported',attempted:0,completed:0,busy_frames:0,failed:0,last:null,busy:false,resources:[],stopped:false};\nT.cleanup_errors=[];T.stop=function(reason){if(T.stopped)return;T.stopped=true;T.state=reason;T.busy=false;const owned=T.resources.splice(0);for(const r of owned){try{r.destroy();}catch(e){T.cleanup_errors.push(String(e));}}};\nif(!dev.features.has('timestamp-query'))return T;\ntry{await nxGpuTimerChecked(dev,function(){\nT.query=dev.createQuerySet({type:'timestamp',count:2});T.resources.push(T.query);\nT.resolve=dev.createBuffer({size:16,usage:GPUBufferUsage.QUERY_RESOLVE|GPUBufferUsage.COPY_SRC});T.resources.push(T.resolve);\nT.read=dev.createBuffer({size:16,usage:GPUBufferUsage.COPY_DST|GPUBufferUsage.MAP_READ});T.resources.push(T.read);\n});}catch(e){T.error=String(e);T.stop('initialization-failed');return T;}\nT.state='ready';dev.lost.then(function(){T.stop('device-lost');});return T;\n}\nfunction nxGpuTimerBegin(T,descriptor,frame){\nif(!T||T.stopped||T.state==='unsupported')return false;\nT.attempted++;if(T.busy){T.busy_frames++;return false;}\nT.busy=true;T.frame=frame;T.state='pending';\ndescriptor.timestampWrites={querySet:T.query,beginningOfPassWriteIndex:0,endOfPassWriteIndex:1};return true;\n}\nfunction nxGpuTimerResolve(T,enc){enc.resolveQuerySet(T.query,0,2,T.resolve,0);enc.copyBufferToBuffer(T.resolve,0,T.read,0,16);}\nasync function nxGpuTimerRead(T,owner,submission){\nconst frame=T.frame,dev=owner.dev;let mapped=false;\ntry{\nawait submission;\nif(GPU!==owner||T.stopped){T.stop('renderer-inactive');return;}\nawait T.read.mapAsync(GPUMapMode.READ);mapped=true;\nif(GPU!==owner||T.stopped){T.stop('renderer-replaced');return;}\nconst values=new BigUint64Array(T.read.getMappedRange());const start=values[0],end=values[1];\nif(end<start)throw Error('GPU timestamp interval reversed');\nT.last={frame:frame,start_ns:String(start),end_ns:String(end),duration_ns:String(end-start),duration_ms:Number(end-start)/1000000,scope:'world-and-cast-render-pass'};\nT.completed++;T.state='ready';\n}catch(e){if(!T.stopped){T.failed++;T.error=String(e);T.stop('readback-failed');}}\nfinally{if(mapped&&!T.stopped)T.read.unmap();T.busy=false;}\n}\nfunction nxGpuTimerStop(owner,reason){const T=owner&&owner.timer;if(T&&typeof T.stop==='function')T.stop(reason);}\nasync function nxGpuTimerPoolInit(dev,policy){\nconst P={state:'configuration-required',observed_frames:0,unavailable_frames:0,attempted:0,completed:0,busy_frames:0,failed:0,cancelled:0,inflight:0,peak_inflight:0,last:null,slots:[],stopped:false,cleanup_errors:[],results:[],result_dropped:0};\nP.drain=function(){return P.results.splice(0);};\nP.stop=function(reason){if(P.stopped)return;P.stopped=true;P.state=reason;for(const slot of P.slots){if(slot.leased){P.cancelled++;slot.leased=false;}slot.stop(reason);P.cleanup_errors.push(...slot.cleanup_errors);}P.inflight=0;};\nif(!policy||!Number.isSafeInteger(policy.slots)||!Number.isSafeInteger(policy.buffer_budget_bytes)||policy.slots<1||policy.buffer_budget_bytes<1||policy.slots>Math.floor(policy.buffer_budget_bytes/32)){P.error='GPU timing policy requires positive integer slots within the explicit buffer budget (32 bytes per slot; driver/query allocation overhead excluded).';return P;}\nP.capacity=policy.slots;P.buffer_bytes=policy.slots*32;P.buffer_budget_bytes=policy.buffer_budget_bytes;\nif(!dev.features.has('timestamp-query')){P.state='unsupported';return P;}\nfor(let i=0;i<P.capacity;i++){const slot=await nxGpuTimerInit(dev);P.slots.push(slot);if(P.stopped){slot.stop(P.state);return P;}if(slot.state!=='ready'){P.error=slot.error;P.stop(slot.state);return P;}}\nP.state='ready';dev.lost.then(function(){P.stop('device-lost');});return P;\n}\nfunction nxGpuTimerPoolBegin(P,descriptor,frame){\nif(!P)return null;\nP.observed_frames++;\nif(P.stopped||P.state==='unsupported'||P.state==='configuration-required'){P.unavailable_frames++;return null;}\nP.attempted++;const slot=P.slots.find(function(s){return !s.leased&&!s.stopped;});\nif(!slot){P.busy_frames++;return null;}\nif(!nxGpuTimerBegin(slot,descriptor,frame)){P.failed++;return null;}\nslot.leased=true;P.inflight++;P.peak_inflight=Math.max(P.peak_inflight,P.inflight);P.state='pending';return slot;\n}\nasync function nxGpuTimerPoolRead(P,slot,owner,submission){\nif(!slot||!slot.leased||slot.reading||P.stopped)return;\nslot.reading=true;const completed=slot.completed;\ntry{await nxGpuTimerRead(slot,owner,submission);\nif(P.stopped)return;\nif(slot.stopped){P.failed++;P.error=slot.error;slot.leased=false;P.inflight--;P.stop(slot.state);return;}\nif(slot.completed===completed+1){P.completed++;if(P.results.length===P.capacity){P.results.shift();P.result_dropped++;}P.results.push(slot.last);if(!P.last||slot.last.frame>P.last.frame)P.last=slot.last;}\nelse{P.failed++;P.error='readback completed without one attributable interval';slot.leased=false;P.inflight--;P.stop('readback-failed');}\n}catch(e){if(!P.stopped){P.failed++;P.error=String(e);slot.leased=false;P.inflight--;P.stop('readback-failed');}}\nfinally{slot.reading=false;if(slot.leased){slot.leased=false;P.inflight--;}if(!P.stopped)P.state=P.inflight?'pending':'ready';}\n}\nasync function nxGpuTimerAttach(owner){const token={};owner.timerAttachToken=token;nxGpuTimerStop(owner,'renderer-replaced');const pool=await nxGpuTimerPoolInit(owner.dev,window.__nx_gpu_timing_policy);if(!nxDemand.active||GPU!==owner||owner.timerAttachToken!==token){pool.stop('renderer-inactive');return;}owner.timer=pool;window.__nx_gpu_timer=pool;}\nnxDemand.onChange(function(active){if(!GPU)return;if(!active){GPU.timerAttachToken=null;nxGpuTimerStop(GPU,'page-inactive');return;}const owner=GPU;nxGpuTimerAttach(owner).catch(function(error){if(GPU===owner)window.__nx_gpu_timer={state:'initialization-failed',error:String(error)};});});\nasync function gpuInit(){try{\nconst ad=await navigator.gpu.requestAdapter(nxGpuAdapterOptions());if(!ad)throw \"no-adapter\";\nconst dev=await nxGpuTimingDevice(ad);\n// EVERY WEBGPU ERROR IS NAMED (2026-09-06): validation and out-of-memory errors never throw, so without this listener a broken pass reads as a taken door over a black canvas. gpuDraw refuses on the first recorded error, which demotes through the bounded-retry ladder with the reason in the URL.\ndev.addEventListener('uncapturederror',function(e9u){window.__sov_gpuerr=String(e9u.error&&e9u.error.message?e9u.error.message:e9u.error);console.log('nishi: webgpu uncaptured error '+window.__sov_gpuerr);});\n// GP3: the kernel's limits come from knowledge/tier_ladder.conf (limit| rows); a device under any minimum refuses THIS door by name and the ladder walks on.\nconst L9=window.__nx_gpu_limits||{};for(const k9 in L9){const h9=(dev.limits&&typeof dev.limits[k9]===\"number\")?dev.limits[k9]:undefined;if(typeof h9===\"number\"&&h9<L9[k9])throw \"limit:\"+k9+\"=\"+h9+\"<\"+L9[k9];}\nconst fmt=navigator.gpu.getPreferredCanvasFormat();\nconst t3=dev.createTexture({size:[128,128,48],dimension:\"3d\",format:\"r8uint\",usage:GPUTextureUsage.TEXTURE_BINDING|GPUTextureUsage.COPY_DST});\nconst th=dev.createTexture({size:[128,128],format:\"r32float\",usage:GPUTextureUsage.TEXTURE_BINDING|GPUTextureUsage.COPY_DST});\nif(!NXU_SIZE)throw \"uniform-layout-absent-at-emit\";\nconst ub=dev.createBuffer({size:NXU_SIZE,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST});\nif(location.search.indexOf(\"hand=1\")>=0)throw \"hand-world-shader-retired-2026-09-05\";const IR=true;if(!WGSL_IRF)throw \"world-ir-absent-at-emit\";if(IR&&!WGSL_IRV)throw \"world-ir-vertex-absent-at-emit\";\nconst mkm=async(code,tag)=>{const md=dev.createShaderModule({code});const inf=await md.getCompilationInfo();for(const m of inf.messages){if(m.type===\"error\")throw tag+\":\"+m.lineNum+\":\"+m.message;}return md;};\nwindow.__nx_gpugate.step=\"shaders\";const mdV=await mkm(IR?WGSL_IRV:WGSL,IR?\"irvs\":\"wgsl\");const mdF=IR?await mkm(WGSL_IRF,\"irfs\"):mdV;\n// S12 step 1 (2026-09-06): the CAST stages (one NishiLang source, IDENTICAL to the hand GLSL under nx_glsl_tokdiff) are COMPILED\n// on this device through the same mkm and the verdict is announced -- the GPU-host compile IS the WGSL validity oracle, so it\n// runs on every load; a refusal is named, never thrown: the world door must not die for a cast that is not yet drawn here.\ndev.pushErrorScope('validation');let castW9=\"absent-at-emit\";if(WGSL_CASTV&&WGSL_CASTF){try{await mkm(WGSL_CASTV,\"castvs\");await mkm(WGSL_CASTF,\"castfs\");castW9=\"compiled\";}catch(e9c){castW9=\"refused:\"+String(e9c);}}window.__nx_cast_wgsl=castW9;console.log(\"nishi: cast WGSL \"+castW9);\nlet cpl9=null,hpl9=null,authoredPipeline9=null;try{if(WGSL_CASTV&&WGSL_CASTF){const cvm=await mkm(WGSL_CASTV,'castvsP');const cfm=await mkm(WGSL_CASTF,'castfsP');const vb9=function(st9,loc9,fm9){return {arrayStride:st9,attributes:[{shaderLocation:loc9,offset:0,format:fm9}]};};cpl9=dev.createRenderPipeline({layout:'auto',depthStencil:{format:'depth24plus',depthWriteEnabled:true,depthCompare:'less'},vertex:{module:cvm,entryPoint:'main',buffers:[vb9(12,0,'float32x3'),vb9(16,1,'float32x4'),vb9(16,2,'float32x4'),vb9(12,3,'float32x3'),vb9(8,4,'float32x2'),vb9(4,5,'float32'),vb9(0,6,'float32x4')]},fragment:{module:cfm,entryPoint:'main',targets:[{format:fmt}]},primitive:{topology:'triangle-list'}});hpl9=dev.createRenderPipeline({layout:'auto',depthStencil:{format:'depth24plus',depthWriteEnabled:true,depthCompare:'less'},vertex:{module:cvm,entryPoint:'main',buffers:[vb9(12,0,'float32x3'),vb9(16,1,'float32x4'),vb9(16,2,'float32x4'),vb9(12,3,'float32x3'),vb9(8,4,'float32x2'),vb9(4,5,'float32'),vb9(0,6,'float32x4')]},fragment:{module:cfm,entryPoint:'main',targets:[{format:fmt}]},primitive:{topology:'line-list'}});const authoredCache=new Map();authoredPipeline9=function(alpha,doubleSided){const key=alpha+':'+doubleSided;if(authoredCache.has(key))return authoredCache.get(key);const target={format:fmt};if(alpha===2)target.blend={color:{srcFactor:'src-alpha',dstFactor:'one-minus-src-alpha',operation:'add'},alpha:{srcFactor:'one',dstFactor:'one-minus-src-alpha',operation:'add'}};const pipeline=dev.createRenderPipeline({layout:'auto',depthStencil:{format:'depth24plus',depthWriteEnabled:alpha!==2,depthCompare:'less'},vertex:{module:cvm,entryPoint:'main',buffers:[vb9(12,0,'float32x3'),vb9(16,1,'float32x4'),vb9(16,2,'float32x4'),vb9(12,3,'float32x3'),vb9(8,4,'float32x2'),vb9(4,5,'float32'),vb9(16,6,'float32x4')]},fragment:{module:cfm,entryPoint:'main',targets:[target]},primitive:{topology:'triangle-list',frontFace:'cw',cullMode:doubleSided?'none':'back'}});authoredCache.set(key,pipeline);return pipeline;};window.__nx_cast_pipe='created';}else{window.__nx_cast_pipe='absent-at-emit';}}catch(e9p){window.__nx_cast_pipe='refused:'+String(e9p);}const ce9=await dev.popErrorScope();window.__nx_cast_scope=ce9?String(ce9.message):'clean';window.__nx_world_src=IR?\"ir\":\"hand\";\nconst pl=dev.createRenderPipeline({layout:\"auto\",depthStencil:{format:\"depth24plus\",depthWriteEnabled:NX_WORLD_DEPTH,depthCompare:\"always\"},vertex:{module:mdV,entryPoint:IR?\"main\":\"vs\"},fragment:{module:mdF,entryPoint:IR?\"main\":\"fs\",targets:[{format:fmt}]},primitive:{topology:\"triangle-list\"}});\nwindow.__nx_frame_blocks=function(gx,gy){const c2=document.createElement(\"canvas\");c2.width=cv.width;c2.height=cv.height;const x2=c2.getContext(\"2d\");x2.drawImage(cv,0,0);const d=x2.getImageData(0,0,cv.width,cv.height).data;const o=[];for(let by=0;by<gy;by++)for(let bx=0;bx<gx;bx++){let r=0,g=0,b=0,k=0;const x0=Math.floor(bx*cv.width/gx),x1=Math.floor((bx+1)*cv.width/gx),y0=Math.floor(by*cv.height/gy),y1=Math.floor((by+1)*cv.height/gy);for(let y=y0;y<y1;y++)for(let x=x0;x<x1;x++){const i=(y*cv.width+x)*4;r+=d[i];g+=d[i+1];b+=d[i+2];k++;}o.push(Math.round(r/k),Math.round(g/k),Math.round(b/k));}return o;};\n// BIND ONLY WHAT THE SHADER DECLARES (2026-09-06, the black-frame root cause): the page bound the GE53 heightfield texture at binding 2 while the emitted world shader declared bindings 0 and 1 only. Under layout:auto that is a WebGPU VALIDATION error: createBindGroup does not throw, the bind group is invalid, every pass that uses it is dropped, and the canvas stays clear-black while the door reads taken. The entries are DERIVED from the shader text, so page and shader cannot disagree, and the validation scope turns any residual mismatch into a NAMED refusal that walks the ladder.\nconst bnd9=[];{const s9=IR?WGSL_IRF:WGSL;let p9=0;for(;;){const k9=s9.indexOf('@binding',p9);if(k9<0)break;let e9=k9+9;let n9=0;while(e9<s9.length&&s9.charCodeAt(e9)>=48&&s9.charCodeAt(e9)<=57){n9=n9*10+(s9.charCodeAt(e9)-48);e9++;}bnd9.push(n9);p9=e9;}}\nconst ent9=[{binding:0,resource:{buffer:ub}}];if(bnd9.indexOf(1)>=0)ent9.push({binding:1,resource:t3.createView()});if(bnd9.indexOf(2)>=0)ent9.push({binding:2,resource:th.createView()});\nwindow.__nx_gpubind={declared:bnd9,bound:ent9.length};\ndev.pushErrorScope('validation');\nconst bg=dev.createBindGroup({layout:pl.getBindGroupLayout(0),entries:ent9});\nconst ve9=await dev.popErrorScope();if(ve9)throw 'bindgroup-validation:'+ve9.message;\nif(window.__gpu_late){window.__sov_gpufail=\"finished-after-boot-ceiling; ladder already moved on (canvas untouched)\";return;}\n// CANVAS CLAIMED LAST (2026-08-23): a canvas holds ONE context type forever, and the old order\n// claimed it FIRST -- any wgsl, pipeline or late failure after that left a poisoned canvas where\n// webgl2 AND 2d both return null: the silent black screen. Everything device-side is proven\n// BEFORE the page surface is touched; only configure() can fail post-claim, and the sovCanvas2d\n// recovery reloads onto ?gl=0 for exactly that residual.\nconst gctx=cv.getContext(\"webgpu\");if(!gctx)throw \"no-context\";\ngctx.configure({device:dev,format:fmt,alphaMode:\"opaque\"});\nVOX=Number(ex.vox_off());SPC=Number(ex.spec_off());\nnxGpuTimerStop(GPU,'renderer-replaced');GPU={dev,gctx,t3,th,ub,pl,bg,cpl:cpl9,hpl:hpl9,authoredPipeline:authoredPipeline9,lastEd:-1};try{await nxGpuTimerAttach(GPU);}catch(e){window.__nx_gpu_timer={state:'initialization-failed',attempted:0,completed:0,busy_frames:0,failed:1,last:null,error:String(e)};}window.__nx_gpugate.step=\"afterGPU\";\n// S11: the device arrives AFTER the page-bottom loadNPC call site has run, so the cast upload is hooked here; loadNPC carries an idempotency flag, so whichever hook wins runs it once.\nif(ex.mobx&&typeof loadNPC==='function')loadNPC().then(function(){if(CAST9)return loadDonors();}).catch(function(e9G){window.__gpu_npcfail=String(e9G);});\nex.set_yflip(1n);\nwindow.__sov_gpu=1;nxGpuAdapterReport(ad);\n// GP2 KERNEL DOOR PROBE (?kernel=1): the GE43 compute kernel through THIS device, read back and diffed against the CPU reference.\nif(location.search.indexOf(\"kernel=1\")>=0){nxKernelProbe(dev);}\n}catch(e){window.__sov_gpufail=String(e);console.log(\"nishi: WebGPU unavailable, next tier\",e);GPU=null;}}\n" as *u8)
949 p = gpe_ap(out, p, "// S12 step 2 (2026-09-06): THE CAST ON THE WEBGPU DOOR -- the resident cast body mesh drawn by the ported MVS/MFS (one NishiLang source, nx_cast_shader_src) through a real render pipeline: the SAME per-frame state castFrame() builds for WebGL2 (positions, heading, gait, joint dual-quats, skin/outfit/hair genome, garment ids, mood) packed into the two uniform blocks at the offsets nx_wgsl cast DERIVED at emit (NXCV / NXCF), the joint rows written to the rgba32float table, six vertex buffers + u16 indices, drawIndexed over the visible girls. Vertex resources ride bind group 0, fragment resources group 1 (two structs named U cannot share one buffer). Not on this door yet, declared: planar cast shadows, the dress and garment meshes, hair ribbons, eyeballs, the visiting cast. Every failure is CAPTURED in a validation scope and named in window.__nx_cast_draw -- the world pass is never demoted for the cast.\nfunction nxCastPk3(F9,off9,a9,n9){for(let i9=0;i9<n9;i9++){F9[off9/4+i9*4]=a9[i9*3];F9[off9/4+i9*4+1]=a9[i9*3+1];F9[off9/4+i9*4+2]=a9[i9*3+2];}}\nfunction nxCastSun(){if(window.__sund)return window.__sund;const U9=new Int32Array(ex.memory.buffer,Number(ex.uniform_off()),44);const sel9=U9[6]/4096,dfr9=U9[7]/Math.max(1,U9[8]);const az9=Math.PI*(1-dfr9*1.6),el9=Math.asin(Math.max(-.99,Math.min(.99,sel9)));let sx9=Math.cos(el9)*Math.cos(az9),sy9=Math.sin(el9),sz9=Math.cos(el9)*.45;const sl9=Math.hypot(sx9,sy9,sz9)||1;return [sx9/sl9,sy9/sl9,sz9/sl9];}\nfunction nxGpuCastPrepare(dev,G,enc){G.castPreparedRows=0;try{const R=GPU.npc,N=GPU.cast;if(!G.cpl||!R||!R.ok||!N||!N.ok||G.castdead)return;if(!NXCV||!NXCF){window.__nx_cast_draw='refused:layout-absent-at-emit';G.castdead=1;return;}\nconst nm=Number(ex.mobs());if(nm<=0)return;const nv=castFrame(N,nm);if(nv===0)return;\ndev.pushErrorScope('validation');G.cscope=1;\nif(!G.cub){G.cub=dev.createBuffer({size:NXCV_SIZE,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST});G.cuf=dev.createBuffer({size:NXCF_SIZE,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST});G.cvb=new ArrayBuffer(NXCV_SIZE);G.cfb=new ArrayBuffer(NXCF_SIZE);G.castCVBytes=new Uint8Array(G.cvb);G.castCFBytes=new Uint8Array(G.cfb);\nG.dum=dev.createTexture({size:[1,1],format:'rgba8unorm',usage:GPUTextureUsage.TEXTURE_BINDING|GPUTextureUsage.COPY_DST});dev.queue.writeTexture({texture:G.dum},new Uint8Array([128,128,255,255]),{bytesPerRow:4},[1,1]);\nG.cbgv=dev.createBindGroup({layout:G.cpl.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:G.cub}},{binding:1,resource:R.jt.createView()},{binding:3,resource:G.dum.createView()}]});\nG.cbgf=dev.createBindGroup({layout:G.cpl.getBindGroupLayout(1),entries:[{binding:0,resource:{buffer:G.cuf}},{binding:1,resource:G.t3.createView()},{binding:2,resource:(R.atl||G.dum).createView()},{binding:3,resource:R.samp},{binding:4,resource:(R.nrm||G.dum).createView()},{binding:5,resource:R.samp}]});}\ndev.queue.writeTexture({texture:R.jt,origin:[0,1,0]},N.jf.subarray(0,R.nj*8*nv),{bytesPerRow:R.nj*16,rowsPerImage:2*nv},[R.nj,2*nv,1]);\nconst F=new Float32Array(G.cvb),I=new Int32Array(G.cvb),H=new Float32Array(G.cfb),J=new Int32Array(G.cfb);F.fill(0);H.fill(0);\nconst cam0=Number(nxView(\"view_x\",\"camx\"))/256,cam1=Number(nxView(\"view_y\",\"camy\"))/256,cam2=Number(nxView(\"view_z\",\"camz\"))/256,ya=Number(nxView(\"view_yaw\",\"yaw\"))/4096,pi3=Number(nxView(\"view_pitch\",\"pitch\"))/4096;\nconst sd9=nxCastSun();const dv9=new DataView(ex.memory.buffer);const skt9=Number(dv9.getBigInt64(SPC+7*8,true));const V9=NXCV,K9=NXCF;\nF[V9.uSc/4]=1.78/171530;nxCastPk3(F,V9.uIP,N.ip,12);F.set(N.ih,V9.uIH/4);if(ex.sbx)nxCastPk3(F,V9.uSB,N.sb,72);F.set(N.of,V9.uOF/4);if(N.gb){F.set(N.gb,V9.uGB/4);F.set(N.gt,V9.uGT/4);}I[V9.uGK/4]=0;F.set(N.gn,V9.uGN/4);\nF[V9.uTm/4]=Number(ex.tnow())/60;{const w9x=(window.__wxw&&window.__wxw[0])||0,w9z=(window.__wxw&&window.__wxw[1])||0;F[V9.uWnd/4]=Math.min(1,Math.hypot(w9x,w9z))*(NXHCH_N*NXHCH_LIM/NXHCH_Q8)*(N.hscale||0)*(1.78/171530);}\nF[V9.uZMN/4]=N.an.zmn;F[V9.uH/4]=N.an.H;F[V9.uNIP/4]=N.an.nip;\nif(N.dyn&&N.dyn.length>=2){const dl9=N.dyn.find(function(d){return d.side<0;}),dr9=N.dyn.find(function(d){return d.side>0;});if(dl9&&dr9){F.set([dl9.x,dl9.y,dl9.z,dl9.infl],V9.uDNL/4);F.set([dr9.x,dr9.y,dr9.z,dr9.infl],V9.uDNR/4);if(N.dyn.length>=6){const db9=N.dyn[2],dg9=N.dyn[3],dt19=N.dyn[4],dt29=N.dyn[5];F.set([db9.x,db9.y,db9.z,db9.infl],V9.uDNB/4);F.set([dg9.x,dg9.y,dg9.z,dg9.infl],V9.uDNG/4);F.set([dt19.x,dt19.y,dt19.z,dt19.infl],V9.uDNTl/4);F.set([dt29.x,dt29.y,dt29.z,dt29.infl],V9.uDNTr/4);}}}\nF.set([cam0,cam1,cam2],V9.uCamM/4);F.set([Math.sin(ya),Math.cos(ya),Math.sin(pi3),Math.cos(pi3)],V9.uYPM/4);F.set([cv.width,cv.height],V9.uResM/4);F.set([sd9[0],sd9[1],sd9[2]],V9.uSunM/4);I[V9.uHM/4]=1;I[V9.uGar/4]=0;I[V9.uAuth/4]=0;I[V9.uShd/4]=0;\nH.set([cam0,cam1,cam2],K9.uCamM/4);H.set([(skt9&255)/255,((skt9>>8)&255)/255,((skt9>>16)&255)/255],K9.uSkTM/4);J[K9.uOcc/4]=location.search.indexOf('npcocc=0')>=0?0:(location.search.indexOf('npcocc=2')>=0?2:1);\nnxCastPk3(H,K9.uCS,N.cs,12);nxCastPk3(H,K9.uCO,N.co,12);nxCastPk3(H,K9.uCH,N.ch,12);J[K9.uGar/4]=0;H.set(N.gn,K9.uGN/4);H.set(N.of,K9.uOF/4);if(N.gt){H.set(N.gt,K9.uGT/4);H.set(N.gb,K9.uGB/4);nxCastPk3(H,K9.uCT,N.ct,12);nxCastPk3(H,K9.uCB,N.cb,12);}\nJ[K9.uGK/4]=0;J[K9.uGM/4]=0;J[K9.uGMH/4]=(R.gmValidated&&location.search.indexOf('garpaint=1')<0)?R.gmValidatedMask:0;H.set(N.mdf,K9.uMoodF/4);H.set(N.bh,K9.uBH/4);H[K9.uTm/4]=Number(ex.tnow())/60;H.set(N.ih,K9.uIH/4);J[K9.uEyeG/4]=0;J[K9.uAnatM/4]=(typeof ANAT9!=='undefined'&&ANAT9)?1:0;\nJ[K9.uAtlOn/4]=R.atl?1:0;H.set(N.atlMean||[1,1,1],K9.uAtlMean/4);J[K9.uAuth/4]=0;H[K9.uZMN/4]=N.an.zmn;H[K9.uH/4]=N.an.H;H[K9.uNIP/4]=N.an.nip;H[K9.uEYE/4]=N.an.eye;H.set([sd9[0],sd9[1],sd9[2]],K9.uSunM/4);J[K9.uShd/4]=0;H.set(NXSKYF,K9.uSkyF/4);J[K9.uVt/4]=location.search.indexOf('tm=0')>=0?0:1;J[K9.uNrmOn/4]=R.nrm?1:0;nxBindNormalEncodingGPU(J,K9,R.normalEncoding);J[K9.uSkinMaps/4]=nxSkinMapMode(R.skinMaps);J[K9.uInspect/4]=REV?nxInspect.surface:0;J[K9.uEyeG/4]=nxGpuEyePrepare(dev,G,R,N,nv)?1:0;\ndev.queue.writeBuffer(G.cub,0,G.cvb);dev.queue.writeBuffer(G.cuf,0,G.cfb);\nif(R.surface)R.surface.prepare(enc,G,N,nv,nm);nxGpuHairPrepare(dev,G,R,N,nv);G.castPreparedRows=nv;\n}catch(e){window.__nx_cast_draw='prepare-refused:'+String(e);if(window.__nx_surface){window.__nx_surface.state='refused';window.__nx_surface.reason=String(e);}G.castdead=1;}finally{nxPreparedRefresh();}}\nfunction nxGpuHairPrepare(dev,G,R,N,nv){const h=R.hair;G.hairSubmitted=0;if(!h)return;\n const pipeline=h.mode===1?G.cpl:G.hpl;if(!pipeline){window.__nx_hair_gpu.state='refused';window.__nx_hair_gpu.reason='hair topology pipeline unavailable';return;}\n if(h.pipeline!==pipeline){h.bgv=dev.createBindGroup({layout:pipeline.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:h.cub}},{binding:1,resource:R.jt.createView()},{binding:3,resource:G.dum.createView()}]});h.bgf=dev.createBindGroup({layout:pipeline.getBindGroupLayout(1),entries:[{binding:0,resource:{buffer:h.cuf}},{binding:1,resource:G.t3.createView()},{binding:2,resource:(R.atl||G.dum).createView()},{binding:3,resource:R.samp},{binding:4,resource:(R.nrm||G.dum).createView()},{binding:5,resource:R.samp}]});h.pipeline=pipeline;}\n new Uint8Array(h.cvb).set(new Uint8Array(G.cvb));new Uint8Array(h.cfb).set(new Uint8Array(G.cfb));\n const F=new Float32Array(h.cvb),I=new Int32Array(h.cvb),J=new Int32Array(h.cfb);\n if(nxHairStep(N))nxCastPk3(F,NXCV.uHF2,N.hch.hf,NXHCH_N*NXHCH_NPC);\n I[NXCV.uGar/4]=2;I[NXCV.uHM/4]=h.mode===1?1:8;J[NXCF.uGar/4]=2;\n dev.queue.writeBuffer(h.cub,0,h.cvb);dev.queue.writeBuffer(h.cuf,0,h.cfb);\n const kids=Math.max(1,N.hkid|0),quality=window.__hairq>0?window.__hairq:1;let count=Math.min(kids,Math.max(1,Math.round(kids*quality)));const floor=window.__hairfloor|0;if(floor>0)count=Math.min(count,floor);\n h.drawVertices=h.mode===1&&N.hvpk>0&&count<kids?count*N.hvpk:h.nv;h.drawInstances=h.mode===1?nv:nv*8;h.prepared=true;\n}\nfunction nxGpuHairDraw(G,rp){const h=G.npc.hair;if(!h||!h.prepared)return;h.prepared=false;rp.setPipeline(h.pipeline);rp.setBindGroup(0,h.bgv);rp.setBindGroup(1,h.bgf);rp.setVertexBuffer(0,h.bp);rp.setVertexBuffer(1,h.bj);rp.setVertexBuffer(2,h.bw);rp.setVertexBuffer(3,h.bn);rp.setVertexBuffer(4,h.buv);rp.setVertexBuffer(5,h.bhs);rp.setVertexBuffer(6,h.bt);rp.draw(h.drawVertices,h.drawInstances);G.hairSubmitted=h.drawVertices;window.__nx_hair_gpu.state='submitted';window.__nx_hair_gpu.submitted=h.drawVertices;window.__nx_hair_gpu.instances=h.drawInstances;}\nfunction nxGpuCast(dev,G,rp){try{const R=G.npc,N=G.cast,nv=G.castPreparedRows,V9=NXCV,K9=NXCF;if(!nv||G.castdead||!R||!N)return;\nrp.setPipeline(G.cpl);rp.setBindGroup(0,G.cbgv);rp.setBindGroup(1,G.cbgf);rp.setVertexBuffer(0,R.bp);rp.setVertexBuffer(1,R.bj);rp.setVertexBuffer(2,R.bw);rp.setVertexBuffer(3,R.bn);rp.setVertexBuffer(4,R.buv);rp.setVertexBuffer(5,R.bhs);rp.setVertexBuffer(6,R.bt);rp.setIndexBuffer(R.ib,'uint16');rp.drawIndexed(R.ni,nv);\n\nlet garmentSubmitted=0,garmentSubmittedMask=0;\nfor(const mesh of R.gm||[]){\n let worn=false;for(let ii=0;ii<nv;ii++){const wardrobe=(mesh.id===1||mesh.id===6)?N.gt:N.gb;const id=wardrobe?Math.round(wardrobe[ii]):0;if(nxGarmentFamilyWorn(mesh.id,id)){worn=true;break;}}\n if(!worn)continue;\n let surfaceDrawn=false;\n if(R.surface&&mesh.id===R.surface.kind&&R.surface.rows===nv){R.surface.draw(rp,mesh);garmentSubmitted++;garmentSubmittedMask|=1<<mesh.id;surfaceDrawn=true;if(!mesh.strapNi)continue;}\n if(mesh.pipeline!==G.cpl){mesh.bgv=dev.createBindGroup({layout:G.cpl.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:mesh.cub}},{binding:1,resource:R.jt.createView()},{binding:3,resource:G.dum.createView()}]});mesh.bgf=dev.createBindGroup({layout:G.cpl.getBindGroupLayout(1),entries:[{binding:0,resource:{buffer:mesh.cuf}},{binding:1,resource:G.t3.createView()},{binding:2,resource:(R.atl||G.dum).createView()},{binding:3,resource:R.samp},{binding:4,resource:(R.nrm||G.dum).createView()},{binding:5,resource:R.samp}]});mesh.pipeline=G.cpl;}\n new Uint8Array(mesh.cvb).set(new Uint8Array(G.cvb));new Uint8Array(mesh.cfb).set(new Uint8Array(G.cfb));\n const mi=new Int32Array(mesh.cvb),mj=new Int32Array(mesh.cfb);mi[V9.uGar/4]=3;mi[V9.uGK/4]=mesh.id;mj[K9.uGar/4]=3;mj[K9.uGK/4]=mesh.id;mj[K9.uGM/4]=mesh.m;\n dev.queue.writeBuffer(mesh.cub,0,mesh.cvb);dev.queue.writeBuffer(mesh.cuf,0,mesh.cfb);\n rp.setBindGroup(0,mesh.bgv);rp.setBindGroup(1,mesh.bgf);rp.setVertexBuffer(0,mesh.bp);rp.setVertexBuffer(1,mesh.bj);rp.setVertexBuffer(2,mesh.bw);rp.setVertexBuffer(3,mesh.bn);rp.setVertexBuffer(4,mesh.buv);rp.setVertexBuffer(5,mesh.bhs);rp.setVertexBuffer(6,mesh.bt);rp.setIndexBuffer(surfaceDrawn?mesh.strapIb:mesh.ib,'uint16');rp.drawIndexed(surfaceDrawn?mesh.strapNi:mesh.ni,nv);if(!surfaceDrawn){garmentSubmitted++;garmentSubmittedMask|=1<<mesh.id;}else if(window.__nx_surface){window.__nx_surface.strap_indices=mesh.strapNi;window.__nx_surface.mixed_strap_triangles=mesh.mixedStrapTriangles;}\n}\nnxGpuHairDraw(G,rp);nxGpuEyeDraw(G,rp);\nG.garmentSubmitted=garmentSubmitted;G.garmentSubmittedMask=garmentSubmittedMask;if(window.__nx_garment_gpu){window.__nx_garment_gpu.submitted=garmentSubmitted;window.__nx_garment_gpu.state='submitted';}\nwindow.__nx_cast_drawn=nv;window.__nx_cast_draw='drawn';}catch(e9c){window.__nx_cast_draw='refused:'+String(e9c);G.castdead=1;}}\nfunction nxGpuCastPop(dev,G){\n if(!G.cscope)return;G.cscope=0;\n const resident=G.npc,submitted=G.garmentSubmitted||0,mask=G.garmentSubmittedMask||0,hairSubmitted=G.hairSubmitted||0,eyeSubmitted=G.eyeSubmitted||0,eyeFrame=G.eyeFrame;\n const refuse=function(error){if(GPU!==G||G.npc!==resident)return;G.castdead=1;if(window.__nx_eye_gpu){window.__nx_eye_gpu.state='refused';window.__nx_eye_gpu.reason=String(error.message||error);}if(window.__nx_hair_gpu){window.__nx_hair_gpu.state='refused';window.__nx_hair_gpu.reason=String(error.message||error);}if(resident)resident.gmValidated=false;if(window.__nx_garment_gpu){window.__nx_garment_gpu.state='refused';window.__nx_garment_gpu.reason=String(error.message||error);}window.__nx_cast_draw='validation:'+String(error.message||error);};\n dev.popErrorScope().then(function(error){if(GPU!==G||G.npc!==resident)return;if(error){refuse(error);return;}if(G.castdead)return;\n if(eyeSubmitted&&G.eyeFrame===eyeFrame&&window.__nx_eye_gpu){window.__nx_eye_gpu.state='validated';window.__nx_eye_gpu.validated=eyeSubmitted;}\n if(hairSubmitted&&window.__nx_hair_gpu){window.__nx_hair_gpu.state='validated';window.__nx_hair_gpu.validated=hairSubmitted;}\n if(resident){resident.gmValidated=true;resident.gmValidatedMask=mask;}\n if(window.__nx_garment_gpu){window.__nx_garment_gpu.state='validated';window.__nx_garment_gpu.validated=submitted;window.__nx_garment_gpu.validatedMask=mask;}\n }).catch(refuse);\n}\nfunction gpuDraw(){const G=GPU,dev=G.dev;\nif(window.__sov_gpuerr)throw 'webgpu-uncaptured:'+window.__sov_gpuerr;\nif(!G.castsaid){G.castsaid=1;window.__sov_gpucast='Resident body mesh is wired on WebGPU; inspect __nx_cast_draw for submission or validation status. Shader compilation: '+window.__nx_cast_wgsl+'. Garment mesh upload/submission is reported by __nx_garment_gpu. Hair ribbons, eyeballs, planar cast shadows and visiting characters still need parity with WebGL2.';console.log('nishi: '+window.__sov_gpucast);}\n// resolution + refresh + uniform VALUES mirror glDraw exactly (same organ doors, same math);\n// consolidation into one shared frameU() is OWED AT GRADUATION -- while this tier is levered,\n// touching the proven GL path to share code would put the experiment inside the incumbent.\nconst dpr=devicePixelRatio||1;const q=Number(ex.quality?ex.quality():2);\nlet scl=1;\n// scale floor + review-outranks-governor: MIRRORS glDraw exactly (see its derivation; the shared\n// frameU() consolidation stays owed at this tier's graduation).\n\n\nconst _mob9=(\"ontouchstart\" in window)||navigator.maxTouchPoints>0;\nconst _PXB=_mob9?2300000:8300000;\nlet wpx=Math.max(64,Math.floor(cv.clientWidth*dpr*scl)),hpx=Math.max(64,Math.floor(cv.clientHeight*dpr*scl));\nif(wpx*hpx>_PXB){const f9=Math.sqrt(_PXB/(wpx*hpx));wpx=Math.max(64,Math.floor(wpx*f9));hpx=Math.max(64,Math.floor(hpx*f9));}\nwindow.__px=wpx+\"x\"+hpx+(_mob9?\"mG\":\"dG\");\nif(cv.width!==wpx||cv.height!==hpx){cv.width=wpx;cv.height=hpx;}\n// S10 (2026-09-05): the DEPTH ATTACHMENT of the WebGPU tier -- one depth24plus texture sized to the canvas, recreated on resize,\n// cleared to 1.0 every frame. The world pass is a BACKGROUND (depthWriteEnabled:false, depthCompare:always); the cast pipeline\n// (S12) tests against the cleared buffer. Owed S10b: the raycaster writes its hit distance through @builtin(frag_depth).\nif(!G.dt||G.dtw!==cv.width||G.dth!==cv.height){if(G.dt){G.dt.destroy();}G.dt=dev.createTexture({size:[cv.width,cv.height],format:\"depth24plus\",usage:GPUTextureUsage.RENDER_ATTACHMENT});G.dtw=cv.width;G.dth=cv.height;G.dtv=G.dt.createView();}\nconst ed=Number(ex.broken())+Number(ex.placed());const tn9=Number(ex.tnow());const ag9=ex.arena_gen?Number(ex.arena_gen()):0;\nif(ed!==G.lastEd||ag9!==G.lastAg||((tn9&63)===0&&tn9!==G.lastRefreshTick)){G.lastEd=ed;G.lastAg=ag9;G.lastRefreshTick=tn9;\ndev.queue.writeTexture({texture:G.t3},new Uint8Array(ex.memory.buffer,VOX,128*48*128),{bytesPerRow:128,rowsPerImage:128},[128,128,48]);\nif(G.th&&ex.hq_off){const hb9=new BigInt64Array(ex.memory.buffer,Number(ex.hq_off()),16384);const hf9=new Float32Array(16384);for(let i9=0;i9<16384;i9++){hf9[i9]=Number(hb9[i9])/256;}dev.queue.writeTexture({texture:G.th},hf9,{bytesPerRow:512},[128,128]);}}\nex.set_res(BigInt(cv.width),BigInt(cv.height));nxInspectionUpdate();ex.pack_uniforms();\ndev.queue.writeBuffer(G.ub,0,ex.memory.buffer,Number(ex.uniform_off()),NXU_SIZE);\nconst enc=dev.createCommandEncoder();\nconst passDescriptor={colorAttachments:[{view:G.gctx.getCurrentTexture().createView(),loadOp:\"clear\",storeOp:\"store\",clearValue:{r:0,g:0,b:0,a:1}}],depthStencilAttachment:{view:G.dtv,depthClearValue:1.0,depthLoadOp:\"clear\",depthStoreOp:\"store\"}};const timed=nxGpuTimerPoolBegin(G.timer,passDescriptor,G.frames||0);\nnxGpuCastPrepare(dev,G,enc);\nconst rp=enc.beginRenderPass(passDescriptor);\nrp.setPipeline(G.pl);rp.setBindGroup(0,G.bg);rp.draw(3);nxGpuCast(dev,G,rp);nxGpuDrawVisitors(dev,G,rp);rp.end();\nconst timerSubmission=timed?nxGpuTimerChecked(dev,function(){nxGpuTimerResolve(timed,enc);dev.queue.submit([enc.finish()]);}):null;if(!timed)dev.queue.submit([enc.finish()]);nxGpuCastPop(dev,G);if(timed)nxGpuTimerPoolRead(G.timer,timed,G,timerSubmission);\nif(NXBLOCKS&&!G.blocksDone&&G.frames>2){G.blocksDone=1;nxReadBlocks(dev,G);}G.frames=(G.frames||0)+1;}\n" as *u8)
950 return p
951}
952
953// GPE-VERIFY v2 (negctl PROVEN 2026-08-02: uBAD9 refused the ship, name printed) -- the
954// page-side compile lint (debt 1785728065, which bit TWICE on 2026-08-02:
955// a backtick inside a shader comment killed the whole page script, and a uniform used in a
956// stage that never declared it killed the NPC program -- both shipped behind GREEN gates,
957// caught only by screenshots). The emit lane cannot run a browser, but BOTH classes are
958// mechanically visible in the emitted bytes: (a) an UNCLOSED backtick segment = the JS-string
959// kill; (b) inside each backtick segment (the shader sources are the page's only template
960// literals), any uXxx token USED but not DECLARED as a uniform in THAT segment = the stage
961// kill. Fails CLOSED: any hit refuses the ship with the name printed.
962func gpe_verify(out: *u8, n: i64) -> i64 {
963 let names: *u8 = sys_mmap(64*32)
964 var nn: i64 = 0
965 var bad: i64 = 0
966 var seg: i64 = 0 - 1
967 var i: i64 = 0
968 while i < n {
969 if out[i] == (96 as u8) {
970 if seg < 0 { seg = i + 1 } else {
971 // ---- declarations in [seg, i) ----
972 nn = 0
973 var p: i64 = seg
974 while p < i - 8 {
975 var hit: i64 = 1
976 let kw: *u8 = "uniform " as *u8
977 var kk: i64 = 0
978 while kk < 8 { if out[p+kk] != kw[kk] { hit = 0; kk = 8 } else { kk = kk + 1 } }
979 if hit == 1 {
980 var q: i64 = p + 8
981 var ts: i64 = 0 - 1
982 var ls: i64 = 0 - 1
983 var le: i64 = 0 - 1
984 var run: i64 = 1
985 while run == 1 {
986 if q >= i { run = 0 } else {
987 let c: i64 = out[q] as i64
988 var idc: i64 = 0
989 if c >= 97 { if c <= 122 { idc = 1 } }
990 if c >= 65 { if c <= 90 { idc = 1 } }
991 if c >= 48 { if c <= 57 { idc = 1 } }
992 if c == 95 { idc = 1 }
993 if idc == 1 { if ts < 0 { ts = q } }
994 if idc == 0 {
995 if ts >= 0 { ls = ts; le = q; ts = 0 - 1 }
996 if c == 59 { run = 0 }
997 if c == 91 { run = 0 }
998 }
999 q = q + 1
1000 }
1001 }
1002 if ls >= 0 { if nn < 64 {
1003 var k: i64 = 0
1004 while k < 31 {
1005 if ls + k < le { names[nn*32+k] = out[ls+k] } else { names[nn*32+k] = 0 as u8 }
1006 k = k + 1
1007 }
1008 names[nn*32+31] = 0 as u8
1009 nn = nn + 1
1010 } }
1011 }
1012 p = p + 1
1013 }
1014 // ---- WGSL declarations in [seg, i) (S12 step 1, 2026-09-06): a WGSL stage declares its uniforms as
1015 // members of `struct U{ name:type, ... }` and its textures and samplers as `var name:...;`, never with the
1016 // `uniform` keyword -- so an identifier uXxx IMMEDIATELY followed by ':' (and not reached through '.',
1017 // which is a use) is a declaration in that segment. Without this the two cast WGSL literals killed the
1018 // ship on every one of their names (EMIT-FAIL, page under floor): the verifier working as designed
1019 // against a stage shape it had never seen, and the fix is the shape, not an exemption.
1020 var p3: i64 = seg
1021 while p3 < i - 2 {
1022 var go3: i64 = 0
1023 if out[p3] == (117 as u8) {
1024 let c4: i64 = out[p3+1] as i64
1025 if c4 >= 65 { if c4 <= 90 { go3 = 1 } }
1026 }
1027 if go3 == 1 { if p3 > seg {
1028 let pb3: i64 = out[p3-1] as i64
1029 if pb3 >= 97 { if pb3 <= 122 { go3 = 0 } }
1030 if pb3 >= 65 { if pb3 <= 90 { go3 = 0 } }
1031 if pb3 >= 48 { if pb3 <= 57 { go3 = 0 } }
1032 if pb3 == 95 { go3 = 0 }
1033 if pb3 == 46 { go3 = 0 }
1034 } }
1035 if go3 == 1 {
1036 var e3: i64 = p3 + 1
1037 var r3: i64 = 1
1038 while r3 == 1 {
1039 if e3 >= i { r3 = 0 } else {
1040 let c5: i64 = out[e3] as i64
1041 var id5: i64 = 0
1042 if c5 >= 97 { if c5 <= 122 { id5 = 1 } }
1043 if c5 >= 65 { if c5 <= 90 { id5 = 1 } }
1044 if c5 >= 48 { if c5 <= 57 { id5 = 1 } }
1045 if c5 == 95 { id5 = 1 }
1046 if id5 == 1 { e3 = e3 + 1 } else { r3 = 0 }
1047 }
1048 }
1049 if e3 < i { if out[e3] == (58 as u8) { if nn < 64 {
1050 var k3: i64 = 0
1051 while k3 < 31 {
1052 if p3 + k3 < e3 { names[nn*32+k3] = out[p3+k3] } else { names[nn*32+k3] = 0 as u8 }
1053 k3 = k3 + 1
1054 }
1055 names[nn*32+31] = 0 as u8
1056 nn = nn + 1
1057 } } }
1058 p3 = e3
1059 } else { p3 = p3 + 1 }
1060 }
1061 // ---- usages uXxx in [seg, i) ----
1062 var p2: i64 = seg
1063 while p2 < i - 1 {
1064 var go: i64 = 0
1065 if out[p2] == (117 as u8) {
1066 let c2: i64 = out[p2+1] as i64
1067 if c2 >= 65 { if c2 <= 90 { go = 1 } }
1068 }
1069 if go == 1 { if p2 > seg {
1070 let pb: i64 = out[p2-1] as i64
1071 if pb >= 97 { if pb <= 122 { go = 0 } }
1072 if pb >= 65 { if pb <= 90 { go = 0 } }
1073 if pb >= 48 { if pb <= 57 { go = 0 } }
1074 if pb == 95 { go = 0 }
1075 } }
1076 if go == 1 {
1077 var e2: i64 = p2 + 1
1078 var r2: i64 = 1
1079 while r2 == 1 {
1080 if e2 >= i { r2 = 0 } else {
1081 let c3: i64 = out[e2] as i64
1082 var id3: i64 = 0
1083 if c3 >= 97 { if c3 <= 122 { id3 = 1 } }
1084 if c3 >= 65 { if c3 <= 90 { id3 = 1 } }
1085 if c3 >= 48 { if c3 <= 57 { id3 = 1 } }
1086 if c3 == 95 { id3 = 1 }
1087 if id3 == 1 { e2 = e2 + 1 } else { r2 = 0 }
1088 }
1089 }
1090 let ln: i64 = e2 - p2
1091 var found: i64 = 0
1092 var t2: i64 = 0
1093 while t2 < nn {
1094 var m2: i64 = 1
1095 if ln > 31 { m2 = 0 }
1096 if m2 == 1 {
1097 var k2: i64 = 0
1098 while k2 < ln {
1099 if names[t2*32+k2] != out[p2+k2] { m2 = 0; k2 = ln } else { k2 = k2 + 1 }
1100 }
1101 }
1102 if m2 == 1 { if names[t2*32+ln] != (0 as u8) { m2 = 0 } }
1103 if m2 == 1 { found = 1; t2 = nn } else { t2 = t2 + 1 }
1104 }
1105 if found == 0 {
1106 bad = bad + 1
1107 let msg: *u8 = "GPE-VERIFY v2 RED: uniform used but not declared in its shader stage: " as *u8
1108 sys_write(2, msg, gpe_slen(msg))
1109 sys_write(2, ((out as i64) + p2) as *u8, ln)
1110 sys_write(2, "\n" as *u8, 1)
1111 }
1112 p2 = e2 - 1
1113 }
1114 p2 = p2 + 1
1115 }
1116 seg = 0 - 1
1117 }
1118 }
1119 i = i + 1
1120 }
1121 if seg >= 0 {
1122 bad = bad + 1
1123 let m2s: *u8 = "GPE-VERIFY RED: UNCLOSED backtick segment -- the page script is dead\n" as *u8
1124 sys_write(2, m2s, gpe_slen(m2s))
1125 }
1126 return bad
1127}
1128
1129// build the page into `out`; returns its byte length. Pure of the filesystem so the gate can
1130// drive it with synthetic wasm bytes and byte-assert the result. vnum = game-spec VARIANT the
1131// page selects at init (one engine wasm, many games -- the emission lever).
1132// gpe_num: append a decimal integer -- pages carry NUMBERS as data (the JS/HTML-interop-only
1133// law, 2026-08-12: values may cross into the page; logic may not)
1134func gpe_num(out: *u8, pos: i64, v: i64) -> i64 {
1135 var p: i64 = pos
1136 var x: i64 = v
1137 if x < 0 { out[p] = 45 as u8; p = p + 1; x = 0 - x }
1138 if x == 0 { out[p] = 48 as u8; return p + 1 }
1139 let t: *u8 = sys_mmap(32)
1140 var k: i64 = 0
1141 while x > 0 { t[k] = (48 + (x % 10)) as u8; x = x / 10; k = k + 1 }
1142 while k > 0 { k = k - 1; out[p] = t[k]; p = p + 1 }
1143 return p
1144}
1145// legacy 7-arg entry, byte-preserving: delegates with the historic constant seed, so every
1146// existing caller emits the exact bytes it always did (proven by the W1 KAT: recipe rows at
1147// seed 20260728 reproduce the shipped craft/beach/vale pages hash-identically)
1148// NX-WORLD-NPCS (donors-into-world, 2026-08-23): emit const NXNPCS=[...] from
1149// knowledge/world_npcs.conf rows name\tasset\tlabel\tworlds (worlds = * or a digit list of
1150// vnums). ABSENT conf = empty cast, announced on-page (config-hierarchy law: the fallback is
1151// declared, never silent). A malformed row REFUSES the whole build via gpr_refuse -- half a
1152// cast must not ship. The asset URL namespace is /world/<asset>.nxa by construction, so the
1153// conf cannot point a page outside the world dir.
1154// SUNT: sun-colour LUT baked at EMIT time from the gated transmittance oracle (ATMTRANS 10/10):
1155// 64 rows RGB in [0,1], mu = row/63 -- noon white, sunset reddened at the measured 25:1 R:B ratio.
1156func gpe_sunt(out: *u8, pos: i64) -> i64 {
1157 var p: i64 = pos
1158 p = gpe_ap(out, p, "if(!window.__sunt)window.__sunt=[" as *u8)
1159 let rgb: *i64 = sys_mmap(ATM_SUNLUT_N * 24) as *i64
1160 atm_bake_sun_lut(rgb)
1161 var row: i64 = 0
1162 while row < ATM_SUNLUT_N {
1163 var c: i64 = 0
1164 while c < 3 {
1165 if row + c > 0 { p = gpe_ap(out, p, "," as *u8) }
1166 p = gpe_num(out, p, rgb[row*3 + c])
1167 p = gpe_ap(out, p, "/65536" as *u8)
1168 c = c + 1
1169 }
1170 row = row + 1
1171 }
1172 p = gpe_ap(out, p, "];" as *u8)
1173 return p
1174}
1175
1176func gpe_npcs_emit(out: *u8, pos: i64, vnum: i64) -> i64 {
1177 var p: i64 = pos
1178 p = gpe_ap(out, p, "const NXNPCS=[" as *u8)
1179 let ln: *i64 = sys_mmap(16) as *i64
1180 let buf: *u8 = sys_read_file("knowledge/world_npcs.conf" as *u8, ln)
1181 if (buf as i64) == 0 { p = gpe_ap(out, p, "];\n" as *u8); return p }
1182 let n: i64 = ln[0]
1183 var lno: i64 = 0
1184 var i: i64 = 0
1185 var emitted: i64 = 0
1186 while i < n {
1187 lno = lno + 1
1188 let ls: i64 = i
1189 var le: i64 = ls
1190 var scan: i64 = 1
1191 while scan == 1 {
1192 if le >= n { scan = 0 } else { if buf[le] == (10 as u8) { scan = 0 } else { le = le + 1 } }
1193 }
1194 if le >= n { return gpr_refuse(lno, "npcs.conf: no trailing newline (append one)" as *u8) }
1195 i = le + 1
1196 if le > ls { if buf[ls] != (35 as u8) {
1197 buf[le] = 0 as u8
1198 let F: *i64 = sys_mmap(48) as *i64
1199 F[0] = (buf as i64) + ls
1200 var nf: i64 = 1
1201 var q: i64 = ls
1202 while q < le {
1203 if buf[q] == (9 as u8) { buf[q] = 0 as u8; if nf < 5 { F[nf] = (buf as i64) + q + 1 }; nf = nf + 1 }
1204 q = q + 1
1205 }
1206 if nf != 4 { return gpr_refuse(lno, "npcs.conf: needs 4 tab fields name/asset/label/worlds" as *u8) }
1207 let nm: *u8 = F[0] as *u8
1208 let asx: *u8 = F[1] as *u8
1209 let lb: *u8 = F[2] as *u8
1210 let wl: *u8 = F[3] as *u8
1211 if nm[0] == (0 as u8) { return gpr_refuse(lno, "npcs.conf: empty name" as *u8) }
1212 if asx[0] == (0 as u8) { return gpr_refuse(lno, "npcs.conf: empty asset" as *u8) }
1213 if lb[0] == (0 as u8) { return gpr_refuse(lno, "npcs.conf: empty label" as *u8) }
1214 var hit: i64 = 0
1215 if wl[0] == (42 as u8) { hit = 1 } else {
1216 var w2: i64 = 0
1217 while wl[w2] != (0 as u8) {
1218 if (wl[w2] as i64) == 48 + vnum { hit = 1 }
1219 w2 = w2 + 1
1220 }
1221 }
1222 if hit == 1 {
1223 if emitted > 0 { p = gpe_ap(out, p, "," as *u8) }
1224 p = gpe_ap(out, p, "{n:\"" as *u8); p = gpe_ap(out, p, nm)
1225 p = gpe_ap(out, p, "\",u:\"/world/" as *u8); p = gpe_ap(out, p, asx)
1226 p = gpe_ap(out, p, ".nxa\",l:\"" as *u8); p = gpe_ap(out, p, lb)
1227 p = gpe_ap(out, p, "\"}" as *u8)
1228 emitted = emitted + 1
1229 }
1230 } }
1231 }
1232 p = gpe_ap(out, p, "];\n" as *u8)
1233 return p
1234}
1235
1236func gpe_build(wasm: *u8, wn: i64, title: *u8, native: *u8, ctrl: *u8, vnum: i64, out: *u8) -> i64 {
1237 return gpe_build_s(wasm, wn, title, native, ctrl, vnum, GPE_MAGIC_20260728, 0 as *u8, out)
1238}
1239// ---- HAIR GEOMETRY, DRIVEN BY THE N-SEGMENT CHAIN (2026-08-25) -------------------------------
1240// THE RUNG THIS CLOSES. Hair geometry was already in the asset and already on screen: ref9d.nxa
1241// carries HSTR 2200 strands x 8 points (measured, nx_asset_floor_gate) and this emitter drew it.
1242// It drew it RIGID -- every hair vertex skinned haw=1 to the head joint -- so the groom was a
1243// helmet that could only translate and rotate with the skull. Separately nx_hairdyn_lib shipped a
1244// spring-bone CHAIN on nx_softdyn's one solver and was imported by NOTHING but its own gate.
1245// This is the join: the renderer now consumes N PER-SEGMENT offsets, not one.
1246//
1247// CORRECTED 2026-09-01. THE PARAGRAPH THAT STOOD HERE READ "ONE SOLVER, NO JS TWIN. The page does
1248// not integrate springs ... baked into the page as a table the page replays." That was true of the
1249// baked-table design and is FALSE of what ships -- and the same false sentence was being EMITTED
1250// into every served page (gpe_hair_chain, corrected in the same edit). The shared table was
1251// replaced by a PER-INSTANCE runtime chain: nxHairTick integrates NXHCH_NPC*NXHCH_N = 84
1252// spring-bone links every frame, and its own comment says so -- "sd_step_axq X/Z verbatim".
1253// It IS a JS twin, and it is deliberate: per-instance state lets girls differ, which one shared
1254// table can never do. What keeps it honest is INTEGER FIDELITY, not absence -- K, C, GDIV, LIM, Q8
1255// and the segment count are all emitted from the same NishiLang constants the plant uses, and every
1256// division is Math.trunc, so the JS arithmetic IS the i64 arithmetic. The duplicate-ruler risk the
1257// old paragraph feared is real and is now CARRIED, not denied; the rungs that discharge it are
1258// GE21 wc_hair_tick and GE22 gpe_wasm_hair_bind. Until those land, say what ships.
1259//
1260// EVERY NUMBER BELOW IS DERIVED, NONE CHOSEN:
1261// nseg = HSTR's own points-per-strand minus one -- the groom's segmentation, not a taste.
1262// frames = ticks per ONE natural period = ticks_per_second*1000/SB_HAIR_FN_MHZ, so the table is
1263// exactly one cycle of the SHIPPED plant and loops seamlessly. The gate-pinned 4221
1264// and the ringdown-MEASURED 4285 floor to the same integer, so the table length does
1265// not depend on which of the two a reader trusts.
1266// seglen = SD_Q8, one model unit. nx_hairdyn_gate's T4 PROVES the frequency is independent of
1267// seglen, so this is provably immaterial to the dynamics rather than tuned.
1268// amp = hd_amp_q8(), the lib's own excitation, derived from the SB_MAXD_HAIR clamp.
1269const GPE_HSTR_WORDS_PER_STRAND: i64 = 24
1270const GPE_AXES: i64 = 3
1271// The shipped guide budget: the incumbent block sampled 550 guides and its own comment states the
1272// consequence -- 8 jittered locks per guide per girl = 4400 locks/head. PRESERVED, not re-chosen:
1273// changing it would change the shipped look under cover of a dynamics change.
1274// 900: operator re-chose the density 2026-08-26 ("balding man in sparseness" at 550); the
1275// budget note below still holds -- locks per guide stay 8, so the cost scales linearly ~1.6x.
1276const GPE_HAIR_GUIDES: i64 = 900
1277func gpe_hstr_pts() -> i64 { return GPE_HSTR_WORDS_PER_STRAND/GPE_AXES }
1278func gpe_hair_nseg() -> i64 { return gpe_hstr_pts() - 1 }
1279func gpe_hair_seglen() -> i64 { return SD_Q8 }
1280
1281// THE ONE SEEDING RULER, shared by the cycle measurement and BOTH bakes. Settle to rest, then
1282// displace the whole strand laterally and release -- nx_hairdyn_lib's own excitation, which strains
1283// ONLY the root joint and so excites the fundamental sway rather than a shear mode real hair does
1284// not have. A second copy of this preamble beside the first would be free to drift, and the drift
1285// would show up as a table MEASURED under one excitation and REPLAYED under another, with no wrong
1286// number anywhere to find.
1287func gpe_hair_seed(st: *i64, n: i64, rigid: i64) -> i64 {
1288 let seglen: i64 = gpe_hair_seglen()
1289 hd_seat(st, n, 0, 0, 0, seglen)
1290 var s: i64 = 0
1291 while s < HD_RD_SETTLE {
1292 if rigid == 0 { hd_tick(st, n, 0, 0, 0, seglen, SB_K_HAIR, SB_C_HAIR, SB_MAXD_HAIR) }
1293 if rigid == 1 { hd_tick_rigid(st, n, 0, 0, 0, seglen) }
1294 s = s + 1
1295 }
1296 let amp: i64 = hd_amp_q8()
1297 var d: i64 = 0
1298 while d < n {
1299 st[d*SD_STRIDE] = st[d*SD_STRIDE] + amp
1300 d = d + 1
1301 }
1302 return 0
1303}
1304
1305// ---- ONE CHAIN CYCLE, MEASURED FROM THE TIP'S OWN TRACE. ----
1306// SB_HAIR_FN_MHZ is SEGMENT 0's plant frequency, and nx_hairdyn_lib's header says exactly why:
1307// segment 0 is the free decay, the one-degree-of-freedom oscillator sb_k_sym actually describes,
1308// while the tip is a property of PROPAGATION and not of the plant. Sizing a WHOLE-CHAIN table by
1309// segment 0's period is therefore a SUBJECT MISMATCH, and it shipped: nx_gpe_hair_geometry_gate
1310// measured the emitted table and found the tip crossing zero ONCE where a closed cycle needs twice,
1311// i.e. the replay wrapped mid-swing and jump-cut every 14 frames. The analyser cannot be asked for
1312// the tip's period either -- the same header records rd_analyze REFUSING the tip with rc=-4 because
1313// the tip's amplitude GROWS first while energy propagates down the chain. So the period is MEASURED
1314// from the trace: the interval between two zero crossings IN THE SAME DIRECTION IS one period, by
1315// definition. No tolerance is chosen anywhere here.
1316const GPE_HAIR_CYC_FIRST: i64 = 1
1317const GPE_HAIR_CYC_LAST: i64 = 3
1318// TWO NUMBERS OUT OF ONE SCAN. A second scan for the second number would be a duplicate ruler
1319// reading the same trace twice, free to disagree with itself about the cycle it just measured.
1320const GPE_HAIR_CYC_SKIP: i64 = 0
1321const GPE_HAIR_CYC_LEN: i64 = 1
1322const GPE_HAIR_CYC_SLOTS: i64 = 2
1323// SEARCH BOUND: nx_hairdyn_lib's OWN analysis window -- the longest trace that lib ever hands its
1324// analyser. Borrowing it means this scan can never outlast the evidence window the plant itself was
1325// measured in, and it is the lib's constant rather than a fresh guess. An exhausted scan ANNOUNCES
1326// by returning 0 rather than inventing a length, and a zero-frame table fails the gate's own
1327// fixture tooth -- loud, never silently short.
1328func gpe_hair_cycle(out: *i64) -> i64 {
1329 let n: i64 = gpe_hair_nseg()
1330 let seglen: i64 = gpe_hair_seglen()
1331 let st: *i64 = hd_alloc(n)
1332 gpe_hair_seed(st, n, 0)
1333 var cross: i64 = 0
1334 var prev: i64 = 0
1335 var f1: i64 = 0
1336 var f3: i64 = 0
1337 var fr: i64 = 0
1338 while fr < HD_RD_SAMPLES {
1339 hd_tick(st, n, 0, 0, 0, seglen, SB_K_HAIR, SB_C_HAIR, SB_MAXD_HAIR)
1340 fr = fr + 1
1341 let v: i64 = hd_tip_x_q8(st, n)
1342 var sg: i64 = 0
1343 if v > 0 { sg = 1 }
1344 if v < 0 { sg = 0 - 1 }
1345 if sg != 0 {
1346 if prev != 0 {
1347 if sg != prev {
1348 cross = cross + 1
1349 if cross == GPE_HAIR_CYC_FIRST { f1 = fr }
1350 if cross == GPE_HAIR_CYC_LAST { f3 = fr }
1351 }
1352 }
1353 prev = sg
1354 }
1355 }
1356 if f3 == 0 { return 0 }
1357 out[GPE_HAIR_CYC_SKIP] = f1
1358 out[GPE_HAIR_CYC_LEN] = f3 - f1
1359 return 1
1360}
1361func gpe_hair_cycle_at(slot: i64) -> i64 {
1362 let o: *i64 = sys_mmap(GPE_HAIR_CYC_SLOTS*8) as *i64
1363 o[GPE_HAIR_CYC_SKIP] = 0
1364 o[GPE_HAIR_CYC_LEN] = 0
1365 gpe_hair_cycle(o)
1366 return o[slot]
1367}
1368// ---- THE DRIVE: hair is DRIVEN at the head's gait cadence, and the table is baked at STEADY
1369// STATE. WHY NOT FREE DECAY (the previous design): measured 2026-08-25 by bake replication -- a
1370// release excitation is a TRANSIENT. The tip whips to ~64x the seed while energy cascades down the
1371// chain (seed 64 q8 -> tip 4078 q8), then rings down to ZERO within ~900 ticks. A damped free decay
1372// has no periodic cycle to bake: looping its loudest cycle replayed the whip forever with a
1373// jump-cut at every wrap. That WAS /world hair "flying about". A PERIODICALLY DRIVEN chain settles
1374// to a steady state sharing the drive's period, so a one-period table loops BY CONSTRUCTION.
1375// FREQUENCY: the banked gait band is gamefeel_oracle.conf's scurr2011 row (2to3hz-gait -- the same
1376// citation the chest lane derives from). The table needs an INTEGER tick period; at 60 ticks/s
1377// every frames value in [20,30] lands in-band, and 24 is the one whose frequency sits exactly on
1378// the band midpoint: 60000/24 = 2500 mHz.
1379const GPE_HAIR_DRIVE_FRAMES: i64 = 24
1380// AMPLITUDE: a picked display value, NAMED as picked, and fenced by two MECHANICAL refusals in the
1381// bake: (1) validity -- peak per-joint x-strain must stay under seglen/4 (a 14 deg joint angle, the
1382// small-angle regime the linear chain is valid in; the retired release excitation was 3 seglen =
1383// 71.6 deg); (2) sub-resonance -- the drive period must exceed the chain's own MEASURED free
1384// period, bounding the steady-state gain. A violation returns a zero-entry table (the loud refusal
1385// the gate's fixture tooth already fails on), never a resonant one.
1386const GPE_HAIR_DRIVE_AMP_Q8: i64 = 32
1387// SETTLE HORIZON: the v3 probe measured free-decay silence within ~900 ticks; 40 drive periods =
1388// 960 ticks covers it with margin. The steady-state DETECTOR normally exits far earlier.
1389const GPE_HAIR_SETTLE_PERIODS_MAX: i64 = 40
1390// Root sway at bake tick t: Q16 sine COMPOSED from nx_audio_osc -- the estate's one integer sine,
1391// never re-implemented. Phase derives from t mod frames, so every period repeats the identical
1392// phases and the table closes exactly.
1393func gpe_hair_drive(t: i64) -> i64 {
1394 let ph: i64 = ((t % GPE_HAIR_DRIVE_FRAMES)*OSC_PHASE)/GPE_HAIR_DRIVE_FRAMES
1395 return (GPE_HAIR_DRIVE_AMP_Q8*osc_sin_unit(ph))/OSC_MAGIC_65536
1396}
1397// FRAMES = one DRIVE period, an integer by construction (see GPE_HAIR_DRIVE_FRAMES above).
1398func gpe_hair_frames() -> i64 { return GPE_HAIR_DRIVE_FRAMES }
1399// (the RELEASE-TRANSIENT skip helper was retired with the free-decay bake: the driven bake settles
1400// to steady state instead. gpe_hair_cycle still records the skip slot inside its own scan.)
1401
1402// Bake one natural period of the chain. rigid=1 swaps hd_tick for hd_tick_rigid -- the lib's OWN
1403// dynamics-removed control -- which yields a table with ZERO variance across frames. That is the
1404// anti-vacuity subject: a renderer fed the rigid table CANNOT move, so a gate that passes on it
1405// is measuring nothing. Returns the number of table entries written.
1406func gpe_hair_chain_bake(tbl: *i64, rigid: i64) -> i64 {
1407 let n: i64 = gpe_hair_nseg()
1408 let f: i64 = gpe_hair_frames()
1409 let seglen: i64 = gpe_hair_seglen()
1410 let st: *i64 = hd_alloc(n)
1411 // SETTLE UNDER THE DRIVE to steady state -- DETECTED, never assumed: whole drive periods run
1412 // until two consecutive periods' peak |tip| agree within 1 q8. The rigid control follows the
1413 // root instantly, so it converges on its second period by construction.
1414 hd_seat(st, n, 0, 0, 0, seglen)
1415 var t: i64 = 0
1416 var prevpk: i64 = 0 - 1
1417 var steady: i64 = 0
1418 var per: i64 = 0
1419 while steady == 0 {
1420 if per >= GPE_HAIR_SETTLE_PERIODS_MAX { return 0 }
1421 var pk: i64 = 0
1422 var k: i64 = 0
1423 while k < f {
1424 let rx: i64 = gpe_hair_drive(t)
1425 if rigid == 0 { hd_tick(st, n, rx, 0, 0, seglen, SB_K_HAIR, SB_C_HAIR, SB_MAXD_HAIR) }
1426 if rigid == 1 { hd_tick_rigid(st, n, rx, 0, 0, seglen) }
1427 var v: i64 = hd_tip_x_q8(st, n)
1428 if v < 0 { v = 0 - v }
1429 if v > pk { pk = v }
1430 t = t + 1
1431 k = k + 1
1432 }
1433 var dd: i64 = pk - prevpk
1434 if dd < 0 { dd = 0 - dd }
1435 if prevpk >= 0 { if dd <= 1 { steady = 1 } }
1436 prevpk = pk
1437 per = per + 1
1438 }
1439 // SUB-RESONANCE REFUSAL (mechanical): the drive period must exceed the chain's own measured
1440 // free period -- gpe_hair_cycle still measures it from the free-decay trace -- or the steady
1441 // gain is resonant. Refuse rather than bake a resonant table.
1442 if rigid == 0 {
1443 let freeper: i64 = gpe_hair_cycle_at(GPE_HAIR_CYC_LEN)
1444 if freeper == 0 { return 0 }
1445 if f <= freeper { return 0 }
1446 }
1447 // BAKE exactly one drive period at steady state, TABLE RELATIVE TO THE ROOT: the root's sway
1448 // is virtual (the body mesh does not move), so the consumer sees hair motion relative to the
1449 // scalp -- segment 0 nearly still, lag growing down the strand. The rigid control follows the
1450 // root exactly, so its root-relative table is ALL ZEROS: zero variance, the anti-vacuity
1451 // subject preserved.
1452 var mxstrain: i64 = 0
1453 var fr: i64 = 0
1454 while fr < f {
1455 let rx: i64 = gpe_hair_drive(t)
1456 if rigid == 0 { hd_tick(st, n, rx, 0, 0, seglen, SB_K_HAIR, SB_C_HAIR, SB_MAXD_HAIR) }
1457 if rigid == 1 { hd_tick_rigid(st, n, rx, 0, 0, seglen) }
1458 var px: i64 = rx
1459 var i: i64 = 0
1460 while i < n {
1461 let x: i64 = hd_x_q8(st, i)
1462 tbl[fr*n + i] = x - rx
1463 var strain: i64 = x - px
1464 if strain < 0 { strain = 0 - strain }
1465 if strain > mxstrain { mxstrain = strain }
1466 px = x
1467 i = i + 1
1468 }
1469 t = t + 1
1470 fr = fr + 1
1471 }
1472 // VALIDITY REFUSAL (mechanical): peak per-joint x-strain must sit in the small-angle regime.
1473 if mxstrain > seglen/4 { return 0 }
1474 return f*n
1475}
1476
1477// gpe_hair_geometry -- THE CONTRACT SYMBOL. Emits the asset's own hair GEOMETRY (HVRT/HTRI mesh
1478// preferred, HSTR guide strands otherwise) plus the baked chain table, and the per-frame consumer
1479// that displaces each hair vertex by the offset of ITS OWN chain segment. A vertex's segment is
1480// DERIVED from its depth below the top of the groom, so the lag grows down the strand -- the one
1481// thing N copies of a single point can never produce.
1482// gpe_dress_runtime -- DRESS DYNAMICS, SCRIPT-SCOPE HALF (2026-08-26). The GVRT dress was skinned
1483// by nearest-body-vert copy -- the page's own comment: MOVES WITH THE SKIN, ZERO PHYSICS. This is
1484// the overlay tier (industry-standard skinned+dynamic): guide-grid XPBD per girl in BIND space
1485// (pins = top guide rows, gravity = bind -z, inertial kick from HER OWN ip motion exactly like
1486// the hair chain), capsule contact vs the bind-pose legs/torso (static -- the NAMED v1 limit:
1487// extreme swing-leg poses can still clip), upsampled to every dress vert and applied PRE-SKIN
1488// via a deformation texture (TEXTURE3, texelFetch by (gl_VertexID, girl)). Solver arithmetic
1489// replicates the gate-proven nx_gm_cloth_lib in integer-faithful JS: the XPBD projection, the
1490// st_alpha_tilde chain (Q12, dt-ref 4167us), and the GM_SKIN=2 truncation skin. Compliance is
1491// the gate's proven soft value; gravity derives from the page's own scale pairing.
1492func gpe_dress_runtime(out: *u8, pos: i64) -> i64 {
1493 var p: i64 = pos
1494 p = gpe_ap(out, p, "const NXGD_SUB=3,NXGD_ALPHA_SOFT=" as *u8)
1495 p = gpe_num(out, p, GPE_ALPHA_BEND_SOFT_Q12)
1496 p = gpe_ap(out, p, ",NXGD_G=" as *u8)
1497 p = gpe_num(out, p, 981*GPE_UNITS_PER_178CM/GPE_G_DEN_60HZ)
1498 p = gpe_ap(out, p, ",NXGD_SKIN=2,NXGD_Q12=4096,NXGD_DTREF=4167,NXGD_DTUS=16666,NXGD_PINROWS=2,NXGD_NPC=12;\n" as *u8)
1499 p = gpe_ap(out, p, "// NXGD_G = 981*171530/640800 (9.81 m/s^2 through the page's 1.78m=171530-unit pairing at 60Hz);\n// NXGD_ALPHA_SOFT = the gate-proven XG_ALPHA_BEND_SOFT_Q12; SKIN/Q12/DTREF are the lib's own.\n" as *u8)
1500 p = gpe_ap(out, p, "function nxDressTick(g,N){if(!N||!N.gdt||!N.l||!N.l.uGD)return 0;\nconst NG=N.gdGU*N.gdGV,NP=NXGD_NPC;\nif(!N.gds){N.gds={x:new Float64Array(NP*NG*3),v:new Float64Array(NP*NG*3),px:new Float64Array(NP*2),tex:new Float32Array(N.gnv2*NP*4),t:performance.now(),init:0};}\nconst st=N.gds,now=performance.now();\nconst dvr=(a9,b9)=>{if(b9===0)return 0;return a9>=0?Math.trunc((a9+Math.trunc(b9/2))/b9):-Math.trunc((-a9+Math.trunc(b9/2))/b9);};\n" as *u8)
1501 p = gpe_ap(out, p, "if(!st.init){for(let g9=0;g9<NP;g9++){for(let q9=0;q9<NG;q9++){st.x[(g9*NG+q9)*3]=N.gdRest[q9*3];st.x[(g9*NG+q9)*3+1]=N.gdRest[q9*3+1];st.x[(g9*NG+q9)*3+2]=N.gdRest[q9*3+2];}st.px[g9*2]=N.ip[g9*3];st.px[g9*2+1]=N.ip[g9*3+2];}st.init=1;st.t=now;}\n// alpha-tilde, the lib's exact chain: round(alpha*2/4096) then twice round(*4167/dtus)\nlet at9=dvr(NXGD_ALPHA_SOFT*2,NXGD_Q12);at9=dvr(at9*NXGD_DTREF,NXGD_DTUS);at9=dvr(at9*NXGD_DTREF,NXGD_DTUS);\nlet nt=Math.floor((now-st.t)*60/1000);if(nt>4)nt=4;if(nt<0)nt=0;st.t+=nt*1000/60;\n" as *u8)
1502 p = gpe_ap(out, p, "for(let g9=0;g9<NP;g9++){\n// inertial kick: HER world motion rotated into bind space by her heading (ih = sinA,cosA)\nconst wx=N.ip[g9*3],wz=N.ip[g9*3+2];const ddx=wx-st.px[g9*2],ddz=wz-st.px[g9*2+1];st.px[g9*2]=wx;st.px[g9*2+1]=wz;\nconst sA=N.ih[g9*4],cA=N.ih[g9*4+1],W2B=171530/1.78;\n// A TELEPORT IS NOT DYNAMICS (2026-08-30; the hair chain already carries this guard, the dress did not): the review\n// re-summon and the N key move a girl BLOCKS in one frame, and that delta became an inertial kick of ~5e5 bind\n// units that flung a guide across the beach (the red streak in frame b1788128841, second capture). Bound DERIVED\n// from the asset: a root jump in one frame longer than the skirt's own vertical span is not a stride -- no kick,\n// the guides simply follow her to the new spot.\nif(N.gdSpanB===undefined){let z0=1e18,z1=-1e18;for(let q=0;q<NG;q++){const z=N.gdRest[q*3+2];if(z<z0)z0=z;if(z>z1)z1=z;}N.gdSpanB=(z1-z0)/W2B;}\nconst tp9=Math.hypot(ddx,ddz)>N.gdSpanB;\nconst kbx=tp9?0:Math.trunc((ddx*cA-ddz*sA)*W2B),kby=tp9?0:Math.trunc((ddx*sA+ddz*cA)*W2B);\nfor(let k9=0;k9<nt;k9++){\nfor(let q9=0;q9<NG;q9++){const b9=(g9*NG+q9)*3;const pin9=q9<NXGD_PINROWS*N.gdGU;\nif(pin9){st.v[b9]=0;st.v[b9+1]=0;st.v[b9+2]=0;st.x[b9]=N.gdRest[q9*3];st.x[b9+1]=N.gdRest[q9*3+1];st.x[b9+2]=N.gdRest[q9*3+2];continue;}\nst.v[b9+2]-=NXGD_G;if(k9===0){st.v[b9]-=Math.trunc(kbx/(nt||1));st.v[b9+1]-=Math.trunc(kby/(nt||1));}\nst.x[b9]+=st.v[b9];st.x[b9+1]+=st.v[b9+1];st.x[b9+2]+=st.v[b9+2];}\n" as *u8)
1503 p = gpe_ap(out, p, "for(let it9=0;it9<8;it9++){const E=N.gdEdge;\nfor(let e9=0;e9<E.length;e9+=4){const a9=g9*NG+E[e9],c9=g9*NG+E[e9+1],rest9=E[e9+2],atl9=E[e9+3]===2?at9:0;\nconst dx9=st.x[c9*3]-st.x[a9*3],dy9=st.x[c9*3+1]-st.x[a9*3+1],dz9=st.x[c9*3+2]-st.x[a9*3+2];\nlet ln9=Math.trunc(Math.sqrt(dx9*dx9+dy9*dy9+dz9*dz9));if(ln9<1)ln9=1;\nconst dl9=Math.trunc((ln9-rest9)*4096/(8192+atl9));\nconst cx9=Math.trunc(dx9*dl9/ln9),cy9=Math.trunc(dy9*dl9/ln9),cz9=Math.trunc(dz9*dl9/ln9);\nconst af9=E[e9]>=NXGD_PINROWS*N.gdGU,bf9=E[e9+1]>=NXGD_PINROWS*N.gdGU;\nif(af9&&bf9){st.x[a9*3]+=Math.trunc(cx9/2);st.x[a9*3+1]+=Math.trunc(cy9/2);st.x[a9*3+2]+=Math.trunc(cz9/2);st.x[c9*3]-=Math.trunc(cx9/2);st.x[c9*3+1]-=Math.trunc(cy9/2);st.x[c9*3+2]-=Math.trunc(cz9/2);}\nelse if(af9){st.x[a9*3]+=cx9;st.x[a9*3+1]+=cy9;st.x[a9*3+2]+=cz9;}\nelse if(bf9){st.x[c9*3]-=cx9;st.x[c9*3+1]-=cy9;st.x[c9*3+2]-=cz9;}}}\n" as *u8)
1504 p = gpe_ap(out, p, "// capsule projection, gm_capsule_project verbatim (3 capsules: legs + torso)\nfor(let cp9=0;cp9<3;cp9++){const C=N.gdCap,o9=cp9*7;const ux9=C[o9+3]-C[o9],uy9=C[o9+4]-C[o9+1],uz9=C[o9+5]-C[o9+2];\nlet uu9=ux9*ux9+uy9*uy9+uz9*uz9;if(uu9<1)uu9=1;const rad9=C[o9+6],rs9=rad9+NXGD_SKIN;\nfor(let q9=NXGD_PINROWS*N.gdGU;q9<NG;q9++){const b9=(g9*NG+q9)*3;\nconst px9=st.x[b9]-C[o9],py9=st.x[b9+1]-C[o9+1],pz9=st.x[b9+2]-C[o9+2];\nlet tq9=Math.trunc((px9*ux9+py9*uy9+pz9*uz9)*4096/uu9);if(tq9<0)tq9=0;if(tq9>4096)tq9=4096;\nconst qx9=C[o9]+Math.trunc(ux9*tq9/4096),qy9=C[o9+1]+Math.trunc(uy9*tq9/4096),qz9=C[o9+2]+Math.trunc(uz9*tq9/4096);\nconst ex9=st.x[b9]-qx9,ey9=st.x[b9+1]-qy9,ez9=st.x[b9+2]-qz9;const dd9=ex9*ex9+ey9*ey9+ez9*ez9;\nif(dd9<rad9*rad9){let dn9=Math.trunc(Math.sqrt(dd9));if(dn9<1)dn9=1;\nst.x[b9]=qx9+Math.trunc(ex9*rs9/dn9);st.x[b9+1]=qy9+Math.trunc(ey9*rs9/dn9);st.x[b9+2]=qz9+Math.trunc(ez9*rs9/dn9);\nst.v[b9]=0;st.v[b9+1]=0;st.v[b9+2]=0;window.__nx_dress_hits=(window.__nx_dress_hits||0)+1;}}}}\n" as *u8)
1505 p = gpe_ap(out, p, "// upsample guide deltas to every dress vert and write the girl's texture row\nfor(let v9=0;v9<N.gnv2;v9++){const m9=v9*4;let ox9=0,oy9=0,oz9=0;\nfor(let w9=0;w9<4;w9++){const gi9=g9*NG+N.gdMap[m9+w9],wt9=N.gdWgt[m9+w9],r0=N.gdMap[m9+w9]*3;\nox9+=wt9*(st.x[gi9*3]-N.gdRest[r0]);oy9+=wt9*(st.x[gi9*3+1]-N.gdRest[r0+1]);oz9+=wt9*(st.x[gi9*3+2]-N.gdRest[r0+2]);}\nconst t9=(g9*N.gnv2+v9)*4;st.tex[t9]=ox9;st.tex[t9+1]=oy9;st.tex[t9+2]=oz9;}}\ng.activeTexture(g.TEXTURE3);g.bindTexture(g.TEXTURE_2D,N.gdt);\ng.texSubImage2D(g.TEXTURE_2D,0,0,0,N.gnv2,NXGD_NPC,g.RGBA,g.FLOAT,st.tex);g.activeTexture(g.TEXTURE0);\nwindow.__nx_dress_ticks=(window.__nx_dress_ticks||0)+nt;return 1;}\n" as *u8)
1506 p = gpe_ap(out, p, "// ?dressprobe -- girls_moving from the offsets the RENDERER consumes, the same honesty\n// contract as the hair probe\nwindow.__nx_dress_probe=function(){if(!GL||!GL.npc||!GL.npc.gds)return 'no-dress-state';\nconst N=GL.npc,tex=N.gds.tex;let mx=0,girls=0;\nfor(let g9=0;g9<NXGD_NPC;g9++){let gm=0;for(let v9=0;v9<N.gnv2;v9++){const t9=(g9*N.gnv2+v9)*4;\nconst d9=Math.hypot(tex[t9],tex[t9+1],tex[t9+2]);if(d9>gm)gm=d9;}if(gm>1e-9)girls++;if(gm>mx)mx=gm;}\nreturn 'NXDRESSPROBE1 verts='+N.gnv2+' guides='+(N.gdGU*N.gdGV)+' girls_moving='+girls+' maxdisp='+mx.toFixed(1)+' ticks='+(window.__nx_dress_ticks||0)+' capsule_hits='+(window.__nx_dress_hits||0);};\n" as *u8)
1507 return p
1508}
1509
1510// gpe_hair_runtime -- THE SCRIPT-SCOPE HALF. Emits the derived NXHCH_* constants, the baked chain
1511// table and nxHairTick, all of which are per-PLANT and shared by every NPC. It MUST be called at
1512// script scope: until 2026-08-25 all of this was emitted inside loadNPC, so nxHairTick was a
1513// function declaration nested two scopes deep, and drawNPCs -- at script scope -- threw
1514// ReferenceError: nxHairTick is not defined on its first frame. That exception killed the WebGL tier
1515// on EVERY world with a cast and dropped every visitor to the CPU renderer, which draws none of the
1516// skinned figures. The reason was invisible until the gl=0 reload was made to carry it in its URL.
1517// ★A FUNCTION DECLARED INSIDE ANOTHER FUNCTION IS NOT HOISTED PAST IT -- EMIT SHARED RUNTIME AT THE
1518// SCOPE ITS CALLERS LIVE IN.
1519func gpe_hair_runtime(out: *u8, pos: i64) -> i64 {
1520 var p: i64 = pos
1521 let n: i64 = gpe_hair_nseg()
1522 let f: i64 = gpe_hair_frames()
1523 let tbl: *i64 = sys_mmap(f*n*8 + 64) as *i64
1524 gpe_hair_chain_bake(tbl, 0)
1525 p = gpe_ap(out, p, "\n// HAIR GEOMETRY driven by the CHAIN: N per-segment offsets, one spring-bone chain PER GIRL,\n// integrated in nxHairTick below on the constants nx_hairdyn_lib/nx_softdyn ship (sd_step_axq,\n// integer-faithful -- every division truncs). CORRECTED 2026-09-01: this page used to say it\n// replays a baked table and does not integrate springs. It has not been a table since the\n// per-instance chain landed. Owed GE21/GE22: move the integration into the wasm engine.\nconst NXHCH_N=" as *u8)
1526 p = gpe_num(out, p, n)
1527 p = gpe_ap(out, p, ",NXHCH_F=" as *u8)
1528 p = gpe_num(out, p, f)
1529 p = gpe_ap(out, p, ",NXHCH_Q8=" as *u8)
1530 p = gpe_num(out, p, SD_Q8)
1531 p = gpe_ap(out, p, ",NXHCH_TPS=" as *u8)
1532 p = gpe_num(out, p, hd_ticks_per_s())
1533 p = gpe_ap(out, p, ",NXHCH_G=" as *u8)
1534 p = gpe_num(out, p, GPE_HAIR_GUIDES)
1535 p = gpe_ap(out, p, ",NXHCH_W=" as *u8)
1536 p = gpe_num(out, p, GPE_HSTR_WORDS_PER_STRAND)
1537 p = gpe_ap(out, p, ";\nconst NXHCH=[" as *u8)
1538 var k: i64 = 0
1539 while k < f*n {
1540 if k > 0 { p = gpe_ap(out, p, "," as *u8) }
1541 p = gpe_num(out, p, tbl[k])
1542 k = k + 1
1543 }
1544 p = gpe_ap(out, p, "];\n" as *u8)
1545 // RUNTIME REACTIVE CHAIN (2026-08-26, supersedes the baked-table replay): per-girl chain state
1546 // stepped every frame from HER OWN motion (N.ip deltas), sd_step_axq arithmetic REPLICATED
1547 // VERBATIM in integer-faithful JS (Math.trunc division == i64 division; K/C/G emitted from the
1548 // very constants the solver compiles). The baked NXHCH table stays emitted: the ship gate
1549 // judges the PLANT through it and its bake-time refusals still fence K/C on every ship.
1550 // The runtime clamp is the SMALL-ANGLE VALIDITY BOUND seglen/4 -- the same derivation as the
1551 // bake fence -- because this clamp IS the display plant validity fence, not a divergence guard.
1552 p = gpe_ap(out, p, "const NXHCH_K=" as *u8)
1553 p = gpe_num(out, p, SB_K_HAIR)
1554 p = gpe_ap(out, p, ",NXHCH_C=" as *u8)
1555 p = gpe_num(out, p, SB_C_HAIR)
1556 p = gpe_ap(out, p, ",NXHCH_GDIV=" as *u8)
1557 p = gpe_num(out, p, SD_G)
1558 p = gpe_ap(out, p, ",NXHCH_LIM=" as *u8)
1559 p = gpe_num(out, p, SD_Q8/4)
1560 p = gpe_ap(out, p, ",NXHCH_NPC=12;// NPC cap mirrors uIP[12]/uIH[12] in MVS\n" as *u8)
1561 p = gpe_ap(out, p, "function nxHairStep(N){if(!N||!N.hn)return 0;\nconst NS=NXHCH_N,NP=NXHCH_NPC;\nif(!N.hch){N.hch={x:new Float64Array(NP*NS),y:new Float64Array(NP*NS),z:new Float64Array(NP*NS),vx:new Float64Array(NP*NS),vy:new Float64Array(NP*NS),vz:new Float64Array(NP*NS),rx:new Float64Array(NP),ry:new Float64Array(NP),rz:new Float64Array(NP),hf:new Float32Array(NP*NS*3),t:performance.now(),init:0};}\n" as *u8)
1562 p = gpe_ap(out, p, "const st=N.hch,now=performance.now();\n// world->chain scale (CORRECTED 2026-08-30): chain space is Q8 of one SEGMENT, not Q8 of one mesh unit --\n// the readback below multiplies (x-b)/NXHCH_Q8 by N.hscale (mesh units per segment), so the root must be\n// divided by that same hscale on the way in. The old value treated a solver unit as one mesh unit, a factor\n// hscale (2478 on the shipped groom) too large: a strolling girl's per-tick root delta landed at ~1.2e5 chain\n// units against the teleport guard NXHCH_LIM*4=256, so EVERY moving tick snapped the chain rigid and the groom\n// never lagged anything. MEASURED on the live page before this fix: girls_moving=0 segs_nonzero=0 maxdisp=0\n// with four girls striding. ONE ruler both ways: blocks -> mesh units (171530/1.78) -> segments (/hscale)\n// -> chain Q8 (x NXHCH_Q8).\nconst W2Q=NXHCH_Q8*171530/1.78/(N.hscale||1);\n// WIND (2026-08-30): the world's own wind field -- the ORGAN's P_WXWINDX/Z spec slots, published by glDraw as\n// window.__wxw[0..1] in gale fractions (nx_weather_lib clamps speed at WX_Q, so |w| <= 1) -- shifts every\n// link's REST POINT downwind by NXHCH_LIM*|w|*g(t): at the gale bound the chain sits on its own small-angle\n// validity fence, at a breeze a fraction of it, in still air nothing -- no constant of ours. g(t) in [0,1) is a\n// value-noise gust: the page's own hash (127.1/43758.5453, the shader hsh) sampled at the incumbent sway rate\n// (3.1 rad/s on uTm, the MVS weather-in-the-hair term shipped before this), phase per girl from the same hash of\n// her slot so a crowd never gusts in unison. Direction is the wind vector's own. ⚠CORRECTED 2026-09-01: this note used to say the term was inert. It is NOT: step_impl calls\n// wc_weather_tick before the input core (nx_wasm_craft.nx), so slots 11-15 are live on this path.\n// Held now by nx_wasm_craft_gate T88.\nconst wx9=(window.__wxw&&window.__wxw[0])||0,wz9=(window.__wxw&&window.__wxw[1])||0;const wm9=Math.hypot(wx9,wz9);\nconst gh9=function(a){const n9=Math.sin(a*127.1)*43758.5453;return n9-Math.floor(n9);};\nconst tg9=now/1000*3.1/(2*Math.PI);\nif(!st.init){for(let g9=0;g9<NP;g9++){const wx=N.ip[g9*3]*W2Q,wy=N.ip[g9*3+1]*W2Q,wz=N.ip[g9*3+2]*W2Q;st.rx[g9]=wx;st.ry[g9]=wy;st.rz[g9]=wz;for(let s9=0;s9<NS;s9++){st.x[g9*NS+s9]=wx;st.y[g9*NS+s9]=wy;st.z[g9*NS+s9]=wz;}}st.init=1;st.t=now;}\n" as *u8)
1563 p = gpe_ap(out, p, "// fixed steps at the solver cadence; cap 4/frame so a stall reads as a gentle restart,\n// never a velocity spike\nlet nt=Math.floor((now-st.t)*NXHCH_TPS/1000);if(nt>4){nt=4;st.t=now-nt*1000/NXHCH_TPS;}if(nt<0)nt=0;st.t+=nt*1000/NXHCH_TPS;\nfor(let g9=0;g9<NP;g9++){\nconst wx=N.ip[g9*3]*W2Q,wy=N.ip[g9*3+1]*W2Q,wz=N.ip[g9*3+2]*W2Q;\n// a TELEPORT is not dynamics: a root jump beyond 4 clamp-lengths per tick snaps the chain\nif(Math.abs(wx-st.rx[g9])>NXHCH_LIM*4*(nt||1)||Math.abs(wz-st.rz[g9])>NXHCH_LIM*4*(nt||1)){st.rx[g9]=wx;st.ry[g9]=wy;st.rz[g9]=wz;for(let s9=0;s9<NS;s9++){st.x[g9*NS+s9]=wx;st.y[g9*NS+s9]=wy;st.z[g9*NS+s9]=wz;st.vx[g9*NS+s9]=0;st.vy[g9*NS+s9]=0;st.vz[g9*NS+s9]=0;}}\nconst rdx=(wx-st.rx[g9])/(nt||1),rdy=(wy-st.ry[g9])/(nt||1),rdz=(wz-st.rz[g9])/(nt||1);\n" as *u8)
1564 p = gpe_ap(out, p, "// per-girl wind rest offset for THIS tick (see the WIND note above): integer chain units, so the solver stays\n// integer-faithful; zero whenever the world's wind is zero\nlet wox=0,woz=0;if(wm9>0){const u9=tg9+gh9(g9+1);const i9=Math.floor(u9),f9=u9-i9,s8=f9*f9*(3-2*f9);const gg9=gh9(i9+g9*13)*(1-s8)+gh9(i9+1+g9*13)*s8;const wa9=NXHCH_LIM*gg9*(wm9>1?1/wm9:1);wox=Math.trunc(wx9*wa9);woz=Math.trunc(wz9*wa9);}\nfor(let k9=0;k9<nt;k9++){\nst.rx[g9]+=rdx;st.ry[g9]+=rdy;st.rz[g9]+=rdz;\nlet ax=Math.trunc(st.rx[g9]),ay=Math.trunc(st.ry[g9]),az=Math.trunc(st.rz[g9]);\nfor(let s9=0;s9<NS;s9++){const q9=g9*NS+s9;\n// sd_step_axq X/Z verbatim: spring toward anchor + viscous damping, trunc = i64 division; the anchor carries\n// the wind rest offset per link, so the offsets accumulate down the chain (tip = NS x one link)\nconst accx=Math.trunc((ax+wox-st.x[q9])*NXHCH_K/NXHCH_GDIV)-Math.trunc(st.vx[q9]*NXHCH_C/NXHCH_GDIV);\nconst accz=Math.trunc((az+woz-st.z[q9])*NXHCH_K/NXHCH_GDIV)-Math.trunc(st.vz[q9]*NXHCH_C/NXHCH_GDIV);\nconst accy=Math.trunc((ay-st.y[q9])*NXHCH_K/NXHCH_GDIV)-Math.trunc(st.vy[q9]*NXHCH_C/NXHCH_GDIV);\nst.vx[q9]+=accx;st.vy[q9]+=accy;st.vz[q9]+=accz;st.x[q9]+=st.vx[q9];st.y[q9]+=st.vy[q9];st.z[q9]+=st.vz[q9];\nlet dx=st.x[q9]-ax,dy=st.y[q9]-ay,dz=st.z[q9]-az;const d9=dx*dx+dy*dy+dz*dz,L9=NXHCH_LIM*NXHCH_LIM;\nif(d9>L9){const dd=Math.sqrt(d9)||1;st.x[q9]=ax+Math.trunc(dx*NXHCH_LIM/dd);st.y[q9]=ay+Math.trunc(dy*NXHCH_LIM/dd);st.z[q9]=az+Math.trunc(dz*NXHCH_LIM/dd);st.vx[q9]=0;st.vy[q9]=0;st.vz[q9]=0;}\nax=Math.trunc(st.x[q9]);ay=Math.trunc(st.y[q9]);az=Math.trunc(st.z[q9]);}}\n" as *u8)
1565 p = gpe_ap(out, p, "const bx=st.rx[g9],by=st.ry[g9],bz=st.rz[g9];const ihx=N.ih[g9*4],ihy=N.ih[g9*4+1];\n// WORLD -> MODEL (2026-08-30): the chain integrates in WORLD axes (its root is N.ip) but the MVS adds uHF2 to\n// aP2 in MODEL space, before the yup remap and the heading rotation -- so the offset must come back through\n// the inverse of both: yup = heading^-1 * world, then model x = yup.x, model y = -yup.z, model z = yup.y (the\n// exact inverse of the shader's yup=(sp.x,sp.z,-sp.y) and rot=heading*yup). With the chain dead (see W2Q)\n// this frame mismatch never showed; alive, a world-vertical lag would have read as front-back and a turn of\n// the head would have swung the groom the wrong way. Scale: N.hscale mesh units per segment (the groom's own).\nfor(let s9=0;s9<NS;s9++){const q9=g9*NS+s9;\nconst dX=(st.x[q9]-bx)/NXHCH_Q8*N.hscale,dY=(st.y[q9]-by)/NXHCH_Q8*N.hscale,dZ=(st.z[q9]-bz)/NXHCH_Q8*N.hscale;\nconst yx=dX*ihy+dZ*ihx,yz=-dX*ihx+dZ*ihy;\nst.hf[q9*3]=yx;st.hf[q9*3+1]=-yz;st.hf[q9*3+2]=dY;}}\nwindow.__nx_hair_ticks=(window.__nx_hair_ticks||0)+nt;return 1;}\nfunction nxHairTick(g,N){if(!N||!N.l||!N.l.uHF2||!nxHairStep(N))return 0;g.uniform3fv(N.l.uHF2,N.hch.hf);return 1;}\n" as *u8)
1566 return p
1567}
1568
1569// gpe_hair_npc_doors -- the LOADNPC-SCOPE doors. __nx_hair and the probe close over hgeo/hmode/hn
1570// (loadNPC locals) and GL, so when the 2026-08-25 script-scope extraction carried them along, the
1571// OBJECT LITERAL executed at script eval, threw ReferenceError, and KILLED THE ENTIRE ENGINE SCRIPT
1572// on /world/beach AND /world/craft -- every window door undefined, both flagship worlds dead,
1573// measured live. ★A FUNCTION MOVED TO AN OUTER SCOPE IS SAFE (it runs later); ANY EXPRESSION MOVED
1574// WITH IT RUNS AT EVAL TIME AND THROWS THERE. Only nxHairTick and the consts are scope-free; these
1575// two doors belong where their variables live, and this function is called from gpe_hair_geometry
1576// -- inside loadNPC -- for exactly that reason.
1577func gpe_hair_npc_doors(out: *u8, pos: i64) -> i64 {
1578 var p: i64 = pos
1579 p = gpe_ap(out, p, "window.__nx_hair={geo:hgeo,mode:hmode,seg:NXHCH_N,frames:NXHCH_F,verts:hn};\n// Reports computed source-space offsets, not collision or pixel correctness.\n// Optional structured output preserves the existing default text call contract.\nwindow.__nx_hair_probe=function(options){\n const backend=GPU?'webgpu':GL?'webgl2':'unavailable';\n const N=GPU?GPU.cast:GL?GL.npc:null;\n const result={version:3,backend,state:'waiting',scope:'computed-source-space-offsets',units:'source-mesh-units',reason:null,vertices:N?.hn||0,segments:NXHCH_N,instances:NXHCH_NPC,movingInstances:null,nonzeroSegments:null,maxDisplacement:null,ticks:window.__nx_hair_ticks||0,collisionQualified:false,packedAgreement:null};\n if(!N){result.reason=backend==='unavailable'?'renderer-unavailable':'resident-pending';}\n else if(!N.hn){result.state='absent';result.reason='no-hair-geometry';}\n else if(!N.hch){result.reason='not-ticked-yet';}\n else{\n const hf=N.hch.hf;\n if(!hf||hf.length!==NXHCH_NPC*NXHCH_N*3){result.state='refused';result.reason='offset-extent';}\n else{\n result.state='measured';result.movingInstances=0;result.nonzeroSegments=0;result.maxDisplacement=0;\n for(let g=0;g<NXHCH_NPC;g++){\n let gm=0;\n for(let s=0;s<NXHCH_N;s++){\n const q=(g*NXHCH_N+s)*3,x=hf[q],y=hf[q+1],z=hf[q+2];\n if(!Number.isFinite(x)||!Number.isFinite(y)||!Number.isFinite(z)){result.state='refused';result.reason='nonfinite-offset';break;}\n const d=Math.hypot(x,y,z);if(d>0)result.nonzeroSegments++;if(d>gm)gm=d;\n }\n if(result.state==='refused')break;\n if(gm>0)result.movingInstances++;if(gm>result.maxDisplacement)result.maxDisplacement=gm;\n }\n if(result.state==='refused'){result.movingInstances=null;result.nonzeroSegments=null;result.maxDisplacement=null;}\n const packed=GPU?.npc?.hair?.cvb;\n if(result.state==='measured'&&backend==='webgpu'&&packed&&NXCV&&Number.isInteger(NXCV.uHF2)&&NXCV.uHF2>=0){\n const start=NXCV.uHF2/4,count=NXHCH_NPC*NXHCH_N;\n if(Number.isInteger(start)&&packed.byteLength>=(start+count*4)*4){\n const values=new Float32Array(packed);let mismatch=0;\n for(let q=0;q<count;q++)for(let axis=0;axis<3;axis++)if(values[start+q*4+axis]!==hf[q*3+axis])mismatch++;\n result.packedAgreement={scope:'CPU-uniform-staging-buffer',mismatchedComponents:mismatch,comparedComponents:count*3};\n }\n }\n }\n }\n if(options&&options.structured===true&&options.guides!==undefined){\n const g=N?.hguide,rows=GPU?GPU.castPreparedRows:null,slot=options.instance===undefined?0:options.instance;\n if(!g||g.state!=='ready'||!g.attachment){result.attachment={state:'unavailable',reason:'guide-attachment-unavailable'};}\n else if(!Array.isArray(options.guides)||options.guides.length>g.sourceIndices.length||options.guides.some(i=>!Number.isInteger(i)||i<0||i>=g.sourceIndices.length)||!Number.isInteger(slot)||slot<0||slot>=NXHCH_NPC||(rows!==null&&slot>=rows)){result.attachment={state:'refused',reason:'attachment-request-range'};}\n else{\n const a=g.attachment,offset=slot*N.nj*8,frame=N.jf.slice(offset,offset+N.nj*8);\n result.attachment={state:'snapshot',method:a.method,anatomicalSemantics:false,scope:'current-CPU-palette-and-source-correspondence',drawSlot:slot,nativeId:N.nativeIds?.[slot]??null,joints:N.nj,palette:Array.from(frame),guides:options.guides.map(i=>({guide:i,sourceGuide:g.sourceIndices[i],sourceVertex:a.vertices[i],root:Array.from(g.rest.slice(i*g.nodesPerGuide*3,i*g.nodesPerGuide*3+3)),surface:Array.from(N.dbg.pos.slice(a.vertices[i]*3,a.vertices[i]*3+3)),joints:Array.from(a.joints.slice(i*4,i*4+4)),weights:Array.from(a.weights.slice(i*4,i*4+4)),distance:a.distance[i]}))};\n }\n}\nif(options&&options.structured===true)return result;\n if(result.state!=='measured')return 'NXHAIRPROBE2 state='+result.state+' backend='+backend+' reason='+result.reason;\n return 'NXHAIRPROBE2 verts='+result.vertices+' seg='+result.segments+' girls_moving='+result.movingInstances+' segs_nonzero='+result.nonzeroSegments+' maxdisp='+result.maxDisplacement.toFixed(6)+' ticks='+result.ticks+' backend='+backend+' scope='+result.scope;\n};\n" as *u8)
1580 return p
1581}
1582
1583// The hair chain amplitude ceiling, in MESH UNITS. Hoisted out of the emitted JS 2026-09-01
1584// because the magic ratchet was right to refuse it: a ceiling nobody can name is a defect
1585// generator in both directions. It is NOT free to move -- it is the working amplitude of the
1586// original short groom, about 2 percent of stature, held as a bound so that a long groom span/N
1587// cannot amplify deflections (measured at ~5x: hair swimming off the scalp).
1588const GPE_HAIR_AMP_CAP: i64 = 3400
1589
1590// gpe_hair_geometry -- THE CONTRACT SYMBOL, now the PER-ASSET half only: the asset's own hair
1591// geometry (HVRT/HTRI mesh preferred, HSTR guide strands otherwise) and each vertex's chain segment,
1592// derived from its depth below the top of the groom. Emitted inside loadNPC, where hj and S live.
1593func gpe_hair_geometry(out: *u8, pos: i64) -> i64 {
1594 var p: i64 = pos
1595 p = gpe_ap(out, p, "let hverts=null,hn=0,hseg=null,hbase=null,hpb=null,hmode=0,hscale=1,hgeo=0,huv=[],hkid=1,hvpk=0,hguide=null;\n" as *u8)
1596 p = gpe_ap(out, p, "// HVRT/HTRI = the FBX groom MESH (nx_nxa_hair), written in the SAME mesh space as VERT\nif(S.HVRT&&S.HTRI&&hj>=0){const hnv=rdU(S.HVRT.o),hnt=rdU(S.HTRI.o);\nconst hp=new Float32Array(hnv*3);\nfor(let i=0;i<hnv*3;i++)hp[i]=rdU(S.HVRT.o+8+i*8);\nconst tri=[];\nfor(let e=0;e<hnt*3;e++){const q=rdU(S.HTRI.o+8+e*8);tri.push(hp[q*3],hp[q*3+1],hp[q*3+2]);}\nhn=tri.length/3;hverts=new Float32Array(tri);hmode=1;hgeo=1;}\n" as *u8)
1597 p = gpe_ap(out, p, "// HSTR = sampled guide strands (the incumbent geometry path, preserved byte-for-byte in\n// behaviour; only its hand-written 7/24/550 are now the DERIVED constants above)\nelse if(S.HSTR&&hj>=0){const hs=S.HSTR;let hgState='ready',hgReason=null,nstr=0;\nif(!Number.isSafeInteger(hs.e)||hs.e<0||hs.e>U8.byteLength-32||!Number.isSafeInteger(hs.o)||!Number.isSafeInteger(hs.n)||hs.o<0||hs.n<1||hs.o>U8.byteLength||hs.n>Math.floor((U8.byteLength-hs.o)/8)){hgState='refused';hgReason='section-extent';}\nif(hgState==='ready'){nstr=rdU(hs.o);if(!Number.isSafeInteger(nstr)||nstr<0||nstr!==(hs.n-1)/NXHCH_W){hgState='refused';hgReason='guide-count-extent';}}\nif(hgState==='ready'){const hc=ckf(hs.o,hs.n);if(hc[0]!==dv.getUint32(hs.e+24,true)||hc[1]!==dv.getUint32(hs.e+28,true)){hgState='refused';hgReason='section-checksum';}}\nif(hgState==='ready'){for(let q=0;q<nstr*NXHCH_W;q++){const v=rdU(hs.o+8+q*8);if(!Number.isSafeInteger(v)||!Number.isSafeInteger(v*NXHCH_Q8)){hgState='refused';hgReason='coordinate-range';break;}}}\nif(hgState==='ready'&&nstr===0){hgState='absent';hgReason='empty-guides';}\nif(hgState!=='ready'){hguide={version:1,state:hgState,reason:hgReason};window.__nx_hair_guides={state:hgState,reason:hgReason};}else{\n// RIBBON HAIR (2026-08-26): guides -> Catmull-Rom smoothed -> interpolated children -> tapered\n// quad ribbons. Lines were sparse BY CONSTRUCTION (1px); ribbons carry width, taper and body --\n// the hair-card method every shipped game uses, built from the SAME generated guides.\n// COVERAGE (operator frames 2026-08-27: scalp glints between locks, speckle instead of locks): 4->6 children\n// per guide = 50% more ribbon area over the SAME groom (7,200 ribbons/head, ~202k tris/head, one VAO\n// instanced per girl, built once at load). The stripe/discard pair in the MFS is the other half.\nconst NXH_GUIDES=1200,NXH_KIDS=6,NXH_SUB=2;\nconst nsel=Math.min(nstr,NXH_GUIDES);\nconst hgRest=new Float64Array(nsel*(NXHCH_N+1)*3),hgSource=new Uint32Array(nsel);\nconst segs=[];huv=[];const KB9=[],KU9=[];for(let z9=0;z9<NXH_KIDS;z9++){KB9.push([]);KU9.push([]);}let sg9=KB9[0],uv9=KU9[0];\nconst hsh9=function(a9,b9){let n9=a9*374761393+b9*668265263+1442695041;n9^=n9>>13;n9=(n9*1274126177)|0;n9^=n9>>16;return (n9<0?-n9:n9)%2048/2048-.5;};\nlet gidx9=0;\nfor(let q5=0;q5<nsel;q5++){const s5=Math.floor(q5*nstr/nsel);const so=S.HSTR.o+8+s5*NXHCH_W*8;gidx9++;\n// HSTR and the renderer are Z-up. The ribbon builder below is Y-up; convert at its input and output boundaries.\nconst gp=[];for(let p5=0;p5<=NXHCH_N;p5++)gp.push([rdU(so+(p5*3)*8),rdU(so+(p5*3+2)*8),rdU(so+(p5*3+1)*8)]);\nhgSource[q5]=s5;for(let p5=0;p5<gp.length;p5++){const o5=(q5*gp.length+p5)*3;hgRest[o5]=gp[p5][0];hgRest[o5+1]=gp[p5][2];hgRest[o5+2]=gp[p5][1];}\n// Catmull-Rom subdivide x2: kills the 8-point kinks\nconst sp=[];for(let p5=0;p5<gp.length-1;p5++){const P0=gp[Math.max(0,p5-1)],P1=gp[p5],P2=gp[p5+1],P3=gp[Math.min(gp.length-1,p5+2)];\nfor(let u5=0;u5<NXH_SUB;u5++){const t9=u5/NXH_SUB,t2=t9*t9,t3=t2*t9;const c9=[0,0,0];\nfor(let a5=0;a5<3;a5++)c9[a5]=.5*((2*P1[a5])+(-P0[a5]+P2[a5])*t9+(2*P0[a5]-5*P1[a5]+4*P2[a5]-P3[a5])*t2+(-P0[a5]+3*P1[a5]-3*P2[a5]+P3[a5])*t3);\nsp.push(c9);}}sp.push(gp[gp.length-1]);\n// strand lock width from the groom's own span; root wide, tip narrow\nlet gyt=-1e18,gyb=1e18;for(const q5 of sp){if(q5[1]>gyt)gyt=q5[1];if(q5[1]<gyb)gyb=q5[1];}\nconst w09=Math.max(900,(gyt-gyb)*.045);\n// per-strand STABLE lateral axis: perpendicular of the strand's own root-to-tip horizontal\n// sweep. A tangent-derived axis collapses to zero on vertical segments (post-gravity, i.e.\n// MOST of the strand) and every quad degenerates to a sliver -- the pixel-dust class.\nconst shx9=sp[sp.length-1][0]-sp[0][0],shz9=sp[sp.length-1][2]-sp[0][2];\nlet fbx9=shz9,fbz9=-shx9;const fbl9=Math.hypot(fbx9,fbz9);\nif(fbl9<w09){fbx9=1;fbz9=0;}else{fbx9/=fbl9;fbz9/=fbl9;}\nfor(let k5=0;k5<NXH_KIDS;k5++){sg9=KB9[k5];uv9=KU9[k5];let ox9=hsh9(gidx9,k5)*w09*1.2,oz9=hsh9(gidx9+7,k5)*w09*1.2;\n// Child-center jitter is clamped outward in the builder's horizontal XZ plane.\n// This does not constrain ribbon edges or later motion against the body surface.\nconst rq9=Math.hypot(sp[0][0],sp[0][2])||1,nrx9=sp[0][0]/rq9,nrz9=sp[0][2]/rq9,rad9=ox9*nrx9+oz9*nrz9;\nif(rad9<0){ox9-=rad9*nrx9;oz9-=rad9*nrz9;}\nfor(let p5=0;p5<sp.length-1;p5++){const A=sp[p5],C=sp[p5+1];\nconst tx9=C[0]-A[0],ty9=C[1]-A[1],tz9=C[2]-A[2];\nlet lx9=tz9,lz9=-tx9;if(k5%2===1){lx9=tx9*.3+tz9;lz9=tz9*.3-tx9;}\nlet ll9=Math.hypot(lx9,lz9);\nif(ll9<w09*.5){lx9=fbx9;lz9=fbz9;ll9=1;}\nif(ll9===0)ll9=1;\nconst tp9=1-p5/sp.length*.75;const wA=w09*tp9,wB=w09*(1-(p5+1)/sp.length*.75);\nconst ax=A[0]+ox9,ay=A[1],az=A[2]+oz9,cx2=C[0]+ox9,cy2=C[1],cz2=C[2]+oz9;\nconst l1x=lx9/ll9*wA,l1z=lz9/ll9*wA,l2x=lx9/ll9*wB,l2z=lz9/ll9*wB;\nsg9.push(ax-l1x,ay,az-l1z, ax+l1x,ay,az+l1z, cx2+l2x,cy2,cz2+l2z);\nsg9.push(ax-l1x,ay,az-l1z, cx2+l2x,cy2,cz2+l2z, cx2-l2x,cy2,cz2-l2z);\nconst vA9=p5/sp.length,vB9=(p5+1)/sp.length;\nuv9.push(0,vA9, 1,vA9, 1,vB9, 0,vA9, 1,vB9, 0,vB9);}}}\nlet tv9=0,tu9=0;for(let z9=0;z9<NXH_KIDS;z9++){tv9+=KB9[z9].length;tu9+=KU9[z9].length;}hverts=new Float32Array(tv9);huv=new Array(tu9);let w9=0,x9=0;for(let z9=0;z9<NXH_KIDS;z9++){const b9=KB9[z9];/* Restore mesh Z-up before skinning and segment assignment. */for(let i9=0;i9<b9.length;i9+=3){hverts[w9++]=b9[i9];hverts[w9++]=b9[i9+2];hverts[w9++]=b9[i9+1];}const c9=KU9[z9];for(let i9=0;i9<c9.length;i9++)huv[x9++]=c9[i9];}hn=tv9/3;hkid=NXH_KIDS;hvpk=Math.floor(hn/NXH_KIDS);hmode=1;hgeo=2;hguide={version:1,state:'ready',validate:function(current,first,count,out){if(!current||current.length!==this.rest.length||!out||out.length<3)return {ok:false,reason:'state-extent'};if(!Number.isSafeInteger(first)||!Number.isSafeInteger(count)||first<0||count<0||first>hn||count>hn-first)return {ok:false,reason:'vertex-extent'};for(let i=0;i<current.length;i++)if(!Number.isFinite(current[i]))return {ok:false,reason:'state-nonfinite'};return {ok:true};},frame:'mesh-bind-z-up',transform:'identity',nodesPerGuide:NXHCH_N+1,subdivisions:NXH_SUB,verticesPerGuide:NXHCH_N*NXH_SUB*6,verticesPerChild:hvpk,children:hkid,sourceIndices:hgSource,rest:hgRest,bindSource:function(P,J,W,jointCount){if(P.length%3!==0||J.length!==P.length/3*4||W.length!==J.length)return {ok:false,reason:'surface-extent'};for(let i=0;i<P.length;i++)if(!Number.isFinite(P[i]))return {ok:false,reason:'surface-nonfinite'};const count=this.sourceIndices.length,vertices=new Uint32Array(count),distance=new Float64Array(count),joints=new Float32Array(count*4),weights=new Float32Array(count*4);for(let g=0;g<count;g++){const r=g*this.nodesPerGuide*3,rx=this.rest[r],ry=this.rest[r+1],rz=this.rest[r+2];let nearest=-1,d2=Infinity;for(let v=0;v<P.length/3;v++){const x=P[v*3]-rx,y=P[v*3+1]-ry,z=P[v*3+2]-rz,q=x*x+y*y+z*z;if(q<d2){d2=q;nearest=v;}}if(nearest<0)return {ok:false,reason:'surface-empty'};let sum=0;for(let k=0;k<4;k++){const j=J[nearest*4+k],w=W[nearest*4+k];if(!Number.isInteger(j)||j<0||j>=jointCount||!Number.isFinite(w)||w<0||w>1)return {ok:false,reason:'surface-weight-range'};joints[g*4+k]=j;weights[g*4+k]=w;sum+=w;}if(sum!==1)return {ok:false,reason:'surface-weight-sum'};vertices[g]=nearest;distance[g]=Math.sqrt(d2);}this.attachment={method:'nearest-source-vertex',anatomicalSemantics:false,vertices,distance,joints,weights};return {ok:true};},delta:function(current,vertex,out){const local=vertex%this.verticesPerChild,g=Math.floor(local/this.verticesPerGuide),q=local%this.verticesPerGuide,tri=q%6,s=Math.floor(q/6)+(tri===2||tri===4||tri===5?1:0),n=this.nodesPerGuide,p=Math.min(n-2,Math.floor(s/this.subdivisions)),t=(s-p*this.subdivisions)/this.subdivisions,t2=t*t,t3=t2*t,w0=(-t+2*t2-t3)*.5,w1=1-2.5*t2+1.5*t3,w2=(t+4*t2-3*t3)*.5,w3=(-t2+t3)*.5,i0=(g*n+Math.max(0,p-1))*3,i1=(g*n+p)*3,i2=i1+3,i3=(g*n+Math.min(n-1,p+2))*3;for(let a=0;a<3;a++)out[a]=w0*(current[i0+a]-this.rest[i0+a])+w1*(current[i1+a]-this.rest[i1+a])+w2*(current[i2+a]-this.rest[i2+a])+w3*(current[i3+a]-this.rest[i3+a]);return out;}};const hbind=hguide.bindSource(pos,aj,aw3,nj);if(!hbind.ok){hguide={version:1,state:'refused',reason:hbind.reason};hverts=null;hn=0;window.__nx_hair_guides={state:'refused',reason:hbind.reason};}else{window.__nx_hair_guides={state:'ready',guides:nsel,sourceGuides:nstr,attachment:'nearest-source-vertex'};}}}/*CHILD-MAJOR LAYOUT (2026-08-28): the ribbons are now emitted child-layer by child-layer instead of
1598guide by guide, so drawing a PREFIX of this buffer is every guide on the scalp at a lower child
1599count -- the groom thins evenly. The old guide-major order made a prefix a contiguous PATCH of
1600scalp, i.e. bald spots, which is why there was no geometry LOD to reach for. Content is unchanged:
1601the same triangles in a different order, and every consumer downstream is order-independent --
1602hseg is derived per-vertex from that vertex own Z (component 2, the up axis) against the global span, hbase is a copy, and the
1603fit pass translates all vertices uniformly. huv is reordered in lockstep, and the existing
1604huv.length===hn*2 guard downstream is the arity check on that.*/\n" as *u8)
1605 p = gpe_ap(out, p, "// PER-VERTEX CHAIN SEGMENT, DERIVED from depth below the top of the groom. This is what makes\n// the renderer consume N offsets instead of one: a vertex deep down the strand rides a later\n// segment, so it LAGS the crown.\nif(hverts&&hn>0&&hj>=0){const hcx9=bindR[hj*4],hcy9=bindR[hj*4+1];let hx0=1e18,hx1=-1e18,hy0=1e18,hy1=-1e18,hzt=-1e18,hzb=1e18;for(let v=0;v<hn;v++){const X9=hverts[v*3],Y9=hverts[v*3+1],Z9=hverts[v*3+2];if(X9<hx0)hx0=X9;if(X9>hx1)hx1=X9;if(Y9<hy0)hy0=Y9;if(Y9>hy1)hy1=Y9;if(Z9>hzt)hzt=Z9;if(Z9<hzb)hzb=Z9;}const hrx9=(hx1-hx0)/2||1,hry9=(hy1-hy0)/2||1;let htz9=-1e18;for(let u=0;u<nv;u++){const bx9=pos[u*3],by9=pos[u*3+1],bz9=pos[u*3+2];if(Math.abs(bx9-hcx9)<hrx9&&Math.abs(by9-hcy9)<hry9&&bz9>htz9)htz9=bz9;}if(htz9>-1e17){const NXHAIR_INSET=.06;const dz9=(htz9-hzt)+((hzt-hzb)*NXHAIR_INSET);let dx9=hcx9-(hx0+hx1)/2,dy9=hcy9-(hy0+hy1)/2;const cap9=hrx9*.5;if(dx9>cap9)dx9=cap9;if(dx9<-cap9)dx9=-cap9;if(dy9>cap9)dy9=cap9;if(dy9<-cap9)dy9=-cap9;if(hgeo===2){dx9=0;dy9=0;}/*generated groom: authored ON this mesh (gate-verified), fit must be IDENTITY -- recentering a posterior-biased groom onto the head joint shoved the mass onto the face (operator frames 2026-08-27)*/for(let v=0;v<hn;v++){hverts[v*3]+=dx9;hverts[v*3+1]+=dy9;hverts[v*3+2]+=(hgeo===2?0.0:dz9);}window.__nx_hairfit=[dx9,dy9,dz9];}}if(hverts&&hn>0){hbase=new Float32Array(hverts);hseg=new Uint8Array(hn);\n// PER-VERTEX SEGMENT ON THE UP AXIS. Component 2 is UP in this mesh space, not component 1:
1606// the fit pass above takes hzt/hzb (top/bottom of the groom) from Z and compares them to the
1607// topmost BODY vert pos[u*3+2], the shader remaps yup=vec3(sp.x,sp.z,-sp.y), and nxHairTick
1608// inverts that as model z = yup.y. This block read component 1 until 2026-09-01, which spread
1609// the 7-link lag and its squared weight hw9=(aHS/6)^2 ACROSS the head front-to-back instead of
1610// DOWN each strand: the groom sheared as rigid slabs and a root band could take full tip swing
1611// straight through the face.
1612let ztop=-1e18,zbot=1e18;
1613for(let v=0;v<hn;v++){const z9=hverts[v*3+2];if(z9>ztop)ztop=z9;if(z9<zbot)zbot=z9;}
1614const span=(ztop-zbot)||1;
1615// motion amplitude CAPPED: span is the groom's LENGTH along that axis, so span/N is a real
1616// per-segment reach. A long groom made span/N amplify deflections ~5x (hair swimming off the
1617// scalp). 3400 mesh units ~= 2 percent of stature -- the working amplitude of the original
1618// short groom, now a named bound instead of an accident of asset length.
1619hscale=Math.min(span/NXHCH_N," as *u8)
1620 p = gpe_num(out, p, GPE_HAIR_AMP_CAP)
1621 p = gpe_ap(out, p, ");
1622for(let v=0;v<hn;v++){let t=Math.floor((ztop-hverts[v*3+2])/span*NXHCH_N);
1623if(t<0)t=0;if(t>NXHCH_N-1)t=NXHCH_N-1;hseg[v]=t;}}\n" as *u8)
1624 // The loadNPC-scope doors FIRST (their variables live here; see gpe_hair_npc_doors for the
1625 // eval-time death their script-scope placement caused), THEN the DOM wiring that reads them.
1626 p = gpe_hair_npc_doors(out, p)
1627 // WIRE THE PROBE INTO THE PAGE -- do not merely DEFINE it. Measured on the shipped page:
1628 // __nx_hair_probe occurred exactly ONCE, its own definition, and NOTHING called it. The single
1629 // measurement built for this rung was reachable only from a hand-typed JS console and was
1630 // therefore INVISIBLE to the capture wire that verifies the picture -- the estate's
1631 // built-and-unwired defect happening INSIDE an artifact. ?hairprobe now renders it into the DOM
1632 // on the page's OWN frame clock (requestAnimationFrame: no new cadence constant to pick, and it
1633 // stops when the page does), so a headless screenshot or --dump-dom can read the number the
1634 // gate judges instead of the operator having to trust a screenshot.
1635 p = gpe_ap(out, p, "if(location.search.indexOf('hairprobe')>=0){\nconst hpEl=document.createElement('pre');hpEl.id='nxhairprobe';\nhpEl.style.cssText='font:12px ui-monospace,monospace;color:#a8e6c0;white-space:pre-wrap;max-width:96vw;margin:0';\nhpEl.textContent='NXHAIRPROBE1 pending';\nconst hpM=document.querySelector('main');if(hpM)hpM.appendChild(hpEl);\nconst hpTick=function(){var s='';try{s=window.__nx_hair_probe();}catch(e){s='NXHAIRPROBE1 error';}\nhpEl.textContent=s;window.__nx_hair_probe_text=s;nxDemand.frame(hpTick);};\nnxDemand.frame(hpTick);}\n" as *u8)
1636 return p
1637}
1638
1639// gpe_garment_draw -- THE CONTRACT SYMBOL (GE13c, 2026-08-30): clothing BY GARMENT ID, the engine's garment table
1640// made visible (operator: random dresses, not beach outfits). Emits the MFS band block; the JS half (drawNPCs)
1641// feeds uGT/uGB (ids) and uCT/uCB (tints) per girl from mobgar/mobgart/mobgarcol, and the MVS half degenerates the
1642// GVRT skirt instance for every id that is not a skirt-class garment. Reuses what exists -- the incumbent's
1643// painted torso bands and the skirt mesh -- so nothing here is new geometry; the E4 mesh-top ladder is the rung
1644// after this one.
1645func gpe_garment_draw(out: *u8, pos: i64) -> i64 {
1646 var p: i64 = pos
1647 p = gpe_ap(out, p, "// ---- gpe_garment_draw: bands BY GARMENT ID. Ids (the engine's table): 0 none 1 bikini-top 2 bikini-bottom\n// 3 one-piece 4 sarong 5 sundress 6 tee 7 shorts 8 skirt 9 evening-dress. Bands: 6 tee = the incumbent top band\n// (.545 -> uNIP+.055, torso-gated |x|<15000) in the UPPER tint; 1 bikini top = the bust band |h-uNIP|<.055 (the\n// half-width the nipple detail itself uses) in the upper tint; 7 shorts = the incumbent hip band (.395 = mid-thigh\n// -> .545) in the lower tint, the incumbent's .8 shade kept; 2 bikini bottom = crotch .475 (Drillis-Contini, the\n// pubic block's own line) -> hip .545; 3 one-piece = top band continued through the hip band in ONE tint, no\n// skirt; 5 sundress / 9 evening = the top band in the dress tint + the skirt mesh (MVS); 8 skirt / 4 sarong = the\n// skirt mesh only. 0 = bare, the uOF>1.5 path. Coverage for the older consumers (nipple detail, pubic hair, the\n// under-cloth hair cull) still arrives as uOF, DERIVED from these ids JS-side.\n// gpe_garment_mesh (2026-08-30): every band below is now a FALLBACK. uGMH carries one bit per garment id whose\n// generated MESH loaded from the asset's GARM section (bit k = id k); a band paints only while its id's bit is\n// clear -- an asset without GARM (or a failed parse) degrades to paint, never to nude, and ?garpaint=1 clears\n// the mask so the bands can be viewed UNDER the meshes as the falsifiability lever.\nif(uAuth==0){\nint gt9=int(uGT[vII]+.5);int gb9=int(uGB[vII]+.5);bool dr9=(gb9==5||gb9==9);bool op9=(gb9==3);\nbool pm1=(uGMH&2)==0,pm2=(uGMH&4)==0,pm3=(uGMH&8)==0,pm5=(uGMH&32)==0,pm6=(uGMH&64)==0,pm7=(uGMH&128)==0,pm9=(uGMH&512)==0;\nif(pm6&>9==6&&!dr9&&!op9&&h>.545&&h<uNIP+.055&&axb<15000.)mc=uCT[vII];\nif((dr9||op9)&&h>.545&&h<uNIP+.055&&axb<15000.&&((gb9==5&&pm5)||(gb9==9&&pm9)||(gb9==3&&pm3)))mc=uCB[vII];\nif(pm1&>9==1&&!dr9&&!op9&&abs(h-uNIP)<.055&&axb<15000.)mc=uCT[vII];\nif(pm3&&op9&&h>.395&&h<.545&&axb<15000.)mc=uCB[vII];\nif(pm7&&gb9==7&&h>.395&&h<.545&&axb<15000.)mc=uCB[vII]*.8;\nif(pm2&&gb9==2&&h>.475&&h<.545&&axb<15000.)mc=uCB[vII];\n}\n" as *u8)
1648 return p
1649}
1650
1651// gpe_vb_find -- bounded first-offset scan for NUL-terminated pat in b[from..n); -1 when absent.
1652// Exit is FLAG-carried (hit), never written into the cursor -- the cursor-sentinel idiom erases
1653// the answer and nx_srclint hunts it by name.
1654func gpe_vb_find(b: *u8, n: i64, pat: *u8, from: i64) -> i64 {
1655 let pl: i64 = gpe_slen(pat)
1656 var i: i64 = from
1657 while i + pl <= n {
1658 var k: i64 = 0
1659 var hit: i64 = 1
1660 while k < pl {
1661 if b[i+k] != pat[k] { hit = 0; k = pl } else { k = k + 1 }
1662 }
1663 if hit == 1 { return i }
1664 i = i + 1
1665 }
1666 return 0 - 1
1667}
1668
1669// gpe_version_badge -- GE20 (operator: the beach "still shows the same build number"): the engine
1670// version LADDER and declared TARGET VERSION, read from the compare plane's OWN BYTES at every
1671// emit and rendered beside the renderer tier badge. Sources: buildroot/knowledge/compare/
1672// gameengine.plan `ver|` rows (the ladder) and buildroot/knowledge/compare/gameengine.rank stamp
1673// token `target_version=` (measured 2026-08-30: the rank artifact's LAST LINE is a `# asof=...
1674// target_version=X ...` stamp; it carries NO prose "TARGET VERSION" line, so the token is the
1675// anchor). NEVER a hand-typed version: a republish re-reads, so the world pages and the compare
1676// board cannot disagree. An unreadable plan/rank degrades to a NAMED absence in the badge text
1677// (never a fabricated number), and the announce line puts the read outcome in the emit log.
1678func gpe_version_badge(out: *u8, pos: i64) -> i64 {
1679 var p: i64 = pos
1680 p = gpe_ap(out, p, "const __vb=document.createElement(\"div\");__vb.style.cssText=\"font:11px ui-monospace,monospace;color:#7d76a0;letter-spacing:.08em\";__vb.textContent=\"Nishi Engine \\u2014 target " as *u8)
1681 let lpr: *i64 = sys_mmap(16) as *i64
1682 let rank: *u8 = sys_read_file("buildroot/knowledge/compare/gameengine.rank" as *u8, lpr)
1683 let rn: i64 = lpr[0]
1684 var vgot: i64 = 0
1685 if (rank as i64) != 0 {
1686 let tpat: *u8 = "target_version=" as *u8
1687 let ti: i64 = gpe_vb_find(rank, rn, tpat, 0)
1688 if ti >= 0 {
1689 let ts: i64 = ti + gpe_slen(tpat)
1690 var te: i64 = ts
1691 var run: i64 = 1
1692 // 32=space 10=newline: the stamp line's own field separators end the token
1693 while run == 1 {
1694 if te >= rn { run = 0 } else {
1695 let c: i64 = rank[te] as i64
1696 if c == 32 { run = 0 } else { if c == 10 { run = 0 } else { te = te + 1 } }
1697 }
1698 }
1699 if te > ts { p = gpe_ap(out, p, "v" as *u8); p = gpe_ap_n(out, p, ((rank as i64) + ts) as *u8, te - ts); vgot = 1 }
1700 }
1701 }
1702 if vgot == 0 { p = gpe_ap(out, p, "v-unread" as *u8) }
1703 p = gpe_ap(out, p, " (ladder " as *u8)
1704 let lpp: *i64 = sys_mmap(16) as *i64
1705 let plan: *u8 = sys_read_file("buildroot/knowledge/compare/gameengine.plan" as *u8, lpp)
1706 let pn2: i64 = lpp[0]
1707 var lgot: i64 = 0
1708 if (plan as i64) != 0 {
1709 let vpat: *u8 = "\nver|" as *u8
1710 var vi: i64 = gpe_vb_find(plan, pn2, vpat, 0)
1711 while vi >= 0 {
1712 let vs: i64 = vi + gpe_slen(vpat)
1713 var ve: i64 = vs
1714 var run2: i64 = 1
1715 // 124='|' 10=newline: the ver-row grammar's own separators end the label
1716 while run2 == 1 {
1717 if ve >= pn2 { run2 = 0 } else {
1718 let c2: i64 = plan[ve] as i64
1719 if c2 == 124 { run2 = 0 } else { if c2 == 10 { run2 = 0 } else { ve = ve + 1 } }
1720 }
1721 }
1722 if ve > vs {
1723 if lgot > 0 { p = gpe_ap(out, p, "/" as *u8) }
1724 p = gpe_ap_n(out, p, ((plan as i64) + vs) as *u8, ve - vs)
1725 lgot = lgot + 1
1726 }
1727 vi = gpe_vb_find(plan, pn2, vpat, ve)
1728 }
1729 }
1730 if lgot == 0 { p = gpe_ap(out, p, "unread" as *u8) }
1731 p = gpe_ap(out, p, ") \\u00b7 emit " as *u8)
1732 p = gpe_num(out, p, sys_now_realtime_sec())
1733 p = gpe_ap(out, p, "\";window.__nx_engine_badge=__vb.textContent;if(__mp)__mp.parentNode.insertBefore(__vb,__mp);\n" as *u8)
1734 gpe_puts("gpe_version_badge: rank_target=" as *u8)
1735 if vgot == 1 { gpe_puts("READ" as *u8) } else { gpe_puts("ABSENT" as *u8) }
1736 gpe_puts(" ladder_rows=" as *u8)
1737 gpe_pn(lgot)
1738 gpe_puts("\n" as *u8)
1739 return p
1740}
1741
1742// GE52 gpe_release_block -- THE RELEASE DELTA ON THE REVIEW PAGE (2026-09-04; operator: consistent progress each
1743// release on the /world/beach review page, which had not moved -- the accept- plane held four REJECT rows and one
1744// UNJUDGED from 2026-08-30 and nothing after, while every seat since shipped plumbing the page could not show).
1745// Every emit renders, FROM DATA: the operator's latest verdict per subject (knowledge/store/accept-), the referee
1746// percept beside it (knowledge/store/referee-), every land row on the gameengine, graphics and charsim boards dated
1747// strictly after the newest operator verdict, and the exact accept-row recipe for THIS build stamp. The arithmetic
1748// is nx_release_delta_lib (proven by nx_release_delta_gate); this function only reads the planes and boards and
1749// hands buffers over. An unreadable plane or board is a NAMED absence in the emit log and a counted gap in the
1750// block (boards read n/m), never a fabricated zero. Exported for instruments as window.__nx_release.
1751// THE FLIP IS THE RECEIPT, THE ACCEPT ROW IS THE PROOF: only an operator ACCEPT row moves a subject out of INCOMPLETE.
1752const GPE_RD_HTML_CAP: i64 = 262144
1753const GPE_RD_PLANS: i64 = 3
1754const GPE_RD_PLAN_GE: *u8 = "buildroot/knowledge/compare/gameengine.plan"
1755const GPE_RD_PLAN_GR: *u8 = "buildroot/knowledge/compare/graphics.plan"
1756const GPE_RD_PLAN_CS: *u8 = "buildroot/knowledge/compare/charsim.plan"
1757func gpe_rd_board(path: *u8, dom: *u8, since: *u8, recent: *ReleaseRecent, counts: *i64, read: *i64) -> i64 {
1758 let lp: *i64 = sys_mmap(16) as *i64
1759 let plan: *u8 = sys_read_file(path, lp)
1760 if (plan as i64) == 0 { gpe_puts("gpe_release_block: BOARD-UNREADABLE " as *u8); gpe_puts(path); gpe_puts("\n" as *u8); return 0 }
1761 if rr_collect(recent,plan,lp[0],since,dom,counts)<0 {
1762 gpe_puts("gpe_release_block: release allocation refused; no partial history emitted\n" as *u8);sys_exit(65)
1763 }
1764 read[0] = read[0] + 1
1765 return 1
1766}
1767func gpe_release_block(out: *u8, pos: i64) -> i64 {
1768 var p: i64 = pos
1769 let tab: *u8 = sys_mmap(RD_REC * RD_MAX_SUBJ)
1770 let since: *u8 = sys_mmap(RD_W_DATE)
1771 since[0] = 0 as u8
1772 var ns: i64 = 0
1773 var acc_bytes: i64 = 0
1774 let acc: *i64 = al_rows_open(AL_PFX_ACCEPT)
1775 if acc[AL_RS_LEN] > 0 { acc_bytes = acc[AL_RS_LEN]; ns = rd_op_latest(acc[AL_RS_BUF] as *u8, acc[AL_RS_LEN], tab, since) }
1776 var ref_bytes: i64 = 0
1777 let ref: *i64 = al_rows_open(AL_PFX_REFEREE)
1778 if ref[AL_RS_LEN] > 0 { ref_bytes = ref[AL_RS_LEN]; ns = rd_ref_latest(ref[AL_RS_BUF] as *u8, ref[AL_RS_LEN], tab, ns) }
1779 let recent: *ReleaseRecent = rr_new()
1780 if (recent as i64)<=0 { gpe_puts("gpe_release_block: allocation failed\n" as *u8);sys_exit(65) }
1781 let counts: *i64 = sys_mmap(8 * RD_COUNTS) as *i64
1782 var ci: i64 = 0
1783 while ci < RD_COUNTS { counts[ci] = 0; ci = ci + 1 }
1784 let read: *i64 = sys_mmap(16) as *i64
1785 read[0] = 0
1786 gpe_rd_board(GPE_RD_PLAN_GE, "gameengine" as *u8, since, recent, counts, read)
1787 gpe_rd_board(GPE_RD_PLAN_GR, "graphics" as *u8, since, recent, counts, read)
1788 gpe_rd_board(GPE_RD_PLAN_CS, "charsim" as *u8, since, recent, counts, read)
1789 let land_cap: i64=rr_required(recent)
1790 if land_cap<1 || land_cap>GPE_OUT_CAP-p-GPE_RD_HTML_CAP {
1791 gpe_puts("gpe_release_block: complete history exceeds page output budget; required=" as *u8);gpe_pn(land_cap);gpe_puts("\n" as *u8);sys_exit(65)
1792 }
1793 let land: *u8=sys_mmap(land_cap)
1794 if (land as i64)<=0 { gpe_puts("gpe_release_block: history allocation failed\n" as *u8);sys_exit(65) }
1795 let lo: i64=rr_render(recent,land,land_cap,counts)
1796 if lo<0 || counts[RD_C_LISTED]!=counts[RD_C_LAND] { gpe_puts("gpe_release_block: complete history rendering refused\n" as *u8);sys_exit(65) }
1797 let stamp: i64 = sys_now_realtime_sec()
1798 let html_cap: i64=GPE_RD_HTML_CAP+lo
1799 let html: *u8 = sys_mmap(html_cap)
1800 if (html as i64)<=0 { gpe_puts("gpe_release_block: HTML allocation failed\n" as *u8);sys_exit(65) }
1801 let hn: i64 = rd_emit(html, 0, html_cap, stamp, since, tab, ns, land, counts, read[0], GPE_RD_PLANS)
1802 p = gpe_ap(out, p, "const __rb=document.createElement(\"div\");__rb.id=\"nxrelease\";__rb.innerHTML=\"" as *u8)
1803 p = gpe_ap_n(out, p, html, hn)
1804 p = gpe_ap(out, p, "\";if(__mp)__mp.parentNode.insertBefore(__rb,__mp.nextSibling);const __releaseEvidence=document.getElementById(\"nx-release-evidence\");if(__releaseEvidence)__rb.prepend(__releaseEvidence);window.__nx_release={since:\"" as *u8)
1805 p = gpe_ap(out, p, since)
1806 p = gpe_ap(out, p, "\",landed:" as *u8)
1807 p = gpe_num(out, p, counts[RD_C_LAND])
1808 p = gpe_ap(out, p, ",retracted:" as *u8)
1809 p = gpe_num(out, p, counts[RD_C_RETRACT])
1810 p = gpe_ap(out, p, ",subjects:" as *u8)
1811 p = gpe_num(out, p, ns)
1812 p = gpe_ap(out, p, ",boards:" as *u8)
1813 p = gpe_num(out, p, read[0])
1814 p = gpe_ap(out, p, "};\n" as *u8)
1815 p = gpe_ap(out, p, nrv_source())
1816 p = gpe_ap(out,p,"window.NishiWorkspace?.registerPart('progress',__rb);\n" as *u8)
1817 gpe_puts("gpe_release_block: accept_bytes=" as *u8); gpe_pn(acc_bytes)
1818 gpe_puts(" referee_bytes=" as *u8); gpe_pn(ref_bytes)
1819 gpe_puts(" subjects=" as *u8); gpe_pn(ns)
1820 gpe_puts(" since=" as *u8)
1821 if since[0] == (0 as u8) { gpe_puts("NEVER" as *u8) } else { gpe_puts(since) }
1822 gpe_puts(" landed=" as *u8); gpe_pn(counts[RD_C_LAND])
1823 gpe_puts(" listed=" as *u8); gpe_pn(counts[RD_C_LISTED])
1824 gpe_puts(" boards=" as *u8); gpe_pn(read[0]); gpe_puts("/" as *u8); gpe_pn(GPE_RD_PLANS)
1825 gpe_puts(" html=" as *u8); gpe_pn(hn); gpe_puts("\n" as *u8)
1826 return p
1827}
1828
1829// GE32 (2026-09-02): THE FRAME-BUDGET HUD. Every statistic is computed in the ENGINE (nx_perf_lib through the
1830// perf_* doors); this block only READS doors, prints one line, mirrors it onto the tier badge as
1831// data-nx-telemetry (and the raw window as data-nx-frames, so a headless capture yields a trace the pacing
1832// referee nx_frame_pacing_gate can judge), exports window.__nx_telemetry, and beacons the line on pagehide to
1833// the sovereign telemetry door (/world/__telemetry -- the server half is GE33's inflow, owed and named here).
1834// Visible under ?hud=1; exported always. Draw calls print UNCOUNTED until the GL instrument block publishes a
1835// counter; GPU memory is declared UNOBSERVABLE in a browser rather than guessed.
1836func gpe_frame_hud(out: *u8, pos: i64) -> i64 {
1837 var p: i64 = pos
1838 p = gpe_ap(out, p, "// GE32 FRAME-BUDGET HUD: every number below is READ from an engine door; this block decides nothing.\n(function(){if(!ex.perf_n)return;\nconst H=document.createElement(\"div\");H.id=\"nxhud\";H.style.cssText=\"font:11px ui-monospace,monospace;color:#b9b1dc;letter-spacing:.04em;white-space:pre-wrap\";\nif(location.search.indexOf(\"hud=1\")<0)H.hidden=true;\nconst _mp3=document.querySelector(\"p\");if(_mp3)_mp3.parentNode.insertBefore(H,_mp3);\nconst N=f=>f?Number(f()):-1;\nfunction tele(){const t={frame_interval_mode:(ex.perf_frame_raw?\"raw-normal-loop-ms-includes-pauses\":\"legacy-recorder\"),gpu_execution_ms:null,tier:window.__sov_tier||\"probing\",res:cv.width+\"x\"+cv.height,q:N(ex.quality),work_ms:N(ex.work_ms),budget_ms:N(ex.perf_budget),n:N(ex.perf_n),total:N(ex.perf_total),p50:N(ex.perf_p50),p95:N(ex.perf_p95),p99:N(ex.perf_p99),worst:N(ex.perf_worst),worst_ever:N(ex.perf_worst_ever),spikes:N(ex.perf_spikes),over:N(ex.perf_over),long:N(ex.perf_long),draws:(typeof window.__sov_gldraws===\"number\")?window.__sov_gldraws:\"UNCOUNTED\",wasm_mb:Math.round(ex.memory.buffer.byteLength/1048576),heap_mb:(performance.memory&&performance.memory.usedJSHeapSize)?Math.round(performance.memory.usedJSHeapSize/1048576):\"UNOBSERVABLE\",gpu_mem:\"UNOBSERVABLE-in-browser\",gl:(window.__nx_gl?String(window.__nx_gl.state||\"probed\"):\"unprobed\"),gpu:(window.GPU?1:0),cast:(window.__npc_up?\"up\":\"down\"),stage:String(window.__lst||\"pre\"),kernel:(window.__nx_kernel?String(window.__nx_kernel.s):\"unrun\"),door:((typeof nxDoor===\"function\")?nxDoor():\"ladder-absent\"),refused:((typeof nxDoorReport===\"function\")?nxDoorReport():\"ladder-absent\")};const P=window.__nx_gpu_timer;const last=P&&P.last;t.gpu_execution_ms=last?last.duration_ms:null;t.gpu_timing={state:P?P.state:'not-initialized',scope:'world-and-cast-render-pass',last:last||null};if(P){for(const key of ['observed_frames','unavailable_frames','attempted','completed','busy_frames','failed','cancelled','inflight','peak_inflight','result_dropped','capacity','buffer_bytes','buffer_budget_bytes','error','cleanup_errors']){if(P[key]!==undefined)t.gpu_timing[key]=P[key];}}t.cpu_frame=window.__nx_cpu_frame||null;t.gpu_adapter=window.__nx_gpu_adapter||null;window.__nx_telemetry=t;return t;}\nfunction frames(){const n=N(ex.perf_n);const a=[];for(let i=0;i<n;i++)a.push(Number(ex.perf_sample(BigInt(i))));return a.join(\",\");}\nfunction line(t){return \"timing \"+t.frame_interval_mode+\" | frame budget \"+t.budget_ms+\"ms | \"+t.tier+\" \"+t.res+\" q\"+t.q+\" | frame p50 \"+t.p50+\" p95 \"+t.p95+\" p99 \"+t.p99+\" worst \"+t.worst+\" (ever \"+t.worst_ever+\") ms over \"+t.n+\"/\"+t.total+\" frames | spikes \"+t.spikes+\" over-budget \"+t.over+\" | controller input \"+t.work_ms+\"ms (not GPU execution) | draws \"+t.draws+\" | wasm \"+t.wasm_mb+\"MB heap \"+t.heap_mb+\" gpu \"+t.gpu_mem+\" | gl-probe \"+t.gl+\" gpu-api \"+t.gpu+\" cast \"+t.cast+\" stage \"+t.stage+\" kernel \"+t.kernel+\" door \"+t.door+\" refused \"+t.refused+\" | GPU pass latest \"+(t.gpu_execution_ms===null?\"unavailable\":t.gpu_execution_ms+\"ms\")+\" [\"+t.gpu_timing.state+\"] frame \"+(t.gpu_timing.last?t.gpu_timing.last.frame:\"none\")+\" measured \"+(t.gpu_timing.completed||0)+\" busy \"+(t.gpu_timing.busy_frames||0)+\" failed \"+(t.gpu_timing.failed||0);}\nnxDemand.interval(()=>{const t=tele();const l=line(t);H.textContent=l;__tb.setAttribute(\"data-nx-telemetry\",l);__tb.setAttribute(\"data-nx-frames\",frames());},1000);\n// GE37 BEACON -> nx_world_telemetry: the WINDOW travels (frames[]), not only its summary, so the sink re-judges it through the same ruler; ?w= names the world (the sink refuses anything but [a-z0-9_]).\nconst captureCadenceMs=300000;\nlet capturePending=null,captureFlight=null,captureAccepted=0,captureSkipped=0;\nfunction captureStatus(state,reason){\n const status=Object.freeze({version:2,state,reason,capture:capturePending?capturePending.id:null,accepted:captureAccepted,skipped:captureSkipped});\n window.__nx_capture_delivery=status;\n renderDeliveryStatus();\n}\nfunction renderDeliveryStatus(){\n try{\n if(typeof document==='undefined')return;\n const status=window.__nx_capture_delivery;if(!status)return;\n let output=document.getElementById('nx-capture-delivery');\n if(!output){\n const canvas=document.getElementById('c');if(!canvas)return;\n output=document.createElement('output');output.id='nx-capture-delivery';\n output.setAttribute('role','status');output.setAttribute('aria-live','polite');output.setAttribute('aria-atomic','true');\n output.style.cssText='display:block;max-width:100%;overflow-wrap:anywhere;color:inherit;font:inherit';\n canvas.insertAdjacentElement('afterend',output);\n }\n const labels={idle:'Waiting for a capture',sending:'Sending capture',accepted:'Capture accepted by the server','retry-pending':'Capture retained for retry','queued-unacknowledged':'Capture queued; server acceptance unconfirmed',refused:'Capture refused; automatic sending paused',unavailable:'Capture unavailable'};\n const persistence=window.__sov?.persistence;\n const captureText='Evidence capture · '+(labels[status.state]||status.state)+' · '+status.accepted+' accepted'+(status.reason?' · '+status.reason:'');\n output.textContent=(persistence?.state==='needs-intervention'?'SAVE PAUSED: '+persistence.reason+' · ':'')+captureText;\n output.setAttribute('data-capture-state',status.state);\n output.setAttribute('data-persistence-state',persistence?.state||'unobserved');\n }catch(_e){/* Display failure must not change delivery state or interrupt the game. */}\n}\naddEventListener('nx-persistence-change',renderDeliveryStatus);\nfunction capturePrepare(){\n if(capturePending){captureSkipped++;return capturePending;}\n const identity=window.__nx_identity;\n if(!identity||identity.state!=='ready')throw new Error('identity-unavailable');\n const t=tele();t.frames=frames().split(',').filter(s=>s.length).map(Number);\n if(!t.frames.length)throw new Error('frames-empty');\n const world=new URLSearchParams(location.search).get('w')||location.pathname.split('/').pop()||'world';\n const renderer=window.__nx_cpu_frame&&window.__nx_cpu_frame.renderer;\n const fields={w:world,capture:crypto.randomUUID(),release:identity.release,wasm:identity.wasm,renderer,mode:t.frame_interval_mode,res:t.res};\n if(!/^[a-z0-9_]{1,32}$/.test(world)||typeof renderer!=='string'||!/^[a-z0-9_-]{1,64}$/.test(renderer))throw new Error('capture-metadata-unavailable');\n t.capture_identity=identity;t.renderer_at_capture=renderer;\n const url='/world/__telemetry/v2?'+Object.entries(fields).map(([k,v])=>k+'='+encodeURIComponent(v)).join('&');\n capturePending=Object.freeze({id:fields.capture,url,body:JSON.stringify(t)});\n return capturePending;\n}\nasync function captureSend(){\n try{\n if(captureFlight){captureSkipped++;return;}\n const request=capturePrepare();\n if(window.__nx_capture_delivery&&window.__nx_capture_delivery.state==='refused')return;\n const controller=new AbortController();captureFlight=controller;\n const deadline=setTimeout(()=>controller.abort(),captureCadenceMs);\n captureStatus('sending',null);\n try{\n const response=await fetch(request.url,{method:'POST',body:request.body,signal:controller.signal});\n if(response.status===204){captureAccepted++;captureStatus('accepted',null);capturePending=null;}\n else captureStatus(response.status>=400&&response.status<500&&response.status!==429?'refused':'retry-pending','http-'+response.status);\n }catch(_e){captureStatus('retry-pending',controller.signal.aborted?'deadline':'transport-failed');}\n finally{clearTimeout(deadline);captureFlight=null;}\n }catch(_e){captureStatus('unavailable',String(_e.message||_e));}\n}\nfunction capturePagehide(){\n try{\n if(window.__nx_capture_delivery&&window.__nx_capture_delivery.state==='refused')return;\n const request=capturePrepare();\n if(!navigator.sendBeacon){captureStatus('retry-pending','beacon-unavailable');return;}\n const queued=navigator.sendBeacon(request.url,request.body);\n captureStatus(queued?'queued-unacknowledged':'retry-pending',queued?null:'beacon-queue-refused');\n }catch(_e){captureStatus('unavailable',String(_e.message||_e));}\n}\ncaptureStatus('idle',null);\naddEventListener('pagehide',capturePagehide);nxDemand.interval(captureSend,captureCadenceMs);\n})();\n" as *u8)
1839 return p
1840}
1841
1842// GR26 gpe_sky_atmos -- THE SKY EMISSION, UNDER ITS CONTRACT NAME AT LAST.
1843// The physically-based sky has SHIPPED for some time: derived Rayleigh with wavelength-dependent tau
1844// (440/lambda)^4 => (.123,.287,.700), Kasten-Young airmass clamped at 38, single-scatter 1-exp(-tau*am),
1845// a sun disc, the SUNT transmittance dusk tint, and volumetric clouds; the aerial-perspective term in
1846// shade() uses the SAME constants. What did NOT exist was the SYMBOL -- the emission sat inline in
1847// gpe_build_s, so the board watch read _ABSENT_:gpe_sky_atmos forever while the matrix note still
1848// described a two-stop gradient this shader had already replaced.
1849// * A CAPABILITY THAT SHIPS WITHOUT ITS CONTRACT NAME IS INVISIBLE TO EVERY INSTRUMENT WATCHING FOR
1850// THE NAME, AND IT ROTS IN THE PESSIMISTIC DIRECTION -- THE BOARD UNDERSTATES WHAT IS BUILT, WHICH
1851// IS THE HALF NOBODY AUDITS.
1852// SCOPE, STATED PLAINLY: this names and OWNS the sky emission point -- every sky byte the page ever
1853// emits passes through here -- but the shader SOURCE literal still sits at the call site. Hoisting the
1854// literal in here was built and proven content-neutral locally (nx_contentdiff 3592 runs, lost 0,
1855// gained 0, symmetry=IDENTICAL-CONTENT); it is not shipped because doing so means retyping 4 KB of
1856// shader across a lossy transport, and one wrong byte is a corrupted sky nobody would see until a
1857// human looked at the page.
1858func gpe_sky_atmos(out: *u8, p: i64, src: *u8) -> i64 {
1859 return gpe_ap(out, p, src)
1860}
1861
1862func gpe_demand_lifecycle(out: *u8, p0: i64) -> i64 {
1863 return gpe_ap(out,p0,"<script>var nxDemand=window.__nx_demand=(()=>{\nconst jobs=new Map(),hooks=new Set();let next=0,away=false,frozen=false,active=!document.hidden,revision=0;const metrics={frames:0,intervals:0,idles:0,cancelled:0,suppressed:0,pauses:0,resumes:0,finalizations:0,finalization_failures:0};const finals=new Map();\nfunction state(){return {version:1,state:active?'running':'paused',reason:away?'page-hidden':frozen?'frozen':document.hidden?'document-hidden':'visible',revision,pending:jobs.size,metrics:{...metrics}};}\nfunction cancel(j){if(j.handle===null)return;metrics.cancelled++;if(j.kind==='frame')cancelAnimationFrame(j.handle);else if(j.kind==='idle'&&window.cancelIdleCallback)cancelIdleCallback(j.handle);else clearTimeout(j.handle);j.handle=null;}\nfunction arm(j){if(!active||j.handle!==null)return;const run=(arg)=>{j.handle=null;if(!active){metrics.suppressed++;return;}metrics[j.kind==='frame'?'frames':j.kind==='interval'?'intervals':'idles']++;if(j.kind!=='interval')jobs.delete(j.id);try{j.fn(arg);}finally{if(j.kind==='interval'&&jobs.has(j.id))arm(j);}};if(j.kind==='frame')j.handle=requestAnimationFrame(run);else if(j.kind==='idle'&&window.requestIdleCallback)j.handle=requestIdleCallback(run,j.options);else j.handle=setTimeout(run,j.kind==='interval'?j.ms:0);}\nfunction add(kind,fn,ms,options){const j={id:++next,kind,fn,ms,options,handle:null};jobs.set(j.id,j);arm(j);return j.id;}\nfunction update(){const wanted=!away&&!frozen&&!document.hidden;if(wanted===active)return;active=wanted;revision++;metrics[active?'resumes':'pauses']++;if(!active)for(const j of jobs.values())cancel(j);for(const hook of hooks){try{hook(active);}catch(error){console.error('Nishi lifecycle callback failed',error);}}if(active)for(const j of jobs.values())arm(j);}\ndocument.addEventListener('visibilitychange',update);addEventListener('pagehide',()=>{away=true;update();});addEventListener('pageshow',()=>{away=false;update();});document.addEventListener('freeze',()=>{frozen=true;update();});document.addEventListener('resume',()=>{frozen=false;update();});\nreturn {get active(){return active;},get revision(){return revision;},state,finalize:(key,fn)=>{if(finals.get(key)===revision)return;finals.set(key,revision);try{const result=fn();if(result===-1){finals.delete(key);metrics.finalization_failures++;return result;}metrics.finalizations++;return result;}catch(error){finals.delete(key);metrics.finalization_failures++;throw error;}},frame:fn=>add('frame',fn),interval:(fn,ms)=>add('interval',fn,ms),clearInterval:id=>{const j=jobs.get(id);if(j){cancel(j);jobs.delete(id);}},idle:(fn,options)=>add('idle',fn,0,options),onChange:fn=>{hooks.add(fn);return ()=>hooks.delete(fn);}};\n})();\n</script>" as *u8)
1864}
1865
1866func gpe_build_context_s(wasm: *u8, wn: i64, title: *u8, native: *u8, ctrl: *u8, vnum: i64, seed: i64, spec: *u8, out: *u8, context_path:*u8) -> i64 {
1867 // ★NO PAGE IS BUILT AROUND A MODULE THAT CANNOT RUN. The arithmetic that decides this MOVED to
1868 // nx_wasmfit on 2026-08-15 and this function became one of its callers rather than its owner.
1869 //
1870 // WHY IT MOVED. The guard used to live here, under a header claiming "every wasm page in the
1871 // estate is built through this function -- one guard here covers all of them". nx_wasmpage_census
1872 // then measured all 62,906 shipped pages: 25 carry an embedded module and only 9 reach this
1873 // function. The other 16 are emitted by organs that hand-pasted the blit shim and none of the
1874 // guard. ★★★★★★A GUARD PLACED IN "THE" SHARED PATH IS ONLY AS BROAD AS THE CLAIM THAT THE PATH IS
1875 // SHARED, AND THAT CLAIM IS A MEASUREMENT NOBODY TOOK -- here it was 9 of 25.
1876 if wf_guard(wasm, wn, "gpe_build_s" as *u8) == WF_REFUSE { return 0 - 1 }
1877 let b64: *u8 = sys_mmap((wn/3 + 2)*4 + 64)
1878 let bn: i64 = b64_encode(wasm, wn, b64)
1879 var p: i64 = 0
1880 // The release seal covers these bytes; request-time ad insertion would invalidate delivery identity.
1881 p = gpe_ap(out, p, "<!DOCTYPE html><html lang=\"en\"><head><!--nx-ad-optout--><meta charset=\"utf-8\"><meta name=\"nishi-release-sha256\" content=\"0000000000000000000000000000000000000000000000000000000000000000\"><title>" as *u8)
1882 p = gpe_ap(out, p, title)
1883 p = gpe_ap(out, p, "</title><meta name=\"nishi-game\" content=\"" as *u8)
1884 p = gpe_ap(out, p, native)
1885 p = gpe_ap(out, p, "\"><meta name=\"viewport\" content=\"width=device-width,initial-scale=1\"><style>\nhtml{height:100%}\nmain{width:100%;min-width:0;box-sizing:border-box;overflow-wrap:anywhere}\nbody{margin:0;min-height:100%;background:#08070f;color:#e9e5f5;font:14px/1.5 system-ui,sans-serif;\ndisplay:flex;flex-direction:column;align-items:center;justify-content:center;gap:14px;padding:12px 0;box-sizing:border-box}\ncanvas{width:98vw;border:1px solid #2f2a4a;border-radius:4px;touch-action:none}\ncanvas:fullscreen{width:100vw;height:100vh;border:0}\nh1{margin:0;font:600 15px/1 ui-monospace,monospace;letter-spacing:.14em;text-transform:uppercase;color:#b9b1dc}\np{margin:0;color:#7d76a0;font:12px/1.6 ui-monospace,monospace;text-align:center;max-width:70ch}\nb{color:#a8e6c0}</style><meta name=\"nishi-nxa\" data-nishi-role=\"cast\" data-sha256=\"31778134b5167258b05b18ae9ae062c073fd03fb3f46d212e3512d28660c4fed\" data-bytes=\"12449344\" data-locomotion=\"forward-walk-v1\" data-required-section=\"GAT1\" content=\"/releases/ref9e-gat1-31778134b5167258b05b18ae9ae062c073fd03fb3f46d212e3512d28660c4fed.nxa\"><meta name=\"nishi-nxa\" data-nishi-role=\"cast\" content=\"/world/ref9e.nxa\"><meta name=\"nishi-nxa\" data-nishi-role=\"cast\" content=\"/world/ref9d.nxa\"><meta name=\"nishi-nxa\" data-nishi-role=\"cast\" content=\"/world/ref9.nxa\"></head><body>" as *u8)
1886 p = gpe_demand_lifecycle(out,p)
1887 p = gpe_workspace_begin_context(out,p,context_path)
1888 if p<0 {return -1}
1889 p = gpe_ap(out,p,"<main><h1>" as *u8)
1890 p = gpe_ap(out, p, title)
1891 p = gpe_ap(out, p, "</h1><script>function nxCastDelivery(){const renderer=String(window.__sov_door||(typeof nxDoor==='function'?nxDoor():'unresolved')),draw=String(window.__nx_cast_draw||''),gpu=renderer.indexOf('webgpu')===0,prep=window.__nx_garment_prepare;let state='waiting',reason='Character assets are loading';const failure=window.__npcfail||(gpu&&window.__gpu_npcfail)||(/^(refused|validation):/.test(draw)?draw:null);if(failure){state='needs-intervention';reason=String(failure);}else if(!nxDemand.active||prep&&prep.state==='paused'){state='paused';reason='Character preparation is paused while the page is inactive';}else if(gpu&&window.__gpu_npc_up&&draw==='drawn'){state='running';reason='Character draw submitted';}else if(!gpu&&window.__npc_up){state='running';reason='Character assets ready';}else if(gpu&&window.__gpu_npc_up){reason='Character assets uploaded; waiting for a visible draw';}else if(prep&&prep.state==='preparing'){reason='Preparing character bindings';}return window.__nx_cast_delivery={version:1,state,reason,renderer,draw,observed_at:new Date().toISOString()};}\nwindow.__nx_bootfail=null;window.onerror=function(m9,s9,l9,c9){if(!window.__nx_bootfail){window.__nx_bootfail=String(m9)+' @'+l9+':'+c9;var d9=document.createElement('pre');d9.style.cssText='position:fixed;top:0;left:0;right:0;background:#300;color:#fcc;padding:8px;z-index:9999;font:12px monospace;white-space:pre-wrap';d9.textContent='NISHI BOOT FAILURE (self-report): '+window.__nx_bootfail;try{fetch('/world/__clienterr?e='+encodeURIComponent(String(window.__nx_bootfail).slice(0,200))+'&p='+encodeURIComponent(location.pathname),{method:'GET',keepalive:true}).catch(function(){});}catch(e0){}if(document.body){document.body.appendChild(d9);}else{addEventListener('DOMContentLoaded',function(){document.body.appendChild(d9);});}}return false;};window.addEventListener('unhandledrejection',function(ev9){var r9=ev9&&ev9.reason;window.onerror('PROMISE: '+String(r9&&r9.stack?r9.stack:r9).slice(0,260),'',0,0);});setTimeout(function(){var t8=nxDemand.interval(function(){try{var d8=document.getElementById('nxstall');var status=nxCastDelivery();if(status.state==='running'||status.state==='paused'){if(d8)d8.remove();return;}var s8=status.reason;if(!d8){d8=document.createElement('div');d8.id='nxstall';d8.style.cssText='position:fixed;left:8px;bottom:8px;background:#711;color:#fff;padding:6px 10px;font:12px monospace;z-index:9999';document.body.appendChild(d8);try{fetch('/world/__clienterr?e='+encodeURIComponent('npc-stall '+s8)+'&p='+encodeURIComponent(location.pathname),{method:'GET',keepalive:true}).catch(function(){});}catch(x8){}}d8.textContent='Characters: '+status.reason;}catch(x9){}},5000);},12000);</script><canvas id=\"c\"></canvas>\n<p>" as *u8)
1892 p = gpe_ap(out, p, ctrl)
1893 // the footer must describe the page that was actually emitted: under WEBGL the renderer choice and
1894 // the toggle links are real controls; sovereign-only, a ?gl=1 link would be a control that silently
1895 // does nothing -- a lying switch is worse than none.
1896 if GPE_EMIT_WEBGL == 1 {
1897 p = gpe_ap(out, p, "<br>Renderer: <a href=\"?gl=0\">CPU</a> · <a href=\"?gpu=0\">WebGL fallback</a> · <a href=\"?gpu=1\">WebGPU</a>. Visiting characters: <a href=\"?cast=1\">show</a> · <a href=\"?cast=0\">hide</a>. Use Frame character for inspection; free movement is the default. Open Progress for verified changes and pending work. <a href=\"?hud=1\">Show frame measurements</a>.</p>\n</main>\n<script>\nconst B=\"" as *u8)
1898 } else {
1899 p = gpe_ap(out, p, "<br>\nEvery pixel above is emitted by NishiLang compiled to WebAssembly.<br>\nThis page holds no game logic — every rule, every position, the light and the characters live in NishiLang compiled to WebAssembly, and the sovereign rasteriser draws every pixel. One renderer, one truth, no GPU shader path.</p>\n</main>\n<script>\nconst B=\"" as *u8)
1900 }
1901 p = gpe_ap_n(out, p, b64, bn)
1902 p = gpe_ap(out, p, "\";\n" as *u8)
1903 // GP3/GE45: the door ladder as data. ONE table (knowledge/tier_ladder.conf) emitted verbatim; the
1904 // page's ladder resolution names its door through nxDoorId(requires), never by spelling an id, and
1905 // the HUD prints nxDoorReport() -- which door drew the frame and WHY each higher door was not taken
1906 // (levered-off, capability-absent, failed:<the thrown message>). An unreadable conf emits a NAMED
1907 // absence (tl_emit announces TIER-LADDER-ABSENT-AT-EMIT on stderr) so a page never draws an
1908 // unexplained frame silently. Emitted HERE, ahead of the module, so the GE30 threaded boot can ask
1909 // nxThreads() for this visitor's worker count before anything is instantiated or initialised.
1910 p = gpe_ap(out, p, rk_tier_ladder())
1911 p = gpe_normal_encoding_runtime(out,p)
1912 p = gpe_ap(out, p, "let nxIdentityEpoch=0;\nfunction nxIdentitySelect(moduleBytes,kind){\n const epoch=++nxIdentityEpoch;\n const meta=document.querySelector('meta[name=\"nishi-release-sha256\"]');\n const value=meta?meta.getAttribute('content'):null;\n const release=typeof value==='string'&&/^[0-9a-f]{64}$/.test(value)?value:null;\n const publish=(state,wasm,reason)=>{if(epoch===nxIdentityEpoch)window.__nx_identity=Object.freeze({version:1,epoch,release,wasm,module:kind,state,reason});};\n publish('pending',null,null);\n if(!globalThis.crypto||!globalThis.crypto.subtle){publish('unavailable',null,'sha256-unavailable');return;}\n try{\n const snapshot=moduleBytes instanceof ArrayBuffer?new Uint8Array(moduleBytes).slice():moduleBytes.slice();\n Promise.resolve(globalThis.crypto.subtle.digest('SHA-256',snapshot)).then(hash=>{\n const digest=Array.from(new Uint8Array(hash),v=>v.toString(16).padStart(2,'0')).join('');\n if(!/^[0-9a-f]{64}$/.test(digest)){publish('unavailable',null,'sha256-invalid-result');return;}\n publish(release===null?'unavailable':'ready',digest,release===null?'release-identity-absent':null);\n }).catch(()=>publish('unavailable',null,'sha256-failed'));\n }catch(_e){publish('unavailable',null,'sha256-failed');}\n}\nconst bytes=Uint8Array.from(atob(B),c=>c.charCodeAt(0));\nWebAssembly.instantiate(bytes).then(async r=>{let ex=r.instance.exports;\nnxIdentitySelect(bytes,\"plain\");\n" as *u8)
1913 // GE30: ex is LET, not const -- an isolated visitor is UPGRADED to the shared-memory twin here,
1914 // before ww/hh/fb_off are read and long before init(), so every number below describes the engine
1915 // that will actually draw. A non-isolated visitor falls through with the inlined build untouched.
1916 p = gpe_mt_boot(out, p)
1917 // GE31/GE23 (2026-09-06): the ENGINE owns its memory size. wasm_pages_req() is derived from the
1918 // extended arena (the cast clip extension past CRAFT_TOTAL); the backend still declares only the
1919 // base pages it can read, so the page grows the LIVE memory to the engine's request here -- after
1920 // the MT boot has chosen which instance draws and before any view or init exists. On the twin this
1921 // is the shared memory the workers already hold, inside its declared maximum. A refusal is NAMED,
1922 // never silent: the clip door then stays closed and the reason is on the window.
1923 p = gpe_ap(out, p, "window.__nx_memgrow='absent';\nif(ex.wasm_pages_req&&ex.memory){const need9=Number(ex.wasm_pages_req()),have9=Math.floor(ex.memory.buffer.byteLength/65536);\nif(need9>have9){try{ex.memory.grow(need9-have9);window.__nx_memgrow={grew:need9-have9,pages:need9};}catch(e9){window.__nx_memgrow='refused:'+String(e9);}}else{window.__nx_memgrow={grew:0,pages:have9};}}\n" as *u8)
1924 p = gpe_ap(out, p, "const W=Number(ex.ww()),H=Number(ex.hh()),off=Number(ex.fb_off());\nlet cv=document.getElementById(\"c\");\n// a canvas holds ONE context type forever -- GL must claim it BEFORE any 2d setup.\n// cv is LET, not const: a canvas whose GL/GPU context died can never host a 2d context again\n// (the spec one-context rule), so the sovereign fallback must swap in a fresh element (sovSwap).\n// FIRST-PAINT PLACEHOLDER: an undrawn canvas is TRANSPARENT over the near-black body, which\n// reads as a BLACK SCREEN for exactly as long as the first frame takes. Paint the world's own\n// palette (sky over sand) via CSS immediately; the first real frame covers it opaquely.\ncv.style.background=\"linear-gradient(rgb(127,178,229) 55%,rgb(232,217,176) 55%)\";\n// THE TIER BADGE: the active renderer is ANNOUNCED on the page -- a black or wrong frame must\n// never be unexplained. window.__sov_tier mirrors it for instruments.\n// S0 (2026-09-04): the badge also names WHAT the door draws -- the ladder's draws word for the door that\n// drew the frame (world / world+cast / world+markers, undecided until the ladder resolves) -- mirrored as\n// window.__sov_draws, so a WebGPU frame missing every character says so on the page, not only in a conf label.\nconst __tb=document.createElement(\"div\");__tb.style.cssText=\"font:11px ui-monospace,monospace;color:#7d76a0;letter-spacing:.08em\";__tb.textContent=\"renderer: probing\";\nconst __mp=document.querySelector(\"p\");if(__mp)__mp.parentNode.insertBefore(__tb,__mp);\nconst __tier=t=>{const dw9=nxDoorDraws();__tb.textContent=\"renderer: \"+t+\" | draws: \"+dw9;window.__sov_tier=t;window.__sov_draws=dw9;};\n" as *u8)
1925 // GE20: the engine version badge rides beside the tier badge -- ladder + target version read
1926 // from the compare plane bytes at emit (gpe_version_badge), so a republished page updates itself.
1927 p = gpe_version_badge(out, p)
1928 // GE52: the release delta rides under the prose -- what changed since the operator last judged, the referee
1929 // percept beside each subject, and the accept-row recipe for this build (gpe_release_block, data at every emit).
1930 p = gpe_release_block(out, p)
1931 p = gpe_ap(out, p, "let ctx=null,img=null,cw=0,ch=0;\n// RESOLUTION FOLLOWS THE HARDWARE: the organ reports its CURRENT ray resolution through ww/hh and the\n// canvas is resized to match, so the BROWSER does the upscale. The page never chooses a size, and the\n// adaptive controller inside the organ is the only thing that decides how much detail this machine gets.\nfunction blit(){if(!ctx)return;\nconst w=Number(ex.ww()),h=Number(ex.hh());\nif(w!==cw||h!==ch){cw=w;ch=h;cv.width=w;cv.height=h;img=ctx.createImageData(w,h);}\nconst m=new Uint32Array(ex.memory.buffer,off,w*h*2);const d=new Uint32Array(img.data.buffer);\nfor(let i=0;i<w*h;i++){d[i]=m[i*2]|0xff000000;}\nctx.putImageData(img,0,0);}\nconst NXV=" as *u8)
1932 // the ACTUAL identity digit (a 1-else-0 emit silently booted every v>=2 world as v0)
1933 out[p] = (48 + vnum) as u8
1934 p = p + 1
1935 // W1c GEN-TIME OVERLAY: gen rows (idx 0..6, 59, 60) cross as DATA *BEFORE* init_v -- written
1936 // into the engine's GENP region so identity defaults are overridden before genworld reads
1937 // them (post-boot they would be the silent no-op the old refusal named). Emitted ONLY when
1938 // a gen row exists -> pages without one stay byte-identical (the W1 KATs keep holding).
1939 if (spec as i64) != 0 { if spec[0] != (0 as u8) {
1940 let gposn: *i64 = sys_mmap(16) as *i64
1941 gposn[0] = 0
1942 var gcnt: i64 = 0
1943 var grun: i64 = 1
1944 while grun == 1 {
1945 let giv: i64 = gpr_num_at(spec, gposn)
1946 if spec[gposn[0]] != (58 as u8) { grun = 0 } else {
1947 gposn[0] = gposn[0] + 1
1948 gpr_num_at(spec, gposn)
1949 // THE ONE ALLOWLIST (nx_genp_allow_lib, 2026-09-04). This pass used to enumerate 0..6/59/60/61/64 by hand
1950 // and was never widened when the validator admitted 67 and 68, so a recipe's 66/67/68 pairs validated and
1951 // were silently dropped here: the served ridge.html read const NXGP=[[64,0]] against 67:12,68:32 and the
1952 // STAGED-PIPELINE world served legacy terrain. The engine, the snap and both passes now read one ruler.
1953 let gg: i64 = genp_dune_gen_ok(giv)
1954 if gg == 1 { gcnt = gcnt + 1 }
1955 if spec[gposn[0]] == (44 as u8) { gposn[0] = gposn[0] + 1 } else { grun = 0 }
1956 }
1957 }
1958 if gcnt > 0 {
1959 p = gpe_ap(out, p, ";\nconst NXGP=[" as *u8)
1960 gposn[0] = 0
1961 var gfirst: i64 = 1
1962 grun = 1
1963 while grun == 1 {
1964 let giv2: i64 = gpr_num_at(spec, gposn)
1965 if spec[gposn[0]] != (58 as u8) { grun = 0 } else {
1966 gposn[0] = gposn[0] + 1
1967 let gvv2: i64 = gpr_num_at(spec, gposn)
1968 // the SAME ruler as the count pass (nx_genp_allow_lib): a row counted and not written, or written
1969 // and not counted, was a length that disagreed with its own payload -- one function cannot disagree
1970 let gg2: i64 = genp_dune_gen_ok(giv2)
1971 if gg2 == 1 {
1972 if gfirst == 0 { p = gpe_ap(out, p, "," as *u8) }
1973 gfirst = 0
1974 p = gpe_ap(out, p, "[" as *u8)
1975 p = gpe_num(out, p, giv2)
1976 p = gpe_ap(out, p, "," as *u8)
1977 p = gpe_num(out, p, gvv2)
1978 p = gpe_ap(out, p, "]" as *u8)
1979 }
1980 if spec[gposn[0]] == (44 as u8) { gposn[0] = gposn[0] + 1 } else { grun = 0 }
1981 }
1982 }
1983 p = gpe_ap(out, p, "];\nif(NXGP.some(q=>q[0]===79)&&typeof ex.wc_dune_valid!==\"function\")throw Error(\"runtime-dune-recipe-unavailable\");\nif(ex.genp_off&&NXGP.length){const GP=new BigInt64Array(ex.memory.buffer,Number(ex.genp_off()),24);GP[0]=BigInt(20260813001);GP[1]=BigInt(NXGP.length);for(let i=0;i<NXGP.length;i++){GP[2+2*i]=BigInt(NXGP[i][0]);GP[3+2*i]=BigInt(NXGP[i][1]);}}" as *u8)
1984 }
1985 } }
1986 p = gpe_ap(out, p, ";\nconst nxInitCode=Number(NXV&&ex.init_v?ex.init_v(BigInt(NXV),BigInt(" as *u8)
1987 p = gpe_num(out, p, seed)
1988 p = gpe_ap(out, p, ")):ex.init());\nwindow.__nx_init={state:nxInitCode===0?\"ready\":\"needs-intervention\",code:nxInitCode,observedAt:new Date().toISOString()};\nif(!Number.isSafeInteger(nxInitCode)||nxInitCode!==0)throw Error(\"world-init-refused:\"+nxInitCode);\n" as *u8)
1989 p = gpe_facing_policy(out,p)
1990 // W1b STYLE OVERLAY: recipe style rows poked into the engine's LIVE spec table after boot.
1991 // Pure DATA across the interop boundary (JS/HTML-interop-only law: values cross, logic
1992 // does not). idx guard 7..58 repeated page-side as bounds belt; the loader already refused
1993 // gen-time rows by name. Emitted ONLY when a style column exists -> spec-less pages stay
1994 // byte-identical (the W1 KAT keeps holding).
1995 if (spec as i64) != 0 { if spec[0] != (0 as u8) {
1996 p = gpe_ap(out, p, "const NXSP=[" as *u8)
1997 let sposn: *i64 = sys_mmap(16) as *i64
1998 sposn[0] = 0
1999 var sfirst: i64 = 1
2000 var srun: i64 = 1
2001 while srun == 1 {
2002 let iv: i64 = gpr_num_at(spec, sposn)
2003 if spec[sposn[0]] != (58 as u8) { srun = 0 } else {
2004 sposn[0] = sposn[0] + 1
2005 let vv: i64 = gpr_num_at(spec, sposn)
2006 if sfirst == 0 { p = gpe_ap(out, p, "," as *u8) }
2007 sfirst = 0
2008 p = gpe_ap(out, p, "[" as *u8)
2009 p = gpe_num(out, p, iv)
2010 p = gpe_ap(out, p, "," as *u8)
2011 p = gpe_num(out, p, vv)
2012 p = gpe_ap(out, p, "]" as *u8)
2013 if spec[sposn[0]] == (44 as u8) { sposn[0] = sposn[0] + 1 } else { srun = 0 }
2014 }
2015 }
2016 p = gpe_ap(out, p, "];\nif(ex.spec_off){const SP=new BigInt64Array(ex.memory.buffer,Number(ex.spec_off()),64);for(const q of NXSP)if(q[0]>=7&&q[0]<=58)SP[q[0]]=BigInt(q[1]);}\n" as *u8)
2017 } }
2018 p = gpe_ap(out, p, "// GPU DISPLAY PATH: the same DDA raycast as a fragment shader, EMITTED by the sovereign page\n// emitter. The organ keeps ALL game logic + quality authority; the GPU only draws its state at\n// TRUE DEVICE RESOLUTION (4K on a 4K panel). CPU wasm render remains the gate-proven truth and\n// the automatic fallback (?gl=0 forces it). GPU (WebGPU, ?gpu=1 lever) and GL (WebGL2, default\n// when emitted) both always DECLARE so the frame loop can test them on every page shape.\nlet GL=null;let GPU=null;\n" as *u8)
2019 // SOVEREIGN DEFAULT (operator 2026-08-14: we shouldnt even have webgl). The wasm rasteriser IS
2020 // the product path. `let GL=null` always ships because the frame loop tests it; everything below
2021 // -- shaders, GL setup, the NPC and eye passes -- is emitted ONLY when GPE_EMIT_WEBGL is 1, so the
2022 // default page carries NO GLSL at all rather than carrying ~50KB of it inert.
2023 if GPE_EMIT_WEBGL == 1 {
2024 p = gpe_ap(out, p, "const VSH=`#version 300 es\\nvoid main(){vec2 v=vec2((gl_VertexID<<1)&2,gl_VertexID&2);gl_Position=vec4(v*2.-1.,0.,1.);}`;\n" as *u8)
2025 p = gpe_ap(out, p, "const FSH=`#version 300 es\nprecision highp float;precision highp int;\nuniform highp usampler3D uV;uniform vec3 uCam;uniform vec4 uYP;uniform vec3 uPal[12];\nuniform vec3 uPalF[5];uniform vec3 uSunD;uniform vec3 uSunC;uniform int uRain;\nuniform vec3 uSkT;uniform vec3 uSkH;uniform int uSun;uniform int uCld;uniform float uT;uniform int uWxT;uniform vec2 uWxW;uniform float uWxC;\nuniform vec2 uRes;uniform int uWmax;uniform int uSelB;uniform int uHok;uniform int uVt;\nuniform int uNpcT;\nout vec4 fc;\nuint vx(ivec3 c){if(c.x<0||c.y<0||c.z<0||c.x>127||c.y>47||c.z>127)return 0u;return texelFetch(uV,ivec3(c.x,c.z,c.y),0).r;}\nfloat h21(vec2 p){return fract(sin(dot(p,vec2(127.1,311.7)))*43758.5453);}\nfloat h31(vec3 p){return fract(sin(dot(p,vec3(127.1,311.7,74.7)))*43758.5453);}\nvec3 pal(uint b){int i=int(b);if(i<0)i=0;if(i>16)i=16;return i<12?uPal[i]:uPalF[i-12];}\n" as *u8)
2026 p = gpe_sky_atmos(out, p, "vec3 sky(vec3 rd){\n// derived Rayleigh sky (nx_atmosphere port, ONE owner): airmass sec(z) clamped 38 (Kasten-Young\n// horizon, .0264=1/38), tau=(440/lambda)^4*.7 => (.123,.287,.700), single-scatter 1-exp(-tau),\n// sqrt display encode (declared approx of sRGB). World data (uSkT+uSkH) supplies ENERGY (day/night/\n// weather); the SUNT transmittance colour supplies the dusk tint. The two-stop painted gradient is gone.\nfloat am=clamp(1./max(rd.y,.0264),1.,38.);\nvec3 ray9=1.-exp(-vec3(.123,.287,.700)*am);\nfloat envk=clamp(dot(uSkT+uSkH,vec3(.3333)),0.,1.);\nvec3 st8=(uSun==1&&dot(uSunC,uSunC)>.01)?uSunC:vec3(1.);\nvec3 s=sqrt(ray9*envk)*st8;\nif(uSun==1){float d=dot(rd,uSunD);\nvec3 sc9=(dot(uSunC,uSunC)>.01)?uSunC:vec3(1.,.98,.88);if(d>.99996)s=sc9*1.6;else if(d>.9993)s=mix(s,sc9,(d-.9993)/.00066*.5);}\nif(uCld==1&&rd.y>.04){vec2 cp=uCam.xz+rd.xz*((56.-uCam.y)/rd.y);\nvec2 p1=cp/14.+vec2(uT/240.,uT/540.);vec2 i1=floor(p1),f1=smoothstep(0.,1.,fract(p1));\nfloat n=mix(mix(h21(i1),h21(i1+vec2(1.,0.)),f1.x),mix(h21(i1+vec2(0.,1.)),h21(i1+vec2(1.,1.)),f1.x),f1.y);\nvec2 p2=cp/37.+vec2(uT/300.,0.);vec2 i2=floor(p2),f2=smoothstep(0.,1.,fract(p2));\nfloat n2=mix(mix(h21(i2),h21(i2+vec2(1.,0.)),f2.x),mix(h21(i2+vec2(0.,1.)),h21(i2+vec2(1.,1.)),f2.x),f2.y);\n// VOLUMETRIC CLOUDS (2026-08-26, from knowledge/library/sky_volumetrics_impl_spec: the\n// HZD/Nubis lineage verified across three public implementations). A raymarched slab with\n// remap density shaping, Beer-Lambert extinction, dual-lobe HG phase (g +/-.08, the\n// terrainengine values), powder darkening, and ONE wind advection: every octave moves with\n// the weather system's own wind vector -- coherent drift, not four unrelated scroll rates\n// (the churn the operator read as jumping). Steps 16/8 are the low-HW reduction of the cited\n// 54-96/6 -- NAMED as such; raise via the quality controller when budget allows.\nfloat t0c=(46.-uCam.y)/max(rd.y,.02);float t1c=(66.-uCam.y)/max(rd.y,.02);\nif(t1c>t0c&&t0c<900.){\nvec2 wadv=uWxW*uT*2.2;\nfloat trn=1.;vec3 cac=vec3(0.);\nfloat mu=dot(rd,uSunD);\nfloat ph=.0795775*mix((1.-.0064)/pow(1.0064-.16*mu,1.5),(1.-.0064)/pow(1.0064+.16*mu,1.5),.5);\nfloat dsc=(t1c-t0c)/16.;\nfloat jt=h21(floor(cp))*dsc;\nfor(int ci=0;ci<16;ci++){\nfloat tc=t0c+jt+dsc*float(ci);\nvec3 cpw=uCam+rd*tc;\nvec2 cqA=(cpw.xz+wadv)/148.;vec2 iqA=floor(cqA),fqA=smoothstep(0.,1.,fract(cqA));\nfloat nA=mix(mix(h21(iqA),h21(iqA+vec2(1.,0.)),fqA.x),mix(h21(iqA+vec2(0.,1.)),h21(iqA+vec2(1.,1.)),fqA.x),fqA.y);\nvec2 cqB=(cpw.xz+wadv*1.15)/52.;vec2 iqB=floor(cqB),fqB=smoothstep(0.,1.,fract(cqB));\nfloat nB=mix(mix(h21(iqB),h21(iqB+vec2(1.,0.)),fqB.x),mix(h21(iqB+vec2(0.,1.)),h21(iqB+vec2(1.,1.)),fqB.x),fqB.y);\nvec2 cq2=(cpw.xz+wadv*1.3)/19.;\nvec2 iq2=floor(cq2),fq2=smoothstep(0.,1.,fract(cq2));\nfloat nd2=mix(mix(h21(iq2),h21(iq2+vec2(1.,0.)),fq2.x),mix(h21(iq2+vec2(0.,1.)),h21(iq2+vec2(1.,1.)),fq2.x),fq2.y);\nfloat nb=clamp(nA*.625+nB*.25+nd2*.125,0.,1.);\nfloat hf=clamp((cpw.y-46.)/20.,0.,1.);\nfloat grad=smoothstep(0.,.12,hf)*(1.-smoothstep(.55,1.,hf));\nfloat cov=mix(.38,.78,uWxC);\nfloat den=clamp((nb*grad-(1.-cov))/max(cov,.001),0.,1.);\nden=clamp(den-nd2*.34*(1.-hf),0.,1.);den=den*den*(3.-2.*den);den=den*den*(3.-2.*den);\nif(den>.01){\nfloat sd=den*dsc*.09;\nfloat lt=exp(-den*1.6)*(1.-exp(-den*3.2));\nvec3 lc=mix(vec3(.62,.66,.74),vec3(1.,.985,.95),lt);\ncac+=trn*sd*lc*(0.6+2.6*ph);\ntrn*=exp(-sd*1.35);\nif(trn<.1)break;}}\nfloat cfad=smoothstep(.02,.10,rd.y)*(1.-smoothstep(500.,900.,t0c));\n// ONE composite: sky attenuated by cloud transmittance plus in-scattered cloud light, faded\n// at the horizon. (v1 of this block left two alternative composites stacked -- double-applied.)\ns=mix(s,s*trn+cac,cfad);}}\nreturn s;}\n" as *u8)
2027 p = gpe_ap(out, p, "float march(vec3 ro,vec3 rd,out ivec3 hc,out int fce,out uint hb,int skipw,int mx){\nivec3 c=ivec3(floor(ro));ivec3 st=ivec3(sign(rd));vec3 dd=abs(1./max(abs(rd),1e-6));\nvec3 tm=(vec3(st)*(vec3(c)-ro)+vec3(st)*.5+.5)*dd;float t=0.;\nfor(int i=0;i<200;i++){if(i>=mx)break;\nif(tm.x<tm.y&&tm.x<tm.z){c.x+=st.x;t=tm.x;tm.x+=dd.x;fce=st.x>0?2:1;}\nelse if(tm.y<tm.z){c.y+=st.y;t=tm.y;tm.y+=dd.y;fce=st.y>0?4:3;}\nelse{c.z+=st.z;t=tm.z;tm.z+=dd.z;fce=st.z>0?6:5;}\nif(c.y>uWmax&&rd.y>=0.)return -1.;if(c.y<0)return -1.;\nif(c.x<-8||c.x>135||c.z<-8||c.z>135)return -1.;\nuint b=vx(c);if(skipw==1&&b==4u)b=0u;\nif(b!=0u){hc=c;hb=b;return t;}}\nreturn -1.;}\n" as *u8)
2028 p = gpe_ap(out, p, "vec3 shade(vec3 ro,vec3 rd,float t,ivec3 c,int fce,uint b){\nvec3 hp=ro+rd*t;\nvec2 uv;ivec3 oc=c;vec3 n=vec3(0.);\nif(fce==1){uv=hp.zy;oc.x+=1;n=vec3(1.,0.,0.);}else if(fce==2){uv=hp.zy;oc.x-=1;n=vec3(-1.,0.,0.);}\nelse if(fce==3){uv=hp.xz;oc.y+=1;n=vec3(0.,1.,0.);}else if(fce==4){uv=hp.xz;oc.y-=1;n=vec3(0.,-1.,0.);}\nelse if(fce==5){uv=hp.xy;oc.z+=1;n=vec3(0.,0.,1.);}else{uv=hp.xy;oc.z-=1;n=vec3(0.,0.,-1.);}\nvec2 f=fract(uv);\nuint bb=b;if(b==1u&&fce!=3&&fce!=4){bb=2u;if(f.y>.8)bb=1u;}\nfloat li=fce==3?1.:fce==4?.42:fce==1?.76:fce==2?.7:fce==5?.62:.56;\nif(uSun==1){if(fce==1)li*=1.12;if(fce==2)li*=.92;if(fce==5)li*=1.04;}\n// BUMP MAPPING: texel-hash height field -> gradient -> sun-lit micro-relief (the det lever:\n// real 1px luminance structure on every face, the difference between flat tint and rough matter)\nvec3 sd3=floor(hp)*.13;float bs=float(b)*7.;\nfloat t00=h31(vec3(floor(f*24.),bs)+sd3);\nfloat t10=h31(vec3(floor(f*24.+vec2(1.,0.)),bs)+sd3);\nfloat t01=h31(vec3(floor(f*24.+vec2(0.,1.)),bs)+sd3);\nfloat bmp=(t10-t00)*.6+(t01-t00)*.45;\nfloat bamp=b==3u||b==2u||b==9u||b==10u||b==11u?1.:b==7u?1.3:b==4u?.25:.7;\nfloat dfade=clamp(1.-t/24.,0.,1.);/*hash detail below pixel frequency reads as TV static (beach sand vistas, 08-03 frame); a hash cannot be mip-averaged, so micro-relief fades out by 24 blocks and flat tint + fog carry the far field*/li*=clamp(1.+bmp*bamp*dfade,.55,1.45);\nfloat tx=t00;\nli*=.9+tx*.2*dfade;\n// grass tufts: sparse taller blades on grass tops read as vegetation, not paint\nif(bb==1u&&fce==3&&t<24.){float tf=h21(floor(f*38.)+floor(hp.xz)*3.7);\nif(tf>.82)li*=1.28;else if(tf<.14)li*=.78;}\nif(f.x<.055||f.x>.945||f.y<.055||f.y>.945)li*=.82;\nfloat ao=0.;\nvec2 ua=fce==3||fce==4?vec2(1.,0.):fce<3?vec2(0.,0.):vec2(1.,0.);\nif(f.x<.17){ivec3 nb=oc;if(fce==3||fce==4)nb.x-=1;else if(fce<3)nb.z-=1;else nb.x-=1;if(vx(nb)!=0u&&vx(nb)!=4u)ao+=(.17-f.x)*2.;}\nif(f.x>.83){ivec3 nb=oc;if(fce==3||fce==4)nb.x+=1;else if(fce<3)nb.z+=1;else nb.x+=1;if(vx(nb)!=0u&&vx(nb)!=4u)ao+=(f.x-.83)*2.;}\nif(f.y<.17){ivec3 nb=oc;if(fce==3||fce==4)nb.z-=1;else nb.y-=1;if(vx(nb)!=0u&&vx(nb)!=4u)ao+=(.17-f.y)*2.;}\nif(f.y>.83){ivec3 nb=oc;if(fce==3||fce==4)nb.z+=1;else nb.y+=1;if(vx(nb)!=0u&&vx(nb)!=4u)ao+=(f.y-.83)*2.;}\nli*=1.-min(ao,.45);\n// SUN SHADOWS: one march from the hit point toward the sun; blocked = shadow (ambient kept)\nif(uSun==1){ivec3 sc2;int sf2;uint sb2;\nif(march(hp+n*.02,uSunD,sc2,sf2,sb2,1,60)>0.)li*=.55;}\nvec3 col=pal(bb)*li;\nvec3 fw9=1.-exp(-vec3(.123,.287,.700)*t/168.);\nreturn mix(col,sky(rd),fw9);}\n" as *u8)
2029 p = gpe_ap(out, p, "void main(){\nvec2 sc=(gl_FragCoord.xy-uRes*.5)/(uRes.x*.5);\nvec3 fw=vec3(uYP.x*uYP.w,uYP.z,uYP.y*uYP.w);\nvec3 rt=vec3(uYP.y,0.,-uYP.x);\nvec3 up=vec3(-uYP.x*uYP.z,uYP.w,-uYP.y*uYP.z);\nvec3 rd=normalize(fw+rt*sc.x+up*sc.y);\nvec3 ro=uCam;\nivec3 hc;int fce=0;uint hb=0u;\nfloat t=march(ro,rd,hc,fce,hb,0,200);\nvec3 col;\nif(t<0.)col=sky(rd);\nelse{col=shade(ro,rd,t,hc,fce,hb);\nif(hb==4u){ivec3 h2;int f2;uint b2;float t2=march(ro,rd,h2,f2,b2,1,200);\nif(t2>0.)col=col*.58+shade(ro,rd,t2,h2,f2,b2)*.42;}}\n" as *u8)
2030 p = gpe_ap(out, p, "// VALUE-STRUCTURE GRADE (operator: \"color palette barely used\". MEASURED 2026-08-28, PIL over the\n// operator's own 20:19 frame vs the given references: saturation is NOT the gap (S mean .29 vs\n// .27-.32, lift x1.01) -- the gaps are HUE MONOCULTURE (hue concentration .94 vs .31-.58; the\n// ocean supplies the missing axis) and HIGH-KEY MIDS (V p50 .79 vs .59-.66). A p95-anchored power\n// pivot moves the median HALF-way to the reference (half, because sand content legitimately\n// differs from the reference scenes): .94*(x/.94)^1.45. Inlined at every non-UI output (here,\n// figures, hair, WGSL) -- one measurement, four copies; a uniform consolidation is owed if it\n// ever needs to move. Declared side effects: non-grey chroma rises slightly (toward the refs),\n// and the multiplicative figure shadow deepens to k^1.45.\nif(uVt==1)col=vec3(.94)*pow(max(col,vec3(0.))*(1./.94),vec3(1.45));// ?tm=0 = the falsifiability lever: the operator can A/B the view transform on his own screen\nvec2 px=gl_FragCoord.xy;vec2 ctr=uRes*.5;\n// RAIN (A1 weather made visible): cheap screen-space streaks + a wet dim, organ-driven\nif(uRain==1){float wsl9=.35+uWxW.x*.9;float rr=h21(vec2(floor((px.x+px.y*wsl9)/2.),floor((px.y+uT*(uWxT==2?4.:13.))/26.)));\nif(uWxT==2){if(rr>.93)col=mix(col,vec3(.97,.98,1.),.75);col*=.97;}else{if(rr>.945)col=mix(col,vec3(.75,.8,.92),.45);col*=.93;}/*re-raised 08-03: .965/.28 had thinned rain to invisible -- HUD said RAIN | MOOD -8 (soaked) over a clean blue sky; weather the mood ledger charges for must be visible in the frame*/}\nif((abs(px.x-ctr.x)<8.&&abs(px.y-ctr.y)<1.5)||(abs(px.y-ctr.y)<8.&&abs(px.x-ctr.x)<1.5))col=uNpcT>=0?vec3(1.,.45,.65):(uHok==1?vec3(1.,.82,.35):vec3(1.));\nfloat hbY=uRes.y*.045;float hbS=uRes.x*.018;\nfor(int s=0;s<7;s++){vec2 o=vec2(uRes.x*.02+float(s)*hbS*1.5,hbY);\nif(px.x>=o.x&&px.x<o.x+hbS&&px.y>=o.y&&px.y<o.y+hbS){int bt=s==0?3:s==1?2:s==2?6:s==3?7:s==4?5:s==5?12:13;col=s<5?uPal[bt-1]:uPalF[bt-12];\nif(bt==uSelB&&(px.x<o.x+2.||px.x>o.x+hbS-2.||px.y<o.y+2.||px.y>o.y+hbS-2.))col=vec3(1.);}}\nfc=vec4(col,1.);}`;\n" as *u8)
2031 // Cast GLSL and WGSL are emitted together by rk_cast_block from one selected producer.
2032 p = gpe_emit_webgpu(out, p)
2033 p = rk_webgpu_door(out, p) // GP2 / GE44: the kernel WGSL (captured from the shader backend) + the readback probe
2034 p = gpe_ap(out, p, glp_js())
2035 // GP3/GE45: the door ladder as data. ONE table (knowledge/tier_ladder.conf) emitted verbatim; the page's
2036 // ladder resolution below names its door through nxDoorId(requires), never by spelling an id, and the HUD
2037 // prints nxDoorReport() -- which door drew the frame and WHY each higher door was not taken (levered-off,
2038 // capability-absent, failed:<the thrown message>). An unreadable conf emits a NAMED absence (tl_emit
2039 // announces TIER-LADDER-ABSENT-AT-EMIT on stderr) so a page never draws an unexplained frame silently.
2040 // GE30 2026-09-03: the ladder itself is now emitted EARLIER, at top-level script scope just before
2041 // the module is instantiated, because the threaded boot must ask nxThreads() how many workers this
2042 // visitor gets BEFORE init() runs -- and window.nxThreads is an assignment STATEMENT that would not
2043 // have executed yet at that point. Only the declaration order can serve a caller that early, so the
2044 // table moved rather than the boot. Nothing else here depended on its position: it emits pure
2045 // functions over the conf plus its window publication, and holds no page state.
2046 p = gpe_ap(out, p, "let VOX=0,SPC=0;\n// WEBGPU TIER, STAGE A (LEVERED): world pass only -- the NPC and eye passes are GL programs, so\n// WebGPU must be ASKED FOR (?gpu=1) until they reach parity; every ordinary visitor keeps the\n// proven ladder below. A canvas holds ONE context type forever, so a successful WebGPU claim\n// means the GL attempt is skipped entirely.\n// THE DOOR IS DATA (2026-09-06, operator order: WebGPU is the default door, CPU and WebGL2 are fallbacks). The webgpu row of knowledge/tier_ladder.conf decides, exactly as tl_pick walks it natively: state=default takes the door whenever the device can, state=levered needs its lever in the URL, ?gpu=0 opts out either way, and a hand-typed ?gl=0 (no why=) still forces the sovereign tier; a crash breadcrumb (?gl=0&why=...) is retried while gltry<2, like the GL path. The old gate hard-coded the ?gpu=1 lever, so the conf's promise that flipping the default is a data edit was never true.\nconst nxgd_row=(window.__nx_ladder||[]).filter(function(r9){return r9.requires==='webgpu';})[0]||null;\nconst nxgd_q=new URL(location.href).searchParams;const nxgd_why=nxgd_q.get('why')||'';const nxgd_try=(parseInt(nxgd_q.get('gltry')||'0',10)||0);\nconst nxgd_def=(nxgd_row&&nxgd_row.state==='default')?true:false;\nconst nxgd_lev=(nxgd_row&&nxgd_row.lever&&nxgd_row.lever!=='-'&&location.search.indexOf(nxgd_row.lever)>=0)?true:false;\nconst nxgd_opt=location.search.indexOf('gpu=0')>=0;\nconst nxgd_cpu=(location.search.indexOf('gl=0')>=0&&(nxgd_why===''||nxgd_try>=2))?true:false;\nconst nxgd_want=((nxgd_def||nxgd_lev||location.search.indexOf('gpu=1')>=0)&&nxgd_opt===false&&nxgd_cpu===false)?true:false;\nwindow.__nx_gpugate={g1:nxgd_want,def:nxgd_def,lev:nxgd_lev,opt:nxgd_opt,cpu:nxgd_cpu,state:nxgd_row?nxgd_row.state:'no-row',ng:!!navigator.gpu,vo:!!(typeof ex!==\"undefined\"&&ex&&ex.vox_off),yw:!!(typeof ex!==\"undefined\"&&ex&&ex.yaw),g0:location.search.indexOf(\"gl=0\")>=0,ran:0};\nif(nxgd_want&&navigator.gpu&&ex.vox_off&&ex.yaw){window.__nx_gpugate.ran=1;\n// BOOT-STALL CEILING: a wedged WebGPU stack hangs INSIDE requestAdapter/createShaderModule --\n// no rejection, no throw (measured 2026-08-18: BOTH headless Chromiums on the dev box wedge\n// exactly there). The race caps the visitor's cost at GPU_BOOT_MS and the ladder continues to\n// GL/CPU; a LATE gpuInit completion is discarded because the canvas may belong to another\n// context by then. 4000ms = generous first-visit shader-compile budget on weak hardware; a\n// too-small ceiling would silently demote CAPABLE devices, which is the worse direction.\nconst GPU_BOOT_MS=nxGpuBootMs();\nawait Promise.race([gpuInit(),new Promise(rs=>setTimeout(rs,GPU_BOOT_MS))]);\nif(!GPU)window.__gpu_late=1;\n}\n// USE THE BEST RENDERER THE MACHINE ACTUALLY HAS. This probes for a GPU and takes it; if the\n// context, shader compile or link fails for any reason the catch below falls through to the\n// sovereign wasm rasteriser, which is always compiled into this page. Selection is AUTOMATIC --\n// it was briefly gated behind a ?gl=1 query string, which meant every ordinary visitor silently\n// got the CPU fallback and none of the skinned characters. ?gl=0 forces the sovereign path.\n// A CRASH BREADCRUMB IS NOT AN OPERATOR CHOICE (2026-08-28). ?gl=0 typed by hand is a\n// deliberate lever and stays honoured. ?gl=0 carrying a why= is the OLD recovery reload\n// BRANDING a visitor onto the bottom tier -- and because the brand lives in the URL it was\n// PERMANENT: every reload, every bookmark and every shared link re-pinned the family to the\n// 384x240 CPU tier on hardware that was never at fault. A recoverable fault must be RETRIED,\n// not inherited. gltry bounds the retry so genuinely dead hardware still settles on the CPU\n// tier instead of oscillating between two tiers forever.\nconst _q9=new URL(location.href).searchParams;\nconst _gl0=location.search.indexOf(\"gl=0\")>=0;\nconst _why9=_q9.get(\"why\")||\"\";\nconst _try9=(parseInt(_q9.get(\"gltry\")||\"0\",10)||0);\nconst GLWANT=(!_gl0)||(_why9!==\"\"&&_try9<2);\nwindow.__glretry=(_gl0&&_why9!==\"\"&&_try9<2)?_try9+1:0;\nif(!GPU&&ex.vox_off&&ex.yaw&&GLWANT){try{\nconst g=nxGlProbe(cv,{antialias:false,preserveDrawingBuffer:true,stencil:true});\n// ?glfail=1 -- TEST LEVER for the poisoned-canvas recovery (mirrors ?gl=0): throws AFTER the\n// context exists, exactly like a driver compile failure, so the recovery chain is provable in\n// any real browser.\nif(location.search.indexOf(\"glfail=1\")>=0)throw \"test-lever-glfail\";
2047// ==== CONTEXT-LOSS SURVIVAL (operator 2026-08-28: /world/beach?gl=0&why=webgl-context-lost) ====
2048// This page had NO webglcontextlost listener at all -- proven absent over the whole tree -- so
2049// preventDefault() was never called, and by spec a UA only attempts restoration when the default is
2050// prevented. The loss therefore ran the poisoned-canvas path: getContext(2d) on a canvas already in
2051// webgl2 mode returns null FOREVER, so sovCanvas2d reloaded into ?gl=0 -- the CPU raycaster,
2052// permanently, for the rest of the session, and stickily, because the reload leaves gl=0 in the URL.
2053// A loss we cannot prevent must cost a hiccup, not the renderer.
2054cv.addEventListener(\"webglcontextlost\",function(ev9){ev9.preventDefault();
2055// preventDefault() IS THE WHOLE PRECONDITION: the spec makes restoration OPT-IN, so a page that
2056// does not call it can only ever fall DOWN the ladder. Measured over the COMPLETE client payload
2057// of /world/beach (478,696 B, 0 external scripts) on 2026-08-28: ZERO listeners of either name.
2058// That absence is why one lost context branded a visitor onto the CPU tier for the whole session.
2059window.__sov_gllost=(window.__sov_gllost|0)+1;
2060// AND HOLD THE CANVAS. Without __glrestoring the frame loop's own catch reaches sovCanvas2d, which
2061// calls getContext(2d) on a canvas that is already in webgl2 mode -- that returns null FOREVER, and
2062// the null is what triggered the ?gl=0 reload. The 2D fallback must not steal the canvas during the
2063// window in which the driver is handing the context back.
2064window.__glrestoring=1;GL=null;window.__sov_glfail=\"context-lost (restore armed)\";
2065__tier(\"GPU context lost -- holding the world while the driver hands it back\");
2066console.log(\"nishi: webgl context lost, restore armed (preventDefault called)\");},false);
2067// RESTORE = RELOAD, and the reload is NOT BLIND: there is no re-callable GL init on this page (the
2068// setup is one inline block), so the honest rebuild is a reload -- but it carries a HALVED ribbon
2069// budget in the URL, so the retry runs a configuration measurably cheaper than the one that just
2070// died. The zero-blind-retry policy the WebGPU path states is honoured: this retry is not blind, it
2071// is a different budget. The ladder is bounded and self-reporting -- at hairlod=1 a further loss
2072// falls to ?gl=0 exactly as before, and relost= carries the count so the URL still says why.
2073cv.addEventListener(\"webglcontextrestored\",function(){try{
2074// Every GL object died with the context -- programs, textures, VAOs, the whole NPC pass -- and this
2075// page has no re-callable GL init (setup is one inline block), so the honest rebuild is the ordinary
2076// boot. The world save and the passport are already persisted, so this costs a moment and never the
2077// progress, and it climbs back to the TOP of the ladder rather than the bottom.
2078// THIS IS NOT THE BLIND RETRY THE WebGPU PATH FORBIDS. That policy bans US re-arming a dead adapter
2079// on a cadence; webglcontextrestored is the BROWSER telling us it has already restored one. Acting
2080// on an authoritative hand-back is a different act from speculatively poking dead hardware.
2081var u9=new URL(location.href);
2082// THE BRAND MUST NOT OUTLIVE THE CRASH: drop gl/why/gltry, or a URL the family bookmarks or shares
2083// carries a demotion that is no longer true.
2084u9.searchParams.delete(\"gl\");u9.searchParams.delete(\"why\");u9.searchParams.delete(\"gltry\");
2085// ...BUT THE RETRY IS NOT BLIND EITHER: it comes back on a HALVED ribbon budget, so the
2086// configuration we return to is measurably cheaper than the one that just died. The ladder has
2087// exactly as many rungs as the actuator has budgets (6 -> 3 -> 1); once it is exhausted and we
2088// still lose the context, the cause is not our geometry and ?gl=0 is the honest answer.
2089var kc=(window.__hairkids|0)||2;
2090// THE DEGRADE IS BANKED IN SESSION STATE, NEVER IN THE URL -- see the ladder note at the hair draw.
2091// An older bookmark may still carry ?hairlod=; strip it here so a stale one cannot outlive its tab.
2092u9.searchParams.delete(\"hairlod\");
2093if(kc<=1&&(window.__sov_gllost|0)>1){u9.searchParams.set(\"gl\",\"0\");u9.searchParams.set(\"why\",\"webgl-context-lost-ladder-exhausted\");}
2094else{try{sessionStorage.setItem(\"nxHairLod\",String(Math.max(1,Math.floor(kc/2))));sessionStorage.setItem(\"nxHairFresh\",\"1\");}catch(e9s){}}
2095// RECURRENCE MUST STAY VISIBLE -- a detector that cannot say AGAIN is a latch, not a detector.
2096u9.searchParams.set(\"relost\",String(window.__sov_gllost|0));
2097location.replace(u9.href);}catch(e9r){location.reload();}},false);\nif(g){const cs=(t,s)=>{const o=g.createShader(t);g.shaderSource(o,s);g.compileShader(o);if(!g.getShaderParameter(o,g.COMPILE_STATUS))throw g.getShaderInfoLog(o);return o;};\nconst pr=g.createProgram();g.attachShader(pr,cs(g.VERTEX_SHADER,VSH));g.attachShader(pr,cs(g.FRAGMENT_SHADER,FSH));g.linkProgram(pr);\nif(!g.getProgramParameter(pr,g.LINK_STATUS))throw g.getProgramInfoLog(pr);\ng.useProgram(pr);\nconst L=n=>g.getUniformLocation(pr,n);\nconst tex=g.createTexture();g.activeTexture(g.TEXTURE0);g.bindTexture(g.TEXTURE_3D,tex);\ng.texStorage3D(g.TEXTURE_3D,1,g.R8UI,128,128,48);\ng.texParameteri(g.TEXTURE_3D,g.TEXTURE_MIN_FILTER,g.NEAREST);g.texParameteri(g.TEXTURE_3D,g.TEXTURE_MAG_FILTER,g.NEAREST);\ng.uniform1i(L(\"uV\"),0);g.uniform1i(L(\"uVt\"),location.search.indexOf(\"tm=0\")>=0?0:1);\nVOX=Number(ex.vox_off());SPC=Number(ex.spec_off());\nGL={g,pr,L,lastEd:-1};\n// THE SPEC-REQUIRED RECOVERY PAIR (2026-08-28). A WebGL context is lost for reasons that\n// are ORDINARY and not a fault of this page: a driver reset, a laptop GPU switch, a\n// sleep/wake, or the browser reclaiming the oldest context when the family opens several\n// worlds in tabs. The spec makes restoration OPT-IN -- unless preventDefault() is called on\n// webglcontextlost the browser NEVER fires webglcontextrestored -- so a page without this\n// pair can only ever fall DOWN the ladder. Measured 2026-08-28 over the COMPLETE client\n// payload of /world/beach (478,696 B, 0 external scripts): ZERO listeners of either name.\n// That absence is exactly why one lost context branded a visitor onto the CPU tier for good.\n// SECOND LISTENER PAIR REMOVED 2026-08-28 (merge of two lanes that fixed this hour apart). Two
2098// lost/restored pairs on ONE canvas both ran, both called location.replace with DIFFERENT URL
2099// mutations, and whichever fired second won -- one of the two orderings kept the ?gl=0 brand alive
2100// across a successful restore, i.e. defeated the exact fix both pairs existed to make. The single
2101// surviving pair is registered above, immediately after the context is acquired, and it is the UNION
2102// of both: preventDefault + a loss counter + the __glrestoring canvas hold on the way down, and
2103// brand-deletion + a halved ribbon budget + relost on the way back up.
2104// The climb succeeded, so the brand must not outlive the crash that wrote it: drop gl/why/\n// gltry from the address bar WITHOUT a reload, so nothing the family bookmarks or shares\n// carries the demotion forward.\nif(_gl0&&_why9!==\"\"){try{const _c9=new URL(location.href);_c9.searchParams.delete(\"gl\");_c9.searchParams.delete(\"why\");_c9.searchParams.delete(\"gltry\");window.history.replaceState(null,\"\",_c9.href);}catch(e){}}\n}else{window.__sov_glfail=\"no-webgl2-context: \"+window.__nx_gl.state;window.__sov_glremedy=window.__nx_gl.remedy;console.log(\"nishi: no webgl2 context (\"+window.__nx_gl.state+\"), sovereign render -- \"+window.__nx_gl.remedy);}\n}catch(e){window.__sov_glfail=String(e);console.log(\"nishi: GL unavailable, CPU render\",e);GL=null;}}\n" as *u8)
2105 p = gpe_ap(out, p, "function glDraw(){const g=GL.g,L=GL.L;\n// the mesh pass leaves program/VAO/texture-unit state behind -- reset OURS every frame\ng.useProgram(GL.pr);g.bindVertexArray(null);g.activeTexture(g.TEXTURE0);\nconst dpr=devicePixelRatio||1;const q=Number(ex.quality?ex.quality():2);\n// ★DERIVED FROM q, NOT A LOOKUP TABLE. Each quality step is meant to halve the RENDERED PIXEL\n// COUNT, so the LINEAR scale is 2^(-(q-1)/2): q=1 -> 1, 2 -> .707, 3 -> .5, 4 -> .354, 5 -> .25 --\n// exactly the five values the old table spelled out by hand, and it keeps going past them.\n// THE DEFECT THIS REPLACES: that table had SIX entries while q ranges to Q_MAX, which was widened\n// from 5 to 24 in the engine -- a different file. Any q past 5 read undefined, so scl was NaN, so\n// wpx/hpx were NaN, so the canvas sized to zero and the page went black. It bit MOBILE hardest,\n// because weak hardware is precisely what the frame-time controller coarsens past 5.\n// A hardcoded table indexed by a range that lives somewhere else is a defect waiting for that\n// range to move. This expression cannot go out of range.\nlet scl=1;\n// SCALE FLOOR (operator 20:43, whole-frame mush, \"this bug is back\"): the governor's sensor is the\n// WHOLE rAF delta (the frame_ms report), which includes the wasm tick and its catch-up steps --\n// cost the resolution actuator cannot touch. When THAT is what is slow, q ratchets toward Q_MAX\n// (24) and the picture dissolves while fixing nothing. Past q=4 the fill term is already cut 8x,\n// so a frame still slow there is tick-bound BY CONSTRUCTION and coarsening further only erases\n// the image: the actuator saturates at scl=.354 (q=4). The engine's own work_ms export is the\n// honest sensor split; subtracting it is the engine lane's root fix. REVIEW MODE IS THE VERDICT\n// SCREEN and outranks the governor; ?hi=1 stays as the explicit lever for any other page.\n\n\n// record mode shrinks the canvas (measurement outranks pixels) -- though the REAL headless\n// cost is the NPC mesh pass, so 600-tick measurement runs should use ?gl=0&review=1&record=1:\n// the recorder reads DOORS, not pixels, and the CPU path ticks fast\n// RECORD MODE NO LONGER OVERRIDES AN EXPLICIT FULL-RESOLUTION REQUEST (2026-08-28).
2106// This line used to run AFTER the hi=1/review override and silently undo it, so a capture taken on
2107// a VERDICT path came back at QUARTER SCALE -- the one path whose entire purpose is producing
2108// evidence was the path that quietly reduced it. ★AN EXPLICIT REQUEST OUTRANKS A DEFAULT
2109// OPTIMISATION: scl=.25 here is an optimisation whose whole justification is >>nobody is looking at
2110// these pixels<< (record mode reads DOORS, not pixels), and ?hi=1 / ?review=1 is a caller stating
2111// that somebody IS. The moment the explicit flag is present the optimisation's own premise is
2112// false, so it must yield -- it is not a policy tie to be broken by ordering.
2113// AND WHEN IT DOES REDUCE, IT SAYS SO: a cap reached in silence becomes a measurement nobody knows
2114// is partial, which is exactly how a 240x150 frame gets published as though it were the product.
2115var hrev9=(location.search.indexOf(\"hi=1\")>=0||REV);
2116if(REC&&!hrev9)scl=.25;
2117window.__scl=scl;window.__sclwhy=(REC&&!hrev9)?\"record-quarter\":(hrev9?\"explicit-full\":\"governor\");
2118// ==== GEOMETRY ACTUATOR -- THE ONE THIS GOVERNOR NEVER HAD (crash lane 2026-08-28) ====
2119// Above, the resolution actuator saturates at q=4 (scl=.354) and the note there concludes that a
2120// frame still slow past q=4 is tick-bound BY CONSTRUCTION. That was true when the groom was small.
2121// It is not true now. Ribbon hair is NXH_KIDS(6) children x 1200 guides x 14 segments x 2 tris =
2122// 201,600 triangles PER HEAD, drawn instanced over up to 12 culled figures = 2,419,200 triangles a
2123// frame -- and that count is INVARIANT under scl, because scl only sizes the framebuffer. Worse,
2124// coarsening drives every ribbon SUB-PIXEL, where quad overshading floors the fragment count while
2125// the triangle count stays fixed: past q=4 the pixel knob stops paying and the frame that is still
2126// slow is HAIR-GEOMETRY bound. So the ribbon count takes over exactly where the pixel count gives
2127// up, on the SAME 2^(-d/2) half-the-area law, so one more quality step still means one more halving
2128// of rasterised area. NOTHING IS STRIPPED: at q<=4 the groom is untouched, and the LOD thins the
2129// whole scalp evenly (child-major layout) rather than removing figures or shaving bald patches.
2130// (the ribbon floor is resolved ONCE at the hair draw, where the full child count hk9 is in scope --
2131// see the ladder note there. It used to be read here from the URL; the URL is the wrong home for it.)
2132// (hrev9 -- >>the caller asked for full resolution<< -- is defined ONCE, hoisted above the record-mode
2133// line that now yields to it. Two definitions of one predicate is the duplicate-ruler defect.)
2134// REVIEW OUTRANKS THE GEOMETRY ACTUATOR TOO. The verdict screen is where the groom is JUDGED, so a
2135// q-driven thinning there would degrade the exact thing being looked at -- the same reason review
2136// already outranks the pixel governor. What review may NOT outrank is the watchdog ceiling below:
2137// that one binds everywhere, because a lost context costs the whole renderer, not a little detail.
2138var hq9=(q>4&&!hrev9)?Math.pow(2,-(q-4)/2):1;
2139// TDR SAFETY CEILING -- BINDS EVEN IN REVIEW, BY DESIGN. ?review=1 and ?hi=1 outrank the RESOLUTION
2140// governor on purpose (the verdict screen must be full-res), and that stays. Nothing may outrank the
2141// GPU watchdog: on Windows a frame overrunning TdrDelay (2 s default) has its context reset, and
2142// this page then falls all the way to the CPU raycaster -- which is exactly the report that opened
2143// this lane. The ceiling reuses the render loop OWN out-of-real-time clamp via window.__oor, so no
2144// new constant is introduced, and it recovers only when frames are back under an eighth of it
2145// (hysteresis, so the actuator cannot oscillate against its own effect).
2146var oor9=window.__oor|0;
2147if(oor9>0){if((window.__lastdt|0)>oor9)window.__hairtdr=Math.max(.25,(window.__hairtdr||1)*.5);
2148else if((window.__lastdt|0)<oor9/8&&(window.__hairtdr||1)<1)window.__hairtdr=Math.min(1,(window.__hairtdr||1)*1.25);}
2149window.__hairq=hq9*(window.__hairtdr||1);\n// MAXIMUM RESOURCES THAT ARE LOGICAL PER DEVICE CLASS (operator 2026-08-02): render at full\n// devicePixelRatio sharpness UP TO a per-class pixel budget, and let the adaptive quality\n// controller own the dynamic response below it. Without the budget a dpr-3 phone allocates a\n// 4M+px backing store (thermal + memory pressure the frame-time controller cannot see in its\n// first seconds), and desktop had no defined ceiling at all. Budgets: mobile 2.3Mpx (1080p\n// class), desktop 8.3Mpx (4K). The clamp preserves aspect: scale both axes by sqrt(over).\nconst _mob9=(\"ontouchstart\" in window)||navigator.maxTouchPoints>0;\nconst _PXB=_mob9?2300000:8300000;\nlet wpx=Math.max(64,Math.floor(cv.clientWidth*dpr*scl)),hpx=Math.max(64,Math.floor(cv.clientHeight*dpr*scl));\nif(wpx*hpx>_PXB){const _f9=Math.sqrt(_PXB/(wpx*hpx));wpx=Math.max(64,Math.floor(wpx*_f9));hpx=Math.max(64,Math.floor(hpx*_f9));}\nwindow.__px=wpx+\"x\"+hpx+(_mob9?\"m\":\"d\");\nif(cv.width!==wpx||cv.height!==hpx){cv.width=wpx;cv.height=hpx;g.viewport(0,0,wpx,hpx);}\nex.set_res(BigInt(cv.width),BigInt(cv.height));nxInspectionUpdate();\n// crops grow and soil wets WITHOUT player edits -- refresh the voxel texture on the edit\n// counter OR every 64 organ ticks, whichever fires first (growth stays visible)\nconst ed=Number(ex.broken())+Number(ex.placed());const tn9=Number(ex.tnow());const ag9=ex.arena_gen?Number(ex.arena_gen()):0;\nif(ed!==GL.lastEd||ag9!==GL.lastAg||((tn9&63)===0&&tn9!==GL.lastRefreshTick)){GL.lastEd=ed;GL.lastAg=ag9;GL.lastRefreshTick=tn9;\ng.texSubImage3D(g.TEXTURE_3D,0,0,0,0,128,128,48,g.RED_INTEGER,g.UNSIGNED_BYTE,new Uint8Array(ex.memory.buffer,VOX,128*48*128));}\nconst dv=new DataView(ex.memory.buffer);\n// A1 made visible: the organ's sun elevation drives palette light, sky colour, sun disc + rain\nconst sel=ex.sunel?Number(ex.sunel())/4096:1;const df=Math.max(0,sel);\nconst dl2=.22+.78*Math.pow(df,.6);\nconst pal=new Float32Array(36);\nfor(let i=0;i<12;i++){const v=Number(dv.getBigInt64(SPC+(16+i)*8,true));pal[i*3]=(v&255)/255*dl2;pal[i*3+1]=((v>>8)&255)/255*dl2;pal[i*3+2]=((v>>16)&255)/255*dl2;}\ng.uniform3fv(L(\"uPal\"),pal);\nconst palf=new Float32Array(15);\nfor(let i=0;i<5;i++){const v=Number(dv.getBigInt64(SPC+(34+i)*8,true));palf[i*3]=(v&255)/255*dl2;palf[i*3+1]=((v>>8)&255)/255*dl2;palf[i*3+2]=((v>>16)&255)/255*dl2;}\ng.uniform3fv(L(\"uPalF\"),palf);\nconst skt=Number(dv.getBigInt64(SPC+7*8,true)),skh=Number(dv.getBigInt64(SPC+8*8,true));\nconst nn=1-dl2;\ng.uniform3f(L(\"uSkT\"),(skt&255)/255*dl2+.02*nn,((skt>>8)&255)/255*dl2+.03*nn,((skt>>16)&255)/255*dl2+.10*nn);\ng.uniform3f(L(\"uSkH\"),(skh&255)/255*dl2+.04*nn,((skh>>8)&255)/255*dl2+.05*nn,((skh>>16)&255)/255*dl2+.12*nn);\nconst dfr=(ex.dayt&&ex.dlen)?Number(ex.dayt())/Math.max(1,Number(ex.dlen())):.3;\nconst az=Math.PI*(1.-dfr*1.6);const el=Math.asin(Math.max(-.99,Math.min(.99,sel)));\nlet sdx=Math.cos(el)*Math.cos(az),sdy=Math.sin(el),sdz=Math.cos(el)*.45;\nconst sdl=Math.hypot(sdx,sdy,sdz)||1;\nwindow.__sund=[sdx/sdl,sdy/sdl,sdz/sdl];g.uniform3f(L(\"uSunD\"),sdx/sdl,sdy/sdl,sdz/sdl);if(window.__sunt){const s7=window.__sunt;const mu9=Math.max(0,sdy/sdl),f9=mu9*63,i9=Math.min(62,Math.floor(f9)),t9=f9-i9;g.uniform3f(L(\"uSunC\"),s7[i9*3]*(1-t9)+s7[i9*3+3]*t9,s7[i9*3+1]*(1-t9)+s7[i9*3+4]*t9,s7[i9*3+2]*(1-t9)+s7[i9*3+5]*t9);}\ng.uniform1i(L(\"uSun\"),(Number(dv.getBigInt64(SPC+9*8,true))===1&&df>.04)?1:0);\nconst wxT=Number(dv.getBigInt64(SPC+14*8,true)),wxX=Number(dv.getBigInt64(SPC+12*8,true)),wxZ=Number(dv.getBigInt64(SPC+13*8,true)),wxC=Number(dv.getBigInt64(SPC+11*8,true));\ng.uniform1i(L(\"uWxT\"),wxT);g.uniform2f(L(\"uWxW\"),wxX/4096,wxZ/4096);g.uniform1f(L(\"uWxC\"),wxC/4096);\n" as *u8)
2150 p = gpe_sunt(out, p)
2151 p = gpe_ap(out, p, "window.__wxw=[wxX/4096,wxZ/4096,wxT,wxC/4096];\ng.uniform1i(L(\"uRain\"),ex.rainf?Number(ex.rainf()):0);\ng.uniform1i(L(\"uCld\"),Number(dv.getBigInt64(SPC+10*8,true)));\n" as *u8)
2152 p = gpe_ap(out, p, "g.uniform3f(L(\"uCam\"),Number(nxView(\"view_x\",\"camx\"))/256,Number(nxView(\"view_y\",\"camy\"))/256,Number(nxView(\"view_z\",\"camz\"))/256);\nconst ya=Number(nxView(\"view_yaw\",\"yaw\"))/4096,pi2=Number(nxView(\"view_pitch\",\"pitch\"))/4096;\ng.uniform4f(L(\"uYP\"),Math.sin(ya),Math.cos(ya),Math.sin(pi2),Math.cos(pi2));\ng.uniform1f(L(\"uT\"),Number(ex.tnow()));\ng.uniform1i(L(\"uWmax\"),Number(ex.wmax()));\ng.uniform1i(L(\"uSelB\"),Number(ex.tsel()));\ng.uniform1i(L(\"uHok\"),Number(ex.hok()));\ng.uniform2f(L(\"uRes\"),cv.width,cv.height);\nconst nm=Number(ex.mobs());\ng.uniform1i(L(\"uNpcT\"),ex.npc_t?Number(ex.npc_t()):-1);\ng.disable(g.DEPTH_TEST);\ng.drawArrays(g.TRIANGLES,0,3);\nif(GL.npc&&GL.npc.ok&&nm>0){drawNPCs(g,nm);drawEyes(g);}\nif(GL.npc&&GL.npc.ok)drawDonors(g);\n// ONE call. This line was DOUBLED -- two byte-identical consecutive calls with no state change\n// between them -- so every visiting donor was submitted TWICE per frame, its draw calls and its\n// triangles both. Nothing in the page could disagree: there was no per-frame draw-call or triangle\n// counter, and a second pass over identical geometry at identical depth is invisible on screen. The\n// instrument block at the foot of this page now counts every GL submission, so this whole class\n// reports itself instead of waiting to be read out of the source.\nwindow.__sov_glerr=g.getError();\n// FIRST-FRAME PROOF (one-shot): a tier that drew must show a non-uniform frame -- the world\n// always has sky above sand, so 16 probes on a 4x4 grid (one per quarter-axis cell) that all\n// match mean the renderer painted nothing, whatever the driver claims. The tier is abandoned\n// VISIBLY and sovCanvas2d owns the canvas hand-off.\nif(!GL.ck){GL.ck=1;const _pb=new Uint8Array(64);let _u9=1;\nfor(let _i=0;_i<16;_i++){const _x=Math.floor((_i%4+.5)*cv.width/4),_y=Math.floor((Math.floor(_i/4)+.5)*cv.height/4);\ng.readPixels(_x,_y,1,1,g.RGBA,g.UNSIGNED_BYTE,_pb.subarray(_i*4,_i*4+4));}\nfor(let _i=1;_i<16;_i++){if(_pb[_i*4]!==_pb[0]||_pb[_i*4+1]!==_pb[1]||_pb[_i*4+2]!==_pb[2]){_u9=0;break;}}\nif(_u9){window.__sov_glfail=\"uniform-first-frame (GL drew nothing)\";console.log(\"nishi: GL drew a uniform frame, CPU render\");GL=null;sovCanvas2d();return;}}}\n" as *u8)
2153 p = gpe_ap(out, p, "// GE23 RUNG ONE (2026-09-06): the clip is evaluated IN THE ENGINE. nx_nxa_anim_lib samples the ch2\n// tracks at HER OWN path-length stride phase, removes the fitted root drift, blends toward the idle\n// POSE and forms the dual-quaternion rows; this function is now a typed copy with one divide --\n// interop, not logic. evalTrack and the JS row algebra are GONE, not parked behind a flag. The\n// ankle levelling below stays page-side until the VERT ingest rung moves the sole landmarks in.\nfunction animEval(N,st,m,v,dtf){if(nxResidentComparison.apply(N,m,v))return;const jf=N.jf,nj=N.nj;\nconst o0=(2*v)*nj*4,o1=(2*v+1)*nj*4;\n// ANKLE (operator: she walks on tippy-toes -- a constant plantarflexion rides the retargeted clip). Feet are\n// CHAIN ENDS here (no runtime hierarchy; the toes copy the foot row below), so composing a counter-rotation\n// onto the foot pivot rows is safe. HISTORY: the first cut applied a FIXED 0.30 rad -- and measured on the live\n// page 2026-08-30 its foot set N.fj was EMPTY (the load-time bar excluded this rig's 14.8 cm ankle pivot), so\n// it had never rotated anything; the fix below measures the angle from the mesh's own sole landmarks instead.\n// FOOT LANDMARKS (2026-08-30, ap_foot_ground): heel = the lowest bind vertex BEHIND the ankle pivot, toe = the\n// lowest bind vertex IN FRONT of it, over the vertices this pivot moves rigidly (its dominant-weight set plus the\n// toe-collapse joints welded onto it). Two points, both read off the mesh: they ARE the sole line, and the sole is\n// level exactly when they are. Cached once per asset. L.off = the clip's CONSTANT plantarflexion (what the old\n// fixed 0.30 rad was guessing at): the median over this pivot's own keyframes of the angle that levels its sole --\n// stance is most of a gait cycle, so the median is the flat-foot phase and the swing extremes fall outside it.\nif(N.fj&&!N.fl&&N.dbg&&N.hc&&N.bind){N.fl={};const P=N.dbg.pos,AJ=N.dbg.aj,AW=N.dbg.aw,nvt=P.length/3;const dom=new Int32Array(nvt);\nfor(let v9=0;v9<nvt;v9++){let b9=0,w9=-1;for(let k9=0;k9<4;k9++){if(AW[v9*4+k9]>w9){w9=AW[v9*4+k9];b9=AJ[v9*4+k9];}}dom[v9]=b9;}\nfor(const j of N.fj){const J9={};J9[j]=1;for(let h9=0;h9<N.hc.length;h9++)if(N.hc[h9][1]===j)J9[N.hc[h9][0]]=1;\nconst ay9=N.bind[j*4+1];let hz=1e18,tz=1e18,hv=-1,tv=-1;\nfor(let v9=0;v9<nvt;v9++){if(!J9[dom[v9]])continue;const y9=P[v9*3+1],z9=P[v9*3+2];if(y9>ay9){if(z9<hz){hz=z9;hv=v9;}}else{if(z9<tz){tz=z9;tv=v9;}}}\nif(hv<0||tv<0)continue;\nconst L={heel:[P[hv*3],P[hv*3+1],P[hv*3+2]],toe:[P[tv*3],P[tv*3+1],P[tv*3+2]],off:0};\nconst tr=N.tr[j];if(tr){const as=[];const fx0=L.toe[0]-L.heel[0],fy0=L.toe[1]-L.heel[1],fz0=L.toe[2]-L.heel[2];\nfor(let k9=0;k9<tr.n;k9++){let qx=tr.q[k9*4],qy=tr.q[k9*4+1],qz=tr.q[k9*4+2],qw=tr.q[k9*4+3];const il=1/(Math.hypot(qx,qy,qz,qw)||1);qx*=il;qy*=il;qz*=il;qw*=il;\nconst cx=qy*fz0-qz*fy0+qw*fx0,cy=qz*fx0-qx*fz0+qw*fy0,cz=qx*fy0-qy*fx0+qw*fz0;const fy=fy0+2*(qz*cx-qx*cz),fz=fz0+2*(qx*cy-qy*cx);\nas.push(Math.atan2(-fz*(fy<0?-1:1),Math.abs(fy)));}\nas.sort((a,b)=>a-b);if(as.length)L.off=as[as.length>>1];}\nN.fl[j]=L;}\nwindow.__nx_foot=N.fl;}\nconst gaitGeneration=ex.nxa_gait_generation?String(ex.nxa_gait_generation()):\"legacy\";\nif(N.fl&&N.gaitAttempted!==gaitGeneration&&ex.nxa_gait_calibrate){N.gaitAttempted=gaitGeneration;const ids=N.fj.filter(j=>N.fl[j]);let rc=-81;if(ids.length===2&&Number(ex.nxa_gait_input_words())===18){const input=new BigInt64Array(ex.memory.buffer,Number(ex.nxa_gait_input_off()),18);let q=0;for(const j of ids){const L=N.fl[j];for(const value of [j,...L.heel,...L.toe,Math.round(Math.sin(L.off/2)*4096),Math.round(Math.cos(L.off/2)*4096)])input[q++]=BigInt(Math.round(value));}rc=Number(ex.nxa_gait_calibrate());}window.__nx_gait_fit={rc,method:'sole-contact-distance',contactLabels:'inferred-lower-sole-rearward-travel',samples:Number(ex.nxa_gait_report(0n)),modelDistance:Number(ex.nxa_gait_report(1n)),transitions:Number(ex.nxa_gait_report(2n)),supportedIntervals:Number(ex.nxa_gait_report(3n)),unknownIntervals:Number(ex.nxa_gait_report(4n)),durationMs:Number(ex.nxa_gait_report(5n)),measuredMpb:Number(ex.nxa_gait_report(6n))};}\n\nconst off9=Number(ex.cast_jt(BigInt(m),BigInt(Math.round(dtf*1000))));\nif(off9>=0){const jb9=new BigInt64Array(ex.memory.buffer,off9,nj*8);for(let i9=0;i9<nj*8;i9++)jf[o0+i9]=Number(jb9[i9])/4096;}\nelse{window.__nx_cast_engrow=off9;for(let j=0;j<nj;j++){jf[o0+j*4]=0;jf[o0+j*4+1]=0;jf[o0+j*4+2]=0;jf[o0+j*4+3]=1;jf[o1+j*4]=0;jf[o1+j*4+1]=0;jf[o1+j*4+2]=0;jf[o1+j*4+3]=0;}}\nnxResidentRigStage(N,m,v,'native',off9);\n// ANKLE LEVELLING, MEASURED NOT GUESSED (supersedes the fixed 0.30 rad): the angle comes from THIS frame's\n// posed sole line -- heel and toe rotated through the foot pivot's own quaternion -- so a standing girl\n// (st.iw -> 1) gets her sole level with the ground normal and a striding girl keeps the clip's foot motion\n// minus its constant retarget offset L.off. Rotation about the model lateral axis at the ankle bind pivot:\n// world = D(x-b)+b+dt keeps b fixed under left-composition, so the ankle stays put and the heel drops.\n// ?ankle=<centirad> still overrides for calibration frames.\nif(N.fj&&N.fl){for(const j of N.fj){\nconst rx0=jf[o0+j*4],ry0=jf[o0+j*4+1],rz0=jf[o0+j*4+2],rw0=jf[o0+j*4+3];\nconst L=N.fl[j];let a9=0;if(window.__ankle!==undefined)a9=window.__ankle;else if(L){const fx0=L.toe[0]-L.heel[0],fy0=L.toe[1]-L.heel[1],fz0=L.toe[2]-L.heel[2];const cx=ry0*fz0-rz0*fy0+rw0*fx0,cy=rz0*fx0-rx0*fz0+rw0*fy0,cz=rx0*fy0-ry0*fx0+rw0*fz0;const fy=fy0+2*(rz0*cx-rx0*cz),fz=fz0+2*(rx0*cy-ry0*cx);const al=Math.atan2(-fz*(fy<0?-1:1),Math.abs(fy));const iw9=window.__np9?0:st.iw;a9=al*iw9+L.off*(1-iw9);}\nif(a9===0)continue;\nconst s9=Math.sin(a9/2),c9=Math.cos(a9/2);\n// q_dx (x-axis) times r, then rebuild the dual from the SAME world translation T\nconst rx=s9*rw0+c9*rx0,ry=c9*ry0-s9*rz0,rz=s9*ry0+c9*rz0,rw=c9*rw0-s9*rx0;\nconst dx0=jf[o1+j*4],dy0=jf[o1+j*4+1],dz0=jf[o1+j*4+2],dw0=jf[o1+j*4+3];\n// T = 2 * dual times conj(real) (vector part)\nconst Tx=2*( dx0*rw0-dw0*rx0-dy0*rz0+dz0*ry0);\nconst Ty=2*( dy0*rw0-dw0*ry0-dz0*rx0+dx0*rz0);\nconst Tz=2*( dz0*rw0-dw0*rz0-dx0*ry0+dy0*rx0);\n// re-anchor: T2 = b + (T - b_rotated_delta) -- keep ankle pivot: T2 = b + Told - D2 b, where\n// Told already equals b+dt-D b; rotating D about b needs Db under the NEW rotation:\nconst bx=N.bind[j*4],by=N.bind[j*4+1],bz=N.bind[j*4+2];\nconst cX=ry*bz-rz*by+rw*bx,cY=rz*bx-rx*bz+rw*by,cZ=rx*by-ry*bx+rw*bz;\nconst Dbx=bx+2*(ry*cZ-rz*cY),Dby=by+2*(rz*cX-rx*cZ),Dbz=bz+2*(rx*cY-ry*cX);\nconst c0X=ry0*bz-rz0*by+rw0*bx,c0Y=rz0*bx-rx0*bz+rw0*by,c0Z=rx0*by-ry0*bx+rw0*bz;\nconst D0x=bx+2*(ry0*c0Z-rz0*c0Y),D0y=by+2*(rz0*c0X-rx0*c0Z),D0z=bz+2*(rx0*c0Y-ry0*c0X);\nconst T2x=Tx+D0x-Dbx,T2y=Ty+D0y-Dby,T2z=Tz+D0z-Dbz;\njf[o0+j*4]=rx;jf[o0+j*4+1]=ry;jf[o0+j*4+2]=rz;jf[o0+j*4+3]=rw;\njf[o1+j*4] =.5*( T2x*rw+T2y*rz-T2z*ry);\njf[o1+j*4+1]=.5*(-T2x*rz+T2y*rw+T2z*rx);\njf[o1+j*4+2]=.5*( T2x*ry-T2y*rx+T2z*rw);\njf[o1+j*4+3]=.5*(-T2x*rx-T2y*ry-T2z*rz);}}\nnxResidentRigStage(N,m,v,'ankle');\n// rigid hands: finger rows copy their wrist-line anchor (see hcol at load; ?npchc=0 disables)\nif(location.search.indexOf(\"npchc=0\")<0)for(let hI=0;hI<N.hc.length;hI++){const j=N.hc[hI][0],a=N.hc[hI][1];\nfor(let c=0;c<4;c++)jf[o0+j*4+c]=jf[o0+a*4+c];\nfor(let c=0;c<4;c++)jf[o1+j*4+c]=jf[o1+a*4+c];}\nnxResidentRigStage(N,m,v,'collapse');\n// PLANT (ap_foot_ground): the lowest sole landmark of either foot -- AFTER the levelling above and the rigid\n// toe copy -- is where she meets the ground. N.zf[v] carries that height in model units; drawNPCs puts it ON\n// the terrain top, so uIP.y IS the sole plane, the same plane the cast shadow projects onto. Falls back to\n// the bind floor (N.an.zmn) for an asset with no foot landmarks.\nif(!N.zf)N.zf=new Float32Array(12);let zf9=1e18;\nif(N.fj&&N.fl){for(const j of N.fj){const L=N.fl[j];if(!L)continue;const rx=jf[o0+j*4],ry=jf[o0+j*4+1],rz=jf[o0+j*4+2],rw=jf[o0+j*4+3],dx=jf[o1+j*4],dy=jf[o1+j*4+1],dz=jf[o1+j*4+2],dw=jf[o1+j*4+3];\nconst tz=2*(rw*dz-dw*rz+(rx*dy-ry*dx));\nfor(const p of[L.heel,L.toe]){const bx=p[0],by=p[1],bz=p[2];const cx=ry*bz-rz*by+rw*bx,cy=rz*bx-rx*bz+rw*by,cz=rx*by-ry*bx+rw*bz;const sz=bz+2*(rx*cy-ry*cx);if(sz+tz<zf9)zf9=sz+tz;}}}\nN.zf[v]=(zf9<1e17)?zf9:N.an.zmn;\n// ...and APPLY it INSIDE the joint rows (2026-08-30, second cut): every joint's translation drops by zf so the\n// levelled sole sits at model z=0 and uIP.y can stay py, the terrain top -- the cast-shadow plane (uIP.y + one\n// voxel lift) then reads the AIR cell above the sand as it always did. The first cut lowered uIP.y instead and the\n// plane fell INSIDE the sand block whenever zf*S exceeded the lift; the MFS in-solid discard then ate every shadow\n// texel (measured on b1788128164: soles planted, shadows gone). dual(T-(0,0,zf)) = dual(T) - .5*(0,0,zf)*real.\n{const zs=N.zf[v];for(let j=0;j<nj;j++){const rx=jf[o0+j*4],ry=jf[o0+j*4+1],rz=jf[o0+j*4+2],rw=jf[o0+j*4+3];jf[o1+j*4]+=.5*zs*ry;jf[o1+j*4+1]-=.5*zs*rx;jf[o1+j*4+2]-=.5*zs*rw;jf[o1+j*4+3]+=.5*zs*rz;}}nxResidentRigStage(N,m,v,'plant');}\n" as *u8)
2154 p = gpe_ap(out, p, "// ALL mobs render as skinned NXA instances (the SDF figures are RETIRED -- genome identity\n// rides the mesh: per-instance skin/outfit/hair/warden/height). Culling: >44 blocks or well\n// behind the camera. Clip time is DISTANCE-DRIVEN (ct += moved * ms-per-block) so nobody\n// walks in place or moonwalks; heading = smoothed motion direction (display derivative;\n// the ORGAN owns every position).\n// HAIR PALETTE (2026-08-30, operator: the cast reads blonde and static on the same lock colours): 8 melanin
2155// classes spanning the banked reference population -- 4 eumelanin-dominant (black, dark brown, brown,
2156// chestnut), 2 pheomelanin-dominant (auburn, copper red: the Marschner TT lobe now lights exactly these),
2157// 2 low-melanin blondes (dark, golden). The retired palette carried pink and platinum FANTASY entries and
2158// 5 of 8 light entries, so 62 percent of a uniformly-rolled cast read blonde; fantasy hair belongs to a
2159// THEME delta (GE16 wc_theme_bundle), never the realism default. sRGB reflectance per class follows the
2160// d'Eon 2011 melanin absorption already cited in the hair BSDF, at increasing melanin density.
2161const H8=[[.09,.07,.07],[.24,.15,.10],[.38,.24,.14],[.48,.28,.15],[.55,.25,.14],[.70,.32,.14],[.62,.47,.28],[.82,.66,.40]];\n// E-2 EYEBALL GEOMETRY. Painted eyes top out at 'alive'; a real eye is a SPHERE, which is why\n// it catches light and why the iris shifts with parallax as the head turns -- a flat disc never\n// will at any resolution. This transforms the bind-space eye centre through the HEAD joint's own\n// dual quaternion (the same composition the vertex shader uses), so the eyeball rides her skull\n// exactly. Falls back to paint if anything failed at load (uEyeG stays 0).\nfunction eyeWorld(N,v,bp,ihx,ihy,scl,px,py,pz,joint=N.hj){\nconst nj=N.nj,jf=N.jf,hj=joint;\nconst o0=(2*v)*nj*4,o1=(2*v+1)*nj*4;\nconst rx=jf[o0+hj*4],ry=jf[o0+hj*4+1],rz=jf[o0+hj*4+2],rw=jf[o0+hj*4+3];\nconst dx=jf[o1+hj*4],dy=jf[o1+hj*4+1],dz=jf[o1+hj*4+2],dw=jf[o1+hj*4+3];\nconst bx=bp[0],by=bp[1],bz=bp[2];\nconst cx=ry*bz-rz*by+rw*bx,cy=rz*bx-rx*bz+rw*by,cz=rx*by-ry*bx+rw*bz;\nconst sx=bx+2*(ry*cz-rz*cy),sy=by+2*(rz*cx-rx*cz),sz=bz+2*(rx*cy-ry*cx);\nconst tx=2*(rw*dx-dw*rx+(ry*dz-rz*dy));\nconst ty=2*(rw*dy-dw*ry+(rz*dx-rx*dz));\nconst tz=2*(rw*dz-dw*rz+(rx*dy-ry*dx));\nconst mx=sx+tx,my=sy+ty,mz=sz+tz;\nconst yx=mx,yy=mz,yz=-my;\nconst S=1.78/171530*scl;\nreturn [px+(yx*ihy-yz*ihx)*S,py+yy*S,pz+(yx*ihx+yz*ihy)*S];\n}\nfunction nxEyeSource(pos,nv,AN9){\n const SEG=18,RNG=12,SPv=[],SIv=[];\n for(let r=0;r<=RNG;r++){const th=r*Math.PI/RNG;for(let s=0;s<=SEG;s++){const ph=s*2*Math.PI/SEG;SPv.push(Math.sin(th)*Math.cos(ph),Math.cos(th),Math.sin(th)*Math.sin(ph));}}\n for(let r=0;r<RNG;r++)for(let s=0;s<SEG;s++){const a=r*(SEG+1)+s,b=a+SEG+1;SIv.push(a,b,a+1,a+1,b,b+1);}\n const HHb=.115*AN9.H,exl=.16*HHb,ezb=AN9.zmn+.9420*AN9.H,Rb=.046*HHb;let my0=1e18,my1=1e18;\n for(let v=0;v<nv;v++){const vx=pos[v*3],vy=pos[v*3+1],vz=pos[v*3+2];if(Math.abs(vz-ezb)>.07*HHb||Math.abs(Math.abs(vx)-exl)>.11*HHb)continue;if(vx<0){if(vy<my0)my0=vy;}else if(vy<my1)my1=vy;}\n if(my0>1e17)my0=-.10*HHb;if(my1>1e17)my1=-.10*HHb;\n return{vertices:new Float32Array(SPv),indices:new Uint16Array(SIv),R:Rb,bp:[[-exl,my0+.70*Rb,ezb],[exl,my1+.70*Rb,ezb]],ec:new Float32Array(72),eg:new Float32Array(96),ecol:new Float32Array(72)};\n}\nasync function nxGpuEyeCreate(dev,owner,source,mkg){\n if(!source||!(source.vertices instanceof Float32Array)||!(source.indices instanceof Uint16Array)||source.vertices.length%3||!source.indices.length)throw Error('eye source: invalid geometry');\n for(const v of source.vertices)if(!Number.isFinite(v))throw Error('eye source: nonfinite vertex');for(const i of source.indices)if(i>=source.vertices.length/3)throw Error('eye source: index range');\n if(!NXEV||!NXEF||NXEV_SIZE<=0||NXEF_SIZE<=0)throw Error('eye shader: layout absent');\n const module=async function(code){if(!code)throw Error('eye shader: absent');const m=dev.createShaderModule({code});const info=await m.getCompilationInfo();const bad=info.messages.filter(x=>x.type==='error');if(bad.length)throw Error('eye shader: '+bad.map(x=>x.message).join(';'));return m;};\n const vm=await module(EYE_WGSL_VS),fm=await module(EYE_WGSL_FS);\n const pipeline=await dev.createRenderPipelineAsync({layout:'auto',vertex:{module:vm,entryPoint:'main',buffers:[{arrayStride:12,attributes:[{shaderLocation:0,offset:0,format:'float32x3'}]}]},fragment:{module:fm,entryPoint:'main',targets:[{format:navigator.gpu.getPreferredCanvasFormat()}]},primitive:{topology:'triangle-list',cullMode:'none'},depthStencil:{format:'depth24plus',depthWriteEnabled:true,depthCompare:'less'}});\n if(GPU!==owner)throw Error('eye upload: renderer replaced');\n const e={pipeline,bp:mkg(source.vertices,GPUBufferUsage.VERTEX),ib:mkg(source.indices,GPUBufferUsage.INDEX),ni:source.indices.length,vb:mkg(new Uint8Array(NXEV_SIZE),GPUBufferUsage.UNIFORM),fb:mkg(new Uint8Array(NXEF_SIZE),GPUBufferUsage.UNIFORM),vdata:new ArrayBuffer(NXEV_SIZE),fdata:new ArrayBuffer(NXEF_SIZE),rows:0};\n e.bgv=dev.createBindGroup({layout:pipeline.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:e.vb}}]});e.bgf=dev.createBindGroup({layout:pipeline.getBindGroupLayout(1),entries:[{binding:0,resource:{buffer:e.fb}}]});return e;\n}\nfunction nxGpuEyePrepare(dev,G,R,N,nv){G.eyeFrame=(G.eyeFrame||0)+1;G.eyeSubmitted=0;const e=R.eye;G.eyePrepared=false;const status=window.__nx_eye_gpu;if(status){status.frame=G.eyeFrame;status.submitted=0;status.validated=0;}if(!e||!N.eye||window.__nx_eye_override===0){if(status&&e)status.state='painted-fallback';return false;}if(status)status.state='prepared';\n const E=N.eye,F=new Float32Array(e.vdata),H=new Float32Array(e.fdata),V=NXEV,K=NXEF;F.fill(0);H.fill(0);const camera=[Number(nxView(\"view_x\",\"camx\"))/25