import fs from 'node:fs'; import vm from 'node:vm'; const prodHtml=fs.readFileSync(new URL('../../index.html',import.meta.url),'utf8'); const scripts=[...prodHtml.matchAll(/]*>([\s\S]*?)<\/script>/g)].map(m=>m[1]); const kc={};vm.runInNewContext(scripts[0],kc);const kernels=kc.MANDEL_WEBGPU_KERNELS; function appContext(){ const element={width:1365,height:768,clientWidth:1365,clientHeight:768,style:{},hidden:false,value:'',textContent:'',disabled:false,addEventListener(){},classList:{toggle(){}},setAttribute(){},removeAttribute(){},showModal(){},close(){},toBlob(){},getBoundingClientRect(){return{left:0,top:0,width:1365,height:768}}}; const context={MANDEL_WEBGPU_KERNELS:kernels,document:{querySelector:()=>element,getElementById:()=>element,documentElement:{classList:{toggle(){}}},body:{classList:{toggle(){}},appendChild(){}}},navigator:{hardwareConcurrency:4,deviceMemory:8},location:{search:'',hash:''},history:{replaceState(){}},performance,URLSearchParams,URL:{createObjectURL:()=>`blob:test`,revokeObjectURL(){}},TextEncoder,Blob:class{},console,addEventListener(){},requestAnimationFrame:()=>1,cancelAnimationFrame(){},setTimeout,clearTimeout,setInterval,clearInterval,innerWidth:1365,innerHeight:768,devicePixelRatio:1,localStorage:{getItem(){return null},setItem(){},removeItem(){}}}; const cut=scripts[1].indexOf('// ── boot / teardown'); const code=scripts[1].slice(0,cut)+`\nglobalThis.internal={state,fastReferenceWorkerSource,referenceWorkerSource,precisionFallbackWorkerSource,fastReferenceBits,pixelPrecisionBits,referencePixelForSource,spanMantExp,adaptiveProbeSources,adaptiveProbeChoice,adaptiveIterationBonus,fixedSourceForPixel,log2FixedAt};})();`; vm.runInNewContext(code,context);return context.internal; } const app=appContext(); function runWorker(source,data){let result;const c={self:{},postMessage:d=>{result=d},performance,console,BigInt,Math,ArrayBuffer,DataView,Float32Array,Uint32Array,Uint8Array};vm.runInNewContext(source,c);c.self.onmessage({data});if(!result)throw new Error('no result');if(result.type==='error')throw new Error(result.error);return result;} function maxAdaptive(snap,w){const spanLog2=app.log2FixedAt(snap.span,snap.bits),z=Math.max(0,Math.log10(3.4)-spanLog2/Math.log2(10)),screenBits=Math.max(0,Math.log2(w)+z*Math.LOG2E*Math.LN10),bonus=app.adaptiveIterationBonus(screenBits,1);return Math.min(16384,Math.max(350,350+bonus));} function initialIter(snap,w,h){const adaptive=maxAdaptive(snap,w),sources=app.adaptiveProbeSources(snap,w,h),targetBits=Math.max(app.pixelPrecisionBits(snap,w,40)+32),scored=runWorker(app.referenceWorkerSource(),{type:'score',id:1,bits:snap.bits,targetBits,re:snap.re.toString(),im:snap.im.toString(),span:snap.span.toString(),width:w,height:h,iter:adaptive,candidates:sources.map(c=>({re:c.re.toString(),im:c.im.toString()}))});return {adaptive,...app.adaptiveProbeChoice(scored.escapes||[],adaptive,350),escapes:scored.escapes};} function buildFast(snap,iter,w,h){const targetBits=app.fastReferenceBits(snap,w),d=runWorker(app.fastReferenceWorkerSource(),{type:'build',id:2,key:'analysis',sourceBits:snap.bits,targetBits,re:snap.re.toString(),im:snap.im.toString(),span:snap.span.toString(),width:w,height:h,iter});d.source={bits:snap.bits,re:BigInt(d.referenceRe),im:BigInt(d.referenceIm),viewRe:snap.re,viewIm:snap.im,span:snap.span,iter};return d;} function oracle(snap,iter,w,h,indices){const targetBits=app.pixelPrecisionBits(snap,w,40);return runWorker(app.precisionFallbackWorkerSource(),{type:'solve',id:3,bits:snap.bits,targetBits,re:snap.re.toString(),im:snap.im.toString(),span:snap.span.toString(),width:w,height:h,iter,terminalClass:-1,indices:Uint32Array.from(indices).buffer});} const f=Math.fround;const add=(a,b)=>f(f(a)+f(b)),mul=(a,b)=>f(f(a)*f(b));const maxabs=v=>Math.max(Math.abs(v[0]),Math.abs(v[1])); function cmul(a,b){return [add(mul(a[0],b[0]),-mul(a[1],b[1])),add(mul(a[0],b[1]),mul(a[1],b[0]))]} function ld(v,e){return f(v*Math.pow(2,e))} function refsFrom(buf,n){const dv=new DataView(buf),a=[];for(let i=0;i<=n;i++){const o=i*16;a.push([[dv.getFloat32(o,true),dv.getFloat32(o+4,true)],[dv.getFloat32(o+8,true),dv.getFloat32(o+12,true)]])}return a} function simulate(snap,w,h,iter,ctx,index,{rebase=false,glitchG=0}={}){const px=index%w,py=Math.floor(index/w),rpix=app.referencePixelForSource(ctx.source,snap,w,h),se=app.spanMantExp(snap),mh=f(se.mant),ml=f(se.mant-mh),iw=f(1/w),iwlo=f(1/w-iw),gx=f(px+.5),gy=f(py+.5),ox=f(gx-f(rpix.x)),oy=f(f(rpix.y)-gy),dxh=mul(ox,iw),dxl=mul(ox,iwlo),dyh=mul(oy,iw),dyl=mul(oy,iwlo);let d=[add(mul(mh,dxh),add(mul(mh,dxl),mul(ml,dxh))),add(mul(mh,dyh),add(mul(mh,dyl),mul(ml,dyh)))];let ww=[0,0],scaleExp=se.exp,n=0,m=0,rebases=0,glitches=0,minRatio=Infinity;const refs=refsFrom(ctx.refs,ctx.refLen); while(true){const rp=refs[Math.min(m,ctx.refLen)],delta=[ld(ww[0],scaleExp),ld(ww[1],scaleExp)],rv=[add(rp[0][0],rp[1][0]),add(rp[0][1],rp[1][1])],z=[add(rp[0][0],add(rp[1][0],delta[0])),add(rp[0][1],add(rp[1][1],delta[1]))],mag=add(mul(z[0],z[0]),mul(z[1],z[1])),rmag=add(mul(rv[0],rv[0]),mul(rv[1],rv[1])),dmag=add(mul(delta[0],delta[0]),mul(delta[1],delta[1]));if(rmag>0)minRatio=Math.min(minRatio,mag/rmag); if(m>0&&glitchG>0&&rmag>0&&mag4)return{kind:'escape',n,rebases,glitches,minRatio};if(n>=iter)return{kind:'op',n,rebases,glitches,minRatio};if(m>=ctx.refLen)return{kind:'refend',n,rebases,glitches,minRatio}; if(rebase&&m>0&&mag=1e30)return{kind:'range',n,rebases,glitches,minRatio};if(mm>65536){ww=[mul(ww[0],1/65536),mul(ww[1],1/65536)];d=[mul(d[0],1/65536),mul(d[1],1/65536)];scaleExp+=16}else if(mm>0&&mm<1/65536&&scaleExp>se.exp){ww=[mul(ww[0],65536),mul(ww[1],65536)];d=[mul(d[0],65536),mul(d[1],65536)];scaleExp-=16}if(scaleExp>126)return{kind:'range',n,rebases,glitches,minRatio};}} function grid(w,h,nx=16,ny=10){const out=[];for(let j=0;j>>28)&3)===1,q=simulate(snap,1365,768,sel.iter,ctx,indices[k],mode),fast=q.kind==='escape';counts[q.kind]=(counts[q.kind]||0)+1;rebases+=q.rebases||0;minRatio=Math.min(minRatio,q.minRatio??Infinity);if(fast!==exact){mismatch++;if(fast)falseEscape++;else falseNon++;}}rows.push({case:c.name,initial:sel.iter,adaptive:sel.adaptive,refLen:ctx.refLen,selectionEscape:ctx.selectionEscape,refPixel:app.referencePixelForSource(ctx.source,snap,1365,768),mode:mode.name,counts,mismatch,falseEscape,falseNon,rebases,minRatio});}} console.log(JSON.stringify(rows,null,2));