{"_id":"@codyjasonbennett/fourwastaken4","name":"@codyjasonbennett/fourwastaken4","dist-tags":{"latest":"0.2.2"},"versions":{"0.2.2":{"name":"@codyjasonbennett/fourwastaken4","version":"0.2.2","description":"Minimal three.js alternative.","keywords":["3d","graphics","compute","webgl","webgpu","webxr","shaders","three","minimal"],"author":{"name":"Cody Bennett","url":"https://github.com/CodyJasonBennett"},"homepage":"https://github.com/CodyJasonBennett/four","repository":{"type":"git","url":"https://github.com/CodyJasonBennett/four"},"license":"MIT","type":"module","main":"./dist/index.js","exports":"./dist/index.js","sideEffects":false,"devDependencies":{"@types/node":"^20.4.2","typescript":"^5.1.6","vite":"^4.4.3"},"dependencies":{"@webgpu/types":"^0.1.34"},"scripts":{"dev":"vite","build":"vite build","lint":"tsc"},"licenseText":"MIT License\n\nCopyright (c) 2021-2023 Cody Bennett\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n","_id":"@codyjasonbennett/fourwastaken4@0.2.2","dist":{"shasum":"bd8476565353387c0b14323eaa20e743b3e396a0","integrity":"sha512-nffsmw1imuE6W79M7h1FrQC2hrezmJq7UQuUjpVWKAM/FQc98rYh75LEk3JUDoQOtPIvkvBmVRtwHBXzOPcVyA==","tarball":"https://registry.npmjs.org/@codyjasonbennett/fourwastaken4/-/fourwastaken4-0.2.2.tgz","fileCount":27,"unpackedSize":169274,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIDtfWUhMXtVtJAli4vBkTIInW70C1uTto2JEXp7mVpq5AiEArLq0wuHLrnREEDl+7f5ycv86y7Z+nlD5DaA0MBx6zLQ="}]},"_npmUser":{"name":"codyjasonbennett","email":"hi@codyb.co"},"directories":{},"maintainers":[{"name":"codyjasonbennett","email":"hi@codyb.co"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/fourwastaken4_0.2.2_1692325295215_0.4272673070227142"},"_hasShrinkwrap":false}},"time":{"created":"2023-08-18T02:21:35.126Z","0.2.2":"2023-08-18T02:21:35.613Z","modified":"2023-08-18T02:21:35.848Z"},"maintainers":[{"name":"codyjasonbennett","email":"hi@codyb.co"}],"description":"Minimal three.js alternative.","homepage":"https://github.com/CodyJasonBennett/four","keywords":["3d","graphics","compute","webgl","webgpu","webxr","shaders","three","minimal"],"repository":{"type":"git","url":"https://github.com/CodyJasonBennett/four"},"author":{"name":"Cody Bennett","url":"https://github.com/CodyJasonBennett"},"license":"MIT","readme":"[![Size](https://img.shields.io/bundlephobia/minzip/fourwastaken?label=gzip&style=flat&colorA=000000&colorB=000000)](https://bundlephobia.com/package/fourwastaken)\n[![Version](https://img.shields.io/npm/v/fourwastaken?style=flat&colorA=000000&colorB=000000)](https://npmjs.com/package/fourwastaken)\n[![Downloads](https://img.shields.io/npm/dt/fourwastaken.svg?style=flat&colorA=000000&colorB=000000)](https://npmjs.com/package/fourwastaken)\n\n# four\n\nMinimal three.js alternative.\n\n## Table of Contents\n\n- [Installation](#installation)\n- [Getting Started](#getting-started)\n- [Object3D](#object3d)\n  - [Vector3](#vector3)\n  - [Quaternion](#quaternion)\n  - [Matrix4](#matrix4)\n- [Mesh](#mesh)\n- [Geometry](#geometry)\n  - [Attribute](#attribute)\n- [Material](#material)\n  - [Uniforms](#uniforms)\n  - [Blending](#blending)\n- [Texture](#texture)\n  - [Sampler](#sampler)\n- [RenderTarget](#rendertarget)\n- [Camera](#camera)\n  - [Frustum](#frustum)\n  - [PerspectiveCamera](#perspectivecamera)\n  - [OrthographicCamera](#orthographiccamera)\n- [Rendering](#rendering)\n  - [Instancing](#instancing)\n  - [Compute](#compute)\n\n## Installation\n\nTo install, use your preferred package manager:\n\n```bash\nnpm install four@npm:fourwastaken\nyarn add four@npm:fourwastaken\npnpm add four@npm:fourwastaken\n```\n\nThis will install `fourwastaken` as `four`; both will be available.\n\n```ts\nimport * as FOUR from 'four'\n```\n\n> **Note**: Vite may have issues consuming WebGPU code which relies on top-level await via ESM. This is well supported since 2021, but you may need to use [vite-plugin-top-level-await](https://github.com/Menci/vite-plugin-top-level-await) to use this library with `vite.optimizeDeps`.\n\n## Getting Started\n\nThe following creates a renderer, camera, and renders a red cube:\n\n<details>\n\n<summary>Show WebGL example</summary>\n\n```ts\nimport { WebGLRenderer, PerspectiveCamera, Geometry, Material, Mesh } from 'four'\n\nconst renderer = new WebGLRenderer()\nrenderer.setSize(window.innerWidth, window.innerHeight)\ndocument.body.appendChild(renderer.canvas)\n\nconst camera = new PerspectiveCamera(45, window.innerWidth / window.innerHeight)\ncamera.position.z = 5\n\nconst geometry = new Geometry({\n  position: {\n    size: 3,\n    data: new Float32Array([\n      0.5, 0.5, 0.5, 0.5, -0.5, 0.5, 0.5, 0.5, -0.5, 0.5, -0.5, 0.5, 0.5, -0.5, -0.5, 0.5, 0.5, -0.5, -0.5, 0.5, -0.5,\n      -0.5, -0.5, -0.5, -0.5, 0.5, 0.5, -0.5, -0.5, -0.5, -0.5, -0.5, 0.5, -0.5, 0.5, 0.5, -0.5, 0.5, -0.5, -0.5, 0.5,\n      0.5, 0.5, 0.5, -0.5, -0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, -0.5, -0.5, -0.5, 0.5, -0.5, -0.5, -0.5, 0.5, -0.5,\n      0.5, -0.5, -0.5, -0.5, 0.5, -0.5, -0.5, 0.5, -0.5, 0.5, -0.5, 0.5, 0.5, -0.5, -0.5, 0.5, 0.5, 0.5, 0.5, -0.5,\n      -0.5, 0.5, 0.5, -0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, -0.5, 0.5, -0.5, -0.5, -0.5, 0.5, -0.5, 0.5, -0.5, -0.5, -0.5,\n      -0.5, -0.5, -0.5, 0.5, -0.5,\n    ]),\n  },\n})\nconst material = new Material({\n  vertex: /* glsl */ `#version 300 es\n    uniform mat4 projectionMatrix;\n    uniform mat4 modelViewMatrix;\n    in vec3 position;\n    void main() {\n      gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1);\n    }\n  `,\n  fragment: /* glsl */ `#version 300 es\n    out lowp vec4 color;\n    void main() {\n      color = vec4(1, 0, 0, 1);\n    }\n  `,\n})\nconst mesh = new Mesh(geometry, material)\n\nrenderer.render(mesh, camera)\n```\n\n</details>\n\n<details>\n\n<summary>Show WebGPU example</summary>\n\n```ts\nimport { WebGPURenderer, PerspectiveCamera, Geometry, Material, Mesh } from 'four'\n\nconst renderer = new WebGPURenderer()\nrenderer.setSize(window.innerWidth, window.innerHeight)\ndocument.body.appendChild(renderer.canvas)\n\nconst camera = new PerspectiveCamera(45, window.innerWidth / window.innerHeight)\ncamera.position.z = 5\n\nconst geometry = new Geometry({\n  position: {\n    size: 3,\n    data: new Float32Array([\n      0.5, 0.5, 0.5, 0.5, -0.5, 0.5, 0.5, 0.5, -0.5, 0.5, -0.5, 0.5, 0.5, -0.5, -0.5, 0.5, 0.5, -0.5, -0.5, 0.5, -0.5,\n      -0.5, -0.5, -0.5, -0.5, 0.5, 0.5, -0.5, -0.5, -0.5, -0.5, -0.5, 0.5, -0.5, 0.5, 0.5, -0.5, 0.5, -0.5, -0.5, 0.5,\n      0.5, 0.5, 0.5, -0.5, -0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, -0.5, -0.5, -0.5, 0.5, -0.5, -0.5, -0.5, 0.5, -0.5,\n      0.5, -0.5, -0.5, -0.5, 0.5, -0.5, -0.5, 0.5, -0.5, 0.5, -0.5, 0.5, 0.5, -0.5, -0.5, 0.5, 0.5, 0.5, 0.5, -0.5,\n      -0.5, 0.5, 0.5, -0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, -0.5, 0.5, -0.5, -0.5, -0.5, 0.5, -0.5, 0.5, -0.5, -0.5, -0.5,\n      -0.5, -0.5, -0.5, 0.5, -0.5,\n    ]),\n  },\n})\nconst material = new Material({\n  vertex: /* wgsl */ `\n    struct Uniforms {\n      projectionMatrix: mat4x4<f32>,\n      modelViewMatrix: mat4x4<f32>,\n    };\n    @group(0) @binding(0) var<uniform> uniforms: Uniforms;\n\n    @vertex\n    fn main(@location(0) position: vec3<f32>) -> @builtin(position) vec4<f32> {\n      return uniforms.projectionMatrix * uniforms.modelViewMatrix * vec4(position, 1);\n    }\n  `,\n  fragment: /* wgsl */ `\n    @fragment\n    fn main() -> @location(0) vec4<f32> {\n      return vec4(1, 0, 0, 1);\n    }\n  `,\n})\nconst mesh = new Mesh(geometry, material)\n\nrenderer.render(mesh, camera)\n```\n\n</details>\n\n## Object3D\n\nAn `Object3D` represents a basic 3D object and its transforms. Objects are linked via their `parent` and `children` properties, constructing a rooted scene-graph.\n\n```ts\nconst object = new Object3D()\nobject.add(new Object3D(), new Object3D())\nobject.traverse((node) => {\n  if (node !== object) object.remove(node)\n  if (!node.visible) return true\n})\n```\n\n### Vector3\n\nA `Vector3` represents a three-dimensional (x, y, z) vector and describes local position in `Object3D.position`. It is also used to control local scale in `Object3D.scale`.\n\n```ts\nobject.position.set(1, 2, 3)\nobject.position.x = 4\nobject.position[0] = 5\n```\n\n### Quaternion\n\nA `Quaternion` represents a four-dimensional vector with a rotation axis (x, y, z) and magnitude (w) and describes local orientation in `Object3D.quaternion`.\n\n```ts\nobject.quaternion.set(0, 0, 0, 1)\nobject.quaternion.fromEuler(Math.PI / 2, 0, 0)\nobject.quaternion.x *= -1\nobject.quaternion[0] *= -1\n```\n\n### Matrix4\n\nA `Matrix4` represents a 4x4 transformation matrix and describes world transforms in `Object3D.matrix`.\n\n```ts\nobject.matrix.set(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 2, 3, 1)\nobject.matrix[12] = 4\nobject.matrix.invert()\nobject.matrix.identity()\n```\n\n## Mesh\n\nA `Mesh` contains a `Geometry` and `Material` to describe visual behavior, and can be manipulated in 3D as an `Object3D`.\n\n```ts\nconst geometry = new Geometry({ ... })\nconst material = new Material({ ... })\nconst mesh = new Mesh(geometry, material)\n```\n\n## Geometry\n\nA `Geometry` contains an `Attribute` list of vertex or storage buffer data, with a GPU buffer allocated for each `Attribute`.\n\n```ts\nconst geometry = new Geometry({\n  position: { size: 2, data: new Float32Array([-1, -1, 3, -1, -1, 3]) },\n  uv: { size: 2, data: new Float32Array([0, 0, 2, 0, 0, 2]) },\n  index: { size: 1, data: new Uint16Array([0, 1, 2]) },\n})\n```\n\nA `DrawRange` can also be configured to control rendering without submitting vertex data. This is useful for GPU-computed geometry or vertex pulling, as demonstrated in the fullscreen demos.\n\n```ts\nconst geometry = new Geometry()\ngeometry.drawRange = { start: 0, count: 3 } // renders 3 vertices at starting index 0\n```\n\n### Attribute\n\nAn `Attribute` defines a data view, its per-vertex size, and an optional per-instance divisor (see [instancing](#instancing)).\n\n```ts\n// Creates a 4x4 instance matrix for 2 instances\n{\n  data: new Float32Array([\n    1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1,\n    1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1,\n  ]),\n  size: 16,\n  divisor: 1,\n}\n```\n\n## Material\n\nA `Material` describes a program or shader interface for rasterization and compute (see [compute](#compute)), defining a `vertex` and `fragment` or `compute` shader, respectively.\n\n<details>\n\n<summary>Show WebGL example</summary>\n\n```ts\nconst material = new Material({\n  vertex: /* glsl */ `#version 300 es\n    uniform mat4 projectionMatrix;\n    uniform mat4 modelViewMatrix;\n    in vec3 position;\n    void main() {\n      gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1);\n    }\n  `,\n  fragment: /* glsl */ `#version 300 es\n    out lowp vec4 color;\n    void main() {\n      color = vec4(1, 0, 0, 1);\n    }\n  `,\n  side: 'front',\n  transparent: false,\n  depthTest: true,\n  depthWrite: true,\n})\n```\n\n</details>\n\n<details>\n\n<summary>Show WebGPU example</summary>\n\n```ts\nconst material = new Material({\n  vertex: /* wgsl */ `\n    struct Uniforms {\n      projectionMatrix: mat4x4<f32>,\n      modelViewMatrix: mat4x4<f32>,\n    };\n    @group(0) @binding(0) var<uniform> uniforms: Uniforms;\n\n    @vertex\n    fn main(@location(0) position: vec3<f32>) -> @builtin(position) vec4<f32> {\n      return uniforms.projectionMatrix * uniforms.modelViewMatrix * vec4(position, 1);\n    }\n  `,\n  fragment: /* wgsl */ `\n    @fragment\n    fn main() -> @location(0) vec4<f32> {\n      return vec4(1, 0, 0, 1);\n    }\n  `,\n  side: 'front',\n  transparent: false,\n  depthTest: true,\n  depthWrite: true,\n})\n```\n\n</details>\n\n### Uniforms\n\nThe following uniforms are built-in and will be automatically populated when specified:\n\n| Type     | Name             | Description                                        | Conversion                 |\n| -------- | ---------------- | -------------------------------------------------- | -------------------------- |\n| `mat4x4` | modelMatrix      | world-space mesh transform                         | local space => world space |\n| `mat4x4` | projectionMatrix | clip-space camera projection                       | view space => clip space   |\n| `mat4x4` | viewMatrix       | inverse camera transform                           | world space => view space  |\n| `mat4x4` | modelViewMatrix  | premultiplied model-view transform                 | local space => view space  |\n| `mat4x4` | normalMatrix     | isotropic inverse model-view or \"normal\" transform | local space => view space  |\n\nIn WebGPU, uniforms are bound to a single uniform buffer, preceded by storage buffers, and followed by sampler-texture for texture uniforms.\n\n```wgsl\n// Storage buffers\n@group(0) @binding(0)\nvar<storage, read_write> data: array<vec2<f32>>;\n\n// Uniform buffer\nstruct Uniforms {\n  time: f32,\n};\n@group(0) @binding(1) var<uniform> uniforms: Uniforms;\n\n// Texture bindings\n@group(0) @binding(2) var sample: sampler;\n@group(0) @binding(3) var color: texture_2d<f32>;\n\n@group(0) @binding(4) var sample_2: sampler;\n@group(0) @binding(5) var color_2: texture_2d<f32>;\n```\n\n### Blending\n\nBy default, opaque meshes do not blend but replace values, and transparent meshes alpha blend by the following blend equation:\n\n```ts\nmaterial.blending = {\n  color: {\n    operation: 'add',\n    srcFactor: 'src-alpha',\n    dstFactor: 'one-minus-src-alpha',\n  },\n  alpha: {\n    operation: 'add',\n    srcFactor: 'one',\n    dstFactor: 'one-minus-src-alpha',\n  },\n}\n```\n\nThis gets applied to the final fragment color as `src * srcFactor + dst * dstFactor`, assuming a premultiplied alpha.\n\nCustom blending can be used for postprocessing and various VFX. The following are the most common configurations:\n\n| Blend Mode     | BlendOperation     | BlendFactor (src)     | BlendFactor (dst) |\n| -------------- | ------------------ | --------------------- | ----------------- |\n| Additive       | `add`              | `src-alpha`           | `one`             |\n| Subtractive    | `reverse-subtract` | `src-alpha`           | `one`             |\n| Multiply       | `add`              | `dst-color`           | `zero`            |\n| Screen         | `add`              | `one-minus-src-color` | `one`             |\n| Maximize       | `max`              | `src-alpha`           | `dst-alpha`       |\n| Custom         | `add`              | `one`                 | `one`             |\n| Local Additive | `add`              | `dst-alpha`           | `one`             |\n| Disabled       | `add`              | `one`                 | `zero`            |\n\n## Texture\n\nA `Texture` transports or stores image or video data to the GPU as well as data like normals or depth.\n\n```ts\nconst pixel = new Uint8ClampedArray([76, 51, 128, 255])\nconst image = await createImageBitmap(new ImageData(pixel, 1, 1))\nconst texture = new Texture(image)\n```\n\n### Sampler\n\nA `Sampler` configures texel filtering and transforms for a texture, and can be used to sample a texture multiple times with different configurations in a shader.\n\n```ts\nconst sampler = new Sampler({\n  magFilter: 'nearest',\n  minFilter: 'nearest',\n  wrapS: 'clamp',\n  wrapT: 'clamp',\n  anisotropy: 1,\n})\ntexture.sampler = sampler\n```\n\n## RenderTarget\n\nA `RenderTarget` constructs a frame buffer object which can be drawn to, similar to the canvas itself. Unlike the canvas, render targets can have multiple attachments or texture channels, configurable as the third argument `count`, enabling efficient use of techniques like deferred rendering and postprocessing.\n\n```ts\n// Create render target with 4 channels\nconst width = window.innerWidth\nconst height = window.innerHeight\nconst count = 4\nconst renderTarget = new RenderTarget(width, height, count)\n\n// Resize with page\nwindow.addEventListener('resize', () => {\n  const width = window.innerWidth\n  const height = window.innerHeight\n  renderTarget.setSize(width, height)\n})\n\n// Bind and render to render target\nrenderer.setRenderTarget(renderTarget)\nrenderer.render(scene, camera)\n\n// Unbind to canvas\nrenderer.setRenderTarget(null)\n```\n\n## Camera\n\nA `Camera` contains matrices and a frustum for projection transforms and queries. The type of projection is defined by `Camera.projectionMatrix`.\n\n### Frustum\n\nA `Frustum` contains clipping planes used for frustum culling and queries, set from a projectionViewMatrix.\n\n```ts\ncamera.frustum.fromMatrix4(camera.projectionViewMatrix)\nif (camera.frustum.contains(mesh)) {\n  // ...\n}\n```\n\n### PerspectiveCamera\n\nA `PerspectiveCamera` calculates a perspective or non-linear `projectionMatrix`, where objects appear smaller by distance.\n\n```ts\nconst fov = 75\nconst aspect = canvas.width / canvas.height\nconst near = 0.1\nconst far = 1000\nconst camera = new PerspectiveCamera(fov, aspect, near, far)\n```\n\n### OrthographicCamera\n\nAn `OrthographicCamera` calculates an orthographic or linear `projectionMatrix`, where objects are unaffected by distance.\n\n```ts\nconst near = 0.1\nconst far = 1000\nconst left = -(canvas.width / 2)\nconst right = canvas.width / 2\nconst bottom = -(canvas.height / 2)\nconst top = canvas.height / 2\nconst camera = new OrthographicCamera(near, far, left, right, bottom, top)\n```\n\n## Rendering\n\nFour supports WebGL 2 and WebGPU with `WebGLRenderer` and `WebGPURenderer`, respectively, and implements a shared API for rendering and compute.\n\n```ts\nconst renderer = new WebGLRenderer()\nrenderer.setSize(window.innerWidth, window.innerHeight)\ndocument.body.appendChild(renderer.canvas)\n\n//\n\nconst renderer = new WebGPURenderer()\nrenderer.setSize(window.innerWidth, window.innerHeight)\ndocument.body.appendChild(renderer.canvas)\n```\n\n### Instancing\n\nFour instances by default, which better aligns with WebGPU. Instanced rendering rasterizes multiple vertex primitives with the same shader interface to render multiple meshes at the cost of one.\n\nYou can specify the number of instances to render with `Mesh.instances` and add variance or control each instance with `Attribute.divisor` to specify a per-instance divisor. A divisor of one will be used by a single instance, and a divisor greater than one will be used by multiple instances.\n\n> **Note**: Attributes can only allocate primitive types in WebGPU ([gpuweb/gpuweb#1652](https://github.com/gpuweb/gpuweb/issues/1652)), so you must allocate and index storage or uniform buffers via the `instance_index` built-in for complex types like matrices.\n\n<details>\n\n<summary>Show WebGL example</summary>\n\n```ts\nconst geometry = new Geometry({\n  position: { size: 3, data: new Float32Array([...]) },\n  instanceMatrix: { divisor: 1, size: 16, data: new Float32Array([...]) }\n})\n\nconst material = new Material({\n  vertex: /* glsl */`#version 300 es\n    uniform mat4 projectionMatrix;\n    uniform mat4 modelViewMatrix;\n    in mat4 instanceMatrix;\n    in vec3 position;\n    void main() {\n      gl_Position = projectionMatrix * modelViewMatrix * instanceMatrix * vec4(position, 1);\n    }\n  `,\n  fragment: /* glsl */`#version 300 es\n    out lowp vec4 color;\n    void main() {\n      color = vec4(1, 0, 0, 1);\n    }\n  `\n})\n\nconst mesh = new Mesh(geometry, material)\nmesh.instances = 2\n```\n\n</details>\n\n<details>\n\n<summary>Show WebGPU example</summary>\n\n```ts\nconst geometry = new Geometry({\n  position: { size: 3, data: new Float32Array([...]) },\n})\n\nconst material = new Material({\n  uniforms: {\n    instanceMatrix: new Float32Array([...]),\n  },\n  vertex: /* wgsl */ `\n    struct Uniforms {\n      projectionMatrix: mat4x4<f32>,\n      modelViewMatrix: mat4x4<f32>,\n      instanceMatrix: array<mat4x4<f32>, 2>,\n    };\n    @group(0) @binding(0) var<uniform> uniforms: Uniforms;\n\n    @vertex\n    fn main(\n      @builtin(instance_index) instanceID: u32,\n      @location(0) position: vec3<f32>,\n    ) -> @builtin(position) vec4<f32> {\n      return uniforms.projectionMatrix * uniforms.modelViewMatrix * uniforms.instanceMatrix[instanceID] * vec4(position, 1.0);\n    }\n  `,\n  fragment: /* wgsl */ `\n    @fragment\n    fn main() -> @location(0) vec4<f32> {\n      return vec4(1, 0, 0, 1);\n    }\n  `,\n})\n\nconst mesh = new Mesh(geometry, material)\nmesh.instances = 2\n```\n\n</details>\n\n### Compute\n\nFour supports compute for both WebGL and WebGPU via transform feedback and compute pipelines, respectively. This can be used in lieu of pixel shaders to write directly to buffer storage without any CPU reads/writes to textures. Useful for high precision compute or large simulations where VRAM is limited.\n\nThe following populates geometry buffers on the GPU, computing a fullscreen triangle geometry:\n\n<details>\n  <summary>Show WebGL example</summary>\n\n```ts\nconst geometry = new Geometry({\n  position: { size: 2, data: new Float32Array(6) },\n  uv: { size: 2, data: new Float32Array(6) },\n})\nconst computeMaterial = new Material({\n  compute: /* glsl */ `#version 300 es\n    out vec2 position;\n    out vec2 uv;\n\n    const vec2 vertex[3] = vec2[](vec2(-1), vec2(3, -1), vec2(-1, 3));\n\n    void main() {\n      position = vertex[gl_VertexID];\n      uv = abs(position) - 1.0;\n    }\n  `,\n})\nconst mesh = new Mesh(geometry, computeMaterial)\n\nrenderer.compute(mesh)\n```\n\n</details>\n\n<details>\n  <summary>Show WebGPU example</summary>\n\n```ts\nconst geometry = new Geometry({\n  position: { size: 2, data: new Float32Array(6) },\n  uv: { size: 2, data: new Float32Array(6) },\n})\nconst computeMaterial = new Material({\n  compute: /* wgsl */ `\n    @group(0) @binding(0)\n    var<storage, read_write> position: array<vec2<f32>>;\n\n    @group(0) @binding(1)\n    var<storage, read_write> uv: array<vec2<f32>>;\n\n    const vertex = array<vec2<f32>, 3>(vec2(-1), vec2(3, -1), vec2(-1, 3));\n\n    @compute @workgroup_size(64)\n    fn main(@builtin(local_invocation_index) i: u32) {\n      position[i] = vertex[i];\n      uv[i] = abs(vertex[i]) - 1.0;\n    }\n  `,\n})\nconst mesh = new Mesh(geometry, computeMaterial)\n\nrenderer.compute(mesh)\n```\n\n</details>\n","readmeFilename":"README.md"}