• Runtimes
  • How to make the size of Root as the size of the canvas

How to make the size of Root as the size of the canvas, and cut off all elements that exceed the size of Root, similar to a canvas concept. How can this be achieved? As shown in the diagram, remove the excess part of sunshine.

I tried to configure it in spine-ts player, but couldn't make it work.

Related Discussions
...

Mario Here is my config, I don't want to hard code the viewport option, I just want the bottom background image(child of the root) can resize to fill the entire canvas, and other nodes won't to exceed the size of the last bottom background image.

    instance.current = new SpinePlayer(ref.current, {
      jsonUrl: finalJsonUrl,
      atlasUrl: finalAtlasUrl,
      preserveDrawingBuffer: false,
      showControls: false,
      showLoading: false,
      backgroundColor: '#00000000',
      fullScreenBackgroundColor: '#00000000',
      viewport: {
        padLeft: '0%',
        padRight: '0%',
        padTop: '0%',
        padBottom: '0%',
        debugRender: true,
      },
      success(player) {
        player.paused = false
        const animation = player.skeleton?.data?.animations?.[0]?.name
        console.log(player)
        // if (animation) player.setAnimation(animation)
      },
    })

As Mario mentioned, you need to configure the viewport. See here:
https://esotericsoftware.com/spine-player#Viewports
Set the x, y, width, and height of your viewport to match your background (or whatever you like). Since it looks like you have the world origin in Spine set to the center of your background, you want to use something like:

x: -bgWidth / 2,
y: 0,
width: bgWidth,
height: bgHeight,

Replace bgWidth and bgHeight with numbers that are the width and height of your background.

    Nate thanks for replying. I don't want to hard code the bg's width because the code will be used by many spine projects, So how can I get the bg's reference or width, What I can do is let my designer to make the bg as the first child of root in spine editor

    You would need a way of knowing which attachment is that background. Then you can get the attachment and inspect it to determine its size and position.

    You could use the first slot found on the root bone, but there may be multiple. The order of slots is not controlled on the bone, it is done in the draw order. I think it would be easier to use a name, like bg. It should still be under the root bone though, so you don't need to compute the world position.

    If you use a region attachment, it has x, y, width, and height properties. Note the X and Y are the center of the region attachment.

    It looks like you are using a clipping attachment. If you name that bg and put it in a bg slot, then you can easily find it. Loop through the vertices and take the min and max values for X and Y out of all the vertices. minX and minY are your viewport X and Y. maxX - minX and maxY - minY are the viewport width and height.

    Make sure the clipping attachment is not weighted to bones, otherwise the vertices are in a more complex format. They shouldn't be animating the clipping attachment vertices for the viewport anyway.

      Nate Sounds complex for a newbie to Spine, It seems that I should do the calculation in the frame or update callback?

      You need to set the viewport once in the beginning. Start by getting the example to run:
      https://github.com/EsotericSoftware/spine-runtimes/tree/4.1/spine-ts/spine-player/example

      Eg, install Python 3 if you don't have it, change to the spine-ts/spine-player folder, then:

      python -m http.server

      Then open a browser to:
      http://localhost:8000/example/example.html

      Look at the callbacks available:
      https://github.com/EsotericSoftware/spine-runtimes/blob/4.1/spine-ts/spine-player/src/Player.ts#L145-L162

      Use the success callback so your code runs after the skeleton is loaded. See docs here:
      https://esotericsoftware.com/spine-player#Advanced-playback

      Figure out how to get an attachment by name:
      http://esotericsoftware.com/spine-api-reference#Skeleton-getAttachment2
      The API is generic and applies to all languages. Check the spine-ts code to be sure of the method you want to call:
      https://github.com/EsotericSoftware/spine-runtimes/blob/4.1/spine-ts/spine-core/src/Skeleton.ts#L515

      Now you can modify the example:

      new spine.SpinePlayer("container", {
      	skelUrl: "assets/spineboy-pro.skel",
      	atlasUrl: "assets/spineboy-pma.atlas",
      	premultipliedAlpha: true,
      	backgroundColor: "#cccccc",
      	viewport: {
      		debugRender: true,
      	},
      	showControls: false,
      	success: function (player) {
      		var vertices = player.skeleton.getAttachmentByName("head-bb", "head").vertices;
      		var minX = 99999, minY = 99999, maxX = -99999, maxY = -99999;
      		for (var i = 0, n = vertices.length; i < n; i += 2) {
      			var x = vertices[i], y = vertices[i + 1];
      			minX = Math.min(minX, x);
      			minY = Math.min(minY, y);
      			maxX = Math.max(maxX, x);
      			maxY = Math.max(maxY, y);
      		}
      		player.config.viewport.x = minX;
      		player.config.viewport.y = minY;
      		player.config.viewport.width = maxX - minX;
      		player.config.viewport.height = maxX - minX;
      
      		// Needed to show skeleton when no animation is specified (bug fixed in 4.2):
      		player.skeleton.updateWorldTransform();
      	}
      });

      For that to work you'll have to move the spineboy head-bb slot to the root (here spineboy-pro.skel), then you get:

        Nate I did find the Background Attachment, But I didn't find the vertices properties, I use code below

              success(player) {
                player.paused = false
                const bg = player.skeleton?.getAttachmentByName('Background', 'Background')
                player.config.viewport.x = bg.x
                player.config.viewport.y = bg.y
                player.config.viewport.width = bg.width
                player.config.viewport.height = bg.height
                player.skeleton.updateWorldTransform()
        
                const animation = player.skeleton?.data?.animations?.[0]?.name
                player.setAnimation(animation)
        }

        It turns out

        You don't get a vertices array, because your attachment is a region, not a mesh. Set viewport.x to bg.x - bg.width / 2 and viewport.y to bg.y - bg.height / 2.

        Yep, or use the clipping attachment, not the background.

          Nate designer did give me a clipping attachment
          using player.skeleton?.getAttachmentByName('Background', 'Background') can get an Attachment, but getAttachmentByName('Background'2, 'Background') can not, it throw an error says: Can't find slot with name Background2

          Likely your export doesn't match the project file. Also to get the clipping attachment, use it's name eg 'Background2', 'Background2'.

            Nate It' works well, but it still has some black area in the top and bottom, how can I cut them off

            You'll need to adjust the size of your canvas to match the attachment width and height. Note that you'll need to set both canvas.width/.height and canvas.style.width/height.

              Mario My canvas' size is equal to the screen of the user's phone. Is it possible to adjust the size of viewport to match the canvas's size

              Your problem is that your background aspect ratio doesn't match your canvas size. There are only 3 solutions:

              1. You could stretch your Spine skeleton to fill the canvas.
              2. You could zoom in so the height fills the canvas, but that will cut off some of the Spine skeleton on the left and right edges.
              3. You could live with the "black bars".

              I suggest option 2. To do it you need to calculate the viewport size and position based on 1) your background size, as we've already computed above, and 2) the aspect ratio of the user's screen. To do that you can look at the functions provided here:
              https://github.com/libgdx/libgdx/blob/master/gdx/src/com/badlogic/gdx/utils/Scaling.java
              Each function is a different way of fitting a source width/height (your background size) to a target width/height (the user's screen size). The result is the width height you want to use for your viewport, which you should center using this x, y, width, height:

              -width / 2, height / 2 - bgHeight / 2, width, height

              Which scaling function you choose from my link is up to you. To fill the screen, choose fill.

              I also suggest that you get rid of that clipping attachment. Clipping uses a lot of CPU, based on how many triangles you are clipping. See here:
              http://esotericsoftware.com/spine-clipping#Performance
              When you are clipping your ENTIRE skeleton, like you are doing, it can use a lot of CPU. That may be acceptable, especially if your app isn't doing much else. However, if it is not needed, then it is wasteful. With option 2, any content off screen can't be seen anyway, so clipping is not needed.