v146 · Web APIs · WebGPU · WGSL

WebGPU texture and sampler lets

Chrome 146 adds support for declaring textures and samplers as local let variables in WGSL shaders. Previously these could only be declared as module-scope vars bound to specific binding groups. The new syntax enables more flexible shader code patterns.

concepts

  1. Texture Lets Demo

    A WebGPU shader that uses texture and sampler let declarations — samples a texture into a local variable and uses it across the fragment shader without repeating the binding group syntax.

  2. WGSL Syntax

    Side-by-side WGSL before and after: the old module-scope var pattern vs the new let declarations, with examples of helper functions that accept textures as parameters.

  3. Binding tagger playground

    Paste WGSL, hit "rewrite", get the 146-style version that aliases bindings into lets. The meter shows how many binding declarations the lets remove.

  4. Sampler Gallery

    Six sampler configurations — nearest vs linear filter, clamp/repeat/mirror-repeat address modes — rendered on a checkerboard texture. Demonstrates how WGSL texture/sampler let bindings enable concise reuse of the same texture across multiple sample calls.

why it shipped

WGSL previously required textures and samplers to be declared at module scope as var bindings. This made it difficult to write reusable shader functions that take a texture as an argument, or to alias a texture with a local name inside a function. Chrome 146 allows texture and sampler handles to be stored in let variables and passed as function parameters, enabling cleaner, more composable shader code.

the change

// WGSL — before Chrome 146 (module-scope var only)
@group(0) @binding(0) var myTex: texture_2d<f32>;
@group(0) @binding(1) var mySampler: sampler;

@fragment fn main(@location(0) uv: vec2f) -> @location(0) vec4f {
  // Must reference module-level names directly
  return textureSample(myTex, mySampler, uv);
}

// WGSL — Chrome 146+ (texture/sampler let variables)
@group(0) @binding(0) var myTex: texture_2d<f32>;
@group(0) @binding(1) var mySampler: sampler;

fn sampleAt(tex: texture_2d<f32>, smp: sampler, uv: vec2f) -> vec4f {
  return textureSample(tex, smp, uv);
}

@fragment fn main(@location(0) uv: vec2f) -> @location(0) vec4f {
  // Local let alias
  let t = myTex;
  let s = mySampler;
  return sampleAt(t, s, uv);  // pass as parameters
}

references