THREE.ComposedTexture - play GIF, APNG etc as texture

This is a texture class which allows to use multi-frame images such as GIF or APNG.

Other than most plain GIF players it doesn’t decode every pixel per frame on the fly, or uses putImageData (for larger GIFs this is too expensive), instead if no images provided, the decoded frame buffers will be converted to compressed images.

As GIF and other animated image formats get optimized not every frame is necessarily a full frame, most might only contain changing regions and pixels, so a frame needs to be composed across multiple frames. It also ensures the animation is rendered on a PO2 composition canvas.

This isn’t a GIF decoder, the example uses gifuct-js to decode a gif, you can use any multi-frame format as well as custom frames. A GIF and APNG loader example is included. The structure for the container object which holds the frames is the following.


In you render loop, you need to call texture.update( deltaTime ), or you control which frame is rendered yourself by calling texture.compose( frameIndex ).

Container structure


downscale : Boolean optional
Canvas needs to be power of 2, by default size is upscaled (false).

width : Number
height : Number
frames : Array

Either patch or image should be provided, if a buffer is provided it will be converted to a image.

patch : Uint8Array
image : Image
dims : Object
With left, top, width, height dimensions.
delay : Number
How long the frame is display in milliseconds.
disposalType : Numer
1 of the 3 methods, see GIF specification for more details.



THREE.ComposedTexture( container, ... )
Container object as described above. Other parameters as usual, you can also assign the container later by calling texture.assign( container ).


autoplay : Boolean
If playback automatically starts when loaded, default is true.

auto: Boolean
If playback should be handled globally, call THREE.ComposedTexture.update( delta ) in your render loop to handle all, default is true.

loop: Boolean
If the playback will be looped, default is true.

ready: Boolean
Will be true once all frames are ready to play.

isPlaying: Boolean
Indicates if the animation is currently playing.

time: Number
The current time in ms.

duration: Number
Total duration in ms.


async assign( container )
To assign a container object, if buffers are provided frames will be converted to images first.

update( deltaTime )
For automatic playback of the animation.

Start playback.

Pause playback.

Resume playback.

Stop playback, first frame is shown.

Enjoy cat GIFs in the third dimension :cat:



Pretty cool !
Did you notice what happens when you switch of browser’s tab for some time and come back later ? Seems that play speed get accelerated somehow.

1 Like

That’s probably the delta from THREE.Clock in the demo, animation frame callbacks get paused or throttled in inactive tabs, especially without audio. I’ll check tomorrow :+1: :unicorn:

I’ve made an update now to prevent this, before i considered the overshoot with delta, THREE.Clock doesn’t take into account that requestAnimationFrame is throttled or paused and will give a huge number when running normally again.

Edit: You can also call now THREE.ComposedTexture.update( delta ) in order to automatically handle playback of all composed textures, if you want to handle it yourself you can set auto to false in the container object.

Changed the example, it has a GIF and APNG loader example included now.

1 Like

Just what I need :slight_smile: However, the demo (and the download received after paying at gumroad) fails with a
Cannot set property 'value' of undefined at ComposedTexture.html:46
error. Help?

Sorry for the trouble, as mentioned in the PM the issue was related to the updated skybox plugin used for the demo, i fixed the line and sent out the updated files.

Thank you very much for the support :heart:

1 Like

Very very useful! Thank you!

1 Like

sweet! thanks!

1 Like

Very excited to use this, however I think it’s out of date now… I keep getting

ComposedTexture.js:22 Uncaught (in promise) TypeError: Class constructor CanvasTexture cannot be invoked without 'new'
at new ComposedTexture

Tried changing the source to make this work but can’t quite seem to get there

Just integrated this into my project and it’s working for me.

Are you sure you’re instantiating with new THREE.ComposedTexture?

Thank you for reporting this. This is exactly why i’m not a fan of the ES6 classes change they applied now, while they technically don’t offer more but adding syntactical sugar, they restrict compatibility with the regular approach.

It works fine till THREE 126 but since 127 CanvasTexture is wrapped into ES6 class syntax, where isn’t allowed anymore.

I will look into if this can be fixed without making 2 versions now, in order to stay compatible with older versions, once i updated it you will receive a mail, sorry for the trouble.


I fixed it and you should have received a email with the update, it works now with older versions as well as newer with ES6 syntax.

It didn’t require 2 separate files/implementations, just a patch override for releases later than 126.

Great thank you! Will try now. Just a quick note – I downloaded directly from the email and i still the line in question this, this.canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy );

edit: nevermind!

Yes the patch below turns it into a ES6 class so it won’t be an issue, the regular constructor is for older versions.

1 Like

Quick question, do you know if the packages at and available via npm?

I think this is the upng package: @syncfusion/ej2-angular-calendars - npm

UPNG: @syncfusion/ej2-angular-calendars - npm
GIF: gif-decode - npm

For GIF i’m not sure if it is the same but it should do the exact same, as you see in the example any format can be used as long as they serve frames, also if they’re just partial frames as GIF and UPNG can have.