• Runtimes
  • Preloading Spine animation using WebGL before the Canvas exists

Hi! I am using a spine animation for a website, which pops up in a side menu when hitting a menu button. When the side menu pops up it takes a half second until the animation becomes visible, which feels slow. How can I preload the resources without having any canvas? I am using the WebGL runtime. I was trying to load the resources with fetch(url), but the site ignores this and loads the resources again… looking at your given components, I got the feeling, that a canvas is a requirement for loading a Spine animation correctly.

  • Davide hat auf diesen Beitrag geantwortet.
    Related Discussions
    ...

    To preload Spine animations using WebGL before the canvas is created, you can load the necessary resources such as the JSON data and texture atlas in advance. This can be done by fetching these resources and storing them in memory. However, the actual rendering of the animation will require a canvas element. You can use the fetch API to load the JSON and atlas files, and then create a SkeletonData object from these resources. Once the side menu is triggered, you can quickly initialize the canvas and render the animation using the preloaded data. This approach should reduce the delay when the animation is first displayed.

    Here's a basic outline of how you might implement this:

    1. Use fetch to load the JSON and atlas files:

         let skeletonData, atlasData;
      
         fetch('path/to/your/skeleton.json')
           .then(response => response.json())
           .then(data => {
             skeletonData = data;
             return fetch('path/to/your/atlas.atlas');
           })
           .then(response => response.text())
           .then(data => {
             atlasData = data;
             // Now you have both skeletonData and atlasData preloaded
           });
    2. When the side menu is opened, create the canvas and initialize the Spine animation using the preloaded data.

    This method allows you to have the resources ready to go, minimizing the delay when the animation is first rendered.

    Lotes

    WebGL needs a canvas to render. As it is build right now, the asset manager does not expose a way to directly set the assets to use, rather than downloading. We could expose a set asset, as the get or require.

    Did you give a look at embedding asset data as base64? In that case the data are already on the page.

    If you don't want to encode your data in base64, you could use some js to do that. I was able to achieve preloading by using this code:

    // function to transform an asset url to a base64 uri
    const toDataURL = url => fetch(url)
    	.then(response => response.blob())
    	.then(blob => new Promise((resolve, reject) => {
    		const reader = new FileReader()
    		reader.onloadend = () => resolve(reader.result)
    		reader.onerror = reject
    		reader.readAsDataURL(blob)
    	}))
    
    // preload the assets
    let urlSkel, urlAtlas, urlPng;
    Promise.all([
    	toDataURL('assets/spineboy-pro.json'),
    	toDataURL('assets/spineboy-pma.atlas'),
    	toDataURL('assets/spineboy-pma.png'),
    ])
    	.then(([skel, atlas, png]) => {
    		urlSkel = skel;
    		urlAtlas = atlas;
    		urlPng = png;
    		new spine.SpineCanvas(document.getElementById("canvas"), {
    			app: new App()
    		})
    	})
    
    // app class
    class App {
            ....
    
    	loadAssets(canvas) {
    		canvas.assetManager.setRawDataURI("assets/spineboy-pro.skel", urlSkel);
    		canvas.assetManager.setRawDataURI("assets/spineboy-pma.atlas", urlAtlas);
    		canvas.assetManager.setRawDataURI("assets/spineboy-pma.png", urlPng);
    
    		canvas.assetManager.loadBinary("assets/spineboy-pro.skel");
    		canvas.assetManager.loadTextureAtlas("assets/spineboy-pma.atlas");
    	}
    
           ....
    }

    Thank you! This looks very promising. I will try out later today and give feedback then. Data URIs are not a problem.

    Works as desired, thank you very much!!! 🙂