Texture Types and Color Space

A Texture wraps an image source plus Textures's sampler state: wrapS and wrapT, repeat, offset and rotation for the uv transform, magFilter and minFilter, anisotropy (up to renderer.capabilities.getMaxAnisotropy(), 16 on the GTX 1650), generateMipmaps, flipY and colorSpace. Subclasses change where the pixels come from:

Texture classes and where their pixels come from
Class Source Typical use
Texture An image or ImageBitmap Photos, cover art
CanvasTexture A 2D canvas (Canvas 2D) Generated labels (Generated Covers)
VideoTexture A <video> element Trailers (Video Textures)
DataTexture A typed array Lookup tables, noise
CompressedTexture KTX2, DDS or KTX data GPU-compressed images (KTX2Loader)
CubeTexture Six images Skyboxes and reflections
DepthTexture A render target's depth Shadows, post-processing (EffectComposer)

Only color data is sRGB: set colorSpace = THREE.SRGBColorSpace on map, emissiveMap and sheen or specular colors, and leave normal, roughness, metalness and ambient-occlusion maps as NoColorSpace (Color Management). After changing a texture's pixels, as a canvas or data texture does, set texture.needsUpdate = true.

A CanvasTexture, a DataTexture with nearest filtering and a repeated, rotated textureHTMLLive
<!doctype html>
<style>
  body { margin: 0; background: #f5f1e8; font: 12px system-ui, sans-serif; color: #263238; }
  canvas { display: block; max-width: 100%; }
  .labels { display: flex; width: 600px; max-width: 100%; text-align: center; }
  .labels div { flex: 1; }
  .ui { padding: 4px 8px; }
</style>
<script type="importmap">
{ "imports": {
  "three": "https://cdn.jsdelivr.net/npm/three@0.186.1/build/three.module.js",
  "three/addons/": "https://cdn.jsdelivr.net/npm/three@0.186.1/examples/jsm/" } }
</script>
<div class="labels"><div>CanvasTexture (sRGB)</div><div>DataTexture, NearestFilter</div><div>repeat + rotation</div></div>
<div class="ui">repeat <input type="range" id="rep" min="1" max="6" value="3"> rotation <input type="range" id="rot" min="0" max="90" value="20"></div>
<script type="module">
import * as THREE from 'three';

const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(Math.min(devicePixelRatio, 2));
renderer.setSize(600, 220);
document.body.prepend(renderer.domElement);
const scene = new THREE.Scene();
scene.background = new THREE.Color('#fbf8f2');
const camera = new THREE.OrthographicCamera(-3, 3, 1.1, -1.1, 0, 10);
camera.position.z = 5;

// 1. CanvasTexture: generated cover art, a color map, so sRGB
const canvas = Object.assign(document.createElement('canvas'), { width: 256, height: 360 });
const g = canvas.getContext('2d');
g.fillStyle = '#e09a10';  g.fillRect(0, 0, 256, 360);
g.fillStyle = '#fff3e0';  g.font = 'bold 40px Georgia';
['Salt', 'and', 'Saffron'].forEach((w, i) => g.fillText(w, 22, 70 + i * 48));
g.font = 'italic 22px Georgia';  g.fillText('Leila Haddad', 22, 330);
const cover = new THREE.CanvasTexture(canvas);
cover.colorSpace = THREE.SRGBColorSpace;
cover.anisotropy = renderer.capabilities.getMaxAnisotropy();

// 2. DataTexture: 8×8 RGBA bytes written in code; NearestFilter keeps the texels square
const size = 8, data = new Uint8Array(size * size * 4);
for (let i = 0; i < size * size; i++) {
  const x = i % size, y = Math.floor(i / size), v = (x + y) % 2 ? 255 : 40 + ((x * y * 37) % 160);
  data.set([v, v * 0.8, 120, 255], i * 4);
}
const noise = new THREE.DataTexture(data, size, size);
noise.magFilter = THREE.NearestFilter;
noise.colorSpace = THREE.SRGBColorSpace;
noise.needsUpdate = true;                            // upload the typed array

// 3. A tile with RepeatWrapping, repeat and rotation (the uv transform)
const tileCanvas = Object.assign(document.createElement('canvas'), { width: 64, height: 64 });
const t = tileCanvas.getContext('2d');
t.fillStyle = '#1f5f8b';  t.fillRect(0, 0, 64, 64);
t.fillStyle = '#fff3e0';  t.beginPath();  t.arc(32, 32, 14, 0, 7);  t.fill();
const tile = new THREE.CanvasTexture(tileCanvas);
tile.colorSpace = THREE.SRGBColorSpace;
tile.wrapS = tile.wrapT = THREE.RepeatWrapping;
tile.center.set(0.5, 0.5);                           // rotate about the middle

[cover, noise, tile].forEach((map, i) => {
  const plane = new THREE.Mesh(new THREE.PlaneGeometry(1.4, 1.96), new THREE.MeshBasicMaterial({ map }));
  plane.position.x = (i - 1) * 2;
  scene.add(plane);
});

function update() {
  const r = +document.getElementById('rep').value;
  tile.repeat.set(r, r);
  tile.rotation = THREE.MathUtils.degToRad(+document.getElementById('rot').value);
  renderer.render(scene, camera);                    // uv transforms need no needsUpdate
}
['rep', 'rot'].forEach((id) => document.getElementById(id).addEventListener('input', update));
update();
</script>