<script src="https://unpkg.com/@esotericsoftware/spine-player@4.2.*/dist/iife/spine-player.js"> </script>
<link rel="stylesheet" href="https://unpkg.com/@esotericsoftware/spine-player@4.2.*/dist/spine-player.css">
<link rel="stylesheet" href="https://gist.githubusercontent.com/saintedlama/628ba457dd5ae8b97ece/raw/8879ee2b4a8f8bb0e4d6ac0a14ab90c4c2d0a564/monokai.css">
<style>

#player-all-together {
   margin-bottom: 1.1em;
}

#player-all-together iframe {
  border: none !important;
  padding: 0 !important;
  margin: 0 !important;
  box-shadow: none !important;
  max-width: none !important;
  border-radius: 4px;
}

#player-all-together {
   margin-bottom: 1.1em;
}

#player-all-together iframe {
  border: none !important;
  padding: 0 !important;
  margin: 0 !important;
  box-shadow: none !important;
  max-width: none !important;
  border-radius: 4px;
}

#player-all-together .CodeMirror {
  line-height: normal;
  background-color: #000;
  color: #ddd;
}
</style>
!!

# Spine Web Player

Spine Web Player可轻松地将Spine动画嵌入到你的网站上.

<div id="player-top" style="margin-bottom: 2em;"></div>
<script>
new spine.SpinePlayer("player-top", {
   skeleton: "/files/examples/4.2/raptor/export/raptor-pro.json",
   atlas: "/files/examples/4.2/raptor/export/raptor-pma.atlas",
   animation: "walk",
   premultipliedAlpha: true,
   backgroundColor: "#666666",
});
</script>
!!
Web Player包含控件, 用户可以:

* 暂停/恢复当前播放的动画.
* 刷新时间线.
* 改变播放速度.
* 从可选动画列表中选中一个动画.
* 从可选皮肤列表中选中一个皮肤.
* 隐藏/显示区域、网格或骨骼等的调试渲染.
* 拖动skeleton的骨骼.

可以禁用Web Player的控件来只用于显示动画, 而无需用户输入([示例](/blog/Spine-4.0-is-here)).

> **注意**: Spine Web Player使用[WebGL](https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API)进行渲染. 虽然WebGL被所有流行的桌面和移动浏览器的最新版本所支持, 但也存在[与旧浏览器的兼容性问题](https://caniuse.com/#search=webgl).

## 为Web Player导出文件

Spine Web Player可以显示以`JSON`格式从Spine编辑器导出的Spine Skeleton.

![Export](/img/spine-runtimes-guide/spine-player/export.png)

除了导出的`.json`文件外, Web Player还需要一个由`.atlas`文件和一个或多个`.png`文件组成的texture atlas. 请参阅Spine用户指南中关于如何[导出skeleton为`JSON`](/spine-export)以及如何[导出texture atlas](/spine-texture-packer)的详细信息.

我们将使用[Spineboy项目](/spine-examples-spineboy)来完成下文中的示例, 为此导出了以下文件:

![Spineboy files](/img/spine-runtimes-guide/spine-ue4/exported-files.png)

这些文件应上传至一个网络服务器上, 再通过URL访问.

> `.png`文件需要与`.altas`文件在同一路径下. 例如, 如果`.atlas`文件可以通过`https://mysite.com/assets/spineboy.atlas`访问, `.png`文件也应可通过`https://mysite.com/assets/spineboy.png`访问.

## 嵌入Web Player

将Web Player嵌入你的网站需要完成简单的几步, 详细步骤如下:

### 添加JavaScript & CSS文件

Spine Web Player由两个文件组成: `spine-player.js`和`spine-player.css`. JS文件包含播放功能所需的JavaScript代码, 而CSS文件定义了Player的UI.

这两个文件可以像这样嵌入网页:

```
<script src="https://unpkg.com/@esotericsoftware/spine-player@4.1.*/dist/iife/spine-player.js"></script>
<link rel="stylesheet" href="https://unpkg.com/@esotericsoftware/spine-player@4.1.*/dist/spine-player.css">
```

在该示例中, 这两个文件是通过[UNPKG(一个快速的NPM CDN)](https://unpkg.com/)加载的. 这些URL包含一个版本号(`4.0`), 它必须与你用来导出skeleton和atlas的Spine编辑器版本相匹配. 像这样加载文件可以确保SpineWeb Player始终使用最新的JavaScript代码和CSS.

在UNPKG CDN上使用`.min.js`和`.min.css`文件扩展名, 则能使文件最小化:

```
<script src="https://unpkg.com/@esotericsoftware/spine-player@4.1.*/dist/iife/spine-player.min.js"></script>
<link rel="stylesheet" href="https://unpkg.com/@esotericsoftware/spine-player@4.1.*/dist/spine-player.min.css">
```

如果你不想使用UNPKG, 也可以通过从UNPKG下载文件或从我们的[GitHub仓库](/git/runtimes/spine-ts)上提供的源代码构建文件, 然后自己托管这些文件. 在这里还可以找到关于如何通过NPM或Yarn来使用Spine Web Player的说明.

### 创建container元素

Web Player需要一个可加载于其中的包裹元素. 最简单的方法是创建一个带有`id`的`div`元素:

```
<div id="player-container" style="width: 640px; height: 480px;"></div>
```

### 初始化Player

最后一步, 用一段简短的JavaScript代码来初始化Web Player:

```
<script>
new spine.SpinePlayer("player-container", {
		skeleton: "/files/spineboy/export/spineboy-pro.json",
		atlas: "/files/spineboy/export/spineboy.atlas",
});
</script>
```

这将在`player-container`元素中创建一个新的`SpinePlayer`. Web Player从相对路径URL`/files/spineboy/export/spineboy-pro.json`加载了skeleton的`.json`, 从`/files/spineboy/export/spineboy.atlas`加载了`.atlas`文件. 这个texture atlas有一个名为`spineboy.png`的页, 所以该图片是相对于`/files/spineboy/export/spineboy.png`的`.atlas`文件来加载的.

### 组合在一起

<div id="player-all-together" style="height: 660px"></div>
<script>
var code = "<script src=\"https://unpkg.com/@esotericsoftware/spine-player@4.2.*/dist/iife/spine-player.js\"></" + "script>\n<link rel=\"stylesheet\" href=\"https://unpkg.com/@esotericsoftware/spine-player@4.2.*/dist/spine-player.css\">\n\n<div id=\"player-container\" style=\"width: 100%; height: 100vh;\"></div>\n\n<script>\nnew spine.SpinePlayer(\"player-container\", {\n skeleton: \"https://esotericsoftware.com/files/examples/4.2/spineboy/export/spineboy-pro.json\",\n atlas: \"https://esotericsoftware.com/files/examples/4.2/spineboy/export/spineboy-pma.atlas\"\n});\n</" + "script>".trim();
spine.SpinePlayerEditor.DEFAULT_CODE = code;
var player = new spine.SpinePlayerEditor(document.getElementById("player-all-together"));
</script>
!!

> 以上的Web Player代码是可修改的！可以用它来试试下一节中的配置选项.

使用上述代码, Web Player将把其所有可配置的属性置为默认值: 播放哪种动画, 背景颜色等等等等. 你可以通过下面详述的配置进一步定制Web Player的外观和行为.

## 大功告成

Spine Web Player提供了广泛的配置选项, 以适应您的需求.

### JSON, 二进制和 atlas URL

在上面的例子中, 包含了两个必填的配置属性 `skeleton` 和 `atlas`. 它们指定了Web Player应从何处加载skeleton的`.json`或二进制`.skel`文件以及`.atlas`文件. 在这里填入相对URL和绝对URL都是可以的:

```
<script>
new spine.SpinePlayer("player-container", {
   // Relative URLs
   skeleton: "assets/spineboy.json",
   atlas: "assets/spineboy.atlas",
});

new spine.SpinePlayer("player-container", {
   // Absolute URLs
   skeleton: "https://esotericsoftware.com/files/examples/4.2/spineboy/export/spineboy-pro.skel",
   atlas: "https://esotericsoftware.com/files/examples/4.2/spineboy/export/spineboy-pma.atlas"
});
</script>
```

> 当使用另一个域上的绝对路径URL时, 浏览器有可能无法加载资产. 这通常是由于托管资产的服务器上没有启用[CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS).

### 内嵌数据

若您不希望从 URL 加载数据, 也可以在 JavaScript 源代码中直接嵌入原生 `.json/.skel`、`.atlas` 和 `.png`文件. 使用 `rawDataURIs` 配置属性即可实现:

```
new spine.SpinePlayer("player", {
		skeleton: "raptor-pro.json",
		atlas: "raptor-pma.atlas",
		rawDataURIs: {
			"raptor-pro.json": "data:application/json;base64,<base64 encoded raptor-pro.json>",
			"raptor-pma.atlas": "data:application/octet-stream;base64,<base64 encoded raptor-pma.atlas>",
			"raptor-pma.png": "data:image/png;base64,<base64 encoded raptor-pma.png>"
		}
}
```

`rawDataURIs` 也可用于使用来自不同路径甚至其他域(如果启用了 CORS)中的atlas图片.

```
			"raptor-pma.png": "https://example.com/assets/raptor.png"
```

### 默认动画

默认情况下, Web Player会播放在skeleton中找到的第一个动画. 默认动画也可以在配置中明确指定:

```
<script>
new spine.SpinePlayer("player-container", {
   ...
   animation: "walk" // Player will start with "walk" animation
});
</script>
```

### 动画限制

Web Player允许用户选择活动的动画. 可以用`animations`属性来限制可选动画集:

```
<script>
new spine.SpinePlayer("player-container", {
   ...
   animations: ["walk", "run", "jump"] // The user can only select one of these three animations
});
</script>
```

若只能选择一个动画, 动画按钮将被Web Player隐藏, 这可能是因为skeleton中只有一个动画, 或者是`animations`列表中只有一个动画.

### 默认mix时长

当在两个动画之间切换时, Web Player将默认动画mix时长为`0.25`秒, 以显示平滑的过渡. 这个mix时长可以通过`defaultMix`属性设置:

```
<script>
new spine.SpinePlayer("player-container", {
   ...
   defaultMix: 0.1 // Mix animation changes for 0.1 seconds
});
</script>
```

### 默认皮肤

默认情况下, Web Player将使用skeleton的默认皮肤, 它们是Spine编辑器中的非皮肤附件. 活动皮肤可以在配置中通过`skin`属性显式指定:

```
<script>
new spine.SpinePlayer("player-container", {
   ...
   skin: "funky" // Start with  the "funky" skin
});
</script>
```

### 皮肤限制

Web Player允许用户选择活动皮肤. 可以通过`skin`属性来限制可选皮肤集:

```
<script>
new spine.SpinePlayer("player-container", {
   ...
   skins: ["default", "funky"] // The user can only select one of these two skins
});
</script>
```

若只能选择一个皮肤, 皮肤按钮将被Web Player隐藏, 这可能是因为skeleton中只有一个皮肤, 或者`skins`列表中只有一个皮肤.

### Premultiplied alpha

默认情况下, Web Player在加载图像时会启用[premultiplied alpha](/spine-texture-packer#Settings). 要禁用premultiplied alpha, 必须设置`premultipliedAlpha`配置属性:

```
<script>
new spine.SpinePlayer("player-container", {
   ...
   premultipliedAlpha: false // Disable premultiplied alpha rendering
});
</script>
```

> 我们建议对所有Spine Web Player需显示的资产均使用premultiplied alpha. 它减少了不使用premultiplied alpha时可能出现的伪影和接缝问题.

### 隐藏控件

可以通过`showControls`配置属性来隐藏Web Player的控件:

```
<script>
new spine.SpinePlayer("player-container", {
   ...
   showControls: false // Hide the player controls
});
</script>
```

### Debug信息可视化

默认情况下, Web Player不显示任何调试的可视化信息, 如区域、网格三角形、骨骼等. 这些信息的显示可以由用户通过Web Player控件手动启用. 可以用`debug`属性来指定默认启用哪些调试信息的显示:

```
<script>
new spine.SpinePlayer("player-container", {
   ...
   debug: {
      bones: true, 
      regions: true,
      meshes: true,
      bounds: true,
      paths: true,
      clipping: true,
      points: true,
      hulls: true
   }
});
</script>
```

当然, 你可以略过任何你不想默认启用的可视化信息, 或将其各自属性置为`false`.

### 背景色

Web Player的背景色可以通过`backgroundColor`配置属性设置. 该颜色须被设置为十六进制的RGBA颜色(`#rrggbbaa`).

```
<script>
new spine.SpinePlayer("player-container", {
   ...
   backgroundColor: "#ff00ffff" // Magenta player background
});
</script>
```

Web Player可以切换为全屏. 全屏模式单独的背景色可以通过`fullscreenBackgroundColor`配置属性设置. 如果没有指定, 全屏背景色将与`backgroundColor`相同.

```
<script>
new spine.SpinePlayer("player-container", {
   ...
   backgroundColor: "#ff00ffff" // Magenta player background
   fullScreenBackgroundColor: "#00ff00ff" // Green player background in fullscreen mode
});
</script>
```

### 背景图片

Web Player也可以在skeleton后显示一张背景图片, 而非纯背景色. 该图像可以通过`backgroundImage`配置属性指定:

```
<script>
new spine.SpinePlayer("player-container", {
   ...
   backgroundImage: {  // Display a background image behind the skeleton
      url: "assets/background.png",
      x: 0,
      y: 0,
      width: 330,
      height: 330
   }
});
</script>
```

`url`是背景图片的相对或绝对URL. `x`和`y`属性指定了图像的左下角在skeleton的世界坐标空间中的位置. `width`和`height`属性指定了图像的尺寸.

### 半透明Web Player

默认情况下Web Player是不透明的, 它被绘制在任何其后的其他HTML元素上. `alpha`配置属性可以与`backgroundColor`属性结合使用, 使Web Player成为半透明的, 让后面的HTML元素透过Web Player.

```
<script>
new spine.SpinePlayer("player-container", {
   ...
   alpha: true, // Enable player translucency
   backgroundColor: "#00000000" // Background is fully transparent
});
</script>
```

### 视口

Web Player 总是试图填充它所嵌入的容器元素. 当选中了一个动画(或在配置中指定), Web Player 会确保该动画在 Web Player 可用的空间内完全可见.

![Viewport](/img/spine-runtimes-guide/spine-player/viewport.png)

在上图中, 绿色矩形代表了为 Spineboy 自动计算的`run`动画边界框. 默认情况下, 它每边都被 pad 了10%. 由此产生的视口, 由红色矩形表示, 然后保持视口长宽比后被嵌入到 Web Player 的可用空间中.

这种自动视口机制可以通过 Web Player 的配置来定制. 如果没有给出视口配置, Web Player 自动将采用上述行为默认行为.

你可以设置用于所有动画的**全局视口**, 像这样:

```
<script>
new spine.SpinePlayer("player-container", {
   ...
   viewport: {
      x: 0,
      y: 0,
      width: 300,
      height: 300,
      padLeft: "5%",
      padRight: "5%",
      padTop: "5%",
      padBottom: "5%"
   }
});
</script>
```

`x`和`y`属性指定视口的左下角在skeleton的世界坐标空间中的位置. `width`和`height`属性指定了视口的尺寸. 如果这些属性中的任何一个被省略, Web Player就会忽略所有其他的属性, 转而使用上述的自动行为.

`padLeft`、`padRight`、`padTop`和`padBottom`属性指定了要添加到视口各边的填充量. 在上面的例子中, 它们表为百分比. 你也可以指定在skeleton的世界坐标空间中的绝对数值. 如果这些属性中的一个被省略了, Web Player就会使用默认值`10%`.

你可以通过指定`debugRender`属性来**可视化视口**, 如上图所示:

```
<script>
new spine.SpinePlayer("player-container", {
   ...
   viewport: {
      ...
      debugRender: true // Show the viewport bounds
   }
});
</script>
```

当Web Player在动画之间切换时, 它会将新旧动画的视口间进行`0.2`秒的插值. 这个**视口转换时间**可以通过`transitionTime`属性设置:

```
<script>
new spine.SpinePlayer("player-container", {
   ...
   viewport: {
      ...
      transitionTime: 1 // Transition  between viewports for 1 second
   }
});
</script>
```

有时, **为一个特定的动画指定一个视口**是很有帮助的. 这可以通过`animations`属性来实现:

```
<script>
new spine.SpinePlayer("player-container", {
   ...
   viewport: {
      ...
      animations: {
         "walk": {
            x: 0,
            y: 0,
            width: 300,
            height: 300,
            padLeft: "5%",
            padRight: "5%",
            padTop: "5%",
            padBottom: "5%"
         },
         "run": {
            padTop: "20%",
         }
      }
   }
});
</script>
```

在上例中, 我们为`walk`和`run`动画各指定了一个视口. 对于`walk`动画, 我们定义了完整的视口边界, 包括padding. 全局视口(如果没有给出全局视口, 则为自动行为)将完全覆盖这个动画.

而对于`run`动画, 我们只指定了顶部的padding. 所有其他的视口设置值将来自全局视口设置, 或者是自动行为.

## 生命周期回调

Web Player 提供了可选的回调函数, 用于介入资产加载生命周期和渲染循环. 所有回调函数都将 `SpinePlayer` 实例作为其第一个参数.
以下示例一目了然地展示了所有可用的回调函数:

```
<script>
new spine.SpinePlayer("player-container", {
   ...
   // Called each frame while assets are still being loaded.
   loading: function (player, delta) {
      console.log("Still loading...");
   },
   // Called when the skeleton and its assets have been successfully loaded.
   success: function (player) {
      console.log("Skeleton loaded!");
   },
   // Called when the skeleton could not be loaded or rendered.
   error: function (player, reason) {
      alert(reason);
   },
   // Called at the start of each frame, before the skeleton is posed or drawn.
   frame: function (player, delta) {
      console.log("Frame start, delta: " + delta);
   },
   // Called instead of the default skeleton.updateWorldTransform(Physics.update).
   updateWorldTransform: function (player, delta) {
      player.skeleton.updateWorldTransform(spine.Physics.update);
   },
   // Called after the skeleton is posed, before it is drawn.
   update: function (player, delta) {
      console.log("Skeleton posed, about to draw.");
   },
   // Called after the skeleton is drawn.
   draw: function (player, delta) {
      console.log("Skeleton drawn.");
   }
});
</script>
```

当资源正在加载时, `loading` 回调函数每帧都会被调用. 它的 `delta` 是原始的帧间隔时间, 不受暂停或速度的影响. 加载完成后, 将会调用 `success` 或 `error` 回调. 成功时, Web Player 的 `skeleton` 和 `animationState` 属性变得可用, 渲染循环开始. 每一帧中, 以下回调函数按顺序被调用: `frame` → 动画更新 → `updateWorldTransform` → `update` → 绘制skeleton → `draw`. 它们的 `delta` 参数以秒为单位, 已经根据 Web Player 的速度和暂停状态进行了缩放(暂停时为 `0`).

| 回调函数 | 参数 | 描述 |
|---|---|---|
| `loading` | `player`, `delta` | 在 skeleton 可用前资源加载过程中每帧调用. `delta` 是原始的帧间隔时间(不受暂停或速度影响). 使用此回调来实现自定义加载指示器. |
| `success` | `player` | 当 skeleton 及其资源成功加载后调用. 从此时起, Web Player 的 `skeleton` 和 `animationState` 属性将会可用. 如果在此回调中设置了轨道0上的动画, Web Player 将不会设置自己的默认动画. |
| `error` | `player`, `reason` | 当 skeleton 无法加载或渲染时调用. `reason` 参数是一个人类可读的错误消息. |
| `frame` | `player`, `delta` | 在 skeleton 摆出姿势或绘制 skeleton 之前, 于每帧开始时调用. 使用此回调在动画状态更新前执行自定义逻辑. |
| `updateWorldTransform` | `player`, `delta` | 替代默认的 `skeleton.updateWorldTransform(Physics.update)` 调用. 使用此回调来自定义世界变换的计算方式, 例如使用不同的 `Physics` 模式. 如果未设置, Web Player 会自动调用 `player.skeleton.updateWorldTransform(spine.Physics.update)`. |
| `update` | `player`, `delta` | Skeleton 摆出姿势后到绘制 skeleton 之前这期间, 于每帧中调用(在 `updateWorldTransform` 之后). 使用此回调在渲染前检查或修改 skeleton 的状态. 如果在此处修改了 skeleton, 请调用 `player.skeleton.updateWorldTransform(spine.Physics.none)` 使更改生效. |
| `draw` | `player`, `delta` | 在每帧中绘制了 skeleton 后调用. 使用此回调可通过 Web Player 的 `SceneRenderer` 进行自定义 skeleton 渲染. |

## 高级回放设置

Web Player提供了函数 `setAnimation(name: string, loop: boolean)` 来设置一个动画的名称并指定它是否循环. 这个函数根据指定的动画来调整[视口](#视口).

`setAnimation` 在 `success` 回调触发后才能被调用, 这个回调在 atlas 和 skeleton数据加载完成时就会触发.

```
<script>
new spine.SpinePlayer("player-container", {
   ...
   success: function (player) {
      player.setAnimation("run", true);
   }
});
</script>
```

为了实现更多的控制, 可以直接访问Web Player的[Skeleton](/spine-api-reference#Skeleton)和[AnimationState](/spine-api-reference#AnimationState)来设置skeleton上的附件, 改变skeleton的皮肤, 队列动画, 在不同的轨道上一次播放多个动画及[更多](/spine-applying-animations)操作. Web Player提供了`skeleton`和`animationState`属性:

```
<script>
new spine.SpinePlayer("player-container", {
   ...
   success: function (player) {
      player.skeleton.setAttachment("weapon", "sword");
      player.animationState.setAnimation(0, "jump");
      player.animationState.addAnimation(0, "walk", true, 0);
   }
});
</script>
```

当直接访问这些属性时, 建议设置`showControls: false`, 这样控件输入就不会干扰你代码所设置的配置.

默认情况下, [视口](#视口)是基于[默认动画](#默认动画)中skeleton的边界. 与Web Player的`setAnimation`函数不同, 当用动画状态来改变动画时视口也保持不变.