Vector components have three sets of names: x y z w for positions, r g b a for colors and s t p q for texture coordinates, so v.x, v.r and v.s are the same component. Naming several at once is a swizzle: v.zx builds a vec2, v.rrr repeats red, and a swizzle on the left of = writes only those components. Matrices use array syntax instead: m[2] is column 2 and m[2][0] its first row.
show('vec3 v = vec3(1.0, 2.0, 3.0); result = vec4(v.zx, v.rr);');
show('vec4 v = vec4(0.0); v.wy = vec2(8.0, 9.0); v.s += 1.0; result = v;');
show('vec3 v = vec3(1.0); result = vec4(v.xgb, 1.0);');
show('vec3 v = vec3(1.0); v.xx = vec2(2.0); result = vec4(v, 1.0);');Output
3, 1, 1, 1 1, 9, 0, 8 ERROR: 0:3: 'xgb' : illegal - vector component fields not from the same set ERROR: 0:3: 'assign' : l-value of swizzle cannot have duplicate components
Swizzles are free on GPUs, which route components within each instruction: color.bgr reorders channels.
<!doctype html>
<style>
body { margin: 0; font: 12px system-ui, sans-serif; background: #f7f4ee; color: #333; }
canvas { display: block; width: 100%; max-width: 600px; }
.names { display: flex; max-width: 600px; text-align: center; font-family: monospace; }
.names div { flex: 1; padding: 4px 0; }
</style>
<canvas id="view" width="600" height="230"></canvas>
<div class="names"><div>c.rgb</div><div>c.bgr</div><div>c.rrr</div><div>c.gbr</div><div>c.rb = c.br</div></div>
<script>
// Draw a BookNest cover on a 2D canvas to use as a texture.
const cover = document.createElement('canvas');
cover.width = 128; cover.height = 192;
const g = cover.getContext('2d');
g.fillStyle = '#1f5f8b'; g.fillRect(0, 0, 128, 192);
g.fillStyle = '#e09a10'; g.beginPath(); g.arc(90, 60, 22, 0, Math.PI * 2); g.fill(); // sun
g.fillStyle = '#3f7d3a'; g.fillRect(0, 120, 128, 72); // hills
g.fillStyle = '#b5452f'; g.fillRect(40, 96, 40, 30); // boat
g.fillStyle = '#fff'; g.font = 'bold 15px sans-serif'; g.textAlign = 'center';
g.fillText('The Quiet', 64, 158); g.fillText('Harbor', 64, 176);
const gl = document.getElementById('view').getContext('webgl2');
const vs = `#version 300 es
in vec2 aPos; out vec2 vUV;
void main() { vUV = vec2(aPos.x, 1.0 - aPos.y); gl_Position = vec4(aPos * 2.0 - 1.0, 0.0, 1.0); }`;
const fs = `#version 300 es
precision mediump float;
in vec2 vUV; uniform sampler2D uCover; uniform int uMode;
out vec4 outColor;
void main() {
vec4 c = texture(uCover, vUV);
// x y z w, r g b a and s t p q name the same four components.
if (uMode == 0) outColor = vec4(c.rgb, 1.0);
if (uMode == 1) outColor = vec4(c.bgr, 1.0); // reorder channels: red <-> blue
if (uMode == 2) outColor = vec4(c.rrr, 1.0); // repeat one component
if (uMode == 3) outColor = vec4(c.gbr, c.a); // rotate channels
if (uMode == 4) { c.rb = c.br; c.g *= 0.5; outColor = c; } // swizzled write on the left of =
}`;
const program = gl.createProgram();
for (const [type, src] of [[gl.VERTEX_SHADER, vs], [gl.FRAGMENT_SHADER, fs]]) {
const s = gl.createShader(type);
gl.shaderSource(s, src); gl.compileShader(s);
if (!gl.getShaderParameter(s, gl.COMPILE_STATUS)) throw new Error(gl.getShaderInfoLog(s));
gl.attachShader(program, s);
}
gl.linkProgram(program);
gl.useProgram(program);
gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer());
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([0,0, 1,0, 1,1, 0,0, 1,1, 0,1]), gl.STATIC_DRAW);
const aPos = gl.getAttribLocation(program, 'aPos');
gl.enableVertexAttribArray(aPos);
gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, 0, 0);
const texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, cover);
gl.generateMipmap(gl.TEXTURE_2D);
gl.clearColor(0.97, 0.96, 0.93, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
const uMode = gl.getUniformLocation(program, 'uMode');
for (let i = 0; i < 5; i++) {
gl.viewport(i * 120 + 6, 5, 108, 220); // one tile per swizzle
gl.uniform1i(uMode, i);
gl.drawArrays(gl.TRIANGLES, 0, 6);
}
</script>