diff --git a/404.html b/404.html
deleted file mode 100644
index 3a3188c8..00000000
--- a/404.html
+++ /dev/null
@@ -1,12 +0,0 @@
-
404: This page could not be found404
This page could not be found.
\ No newline at end of file
diff --git a/_next/data/8K1g64DscQoFBkH0FrGIu/samples/A-buffer.json b/_next/data/8K1g64DscQoFBkH0FrGIu/samples/A-buffer.json
deleted file mode 100644
index ed87637a..00000000
--- a/_next/data/8K1g64DscQoFBkH0FrGIu/samples/A-buffer.json
+++ /dev/null
@@ -1 +0,0 @@
-{"pageProps":{"slug":"A-buffer"},"__N_SSG":true}
\ No newline at end of file
diff --git a/_next/data/8K1g64DscQoFBkH0FrGIu/samples/animometer.json b/_next/data/8K1g64DscQoFBkH0FrGIu/samples/animometer.json
deleted file mode 100644
index b53d301f..00000000
--- a/_next/data/8K1g64DscQoFBkH0FrGIu/samples/animometer.json
+++ /dev/null
@@ -1 +0,0 @@
-{"pageProps":{"slug":"animometer"},"__N_SSG":true}
\ No newline at end of file
diff --git a/_next/data/8K1g64DscQoFBkH0FrGIu/samples/bitonicSort.json b/_next/data/8K1g64DscQoFBkH0FrGIu/samples/bitonicSort.json
deleted file mode 100644
index 2adcbc4d..00000000
--- a/_next/data/8K1g64DscQoFBkH0FrGIu/samples/bitonicSort.json
+++ /dev/null
@@ -1 +0,0 @@
-{"pageProps":{"slug":"bitonicSort"},"__N_SSG":true}
\ No newline at end of file
diff --git a/_next/data/8K1g64DscQoFBkH0FrGIu/samples/cameras.json b/_next/data/8K1g64DscQoFBkH0FrGIu/samples/cameras.json
deleted file mode 100644
index 2b120401..00000000
--- a/_next/data/8K1g64DscQoFBkH0FrGIu/samples/cameras.json
+++ /dev/null
@@ -1 +0,0 @@
-{"pageProps":{"slug":"cameras"},"__N_SSG":true}
\ No newline at end of file
diff --git a/_next/data/8K1g64DscQoFBkH0FrGIu/samples/computeBoids.json b/_next/data/8K1g64DscQoFBkH0FrGIu/samples/computeBoids.json
deleted file mode 100644
index 3552cc6e..00000000
--- a/_next/data/8K1g64DscQoFBkH0FrGIu/samples/computeBoids.json
+++ /dev/null
@@ -1 +0,0 @@
-{"pageProps":{"slug":"computeBoids"},"__N_SSG":true}
\ No newline at end of file
diff --git a/_next/data/8K1g64DscQoFBkH0FrGIu/samples/cornell.json b/_next/data/8K1g64DscQoFBkH0FrGIu/samples/cornell.json
deleted file mode 100644
index d2e48612..00000000
--- a/_next/data/8K1g64DscQoFBkH0FrGIu/samples/cornell.json
+++ /dev/null
@@ -1 +0,0 @@
-{"pageProps":{"slug":"cornell"},"__N_SSG":true}
\ No newline at end of file
diff --git a/_next/data/8K1g64DscQoFBkH0FrGIu/samples/cubemap.json b/_next/data/8K1g64DscQoFBkH0FrGIu/samples/cubemap.json
deleted file mode 100644
index b528786b..00000000
--- a/_next/data/8K1g64DscQoFBkH0FrGIu/samples/cubemap.json
+++ /dev/null
@@ -1 +0,0 @@
-{"pageProps":{"slug":"cubemap"},"__N_SSG":true}
\ No newline at end of file
diff --git a/_next/data/8K1g64DscQoFBkH0FrGIu/samples/deferredRendering.json b/_next/data/8K1g64DscQoFBkH0FrGIu/samples/deferredRendering.json
deleted file mode 100644
index 09f091c1..00000000
--- a/_next/data/8K1g64DscQoFBkH0FrGIu/samples/deferredRendering.json
+++ /dev/null
@@ -1 +0,0 @@
-{"pageProps":{"slug":"deferredRendering"},"__N_SSG":true}
\ No newline at end of file
diff --git a/_next/data/8K1g64DscQoFBkH0FrGIu/samples/fractalCube.json b/_next/data/8K1g64DscQoFBkH0FrGIu/samples/fractalCube.json
deleted file mode 100644
index 7801b561..00000000
--- a/_next/data/8K1g64DscQoFBkH0FrGIu/samples/fractalCube.json
+++ /dev/null
@@ -1 +0,0 @@
-{"pageProps":{"slug":"fractalCube"},"__N_SSG":true}
\ No newline at end of file
diff --git a/_next/data/8K1g64DscQoFBkH0FrGIu/samples/gameOfLife.json b/_next/data/8K1g64DscQoFBkH0FrGIu/samples/gameOfLife.json
deleted file mode 100644
index 6de743ba..00000000
--- a/_next/data/8K1g64DscQoFBkH0FrGIu/samples/gameOfLife.json
+++ /dev/null
@@ -1 +0,0 @@
-{"pageProps":{"slug":"gameOfLife"},"__N_SSG":true}
\ No newline at end of file
diff --git a/_next/data/8K1g64DscQoFBkH0FrGIu/samples/helloTriangle.json b/_next/data/8K1g64DscQoFBkH0FrGIu/samples/helloTriangle.json
deleted file mode 100644
index 235e921b..00000000
--- a/_next/data/8K1g64DscQoFBkH0FrGIu/samples/helloTriangle.json
+++ /dev/null
@@ -1 +0,0 @@
-{"pageProps":{"slug":"helloTriangle"},"__N_SSG":true}
\ No newline at end of file
diff --git a/_next/data/8K1g64DscQoFBkH0FrGIu/samples/helloTriangleMSAA.json b/_next/data/8K1g64DscQoFBkH0FrGIu/samples/helloTriangleMSAA.json
deleted file mode 100644
index a9e70d45..00000000
--- a/_next/data/8K1g64DscQoFBkH0FrGIu/samples/helloTriangleMSAA.json
+++ /dev/null
@@ -1 +0,0 @@
-{"pageProps":{"slug":"helloTriangleMSAA"},"__N_SSG":true}
\ No newline at end of file
diff --git a/_next/data/8K1g64DscQoFBkH0FrGIu/samples/imageBlur.json b/_next/data/8K1g64DscQoFBkH0FrGIu/samples/imageBlur.json
deleted file mode 100644
index be5632dd..00000000
--- a/_next/data/8K1g64DscQoFBkH0FrGIu/samples/imageBlur.json
+++ /dev/null
@@ -1 +0,0 @@
-{"pageProps":{"slug":"imageBlur"},"__N_SSG":true}
\ No newline at end of file
diff --git a/_next/data/8K1g64DscQoFBkH0FrGIu/samples/instancedCube.json b/_next/data/8K1g64DscQoFBkH0FrGIu/samples/instancedCube.json
deleted file mode 100644
index 517a45cf..00000000
--- a/_next/data/8K1g64DscQoFBkH0FrGIu/samples/instancedCube.json
+++ /dev/null
@@ -1 +0,0 @@
-{"pageProps":{"slug":"instancedCube"},"__N_SSG":true}
\ No newline at end of file
diff --git a/_next/data/8K1g64DscQoFBkH0FrGIu/samples/normalMap.json b/_next/data/8K1g64DscQoFBkH0FrGIu/samples/normalMap.json
deleted file mode 100644
index 79c4af10..00000000
--- a/_next/data/8K1g64DscQoFBkH0FrGIu/samples/normalMap.json
+++ /dev/null
@@ -1 +0,0 @@
-{"pageProps":{"slug":"normalMap"},"__N_SSG":true}
\ No newline at end of file
diff --git a/_next/data/8K1g64DscQoFBkH0FrGIu/samples/particles.json b/_next/data/8K1g64DscQoFBkH0FrGIu/samples/particles.json
deleted file mode 100644
index 677b8b42..00000000
--- a/_next/data/8K1g64DscQoFBkH0FrGIu/samples/particles.json
+++ /dev/null
@@ -1 +0,0 @@
-{"pageProps":{"slug":"particles"},"__N_SSG":true}
\ No newline at end of file
diff --git a/_next/data/8K1g64DscQoFBkH0FrGIu/samples/renderBundles.json b/_next/data/8K1g64DscQoFBkH0FrGIu/samples/renderBundles.json
deleted file mode 100644
index e22f92dc..00000000
--- a/_next/data/8K1g64DscQoFBkH0FrGIu/samples/renderBundles.json
+++ /dev/null
@@ -1 +0,0 @@
-{"pageProps":{"slug":"renderBundles"},"__N_SSG":true}
\ No newline at end of file
diff --git a/_next/data/8K1g64DscQoFBkH0FrGIu/samples/resizeCanvas.json b/_next/data/8K1g64DscQoFBkH0FrGIu/samples/resizeCanvas.json
deleted file mode 100644
index 20c1c638..00000000
--- a/_next/data/8K1g64DscQoFBkH0FrGIu/samples/resizeCanvas.json
+++ /dev/null
@@ -1 +0,0 @@
-{"pageProps":{"slug":"resizeCanvas"},"__N_SSG":true}
\ No newline at end of file
diff --git a/_next/data/8K1g64DscQoFBkH0FrGIu/samples/reversedZ.json b/_next/data/8K1g64DscQoFBkH0FrGIu/samples/reversedZ.json
deleted file mode 100644
index cd2b20a5..00000000
--- a/_next/data/8K1g64DscQoFBkH0FrGIu/samples/reversedZ.json
+++ /dev/null
@@ -1 +0,0 @@
-{"pageProps":{"slug":"reversedZ"},"__N_SSG":true}
\ No newline at end of file
diff --git a/_next/data/8K1g64DscQoFBkH0FrGIu/samples/rotatingCube.json b/_next/data/8K1g64DscQoFBkH0FrGIu/samples/rotatingCube.json
deleted file mode 100644
index 0bf260de..00000000
--- a/_next/data/8K1g64DscQoFBkH0FrGIu/samples/rotatingCube.json
+++ /dev/null
@@ -1 +0,0 @@
-{"pageProps":{"slug":"rotatingCube"},"__N_SSG":true}
\ No newline at end of file
diff --git a/_next/data/8K1g64DscQoFBkH0FrGIu/samples/samplerParameters.json b/_next/data/8K1g64DscQoFBkH0FrGIu/samples/samplerParameters.json
deleted file mode 100644
index 87509f61..00000000
--- a/_next/data/8K1g64DscQoFBkH0FrGIu/samples/samplerParameters.json
+++ /dev/null
@@ -1 +0,0 @@
-{"pageProps":{"slug":"samplerParameters"},"__N_SSG":true}
\ No newline at end of file
diff --git a/_next/data/8K1g64DscQoFBkH0FrGIu/samples/shadowMapping.json b/_next/data/8K1g64DscQoFBkH0FrGIu/samples/shadowMapping.json
deleted file mode 100644
index d4fa742a..00000000
--- a/_next/data/8K1g64DscQoFBkH0FrGIu/samples/shadowMapping.json
+++ /dev/null
@@ -1 +0,0 @@
-{"pageProps":{"slug":"shadowMapping"},"__N_SSG":true}
\ No newline at end of file
diff --git a/_next/data/8K1g64DscQoFBkH0FrGIu/samples/skinnedMesh.json b/_next/data/8K1g64DscQoFBkH0FrGIu/samples/skinnedMesh.json
deleted file mode 100644
index f44c055b..00000000
--- a/_next/data/8K1g64DscQoFBkH0FrGIu/samples/skinnedMesh.json
+++ /dev/null
@@ -1 +0,0 @@
-{"pageProps":{"slug":"skinnedMesh"},"__N_SSG":true}
\ No newline at end of file
diff --git a/_next/data/8K1g64DscQoFBkH0FrGIu/samples/texturedCube.json b/_next/data/8K1g64DscQoFBkH0FrGIu/samples/texturedCube.json
deleted file mode 100644
index 067335cf..00000000
--- a/_next/data/8K1g64DscQoFBkH0FrGIu/samples/texturedCube.json
+++ /dev/null
@@ -1 +0,0 @@
-{"pageProps":{"slug":"texturedCube"},"__N_SSG":true}
\ No newline at end of file
diff --git a/_next/data/8K1g64DscQoFBkH0FrGIu/samples/twoCubes.json b/_next/data/8K1g64DscQoFBkH0FrGIu/samples/twoCubes.json
deleted file mode 100644
index 257276e7..00000000
--- a/_next/data/8K1g64DscQoFBkH0FrGIu/samples/twoCubes.json
+++ /dev/null
@@ -1 +0,0 @@
-{"pageProps":{"slug":"twoCubes"},"__N_SSG":true}
\ No newline at end of file
diff --git a/_next/data/8K1g64DscQoFBkH0FrGIu/samples/videoUploading.json b/_next/data/8K1g64DscQoFBkH0FrGIu/samples/videoUploading.json
deleted file mode 100644
index dd593ae2..00000000
--- a/_next/data/8K1g64DscQoFBkH0FrGIu/samples/videoUploading.json
+++ /dev/null
@@ -1 +0,0 @@
-{"pageProps":{"slug":"videoUploading"},"__N_SSG":true}
\ No newline at end of file
diff --git a/_next/data/8K1g64DscQoFBkH0FrGIu/samples/worker.json b/_next/data/8K1g64DscQoFBkH0FrGIu/samples/worker.json
deleted file mode 100644
index 1ac88928..00000000
--- a/_next/data/8K1g64DscQoFBkH0FrGIu/samples/worker.json
+++ /dev/null
@@ -1 +0,0 @@
-{"pageProps":{"slug":"worker"},"__N_SSG":true}
\ No newline at end of file
diff --git a/_next/static/8K1g64DscQoFBkH0FrGIu/_buildManifest.js b/_next/static/8K1g64DscQoFBkH0FrGIu/_buildManifest.js
deleted file mode 100644
index 425bb00f..00000000
--- a/_next/static/8K1g64DscQoFBkH0FrGIu/_buildManifest.js
+++ /dev/null
@@ -1 +0,0 @@
-self.__BUILD_MANIFEST={__rewrites:{beforeFiles:[],afterFiles:[],fallback:[]},"/":["static/css/c90c6796236b02d5.css","static/chunks/pages/index-81b438bb72bc0aad.js"],"/_error":["static/chunks/pages/_error-8353112a01355ec2.js"],"/samples/videoUploadingWebCodecs":["static/chunks/pages/samples/videoUploadingWebCodecs-ef64dfaec9dfe8b3.js"],"/samples/[slug]":["static/chunks/pages/samples/[slug]-ea943101c4de1afe.js"],sortedPages:["/","/_app","/_error","/samples/videoUploadingWebCodecs","/samples/[slug]"]},self.__BUILD_MANIFEST_CB&&self.__BUILD_MANIFEST_CB();
\ No newline at end of file
diff --git a/_next/static/8K1g64DscQoFBkH0FrGIu/_ssgManifest.js b/_next/static/8K1g64DscQoFBkH0FrGIu/_ssgManifest.js
deleted file mode 100644
index 8ef34629..00000000
--- a/_next/static/8K1g64DscQoFBkH0FrGIu/_ssgManifest.js
+++ /dev/null
@@ -1 +0,0 @@
-self.__SSG_MANIFEST=new Set(["\u002Fsamples\u002F[slug]"]);self.__SSG_MANIFEST_CB&&self.__SSG_MANIFEST_CB()
\ No newline at end of file
diff --git a/_next/static/chunks/0.6a50185fa8ff8ed2.js b/_next/static/chunks/0.6a50185fa8ff8ed2.js
deleted file mode 100644
index 848a716b..00000000
--- a/_next/static/chunks/0.6a50185fa8ff8ed2.js
+++ /dev/null
@@ -1 +0,0 @@
-(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[0],{5671:function(e,n,t){"use strict";t.d(n,{Tl:function(){return p},hu:function(){return d}});var o=t(5893),r=t(9008),i=t.n(r),a=t(1163),s=t(7294),l=t(9147),u=t.n(l);t(7319);let c=e=>{let n=(0,s.useRef)(null),r=(0,s.useRef)(null),l=(0,s.useMemo)(()=>e.sources.map(e=>{let{name:n,contents:r}=e;return{name:n,...function(e){let n;let r=null;{r=document.createElement("div");let i=t(4631);n=i(r,{lineNumbers:!0,lineWrapping:!0,theme:"monokai",readOnly:!0})}return{Container:function(t){return(0,o.jsx)("div",{...t,children:(0,o.jsx)("div",{ref(t){r&&t&&(t.appendChild(r),n.setOption("value",e))}})})}}}(r)}}),e.sources),c=(0,s.useRef)(null),p=(0,s.useMemo)(()=>{if(e.gui){let n=t(4376),o=new n.GUI({autoPlace:!1});return o.domElement.style.position="relative",o.domElement.style.zIndex="1000",o}},[]),d=(0,s.useRef)(null),m=(0,s.useMemo)(()=>{if(e.stats){let n=t(2792);return new n}},[]),f=(0,a.useRouter)(),g=f.asPath.match(/#([a-zA-Z0-9\.\/]+)/),[h,S]=(0,s.useState)(null),[E,_]=(0,s.useState)(null);return(0,s.useEffect)(()=>{if(g?_(g[1]):_(l[0].name),p&&c.current)for(c.current.appendChild(p.domElement);p.__controllers.length>0;)p.__controllers[0].remove();m&&d.current&&(m.dom.style.position="absolute",m.showPanel(1),d.current.appendChild(m.dom));let t={active:!0},o=()=>{t.active=!1};try{let r=n.current;if(!r)throw Error("The canvas is not available");let i=e.init({canvas:r,pageState:t,gui:p,stats:m});i instanceof Promise&&i.catch(e=>{console.error(e),S(e)})}catch(a){console.error(a),S(a)}return o},[]),(0,o.jsxs)("main",{children:[(0,o.jsxs)(i(),{children:[(0,o.jsx)("style",{dangerouslySetInnerHTML:{__html:"\n .CodeMirror {\n height: auto !important;\n margin: 1em 0;\n }\n\n .CodeMirror-scroll {\n height: auto !important;\n overflow: visible !important;\n }\n "}}),(0,o.jsx)("title",{children:"".concat(e.name," - WebGPU Samples")}),(0,o.jsx)("meta",{name:"description",content:e.description}),(0,o.jsx)("meta",{httpEquiv:"origin-trial",content:e.originTrial})]}),(0,o.jsxs)("div",{children:[(0,o.jsx)("h1",{children:e.name}),(0,o.jsx)("a",{target:"_blank",rel:"noreferrer",href:"https://github.com/".concat("webgpu/webgpu-samples","/tree/main/").concat(e.filename),children:"See it on Github!"}),(0,o.jsx)("p",{children:e.description}),h?(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)("p",{children:"Something went wrong. Do your browser and device support WebGPU?"}),(0,o.jsx)("p",{children:"".concat(h)})]}):null]}),(0,o.jsxs)("div",{className:u().canvasContainer,children:[(0,o.jsx)("div",{style:{position:"absolute",left:10},ref:d}),(0,o.jsx)("div",{style:{position:"absolute",right:10},ref:c}),(0,o.jsx)("canvas",{ref:n})]}),(0,o.jsxs)("div",{children:[(0,o.jsx)("nav",{className:u().sourceFileNav,ref:r,children:(0,o.jsx)("div",{className:u().sourceFileScrollContainer,onScroll(e){let n=e.currentTarget,t=n.scrollWidth-n.clientWidth-n.scrollLeft;n.scrollLeft>25?r.current.setAttribute("data-left","true"):r.current.setAttribute("data-left","false"),t>25?r.current.setAttribute("data-right","true"):r.current.setAttribute("data-right","false")},children:(0,o.jsx)("ul",{children:l.map((e,n)=>(0,o.jsx)("li",{children:(0,o.jsx)("a",{href:"#".concat(e.name),"data-active":E==e.name,onClick(){_(e.name)},children:e.name})},n))})})}),l.map((e,n)=>(0,o.jsx)(e.Container,{className:u().sourceFileContainer,"data-active":E==e.name},n))]})]})},p=e=>(0,o.jsx)(c,{...e});function d(e,n){if(!e)throw Error(n)}},2e3:function(e,n,t){"use strict";let o;t.r(n),t.d(n,{default:function(){return h}});var r,i,a=t(5671),s=t(7606),l="struct ComputeUniforms {\n width: f32,\n height: f32,\n algo: u32,\n blockHeight: u32,\n}\n\nstruct FragmentUniforms {\n // boolean, either 0 or 1\n highlight: u32,\n}\n\nstruct VertexOutput {\n @builtin(position) Position: vec4,\n @location(0) fragUV: vec2\n}\n\n// Uniforms from compute shader\n@group(0) @binding(0) var data: array;\n@group(0) @binding(2) var uniforms: ComputeUniforms;\n// Fragment shader uniforms\n@group(1) @binding(0) var fragment_uniforms: FragmentUniforms;\n\n@fragment\nfn frag_main(input: VertexOutput) -> @location(0) vec4 {\n var uv: vec2 = vec2(\n input.fragUV.x * uniforms.width,\n input.fragUV.y * uniforms.height\n );\n\n var pixel: vec2 = vec2(\n u32(floor(uv.x)),\n u32(floor(uv.y)),\n );\n \n var elementIndex = u32(uniforms.width) * pixel.y + pixel.x;\n var colorChanger = data[elementIndex];\n\n var subtracter = f32(colorChanger) / (uniforms.width * uniforms.height);\n\n if (fragment_uniforms.highlight == 1) {\n return select(\n //If element is above halfHeight, highlight green\n vec4(vec3(0.0, 1.0 - subtracter, 0.0).rgb, 1.0),\n //If element is below halfheight, highlight red\n vec4(vec3(1.0 - subtracter, 0.0, 0.0).rgb, 1.0),\n elementIndex % uniforms.blockHeight < uniforms.blockHeight / 2\n );\n }\n\n var color: vec3 = vec3f(\n 1.0 - subtracter\n );\n\n return vec4(color.rgb, 1.0);\n}\n";class u extends s.NJ{startRun(e,n){this.setArguments(n),super.executeRun(e,this.renderPassDescriptor,this.pipeline,[this.computeBGDescript.bindGroups[0],this.currentBindGroup])}constructor(e,n,t,o,r){super(),this.renderPassDescriptor=t,this.computeBGDescript=o;let i=e.createBuffer({size:Uint32Array.BYTES_PER_ELEMENT,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST}),a=(0,s.a1)([0],[GPUShaderStage.FRAGMENT],["buffer"],[{type:"uniform"}],[[{buffer:i}]],r,e);this.currentBindGroup=a.bindGroups[0],this.pipeline=super.create2DRenderPipeline(e,r,[this.computeBGDescript.bindGroupLayout,a.bindGroupLayout],l,n),this.setArguments=n=>{e.queue.writeBuffer(i,0,new Uint32Array([n.highlight]))}}}u.sourceInfo={name:"src/sample/bitonicSort/bitonicDisplay.ts".substring(23),contents:"import {\n BindGroupCluster,\n Base2DRendererClass,\n createBindGroupCluster,\n} from './utils';\n\nimport bitonicDisplay from './bitonicDisplay.frag.wgsl';\n\ninterface BitonicDisplayRenderArgs {\n highlight: number;\n}\n\nexport default class BitonicDisplayRenderer extends Base2DRendererClass {\n static sourceInfo = {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n };\n\n switchBindGroup: (name: string) => void;\n setArguments: (args: BitonicDisplayRenderArgs) => void;\n computeBGDescript: BindGroupCluster;\n\n constructor(\n device: GPUDevice,\n presentationFormat: GPUTextureFormat,\n renderPassDescriptor: GPURenderPassDescriptor,\n computeBGDescript: BindGroupCluster,\n label: string\n ) {\n super();\n this.renderPassDescriptor = renderPassDescriptor;\n this.computeBGDescript = computeBGDescript;\n\n const uniformBuffer = device.createBuffer({\n size: Uint32Array.BYTES_PER_ELEMENT,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n });\n\n const bgCluster = createBindGroupCluster(\n [0],\n [GPUShaderStage.FRAGMENT],\n ['buffer'],\n [{ type: 'uniform' }],\n [[{ buffer: uniformBuffer }]],\n label,\n device\n );\n\n this.currentBindGroup = bgCluster.bindGroups[0];\n\n this.pipeline = super.create2DRenderPipeline(\n device,\n label,\n [this.computeBGDescript.bindGroupLayout, bgCluster.bindGroupLayout],\n bitonicDisplay,\n presentationFormat\n );\n\n this.setArguments = (args: BitonicDisplayRenderArgs) => {\n device.queue.writeBuffer(\n uniformBuffer,\n 0,\n new Uint32Array([args.highlight])\n );\n };\n }\n\n startRun(commandEncoder: GPUCommandEncoder, args: BitonicDisplayRenderArgs) {\n this.setArguments(args);\n super.executeRun(commandEncoder, this.renderPassDescriptor, this.pipeline, [\n this.computeBGDescript.bindGroups[0],\n this.currentBindGroup,\n ]);\n }\n}\n"};let c=e=>((e%2!=0||e>256)&&(e=256),"\n\nstruct Uniforms {\n width: f32,\n height: f32,\n algo: u32,\n blockHeight: u32,\n}\n\n// Create local workgroup data that can contain all elements\nvar local_data: array;\n\n// Define groups (functions refer to this data)\n@group(0) @binding(0) var input_data: array;\n@group(0) @binding(1) var output_data: array;\n@group(0) @binding(2) var uniforms: Uniforms;\n@group(0) @binding(3) var counter: atomic;\n\n// Compare and swap values in local_data\nfn local_compare_and_swap(idx_before: u32, idx_after: u32) {\n //idx_before should always be < idx_after\n if (local_data[idx_after] < local_data[idx_before]) {\n atomicAdd(&counter, 1);\n var temp: u32 = local_data[idx_before];\n local_data[idx_before] = local_data[idx_after];\n local_data[idx_after] = temp;\n }\n return;\n}\n\n// invoke_id goes from 0 to workgroupSize\nfn get_flip_indices(invoke_id: u32, block_height: u32) -> vec2 {\n // Caculate index offset (i.e move indices into correct block)\n let block_offset: u32 = ((2 * invoke_id) / block_height) * block_height;\n let half_height = block_height / 2;\n // Calculate index spacing\n var idx: vec2 = vec2(\n invoke_id % half_height, block_height - (invoke_id % half_height) - 1,\n );\n idx.x += block_offset;\n idx.y += block_offset;\n return idx;\n}\n\nfn get_disperse_indices(invoke_id: u32, block_height: u32) -> vec2 {\n var block_offset: u32 = ((2 * invoke_id) / block_height) * block_height;\n let half_height = block_height / 2;\n var idx: vec2 = vec2(\n invoke_id % half_height, (invoke_id % half_height) + half_height\n );\n idx.x += block_offset;\n idx.y += block_offset;\n return idx;\n}\n\nfn global_compare_and_swap(idx_before: u32, idx_after: u32) {\n if (input_data[idx_after] < input_data[idx_before]) {\n output_data[idx_before] = input_data[idx_after];\n output_data[idx_after] = input_data[idx_before];\n } \n}\n\n// Constants/enum\nconst ALGO_NONE = 0;\nconst ALGO_LOCAL_FLIP = 1;\nconst ALGO_LOCAL_DISPERSE = 2;\nconst ALGO_GLOBAL_FLIP = 3;\n\n// Our compute shader will execute specified # of invocations or elements / 2 invocations\n@compute @workgroup_size(").concat(e,", 1, 1)\nfn computeMain(\n @builtin(global_invocation_id) global_id: vec3,\n @builtin(local_invocation_id) local_id: vec3,\n @builtin(workgroup_id) workgroup_id: vec3,\n) {\n\n let offset = ").concat(e," * 2 * workgroup_id.x;\n // If we will perform a local swap, then populate the local data\n if (uniforms.algo <= 2) {\n // Assign range of input_data to local_data.\n // Range cannot exceed maxWorkgroupsX * 2\n // Each invocation will populate the workgroup data... (1 invocation for every 2 elements)\n local_data[local_id.x * 2] = input_data[offset + local_id.x * 2];\n local_data[local_id.x * 2 + 1] = input_data[offset + local_id.x * 2 + 1];\n }\n\n //...and wait for each other to finish their own bit of data population.\n workgroupBarrier();\n\n switch uniforms.algo {\n case 1: { // Local Flip\n let idx = get_flip_indices(local_id.x, uniforms.blockHeight);\n local_compare_and_swap(idx.x, idx.y);\n } \n case 2: { // Local Disperse\n let idx = get_disperse_indices(local_id.x, uniforms.blockHeight);\n local_compare_and_swap(idx.x, idx.y);\n } \n case 3: { // Global Flip\n let idx = get_flip_indices(global_id.x, uniforms.blockHeight);\n global_compare_and_swap(idx.x, idx.y);\n }\n case 4: { \n let idx = get_disperse_indices(global_id.x, uniforms.blockHeight);\n global_compare_and_swap(idx.x, idx.y);\n }\n default: { \n \n }\n }\n\n // Ensure that all invocations have swapped their own regions of data\n workgroupBarrier();\n\n if (uniforms.algo <= ALGO_LOCAL_DISPERSE) {\n //Repopulate global data with local data\n output_data[offset + local_id.x * 2] = local_data[local_id.x * 2];\n output_data[offset + local_id.x * 2 + 1] = local_data[local_id.x * 2 + 1];\n }\n\n}"));var p=t(134),d="@group(0) @binding(3) var counter: atomic;\n\n@compute @workgroup_size(1, 1, 1)\nfn atomicToZero() {\n let counterValue = atomicLoad(&counter);\n atomicSub(&counter, counterValue);\n}",m="src/sample/bitonicSort/main.ts";(r=i||(i={}))[r.NONE=0]="NONE",r[r.FLIP_LOCAL=1]="FLIP_LOCAL",r[r.DISPERSE_LOCAL=2]="DISPERSE_LOCAL",r[r.FLIP_GLOBAL=3]="FLIP_GLOBAL",r[r.DISPERSE_GLOBAL=4]="DISPERSE_GLOBAL";let f=e=>{let n=Math.log2(e);return n*(n+1)/2};(0,s.Ot)(async e=>{let n,t,o,{pageState:r,device:a,gui:l,presentationFormat:p,context:m,canvas:g,timestampQueryAvailable:h}=e,S=a.limits.maxComputeWorkgroupSizeX;h&&(n=a.createQuerySet({type:"timestamp",count:2}),t=a.createBuffer({size:2*BigInt64Array.BYTES_PER_ELEMENT,usage:GPUBufferUsage.QUERY_RESOLVE|GPUBufferUsage.COPY_SRC}),o=a.createBuffer({size:2*BigInt64Array.BYTES_PER_ELEMENT,usage:GPUBufferUsage.COPY_DST|GPUBufferUsage.MAP_READ}));let E=[],_=32*S;for(let v=_;v>=4;v/=2)E.push(v);let x=[];for(let y=S;y>=2;y/=2)x.push(y);let b=Math.sqrt(_)%2==0?Math.floor(Math.sqrt(_)):Math.floor(Math.sqrt(_/2)),w=_/b,C={"Total Elements":_,"Grid Width":b,"Grid Height":w,"Grid Dimensions":"".concat(b,"x").concat(w),"Workgroup Size":S,"Size Limit":S,"Workgroups Per Step":_/(2*S),"Hovered Cell":0,"Swapped Cell":1,"Step Index":0,"Total Steps":f(_),"Current Step":"0 of 91","Prev Step":"NONE","Next Step":"FLIP_LOCAL","Prev Swap Span":0,"Next Swap Span":2,executeStep:!1,"Randomize Values"(){},"Execute Sort Step"(){},"Log Elements"(){},"Auto Sort"(){},"Auto Sort Speed":50,"Display Mode":"Elements","Total Swaps":0,"Step Time":"0ms",stepTime:0,"Sort Time":"0ms",sortTime:0,"Average Sort Time":"0ms",configToCompleteSwapsMap:{"8192 256":{sorts:0,time:0}},configKey:"8192 256"},T=new Uint32Array(Array.from({length:C["Total Elements"]},(e,n)=>n)),P=Float32Array.BYTES_PER_ELEMENT*E[0],B=a.createBuffer({size:P,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST}),L=a.createBuffer({size:P,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_SRC}),A=a.createBuffer({size:P,usage:GPUBufferUsage.MAP_READ|GPUBufferUsage.COPY_DST}),G=a.createBuffer({size:Uint32Array.BYTES_PER_ELEMENT,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_SRC}),I=a.createBuffer({size:Uint32Array.BYTES_PER_ELEMENT,usage:GPUBufferUsage.MAP_READ|GPUBufferUsage.COPY_DST}),k=a.createBuffer({size:4*Float32Array.BYTES_PER_ELEMENT,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST}),U=(0,s.a1)([0,1,2,3],[GPUShaderStage.COMPUTE|GPUShaderStage.FRAGMENT,GPUShaderStage.COMPUTE,GPUShaderStage.COMPUTE|GPUShaderStage.FRAGMENT,GPUShaderStage.COMPUTE],["buffer","buffer","buffer","buffer"],[{type:"read-only-storage"},{type:"storage"},{type:"uniform"},{type:"storage"}],[[{buffer:B},{buffer:L},{buffer:k},{buffer:G}]],"BitonicSort",a),M=a.createComputePipeline({layout:a.createPipelineLayout({bindGroupLayouts:[U.bindGroupLayout]}),compute:{module:a.createShaderModule({code:c(C["Workgroup Size"])}),entryPoint:"computeMain"}}),R=a.createComputePipeline({layout:a.createPipelineLayout({bindGroupLayouts:[U.bindGroupLayout]}),compute:{module:a.createShaderModule({code:d}),entryPoint:"atomicToZero"}}),O={colorAttachments:[{view:void 0,clearValue:{r:.1,g:.4,b:.5,a:1},loadOp:"clear",storeOp:"store"}]},N=new u(a,p,O,U,"BitonicDisplay"),D=()=>{C.stepTime=0,C.sortTime=0,ec.setValue("0ms"),ep.setValue("0ms");let e=C.configToCompleteSwapsMap[C.configKey].time/C.configToCompleteSwapsMap[C.configKey].sorts;ed.setValue("".concat((e||0).toFixed(5),"ms"))},z=()=>{Q.setValue(Math.min(C["Total Elements"]/2,C["Size Limit"]));let e=(C["Total Elements"]-1)/(2*C["Size Limit"]);$.setValue(Math.ceil(e)),C["Step Index"]=0,C["Total Steps"]=f(C["Total Elements"]),eo.setValue("".concat(C["Step Index"]," of ").concat(C["Total Steps"]));let n=Math.sqrt(C["Total Elements"])%2==0?Math.floor(Math.sqrt(C["Total Elements"])):Math.floor(Math.sqrt(C["Total Elements"]/2)),t=C["Total Elements"]/n;C["Grid Width"]=n,C["Grid Height"]=t,J.setValue("".concat(n,"x").concat(t)),er.setValue("NONE"),ei.setValue("FLIP_LOCAL"),es.setValue(0),el.setValue(2);let o=a.createCommandEncoder(),r=o.beginComputePass();r.setPipeline(R),r.setBindGroup(0,U.bindGroups[0]),r.dispatchWorkgroups(1),r.end(),a.queue.submit([o.finish()]),ea.setValue(0),eg=2},F=()=>{let e=T.length;for(;0!==e;){let n=Math.floor(Math.random()*e);e-=1,[T[e],T[n]]=[T[n],T[e]]}},H=()=>{T=new Uint32Array(Array.from({length:C["Total Elements"]},(e,n)=>n)),z(),M=a.createComputePipeline({layout:a.createPipelineLayout({bindGroupLayouts:[U.bindGroupLayout]}),compute:{module:a.createShaderModule({code:c(Math.min(C["Total Elements"]/2,C["Size Limit"]))}),entryPoint:"computeMain"}}),F(),eg=2};F();let V=()=>{let e;switch(C["Next Step"]){case"FLIP_LOCAL":case"FLIP_GLOBAL":{let n=C["Next Swap Span"],t=Math.floor(C["Hovered Cell"]/n)+1,o=C["Hovered Cell"]%n;e=n*t-o-1,en.setValue(e)}break;case"DISPERSE_LOCAL":{let r=C["Next Swap Span"],i=r/2;e=C["Hovered Cell"]%r{null!==W&&(clearInterval(W),W=null)},q=()=>{let e=C["Auto Sort Speed"];W=setInterval(()=>{"NONE"===C["Next Step"]&&(clearInterval(W),W=null,K.domElement.style.pointerEvents="auto"),C["Auto Sort Speed"]!==e&&(clearInterval(W),W=null,q()),C.executeStep=!0,V()},C["Auto Sort Speed"])},j=l.addFolder("Compute Resources");j.add(C,"Total Elements",E).onChange(()=>{Y(),H(),K.domElement.style.pointerEvents="auto";let e="".concat(C["Total Elements"]," ").concat(C["Size Limit"]);C.configToCompleteSwapsMap[e]||(C.configToCompleteSwapsMap[e]={sorts:0,time:0}),C.configKey=e,D()});let K=j.add(C,"Size Limit",x).onChange(()=>{let e=Math.min(C["Total Elements"]/2,C["Size Limit"]),n=(C["Total Elements"]-1)/(2*C["Size Limit"]);Q.setValue(e),$.setValue(Math.ceil(n)),M=M=a.createComputePipeline({layout:a.createPipelineLayout({bindGroupLayouts:[U.bindGroupLayout]}),compute:{module:a.createShaderModule({code:c(Math.min(C["Total Elements"]/2,C["Size Limit"]))}),entryPoint:"computeMain"}});let t="".concat(C["Total Elements"]," ").concat(C["Size Limit"]);C.configToCompleteSwapsMap[t]||(C.configToCompleteSwapsMap[t]={sorts:0,time:0}),C.configKey=t,D()}),Q=j.add(C,"Workgroup Size"),$=j.add(C,"Workgroups Per Step");j.open();let Z=l.addFolder("Sort Controls");Z.add(C,"Execute Sort Step").onChange(()=>{K.domElement.style.pointerEvents="none",Y(),C.executeStep=!0}),Z.add(C,"Randomize Values").onChange(()=>{Y(),F(),z(),D(),K.domElement.style.pointerEvents="auto"}),Z.add(C,"Log Elements").onChange(()=>console.log(T)),Z.add(C,"Auto Sort").onChange(()=>{K.domElement.style.pointerEvents="none",q()}),Z.add(C,"Auto Sort Speed",50,1e3).step(50),Z.open();let X=l.addFolder("Grid Information");X.add(C,"Display Mode",["Elements","Swap Highlight"]);let J=X.add(C,"Grid Dimensions"),ee=X.add(C,"Hovered Cell").onChange(V),en=X.add(C,"Swapped Cell"),et=l.addFolder("Execution Information"),eo=et.add(C,"Current Step"),er=et.add(C,"Prev Step"),ei=et.add(C,"Next Step"),ea=et.add(C,"Total Swaps"),es=et.add(C,"Prev Swap Span"),el=et.add(C,"Next Swap Span"),eu=l.addFolder("Timestamp Info (Chrome 121+)"),ec=eu.add(C,"Step Time"),ep=eu.add(C,"Sort Time"),ed=eu.add(C,"Average Sort Time"),em=document.getElementsByClassName("cr function");for(let ef=0;ef{let n=g.getBoundingClientRect().width,t=g.getBoundingClientRect().height,o=[n/C["Grid Width"],t/C["Grid Height"]],r=Math.floor(e.offsetX/o[0]),i=C["Grid Height"]-1-Math.floor(e.offsetY/o[1]);ee.setValue(i*C["Grid Width"]+r),C["Hovered Cell"]=i*C["Grid Width"]+r}),K.domElement.style.pointerEvents="none",$.domElement.style.pointerEvents="none",ee.domElement.style.pointerEvents="none",en.domElement.style.pointerEvents="none",eo.domElement.style.pointerEvents="none",er.domElement.style.pointerEvents="none",es.domElement.style.pointerEvents="none",ei.domElement.style.pointerEvents="none",el.domElement.style.pointerEvents="none",Q.domElement.style.pointerEvents="none",J.domElement.style.pointerEvents="none",ea.domElement.style.pointerEvents="none",ec.domElement.style.pointerEvents="none",ep.domElement.style.pointerEvents="none",ed.domElement.style.pointerEvents="none",l.width=325;let eg=2;async function eh(){if(!r.active)return;a.queue.writeBuffer(B,0,T.buffer,T.byteOffset,T.byteLength);let e=new Float32Array([C["Grid Width"],C["Grid Height"]]),s=new Uint32Array([i[C["Next Step"]],C["Next Swap Span"]]);a.queue.writeBuffer(k,0,e.buffer,e.byteOffset,e.byteLength),a.queue.writeBuffer(k,8,s),O.colorAttachments[0].view=m.getCurrentTexture().createView();let l=a.createCommandEncoder();if(N.startRun(l,{highlight:"Elements"===C["Display Mode"]?0:1}),C.executeStep&&eg<2*C["Total Elements"]){let u;(u=h?l.beginComputePass({timestampWrites:{querySet:n,beginningOfPassWriteIndex:0,endOfPassWriteIndex:1}}):l.beginComputePass()).setPipeline(M),u.setBindGroup(0,U.bindGroups[0]),u.dispatchWorkgroups(C["Workgroups Per Step"]),u.end(),h&&(l.resolveQuerySet(n,0,2,t,0),l.copyBufferToBuffer(t,0,o,0,2*BigInt64Array.BYTES_PER_ELEMENT)),C["Step Index"]=C["Step Index"]+1,eo.setValue("".concat(C["Step Index"]," of ").concat(C["Total Steps"])),er.setValue(C["Next Step"]),es.setValue(C["Next Swap Span"]),el.setValue(C["Next Swap Span"]/2),1===C["Next Swap Span"]?(eg*=2)==2*C["Total Elements"]?(ei.setValue("NONE"),el.setValue(0),C.configToCompleteSwapsMap[C.configKey].sorts+=1):eg>2*C["Workgroup Size"]?(ei.setValue("FLIP_GLOBAL"),el.setValue(eg)):(ei.setValue("FLIP_LOCAL"),el.setValue(eg)):C["Next Swap Span"]>2*C["Workgroup Size"]?ei.setValue("DISPERSE_GLOBAL"):ei.setValue("DISPERSE_LOCAL"),l.copyBufferToBuffer(L,0,A,0,P),l.copyBufferToBuffer(G,0,I,0,Uint32Array.BYTES_PER_ELEMENT)}if(a.queue.submit([l.finish()]),C.executeStep&&eg<4*C["Total Elements"]){await A.mapAsync(GPUMapMode.READ,0,P);let c=A.getMappedRange(0,P);await I.mapAsync(GPUMapMode.READ,0,Uint32Array.BYTES_PER_ELEMENT);let p=I.getMappedRange(0,Uint32Array.BYTES_PER_ELEMENT),d=c.slice(0,Uint32Array.BYTES_PER_ELEMENT*C["Total Elements"]),f=p.slice(0,Uint32Array.BYTES_PER_ELEMENT),g=new Uint32Array(d);if(ea.setValue(new Uint32Array(f)[0]),A.unmap(),I.unmap(),T=g,V(),h){await o.mapAsync(GPUMapMode.READ,0,2*BigInt64Array.BYTES_PER_ELEMENT);let S=new BigInt64Array(o.getMappedRange()),E=Number(S[1]-S[0])/1e6,_=C.sortTime+E;if(C.stepTime=E,C.sortTime=_,ec.setValue("".concat(E.toFixed(5),"ms")),ep.setValue("".concat(_.toFixed(5),"ms")),eg===2*C["Total Elements"]){eg*=2,C.configToCompleteSwapsMap[C.configKey].time+=_;let v=C.configToCompleteSwapsMap[C.configKey].time/C.configToCompleteSwapsMap[C.configKey].sorts;ed.setValue("".concat(v.toFixed(5),"ms"))}o.unmap()}}C.executeStep=!1,requestAnimationFrame(eh)}q(),requestAnimationFrame(eh)}).then(e=>o=e);let g=()=>(0,a.Tl)({name:"Bitonic Sort",description:"A naive bitonic sort algorithm executed on the GPU, based on tgfrerer's implementation at poniesandlight.co.uk/reflect/bitonic_merge_sort/. Each dispatch of the bitonic sort shader dispatches a workgroup containing elements/2 invocations. The GUI's Execution Information folder contains information about the sort's current state. The visualizer displays the sort's results as colored cells sorted from brightest to darkest.",init:o,gui:!0,sources:[{name:m.substring(23),contents:"import { makeSample, SampleInit } from '../../components/SampleLayout';\nimport { createBindGroupCluster, SampleInitFactoryWebGPU } from './utils';\nimport BitonicDisplayRenderer from './bitonicDisplay';\nimport bitonicDisplay from './bitonicDisplay.frag.wgsl';\nimport { NaiveBitonicCompute } from './bitonicCompute';\nimport fullscreenTexturedQuad from '../../shaders/fullscreenTexturedQuad.wgsl';\nimport atomicToZero from './atomicToZero.wgsl';\n\n// Type of step that will be executed in our shader\nenum StepEnum {\n NONE,\n FLIP_LOCAL,\n DISPERSE_LOCAL,\n FLIP_GLOBAL,\n DISPERSE_GLOBAL,\n}\n\ntype StepType =\n // NONE: No sort step has or will occur\n | 'NONE'\n // FLIP_LOCAL: A sort step that performs a flip operation over indices in a workgroup's locally addressable area\n // (i.e invocations * workgroup_index -> invocations * (workgroup_index + 1) - 1.\n | 'FLIP_LOCAL'\n // DISPERSE_LOCAL A sort step that performs a flip operation over indices in a workgroup's locally addressable area.\n | 'DISPERSE_LOCAL'\n // FLIP_GLOBAL A sort step that performs a flip step across a range of indices outside a workgroup's locally addressable area.\n | 'FLIP_GLOBAL'\n // DISPERSE_GLOBAL A sort step that performs a disperse operation across a range of indices outside a workgroup's locally addressable area.\n | 'DISPERSE_GLOBAL';\n\ntype DisplayType = 'Elements' | 'Swap Highlight';\n\ninterface ConfigInfo {\n // Number of sorts executed under a given elements + size limit config\n sorts: number;\n // Total collective time taken to execute each complete sort under this config\n time: number;\n}\n\ninterface StringKeyToNumber {\n [key: string]: ConfigInfo;\n}\n\n// Gui settings object\ninterface SettingsInterface {\n 'Total Elements': number;\n 'Grid Width': number;\n 'Grid Height': number;\n 'Grid Dimensions': string;\n 'Workgroup Size': number;\n 'Size Limit': number;\n 'Workgroups Per Step': number;\n 'Hovered Cell': number;\n 'Swapped Cell': number;\n 'Current Step': string;\n 'Step Index': number;\n 'Total Steps': number;\n 'Prev Step': StepType;\n 'Next Step': StepType;\n 'Prev Swap Span': number;\n 'Next Swap Span': number;\n executeStep: boolean;\n 'Randomize Values': () => void;\n 'Execute Sort Step': () => void;\n 'Log Elements': () => void;\n 'Auto Sort': () => void;\n 'Auto Sort Speed': number;\n 'Display Mode': DisplayType;\n 'Total Swaps': number;\n stepTime: number;\n 'Step Time': string;\n sortTime: number;\n 'Sort Time': string;\n 'Average Sort Time': string;\n configToCompleteSwapsMap: StringKeyToNumber;\n configKey: string;\n}\n\nconst getNumSteps = (numElements: number) => {\n const n = Math.log2(numElements);\n return (n * (n + 1)) / 2;\n};\n\nlet init: SampleInit;\nSampleInitFactoryWebGPU(\n async ({\n pageState,\n device,\n gui,\n presentationFormat,\n context,\n canvas,\n timestampQueryAvailable,\n }) => {\n const maxInvocationsX = device.limits.maxComputeWorkgroupSizeX;\n\n let querySet: GPUQuerySet;\n let timestampQueryResolveBuffer: GPUBuffer;\n let timestampQueryResultBuffer: GPUBuffer;\n if (timestampQueryAvailable) {\n querySet = device.createQuerySet({ type: 'timestamp', count: 2 });\n timestampQueryResolveBuffer = device.createBuffer({\n // 2 timestamps * BigInt size for nanoseconds\n size: 2 * BigInt64Array.BYTES_PER_ELEMENT,\n usage: GPUBufferUsage.QUERY_RESOLVE | GPUBufferUsage.COPY_SRC,\n });\n timestampQueryResultBuffer = device.createBuffer({\n // 2 timestamps * BigInt size for nanoseconds\n size: 2 * BigInt64Array.BYTES_PER_ELEMENT,\n usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ,\n });\n }\n\n const totalElementOptions = [];\n const maxElements = maxInvocationsX * 32;\n for (let i = maxElements; i >= 4; i /= 2) {\n totalElementOptions.push(i);\n }\n\n const sizeLimitOptions: number[] = [];\n for (let i = maxInvocationsX; i >= 2; i /= 2) {\n sizeLimitOptions.push(i);\n }\n\n const defaultGridWidth =\n Math.sqrt(maxElements) % 2 === 0\n ? Math.floor(Math.sqrt(maxElements))\n : Math.floor(Math.sqrt(maxElements / 2));\n\n const defaultGridHeight = maxElements / defaultGridWidth;\n\n const settings: SettingsInterface = {\n // TOTAL ELEMENT AND GRID SETTINGS\n // The number of elements to be sorted. Must equal gridWidth * gridHeight || Workgroup Size * Workgroups * 2.\n // When changed, all relevant values within the settings object are reset to their defaults at the beginning of a sort with n elements.\n 'Total Elements': maxElements,\n // The width of the screen in cells.\n 'Grid Width': defaultGridWidth,\n // The height of the screen in cells.\n 'Grid Height': defaultGridHeight,\n // Grid Dimensions as string\n 'Grid Dimensions': `${defaultGridWidth}x${defaultGridHeight}`,\n\n // INVOCATION, WORKGROUP SIZE, AND WORKGROUP DISPATCH SETTINGS\n // The size of a workgroup, or the number of invocations executed within each workgroup\n // Determined algorithmically based on 'Size Limit', maxInvocationsX, and the current number of elements to sort\n 'Workgroup Size': maxInvocationsX,\n // An artifical constraint on the maximum workgroup size/maximumn invocations per workgroup as specified by device.limits.maxComputeWorkgroupSizeX\n 'Size Limit': maxInvocationsX,\n // Total workgroups that are dispatched during each step of the bitonic sort\n 'Workgroups Per Step': maxElements / (maxInvocationsX * 2),\n\n // HOVER SETTINGS\n // The element/cell in the element visualizer directly beneath the mouse cursor\n 'Hovered Cell': 0,\n // The element/cell in the element visualizer that the hovered cell will swap with in the next execution step of the bitonic sort.\n 'Swapped Cell': 1,\n\n // STEP INDEX, STEP TYPE, AND STEP SWAP SPAN SETTINGS\n // The index of the current step in the bitonic sort.\n 'Step Index': 0,\n // The total number of steps required to sort the displayed elements.\n 'Total Steps': getNumSteps(maxElements),\n // A string that condenses 'Step Index' and 'Total Steps' into a single GUI Controller display element.\n 'Current Step': `0 of 91`,\n // The category of the previously executed step. Always begins the bitonic sort with a value of 'NONE' and ends with a value of 'DISPERSE_LOCAL'\n 'Prev Step': 'NONE',\n // The category of the next step that will be executed. Always begins the bitonic sort with a value of 'FLIP_LOCAL' and ends with a value of 'NONE'\n 'Next Step': 'FLIP_LOCAL',\n // The maximum span of a swap operation in the sort's previous step.\n 'Prev Swap Span': 0,\n // The maximum span of a swap operation in the sort's upcoming step.\n 'Next Swap Span': 2,\n\n // ANIMATION LOOP AND FUNCTION SETTINGS\n // A flag that designates whether we will dispatch a workload this frame.\n executeStep: false,\n // A function that randomizes the values of each element.\n // When called, all relevant values within the settings object are reset to their defaults at the beginning of a sort with n elements.\n 'Randomize Values': () => {\n return;\n },\n // A function that manually executes a single step of the bitonic sort.\n 'Execute Sort Step': () => {\n return;\n },\n // A function that logs the values of each element as an array to the browser's console.\n 'Log Elements': () => {\n return;\n },\n // A function that automatically executes each step of the bitonic sort at an interval determined by 'Auto Sort Speed'\n 'Auto Sort': () => {\n return;\n },\n // The speed at which each step of the bitonic sort will be executed after 'Auto Sort' has been called.\n 'Auto Sort Speed': 50,\n\n // MISCELLANEOUS SETTINGS\n 'Display Mode': 'Elements',\n // An atomic value representing the total number of swap operations executed over the course of the bitonic sort.\n 'Total Swaps': 0,\n\n // TIMESTAMP SETTINGS\n // NOTE: Timestep values below all are calculated in terms of milliseconds rather than the nanoseconds a timestamp query set usually outputs.\n // Time taken to execute the previous step of the bitonic sort in milliseconds\n 'Step Time': '0ms',\n stepTime: 0,\n // Total taken to colletively execute each step of the complete bitonic sort, represented in milliseconds.\n 'Sort Time': '0ms',\n sortTime: 0,\n // Average time taken to complete a bitonic sort with the current combination of n 'Total Elements' and x 'Size Limit'\n 'Average Sort Time': '0ms',\n // A string to number map that maps a string representation of the current 'Total Elements' + 'Size Limit' configuration to a number\n // representing the total number of sorts that have been executed under that same configuration.\n configToCompleteSwapsMap: {\n '8192 256': {\n sorts: 0,\n time: 0,\n },\n },\n // Current key into configToCompleteSwapsMap\n configKey: '8192 256',\n };\n\n // Initialize initial elements array\n let elements = new Uint32Array(\n Array.from({ length: settings['Total Elements'] }, (_, i) => i)\n );\n\n // Initialize elementsBuffer and elementsStagingBuffer\n const elementsBufferSize =\n Float32Array.BYTES_PER_ELEMENT * totalElementOptions[0];\n // Initialize input, output, staging buffers\n const elementsInputBuffer = device.createBuffer({\n size: elementsBufferSize,\n usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,\n });\n const elementsOutputBuffer = device.createBuffer({\n size: elementsBufferSize,\n usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC,\n });\n const elementsStagingBuffer = device.createBuffer({\n size: elementsBufferSize,\n usage: GPUBufferUsage.MAP_READ | GPUBufferUsage.COPY_DST,\n });\n\n // Initialize atomic swap buffer on GPU and CPU. Counts number of swaps actually performed by\n // compute shader (when value at index x is greater than value at index y)\n const atomicSwapsOutputBuffer = device.createBuffer({\n size: Uint32Array.BYTES_PER_ELEMENT,\n usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC,\n });\n const atomicSwapsStagingBuffer = device.createBuffer({\n size: Uint32Array.BYTES_PER_ELEMENT,\n usage: GPUBufferUsage.MAP_READ | GPUBufferUsage.COPY_DST,\n });\n\n // Create uniform buffer for compute shader\n const computeUniformsBuffer = device.createBuffer({\n // width, height, blockHeight, algo\n size: Float32Array.BYTES_PER_ELEMENT * 4,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n });\n\n const computeBGCluster = createBindGroupCluster(\n [0, 1, 2, 3],\n [\n GPUShaderStage.COMPUTE | GPUShaderStage.FRAGMENT,\n GPUShaderStage.COMPUTE,\n GPUShaderStage.COMPUTE | GPUShaderStage.FRAGMENT,\n GPUShaderStage.COMPUTE,\n ],\n ['buffer', 'buffer', 'buffer', 'buffer'],\n [\n { type: 'read-only-storage' },\n { type: 'storage' },\n { type: 'uniform' },\n { type: 'storage' },\n ],\n [\n [\n { buffer: elementsInputBuffer },\n { buffer: elementsOutputBuffer },\n { buffer: computeUniformsBuffer },\n { buffer: atomicSwapsOutputBuffer },\n ],\n ],\n 'BitonicSort',\n device\n );\n\n let computePipeline = device.createComputePipeline({\n layout: device.createPipelineLayout({\n bindGroupLayouts: [computeBGCluster.bindGroupLayout],\n }),\n compute: {\n module: device.createShaderModule({\n code: NaiveBitonicCompute(settings['Workgroup Size']),\n }),\n entryPoint: 'computeMain',\n },\n });\n\n // Simple pipeline that zeros out an atomic value at group 0 binding 3\n const atomicToZeroComputePipeline = device.createComputePipeline({\n layout: device.createPipelineLayout({\n bindGroupLayouts: [computeBGCluster.bindGroupLayout],\n }),\n compute: {\n module: device.createShaderModule({\n code: atomicToZero,\n }),\n entryPoint: 'atomicToZero',\n },\n });\n\n // Create bitonic debug renderer\n const renderPassDescriptor: GPURenderPassDescriptor = {\n colorAttachments: [\n {\n view: undefined, // Assigned later\n\n clearValue: { r: 0.1, g: 0.4, b: 0.5, a: 1.0 },\n loadOp: 'clear',\n storeOp: 'store',\n },\n ],\n };\n\n const bitonicDisplayRenderer = new BitonicDisplayRenderer(\n device,\n presentationFormat,\n renderPassDescriptor,\n computeBGCluster,\n 'BitonicDisplay'\n );\n\n const resetTimeInfo = () => {\n settings.stepTime = 0;\n settings.sortTime = 0;\n stepTimeController.setValue('0ms');\n sortTimeController.setValue(`0ms`);\n const nanCheck =\n settings.configToCompleteSwapsMap[settings.configKey].time /\n settings.configToCompleteSwapsMap[settings.configKey].sorts;\n const ast = nanCheck ? nanCheck : 0;\n averageSortTimeController.setValue(`${ast.toFixed(5)}ms`);\n };\n\n const resetExecutionInformation = () => {\n // The workgroup size is either elements / 2 or Size Limit\n workgroupSizeController.setValue(\n Math.min(settings['Total Elements'] / 2, settings['Size Limit'])\n );\n\n // Dispatch a workgroup for every (Size Limit * 2) elements\n const workgroupsPerStep =\n (settings['Total Elements'] - 1) / (settings['Size Limit'] * 2);\n\n workgroupsPerStepController.setValue(Math.ceil(workgroupsPerStep));\n\n // Reset step Index and number of steps based on elements size\n settings['Step Index'] = 0;\n settings['Total Steps'] = getNumSteps(settings['Total Elements']);\n currentStepController.setValue(\n `${settings['Step Index']} of ${settings['Total Steps']}`\n );\n\n // Get new width and height of screen display in cells\n const newCellWidth =\n Math.sqrt(settings['Total Elements']) % 2 === 0\n ? Math.floor(Math.sqrt(settings['Total Elements']))\n : Math.floor(Math.sqrt(settings['Total Elements'] / 2));\n const newCellHeight = settings['Total Elements'] / newCellWidth;\n settings['Grid Width'] = newCellWidth;\n settings['Grid Height'] = newCellHeight;\n gridDimensionsController.setValue(`${newCellWidth}x${newCellHeight}`);\n\n // Set prevStep to None (restart) and next step to FLIP\n prevStepController.setValue('NONE');\n nextStepController.setValue('FLIP_LOCAL');\n\n // Reset block heights\n prevBlockHeightController.setValue(0);\n nextBlockHeightController.setValue(2);\n\n // Reset Total Swaps by setting atomic value to 0\n const commandEncoder = device.createCommandEncoder();\n const computePassEncoder = commandEncoder.beginComputePass();\n computePassEncoder.setPipeline(atomicToZeroComputePipeline);\n computePassEncoder.setBindGroup(0, computeBGCluster.bindGroups[0]);\n computePassEncoder.dispatchWorkgroups(1);\n computePassEncoder.end();\n device.queue.submit([commandEncoder.finish()]);\n totalSwapsController.setValue(0);\n\n highestBlockHeight = 2;\n };\n\n const randomizeElementArray = () => {\n let currentIndex = elements.length;\n // While there are elements to shuffle\n while (currentIndex !== 0) {\n // Pick a remaining element\n const randomIndex = Math.floor(Math.random() * currentIndex);\n currentIndex -= 1;\n [elements[currentIndex], elements[randomIndex]] = [\n elements[randomIndex],\n elements[currentIndex],\n ];\n }\n };\n\n const resizeElementArray = () => {\n // Recreate elements array with new length\n elements = new Uint32Array(\n Array.from({ length: settings['Total Elements'] }, (_, i) => i)\n );\n\n resetExecutionInformation();\n\n // Create new shader invocation with workgroupSize that reflects number of invocations\n computePipeline = device.createComputePipeline({\n layout: device.createPipelineLayout({\n bindGroupLayouts: [computeBGCluster.bindGroupLayout],\n }),\n compute: {\n module: device.createShaderModule({\n code: NaiveBitonicCompute(\n Math.min(settings['Total Elements'] / 2, settings['Size Limit'])\n ),\n }),\n entryPoint: 'computeMain',\n },\n });\n // Randomize array elements\n randomizeElementArray();\n highestBlockHeight = 2;\n };\n\n randomizeElementArray();\n\n const setSwappedCell = () => {\n let swappedIndex: number;\n switch (settings['Next Step']) {\n case 'FLIP_LOCAL':\n case 'FLIP_GLOBAL':\n {\n const blockHeight = settings['Next Swap Span'];\n const p2 = Math.floor(settings['Hovered Cell'] / blockHeight) + 1;\n const p3 = settings['Hovered Cell'] % blockHeight;\n swappedIndex = blockHeight * p2 - p3 - 1;\n swappedCellController.setValue(swappedIndex);\n }\n break;\n case 'DISPERSE_LOCAL':\n {\n const blockHeight = settings['Next Swap Span'];\n const halfHeight = blockHeight / 2;\n swappedIndex =\n settings['Hovered Cell'] % blockHeight < halfHeight\n ? settings['Hovered Cell'] + halfHeight\n : settings['Hovered Cell'] - halfHeight;\n swappedCellController.setValue(swappedIndex);\n }\n break;\n case 'NONE': {\n swappedIndex = settings['Hovered Cell'];\n swappedCellController.setValue(swappedIndex);\n }\n default:\n {\n swappedIndex = settings['Hovered Cell'];\n swappedCellController.setValue(swappedIndex);\n }\n break;\n }\n };\n\n let autoSortIntervalID: ReturnType | null = null;\n const endSortInterval = () => {\n if (autoSortIntervalID !== null) {\n clearInterval(autoSortIntervalID);\n autoSortIntervalID = null;\n }\n };\n const startSortInterval = () => {\n const currentIntervalSpeed = settings['Auto Sort Speed'];\n autoSortIntervalID = setInterval(() => {\n if (settings['Next Step'] === 'NONE') {\n clearInterval(autoSortIntervalID);\n autoSortIntervalID = null;\n sizeLimitController.domElement.style.pointerEvents = 'auto';\n }\n if (settings['Auto Sort Speed'] !== currentIntervalSpeed) {\n clearInterval(autoSortIntervalID);\n autoSortIntervalID = null;\n startSortInterval();\n }\n settings.executeStep = true;\n setSwappedCell();\n }, settings['Auto Sort Speed']);\n };\n\n // At top level, information about resources used to execute the compute shader\n // i.e elements sorted, invocations per workgroup, and workgroups dispatched\n const computeResourcesFolder = gui.addFolder('Compute Resources');\n computeResourcesFolder\n .add(settings, 'Total Elements', totalElementOptions)\n .onChange(() => {\n endSortInterval();\n resizeElementArray();\n sizeLimitController.domElement.style.pointerEvents = 'auto';\n // Create new config key for current element + size limit configuration\n const currConfigKey = `${settings['Total Elements']} ${settings['Size Limit']}`;\n // If configKey doesn't exist in the map, create it.\n if (!settings.configToCompleteSwapsMap[currConfigKey]) {\n settings.configToCompleteSwapsMap[currConfigKey] = {\n sorts: 0,\n time: 0,\n };\n }\n settings.configKey = currConfigKey;\n resetTimeInfo();\n });\n const sizeLimitController = computeResourcesFolder\n .add(settings, 'Size Limit', sizeLimitOptions)\n .onChange(() => {\n // Change total workgroups per step and size of a workgroup based on arbitrary constraint\n // imposed by size limit.\n const constraint = Math.min(\n settings['Total Elements'] / 2,\n settings['Size Limit']\n );\n const workgroupsPerStep =\n (settings['Total Elements'] - 1) / (settings['Size Limit'] * 2);\n workgroupSizeController.setValue(constraint);\n workgroupsPerStepController.setValue(Math.ceil(workgroupsPerStep));\n // Apply new compute resources values to the sort's compute pipeline\n computePipeline = computePipeline = device.createComputePipeline({\n layout: device.createPipelineLayout({\n bindGroupLayouts: [computeBGCluster.bindGroupLayout],\n }),\n compute: {\n module: device.createShaderModule({\n code: NaiveBitonicCompute(\n Math.min(settings['Total Elements'] / 2, settings['Size Limit'])\n ),\n }),\n entryPoint: 'computeMain',\n },\n });\n // Create new config key for current element + size limit configuration\n const currConfigKey = `${settings['Total Elements']} ${settings['Size Limit']}`;\n // If configKey doesn't exist in the map, create it.\n if (!settings.configToCompleteSwapsMap[currConfigKey]) {\n settings.configToCompleteSwapsMap[currConfigKey] = {\n sorts: 0,\n time: 0,\n };\n }\n settings.configKey = currConfigKey;\n resetTimeInfo();\n });\n const workgroupSizeController = computeResourcesFolder.add(\n settings,\n 'Workgroup Size'\n );\n const workgroupsPerStepController = computeResourcesFolder.add(\n settings,\n 'Workgroups Per Step'\n );\n\n computeResourcesFolder.open();\n\n // Folder with functions that control the execution of the sort\n const controlFolder = gui.addFolder('Sort Controls');\n controlFolder.add(settings, 'Execute Sort Step').onChange(() => {\n // Size Limit locked upon sort\n sizeLimitController.domElement.style.pointerEvents = 'none';\n endSortInterval();\n settings.executeStep = true;\n });\n controlFolder.add(settings, 'Randomize Values').onChange(() => {\n endSortInterval();\n randomizeElementArray();\n resetExecutionInformation();\n resetTimeInfo();\n // Unlock workgroup size limit controller since sort has stopped\n sizeLimitController.domElement.style.pointerEvents = 'auto';\n });\n controlFolder\n .add(settings, 'Log Elements')\n .onChange(() => console.log(elements));\n controlFolder.add(settings, 'Auto Sort').onChange(() => {\n // Invocation Limit locked upon sort\n sizeLimitController.domElement.style.pointerEvents = 'none';\n startSortInterval();\n });\n controlFolder.add(settings, 'Auto Sort Speed', 50, 1000).step(50);\n controlFolder.open();\n\n // Information about grid display\n const gridFolder = gui.addFolder('Grid Information');\n gridFolder.add(settings, 'Display Mode', ['Elements', 'Swap Highlight']);\n const gridDimensionsController = gridFolder.add(\n settings,\n 'Grid Dimensions'\n );\n const hoveredCellController = gridFolder\n .add(settings, 'Hovered Cell')\n .onChange(setSwappedCell);\n const swappedCellController = gridFolder.add(settings, 'Swapped Cell');\n\n // Additional Information about the execution state of the sort\n const executionInformationFolder = gui.addFolder('Execution Information');\n const currentStepController = executionInformationFolder.add(\n settings,\n 'Current Step'\n );\n const prevStepController = executionInformationFolder.add(\n settings,\n 'Prev Step'\n );\n const nextStepController = executionInformationFolder.add(\n settings,\n 'Next Step'\n );\n const totalSwapsController = executionInformationFolder.add(\n settings,\n 'Total Swaps'\n );\n const prevBlockHeightController = executionInformationFolder.add(\n settings,\n 'Prev Swap Span'\n );\n const nextBlockHeightController = executionInformationFolder.add(\n settings,\n 'Next Swap Span'\n );\n\n // Timestamp information for Chrome 121+ or other compatible browsers\n const timestampFolder = gui.addFolder('Timestamp Info (Chrome 121+)');\n const stepTimeController = timestampFolder.add(settings, 'Step Time');\n const sortTimeController = timestampFolder.add(settings, 'Sort Time');\n const averageSortTimeController = timestampFolder.add(\n settings,\n 'Average Sort Time'\n );\n\n // Adjust styles of Function List Elements within GUI\n const liFunctionElements = document.getElementsByClassName('cr function');\n for (let i = 0; i < liFunctionElements.length; i++) {\n (liFunctionElements[i].children[0] as HTMLElement).style.display = 'flex';\n (liFunctionElements[i].children[0] as HTMLElement).style.justifyContent =\n 'center';\n (\n liFunctionElements[i].children[0].children[1] as HTMLElement\n ).style.position = 'absolute';\n }\n\n // Mouse listener that determines values of hoveredCell and swappedCell\n canvas.addEventListener('mousemove', (event) => {\n const currWidth = canvas.getBoundingClientRect().width;\n const currHeight = canvas.getBoundingClientRect().height;\n const cellSize: [number, number] = [\n currWidth / settings['Grid Width'],\n currHeight / settings['Grid Height'],\n ];\n const xIndex = Math.floor(event.offsetX / cellSize[0]);\n const yIndex =\n settings['Grid Height'] - 1 - Math.floor(event.offsetY / cellSize[1]);\n hoveredCellController.setValue(yIndex * settings['Grid Width'] + xIndex);\n settings['Hovered Cell'] = yIndex * settings['Grid Width'] + xIndex;\n });\n\n // Deactivate interaction with select GUI elements\n sizeLimitController.domElement.style.pointerEvents = 'none';\n workgroupsPerStepController.domElement.style.pointerEvents = 'none';\n hoveredCellController.domElement.style.pointerEvents = 'none';\n swappedCellController.domElement.style.pointerEvents = 'none';\n currentStepController.domElement.style.pointerEvents = 'none';\n prevStepController.domElement.style.pointerEvents = 'none';\n prevBlockHeightController.domElement.style.pointerEvents = 'none';\n nextStepController.domElement.style.pointerEvents = 'none';\n nextBlockHeightController.domElement.style.pointerEvents = 'none';\n workgroupSizeController.domElement.style.pointerEvents = 'none';\n gridDimensionsController.domElement.style.pointerEvents = 'none';\n totalSwapsController.domElement.style.pointerEvents = 'none';\n stepTimeController.domElement.style.pointerEvents = 'none';\n sortTimeController.domElement.style.pointerEvents = 'none';\n averageSortTimeController.domElement.style.pointerEvents = 'none';\n gui.width = 325;\n\n let highestBlockHeight = 2;\n\n startSortInterval();\n\n async function frame() {\n if (!pageState.active) return;\n\n // Write elements buffer\n device.queue.writeBuffer(\n elementsInputBuffer,\n 0,\n elements.buffer,\n elements.byteOffset,\n elements.byteLength\n );\n\n const dims = new Float32Array([\n settings['Grid Width'],\n settings['Grid Height'],\n ]);\n const stepDetails = new Uint32Array([\n StepEnum[settings['Next Step']],\n settings['Next Swap Span'],\n ]);\n device.queue.writeBuffer(\n computeUniformsBuffer,\n 0,\n dims.buffer,\n dims.byteOffset,\n dims.byteLength\n );\n\n device.queue.writeBuffer(computeUniformsBuffer, 8, stepDetails);\n\n renderPassDescriptor.colorAttachments[0].view = context\n .getCurrentTexture()\n .createView();\n\n const commandEncoder = device.createCommandEncoder();\n bitonicDisplayRenderer.startRun(commandEncoder, {\n highlight: settings['Display Mode'] === 'Elements' ? 0 : 1,\n });\n if (\n settings.executeStep &&\n highestBlockHeight < settings['Total Elements'] * 2\n ) {\n let computePassEncoder: GPUComputePassEncoder;\n if (timestampQueryAvailable) {\n computePassEncoder = commandEncoder.beginComputePass({\n timestampWrites: {\n querySet,\n beginningOfPassWriteIndex: 0,\n endOfPassWriteIndex: 1,\n },\n });\n } else {\n computePassEncoder = commandEncoder.beginComputePass();\n }\n computePassEncoder.setPipeline(computePipeline);\n computePassEncoder.setBindGroup(0, computeBGCluster.bindGroups[0]);\n computePassEncoder.dispatchWorkgroups(settings['Workgroups Per Step']);\n computePassEncoder.end();\n // Resolve time passed in between beginning and end of computePass\n if (timestampQueryAvailable) {\n commandEncoder.resolveQuerySet(\n querySet,\n 0,\n 2,\n timestampQueryResolveBuffer,\n 0\n );\n commandEncoder.copyBufferToBuffer(\n timestampQueryResolveBuffer,\n 0,\n timestampQueryResultBuffer,\n 0,\n 2 * BigInt64Array.BYTES_PER_ELEMENT\n );\n }\n settings['Step Index'] = settings['Step Index'] + 1;\n currentStepController.setValue(\n `${settings['Step Index']} of ${settings['Total Steps']}`\n );\n prevStepController.setValue(settings['Next Step']);\n prevBlockHeightController.setValue(settings['Next Swap Span']);\n nextBlockHeightController.setValue(settings['Next Swap Span'] / 2);\n // Each cycle of a bitonic sort contains a flip operation followed by multiple disperse operations\n // Next Swap Span will equal one when the sort needs to begin a new cycle of flip and disperse operations\n if (settings['Next Swap Span'] === 1) {\n // The next cycle's flip operation will have a maximum swap span 2 times that of the previous cycle\n highestBlockHeight *= 2;\n if (highestBlockHeight === settings['Total Elements'] * 2) {\n // The next cycle's maximum swap span exceeds the total number of elements. Therefore, the sort is over.\n // Accordingly, there will be no next step.\n nextStepController.setValue('NONE');\n // And if there is no next step, then there are no swaps, and no block range within which two elements are swapped.\n nextBlockHeightController.setValue(0);\n // Finally, with our sort completed, we can increment the number of total completed sorts executed with n 'Total Elements'\n // and x 'Size Limit', which will allow us to calculate the average time of all sorts executed with this specific\n // configuration of compute resources\n settings.configToCompleteSwapsMap[settings.configKey].sorts += 1;\n } else if (highestBlockHeight > settings['Workgroup Size'] * 2) {\n // The next cycle's maximum swap span exceeds the range of a single workgroup, so our next flip will operate on global indices.\n nextStepController.setValue('FLIP_GLOBAL');\n nextBlockHeightController.setValue(highestBlockHeight);\n } else {\n // The next cycle's maximum swap span can be executed on a range of indices local to the workgroup.\n nextStepController.setValue('FLIP_LOCAL');\n nextBlockHeightController.setValue(highestBlockHeight);\n }\n } else {\n // Otherwise, execute the next disperse operation\n settings['Next Swap Span'] > settings['Workgroup Size'] * 2\n ? nextStepController.setValue('DISPERSE_GLOBAL')\n : nextStepController.setValue('DISPERSE_LOCAL');\n }\n\n // Copy GPU accessible buffers to CPU accessible buffers\n commandEncoder.copyBufferToBuffer(\n elementsOutputBuffer,\n 0,\n elementsStagingBuffer,\n 0,\n elementsBufferSize\n );\n\n commandEncoder.copyBufferToBuffer(\n atomicSwapsOutputBuffer,\n 0,\n atomicSwapsStagingBuffer,\n 0,\n Uint32Array.BYTES_PER_ELEMENT\n );\n }\n device.queue.submit([commandEncoder.finish()]);\n\n if (\n settings.executeStep &&\n highestBlockHeight < settings['Total Elements'] * 4\n ) {\n // Copy GPU element data to CPU\n await elementsStagingBuffer.mapAsync(\n GPUMapMode.READ,\n 0,\n elementsBufferSize\n );\n const copyElementsBuffer = elementsStagingBuffer.getMappedRange(\n 0,\n elementsBufferSize\n );\n // Copy atomic swaps data to CPU\n await atomicSwapsStagingBuffer.mapAsync(\n GPUMapMode.READ,\n 0,\n Uint32Array.BYTES_PER_ELEMENT\n );\n const copySwapsBuffer = atomicSwapsStagingBuffer.getMappedRange(\n 0,\n Uint32Array.BYTES_PER_ELEMENT\n );\n const elementsData = copyElementsBuffer.slice(\n 0,\n Uint32Array.BYTES_PER_ELEMENT * settings['Total Elements']\n );\n const swapsData = copySwapsBuffer.slice(\n 0,\n Uint32Array.BYTES_PER_ELEMENT\n );\n // Extract data\n const elementsOutput = new Uint32Array(elementsData);\n totalSwapsController.setValue(new Uint32Array(swapsData)[0]);\n elementsStagingBuffer.unmap();\n atomicSwapsStagingBuffer.unmap();\n // Elements output becomes elements input, swap accumulate\n elements = elementsOutput;\n setSwappedCell();\n\n // Handle timestamp query stuff\n if (timestampQueryAvailable) {\n // Copy timestamp query result buffer data to CPU\n await timestampQueryResultBuffer.mapAsync(\n GPUMapMode.READ,\n 0,\n 2 * BigInt64Array.BYTES_PER_ELEMENT\n );\n const copyTimestampResult = new BigInt64Array(\n timestampQueryResultBuffer.getMappedRange()\n );\n // Calculate new step, sort, and average sort times\n const newStepTime =\n Number(copyTimestampResult[1] - copyTimestampResult[0]) / 1000000;\n const newSortTime = settings.sortTime + newStepTime;\n // Apply calculated times to settings object as both number and 'ms' appended string\n settings.stepTime = newStepTime;\n settings.sortTime = newSortTime;\n stepTimeController.setValue(`${newStepTime.toFixed(5)}ms`);\n sortTimeController.setValue(`${newSortTime.toFixed(5)}ms`);\n // Calculate new average sort upon end of final execution step of a full bitonic sort.\n if (highestBlockHeight === settings['Total Elements'] * 2) {\n // Lock off access to this larger if block..not best architected solution but eh\n highestBlockHeight *= 2;\n settings.configToCompleteSwapsMap[settings.configKey].time +=\n newSortTime;\n const averageSortTime =\n settings.configToCompleteSwapsMap[settings.configKey].time /\n settings.configToCompleteSwapsMap[settings.configKey].sorts;\n averageSortTimeController.setValue(\n `${averageSortTime.toFixed(5)}ms`\n );\n }\n timestampQueryResultBuffer.unmap();\n // Get correct range of data from CPU copy of GPU Data\n }\n }\n settings.executeStep = false;\n requestAnimationFrame(frame);\n }\n requestAnimationFrame(frame);\n }\n).then((resultInit) => (init = resultInit));\n\nconst bitonicSortExample: () => JSX.Element = () =>\n makeSample({\n name: 'Bitonic Sort',\n description:\n \"A naive bitonic sort algorithm executed on the GPU, based on tgfrerer's implementation at poniesandlight.co.uk/reflect/bitonic_merge_sort/. Each dispatch of the bitonic sort shader dispatches a workgroup containing elements/2 invocations. The GUI's Execution Information folder contains information about the sort's current state. The visualizer displays the sort's results as colored cells sorted from brightest to darkest.\",\n init,\n gui: true,\n sources: [\n {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n },\n BitonicDisplayRenderer.sourceInfo,\n {\n name: '../../../shaders/fullscreenTexturedQuad.vert.wgsl',\n contents: fullscreenTexturedQuad,\n },\n {\n name: './bitonicDisplay.frag.wgsl',\n contents: bitonicDisplay,\n },\n {\n name: './bitonicCompute.ts',\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n contents: require('!!raw-loader!./bitonicCompute.ts').default,\n },\n {\n name: './atomicToZero.wgsl',\n contents: atomicToZero,\n },\n ],\n filename: __filename,\n });\n\nexport default bitonicSortExample;\n"},u.sourceInfo,{name:"../../../shaders/fullscreenTexturedQuad.vert.wgsl",contents:p.Z},{name:"./bitonicDisplay.frag.wgsl",contents:l},{name:"./bitonicCompute.ts",contents:t(6502).Z},{name:"./atomicToZero.wgsl",contents:d}],filename:m});var h=g},7606:function(e,n,t){"use strict";t.d(n,{NJ:function(){return a},Ot:function(){return i},a1:function(){return r}});var o=t(134);let r=(e,n,t,o,r,i,a)=>{let s=[];for(let l=0;l{let n=async n=>{let t,{canvas:o,pageState:r,gui:i,stats:a}=n,s=await navigator.gpu.requestAdapter(),l=s.features.has("timestamp-query");if(t=l?await s.requestDevice({requiredFeatures:["timestamp-query"]}):await s.requestDevice(),!r.active)return;let u=o.getContext("webgpu"),c=window.devicePixelRatio;o.width=o.clientWidth*c,o.height=o.clientHeight*c;let p=navigator.gpu.getPreferredCanvasFormat();u.configure({device:t,format:p,alphaMode:"premultiplied"}),e({canvas:o,pageState:r,gui:i,device:t,context:u,presentationFormat:p,stats:a,timestampQueryAvailable:l})};return n};class a{executeRun(e,n,t,o){let r=e.beginRenderPass(n);r.setPipeline(t);for(let i=0;i {\n if (workgroupSize % 2 !== 0 || workgroupSize > 256) {\n workgroupSize = 256;\n }\n // Ensure that workgroupSize is half the number of elements\n return `\n\nstruct Uniforms {\n width: f32,\n height: f32,\n algo: u32,\n blockHeight: u32,\n}\n\n// Create local workgroup data that can contain all elements\nvar local_data: array;\n\n// Define groups (functions refer to this data)\n@group(0) @binding(0) var input_data: array;\n@group(0) @binding(1) var output_data: array;\n@group(0) @binding(2) var uniforms: Uniforms;\n@group(0) @binding(3) var counter: atomic;\n\n// Compare and swap values in local_data\nfn local_compare_and_swap(idx_before: u32, idx_after: u32) {\n //idx_before should always be < idx_after\n if (local_data[idx_after] < local_data[idx_before]) {\n atomicAdd(&counter, 1);\n var temp: u32 = local_data[idx_before];\n local_data[idx_before] = local_data[idx_after];\n local_data[idx_after] = temp;\n }\n return;\n}\n\n// invoke_id goes from 0 to workgroupSize\nfn get_flip_indices(invoke_id: u32, block_height: u32) -> vec2 {\n // Caculate index offset (i.e move indices into correct block)\n let block_offset: u32 = ((2 * invoke_id) / block_height) * block_height;\n let half_height = block_height / 2;\n // Calculate index spacing\n var idx: vec2 = vec2(\n invoke_id % half_height, block_height - (invoke_id % half_height) - 1,\n );\n idx.x += block_offset;\n idx.y += block_offset;\n return idx;\n}\n\nfn get_disperse_indices(invoke_id: u32, block_height: u32) -> vec2 {\n var block_offset: u32 = ((2 * invoke_id) / block_height) * block_height;\n let half_height = block_height / 2;\n var idx: vec2 = vec2(\n invoke_id % half_height, (invoke_id % half_height) + half_height\n );\n idx.x += block_offset;\n idx.y += block_offset;\n return idx;\n}\n\nfn global_compare_and_swap(idx_before: u32, idx_after: u32) {\n if (input_data[idx_after] < input_data[idx_before]) {\n output_data[idx_before] = input_data[idx_after];\n output_data[idx_after] = input_data[idx_before];\n } \n}\n\n// Constants/enum\nconst ALGO_NONE = 0;\nconst ALGO_LOCAL_FLIP = 1;\nconst ALGO_LOCAL_DISPERSE = 2;\nconst ALGO_GLOBAL_FLIP = 3;\n\n// Our compute shader will execute specified # of invocations or elements / 2 invocations\n@compute @workgroup_size(${workgroupSize}, 1, 1)\nfn computeMain(\n @builtin(global_invocation_id) global_id: vec3,\n @builtin(local_invocation_id) local_id: vec3,\n @builtin(workgroup_id) workgroup_id: vec3,\n) {\n\n let offset = ${workgroupSize} * 2 * workgroup_id.x;\n // If we will perform a local swap, then populate the local data\n if (uniforms.algo <= 2) {\n // Assign range of input_data to local_data.\n // Range cannot exceed maxWorkgroupsX * 2\n // Each invocation will populate the workgroup data... (1 invocation for every 2 elements)\n local_data[local_id.x * 2] = input_data[offset + local_id.x * 2];\n local_data[local_id.x * 2 + 1] = input_data[offset + local_id.x * 2 + 1];\n }\n\n //...and wait for each other to finish their own bit of data population.\n workgroupBarrier();\n\n switch uniforms.algo {\n case 1: { // Local Flip\n let idx = get_flip_indices(local_id.x, uniforms.blockHeight);\n local_compare_and_swap(idx.x, idx.y);\n } \n case 2: { // Local Disperse\n let idx = get_disperse_indices(local_id.x, uniforms.blockHeight);\n local_compare_and_swap(idx.x, idx.y);\n } \n case 3: { // Global Flip\n let idx = get_flip_indices(global_id.x, uniforms.blockHeight);\n global_compare_and_swap(idx.x, idx.y);\n }\n case 4: { \n let idx = get_disperse_indices(global_id.x, uniforms.blockHeight);\n global_compare_and_swap(idx.x, idx.y);\n }\n default: { \n \n }\n }\n\n // Ensure that all invocations have swapped their own regions of data\n workgroupBarrier();\n\n if (uniforms.algo <= ALGO_LOCAL_DISPERSE) {\n //Repopulate global data with local data\n output_data[offset + local_id.x * 2] = local_data[local_id.x * 2];\n output_data[offset + local_id.x * 2 + 1] = local_data[local_id.x * 2 + 1];\n }\n\n}`;\n};\n"},134:function(e,n){"use strict";n.Z="@group(0) @binding(0) var mySampler : sampler;\n@group(0) @binding(1) var myTexture : texture_2d;\n\nstruct VertexOutput {\n @builtin(position) Position : vec4,\n @location(0) fragUV : vec2,\n}\n\n@vertex\nfn vert_main(@builtin(vertex_index) VertexIndex : u32) -> VertexOutput {\n const pos = array(\n vec2( 1.0, 1.0),\n vec2( 1.0, -1.0),\n vec2(-1.0, -1.0),\n vec2( 1.0, 1.0),\n vec2(-1.0, -1.0),\n vec2(-1.0, 1.0),\n );\n\n const uv = array(\n vec2(1.0, 0.0),\n vec2(1.0, 1.0),\n vec2(0.0, 1.0),\n vec2(1.0, 0.0),\n vec2(0.0, 1.0),\n vec2(0.0, 0.0),\n );\n\n var output : VertexOutput;\n output.Position = vec4(pos[VertexIndex], 0.0, 1.0);\n output.fragUV = uv[VertexIndex];\n return output;\n}\n\n@fragment\nfn frag_main(@location(0) fragUV : vec2) -> @location(0) vec4 {\n return textureSample(myTexture, mySampler, fragUV);\n}\n"}}]);
\ No newline at end of file
diff --git a/_next/static/chunks/103.a57629bead49e47f.js b/_next/static/chunks/103.a57629bead49e47f.js
deleted file mode 100644
index 5e8fd3bf..00000000
--- a/_next/static/chunks/103.a57629bead49e47f.js
+++ /dev/null
@@ -1 +0,0 @@
-(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[103],{5671:function(e,n,t){"use strict";t.d(n,{Tl:function(){return f},hu:function(){return m}});var r=t(5893),a=t(9008),i=t.n(a),o=t(1163),s=t(7294),c=t(9147),u=t.n(c);t(7319);let l=e=>{let n=(0,s.useRef)(null),a=(0,s.useRef)(null),c=(0,s.useMemo)(()=>e.sources.map(e=>{let{name:n,contents:a}=e;return{name:n,...function(e){let n;let a=null;{a=document.createElement("div");let i=t(4631);n=i(a,{lineNumbers:!0,lineWrapping:!0,theme:"monokai",readOnly:!0})}return{Container:function(t){return(0,r.jsx)("div",{...t,children:(0,r.jsx)("div",{ref(t){a&&t&&(t.appendChild(a),n.setOption("value",e))}})})}}}(a)}}),e.sources),l=(0,s.useRef)(null),f=(0,s.useMemo)(()=>{if(e.gui){let n=t(4376),r=new n.GUI({autoPlace:!1});return r.domElement.style.position="relative",r.domElement.style.zIndex="1000",r}},[]),m=(0,s.useRef)(null),d=(0,s.useMemo)(()=>{if(e.stats){let n=t(2792);return new n}},[]),p=(0,o.useRouter)(),h=p.asPath.match(/#([a-zA-Z0-9\.\/]+)/),[g,x]=(0,s.useState)(null),[v,b]=(0,s.useState)(null);return(0,s.useEffect)(()=>{if(h?b(h[1]):b(c[0].name),f&&l.current)for(l.current.appendChild(f.domElement);f.__controllers.length>0;)f.__controllers[0].remove();d&&m.current&&(d.dom.style.position="absolute",d.showPanel(1),m.current.appendChild(d.dom));let t={active:!0},r=()=>{t.active=!1};try{let a=n.current;if(!a)throw Error("The canvas is not available");let i=e.init({canvas:a,pageState:t,gui:f,stats:d});i instanceof Promise&&i.catch(e=>{console.error(e),x(e)})}catch(o){console.error(o),x(o)}return r},[]),(0,r.jsxs)("main",{children:[(0,r.jsxs)(i(),{children:[(0,r.jsx)("style",{dangerouslySetInnerHTML:{__html:"\n .CodeMirror {\n height: auto !important;\n margin: 1em 0;\n }\n\n .CodeMirror-scroll {\n height: auto !important;\n overflow: visible !important;\n }\n "}}),(0,r.jsx)("title",{children:"".concat(e.name," - WebGPU Samples")}),(0,r.jsx)("meta",{name:"description",content:e.description}),(0,r.jsx)("meta",{httpEquiv:"origin-trial",content:e.originTrial})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("h1",{children:e.name}),(0,r.jsx)("a",{target:"_blank",rel:"noreferrer",href:"https://github.com/".concat("webgpu/webgpu-samples","/tree/main/").concat(e.filename),children:"See it on Github!"}),(0,r.jsx)("p",{children:e.description}),g?(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("p",{children:"Something went wrong. Do your browser and device support WebGPU?"}),(0,r.jsx)("p",{children:"".concat(g)})]}):null]}),(0,r.jsxs)("div",{className:u().canvasContainer,children:[(0,r.jsx)("div",{style:{position:"absolute",left:10},ref:m}),(0,r.jsx)("div",{style:{position:"absolute",right:10},ref:l}),(0,r.jsx)("canvas",{ref:n})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("nav",{className:u().sourceFileNav,ref:a,children:(0,r.jsx)("div",{className:u().sourceFileScrollContainer,onScroll(e){let n=e.currentTarget,t=n.scrollWidth-n.clientWidth-n.scrollLeft;n.scrollLeft>25?a.current.setAttribute("data-left","true"):a.current.setAttribute("data-left","false"),t>25?a.current.setAttribute("data-right","true"):a.current.setAttribute("data-right","false")},children:(0,r.jsx)("ul",{children:c.map((e,n)=>(0,r.jsx)("li",{children:(0,r.jsx)("a",{href:"#".concat(e.name),"data-active":v==e.name,onClick(){b(e.name)},children:e.name})},n))})})}),c.map((e,n)=>(0,r.jsx)(e.Container,{className:u().sourceFileContainer,"data-active":v==e.name},n))]})]})},f=e=>(0,r.jsx)(l,{...e});function m(e,n){if(!e)throw Error(n)}},4655:function(e,n,t){"use strict";t.d(n,{Ax:function(){return i},MO:function(){return o},O$:function(){return r},v8:function(){return a},zS:function(){return s}});let r=40,a=0,i=32,o=36,s=new Float32Array([1,-1,1,1,1,0,1,1,0,1,-1,-1,1,1,0,0,1,1,1,1,-1,-1,-1,1,0,0,0,1,1,0,1,-1,-1,1,1,0,0,1,0,0,1,-1,1,1,1,0,1,1,0,1,-1,-1,-1,1,0,0,0,1,1,0,1,1,1,1,1,1,1,1,0,1,1,-1,1,1,1,0,1,1,1,1,1,-1,-1,1,1,0,0,1,1,0,1,1,-1,1,1,1,0,1,0,0,1,1,1,1,1,1,1,1,0,1,1,-1,-1,1,1,0,0,1,1,0,-1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,-1,1,1,1,0,1,1,0,-1,1,-1,1,0,1,0,1,0,0,-1,1,1,1,0,1,1,1,0,1,1,1,-1,1,1,1,0,1,1,0,-1,-1,1,1,0,0,1,1,0,1,-1,1,1,1,0,1,1,1,1,1,-1,1,-1,1,0,1,0,1,1,0,-1,-1,-1,1,0,0,0,1,0,0,-1,-1,1,1,0,0,1,1,0,1,-1,1,-1,1,0,1,0,1,1,0,1,1,1,1,1,1,1,1,0,1,-1,1,1,1,0,1,1,1,1,1,-1,-1,1,1,0,0,1,1,1,0,-1,-1,1,1,0,0,1,1,1,0,1,-1,1,1,1,0,1,1,0,0,1,1,1,1,1,1,1,1,0,1,1,-1,-1,1,1,0,0,1,0,1,-1,-1,-1,1,0,0,0,1,1,1,-1,1,-1,1,0,1,0,1,1,0,1,1,-1,1,1,1,0,1,0,0,1,-1,-1,1,1,0,0,1,0,1,-1,1,-1,1,0,1,0,1,1,0])},5103:function(e,n,t){"use strict";t.r(n),t.d(n,{default:function(){return f}});var r=t(6416),a=t(5671),i=t(4655),o=t(3569),s="@binding(1) @group(0) var mySampler: sampler;\n@binding(2) @group(0) var myTexture: texture_2d;\n\n@fragment\nfn main(\n @location(0) fragUV: vec2,\n @location(1) fragPosition: vec4\n) -> @location(0) vec4 {\n let texColor = textureSample(myTexture, mySampler, fragUV * 0.8 + vec2(0.1));\n let f = select(1.0, 0.0, length(texColor.rgb - vec3(0.5)) < 0.01);\n return f * texColor + (1.0 - f) * fragPosition;\n}\n",c="src/sample/fractalCube/main.ts";let u=async e=>{let{canvas:n,pageState:t}=e,a=await navigator.gpu.requestAdapter(),c=await a.requestDevice();if(!t.active)return;let u=n.getContext("webgpu"),l=window.devicePixelRatio;n.width=n.clientWidth*l,n.height=n.clientHeight*l;let f=navigator.gpu.getPreferredCanvasFormat();u.configure({device:c,format:f,usage:GPUTextureUsage.RENDER_ATTACHMENT|GPUTextureUsage.COPY_SRC,alphaMode:"premultiplied"});let m=c.createBuffer({size:i.zS.byteLength,usage:GPUBufferUsage.VERTEX,mappedAtCreation:!0});new Float32Array(m.getMappedRange()).set(i.zS),m.unmap();let d=c.createRenderPipeline({layout:"auto",vertex:{module:c.createShaderModule({code:o.Z}),entryPoint:"main",buffers:[{arrayStride:i.O$,attributes:[{shaderLocation:0,offset:i.v8,format:"float32x4"},{shaderLocation:1,offset:i.Ax,format:"float32x2"}]}]},fragment:{module:c.createShaderModule({code:s}),entryPoint:"main",targets:[{format:f}]},primitive:{topology:"triangle-list",cullMode:"back"},depthStencil:{depthWriteEnabled:!0,depthCompare:"less",format:"depth24plus"}}),p=c.createTexture({size:[n.width,n.height],format:"depth24plus",usage:GPUTextureUsage.RENDER_ATTACHMENT}),h=c.createBuffer({size:64,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST}),g=c.createTexture({size:[n.width,n.height],format:f,usage:GPUTextureUsage.TEXTURE_BINDING|GPUTextureUsage.COPY_DST}),x=c.createSampler({magFilter:"linear",minFilter:"linear"}),v=c.createBindGroup({layout:d.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:h}},{binding:1,resource:x},{binding:2,resource:g.createView()}]}),b={colorAttachments:[{view:void 0,clearValue:{r:.5,g:.5,b:.5,a:1},loadOp:"clear",storeOp:"store"}],depthStencilAttachment:{view:p.createView(),depthClearValue:1,depthLoadOp:"clear",depthStoreOp:"store"}},w=n.width/n.height,S=r._E.perspective(2*Math.PI/5,w,1,100),C=r._E.create();requestAnimationFrame(function e(){if(!t.active)return;let a=function(){let e=r._E.identity();r._E.translate(e,r.R3.fromValues(0,0,-4),e);let n=Date.now()/1e3;return r._E.rotate(e,r.R3.fromValues(Math.sin(n),Math.cos(n),0),1,e),r._E.multiply(S,e,C),C}();c.queue.writeBuffer(h,0,a.buffer,a.byteOffset,a.byteLength);let o=u.getCurrentTexture();b.colorAttachments[0].view=o.createView();let s=c.createCommandEncoder(),l=s.beginRenderPass(b);l.setPipeline(d),l.setBindGroup(0,v),l.setVertexBuffer(0,m),l.draw(i.MO),l.end(),s.copyTextureToTexture({texture:o},{texture:g},[n.width,n.height]),c.queue.submit([s.finish()]),requestAnimationFrame(e)})},l=()=>(0,a.Tl)({name:"Fractal Cube",description:"This example uses the previous frame's rendering result as the source texture for the next frame.",init:u,sources:[{name:c.substring(23),contents:"import { mat4, vec3 } from 'wgpu-matrix';\nimport { makeSample, SampleInit } from '../../components/SampleLayout';\n\nimport {\n cubeVertexArray,\n cubeVertexSize,\n cubeUVOffset,\n cubePositionOffset,\n cubeVertexCount,\n} from '../../meshes/cube';\n\nimport basicVertWGSL from '../../shaders/basic.vert.wgsl';\nimport sampleSelfWGSL from './sampleSelf.frag.wgsl';\n\nconst init: SampleInit = async ({ canvas, pageState }) => {\n const adapter = await navigator.gpu.requestAdapter();\n const device = await adapter.requestDevice();\n\n if (!pageState.active) return;\n const context = canvas.getContext('webgpu') as GPUCanvasContext;\n\n const devicePixelRatio = window.devicePixelRatio;\n canvas.width = canvas.clientWidth * devicePixelRatio;\n canvas.height = canvas.clientHeight * devicePixelRatio;\n const presentationFormat = navigator.gpu.getPreferredCanvasFormat();\n\n context.configure({\n device,\n format: presentationFormat,\n\n // Specify we want both RENDER_ATTACHMENT and COPY_SRC since we\n // will copy out of the swapchain texture.\n usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.COPY_SRC,\n alphaMode: 'premultiplied',\n });\n\n // Create a vertex buffer from the cube data.\n const verticesBuffer = device.createBuffer({\n size: cubeVertexArray.byteLength,\n usage: GPUBufferUsage.VERTEX,\n mappedAtCreation: true,\n });\n new Float32Array(verticesBuffer.getMappedRange()).set(cubeVertexArray);\n verticesBuffer.unmap();\n\n const pipeline = device.createRenderPipeline({\n layout: 'auto',\n vertex: {\n module: device.createShaderModule({\n code: basicVertWGSL,\n }),\n entryPoint: 'main',\n buffers: [\n {\n arrayStride: cubeVertexSize,\n attributes: [\n {\n // position\n shaderLocation: 0,\n offset: cubePositionOffset,\n format: 'float32x4',\n },\n {\n // uv\n shaderLocation: 1,\n offset: cubeUVOffset,\n format: 'float32x2',\n },\n ],\n },\n ],\n },\n fragment: {\n module: device.createShaderModule({\n code: sampleSelfWGSL,\n }),\n entryPoint: 'main',\n targets: [\n {\n format: presentationFormat,\n },\n ],\n },\n primitive: {\n topology: 'triangle-list',\n\n // Backface culling since the cube is solid piece of geometry.\n // Faces pointing away from the camera will be occluded by faces\n // pointing toward the camera.\n cullMode: 'back',\n },\n\n // Enable depth testing so that the fragment closest to the camera\n // is rendered in front.\n depthStencil: {\n depthWriteEnabled: true,\n depthCompare: 'less',\n format: 'depth24plus',\n },\n });\n\n const depthTexture = device.createTexture({\n size: [canvas.width, canvas.height],\n format: 'depth24plus',\n usage: GPUTextureUsage.RENDER_ATTACHMENT,\n });\n\n const uniformBufferSize = 4 * 16; // 4x4 matrix\n const uniformBuffer = device.createBuffer({\n size: uniformBufferSize,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n });\n\n // We will copy the frame's rendering results into this texture and\n // sample it on the next frame.\n const cubeTexture = device.createTexture({\n size: [canvas.width, canvas.height],\n format: presentationFormat,\n usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST,\n });\n\n // Create a sampler with linear filtering for smooth interpolation.\n const sampler = device.createSampler({\n magFilter: 'linear',\n minFilter: 'linear',\n });\n\n const uniformBindGroup = device.createBindGroup({\n layout: pipeline.getBindGroupLayout(0),\n entries: [\n {\n binding: 0,\n resource: {\n buffer: uniformBuffer,\n },\n },\n {\n binding: 1,\n resource: sampler,\n },\n {\n binding: 2,\n resource: cubeTexture.createView(),\n },\n ],\n });\n\n const renderPassDescriptor: GPURenderPassDescriptor = {\n colorAttachments: [\n {\n view: undefined, // Assigned later\n\n clearValue: { r: 0.5, g: 0.5, b: 0.5, a: 1.0 },\n loadOp: 'clear',\n storeOp: 'store',\n },\n ],\n depthStencilAttachment: {\n view: depthTexture.createView(),\n\n depthClearValue: 1.0,\n depthLoadOp: 'clear',\n depthStoreOp: 'store',\n },\n };\n\n const aspect = canvas.width / canvas.height;\n const projectionMatrix = mat4.perspective(\n (2 * Math.PI) / 5,\n aspect,\n 1,\n 100.0\n );\n const modelViewProjectionMatrix = mat4.create();\n\n function getTransformationMatrix() {\n const viewMatrix = mat4.identity();\n mat4.translate(viewMatrix, vec3.fromValues(0, 0, -4), viewMatrix);\n const now = Date.now() / 1000;\n mat4.rotate(\n viewMatrix,\n vec3.fromValues(Math.sin(now), Math.cos(now), 0),\n 1,\n viewMatrix\n );\n\n mat4.multiply(projectionMatrix, viewMatrix, modelViewProjectionMatrix);\n\n return modelViewProjectionMatrix as Float32Array;\n }\n\n function frame() {\n // Sample is no longer the active page.\n if (!pageState.active) return;\n\n const transformationMatrix = getTransformationMatrix();\n device.queue.writeBuffer(\n uniformBuffer,\n 0,\n transformationMatrix.buffer,\n transformationMatrix.byteOffset,\n transformationMatrix.byteLength\n );\n\n const swapChainTexture = context.getCurrentTexture();\n // prettier-ignore\n renderPassDescriptor.colorAttachments[0].view = swapChainTexture.createView();\n\n const commandEncoder = device.createCommandEncoder();\n const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);\n passEncoder.setPipeline(pipeline);\n passEncoder.setBindGroup(0, uniformBindGroup);\n passEncoder.setVertexBuffer(0, verticesBuffer);\n passEncoder.draw(cubeVertexCount);\n passEncoder.end();\n\n // Copy the rendering results from the swapchain into |cubeTexture|.\n commandEncoder.copyTextureToTexture(\n {\n texture: swapChainTexture,\n },\n {\n texture: cubeTexture,\n },\n [canvas.width, canvas.height]\n );\n\n device.queue.submit([commandEncoder.finish()]);\n\n requestAnimationFrame(frame);\n }\n requestAnimationFrame(frame);\n};\n\nconst FractalCube: () => JSX.Element = () =>\n makeSample({\n name: 'Fractal Cube',\n description:\n \"This example uses the previous frame's rendering result \\\n as the source texture for the next frame.\",\n init,\n sources: [\n {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n },\n {\n name: '../../shaders/basic.vert.wgsl',\n contents: basicVertWGSL,\n editable: true,\n },\n {\n name: './sampleSelf.frag.wgsl',\n contents: sampleSelfWGSL,\n editable: true,\n },\n {\n name: '../../meshes/cube.ts',\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n contents: require('!!raw-loader!../../meshes/cube.ts').default,\n },\n ],\n filename: __filename,\n });\n\nexport default FractalCube;\n"},{name:"../../shaders/basic.vert.wgsl",contents:o.Z,editable:!0},{name:"./sampleSelf.frag.wgsl",contents:s,editable:!0},{name:"../../meshes/cube.ts",contents:t(2448).Z}],filename:c});var f=l},9147:function(e){e.exports={canvasContainer:"SampleLayout_canvasContainer__zRR_l",sourceFileNav:"SampleLayout_sourceFileNav__ml48P",sourceFileScrollContainer:"SampleLayout_sourceFileScrollContainer__LsNEm",sourceFileContainer:"SampleLayout_sourceFileContainer__3s84x"}},2448:function(e,n){"use strict";n.Z="export const cubeVertexSize = 4 * 10; // Byte size of one cube vertex.\nexport const cubePositionOffset = 0;\nexport const cubeColorOffset = 4 * 4; // Byte offset of cube vertex color attribute.\nexport const cubeUVOffset = 4 * 8;\nexport const cubeVertexCount = 36;\n\n// prettier-ignore\nexport const cubeVertexArray = new Float32Array([\n // float4 position, float4 color, float2 uv,\n 1, -1, 1, 1, 1, 0, 1, 1, 0, 1,\n -1, -1, 1, 1, 0, 0, 1, 1, 1, 1,\n -1, -1, -1, 1, 0, 0, 0, 1, 1, 0,\n 1, -1, -1, 1, 1, 0, 0, 1, 0, 0,\n 1, -1, 1, 1, 1, 0, 1, 1, 0, 1,\n -1, -1, -1, 1, 0, 0, 0, 1, 1, 0,\n\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n 1, -1, 1, 1, 1, 0, 1, 1, 1, 1,\n 1, -1, -1, 1, 1, 0, 0, 1, 1, 0,\n 1, 1, -1, 1, 1, 1, 0, 1, 0, 0,\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n 1, -1, -1, 1, 1, 0, 0, 1, 1, 0,\n\n -1, 1, 1, 1, 0, 1, 1, 1, 0, 1,\n 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n 1, 1, -1, 1, 1, 1, 0, 1, 1, 0,\n -1, 1, -1, 1, 0, 1, 0, 1, 0, 0,\n -1, 1, 1, 1, 0, 1, 1, 1, 0, 1,\n 1, 1, -1, 1, 1, 1, 0, 1, 1, 0,\n\n -1, -1, 1, 1, 0, 0, 1, 1, 0, 1,\n -1, 1, 1, 1, 0, 1, 1, 1, 1, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n -1, -1, -1, 1, 0, 0, 0, 1, 0, 0,\n -1, -1, 1, 1, 0, 0, 1, 1, 0, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n -1, 1, 1, 1, 0, 1, 1, 1, 1, 1,\n -1, -1, 1, 1, 0, 0, 1, 1, 1, 0,\n -1, -1, 1, 1, 0, 0, 1, 1, 1, 0,\n 1, -1, 1, 1, 1, 0, 1, 1, 0, 0,\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n\n 1, -1, -1, 1, 1, 0, 0, 1, 0, 1,\n -1, -1, -1, 1, 0, 0, 0, 1, 1, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n 1, 1, -1, 1, 1, 1, 0, 1, 0, 0,\n 1, -1, -1, 1, 1, 0, 0, 1, 0, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n]);\n"},3569:function(e,n){"use strict";n.Z="struct Uniforms {\n modelViewProjectionMatrix : mat4x4,\n}\n@binding(0) @group(0) var uniforms : Uniforms;\n\nstruct VertexOutput {\n @builtin(position) Position : vec4,\n @location(0) fragUV : vec2,\n @location(1) fragPosition: vec4,\n}\n\n@vertex\nfn main(\n @location(0) position : vec4,\n @location(1) uv : vec2\n) -> VertexOutput {\n var output : VertexOutput;\n output.Position = uniforms.modelViewProjectionMatrix * position;\n output.fragUV = uv;\n output.fragPosition = 0.5 * (position + vec4(1.0, 1.0, 1.0, 1.0));\n return output;\n}\n"}}]);
\ No newline at end of file
diff --git a/_next/static/chunks/118.bbbd30415a0af966.js b/_next/static/chunks/118.bbbd30415a0af966.js
deleted file mode 100644
index 1b441496..00000000
--- a/_next/static/chunks/118.bbbd30415a0af966.js
+++ /dev/null
@@ -1 +0,0 @@
-(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[118],{5671:function(e,t,n){"use strict";n.d(t,{Tl:function(){return p},hu:function(){return d}});var r=n(5893),a=n(9008),i=n.n(a),o=n(1163),s=n(7294),l=n(9147),u=n.n(l);n(7319);let c=e=>{let t=(0,s.useRef)(null),a=(0,s.useRef)(null),l=(0,s.useMemo)(()=>e.sources.map(e=>{let{name:t,contents:a}=e;return{name:t,...function(e){let t;let a=null;{a=document.createElement("div");let i=n(4631);t=i(a,{lineNumbers:!0,lineWrapping:!0,theme:"monokai",readOnly:!0})}return{Container:function(n){return(0,r.jsx)("div",{...n,children:(0,r.jsx)("div",{ref(n){a&&n&&(n.appendChild(a),t.setOption("value",e))}})})}}}(a)}}),e.sources),c=(0,s.useRef)(null),p=(0,s.useMemo)(()=>{if(e.gui){let t=n(4376),r=new t.GUI({autoPlace:!1});return r.domElement.style.position="relative",r.domElement.style.zIndex="1000",r}},[]),d=(0,s.useRef)(null),m=(0,s.useMemo)(()=>{if(e.stats){let t=n(2792);return new t}},[]),f=(0,o.useRouter)(),g=f.asPath.match(/#([a-zA-Z0-9\.\/]+)/),[h,x]=(0,s.useState)(null),[b,v]=(0,s.useState)(null);return(0,s.useEffect)(()=>{if(g?v(g[1]):v(l[0].name),p&&c.current)for(c.current.appendChild(p.domElement);p.__controllers.length>0;)p.__controllers[0].remove();m&&d.current&&(m.dom.style.position="absolute",m.showPanel(1),d.current.appendChild(m.dom));let n={active:!0},r=()=>{n.active=!1};try{let a=t.current;if(!a)throw Error("The canvas is not available");let i=e.init({canvas:a,pageState:n,gui:p,stats:m});i instanceof Promise&&i.catch(e=>{console.error(e),x(e)})}catch(o){console.error(o),x(o)}return r},[]),(0,r.jsxs)("main",{children:[(0,r.jsxs)(i(),{children:[(0,r.jsx)("style",{dangerouslySetInnerHTML:{__html:"\n .CodeMirror {\n height: auto !important;\n margin: 1em 0;\n }\n\n .CodeMirror-scroll {\n height: auto !important;\n overflow: visible !important;\n }\n "}}),(0,r.jsx)("title",{children:"".concat(e.name," - WebGPU Samples")}),(0,r.jsx)("meta",{name:"description",content:e.description}),(0,r.jsx)("meta",{httpEquiv:"origin-trial",content:e.originTrial})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("h1",{children:e.name}),(0,r.jsx)("a",{target:"_blank",rel:"noreferrer",href:"https://github.com/".concat("webgpu/webgpu-samples","/tree/main/").concat(e.filename),children:"See it on Github!"}),(0,r.jsx)("p",{children:e.description}),h?(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("p",{children:"Something went wrong. Do your browser and device support WebGPU?"}),(0,r.jsx)("p",{children:"".concat(h)})]}):null]}),(0,r.jsxs)("div",{className:u().canvasContainer,children:[(0,r.jsx)("div",{style:{position:"absolute",left:10},ref:d}),(0,r.jsx)("div",{style:{position:"absolute",right:10},ref:c}),(0,r.jsx)("canvas",{ref:t})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("nav",{className:u().sourceFileNav,ref:a,children:(0,r.jsx)("div",{className:u().sourceFileScrollContainer,onScroll(e){let t=e.currentTarget,n=t.scrollWidth-t.clientWidth-t.scrollLeft;t.scrollLeft>25?a.current.setAttribute("data-left","true"):a.current.setAttribute("data-left","false"),n>25?a.current.setAttribute("data-right","true"):a.current.setAttribute("data-right","false")},children:(0,r.jsx)("ul",{children:l.map((e,t)=>(0,r.jsx)("li",{children:(0,r.jsx)("a",{href:"#".concat(e.name),"data-active":b==e.name,onClick(){v(e.name)},children:e.name})},t))})})}),l.map((e,t)=>(0,r.jsx)(e.Container,{className:u().sourceFileContainer,"data-active":b==e.name},t))]})]})},p=e=>(0,r.jsx)(c,{...e});function d(e,t){if(!e)throw Error(t)}},7118:function(e,t,n){"use strict";n.r(t),n.d(t,{default:function(){return x}});var r,a,i=n(6416),o=n(5671),s="\nconst modeAlbedoTexture = 0;\nconst modeNormalTexture = 1;\nconst modeDepthTexture = 2;\nconst modeNormalMap = 3;\nconst modeParallaxScale = 4;\nconst modeSteepParallax = 5;\n\nstruct SpaceTransforms {\n worldViewProjMatrix: mat4x4f,\n worldViewMatrix: mat4x4f,\n}\n\nstruct MapInfo {\n lightPosVS: vec3f, // Light position in view space\n mode: u32,\n lightIntensity: f32,\n depthScale: f32,\n depthLayers: f32,\n}\n\nstruct VertexInput {\n // Shader assumes the missing 4th float is 1.0\n @location(0) position : vec4f,\n @location(1) normal : vec3f,\n @location(2) uv : vec2f,\n @location(3) vert_tan: vec3f,\n @location(4) vert_bitan: vec3f,\n}\n\nstruct VertexOutput {\n @builtin(position) posCS : vec4f, // vertex position in clip space\n @location(0) posVS : vec3f, // vertex position in view space\n @location(1) tangentVS: vec3f, // vertex tangent in view space\n @location(2) bitangentVS: vec3f, // vertex tangent in view space\n @location(3) normalVS: vec3f, // vertex normal in view space\n @location(5) uv : vec2f, // vertex texture coordinate\n}\n\n// Uniforms\n@group(0) @binding(0) var spaceTransform : SpaceTransforms;\n@group(0) @binding(1) var mapInfo: MapInfo;\n\n// Texture info\n@group(1) @binding(0) var textureSampler: sampler;\n@group(1) @binding(1) var albedoTexture: texture_2d;\n@group(1) @binding(2) var normalTexture: texture_2d;\n@group(1) @binding(3) var depthTexture: texture_2d;\n\n\n@vertex\nfn vertexMain(input: VertexInput) -> VertexOutput {\n var output : VertexOutput;\n\n output.posCS = spaceTransform.worldViewProjMatrix * input.position;\n output.posVS = (spaceTransform.worldViewMatrix * input.position).xyz;\n output.tangentVS = (spaceTransform.worldViewMatrix * vec4(input.vert_tan, 0)).xyz;\n output.bitangentVS = (spaceTransform.worldViewMatrix * vec4(input.vert_bitan, 0)).xyz;\n output.normalVS = (spaceTransform.worldViewMatrix * vec4(input.normal, 0)).xyz;\n output.uv = input.uv;\n\n return output;\n}\n\n@fragment\nfn fragmentMain(input: VertexOutput) -> @location(0) vec4f {\n // Build the matrix to convert from tangent space to view space\n let tangentToView = mat3x3f(\n input.tangentVS,\n input.bitangentVS,\n input.normalVS,\n );\n\n // The inverse of a non-scaling affine 3x3 matrix is it's transpose\n let viewToTangent = transpose(tangentToView);\n\n // Calculate the normalized vector in tangent space from the camera to the fragment\n let viewDirTS = normalize(viewToTangent * input.posVS);\n\n // Apply parallax to the texture coordinate, if parallax is enabled\n var uv : vec2f;\n switch (mapInfo.mode) {\n case modeParallaxScale: {\n uv = parallaxScale(input.uv, viewDirTS);\n break;\n }\n case modeSteepParallax: {\n uv = parallaxSteep(input.uv, viewDirTS);\n break;\n }\n default: {\n uv = input.uv;\n break;\n }\n }\n\n // Sample the albedo texture\n let albedoSample = textureSample(albedoTexture, textureSampler, uv);\n\n // Sample the normal texture\n let normalSample = textureSample(normalTexture, textureSampler, uv);\n\n switch (mapInfo.mode) {\n case modeAlbedoTexture: { // Output the albedo sample\n return albedoSample;\n }\n case modeNormalTexture: { // Output the normal sample\n return normalSample;\n }\n case modeDepthTexture: { // Output the depth map\n return textureSample(depthTexture, textureSampler, input.uv);\n }\n default: {\n // Transform the normal sample to a tangent space normal\n let normalTS = normalSample.xyz * 2 - 1;\n\n // Convert normal from tangent space to view space, and normalize\n let normalVS = normalize(tangentToView * normalTS);\n\n // Calculate the vector in view space from the light position to the fragment\n let fragToLightVS = mapInfo.lightPosVS - input.posVS;\n\n // Calculate the square distance from the light to the fragment\n let lightSqrDist = dot(fragToLightVS, fragToLightVS);\n\n // Calculate the normalized vector in view space from the fragment to the light\n let lightDirVS = fragToLightVS * inverseSqrt(lightSqrDist);\n\n // Light strength is inversely proportional to square of distance from light\n let diffuseLight = mapInfo.lightIntensity * max(dot(lightDirVS, normalVS), 0) / lightSqrDist;\n\n // The diffuse is the albedo color multiplied by the diffuseLight\n let diffuse = albedoSample.rgb * diffuseLight;\n\n return vec4f(diffuse, 1.0);\n }\n }\n}\n\n\n// Returns the uv coordinate displaced in the view direction by a magnitude calculated by the depth\n// sampled from the depthTexture and the angle between the surface normal and view direction.\nfn parallaxScale(uv: vec2f, viewDirTS: vec3f) -> vec2f {\n let depthSample = textureSample(depthTexture, textureSampler, uv).r;\n return uv + viewDirTS.xy * (depthSample * mapInfo.depthScale) / -viewDirTS.z;\n}\n\n// Returns the uv coordinates displaced in the view direction by ray-tracing the depth map.\nfn parallaxSteep(startUV: vec2f, viewDirTS: vec3f) -> vec2f {\n // Calculate derivatives of the texture coordinate, so we can sample the texture with non-uniform\n // control flow.\n let ddx = dpdx(startUV);\n let ddy = dpdy(startUV);\n\n // Calculate the delta step in UV and depth per iteration\n let uvDelta = viewDirTS.xy * mapInfo.depthScale / (-viewDirTS.z * mapInfo.depthLayers);\n let depthDelta = 1.0 / f32(mapInfo.depthLayers);\n let posDelta = vec3(uvDelta, depthDelta);\n\n // Walk the depth texture, and stop when the ray intersects the depth map\n var pos = vec3(startUV, 0);\n for (var i = 0; i < 32; i++) {\n if (pos.z >= textureSampleGrad(depthTexture, textureSampler, pos.xy, ddx, ddy).r) {\n break; // Hit the surface\n }\n pos += posDelta;\n }\n\n return pos.xy;\n}\n";let l=function(e,t){let n=arguments.length>2&&void 0!==arguments[2]&&arguments[2],r=arguments.length>3&&void 0!==arguments[3]&&arguments[3],a=n?GPUBufferUsage.VERTEX|GPUBufferUsage.STORAGE:GPUBufferUsage.VERTEX,i=r?GPUBufferUsage.INDEX|GPUBufferUsage.STORAGE:GPUBufferUsage.INDEX,o=e.createBuffer({size:t.vertices.byteLength,usage:a,mappedAtCreation:!0});new Float32Array(o.getMappedRange()).set(t.vertices),o.unmap();let s=e.createBuffer({size:t.indices.byteLength,usage:i,mappedAtCreation:!0});return t.indices.byteLength===t.indices.length*Uint16Array.BYTES_PER_ELEMENT?new Uint16Array(s.getMappedRange()).set(t.indices):new Uint32Array(s.getMappedRange()).set(t.indices),s.unmap(),{vertexBuffer:o,indexBuffer:s,indexCount:t.indices.length}},u=(e,t,n,r,a,i,o)=>{let s=[];for(let l=0;l{let t=e.split("x"),n=parseInt(t[0].replace(/[^0-9]/g,""))/8,r=n*(void 0!==t[1]?parseInt(t[1]):1);return r},p=e=>{let t=e.reduce((e,t,n)=>{let r={shaderLocation:n,offset:e.arrayStride,format:t},a=e.arrayStride+c(t),i={attributes:[...e.attributes,r],arrayStride:a};return i},{attributes:[],arrayStride:0}),n={arrayStride:t.arrayStride,attributes:t.attributes};return n},d=function(e,t,n,r,a,i,o){let s=arguments.length>7&&void 0!==arguments[7]&&arguments[7],l=arguments.length>8&&void 0!==arguments[8]?arguments[8]:"triangle-list",u=arguments.length>9&&void 0!==arguments[9]?arguments[9]:"back",c={label:"".concat(t,".pipeline"),layout:e.createPipelineLayout({label:"".concat(t,".pipelineLayout"),bindGroupLayouts:n}),vertex:{module:e.createShaderModule({label:"".concat(t,".vertexShader"),code:r}),entryPoint:"vertexMain",buffers:0!==a.length?[p(a)]:[]},fragment:{module:e.createShaderModule({label:"".concat(t,".fragmentShader"),code:i}),entryPoint:"fragmentMain",targets:[{format:o}]},primitive:{topology:l,cullMode:u}};return s&&(c.depthStencil={depthCompare:"less",depthWriteEnabled:!0,format:"depth24plus"}),e.createRenderPipeline(c)},m=(e,t)=>{let n=e.createTexture({size:[t.width,t.height,1],format:"rgba8unorm",usage:GPUTextureUsage.TEXTURE_BINDING|GPUTextureUsage.COPY_DST|GPUTextureUsage.RENDER_ATTACHMENT});return e.queue.copyExternalImageToTexture({source:t},{texture:n},[t.width,t.height]),n};var f="src/sample/normalMap/main.ts";(r=a||(a={}))[r.Spiral=0]="Spiral",r[r.Toybox=1]="Toybox",r[r.BrickWall=2]="BrickWall";let g=async e=>{let t,n,r,o,c,p,f,g,{canvas:h,pageState:x,gui:b}=e,v=await navigator.gpu.requestAdapter(),w=await v.requestDevice();if(!x.active)return;let y=h.getContext("webgpu"),T=window.devicePixelRatio;h.width=h.clientWidth*T,h.height=h.clientHeight*T;let S=navigator.gpu.getPreferredCanvasFormat();y.configure({device:w,format:S,alphaMode:"premultiplied"});let P={"Bump Mode":"Normal Map",cameraPosX:0,cameraPosY:.8,cameraPosZ:-1.4,lightPosX:1.7,lightPosY:.7,lightPosZ:-1.9,lightIntensity:5,depthScale:.05,depthLayers:16,Texture:"Spiral","Reset Light"(){}},B=w.createTexture({size:[h.width,h.height],format:"depth24plus",usage:GPUTextureUsage.RENDER_ATTACHMENT}),G=w.createBuffer({size:256,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST}),U=w.createBuffer({size:8*Float32Array.BYTES_PER_ELEMENT,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST}),V=new ArrayBuffer(U.size),M=new DataView(V,0,V.byteLength);{let E=await fetch("../assets/img/wood_albedo.png"),A=await createImageBitmap(await E.blob());t=m(w,A)}{let _=await fetch("../assets/img/spiral_normal.png"),I=await createImageBitmap(await _.blob());n=m(w,I)}{let F=await fetch("../assets/img/spiral_height.png"),L=await createImageBitmap(await F.blob());r=m(w,L)}{let C=await fetch("../assets/img/toybox_normal.png"),R=await createImageBitmap(await C.blob());o=m(w,R)}{let D=await fetch("../assets/img/toybox_height.png"),N=await createImageBitmap(await D.blob());c=m(w,N)}{let O=await fetch("../assets/img/brickwall_albedo.png"),j=await createImageBitmap(await O.blob());p=m(w,j)}{let X=await fetch("../assets/img/brickwall_normal.png"),k=await createImageBitmap(await X.blob());f=m(w,k)}{let z=await fetch("../assets/img/brickwall_height.png"),Y=await createImageBitmap(await z.blob());g=m(w,Y)}let q=w.createSampler({magFilter:"linear",minFilter:"linear"}),Z={colorAttachments:[{view:void 0,clearValue:{r:0,g:0,b:0,a:1},loadOp:"clear",storeOp:"store"}],depthStencilAttachment:{view:B.createView(),depthClearValue:1,depthLoadOp:"clear",depthStoreOp:"store"}},W=l(w,function(e,t,n){let r=[{tangent:5,bitangent:2,normal:0},{tangent:4,bitangent:2,normal:1},{tangent:0,bitangent:5,normal:2},{tangent:0,bitangent:4,normal:3},{tangent:0,bitangent:2,normal:4},{tangent:1,bitangent:2,normal:5}],a=new Float32Array(56*r.length),i=new Uint16Array(6*r.length),o=[[+e/2,0,0],[-e/2,0,0],[0,+t/2,0],[0,-t/2,0],[0,0,+n/2],[0,0,-n/2]],s=0,l=0;for(let u=0;u{switch(P["Bump Mode"]){case"Albedo Texture":return 0;case"Normal Texture":return 1;case"Depth Texture":return 2;case"Normal Map":return 3;case"Parallax Scale":return 4;case"Steep Parallax":return 5}},ee=d(w,"NormalMappingRender",[H.bindGroupLayout,$.bindGroupLayout],s,["float32x3","float32x3","float32x2","float32x3","float32x3"],s,S,!0),et=0,en=()=>{et=a[P.Texture]};b.add(P,"Bump Mode",["Albedo Texture","Normal Texture","Depth Texture","Normal Map","Parallax Scale","Steep Parallax"]),b.add(P,"Texture",["Spiral","Toybox","BrickWall"]).onChange(en);let er=b.addFolder("Light"),ea=b.addFolder("Depth");er.add(P,"Reset Light").onChange(()=>{ei.setValue(1.7),eo.setValue(.7),es.setValue(-1.9),el.setValue(5)});let ei=er.add(P,"lightPosX",-5,5).step(.1),eo=er.add(P,"lightPosY",-5,5).step(.1),es=er.add(P,"lightPosZ",-5,5).step(.1),el=er.add(P,"lightIntensity",0,10).step(.1);ea.add(P,"depthScale",0,.1).step(.01),ea.add(P,"depthLayers",1,32).step(1),requestAnimationFrame(function e(){if(!x.active)return;let t=i._E.lookAt([P.cameraPosX,P.cameraPosY,P.cameraPosZ],[0,0,0],[0,1,0]),n=i._E.mul(t,function(){let e=i._E.create();i._E.identity(e);let t=Date.now()/1e3;return i._E.rotateY(e,-.5*t,e),e}()),r=i._E.mul(J,n),a=new Float32Array([...r,...n]),o=i.R3.create(P.lightPosX,P.lightPosY,P.lightPosZ),s=i.R3.transformMat4(o,t),l=Q();w.queue.writeBuffer(G,0,a.buffer,a.byteOffset,a.byteLength),M.setFloat32(0,s[0],!0),M.setFloat32(4,s[1],!0),M.setFloat32(8,s[2],!0),M.setUint32(12,l,!0),M.setFloat32(16,P.lightIntensity,!0),M.setFloat32(20,P.depthScale,!0),M.setFloat32(24,P.depthLayers,!0),w.queue.writeBuffer(U,0,V),Z.colorAttachments[0].view=y.getCurrentTexture().createView();let u=w.createCommandEncoder(),c=u.beginRenderPass(Z);c.setPipeline(ee),c.setBindGroup(0,H.bindGroups[0]),c.setBindGroup(1,$.bindGroups[et]),c.setVertexBuffer(0,W.vertexBuffer),c.setIndexBuffer(W.indexBuffer,"uint16"),c.drawIndexed(W.indexCount),c.end(),w.queue.submit([u.finish()]),requestAnimationFrame(e)})},h=()=>(0,o.Tl)({name:"Normal Mapping",description:"This example demonstrates multiple different methods that employ fragment shaders to achieve additional perceptual depth on the surface of a cube mesh. Demonstrated methods include normal mapping, parallax mapping, and steep parallax mapping.",gui:!0,init:g,sources:[{name:f.substring(21),contents:"import { mat4, vec3 } from 'wgpu-matrix';\nimport { makeSample, SampleInit } from '../../components/SampleLayout';\nimport normalMapWGSL from './normalMap.wgsl';\nimport { createMeshRenderable } from '../../meshes/mesh';\nimport { createBoxMeshWithTangents } from '../../meshes/box';\nimport {\n createBindGroupDescriptor,\n create3DRenderPipeline,\n createTextureFromImage,\n} from './utils';\n\nconst MAT4X4_BYTES = 64;\nenum TextureAtlas {\n Spiral,\n Toybox,\n BrickWall,\n}\n\nconst init: SampleInit = async ({ canvas, pageState, gui }) => {\n const adapter = await navigator.gpu.requestAdapter();\n const device = await adapter.requestDevice();\n if (!pageState.active) return;\n const context = canvas.getContext('webgpu') as GPUCanvasContext;\n const devicePixelRatio = window.devicePixelRatio;\n canvas.width = canvas.clientWidth * devicePixelRatio;\n canvas.height = canvas.clientHeight * devicePixelRatio;\n const presentationFormat = navigator.gpu.getPreferredCanvasFormat();\n context.configure({\n device,\n format: presentationFormat,\n alphaMode: 'premultiplied',\n });\n\n interface GUISettings {\n 'Bump Mode':\n | 'Albedo Texture'\n | 'Normal Texture'\n | 'Depth Texture'\n | 'Normal Map'\n | 'Parallax Scale'\n | 'Steep Parallax';\n cameraPosX: number;\n cameraPosY: number;\n cameraPosZ: number;\n lightPosX: number;\n lightPosY: number;\n lightPosZ: number;\n lightIntensity: number;\n depthScale: number;\n depthLayers: number;\n Texture: string;\n 'Reset Light': () => void;\n }\n\n const settings: GUISettings = {\n 'Bump Mode': 'Normal Map',\n cameraPosX: 0.0,\n cameraPosY: 0.8,\n cameraPosZ: -1.4,\n lightPosX: 1.7,\n lightPosY: 0.7,\n lightPosZ: -1.9,\n lightIntensity: 5.0,\n depthScale: 0.05,\n depthLayers: 16,\n Texture: 'Spiral',\n 'Reset Light': () => {\n return;\n },\n };\n\n // Create normal mapping resources and pipeline\n const depthTexture = device.createTexture({\n size: [canvas.width, canvas.height],\n format: 'depth24plus',\n usage: GPUTextureUsage.RENDER_ATTACHMENT,\n });\n\n const spaceTransformsBuffer = device.createBuffer({\n // Buffer holding projection, view, and model matrices plus padding bytes\n size: MAT4X4_BYTES * 4,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n });\n\n const mapInfoBuffer = device.createBuffer({\n // Buffer holding mapping type, light uniforms, and depth uniforms\n size: Float32Array.BYTES_PER_ELEMENT * 8,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n });\n const mapInfoArray = new ArrayBuffer(mapInfoBuffer.size);\n const mapInfoView = new DataView(mapInfoArray, 0, mapInfoArray.byteLength);\n\n // Fetch the image and upload it into a GPUTexture.\n let woodAlbedoTexture: GPUTexture;\n {\n const response = await fetch('../assets/img/wood_albedo.png');\n const imageBitmap = await createImageBitmap(await response.blob());\n woodAlbedoTexture = createTextureFromImage(device, imageBitmap);\n }\n\n let spiralNormalTexture: GPUTexture;\n {\n const response = await fetch('../assets/img/spiral_normal.png');\n const imageBitmap = await createImageBitmap(await response.blob());\n spiralNormalTexture = createTextureFromImage(device, imageBitmap);\n }\n\n let spiralHeightTexture: GPUTexture;\n {\n const response = await fetch('../assets/img/spiral_height.png');\n const imageBitmap = await createImageBitmap(await response.blob());\n spiralHeightTexture = createTextureFromImage(device, imageBitmap);\n }\n\n let toyboxNormalTexture: GPUTexture;\n {\n const response = await fetch('../assets/img/toybox_normal.png');\n const imageBitmap = await createImageBitmap(await response.blob());\n toyboxNormalTexture = createTextureFromImage(device, imageBitmap);\n }\n\n let toyboxHeightTexture: GPUTexture;\n {\n const response = await fetch('../assets/img/toybox_height.png');\n const imageBitmap = await createImageBitmap(await response.blob());\n toyboxHeightTexture = createTextureFromImage(device, imageBitmap);\n }\n\n let brickwallAlbedoTexture: GPUTexture;\n {\n const response = await fetch('../assets/img/brickwall_albedo.png');\n const imageBitmap = await createImageBitmap(await response.blob());\n brickwallAlbedoTexture = createTextureFromImage(device, imageBitmap);\n }\n\n let brickwallNormalTexture: GPUTexture;\n {\n const response = await fetch('../assets/img/brickwall_normal.png');\n const imageBitmap = await createImageBitmap(await response.blob());\n brickwallNormalTexture = createTextureFromImage(device, imageBitmap);\n }\n\n let brickwallHeightTexture: GPUTexture;\n {\n const response = await fetch('../assets/img/brickwall_height.png');\n const imageBitmap = await createImageBitmap(await response.blob());\n brickwallHeightTexture = createTextureFromImage(device, imageBitmap);\n }\n\n // Create a sampler with linear filtering for smooth interpolation.\n const sampler = device.createSampler({\n magFilter: 'linear',\n minFilter: 'linear',\n });\n\n const renderPassDescriptor: GPURenderPassDescriptor = {\n colorAttachments: [\n {\n view: undefined, // Assigned later\n\n clearValue: { r: 0.0, g: 0.0, b: 0.0, a: 1.0 },\n loadOp: 'clear',\n storeOp: 'store',\n },\n ],\n depthStencilAttachment: {\n view: depthTexture.createView(),\n\n depthClearValue: 1.0,\n depthLoadOp: 'clear',\n depthStoreOp: 'store',\n },\n };\n\n const box = createMeshRenderable(\n device,\n createBoxMeshWithTangents(1.0, 1.0, 1.0)\n );\n\n // Uniform bindGroups and bindGroupLayout\n const frameBGDescriptor = createBindGroupDescriptor(\n [0, 1],\n [\n GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,\n GPUShaderStage.FRAGMENT | GPUShaderStage.VERTEX,\n ],\n ['buffer', 'buffer'],\n [{ type: 'uniform' }, { type: 'uniform' }],\n [[{ buffer: spaceTransformsBuffer }, { buffer: mapInfoBuffer }]],\n 'Frame',\n device\n );\n\n // Texture bindGroups and bindGroupLayout\n const surfaceBGDescriptor = createBindGroupDescriptor(\n [0, 1, 2, 3],\n [GPUShaderStage.FRAGMENT],\n ['sampler', 'texture', 'texture', 'texture'],\n [\n { type: 'filtering' },\n { sampleType: 'float' },\n { sampleType: 'float' },\n { sampleType: 'float' },\n ],\n // Multiple bindgroups that accord to the layout defined above\n [\n [\n sampler,\n woodAlbedoTexture.createView(),\n spiralNormalTexture.createView(),\n spiralHeightTexture.createView(),\n ],\n [\n sampler,\n woodAlbedoTexture.createView(),\n toyboxNormalTexture.createView(),\n toyboxHeightTexture.createView(),\n ],\n [\n sampler,\n brickwallAlbedoTexture.createView(),\n brickwallNormalTexture.createView(),\n brickwallHeightTexture.createView(),\n ],\n ],\n 'Surface',\n device\n );\n\n const aspect = canvas.width / canvas.height;\n const projectionMatrix = mat4.perspective(\n (2 * Math.PI) / 5,\n aspect,\n 0.1,\n 10.0\n ) as Float32Array;\n\n function getViewMatrix() {\n return mat4.lookAt(\n [settings.cameraPosX, settings.cameraPosY, settings.cameraPosZ],\n [0, 0, 0],\n [0, 1, 0]\n );\n }\n\n function getModelMatrix() {\n const modelMatrix = mat4.create();\n mat4.identity(modelMatrix);\n const now = Date.now() / 1000;\n mat4.rotateY(modelMatrix, now * -0.5, modelMatrix);\n return modelMatrix;\n }\n\n // Change the model mapping type\n const getMode = (): number => {\n switch (settings['Bump Mode']) {\n case 'Albedo Texture':\n return 0;\n case 'Normal Texture':\n return 1;\n case 'Depth Texture':\n return 2;\n case 'Normal Map':\n return 3;\n case 'Parallax Scale':\n return 4;\n case 'Steep Parallax':\n return 5;\n }\n };\n\n const texturedCubePipeline = create3DRenderPipeline(\n device,\n 'NormalMappingRender',\n [frameBGDescriptor.bindGroupLayout, surfaceBGDescriptor.bindGroupLayout],\n normalMapWGSL,\n // Position, normal uv tangent bitangent\n ['float32x3', 'float32x3', 'float32x2', 'float32x3', 'float32x3'],\n normalMapWGSL,\n presentationFormat,\n true\n );\n\n let currentSurfaceBindGroup = 0;\n const onChangeTexture = () => {\n currentSurfaceBindGroup = TextureAtlas[settings.Texture];\n };\n\n gui.add(settings, 'Bump Mode', [\n 'Albedo Texture',\n 'Normal Texture',\n 'Depth Texture',\n 'Normal Map',\n 'Parallax Scale',\n 'Steep Parallax',\n ]);\n gui\n .add(settings, 'Texture', ['Spiral', 'Toybox', 'BrickWall'])\n .onChange(onChangeTexture);\n const lightFolder = gui.addFolder('Light');\n const depthFolder = gui.addFolder('Depth');\n lightFolder.add(settings, 'Reset Light').onChange(() => {\n lightPosXController.setValue(1.7);\n lightPosYController.setValue(0.7);\n lightPosZController.setValue(-1.9);\n lightIntensityController.setValue(5.0);\n });\n const lightPosXController = lightFolder\n .add(settings, 'lightPosX', -5, 5)\n .step(0.1);\n const lightPosYController = lightFolder\n .add(settings, 'lightPosY', -5, 5)\n .step(0.1);\n const lightPosZController = lightFolder\n .add(settings, 'lightPosZ', -5, 5)\n .step(0.1);\n const lightIntensityController = lightFolder\n .add(settings, 'lightIntensity', 0.0, 10)\n .step(0.1);\n depthFolder.add(settings, 'depthScale', 0.0, 0.1).step(0.01);\n depthFolder.add(settings, 'depthLayers', 1, 32).step(1);\n\n function frame() {\n if (!pageState.active) return;\n\n // Update spaceTransformsBuffer\n const viewMatrix = getViewMatrix();\n const worldViewMatrix = mat4.mul(viewMatrix, getModelMatrix());\n const worldViewProjMatrix = mat4.mul(projectionMatrix, worldViewMatrix);\n const matrices = new Float32Array([\n ...worldViewProjMatrix,\n ...worldViewMatrix,\n ]);\n\n // Update mapInfoBuffer\n const lightPosWS = vec3.create(\n settings.lightPosX,\n settings.lightPosY,\n settings.lightPosZ\n );\n const lightPosVS = vec3.transformMat4(lightPosWS, viewMatrix);\n const mode = getMode();\n device.queue.writeBuffer(\n spaceTransformsBuffer,\n 0,\n matrices.buffer,\n matrices.byteOffset,\n matrices.byteLength\n );\n\n // struct MapInfo {\n // lightPosVS: vec3f,\n // mode: u32,\n // lightIntensity: f32,\n // depthScale: f32,\n // depthLayers: f32,\n // }\n mapInfoView.setFloat32(0, lightPosVS[0], true);\n mapInfoView.setFloat32(4, lightPosVS[1], true);\n mapInfoView.setFloat32(8, lightPosVS[2], true);\n mapInfoView.setUint32(12, mode, true);\n mapInfoView.setFloat32(16, settings.lightIntensity, true);\n mapInfoView.setFloat32(20, settings.depthScale, true);\n mapInfoView.setFloat32(24, settings.depthLayers, true);\n device.queue.writeBuffer(mapInfoBuffer, 0, mapInfoArray);\n\n renderPassDescriptor.colorAttachments[0].view = context\n .getCurrentTexture()\n .createView();\n\n const commandEncoder = device.createCommandEncoder();\n const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);\n // Draw textured Cube\n passEncoder.setPipeline(texturedCubePipeline);\n passEncoder.setBindGroup(0, frameBGDescriptor.bindGroups[0]);\n passEncoder.setBindGroup(\n 1,\n surfaceBGDescriptor.bindGroups[currentSurfaceBindGroup]\n );\n passEncoder.setVertexBuffer(0, box.vertexBuffer);\n passEncoder.setIndexBuffer(box.indexBuffer, 'uint16');\n passEncoder.drawIndexed(box.indexCount);\n passEncoder.end();\n device.queue.submit([commandEncoder.finish()]);\n\n requestAnimationFrame(frame);\n }\n requestAnimationFrame(frame);\n};\n\nconst NormalMapping: () => JSX.Element = () =>\n makeSample({\n name: 'Normal Mapping',\n description:\n 'This example demonstrates multiple different methods that employ fragment shaders to achieve additional perceptual depth on the surface of a cube mesh. Demonstrated methods include normal mapping, parallax mapping, and steep parallax mapping.',\n gui: true,\n init,\n sources: [\n {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n },\n {\n name: './normalMap.wgsl',\n contents: normalMapWGSL,\n editable: true,\n },\n {\n name: '../../meshes/box.ts',\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n contents: require('!!raw-loader!../../meshes/box.ts').default,\n },\n {\n name: '../../meshes/mesh.ts',\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n contents: require('!!raw-loader!../../meshes/mesh.ts').default,\n },\n {\n name: './utils.ts',\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n contents: require('!!raw-loader!./utils.ts').default,\n },\n ],\n filename: __filename,\n });\n\nexport default NormalMapping;\n"},{name:"./normalMap.wgsl",contents:s,editable:!0},{name:"../../meshes/box.ts",contents:n(3583).Z},{name:"../../meshes/mesh.ts",contents:n(3150).Z},{name:"./utils.ts",contents:n(1146).Z}],filename:f});var x=h},9147:function(e){e.exports={canvasContainer:"SampleLayout_canvasContainer__zRR_l",sourceFileNav:"SampleLayout_sourceFileNav__ml48P",sourceFileScrollContainer:"SampleLayout_sourceFileScrollContainer__LsNEm",sourceFileContainer:"SampleLayout_sourceFileContainer__3s84x"}},3583:function(e,t){"use strict";t.Z="import { Mesh } from './mesh';\n\n/**\n * Constructs a box mesh with the given dimensions.\n * The vertex buffer will have the following vertex fields (in the given order):\n * position : float32x3\n * normal : float32x3\n * uv : float32x2\n * tangent : float32x3\n * bitangent : float32x3\n * @param width the width of the box\n * @param height the height of the box\n * @param depth the depth of the box\n * @returns the box mesh with tangent and bitangents.\n */\nexport function createBoxMeshWithTangents(\n width: number,\n height: number,\n depth: number\n): Mesh {\n // __________\n // / /| y\n // / +y / | ^\n // /_________/ | |\n // | |+x| +---> x\n // | +z | | /\n // | | / z\n // |_________|/\n //\n const pX = 0; // +x\n const nX = 1; // -x\n const pY = 2; // +y\n const nY = 3; // -y\n const pZ = 4; // +z\n const nZ = 5; // -z\n const faces = [\n { tangent: nZ, bitangent: pY, normal: pX },\n { tangent: pZ, bitangent: pY, normal: nX },\n { tangent: pX, bitangent: nZ, normal: pY },\n { tangent: pX, bitangent: pZ, normal: nY },\n { tangent: pX, bitangent: pY, normal: pZ },\n { tangent: nX, bitangent: pY, normal: nZ },\n ];\n const verticesPerSide = 4;\n const indicesPerSize = 6;\n const f32sPerVertex = 14; // position : vec3f, tangent : vec3f, bitangent : vec3f, normal : vec3f, uv :vec2f\n const vertexStride = f32sPerVertex * 4;\n const vertices = new Float32Array(\n faces.length * verticesPerSide * f32sPerVertex\n );\n const indices = new Uint16Array(faces.length * indicesPerSize);\n const halfVecs = [\n [+width / 2, 0, 0], // +x\n [-width / 2, 0, 0], // -x\n [0, +height / 2, 0], // +y\n [0, -height / 2, 0], // -y\n [0, 0, +depth / 2], // +z\n [0, 0, -depth / 2], // -z\n ];\n\n let vertexOffset = 0;\n let indexOffset = 0;\n for (let faceIndex = 0; faceIndex < faces.length; faceIndex++) {\n const face = faces[faceIndex];\n const tangent = halfVecs[face.tangent];\n const bitangent = halfVecs[face.bitangent];\n const normal = halfVecs[face.normal];\n\n for (let u = 0; u < 2; u++) {\n for (let v = 0; v < 2; v++) {\n for (let i = 0; i < 3; i++) {\n vertices[vertexOffset++] =\n normal[i] +\n (u == 0 ? -1 : 1) * tangent[i] +\n (v == 0 ? -1 : 1) * bitangent[i];\n }\n for (let i = 0; i < 3; i++) {\n vertices[vertexOffset++] = normal[i];\n }\n vertices[vertexOffset++] = u;\n vertices[vertexOffset++] = v;\n for (let i = 0; i < 3; i++) {\n vertices[vertexOffset++] = tangent[i];\n }\n for (let i = 0; i < 3; i++) {\n vertices[vertexOffset++] = bitangent[i];\n }\n }\n }\n\n indices[indexOffset++] = faceIndex * verticesPerSide + 0;\n indices[indexOffset++] = faceIndex * verticesPerSide + 2;\n indices[indexOffset++] = faceIndex * verticesPerSide + 1;\n\n indices[indexOffset++] = faceIndex * verticesPerSide + 2;\n indices[indexOffset++] = faceIndex * verticesPerSide + 3;\n indices[indexOffset++] = faceIndex * verticesPerSide + 1;\n }\n\n return {\n vertices,\n indices,\n vertexStride,\n };\n}\n"},3150:function(e,t){"use strict";t.Z="import { vec3, vec2 } from 'wgpu-matrix';\n\n// Defines what to pass to pipeline to render mesh\nexport interface Renderable {\n vertexBuffer: GPUBuffer;\n indexBuffer: GPUBuffer;\n indexCount: number;\n bindGroup?: GPUBindGroup;\n}\n\nexport interface Mesh {\n vertices: Float32Array;\n indices: Uint16Array | Uint32Array;\n vertexStride: number;\n}\n\n/**\n * @param {GPUDevice} device - A valid GPUDevice.\n * @param {Mesh} mesh - An indexed triangle-list mesh, containing its vertices, indices, and vertexStride (number of elements per vertex).\n * @param {boolean} storeVertices - A boolean flag indicating whether the vertexBuffer should be available to use as a storage buffer.\n * @returns {boolean} An object containing an array of bindGroups and the bindGroupLayout they implement.\n */\nexport const createMeshRenderable = (\n device: GPUDevice,\n mesh: Mesh,\n storeVertices = false,\n storeIndices = false\n): Renderable => {\n // Define buffer usage\n const vertexBufferUsage = storeVertices\n ? GPUBufferUsage.VERTEX | GPUBufferUsage.STORAGE\n : GPUBufferUsage.VERTEX;\n const indexBufferUsage = storeIndices\n ? GPUBufferUsage.INDEX | GPUBufferUsage.STORAGE\n : GPUBufferUsage.INDEX;\n\n // Create vertex and index buffers\n const vertexBuffer = device.createBuffer({\n size: mesh.vertices.byteLength,\n usage: vertexBufferUsage,\n mappedAtCreation: true,\n });\n new Float32Array(vertexBuffer.getMappedRange()).set(mesh.vertices);\n vertexBuffer.unmap();\n\n const indexBuffer = device.createBuffer({\n size: mesh.indices.byteLength,\n usage: indexBufferUsage,\n mappedAtCreation: true,\n });\n\n // Determine whether index buffer is indices are in uint16 or uint32 format\n if (\n mesh.indices.byteLength ===\n mesh.indices.length * Uint16Array.BYTES_PER_ELEMENT\n ) {\n new Uint16Array(indexBuffer.getMappedRange()).set(mesh.indices);\n } else {\n new Uint32Array(indexBuffer.getMappedRange()).set(mesh.indices);\n }\n\n indexBuffer.unmap();\n\n return {\n vertexBuffer,\n indexBuffer,\n indexCount: mesh.indices.length,\n };\n};\n\nexport const getMeshPosAtIndex = (mesh: Mesh, index: number) => {\n const arr = new Float32Array(\n mesh.vertices.buffer,\n index * mesh.vertexStride + 0,\n 3\n );\n return vec3.fromValues(arr[0], arr[1], arr[2]);\n};\n\nexport const getMeshNormalAtIndex = (mesh: Mesh, index: number) => {\n const arr = new Float32Array(\n mesh.vertices.buffer,\n index * mesh.vertexStride + 3 * Float32Array.BYTES_PER_ELEMENT,\n 3\n );\n return vec3.fromValues(arr[0], arr[1], arr[2]);\n};\n\nexport const getMeshUVAtIndex = (mesh: Mesh, index: number) => {\n const arr = new Float32Array(\n mesh.vertices.buffer,\n index * mesh.vertexStride + 6 * Float32Array.BYTES_PER_ELEMENT,\n 2\n );\n return vec2.fromValues(arr[0], arr[1]);\n};\n"},1146:function(e,t){"use strict";t.Z="type BindGroupBindingLayout =\n | GPUBufferBindingLayout\n | GPUTextureBindingLayout\n | GPUSamplerBindingLayout\n | GPUStorageTextureBindingLayout\n | GPUExternalTextureBindingLayout;\n\nexport type BindGroupsObjectsAndLayout = {\n bindGroups: GPUBindGroup[];\n bindGroupLayout: GPUBindGroupLayout;\n};\n\ntype ResourceTypeName =\n | 'buffer'\n | 'texture'\n | 'sampler'\n | 'externalTexture'\n | 'storageTexture';\n\n/**\n * @param {number[]} bindings - The binding value of each resource in the bind group.\n * @param {number[]} visibilities - The GPUShaderStage visibility of the resource at the corresponding index.\n * @param {ResourceTypeName[]} resourceTypes - The resourceType at the corresponding index.\n * @returns {BindGroupsObjectsAndLayout} An object containing an array of bindGroups and the bindGroupLayout they implement.\n */\nexport const createBindGroupDescriptor = (\n bindings: number[],\n visibilities: number[],\n resourceTypes: ResourceTypeName[],\n resourceLayouts: BindGroupBindingLayout[],\n resources: GPUBindingResource[][],\n label: string,\n device: GPUDevice\n): BindGroupsObjectsAndLayout => {\n // Create layout of each entry within a bindGroup\n const layoutEntries: GPUBindGroupLayoutEntry[] = [];\n for (let i = 0; i < bindings.length; i++) {\n layoutEntries.push({\n binding: bindings[i],\n visibility: visibilities[i % visibilities.length],\n [resourceTypes[i]]: resourceLayouts[i],\n });\n }\n\n // Apply entry layouts to bindGroupLayout\n const bindGroupLayout = device.createBindGroupLayout({\n label: `${label}.bindGroupLayout`,\n entries: layoutEntries,\n });\n\n // Create bindGroups that conform to the layout\n const bindGroups: GPUBindGroup[] = [];\n for (let i = 0; i < resources.length; i++) {\n const groupEntries: GPUBindGroupEntry[] = [];\n for (let j = 0; j < resources[0].length; j++) {\n groupEntries.push({\n binding: j,\n resource: resources[i][j],\n });\n }\n const newBindGroup = device.createBindGroup({\n label: `${label}.bindGroup${i}`,\n layout: bindGroupLayout,\n entries: groupEntries,\n });\n bindGroups.push(newBindGroup);\n }\n\n return {\n bindGroups,\n bindGroupLayout,\n };\n};\n\nexport type ShaderKeyInterface = {\n [K in T[number]]: number;\n};\n\ninterface AttribAcc {\n attributes: GPUVertexAttribute[];\n arrayStride: number;\n}\n\n/**\n * @param {GPUVertexFormat} vf - A valid GPUVertexFormat, representing a per-vertex value that can be passed to the vertex shader.\n * @returns {number} The number of bytes present in the value to be passed.\n */\nexport const convertVertexFormatToBytes = (vf: GPUVertexFormat): number => {\n const splitFormat = vf.split('x');\n const bytesPerElement = parseInt(splitFormat[0].replace(/[^0-9]/g, '')) / 8;\n\n const bytesPerVec =\n bytesPerElement *\n (splitFormat[1] !== undefined ? parseInt(splitFormat[1]) : 1);\n\n return bytesPerVec;\n};\n\n/** Creates a GPUVertexBuffer Layout that maps to an interleaved vertex buffer.\n * @param {GPUVertexFormat[]} vertexFormats - An array of valid GPUVertexFormats.\n * @returns {GPUVertexBufferLayout} A GPUVertexBufferLayout representing an interleaved vertex buffer.\n */\nexport const createVBuffer = (\n vertexFormats: GPUVertexFormat[]\n): GPUVertexBufferLayout => {\n const initialValue: AttribAcc = { attributes: [], arrayStride: 0 };\n\n const vertexBuffer = vertexFormats.reduce(\n (acc: AttribAcc, curr: GPUVertexFormat, idx: number) => {\n const newAttribute: GPUVertexAttribute = {\n shaderLocation: idx,\n offset: acc.arrayStride,\n format: curr,\n };\n const nextOffset: number =\n acc.arrayStride + convertVertexFormatToBytes(curr);\n\n const retVal: AttribAcc = {\n attributes: [...acc.attributes, newAttribute],\n arrayStride: nextOffset,\n };\n return retVal;\n },\n initialValue\n );\n\n const layout: GPUVertexBufferLayout = {\n arrayStride: vertexBuffer.arrayStride,\n attributes: vertexBuffer.attributes,\n };\n\n return layout;\n};\n\nexport const create3DRenderPipeline = (\n device: GPUDevice,\n label: string,\n bgLayouts: GPUBindGroupLayout[],\n vertexShader: string,\n vBufferFormats: GPUVertexFormat[],\n fragmentShader: string,\n presentationFormat: GPUTextureFormat,\n depthTest = false,\n topology: GPUPrimitiveTopology = 'triangle-list',\n cullMode: GPUCullMode = 'back'\n) => {\n const pipelineDescriptor: GPURenderPipelineDescriptor = {\n label: `${label}.pipeline`,\n layout: device.createPipelineLayout({\n label: `${label}.pipelineLayout`,\n bindGroupLayouts: bgLayouts,\n }),\n vertex: {\n module: device.createShaderModule({\n label: `${label}.vertexShader`,\n code: vertexShader,\n }),\n entryPoint: 'vertexMain',\n buffers:\n vBufferFormats.length !== 0 ? [createVBuffer(vBufferFormats)] : [],\n },\n fragment: {\n module: device.createShaderModule({\n label: `${label}.fragmentShader`,\n code: fragmentShader,\n }),\n entryPoint: 'fragmentMain',\n targets: [\n {\n format: presentationFormat,\n },\n ],\n },\n primitive: {\n topology: topology,\n cullMode: cullMode,\n },\n };\n if (depthTest) {\n pipelineDescriptor.depthStencil = {\n depthCompare: 'less',\n depthWriteEnabled: true,\n format: 'depth24plus',\n };\n }\n return device.createRenderPipeline(pipelineDescriptor);\n};\n\nexport const createTextureFromImage = (\n device: GPUDevice,\n bitmap: ImageBitmap\n) => {\n const texture: GPUTexture = device.createTexture({\n size: [bitmap.width, bitmap.height, 1],\n format: 'rgba8unorm',\n usage:\n GPUTextureUsage.TEXTURE_BINDING |\n GPUTextureUsage.COPY_DST |\n GPUTextureUsage.RENDER_ATTACHMENT,\n });\n device.queue.copyExternalImageToTexture(\n { source: bitmap },\n { texture: texture },\n [bitmap.width, bitmap.height]\n );\n return texture;\n};\n"}}]);
\ No newline at end of file
diff --git a/_next/static/chunks/15.76e5ebcf98e58827.js b/_next/static/chunks/15.76e5ebcf98e58827.js
deleted file mode 100644
index 1cbad103..00000000
--- a/_next/static/chunks/15.76e5ebcf98e58827.js
+++ /dev/null
@@ -1 +0,0 @@
-(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[15],{5671:function(e,n,t){"use strict";t.d(n,{Tl:function(){return f},hu:function(){return d}});var r=t(5893),a=t(9008),o=t.n(a),i=t(1163),s=t(7294),c=t(9147),u=t.n(c);t(7319);let l=e=>{let n=(0,s.useRef)(null),a=(0,s.useRef)(null),c=(0,s.useMemo)(()=>e.sources.map(e=>{let{name:n,contents:a}=e;return{name:n,...function(e){let n;let a=null;{a=document.createElement("div");let o=t(4631);n=o(a,{lineNumbers:!0,lineWrapping:!0,theme:"monokai",readOnly:!0})}return{Container:function(t){return(0,r.jsx)("div",{...t,children:(0,r.jsx)("div",{ref(t){a&&t&&(t.appendChild(a),n.setOption("value",e))}})})}}}(a)}}),e.sources),l=(0,s.useRef)(null),f=(0,s.useMemo)(()=>{if(e.gui){let n=t(4376),r=new n.GUI({autoPlace:!1});return r.domElement.style.position="relative",r.domElement.style.zIndex="1000",r}},[]),d=(0,s.useRef)(null),m=(0,s.useMemo)(()=>{if(e.stats){let n=t(2792);return new n}},[]),p=(0,i.useRouter)(),h=p.asPath.match(/#([a-zA-Z0-9\.\/]+)/),[v,g]=(0,s.useState)(null),[x,b]=(0,s.useState)(null);return(0,s.useEffect)(()=>{if(h?b(h[1]):b(c[0].name),f&&l.current)for(l.current.appendChild(f.domElement);f.__controllers.length>0;)f.__controllers[0].remove();m&&d.current&&(m.dom.style.position="absolute",m.showPanel(1),d.current.appendChild(m.dom));let t={active:!0},r=()=>{t.active=!1};try{let a=n.current;if(!a)throw Error("The canvas is not available");let o=e.init({canvas:a,pageState:t,gui:f,stats:m});o instanceof Promise&&o.catch(e=>{console.error(e),g(e)})}catch(i){console.error(i),g(i)}return r},[]),(0,r.jsxs)("main",{children:[(0,r.jsxs)(o(),{children:[(0,r.jsx)("style",{dangerouslySetInnerHTML:{__html:"\n .CodeMirror {\n height: auto !important;\n margin: 1em 0;\n }\n\n .CodeMirror-scroll {\n height: auto !important;\n overflow: visible !important;\n }\n "}}),(0,r.jsx)("title",{children:"".concat(e.name," - WebGPU Samples")}),(0,r.jsx)("meta",{name:"description",content:e.description}),(0,r.jsx)("meta",{httpEquiv:"origin-trial",content:e.originTrial})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("h1",{children:e.name}),(0,r.jsx)("a",{target:"_blank",rel:"noreferrer",href:"https://github.com/".concat("webgpu/webgpu-samples","/tree/main/").concat(e.filename),children:"See it on Github!"}),(0,r.jsx)("p",{children:e.description}),v?(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("p",{children:"Something went wrong. Do your browser and device support WebGPU?"}),(0,r.jsx)("p",{children:"".concat(v)})]}):null]}),(0,r.jsxs)("div",{className:u().canvasContainer,children:[(0,r.jsx)("div",{style:{position:"absolute",left:10},ref:d}),(0,r.jsx)("div",{style:{position:"absolute",right:10},ref:l}),(0,r.jsx)("canvas",{ref:n})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("nav",{className:u().sourceFileNav,ref:a,children:(0,r.jsx)("div",{className:u().sourceFileScrollContainer,onScroll(e){let n=e.currentTarget,t=n.scrollWidth-n.clientWidth-n.scrollLeft;n.scrollLeft>25?a.current.setAttribute("data-left","true"):a.current.setAttribute("data-left","false"),t>25?a.current.setAttribute("data-right","true"):a.current.setAttribute("data-right","false")},children:(0,r.jsx)("ul",{children:c.map((e,n)=>(0,r.jsx)("li",{children:(0,r.jsx)("a",{href:"#".concat(e.name),"data-active":x==e.name,onClick(){b(e.name)},children:e.name})},n))})})}),c.map((e,n)=>(0,r.jsx)(e.Container,{className:u().sourceFileContainer,"data-active":x==e.name},n))]})]})},f=e=>(0,r.jsx)(l,{...e});function d(e,n){if(!e)throw Error(n)}},4655:function(e,n,t){"use strict";t.d(n,{Ax:function(){return o},MO:function(){return i},O$:function(){return r},v8:function(){return a},zS:function(){return s}});let r=40,a=0,o=32,i=36,s=new Float32Array([1,-1,1,1,1,0,1,1,0,1,-1,-1,1,1,0,0,1,1,1,1,-1,-1,-1,1,0,0,0,1,1,0,1,-1,-1,1,1,0,0,1,0,0,1,-1,1,1,1,0,1,1,0,1,-1,-1,-1,1,0,0,0,1,1,0,1,1,1,1,1,1,1,1,0,1,1,-1,1,1,1,0,1,1,1,1,1,-1,-1,1,1,0,0,1,1,0,1,1,-1,1,1,1,0,1,0,0,1,1,1,1,1,1,1,1,0,1,1,-1,-1,1,1,0,0,1,1,0,-1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,-1,1,1,1,0,1,1,0,-1,1,-1,1,0,1,0,1,0,0,-1,1,1,1,0,1,1,1,0,1,1,1,-1,1,1,1,0,1,1,0,-1,-1,1,1,0,0,1,1,0,1,-1,1,1,1,0,1,1,1,1,1,-1,1,-1,1,0,1,0,1,1,0,-1,-1,-1,1,0,0,0,1,0,0,-1,-1,1,1,0,0,1,1,0,1,-1,1,-1,1,0,1,0,1,1,0,1,1,1,1,1,1,1,1,0,1,-1,1,1,1,0,1,1,1,1,1,-1,-1,1,1,0,0,1,1,1,0,-1,-1,1,1,0,0,1,1,1,0,1,-1,1,1,1,0,1,1,0,0,1,1,1,1,1,1,1,1,0,1,1,-1,-1,1,1,0,0,1,0,1,-1,-1,-1,1,0,0,0,1,1,1,-1,1,-1,1,0,1,0,1,1,0,1,1,-1,1,1,1,0,1,0,0,1,-1,-1,1,1,0,0,1,0,1,-1,1,-1,1,0,1,0,1,1,0])},9015:function(e,n,t){"use strict";var r="src/sample/rotatingCube/main.ts";t.r(n);var a=t(6416),o=t(5671),i=t(4655),s=t(3569),c=t(1945);let u=async e=>{let{canvas:n,pageState:t}=e,r=await navigator.gpu.requestAdapter(),o=await r.requestDevice();if(!t.active)return;let u=n.getContext("webgpu"),l=window.devicePixelRatio;n.width=n.clientWidth*l,n.height=n.clientHeight*l;let f=navigator.gpu.getPreferredCanvasFormat();u.configure({device:o,format:f,alphaMode:"premultiplied"});let d=o.createBuffer({size:i.zS.byteLength,usage:GPUBufferUsage.VERTEX,mappedAtCreation:!0});new Float32Array(d.getMappedRange()).set(i.zS),d.unmap();let m=o.createRenderPipeline({layout:"auto",vertex:{module:o.createShaderModule({code:s.Z}),entryPoint:"main",buffers:[{arrayStride:i.O$,attributes:[{shaderLocation:0,offset:i.v8,format:"float32x4"},{shaderLocation:1,offset:i.Ax,format:"float32x2"}]}]},fragment:{module:o.createShaderModule({code:c.Z}),entryPoint:"main",targets:[{format:f}]},primitive:{topology:"triangle-list",cullMode:"back"},depthStencil:{depthWriteEnabled:!0,depthCompare:"less",format:"depth24plus"}}),p=o.createTexture({size:[n.width,n.height],format:"depth24plus",usage:GPUTextureUsage.RENDER_ATTACHMENT}),h=o.createBuffer({size:64,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST}),v=o.createBindGroup({layout:m.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:h}}]}),g={colorAttachments:[{view:void 0,clearValue:{r:.5,g:.5,b:.5,a:1},loadOp:"clear",storeOp:"store"}],depthStencilAttachment:{view:p.createView(),depthClearValue:1,depthLoadOp:"clear",depthStoreOp:"store"}},x=n.width/n.height,b=a._E.perspective(2*Math.PI/5,x,1,100),w=a._E.create();requestAnimationFrame(function e(){if(!t.active)return;let n=function(){let e=a._E.identity();a._E.translate(e,a.R3.fromValues(0,0,-4),e);let n=Date.now()/1e3;return a._E.rotate(e,a.R3.fromValues(Math.sin(n),Math.cos(n),0),1,e),a._E.multiply(b,e,w),w}();o.queue.writeBuffer(h,0,n.buffer,n.byteOffset,n.byteLength),g.colorAttachments[0].view=u.getCurrentTexture().createView();let r=o.createCommandEncoder(),s=r.beginRenderPass(g);s.setPipeline(m),s.setBindGroup(0,v),s.setVertexBuffer(0,d),s.draw(i.MO),s.end(),o.queue.submit([r.finish()]),requestAnimationFrame(e)})},l=()=>(0,o.Tl)({name:"Rotating Cube",description:"This example shows how to upload uniform data every frame to render a rotating object.",init:u,sources:[{name:r.substring(24),contents:"import { mat4, vec3 } from 'wgpu-matrix';\nimport { makeSample, SampleInit } from '../../components/SampleLayout';\n\nimport {\n cubeVertexArray,\n cubeVertexSize,\n cubeUVOffset,\n cubePositionOffset,\n cubeVertexCount,\n} from '../../meshes/cube';\n\nimport basicVertWGSL from '../../shaders/basic.vert.wgsl';\nimport vertexPositionColorWGSL from '../../shaders/vertexPositionColor.frag.wgsl';\n\nconst init: SampleInit = async ({ canvas, pageState }) => {\n const adapter = await navigator.gpu.requestAdapter();\n const device = await adapter.requestDevice();\n\n if (!pageState.active) return;\n const context = canvas.getContext('webgpu') as GPUCanvasContext;\n\n const devicePixelRatio = window.devicePixelRatio;\n canvas.width = canvas.clientWidth * devicePixelRatio;\n canvas.height = canvas.clientHeight * devicePixelRatio;\n const presentationFormat = navigator.gpu.getPreferredCanvasFormat();\n\n context.configure({\n device,\n format: presentationFormat,\n alphaMode: 'premultiplied',\n });\n\n // Create a vertex buffer from the cube data.\n const verticesBuffer = device.createBuffer({\n size: cubeVertexArray.byteLength,\n usage: GPUBufferUsage.VERTEX,\n mappedAtCreation: true,\n });\n new Float32Array(verticesBuffer.getMappedRange()).set(cubeVertexArray);\n verticesBuffer.unmap();\n\n const pipeline = device.createRenderPipeline({\n layout: 'auto',\n vertex: {\n module: device.createShaderModule({\n code: basicVertWGSL,\n }),\n entryPoint: 'main',\n buffers: [\n {\n arrayStride: cubeVertexSize,\n attributes: [\n {\n // position\n shaderLocation: 0,\n offset: cubePositionOffset,\n format: 'float32x4',\n },\n {\n // uv\n shaderLocation: 1,\n offset: cubeUVOffset,\n format: 'float32x2',\n },\n ],\n },\n ],\n },\n fragment: {\n module: device.createShaderModule({\n code: vertexPositionColorWGSL,\n }),\n entryPoint: 'main',\n targets: [\n {\n format: presentationFormat,\n },\n ],\n },\n primitive: {\n topology: 'triangle-list',\n\n // Backface culling since the cube is solid piece of geometry.\n // Faces pointing away from the camera will be occluded by faces\n // pointing toward the camera.\n cullMode: 'back',\n },\n\n // Enable depth testing so that the fragment closest to the camera\n // is rendered in front.\n depthStencil: {\n depthWriteEnabled: true,\n depthCompare: 'less',\n format: 'depth24plus',\n },\n });\n\n const depthTexture = device.createTexture({\n size: [canvas.width, canvas.height],\n format: 'depth24plus',\n usage: GPUTextureUsage.RENDER_ATTACHMENT,\n });\n\n const uniformBufferSize = 4 * 16; // 4x4 matrix\n const uniformBuffer = device.createBuffer({\n size: uniformBufferSize,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n });\n\n const uniformBindGroup = device.createBindGroup({\n layout: pipeline.getBindGroupLayout(0),\n entries: [\n {\n binding: 0,\n resource: {\n buffer: uniformBuffer,\n },\n },\n ],\n });\n\n const renderPassDescriptor: GPURenderPassDescriptor = {\n colorAttachments: [\n {\n view: undefined, // Assigned later\n\n clearValue: { r: 0.5, g: 0.5, b: 0.5, a: 1.0 },\n loadOp: 'clear',\n storeOp: 'store',\n },\n ],\n depthStencilAttachment: {\n view: depthTexture.createView(),\n\n depthClearValue: 1.0,\n depthLoadOp: 'clear',\n depthStoreOp: 'store',\n },\n };\n\n const aspect = canvas.width / canvas.height;\n const projectionMatrix = mat4.perspective(\n (2 * Math.PI) / 5,\n aspect,\n 1,\n 100.0\n );\n const modelViewProjectionMatrix = mat4.create();\n\n function getTransformationMatrix() {\n const viewMatrix = mat4.identity();\n mat4.translate(viewMatrix, vec3.fromValues(0, 0, -4), viewMatrix);\n const now = Date.now() / 1000;\n mat4.rotate(\n viewMatrix,\n vec3.fromValues(Math.sin(now), Math.cos(now), 0),\n 1,\n viewMatrix\n );\n\n mat4.multiply(projectionMatrix, viewMatrix, modelViewProjectionMatrix);\n\n return modelViewProjectionMatrix as Float32Array;\n }\n\n function frame() {\n // Sample is no longer the active page.\n if (!pageState.active) return;\n\n const transformationMatrix = getTransformationMatrix();\n device.queue.writeBuffer(\n uniformBuffer,\n 0,\n transformationMatrix.buffer,\n transformationMatrix.byteOffset,\n transformationMatrix.byteLength\n );\n renderPassDescriptor.colorAttachments[0].view = context\n .getCurrentTexture()\n .createView();\n\n const commandEncoder = device.createCommandEncoder();\n const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);\n passEncoder.setPipeline(pipeline);\n passEncoder.setBindGroup(0, uniformBindGroup);\n passEncoder.setVertexBuffer(0, verticesBuffer);\n passEncoder.draw(cubeVertexCount);\n passEncoder.end();\n device.queue.submit([commandEncoder.finish()]);\n\n requestAnimationFrame(frame);\n }\n requestAnimationFrame(frame);\n};\n\nconst RotatingCube: () => JSX.Element = () =>\n makeSample({\n name: 'Rotating Cube',\n description:\n 'This example shows how to upload uniform data every frame to render a rotating object.',\n init,\n sources: [\n {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n },\n {\n name: '../../shaders/basic.vert.wgsl',\n contents: basicVertWGSL,\n editable: true,\n },\n {\n name: '../../shaders/vertexPositionColor.frag.wgsl',\n contents: vertexPositionColorWGSL,\n editable: true,\n },\n {\n name: '../../meshes/cube.ts',\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n contents: require('!!raw-loader!../../meshes/cube.ts').default,\n },\n ],\n filename: __filename,\n });\n\nexport default RotatingCube;\n"},{name:"../../shaders/basic.vert.wgsl",contents:s.Z,editable:!0},{name:"../../shaders/vertexPositionColor.frag.wgsl",contents:c.Z,editable:!0},{name:"../../meshes/cube.ts",contents:t(2448).Z}],filename:r});n.default=l},9147:function(e){e.exports={canvasContainer:"SampleLayout_canvasContainer__zRR_l",sourceFileNav:"SampleLayout_sourceFileNav__ml48P",sourceFileScrollContainer:"SampleLayout_sourceFileScrollContainer__LsNEm",sourceFileContainer:"SampleLayout_sourceFileContainer__3s84x"}},2448:function(e,n){"use strict";n.Z="export const cubeVertexSize = 4 * 10; // Byte size of one cube vertex.\nexport const cubePositionOffset = 0;\nexport const cubeColorOffset = 4 * 4; // Byte offset of cube vertex color attribute.\nexport const cubeUVOffset = 4 * 8;\nexport const cubeVertexCount = 36;\n\n// prettier-ignore\nexport const cubeVertexArray = new Float32Array([\n // float4 position, float4 color, float2 uv,\n 1, -1, 1, 1, 1, 0, 1, 1, 0, 1,\n -1, -1, 1, 1, 0, 0, 1, 1, 1, 1,\n -1, -1, -1, 1, 0, 0, 0, 1, 1, 0,\n 1, -1, -1, 1, 1, 0, 0, 1, 0, 0,\n 1, -1, 1, 1, 1, 0, 1, 1, 0, 1,\n -1, -1, -1, 1, 0, 0, 0, 1, 1, 0,\n\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n 1, -1, 1, 1, 1, 0, 1, 1, 1, 1,\n 1, -1, -1, 1, 1, 0, 0, 1, 1, 0,\n 1, 1, -1, 1, 1, 1, 0, 1, 0, 0,\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n 1, -1, -1, 1, 1, 0, 0, 1, 1, 0,\n\n -1, 1, 1, 1, 0, 1, 1, 1, 0, 1,\n 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n 1, 1, -1, 1, 1, 1, 0, 1, 1, 0,\n -1, 1, -1, 1, 0, 1, 0, 1, 0, 0,\n -1, 1, 1, 1, 0, 1, 1, 1, 0, 1,\n 1, 1, -1, 1, 1, 1, 0, 1, 1, 0,\n\n -1, -1, 1, 1, 0, 0, 1, 1, 0, 1,\n -1, 1, 1, 1, 0, 1, 1, 1, 1, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n -1, -1, -1, 1, 0, 0, 0, 1, 0, 0,\n -1, -1, 1, 1, 0, 0, 1, 1, 0, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n -1, 1, 1, 1, 0, 1, 1, 1, 1, 1,\n -1, -1, 1, 1, 0, 0, 1, 1, 1, 0,\n -1, -1, 1, 1, 0, 0, 1, 1, 1, 0,\n 1, -1, 1, 1, 1, 0, 1, 1, 0, 0,\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n\n 1, -1, -1, 1, 1, 0, 0, 1, 0, 1,\n -1, -1, -1, 1, 0, 0, 0, 1, 1, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n 1, 1, -1, 1, 1, 1, 0, 1, 0, 0,\n 1, -1, -1, 1, 1, 0, 0, 1, 0, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n]);\n"},3569:function(e,n){"use strict";n.Z="struct Uniforms {\n modelViewProjectionMatrix : mat4x4,\n}\n@binding(0) @group(0) var uniforms : Uniforms;\n\nstruct VertexOutput {\n @builtin(position) Position : vec4,\n @location(0) fragUV : vec2,\n @location(1) fragPosition: vec4,\n}\n\n@vertex\nfn main(\n @location(0) position : vec4,\n @location(1) uv : vec2\n) -> VertexOutput {\n var output : VertexOutput;\n output.Position = uniforms.modelViewProjectionMatrix * position;\n output.fragUV = uv;\n output.fragPosition = 0.5 * (position + vec4(1.0, 1.0, 1.0, 1.0));\n return output;\n}\n"},1945:function(e,n){"use strict";n.Z="@fragment\nfn main(\n @location(0) fragUV: vec2,\n @location(1) fragPosition: vec4\n) -> @location(0) vec4 {\n return fragPosition;\n}\n"}}]);
\ No newline at end of file
diff --git a/_next/static/chunks/167.ebd957fe7db1b37a.js b/_next/static/chunks/167.ebd957fe7db1b37a.js
deleted file mode 100644
index 7904a885..00000000
--- a/_next/static/chunks/167.ebd957fe7db1b37a.js
+++ /dev/null
@@ -1 +0,0 @@
-(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[167],{5671:function(e,n,t){"use strict";t.d(n,{Tl:function(){return d},hu:function(){return p}});var r=t(5893),i=t(9008),a=t.n(i),o=t(1163),s=t(7294),l=t(9147),u=t.n(l);t(7319);let c=e=>{let n=(0,s.useRef)(null),i=(0,s.useRef)(null),l=(0,s.useMemo)(()=>e.sources.map(e=>{let{name:n,contents:i}=e;return{name:n,...function(e){let n;let i=null;{i=document.createElement("div");let a=t(4631);n=a(i,{lineNumbers:!0,lineWrapping:!0,theme:"monokai",readOnly:!0})}return{Container:function(t){return(0,r.jsx)("div",{...t,children:(0,r.jsx)("div",{ref(t){i&&t&&(t.appendChild(i),n.setOption("value",e))}})})}}}(i)}}),e.sources),c=(0,s.useRef)(null),d=(0,s.useMemo)(()=>{if(e.gui){let n=t(4376),r=new n.GUI({autoPlace:!1});return r.domElement.style.position="relative",r.domElement.style.zIndex="1000",r}},[]),p=(0,s.useRef)(null),f=(0,s.useMemo)(()=>{if(e.stats){let n=t(2792);return new n}},[]),m=(0,o.useRouter)(),v=m.asPath.match(/#([a-zA-Z0-9\.\/]+)/),[g,h]=(0,s.useState)(null),[b,x]=(0,s.useState)(null);return(0,s.useEffect)(()=>{if(v?x(v[1]):x(l[0].name),d&&c.current)for(c.current.appendChild(d.domElement);d.__controllers.length>0;)d.__controllers[0].remove();f&&p.current&&(f.dom.style.position="absolute",f.showPanel(1),p.current.appendChild(f.dom));let t={active:!0},r=()=>{t.active=!1};try{let i=n.current;if(!i)throw Error("The canvas is not available");let a=e.init({canvas:i,pageState:t,gui:d,stats:f});a instanceof Promise&&a.catch(e=>{console.error(e),h(e)})}catch(o){console.error(o),h(o)}return r},[]),(0,r.jsxs)("main",{children:[(0,r.jsxs)(a(),{children:[(0,r.jsx)("style",{dangerouslySetInnerHTML:{__html:"\n .CodeMirror {\n height: auto !important;\n margin: 1em 0;\n }\n\n .CodeMirror-scroll {\n height: auto !important;\n overflow: visible !important;\n }\n "}}),(0,r.jsx)("title",{children:"".concat(e.name," - WebGPU Samples")}),(0,r.jsx)("meta",{name:"description",content:e.description}),(0,r.jsx)("meta",{httpEquiv:"origin-trial",content:e.originTrial})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("h1",{children:e.name}),(0,r.jsx)("a",{target:"_blank",rel:"noreferrer",href:"https://github.com/".concat("webgpu/webgpu-samples","/tree/main/").concat(e.filename),children:"See it on Github!"}),(0,r.jsx)("p",{children:e.description}),g?(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("p",{children:"Something went wrong. Do your browser and device support WebGPU?"}),(0,r.jsx)("p",{children:"".concat(g)})]}):null]}),(0,r.jsxs)("div",{className:u().canvasContainer,children:[(0,r.jsx)("div",{style:{position:"absolute",left:10},ref:p}),(0,r.jsx)("div",{style:{position:"absolute",right:10},ref:c}),(0,r.jsx)("canvas",{ref:n})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("nav",{className:u().sourceFileNav,ref:i,children:(0,r.jsx)("div",{className:u().sourceFileScrollContainer,onScroll(e){let n=e.currentTarget,t=n.scrollWidth-n.clientWidth-n.scrollLeft;n.scrollLeft>25?i.current.setAttribute("data-left","true"):i.current.setAttribute("data-left","false"),t>25?i.current.setAttribute("data-right","true"):i.current.setAttribute("data-right","false")},children:(0,r.jsx)("ul",{children:l.map((e,n)=>(0,r.jsx)("li",{children:(0,r.jsx)("a",{href:"#".concat(e.name),"data-active":b==e.name,onClick(){x(e.name)},children:e.name})},n))})})}),l.map((e,n)=>(0,r.jsx)(e.Container,{className:u().sourceFileContainer,"data-active":b==e.name},n))]})]})},d=e=>(0,r.jsx)(c,{...e});function p(e,n){if(!e)throw Error(n)}},6167:function(e,n,t){"use strict";t.r(n),t.d(n,{default:function(){return c}});var r=t(6416),i=t(5671),a="////////////////////////////////////////////////////////////////////////////////\n// Utilities\n////////////////////////////////////////////////////////////////////////////////\nvar rand_seed : vec2;\n\nfn init_rand(invocation_id : u32, seed : vec4) {\n rand_seed = seed.xz;\n rand_seed = fract(rand_seed * cos(35.456+f32(invocation_id) * seed.yw));\n rand_seed = fract(rand_seed * cos(41.235+f32(invocation_id) * seed.xw));\n}\n\nfn rand() -> f32 {\n rand_seed.x = fract(cos(dot(rand_seed, vec2(23.14077926, 232.61690225))) * 136.8168);\n rand_seed.y = fract(cos(dot(rand_seed, vec2(54.47856553, 345.84153136))) * 534.7645);\n return rand_seed.y;\n}\n\n////////////////////////////////////////////////////////////////////////////////\n// Vertex shader\n////////////////////////////////////////////////////////////////////////////////\nstruct RenderParams {\n modelViewProjectionMatrix : mat4x4,\n right : vec3,\n up : vec3\n}\n@binding(0) @group(0) var render_params : RenderParams;\n\nstruct VertexInput {\n @location(0) position : vec3,\n @location(1) color : vec4,\n @location(2) quad_pos : vec2, // -1..+1\n}\n\nstruct VertexOutput {\n @builtin(position) position : vec4,\n @location(0) color : vec4,\n @location(1) quad_pos : vec2, // -1..+1\n}\n\n@vertex\nfn vs_main(in : VertexInput) -> VertexOutput {\n var quad_pos = mat2x3(render_params.right, render_params.up) * in.quad_pos;\n var position = in.position + quad_pos * 0.01;\n var out : VertexOutput;\n out.position = render_params.modelViewProjectionMatrix * vec4(position, 1.0);\n out.color = in.color;\n out.quad_pos = in.quad_pos;\n return out;\n}\n\n////////////////////////////////////////////////////////////////////////////////\n// Fragment shader\n////////////////////////////////////////////////////////////////////////////////\n@fragment\nfn fs_main(in : VertexOutput) -> @location(0) vec4 {\n var color = in.color;\n // Apply a circular particle alpha mask\n color.a = color.a * max(1.0 - length(in.quad_pos), 0.0);\n return color;\n}\n\n////////////////////////////////////////////////////////////////////////////////\n// Simulation Compute shader\n////////////////////////////////////////////////////////////////////////////////\nstruct SimulationParams {\n deltaTime : f32,\n seed : vec4,\n}\n\nstruct Particle {\n position : vec3,\n lifetime : f32,\n color : vec4,\n velocity : vec3,\n}\n\nstruct Particles {\n particles : array,\n}\n\n@binding(0) @group(0) var sim_params : SimulationParams;\n@binding(1) @group(0) var data : Particles;\n@binding(2) @group(0) var texture : texture_2d;\n\n@compute @workgroup_size(64)\nfn simulate(@builtin(global_invocation_id) global_invocation_id : vec3) {\n let idx = global_invocation_id.x;\n\n init_rand(idx, sim_params.seed);\n\n var particle = data.particles[idx];\n\n // Apply gravity\n particle.velocity.z = particle.velocity.z - sim_params.deltaTime * 0.5;\n\n // Basic velocity integration\n particle.position = particle.position + sim_params.deltaTime * particle.velocity;\n\n // Age each particle. Fade out before vanishing.\n particle.lifetime = particle.lifetime - sim_params.deltaTime;\n particle.color.a = smoothstep(0.0, 0.5, particle.lifetime);\n\n // If the lifetime has gone negative, then the particle is dead and should be\n // respawned.\n if (particle.lifetime < 0.0) {\n // Use the probability map to find where the particle should be spawned.\n // Starting with the 1x1 mip level.\n var coord : vec2;\n for (var level = u32(textureNumLevels(texture) - 1); level > 0; level--) {\n // Load the probability value from the mip-level\n // Generate a random number and using the probabilty values, pick the\n // next texel in the next largest mip level:\n //\n // 0.0 probabilites.r probabilites.g probabilites.b 1.0\n // | | | | |\n // | TOP-LEFT | TOP-RIGHT | BOTTOM-LEFT | BOTTOM_RIGHT |\n //\n let probabilites = textureLoad(texture, coord, level);\n let value = vec4(rand());\n let mask = (value >= vec4(0.0, probabilites.xyz)) & (value < probabilites);\n coord = coord * 2;\n coord.x = coord.x + select(0, 1, any(mask.yw)); // x y\n coord.y = coord.y + select(0, 1, any(mask.zw)); // z w\n }\n let uv = vec2(coord) / vec2(textureDimensions(texture));\n particle.position = vec3((uv - 0.5) * 3.0 * vec2(1.0, -1.0), 0.0);\n particle.color = textureLoad(texture, coord, 0);\n particle.velocity.x = (rand() - 0.5) * 0.1;\n particle.velocity.y = (rand() - 0.5) * 0.1;\n particle.velocity.z = rand() * 0.3;\n particle.lifetime = 0.5 + rand() * 3.0;\n }\n\n // Store the new particle value\n data.particles[idx] = particle;\n}\n",o="struct UBO {\n width : u32,\n}\n\nstruct Buffer {\n weights : array,\n}\n\n@binding(0) @group(0) var ubo : UBO;\n@binding(1) @group(0) var buf_in : Buffer;\n@binding(2) @group(0) var buf_out : Buffer;\n@binding(3) @group(0) var tex_in : texture_2d;\n@binding(3) @group(0) var tex_out : texture_storage_2d;\n\n\n////////////////////////////////////////////////////////////////////////////////\n// import_level\n//\n// Loads the alpha channel from a texel of the source image, and writes it to\n// the buf_out.weights.\n////////////////////////////////////////////////////////////////////////////////\n@compute @workgroup_size(64)\nfn import_level(@builtin(global_invocation_id) coord : vec3) {\n _ = &buf_in;\n let offset = coord.x + coord.y * ubo.width;\n buf_out.weights[offset] = textureLoad(tex_in, vec2(coord.xy), 0).w;\n}\n\n////////////////////////////////////////////////////////////////////////////////\n// export_level\n//\n// Loads 4 f32 weight values from buf_in.weights, and stores summed value into\n// buf_out.weights, along with the calculated 'probabilty' vec4 values into the\n// mip level of tex_out. See simulate() in particle.wgsl to understand the\n// probability logic.\n////////////////////////////////////////////////////////////////////////////////\n@compute @workgroup_size(64)\nfn export_level(@builtin(global_invocation_id) coord : vec3) {\n if (all(coord.xy < vec2(textureDimensions(tex_out)))) {\n let dst_offset = coord.x + coord.y * ubo.width;\n let src_offset = coord.x*2u + coord.y*2u * ubo.width;\n\n let a = buf_in.weights[src_offset + 0u];\n let b = buf_in.weights[src_offset + 1u];\n let c = buf_in.weights[src_offset + 0u + ubo.width];\n let d = buf_in.weights[src_offset + 1u + ubo.width];\n let sum = dot(vec4(a, b, c, d), vec4(1.0));\n\n buf_out.weights[dst_offset] = sum / 4.0;\n\n let probabilities = vec4(a, a+b, a+b+c, sum) / max(sum, 0.0001);\n textureStore(tex_out, vec2(coord.xy), probabilities);\n }\n}\n",s="src/sample/particles/main.ts";let l=async e=>{let n,{canvas:t,pageState:i,gui:s}=e,l=await navigator.gpu.requestAdapter(),u=await l.requestDevice();if(!i.active)return;let c=t.getContext("webgpu"),d=window.devicePixelRatio;t.width=t.clientWidth*d,t.height=t.clientHeight*d;let p=navigator.gpu.getPreferredCanvasFormat();c.configure({device:u,format:p,alphaMode:"premultiplied"});let f=u.createBuffer({size:24e5,usage:GPUBufferUsage.VERTEX|GPUBufferUsage.STORAGE}),m=u.createRenderPipeline({layout:"auto",vertex:{module:u.createShaderModule({code:a}),entryPoint:"vs_main",buffers:[{arrayStride:48,stepMode:"instance",attributes:[{shaderLocation:0,offset:0,format:"float32x3"},{shaderLocation:1,offset:16,format:"float32x4"}]},{arrayStride:8,stepMode:"vertex",attributes:[{shaderLocation:2,offset:0,format:"float32x2"}]}]},fragment:{module:u.createShaderModule({code:a}),entryPoint:"fs_main",targets:[{format:p,blend:{color:{srcFactor:"src-alpha",dstFactor:"one",operation:"add"},alpha:{srcFactor:"zero",dstFactor:"one",operation:"add"}}}]},primitive:{topology:"triangle-list"},depthStencil:{depthWriteEnabled:!1,depthCompare:"less",format:"depth24plus"}}),v=u.createTexture({size:[t.width,t.height],format:"depth24plus",usage:GPUTextureUsage.RENDER_ATTACHMENT}),g=u.createBuffer({size:96,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST}),h=u.createBindGroup({layout:m.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:g}}]}),b={colorAttachments:[{view:void 0,clearValue:{r:0,g:0,b:0,a:1},loadOp:"clear",storeOp:"store"}],depthStencilAttachment:{view:v.createView(),depthClearValue:1,depthLoadOp:"clear",depthStoreOp:"store"}},x=u.createBuffer({size:48,usage:GPUBufferUsage.VERTEX,mappedAtCreation:!0});new Float32Array(x.getMappedRange()).set([-1,-1,1,-1,-1,1,-1,1,1,-1,1,1]),x.unmap();let _=1,w=1,P=1;{let y=await fetch("../assets/img/webgpu.png"),B=await createImageBitmap(await y.blob());for(;_>C,L=w>>C,R=0==C?E.getBindGroupLayout(0):U.getBindGroupLayout(0),A=u.createBindGroup({layout:R,entries:[{binding:0,resource:{buffer:G}},{binding:1,resource:{buffer:1&C?T:S}},{binding:2,resource:{buffer:1&C?S:T}},{binding:3,resource:n.createView({format:"rgba8unorm",dimension:"2d",baseMipLevel:C,mipLevelCount:1})}]});if(0==C){let z=M.beginComputePass();z.setPipeline(E),z.setBindGroup(0,A),z.dispatchWorkgroups(Math.ceil(O/64),L),z.end()}else{let F=M.beginComputePass();F.setPipeline(U),F.setBindGroup(0,A),F.dispatchWorkgroups(Math.ceil(O/64),L),F.end()}}u.queue.submit([M.finish()])}let I={simulate:!0,deltaTime:.04},V=u.createBuffer({size:32,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST});Object.keys(I).forEach(e=>{s.add(I,e)});let j=u.createComputePipeline({layout:"auto",compute:{module:u.createShaderModule({code:a}),entryPoint:"simulate"}}),q=u.createBindGroup({layout:j.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:V}},{binding:1,resource:{buffer:f,offset:0,size:24e5}},{binding:2,resource:n.createView()}]}),N=t.width/t.height,W=r._E.perspective(2*Math.PI/5,N,1,100),k=r._E.create(),D=r._E.create();requestAnimationFrame(function e(){if(!i.active)return;u.queue.writeBuffer(V,0,new Float32Array([I.simulate?I.deltaTime:0,0,0,0,100*Math.random(),100*Math.random(),1+Math.random(),1+Math.random()])),r._E.identity(k),r._E.translate(k,r.R3.fromValues(0,0,-3),k),r._E.rotateX(k,-.2*Math.PI,k),r._E.multiply(W,k,D),u.queue.writeBuffer(g,0,new Float32Array([D[0],D[1],D[2],D[3],D[4],D[5],D[6],D[7],D[8],D[9],D[10],D[11],D[12],D[13],D[14],D[15],k[0],k[4],k[8],0,k[1],k[5],k[9],0]));let n=c.getCurrentTexture();b.colorAttachments[0].view=n.createView();let t=u.createCommandEncoder();{let a=t.beginComputePass();a.setPipeline(j),a.setBindGroup(0,q),a.dispatchWorkgroups(Math.ceil(781.25)),a.end()}{let o=t.beginRenderPass(b);o.setPipeline(m),o.setBindGroup(0,h),o.setVertexBuffer(0,f),o.setVertexBuffer(1,x),o.draw(6,5e4,0,0),o.end()}u.queue.submit([t.finish()]),requestAnimationFrame(e)})},u=()=>(0,i.Tl)({name:"Particles",description:"This example demonstrates rendering of particles simulated with compute shaders.",gui:!0,init:l,sources:[{name:s.substring(21),contents:"import { mat4, vec3 } from 'wgpu-matrix';\nimport { makeSample, SampleInit } from '../../components/SampleLayout';\n\nimport particleWGSL from './particle.wgsl';\nimport probabilityMapWGSL from './probabilityMap.wgsl';\n\nconst numParticles = 50000;\nconst particlePositionOffset = 0;\nconst particleColorOffset = 4 * 4;\nconst particleInstanceByteSize =\n 3 * 4 + // position\n 1 * 4 + // lifetime\n 4 * 4 + // color\n 3 * 4 + // velocity\n 1 * 4 + // padding\n 0;\n\nconst init: SampleInit = async ({ canvas, pageState, gui }) => {\n const adapter = await navigator.gpu.requestAdapter();\n const device = await adapter.requestDevice();\n\n if (!pageState.active) return;\n const context = canvas.getContext('webgpu') as GPUCanvasContext;\n\n const devicePixelRatio = window.devicePixelRatio;\n canvas.width = canvas.clientWidth * devicePixelRatio;\n canvas.height = canvas.clientHeight * devicePixelRatio;\n const presentationFormat = navigator.gpu.getPreferredCanvasFormat();\n\n context.configure({\n device,\n format: presentationFormat,\n alphaMode: 'premultiplied',\n });\n\n const particlesBuffer = device.createBuffer({\n size: numParticles * particleInstanceByteSize,\n usage: GPUBufferUsage.VERTEX | GPUBufferUsage.STORAGE,\n });\n\n const renderPipeline = device.createRenderPipeline({\n layout: 'auto',\n vertex: {\n module: device.createShaderModule({\n code: particleWGSL,\n }),\n entryPoint: 'vs_main',\n buffers: [\n {\n // instanced particles buffer\n arrayStride: particleInstanceByteSize,\n stepMode: 'instance',\n attributes: [\n {\n // position\n shaderLocation: 0,\n offset: particlePositionOffset,\n format: 'float32x3',\n },\n {\n // color\n shaderLocation: 1,\n offset: particleColorOffset,\n format: 'float32x4',\n },\n ],\n },\n {\n // quad vertex buffer\n arrayStride: 2 * 4, // vec2\n stepMode: 'vertex',\n attributes: [\n {\n // vertex positions\n shaderLocation: 2,\n offset: 0,\n format: 'float32x2',\n },\n ],\n },\n ],\n },\n fragment: {\n module: device.createShaderModule({\n code: particleWGSL,\n }),\n entryPoint: 'fs_main',\n targets: [\n {\n format: presentationFormat,\n blend: {\n color: {\n srcFactor: 'src-alpha',\n dstFactor: 'one',\n operation: 'add',\n },\n alpha: {\n srcFactor: 'zero',\n dstFactor: 'one',\n operation: 'add',\n },\n },\n },\n ],\n },\n primitive: {\n topology: 'triangle-list',\n },\n\n depthStencil: {\n depthWriteEnabled: false,\n depthCompare: 'less',\n format: 'depth24plus',\n },\n });\n\n const depthTexture = device.createTexture({\n size: [canvas.width, canvas.height],\n format: 'depth24plus',\n usage: GPUTextureUsage.RENDER_ATTACHMENT,\n });\n\n const uniformBufferSize =\n 4 * 4 * 4 + // modelViewProjectionMatrix : mat4x4\n 3 * 4 + // right : vec3\n 4 + // padding\n 3 * 4 + // up : vec3\n 4 + // padding\n 0;\n const uniformBuffer = device.createBuffer({\n size: uniformBufferSize,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n });\n\n const uniformBindGroup = device.createBindGroup({\n layout: renderPipeline.getBindGroupLayout(0),\n entries: [\n {\n binding: 0,\n resource: {\n buffer: uniformBuffer,\n },\n },\n ],\n });\n\n const renderPassDescriptor: GPURenderPassDescriptor = {\n colorAttachments: [\n {\n view: undefined, // Assigned later\n clearValue: { r: 0.0, g: 0.0, b: 0.0, a: 1.0 },\n loadOp: 'clear',\n storeOp: 'store',\n },\n ],\n depthStencilAttachment: {\n view: depthTexture.createView(),\n\n depthClearValue: 1.0,\n depthLoadOp: 'clear',\n depthStoreOp: 'store',\n },\n };\n\n //////////////////////////////////////////////////////////////////////////////\n // Quad vertex buffer\n //////////////////////////////////////////////////////////////////////////////\n const quadVertexBuffer = device.createBuffer({\n size: 6 * 2 * 4, // 6x vec2\n usage: GPUBufferUsage.VERTEX,\n mappedAtCreation: true,\n });\n // prettier-ignore\n const vertexData = [\n -1.0, -1.0, +1.0, -1.0, -1.0, +1.0, -1.0, +1.0, +1.0, -1.0, +1.0, +1.0,\n ];\n new Float32Array(quadVertexBuffer.getMappedRange()).set(vertexData);\n quadVertexBuffer.unmap();\n\n //////////////////////////////////////////////////////////////////////////////\n // Texture\n //////////////////////////////////////////////////////////////////////////////\n let texture: GPUTexture;\n let textureWidth = 1;\n let textureHeight = 1;\n let numMipLevels = 1;\n {\n const response = await fetch('../assets/img/webgpu.png');\n const imageBitmap = await createImageBitmap(await response.blob());\n\n // Calculate number of mip levels required to generate the probability map\n while (\n textureWidth < imageBitmap.width ||\n textureHeight < imageBitmap.height\n ) {\n textureWidth *= 2;\n textureHeight *= 2;\n numMipLevels++;\n }\n texture = device.createTexture({\n size: [imageBitmap.width, imageBitmap.height, 1],\n mipLevelCount: numMipLevels,\n format: 'rgba8unorm',\n usage:\n GPUTextureUsage.TEXTURE_BINDING |\n GPUTextureUsage.STORAGE_BINDING |\n GPUTextureUsage.COPY_DST |\n GPUTextureUsage.RENDER_ATTACHMENT,\n });\n device.queue.copyExternalImageToTexture(\n { source: imageBitmap },\n { texture: texture },\n [imageBitmap.width, imageBitmap.height]\n );\n }\n\n //////////////////////////////////////////////////////////////////////////////\n // Probability map generation\n // The 0'th mip level of texture holds the color data and spawn-probability in\n // the alpha channel. The mip levels 1..N are generated to hold spawn\n // probabilities up to the top 1x1 mip level.\n //////////////////////////////////////////////////////////////////////////////\n {\n const probabilityMapImportLevelPipeline = device.createComputePipeline({\n layout: 'auto',\n compute: {\n module: device.createShaderModule({ code: probabilityMapWGSL }),\n entryPoint: 'import_level',\n },\n });\n const probabilityMapExportLevelPipeline = device.createComputePipeline({\n layout: 'auto',\n compute: {\n module: device.createShaderModule({ code: probabilityMapWGSL }),\n entryPoint: 'export_level',\n },\n });\n\n const probabilityMapUBOBufferSize =\n 1 * 4 + // stride\n 3 * 4 + // padding\n 0;\n const probabilityMapUBOBuffer = device.createBuffer({\n size: probabilityMapUBOBufferSize,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n });\n const buffer_a = device.createBuffer({\n size: textureWidth * textureHeight * 4,\n usage: GPUBufferUsage.STORAGE,\n });\n const buffer_b = device.createBuffer({\n size: textureWidth * textureHeight * 4,\n usage: GPUBufferUsage.STORAGE,\n });\n device.queue.writeBuffer(\n probabilityMapUBOBuffer,\n 0,\n new Int32Array([textureWidth])\n );\n const commandEncoder = device.createCommandEncoder();\n for (let level = 0; level < numMipLevels; level++) {\n const levelWidth = textureWidth >> level;\n const levelHeight = textureHeight >> level;\n const pipeline =\n level == 0\n ? probabilityMapImportLevelPipeline.getBindGroupLayout(0)\n : probabilityMapExportLevelPipeline.getBindGroupLayout(0);\n const probabilityMapBindGroup = device.createBindGroup({\n layout: pipeline,\n entries: [\n {\n // ubo\n binding: 0,\n resource: { buffer: probabilityMapUBOBuffer },\n },\n {\n // buf_in\n binding: 1,\n resource: { buffer: level & 1 ? buffer_a : buffer_b },\n },\n {\n // buf_out\n binding: 2,\n resource: { buffer: level & 1 ? buffer_b : buffer_a },\n },\n {\n // tex_in / tex_out\n binding: 3,\n resource: texture.createView({\n format: 'rgba8unorm',\n dimension: '2d',\n baseMipLevel: level,\n mipLevelCount: 1,\n }),\n },\n ],\n });\n if (level == 0) {\n const passEncoder = commandEncoder.beginComputePass();\n passEncoder.setPipeline(probabilityMapImportLevelPipeline);\n passEncoder.setBindGroup(0, probabilityMapBindGroup);\n passEncoder.dispatchWorkgroups(Math.ceil(levelWidth / 64), levelHeight);\n passEncoder.end();\n } else {\n const passEncoder = commandEncoder.beginComputePass();\n passEncoder.setPipeline(probabilityMapExportLevelPipeline);\n passEncoder.setBindGroup(0, probabilityMapBindGroup);\n passEncoder.dispatchWorkgroups(Math.ceil(levelWidth / 64), levelHeight);\n passEncoder.end();\n }\n }\n device.queue.submit([commandEncoder.finish()]);\n }\n\n //////////////////////////////////////////////////////////////////////////////\n // Simulation compute pipeline\n //////////////////////////////////////////////////////////////////////////////\n const simulationParams = {\n simulate: true,\n deltaTime: 0.04,\n };\n\n const simulationUBOBufferSize =\n 1 * 4 + // deltaTime\n 3 * 4 + // padding\n 4 * 4 + // seed\n 0;\n const simulationUBOBuffer = device.createBuffer({\n size: simulationUBOBufferSize,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n });\n\n Object.keys(simulationParams).forEach((k) => {\n gui.add(simulationParams, k);\n });\n\n const computePipeline = device.createComputePipeline({\n layout: 'auto',\n compute: {\n module: device.createShaderModule({\n code: particleWGSL,\n }),\n entryPoint: 'simulate',\n },\n });\n const computeBindGroup = device.createBindGroup({\n layout: computePipeline.getBindGroupLayout(0),\n entries: [\n {\n binding: 0,\n resource: {\n buffer: simulationUBOBuffer,\n },\n },\n {\n binding: 1,\n resource: {\n buffer: particlesBuffer,\n offset: 0,\n size: numParticles * particleInstanceByteSize,\n },\n },\n {\n binding: 2,\n resource: texture.createView(),\n },\n ],\n });\n\n const aspect = canvas.width / canvas.height;\n const projection = mat4.perspective((2 * Math.PI) / 5, aspect, 1, 100.0);\n const view = mat4.create();\n const mvp = mat4.create();\n\n function frame() {\n // Sample is no longer the active page.\n if (!pageState.active) return;\n\n device.queue.writeBuffer(\n simulationUBOBuffer,\n 0,\n new Float32Array([\n simulationParams.simulate ? simulationParams.deltaTime : 0.0,\n 0.0,\n 0.0,\n 0.0, // padding\n Math.random() * 100,\n Math.random() * 100, // seed.xy\n 1 + Math.random(),\n 1 + Math.random(), // seed.zw\n ])\n );\n\n mat4.identity(view);\n mat4.translate(view, vec3.fromValues(0, 0, -3), view);\n mat4.rotateX(view, Math.PI * -0.2, view);\n mat4.multiply(projection, view, mvp);\n\n // prettier-ignore\n device.queue.writeBuffer(\n uniformBuffer,\n 0,\n new Float32Array([\n // modelViewProjectionMatrix\n mvp[0], mvp[1], mvp[2], mvp[3],\n mvp[4], mvp[5], mvp[6], mvp[7],\n mvp[8], mvp[9], mvp[10], mvp[11],\n mvp[12], mvp[13], mvp[14], mvp[15],\n\n view[0], view[4], view[8], // right\n\n 0, // padding\n\n view[1], view[5], view[9], // up\n\n 0, // padding\n ])\n );\n const swapChainTexture = context.getCurrentTexture();\n // prettier-ignore\n renderPassDescriptor.colorAttachments[0].view = swapChainTexture.createView();\n\n const commandEncoder = device.createCommandEncoder();\n {\n const passEncoder = commandEncoder.beginComputePass();\n passEncoder.setPipeline(computePipeline);\n passEncoder.setBindGroup(0, computeBindGroup);\n passEncoder.dispatchWorkgroups(Math.ceil(numParticles / 64));\n passEncoder.end();\n }\n {\n const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);\n passEncoder.setPipeline(renderPipeline);\n passEncoder.setBindGroup(0, uniformBindGroup);\n passEncoder.setVertexBuffer(0, particlesBuffer);\n passEncoder.setVertexBuffer(1, quadVertexBuffer);\n passEncoder.draw(6, numParticles, 0, 0);\n passEncoder.end();\n }\n\n device.queue.submit([commandEncoder.finish()]);\n\n requestAnimationFrame(frame);\n }\n requestAnimationFrame(frame);\n};\n\nconst Particles: () => JSX.Element = () =>\n makeSample({\n name: 'Particles',\n description:\n 'This example demonstrates rendering of particles simulated with compute shaders.',\n gui: true,\n init,\n sources: [\n {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n },\n {\n name: './particle.wgsl',\n contents: particleWGSL,\n editable: true,\n },\n {\n name: './probabilityMap.wgsl',\n contents: probabilityMapWGSL,\n editable: true,\n },\n ],\n filename: __filename,\n });\n\nexport default Particles;\n"},{name:"./particle.wgsl",contents:a,editable:!0},{name:"./probabilityMap.wgsl",contents:o,editable:!0}],filename:s});var c=u},9147:function(e){e.exports={canvasContainer:"SampleLayout_canvasContainer__zRR_l",sourceFileNav:"SampleLayout_sourceFileNav__ml48P",sourceFileScrollContainer:"SampleLayout_sourceFileScrollContainer__LsNEm",sourceFileContainer:"SampleLayout_sourceFileContainer__3s84x"}}}]);
\ No newline at end of file
diff --git a/_next/static/chunks/198.4cc4bc46b0ac1516.js b/_next/static/chunks/198.4cc4bc46b0ac1516.js
deleted file mode 100644
index 793c17bf..00000000
--- a/_next/static/chunks/198.4cc4bc46b0ac1516.js
+++ /dev/null
@@ -1 +0,0 @@
-(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[198],{5671:function(e,n,t){"use strict";t.d(n,{Tl:function(){return d},hu:function(){return m}});var r=t(5893),a=t(9008),i=t.n(a),o=t(1163),s=t(7294),l=t(9147),c=t.n(l);t(7319);let u=e=>{let n=(0,s.useRef)(null),a=(0,s.useRef)(null),l=(0,s.useMemo)(()=>e.sources.map(e=>{let{name:n,contents:a}=e;return{name:n,...function(e){let n;let a=null;{a=document.createElement("div");let i=t(4631);n=i(a,{lineNumbers:!0,lineWrapping:!0,theme:"monokai",readOnly:!0})}return{Container:function(t){return(0,r.jsx)("div",{...t,children:(0,r.jsx)("div",{ref(t){a&&t&&(t.appendChild(a),n.setOption("value",e))}})})}}}(a)}}),e.sources),u=(0,s.useRef)(null),d=(0,s.useMemo)(()=>{if(e.gui){let n=t(4376),r=new n.GUI({autoPlace:!1});return r.domElement.style.position="relative",r.domElement.style.zIndex="1000",r}},[]),m=(0,s.useRef)(null),p=(0,s.useMemo)(()=>{if(e.stats){let n=t(2792);return new n}},[]),g=(0,o.useRouter)(),h=g.asPath.match(/#([a-zA-Z0-9\.\/]+)/),[v,f]=(0,s.useState)(null),[x,w]=(0,s.useState)(null);return(0,s.useEffect)(()=>{if(h?w(h[1]):w(l[0].name),d&&u.current)for(u.current.appendChild(d.domElement);d.__controllers.length>0;)d.__controllers[0].remove();p&&m.current&&(p.dom.style.position="absolute",p.showPanel(1),m.current.appendChild(p.dom));let t={active:!0},r=()=>{t.active=!1};try{let a=n.current;if(!a)throw Error("The canvas is not available");let i=e.init({canvas:a,pageState:t,gui:d,stats:p});i instanceof Promise&&i.catch(e=>{console.error(e),f(e)})}catch(o){console.error(o),f(o)}return r},[]),(0,r.jsxs)("main",{children:[(0,r.jsxs)(i(),{children:[(0,r.jsx)("style",{dangerouslySetInnerHTML:{__html:"\n .CodeMirror {\n height: auto !important;\n margin: 1em 0;\n }\n\n .CodeMirror-scroll {\n height: auto !important;\n overflow: visible !important;\n }\n "}}),(0,r.jsx)("title",{children:"".concat(e.name," - WebGPU Samples")}),(0,r.jsx)("meta",{name:"description",content:e.description}),(0,r.jsx)("meta",{httpEquiv:"origin-trial",content:e.originTrial})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("h1",{children:e.name}),(0,r.jsx)("a",{target:"_blank",rel:"noreferrer",href:"https://github.com/".concat("webgpu/webgpu-samples","/tree/main/").concat(e.filename),children:"See it on Github!"}),(0,r.jsx)("p",{children:e.description}),v?(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("p",{children:"Something went wrong. Do your browser and device support WebGPU?"}),(0,r.jsx)("p",{children:"".concat(v)})]}):null]}),(0,r.jsxs)("div",{className:c().canvasContainer,children:[(0,r.jsx)("div",{style:{position:"absolute",left:10},ref:m}),(0,r.jsx)("div",{style:{position:"absolute",right:10},ref:u}),(0,r.jsx)("canvas",{ref:n})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("nav",{className:c().sourceFileNav,ref:a,children:(0,r.jsx)("div",{className:c().sourceFileScrollContainer,onScroll(e){let n=e.currentTarget,t=n.scrollWidth-n.clientWidth-n.scrollLeft;n.scrollLeft>25?a.current.setAttribute("data-left","true"):a.current.setAttribute("data-left","false"),t>25?a.current.setAttribute("data-right","true"):a.current.setAttribute("data-right","false")},children:(0,r.jsx)("ul",{children:l.map((e,n)=>(0,r.jsx)("li",{children:(0,r.jsx)("a",{href:"#".concat(e.name),"data-active":x==e.name,onClick(){w(e.name)},children:e.name})},n))})})}),l.map((e,n)=>(0,r.jsx)(e.Container,{className:c().sourceFileContainer,"data-active":x==e.name},n))]})]})},d=e=>(0,r.jsx)(u,{...e});function m(e,n){if(!e)throw Error(n)}},1198:function(e,n,t){"use strict";var r="src/sample/helloTriangleMSAA/main.ts";t.r(n);var a=t(5671),i=t(1974),o=t(2690);let s=async e=>{let{canvas:n,pageState:t}=e,r=await navigator.gpu.requestAdapter(),a=await r.requestDevice();if(!t.active)return;let s=n.getContext("webgpu"),l=window.devicePixelRatio;n.width=n.clientWidth*l,n.height=n.clientHeight*l;let c=navigator.gpu.getPreferredCanvasFormat();s.configure({device:a,format:c,alphaMode:"premultiplied"});let u=a.createRenderPipeline({layout:"auto",vertex:{module:a.createShaderModule({code:i.Z}),entryPoint:"main"},fragment:{module:a.createShaderModule({code:o.Z}),entryPoint:"main",targets:[{format:c}]},primitive:{topology:"triangle-list"},multisample:{count:4}}),d=a.createTexture({size:[n.width,n.height],sampleCount:4,format:c,usage:GPUTextureUsage.RENDER_ATTACHMENT}),m=d.createView();requestAnimationFrame(function e(){if(!t.active)return;let n=a.createCommandEncoder(),r={colorAttachments:[{view:m,resolveTarget:s.getCurrentTexture().createView(),clearValue:{r:0,g:0,b:0,a:1},loadOp:"clear",storeOp:"discard"}]},i=n.beginRenderPass(r);i.setPipeline(u),i.draw(3),i.end(),a.queue.submit([n.finish()]),requestAnimationFrame(e)})},l=()=>(0,a.Tl)({name:"Hello Triangle MSAA",description:"Shows multisampled rendering a basic triangle.",init:s,sources:[{name:r.substring(29),contents:"import { makeSample, SampleInit } from '../../components/SampleLayout';\n\nimport triangleVertWGSL from '../../shaders/triangle.vert.wgsl';\nimport redFragWGSL from '../../shaders/red.frag.wgsl';\n\nconst init: SampleInit = async ({ canvas, pageState }) => {\n const adapter = await navigator.gpu.requestAdapter();\n const device = await adapter.requestDevice();\n\n if (!pageState.active) return;\n const context = canvas.getContext('webgpu') as GPUCanvasContext;\n\n const devicePixelRatio = window.devicePixelRatio;\n canvas.width = canvas.clientWidth * devicePixelRatio;\n canvas.height = canvas.clientHeight * devicePixelRatio;\n const presentationFormat = navigator.gpu.getPreferredCanvasFormat();\n\n context.configure({\n device,\n format: presentationFormat,\n alphaMode: 'premultiplied',\n });\n\n const sampleCount = 4;\n\n const pipeline = device.createRenderPipeline({\n layout: 'auto',\n vertex: {\n module: device.createShaderModule({\n code: triangleVertWGSL,\n }),\n entryPoint: 'main',\n },\n fragment: {\n module: device.createShaderModule({\n code: redFragWGSL,\n }),\n entryPoint: 'main',\n targets: [\n {\n format: presentationFormat,\n },\n ],\n },\n primitive: {\n topology: 'triangle-list',\n },\n multisample: {\n count: 4,\n },\n });\n\n const texture = device.createTexture({\n size: [canvas.width, canvas.height],\n sampleCount,\n format: presentationFormat,\n usage: GPUTextureUsage.RENDER_ATTACHMENT,\n });\n const view = texture.createView();\n\n function frame() {\n // Sample is no longer the active page.\n if (!pageState.active) return;\n\n const commandEncoder = device.createCommandEncoder();\n\n const renderPassDescriptor: GPURenderPassDescriptor = {\n colorAttachments: [\n {\n view,\n resolveTarget: context.getCurrentTexture().createView(),\n clearValue: { r: 0.0, g: 0.0, b: 0.0, a: 1.0 },\n loadOp: 'clear',\n storeOp: 'discard',\n },\n ],\n };\n\n const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);\n passEncoder.setPipeline(pipeline);\n passEncoder.draw(3);\n passEncoder.end();\n\n device.queue.submit([commandEncoder.finish()]);\n requestAnimationFrame(frame);\n }\n\n requestAnimationFrame(frame);\n};\n\nconst HelloTriangleMSAA: () => JSX.Element = () =>\n makeSample({\n name: 'Hello Triangle MSAA',\n description: 'Shows multisampled rendering a basic triangle.',\n init,\n sources: [\n {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n },\n {\n name: '../../shaders/triangle.vert.wgsl',\n contents: triangleVertWGSL,\n editable: true,\n },\n {\n name: '../../shaders/red.frag.wgsl',\n contents: redFragWGSL,\n editable: true,\n },\n ],\n filename: __filename,\n });\n\nexport default HelloTriangleMSAA;\n"},{name:"../../shaders/triangle.vert.wgsl",contents:i.Z,editable:!0},{name:"../../shaders/red.frag.wgsl",contents:o.Z,editable:!0}],filename:r});n.default=l},9147:function(e){e.exports={canvasContainer:"SampleLayout_canvasContainer__zRR_l",sourceFileNav:"SampleLayout_sourceFileNav__ml48P",sourceFileScrollContainer:"SampleLayout_sourceFileScrollContainer__LsNEm",sourceFileContainer:"SampleLayout_sourceFileContainer__3s84x"}},2690:function(e,n){"use strict";n.Z="@fragment\nfn main() -> @location(0) vec4 {\n return vec4(1.0, 0.0, 0.0, 1.0);\n}\n"},1974:function(e,n){"use strict";n.Z="@vertex\nfn main(\n @builtin(vertex_index) VertexIndex : u32\n) -> @builtin(position) vec4 {\n var pos = array, 3>(\n vec2(0.0, 0.5),\n vec2(-0.5, -0.5),\n vec2(0.5, -0.5)\n );\n\n return vec4(pos[VertexIndex], 0.0, 1.0);\n}\n"}}]);
\ No newline at end of file
diff --git a/_next/static/chunks/305.b34aadcd4e438a4b.js b/_next/static/chunks/305.b34aadcd4e438a4b.js
deleted file mode 100644
index 43d95893..00000000
--- a/_next/static/chunks/305.b34aadcd4e438a4b.js
+++ /dev/null
@@ -1 +0,0 @@
-(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[305],{5671:function(e,n,t){"use strict";t.d(n,{Tl:function(){return d},hu:function(){return m}});var r=t(5893),a=t(9008),i=t.n(a),o=t(1163),s=t(7294),l=t(9147),c=t.n(l);t(7319);let u=e=>{let n=(0,s.useRef)(null),a=(0,s.useRef)(null),l=(0,s.useMemo)(()=>e.sources.map(e=>{let{name:n,contents:a}=e;return{name:n,...function(e){let n;let a=null;{a=document.createElement("div");let i=t(4631);n=i(a,{lineNumbers:!0,lineWrapping:!0,theme:"monokai",readOnly:!0})}return{Container:function(t){return(0,r.jsx)("div",{...t,children:(0,r.jsx)("div",{ref(t){a&&t&&(t.appendChild(a),n.setOption("value",e))}})})}}}(a)}}),e.sources),u=(0,s.useRef)(null),d=(0,s.useMemo)(()=>{if(e.gui){let n=t(4376),r=new n.GUI({autoPlace:!1});return r.domElement.style.position="relative",r.domElement.style.zIndex="1000",r}},[]),m=(0,s.useRef)(null),p=(0,s.useMemo)(()=>{if(e.stats){let n=t(2792);return new n}},[]),v=(0,o.useRouter)(),g=v.asPath.match(/#([a-zA-Z0-9\.\/]+)/),[f,x]=(0,s.useState)(null),[h,b]=(0,s.useState)(null);return(0,s.useEffect)(()=>{if(g?b(g[1]):b(l[0].name),d&&u.current)for(u.current.appendChild(d.domElement);d.__controllers.length>0;)d.__controllers[0].remove();p&&m.current&&(p.dom.style.position="absolute",p.showPanel(1),m.current.appendChild(p.dom));let t={active:!0},r=()=>{t.active=!1};try{let a=n.current;if(!a)throw Error("The canvas is not available");let i=e.init({canvas:a,pageState:t,gui:d,stats:p});i instanceof Promise&&i.catch(e=>{console.error(e),x(e)})}catch(o){console.error(o),x(o)}return r},[]),(0,r.jsxs)("main",{children:[(0,r.jsxs)(i(),{children:[(0,r.jsx)("style",{dangerouslySetInnerHTML:{__html:"\n .CodeMirror {\n height: auto !important;\n margin: 1em 0;\n }\n\n .CodeMirror-scroll {\n height: auto !important;\n overflow: visible !important;\n }\n "}}),(0,r.jsx)("title",{children:"".concat(e.name," - WebGPU Samples")}),(0,r.jsx)("meta",{name:"description",content:e.description}),(0,r.jsx)("meta",{httpEquiv:"origin-trial",content:e.originTrial})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("h1",{children:e.name}),(0,r.jsx)("a",{target:"_blank",rel:"noreferrer",href:"https://github.com/".concat("webgpu/webgpu-samples","/tree/main/").concat(e.filename),children:"See it on Github!"}),(0,r.jsx)("p",{children:e.description}),f?(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("p",{children:"Something went wrong. Do your browser and device support WebGPU?"}),(0,r.jsx)("p",{children:"".concat(f)})]}):null]}),(0,r.jsxs)("div",{className:c().canvasContainer,children:[(0,r.jsx)("div",{style:{position:"absolute",left:10},ref:m}),(0,r.jsx)("div",{style:{position:"absolute",right:10},ref:u}),(0,r.jsx)("canvas",{ref:n})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("nav",{className:c().sourceFileNav,ref:a,children:(0,r.jsx)("div",{className:c().sourceFileScrollContainer,onScroll(e){let n=e.currentTarget,t=n.scrollWidth-n.clientWidth-n.scrollLeft;n.scrollLeft>25?a.current.setAttribute("data-left","true"):a.current.setAttribute("data-left","false"),t>25?a.current.setAttribute("data-right","true"):a.current.setAttribute("data-right","false")},children:(0,r.jsx)("ul",{children:l.map((e,n)=>(0,r.jsx)("li",{children:(0,r.jsx)("a",{href:"#".concat(e.name),"data-active":h==e.name,onClick(){b(e.name)},children:e.name})},n))})})}),l.map((e,n)=>(0,r.jsx)(e.Container,{className:c().sourceFileContainer,"data-active":h==e.name},n))]})]})},d=e=>(0,r.jsx)(u,{...e});function m(e,n){if(!e)throw Error(n)}},3305:function(e,n,t){"use strict";t.r(n),t.d(n,{default:function(){return c}});var r=t(5671),a=t(134),i="@group(0) @binding(1) var mySampler: sampler;\n@group(0) @binding(2) var myTexture: texture_external;\n\n@fragment\nfn main(@location(0) fragUV : vec2) -> @location(0) vec4 {\n return textureSampleBaseClampToEdge(myTexture, mySampler, fragUV);\n}\n",o="src/sample/videoUploading/main.ts";let s=async e=>{let{canvas:n,pageState:t,gui:r}=e,o=document.createElement("video");o.loop=!0,o.autoplay=!0,o.muted=!0,o.src="../assets/video/pano.webm",await o.play();let s=await navigator.gpu.requestAdapter(),l=await s.requestDevice();if(!t.active)return;let c=n.getContext("webgpu"),u=window.devicePixelRatio;n.width=n.clientWidth*u,n.height=n.clientHeight*u;let d=navigator.gpu.getPreferredCanvasFormat();c.configure({device:l,format:d,alphaMode:"premultiplied"});let m=l.createRenderPipeline({layout:"auto",vertex:{module:l.createShaderModule({code:a.Z}),entryPoint:"vert_main"},fragment:{module:l.createShaderModule({code:i}),entryPoint:"main",targets:[{format:d}]},primitive:{topology:"triangle-list"}}),p=l.createSampler({magFilter:"linear",minFilter:"linear"}),v=new URLSearchParams(window.location.search),g={requestFrame:"requestAnimationFrame",videoSource:v.get("videoSource")||"videoElement"};function f(){if(!t.active)return;let e="videoFrame"===g.videoSource?new VideoFrame(o):o,n=l.createBindGroup({layout:m.getBindGroupLayout(0),entries:[{binding:1,resource:p},{binding:2,resource:l.importExternalTexture({source:e})}]}),r=l.createCommandEncoder(),a=c.getCurrentTexture().createView(),i=r.beginRenderPass({colorAttachments:[{view:a,clearValue:{r:0,g:0,b:0,a:1},loadOp:"clear",storeOp:"store"}]});i.setPipeline(m),i.setBindGroup(0,n),i.draw(6),i.end(),l.queue.submit([r.finish()]),"requestVideoFrameCallback"==g.requestFrame?o.requestVideoFrameCallback(f):requestAnimationFrame(f)}r.add(g,"videoSource",["videoElement","videoFrame"]),r.add(g,"requestFrame",["requestAnimationFrame","requestVideoFrameCallback"]),"requestVideoFrameCallback"==g.requestFrame?o.requestVideoFrameCallback(f):requestAnimationFrame(f)},l=()=>(0,r.Tl)({name:"Video Uploading",description:"This example shows how to upload video frame to WebGPU.",gui:!0,init:s,sources:[{name:o.substring(26),contents:"import { makeSample, SampleInit } from '../../components/SampleLayout';\n\nimport fullscreenTexturedQuadWGSL from '../../shaders/fullscreenTexturedQuad.wgsl';\nimport sampleExternalTextureWGSL from '../../shaders/sampleExternalTexture.frag.wgsl';\n\nconst init: SampleInit = async ({ canvas, pageState, gui }) => {\n // Set video element\n const video = document.createElement('video');\n video.loop = true;\n video.autoplay = true;\n video.muted = true;\n video.src = '../assets/video/pano.webm';\n await video.play();\n\n const adapter = await navigator.gpu.requestAdapter();\n const device = await adapter.requestDevice();\n\n if (!pageState.active) return;\n\n const context = canvas.getContext('webgpu') as GPUCanvasContext;\n const devicePixelRatio = window.devicePixelRatio;\n canvas.width = canvas.clientWidth * devicePixelRatio;\n canvas.height = canvas.clientHeight * devicePixelRatio;\n const presentationFormat = navigator.gpu.getPreferredCanvasFormat();\n\n context.configure({\n device,\n format: presentationFormat,\n alphaMode: 'premultiplied',\n });\n\n const pipeline = device.createRenderPipeline({\n layout: 'auto',\n vertex: {\n module: device.createShaderModule({\n code: fullscreenTexturedQuadWGSL,\n }),\n entryPoint: 'vert_main',\n },\n fragment: {\n module: device.createShaderModule({\n code: sampleExternalTextureWGSL,\n }),\n entryPoint: 'main',\n targets: [\n {\n format: presentationFormat,\n },\n ],\n },\n primitive: {\n topology: 'triangle-list',\n },\n });\n\n const sampler = device.createSampler({\n magFilter: 'linear',\n minFilter: 'linear',\n });\n\n const params = new URLSearchParams(window.location.search);\n\n const settings = {\n requestFrame: 'requestAnimationFrame',\n videoSource: params.get('videoSource') || 'videoElement',\n };\n\n gui.add(settings, 'videoSource', ['videoElement', 'videoFrame']);\n gui.add(settings, 'requestFrame', [\n 'requestAnimationFrame',\n 'requestVideoFrameCallback',\n ]);\n\n function frame() {\n // Sample is no longer the active page.\n if (!pageState.active) return;\n\n const externalTextureSource =\n settings.videoSource === 'videoFrame' ? new VideoFrame(video) : video;\n\n const uniformBindGroup = device.createBindGroup({\n layout: pipeline.getBindGroupLayout(0),\n entries: [\n {\n binding: 1,\n resource: sampler,\n },\n {\n binding: 2,\n resource: device.importExternalTexture({\n source: externalTextureSource,\n }),\n },\n ],\n });\n\n const commandEncoder = device.createCommandEncoder();\n const textureView = context.getCurrentTexture().createView();\n\n const renderPassDescriptor: GPURenderPassDescriptor = {\n colorAttachments: [\n {\n view: textureView,\n clearValue: { r: 0.0, g: 0.0, b: 0.0, a: 1.0 },\n loadOp: 'clear',\n storeOp: 'store',\n },\n ],\n };\n\n const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);\n passEncoder.setPipeline(pipeline);\n passEncoder.setBindGroup(0, uniformBindGroup);\n passEncoder.draw(6);\n passEncoder.end();\n device.queue.submit([commandEncoder.finish()]);\n\n if (settings.requestFrame == 'requestVideoFrameCallback') {\n video.requestVideoFrameCallback(frame);\n } else {\n requestAnimationFrame(frame);\n }\n }\n\n if (settings.requestFrame == 'requestVideoFrameCallback') {\n video.requestVideoFrameCallback(frame);\n } else {\n requestAnimationFrame(frame);\n }\n};\n\nconst VideoUploading: () => JSX.Element = () =>\n makeSample({\n name: 'Video Uploading',\n description: 'This example shows how to upload video frame to WebGPU.',\n gui: true,\n init,\n sources: [\n {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n },\n {\n name: '../../shaders/fullscreenTexturedQuad.wgsl',\n contents: fullscreenTexturedQuadWGSL,\n editable: true,\n },\n {\n name: '../../shaders/sampleExternalTexture.wgsl',\n contents: sampleExternalTextureWGSL,\n editable: true,\n },\n ],\n filename: __filename,\n });\n\nexport default VideoUploading;\n"},{name:"../../shaders/fullscreenTexturedQuad.wgsl",contents:a.Z,editable:!0},{name:"../../shaders/sampleExternalTexture.wgsl",contents:i,editable:!0}],filename:o});var c=l},9147:function(e){e.exports={canvasContainer:"SampleLayout_canvasContainer__zRR_l",sourceFileNav:"SampleLayout_sourceFileNav__ml48P",sourceFileScrollContainer:"SampleLayout_sourceFileScrollContainer__LsNEm",sourceFileContainer:"SampleLayout_sourceFileContainer__3s84x"}},134:function(e,n){"use strict";n.Z="@group(0) @binding(0) var mySampler : sampler;\n@group(0) @binding(1) var myTexture : texture_2d;\n\nstruct VertexOutput {\n @builtin(position) Position : vec4,\n @location(0) fragUV : vec2,\n}\n\n@vertex\nfn vert_main(@builtin(vertex_index) VertexIndex : u32) -> VertexOutput {\n const pos = array(\n vec2( 1.0, 1.0),\n vec2( 1.0, -1.0),\n vec2(-1.0, -1.0),\n vec2( 1.0, 1.0),\n vec2(-1.0, -1.0),\n vec2(-1.0, 1.0),\n );\n\n const uv = array(\n vec2(1.0, 0.0),\n vec2(1.0, 1.0),\n vec2(0.0, 1.0),\n vec2(1.0, 0.0),\n vec2(0.0, 1.0),\n vec2(0.0, 0.0),\n );\n\n var output : VertexOutput;\n output.Position = vec4(pos[VertexIndex], 0.0, 1.0);\n output.fragUV = uv[VertexIndex];\n return output;\n}\n\n@fragment\nfn frag_main(@location(0) fragUV : vec2) -> @location(0) vec4 {\n return textureSample(myTexture, mySampler, fragUV);\n}\n"}}]);
\ No newline at end of file
diff --git a/_next/static/chunks/342.d6072efffddc945c.js b/_next/static/chunks/342.d6072efffddc945c.js
deleted file mode 100644
index b692e58a..00000000
--- a/_next/static/chunks/342.d6072efffddc945c.js
+++ /dev/null
@@ -1 +0,0 @@
-(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[342],{5671:function(e,n,t){"use strict";t.d(n,{Tl:function(){return d},hu:function(){return f}});var r=t(5893),a=t(9008),i=t.n(a),o=t(1163),s=t(7294),l=t(9147),u=t.n(l);t(7319);let c=e=>{let n=(0,s.useRef)(null),a=(0,s.useRef)(null),l=(0,s.useMemo)(()=>e.sources.map(e=>{let{name:n,contents:a}=e;return{name:n,...function(e){let n;let a=null;{a=document.createElement("div");let i=t(4631);n=i(a,{lineNumbers:!0,lineWrapping:!0,theme:"monokai",readOnly:!0})}return{Container:function(t){return(0,r.jsx)("div",{...t,children:(0,r.jsx)("div",{ref(t){a&&t&&(t.appendChild(a),n.setOption("value",e))}})})}}}(a)}}),e.sources),c=(0,s.useRef)(null),d=(0,s.useMemo)(()=>{if(e.gui){let n=t(4376),r=new n.GUI({autoPlace:!1});return r.domElement.style.position="relative",r.domElement.style.zIndex="1000",r}},[]),f=(0,s.useRef)(null),p=(0,s.useMemo)(()=>{if(e.stats){let n=t(2792);return new n}},[]),m=(0,o.useRouter)(),h=m.asPath.match(/#([a-zA-Z0-9\.\/]+)/),[g,v]=(0,s.useState)(null),[x,P]=(0,s.useState)(null);return(0,s.useEffect)(()=>{if(h?P(h[1]):P(l[0].name),d&&c.current)for(c.current.appendChild(d.domElement);d.__controllers.length>0;)d.__controllers[0].remove();p&&f.current&&(p.dom.style.position="absolute",p.showPanel(1),f.current.appendChild(p.dom));let t={active:!0},r=()=>{t.active=!1};try{let a=n.current;if(!a)throw Error("The canvas is not available");let i=e.init({canvas:a,pageState:t,gui:d,stats:p});i instanceof Promise&&i.catch(e=>{console.error(e),v(e)})}catch(o){console.error(o),v(o)}return r},[]),(0,r.jsxs)("main",{children:[(0,r.jsxs)(i(),{children:[(0,r.jsx)("style",{dangerouslySetInnerHTML:{__html:"\n .CodeMirror {\n height: auto !important;\n margin: 1em 0;\n }\n\n .CodeMirror-scroll {\n height: auto !important;\n overflow: visible !important;\n }\n "}}),(0,r.jsx)("title",{children:"".concat(e.name," - WebGPU Samples")}),(0,r.jsx)("meta",{name:"description",content:e.description}),(0,r.jsx)("meta",{httpEquiv:"origin-trial",content:e.originTrial})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("h1",{children:e.name}),(0,r.jsx)("a",{target:"_blank",rel:"noreferrer",href:"https://github.com/".concat("webgpu/webgpu-samples","/tree/main/").concat(e.filename),children:"See it on Github!"}),(0,r.jsx)("p",{children:e.description}),g?(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("p",{children:"Something went wrong. Do your browser and device support WebGPU?"}),(0,r.jsx)("p",{children:"".concat(g)})]}):null]}),(0,r.jsxs)("div",{className:u().canvasContainer,children:[(0,r.jsx)("div",{style:{position:"absolute",left:10},ref:f}),(0,r.jsx)("div",{style:{position:"absolute",right:10},ref:c}),(0,r.jsx)("canvas",{ref:n})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("nav",{className:u().sourceFileNav,ref:a,children:(0,r.jsx)("div",{className:u().sourceFileScrollContainer,onScroll(e){let n=e.currentTarget,t=n.scrollWidth-n.clientWidth-n.scrollLeft;n.scrollLeft>25?a.current.setAttribute("data-left","true"):a.current.setAttribute("data-left","false"),t>25?a.current.setAttribute("data-right","true"):a.current.setAttribute("data-right","false")},children:(0,r.jsx)("ul",{children:l.map((e,n)=>(0,r.jsx)("li",{children:(0,r.jsx)("a",{href:"#".concat(e.name),"data-active":x==e.name,onClick(){P(e.name)},children:e.name})},n))})})}),l.map((e,n)=>(0,r.jsx)(e.Container,{className:u().sourceFileContainer,"data-active":x==e.name},n))]})]})},d=e=>(0,r.jsx)(c,{...e});function f(e,n){if(!e)throw Error(n)}},6888:function(e,n,t){"use strict";t.d(n,{W:function(){return i}});var r=t(6906),a=t(9385);let i={positions:r.m,triangles:r.g,normals:[],uvs:[]};i.normals=(0,a.b)(i.positions,i.triangles),i.uvs=(0,a.q)(i.positions,"xy"),i.triangles.push([i.positions.length,i.positions.length+2,i.positions.length+1],[i.positions.length,i.positions.length+1,i.positions.length+3]),i.positions.push([-100,20,-100],[100,20,100],[-100,20,100],[100,20,-100]),i.normals.push([0,1,0],[0,1,0],[0,1,0],[0,1,0]),i.uvs.push([0,0],[1,1],[0,1],[1,0])},9385:function(e,n,t){"use strict";t.d(n,{b:function(){return a},q:function(){return o}});var r=t(6416);function a(e,n){let t=e.map(()=>[0,0,0]);return n.forEach(n=>{let[a,i,o]=n,s=e[a],l=e[i],u=e[o],c=r.R3.subtract(l,s),d=r.R3.subtract(u,s);r.R3.normalize(c,c),r.R3.normalize(d,d);let f=r.R3.cross(c,d);r.R3.add(t[a],f,t[a]),r.R3.add(t[i],f,t[i]),r.R3.add(t[o],f,t[o])}),t.forEach(e=>{r.R3.normalize(e,e)}),t}let i={xy:[0,1],xz:[0,2],yz:[1,2]};function o(e){let n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"xy",t=i[n],r=e.map(()=>[0,0]),a=[1/0,1/0],o=[-1/0,-1/0];return e.forEach((e,n)=>{r[n][0]=e[t[0]],r[n][1]=e[t[1]],a[0]=Math.min(e[t[0]],a[0]),a[1]=Math.min(e[t[1]],a[1]),o[0]=Math.max(e[t[0]],o[0]),o[1]=Math.max(e[t[1]],o[1])}),r.forEach(e=>{e[0]=(e[0]-a[0])/(o[0]-a[0]),e[1]=(e[1]-a[1])/(o[1]-a[1])}),r}},2342:function(e,n,t){"use strict";t.r(n),t.d(n,{default:function(){return f}});var r=t(6416),a=t(5671),i=t(6888),o="struct Scene {\n lightViewProjMatrix: mat4x4,\n cameraViewProjMatrix: mat4x4,\n lightPos: vec3,\n}\n\nstruct Model {\n modelMatrix: mat4x4,\n}\n\n@group(0) @binding(0) var scene : Scene;\n@group(1) @binding(0) var model : Model;\n\n@vertex\nfn main(\n @location(0) position: vec3\n) -> @builtin(position) vec4 {\n return scene.lightViewProjMatrix * model.modelMatrix * vec4(position, 1.0);\n}\n",s="struct Scene {\n lightViewProjMatrix: mat4x4,\n cameraViewProjMatrix: mat4x4,\n lightPos: vec3,\n}\n\nstruct Model {\n modelMatrix: mat4x4,\n}\n\n@group(0) @binding(0) var scene : Scene;\n@group(1) @binding(0) var model : Model;\n\nstruct VertexOutput {\n @location(0) shadowPos: vec3,\n @location(1) fragPos: vec3,\n @location(2) fragNorm: vec3,\n\n @builtin(position) Position: vec4,\n}\n\n@vertex\nfn main(\n @location(0) position: vec3,\n @location(1) normal: vec3\n) -> VertexOutput {\n var output : VertexOutput;\n\n // XY is in (-1, 1) space, Z is in (0, 1) space\n let posFromLight = scene.lightViewProjMatrix * model.modelMatrix * vec4(position, 1.0);\n\n // Convert XY to (0, 1)\n // Y is flipped because texture coords are Y-down.\n output.shadowPos = vec3(\n posFromLight.xy * vec2(0.5, -0.5) + vec2(0.5),\n posFromLight.z\n );\n\n output.Position = scene.cameraViewProjMatrix * model.modelMatrix * vec4(position, 1.0);\n output.fragPos = output.Position.xyz;\n output.fragNorm = normal;\n return output;\n}\n",l="override shadowDepthTextureSize: f32 = 1024.0;\n\nstruct Scene {\n lightViewProjMatrix : mat4x4,\n cameraViewProjMatrix : mat4x4,\n lightPos : vec3,\n}\n\n@group(0) @binding(0) var scene : Scene;\n@group(0) @binding(1) var shadowMap: texture_depth_2d;\n@group(0) @binding(2) var shadowSampler: sampler_comparison;\n\nstruct FragmentInput {\n @location(0) shadowPos : vec3,\n @location(1) fragPos : vec3,\n @location(2) fragNorm : vec3,\n}\n\nconst albedo = vec3(0.9);\nconst ambientFactor = 0.2;\n\n@fragment\nfn main(input : FragmentInput) -> @location(0) vec4 {\n // Percentage-closer filtering. Sample texels in the region\n // to smooth the result.\n var visibility = 0.0;\n let oneOverShadowDepthTextureSize = 1.0 / shadowDepthTextureSize;\n for (var y = -1; y <= 1; y++) {\n for (var x = -1; x <= 1; x++) {\n let offset = vec2(vec2(x, y)) * oneOverShadowDepthTextureSize;\n\n visibility += textureSampleCompare(\n shadowMap, shadowSampler,\n input.shadowPos.xy + offset, input.shadowPos.z - 0.007\n );\n }\n }\n visibility /= 9.0;\n\n let lambertFactor = max(dot(normalize(scene.lightPos - input.fragPos), normalize(input.fragNorm)), 0.0);\n let lightingFactor = min(ambientFactor + visibility * lambertFactor, 1.0);\n\n return vec4(lightingFactor * albedo, 1.0);\n}\n",u="src/sample/shadowMapping/main.ts";let c=async e=>{let{canvas:n,pageState:t}=e,a=await navigator.gpu.requestAdapter(),u=await a.requestDevice();if(!t.active)return;let c=n.getContext("webgpu"),d=window.devicePixelRatio;n.width=n.clientWidth*d,n.height=n.clientHeight*d;let f=n.width/n.height,p=navigator.gpu.getPreferredCanvasFormat();c.configure({device:u,format:p,alphaMode:"premultiplied"});let m=u.createBuffer({size:6*i.W.positions.length*Float32Array.BYTES_PER_ELEMENT,usage:GPUBufferUsage.VERTEX,mappedAtCreation:!0});{let h=new Float32Array(m.getMappedRange());for(let g=0;g(0,a.Tl)({name:"Shadow Mapping",description:"This example shows how to sample from a depth texture to render shadows.",init:c,sources:[{name:u.substring(25),contents:"import { mat4, vec3 } from 'wgpu-matrix';\nimport { makeSample, SampleInit } from '../../components/SampleLayout';\n\nimport { mesh } from '../../meshes/stanfordDragon';\n\nimport vertexShadowWGSL from './vertexShadow.wgsl';\nimport vertexWGSL from './vertex.wgsl';\nimport fragmentWGSL from './fragment.wgsl';\n\nconst shadowDepthTextureSize = 1024;\n\nconst init: SampleInit = async ({ canvas, pageState }) => {\n const adapter = await navigator.gpu.requestAdapter();\n const device = await adapter.requestDevice();\n\n if (!pageState.active) return;\n\n const context = canvas.getContext('webgpu') as GPUCanvasContext;\n\n const devicePixelRatio = window.devicePixelRatio;\n canvas.width = canvas.clientWidth * devicePixelRatio;\n canvas.height = canvas.clientHeight * devicePixelRatio;\n const aspect = canvas.width / canvas.height;\n const presentationFormat = navigator.gpu.getPreferredCanvasFormat();\n context.configure({\n device,\n format: presentationFormat,\n alphaMode: 'premultiplied',\n });\n\n // Create the model vertex buffer.\n const vertexBuffer = device.createBuffer({\n size: mesh.positions.length * 3 * 2 * Float32Array.BYTES_PER_ELEMENT,\n usage: GPUBufferUsage.VERTEX,\n mappedAtCreation: true,\n });\n {\n const mapping = new Float32Array(vertexBuffer.getMappedRange());\n for (let i = 0; i < mesh.positions.length; ++i) {\n mapping.set(mesh.positions[i], 6 * i);\n mapping.set(mesh.normals[i], 6 * i + 3);\n }\n vertexBuffer.unmap();\n }\n\n // Create the model index buffer.\n const indexCount = mesh.triangles.length * 3;\n const indexBuffer = device.createBuffer({\n size: indexCount * Uint16Array.BYTES_PER_ELEMENT,\n usage: GPUBufferUsage.INDEX,\n mappedAtCreation: true,\n });\n {\n const mapping = new Uint16Array(indexBuffer.getMappedRange());\n for (let i = 0; i < mesh.triangles.length; ++i) {\n mapping.set(mesh.triangles[i], 3 * i);\n }\n indexBuffer.unmap();\n }\n\n // Create the depth texture for rendering/sampling the shadow map.\n const shadowDepthTexture = device.createTexture({\n size: [shadowDepthTextureSize, shadowDepthTextureSize, 1],\n usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING,\n format: 'depth32float',\n });\n const shadowDepthTextureView = shadowDepthTexture.createView();\n\n // Create some common descriptors used for both the shadow pipeline\n // and the color rendering pipeline.\n const vertexBuffers: Iterable = [\n {\n arrayStride: Float32Array.BYTES_PER_ELEMENT * 6,\n attributes: [\n {\n // position\n shaderLocation: 0,\n offset: 0,\n format: 'float32x3',\n },\n {\n // normal\n shaderLocation: 1,\n offset: Float32Array.BYTES_PER_ELEMENT * 3,\n format: 'float32x3',\n },\n ],\n },\n ];\n\n const primitive: GPUPrimitiveState = {\n topology: 'triangle-list',\n cullMode: 'back',\n };\n\n const uniformBufferBindGroupLayout = device.createBindGroupLayout({\n entries: [\n {\n binding: 0,\n visibility: GPUShaderStage.VERTEX,\n buffer: {\n type: 'uniform',\n },\n },\n ],\n });\n\n const shadowPipeline = device.createRenderPipeline({\n layout: device.createPipelineLayout({\n bindGroupLayouts: [\n uniformBufferBindGroupLayout,\n uniformBufferBindGroupLayout,\n ],\n }),\n vertex: {\n module: device.createShaderModule({\n code: vertexShadowWGSL,\n }),\n entryPoint: 'main',\n buffers: vertexBuffers,\n },\n depthStencil: {\n depthWriteEnabled: true,\n depthCompare: 'less',\n format: 'depth32float',\n },\n primitive,\n });\n\n // Create a bind group layout which holds the scene uniforms and\n // the texture+sampler for depth. We create it manually because the WebPU\n // implementation doesn't infer this from the shader (yet).\n const bglForRender = device.createBindGroupLayout({\n entries: [\n {\n binding: 0,\n visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,\n buffer: {\n type: 'uniform',\n },\n },\n {\n binding: 1,\n visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,\n texture: {\n sampleType: 'depth',\n },\n },\n {\n binding: 2,\n visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,\n sampler: {\n type: 'comparison',\n },\n },\n ],\n });\n\n const pipeline = device.createRenderPipeline({\n layout: device.createPipelineLayout({\n bindGroupLayouts: [bglForRender, uniformBufferBindGroupLayout],\n }),\n vertex: {\n module: device.createShaderModule({\n code: vertexWGSL,\n }),\n entryPoint: 'main',\n buffers: vertexBuffers,\n },\n fragment: {\n module: device.createShaderModule({\n code: fragmentWGSL,\n }),\n entryPoint: 'main',\n targets: [\n {\n format: presentationFormat,\n },\n ],\n constants: {\n shadowDepthTextureSize,\n },\n },\n depthStencil: {\n depthWriteEnabled: true,\n depthCompare: 'less',\n format: 'depth24plus-stencil8',\n },\n primitive,\n });\n\n const depthTexture = device.createTexture({\n size: [canvas.width, canvas.height],\n format: 'depth24plus-stencil8',\n usage: GPUTextureUsage.RENDER_ATTACHMENT,\n });\n\n const renderPassDescriptor: GPURenderPassDescriptor = {\n colorAttachments: [\n {\n // view is acquired and set in render loop.\n view: undefined,\n\n clearValue: { r: 0.5, g: 0.5, b: 0.5, a: 1.0 },\n loadOp: 'clear',\n storeOp: 'store',\n },\n ],\n depthStencilAttachment: {\n view: depthTexture.createView(),\n\n depthClearValue: 1.0,\n depthLoadOp: 'clear',\n depthStoreOp: 'store',\n stencilClearValue: 0,\n stencilLoadOp: 'clear',\n stencilStoreOp: 'store',\n },\n };\n\n const modelUniformBuffer = device.createBuffer({\n size: 4 * 16, // 4x4 matrix\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n });\n\n const sceneUniformBuffer = device.createBuffer({\n // Two 4x4 viewProj matrices,\n // one for the camera and one for the light.\n // Then a vec3 for the light position.\n // Rounded to the nearest multiple of 16.\n size: 2 * 4 * 16 + 4 * 4,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n });\n\n const sceneBindGroupForShadow = device.createBindGroup({\n layout: uniformBufferBindGroupLayout,\n entries: [\n {\n binding: 0,\n resource: {\n buffer: sceneUniformBuffer,\n },\n },\n ],\n });\n\n const sceneBindGroupForRender = device.createBindGroup({\n layout: bglForRender,\n entries: [\n {\n binding: 0,\n resource: {\n buffer: sceneUniformBuffer,\n },\n },\n {\n binding: 1,\n resource: shadowDepthTextureView,\n },\n {\n binding: 2,\n resource: device.createSampler({\n compare: 'less',\n }),\n },\n ],\n });\n\n const modelBindGroup = device.createBindGroup({\n layout: uniformBufferBindGroupLayout,\n entries: [\n {\n binding: 0,\n resource: {\n buffer: modelUniformBuffer,\n },\n },\n ],\n });\n\n const eyePosition = vec3.fromValues(0, 50, -100);\n const upVector = vec3.fromValues(0, 1, 0);\n const origin = vec3.fromValues(0, 0, 0);\n\n const projectionMatrix = mat4.perspective(\n (2 * Math.PI) / 5,\n aspect,\n 1,\n 2000.0\n );\n\n const viewMatrix = mat4.lookAt(eyePosition, origin, upVector);\n\n const lightPosition = vec3.fromValues(50, 100, -100);\n const lightViewMatrix = mat4.lookAt(lightPosition, origin, upVector);\n const lightProjectionMatrix = mat4.create();\n {\n const left = -80;\n const right = 80;\n const bottom = -80;\n const top = 80;\n const near = -200;\n const far = 300;\n mat4.ortho(left, right, bottom, top, near, far, lightProjectionMatrix);\n }\n\n const lightViewProjMatrix = mat4.multiply(\n lightProjectionMatrix,\n lightViewMatrix\n );\n\n const viewProjMatrix = mat4.multiply(projectionMatrix, viewMatrix);\n\n // Move the model so it's centered.\n const modelMatrix = mat4.translation([0, -45, 0]);\n\n // The camera/light aren't moving, so write them into buffers now.\n {\n const lightMatrixData = lightViewProjMatrix as Float32Array;\n device.queue.writeBuffer(\n sceneUniformBuffer,\n 0,\n lightMatrixData.buffer,\n lightMatrixData.byteOffset,\n lightMatrixData.byteLength\n );\n\n const cameraMatrixData = viewProjMatrix as Float32Array;\n device.queue.writeBuffer(\n sceneUniformBuffer,\n 64,\n cameraMatrixData.buffer,\n cameraMatrixData.byteOffset,\n cameraMatrixData.byteLength\n );\n\n const lightData = lightPosition as Float32Array;\n device.queue.writeBuffer(\n sceneUniformBuffer,\n 128,\n lightData.buffer,\n lightData.byteOffset,\n lightData.byteLength\n );\n\n const modelData = modelMatrix as Float32Array;\n device.queue.writeBuffer(\n modelUniformBuffer,\n 0,\n modelData.buffer,\n modelData.byteOffset,\n modelData.byteLength\n );\n }\n\n // Rotates the camera around the origin based on time.\n function getCameraViewProjMatrix() {\n const eyePosition = vec3.fromValues(0, 50, -100);\n\n const rad = Math.PI * (Date.now() / 2000);\n const rotation = mat4.rotateY(mat4.translation(origin), rad);\n vec3.transformMat4(eyePosition, rotation, eyePosition);\n\n const viewMatrix = mat4.lookAt(eyePosition, origin, upVector);\n\n mat4.multiply(projectionMatrix, viewMatrix, viewProjMatrix);\n return viewProjMatrix as Float32Array;\n }\n\n const shadowPassDescriptor: GPURenderPassDescriptor = {\n colorAttachments: [],\n depthStencilAttachment: {\n view: shadowDepthTextureView,\n depthClearValue: 1.0,\n depthLoadOp: 'clear',\n depthStoreOp: 'store',\n },\n };\n\n function frame() {\n // Sample is no longer the active page.\n if (!pageState.active) return;\n\n const cameraViewProj = getCameraViewProjMatrix();\n device.queue.writeBuffer(\n sceneUniformBuffer,\n 64,\n cameraViewProj.buffer,\n cameraViewProj.byteOffset,\n cameraViewProj.byteLength\n );\n\n renderPassDescriptor.colorAttachments[0].view = context\n .getCurrentTexture()\n .createView();\n\n const commandEncoder = device.createCommandEncoder();\n {\n const shadowPass = commandEncoder.beginRenderPass(shadowPassDescriptor);\n shadowPass.setPipeline(shadowPipeline);\n shadowPass.setBindGroup(0, sceneBindGroupForShadow);\n shadowPass.setBindGroup(1, modelBindGroup);\n shadowPass.setVertexBuffer(0, vertexBuffer);\n shadowPass.setIndexBuffer(indexBuffer, 'uint16');\n shadowPass.drawIndexed(indexCount);\n\n shadowPass.end();\n }\n {\n const renderPass = commandEncoder.beginRenderPass(renderPassDescriptor);\n renderPass.setPipeline(pipeline);\n renderPass.setBindGroup(0, sceneBindGroupForRender);\n renderPass.setBindGroup(1, modelBindGroup);\n renderPass.setVertexBuffer(0, vertexBuffer);\n renderPass.setIndexBuffer(indexBuffer, 'uint16');\n renderPass.drawIndexed(indexCount);\n\n renderPass.end();\n }\n device.queue.submit([commandEncoder.finish()]);\n requestAnimationFrame(frame);\n }\n requestAnimationFrame(frame);\n};\n\nconst ShadowMapping: () => JSX.Element = () =>\n makeSample({\n name: 'Shadow Mapping',\n description:\n 'This example shows how to sample from a depth texture to render shadows.',\n init,\n sources: [\n {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n },\n {\n name: './vertexShadow.wgsl',\n contents: vertexShadowWGSL,\n editable: true,\n },\n {\n name: './vertex.wgsl',\n contents: vertexWGSL,\n editable: true,\n },\n {\n name: './fragment.wgsl',\n contents: fragmentWGSL,\n editable: true,\n },\n ],\n filename: __filename,\n });\n\nexport default ShadowMapping;\n"},{name:"./vertexShadow.wgsl",contents:o,editable:!0},{name:"./vertex.wgsl",contents:s,editable:!0},{name:"./fragment.wgsl",contents:l,editable:!0}],filename:u});var f=d},9147:function(e){e.exports={canvasContainer:"SampleLayout_canvasContainer__zRR_l",sourceFileNav:"SampleLayout_sourceFileNav__ml48P",sourceFileScrollContainer:"SampleLayout_sourceFileScrollContainer__LsNEm",sourceFileContainer:"SampleLayout_sourceFileContainer__3s84x"}}}]);
\ No newline at end of file
diff --git a/_next/static/chunks/391.21122bfcacb731a3.js b/_next/static/chunks/391.21122bfcacb731a3.js
deleted file mode 100644
index 70e73426..00000000
--- a/_next/static/chunks/391.21122bfcacb731a3.js
+++ /dev/null
@@ -1 +0,0 @@
-(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[391],{5671:function(e,n,t){"use strict";t.d(n,{Tl:function(){return d},hu:function(){return f}});var r=t(5893),i=t(9008),a=t.n(i),o=t(1163),s=t(7294),u=t(9147),c=t.n(u);t(7319);let l=e=>{let n=(0,s.useRef)(null),i=(0,s.useRef)(null),u=(0,s.useMemo)(()=>e.sources.map(e=>{let{name:n,contents:i}=e;return{name:n,...function(e){let n;let i=null;{i=document.createElement("div");let a=t(4631);n=a(i,{lineNumbers:!0,lineWrapping:!0,theme:"monokai",readOnly:!0})}return{Container:function(t){return(0,r.jsx)("div",{...t,children:(0,r.jsx)("div",{ref(t){i&&t&&(t.appendChild(i),n.setOption("value",e))}})})}}}(i)}}),e.sources),l=(0,s.useRef)(null),d=(0,s.useMemo)(()=>{if(e.gui){let n=t(4376),r=new n.GUI({autoPlace:!1});return r.domElement.style.position="relative",r.domElement.style.zIndex="1000",r}},[]),f=(0,s.useRef)(null),p=(0,s.useMemo)(()=>{if(e.stats){let n=t(2792);return new n}},[]),m=(0,o.useRouter)(),g=m.asPath.match(/#([a-zA-Z0-9\.\/]+)/),[h,b]=(0,s.useState)(null),[y,v]=(0,s.useState)(null);return(0,s.useEffect)(()=>{if(g?v(g[1]):v(u[0].name),d&&l.current)for(l.current.appendChild(d.domElement);d.__controllers.length>0;)d.__controllers[0].remove();p&&f.current&&(p.dom.style.position="absolute",p.showPanel(1),f.current.appendChild(p.dom));let t={active:!0},r=()=>{t.active=!1};try{let i=n.current;if(!i)throw Error("The canvas is not available");let a=e.init({canvas:i,pageState:t,gui:d,stats:p});a instanceof Promise&&a.catch(e=>{console.error(e),b(e)})}catch(o){console.error(o),b(o)}return r},[]),(0,r.jsxs)("main",{children:[(0,r.jsxs)(a(),{children:[(0,r.jsx)("style",{dangerouslySetInnerHTML:{__html:"\n .CodeMirror {\n height: auto !important;\n margin: 1em 0;\n }\n\n .CodeMirror-scroll {\n height: auto !important;\n overflow: visible !important;\n }\n "}}),(0,r.jsx)("title",{children:"".concat(e.name," - WebGPU Samples")}),(0,r.jsx)("meta",{name:"description",content:e.description}),(0,r.jsx)("meta",{httpEquiv:"origin-trial",content:e.originTrial})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("h1",{children:e.name}),(0,r.jsx)("a",{target:"_blank",rel:"noreferrer",href:"https://github.com/".concat("webgpu/webgpu-samples","/tree/main/").concat(e.filename),children:"See it on Github!"}),(0,r.jsx)("p",{children:e.description}),h?(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("p",{children:"Something went wrong. Do your browser and device support WebGPU?"}),(0,r.jsx)("p",{children:"".concat(h)})]}):null]}),(0,r.jsxs)("div",{className:c().canvasContainer,children:[(0,r.jsx)("div",{style:{position:"absolute",left:10},ref:f}),(0,r.jsx)("div",{style:{position:"absolute",right:10},ref:l}),(0,r.jsx)("canvas",{ref:n})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("nav",{className:c().sourceFileNav,ref:i,children:(0,r.jsx)("div",{className:c().sourceFileScrollContainer,onScroll(e){let n=e.currentTarget,t=n.scrollWidth-n.clientWidth-n.scrollLeft;n.scrollLeft>25?i.current.setAttribute("data-left","true"):i.current.setAttribute("data-left","false"),t>25?i.current.setAttribute("data-right","true"):i.current.setAttribute("data-right","false")},children:(0,r.jsx)("ul",{children:u.map((e,n)=>(0,r.jsx)("li",{children:(0,r.jsx)("a",{href:"#".concat(e.name),"data-active":y==e.name,onClick(){v(e.name)},children:e.name})},n))})})}),u.map((e,n)=>(0,r.jsx)(e.Container,{className:c().sourceFileContainer,"data-active":y==e.name},n))]})]})},d=e=>(0,r.jsx)(l,{...e});function f(e,n){if(!e)throw Error(n)}},7391:function(e,n,t){"use strict";t.r(n),t.d(n,{default:function(){return l}});var r=t(5671),i="@binding(0) @group(0) var size: vec2;\n@binding(1) @group(0) var current: array;\n@binding(2) @group(0) var next: array;\n\noverride blockSize = 8;\n\nfn getIndex(x: u32, y: u32) -> u32 {\n let h = size.y;\n let w = size.x;\n\n return (y % h) * w + (x % w);\n}\n\nfn getCell(x: u32, y: u32) -> u32 {\n return current[getIndex(x, y)];\n}\n\nfn countNeighbors(x: u32, y: u32) -> u32 {\n return getCell(x - 1, y - 1) + getCell(x, y - 1) + getCell(x + 1, y - 1) + \n getCell(x - 1, y) + getCell(x + 1, y) + \n getCell(x - 1, y + 1) + getCell(x, y + 1) + getCell(x + 1, y + 1);\n}\n\n@compute @workgroup_size(blockSize, blockSize)\nfn main(@builtin(global_invocation_id) grid: vec3) {\n let x = grid.x;\n let y = grid.y;\n let n = countNeighbors(x, y);\n next[getIndex(x, y)] = select(u32(n == 3u), u32(n == 2u || n == 3u), getCell(x, y) == 1u); \n} \n",a="struct Out {\n @builtin(position) pos: vec4,\n @location(0) cell: f32,\n}\n\n@binding(0) @group(0) var size: vec2;\n\n@vertex\nfn main(@builtin(instance_index) i: u32, @location(0) cell: u32, @location(1) pos: vec2) -> Out {\n let w = size.x;\n let h = size.y;\n let x = (f32(i % w + pos.x) / f32(w) - 0.5) * 2. * f32(w) / f32(max(w, h));\n let y = (f32((i - (i % w)) / w + pos.y) / f32(h) - 0.5) * 2. * f32(h) / f32(max(w, h));\n\n return Out(vec4(x, y, 0., 1.), f32(cell));\n}\n",o="@fragment\nfn main(@location(0) cell: f32) -> @location(0) vec4 {\n return vec4(cell, cell, cell, 1.);\n}\n",s="src/sample/gameOfLife/main.ts";let u=async e=>{let n,t,{canvas:r,pageState:s,gui:u}=e,c=await navigator.gpu.requestAdapter(),l=await c.requestDevice();if(!s.active)return;let d=r.getContext("webgpu"),f=window.devicePixelRatio;r.width=r.clientWidth*f,r.height=r.clientHeight*f;let p=navigator.gpu.getPreferredCanvasFormat();d.configure({device:l,format:p,alphaMode:"premultiplied"});let m={width:128,height:128,timestep:4,workgroupSize:8},g=l.createShaderModule({code:i}),h=l.createBindGroupLayout({entries:[{binding:0,visibility:GPUShaderStage.COMPUTE,buffer:{type:"read-only-storage"}},{binding:1,visibility:GPUShaderStage.COMPUTE,buffer:{type:"read-only-storage"}},{binding:2,visibility:GPUShaderStage.COMPUTE,buffer:{type:"storage"}}]}),b=new Uint32Array([0,0,0,1,1,0,1,1]),y=l.createBuffer({size:b.byteLength,usage:GPUBufferUsage.VERTEX,mappedAtCreation:!0});new Uint32Array(y.getMappedRange()).set(b),y.unmap();let v={arrayStride:2*b.BYTES_PER_ELEMENT,stepMode:"vertex",attributes:[{shaderLocation:1,offset:0,format:"uint32x2"}]},G=l.createShaderModule({code:a}),E=l.createShaderModule({code:o}),w=l.createBindGroupLayout({entries:[{binding:0,visibility:GPUShaderStage.VERTEX,buffer:{type:"uniform"}}]}),S={arrayStride:Uint32Array.BYTES_PER_ELEMENT,stepMode:"instance",attributes:[{shaderLocation:0,offset:0,format:"uint32"}]},P=0,x=0,U,C;function B(){let e=l.createComputePipeline({layout:l.createPipelineLayout({bindGroupLayouts:[h]}),compute:{module:g,entryPoint:"main",constants:{blockSize:m.workgroupSize}}}),r=l.createBuffer({size:2*Uint32Array.BYTES_PER_ELEMENT,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST|GPUBufferUsage.VERTEX,mappedAtCreation:!0});new Uint32Array(r.getMappedRange()).set([m.width,m.height]),r.unmap();let i=m.width*m.height,a=new Uint32Array(i);for(let o=0;oMath.random()?1:0;U=l.createBuffer({size:a.byteLength,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.VERTEX,mappedAtCreation:!0}),new Uint32Array(U.getMappedRange()).set(a),U.unmap(),C=l.createBuffer({size:a.byteLength,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.VERTEX});let s=l.createBindGroup({layout:h,entries:[{binding:0,resource:{buffer:r}},{binding:1,resource:{buffer:U}},{binding:2,resource:{buffer:C}}]}),u=l.createBindGroup({layout:h,entries:[{binding:0,resource:{buffer:r}},{binding:1,resource:{buffer:C}},{binding:2,resource:{buffer:U}}]}),c=l.createRenderPipeline({layout:l.createPipelineLayout({bindGroupLayouts:[w]}),primitive:{topology:"triangle-strip"},vertex:{module:G,entryPoint:"main",buffers:[S,v]},fragment:{module:E,entryPoint:"main",targets:[{format:p}]}}),f=l.createBindGroup({layout:c.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:r,offset:0,size:2*Uint32Array.BYTES_PER_ELEMENT}}]});x=0,t=()=>{let t=d.getCurrentTexture().createView();n=l.createCommandEncoder();let r=n.beginComputePass();r.setPipeline(e),r.setBindGroup(0,x?u:s),r.dispatchWorkgroups(m.width/m.workgroupSize,m.height/m.workgroupSize),r.end();let a=n.beginRenderPass({colorAttachments:[{view:t,loadOp:"clear",storeOp:"store"}]});a.setPipeline(c),a.setVertexBuffer(0,x?C:U),a.setVertexBuffer(1,y),a.setBindGroup(0,f),a.draw(4,i),a.end(),l.queue.submit([n.finish()])}}u.add(m,"timestep",1,60,1),u.add(m,"width",16,1024,16).onFinishChange(B),u.add(m,"height",16,1024,16).onFinishChange(B),u.add(m,"workgroupSize",[4,8,16]).onFinishChange(B),B(),function e(){m.timestep&&++P>=m.timestep&&(t(),P-=m.timestep,x=1-x),requestAnimationFrame(e)}()},c=()=>(0,r.Tl)({name:"Conway's Game of Life",description:"This example shows how to make Conway's game of life. First, use compute shader to calculate how cells grow or die. Then use render pipeline to draw cells by using instance mesh.",gui:!0,init:u,sources:[{name:s.substring(22),contents:"import { makeSample, SampleInit } from '../../components/SampleLayout';\nimport computeWGSL from './compute.wgsl';\nimport vertWGSL from './vert.wgsl';\nimport fragWGSL from './frag.wgsl';\n\nconst init: SampleInit = async ({ canvas, pageState, gui }) => {\n const adapter = await navigator.gpu.requestAdapter();\n const device = await adapter.requestDevice();\n if (!pageState.active) return;\n const context = canvas.getContext('webgpu') as GPUCanvasContext;\n const devicePixelRatio = window.devicePixelRatio;\n canvas.width = canvas.clientWidth * devicePixelRatio;\n canvas.height = canvas.clientHeight * devicePixelRatio;\n const presentationFormat = navigator.gpu.getPreferredCanvasFormat();\n\n context.configure({\n device,\n format: presentationFormat,\n alphaMode: 'premultiplied',\n });\n\n const GameOptions = {\n width: 128,\n height: 128,\n timestep: 4,\n workgroupSize: 8,\n };\n\n const computeShader = device.createShaderModule({ code: computeWGSL });\n const bindGroupLayoutCompute = device.createBindGroupLayout({\n entries: [\n {\n binding: 0,\n visibility: GPUShaderStage.COMPUTE,\n buffer: {\n type: 'read-only-storage',\n },\n },\n {\n binding: 1,\n visibility: GPUShaderStage.COMPUTE,\n buffer: {\n type: 'read-only-storage',\n },\n },\n {\n binding: 2,\n visibility: GPUShaderStage.COMPUTE,\n buffer: {\n type: 'storage',\n },\n },\n ],\n });\n\n const squareVertices = new Uint32Array([0, 0, 0, 1, 1, 0, 1, 1]);\n const squareBuffer = device.createBuffer({\n size: squareVertices.byteLength,\n usage: GPUBufferUsage.VERTEX,\n mappedAtCreation: true,\n });\n new Uint32Array(squareBuffer.getMappedRange()).set(squareVertices);\n squareBuffer.unmap();\n\n const squareStride: GPUVertexBufferLayout = {\n arrayStride: 2 * squareVertices.BYTES_PER_ELEMENT,\n stepMode: 'vertex',\n attributes: [\n {\n shaderLocation: 1,\n offset: 0,\n format: 'uint32x2',\n },\n ],\n };\n\n const vertexShader = device.createShaderModule({ code: vertWGSL });\n const fragmentShader = device.createShaderModule({ code: fragWGSL });\n let commandEncoder: GPUCommandEncoder;\n\n const bindGroupLayoutRender = device.createBindGroupLayout({\n entries: [\n {\n binding: 0,\n visibility: GPUShaderStage.VERTEX,\n buffer: {\n type: 'uniform',\n },\n },\n ],\n });\n\n const cellsStride: GPUVertexBufferLayout = {\n arrayStride: Uint32Array.BYTES_PER_ELEMENT,\n stepMode: 'instance',\n attributes: [\n {\n shaderLocation: 0,\n offset: 0,\n format: 'uint32',\n },\n ],\n };\n\n function addGUI() {\n gui.add(GameOptions, 'timestep', 1, 60, 1);\n gui.add(GameOptions, 'width', 16, 1024, 16).onFinishChange(resetGameData);\n gui.add(GameOptions, 'height', 16, 1024, 16).onFinishChange(resetGameData);\n gui\n .add(GameOptions, 'workgroupSize', [4, 8, 16])\n .onFinishChange(resetGameData);\n }\n\n let wholeTime = 0,\n loopTimes = 0,\n buffer0: GPUBuffer,\n buffer1: GPUBuffer;\n let render: () => void;\n function resetGameData() {\n // compute pipeline\n const computePipeline = device.createComputePipeline({\n layout: device.createPipelineLayout({\n bindGroupLayouts: [bindGroupLayoutCompute],\n }),\n compute: {\n module: computeShader,\n entryPoint: 'main',\n constants: {\n blockSize: GameOptions.workgroupSize,\n },\n },\n });\n const sizeBuffer = device.createBuffer({\n size: 2 * Uint32Array.BYTES_PER_ELEMENT,\n usage:\n GPUBufferUsage.STORAGE |\n GPUBufferUsage.UNIFORM |\n GPUBufferUsage.COPY_DST |\n GPUBufferUsage.VERTEX,\n mappedAtCreation: true,\n });\n new Uint32Array(sizeBuffer.getMappedRange()).set([\n GameOptions.width,\n GameOptions.height,\n ]);\n sizeBuffer.unmap();\n const length = GameOptions.width * GameOptions.height;\n const cells = new Uint32Array(length);\n for (let i = 0; i < length; i++) {\n cells[i] = Math.random() < 0.25 ? 1 : 0;\n }\n\n buffer0 = device.createBuffer({\n size: cells.byteLength,\n usage: GPUBufferUsage.STORAGE | GPUBufferUsage.VERTEX,\n mappedAtCreation: true,\n });\n new Uint32Array(buffer0.getMappedRange()).set(cells);\n buffer0.unmap();\n\n buffer1 = device.createBuffer({\n size: cells.byteLength,\n usage: GPUBufferUsage.STORAGE | GPUBufferUsage.VERTEX,\n });\n\n const bindGroup0 = device.createBindGroup({\n layout: bindGroupLayoutCompute,\n entries: [\n { binding: 0, resource: { buffer: sizeBuffer } },\n { binding: 1, resource: { buffer: buffer0 } },\n { binding: 2, resource: { buffer: buffer1 } },\n ],\n });\n\n const bindGroup1 = device.createBindGroup({\n layout: bindGroupLayoutCompute,\n entries: [\n { binding: 0, resource: { buffer: sizeBuffer } },\n { binding: 1, resource: { buffer: buffer1 } },\n { binding: 2, resource: { buffer: buffer0 } },\n ],\n });\n\n const renderPipeline = device.createRenderPipeline({\n layout: device.createPipelineLayout({\n bindGroupLayouts: [bindGroupLayoutRender],\n }),\n primitive: {\n topology: 'triangle-strip',\n },\n vertex: {\n module: vertexShader,\n entryPoint: 'main',\n buffers: [cellsStride, squareStride],\n },\n fragment: {\n module: fragmentShader,\n entryPoint: 'main',\n targets: [\n {\n format: presentationFormat,\n },\n ],\n },\n });\n\n const uniformBindGroup = device.createBindGroup({\n layout: renderPipeline.getBindGroupLayout(0),\n entries: [\n {\n binding: 0,\n resource: {\n buffer: sizeBuffer,\n offset: 0,\n size: 2 * Uint32Array.BYTES_PER_ELEMENT,\n },\n },\n ],\n });\n\n loopTimes = 0;\n render = () => {\n const view = context.getCurrentTexture().createView();\n const renderPass: GPURenderPassDescriptor = {\n colorAttachments: [\n {\n view,\n loadOp: 'clear',\n storeOp: 'store',\n },\n ],\n };\n commandEncoder = device.createCommandEncoder();\n\n // compute\n const passEncoderCompute = commandEncoder.beginComputePass();\n passEncoderCompute.setPipeline(computePipeline);\n passEncoderCompute.setBindGroup(0, loopTimes ? bindGroup1 : bindGroup0);\n passEncoderCompute.dispatchWorkgroups(\n GameOptions.width / GameOptions.workgroupSize,\n GameOptions.height / GameOptions.workgroupSize\n );\n passEncoderCompute.end();\n // render\n const passEncoderRender = commandEncoder.beginRenderPass(renderPass);\n passEncoderRender.setPipeline(renderPipeline);\n passEncoderRender.setVertexBuffer(0, loopTimes ? buffer1 : buffer0);\n passEncoderRender.setVertexBuffer(1, squareBuffer);\n passEncoderRender.setBindGroup(0, uniformBindGroup);\n passEncoderRender.draw(4, length);\n passEncoderRender.end();\n\n device.queue.submit([commandEncoder.finish()]);\n };\n }\n\n addGUI();\n resetGameData();\n\n (function loop() {\n if (GameOptions.timestep) {\n wholeTime++;\n if (wholeTime >= GameOptions.timestep) {\n render();\n wholeTime -= GameOptions.timestep;\n loopTimes = 1 - loopTimes;\n }\n }\n\n requestAnimationFrame(loop);\n })();\n};\n\nconst GameOfLife: () => JSX.Element = () =>\n makeSample({\n name: \"Conway's Game of Life\",\n description:\n \"This example shows how to make Conway's game of life. First, use compute shader to calculate how cells grow or die. Then use render pipeline to draw cells by using instance mesh.\",\n gui: true,\n init,\n sources: [\n {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n },\n {\n name: './gameOfLife.compute.wgsl',\n contents: computeWGSL,\n editable: true,\n },\n {\n name: './gameOfLife.vert.wgsl',\n contents: vertWGSL,\n editable: true,\n },\n {\n name: './gameOfLife.frag.wgsl',\n contents: fragWGSL,\n editable: true,\n },\n ],\n filename: __filename,\n });\n\nexport default GameOfLife;\n"},{name:"./gameOfLife.compute.wgsl",contents:i,editable:!0},{name:"./gameOfLife.vert.wgsl",contents:a,editable:!0},{name:"./gameOfLife.frag.wgsl",contents:o,editable:!0}],filename:s});var l=c},9147:function(e){e.exports={canvasContainer:"SampleLayout_canvasContainer__zRR_l",sourceFileNav:"SampleLayout_sourceFileNav__ml48P",sourceFileScrollContainer:"SampleLayout_sourceFileScrollContainer__LsNEm",sourceFileContainer:"SampleLayout_sourceFileContainer__3s84x"}}}]);
\ No newline at end of file
diff --git a/_next/static/chunks/428.4d8cfda9563ae10a.js b/_next/static/chunks/428.4d8cfda9563ae10a.js
deleted file mode 100644
index 4a61fb82..00000000
--- a/_next/static/chunks/428.4d8cfda9563ae10a.js
+++ /dev/null
@@ -1 +0,0 @@
-(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[428],{5671:function(e,n,t){"use strict";t.d(n,{Tl:function(){return l},hu:function(){return m}});var r=t(5893),a=t(9008),i=t.n(a),s=t(1163),o=t(7294),u=t(9147),c=t.n(u);t(7319);let d=e=>{let n=(0,o.useRef)(null),a=(0,o.useRef)(null),u=(0,o.useMemo)(()=>e.sources.map(e=>{let{name:n,contents:a}=e;return{name:n,...function(e){let n;let a=null;{a=document.createElement("div");let i=t(4631);n=i(a,{lineNumbers:!0,lineWrapping:!0,theme:"monokai",readOnly:!0})}return{Container:function(t){return(0,r.jsx)("div",{...t,children:(0,r.jsx)("div",{ref(t){a&&t&&(t.appendChild(a),n.setOption("value",e))}})})}}}(a)}}),e.sources),d=(0,o.useRef)(null),l=(0,o.useMemo)(()=>{if(e.gui){let n=t(4376),r=new n.GUI({autoPlace:!1});return r.domElement.style.position="relative",r.domElement.style.zIndex="1000",r}},[]),m=(0,o.useRef)(null),h=(0,o.useMemo)(()=>{if(e.stats){let n=t(2792);return new n}},[]),p=(0,s.useRouter)(),f=p.asPath.match(/#([a-zA-Z0-9\.\/]+)/),[g,v]=(0,o.useState)(null),[x,b]=(0,o.useState)(null);return(0,o.useEffect)(()=>{if(f?b(f[1]):b(u[0].name),l&&d.current)for(d.current.appendChild(l.domElement);l.__controllers.length>0;)l.__controllers[0].remove();h&&m.current&&(h.dom.style.position="absolute",h.showPanel(1),m.current.appendChild(h.dom));let t={active:!0},r=()=>{t.active=!1};try{let a=n.current;if(!a)throw Error("The canvas is not available");let i=e.init({canvas:a,pageState:t,gui:l,stats:h});i instanceof Promise&&i.catch(e=>{console.error(e),v(e)})}catch(s){console.error(s),v(s)}return r},[]),(0,r.jsxs)("main",{children:[(0,r.jsxs)(i(),{children:[(0,r.jsx)("style",{dangerouslySetInnerHTML:{__html:"\n .CodeMirror {\n height: auto !important;\n margin: 1em 0;\n }\n\n .CodeMirror-scroll {\n height: auto !important;\n overflow: visible !important;\n }\n "}}),(0,r.jsx)("title",{children:"".concat(e.name," - WebGPU Samples")}),(0,r.jsx)("meta",{name:"description",content:e.description}),(0,r.jsx)("meta",{httpEquiv:"origin-trial",content:e.originTrial})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("h1",{children:e.name}),(0,r.jsx)("a",{target:"_blank",rel:"noreferrer",href:"https://github.com/".concat("webgpu/webgpu-samples","/tree/main/").concat(e.filename),children:"See it on Github!"}),(0,r.jsx)("p",{children:e.description}),g?(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("p",{children:"Something went wrong. Do your browser and device support WebGPU?"}),(0,r.jsx)("p",{children:"".concat(g)})]}):null]}),(0,r.jsxs)("div",{className:c().canvasContainer,children:[(0,r.jsx)("div",{style:{position:"absolute",left:10},ref:m}),(0,r.jsx)("div",{style:{position:"absolute",right:10},ref:d}),(0,r.jsx)("canvas",{ref:n})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("nav",{className:c().sourceFileNav,ref:a,children:(0,r.jsx)("div",{className:c().sourceFileScrollContainer,onScroll(e){let n=e.currentTarget,t=n.scrollWidth-n.clientWidth-n.scrollLeft;n.scrollLeft>25?a.current.setAttribute("data-left","true"):a.current.setAttribute("data-left","false"),t>25?a.current.setAttribute("data-right","true"):a.current.setAttribute("data-right","false")},children:(0,r.jsx)("ul",{children:u.map((e,n)=>(0,r.jsx)("li",{children:(0,r.jsx)("a",{href:"#".concat(e.name),"data-active":x==e.name,onClick(){b(e.name)},children:e.name})},n))})})}),u.map((e,n)=>(0,r.jsx)(e.Container,{className:c().sourceFileContainer,"data-active":x==e.name},n))]})]})},l=e=>(0,r.jsx)(d,{...e});function m(e,n){if(!e)throw Error(n)}},3428:function(e,n,t){"use strict";t.r(n),t.d(n,{default:function(){return d}});var r=t(6416),a=t(5671);let i={vertexStride:32,positionsOffset:0,normalOffset:12,uvOffset:24};var s="struct Uniforms {\n viewProjectionMatrix : mat4x4f\n}\n@group(0) @binding(0) var uniforms : Uniforms;\n\n@group(1) @binding(0) var modelMatrix : mat4x4f;\n\nstruct VertexInput {\n @location(0) position : vec4f,\n @location(1) normal : vec3f,\n @location(2) uv : vec2f\n}\n\nstruct VertexOutput {\n @builtin(position) position : vec4f,\n @location(0) normal: vec3f,\n @location(1) uv : vec2f,\n}\n\n@vertex\nfn vertexMain(input: VertexInput) -> VertexOutput {\n var output : VertexOutput;\n output.position = uniforms.viewProjectionMatrix * modelMatrix * input.position;\n output.normal = normalize((modelMatrix * vec4(input.normal, 0)).xyz);\n output.uv = input.uv;\n return output;\n}\n\n@group(1) @binding(1) var meshSampler: sampler;\n@group(1) @binding(2) var meshTexture: texture_2d;\n\n// Static directional lighting\nconst lightDir = vec3f(1, 1, 1);\nconst dirColor = vec3(1);\nconst ambientColor = vec3f(0.05);\n\n@fragment\nfn fragmentMain(input: VertexOutput) -> @location(0) vec4f {\n let textureColor = textureSample(meshTexture, meshSampler, input.uv);\n\n // Very simplified lighting algorithm.\n let lightColor = saturate(ambientColor + max(dot(input.normal, lightDir), 0.0) * dirColor);\n\n return vec4f(textureColor.rgb * lightColor, textureColor.a);\n}",o="src/sample/renderBundles/main.ts";let u=async e=>{let n,t,a,{canvas:o,pageState:u,gui:c,stats:d}=e,l=await navigator.gpu.requestAdapter(),m=await l.requestDevice();if(!u.active)return;let h={useRenderBundles:!0,asteroidCount:5e3};c.add(h,"useRenderBundles"),c.add(h,"asteroidCount",1e3,1e4,1e3).onChange(()=>{_(),N()});let p=o.getContext("webgpu"),f=window.devicePixelRatio;o.width=o.clientWidth*f,o.height=o.clientHeight*f;let g=navigator.gpu.getPreferredCanvasFormat();p.configure({device:m,format:g,alphaMode:"premultiplied"});let v=m.createShaderModule({code:s}),x=m.createRenderPipeline({layout:"auto",vertex:{module:v,entryPoint:"vertexMain",buffers:[{arrayStride:i.vertexStride,attributes:[{shaderLocation:0,offset:i.positionsOffset,format:"float32x3"},{shaderLocation:1,offset:i.normalOffset,format:"float32x3"},{shaderLocation:2,offset:i.uvOffset,format:"float32x2"}]}]},fragment:{module:v,entryPoint:"fragmentMain",targets:[{format:g}]},primitive:{topology:"triangle-list",cullMode:"back"},depthStencil:{depthWriteEnabled:!0,depthCompare:"less",format:"depth24plus"}}),b=m.createTexture({size:[o.width,o.height],format:"depth24plus",usage:GPUTextureUsage.RENDER_ATTACHMENT}),w=m.createBuffer({size:64,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST});{let y=await fetch("../assets/img/saturn.jpg"),M=await createImageBitmap(await y.blob());n=m.createTexture({size:[M.width,M.height,1],format:"rgba8unorm",usage:GPUTextureUsage.TEXTURE_BINDING|GPUTextureUsage.COPY_DST|GPUTextureUsage.RENDER_ATTACHMENT}),m.queue.copyExternalImageToTexture({source:M},{texture:n},[M.width,M.height])}{let S=await fetch("../assets/img/moon.jpg"),B=await createImageBitmap(await S.blob());t=m.createTexture({size:[B.width,B.height,1],format:"rgba8unorm",usage:GPUTextureUsage.TEXTURE_BINDING|GPUTextureUsage.COPY_DST|GPUTextureUsage.RENDER_ATTACHMENT}),m.queue.copyExternalImageToTexture({source:B},{texture:t},[B.width,B.height])}let P=m.createSampler({magFilter:"linear",minFilter:"linear"});function T(e){let n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:32,t=arguments.length>2&&void 0!==arguments[2]?arguments[2]:16,a=arguments.length>3&&void 0!==arguments[3]?arguments[3]:0,i=function(e){let n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:32,t=arguments.length>2&&void 0!==arguments[2]?arguments[2]:16,a=arguments.length>3&&void 0!==arguments[3]?arguments[3]:0,i=[],s=[];n=Math.max(3,Math.floor(n)),t=Math.max(2,Math.floor(t));let o=r.R3.create(),u=r.R3.create(),c=r.R3.create(),d=0,l=[];for(let m=0;m<=t;m++){let h=[],p=m/t,f=0;0===m?f=.5/n:m===t&&(f=-.5/n);for(let g=0;g<=n;g++){let v=g/n;if(g==n)r.R3.copy(o,u);else if(0==g||0!=m&&m!==t){let x=e+(Math.random()-.5)*2*a*e;u[0]=-x*Math.cos(v*Math.PI*2)*Math.sin(p*Math.PI),u[1]=x*Math.cos(p*Math.PI),u[2]=x*Math.sin(v*Math.PI*2)*Math.sin(p*Math.PI),0==g&&r.R3.copy(u,o)}i.push(...u),r.R3.copy(u,c),r.R3.normalize(c,c),i.push(...c),i.push(v+f,1-p),h.push(d++)}l.push(h)}for(let b=0;bh.asteroidCount)break}function N(){let e=m.createRenderBundleEncoder({colorFormats:[g],depthStencilFormat:"depth24plus"});L(e),a=e.finish()}N(),requestAnimationFrame(function e(){if(!u.active)return;d.begin();let n=function(){let e=r._E.identity();r._E.translate(e,r.R3.fromValues(0,0,-4),e);let n=Date.now()/1e3;return r._E.rotateZ(e,.1*Math.PI,e),r._E.rotateX(e,.1*Math.PI,e),r._E.rotateY(e,.05*n,e),r._E.multiply(O,e,F),F}();m.queue.writeBuffer(w,0,n.buffer,n.byteOffset,n.byteLength),I.colorAttachments[0].view=p.getCurrentTexture().createView();let t=m.createCommandEncoder(),i=t.beginRenderPass(I);h.useRenderBundles?i.executeBundles([a]):L(i),i.end(),m.queue.submit([t.finish()]),d.end(),requestAnimationFrame(e)})},c=()=>(0,a.Tl)({name:"Render Bundles",description:"This example shows how to use render bundles. It renders a large number of\n meshes individually as a proxy for a more complex scene in order to demonstrate the reduction\n in JavaScript time spent to issue render commands. (Typically a scene like this would make use\n of instancing to reduce draw overhead.)",gui:!0,stats:!0,init:u,sources:[{name:o.substring(25),contents:"import { mat4, vec3 } from 'wgpu-matrix';\nimport { makeSample, SampleInit } from '../../components/SampleLayout';\nimport { createSphereMesh, SphereLayout } from '../../meshes/sphere';\n\nimport meshWGSL from './mesh.wgsl';\n\ninterface Renderable {\n vertices: GPUBuffer;\n indices: GPUBuffer;\n indexCount: number;\n bindGroup?: GPUBindGroup;\n}\n\nconst init: SampleInit = async ({ canvas, pageState, gui, stats }) => {\n const adapter = await navigator.gpu.requestAdapter();\n const device = await adapter.requestDevice();\n\n if (!pageState.active) return;\n\n const settings = {\n useRenderBundles: true,\n asteroidCount: 5000,\n };\n gui.add(settings, 'useRenderBundles');\n gui.add(settings, 'asteroidCount', 1000, 10000, 1000).onChange(() => {\n // If the content of the scene changes the render bundle must be recreated.\n ensureEnoughAsteroids();\n updateRenderBundle();\n });\n\n const context = canvas.getContext('webgpu') as GPUCanvasContext;\n\n const devicePixelRatio = window.devicePixelRatio;\n canvas.width = canvas.clientWidth * devicePixelRatio;\n canvas.height = canvas.clientHeight * devicePixelRatio;\n const presentationFormat = navigator.gpu.getPreferredCanvasFormat();\n\n context.configure({\n device,\n format: presentationFormat,\n alphaMode: 'premultiplied',\n });\n\n const shaderModule = device.createShaderModule({\n code: meshWGSL,\n });\n\n const pipeline = device.createRenderPipeline({\n layout: 'auto',\n vertex: {\n module: shaderModule,\n entryPoint: 'vertexMain',\n buffers: [\n {\n arrayStride: SphereLayout.vertexStride,\n attributes: [\n {\n // position\n shaderLocation: 0,\n offset: SphereLayout.positionsOffset,\n format: 'float32x3',\n },\n {\n // normal\n shaderLocation: 1,\n offset: SphereLayout.normalOffset,\n format: 'float32x3',\n },\n {\n // uv\n shaderLocation: 2,\n offset: SphereLayout.uvOffset,\n format: 'float32x2',\n },\n ],\n },\n ],\n },\n fragment: {\n module: shaderModule,\n entryPoint: 'fragmentMain',\n targets: [\n {\n format: presentationFormat,\n },\n ],\n },\n primitive: {\n topology: 'triangle-list',\n\n // Backface culling since the sphere is solid piece of geometry.\n // Faces pointing away from the camera will be occluded by faces\n // pointing toward the camera.\n cullMode: 'back',\n },\n\n // Enable depth testing so that the fragment closest to the camera\n // is rendered in front.\n depthStencil: {\n depthWriteEnabled: true,\n depthCompare: 'less',\n format: 'depth24plus',\n },\n });\n\n const depthTexture = device.createTexture({\n size: [canvas.width, canvas.height],\n format: 'depth24plus',\n usage: GPUTextureUsage.RENDER_ATTACHMENT,\n });\n\n const uniformBufferSize = 4 * 16; // 4x4 matrix\n const uniformBuffer = device.createBuffer({\n size: uniformBufferSize,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n });\n\n // Fetch the images and upload them into a GPUTexture.\n let planetTexture: GPUTexture;\n {\n const response = await fetch('../assets/img/saturn.jpg');\n const imageBitmap = await createImageBitmap(await response.blob());\n\n planetTexture = device.createTexture({\n size: [imageBitmap.width, imageBitmap.height, 1],\n format: 'rgba8unorm',\n usage:\n GPUTextureUsage.TEXTURE_BINDING |\n GPUTextureUsage.COPY_DST |\n GPUTextureUsage.RENDER_ATTACHMENT,\n });\n device.queue.copyExternalImageToTexture(\n { source: imageBitmap },\n { texture: planetTexture },\n [imageBitmap.width, imageBitmap.height]\n );\n }\n\n let moonTexture: GPUTexture;\n {\n const response = await fetch('../assets/img/moon.jpg');\n const imageBitmap = await createImageBitmap(await response.blob());\n\n moonTexture = device.createTexture({\n size: [imageBitmap.width, imageBitmap.height, 1],\n format: 'rgba8unorm',\n usage:\n GPUTextureUsage.TEXTURE_BINDING |\n GPUTextureUsage.COPY_DST |\n GPUTextureUsage.RENDER_ATTACHMENT,\n });\n device.queue.copyExternalImageToTexture(\n { source: imageBitmap },\n { texture: moonTexture },\n [imageBitmap.width, imageBitmap.height]\n );\n }\n\n const sampler = device.createSampler({\n magFilter: 'linear',\n minFilter: 'linear',\n });\n\n // Helper functions to create the required meshes and bind groups for each sphere.\n function createSphereRenderable(\n radius: number,\n widthSegments = 32,\n heightSegments = 16,\n randomness = 0\n ): Renderable {\n const sphereMesh = createSphereMesh(\n radius,\n widthSegments,\n heightSegments,\n randomness\n );\n\n // Create a vertex buffer from the sphere data.\n const vertices = device.createBuffer({\n size: sphereMesh.vertices.byteLength,\n usage: GPUBufferUsage.VERTEX,\n mappedAtCreation: true,\n });\n new Float32Array(vertices.getMappedRange()).set(sphereMesh.vertices);\n vertices.unmap();\n\n const indices = device.createBuffer({\n size: sphereMesh.indices.byteLength,\n usage: GPUBufferUsage.INDEX,\n mappedAtCreation: true,\n });\n new Uint16Array(indices.getMappedRange()).set(sphereMesh.indices);\n indices.unmap();\n\n return {\n vertices,\n indices,\n indexCount: sphereMesh.indices.length,\n };\n }\n\n function createSphereBindGroup(\n texture: GPUTexture,\n transform: Float32Array\n ): GPUBindGroup {\n const uniformBufferSize = 4 * 16; // 4x4 matrix\n const uniformBuffer = device.createBuffer({\n size: uniformBufferSize,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n mappedAtCreation: true,\n });\n new Float32Array(uniformBuffer.getMappedRange()).set(transform);\n uniformBuffer.unmap();\n\n const bindGroup = device.createBindGroup({\n layout: pipeline.getBindGroupLayout(1),\n entries: [\n {\n binding: 0,\n resource: {\n buffer: uniformBuffer,\n },\n },\n {\n binding: 1,\n resource: sampler,\n },\n {\n binding: 2,\n resource: texture.createView(),\n },\n ],\n });\n\n return bindGroup;\n }\n\n const transform = mat4.create() as Float32Array;\n mat4.identity(transform);\n\n // Create one large central planet surrounded by a large ring of asteroids\n const planet = createSphereRenderable(1.0);\n planet.bindGroup = createSphereBindGroup(planetTexture, transform);\n\n const asteroids = [\n createSphereRenderable(0.01, 8, 6, 0.15),\n createSphereRenderable(0.013, 8, 6, 0.15),\n createSphereRenderable(0.017, 8, 6, 0.15),\n createSphereRenderable(0.02, 8, 6, 0.15),\n createSphereRenderable(0.03, 16, 8, 0.15),\n ];\n\n const renderables = [planet];\n\n function ensureEnoughAsteroids() {\n for (let i = renderables.length; i <= settings.asteroidCount; ++i) {\n // Place copies of the asteroid in a ring.\n const radius = Math.random() * 1.7 + 1.25;\n const angle = Math.random() * Math.PI * 2;\n const x = Math.sin(angle) * radius;\n const y = (Math.random() - 0.5) * 0.015;\n const z = Math.cos(angle) * radius;\n\n mat4.identity(transform);\n mat4.translate(transform, [x, y, z], transform);\n mat4.rotateX(transform, Math.random() * Math.PI, transform);\n mat4.rotateY(transform, Math.random() * Math.PI, transform);\n renderables.push({\n ...asteroids[i % asteroids.length],\n bindGroup: createSphereBindGroup(moonTexture, transform),\n });\n }\n }\n ensureEnoughAsteroids();\n\n const renderPassDescriptor: GPURenderPassDescriptor = {\n colorAttachments: [\n {\n view: undefined, // Assigned later\n\n clearValue: { r: 0.0, g: 0.0, b: 0.0, a: 1.0 },\n loadOp: 'clear',\n storeOp: 'store',\n },\n ],\n depthStencilAttachment: {\n view: depthTexture.createView(),\n\n depthClearValue: 1.0,\n depthLoadOp: 'clear',\n depthStoreOp: 'store',\n },\n };\n\n const aspect = canvas.width / canvas.height;\n const projectionMatrix = mat4.perspective(\n (2 * Math.PI) / 5,\n aspect,\n 1,\n 100.0\n );\n const modelViewProjectionMatrix = mat4.create();\n\n const frameBindGroup = device.createBindGroup({\n layout: pipeline.getBindGroupLayout(0),\n entries: [\n {\n binding: 0,\n resource: {\n buffer: uniformBuffer,\n },\n },\n ],\n });\n\n function getTransformationMatrix() {\n const viewMatrix = mat4.identity();\n mat4.translate(viewMatrix, vec3.fromValues(0, 0, -4), viewMatrix);\n const now = Date.now() / 1000;\n // Tilt the view matrix so the planet looks like it's off-axis.\n mat4.rotateZ(viewMatrix, Math.PI * 0.1, viewMatrix);\n mat4.rotateX(viewMatrix, Math.PI * 0.1, viewMatrix);\n // Rotate the view matrix slowly so the planet appears to spin.\n mat4.rotateY(viewMatrix, now * 0.05, viewMatrix);\n\n mat4.multiply(projectionMatrix, viewMatrix, modelViewProjectionMatrix);\n\n return modelViewProjectionMatrix as Float32Array;\n }\n\n // Render bundles function as partial, limited render passes, so we can use the\n // same code both to render the scene normally and to build the render bundle.\n function renderScene(\n passEncoder: GPURenderPassEncoder | GPURenderBundleEncoder\n ) {\n passEncoder.setPipeline(pipeline);\n passEncoder.setBindGroup(0, frameBindGroup);\n\n // Loop through every renderable object and draw them individually.\n // (Because many of these meshes are repeated, with only the transforms\n // differing, instancing would be highly effective here. This sample\n // intentionally avoids using instancing in order to emulate a more complex\n // scene, which helps demonstrate the potential time savings a render bundle\n // can provide.)\n let count = 0;\n for (const renderable of renderables) {\n passEncoder.setBindGroup(1, renderable.bindGroup);\n passEncoder.setVertexBuffer(0, renderable.vertices);\n passEncoder.setIndexBuffer(renderable.indices, 'uint16');\n passEncoder.drawIndexed(renderable.indexCount);\n\n if (++count > settings.asteroidCount) {\n break;\n }\n }\n }\n\n // The render bundle can be encoded once and re-used as many times as needed.\n // Because it encodes all of the commands needed to render at the GPU level,\n // those commands will not need to execute the associated JavaScript code upon\n // execution or be re-validated, which can represent a significant time savings.\n //\n // However, because render bundles are immutable once created, they are only\n // appropriate for rendering content where the same commands will be executed\n // every time, with the only changes being the contents of the buffers and\n // textures used. Cases where the executed commands differ from frame-to-frame,\n // such as when using frustrum or occlusion culling, will not benefit from\n // using render bundles as much.\n let renderBundle;\n function updateRenderBundle() {\n const renderBundleEncoder = device.createRenderBundleEncoder({\n colorFormats: [presentationFormat],\n depthStencilFormat: 'depth24plus',\n });\n renderScene(renderBundleEncoder);\n renderBundle = renderBundleEncoder.finish();\n }\n updateRenderBundle();\n\n function frame() {\n // Sample is no longer the active page.\n if (!pageState.active) return;\n\n stats.begin();\n\n const transformationMatrix = getTransformationMatrix();\n device.queue.writeBuffer(\n uniformBuffer,\n 0,\n transformationMatrix.buffer,\n transformationMatrix.byteOffset,\n transformationMatrix.byteLength\n );\n renderPassDescriptor.colorAttachments[0].view = context\n .getCurrentTexture()\n .createView();\n\n const commandEncoder = device.createCommandEncoder();\n const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);\n\n if (settings.useRenderBundles) {\n // Executing a bundle is equivalent to calling all of the commands encoded\n // in the render bundle as part of the current render pass.\n passEncoder.executeBundles([renderBundle]);\n } else {\n // Alternatively, the same render commands can be encoded manually, which\n // can take longer since each command needs to be interpreted by the\n // JavaScript virtual machine and re-validated each time.\n renderScene(passEncoder);\n }\n\n passEncoder.end();\n device.queue.submit([commandEncoder.finish()]);\n\n stats.end();\n\n requestAnimationFrame(frame);\n }\n requestAnimationFrame(frame);\n};\n\nconst RenderBundles: () => JSX.Element = () =>\n makeSample({\n name: 'Render Bundles',\n description: `This example shows how to use render bundles. It renders a large number of\n meshes individually as a proxy for a more complex scene in order to demonstrate the reduction\n in JavaScript time spent to issue render commands. (Typically a scene like this would make use\n of instancing to reduce draw overhead.)`,\n gui: true,\n stats: true,\n init,\n sources: [\n {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n },\n {\n name: './mesh.wgsl',\n contents: meshWGSL,\n editable: true,\n },\n {\n name: '../../meshes/sphere.ts',\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n contents: require('!!raw-loader!../../meshes/sphere.ts').default,\n },\n ],\n filename: __filename,\n });\n\nexport default RenderBundles;\n"},{name:"./mesh.wgsl",contents:s,editable:!0},{name:"../../meshes/sphere.ts",contents:t(8557).Z}],filename:o});var d=c},9147:function(e){e.exports={canvasContainer:"SampleLayout_canvasContainer__zRR_l",sourceFileNav:"SampleLayout_sourceFileNav__ml48P",sourceFileScrollContainer:"SampleLayout_sourceFileScrollContainer__LsNEm",sourceFileContainer:"SampleLayout_sourceFileContainer__3s84x"}},8557:function(e,n){"use strict";n.Z="import { vec3 } from 'wgpu-matrix';\n\nexport interface SphereMesh {\n vertices: Float32Array;\n indices: Uint16Array;\n}\n\nexport const SphereLayout = {\n vertexStride: 8 * 4,\n positionsOffset: 0,\n normalOffset: 3 * 4,\n uvOffset: 6 * 4,\n};\n\n// Borrowed and simplified from https://github.com/mrdoob/three.js/blob/master/src/geometries/SphereGeometry.js\nexport function createSphereMesh(\n radius: number,\n widthSegments = 32,\n heightSegments = 16,\n randomness = 0\n): SphereMesh {\n const vertices = [];\n const indices = [];\n\n widthSegments = Math.max(3, Math.floor(widthSegments));\n heightSegments = Math.max(2, Math.floor(heightSegments));\n\n const firstVertex = vec3.create();\n const vertex = vec3.create();\n const normal = vec3.create();\n\n let index = 0;\n const grid = [];\n\n // generate vertices, normals and uvs\n for (let iy = 0; iy <= heightSegments; iy++) {\n const verticesRow = [];\n const v = iy / heightSegments;\n\n // special case for the poles\n let uOffset = 0;\n if (iy === 0) {\n uOffset = 0.5 / widthSegments;\n } else if (iy === heightSegments) {\n uOffset = -0.5 / widthSegments;\n }\n\n for (let ix = 0; ix <= widthSegments; ix++) {\n const u = ix / widthSegments;\n\n // Poles should just use the same position all the way around.\n if (ix == widthSegments) {\n vec3.copy(firstVertex, vertex);\n } else if (ix == 0 || (iy != 0 && iy !== heightSegments)) {\n const rr = radius + (Math.random() - 0.5) * 2 * randomness * radius;\n\n // vertex\n vertex[0] = -rr * Math.cos(u * Math.PI * 2) * Math.sin(v * Math.PI);\n vertex[1] = rr * Math.cos(v * Math.PI);\n vertex[2] = rr * Math.sin(u * Math.PI * 2) * Math.sin(v * Math.PI);\n\n if (ix == 0) {\n vec3.copy(vertex, firstVertex);\n }\n }\n\n vertices.push(...vertex);\n\n // normal\n vec3.copy(vertex, normal);\n vec3.normalize(normal, normal);\n vertices.push(...normal);\n\n // uv\n vertices.push(u + uOffset, 1 - v);\n verticesRow.push(index++);\n }\n\n grid.push(verticesRow);\n }\n\n // indices\n for (let iy = 0; iy < heightSegments; iy++) {\n for (let ix = 0; ix < widthSegments; ix++) {\n const a = grid[iy][ix + 1];\n const b = grid[iy][ix];\n const c = grid[iy + 1][ix];\n const d = grid[iy + 1][ix + 1];\n\n if (iy !== 0) indices.push(a, b, d);\n if (iy !== heightSegments - 1) indices.push(b, c, d);\n }\n }\n\n return {\n vertices: new Float32Array(vertices),\n indices: new Uint16Array(indices),\n };\n}\n"}}]);
\ No newline at end of file
diff --git a/_next/static/chunks/432.b50494de55023c1c.js b/_next/static/chunks/432.b50494de55023c1c.js
deleted file mode 100644
index b7477147..00000000
--- a/_next/static/chunks/432.b50494de55023c1c.js
+++ /dev/null
@@ -1 +0,0 @@
-(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[432],{5671:function(e,n,t){"use strict";t.d(n,{Tl:function(){return m},hu:function(){return p}});var r=t(5893),a=t(9008),i=t.n(a),o=t(1163),s=t(7294),c=t(9147),u=t.n(c);t(7319);let l=e=>{let n=(0,s.useRef)(null),a=(0,s.useRef)(null),c=(0,s.useMemo)(()=>e.sources.map(e=>{let{name:n,contents:a}=e;return{name:n,...function(e){let n;let a=null;{a=document.createElement("div");let i=t(4631);n=i(a,{lineNumbers:!0,lineWrapping:!0,theme:"monokai",readOnly:!0})}return{Container:function(t){return(0,r.jsx)("div",{...t,children:(0,r.jsx)("div",{ref(t){a&&t&&(t.appendChild(a),n.setOption("value",e))}})})}}}(a)}}),e.sources),l=(0,s.useRef)(null),m=(0,s.useMemo)(()=>{if(e.gui){let n=t(4376),r=new n.GUI({autoPlace:!1});return r.domElement.style.position="relative",r.domElement.style.zIndex="1000",r}},[]),p=(0,s.useRef)(null),d=(0,s.useMemo)(()=>{if(e.stats){let n=t(2792);return new n}},[]),f=(0,o.useRouter)(),g=f.asPath.match(/#([a-zA-Z0-9\.\/]+)/),[h,x]=(0,s.useState)(null),[b,v]=(0,s.useState)(null);return(0,s.useEffect)(()=>{if(g?v(g[1]):v(c[0].name),m&&l.current)for(l.current.appendChild(m.domElement);m.__controllers.length>0;)m.__controllers[0].remove();d&&p.current&&(d.dom.style.position="absolute",d.showPanel(1),p.current.appendChild(d.dom));let t={active:!0},r=()=>{t.active=!1};try{let a=n.current;if(!a)throw Error("The canvas is not available");let i=e.init({canvas:a,pageState:t,gui:m,stats:d});i instanceof Promise&&i.catch(e=>{console.error(e),x(e)})}catch(o){console.error(o),x(o)}return r},[]),(0,r.jsxs)("main",{children:[(0,r.jsxs)(i(),{children:[(0,r.jsx)("style",{dangerouslySetInnerHTML:{__html:"\n .CodeMirror {\n height: auto !important;\n margin: 1em 0;\n }\n\n .CodeMirror-scroll {\n height: auto !important;\n overflow: visible !important;\n }\n "}}),(0,r.jsx)("title",{children:"".concat(e.name," - WebGPU Samples")}),(0,r.jsx)("meta",{name:"description",content:e.description}),(0,r.jsx)("meta",{httpEquiv:"origin-trial",content:e.originTrial})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("h1",{children:e.name}),(0,r.jsx)("a",{target:"_blank",rel:"noreferrer",href:"https://github.com/".concat("webgpu/webgpu-samples","/tree/main/").concat(e.filename),children:"See it on Github!"}),(0,r.jsx)("p",{children:e.description}),h?(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("p",{children:"Something went wrong. Do your browser and device support WebGPU?"}),(0,r.jsx)("p",{children:"".concat(h)})]}):null]}),(0,r.jsxs)("div",{className:u().canvasContainer,children:[(0,r.jsx)("div",{style:{position:"absolute",left:10},ref:p}),(0,r.jsx)("div",{style:{position:"absolute",right:10},ref:l}),(0,r.jsx)("canvas",{ref:n})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("nav",{className:u().sourceFileNav,ref:a,children:(0,r.jsx)("div",{className:u().sourceFileScrollContainer,onScroll(e){let n=e.currentTarget,t=n.scrollWidth-n.clientWidth-n.scrollLeft;n.scrollLeft>25?a.current.setAttribute("data-left","true"):a.current.setAttribute("data-left","false"),t>25?a.current.setAttribute("data-right","true"):a.current.setAttribute("data-right","false")},children:(0,r.jsx)("ul",{children:c.map((e,n)=>(0,r.jsx)("li",{children:(0,r.jsx)("a",{href:"#".concat(e.name),"data-active":b==e.name,onClick(){v(e.name)},children:e.name})},n))})})}),c.map((e,n)=>(0,r.jsx)(e.Container,{className:u().sourceFileContainer,"data-active":b==e.name},n))]})]})},m=e=>(0,r.jsx)(l,{...e});function p(e,n){if(!e)throw Error(n)}},4655:function(e,n,t){"use strict";t.d(n,{Ax:function(){return i},MO:function(){return o},O$:function(){return r},v8:function(){return a},zS:function(){return s}});let r=40,a=0,i=32,o=36,s=new Float32Array([1,-1,1,1,1,0,1,1,0,1,-1,-1,1,1,0,0,1,1,1,1,-1,-1,-1,1,0,0,0,1,1,0,1,-1,-1,1,1,0,0,1,0,0,1,-1,1,1,1,0,1,1,0,1,-1,-1,-1,1,0,0,0,1,1,0,1,1,1,1,1,1,1,1,0,1,1,-1,1,1,1,0,1,1,1,1,1,-1,-1,1,1,0,0,1,1,0,1,1,-1,1,1,1,0,1,0,0,1,1,1,1,1,1,1,1,0,1,1,-1,-1,1,1,0,0,1,1,0,-1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,-1,1,1,1,0,1,1,0,-1,1,-1,1,0,1,0,1,0,0,-1,1,1,1,0,1,1,1,0,1,1,1,-1,1,1,1,0,1,1,0,-1,-1,1,1,0,0,1,1,0,1,-1,1,1,1,0,1,1,1,1,1,-1,1,-1,1,0,1,0,1,1,0,-1,-1,-1,1,0,0,0,1,0,0,-1,-1,1,1,0,0,1,1,0,1,-1,1,-1,1,0,1,0,1,1,0,1,1,1,1,1,1,1,1,0,1,-1,1,1,1,0,1,1,1,1,1,-1,-1,1,1,0,0,1,1,1,0,-1,-1,1,1,0,0,1,1,1,0,1,-1,1,1,1,0,1,1,0,0,1,1,1,1,1,1,1,1,0,1,1,-1,-1,1,1,0,0,1,0,1,-1,-1,-1,1,0,0,0,1,1,1,-1,1,-1,1,0,1,0,1,1,0,1,1,-1,1,1,1,0,1,0,0,1,-1,-1,1,1,0,0,1,0,1,-1,1,-1,1,0,1,0,1,1,0])},1432:function(e,n,t){"use strict";t.r(n),t.d(n,{default:function(){return m}});var r=t(6416),a=t(5671),i=t(4655),o=t(3569),s="@group(0) @binding(1) var mySampler: sampler;\n@group(0) @binding(2) var myTexture: texture_cube;\n\n@fragment\nfn main(\n @location(0) fragUV: vec2,\n @location(1) fragPosition: vec4\n) -> @location(0) vec4 {\n // Our camera and the skybox cube are both centered at (0, 0, 0)\n // so we can use the cube geomtry position to get viewing vector to sample the cube texture.\n // The magnitude of the vector doesn't matter.\n var cubemapVec = fragPosition.xyz - vec3(0.5);\n return textureSample(myTexture, mySampler, cubemapVec);\n}\n",c="src/sample/cubemap/main.ts";let u=async e=>{let n,{canvas:t,pageState:a}=e,c=await navigator.gpu.requestAdapter(),u=await c.requestDevice();if(!a.active)return;let l=t.getContext("webgpu"),m=window.devicePixelRatio;t.width=t.clientWidth*m,t.height=t.clientHeight*m;let p=navigator.gpu.getPreferredCanvasFormat();l.configure({device:u,format:p,alphaMode:"premultiplied"});let d=u.createBuffer({size:i.zS.byteLength,usage:GPUBufferUsage.VERTEX,mappedAtCreation:!0});new Float32Array(d.getMappedRange()).set(i.zS),d.unmap();let f=u.createRenderPipeline({layout:"auto",vertex:{module:u.createShaderModule({code:o.Z}),entryPoint:"main",buffers:[{arrayStride:i.O$,attributes:[{shaderLocation:0,offset:i.v8,format:"float32x4"},{shaderLocation:1,offset:i.Ax,format:"float32x2"}]}]},fragment:{module:u.createShaderModule({code:s}),entryPoint:"main",targets:[{format:p}]},primitive:{topology:"triangle-list",cullMode:"none"},depthStencil:{depthWriteEnabled:!0,depthCompare:"less",format:"depth24plus"}}),g=u.createTexture({size:[t.width,t.height],format:"depth24plus",usage:GPUTextureUsage.RENDER_ATTACHMENT});{let h=["../assets/img/cubemap/posx.jpg","../assets/img/cubemap/negx.jpg","../assets/img/cubemap/posy.jpg","../assets/img/cubemap/negy.jpg","../assets/img/cubemap/posz.jpg","../assets/img/cubemap/negz.jpg"].map(async e=>{let n=await fetch(e);return createImageBitmap(await n.blob())}),x=await Promise.all(h);n=u.createTexture({dimension:"2d",size:[x[0].width,x[0].height,6],format:"rgba8unorm",usage:GPUTextureUsage.TEXTURE_BINDING|GPUTextureUsage.COPY_DST|GPUTextureUsage.RENDER_ATTACHMENT});for(let b=0;b(0,a.Tl)({name:"Cubemap",description:"This example shows how to render and sample from a cubemap texture.",init:u,sources:[{name:c.substring(19),contents:"import { mat4, vec3 } from 'wgpu-matrix';\nimport { makeSample, SampleInit } from '../../components/SampleLayout';\n\nimport {\n cubeVertexArray,\n cubeVertexSize,\n cubeUVOffset,\n cubePositionOffset,\n cubeVertexCount,\n} from '../../meshes/cube';\n\nimport basicVertWGSL from '../../shaders/basic.vert.wgsl';\nimport sampleCubemapWGSL from './sampleCubemap.frag.wgsl';\n\nconst init: SampleInit = async ({ canvas, pageState }) => {\n const adapter = await navigator.gpu.requestAdapter();\n const device = await adapter.requestDevice();\n\n if (!pageState.active) return;\n const context = canvas.getContext('webgpu') as GPUCanvasContext;\n\n const devicePixelRatio = window.devicePixelRatio;\n canvas.width = canvas.clientWidth * devicePixelRatio;\n canvas.height = canvas.clientHeight * devicePixelRatio;\n const presentationFormat = navigator.gpu.getPreferredCanvasFormat();\n\n context.configure({\n device,\n format: presentationFormat,\n alphaMode: 'premultiplied',\n });\n\n // Create a vertex buffer from the cube data.\n const verticesBuffer = device.createBuffer({\n size: cubeVertexArray.byteLength,\n usage: GPUBufferUsage.VERTEX,\n mappedAtCreation: true,\n });\n new Float32Array(verticesBuffer.getMappedRange()).set(cubeVertexArray);\n verticesBuffer.unmap();\n\n const pipeline = device.createRenderPipeline({\n layout: 'auto',\n vertex: {\n module: device.createShaderModule({\n code: basicVertWGSL,\n }),\n entryPoint: 'main',\n buffers: [\n {\n arrayStride: cubeVertexSize,\n attributes: [\n {\n // position\n shaderLocation: 0,\n offset: cubePositionOffset,\n format: 'float32x4',\n },\n {\n // uv\n shaderLocation: 1,\n offset: cubeUVOffset,\n format: 'float32x2',\n },\n ],\n },\n ],\n },\n fragment: {\n module: device.createShaderModule({\n code: sampleCubemapWGSL,\n }),\n entryPoint: 'main',\n targets: [\n {\n format: presentationFormat,\n },\n ],\n },\n primitive: {\n topology: 'triangle-list',\n\n // Since we are seeing from inside of the cube\n // and we are using the regular cube geomtry data with outward-facing normals,\n // the cullMode should be 'front' or 'none'.\n cullMode: 'none',\n },\n\n // Enable depth testing so that the fragment closest to the camera\n // is rendered in front.\n depthStencil: {\n depthWriteEnabled: true,\n depthCompare: 'less',\n format: 'depth24plus',\n },\n });\n\n const depthTexture = device.createTexture({\n size: [canvas.width, canvas.height],\n format: 'depth24plus',\n usage: GPUTextureUsage.RENDER_ATTACHMENT,\n });\n\n // Fetch the 6 separate images for negative/positive x, y, z axis of a cubemap\n // and upload it into a GPUTexture.\n let cubemapTexture: GPUTexture;\n {\n // The order of the array layers is [+X, -X, +Y, -Y, +Z, -Z]\n const imgSrcs = [\n '../assets/img/cubemap/posx.jpg',\n '../assets/img/cubemap/negx.jpg',\n '../assets/img/cubemap/posy.jpg',\n '../assets/img/cubemap/negy.jpg',\n '../assets/img/cubemap/posz.jpg',\n '../assets/img/cubemap/negz.jpg',\n ];\n const promises = imgSrcs.map(async (src) => {\n const response = await fetch(src);\n return createImageBitmap(await response.blob());\n });\n const imageBitmaps = await Promise.all(promises);\n\n cubemapTexture = device.createTexture({\n dimension: '2d',\n // Create a 2d array texture.\n // Assume each image has the same size.\n size: [imageBitmaps[0].width, imageBitmaps[0].height, 6],\n format: 'rgba8unorm',\n usage:\n GPUTextureUsage.TEXTURE_BINDING |\n GPUTextureUsage.COPY_DST |\n GPUTextureUsage.RENDER_ATTACHMENT,\n });\n\n for (let i = 0; i < imageBitmaps.length; i++) {\n const imageBitmap = imageBitmaps[i];\n device.queue.copyExternalImageToTexture(\n { source: imageBitmap },\n { texture: cubemapTexture, origin: [0, 0, i] },\n [imageBitmap.width, imageBitmap.height]\n );\n }\n }\n\n const uniformBufferSize = 4 * 16; // 4x4 matrix\n const uniformBuffer = device.createBuffer({\n size: uniformBufferSize,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n });\n\n const sampler = device.createSampler({\n magFilter: 'linear',\n minFilter: 'linear',\n });\n\n const uniformBindGroup = device.createBindGroup({\n layout: pipeline.getBindGroupLayout(0),\n entries: [\n {\n binding: 0,\n resource: {\n buffer: uniformBuffer,\n offset: 0,\n size: uniformBufferSize,\n },\n },\n {\n binding: 1,\n resource: sampler,\n },\n {\n binding: 2,\n resource: cubemapTexture.createView({\n dimension: 'cube',\n }),\n },\n ],\n });\n\n const renderPassDescriptor: GPURenderPassDescriptor = {\n colorAttachments: [\n {\n view: undefined, // Assigned later\n loadOp: 'clear',\n storeOp: 'store',\n },\n ],\n depthStencilAttachment: {\n view: depthTexture.createView(),\n\n depthClearValue: 1.0,\n depthLoadOp: 'clear',\n depthStoreOp: 'store',\n },\n };\n\n const aspect = canvas.width / canvas.height;\n const projectionMatrix = mat4.perspective((2 * Math.PI) / 5, aspect, 1, 3000);\n\n const modelMatrix = mat4.scaling(vec3.fromValues(1000, 1000, 1000));\n const modelViewProjectionMatrix = mat4.create() as Float32Array;\n const viewMatrix = mat4.identity();\n\n const tmpMat4 = mat4.create();\n\n // Comppute camera movement:\n // It rotates around Y axis with a slight pitch movement.\n function updateTransformationMatrix() {\n const now = Date.now() / 800;\n\n mat4.rotate(\n viewMatrix,\n vec3.fromValues(1, 0, 0),\n (Math.PI / 10) * Math.sin(now),\n tmpMat4\n );\n mat4.rotate(tmpMat4, vec3.fromValues(0, 1, 0), now * 0.2, tmpMat4);\n\n mat4.multiply(tmpMat4, modelMatrix, modelViewProjectionMatrix);\n mat4.multiply(\n projectionMatrix,\n modelViewProjectionMatrix,\n modelViewProjectionMatrix\n );\n }\n\n function frame() {\n // Sample is no longer the active page.\n if (!pageState.active) return;\n\n updateTransformationMatrix();\n device.queue.writeBuffer(\n uniformBuffer,\n 0,\n modelViewProjectionMatrix.buffer,\n modelViewProjectionMatrix.byteOffset,\n modelViewProjectionMatrix.byteLength\n );\n\n renderPassDescriptor.colorAttachments[0].view = context\n .getCurrentTexture()\n .createView();\n\n const commandEncoder = device.createCommandEncoder();\n const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);\n passEncoder.setPipeline(pipeline);\n passEncoder.setVertexBuffer(0, verticesBuffer);\n passEncoder.setBindGroup(0, uniformBindGroup);\n passEncoder.draw(cubeVertexCount);\n passEncoder.end();\n device.queue.submit([commandEncoder.finish()]);\n\n requestAnimationFrame(frame);\n }\n requestAnimationFrame(frame);\n};\n\nconst CubemapCubes: () => JSX.Element = () =>\n makeSample({\n name: 'Cubemap',\n description:\n 'This example shows how to render and sample from a cubemap texture.',\n init,\n sources: [\n {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n },\n {\n name: '../../shaders/basic.vert.wgsl',\n contents: basicVertWGSL,\n editable: true,\n },\n {\n name: './sampleCubemap.frag.wgsl',\n contents: sampleCubemapWGSL,\n editable: true,\n },\n {\n name: '../../meshes/cube.ts',\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n contents: require('!!raw-loader!../../meshes/cube.ts').default,\n },\n ],\n filename: __filename,\n });\n\nexport default CubemapCubes;\n"},{name:"../../shaders/basic.vert.wgsl",contents:o.Z,editable:!0},{name:"./sampleCubemap.frag.wgsl",contents:s,editable:!0},{name:"../../meshes/cube.ts",contents:t(2448).Z}],filename:c});var m=l},9147:function(e){e.exports={canvasContainer:"SampleLayout_canvasContainer__zRR_l",sourceFileNav:"SampleLayout_sourceFileNav__ml48P",sourceFileScrollContainer:"SampleLayout_sourceFileScrollContainer__LsNEm",sourceFileContainer:"SampleLayout_sourceFileContainer__3s84x"}},2448:function(e,n){"use strict";n.Z="export const cubeVertexSize = 4 * 10; // Byte size of one cube vertex.\nexport const cubePositionOffset = 0;\nexport const cubeColorOffset = 4 * 4; // Byte offset of cube vertex color attribute.\nexport const cubeUVOffset = 4 * 8;\nexport const cubeVertexCount = 36;\n\n// prettier-ignore\nexport const cubeVertexArray = new Float32Array([\n // float4 position, float4 color, float2 uv,\n 1, -1, 1, 1, 1, 0, 1, 1, 0, 1,\n -1, -1, 1, 1, 0, 0, 1, 1, 1, 1,\n -1, -1, -1, 1, 0, 0, 0, 1, 1, 0,\n 1, -1, -1, 1, 1, 0, 0, 1, 0, 0,\n 1, -1, 1, 1, 1, 0, 1, 1, 0, 1,\n -1, -1, -1, 1, 0, 0, 0, 1, 1, 0,\n\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n 1, -1, 1, 1, 1, 0, 1, 1, 1, 1,\n 1, -1, -1, 1, 1, 0, 0, 1, 1, 0,\n 1, 1, -1, 1, 1, 1, 0, 1, 0, 0,\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n 1, -1, -1, 1, 1, 0, 0, 1, 1, 0,\n\n -1, 1, 1, 1, 0, 1, 1, 1, 0, 1,\n 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n 1, 1, -1, 1, 1, 1, 0, 1, 1, 0,\n -1, 1, -1, 1, 0, 1, 0, 1, 0, 0,\n -1, 1, 1, 1, 0, 1, 1, 1, 0, 1,\n 1, 1, -1, 1, 1, 1, 0, 1, 1, 0,\n\n -1, -1, 1, 1, 0, 0, 1, 1, 0, 1,\n -1, 1, 1, 1, 0, 1, 1, 1, 1, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n -1, -1, -1, 1, 0, 0, 0, 1, 0, 0,\n -1, -1, 1, 1, 0, 0, 1, 1, 0, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n -1, 1, 1, 1, 0, 1, 1, 1, 1, 1,\n -1, -1, 1, 1, 0, 0, 1, 1, 1, 0,\n -1, -1, 1, 1, 0, 0, 1, 1, 1, 0,\n 1, -1, 1, 1, 1, 0, 1, 1, 0, 0,\n 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,\n\n 1, -1, -1, 1, 1, 0, 0, 1, 0, 1,\n -1, -1, -1, 1, 0, 0, 0, 1, 1, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n 1, 1, -1, 1, 1, 1, 0, 1, 0, 0,\n 1, -1, -1, 1, 1, 0, 0, 1, 0, 1,\n -1, 1, -1, 1, 0, 1, 0, 1, 1, 0,\n]);\n"},3569:function(e,n){"use strict";n.Z="struct Uniforms {\n modelViewProjectionMatrix : mat4x4,\n}\n@binding(0) @group(0) var uniforms : Uniforms;\n\nstruct VertexOutput {\n @builtin(position) Position : vec4,\n @location(0) fragUV : vec2,\n @location(1) fragPosition: vec4,\n}\n\n@vertex\nfn main(\n @location(0) position : vec4,\n @location(1) uv : vec2\n) -> VertexOutput {\n var output : VertexOutput;\n output.Position = uniforms.modelViewProjectionMatrix * position;\n output.fragUV = uv;\n output.fragPosition = 0.5 * (position + vec4(1.0, 1.0, 1.0, 1.0));\n return output;\n}\n"}}]);
\ No newline at end of file
diff --git a/_next/static/chunks/565.ef56f8624a470ccb.js b/_next/static/chunks/565.ef56f8624a470ccb.js
deleted file mode 100644
index b49cb238..00000000
--- a/_next/static/chunks/565.ef56f8624a470ccb.js
+++ /dev/null
@@ -1 +0,0 @@
-(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[565],{5671:function(e,n,t){"use strict";t.d(n,{Tl:function(){return u},hu:function(){return m}});var a=t(5893),r=t(9008),i=t.n(r),s=t(1163),o=t(7294),l=t(9147),c=t.n(l);t(7319);let d=e=>{let n=(0,o.useRef)(null),r=(0,o.useRef)(null),l=(0,o.useMemo)(()=>e.sources.map(e=>{let{name:n,contents:r}=e;return{name:n,...function(e){let n;let r=null;{r=document.createElement("div");let i=t(4631);n=i(r,{lineNumbers:!0,lineWrapping:!0,theme:"monokai",readOnly:!0})}return{Container:function(t){return(0,a.jsx)("div",{...t,children:(0,a.jsx)("div",{ref(t){r&&t&&(t.appendChild(r),n.setOption("value",e))}})})}}}(r)}}),e.sources),d=(0,o.useRef)(null),u=(0,o.useMemo)(()=>{if(e.gui){let n=t(4376),a=new n.GUI({autoPlace:!1});return a.domElement.style.position="relative",a.domElement.style.zIndex="1000",a}},[]),m=(0,o.useRef)(null),h=(0,o.useMemo)(()=>{if(e.stats){let n=t(2792);return new n}},[]),p=(0,s.useRouter)(),v=p.asPath.match(/#([a-zA-Z0-9\.\/]+)/),[g,f]=(0,o.useState)(null),[x,w]=(0,o.useState)(null);return(0,o.useEffect)(()=>{if(v?w(v[1]):w(l[0].name),u&&d.current)for(d.current.appendChild(u.domElement);u.__controllers.length>0;)u.__controllers[0].remove();h&&m.current&&(h.dom.style.position="absolute",h.showPanel(1),m.current.appendChild(h.dom));let t={active:!0},a=()=>{t.active=!1};try{let r=n.current;if(!r)throw Error("The canvas is not available");let i=e.init({canvas:r,pageState:t,gui:u,stats:h});i instanceof Promise&&i.catch(e=>{console.error(e),f(e)})}catch(s){console.error(s),f(s)}return a},[]),(0,a.jsxs)("main",{children:[(0,a.jsxs)(i(),{children:[(0,a.jsx)("style",{dangerouslySetInnerHTML:{__html:"\n .CodeMirror {\n height: auto !important;\n margin: 1em 0;\n }\n\n .CodeMirror-scroll {\n height: auto !important;\n overflow: visible !important;\n }\n "}}),(0,a.jsx)("title",{children:"".concat(e.name," - WebGPU Samples")}),(0,a.jsx)("meta",{name:"description",content:e.description}),(0,a.jsx)("meta",{httpEquiv:"origin-trial",content:e.originTrial})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)("h1",{children:e.name}),(0,a.jsx)("a",{target:"_blank",rel:"noreferrer",href:"https://github.com/".concat("webgpu/webgpu-samples","/tree/main/").concat(e.filename),children:"See it on Github!"}),(0,a.jsx)("p",{children:e.description}),g?(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)("p",{children:"Something went wrong. Do your browser and device support WebGPU?"}),(0,a.jsx)("p",{children:"".concat(g)})]}):null]}),(0,a.jsxs)("div",{className:c().canvasContainer,children:[(0,a.jsx)("div",{style:{position:"absolute",left:10},ref:m}),(0,a.jsx)("div",{style:{position:"absolute",right:10},ref:d}),(0,a.jsx)("canvas",{ref:n})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)("nav",{className:c().sourceFileNav,ref:r,children:(0,a.jsx)("div",{className:c().sourceFileScrollContainer,onScroll(e){let n=e.currentTarget,t=n.scrollWidth-n.clientWidth-n.scrollLeft;n.scrollLeft>25?r.current.setAttribute("data-left","true"):r.current.setAttribute("data-left","false"),t>25?r.current.setAttribute("data-right","true"):r.current.setAttribute("data-right","false")},children:(0,a.jsx)("ul",{children:l.map((e,n)=>(0,a.jsx)("li",{children:(0,a.jsx)("a",{href:"#".concat(e.name),"data-active":x==e.name,onClick(){w(e.name)},children:e.name})},n))})})}),l.map((e,n)=>(0,a.jsx)(e.Container,{className:c().sourceFileContainer,"data-active":x==e.name},n))]})]})},u=e=>(0,a.jsx)(d,{...e});function m(e,n){if(!e)throw Error(n)}},8565:function(e,n,t){"use strict";var a="src/sample/resizeCanvas/main.ts";t.r(n);var r=t(5671),i=t(1974),s=t(2690),o=t(4057),l=t.n(o);let c=async e=>{let n,t,{canvas:a,pageState:o}=e,c=await navigator.gpu.requestAdapter();(0,r.hu)(c,"requestAdapter returned null");let d=await c.requestDevice();if(!o.active)return;let u=a.getContext("webgpu"),m=navigator.gpu.getPreferredCanvasFormat(),h=window.devicePixelRatio;a.width=a.clientWidth*h,a.height=a.clientHeight*h,u.configure({device:d,format:m,alphaMode:"premultiplied"});let p=d.createRenderPipeline({layout:"auto",vertex:{module:d.createShaderModule({code:i.Z}),entryPoint:"main"},fragment:{module:d.createShaderModule({code:s.Z}),entryPoint:"main",targets:[{format:m}]},primitive:{topology:"triangle-list"},multisample:{count:4}});a.classList.add(l().animatedCanvasSize),requestAnimationFrame(function e(){if(!o.active)return;let r=a.clientWidth*h,i=a.clientHeight*h;(r!==a.width||i!==a.height)&&r&&i&&(void 0!==n&&n.destroy(),a.width=r,a.height=i,t=(n=d.createTexture({size:[a.width,a.height],sampleCount:4,format:m,usage:GPUTextureUsage.RENDER_ATTACHMENT})).createView());let s=d.createCommandEncoder(),l={colorAttachments:[{view:t,resolveTarget:u.getCurrentTexture().createView(),clearValue:{r:.2,g:.2,b:.2,a:1},loadOp:"clear",storeOp:"store"}]},c=s.beginRenderPass(l);c.setPipeline(p),c.draw(3),c.end(),d.queue.submit([s.finish()]),requestAnimationFrame(e)})},d=()=>(0,r.Tl)({name:"Resize Canvas",description:"Shows multisampled rendering a basic triangle on a dynamically sized canvas.",init:c,sources:[{name:a.substring(24),contents:"import { assert, makeSample, SampleInit } from '../../components/SampleLayout';\n\nimport triangleVertWGSL from '../../shaders/triangle.vert.wgsl';\nimport redFragWGSL from '../../shaders/red.frag.wgsl';\n\nimport styles from './animatedCanvasSize.module.css';\n\nconst init: SampleInit = async ({ canvas, pageState }) => {\n const adapter = await navigator.gpu.requestAdapter();\n assert(adapter, 'requestAdapter returned null');\n const device = await adapter.requestDevice();\n\n if (!pageState.active) return;\n const context = canvas.getContext('webgpu') as GPUCanvasContext;\n\n const presentationFormat = navigator.gpu.getPreferredCanvasFormat();\n\n const devicePixelRatio = window.devicePixelRatio;\n canvas.width = canvas.clientWidth * devicePixelRatio;\n canvas.height = canvas.clientHeight * devicePixelRatio;\n\n context.configure({\n device,\n format: presentationFormat,\n alphaMode: 'premultiplied',\n });\n\n const sampleCount = 4;\n\n const pipeline = device.createRenderPipeline({\n layout: 'auto',\n vertex: {\n module: device.createShaderModule({\n code: triangleVertWGSL,\n }),\n entryPoint: 'main',\n },\n fragment: {\n module: device.createShaderModule({\n code: redFragWGSL,\n }),\n entryPoint: 'main',\n targets: [\n {\n format: presentationFormat,\n },\n ],\n },\n primitive: {\n topology: 'triangle-list',\n },\n multisample: {\n count: 4,\n },\n });\n\n let renderTarget: GPUTexture | undefined = undefined;\n let renderTargetView: GPUTextureView;\n\n canvas.classList.add(styles.animatedCanvasSize);\n\n function frame() {\n // Sample is no longer the active page.\n if (!pageState.active) return;\n\n const currentWidth = canvas.clientWidth * devicePixelRatio;\n const currentHeight = canvas.clientHeight * devicePixelRatio;\n\n // The canvas size is animating via CSS.\n // When the size changes, we need to reallocate the render target.\n // We also need to set the physical size of the canvas to match the computed CSS size.\n if (\n (currentWidth !== canvas.width || currentHeight !== canvas.height) &&\n currentWidth &&\n currentHeight\n ) {\n if (renderTarget !== undefined) {\n // Destroy the previous render target\n renderTarget.destroy();\n }\n\n // Setting the canvas width and height will automatically resize the textures returned\n // when calling getCurrentTexture() on the context.\n canvas.width = currentWidth;\n canvas.height = currentHeight;\n\n // Resize the multisampled render target to match the new canvas size.\n renderTarget = device.createTexture({\n size: [canvas.width, canvas.height],\n sampleCount,\n format: presentationFormat,\n usage: GPUTextureUsage.RENDER_ATTACHMENT,\n });\n\n renderTargetView = renderTarget.createView();\n }\n\n const commandEncoder = device.createCommandEncoder();\n\n const renderPassDescriptor: GPURenderPassDescriptor = {\n colorAttachments: [\n {\n view: renderTargetView,\n resolveTarget: context.getCurrentTexture().createView(),\n clearValue: { r: 0.2, g: 0.2, b: 0.2, a: 1.0 },\n loadOp: 'clear',\n storeOp: 'store',\n },\n ],\n };\n\n const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);\n passEncoder.setPipeline(pipeline);\n passEncoder.draw(3);\n passEncoder.end();\n\n device.queue.submit([commandEncoder.finish()]);\n requestAnimationFrame(frame);\n }\n\n requestAnimationFrame(frame);\n};\n\nconst ResizeCanvas: () => JSX.Element = () =>\n makeSample({\n name: 'Resize Canvas',\n description:\n 'Shows multisampled rendering a basic triangle on a dynamically sized canvas.',\n init,\n sources: [\n {\n name: __filename.substring(__dirname.length + 1),\n contents: __SOURCE__,\n },\n {\n name: '../../shaders/triangle.vert.wgsl',\n contents: triangleVertWGSL,\n editable: true,\n },\n {\n name: '../../shaders/red.frag.wgsl',\n contents: redFragWGSL,\n editable: true,\n },\n {\n name: './animatedCanvasSize.module.css',\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n contents: require('!!raw-loader!./animatedCanvasSize.module.css')\n .default,\n },\n ],\n filename: __filename,\n });\n\nexport default ResizeCanvas;\n"},{name:"../../shaders/triangle.vert.wgsl",contents:i.Z,editable:!0},{name:"../../shaders/red.frag.wgsl",contents:s.Z,editable:!0},{name:"./animatedCanvasSize.module.css",contents:t(7751).Z}],filename:a});n.default=d},9147:function(e){e.exports={canvasContainer:"SampleLayout_canvasContainer__zRR_l",sourceFileNav:"SampleLayout_sourceFileNav__ml48P",sourceFileScrollContainer:"SampleLayout_sourceFileScrollContainer__LsNEm",sourceFileContainer:"SampleLayout_sourceFileContainer__3s84x"}},4057:function(e){e.exports={animatedCanvasSize:"animatedCanvasSize_animatedCanvasSize__SMQPJ","animated-size":"animatedCanvasSize_animated-size__fXLtb"}},7751:function(e,n){"use strict";n.Z="@keyframes animated-size {\n 0% {\n width: 10px;\n height: 600px;\n }\n 50% {\n width: 100%;\n height: 600px;\n }\n 100% {\n width: 10px;\n height: 600px;\n }\n}\n\n.animatedCanvasSize {\n animation-duration: 3s;\n animation-iteration-count: infinite;\n animation-name: animated-size;\n animation-timing-function: ease;\n}"},2690:function(e,n){"use strict";n.Z="@fragment\nfn main() -> @location(0) vec4 {\n return vec4(1.0, 0.0, 0.0, 1.0);\n}\n"},1974:function(e,n){"use strict";n.Z="@vertex\nfn main(\n @builtin(vertex_index) VertexIndex : u32\n) -> @builtin(position) vec4 {\n var pos = array, 3>(\n vec2(0.0, 0.5),\n vec2(-0.5, -0.5),\n vec2(0.5, -0.5)\n );\n\n return vec4(pos[VertexIndex], 0.0, 1.0);\n}\n"}}]);
\ No newline at end of file
diff --git a/_next/static/chunks/588.7bddbe0e402a2c1b.js b/_next/static/chunks/588.7bddbe0e402a2c1b.js
deleted file mode 100644
index 80082564..00000000
--- a/_next/static/chunks/588.7bddbe0e402a2c1b.js
+++ /dev/null
@@ -1 +0,0 @@
-(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[588],{5671:function(e,n,t){"use strict";t.d(n,{Tl:function(){return l},hu:function(){return p}});var r=t(5893),a=t(9008),o=t.n(a),i=t(1163),s=t(7294),d=t(9147),c=t.n(d);t(7319);let u=e=>{let n=(0,s.useRef)(null),a=(0,s.useRef)(null),d=(0,s.useMemo)(()=>e.sources.map(e=>{let{name:n,contents:a}=e;return{name:n,...function(e){let n;let a=null;{a=document.createElement("div");let o=t(4631);n=o(a,{lineNumbers:!0,lineWrapping:!0,theme:"monokai",readOnly:!0})}return{Container:function(t){return(0,r.jsx)("div",{...t,children:(0,r.jsx)("div",{ref(t){a&&t&&(t.appendChild(a),n.setOption("value",e))}})})}}}(a)}}),e.sources),u=(0,s.useRef)(null),l=(0,s.useMemo)(()=>{if(e.gui){let n=t(4376),r=new n.GUI({autoPlace:!1});return r.domElement.style.position="relative",r.domElement.style.zIndex="1000",r}},[]),p=(0,s.useRef)(null),f=(0,s.useMemo)(()=>{if(e.stats){let n=t(2792);return new n}},[]),m=(0,i.useRouter)(),h=m.asPath.match(/#([a-zA-Z0-9\.\/]+)/),[P,v]=(0,s.useState)(null),[g,x]=(0,s.useState)(null);return(0,s.useEffect)(()=>{if(h?x(h[1]):x(d[0].name),l&&u.current)for(u.current.appendChild(l.domElement);l.__controllers.length>0;)l.__controllers[0].remove();f&&p.current&&(f.dom.style.position="absolute",f.showPanel(1),p.current.appendChild(f.dom));let t={active:!0},r=()=>{t.active=!1};try{let a=n.current;if(!a)throw Error("The canvas is not available");let o=e.init({canvas:a,pageState:t,gui:l,stats:f});o instanceof Promise&&o.catch(e=>{console.error(e),v(e)})}catch(i){console.error(i),v(i)}return r},[]),(0,r.jsxs)("main",{children:[(0,r.jsxs)(o(),{children:[(0,r.jsx)("style",{dangerouslySetInnerHTML:{__html:"\n .CodeMirror {\n height: auto !important;\n margin: 1em 0;\n }\n\n .CodeMirror-scroll {\n height: auto !important;\n overflow: visible !important;\n }\n "}}),(0,r.jsx)("title",{children:"".concat(e.name," - WebGPU Samples")}),(0,r.jsx)("meta",{name:"description",content:e.description}),(0,r.jsx)("meta",{httpEquiv:"origin-trial",content:e.originTrial})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("h1",{children:e.name}),(0,r.jsx)("a",{target:"_blank",rel:"noreferrer",href:"https://github.com/".concat("webgpu/webgpu-samples","/tree/main/").concat(e.filename),children:"See it on Github!"}),(0,r.jsx)("p",{children:e.description}),P?(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("p",{children:"Something went wrong. Do your browser and device support WebGPU?"}),(0,r.jsx)("p",{children:"".concat(P)})]}):null]}),(0,r.jsxs)("div",{className:c().canvasContainer,children:[(0,r.jsx)("div",{style:{position:"absolute",left:10},ref:p}),(0,r.jsx)("div",{style:{position:"absolute",right:10},ref:u}),(0,r.jsx)("canvas",{ref:n})]}),(0,r.jsxs)("div",{children:[(0,r.jsx)("nav",{className:c().sourceFileNav,ref:a,children:(0,r.jsx)("div",{className:c().sourceFileScrollContainer,onScroll(e){let n=e.currentTarget,t=n.scrollWidth-n.clientWidth-n.scrollLeft;n.scrollLeft>25?a.current.setAttribute("data-left","true"):a.current.setAttribute("data-left","false"),t>25?a.current.setAttribute("data-right","true"):a.current.setAttribute("data-right","false")},children:(0,r.jsx)("ul",{children:d.map((e,n)=>(0,r.jsx)("li",{children:(0,r.jsx)("a",{href:"#".concat(e.name),"data-active":g==e.name,onClick(){x(e.name)},children:e.name})},n))})})}),d.map((e,n)=>(0,r.jsx)(e.Container,{className:c().sourceFileContainer,"data-active":g==e.name},n))]})]})},l=e=>(0,r.jsx)(u,{...e});function p(e,n){if(!e)throw Error(n)}},7502:function(e,n,t){"use strict";t.r(n),t.d(n,{default:function(){return b},geometryVertexArray:function(){return h}});var r,a,o=t(5671),i=t(6416),s="struct Uniforms {\n modelMatrix : array, 5>,\n}\nstruct Camera {\n viewProjectionMatrix : mat4x4,\n}\n\n@binding(0) @group(0) var uniforms : Uniforms;\n@binding(1) @group(0) var camera : Camera;\n\nstruct VertexOutput {\n @builtin(position) Position : vec4,\n @location(0) fragColor : vec4,\n}\n\n@vertex\nfn main(\n @builtin(instance_index) instanceIdx : u32,\n @location(0) position : vec4,\n @location(1) color : vec4\n) -> VertexOutput {\n var output : VertexOutput;\n output.Position = camera.viewProjectionMatrix * uniforms.modelMatrix[instanceIdx] * position;\n output.fragColor = color;\n return output;\n}",d="@fragment\nfn main(\n @location(0) fragColor: vec4\n) -> @location(0) vec4 {\n return fragColor;\n}\n",c="struct Uniforms {\n modelMatrix : array, 5>,\n}\nstruct Camera {\n viewProjectionMatrix : mat4x4,\n}\n\n@binding(0) @group(0) var uniforms : Uniforms;\n@binding(1) @group(0) var camera : Camera;\n\n@vertex\nfn main(\n @builtin(instance_index) instanceIdx : u32,\n @location(0) position : vec4\n) -> @builtin(position) vec4 {\n return camera.viewProjectionMatrix * uniforms.modelMatrix[instanceIdx] * position;\n}\n",u="@vertex\nfn main(\n @builtin(vertex_index) VertexIndex : u32\n) -> @builtin(position) vec4 {\n const pos = array(\n vec2(-1.0, -1.0), vec2(1.0, -1.0), vec2(-1.0, 1.0),\n vec2(-1.0, 1.0), vec2(1.0, -1.0), vec2(1.0, 1.0),\n );\n\n return vec4(pos[VertexIndex], 0.0, 1.0);\n}\n",l="@group(0) @binding(0) var depthTexture: texture_depth_2d;\n\n@fragment\nfn main(\n @builtin(position) coord : vec4\n) -> @location(0) vec4 {\n let depthValue = textureLoad(depthTexture, vec2(floor(coord.xy)), 0);\n return vec4(depthValue, depthValue, depthValue, 1.0);\n}\n",p="struct Uniforms {\n modelMatrix : array, 5>,\n}\nstruct Camera {\n viewProjectionMatrix : mat4x4,\n}\n\n@binding(0) @group(0) var uniforms : Uniforms;\n@binding(1) @group(0) var camera : Camera;\n\nstruct VertexOutput {\n @builtin(position) Position : vec4,\n @location(0) clipPos : vec4,\n}\n\n@vertex\nfn main(\n @builtin(instance_index) instanceIdx : u32,\n @location(0) position : vec4