code wiki / (root) / nx_nxa_rig_emit.nx

nx_nxa_rig_emit.nx source

↩ module page · 72 lines · 50225 B

1// nx_nxa_rig_emit.nx -- SKINNED-CHARACTER viewer emitter v5: fetches an NXA (VERT/TRIS/SKEL/ 2// SKIN and optionally ANIM), verifies checksums in-browser, then performs REAL LBS SKINNING on 3// the GPU. With an ANIM section (channel 2 = packed world-delta keys baked by nx_nxa_anim) the 4// figure plays the file's REAL MOCAP. v5 = the REVIEW build (operator: "clothes and hair are 5// bizarre... see all of this before we put it into the game"): RIBBON hair (scalp-wide layered 6// roots, face side excluded, nape-long crown-short, calm damped sim), a chest-pinned DRESS 7// with full body colliders (chest/waist/hip spheres + tapered leg capsules), anchor-driven 8// flesh springs, and an inspection UI (Natural/Clothed toggle, wind calm/breeze/windy, pause). 9// usage: nx_nxa_rig_emit <out.html> <title> <nxa-url> 10// license_tier: ORIGINAL 11import "nx_syscalls.nx" 12 13const NRE_OUT_CAP: i64 = 1048576 14 15func nre_ap(out: *u8, pos: i64, s: *u8) -> i64 { 16 var k: i64 = 0 17 var p: i64 = pos 18 while s[k] != (0 as u8) { out[p] = s[k]; p = p + 1; k = k + 1 } 19 return p 20} 21func nre_w(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 22func nre_num(v: i64) -> i64 { 23 let t: *u8 = sys_mmap(32) as *u8 24 var m: i64 = v; var w: i64 = 0 25 if m==0 { t[0]=48 as u8; sys_write(1,t,1); return 0 } 26 let d: *u8 = sys_mmap(32) as *u8 27 var k: i64=0 28 while m>0 { d[k]=(48+(m%10)) as u8; m=m/10; k=k+1 } 29 var j: i64=0 30 while j<k { t[w]=d[k-1-j]; w=w+1; j=j+1 } 31 sys_write(1,t,w); return 0 32} 33 34func main(argc: i64, argv: *i64) -> i64 { 35 if argc < 4 { nre_w("usage: nx_nxa_rig_emit <out.html> <title> <nxa-url>\n" as *u8); return 2 } 36 let out: *u8 = sys_mmap(NRE_OUT_CAP) 37 var p: i64 = 0 38 p = nre_ap(out, p, "<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"utf-8\"><title>" as *u8) 39 p = nre_ap(out, p, argv[2] as *u8) 40 p = nre_ap(out, p, "</title><meta name=\"nishi-nxa\" content=\"" as *u8) 41 p = nre_ap(out, p, argv[3] as *u8) 42 p = nre_ap(out, p, "\"><meta name=\"viewport\" content=\"width=device-width,initial-scale=1\"><style>\nhtml{height:100%}\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:12px;padding:12px 0;box-sizing:border-box}\ncanvas{width:min(94vw,560px);aspect-ratio:5/8;border:1px solid #2f2a4a;border-radius:4px;touch-action:none;background:#0b0a14}\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:74ch}\n#st{color:#a8e6c0}</style></head><body><h1>" as *u8) 43 p = nre_ap(out, p, argv[2] as *u8) 44 p = nre_ap(out, p, "</h1><canvas id=\"c\"></canvas>\n<div id=\"ui\" style=\"display:flex;gap:8px;flex-wrap:wrap;justify-content:center\"></div>\n<p id=\"st\">fetching rigged NXA&hellip;</p>\n<p>A reference-detail character with a REAL 104-joint skeleton and per-vertex skin weights, all\ncarried in <b>NXA</b> (our sovereign format) and verified by checksum in your browser. The motion is\nthe file&rsquo;s REAL mocap; flesh follows anchor-driven springs; hair and dress are live physics.\nToggle Natural/Clothed, cycle the wind, pause to inspect. Drag to rotate.</p>\n<script>\nconst U=\"" as *u8) 45 p = nre_ap(out, p, argv[3] as *u8) 46 p = nre_ap(out, p, "\";\nconst st=document.getElementById(\"st\");\nasync function main(){\nconst r0=await fetch(U);if(!r0.ok)throw\"fetch \"+r0.status;\nconst by=new Uint8Array(await r0.arrayBuffer());\nconst dv=new DataView(by.buffer);\nconst u32=o=>dv.getUint32(o,true);\nconst w=o=>u32(o)+dv.getInt32(o+4,true)*4294967296;\nfunction ck(o,n){let lo=1,hi=0;\nfor(let i=0;i<n;i++){const a=lo*1000003+u32(o+i*8);lo=a>>>0;\nconst b=hi*1000003+u32(o+i*8+4)+Math.floor(a/4294967296);hi=b>>>0}\nreturn [lo,hi]}\nconst ckeq=(o,pr)=>u32(o)===pr[0]&&u32(o+4)===pr[1];\nconst mg=\"NXANIM01\";for(let i=0;i<8;i++)if(by[i]!=mg.charCodeAt(i))throw\"not NXA\";\nif(w(8)>1)throw\"future version \\u2014 refusing\";\nconst ns=Number(w(16));\nif(!ckeq(24,ck(32,ns*4)))throw\"TOC checksum mismatch\";\nconst tg=s=>s.charCodeAt(0)|(s.charCodeAt(1)<<8)|(s.charCodeAt(2)<<16)|(s.charCodeAt(3)<<24);\nfunction find(t,req){for(let s2=0;s2<ns;s2++){const e=32+s2*32;\nif(u32(e)===(t>>>0)){const off=Number(w(e+8)),wl=Number(w(e+16));\nif(!ckeq(e+24,ck(off,wl)))throw\"section corrupt\";return off}}\nif(req)throw\"section missing\";return -1}\nconst vo=find(tg(\"VERT\"),1),to=find(tg(\"TRIS\"),1),so=find(tg(\"SKEL\"),1),ko=find(tg(\"SKIN\"),1);\nconst ao=find(tg(\"ANIM\"),0);const ho=find(tg(\"HSTR\"),0);\nconst go=find(tg(\"GVRT\"),0),gt2=find(tg(\"GTRI\"),0),gp2=find(tg(\"GPIN\"),0);\nconst nv=Number(w(vo)),nt=Number(w(to)),nj=Number(w(so));\n" as *u8) 47 p = nre_ap(out, p, "st.textContent=\"decoding \"+nv+\" verts, \"+nj+\" joints\\u2026\";\nconst R=new Float64Array(nv*3);\nlet mn=[1e18,1e18,1e18],mx=[-1e18,-1e18,-1e18];\nfor(let i=0;i<nv*3;i++){const v=w(vo+8+i*8)/1000;R[i]=v;const a=i%3;if(v<mn[a])mn[a]=v;if(v>mx[a])mx[a]=v}\nconst ex=[mx[0]-mn[0],mx[1]-mn[1],mx[2]-mn[2]];\nlet up=0;if(ex[1]>ex[up])up=1;if(ex[2]>ex[up])up=2;\nlet lat=up===0?1:0;const o0=3-up-lat;if(ex[o0]>ex[lat])lat=o0;\nconst oth=3-up-lat;\nconst c0=(mn[lat]+mx[lat])/2,c1=(mn[up]+mx[up])/2,c2=(mn[oth]+mx[oth])/2;\nconst P=new Float32Array(nv*3);\nfor(let i=0;i<nv;i++){P[i*3]=R[i*3+lat]-c0;P[i*3+1]=R[i*3+up]-c1;P[i*3+2]=R[i*3+oth]-c2}\nconst P0=new Float32Array(P);\nconst I=new Uint32Array(nt*3);\nfor(let i=0;i<nt*3;i++)I[i]=u32(to+8+i*8);\nconst N=new Float32Array(nv*3);\nfunction calcN(){N.fill(0);\nfor(let t=0;t<nt;t++){const a=I[t*3],b2=I[t*3+1],c3=I[t*3+2];\nconst e1x=P[b2*3]-P[a*3],e1y=P[b2*3+1]-P[a*3+1],e1z=P[b2*3+2]-P[a*3+2];\nconst e2x=P[c3*3]-P[a*3],e2y=P[c3*3+1]-P[a*3+1],e2z=P[c3*3+2]-P[a*3+2];\nconst nx=e1y*e2z-e1z*e2y,ny=e1z*e2x-e1x*e2z,nz=e1x*e2y-e1y*e2x;\nN[a*3]+=nx;N[a*3+1]+=ny;N[a*3+2]+=nz;N[b2*3]+=nx;N[b2*3+1]+=ny;N[b2*3+2]+=nz;N[c3*3]+=nx;N[c3*3+1]+=ny;N[c3*3+2]+=nz}}\ncalcN();\n// skeleton: parents + binds (permuted + centered into the SAME space as P)\nconst par=new Int32Array(nj);const B=new Float32Array(nj*3);\nfor(let j=0;j<nj;j++){const e=so+8+j*64;par[j]=Number(w(e));\nconst bb=[w(e+8)/1000,w(e+16)/1000,w(e+24)/1000];\nB[j*3]=bb[lat]-c0;B[j*3+1]=bb[up]-c1;B[j*3+2]=bb[oth]-c2}\nconst J4=new Float32Array(nv*4);const W4=new Float32Array(nv*4);\nfor(let v=0;v<nv;v++){const e=ko+8+v*64;\nfor(let s=0;s<4;s++){J4[v*4+s]=Number(w(e+s*8));W4[v*4+s]=Number(w(e+32+s*8))/4096}}\n" as *u8) 48 p = nre_ap(out, p, "// STRUCTURAL joint identification (SKEL carries no names by design)\nconst H=ex[up];\nconst h01=j=>(B[j*3+1]+H/2)/H;const latv=j=>B[j*3];\nconst kids=Array.from({length:nj},()=>[]);\nfor(let j=0;j<nj;j++)if(par[j]>=0&&par[j]<nj)kids[par[j]].push(j);\nlet thL=-1,thR=-1,knL=-1,knR=-1,shL=-1,shR=-1;\nfor(let j=0;j<nj;j++){const h=h01(j),l=latv(j);\nif(h>.15&&h<.42&&Math.abs(l)>.02*H){\nfor(const c of kids[j]){\nif(h01(c)<=h-.08){\nif(l>0&&knL<0){knL=j;thL=par[j]>=0?par[j]:j}\nif(l<0&&knR<0){knR=j;thR=par[j]>=0?par[j]:j}}}}\nif(h>.68&&h<.82&&Math.abs(l)>.15*H&&Math.abs(l)<.30*H){\nfor(const c of kids[j]){\nif(Math.abs(latv(c))>Math.abs(l)+.03*H&&Math.sign(latv(c))===Math.sign(l)){\nif(l>0&&shL<0)shL=j;\nif(l<0&&shR<0)shR=j}}}}\nconst found=[thL,thR,knL,knR,shL,shR].filter(x=>x>=0).length;\nfunction mul(a,b){const r=new Float32Array(16);\nfor(let i=0;i<4;i++)for(let k=0;k<4;k++){let s=0;for(let q=0;q<4;q++)s+=a[q*4+i]*b[k*4+q];r[k*4+i]=s}return r}\nconst ID=new Float32Array([1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]);\nfunction rotXpivot(th,bx,byy,bz){const c=Math.cos(th),s=Math.sin(th);\nreturn new Float32Array([1,0,0,0, 0,c,s,0, 0,-s,c,0, bx-bx*1,byy-(c*byy-s*bz),bz-(s*byy+c*bz),1])}\nfunction rotZpivot(th,bx,byy){const c=Math.cos(th),s=Math.sin(th);\nreturn new Float32Array([c,s,0,0, -s,c,0,0, 0,0,1,0, bx-(c*bx-s*byy),byy-(s*bx+c*byy),0,1])}\nfunction trans(tx,ty){return new Float32Array([1,0,0,0,0,1,0,0,0,0,1,0,tx,ty,0,1])}\nconst JM=new Float32Array(128*16);\n" as *u8) 49 p = nre_ap(out, p, "// FEMININE GAIT via GRADED REGION-BROADCAST (fallback when the file carries no ANIM)\nconst sstep=(a,b,x)=>{const t2=Math.min(1,Math.max(0,(x-a)/(b-a)));return t2*t2*(3-2*t2)};\nfunction pose(ph,sw,bob){\nconst G=new Array(nj);for(let j=0;j<nj;j++)G[j]=ID;\nconst gradZ=(px,py,th2,wf)=>{if(Math.abs(th2)<1e-5)return;\nfor(let j=0;j<nj;j++){const w2=wf(j);if(w2>.002)G[j]=mul(rotZpivot(th2*w2,px,py),G[j])}};\nconst gradX=(A,th2,wf)=>{if(A<0||Math.abs(th2)<1e-5)return;\nfor(let j=0;j<nj;j++){const w2=wf(j);if(w2>.002)G[j]=mul(rotXpivot(th2*w2,B[A*3],B[A*3+1],B[A*3+2]),G[j])}};\nconst S=Math.sin(ph);\nconst wArmL=j=>h01(j)>.55?sstep(.13*H,.26*H,latv(j)):0;\nconst wArmR=j=>h01(j)>.55?sstep(.13*H,.26*H,-latv(j)):0;\nif(shL>=0)gradZ(B[shL*3],B[shL*3+1],-1.06,wArmL);\nif(shR>=0)gradZ(B[shR*3],B[shR*3+1],1.06,wArmR);\ngradZ(.30*H,.30*H,-.34,j=>h01(j)>.55?sstep(.26*H,.36*H,latv(j)):0);\ngradZ(-.30*H,.30*H,.34,j=>h01(j)>.55?sstep(.26*H,.36*H,-latv(j)):0);\nif(shL>=0)gradX(shL,-.17*S,wArmL);\nif(shR>=0)gradX(shR,.17*S,wArmR);\ngradZ(.34*H,.26*H,-.09*Math.sin(ph*.5),j=>h01(j)>.55?sstep(.30*H,.40*H,latv(j)):0);\ngradZ(-.34*H,.26*H,.09*Math.sin(ph*.5),j=>h01(j)>.55?sstep(.30*H,.40*H,-latv(j)):0);\nconst kA=-(.10+.22*Math.max(0,-Math.cos(ph))),kB=-(.10+.22*Math.max(0,Math.cos(ph)));\nconst hKL=knL>=0?h01(knL):.33,hKR=knR>=0?h01(knR):.33;\nconst side=(j,s2)=>Math.abs(latv(j))<.13*H?sstep(.004*H,.03*H,s2*latv(j)):0;\ngradX(knL,kA,j=>side(j,1)*(1-sstep(hKL-.03,hKL+.05,h01(j))));\ngradX(knR,kB,j=>side(j,-1)*(1-sstep(hKR-.03,hKR+.05,h01(j))));\ngradX(thL,.26*S,j=>side(j,1)*(1-sstep(.54,.63,h01(j))));\ngradX(thR,-.26*S,j=>side(j,-1)*(1-sstep(.54,.63,h01(j))));\ngradZ(0,.06*H,.10*S,j=>1-sstep(.55,.70,h01(j)));\ngradZ(0,.20*H,-.07*S,j=>sstep(.58,.72,h01(j)));\ngradZ(0,.40*H,.06*S,j=>sstep(.86,.93,h01(j)));\nconst T=trans(sw,bob);\nfor(let j=0;j<nj;j++)G[j]=mul(T,G[j]);\nfor(let j=0;j<nj;j++)JM.set(G[j],j*16)}\n" as *u8) 50 p = nre_ap(out, p, "// ANIM channel-2 playback: packed world-delta keys baked by nx_nxa_anim (D about bind,\n// dt mm); exact LBS in the permuted/centered display space: M x = D(x-B)+B+dt\nlet AT=null,DUR=0;\nif(ao>=0){const ntr=Number(w(ao));AT=new Array(nj).fill(null);let rp=ao+8;\nfor(let t3=0;t3<ntr;t3++){const jj=Number(w(rp)),ch=Number(w(rp+8)),nk2=Number(w(rp+16));rp+=24;\nif(ch===2&&jj<nj){const tm=new Uint16Array(nk2),qq=new Int16Array(nk2*4),d3=new Int16Array(nk2*3);\nfor(let k=0;k<nk2;k++){const b0=rp+k*16;\ntm[k]=dv.getUint16(b0,true);\nqq[k*4]=dv.getInt16(b0+2,true);qq[k*4+1]=dv.getInt16(b0+4,true);qq[k*4+2]=dv.getInt16(b0+6,true);qq[k*4+3]=dv.getInt16(b0+8,true);\nd3[k*3]=dv.getInt16(b0+10,true);d3[k*3+1]=dv.getInt16(b0+12,true);d3[k*3+2]=dv.getInt16(b0+14,true)}\nAT[jj]={tm:tm,q:qq,d:d3,nk:nk2};\nif(tm[nk2-1]>DUR)DUR=tm[nk2-1];rp+=nk2*16}\nelse{rp+=nk2*(ch===2?16:40)}}\nif(DUR<33)AT=null}\nconst map=[lat,up,oth];const M9=new Float64Array(9);\nfunction q2m(x,y,z,w2){const n=Math.hypot(x,y,z,w2)||1;const s=1/n;x*=s;y*=s;z*=s;w2*=s;\nM9[0]=1-2*(y*y+z*z);M9[1]=2*(x*y-z*w2);M9[2]=2*(x*z+y*w2);\nM9[3]=2*(x*y+z*w2);M9[4]=1-2*(x*x+z*z);M9[5]=2*(y*z-x*w2);\nM9[6]=2*(x*z-y*w2);M9[7]=2*(y*z+x*w2);M9[8]=1-2*(x*x+y*y)}\nconst dts=[0,0,0];\nfunction poseAnim(tms){\nfor(let j=0;j<nj;j++){const tr3=AT[j];const o2=j*16;\nif(!tr3){JM.set(ID,o2);continue}\nlet k=Math.floor(tms/33);if(k>tr3.nk-2)k=tr3.nk-2;if(k<0)k=0;\nconst t0=tr3.tm[k],t1=tr3.tm[k+1];let al=t1>t0?(tms-t0)/(t1-t0):0;if(al<0)al=0;if(al>1)al=1;\nconst q=tr3.q;let ax=q[k*4],ay=q[k*4+1],az=q[k*4+2],aw2=q[k*4+3];\nlet bx3=q[k*4+4],by3=q[k*4+5],bz3=q[k*4+6],bw3=q[k*4+7];\nif(ax*bx3+ay*by3+az*bz3+aw2*bw3<0){bx3=-bx3;by3=-by3;bz3=-bz3;bw3=-bw3}\nq2m(ax+(bx3-ax)*al,ay+(by3-ay)*al,az+(bz3-az)*al,aw2+(bw3-aw2)*al);\nconst d=tr3.d;\ndts[0]=(d[k*3]+(d[k*3+3]-d[k*3])*al)/10;\ndts[1]=(d[k*3+1]+(d[k*3+4]-d[k*3+1])*al)/10;\ndts[2]=(d[k*3+2]+(d[k*3+5]-d[k*3+2])*al)/10;\nconst r00=M9[map[0]*3+map[0]],r01=M9[map[0]*3+map[1]],r02=M9[map[0]*3+map[2]];\nconst r10=M9[map[1]*3+map[0]],r11=M9[map[1]*3+map[1]],r12=M9[map[1]*3+map[2]];\nconst r20=M9[map[2]*3+map[0]],r21=M9[map[2]*3+map[1]],r22=M9[map[2]*3+map[2]];\nconst bx2=B[j*3],by2=B[j*3+1],bz2=B[j*3+2];\nJM[o2]=r00;JM[o2+1]=r10;JM[o2+2]=r20;JM[o2+3]=0;\nJM[o2+4]=r01;JM[o2+5]=r11;JM[o2+6]=r21;JM[o2+7]=0;\nJM[o2+8]=r02;JM[o2+9]=r12;JM[o2+10]=r22;JM[o2+11]=0;\nJM[o2+12]=bx2+dts[map[0]]-(r00*bx2+r01*by2+r02*bz2);\nJM[o2+13]=by2+dts[map[1]]-(r10*bx2+r11*by2+r12*bz2);\nJM[o2+14]=bz2+dts[map[2]]-(r20*bx2+r21*by2+r22*bz2);JM[o2+15]=1}}\nlet ts0=performance.now();\n" as *u8) 51 p = nre_ap(out, p, "const cv=document.getElementById(\"c\");\nconst g=cv.getContext(\"webgl2\",{antialias:true,preserveDrawingBuffer:true});\nif(!g)throw\"no webgl2\";\nconst VS=`#version 300 es\nin vec3 aP;in vec3 aN;in vec4 aJ;in vec4 aW;in vec2 aS;\nuniform sampler2D uJT;uniform vec2 uR;uniform vec2 uY;uniform vec2 uP;uniform float uS;uniform vec3 uJ1;uniform vec3 uJ1R;uniform vec3 uJ2;out vec3 vN;out vec2 vB;\nvoid main(){\n// DUAL-QUATERNION skinning: linear-blend collapses the armpit under the T-pose->arms-down\n// delta (the measured shoulder tears); DQ blending preserves volume at large rotations\nvec4 r0=texelFetch(uJT,ivec2(0,int(aJ.x)),0),d0=texelFetch(uJT,ivec2(1,int(aJ.x)),0);\nvec4 r1=texelFetch(uJT,ivec2(0,int(aJ.y)),0),d1=texelFetch(uJT,ivec2(1,int(aJ.y)),0);\nvec4 r2=texelFetch(uJT,ivec2(0,int(aJ.z)),0),d2=texelFetch(uJT,ivec2(1,int(aJ.z)),0);\nvec4 r3=texelFetch(uJT,ivec2(0,int(aJ.w)),0),d3=texelFetch(uJT,ivec2(1,int(aJ.w)),0);\nfloat s1=dot(r0,r1)<0.?-1.:1.;float s2=dot(r0,r2)<0.?-1.:1.;float s3=dot(r0,r3)<0.?-1.:1.;\nvec4 br=aW.x*r0+aW.y*s1*r1+aW.z*s2*r2+aW.w*s3*r3;\nvec4 bd=aW.x*d0+aW.y*s1*d1+aW.z*s2*d2+aW.w*s3*d3;\nfloat nr=max(length(br),1e-6);br/=nr;bd/=nr;\nvec3 p=aP+2.*cross(br.xyz,cross(br.xyz,aP)+br.w*aP)+2.*(br.w*bd.xyz-bd.w*br.xyz+cross(br.xyz,bd.xyz));\nvec3 n0=aN+2.*cross(br.xyz,cross(br.xyz,aN)+br.w*aN);\np+=aS.x*(aP.x<0.?uJ1:uJ1R)+aS.y*uJ2;\nvB=vec2(aP.x,aP.y);\nfloat xr=p.x*uY.x+p.z*uY.y;float zr=-p.x*uY.y+p.z*uY.x;\nvec3 v=vec3(xr,p.y,zr)*uS;\nv=vec3(v.x,v.y*uP.x-v.z*uP.y,v.y*uP.y+v.z*uP.x);\nvN=vec3(n0.x*uY.x+n0.z*uY.y,n0.y,-n0.x*uY.y+n0.z*uY.x);\nvec3 e=vec3(v.x,v.y,v.z-2.3);\ngl_Position=vec4(e.x*1.6*uR.y/uR.x,e.y*1.6,-2.7647*e.z-5.647,-e.z);}`;\nconst FS=`#version 300 es\nprecision highp float;in vec3 vN;in vec2 vB;uniform float uClo;uniform float uH;out vec4 fc;\nvoid main(){vec3 n=normalize(vN);vec3 L=normalize(vec3(-.45,.75,.55));\nfloat d=abs(dot(n,L));vec3 skin=vec3(.925,.77,.675);\nvec3 H2=normalize(L+vec3(0.,0.,1.));float sp=pow(abs(dot(n,H2)),24.);\nfloat rim=pow(1.-abs(n.z),3.);\nfc=vec4(skin*(.30+.72*d)+vec3(1.,.97,.92)*sp*.18+vec3(.35,.30,.45)*rim*.25,1.);\n}`;\nconst cs=(t,s)=>{const o=g.createShader(t);g.shaderSource(o,s);g.compileShader(o);\nif(!g.getShaderParameter(o,g.COMPILE_STATUS))throw g.getShaderInfoLog(o);return o};\nconst pr=g.createProgram();g.attachShader(pr,cs(g.VERTEX_SHADER,VS));g.attachShader(pr,cs(g.FRAGMENT_SHADER,FS));\ng.linkProgram(pr);if(!g.getProgramParameter(pr,g.LINK_STATUS))throw g.getProgramInfoLog(pr);\ng.useProgram(pr);\n" as *u8) 52 p = nre_ap(out, p, "// per-vertex SOFTNESS (chest slot 0, hip slot 1) for the flesh springs\nconst S2=new Float32Array(nv*2);\nfunction calcS2(){S2.fill(0);\nconst bands=[[.60,.78,0],[.40,.58,1]];\nfor(const bd of bands){let rs=[],ids=[];\nfor(let i=0;i<nv;i++){const y01=(P[i*3+1]+H/2)/H;\nif(y01>bd[0]&&y01<bd[1]&&Math.abs(P[i*3])<.16*H){const r=Math.hypot(P[i*3],P[i*3+2]);rs.push(r);ids.push(i)}}\nrs.sort((a,b)=>a-b);const rm=rs[Math.floor(rs.length*.55)]||1;\nfor(const i of ids){const r=Math.hypot(P[i*3],P[i*3+2]);\nconst s=Math.min(1,Math.max(0,(r-rm)/(rm*.6)));\nS2[i*2+bd[2]]=s*s}}}\ncalcS2();\nconst buf=(loc,data,sz)=>{const b=g.createBuffer();g.bindBuffer(g.ARRAY_BUFFER,b);\ng.bufferData(g.ARRAY_BUFFER,data,g.STATIC_DRAW);g.enableVertexAttribArray(loc);g.vertexAttribPointer(loc,sz,g.FLOAT,false,0,0);return b};\ng.bindAttribLocation(pr,0,\"aP\");g.bindAttribLocation(pr,1,\"aN\");g.bindAttribLocation(pr,2,\"aJ\");g.bindAttribLocation(pr,3,\"aW\");g.bindAttribLocation(pr,4,\"aS\");\ng.linkProgram(pr);g.useProgram(pr);\nconst bP=buf(0,P,3),bN=buf(1,N,3);buf(2,J4,4);buf(3,W4,4);const bS=buf(4,S2,2);\nconst bi=g.createBuffer();g.bindBuffer(g.ELEMENT_ARRAY_BUFFER,bi);g.bufferData(g.ELEMENT_ARRAY_BUFFER,I,g.STATIC_DRAW);\ng.enable(g.DEPTH_TEST);\nconst jt=g.createTexture();g.activeTexture(g.TEXTURE0);g.bindTexture(g.TEXTURE_2D,jt);\ng.texStorage2D(g.TEXTURE_2D,1,g.RGBA32F,2,128);\ng.texParameteri(g.TEXTURE_2D,g.TEXTURE_MIN_FILTER,g.NEAREST);g.texParameteri(g.TEXTURE_2D,g.TEXTURE_MAG_FILTER,g.NEAREST);\nconst L2=n=>g.getUniformLocation(pr,n);\ng.uniform1i(L2(\"uJT\"),0);g.uniform1f(L2(\"uS\"),1.5/H);g.uniform1f(L2(\"uH\"),H);g.uniform1f(L2(\"uClo\"),1);\nlet yaw=.5,pitch=0,zoom=1,auto=true,px0=0,py0=0;\nconst ptrs=new Map();let pinch0=0,zoom0=1;\ncv.addEventListener(\"pointerdown\",e=>{auto=false;ptrs.set(e.pointerId,[e.clientX,e.clientY]);px0=e.clientX;py0=e.clientY;cv.setPointerCapture(e.pointerId)});\ncv.addEventListener(\"pointermove\",e=>{if(!ptrs.has(e.pointerId))return;\nptrs.set(e.pointerId,[e.clientX,e.clientY]);\nif(ptrs.size===2){const v2=[...ptrs.values()];\nconst d3=Math.hypot(v2[0][0]-v2[1][0],v2[0][1]-v2[1][1]);\nif(pinch0===0){pinch0=d3;zoom0=zoom}else{zoom=Math.min(4,Math.max(.4,zoom0*d3/pinch0))}}\nelse if(e.buttons){yaw+=(e.clientX-px0)*.012;\npitch=Math.min(.9,Math.max(-.9,pitch+(e.clientY-py0)*.008));\npx0=e.clientX;py0=e.clientY}});\ncv.addEventListener(\"pointerup\",e=>{ptrs.delete(e.pointerId);if(ptrs.size<2)pinch0=0;setTimeout(()=>{auto=true},4000)});\ncv.addEventListener(\"wheel\",e=>{e.preventDefault();auto=false;zoom=Math.min(4,Math.max(.4,zoom*(e.deltaY<0?1.1:.9)))},{passive:false});\nfunction rs(){const r=cv.getBoundingClientRect();const d2=devicePixelRatio||1;\ncv.width=Math.round(r.width*d2);cv.height=Math.round(r.height*d2);g.viewport(0,0,cv.width,cv.height);\ng.uniform2f(L2(\"uR\"),cv.width,cv.height)}\nrs();addEventListener(\"resize\",rs);\ng.clearColor(.045,.04,.07,1);\n" as *u8) 53 p = nre_ap(out, p, "// ---- secondary dynamics v5 ----\nfunction jpos(j,out){const o=j*16;const bx=B[j*3],by=B[j*3+1],bz=B[j*3+2];\nout[0]=JM[o]*bx+JM[o+4]*by+JM[o+8]*bz+JM[o+12];\nout[1]=JM[o+1]*bx+JM[o+5]*by+JM[o+9]*bz+JM[o+13];\nout[2]=JM[o+2]*bx+JM[o+6]*by+JM[o+10]*bz+JM[o+14]}\nfunction xform(j,vx,vy,vz,out){const o=j*16;\nout[0]=JM[o]*vx+JM[o+4]*vy+JM[o+8]*vz+JM[o+12];\nout[1]=JM[o+1]*vx+JM[o+5]*vy+JM[o+9]*vz+JM[o+13];\nout[2]=JM[o+2]*vx+JM[o+6]*vy+JM[o+10]*vz+JM[o+14]}\nfunction nearJ(y0){let bj=0,bd=1e18;for(let j=0;j<nj;j++){const dx=B[j*3],dy=B[j*3+1]-y0;\nconst dd=4*dx*dx+dy*dy;if(dd<bd){bd=dd;bj=j}}return bj}\nconst jaC=nearJ(.19*H),jaH=nearJ(-.02*H),jaHd=nearJ(.42*H);\n" as *u8) 54 p = nre_ap(out, p, "// per-frame JM (4x4 delta) -> dual quaternion texture rows [real|dual]\nconst JMD=new Float32Array(128*8);\nfunction m2q(o,oo){\nconst m00=JM[o],m10=JM[o+1],m20=JM[o+2],m01=JM[o+4],m11=JM[o+5],m21=JM[o+6],m02=JM[o+8],m12=JM[o+9],m22=JM[o+10];\nconst tr=m00+m11+m22;let qx,qy,qz,qw;\nif(tr>0){const s=Math.sqrt(tr+1)*2;qw=.25*s;qx=(m21-m12)/s;qy=(m02-m20)/s;qz=(m10-m01)/s}\nelse if(m00>m11&&m00>m22){const s=Math.sqrt(1+m00-m11-m22)*2;qw=(m21-m12)/s;qx=.25*s;qy=(m01+m10)/s;qz=(m02+m20)/s}\nelse if(m11>m22){const s=Math.sqrt(1+m11-m00-m22)*2;qw=(m02-m20)/s;qx=(m01+m10)/s;qy=.25*s;qz=(m12+m21)/s}\nelse{const s=Math.sqrt(1+m22-m00-m11)*2;qw=(m10-m01)/s;qx=(m02+m20)/s;qy=(m12+m21)/s;qz=.25*s}\nconst tx=JM[o+12],ty=JM[o+13],tz=JM[o+14];\nJMD[oo]=qx;JMD[oo+1]=qy;JMD[oo+2]=qz;JMD[oo+3]=qw;\nJMD[oo+4]=.5*(qw*tx+ty*qz-tz*qy);\nJMD[oo+5]=.5*(qw*ty+tz*qx-tx*qz);\nJMD[oo+6]=.5*(qw*tz+tx*qy-ty*qx);\nJMD[oo+7]=-.5*(tx*qx+ty*qy+tz*qz)}\nfunction packDQ(){for(let j=0;j<nj;j++)m2q(j*16,j*8)}\n// FIGURE morph: reference vs generous -- smooth gaussian falloffs only (no hard edges, no\n// surgery look): hips +13pct, waist -4.5pct, soft front bust volume; face untouched\nconst hdy2=B[jaHd*3+1],hdz2=B[jaHd*3+2];\nlet fsgn2=1,fmx2=0;\nfor(let i=0;i<nv;i++){const dy=P[i*3+1]-hdy2;if(dy>0&&dy<.14*H){const dz=P[i*3+2]-hdz2;\nif(Math.abs(dz)>fmx2){fmx2=Math.abs(dz);fsgn2=Math.sign(dz)||1}}}\nlet fig=0;// figure canon now BAKED into the NXA by nx_nxa_morph; JS morph kept only for A/B\nfunction applyFigure(){P.set(P0);\nif(fig){for(let i=0;i<nv;i++){const x=P[i*3],y=P[i*3+1];const z=P[i*3+2];\nconst y01=(y+H/2)/H;\nconst gh=Math.exp(-((y01-.47)*(y01-.47))/(2*.075*.075));\nconst gw=Math.exp(-((y01-.585)*(y01-.585))/(2*.035*.035));\nconst s=(1+.13*gh)*(1-.045*gw);\nlet nx2=x*s,nz2=z*s;\nconst gb=Math.exp(-((y01-.685)*(y01-.685))/(2*.042*.042));\nconst fr2=Math.min(1,Math.max(0,(z*fsgn2)/(.05*H)));\nif(gb>.03&&Math.abs(x)<.15*H&&fr2>0){\nconst z0=.005*H*fsgn2;\nnx2=nx2*(1+.06*gb*fr2);\nnz2=z0+(nz2-z0)*(1+.17*gb*fr2)}\nP[i*3]=nx2;P[i*3+2]=nz2}}\ncalcN();calcS2();\ng.bindBuffer(g.ARRAY_BUFFER,bP);g.bufferData(g.ARRAY_BUFFER,P,g.STATIC_DRAW);\ng.bindBuffer(g.ARRAY_BUFFER,bN);g.bufferData(g.ARRAY_BUFFER,N,g.STATIC_DRAW);\ng.bindBuffer(g.ARRAY_BUFFER,bS);g.bufferData(g.ARRAY_BUFFER,S2,g.STATIC_DRAW)}\napplyFigure();\nconst j1o=[0,0,0],j1v=[0,0,0],j2o=[0,0,0],j2v=[0,0,0],j1oR=[0,0,0],j1vR=[0,0,0];\n// drive gain is CALIBRATED, not chosen: published walking-gait breast displacement is\n// ~4.2cm resultant relative to the trunk, i.e. ~.024 of stature. jpk measures what we\n// actually produce so the gain can be set against that ruler instead of by eye.\nlet jpk=0;const JTGT=.024;\n// measured peak on this clip at unit gain .85 was .00089 stature, so the gain that lands\n// on the published .024 walking figure is .85*(.024/.00089) = 22.9. Calibrated, not picked.\nconst JGAIN=22.9;\nconst pcC=[0,0,0],pcC1=[0,0,0],pcC2=[0,0,0],pcH=[0,0,0],pcH1=[0,0,0],pcH2=[0,0,0];\nlet sfr=0;\nconst tmp3=[0,0,0],tA=[0,0,0],tB=[0,0,0];\n// HAIR v2: scalp-wide roots (face side excluded), layered lengths (nape long, crown\n// short), calm damped verlet, drawn as camera-facing tapered RIBBONS, not wires\nconst hdx=B[jaHd*3],hdy=B[jaHd*3+1],hdz=B[jaHd*3+2];\nlet fsgn=1,fmx=0;\nfor(let i=0;i<nv;i++){const dy=P[i*3+1]-hdy;if(dy>0&&dy<.14*H){const dz=P[i*3+2]-hdz;\nif(Math.abs(dz)>fmx){fmx=Math.abs(dz);fsgn=Math.sign(dz)||1}}}\n// hair source: HSTR = REAL groom strands (USC-HairSalon ingest, 8 pts/strand, mesh space)\n// -> display space; fallback = procedural scalp roots. hrs = rest positions rel head bind\n// (style retention target); hRL = per-segment rest lengths (the groom's shape).\nlet HS=0;const HN=7;\nlet hp,hq,hro,hph,hsh,hRL,hrs;\nif(ho>=0){\nHS=Number(w(ho));if(HS>2600)HS=2600;\nhp=new Float32Array(HS*(HN+1)*3);hq=new Float32Array(HS*(HN+1)*3);hro=new Float32Array(HS*3);\nhph=new Float32Array(HS);hsh=new Float32Array(HS);hRL=new Float32Array(HS*HN);hrs=new Float32Array(HS*(HN+1)*3);\nfor(let s=0;s<HS;s++){\nhph[s]=(s*2.399)%6.283;hsh[s]=.72+.42*((s*.618)%1);\nfor(let k=0;k<=HN;k++){const wb=ho+8+(s*24+k*3)*8;\nconst sx=[w(wb)/1000,w(wb+8)/1000,w(wb+16)/1000];\nconst px2=sx[lat]-c0,py2=sx[up]-c1,pz2=sx[oth]-c2;\nconst b=(s*(HN+1)+k)*3;\nhp[b]=px2;hp[b+1]=py2;hp[b+2]=pz2;hq[b]=px2;hq[b+1]=py2;hq[b+2]=pz2;\nhrs[b]=px2-B[jaHd*3];hrs[b+1]=py2-B[jaHd*3+1];hrs[b+2]=pz2-B[jaHd*3+2];\nif(k===0){hro[s*3]=hrs[b];hro[s*3+1]=hrs[b+1];hro[s*3+2]=hrs[b+2]}\nif(k>0){const a2=(s*(HN+1)+k-1)*3;\nhRL[s*HN+k-1]=Math.max(.0005*H,Math.hypot(hp[b]-hp[a2],hp[b+1]-hp[a2+1],hp[b+2]-hp[a2+2]))}}}\n}else{\nconst hcand=[];\nfor(let i=0;i<nv;i++){const dx=P[i*3]-hdx,dy=P[i*3+1]-hdy,dz=P[i*3+2]-hdz;\nconst rr=Math.hypot(dx,dy,dz);\nif(dy>.015*H&&rr<.115*H&&dz*fsgn<.035*H)hcand.push(i)}\nconst hroots=[];\nconst hstep=Math.max(1,hcand.length/230);\nfor(let f2=0;f2<hcand.length&&hroots.length<230;f2+=hstep)hroots.push(hcand[Math.floor(f2)]);\nHS=hroots.length;\nhp=new Float32Array(HS*(HN+1)*3);hq=new Float32Array(HS*(HN+1)*3);hro=new Float32Array(HS*3);\nhph=new Float32Array(HS);hsh=new Float32Array(HS);hRL=new Float32Array(HS*HN);hrs=new Float32Array(HS*(HN+1)*3);\nfor(let s=0;s<HS;s++){const r=hroots[s];\nhro[s*3]=P[r*3]-hdx;hro[s*3+1]=P[r*3+1]-hdy;hro[s*3+2]=P[r*3+2]-hdz;\nhph[s]=(s*2.399)%6.283;\nhsh[s]=.72+.42*((s*.618)%1);\nconst back=Math.max(0,-(P[r*3+2]-hdz)*fsgn)/(.115*H);\nconst low=Math.max(0,(.09*H-(P[r*3+1]-hdy))/(.09*H));\nconst hLs=(.010+.012*(back*.6+low*.6)+.003*((s*.377)%1))*H;\nfor(let k=0;k<=HN;k++){const b=(s*(HN+1)+k)*3;\nhp[b]=P[r*3];hp[b+1]=P[r*3+1]-hLs*k;hp[b+2]=P[r*3+2];hq[b]=hp[b];hq[b+1]=hp[b+1];hq[b+2]=hp[b+2];\nhrs[b]=hp[b]-hdx;hrs[b+1]=hp[b+1]-hdy;hrs[b+2]=hp[b+2]-hdz;\nif(k>0)hRL[s*HN+k-1]=hLs}}\n}\n// DENSIFICATION (perf law: CPU sims ONLY guides): guide nodes go to a texture; the hair\n// shader instances M interpolated locks per guide. M by device class + adaptive fps LOD.\nconst GTW=128;const GTH=Math.ceil(HS*(HN+1)/GTW)||1;\nconst gtex=new Float32Array(GTW*GTH*4);\nconst isMob=/Mobi|Android/i.test(navigator.userAgent)||Math.min(screen.width,screen.height)<820;\nlet HM=isMob?6:16;\n// ?hm=N pins density so headless/CI shots measure the SHIPPED look, not the LOD floor\nconst hmQ=+(new URLSearchParams(location.search).get(\"hm\")||0);\nlet hmPin=0;if(hmQ>0){HM=hmQ;hmPin=1}\n// FIBER WIDTH from trichology, not taste: human hair is 17-181um (mean ~70um). Our ribbon\n// was ~5.9mm -- 80x too thick, which is what reads as a helmet before shading matters.\n// Production renderers keep ribbons sub-mm and reconstruct thinness with coverage alpha.\nconst HFIB=.00020*H;const HWD=HFIB*.5;\n// MELANIN -> absorption (pbrt/Chiang): sigma_a = eu*[.419,.697,1.37] + ph*[.187,.4,1.05];\n// eu 0.3 blonde, 1.3 brown, 8 black. Colour is DERIVED from concentration, never picked.\nconst HEU=.55,HPH=.28;\nconst HSA=[HEU*.419+HPH*.187,HEU*.697+HPH*.4,HEU*1.37+HPH*1.05];\nconst HCOL=[Math.exp(-HSA[0]),Math.exp(-HSA[1]),Math.exp(-HSA[2])];\n// ankles = deepest descendant of each knee (calf capsules vs hem clip)\nfunction deepDesc(j){let best=j,by=B[j*3+1];const st=[j];\nwhile(st.length){const q=st.pop();for(const c2 of kids[q]){if(B[c2*3+1]<by){by=B[c2*3+1];best=c2}st.push(c2)}}return best}\nconst akL=knL>=0?deepDesc(knL):-1,akR=knR>=0?deepDesc(knR):-1;\n" as *u8) 55 p = nre_ap(out, p, "// MEASURED collider radii (no hand constants): analytic proxies are INSCRIBED safety cores\n// derived from the real body verts; the skinned surface constraint supplies accuracy.\n// arms lie inside the chest band in a T-pose bind -- exclude them BY SKIN WEIGHT, not by guess\nconst armSet=new Uint8Array(nj);\nfunction markSub(j5){if(j5<0)return;const sk=[j5];while(sk.length){const q5=sk.pop();armSet[q5]=1;for(const c5 of kids[q5])sk.push(c5)}}\nmarkSub(shL);markSub(shR);\nfunction domJ(i5){const o5=i5*4;let bj=J4[o5]|0,bw2=W4[o5];\nfor(let s5=1;s5<4;s5++){if(W4[o5+s5]>bw2){bw2=W4[o5+s5];bj=J4[o5+s5]|0}}return bj}\nfunction bandR(cx,cy,cz,bw,pc){const ds=[];\nfor(let i5=0;i5<nv;i5++){if(Math.abs(P[i5*3+1]-cy)>bw)continue;\nif(armSet[domJ(i5)])continue;\nds.push(Math.hypot(P[i5*3]-cx,P[i5*3+2]-cz))}\nif(!ds.length)return .06*H;ds.sort((a,b)=>a-b);return ds[Math.floor(ds.length*pc)]||.06*H}\nfunction axisR(a5,b5,t0,t1,pc){if(a5<0||b5<0)return .05*H;\nconst ax=B[b5*3]-B[a5*3],ay=B[b5*3+1]-B[a5*3+1],az=B[b5*3+2]-B[a5*3+2];\nconst dn=ax*ax+ay*ay+az*az||1;const ds=[];\nfor(let i5=0;i5<nv;i5++){const rx=P[i5*3]-B[a5*3],ry=P[i5*3+1]-B[a5*3+1],rz=P[i5*3+2]-B[a5*3+2];\nconst t5=(rx*ax+ry*ay+rz*az)/dn;if(t5<t0||t5>t1)continue;\nds.push(Math.hypot(rx-ax*t5,ry-ay*t5,rz-az*t5))}\nif(!ds.length)return .05*H;ds.sort((a,b)=>a-b);return ds[Math.floor(ds.length*pc)]||.05*H}\nconst mcy=jaC>=0?B[jaC*3+1]-.02*H:.1*H,mhy=jaH>=0?B[jaH*3+1]-.02*H:-.05*H;\nconst mcx=jaC>=0?B[jaC*3]:0,mcz=jaC>=0?B[jaC*3+2]:0,mhx=jaH>=0?B[jaH*3]:0,mhz=jaH>=0?B[jaH*3+2]:0;\nconst RC=bandR(mcx,mcy,mcz,.035*H,.25),RH=bandR(mhx,mhy,mhz,.035*H,.25);\nconst RW=bandR((mcx+mhx)/2,(mcy+mhy)/2,(mcz+mhz)/2,.035*H,.25);\nconst RTL=axisR(thL,knL,.15,.40,.30),RTL2=axisR(thL,knL,.60,.85,.30);\nconst RTR=axisR(thR,knR,.15,.40,.30),RTR2=axisR(thR,knR,.60,.85,.30);\nconst RKL=axisR(knL,akL,.15,.40,.30),RKL2=axisR(knL,akL,.60,.85,.30);\nconst RKR=axisR(knR,akR,.15,.40,.30),RKR2=axisR(knR,akR,.60,.85,.30);\nst.setAttribute(\"data-r\",[RC/H,RW/H,RH/H,RTL/H,RTL2/H,RKL/H,RKL2/H].map(v2=>v2.toFixed(4)).join(\",\"));\nlet pyl=1e18,pyh=-1e18;for(let i5=0;i5<nv;i5++){const y5=P[i5*3+1];if(y5<pyl)pyl=y5;if(y5>pyh)pyh=y5}\nlet nbC=0;for(let i5=0;i5<nv;i5++)if(Math.abs(P[i5*3+1]-mcy)<=.035*H)nbC++;\nst.setAttribute(\"data-d\",[pyl/H,pyh/H,mcy/H,mhy/H,mcx/H,mcz/H,nbC].map(v2=>(+v2).toFixed(4)).join(\",\"));\n" as *u8) 56 p = nre_ap(out, p, "// GARMENT: prefer the FITTED mesh from the file (GVRT/GTRI/GPIN, measured per-row body\n// fit); fallback = procedural ring grid. Sim below = GENERAL edge-list XPBD from the\n// triangles -- the same machinery any ingested (GarmentCode) garment will use.\nlet NCV=0,cp,cq2,CI;const cpin=[];let cpro;\nif(go>=0&&gt2>=0){\nNCV=Number(w(go));\ncp=new Float32Array(NCV*3);cq2=new Float32Array(NCV*3);cpro=new Float32Array(NCV*3);\nfor(let i=0;i<NCV;i++){const wb=go+8+i*24;\nconst sx=[w(wb)/1000,w(wb+8)/1000,w(wb+16)/1000];\ncp[i*3]=sx[lat]-c0;cp[i*3+1]=sx[up]-c1;cp[i*3+2]=sx[oth]-c2;\ncq2[i*3]=cp[i*3];cq2[i*3+1]=cp[i*3+1];cq2[i*3+2]=cp[i*3+2]}\nconst ngt=Number(w(gt2));\nCI=new Uint16Array(ngt*3);\nfor(let i=0;i<ngt*3;i++)CI[i]=Number(w(gt2+8+i*8));\nif(gp2>=0){const np2=Number(w(gp2));\nfor(let i=0;i<np2;i++){const vi2=Number(w(gp2+8+i*8));\ncpin.push(vi2);\ncpro[vi2*3]=cp[vi2*3]-B[jaC*3];cpro[vi2*3+1]=cp[vi2*3+1]-B[jaC*3+1];cpro[vi2*3+2]=cp[vi2*3+2]-B[jaC*3+2]}}\n}else{\nconst CU=30,CV=9,CDY=.033*H,CRX=.094*H,CRZ=.074*H,CY0=-.055*H;\nNCV=CU*CV;\ncp=new Float32Array(NCV*3);cq2=new Float32Array(NCV*3);cpro=new Float32Array(NCV*3);\nconst cfl=v=>1+.5*Math.pow(v/CV,1.2);\nfor(let u=0;u<CU;u++){const th=u/CU*6.2832;\nconst ox=Math.cos(th)*CRX,oz=Math.sin(th)*CRZ;\nfor(let v=0;v<CV;v++){const b=(v*CU+u)*3;const fl=cfl(v);\ncp[b]=ox*fl+B[jaC*3];cp[b+1]=CY0-CDY*v+B[jaC*3+1];cp[b+2]=oz*fl+B[jaC*3+2];\ncq2[b]=cp[b];cq2[b+1]=cp[b+1];cq2[b+2]=cp[b+2]}}\nconst cidx=[];\nfor(let v=0;v<CV-1;v++)for(let u=0;u<CU;u++){const a=v*CU+u,b2=v*CU+(u+1)%CU,c3=(v+1)*CU+u,d=(v+1)*CU+(u+1)%CU;\ncidx.push(a,c3,b2,b2,c3,d)}\nCI=new Uint16Array(cidx);\nfor(let u=0;u<CU;u++){cpin.push(u);\ncpro[u*3]=cp[u*3]-B[jaC*3];cpro[u*3+1]=cp[u*3+1]-B[jaC*3+1];cpro[u*3+2]=cp[u*3+2]-B[jaC*3+2]}\n}\nconst cnrm=new Float32Array(NCV*3);\nconst cpinned=new Uint8Array(NCV);\nfor(const pv of cpin)cpinned[pv]=1;\nconst eset=new Set();const ced=[];\nfor(let i=0;i<CI.length;i+=3){\nconst tvs=[CI[i],CI[i+1],CI[i+2]];\nfor(let e=0;e<3;e++){let a=tvs[e],b2=tvs[(e+1)%3];\nif(a>b2){const t9=a;a=b2;b2=t9}\nconst key=a*65536+b2;\nif(!eset.has(key)){eset.add(key);\nconst rl=Math.hypot(cp[a*3]-cp[b2*3],cp[a*3+1]-cp[b2*3+1],cp[a*3+2]-cp[b2*3+2]);\nced.push(a,b2,rl)}}}\n" as *u8) 57 p = nre_ap(out, p, "// BODY SAMPLE CLOUD -- one truth layer for cloth collision. Stride-sampled body verts are\n// skinned per frame into a spatial hash; cloth pushes out of the NEAREST sample sphere.\n// Analytic proxies are gone: a fat proxy IS standoff (measured hip proxy was 2.1x too fat).\nconst BSTR=3;const NBS=Math.floor(nv/BSTR);\nconst bsi=new Int32Array(NBS);for(let i=0;i<NBS;i++)bsi[i]=i*BSTR;\nconst bsx=new Float32Array(NBS*3);const bsn=new Float32Array(NBS*3);\n// OUTWARD sign is DERIVED, never assumed: a surface vert lies outside its own dominant\n// bone, so sign(N . (P - B[domJoint])) tells us which way is out, per sample.\nconst bsf=new Float32Array(NBS);let nflip=0;\nfor(let i=0;i<NBS;i++){const v5=bsi[i];const j6=domJ(v5);\nconst ox=P[v5*3]-B[j6*3],oy=P[v5*3+1]-B[j6*3+1],oz=P[v5*3+2]-B[j6*3+2];\nconst sg=N[v5*3]*ox+N[v5*3+1]*oy+N[v5*3+2]*oz;\nbsf[i]=sg>=0?1:-1;if(sg<0)nflip++}\n// a mesh has ONE winding: take the majority vote globally so concave pockets (armpit,\n// crotch, joint interiors) cannot vote a wrong sign for their own samples.\nconst GSGN=(nflip*2>NBS)?-1:1;bsf.fill(GSGN);\nst.setAttribute(\"data-nf\",nflip+\"/\"+NBS+\"/\"+GSGN);\nconst BRAD=.006*H;const SRCH=.030*H;const SR2=SRCH*SRCH;const CSZ=SRCH;const bgrid=new Map();\nconst CFRIC=.40;\n" as *u8) 58 p = nre_ap(out, p, "// BEND constraints (2-ring, opposite verts across each interior edge). Distance-only cloth\n// is BENDING-FREE, so it seeks the smoothest surface = a cone. With bending + pattern ease,\n// surplus fabric BUCKLES into discrete folds instead of absorbing as smooth curvature.\nconst opp=new Map();const cbd=[];\nfor(let i=0;i<CI.length;i+=3){const tv=[CI[i],CI[i+1],CI[i+2]];\nfor(let e=0;e<3;e++){let a=tv[e],b2=tv[(e+1)%3];const o2=tv[(e+2)%3];\nif(a>b2){const t9=a;a=b2;b2=t9}\nconst key=a*65536+b2;\nif(opp.has(key)){const p2=opp.get(key);\nconst rl=Math.hypot(cp[p2*3]-cp[o2*3],cp[p2*3+1]-cp[o2*3+1],cp[p2*3+2]-cp[o2*3+2]);\ncbd.push(p2,o2,rl)}else opp.set(key,o2)}}\n" as *u8) 59 p = nre_ap(out, p, "const VA=`#version 300 es\nin vec3 aP;in vec3 aN;uniform vec2 uR;uniform vec2 uY;uniform vec2 uP;uniform float uS;out vec3 vN;\nvoid main(){vec3 p=aP;float xr=p.x*uY.x+p.z*uY.y;float zr=-p.x*uY.y+p.z*uY.x;\nvec3 v=vec3(xr,p.y,zr)*uS;\nv=vec3(v.x,v.y*uP.x-v.z*uP.y,v.y*uP.y+v.z*uP.x);\nvN=vec3(aN.x*uY.x+aN.z*uY.y,aN.y,-aN.x*uY.y+aN.z*uY.x);\nvec3 e=vec3(v.x,v.y,v.z-2.3);\ngl_Position=vec4(e.x*1.6*uR.y/uR.x,e.y*1.6,-2.7647*e.z-5.647,-e.z);}`;\nconst FA=`#version 300 es\nprecision highp float;in vec3 vN;uniform vec3 uC;uniform float uLit;out vec4 fc;\nvoid main(){float d=1.;\nif(uLit>.5){vec3 n=normalize(vN);vec3 L=normalize(vec3(-.45,.75,.55));d=.35+.65*abs(dot(n,L));}\nelse if(uLit<-.5){d=clamp(vN.x,.45,1.4);}\nfc=vec4(uC*d,1.);}`;\nconst pr2=g.createProgram();g.attachShader(pr2,cs(g.VERTEX_SHADER,VA));g.attachShader(pr2,cs(g.FRAGMENT_SHADER,FA));\ng.bindAttribLocation(pr2,0,\"aP\");g.bindAttribLocation(pr2,1,\"aN\");\ng.linkProgram(pr2);if(!g.getProgramParameter(pr2,g.LINK_STATUS))throw g.getProgramInfoLog(pr2);\nconst L3=n=>g.getUniformLocation(pr2,n);\nconst cbuf=g.createBuffer(),cnbuf=g.createBuffer(),cibuf=g.createBuffer();\nconst VH=`#version 300 es\nuniform sampler2D uGT;uniform vec2 uR;uniform vec2 uY;uniform vec2 uP;uniform float uS;uniform int uM;uniform float uH;uniform float uWd;\nout float vSh;out float vT;out float vU;out float vA;\nvec3 node(int g2,int n){int idx=g2*8+n;return texelFetch(uGT,ivec2(idx%128,idx/128),0).xyz;}\nfloat hsh2(float n){return fract(sin(n)*43758.5453);}\nvoid main(){\nint nid=gl_VertexID>>1;int side=gl_VertexID&1;\nint g2=gl_InstanceID/uM;int sub=gl_InstanceID-g2*uM;\nvec3 p=node(g2,nid);\nvec3 p2=node(g2,min(nid+1,7));vec3 p0=node(g2,max(nid-1,0));\n// per-strand length spread + a hashed flyaway minority: a uniform strand set reads as a wig\nfloat hl=hsh2(float(g2)*5.77+float(sub)*1.93);\nfloat lenS=.86+.28*hl;\nfloat fly=step(.972,hsh2(float(g2)*3.31+float(sub)*7.19));\nvec3 root=node(g2,0);\np=root+(p-root)*lenS;\nvec3 dirn=normalize(p2-p0+vec3(1e-5));\nfloat t=float(nid)/7.;vT=t;\nfloat h1=hsh2(float(g2)*7.13+float(sub)*3.71)-.5;\nfloat h2=hsh2(float(g2)*2.17+float(sub)*9.31)-.5;\nvec3 lat2=normalize(cross(dirn,vec3(0.,1.,0.))+vec3(1e-4));\nvec3 bin=normalize(cross(dirn,lat2)+vec3(1e-4));\np+=(lat2*h1+bin*h2)*.014*uH*(1.+.7*t)*(sub>0?1.:0.);\np+=(lat2*h2-bin*h1)*fly*.055*uH*t*t;\nvec3 vd=vec3(-uY.y,0.,uY.x);\nvec3 wdir=normalize(cross(dirn,vd)+vec3(1e-4));\n// ANALYTIC COVERAGE: a real fiber is far thinner than a pixel, so a literal-width ribbon\n// simply misses the sample and vanishes. Widen to ~1px and pay for it in alpha instead.\nfloat hw=uWd*(1.-t*.90);\nfloat pxh=hw*uS*.8*uR.y/2.3;\nfloat wsc=max(1.,.5/max(pxh,1e-6));\nvA=1./wsc;\np+=wdir*(float(side)-.5)*2.*hw*wsc;\nvU=float(side);\nvSh=.62+.55*hsh2(float(g2)*1.31+float(sub)*.77);\nfloat xr=p.x*uY.x+p.z*uY.y;float zr=-p.x*uY.y+p.z*uY.x;\nvec3 v=vec3(xr,p.y,zr)*uS;\nv=vec3(v.x,v.y*uP.x-v.z*uP.y,v.y*uP.y+v.z*uP.x);\nvec3 e=vec3(v.x,v.y,v.z-2.3);\ngl_Position=vec4(e.x*1.6*uR.y/uR.x,e.y*1.6,-2.7647*e.z-5.647,-e.z);}`;\n" as *u8) 60 p = nre_ap(out, p, "const FH=`#version 300 es\nprecision highp float;in float vSh;in float vT;in float vU;in float vA;uniform vec3 uC;out vec4 fc;\nvoid main(){float cu=vU*2.-1.;float a=clamp((1.-cu*cu)*1.6,0.,1.)*vA;\nfc=vec4(uC*vSh*(.72+.42*vT),a);}`;\nconst prH=g.createProgram();g.attachShader(prH,cs(g.VERTEX_SHADER,VH));g.attachShader(prH,cs(g.FRAGMENT_SHADER,FH));\ng.linkProgram(prH);if(!g.getProgramParameter(prH,g.LINK_STATUS))throw g.getProgramInfoLog(prH);\nconst L4=n=>g.getUniformLocation(prH,n);\nconst ght=g.createTexture();g.activeTexture(g.TEXTURE1);g.bindTexture(g.TEXTURE_2D,ght);\ng.texStorage2D(g.TEXTURE_2D,1,g.RGBA32F,GTW,GTH);\ng.texParameteri(g.TEXTURE_2D,g.TEXTURE_MIN_FILTER,g.NEAREST);g.texParameteri(g.TEXTURE_2D,g.TEXTURE_MAG_FILTER,g.NEAREST);\ng.activeTexture(g.TEXTURE0);\nconst vaoE=g.createVertexArray();\nconst vaoC=g.createVertexArray();g.bindVertexArray(vaoC);\ng.bindBuffer(g.ARRAY_BUFFER,cbuf);g.bufferData(g.ARRAY_BUFFER,cp,g.DYNAMIC_DRAW);\ng.enableVertexAttribArray(0);g.vertexAttribPointer(0,3,g.FLOAT,false,0,0);\ng.bindBuffer(g.ARRAY_BUFFER,cnbuf);g.bufferData(g.ARRAY_BUFFER,cnrm,g.DYNAMIC_DRAW);\ng.enableVertexAttribArray(1);g.vertexAttribPointer(1,3,g.FLOAT,false,0,0);\ng.bindBuffer(g.ELEMENT_ARRAY_BUFFER,cibuf);g.bufferData(g.ELEMENT_ARRAY_BUFFER,CI,g.STATIC_DRAW);\ng.bindVertexArray(null);\n" as *u8) 61 p = nre_ap(out, p, "// inspection UI: Natural/Clothed, wind level, pause -- review everything before craft\nlet mode=1,windL=1,paused=0;\nconst ui=document.getElementById(\"ui\");\nfunction mkbtn(txt,fn){const b=document.createElement(\"button\");b.textContent=txt;\nb.style.cssText=\"background:#171226;color:#b9b1dc;border:1px solid #2f2a4a;border-radius:4px;font:600 11px ui-monospace,monospace;padding:6px 12px;cursor:pointer\";\nb.addEventListener(\"click\",()=>fn(b));ui.appendChild(b);return b}\nmkbtn(\"clothed\",b=>{mode=1-mode;b.textContent=mode?\"clothed\":\"natural\"});\nmkbtn(\"figure: canon\",b=>{fig=1-fig;applyFigure();b.textContent=fig?\"figure: +JS(A/B)\":\"figure: canon\"});\nconst WNm=[\"calm\",\"breeze\",\"windy\"],WVv=[.2,1,2.3];\nmkbtn(\"wind: breeze\",b=>{windL=(windL+1)%3;b.textContent=\"wind: \"+WNm[windL]});\nmkbtn(\"pause\",b=>{paused=1-paused;b.textContent=paused?\"play\":\"pause\"});\nlet fcnt=0,ph=0,tAnim=0,tp=performance.now();\nwindow.__nxa={ok:1,nv:nv,nt:nt,nj:nj,gait_joints:found,soft:2,hair:HS,cloth:1,mode:1,wind:1,anim:AT?1:0,dur:DUR,fps:0};\nsetInterval(()=>{window.__nxa.fps=fcnt;fcnt=0;\nif(hmPin){}\nelse if(window.__nxa.fps>0&&window.__nxa.fps<40&&HM>3)HM=Math.max(3,HM-3);\nelse if(window.__nxa.fps>55&&HM<(isMob?14:42))HM=Math.min(isMob?14:42,HM+3);\nwindow.__nxa.hm=HM;\nst.setAttribute(\"data-j\",[j1o[0]/H,j1o[1]/H,j1o[2]/H,j1oR[0]/H,j1oR[1]/H,j1oR[2]/H,jpk].map(v3=>v3.toFixed(5)).join(\",\"));\nst.textContent=\"NXA rigged \\u2014 \"+nv+\" verts \\u00b7 \"+nj+\" joints \\u00b7 \"+(AT?\"mocap \"+(DUR/1000).toFixed(1)+\"s\":\"gait \"+found+\"/6\")+\" \\u00b7 \"+(mode?\"clothed \\u00b7 hair \"+(HS*HM):\"natural\")+\" \\u00b7 wind \"+WNm[windL]+\" \\u00b7 \"+window.__nxa.fps+\" fps\"},1000);\nfunction fr(){const now=performance.now();const dt=Math.min(.033,(now-tp)*.001)||.016;tp=now;fcnt++;\nif(!paused){tAnim+=dt*1000;ph+=dt*4}\nif(auto)yaw+=.003;\nif(AT){poseAnim(tAnim%DUR)}else{const S=Math.sin(ph);pose(ph,.010*H*S,.013*H*Math.abs(S))}\njpos(jaC,pcC);jpos(jaH,pcH);\nif(sfr>1){const d2=dt*dt;const hs=dt*.5;\n// SOFT-TISSUE DYNAMICS FROM BIOMECHANICS, NOT TASTE. Measured on walking/running subjects:\n// natural frequency ~4Hz, damping ratio ~0.475, displacement anisotropy vertical:AP:ML =\n// 1 : .62 : .55, and stiffness ASYMMETRIC about rest (~9x stiffer in extension away from\n// the chest wall than pushed toward it). Left and right are INDEPENDENT masses, detuned +-6%\n// -- one shared offset moving both as a unit is exactly what reads as hardwired to the body.\n// Two substeps keep the stiff branch stable under explicit integration.\nconst KB=631,ZT=.475,ANI=[.55,1,.62];\nfor(let sd=0;sd<2;sd++){const jo=sd?j1oR:j1o,jv=sd?j1vR:j1v;const dtu=sd?1.06:.94;\nfor(let ss=0;ss<2;ss++){for(let a=0;a<3;a++){\nconst acC=(pcC[a]-2*pcC1[a]+pcC2[a])/d2;\nlet kk=KB*dtu/ANI[a];\nif(a===1)kk*=(jo[a]<0?3.0:.34);\nconst cc=2*ZT*Math.sqrt(kk);\njv[a]+=(-kk*jo[a]-cc*jv[a]-JGAIN*acC)*hs;\njo[a]+=jv[a]*hs;\njo[a]=Math.max(-.032*H,Math.min(.032*H,jo[a]))}}}\nconst jmg=Math.hypot(j1o[0],j1o[1],j1o[2])/H;if(jmg>jpk)jpk=jmg;\nfor(let a=0;a<3;a++){\nconst acH=(pcH[a]-2*pcH1[a]+pcH2[a])/d2;\nj2v[a]+=(-230*j2o[a]-12*j2v[a]-.6*acH)*dt;\nj2o[a]+=j2v[a]*dt;\nj2o[a]=Math.max(-.024*H,Math.min(.024*H,j2o[a]))}}\nfor(let a=0;a<3;a++){pcC2[a]=pcC1[a];pcC1[a]=pcC[a];pcH2[a]=pcH1[a];pcH1[a]=pcH[a]}\nsfr++;\ng.useProgram(pr);g.bindVertexArray(null);\npackDQ();\ng.bindTexture(g.TEXTURE_2D,jt);g.texSubImage2D(g.TEXTURE_2D,0,0,0,2,128,g.RGBA,g.FLOAT,JMD);\ng.uniform3f(L2(\"uJ1\"),j1o[0],j1o[1],j1o[2]);\ng.uniform3f(L2(\"uJ1R\"),j1oR[0],j1oR[1],j1oR[2]);\ng.uniform3f(L2(\"uJ2\"),j2o[0],j2o[1],j2o[2]);\ng.uniform1f(L2(\"uClo\"),mode);\ng.uniform2f(L2(\"uY\"),Math.cos(yaw),Math.sin(yaw));\ng.uniform2f(L2(\"uP\"),Math.cos(pitch),Math.sin(pitch));\ng.uniform1f(L2(\"uS\"),1.5/H*zoom);\ng.clear(g.COLOR_BUFFER_BIT|g.DEPTH_BUFFER_BIT);\ng.drawElements(g.TRIANGLES,nt*3,g.UNSIGNED_INT,0);\nwindow.__nxa.mode=mode;window.__nxa.wind=windL;\nif(mode){\nconst ts=now*.001;const wb=WVv[windL];\nconst wx=(0.5+0.45*Math.sin(ts*.9))*85*wb,wz=(0.3*Math.sin(ts*.6+1.7))*85*wb;\n" as *u8) 62 p = nre_ap(out, p, "xform(jaHd,B[jaHd*3],B[jaHd*3+1]+.02*H,B[jaHd*3+2],tmp3);\nconst hcx=tmp3[0],hcy=tmp3[1],hcz=tmp3[2],hcr=.068*H;\njpos(jaC,tA);\nconst scx=tA[0],scy=tA[1],scz=tA[2],scr2=.10*H;\n// hair-body colliders: shoulders + neck so draping locks ride the body like flesh does\nconst hcol=[[scx,scy,scz,scr2],[(hcx+scx)/2,(hcy+scy)/2,(hcz+scz)/2,.055*H]];\nif(shL>=0){jpos(shL,tB);hcol.push([tB[0],tB[1],tB[2],.062*H])}\nif(shR>=0){jpos(shR,tB);hcol.push([tB[0],tB[1],tB[2],.062*H])}\nfor(let s=0;s<HS;s++){\nconst rb=s*(HN+1)*3;\nxform(jaHd,B[jaHd*3]+hro[s*3],B[jaHd*3+1]+hro[s*3+1],B[jaHd*3+2]+hro[s*3+2],tmp3);\nhp[rb]=tmp3[0];hp[rb+1]=tmp3[1];hp[rb+2]=tmp3[2];\nconst gws=Math.sin(ts*1.1+hph[s]);\nfor(let k=1;k<=HN;k++){const b=rb+k*3;\nconst nx2=hp[b]+(hp[b]-hq[b])*.945+wx*.5*(1+.3*gws)*dt*dt;\nconst ny2=hp[b+1]+(hp[b+1]-hq[b+1])*.945-900*dt*dt;\nconst nz2=hp[b+2]+(hp[b+2]-hq[b+2])*.945+wz*.5*(1+.3*gws)*dt*dt;\nhq[b]=hp[b];hq[b+1]=hp[b+1];hq[b+2]=hp[b+2];\nhp[b]=nx2;hp[b+1]=ny2;hp[b+2]=nz2}\nfor(let it=0;it<3;it++)for(let k=1;k<=HN;k++){const b=rb+k*3,a2=rb+(k-1)*3;\nconst dx=hp[b]-hp[a2],dy=hp[b+1]-hp[a2+1],dz=hp[b+2]-hp[a2+2];\nconst ln=Math.hypot(dx,dy,dz)||1;const f=hRL[s*HN+k-1]/ln;\nhp[b]=hp[a2]+dx*f;hp[b+1]=hp[a2+1]+dy*f;hp[b+2]=hp[a2+2]+dz*f}\n// style retention: nudge toward the groom's rest shape in the moving head frame (OUR\n// tunable version of what vendor sims hard-bake; tips freer than roots)\nfor(let k=1;k<=HN;k++){const b=rb+k*3;const stw=.14*(1-k/(HN+1));\nxform(jaHd,B[jaHd*3]+hrs[b],B[jaHd*3+1]+hrs[b+1],B[jaHd*3+2]+hrs[b+2],tmp3);\nhp[b]+=(tmp3[0]-hp[b])*stw;hp[b+1]+=(tmp3[1]-hp[b+1])*stw;hp[b+2]+=(tmp3[2]-hp[b+2])*stw}\nfor(let k=1;k<=HN;k++){const b=rb+k*3;\nlet dx=hp[b]-hcx,dy=hp[b+1]-hcy,dz=hp[b+2]-hcz;\nlet dn=Math.hypot(dx,dy,dz);\nif(dn<hcr&&dn>0){const f=hcr/dn;hp[b]=hcx+dx*f;hp[b+1]=hcy+dy*f;hp[b+2]=hcz+dz*f}\nfor(const hc2 of hcol){\ndx=hp[b]-hc2[0];dy=hp[b+1]-hc2[1];dz=hp[b+2]-hc2[2];\ndn=Math.hypot(dx,dy,dz);\nif(dn<hc2[3]&&dn>0){const f=hc2[3]/dn;hp[b]=hc2[0]+dx*f;hp[b+1]=hc2[1]+dy*f;hp[b+2]=hc2[2]+dz*f}}}}\n// pack guide nodes -> texture (the only per-frame hair CPU cost)\nlet gi9=0;\nfor(let s=0;s<HS;s++)for(let k=0;k<=HN;k++){const b=s*(HN+1)*3+k*3;\ngtex[gi9]=hp[b];gtex[gi9+1]=hp[b+1];gtex[gi9+2]=hp[b+2];gi9+=4}\ng.activeTexture(g.TEXTURE1);g.bindTexture(g.TEXTURE_2D,ght);\ng.texSubImage2D(g.TEXTURE_2D,0,0,0,GTW,GTH,g.RGBA,g.FLOAT,gtex);\ng.activeTexture(g.TEXTURE0);\n" as *u8) 63 p = nre_ap(out, p, "// garment sim: pins follow the chest frame; verlet; GENERAL edge constraints; colliders\nfor(const pv of cpin){const b=pv*3;\nxform(jaC,B[jaC*3]+cpro[b],B[jaC*3+1]+cpro[b+1],B[jaC*3+2]+cpro[b+2],tmp3);\ncp[b]=tmp3[0];cp[b+1]=tmp3[1];cp[b+2]=tmp3[2];cq2[b]=cp[b];cq2[b+1]=cp[b+1];cq2[b+2]=cp[b+2]}\nfor(let i9=0;i9<NCV;i9++){if(cpinned[i9])continue;const b=i9*3;\nlet vx9=cp[b]-cq2[b],vy9=cp[b+1]-cq2[b+1],vz9=cp[b+2]-cq2[b+2];\nconst vl9=Math.hypot(vx9,vy9,vz9),vmx=2.2*H*dt;\nif(vl9>vmx){const s9=vmx/vl9;vx9*=s9;vy9*=s9;vz9*=s9}\nconst nx2=cp[b]+vx9*.968+wx*1.1*dt*dt;\nconst ny2=cp[b+1]+vy9*.968-900*dt*dt;\nconst nz2=cp[b+2]+vz9*.968+wz*1.1*dt*dt;\ncq2[b]=cp[b];cq2[b+1]=cp[b+1];cq2[b+2]=cp[b+2];\ncp[b]=nx2;cp[b+1]=ny2;cp[b+2]=nz2}\nfor(let it=0;it<6;it++){\nfor(let e9=0;e9<ced.length;e9+=3){\nconst a9=ced[e9],b9=ced[e9+1],rl=ced[e9+2];\nconst a2=a9*3,b=b9*3;\nconst dx=cp[b]-cp[a2],dy=cp[b+1]-cp[a2+1],dz=cp[b+2]-cp[a2+2];\nconst ln=Math.hypot(dx,dy,dz)||1;const df=(ln-rl)/ln;\nconst pa=cpinned[a9],pb=cpinned[b9];\nif(pa&&pb)continue;\nif(pa){cp[b]-=dx*df;cp[b+1]-=dy*df;cp[b+2]-=dz*df}\nelse if(pb){cp[a2]+=dx*df;cp[a2+1]+=dy*df;cp[a2+2]+=dz*df}\nelse{const hf=df*.5;\ncp[a2]+=dx*hf;cp[a2+1]+=dy*hf;cp[a2+2]+=dz*hf;\ncp[b]-=dx*hf;cp[b+1]-=dy*hf;cp[b+2]-=dz*hf}}\nfor(let e9=0;e9<cbd.length;e9+=3){\nconst a9=cbd[e9],b9=cbd[e9+1],rl=cbd[e9+2];\nconst a2=a9*3,b=b9*3;\nconst dx=cp[b]-cp[a2],dy=cp[b+1]-cp[a2+1],dz=cp[b+2]-cp[a2+2];\nconst ln=Math.hypot(dx,dy,dz)||1;const df=(ln-rl)/ln*.035;\nconst pa=cpinned[a9],pb=cpinned[b9];\nif(pa&&pb)continue;\nif(pa){cp[b]-=dx*df;cp[b+1]-=dy*df;cp[b+2]-=dz*df}\nelse if(pb){cp[a2]+=dx*df;cp[a2+1]+=dy*df;cp[a2+2]+=dz*df}\nelse{const hf=df*.5;\ncp[a2]+=dx*hf;cp[a2+1]+=dy*hf;cp[a2+2]+=dz*hf;\ncp[b]-=dx*hf;cp[b+1]-=dy*hf;cp[b+2]-=dz*hf}}}\n" as *u8) 64 p = nre_ap(out, p, "// BODY SAMPLE-CLOUD collision -- ONE truth layer for chest/waist/hips/legs: stride-3\n// body verts CPU-skinned into a spatial hash; each cloth vert pushes out of its NEAREST\n// sample sphere. cp AND cq2 move together (no velocity injection). __nxa.clip = contacts.\nbgrid.clear();\nfor(let s9=0;s9<NBS;s9++){const bv=bsi[s9];const o4=bv*4;\nconst bx5=P[bv*3],by5=P[bv*3+1],bz5=P[bv*3+2];\nconst nb5=N[bv*3],nb6=N[bv*3+1],nb7=N[bv*3+2];\nlet px3=0,py3=0,pz3=0,nx4=0,ny4=0,nz4=0;\nfor(let s3=0;s3<4;s3++){const j5=J4[o4+s3]|0;const w5=W4[o4+s3];if(w5===0)continue;\nconst o5=j5*16;\npx3+=w5*(JM[o5]*bx5+JM[o5+4]*by5+JM[o5+8]*bz5+JM[o5+12]);\npy3+=w5*(JM[o5+1]*bx5+JM[o5+5]*by5+JM[o5+9]*bz5+JM[o5+13]);\npz3+=w5*(JM[o5+2]*bx5+JM[o5+6]*by5+JM[o5+10]*bz5+JM[o5+14]);\nnx4+=w5*(JM[o5]*nb5+JM[o5+4]*nb6+JM[o5+8]*nb7);\nny4+=w5*(JM[o5+1]*nb5+JM[o5+5]*nb6+JM[o5+9]*nb7);\nnz4+=w5*(JM[o5+2]*nb5+JM[o5+6]*nb6+JM[o5+10]*nb7)}\nbsx[s9*3]=px3;bsx[s9*3+1]=py3;bsx[s9*3+2]=pz3;\nconst nl8=(Math.hypot(nx4,ny4,nz4)||1)/bsf[s9];\nbsn[s9*3]=nx4/nl8;bsn[s9*3+1]=ny4/nl8;bsn[s9*3+2]=nz4/nl8;\nconst k9=(Math.floor(px3/CSZ)+512)+((Math.floor(py3/CSZ)+512)<<10)+((Math.floor(pz3/CSZ)+512)*1048576);\nlet a8=bgrid.get(k9);if(!a8){a8=[];bgrid.set(k9,a8)}a8.push(s9)}\nlet clipN=0;\nfor(let i9=0;i9<NCV;i9++){if(cpinned[i9])continue;const b=i9*3;\nconst gx=Math.floor(cp[b]/CSZ),gy=Math.floor(cp[b+1]/CSZ),gz=Math.floor(cp[b+2]/CSZ);\nlet bd9=1e18,bs9=-1;\nfor(let ox=-1;ox<2;ox++)for(let oy=-1;oy<2;oy++)for(let oz=-1;oz<2;oz++){\nconst a8=bgrid.get((gx+ox+512)+((gy+oy+512)<<10)+((gz+oz+512)*1048576));if(!a8)continue;\nfor(const s9 of a8){const dx=cp[b]-bsx[s9*3],dy=cp[b+1]-bsx[s9*3+1],dz=cp[b+2]-bsx[s9*3+2];\nconst dd=dx*dx+dy*dy+dz*dz;if(dd<bd9){bd9=dd;bs9=s9}}}\nif(bs9<0||bd9>SR2)continue;\nconst ux=bsn[bs9*3],uy=bsn[bs9*3+1],uz=bsn[bs9*3+2];\nconst sd=(cp[b]-bsx[bs9*3])*ux+(cp[b+1]-bsx[bs9*3+1])*uy+(cp[b+2]-bsx[bs9*3+2])*uz;\nif(sd<BRAD){clipN++;\nconst push=BRAD-sd;\ncp[b]+=ux*push;cp[b+1]+=uy*push;cp[b+2]+=uz*push;\ncq2[b]+=ux*push;cq2[b+1]+=uy*push;cq2[b+2]+=uz*push;\nconst vx8=cp[b]-cq2[b],vy8=cp[b+1]-cq2[b+1],vz8=cp[b+2]-cq2[b+2];\nconst vn8=vx8*ux+vy8*uy+vz8*uz;\ncq2[b]+=(vx8-vn8*ux)*CFRIC;cq2[b+1]+=(vy8-vn8*uy)*CFRIC;cq2[b+2]+=(vz8-vn8*uz)*CFRIC}}\nwindow.__nxa.clip=clipN;\n" as *u8) 65 p = nre_ap(out, p, "cnrm.fill(0);\nfor(let i2=0;i2<CI.length;i2+=3){const a2=CI[i2]*3,b2=CI[i2+1]*3,c3=CI[i2+2]*3;\nconst e1x=cp[b2]-cp[a2],e1y=cp[b2+1]-cp[a2+1],e1z=cp[b2+2]-cp[a2+2];\nconst e2x=cp[c3]-cp[a2],e2y=cp[c3+1]-cp[a2+1],e2z=cp[c3+2]-cp[a2+2];\nconst nx3=e1y*e2z-e1z*e2y,ny3=e1z*e2x-e1x*e2z,nz3=e1x*e2y-e1y*e2x;\ncnrm[a2]+=nx3;cnrm[a2+1]+=ny3;cnrm[a2+2]+=nz3;cnrm[b2]+=nx3;cnrm[b2+1]+=ny3;cnrm[b2+2]+=nz3;cnrm[c3]+=nx3;cnrm[c3+1]+=ny3;cnrm[c3+2]+=nz3}\ng.useProgram(prH);\ng.uniform2f(L4(\"uR\"),cv.width,cv.height);g.uniform2f(L4(\"uY\"),Math.cos(yaw),Math.sin(yaw));g.uniform2f(L4(\"uP\"),Math.cos(pitch),Math.sin(pitch));g.uniform1f(L4(\"uS\"),1.5/H*zoom);g.uniform1f(L4(\"uH\"),H);g.uniform1i(L4(\"uGT\"),1);g.uniform1i(L4(\"uM\"),HM);g.uniform1f(L4(\"uWd\"),HWD*Math.sqrt(16/HM));\ng.uniform3f(L4(\"uC\"),HCOL[0],HCOL[1],HCOL[2]);\ng.bindVertexArray(vaoE);\ng.enable(g.BLEND);g.blendFunc(g.SRC_ALPHA,g.ONE_MINUS_SRC_ALPHA);g.depthMask(false);\ng.drawArraysInstanced(g.TRIANGLE_STRIP,0,16,HS*HM);\ng.depthMask(true);g.disable(g.BLEND);\ng.useProgram(pr2);\ng.uniform2f(L3(\"uR\"),cv.width,cv.height);g.uniform2f(L3(\"uY\"),Math.cos(yaw),Math.sin(yaw));g.uniform2f(L3(\"uP\"),Math.cos(pitch),Math.sin(pitch));g.uniform1f(L3(\"uS\"),1.5/H*zoom);\ng.bindVertexArray(vaoC);\ng.bindBuffer(g.ARRAY_BUFFER,cbuf);g.bufferData(g.ARRAY_BUFFER,cp,g.DYNAMIC_DRAW);\ng.bindBuffer(g.ARRAY_BUFFER,cnbuf);g.bufferData(g.ARRAY_BUFFER,cnrm,g.DYNAMIC_DRAW);\ng.uniform3f(L3(\"uC\"),.55,.14,.20);g.uniform1f(L3(\"uLit\"),1);\ng.drawElements(g.TRIANGLES,CI.length,g.UNSIGNED_SHORT,0);\ng.bindVertexArray(null);\n}\nrequestAnimationFrame(fr)}\nfr();\n}\nmain().catch(e=>{st.textContent=\"NXA REFUSED: \"+e;st.style.color=\"#e6919b\";window.__nxa={ok:0,err:String(e)}});\n</script></body></html>\n" as *u8) 66 let fd: i64 = sys_openat_wr(argv[1] as *u8, 0x1a4) 67 if fd < 0 { nre_w("open out failed\n" as *u8); return 9 } 68 sys_write(fd, out, p) 69 sys_close(fd) 70 nre_w("NXA-RIG page bytes=" as *u8); nre_num(p); nre_w("\n" as *u8) 71 return 0 72}