I want to render a Spine animation in a webpage. I I just want it to be responsive and scale with a div that scales. The problem I can't figure out (even with chatGPT) is how to make it ever scale to the size of the Spine Player, and for the Spine Player to not letterbox things.

What I have now is the animation playing, but it's small and centered inside bounding boxes that make no sense for this file. In other files, if things fly off the screen the bounding boxes move around. I want output to be exactly like it would be if I rendered frames to a gif or APNG.

While I was able to increase the zoom, it is illogical and relies on CSS that isn't part of Spine Player so it's not a working solution, just a small victory in getting the scale to increase.

How can I make Spine Player behave like a normal div and render content like frames?

import { SpinePlayer } from "@esotericsoftware/spine-player";
import "@esotericsoftware/spine-player/dist/spine-player.min.css";

const jsonUrl = "../src/assets/Spine.json";
const atlasUrl = "../src/assets/Tiffany.atlas";

const SpineTest = () => {
  useEffect(() => {
    const spinePlayer = new SpinePlayer("player-container", {
      jsonUrl: jsonUrl,
      atlasUrl: atlasUrl,
      showControls: false,
      preserveDrawingBuffer: true,
      premultipliedAlpha: false,
      showLoading: false,
        backgroundColor: "#f100f2",
  fullScreenBackgroundColor: "000000",
  viewport: {
    debugRender: true,
    x: -4000,
    y: -4000,
    width: 4000,
    height: 4000,
    padLeft: "0%",
    padRight: "0%",
    padTop: "0%",
    padBottom: "0%",
  },
      animation: "eyes track FINAL",
      success: function (player) {
        player.fitToCanvas = true; 
        player.play();
      },
    });

    // Adjust canvas size on window resize
    const handleResize = () => {
      const container = document.getElementById('player-container');
      if (container && spinePlayer) {
        spinePlayer.setCanvasSize(container.clientWidth, container.clientHeight);
      }
    };

    window.addEventListener('resize', handleResize);

    return () => {
      spinePlayer?.dispose();
      window.removeEventListener('resize', handleResize);
    };
  }, []);

  return <div id="player-container" style={{ width: '100%', height: '100%' }}></div>;
};

export default SpineTest;```
Related Discussions
...

There should not be anything special needed to resize the Spine player. For example, this page has a player:
http://esotericsoftware.com/spine-player
If you resize the page smaller, the player resizes as expected.

Given that, I'm not sure where you are having trouble? It may help if you can provide HTML + JavaScript that shows the problem, possibly using resources in the spine-runtimes so you don't have to provide your own.

I'm following the docs exactly in my example.

Firstly, the docs give no information how to resize the Spine Player itself. The example from your link shows a large area left and right that is not part of the animation. If you add a background it also has the same problem. (I tried attaching a movie of it, but 9MB is too big.)

Secondly, if you have a non-simple canvas where things not rendered in sprites are off screen, then it is a whole different level of things broken. The bounding boxes move around, and if you have a background meant for different aspect ratios, it makes it even small and moving around.

The goal is to show in a canvas size of choice (can sniff browser size for example) and to display a responsive animation with no letter boxing. I don't know where all of this background space is coming from, because it's not in the Spine file or atlas.

Finally, the atlas really seems to dictate size, the only way I can get it to zoom in is by guessing and checking, but I have no idea what is happening to the divs. The HTML is dead simple with no added CSS.

What is my big picture? To not have to render frames which would be a few hundred MB loaded in the browser as a gif. I want to display an animation in a div that is a responsive wrapped of the Spine Player canvas and contains nothing that wouldn't be rendered in a frame.

Notes: It's not listed either how you should prepare your file. Should 0,0 be in the middle, top-middle, bottom-left (most logical to me) or somewhere else to have the least trouble guessing where the animation is in the canvas.

<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vite + React + TS</title>
  </head>
  <body>
    <div id="root"></div>
    <script type="module" src="/src/main.tsx"></script>
  </body>
</html>

Here is an example of the file with broken output:


import { useEffect } from "react";
import { SpinePlayer } from "@esotericsoftware/spine-player";
import "@esotericsoftware/spine-player/dist/spine-player.min.css";

const jsonUrl = "../src/assets/Spine.json";
const atlasUrl = "../src/assets/Tiffany.atlas";

const SpineTest = () => {
  useEffect(() => {
    const spinePlayer = new SpinePlayer("player-container", {
      jsonUrl: jsonUrl,
      atlasUrl: atlasUrl,
      showControls: true,
      preserveDrawingBuffer: true,
      premultipliedAlpha: false,
      showLoading: true,
      viewport: {
        debugRender: true,
        // Ensure the Spine animation fits to the canvas size
        fitToCanvas: true,
      },
      animation: "eyes track FINAL",
      success: function (player) {
        player.addAnimation("eyes track FINAL", true);
        player.play();
      },
    });

    return () => {
      spinePlayer?.dispose();
    };
  }, []);

  return (
    <div
      id="player-container"
      style={{
        width: "100vw",
        height: "100vh",
      }}
    ></div>
  );
};

export default SpineTest;
  • Nate respondió a esto

    FKL34TI5T5 Firstly, the docs give no information how to resize the Spine Player itself.

    The player renders to a canvas that is an HTML element, so it's size and position are set like anything else in HTML.

    FKL34TI5T5 The example from your link shows a large area left and right that is not part of the animation.

    The player draws a skeleton within the player bounds. By default the skeleton is scaled to fit. This means there can be empty space around the skeleton.

    FKL34TI5T5 If you add a background it also has the same problem.

    You've jumped to defining the behavior as a problem, but the player is working as designed. I have not yet understood your goal, but I see a lot of text so I'll read on! 🙂

    FKL34TI5T5 if you have a non-simple canvas where things not rendered in sprites are off screen, then it is a whole different level of things broken. The bounding boxes move around, and if you have a background meant for different aspect ratios, it makes it even small and moving around.

    It's not clear what non-simple might mean. If you have a background in your skeleton or your attachments are moving off screen, then the default behavior that sets the viewport to fit the animation will probably not be what you want. In that case, set a viewport explicitly (see below).

    FKL34TI5T5 The goal is to show in a canvas size of choice (can sniff browser size for example) and to display a responsive animation with no letter boxing.

    Ah, OK! You should be able to do this. More below.

    FKL34TI5T5 I don't know where all of this background space is coming from, because it's not in the Spine file or atlas.

    You can think of the player as a viewport, like a window looking at your animation. If the window is farther away, you'll see a smaller animation and more space around it. The default automatically defined viewport works by going though your animation and computing the maximal bounds, then it zooms so that fits within the player bounds.

    FKL34TI5T5 Finally, the atlas really seems to dictate size

    The size of your animation comes from the skeleton animation data. You can use different size images and the skeleton should render at the same size, just with more or less pixelated images.

    FKL34TI5T5 the only way I can get it to zoom in is by guessing and checking, but I have no idea what is happening to the divs.

    Guessing and checking at what? I'm not sure what DIVs you mean.

    FKL34TI5T5 It's not listed either how you should prepare your file. Should 0,0 be in the middle, top-middle, bottom-left (most logical to me) or somewhere else

    It doesn't matter. The automatic viewport finds the bounds, no matter where things are placed. If setting viewport bounds manually, then you'd set them to wherever your skeleton is positioned in world space in Spine.

    Onward to defining a viewport manually! See the docs here:
    https://esotericsoftware.com/spine-player#Viewports
    In Spine you can turn on rulers with ctrl+shift+R (cmd on mac), which I see you've done. In 4.2 (which I see you are using) it shows the number, which is handy. The viewport definition looks like:

     viewport: {
        x: 0,
        y: 0,
        width: 300,
        height: 300
     }

    In the Spine take note of the lower left corner of where you want your viewport and set x and y to those coordinates. Then see the coordinates in Spine for the upper right corner to determine the size and set width and height on your viewport. Now the player will show the viewport rectangle you've defined. If you size the player's canvas using the same aspect ratio, then you should not have "gutters" (aka black bars).

    Hopefully that gets you unstuck! If not we'll get you there in time. Sorry if this was frustrating to get going.

    Thanks for your reply. I'm still not having luck. Going to keep troubleshooting and try to sort. I'm not the one creating the animation, I'm just exporting what my wife is making. I'm familiar only with exporting from Spine. I only break things when I touch animation. :-)

    The default automatically defined viewport works by going though your animation and computing the maximal bounds, then it zooms so that fits within the player bounds.

    Now the player will show the viewport rectangle you've defined. If you size the player's canvas using the same aspect ratio, then you should not have "gutters" (aka black bars).

    This is where I've started and remained stuck. I have only had luck hacking the atlas file. That is what I mean by guess and check. I'm not getting any sort of logic.

    Why are the green and red bars visible? This is the crux of the problem. If they were exactly the size of what I want visible, then there is no problem, I can hide the letterboxing of the canvas div with CSS. Since the red and green debug divs are generated from the JS, I have no selector to kill their visibility.

     viewport: {
        x: 0,
        y: 0,
        width: 300,
        height: 300
     }

    The problem is this does nothing in terms of the green and red bounds. I don't get where they come from. In one file the green bar maps to a background that is bigger than the animated area.

    The use case here is just like lottie. It's not for a game but an animation in design. The file I have shown is for debugging only. The actual animation has many more problems with display, but I'm trying to work issue by issue. One way I know how to solve the problem is to load phaser.js and then things work, but it's also 10x heavier which is a dealbreaker. With greensock it's even heavier than that.

    The red and green lines show because you have debugRender: true and they represent the padding. Set the padding to 0 if you don't want it. Here's an example:
    http://n4te.com/x/9612-exG4.txt.html
    Source:
    http://n4te.com/x/9612-exG4.txt.nowrap
    Important bit:

    viewport: {
    	x: -200,
    	y: -15,
    	width: 450,
    	height: 715,
    	padLeft: 0,
    	padRight: 0,
    	padTop: 0,
    	padBottom: 0
    }

      Nate

      I understand the debug shows the lines. I'm trying to debug. What are the green and red lines? What do they represent that I can control in Spine or with CSS? I posted the HTML above.

      Messing with the viewport I've tried, but it's not logical and still can't get the animation to fill the player. There is a conflict somewhere. It's not clear anything yet. I want simply for the red and green bounds to be the same and the animation to fill everything by height. After I can do that, then we see about the bounds of width letterboxing. Right now there is double letterboxing (padding).

      Do you know what coordinates you should start things in? Does that even matter? Can you control that if it does?

      Is the above file shown ok?

      My instinct is no it doesn't matter because I have the same problem with every file.

      • Nate respondió a esto

        FKL34TI5T5 What are the green and red lines?

        Green is the edge of the player's viewport. Red is the viewport you set, or the one that is set automatically if you didn't set one explicitly. This may be larger than the viewport you set if 1) the aspect ratio of the player differs from the aspect ratio of the viewport you set, or 2) if there is viewport padding.

        The lines are drawn are here in the code.

        FKL34TI5T5 What do they represent that I can control in Spine or with CSS?

        You configure the viewport position, size, and padding using the viewport: { ... } section of the player config.

        FKL34TI5T5 I want simply for the red and green bounds to be the same and the animation to fill everything by height.

        Set the viewport padding to zero (see the "important bit" I provided in my last post) and size the player to match the aspect ratio of your viewport.

        FKL34TI5T5 Do you know what coordinates you should start things in? Does that even matter? Can you control that if it does?

        It most certainly matters. Use the rulers in Spine to set your player viewport around your skeleton.

        FKL34TI5T5 Is the above file shown ok?

        Which file? AFAIK you haven't posted anything that I can run to see the behavior. Code snippets are fine, but I cannot run them.

        I believe my example in my last post works like you want. It is self contained and you can run it.


        Maybe this will help to understand how non-sensical those settings are. It's -5000 just to appear on the screen offcenter.

        I understand that they do something, but it's not documented what they do or how to control them. I'm at a complete loss, and I'm pretty good at CSS. It's either a file export issue, an animation composition issue, a bug, or just poor UX. I'm betting on it being 2 or 3. Exporting has had a lot of crazy bugs in the past, so that's also possible, but the files output make sense to me and playing with them doesn't seem to affect anything.

        More Thought: I'm strongly leaning towards 2, with 4 being true. I think there needs to be more transparency of the size parameter.

        The viewport settings are in world coordinates. They match the rulers in Spine. Here's your screenshot above with a rectangle drawn starting at 0,-5000 and having a size of 5000,5000:

        Image removed due to the lack of support for HTTPS. | Show Anyway

        That roughly matches your player screenshot.

        I'd guess you want a viewport at about -1550,-2900 (x,y) with a size of about 3000,2900 (width,height). Here's how I arrived at those values:

        Image removed due to the lack of support for HTTPS. | Show Anyway

        You can place things in Spine to make the viewport easier to calculate. For example, place the lower left corner at 0,0 then it's easier to determine the width and height for your viewport.

          17 días más tarde

          Nate

          Forgot to reply to this. Thank you very much. That was the info missing from the docs. I think the docs assume Spine expertise, when in this case it is not true. I have little idea how my wife understands the program. After consulting with her too I figured it out with this.

          • A Nate le gusta esto.

          Glad you got it working! Coordinate systems can be a pain. We'll consider how to improve the docs.

          6 meses más tarde

          Nate Hello, I want to know how to get the world coordinates and size(width and height) of each animation. Can I only view it in the spine editor? I am not the creator of the spine animation, only got the exported JSON. Is there any other way to get it? Thank you!