Skip to content
On this page

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}

Made with ❤️ using the awesome vitepress