CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-three

JavaScript 3D library providing WebGL and WebGPU renderers for creating interactive 3D graphics in web browsers

Pending
Overview
Eval results
Files

webgpu.mddocs/

WebGPU Rendering

Three.js WebGPU renderer provides next-generation GPU rendering capabilities with compute shaders, advanced graphics features, and improved performance. WebGPU offers more direct access to modern GPU capabilities compared to WebGL, enabling advanced rendering techniques and general-purpose GPU computation.

Import: WebGPU functionality is available via the dedicated WebGPU build:

import { WebGPURenderer } from 'three/webgpu';
import { 
  StorageInstancedBufferAttribute,
  StorageBufferAttribute,
  WebGPUCoordinateSystem
} from 'three/webgpu';

Capabilities

WebGPU Renderer

Advanced GPU renderer with compute capabilities and modern graphics pipeline support.

/**
 * WebGPU-based renderer with compute shader support and advanced rendering features
 */
class WebGPURenderer extends Renderer {
  /**
   * Create WebGPU renderer
   * @param parameters - Renderer configuration options
   */
  constructor(parameters?: WebGPURendererParameters);
  
  /** HTML canvas element for rendering */
  domElement: HTMLCanvasElement;
  
  /** Whether renderer has been initialized */
  isWebGPURenderer: true;
  
  /** Coordinate system used (WebGPU vs WebGL differences) */
  coordinateSystem: typeof WebGPUCoordinateSystem;
  
  /**
   * Initialize WebGPU context and resources
   * @returns Promise that resolves when initialization is complete
   */
  init(): Promise<WebGPURenderer>;
  
  /**
   * Render scene with camera
   * @param scene - Scene to render
   * @param camera - Camera defining viewpoint
   * @returns This renderer for chaining
   */
  render(scene: Object3D, camera: Camera): this;
  
  /**
   * Render scene to render target
   * @param scene - Scene to render
   * @param camera - Camera defining viewpoint  
   * @param renderTarget - Target to render to
   * @param forceClear - Whether to force clear before rendering
   */
  setRenderTarget(renderTarget: RenderTarget | null, activeCubeFace?: number, activeMipmapLevel?: number): void;
  
  /**
   * Execute compute shader operations
   * @param computeNodes - Array of compute nodes to execute
   * @returns Promise that resolves when compute is complete
   */
  compute(computeNodes: Node[]): Promise<void>;
  
  /**
   * Execute compute shader operations asynchronously
   * @param computeNodes - Array of compute nodes to execute
   * @returns Promise that resolves when compute is complete
   */
  computeAsync(computeNodes: Node[]): Promise<void>;
  
  /**
   * Set size of renderer and canvas
   * @param width - Width in pixels
   * @param height - Height in pixels
   * @param updateStyle - Whether to update CSS styles
   */
  setSize(width: number, height: number, updateStyle?: boolean): void;
  
  /**
   * Set device pixel ratio for high-DPI displays
   * @param value - Device pixel ratio (window.devicePixelRatio)
   */
  setPixelRatio(value: number): void;
  
  /**
   * Set viewport within canvas
   * @param x - X offset in pixels
   * @param y - Y offset in pixels
   * @param width - Viewport width in pixels
   * @param height - Viewport height in pixels
   */
  setViewport(x: number, y: number, width: number, height: number): void;
  
  /**
   * Set scissor test region
   * @param x - X offset in pixels
   * @param y - Y offset in pixels
   * @param width - Scissor width in pixels
   * @param height - Scissor height in pixels
   */
  setScissor(x: number, y: number, width: number, height: number): void;
  
  /**
   * Enable or disable scissor test
   * @param boolean - Whether scissor test is enabled
   */
  setScissorTest(boolean: boolean): void;
  
  /**
   * Set clear color for background
   * @param color - Clear color
   * @param alpha - Alpha value for clear color
   */
  setClearColor(color: ColorRepresentation, alpha?: number): void;
  
  /**
   * Set clear alpha value
   * @param alpha - Alpha value (0-1)
   */
  setClearAlpha(alpha: number): void;
  
  /**
   * Clear render buffers
   * @param color - Whether to clear color buffer
   * @param depth - Whether to clear depth buffer
   * @param stencil - Whether to clear stencil buffer
   */
  clear(color?: boolean, depth?: boolean, stencil?: boolean): void;
  
  /**
   * Dispose of WebGPU resources
   */
  dispose(): void;
  
  /**
   * Get current render target
   * @returns Active render target or null
   */
  getRenderTarget(): RenderTarget | null;
  
  /**
   * Get WebGPU device capabilities
   * @returns Object describing supported features and limits
   */
  getCapabilities(): WebGPUCapabilities;
  
  /**
   * Get rendering context information
   * @returns WebGPU context information
   */
  getContext(): GPUCanvasContext;
  
  /**
   * Copy render target to another render target
   * @param source - Source render target
   * @param target - Destination render target
   * @param viewport - Optional viewport for partial copy
   */
  copyFramebufferToTexture(texture: Texture, position?: Vector2, level?: number): void;
  
  /**
   * Copy texture to render target  
   * @param position - Position to copy to
   * @param texture - Source texture
   * @param level - Mipmap level
   */
  copyTextureToTexture(position: Vector2, srcTexture: Texture, dstTexture: Texture, level?: number): void;
}

interface WebGPURendererParameters {
  /** Canvas element to render to */
  canvas?: HTMLCanvasElement;
  
  /** GPU device to use (auto-selected if not specified) */
  device?: GPUDevice;
  
  /** GPU adapter to use (auto-selected if not specified) */
  adapter?: GPUAdapter;
  
  /** Antialiasing configuration */
  antialias?: boolean;
  
  /** Whether canvas has alpha channel */
  alpha?: boolean;
  
  /** Whether to premultiply alpha */
  premultipliedAlpha?: boolean;
  
  /** Whether to preserve drawing buffer */
  preserveDrawingBuffer?: boolean;
  
  /** Power preference for GPU selection */
  powerPreference?: 'low-power' | 'high-performance';
  
  /** Required features for WebGPU device */
  requiredFeatures?: Iterable<GPUFeatureName>;
  
  /** Required limits for WebGPU device */
  requiredLimits?: Record<string, GPUSize64>;
  
  /** Fallback adapter options */
  fallbackAdapters?: GPURequestAdapterOptions[];
}

interface WebGPUCapabilities {
  /** Whether WebGPU is supported */
  isWebGPU: boolean;
  
  /** Maximum texture size */
  maxTextures: number;
  
  /** Maximum vertex attributes */
  maxVertexAttributes: number;
  
  /** Maximum vertex uniform vectors */
  maxVertexUniforms: number;
  
  /** Maximum fragment uniform vectors */
  maxFragmentUniforms: number;
  
  /** Maximum samples for multisampling */
  maxSamples: number;
  
  /** Supported texture formats */
  textureFormats: Set<string>;
  
  /** Device features */
  features: Set<string>;
  
  /** Device limits */
  limits: GPUSupportedLimits;
}

Usage Example:

import { WebGPURenderer } from 'three/webgpu';
import * as THREE from 'three';

async function initWebGPU() {
  // Check WebGPU support
  if (!navigator.gpu) {
    throw new Error('WebGPU not supported');
  }
  
  // Create renderer
  const renderer = new WebGPURenderer({
    antialias: true,
    requiredFeatures: ['timestamp-query'],
    powerPreference: 'high-performance'
  });
  
  // Initialize WebGPU context
  await renderer.init();
  
  // Set up canvas
  renderer.setSize(window.innerWidth, window.innerHeight);
  renderer.setPixelRatio(window.devicePixelRatio);
  document.body.appendChild(renderer.domElement);
  
  // Create scene
  const scene = new THREE.Scene();
  const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
  
  // Render loop
  function animate() {
    requestAnimationFrame(animate);
    renderer.render(scene, camera);
  }
  animate();
}

initWebGPU().catch(console.error);

Compute Shaders

WebGPU enables general-purpose GPU computation through compute shaders for parallel processing tasks.

/**
 * Node-based compute shader system for GPU computation
 */
interface ComputeNode extends Node {
  /** Number of compute workgroups in X dimension */
  workgroupSize: number;
  
  /** Compute shader function */
  computeNode: Node;
  
  /**
   * Execute compute shader
   * @param renderer - WebGPU renderer
   * @returns Promise resolving when compute is complete
   */
  compute(renderer: WebGPURenderer): Promise<void>;
}

/**
 * Create compute node for GPU computation
 * @param computeShader - Compute shader function as node
 * @param count - Number of compute invocations
 * @param workgroupSize - Size of compute workgroup
 * @returns Compute node ready for execution
 */
declare function compute(computeShader: Node, count: number, workgroupSize?: number): ComputeNode;

/**
 * Storage buffer for compute shader data exchange
 */
class StorageBufferNode extends BufferNode {
  /**
   * Create storage buffer node
   * @param value - Initial buffer data
   * @param bufferType - Type of storage buffer
   * @param bufferCount - Number of elements
   */
  constructor(value: ArrayLike<number>, bufferType?: string, bufferCount?: number);
  
  /** Buffer access mode */
  access: 'read' | 'write' | 'read_write';
}

Usage Example:

import { WebGPURenderer, compute, storage, uniform } from 'three/webgpu';
import { wgsl } from 'three/tsl';

async function runCompute() {
  const renderer = new WebGPURenderer();
  await renderer.init();
  
  // Create storage buffers for input/output data
  const inputBuffer = storage(new Float32Array([1, 2, 3, 4, 5]), 'vec4<f32>', 1);
  const outputBuffer = storage(new Float32Array(4), 'vec4<f32>', 1);
  
  // Define compute shader using WGSL
  const computeShader = wgsl(`
    @compute @workgroup_size(1)
    fn main(@builtin(global_invocation_id) global_id : vec3<u32>) {
      let index = global_id.x;
      outputBuffer[index] = inputBuffer[index] * 2.0;
    }
  `);
  
  // Create compute node
  const computeNode = compute(computeShader, 1);
  
  // Execute compute shader
  await renderer.compute([computeNode]);
  
  // Read results
  const results = await renderer.readStorageBuffer(outputBuffer);
  console.log('Compute results:', results);
}

Storage Attributes

Enhanced buffer attributes for compute shaders and advanced rendering techniques.

/**
 * Storage buffer attribute for compute shader data exchange
 */
class StorageBufferAttribute extends BufferAttribute {
  /**
   * Create storage buffer attribute
   * @param array - Typed array containing attribute data
   * @param itemSize - Number of components per vertex
   * @param offset - Byte offset into buffer
   * @param normalized - Whether to normalize integer values
   */
  constructor(array: TypedArray, itemSize: number, offset?: number, normalized?: boolean);
  
  /** Buffer usage flags for WebGPU */
  usage: GPUBufferUsageFlags;
  
  /** Whether buffer can be read by CPU */
  isStorageBufferAttribute: true;
}

/**
 * Instanced storage buffer attribute for compute-driven instancing
 */
class StorageInstancedBufferAttribute extends StorageBufferAttribute {
  /**
   * Create storage instanced buffer attribute
   * @param array - Typed array containing instance data
   * @param itemSize - Number of components per instance
   * @param meshPerAttribute - Number of meshes per attribute (for multidraw)
   * @param offset - Byte offset into buffer
   * @param normalized - Whether to normalize integer values
   */
  constructor(
    array: TypedArray, 
    itemSize: number, 
    meshPerAttribute?: number, 
    offset?: number, 
    normalized?: boolean
  );
  
  /** Number of meshes per attribute */
  meshPerAttribute: number;
  
  /** Whether this is an instanced attribute */
  isInstancedBufferAttribute: true;
}

WebGPU Specific Features

Advanced features unique to WebGPU renderer implementation.

/**
 * Query system for GPU timing and performance metrics
 */
class TimestampQuery {
  /** Query name/identifier */
  name: string;
  
  /** Whether query is active */
  active: boolean;
  
  /**
   * Get query results in nanoseconds
   * @returns GPU time in nanoseconds or null if not ready
   */
  getResult(): number | null;
  
  /**
   * Reset query for reuse
   */
  reset(): void;
}

/**
 * Create timestamp query for GPU timing
 * @param name - Query identifier
 * @returns Timestamp query object
 */
declare function createTimestampQuery(name: string): TimestampQuery;

/**
 * WebGPU render bundle for optimized draw call recording
 */
interface RenderBundle {
  /** Bundle identifier */
  id: string;
  
  /** Recorded draw calls */
  drawCalls: DrawCall[];
  
  /**
   * Execute bundle on GPU
   * @param renderer - WebGPU renderer
   */
  execute(renderer: WebGPURenderer): void;
}

/**
 * Create render bundle for draw call batching
 * @param scene - Scene to record
 * @param camera - Camera for rendering
 * @returns Render bundle with recorded draw calls
 */
declare function createRenderBundle(scene: Object3D, camera: Camera): RenderBundle;

Node System Integration

WebGPU renderer integrates deeply with Three.js node system for advanced material effects.

/**
 * WebGPU-specific node types for advanced rendering
 */

/**
 * Compute texture node for procedural texture generation
 */
class ComputeTextureNode extends TempNode {
  /**
   * Create compute texture node
   * @param computeShader - Compute shader for texture generation
   * @param width - Texture width
   * @param height - Texture height
   * @param format - Texture format
   */
  constructor(computeShader: Node, width: number, height: number, format?: PixelFormat);
  
  /** Texture dimensions */
  width: number;
  height: number;
  
  /** Texture format */
  format: PixelFormat;
}

/**
 * GPU particle system using compute shaders
 */
class GPUParticleSystem extends Object3D {
  /**
   * Create GPU particle system
   * @param maxParticles - Maximum number of particles
   * @param computeShader - Particle update compute shader
   */
  constructor(maxParticles: number, computeShader: Node);
  
  /** Maximum particle count */
  maxParticles: number;
  
  /** Current active particle count */
  particleCount: number;
  
  /** Particle position buffer */
  positionBuffer: StorageBufferAttribute;
  
  /** Particle velocity buffer */
  velocityBuffer: StorageBufferAttribute;
  
  /**
   * Update particle system
   * @param deltaTime - Time delta for simulation
   */
  update(deltaTime: number): void;
  
  /**
   * Reset all particles
   */
  reset(): void;
  
  /**
   * Emit new particles
   * @param count - Number of particles to emit
   * @param position - Emission position
   * @param velocity - Initial velocity
   */
  emit(count: number, position: Vector3, velocity: Vector3): void;
}

Types

// WebGPU-specific type definitions
interface GPUDevice extends EventTarget {
  features: GPUSupportedFeatures;
  limits: GPUSupportedLimits;
  queue: GPUQueue;
  createBuffer(descriptor: GPUBufferDescriptor): GPUBuffer;
  createTexture(descriptor: GPUTextureDescriptor): GPUTexture;
  createSampler(descriptor?: GPUSamplerDescriptor): GPUSampler;
  createShaderModule(descriptor: GPUShaderModuleDescriptor): GPUShaderModule;
  createComputePipeline(descriptor: GPUComputePipelineDescriptor): GPUComputePipeline;
  createRenderPipeline(descriptor: GPURenderPipelineDescriptor): GPURenderPipeline;
}

interface GPUAdapter {
  features: GPUSupportedFeatures;
  limits: GPUSupportedLimits;
  info: GPUAdapterInfo;
  requestDevice(descriptor?: GPUDeviceDescriptor): Promise<GPUDevice>;
}

type GPUBufferUsageFlags = number;
type GPUTextureUsageFlags = number;
type GPUShaderStageFlags = number;

// WebGPU coordinate system constant
declare const WebGPUCoordinateSystem: 2001;

Usage Examples

Advanced Compute-Based Particle System:

import { WebGPURenderer, compute, storage, uniform } from 'three/webgpu';
import { wgsl, vec3, float } from 'three/tsl';
import * as THREE from 'three';

class ComputeParticleSystem {
  constructor(particleCount = 10000) {
    this.particleCount = particleCount;
    this.init();
  }
  
  async init() {
    this.renderer = new WebGPURenderer();
    await this.renderer.init();
    
    // Create particle data buffers
    this.positions = new Float32Array(this.particleCount * 3);
    this.velocities = new Float32Array(this.particleCount * 3);
    
    // Initialize with random positions and velocities
    for (let i = 0; i < this.particleCount; i++) {
      const i3 = i * 3;
      this.positions[i3] = (Math.random() - 0.5) * 10;
      this.positions[i3 + 1] = (Math.random() - 0.5) * 10;
      this.positions[i3 + 2] = (Math.random() - 0.5) * 10;
      
      this.velocities[i3] = (Math.random() - 0.5) * 2;
      this.velocities[i3 + 1] = (Math.random() - 0.5) * 2;
      this.velocities[i3 + 2] = (Math.random() - 0.5) * 2;
    }
    
    // Create storage buffers
    this.positionBuffer = storage(this.positions, 'vec3<f32>');
    this.velocityBuffer = storage(this.velocities, 'vec3<f32>');
    
    // Simulation parameters
    this.timeUniform = uniform(0);
    this.deltaTimeUniform = uniform(0.016);
    this.gravityUniform = uniform(vec3(0, -9.81, 0));
    
    // Create compute shader for particle simulation
    this.updateShader = wgsl(`
      @group(0) @binding(0) var<storage, read_write> positions: array<vec3<f32>>;
      @group(0) @binding(1) var<storage, read_write> velocities: array<vec3<f32>>;
      @group(1) @binding(0) var<uniform> deltaTime: f32;
      @group(1) @binding(1) var<uniform> gravity: vec3<f32>;
      
      @compute @workgroup_size(64)
      fn main(@builtin(global_invocation_id) global_id: vec3<u32>) {
        let index = global_id.x;
        if (index >= ${this.particleCount}u) { return; }
        
        // Apply gravity
        velocities[index] += gravity * deltaTime;
        
        // Update position
        positions[index] += velocities[index] * deltaTime;
        
        // Simple ground collision
        if (positions[index].y < -5.0) {
          positions[index].y = -5.0;
          velocities[index].y = abs(velocities[index].y) * 0.8;
        }
        
        // Simple boundary collision
        for (var i = 0; i < 3; i++) {
          if (abs(positions[index][i]) > 10.0) {
            positions[index][i] = sign(positions[index][i]) * 10.0;
            velocities[index][i] *= -0.9;
          }
        }
      }
    `);
    
    // Create compute node
    const workgroupSize = 64;
    const workgroupCount = Math.ceil(this.particleCount / workgroupSize);
    this.computeNode = compute(this.updateShader, workgroupCount);
    
    this.setupRenderObjects();
  }
  
  setupRenderObjects() {
    // Create geometry for particles
    this.geometry = new THREE.BufferGeometry();
    this.geometry.setAttribute('position', new THREE.BufferAttribute(this.positions, 3));
    
    // Create particle material
    this.material = new THREE.PointsMaterial({
      color: 0x88ccff,
      size: 0.1,
      sizeAttenuation: true
    });
    
    // Create points object
    this.points = new THREE.Points(this.geometry, this.material);
  }
  
  async update(deltaTime) {
    // Update uniforms
    this.deltaTimeUniform.value = deltaTime;
    
    // Run compute shader
    await this.renderer.compute([this.computeNode]);
    
    // Update geometry with new positions
    this.geometry.attributes.position.needsUpdate = true;
  }
  
  addToScene(scene) {
    scene.add(this.points);
  }
}

// Usage
async function createParticleDemo() {
  const scene = new THREE.Scene();
  const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
  camera.position.set(0, 0, 15);
  
  const particleSystem = new ComputeParticleSystem(50000);
  await particleSystem.init();
  particleSystem.addToScene(scene);
  
  const clock = new THREE.Clock();
  
  function animate() {
    const deltaTime = clock.getDelta();
    
    particleSystem.update(deltaTime);
    particleSystem.renderer.render(scene, camera);
    
    requestAnimationFrame(animate);
  }
  
  animate();
}

Install with Tessl CLI

npx tessl i tessl/npm-three

docs

animation.md

cameras.md

geometries.md

index.md

lights.md

loaders.md

materials.md

math.md

renderers.md

scene-management.md

tsl.md

webgpu.md

tile.json