Workaround for SVG texture loading black in three.js
Since April 2025, all SVG textures without a defined width and height load black in webgl, when loaded with an Image element, using TextureLoader
/ImageLoader
in three.js
Simple workaround which loads the image and rasterize the SVG to a fixed size canvas which is used as a texture.
::: note This is already implemented and available by default in webgi and threepipe. :::
typescript
import {CanvasTexture, ImageLoader, Loader, LoadingManager, Texture} from 'three'
import {getUrlQueryParam} from 'ts-browser-helpers'
/**
* Same as TextureLoader but loads SVG images, fixes issues with windows not loading svg files without a defined size.
*/
class SVGTextureLoader extends Loader {
constructor(manager: LoadingManager) {
super(manager)
}
static USE_CANVAS_TEXTURE = getUrlQueryParam('svg-load-disable-canvas') !== 'true'
load(url: string, onLoad: (texture: Texture) => void, onProgress?: (event: ProgressEvent) => void, onError?: (err: unknown) => void): Texture {
const canvas = SVGTextureLoader.USE_CANVAS_TEXTURE ? document.createElement('canvas') : undefined
const texture = SVGTextureLoader.USE_CANVAS_TEXTURE ? new CanvasTexture(canvas!) : new Texture()
const loader = new ImageLoader(this.manager)
loader.setCrossOrigin(this.crossOrigin)
loader.setPath(this.path)
loader.load(url, function(image) {
if (canvas) {
// size can be scaled here, this is based on the viewBox aspect ratio and minimum size of 150hx300w
canvas.width = image.naturalWidth
canvas.height = image.naturalHeight
const ctx = canvas.getContext('2d')
if (ctx) {
ctx.drawImage(image, 0, 0)
} else {
console.error('SVGTextureLoader: Failed to get canvas context.')
}
} else {
texture.image = image
}
texture.needsUpdate = true
if (onLoad !== undefined) {
onLoad(texture)
}
}, onProgress, onError)
return texture
}
}
export {SVGTextureLoader}