chore: dist/ 改为构建产物,从版本库摘除
用户裁定:dist 是产物,不是源码。构建管线与产物拓扑见并发的重构所写的 ADR 0005。 - `git rm -r --cached dist`——只摘索引,**磁盘文件原样保留**。摘除前 dist/ 有 33 个跟踪文件。 - 一并纳入 .gitignore 中已有的 `dist/` 规则(该规则由并发的重构写入),使摘除真正生效; 否则这些文件会以未跟踪身份继续堆在 git status 里。同时纳入的还有 `node_modules/` 与 `.scratch/dist-baseline/` 两条同类忽略规则。 - 之前的两次提交(`eb56efb`、`0ca78ed`)按旧约定把 dist/ 收进了版本库,本次把定位纠回来。 **历史里的 dist blob 不删**:需要旧版产物或那份无损音频时仍可从历史取回。 源码侧的真相现在是 `src/` + `wallpapers/` + `tools/`。 只做索引层面的摘除,不触碰其它任何改动——同一工作区里还有一个重构在实时写盘。
No files matched your search
@@ -2,6 +2,13 @@
|
|||||||
tools/shots/
|
tools/shots/
|
||||||
tools/.cache/
|
tools/.cache/
|
||||||
|
|
||||||
|
# 构建产物:dist/ 完全由 pnpm build 生成(releases/ + dist-map.json)。
|
||||||
|
# 它与源码树必然漂移,且是全量拷贝(约 290 MB),因此不入库。
|
||||||
|
dist/
|
||||||
|
|
||||||
|
# 重构前的基线快照:只作为"重构等价性"的临时判据,验证完即删,不入库。
|
||||||
|
.scratch/dist-baseline/
|
||||||
|
|
||||||
# 对拍中间产物:截图、抽取帧、试压的 GIF 都是可重生成的二进制,不入库
|
# 对拍中间产物:截图、抽取帧、试压的 GIF 都是可重生成的二进制,不入库
|
||||||
.scratch/*.png
|
.scratch/*.png
|
||||||
.scratch/*.gif
|
.scratch/*.gif
|
||||||
@@ -11,3 +18,4 @@ masters/
|
|||||||
|
|
||||||
# 杂项
|
# 杂项
|
||||||
*.log
|
*.log
|
||||||
|
node_modules/
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
【崩坏:星穹铁道】昔涟
|
|
||||||
[b]特色功能[/b]
|
|
||||||
[list]
|
|
||||||
[*]支持切换预设。
|
|
||||||
[olist]
|
|
||||||
[*]官方昔涟动态立绘。
|
|
||||||
[*]官方三点七版本「成为昨日的明天」专题展示页。
|
|
||||||
[/olist]
|
|
||||||
[*]支持音源切换。
|
|
||||||
[olist]
|
|
||||||
[*][quote][b]注意:[/b]目前仅支持 URL 格式。[/quote]
|
|
||||||
[/olist]
|
|
||||||
[/list]
|
|
||||||
|
|
||||||
[Honkai: Star Rail] Cryene
|
|
||||||
[b]Special Features[/b]
|
|
||||||
[list]
|
|
||||||
[*]Supports switching presets.
|
|
||||||
[olist]
|
|
||||||
[*]Official Xilian dynamic portraits.
|
|
||||||
[*]Official version 3.7 "As Tomorrow Became Yesterday" special showcase page.
|
|
||||||
[/olist]
|
|
||||||
[*]Supports switching audio sources.
|
|
||||||
[olist]
|
|
||||||
[*][quote][b]Note: [/b]Currently only URL format is supported.[/quote]
|
|
||||||
[/olist]
|
|
||||||
[/list]
|
|
||||||
|
Before Width: | Height: | Size: 700 KiB |
|
Before Width: | Height: | Size: 183 KiB |
|
Before Width: | Height: | Size: 419 KiB |
|
Before Width: | Height: | Size: 349 KiB |
|
Before Width: | Height: | Size: 830 KiB |
|
Before Width: | Height: | Size: 2.8 MiB |
@@ -1,34 +0,0 @@
|
|||||||
// 「成为昨日的明天」—— 官方 3.7 版本专题展示页
|
|
||||||
// 这份预设自带全部资源,路径由 import.meta.url 从本文件位置推导,
|
|
||||||
// 因此整个目录可以整体搬走或改名,而不用改这里的任何一行。
|
|
||||||
|
|
||||||
const base = new URL("./", import.meta.url);
|
|
||||||
const asset = (path) => new URL(path, base).href;
|
|
||||||
|
|
||||||
export default {
|
|
||||||
id: "kv37", // 与 project.json 中 combo 选项的 value 一致,勿改
|
|
||||||
name: "「成为昨日的明天」",
|
|
||||||
game: "崩坏:星穹铁道",
|
|
||||||
|
|
||||||
backgroundImage: asset("./images/kv37_xilian.webp"),
|
|
||||||
|
|
||||||
spineConfig: {
|
|
||||||
jsonUrl: asset("./effects/kv37.json"),
|
|
||||||
atlasUrl: asset("./images/kv37.atlas"),
|
|
||||||
animation: "animation",
|
|
||||||
viewport: {
|
|
||||||
x: -1215,
|
|
||||||
y: -410,
|
|
||||||
width: 2048,
|
|
||||||
height: 1024,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
audioOptions: {
|
|
||||||
source: asset("./audios/pv37.mp3"),
|
|
||||||
volume: 0.5,
|
|
||||||
},
|
|
||||||
|
|
||||||
// 本壁纸可选的音源(第 6 步会接进 project.json 的 bgm 属性)
|
|
||||||
audioChoices: [{ id: "pv37", name: "版本 PV", source: asset("./audios/pv37.mp3") }],
|
|
||||||
};
|
|
||||||
|
Before Width: | Height: | Size: 239 KiB |
|
Before Width: | Height: | Size: 1.8 MiB |
|
Before Width: | Height: | Size: 2.8 MiB |
|
Before Width: | Height: | Size: 1.8 MiB |
@@ -1,37 +0,0 @@
|
|||||||
// 昔涟立绘 —— 官方昔涟动态立绘
|
|
||||||
// 这份预设自带全部资源,路径由 import.meta.url 从本文件位置推导,
|
|
||||||
// 因此整个目录可以整体搬走或改名,而不用改这里的任何一行。
|
|
||||||
|
|
||||||
const base = new URL("./", import.meta.url);
|
|
||||||
const asset = (path) => new URL(path, base).href;
|
|
||||||
|
|
||||||
export default {
|
|
||||||
id: "xilian", // 与 project.json 中 combo 选项的 value 一致,勿改
|
|
||||||
name: "昔涟立绘",
|
|
||||||
game: "崩坏:星穹铁道",
|
|
||||||
|
|
||||||
backgroundImage: asset("./images/ava.jpg"),
|
|
||||||
|
|
||||||
spineConfig: {
|
|
||||||
jsonUrl: asset("./effects/xilian.json"),
|
|
||||||
atlasUrl: asset("./images/xilian.atlas"),
|
|
||||||
animation: "idle",
|
|
||||||
viewport: {
|
|
||||||
padLeft: "-25%",
|
|
||||||
padRight: "-28%",
|
|
||||||
padTop: "-30%",
|
|
||||||
padBottom: "-23%",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
audioOptions: {
|
|
||||||
source: asset("./audios/「再度和你」.flac"),
|
|
||||||
volume: 0.5,
|
|
||||||
},
|
|
||||||
|
|
||||||
// 本壁纸可选的音源(第 6 步会接进 project.json 的 bgm 属性)
|
|
||||||
audioChoices: [
|
|
||||||
{ id: "zaiduheni", name: "「再度和你」", source: asset("./audios/「再度和你」.flac") },
|
|
||||||
{ id: "xilian", name: "昔涟", source: asset("./audios/昔涟.flac") },
|
|
||||||
],
|
|
||||||
};
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="zh">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
||||||
<title>昔涟动态立绘</title>
|
|
||||||
<!-- 空数据图标:否则 CEF 会自动请求 /favicon.ico 并在控制台留下 404 报错 -->
|
|
||||||
<link rel="icon" href="data:," />
|
|
||||||
<link rel="stylesheet" href="./styles/spine-player.css" />
|
|
||||||
<link rel="stylesheet" href="./styles/index.css" />
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="spine-container"></div>
|
|
||||||
<audio id="background-music"></audio>
|
|
||||||
<script type="text/javascript" src="./scripts/spine-player.js"></script>
|
|
||||||
<script type="module" src="./scripts/index.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
Before Width: | Height: | Size: 347 KiB |
@@ -1,139 +0,0 @@
|
|||||||
{
|
|
||||||
"contentrating" : "Everyone",
|
|
||||||
"description" : "[b]特色功能[/b]\r\n[list]\r\n [*]支持切换预设。\r\n [olist]\r\n [*]官方昔涟动态立绘。\r\n [*]官方三点七版本「成为昨日的明天」专题展示页。\r\n [/olist]\r\n [*]支持音源切换。\r\n [olist]\r\n [*]可切换各预设自带的背景音乐。\r\n [*]也可自行填写音频 URL。\r\n [*][quote][b]注意:[/b]目前仅支持 URL 格式。[/quote]\r\n [/olist]\r\n [*]自适应窗口比例,不同显示器下构图保持一致。\r\n[/list]",
|
|
||||||
"file" : "index.html",
|
|
||||||
"general" :
|
|
||||||
{
|
|
||||||
"properties" :
|
|
||||||
{
|
|
||||||
"audio_file" :
|
|
||||||
{
|
|
||||||
"index" : 6,
|
|
||||||
"order" : 106,
|
|
||||||
"text" : "🎵音频文件路径",
|
|
||||||
"type" : "textinput",
|
|
||||||
"value" : ""
|
|
||||||
},
|
|
||||||
"audio_file_note" :
|
|
||||||
{
|
|
||||||
"index" : 7,
|
|
||||||
"order" : 107,
|
|
||||||
"text" : "<small>更换背景音乐来源:<ul><li>🚨注意:目前仅支持 URL 链接。</li><li>当音源不可用时会切换至上一音源。</li></ul></small><br />",
|
|
||||||
"type" : "text"
|
|
||||||
},
|
|
||||||
"audio_volume" :
|
|
||||||
{
|
|
||||||
"fraction" : true,
|
|
||||||
"index" : 4,
|
|
||||||
"max" : 1,
|
|
||||||
"min" : 0,
|
|
||||||
"order" : 104,
|
|
||||||
"precision" : 1,
|
|
||||||
"step" : 0.1,
|
|
||||||
"text" : "🔊音频音量调整",
|
|
||||||
"type" : "slider",
|
|
||||||
"value" : 1
|
|
||||||
},
|
|
||||||
"audio_volume_note" :
|
|
||||||
{
|
|
||||||
"index" : 5,
|
|
||||||
"order" : 105,
|
|
||||||
"text" : "<small>调整背景音乐音量:<ul><li>为零时暂停。</li><li>为一时最大。</li></ul></small><br />",
|
|
||||||
"type" : "text"
|
|
||||||
},
|
|
||||||
"author_info" :
|
|
||||||
{
|
|
||||||
"condition" : "show_author_info.value == true",
|
|
||||||
"index" : 1,
|
|
||||||
"order" : 101,
|
|
||||||
"text" : "<small>作者信息:<ul><li>作者:品毅</li><li>QQ:2463253700</li><li>哔哩哔哩:<a href=\"https://space.bilibili.com/72266376\">品毅的个人空间</a></li></ul></small><br />",
|
|
||||||
"type" : "text"
|
|
||||||
},
|
|
||||||
"bgm" :
|
|
||||||
{
|
|
||||||
"index" : 8,
|
|
||||||
"options" :
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"label" : "随预设",
|
|
||||||
"value" : "auto"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label" : "「再度和你」",
|
|
||||||
"value" : "zaiduheni"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label" : "昔涟",
|
|
||||||
"value" : "xilian"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label" : "版本 PV",
|
|
||||||
"value" : "pv37"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"order" : 108,
|
|
||||||
"text" : "🎵背景音乐选择",
|
|
||||||
"type" : "combo",
|
|
||||||
"value" : "auto"
|
|
||||||
},
|
|
||||||
"bgm_note" :
|
|
||||||
{
|
|
||||||
"index" : 9,
|
|
||||||
"order" : 109,
|
|
||||||
"text" : "<small>选择各预设自带的背景音乐:<ul><li>默认「随预设」跟随壁纸切换。</li><li>所选项不属于当前壁纸时,自动回落该壁纸的默认音乐,选择仍会保留。</li></ul></small><br />",
|
|
||||||
"type" : "text"
|
|
||||||
},
|
|
||||||
"preset" :
|
|
||||||
{
|
|
||||||
"index" : 2,
|
|
||||||
"options" :
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"label" : "昔涟立绘",
|
|
||||||
"value" : "xilian"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label" : "「成为昨日的明天」",
|
|
||||||
"value" : "kv37"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"order" : 102,
|
|
||||||
"text" : "⚙️壁纸预设切换<br />",
|
|
||||||
"type" : "combo",
|
|
||||||
"value" : "xilian"
|
|
||||||
},
|
|
||||||
"preset_note" :
|
|
||||||
{
|
|
||||||
"index" : 3,
|
|
||||||
"order" : 103,
|
|
||||||
"text" : "<small>切换壁纸预设(包括背景、音乐、动画):<ul><li>当其它选项存在更改,不会覆盖其它选项。</li></ul></small><br />",
|
|
||||||
"type" : "text"
|
|
||||||
},
|
|
||||||
"schemecolor" :
|
|
||||||
{
|
|
||||||
"order" : 0,
|
|
||||||
"text" : "ui_browse_properties_scheme_color",
|
|
||||||
"type" : "color",
|
|
||||||
"value" : "0.38823529411764707 0.14901960784313725 0.6196078431372549"
|
|
||||||
},
|
|
||||||
"show_author_info" :
|
|
||||||
{
|
|
||||||
"index" : 0,
|
|
||||||
"order" : 100,
|
|
||||||
"text" : "📇显示作者信息",
|
|
||||||
"type" : "bool",
|
|
||||||
"value" : true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"preview" : "preview.gif",
|
|
||||||
"ratingsex" : "none",
|
|
||||||
"ratingviolence" : "none",
|
|
||||||
"tags" : [ "Anime" ],
|
|
||||||
"title" : "【崩坏:星穹铁道】昔涟",
|
|
||||||
"type" : "Web",
|
|
||||||
"version" : 3,
|
|
||||||
"visibility" : "public",
|
|
||||||
"workshopid" : "3604974793",
|
|
||||||
"workshopurl" : "steam://url/CommunityFilePage/3604974793"
|
|
||||||
}
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
// 背景音乐。
|
|
||||||
//
|
|
||||||
// 两条交互约定:
|
|
||||||
// 1. 音源与音量是「用户级覆盖」:切换壁纸不得把用户自定义的音源/音量清回预设默认值。
|
|
||||||
// 2. 音源相同的设置是 no-op:否则两档壁纸共用同一首曲子时,一切换就把音乐从头开始放。
|
|
||||||
export default class AudioController {
|
|
||||||
constructor(audioId, options = {}) {
|
|
||||||
this.audio = document.getElementById(audioId);
|
|
||||||
this.isPlaying = false;
|
|
||||||
this.retryTimer = undefined;
|
|
||||||
this.audio.loop = true;
|
|
||||||
|
|
||||||
if (options.source) this.setSource(options.source);
|
|
||||||
if (options.volume !== undefined) this.setVolume(options.volume);
|
|
||||||
}
|
|
||||||
|
|
||||||
// audio.src 会被解析成绝对 URL;预设里的 source 也是绝对 URL(preset.js 用 import.meta.url 推导)
|
|
||||||
get source() {
|
|
||||||
return this.audio.src || "";
|
|
||||||
}
|
|
||||||
|
|
||||||
setSource(source) {
|
|
||||||
if (!source) return;
|
|
||||||
if (this.source === new URL(source, document.baseURI).href) return;
|
|
||||||
|
|
||||||
const wasPlaying = this.isPlaying;
|
|
||||||
this.audio.src = source;
|
|
||||||
this.audio.load();
|
|
||||||
if (wasPlaying) this.play();
|
|
||||||
}
|
|
||||||
|
|
||||||
setVolume(volume) {
|
|
||||||
const value = Math.max(0, Math.min(1, Number(volume)));
|
|
||||||
this.audio.volume = Number.isFinite(value) ? value : 1;
|
|
||||||
|
|
||||||
if (this.audio.volume <= 0) this.pause();
|
|
||||||
else if (!this.isPlaying) this.play();
|
|
||||||
}
|
|
||||||
|
|
||||||
play() {
|
|
||||||
if (this.isPlaying) return;
|
|
||||||
|
|
||||||
this.audio.play().then(
|
|
||||||
() => {
|
|
||||||
this.isPlaying = true;
|
|
||||||
},
|
|
||||||
(error) => {
|
|
||||||
this.isPlaying = false;
|
|
||||||
// 只重试一次:自动播放被拒时重试多少次都没用,重试只是覆盖"音频尚未就绪"
|
|
||||||
if (this.retryTimer === undefined) {
|
|
||||||
this.retryTimer = setTimeout(() => {
|
|
||||||
this.retryTimer = undefined;
|
|
||||||
this.play();
|
|
||||||
}, 500);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
pause() {
|
|
||||||
this.audio.pause();
|
|
||||||
this.isPlaying = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
// 背景图:只在真的换了图时写一次样式。
|
|
||||||
export default class BackgroundController {
|
|
||||||
constructor() {
|
|
||||||
this.appliedImage = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
setImage(backgroundImage) {
|
|
||||||
if (!backgroundImage || backgroundImage === this.appliedImage) return;
|
|
||||||
this.appliedImage = backgroundImage;
|
|
||||||
// 用引号包住,避免路径里出现空格等字符时被 CSS 解析成多个值
|
|
||||||
document.body.style.backgroundImage = `url("${backgroundImage}")`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,122 +0,0 @@
|
|||||||
import Presets from "./presets.js";
|
|
||||||
|
|
||||||
import PresetController from "./preset-controller.js";
|
|
||||||
import BackgroundController from "./background-controller.js";
|
|
||||||
import SpineController from "./spine-controller.js";
|
|
||||||
import AudioController from "./audio-controller.js";
|
|
||||||
|
|
||||||
// 与 project.json 里属性的默认值保持一致
|
|
||||||
const DEFAULT_PRESET_ID = "xilian";
|
|
||||||
const DEFAULT_VOLUME = 0.5;
|
|
||||||
|
|
||||||
const presets = new PresetController(Presets);
|
|
||||||
|
|
||||||
const backgroundController = new BackgroundController();
|
|
||||||
const spineController = new SpineController("spine-container");
|
|
||||||
const audioController = new AudioController("background-music");
|
|
||||||
|
|
||||||
// 唯一的真相来源。WE 可能在 window.load 之前就下发用户属性,所以这里只记录状态;
|
|
||||||
// 渲染时再决定"能不能立刻应用"——只有播放器需要等到 load 之后才存在。
|
|
||||||
const state = {
|
|
||||||
ready: false,
|
|
||||||
presetId: "",
|
|
||||||
audioSource: "", // 空字符串 = 用当前预设的默认音源
|
|
||||||
audioVolume: DEFAULT_VOLUME,
|
|
||||||
bgm: "", // 空字符串 = 随预设;否则是某个 preset.js 里 audioChoices 的 id
|
|
||||||
};
|
|
||||||
|
|
||||||
let appliedPresetId = "";
|
|
||||||
|
|
||||||
// 量出背景图的真实宽高比:立绘层要靠它才能和背景同步缩放。
|
|
||||||
// 直接读图片,避免在预设里再手写一个容易写错的数字。
|
|
||||||
function measureImageAspect(url) {
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
if (!url) {
|
|
||||||
resolve(undefined);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const probe = new Image();
|
|
||||||
probe.onload = () => resolve(probe.naturalWidth / probe.naturalHeight);
|
|
||||||
probe.onerror = () => resolve(undefined);
|
|
||||||
probe.src = url;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// bgm combo 选中的音源只在本壁纸声明过时才生效。否则回落本壁纸默认音源——
|
|
||||||
// 选择本身记着不动,切回那份壁纸时用户的选择还在。
|
|
||||||
function bgmSource(preset) {
|
|
||||||
if (!state.bgm) return "";
|
|
||||||
const choices = preset.audioChoices || [];
|
|
||||||
const hit = choices.find((choice) => choice.id === state.bgm);
|
|
||||||
return hit ? hit.source : "";
|
|
||||||
}
|
|
||||||
|
|
||||||
function render() {
|
|
||||||
const presetId = state.presetId || DEFAULT_PRESET_ID;
|
|
||||||
const preset = presets.get(presetId);
|
|
||||||
if (!preset) return;
|
|
||||||
|
|
||||||
// 只有壁纸真的换了才碰背景与骨架。否则拖动音量滑块都会重建播放器
|
|
||||||
// (重建 = 重新下载 3.4 MB 骨架与全部贴图)。
|
|
||||||
if (appliedPresetId !== presetId) {
|
|
||||||
appliedPresetId = presetId;
|
|
||||||
backgroundController.setImage(preset.backgroundImage);
|
|
||||||
spineController.setConfig(preset.spineConfig); // 播放器还不存在时只是记下来
|
|
||||||
// 图片解码是异步的,回来时可能已经切到别的预设了,所以要核对一次
|
|
||||||
measureImageAspect(preset.backgroundImage).then((aspect) => {
|
|
||||||
if (appliedPresetId === presetId) spineController.setImageAspect(aspect);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 音源优先级:用户自填 URL > bgm 里选的(若本壁纸有)> 本壁纸默认音源
|
|
||||||
audioController.setSource(state.audioSource || bgmSource(preset) || preset.audioOptions.source);
|
|
||||||
audioController.setVolume(state.audioVolume);
|
|
||||||
if (state.ready) audioController.play();
|
|
||||||
}
|
|
||||||
|
|
||||||
window.addEventListener("load", function () {
|
|
||||||
state.ready = true;
|
|
||||||
render(); // 先把状态落到各控制器(此时播放器尚不存在,只写配置)
|
|
||||||
spineController.create(); // 再用写好的配置创建播放器
|
|
||||||
});
|
|
||||||
|
|
||||||
// 必须在模块顶层注册:属性事件可能在 window.load 之前到达
|
|
||||||
window.wallpaperPropertyListener = {
|
|
||||||
applyUserProperties: function (properties) {
|
|
||||||
// 先写状态:无条件记录,与播放器是否存在、是否加载完成无关
|
|
||||||
if (properties.preset) {
|
|
||||||
const presetId = properties.preset.value;
|
|
||||||
if (presets.has(presetId)) {
|
|
||||||
state.presetId = presetId;
|
|
||||||
} else if (presetId) {
|
|
||||||
console.warn(`忽略未知的预设 id:${presetId}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (properties.audio_file) {
|
|
||||||
state.audioSource = String(properties.audio_file.value || "").trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (properties.bgm) {
|
|
||||||
const bgm = String(properties.bgm.value || "").trim();
|
|
||||||
state.bgm = bgm === "auto" ? "" : bgm;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (properties.audio_volume) {
|
|
||||||
const volume = Number(properties.audio_volume.value);
|
|
||||||
if (Number.isFinite(volume)) {
|
|
||||||
state.audioVolume = Math.max(0, Math.min(1, volume));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render();
|
|
||||||
},
|
|
||||||
|
|
||||||
applyGeneralProperties: function (properties) {
|
|
||||||
// WE 不会替壁纸限流,fps 得自己落实。这个属性与预设无关,不进 state。
|
|
||||||
// 判 undefined 而不是真值:0 表示不限流,用真值判断会把"取消限流"整个吞掉。
|
|
||||||
if (properties.fps !== undefined) {
|
|
||||||
spineController.setFps(properties.fps);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
// 预设查表:id → 预设数据。
|
|
||||||
// 预设数据是 ES module 里的模块级常量,返回深拷贝,避免调用方改坏它。
|
|
||||||
// 注意 id 必须与 project.json 里 combo 选项的 value 一致(见 docs/adr/0001)。
|
|
||||||
export default class PresetController {
|
|
||||||
constructor(presets) {
|
|
||||||
this.presets = presets;
|
|
||||||
this.currentId = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
get ids() {
|
|
||||||
return Object.keys(this.presets);
|
|
||||||
}
|
|
||||||
|
|
||||||
has(id) {
|
|
||||||
return Boolean(this.presets[id]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 未知 id 返回 null,由调用方决定是保持现状还是回退——不在这里悄悄改成别的预设
|
|
||||||
get(id) {
|
|
||||||
const preset = this.presets[id];
|
|
||||||
if (!preset) return null;
|
|
||||||
this.currentId = id;
|
|
||||||
return JSON.parse(JSON.stringify(preset));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
// 预设索引:把每份壁纸自己的 preset.js 汇总成 id → 预设 的查表。
|
|
||||||
//
|
|
||||||
// id 必须与 project.json 里 combo 选项的 value 一致(xilian / kv37),
|
|
||||||
// 改了会让老用户已保存的预设选择失效,所以 id 永远跟着 WE 属性走,
|
|
||||||
// 而目录名(游戏名/壁纸显示名)是给人看的、可以改。
|
|
||||||
|
|
||||||
import xilian from "../assets/崩坏:星穹铁道/昔涟立绘/preset.js";
|
|
||||||
import kv37 from "../assets/崩坏:星穹铁道/「成为昨日的明天」/preset.js";
|
|
||||||
|
|
||||||
const Presets = Object.fromEntries([xilian, kv37].map((preset) => [preset.id, preset]));
|
|
||||||
|
|
||||||
export default Presets;
|
|
||||||
@@ -1,174 +0,0 @@
|
|||||||
import { REFERENCE_ASPECT, contain, frameForAspect, resolveViewport, toViewportConfig } from "./viewport-fitter.js";
|
|
||||||
|
|
||||||
// 负责把「当前预设的 spineConfig」应用到 Spine 播放器上,并维持立绘层与背景图的取景同步。
|
|
||||||
//
|
|
||||||
// 核心约定一:写入与应用分开。WE 可能在 window.load 之前就下发用户属性,那时播放器还不存在;
|
|
||||||
// 旧实现把配置赋值也塞在 `if (this.player)` 里,于是那次配置被静默丢弃,
|
|
||||||
// 结果是"背景与音乐已切到新壁纸、立绘还是旧壁纸"的混合状态(已实测复现)。
|
|
||||||
// 现在 setConfig() 无论如何都记下配置,create() 用记下的配置创建。
|
|
||||||
//
|
|
||||||
// 核心约定二:窗口尺寸变化绝不重建播放器。重建意味着重新下载 3.4 MB 骨架与全部贴图;
|
|
||||||
// 取景只是 viewport 的算术,改写 config.viewport 后调 setViewport() 就地生效。
|
|
||||||
export default class SpineController {
|
|
||||||
constructor(containerId, baseConfig = {}) {
|
|
||||||
this.containerId = containerId;
|
|
||||||
this.baseConfig = {
|
|
||||||
alpha: true,
|
|
||||||
premultipliedAlpha: false,
|
|
||||||
showControls: false,
|
|
||||||
showLoading: false,
|
|
||||||
...baseConfig,
|
|
||||||
};
|
|
||||||
|
|
||||||
this.presetConfig = {};
|
|
||||||
this.container = document.getElementById(containerId);
|
|
||||||
this.player = undefined;
|
|
||||||
|
|
||||||
this.framingEnabled = true;
|
|
||||||
this.imageAspect = undefined; // 背景图宽高比,决定立绘层与背景的缩放关系
|
|
||||||
this.framing = undefined; // 作者视口(换算到参考比例后的可见矩形)+ 动画名
|
|
||||||
this.appliedAspect = undefined; // 上一次已应用的画布比例
|
|
||||||
|
|
||||||
this.fps = 0; // 0 = 不限流。WE 不会替壁纸限流,得自己门控绘制
|
|
||||||
this.rawDrawFrame = undefined; // 被包裹前的 drawFrame,用于换档时摘掉旧包装
|
|
||||||
}
|
|
||||||
|
|
||||||
// 只写状态:与播放器是否存在无关,随时可调用
|
|
||||||
setConfig(presetConfig = {}) {
|
|
||||||
this.presetConfig = presetConfig;
|
|
||||||
// 预设可声明 framing:"author" 保留作者原始的「含住视口」行为,不跟随背景缩放
|
|
||||||
this.framingEnabled = presetConfig.framing !== "author";
|
|
||||||
this.framing = undefined;
|
|
||||||
this.appliedAspect = undefined;
|
|
||||||
if (this.player) this.rebuild();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 背景图换了,取景常数也要跟着换(比例一变就重新推导)
|
|
||||||
setImageAspect(aspect) {
|
|
||||||
if (!(aspect > 0) || aspect === this.imageAspect) return;
|
|
||||||
this.imageAspect = aspect;
|
|
||||||
this.appliedAspect = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
create() {
|
|
||||||
if (this.player) return;
|
|
||||||
// 每次都用 baseConfig + 当前 presetConfig 现算,避免上一份预设的键残留。
|
|
||||||
// frame 放在最后:它是内部钩子,不允许被预设数据覆盖。
|
|
||||||
this.rawDrawFrame = undefined;
|
|
||||||
this.player = new spine.SpinePlayer(this.containerId, {
|
|
||||||
...this.baseConfig,
|
|
||||||
...this.presetConfig,
|
|
||||||
frame: (player) => this.maintainFraming(player),
|
|
||||||
});
|
|
||||||
this.applyFpsLimit();
|
|
||||||
}
|
|
||||||
|
|
||||||
// WE 经 applyGeneralProperties 下发 fps,但它不会替壁纸限流,必须自行实现。
|
|
||||||
setFps(fps) {
|
|
||||||
const value = Number(fps);
|
|
||||||
this.fps = Number.isFinite(value) && value > 0 ? value : 0;
|
|
||||||
this.applyFpsLimit();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 门控绘制:把实例上的 drawFrame 换成一层包装。
|
|
||||||
// 播放器的循环写作 requestAnimationFrame(() => this.drawFrame())——箭头闭包在调用时才读
|
|
||||||
// this.drawFrame,所以在实例上换掉它就能接管排程。
|
|
||||||
// 关键点:原实现只在真正绘制时才排下一帧,而被限流丢掉的帧同样要排,否则循环会停摆。
|
|
||||||
applyFpsLimit() {
|
|
||||||
const player = this.player;
|
|
||||||
if (!player) return;
|
|
||||||
|
|
||||||
// 先摘掉上一轮包装,避免换档时叠成多层
|
|
||||||
if (this.rawDrawFrame) {
|
|
||||||
player.drawFrame = this.rawDrawFrame;
|
|
||||||
this.rawDrawFrame = undefined;
|
|
||||||
}
|
|
||||||
if (!this.fps) return;
|
|
||||||
|
|
||||||
const raw = (this.rawDrawFrame = player.drawFrame);
|
|
||||||
const interval = 1000 / this.fps;
|
|
||||||
// rAF 的节拍有抖动,而"距上一帧不足 interval 就丢"会把抖动放大成整拍丢失:
|
|
||||||
// 目标是 30fps 时,落在 33.2ms 的那一帧会被判为不足 33.33ms 而丢掉,实测只剩 22.5fps。
|
|
||||||
// 所以留一点容差,并让到期时间按固定步长推进,避免抖动被累积成额外丢帧。
|
|
||||||
const tolerance = 4;
|
|
||||||
let due = -Infinity;
|
|
||||||
|
|
||||||
player.drawFrame = (requestNextFrame = true) => {
|
|
||||||
if (player.disposed || player.error) return;
|
|
||||||
if (requestNextFrame && !player.stopRequestAnimationFrame) {
|
|
||||||
requestAnimationFrame(() => player.drawFrame());
|
|
||||||
}
|
|
||||||
const now = performance.now();
|
|
||||||
if (now + tolerance < due) return; // 本帧丢弃:不推进动画,也不绘制
|
|
||||||
due = due < 0 || now - due > interval ? now + interval : due + interval;
|
|
||||||
// 排程已由本层负责,让原实现不要再排一次
|
|
||||||
raw.call(player, false);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// 换骨架没有捷径,只能销毁重建
|
|
||||||
rebuild() {
|
|
||||||
this.dispose();
|
|
||||||
this.create();
|
|
||||||
}
|
|
||||||
|
|
||||||
dispose() {
|
|
||||||
if (!this.player) return;
|
|
||||||
this.player.dispose();
|
|
||||||
this.container.innerHTML = "";
|
|
||||||
this.player = undefined;
|
|
||||||
this.rawDrawFrame = undefined;
|
|
||||||
this.framing = undefined;
|
|
||||||
this.appliedAspect = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 播放器每帧在算相机之前调用它(drawFrame 内,renderer.resize 之后)。
|
|
||||||
// 以画布比例作键:比例没变就是一次比较后返回,不会给每帧加负担。
|
|
||||||
maintainFraming(player) {
|
|
||||||
if (!this.framingEnabled) return;
|
|
||||||
|
|
||||||
const canvas = player.canvas;
|
|
||||||
if (!canvas || !canvas.clientWidth || !canvas.clientHeight) return;
|
|
||||||
const aspect = canvas.clientWidth / canvas.clientHeight;
|
|
||||||
if (aspect === this.appliedAspect) return;
|
|
||||||
|
|
||||||
// 骨架加载完成前 currentViewport 还不存在,下一帧再试
|
|
||||||
if (!this.framing && !this.captureFraming(player)) return;
|
|
||||||
this.applyFraming(player, aspect);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 记下作者视口在参考比例下的取景;之后所有比例都从它推导
|
|
||||||
captureFraming(player) {
|
|
||||||
const viewport = player.currentViewport;
|
|
||||||
if (!viewport) return undefined;
|
|
||||||
|
|
||||||
let animation = this.presetConfig.animation;
|
|
||||||
if (!animation) {
|
|
||||||
const entry = player.animationState && player.animationState.getCurrent(0);
|
|
||||||
animation = entry && entry.animation && entry.animation.name;
|
|
||||||
}
|
|
||||||
if (!animation) return undefined;
|
|
||||||
|
|
||||||
this.framing = {
|
|
||||||
animation,
|
|
||||||
reference: contain(resolveViewport(viewport), REFERENCE_ASPECT),
|
|
||||||
};
|
|
||||||
return this.framing;
|
|
||||||
}
|
|
||||||
|
|
||||||
applyFraming(player, aspect) {
|
|
||||||
const { animation, reference } = this.framing;
|
|
||||||
const target = this.imageAspect
|
|
||||||
? frameForAspect(reference, aspect, this.imageAspect)
|
|
||||||
: contain(reference, aspect);
|
|
||||||
|
|
||||||
// 就地改写字段,绝不整体替换 config.viewport:
|
|
||||||
// setViewport() 会无条件读 config.viewport.animations[name],换掉整个对象会崩。
|
|
||||||
Object.assign(player.config.viewport, toViewportConfig(target));
|
|
||||||
|
|
||||||
player.setViewport(animation);
|
|
||||||
// 取景要随窗口实时变化,0.25 秒的过渡插值只会拖出残影:直接跳到位
|
|
||||||
player.viewportTransitionStart = performance.now() - 1e6;
|
|
||||||
this.appliedAspect = aspect;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
// 立绘层的取景计算。纯函数:只做世界坐标矩形的算术,不碰 DOM,也不碰播放器实例。
|
|
||||||
//
|
|
||||||
// 矩形一律是 { x, y, width, height },世界单位,y 轴向上。
|
|
||||||
//
|
|
||||||
// 为什么需要这一层:
|
|
||||||
// 背景图走 CSS `background-size: cover`(铺满、按需裁切),
|
|
||||||
// 立绘层却由播放器按「含住作者视口」映射(contain)。两者只在作者调参的那个比例下一致,
|
|
||||||
// 比例一变,缩放倍率就分叉——竖屏下背景放大 1.78 倍,立绘层却纹丝不动,特效于是和背景插画脱节。
|
|
||||||
// 这里让立绘层的缩放跟着背景 cover 的缩放走,两者始终同倍率、同中心。
|
|
||||||
|
|
||||||
// 作者调参时的基准比例。在这个比例下取景与作者设定逐像素一致。
|
|
||||||
export const REFERENCE_ASPECT = 16 / 9;
|
|
||||||
|
|
||||||
// 播放器把 currentViewport(基矩形 + 四边内边距)解成最终可见矩形。
|
|
||||||
// 对应 spine-player.js 里 `viewport.x = currentViewport.x - padLeft` 那四行。
|
|
||||||
export function resolveViewport(viewport) {
|
|
||||||
return {
|
|
||||||
x: viewport.x - viewport.padLeft,
|
|
||||||
y: viewport.y - viewport.padBottom,
|
|
||||||
width: viewport.width + viewport.padLeft + viewport.padRight,
|
|
||||||
height: viewport.height + viewport.padBottom + viewport.padTop,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// 把矩形按 aspect 撑到刚好含住它,中心不变。这正是播放器在参考比例下的行为。
|
|
||||||
export function contain(rect, aspect) {
|
|
||||||
const width = Math.max(rect.width, rect.height * aspect);
|
|
||||||
const height = width / aspect;
|
|
||||||
const cx = rect.x + rect.width / 2;
|
|
||||||
const cy = rect.y + rect.height / 2;
|
|
||||||
return { x: cx - width / 2, y: cy - height / 2, width, height };
|
|
||||||
}
|
|
||||||
|
|
||||||
// 背景在某个画布比例下的 cover 缩放,以「受高度约束时的倍率」为 1 归一化。
|
|
||||||
// 背景比画布更宽时按高度铺满(倍率不变),画布更宽时按宽度铺满(倍率随 aspect 增长)。
|
|
||||||
export function coverScale(aspect, imageAspect) {
|
|
||||||
return Math.max(aspect / imageAspect, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 目标可见矩形:参考比例下正好等于作者视口,其余比例按背景 cover 缩放的反比收放。
|
|
||||||
// 效果等价于「立绘层相对背景插画永远 cover」。
|
|
||||||
export function frameForAspect(reference, aspect, imageAspect, referenceAspect = REFERENCE_ASPECT) {
|
|
||||||
const height =
|
|
||||||
(reference.height * coverScale(referenceAspect, imageAspect)) / coverScale(aspect, imageAspect);
|
|
||||||
const width = height * aspect;
|
|
||||||
const cx = reference.x + reference.width / 2;
|
|
||||||
const cy = reference.y + reference.height / 2;
|
|
||||||
return { x: cx - width / 2, y: cy - height / 2, width, height };
|
|
||||||
}
|
|
||||||
|
|
||||||
// 把目标可见矩形写成播放器 config.viewport 需要的字段:内边距归零,
|
|
||||||
// 这样 resolveViewport() 得到的就是它本身。
|
|
||||||
export function toViewportConfig(rect) {
|
|
||||||
return {
|
|
||||||
x: rect.x,
|
|
||||||
y: rect.y,
|
|
||||||
width: rect.width,
|
|
||||||
height: rect.height,
|
|
||||||
padLeft: 0,
|
|
||||||
padRight: 0,
|
|
||||||
padTop: 0,
|
|
||||||
padBottom: 0,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
* {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
background-color: white;
|
|
||||||
background-size: cover;
|
|
||||||
background-position: center;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
height: 100vh;
|
|
||||||
width: 100vw;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
#spine-container {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
@@ -1,350 +0,0 @@
|
|||||||
|
|
||||||
/** Player **/
|
|
||||||
.spine-player {
|
|
||||||
box-sizing: border-box;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
background: none;
|
|
||||||
}
|
|
||||||
.spine-player * {
|
|
||||||
box-sizing: border-box;
|
|
||||||
font-family: "PT Sans",Arial,"Helvetica Neue",Helvetica,Tahoma,sans-serif;
|
|
||||||
color: #dddddd;
|
|
||||||
-webkit-touch-callout: none;
|
|
||||||
-webkit-user-select: none;
|
|
||||||
-khtml-user-select: none;
|
|
||||||
-moz-user-select: none;
|
|
||||||
-ms-user-select: none;
|
|
||||||
user-select: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.spine-player-error {
|
|
||||||
font-size: 14px;
|
|
||||||
z-index: 10;
|
|
||||||
border-radius: 4px;
|
|
||||||
-webkit-user-select: text;
|
|
||||||
-khtml-user-select: text;
|
|
||||||
-moz-user-select: text;
|
|
||||||
-ms-user-select: text;
|
|
||||||
user-select: text;
|
|
||||||
}
|
|
||||||
|
|
||||||
.spine-player-hidden {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Canvas **/
|
|
||||||
.spine-player canvas {
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Slider **/
|
|
||||||
.spine-player-slider {
|
|
||||||
width: 100%;
|
|
||||||
height: 16px;
|
|
||||||
position: relative;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
.spine-player-slider-value {
|
|
||||||
position: absolute;
|
|
||||||
bottom: 0;
|
|
||||||
height: 2px;
|
|
||||||
background: rgba(98, 176, 238, 0.6);
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
.spine-player-slider:hover .spine-player-slider-value {
|
|
||||||
height: 4px;
|
|
||||||
background: rgba(98, 176, 238, 1);
|
|
||||||
transition: height 0.2s;
|
|
||||||
}
|
|
||||||
.spine-player-slider-value.hovering {
|
|
||||||
height: 4px;
|
|
||||||
background: rgba(98, 176, 238, 1);
|
|
||||||
transition: height 0.2s;
|
|
||||||
}
|
|
||||||
.spine-player-slider.big {
|
|
||||||
height: 12px;
|
|
||||||
background: rgb(0, 0, 0);
|
|
||||||
}
|
|
||||||
.spine-player-slider.big .spine-player-slider-value {
|
|
||||||
height: 12px;
|
|
||||||
background: rgba(98, 176, 238, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Column and row layout elements **/
|
|
||||||
.spine-player-column {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
.spine-player-row {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** List **/
|
|
||||||
.spine-player-list {
|
|
||||||
list-style: none !important;
|
|
||||||
padding: 0 !important;
|
|
||||||
margin: 0 !important;
|
|
||||||
}
|
|
||||||
.spine-player-list li {
|
|
||||||
cursor: pointer;
|
|
||||||
margin: 8px 8px;
|
|
||||||
}
|
|
||||||
.spine-player-list .selectable {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
margin: 0 !important;
|
|
||||||
padding: 2px 20px 2px 0 !important;
|
|
||||||
}
|
|
||||||
.spine-player-list li.selectable:first-child {
|
|
||||||
margin-top: 4px !important;
|
|
||||||
}
|
|
||||||
.spine-player-list li.selectable:last-child {
|
|
||||||
margin-bottom: 4px !important;
|
|
||||||
}
|
|
||||||
.spine-player-list li.selectable:hover {
|
|
||||||
background: #6e6e6e;
|
|
||||||
}
|
|
||||||
.spine-player-list li.selectable .selectable-circle {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
width: 6px;
|
|
||||||
min-width: 6px;
|
|
||||||
height: 6px;
|
|
||||||
border-radius: 50%;
|
|
||||||
background: #fff;
|
|
||||||
align-self: center;
|
|
||||||
opacity: 0;
|
|
||||||
margin: 5px 10px;
|
|
||||||
}
|
|
||||||
.spine-player-list li.selectable.selected .selectable-circle {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
.spine-player-list li.selectable .selectable-text {
|
|
||||||
color: #aaa;
|
|
||||||
}
|
|
||||||
.spine-player-list li.selectable.selected .selectable-text, .spine-player-list li.selectable:hover .selectable-text {
|
|
||||||
color: #ddd;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Switch **/
|
|
||||||
.spine-player-switch {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
margin: 2px 10px;
|
|
||||||
}
|
|
||||||
.spine-player-switch-text {
|
|
||||||
flex: 1;
|
|
||||||
margin-right: 8px;
|
|
||||||
}
|
|
||||||
.spine-player-switch-knob-area {
|
|
||||||
width: 30px; /* width of the switch */
|
|
||||||
height: 10px;
|
|
||||||
display: block;
|
|
||||||
border-radius: 5px; /* must be half of height */
|
|
||||||
background: #6e6e6e;
|
|
||||||
position: relative;
|
|
||||||
align-self: center;
|
|
||||||
justify-self: flex-end;
|
|
||||||
}
|
|
||||||
.spine-player-switch.active .spine-player-switch-knob-area {
|
|
||||||
background: #5EAFF1;
|
|
||||||
}
|
|
||||||
.spine-player-switch-knob {
|
|
||||||
display: block;
|
|
||||||
width: 14px;
|
|
||||||
height: 14px;
|
|
||||||
border-radius: 50%;
|
|
||||||
background: #9e9e9e;
|
|
||||||
position: absolute;
|
|
||||||
left: 0px;
|
|
||||||
top: -2px;
|
|
||||||
filter: drop-shadow(0 0 1px #333);
|
|
||||||
transition: transform 0.2s;
|
|
||||||
}
|
|
||||||
.spine-player-switch.active .spine-player-switch-knob {
|
|
||||||
background: #fff;
|
|
||||||
transform: translateX(18px);
|
|
||||||
transition: transform 0.2s;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Popup **/
|
|
||||||
.spine-player-popup-parent {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
.spine-player-popup {
|
|
||||||
user-select: none;
|
|
||||||
position: absolute;
|
|
||||||
background: rgba(0, 0, 0, 0.75);
|
|
||||||
z-index: 1;
|
|
||||||
right: 2px;
|
|
||||||
bottom: 40px;
|
|
||||||
border-radius: 4px;
|
|
||||||
max-height: 400%;
|
|
||||||
overflow: auto;
|
|
||||||
font-size: 85%;
|
|
||||||
}
|
|
||||||
.spine-player-popup-title {
|
|
||||||
margin: 4px 15px 2px 15px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
.spine-player-popup hr {
|
|
||||||
margin: 0;
|
|
||||||
border: 0;
|
|
||||||
border-bottom: 1px solid #cccccc70;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Player controls **/
|
|
||||||
.spine-player-controls {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
position: absolute;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
opacity: 1;
|
|
||||||
transition: opacity 0.4s;
|
|
||||||
}
|
|
||||||
.spine-player-controls-hidden {
|
|
||||||
pointer-events: none;
|
|
||||||
opacity: 0;
|
|
||||||
transition: opacity 0.4s;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Player buttons **/
|
|
||||||
.spine-player-buttons {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
width: 100%;
|
|
||||||
background: rgba(0, 0, 0, 0.5);
|
|
||||||
border-bottom-left-radius: 4px;
|
|
||||||
border-bottom-right-radius: 4px;
|
|
||||||
padding: 2px 8px 3px;
|
|
||||||
}
|
|
||||||
.spine-player-button {
|
|
||||||
background: none;
|
|
||||||
outline: 0;
|
|
||||||
border: none;
|
|
||||||
width: 32px;
|
|
||||||
height: 32px;
|
|
||||||
background-size: 20px;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
background-position: center;
|
|
||||||
cursor: pointer;
|
|
||||||
margin-right: 3px;
|
|
||||||
padding-bottom: 3px;
|
|
||||||
filter: drop-shadow(0 0 1px #333);
|
|
||||||
}
|
|
||||||
.spine-player-button-spacer {
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
.spine-player-button-icon-play {
|
|
||||||
background-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2048%2048%22%3E%3Cdefs%3E%3Cstyle%3E.cls-1%7Bfill%3A%23fff%3B%7D%3C%2Fstyle%3E%3C%2Fdefs%3E%3Ctitle%3Eplay%3C%2Ftitle%3E%3Cg%20id%3D%22play%22%3E%3Cpolygon%20class%3D%22cls-1%22%20points%3D%2243%2023.3%204%2047%204%201%2043%2023.3%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E");
|
|
||||||
}
|
|
||||||
.spine-player-button-icon-play:hover {
|
|
||||||
background-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2048%2048%22%3E%3Cdefs%3E%3Cstyle%3E.cls-1%7Bfill%3A%2362B0EE%3B%7D%3C%2Fstyle%3E%3C%2Fdefs%3E%3Ctitle%3Eplay%3C%2Ftitle%3E%3Cg%20id%3D%22play%22%3E%3Cpolygon%20class%3D%22cls-1%22%20points%3D%2243%2023.3%204%2047%204%201%2043%2023.3%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E");
|
|
||||||
}
|
|
||||||
.spine-player-button-icon-play-selected {
|
|
||||||
background-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2048%2048%22%3E%3Cdefs%3E%3Cstyle%3E.cls-1%7Bfill%3A%2362B0EE%3B%7D%3C%2Fstyle%3E%3C%2Fdefs%3E%3Ctitle%3Eplay%3C%2Ftitle%3E%3Cg%20id%3D%22play%22%3E%3Cpolygon%20class%3D%22cls-1%22%20points%3D%2243%2023.3%204%2047%204%201%2043%2023.3%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E");
|
|
||||||
}
|
|
||||||
.spine-player-button-icon-pause {
|
|
||||||
background-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2048%2048%22%3E%3Cdefs%3E%3Cstyle%3E.cls-1%7Bfill%3A%23fff%3B%7D%3C%2Fstyle%3E%3C%2Fdefs%3E%3Ctitle%3Epause%3C%2Ftitle%3E%3Cg%20id%3D%22pause%22%3E%3Crect%20class%3D%22cls-1%22%20x%3D%226%22%20y%3D%221%22%20width%3D%2213%22%20height%3D%2246%22%2F%3E%3Crect%20class%3D%22cls-1%22%20x%3D%2228%22%20y%3D%221%22%20width%3D%2213%22%20height%3D%2246%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E");
|
|
||||||
}
|
|
||||||
.spine-player-button-icon-pause:hover {
|
|
||||||
background-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2048%2048%22%3E%3Cdefs%3E%3Cstyle%3E.cls-1%7Bfill%3A%2362B0EE%3B%7D%3C%2Fstyle%3E%3C%2Fdefs%3E%3Ctitle%3Epause%3C%2Ftitle%3E%3Cg%20id%3D%22pause%22%3E%3Crect%20class%3D%22cls-1%22%20x%3D%226%22%20y%3D%221%22%20width%3D%2213%22%20height%3D%2246%22%2F%3E%3Crect%20class%3D%22cls-1%22%20x%3D%2228%22%20y%3D%221%22%20width%3D%2213%22%20height%3D%2246%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E");
|
|
||||||
}
|
|
||||||
.spine-player-button-icon-pause-selected {
|
|
||||||
background-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2048%2048%22%3E%3Cdefs%3E%3Cstyle%3E.cls-1%7Bfill%3A%2362B0EE%3B%7D%3C%2Fstyle%3E%3C%2Fdefs%3E%3Ctitle%3Epause%3C%2Ftitle%3E%3Cg%20id%3D%22pause%22%3E%3Crect%20class%3D%22cls-1%22%20x%3D%226%22%20y%3D%221%22%20width%3D%2213%22%20height%3D%2246%22%2F%3E%3Crect%20class%3D%22cls-1%22%20x%3D%2228%22%20y%3D%221%22%20width%3D%2213%22%20height%3D%2246%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E");
|
|
||||||
}
|
|
||||||
.spine-player-button-icon-speed {
|
|
||||||
background-image: url("data:image/svg+xml,%3Csvg%20id%3D%22playback%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2048%2048%22%3E%3Cdefs%3E%3Cstyle%3E.cls-1%7Bfill%3A%23fff%3B%7D%3C%2Fstyle%3E%3C%2Fdefs%3E%3Ctitle%3Eplayback%3C%2Ftitle%3E%3Cpath%20class%3D%22cls-1%22%20d%3D%22M48%2C28V20l-4.7-1.18a20.16%2C20.16%2C0%2C0%2C0-2-4.81l2.49-4.15L38.14%2C4.2%2C34%2C6.69a20.16%2C20.16%2C0%2C0%2C0-4.81-2L28%2C0H20L18.82%2C4.7A20.16%2C20.16%2C0%2C0%2C0%2C14%2C6.7L9.86%2C4.2%2C4.2%2C9.86%2C6.69%2C14a20.16%2C20.16%2C0%2C0%2C0-2%2C4.81L0%2C20v8l4.7%2C1.18A20.16%2C20.16%2C0%2C0%2C0%2C6.7%2C34L4.2%2C38.14%2C9.86%2C43.8%2C14%2C41.31a20.16%2C20.16%2C0%2C0%2C0%2C4.81%2C2L20%2C48h8l1.18-4.7a20.16%2C20.16%2C0%2C0%2C0%2C4.81-2l4.15%2C2.49%2C5.66-5.66L41.31%2C34a20.16%2C20.16%2C0%2C0%2C0%2C2-4.81ZM24%2C38A14%2C14%2C0%2C1%2C1%2C38%2C24%2C14%2C14%2C0%2C0%2C1%2C24%2C38Z%22%2F%3E%3Cpolygon%20class%3D%22cls-1%22%20points%3D%2234%2024%2018%2033%2018%2015%2034%2024%2034%2024%22%2F%3E%3C%2Fsvg%3E");
|
|
||||||
}
|
|
||||||
.spine-player-button-icon-speed:hover {
|
|
||||||
background-image: url("data:image/svg+xml,%3Csvg%20id%3D%22playback%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2048%2048%22%3E%3Cdefs%3E%3Cstyle%3E.cls-1%7Bfill%3A%2362B0EE%3B%7D%3C%2Fstyle%3E%3C%2Fdefs%3E%3Ctitle%3Eplayback%3C%2Ftitle%3E%3Cpath%20class%3D%22cls-1%22%20d%3D%22M48%2C28V20l-4.7-1.18a20.16%2C20.16%2C0%2C0%2C0-2-4.81l2.49-4.15L38.14%2C4.2%2C34%2C6.69a20.16%2C20.16%2C0%2C0%2C0-4.81-2L28%2C0H20L18.82%2C4.7A20.16%2C20.16%2C0%2C0%2C0%2C14%2C6.7L9.86%2C4.2%2C4.2%2C9.86%2C6.69%2C14a20.16%2C20.16%2C0%2C0%2C0-2%2C4.81L0%2C20v8l4.7%2C1.18A20.16%2C20.16%2C0%2C0%2C0%2C6.7%2C34L4.2%2C38.14%2C9.86%2C43.8%2C14%2C41.31a20.16%2C20.16%2C0%2C0%2C0%2C4.81%2C2L20%2C48h8l1.18-4.7a20.16%2C20.16%2C0%2C0%2C0%2C4.81-2l4.15%2C2.49%2C5.66-5.66L41.31%2C34a20.16%2C20.16%2C0%2C0%2C0%2C2-4.81ZM24%2C38A14%2C14%2C0%2C1%2C1%2C38%2C24%2C14%2C14%2C0%2C0%2C1%2C24%2C38Z%22%2F%3E%3Cpolygon%20class%3D%22cls-1%22%20points%3D%2234%2024%2018%2033%2018%2015%2034%2024%2034%2024%22%2F%3E%3C%2Fsvg%3E");
|
|
||||||
}
|
|
||||||
.spine-player-button-icon-speed-selected {
|
|
||||||
background-image: url("data:image/svg+xml,%3Csvg%20id%3D%22playback%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2048%2048%22%3E%3Cdefs%3E%3Cstyle%3E.cls-1%7Bfill%3A%2362B0EE%3B%7D%3C%2Fstyle%3E%3C%2Fdefs%3E%3Ctitle%3Eplayback%3C%2Ftitle%3E%3Cpath%20class%3D%22cls-1%22%20d%3D%22M48%2C28V20l-4.7-1.18a20.16%2C20.16%2C0%2C0%2C0-2-4.81l2.49-4.15L38.14%2C4.2%2C34%2C6.69a20.16%2C20.16%2C0%2C0%2C0-4.81-2L28%2C0H20L18.82%2C4.7A20.16%2C20.16%2C0%2C0%2C0%2C14%2C6.7L9.86%2C4.2%2C4.2%2C9.86%2C6.69%2C14a20.16%2C20.16%2C0%2C0%2C0-2%2C4.81L0%2C20v8l4.7%2C1.18A20.16%2C20.16%2C0%2C0%2C0%2C6.7%2C34L4.2%2C38.14%2C9.86%2C43.8%2C14%2C41.31a20.16%2C20.16%2C0%2C0%2C0%2C4.81%2C2L20%2C48h8l1.18-4.7a20.16%2C20.16%2C0%2C0%2C0%2C4.81-2l4.15%2C2.49%2C5.66-5.66L41.31%2C34a20.16%2C20.16%2C0%2C0%2C0%2C2-4.81ZM24%2C38A14%2C14%2C0%2C1%2C1%2C38%2C24%2C14%2C14%2C0%2C0%2C1%2C24%2C38Z%22%2F%3E%3Cpolygon%20class%3D%22cls-1%22%20points%3D%2234%2024%2018%2033%2018%2015%2034%2024%2034%2024%22%2F%3E%3C%2Fsvg%3E");
|
|
||||||
}
|
|
||||||
.spine-player-button-icon-animations {
|
|
||||||
background-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2048%2048%22%3E%3Cdefs%3E%3Cstyle%3E.cls-1%7Bfill%3A%23fff%3B%7D%3C%2Fstyle%3E%3C%2Fdefs%3E%3Ctitle%3Eanimations%3C%2Ftitle%3E%3Cg%20id%3D%22animations%22%3E%3Cpath%20class%3D%22cls-1%22%20d%3D%22M12%2C45V43.22a6.39%2C6.39%2C0%2C0%2C0%2C.63-.81%2C27.83%2C27.83%2C0%2C0%2C1%2C3.79-4.16c.93-.84%2C2.06-1.88%2C2.86-2.71a13.83%2C13.83%2C0%2C0%2C0%2C1.53-1.9l3.9-5.24c1-1.17.95-1.1%2C2.11%2C0l3%2C2.24a4%2C4%2C0%2C0%2C0-2.29%2C2.38c-1.37%2C3-2.39%2C4-2.68%2C4.22l-.23.18c-.54.39-1.81%2C1-1.7%2C1.54l.8%2C1.49a4.5%2C4.5%2C0%2C0%2C1%2C.39%2C1l.57%2C2.15a.69.69%2C0%2C0%2C0%2C.58.48c.47.08%2C1%2C.5%2C1.33.53%2C1.29.1%2C1.79%2C0%2C1.42-.54L26.7%2C42.72a.86.86%2C0%2C0%2C1-.2-.24%2C3.64%2C3.64%2C0%2C0%2C1-.42-2.2A5.39%2C5.39%2C0%2C0%2C1%2C26.61%2C39c1.84-2%2C6.74-6.36%2C6.74-6.36%2C1.71-1.81%2C1.4-2.52.81-3.84a27.38%2C27.38%2C0%2C0%2C0-2-3c-.41-.61-2.08-2.38-2.85-3.28-.43-.5.38-2.08.87-2.82.18-.12-.41.05%2C1.72.07a23.32%2C23.32%2C0%2C0%2C0%2C3.56-.19l1.63.61c.28%2C0%2C1.18-.09%2C1.31-.35l.12-.78c.18-.39.31-1.56-.05-1.75l-.6-.52a2.28%2C2.28%2C0%2C0%2C0-1.61.07l-.2.44c-.14.15-.52.37-.71.29l-2.24%2C0c-.5.12-1.18-.42-1.81-.73L32.05%2C15a8%2C8%2C0%2C0%2C0%2C.8-3.92%2C1.22%2C1.22%2C0%2C0%2C0-.28-.82%2C7.87%2C7.87%2C0%2C0%2C0-1.15-1.06l.11-.73c-.12-.49%2C1-.82%2C1.52-.82l.76-.33c.32%2C0%2C.68-.89.78-1.21L34.94%2C4a11.26%2C11.26%2C0%2C0%2C0%2C0-1.61C34.57.08%2C30.06-1.42%2C28.78%2C2c-.14.38-.62.77.34%2C3.21a1.55%2C1.55%2C0%2C0%2C1-.3%2C1.2L28.4%2C7a4%2C4%2C0%2C0%2C1-1.19.49c-.79%2C0-1.59-.75-4%2C.54C21%2C9.16%2C18.59%2C13%2C17.7%2C14.22a3.21%2C3.21%2C0%2C0%2C0-.61%2C1.58c-.05%2C1.16.7%2C3.74.87%2C5.75.13%2C1.53.21%2C2.52.72%2C3.06%2C1.07%2C1.14%2C2.1-.18%2C2.61-1a2.74%2C2.74%2C0%2C0%2C0-.14-1.86l-.74-.1c-.15-.15-.4-.42-.39-.64-.05-3.48-.22-3.14-.18-5.39%2C1.74-1.46%2C2.4-2.45%2C2.3-2-.2%2C1.15.28%2C2.83.09%2C4.35a6.46%2C6.46%2C0%2C0%2C1-.7%2C2.58s-2.11%2C4.22-2.14%2C4.27l-1.26%2C5.6-.7%2C1.44s-.71.54-1.59%2C1.21a9.67%2C9.67%2C0%2C0%2C0-2.27%2C3.18%2C20.16%2C20.16%2C0%2C0%2C1-1.42%2C2.83l-.87%2C1.31a1.72%2C1.72%2C0%2C0%2C1-.6.61l-1.83%2C1.1a1.39%2C1.39%2C0%2C0%2C0-.16.93l.68%2C1.71a4.07%2C4.07%2C0%2C0%2C1%2C.27%2C1.07l.17%2C1.56a.75.75%2C0%2C0%2C0%2C.71.59%2C18.13%2C18.13%2C0%2C0%2C0%2C3.26-.5c.27-.09-.29-.78-.53-1s-.45-.36-.45-.36A12.78%2C12.78%2C0%2C0%2C1%2C12%2C45Z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E")
|
|
||||||
}
|
|
||||||
.spine-player-button-icon-animations:hover {
|
|
||||||
background-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2048%2048%22%3E%3Cdefs%3E%3Cstyle%3E.cls-1%7Bfill%3A%2362B0EE%3B%7D%3C%2Fstyle%3E%3C%2Fdefs%3E%3Ctitle%3Eanimations%3C%2Ftitle%3E%3Cg%20id%3D%22animations%22%3E%3Cpath%20class%3D%22cls-1%22%20d%3D%22M12%2C45V43.22a6.39%2C6.39%2C0%2C0%2C0%2C.63-.81%2C27.83%2C27.83%2C0%2C0%2C1%2C3.79-4.16c.93-.84%2C2.06-1.88%2C2.86-2.71a13.83%2C13.83%2C0%2C0%2C0%2C1.53-1.9l3.9-5.24c1-1.17.95-1.1%2C2.11%2C0l3%2C2.24a4%2C4%2C0%2C0%2C0-2.29%2C2.38c-1.37%2C3-2.39%2C4-2.68%2C4.22l-.23.18c-.54.39-1.81%2C1-1.7%2C1.54l.8%2C1.49a4.5%2C4.5%2C0%2C0%2C1%2C.39%2C1l.57%2C2.15a.69.69%2C0%2C0%2C0%2C.58.48c.47.08%2C1%2C.5%2C1.33.53%2C1.29.1%2C1.79%2C0%2C1.42-.54L26.7%2C42.72a.86.86%2C0%2C0%2C1-.2-.24%2C3.64%2C3.64%2C0%2C0%2C1-.42-2.2A5.39%2C5.39%2C0%2C0%2C1%2C26.61%2C39c1.84-2%2C6.74-6.36%2C6.74-6.36%2C1.71-1.81%2C1.4-2.52.81-3.84a27.38%2C27.38%2C0%2C0%2C0-2-3c-.41-.61-2.08-2.38-2.85-3.28-.43-.5.38-2.08.87-2.82.18-.12-.41.05%2C1.72.07a23.32%2C23.32%2C0%2C0%2C0%2C3.56-.19l1.63.61c.28%2C0%2C1.18-.09%2C1.31-.35l.12-.78c.18-.39.31-1.56-.05-1.75l-.6-.52a2.28%2C2.28%2C0%2C0%2C0-1.61.07l-.2.44c-.14.15-.52.37-.71.29l-2.24%2C0c-.5.12-1.18-.42-1.81-.73L32.05%2C15a8%2C8%2C0%2C0%2C0%2C.8-3.92%2C1.22%2C1.22%2C0%2C0%2C0-.28-.82%2C7.87%2C7.87%2C0%2C0%2C0-1.15-1.06l.11-.73c-.12-.49%2C1-.82%2C1.52-.82l.76-.33c.32%2C0%2C.68-.89.78-1.21L34.94%2C4a11.26%2C11.26%2C0%2C0%2C0%2C0-1.61C34.57.08%2C30.06-1.42%2C28.78%2C2c-.14.38-.62.77.34%2C3.21a1.55%2C1.55%2C0%2C0%2C1-.3%2C1.2L28.4%2C7a4%2C4%2C0%2C0%2C1-1.19.49c-.79%2C0-1.59-.75-4%2C.54C21%2C9.16%2C18.59%2C13%2C17.7%2C14.22a3.21%2C3.21%2C0%2C0%2C0-.61%2C1.58c-.05%2C1.16.7%2C3.74.87%2C5.75.13%2C1.53.21%2C2.52.72%2C3.06%2C1.07%2C1.14%2C2.1-.18%2C2.61-1a2.74%2C2.74%2C0%2C0%2C0-.14-1.86l-.74-.1c-.15-.15-.4-.42-.39-.64-.05-3.48-.22-3.14-.18-5.39%2C1.74-1.46%2C2.4-2.45%2C2.3-2-.2%2C1.15.28%2C2.83.09%2C4.35a6.46%2C6.46%2C0%2C0%2C1-.7%2C2.58s-2.11%2C4.22-2.14%2C4.27l-1.26%2C5.6-.7%2C1.44s-.71.54-1.59%2C1.21a9.67%2C9.67%2C0%2C0%2C0-2.27%2C3.18%2C20.16%2C20.16%2C0%2C0%2C1-1.42%2C2.83l-.87%2C1.31a1.72%2C1.72%2C0%2C0%2C1-.6.61l-1.83%2C1.1a1.39%2C1.39%2C0%2C0%2C0-.16.93l.68%2C1.71a4.07%2C4.07%2C0%2C0%2C1%2C.27%2C1.07l.17%2C1.56a.75.75%2C0%2C0%2C0%2C.71.59%2C18.13%2C18.13%2C0%2C0%2C0%2C3.26-.5c.27-.09-.29-.78-.53-1s-.45-.36-.45-.36A12.78%2C12.78%2C0%2C0%2C1%2C12%2C45Z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E")
|
|
||||||
}
|
|
||||||
.spine-player-button-icon-animations-selected {
|
|
||||||
background-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2048%2048%22%3E%3Cdefs%3E%3Cstyle%3E.cls-1%7Bfill%3A%2362B0EE%3B%7D%3C%2Fstyle%3E%3C%2Fdefs%3E%3Ctitle%3Eanimations%3C%2Ftitle%3E%3Cg%20id%3D%22animations%22%3E%3Cpath%20class%3D%22cls-1%22%20d%3D%22M12%2C45V43.22a6.39%2C6.39%2C0%2C0%2C0%2C.63-.81%2C27.83%2C27.83%2C0%2C0%2C1%2C3.79-4.16c.93-.84%2C2.06-1.88%2C2.86-2.71a13.83%2C13.83%2C0%2C0%2C0%2C1.53-1.9l3.9-5.24c1-1.17.95-1.1%2C2.11%2C0l3%2C2.24a4%2C4%2C0%2C0%2C0-2.29%2C2.38c-1.37%2C3-2.39%2C4-2.68%2C4.22l-.23.18c-.54.39-1.81%2C1-1.7%2C1.54l.8%2C1.49a4.5%2C4.5%2C0%2C0%2C1%2C.39%2C1l.57%2C2.15a.69.69%2C0%2C0%2C0%2C.58.48c.47.08%2C1%2C.5%2C1.33.53%2C1.29.1%2C1.79%2C0%2C1.42-.54L26.7%2C42.72a.86.86%2C0%2C0%2C1-.2-.24%2C3.64%2C3.64%2C0%2C0%2C1-.42-2.2A5.39%2C5.39%2C0%2C0%2C1%2C26.61%2C39c1.84-2%2C6.74-6.36%2C6.74-6.36%2C1.71-1.81%2C1.4-2.52.81-3.84a27.38%2C27.38%2C0%2C0%2C0-2-3c-.41-.61-2.08-2.38-2.85-3.28-.43-.5.38-2.08.87-2.82.18-.12-.41.05%2C1.72.07a23.32%2C23.32%2C0%2C0%2C0%2C3.56-.19l1.63.61c.28%2C0%2C1.18-.09%2C1.31-.35l.12-.78c.18-.39.31-1.56-.05-1.75l-.6-.52a2.28%2C2.28%2C0%2C0%2C0-1.61.07l-.2.44c-.14.15-.52.37-.71.29l-2.24%2C0c-.5.12-1.18-.42-1.81-.73L32.05%2C15a8%2C8%2C0%2C0%2C0%2C.8-3.92%2C1.22%2C1.22%2C0%2C0%2C0-.28-.82%2C7.87%2C7.87%2C0%2C0%2C0-1.15-1.06l.11-.73c-.12-.49%2C1-.82%2C1.52-.82l.76-.33c.32%2C0%2C.68-.89.78-1.21L34.94%2C4a11.26%2C11.26%2C0%2C0%2C0%2C0-1.61C34.57.08%2C30.06-1.42%2C28.78%2C2c-.14.38-.62.77.34%2C3.21a1.55%2C1.55%2C0%2C0%2C1-.3%2C1.2L28.4%2C7a4%2C4%2C0%2C0%2C1-1.19.49c-.79%2C0-1.59-.75-4%2C.54C21%2C9.16%2C18.59%2C13%2C17.7%2C14.22a3.21%2C3.21%2C0%2C0%2C0-.61%2C1.58c-.05%2C1.16.7%2C3.74.87%2C5.75.13%2C1.53.21%2C2.52.72%2C3.06%2C1.07%2C1.14%2C2.1-.18%2C2.61-1a2.74%2C2.74%2C0%2C0%2C0-.14-1.86l-.74-.1c-.15-.15-.4-.42-.39-.64-.05-3.48-.22-3.14-.18-5.39%2C1.74-1.46%2C2.4-2.45%2C2.3-2-.2%2C1.15.28%2C2.83.09%2C4.35a6.46%2C6.46%2C0%2C0%2C1-.7%2C2.58s-2.11%2C4.22-2.14%2C4.27l-1.26%2C5.6-.7%2C1.44s-.71.54-1.59%2C1.21a9.67%2C9.67%2C0%2C0%2C0-2.27%2C3.18%2C20.16%2C20.16%2C0%2C0%2C1-1.42%2C2.83l-.87%2C1.31a1.72%2C1.72%2C0%2C0%2C1-.6.61l-1.83%2C1.1a1.39%2C1.39%2C0%2C0%2C0-.16.93l.68%2C1.71a4.07%2C4.07%2C0%2C0%2C1%2C.27%2C1.07l.17%2C1.56a.75.75%2C0%2C0%2C0%2C.71.59%2C18.13%2C18.13%2C0%2C0%2C0%2C3.26-.5c.27-.09-.29-.78-.53-1s-.45-.36-.45-.36A12.78%2C12.78%2C0%2C0%2C1%2C12%2C45Z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E")
|
|
||||||
}
|
|
||||||
.spine-player-button-icon-skins {
|
|
||||||
background-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2048%2048%22%3E%3Cdefs%3E%3Cstyle%3E.cls-1%7Bfill%3A%23fff%3B%7D%3C%2Fstyle%3E%3C%2Fdefs%3E%3Ctitle%3Eskins%3C%2Ftitle%3E%3Cg%20id%3D%22skins%22%3E%3Cpath%20class%3D%22cls-1%22%20d%3D%22M36%2C12.54l-6.92%2C1-.79%2C1.2c-1%2C.25-2-.62-3-.55V12.33a1.35%2C1.35%2C0%2C0%2C1%2C.55-1.07c3-2.24%2C3.28-3.75%2C3.28-5.34A5.06%2C5.06%2C0%2C0%2C0%2C24%2C.76c-2.54%2C0-4.38.71-5.49%2C2.13a5.74%2C5.74%2C0%2C0%2C0-.9%2C4.57l2.48-.61a3.17%2C3.17%2C0%2C0%2C1%2C.45-2.4c.6-.75%2C1.75-1.13%2C3.42-1.13%2C2.56%2C0%2C2.56%2C1.24%2C2.56%2C2.56%2C0%2C.92%2C0%2C1.65-2.26%2C3.34a3.92%2C3.92%2C0%2C0%2C0-1.58%2C3.12v1.86c-1-.07-2%2C.8-3%2C.55l-.79-1.2-6.92-1c-2.25%2C0-4.35%2C2.09-5.64%2C3.93L1%2C24c3.83%2C5.11%2C10.22%2C5.11%2C10.22%2C5.11V41.93c0%2C2.34%2C2.68%2C3.88%2C5.59%2C4.86a22.59%2C22.59%2C0%2C0%2C0%2C14.37%2C0c2.91-1%2C5.59-2.52%2C5.59-4.86V29.15S43.17%2C29.15%2C47%2C24l-5.33-7.57C40.38%2C14.63%2C38.27%2C12.54%2C36%2C12.54ZM23.32%2C20.09%2C21%2C17l1.8-.6a3.79%2C3.79%2C0%2C0%2C1%2C2.4%2C0L27%2C17l-2.32%2C3.09A.85.85%2C0%2C0%2C1%2C23.32%2C20.09Z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E");
|
|
||||||
width: 31px;
|
|
||||||
height: 31px;
|
|
||||||
}
|
|
||||||
.spine-player-button-icon-skins:hover {
|
|
||||||
background-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2048%2048%22%3E%3Cdefs%3E%3Cstyle%3E.cls-1%7Bfill%3A%2362B0EE%3B%7D%3C%2Fstyle%3E%3C%2Fdefs%3E%3Ctitle%3Eskins%3C%2Ftitle%3E%3Cg%20id%3D%22skins%22%3E%3Cpath%20class%3D%22cls-1%22%20d%3D%22M36%2C12.54l-6.92%2C1-.79%2C1.2c-1%2C.25-2-.62-3-.55V12.33a1.35%2C1.35%2C0%2C0%2C1%2C.55-1.07c3-2.24%2C3.28-3.75%2C3.28-5.34A5.06%2C5.06%2C0%2C0%2C0%2C24%2C.76c-2.54%2C0-4.38.71-5.49%2C2.13a5.74%2C5.74%2C0%2C0%2C0-.9%2C4.57l2.48-.61a3.17%2C3.17%2C0%2C0%2C1%2C.45-2.4c.6-.75%2C1.75-1.13%2C3.42-1.13%2C2.56%2C0%2C2.56%2C1.24%2C2.56%2C2.56%2C0%2C.92%2C0%2C1.65-2.26%2C3.34a3.92%2C3.92%2C0%2C0%2C0-1.58%2C3.12v1.86c-1-.07-2%2C.8-3%2C.55l-.79-1.2-6.92-1c-2.25%2C0-4.35%2C2.09-5.64%2C3.93L1%2C24c3.83%2C5.11%2C10.22%2C5.11%2C10.22%2C5.11V41.93c0%2C2.34%2C2.68%2C3.88%2C5.59%2C4.86a22.59%2C22.59%2C0%2C0%2C0%2C14.37%2C0c2.91-1%2C5.59-2.52%2C5.59-4.86V29.15S43.17%2C29.15%2C47%2C24l-5.33-7.57C40.38%2C14.63%2C38.27%2C12.54%2C36%2C12.54ZM23.32%2C20.09%2C21%2C17l1.8-.6a3.79%2C3.79%2C0%2C0%2C1%2C2.4%2C0L27%2C17l-2.32%2C3.09A.85.85%2C0%2C0%2C1%2C23.32%2C20.09Z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E");
|
|
||||||
}
|
|
||||||
.spine-player-button-icon-skins-selected {
|
|
||||||
background-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2048%2048%22%3E%3Cdefs%3E%3Cstyle%3E.cls-1%7Bfill%3A%2362B0EE%3B%7D%3C%2Fstyle%3E%3C%2Fdefs%3E%3Ctitle%3Eskins%3C%2Ftitle%3E%3Cg%20id%3D%22skins%22%3E%3Cpath%20class%3D%22cls-1%22%20d%3D%22M36%2C12.54l-6.92%2C1-.79%2C1.2c-1%2C.25-2-.62-3-.55V12.33a1.35%2C1.35%2C0%2C0%2C1%2C.55-1.07c3-2.24%2C3.28-3.75%2C3.28-5.34A5.06%2C5.06%2C0%2C0%2C0%2C24%2C.76c-2.54%2C0-4.38.71-5.49%2C2.13a5.74%2C5.74%2C0%2C0%2C0-.9%2C4.57l2.48-.61a3.17%2C3.17%2C0%2C0%2C1%2C.45-2.4c.6-.75%2C1.75-1.13%2C3.42-1.13%2C2.56%2C0%2C2.56%2C1.24%2C2.56%2C2.56%2C0%2C.92%2C0%2C1.65-2.26%2C3.34a3.92%2C3.92%2C0%2C0%2C0-1.58%2C3.12v1.86c-1-.07-2%2C.8-3%2C.55l-.79-1.2-6.92-1c-2.25%2C0-4.35%2C2.09-5.64%2C3.93L1%2C24c3.83%2C5.11%2C10.22%2C5.11%2C10.22%2C5.11V41.93c0%2C2.34%2C2.68%2C3.88%2C5.59%2C4.86a22.59%2C22.59%2C0%2C0%2C0%2C14.37%2C0c2.91-1%2C5.59-2.52%2C5.59-4.86V29.15S43.17%2C29.15%2C47%2C24l-5.33-7.57C40.38%2C14.63%2C38.27%2C12.54%2C36%2C12.54ZM23.32%2C20.09%2C21%2C17l1.8-.6a3.79%2C3.79%2C0%2C0%2C1%2C2.4%2C0L27%2C17l-2.32%2C3.09A.85.85%2C0%2C0%2C1%2C23.32%2C20.09Z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E");
|
|
||||||
}
|
|
||||||
.spine-player-button-icon-settings {
|
|
||||||
background-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2048%2048%22%3E%3Cdefs%3E%3Cstyle%3E.cls-1%7Bfill%3A%23fff%3B%7D%3C%2Fstyle%3E%3C%2Fdefs%3E%3Ctitle%3Esettings%3C%2Ftitle%3E%3Cg%20id%3D%22settings%22%3E%3Cpath%20class%3D%22cls-1%22%20d%3D%22M40%2C3H8A5%2C5%2C0%2C0%2C0%2C3%2C8V40a5%2C5%2C0%2C0%2C0%2C5%2C5H40a5%2C5%2C0%2C0%2C0%2C5-5V8A5%2C5%2C0%2C0%2C0%2C40%2C3ZM16%2C40H9V33h7Zm0-12H9V21h7Zm0-12H9V9h7ZM39%2C38H20V35H39Zm0-12H20V23H39Zm0-12H20V11H39Z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E");
|
|
||||||
margin-top: 1px;
|
|
||||||
}
|
|
||||||
.spine-player-button-icon-settings:hover {
|
|
||||||
background-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2048%2048%22%3E%3Cdefs%3E%3Cstyle%3E.cls-1%7Bfill%3A%2362B0EE%3B%7D%3C%2Fstyle%3E%3C%2Fdefs%3E%3Ctitle%3Esettings%3C%2Ftitle%3E%3Cg%20id%3D%22settings%22%3E%3Cpath%20class%3D%22cls-1%22%20d%3D%22M40%2C3H8A5%2C5%2C0%2C0%2C0%2C3%2C8V40a5%2C5%2C0%2C0%2C0%2C5%2C5H40a5%2C5%2C0%2C0%2C0%2C5-5V8A5%2C5%2C0%2C0%2C0%2C40%2C3ZM16%2C40H9V33h7Zm0-12H9V21h7Zm0-12H9V9h7ZM39%2C38H20V35H39Zm0-12H20V23H39Zm0-12H20V11H39Z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E");
|
|
||||||
}
|
|
||||||
.spine-player-button-icon-settings-selected {
|
|
||||||
background-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2048%2048%22%3E%3Cdefs%3E%3Cstyle%3E.cls-1%7Bfill%3A%2362B0EE%3B%7D%3C%2Fstyle%3E%3C%2Fdefs%3E%3Ctitle%3Esettings%3C%2Ftitle%3E%3Cg%20id%3D%22settings%22%3E%3Cpath%20class%3D%22cls-1%22%20d%3D%22M40%2C3H8A5%2C5%2C0%2C0%2C0%2C3%2C8V40a5%2C5%2C0%2C0%2C0%2C5%2C5H40a5%2C5%2C0%2C0%2C0%2C5-5V8A5%2C5%2C0%2C0%2C0%2C40%2C3ZM16%2C40H9V33h7Zm0-12H9V21h7Zm0-12H9V9h7ZM39%2C38H20V35H39Zm0-12H20V23H39Zm0-12H20V11H39Z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E");
|
|
||||||
}
|
|
||||||
.spine-player-button-icon-fullscreen {
|
|
||||||
background-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2048%2048%22%3E%3Cdefs%3E%3Cstyle%3E.cls-1%7Bfill%3A%23fff%3B%7D%3C%2Fstyle%3E%3C%2Fdefs%3E%3Ctitle%3Eexpand%3C%2Ftitle%3E%3Cg%20id%3D%22settings%22%3E%3Cpolygon%20class%3D%22cls-1%22%20points%3D%2230.14%208%2040%208%2040%2017.86%2044.5%2017.86%2044.5%203.5%2030.14%203.5%2030.14%208%22%2F%3E%3Cpolygon%20class%3D%22cls-1%22%20points%3D%228%2017.86%208%208%2017.86%208%2017.86%203.5%203.5%203.5%203.5%2017.86%208%2017.86%22%2F%3E%3Cpolygon%20class%3D%22cls-1%22%20points%3D%2240%2030.14%2040%2040%2030.14%2040%2030.14%2044.5%2044.5%2044.5%2044.5%2030.14%2040%2030.14%22%2F%3E%3Cpolygon%20class%3D%22cls-1%22%20points%3D%2217.86%2040%208%2040%208%2030.14%203.5%2030.14%203.5%2044.5%2017.86%2044.5%2017.86%2040%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E");
|
|
||||||
margin-top: 1px;
|
|
||||||
}
|
|
||||||
.spine-player-button-icon-fullscreen:hover {
|
|
||||||
background-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2048%2048%22%3E%3Cdefs%3E%3Cstyle%3E.cls-1%7Bfill%3A%2362B0EE%3B%7D%3C%2Fstyle%3E%3C%2Fdefs%3E%3Ctitle%3Eexpand%3C%2Ftitle%3E%3Cg%20id%3D%22settings%22%3E%3Cpolygon%20class%3D%22cls-1%22%20points%3D%2230.14%208%2040%208%2040%2017.86%2044.5%2017.86%2044.5%203.5%2030.14%203.5%2030.14%208%22%2F%3E%3Cpolygon%20class%3D%22cls-1%22%20points%3D%228%2017.86%208%208%2017.86%208%2017.86%203.5%203.5%203.5%203.5%2017.86%208%2017.86%22%2F%3E%3Cpolygon%20class%3D%22cls-1%22%20points%3D%2240%2030.14%2040%2040%2030.14%2040%2030.14%2044.5%2044.5%2044.5%2044.5%2030.14%2040%2030.14%22%2F%3E%3Cpolygon%20class%3D%22cls-1%22%20points%3D%2217.86%2040%208%2040%208%2030.14%203.5%2030.14%203.5%2044.5%2017.86%2044.5%2017.86%2040%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E");
|
|
||||||
}
|
|
||||||
.spine-player-button-icon-fullscreen-selected {
|
|
||||||
background-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2048%2048%22%3E%3Cdefs%3E%3Cstyle%3E.cls-1%7Bfill%3A%2362B0EE%3B%7D%3C%2Fstyle%3E%3C%2Fdefs%3E%3Ctitle%3Eexpand%3C%2Ftitle%3E%3Cg%20id%3D%22settings%22%3E%3Cpolygon%20class%3D%22cls-1%22%20points%3D%2230.14%208%2040%208%2040%2017.86%2044.5%2017.86%2044.5%203.5%2030.14%203.5%2030.14%208%22%2F%3E%3Cpolygon%20class%3D%22cls-1%22%20points%3D%228%2017.86%208%208%2017.86%208%2017.86%203.5%203.5%203.5%203.5%2017.86%208%2017.86%22%2F%3E%3Cpolygon%20class%3D%22cls-1%22%20points%3D%2240%2030.14%2040%2040%2030.14%2040%2030.14%2044.5%2044.5%2044.5%2044.5%2030.14%2040%2030.14%22%2F%3E%3Cpolygon%20class%3D%22cls-1%22%20points%3D%2217.86%2040%208%2040%208%2030.14%203.5%2030.14%203.5%2044.5%2017.86%2044.5%2017.86%2040%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E");
|
|
||||||
}
|
|
||||||
.spine-player-button-icon-spine-logo {
|
|
||||||
height: 20px;
|
|
||||||
position: relative;
|
|
||||||
top: 1px;
|
|
||||||
margin: 0 8px !important;
|
|
||||||
align-self: center;
|
|
||||||
border: none !important;
|
|
||||||
width: auto !important;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: transform 0.2s;
|
|
||||||
box-shadow: none !important;
|
|
||||||
filter: drop-shadow(0 0 1px #333);
|
|
||||||
}
|
|
||||||
.spine-player-button-icon-spine-logo:hover {
|
|
||||||
transform: scale(1.05);
|
|
||||||
transition: transform 0.2s;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Speed slider **/
|
|
||||||
.spine-player-speed-slider {
|
|
||||||
width: 150px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Player editor **/
|
|
||||||
.spine-player-editor-container {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
.spine-player-editor-code {
|
|
||||||
flex: 1;
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
.spine-player-editor-player {
|
|
||||||
flex: 1;
|
|
||||||
border: none;
|
|
||||||
background: black;
|
|
||||||
}
|
|
||||||
.CodeMirror {
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||