Skip to content

@carrot/engine-textures ​

ts

GPU texture abstractions for WebGL2 - image textures, raw data textures, 3D volumes, cubemaps, render targets, and procedural texture builders.

Installation ​

bash
npm install @carrot/engine-textures

Architecture / How It Works ​

Texture hierarchy ​

All texture types extend the abstract Texture base class, which manages the WebGL handle lifecycle:

Texture (abstract)
├── Texture2D       - loaded from AssetImage (PNG, JPG, etc.)
├── DataTexture     - loaded from raw typed arrays (Float32Array, Uint8Array, etc.)
├── Texture3D       - volumetric data (TEXTURE_3D)
├── TextureCube     - 6-face cubemap (TEXTURE_CUBE_MAP)
└── RenderTexture   - framebuffer-backed render target

The base class handles:

  • Handle creation - createHandle() allocates the GL texture and applies filter/wrap parameters from the TextureDescriptor.
  • Bind/unbind - binds to a numbered texture unit for shader sampling.
  • Dispose - deletes the GPU handle.
  • Mipmap generation - applyMipmaps() called after upload if descriptor.generateMipmaps is true.

Each subclass implements upload() with its specific data source.

TextureDescriptor ​

Immutable configuration object controlling format, filtering, wrapping, and mipmap generation. Three presets are provided: defaultTextureDescriptor, defaultRenderTextureDescriptor, and pixelArtTextureDescriptor.

TextureFormat ​

Maps to WebGL2 internalFormat + format + type combinations. Covers standard 8-bit colour, 16-bit and 32-bit float (for HDR, deferred, volumetric), and depth/stencil formats.

Procedural builders ​

TextureBuilder2D and TextureBuilder3D provide a fluent API for composing procedural textures from noise functions, curves, and blend operations. They output DataTexture and Texture3D respectively, auto-uploaded as R32F.

Noise helpers ​

noiseTexture2D and noiseTexture3D are convenience factories that take a noise function and produce an uploaded R32F texture in one call.

Dependencies ​

PackageUsed For
@carrot/assetsAssetImage type used by Texture2D
@carrot/mathsNoiseFn2, NoiseFn3 types used by noise texture factories

Build ​

bash
npm run build   # runs tsc

Usage Guide ​

GPU texture abstractions for WebGL2 - load images, upload raw data, build procedural textures, render to texture.

Import ​

ts
import {
  Texture2D, DataTexture, Texture3D, TextureCube, RenderTexture,
  TextureFormat, TextureFilter, TextureWrap,
  TextureBuilder2D, TextureBuilder3D,
  noiseTexture2D, noiseTexture3D,
  defaultTextureDescriptor, pixelArtTextureDescriptor,
} from '@carrot/engine-textures';

Common Patterns ​

1. Loading a 2D image texture ​

ts
const tex = new Texture2D(gl, assetImage, {
  format: TextureFormat.RGBA8,
  minFilter: TextureFilter.LinearMipmapLinear,
  generateMipmaps: true,
});
tex.upload();
tex.bind(0); // bind to texture unit 0

2. Pixel-art texture (nearest filtering) ​

ts
import { pixelArtTextureDescriptor } from '@carrot/engine-textures';

const sprite = new Texture2D(gl, spriteImage, pixelArtTextureDescriptor);
sprite.upload();

3. Raw data texture (noise, LUT, SDF) ​

ts
const data = new Float32Array(256 * 256);
// ... fill with data ...

const tex = new DataTexture(gl, 256, 256, data, {
  format: TextureFormat.R32F,
});
tex.upload();

4. Updating a data texture ​

ts
const newData = new Float32Array(256 * 256);
tex.setData(newData);  // marks as not uploaded
tex.upload();          // re-uploads to GPU

5. 3D volumetric texture ​

ts
const volume = new Float32Array(64 * 64 * 64);
// ... fill with density data ...

const tex = new Texture3D(gl, 64, 64, 64, volume, {
  format: TextureFormat.R32F,
});
tex.upload();

6. Cubemap texture ​

ts
import { TextureCube, CubeFace } from '@carrot/engine-textures';

const cube = new TextureCube(gl, 512);
cube.setFace(CubeFace.PositiveX, rightImage);
cube.setFace(CubeFace.NegativeX, leftImage);
cube.setFace(CubeFace.PositiveY, topImage);
cube.setFace(CubeFace.NegativeY, bottomImage);
cube.setFace(CubeFace.PositiveZ, frontImage);
cube.setFace(CubeFace.NegativeZ, backImage);
cube.upload();

7. Render-to-texture ​

ts
const rt = new RenderTexture(gl, 1024, 768);
rt.upload();

// Render into it
rt.bindAsTarget();
// ... draw calls ...
rt.unbindTarget();

// Sample from it in a later pass
rt.bind(0);

// Resize on window change
rt.resize(newWidth, newHeight);

8. Procedural texture with builder ​

ts
const heightMap = TextureBuilder2D.create(gl, 512, 512)
  .set((x, y) => simplex2(x * 8, y * 8))
  .add((x, y) => simplex2(x * 16, y * 16), 0.5)
  .remap(-1, 1, 0, 1)
  .curve((v) => v * v)
  .clamp(0, 1)
  .build();

9. Procedural 3D volume ​

ts
const fogVolume = TextureBuilder3D.create(gl, 64, 64, 64)
  .set((x, y, z) => perlin3(x * 4, y * 4, z * 4))
  .multiply((_x, _y, z) => 1 - z)  // fade out with height
  .normalise()
  .build();

10. Quick noise texture (one-liner) ​

ts
const noiseTex = noiseTexture2D(gl, 256, 256, simplex2, 8);
const noiseVol = noiseTexture3D(gl, 64, 64, 64, perlin3, 4);

11. Cleanup ​

ts
tex.dispose(); // deletes GPU texture handle
rt.dispose();  // deletes framebuffer, depth buffer, and texture handle

Carrot