@pixi-ui-editor/runtime-pixi 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/fonts.d.ts +5 -0
- package/dist/assets/fonts.d.ts.map +1 -0
- package/dist/assets/fonts.js +50 -0
- package/dist/assets/fonts.js.map +1 -0
- package/dist/assets/sounds.d.ts +14 -0
- package/dist/assets/sounds.d.ts.map +1 -0
- package/dist/assets/sounds.js +156 -0
- package/dist/assets/sounds.js.map +1 -0
- package/dist/assets/spine.d.ts +18 -0
- package/dist/assets/spine.d.ts.map +1 -0
- package/dist/assets/spine.js +82 -0
- package/dist/assets/spine.js.map +1 -0
- package/dist/assets/textures.d.ts +15 -0
- package/dist/assets/textures.d.ts.map +1 -0
- package/dist/assets/textures.js +86 -0
- package/dist/assets/textures.js.map +1 -0
- package/dist/controls.d.ts +19 -0
- package/dist/controls.d.ts.map +1 -0
- package/dist/controls.js +55 -0
- package/dist/controls.js.map +1 -0
- package/dist/document.d.ts +8 -0
- package/dist/document.d.ts.map +1 -0
- package/dist/document.js +22 -0
- package/dist/document.js.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/index.test.d.ts +2 -0
- package/dist/index.test.d.ts.map +1 -0
- package/dist/index.test.js +315 -0
- package/dist/index.test.js.map +1 -0
- package/dist/layout.d.ts +32 -0
- package/dist/layout.d.ts.map +1 -0
- package/dist/layout.js +43 -0
- package/dist/layout.js.map +1 -0
- package/dist/layoutGroups.d.ts +31 -0
- package/dist/layoutGroups.d.ts.map +1 -0
- package/dist/layoutGroups.js +139 -0
- package/dist/layoutGroups.js.map +1 -0
- package/dist/particles.d.ts +139 -0
- package/dist/particles.d.ts.map +1 -0
- package/dist/particles.js +275 -0
- package/dist/particles.js.map +1 -0
- package/dist/particles.test.d.ts +2 -0
- package/dist/particles.test.d.ts.map +1 -0
- package/dist/particles.test.js +210 -0
- package/dist/particles.test.js.map +1 -0
- package/dist/scene.d.ts +41 -0
- package/dist/scene.d.ts.map +1 -0
- package/dist/scene.js +147 -0
- package/dist/scene.js.map +1 -0
- package/dist/scrollView.d.ts +28 -0
- package/dist/scrollView.d.ts.map +1 -0
- package/dist/scrollView.js +38 -0
- package/dist/scrollView.js.map +1 -0
- package/dist/test.setup.d.ts +2 -0
- package/dist/test.setup.d.ts.map +1 -0
- package/dist/test.setup.js +6 -0
- package/dist/test.setup.js.map +1 -0
- package/dist/views/ButtonNodeView.d.ts +36 -0
- package/dist/views/ButtonNodeView.d.ts.map +1 -0
- package/dist/views/ButtonNodeView.js +104 -0
- package/dist/views/ButtonNodeView.js.map +1 -0
- package/dist/views/InputNodeView.d.ts +36 -0
- package/dist/views/InputNodeView.d.ts.map +1 -0
- package/dist/views/InputNodeView.js +170 -0
- package/dist/views/InputNodeView.js.map +1 -0
- package/dist/views/NodeView.d.ts +53 -0
- package/dist/views/NodeView.d.ts.map +1 -0
- package/dist/views/NodeView.js +86 -0
- package/dist/views/NodeView.js.map +1 -0
- package/dist/views/ParticleEmitterNodeView.d.ts +26 -0
- package/dist/views/ParticleEmitterNodeView.d.ts.map +1 -0
- package/dist/views/ParticleEmitterNodeView.js +101 -0
- package/dist/views/ParticleEmitterNodeView.js.map +1 -0
- package/dist/views/ParticleEmitterNodeView.test.d.ts +2 -0
- package/dist/views/ParticleEmitterNodeView.test.d.ts.map +1 -0
- package/dist/views/ParticleEmitterNodeView.test.js +148 -0
- package/dist/views/ParticleEmitterNodeView.test.js.map +1 -0
- package/dist/views/ScrollViewNodeView.d.ts +29 -0
- package/dist/views/ScrollViewNodeView.d.ts.map +1 -0
- package/dist/views/ScrollViewNodeView.js +67 -0
- package/dist/views/ScrollViewNodeView.js.map +1 -0
- package/dist/views/SpineNodeView.d.ts +8 -0
- package/dist/views/SpineNodeView.d.ts.map +1 -0
- package/dist/views/SpineNodeView.js +30 -0
- package/dist/views/SpineNodeView.js.map +1 -0
- package/dist/views/ValueControlNodeViews.d.ts +37 -0
- package/dist/views/ValueControlNodeViews.d.ts.map +1 -0
- package/dist/views/ValueControlNodeViews.js +179 -0
- package/dist/views/ValueControlNodeViews.js.map +1 -0
- package/dist/views/basic.d.ts +29 -0
- package/dist/views/basic.d.ts.map +1 -0
- package/dist/views/basic.js +92 -0
- package/dist/views/basic.js.map +1 -0
- package/dist/views/createNodeView.d.ts +13 -0
- package/dist/views/createNodeView.d.ts.map +1 -0
- package/dist/views/createNodeView.js +89 -0
- package/dist/views/createNodeView.js.map +1 -0
- package/package.json +36 -0
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { ProjectDocument } from "@pixi-ui-editor/schema";
|
|
2
|
+
import type { FileUrlResolver } from "./textures.js";
|
|
3
|
+
/** Loads scene fonts before views are built. A load failure is a warning and keeps system fallback usable. */
|
|
4
|
+
export declare function loadSceneFonts(document: ProjectDocument, sceneId: string, resolveFileUrl: FileUrlResolver): Promise<Map<string, string>>;
|
|
5
|
+
//# sourceMappingURL=fonts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fonts.d.ts","sourceRoot":"","sources":["../../src/assets/fonts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAS,eAAe,EAAU,MAAM,wBAAwB,CAAC;AAC7E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAWrD,8GAA8G;AAC9G,wBAAsB,cAAc,CAAC,QAAQ,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,eAAe,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAuB9I"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
const cache = new Map();
|
|
2
|
+
const keyOf = (asset) => `${asset.source.uri}#${asset.source.version ?? ""}`;
|
|
3
|
+
const fromNodes = (nodes) => nodes.flatMap((node) => {
|
|
4
|
+
if (node.type === "text" && node.style?.fontAssetId)
|
|
5
|
+
return [node.style.fontAssetId];
|
|
6
|
+
if (node.type === "input" && node.textStyle.fontAssetId)
|
|
7
|
+
return [node.textStyle.fontAssetId];
|
|
8
|
+
if (node.type === "slider" && node.valueTextStyle?.fontAssetId)
|
|
9
|
+
return [node.valueTextStyle.fontAssetId];
|
|
10
|
+
return [];
|
|
11
|
+
});
|
|
12
|
+
/** Loads scene fonts before views are built. A load failure is a warning and keeps system fallback usable. */
|
|
13
|
+
export async function loadSceneFonts(document, sceneId, resolveFileUrl) {
|
|
14
|
+
const scene = document.scenes.find((item) => item.id === sceneId);
|
|
15
|
+
if (scene === undefined)
|
|
16
|
+
throw new Error(`Scene '${sceneId}' does not exist in the project document.`);
|
|
17
|
+
const ids = new Set(fromNodes(scene.nodes));
|
|
18
|
+
scene.nodes.filter((node) => node.type === "prefab-instance").forEach((node) => fromNodes(document.prefabs.find((item) => item.id === node.prefabId)?.nodes ?? []).forEach((id) => ids.add(id)));
|
|
19
|
+
const fonts = new Map();
|
|
20
|
+
await Promise.all([...ids].map(async (id) => {
|
|
21
|
+
const asset = document.assets.find((item) => item.id === id);
|
|
22
|
+
if (asset?.type !== "font")
|
|
23
|
+
return;
|
|
24
|
+
const key = keyOf(asset);
|
|
25
|
+
let pending = cache.get(key);
|
|
26
|
+
if (pending === undefined) {
|
|
27
|
+
pending = (async () => {
|
|
28
|
+
const url = resolveFileUrl(asset.source.uri);
|
|
29
|
+
if (url === undefined || typeof FontFace === "undefined" || typeof globalThis.document === "undefined")
|
|
30
|
+
return undefined;
|
|
31
|
+
try {
|
|
32
|
+
const face = new FontFace(asset.family, `url(${JSON.stringify(url)})`, { weight: asset.weight, style: asset.style });
|
|
33
|
+
await face.load();
|
|
34
|
+
globalThis.document.fonts.add(face);
|
|
35
|
+
return asset.family;
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
console.warn(`Unable to load font asset '${asset.id}'. Using system fallback.`, error);
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
})();
|
|
42
|
+
cache.set(key, pending);
|
|
43
|
+
}
|
|
44
|
+
const family = await pending;
|
|
45
|
+
if (family !== undefined)
|
|
46
|
+
fonts.set(id, family);
|
|
47
|
+
}));
|
|
48
|
+
return fonts;
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=fonts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fonts.js","sourceRoot":"","sources":["../../src/assets/fonts.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Sound } from "@pixi/sound";
|
|
2
|
+
import type { ProjectDocument, Scene } from "@pixi-ui-editor/schema";
|
|
3
|
+
import type { FileUrlResolver } from "./textures.js";
|
|
4
|
+
/** Loads every sound asset up front, useful for an editor Preview whose assignments change live. */
|
|
5
|
+
export declare function loadProjectSounds(document: ProjectDocument, resolveFileUrl: FileUrlResolver, cache?: Map<string, Sound>): Promise<Map<string, Sound>>;
|
|
6
|
+
/** Loads the background track and button sounds used by one rendered scene. Failed assets stay silent. */
|
|
7
|
+
export declare function loadSceneSounds(document: ProjectDocument, sceneId: string, resolveFileUrl: FileUrlResolver, cache?: Map<string, Sound>): Promise<Map<string, Sound>>;
|
|
8
|
+
export type SceneAudioPlayback = {
|
|
9
|
+
update(audio: Scene["audio"], sounds: ReadonlyMap<string, Sound>): void;
|
|
10
|
+
stop(): void;
|
|
11
|
+
};
|
|
12
|
+
/** Owns one scene's looping background track and retries browser-blocked autoplay on first input. */
|
|
13
|
+
export declare function createSceneAudioPlayback(): SceneAudioPlayback;
|
|
14
|
+
//# sourceMappingURL=sounds.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sounds.d.ts","sourceRoot":"","sources":["../../src/assets/sounds.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAkB,MAAM,aAAa,CAAC;AACzD,OAAO,KAAK,EAAE,eAAe,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAC;AAGrE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAiDrD,oGAAoG;AACpG,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,eAAe,EACzB,cAAc,EAAE,eAAe,EAC/B,KAAK,GAAE,GAAG,CAAC,MAAM,EAAE,KAAK,CAAa,GACpC,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAE7B;AAED,0GAA0G;AAC1G,wBAAsB,eAAe,CACnC,QAAQ,EAAE,eAAe,EACzB,OAAO,EAAE,MAAM,EACf,cAAc,EAAE,eAAe,EAC/B,KAAK,GAAE,GAAG,CAAC,MAAM,EAAE,KAAK,CAAa,GACpC,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAU7B;AAED,MAAM,MAAM,kBAAkB,GAAG;IAC/B,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,KAAK,CAAC,GAAG,IAAI,CAAC;IACxE,IAAI,IAAI,IAAI,CAAC;CACd,CAAC;AAEF,qGAAqG;AACrG,wBAAgB,wBAAwB,IAAI,kBAAkB,CA4E7D"}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { collectRenderedNodes } from "../scene.js";
|
|
2
|
+
import { collectNodeAssetIds } from "../views/createNodeView.js";
|
|
3
|
+
async function loadSound(source) {
|
|
4
|
+
const { Sound } = await import("@pixi/sound");
|
|
5
|
+
return new Promise((resolve, reject) => {
|
|
6
|
+
let created;
|
|
7
|
+
try {
|
|
8
|
+
created = Sound.from({
|
|
9
|
+
source,
|
|
10
|
+
preload: true,
|
|
11
|
+
// @pixi/sound's runtime uses the Node-style `null` success value although its declaration
|
|
12
|
+
// only mentions Error. Accept both null and undefined or every successful decode is rejected.
|
|
13
|
+
loaded: (error, loaded) => error == null ? resolve(loaded ?? created) : reject(error),
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
catch (error) {
|
|
17
|
+
reject(error);
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
async function loadSoundAssets(document, ids, resolveFileUrl, cache = new Map()) {
|
|
22
|
+
const assetsById = new Map(document.assets.map((asset) => [asset.id, asset]));
|
|
23
|
+
const sounds = new Map();
|
|
24
|
+
for (const assetId of ids) {
|
|
25
|
+
const asset = assetsById.get(assetId);
|
|
26
|
+
if (asset?.type !== "sound")
|
|
27
|
+
continue;
|
|
28
|
+
try {
|
|
29
|
+
let loaded = cache.get(asset.source.uri);
|
|
30
|
+
if (loaded === undefined) {
|
|
31
|
+
const url = resolveFileUrl(asset.source.uri);
|
|
32
|
+
if (url === undefined)
|
|
33
|
+
continue;
|
|
34
|
+
const response = await fetch(url);
|
|
35
|
+
if (!response.ok)
|
|
36
|
+
throw new Error(`Unable to fetch '${url}': ${response.status} ${response.statusText}`);
|
|
37
|
+
loaded = await loadSound(await response.arrayBuffer());
|
|
38
|
+
cache.set(asset.source.uri, loaded);
|
|
39
|
+
}
|
|
40
|
+
sounds.set(asset.id, loaded);
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
console.warn(`Unable to load sound for asset '${asset.id}'.`, error);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return sounds;
|
|
47
|
+
}
|
|
48
|
+
/** Loads every sound asset up front, useful for an editor Preview whose assignments change live. */
|
|
49
|
+
export function loadProjectSounds(document, resolveFileUrl, cache = new Map()) {
|
|
50
|
+
return loadSoundAssets(document, document.assets.filter((asset) => asset.type === "sound").map((asset) => asset.id), resolveFileUrl, cache);
|
|
51
|
+
}
|
|
52
|
+
/** Loads the background track and button sounds used by one rendered scene. Failed assets stay silent. */
|
|
53
|
+
export async function loadSceneSounds(document, sceneId, resolveFileUrl, cache = new Map()) {
|
|
54
|
+
const scene = document.scenes.find((candidate) => candidate.id === sceneId);
|
|
55
|
+
if (scene === undefined)
|
|
56
|
+
throw new Error(`Scene '${sceneId}' does not exist in the project document.`);
|
|
57
|
+
const assetsById = new Map(document.assets.map((asset) => [asset.id, asset]));
|
|
58
|
+
const ids = new Set();
|
|
59
|
+
if (scene.audio?.backgroundMusicAssetId !== undefined)
|
|
60
|
+
ids.add(scene.audio.backgroundMusicAssetId);
|
|
61
|
+
for (const node of collectRenderedNodes(document, scene)) {
|
|
62
|
+
for (const assetId of collectNodeAssetIds(node))
|
|
63
|
+
if (assetsById.get(assetId)?.type === "sound")
|
|
64
|
+
ids.add(assetId);
|
|
65
|
+
}
|
|
66
|
+
return loadSoundAssets(document, ids, resolveFileUrl, cache);
|
|
67
|
+
}
|
|
68
|
+
/** Owns one scene's looping background track and retries browser-blocked autoplay on first input. */
|
|
69
|
+
export function createSceneAudioPlayback() {
|
|
70
|
+
let assetId;
|
|
71
|
+
let currentSound;
|
|
72
|
+
let currentInstance;
|
|
73
|
+
let currentVolume = 1;
|
|
74
|
+
let pendingStart;
|
|
75
|
+
const removePendingStart = () => {
|
|
76
|
+
if (pendingStart !== undefined && typeof window !== "undefined")
|
|
77
|
+
window.removeEventListener("pointerdown", pendingStart);
|
|
78
|
+
pendingStart = undefined;
|
|
79
|
+
};
|
|
80
|
+
const stopCurrent = () => {
|
|
81
|
+
removePendingStart();
|
|
82
|
+
currentSound?.stop();
|
|
83
|
+
currentInstance = undefined;
|
|
84
|
+
currentSound = undefined;
|
|
85
|
+
assetId = undefined;
|
|
86
|
+
};
|
|
87
|
+
const audioContextIsSuspended = (sound) => {
|
|
88
|
+
const context = sound.context;
|
|
89
|
+
return context.audioContext?.state === "suspended";
|
|
90
|
+
};
|
|
91
|
+
const scheduleRetry = (start) => {
|
|
92
|
+
if (typeof window === "undefined" || pendingStart !== undefined)
|
|
93
|
+
return;
|
|
94
|
+
pendingStart = () => {
|
|
95
|
+
pendingStart = undefined;
|
|
96
|
+
currentInstance?.stop();
|
|
97
|
+
currentInstance = undefined;
|
|
98
|
+
const context = currentSound?.context?.audioContext;
|
|
99
|
+
if (context?.resume !== undefined)
|
|
100
|
+
void context.resume().finally(start);
|
|
101
|
+
else
|
|
102
|
+
start();
|
|
103
|
+
};
|
|
104
|
+
window.addEventListener("pointerdown", pendingStart, { once: true });
|
|
105
|
+
};
|
|
106
|
+
const playback = {
|
|
107
|
+
update(audio, sounds) {
|
|
108
|
+
const nextAssetId = audio?.backgroundMusicAssetId;
|
|
109
|
+
const nextSound = nextAssetId === undefined ? undefined : sounds.get(nextAssetId);
|
|
110
|
+
const volume = audio?.volume ?? 1;
|
|
111
|
+
currentVolume = volume;
|
|
112
|
+
if (nextAssetId === undefined || nextSound === undefined) {
|
|
113
|
+
stopCurrent();
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
if (assetId === nextAssetId && currentSound === nextSound) {
|
|
117
|
+
if (currentInstance !== undefined)
|
|
118
|
+
currentInstance.volume = currentVolume;
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
stopCurrent();
|
|
122
|
+
assetId = nextAssetId;
|
|
123
|
+
currentSound = nextSound;
|
|
124
|
+
const start = () => {
|
|
125
|
+
if (assetId !== nextAssetId || currentSound !== nextSound)
|
|
126
|
+
return;
|
|
127
|
+
removePendingStart();
|
|
128
|
+
try {
|
|
129
|
+
const result = nextSound.play({ loop: true, volume: currentVolume });
|
|
130
|
+
if (result instanceof Promise) {
|
|
131
|
+
void result.then((instance) => {
|
|
132
|
+
if (assetId === nextAssetId && currentSound === nextSound) {
|
|
133
|
+
currentInstance = instance;
|
|
134
|
+
instance.volume = currentVolume;
|
|
135
|
+
}
|
|
136
|
+
else
|
|
137
|
+
instance.stop();
|
|
138
|
+
}).catch(() => scheduleRetry(start));
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
currentInstance = result;
|
|
142
|
+
if (audioContextIsSuspended(nextSound))
|
|
143
|
+
scheduleRetry(start);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
catch {
|
|
147
|
+
scheduleRetry(start);
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
start();
|
|
151
|
+
},
|
|
152
|
+
stop: stopCurrent,
|
|
153
|
+
};
|
|
154
|
+
return playback;
|
|
155
|
+
}
|
|
156
|
+
//# sourceMappingURL=sounds.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sounds.js","sourceRoot":"","sources":["../../src/assets/sounds.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Spine, TextureAtlas, type SkeletonData } from "@esotericsoftware/spine-pixi-v8";
|
|
2
|
+
import { type Asset, type ProjectDocument } from "@pixi-ui-editor/schema";
|
|
3
|
+
import { Texture, type Ticker } from "pixi.js";
|
|
4
|
+
import { type FileUrlResolver } from "./textures.js";
|
|
5
|
+
/** Assigns atlas pages by their exported image filename, never by their array index. */
|
|
6
|
+
export declare function assignAtlasPageTextures(atlas: TextureAtlas, textures: ReadonlyMap<string, Texture>): void;
|
|
7
|
+
/** Creates a Spine display object, optionally assigning it to a specific renderer ticker. */
|
|
8
|
+
export declare function createSpineView(skeletonData: SkeletonData, animation?: string, options?: {
|
|
9
|
+
autoUpdate?: boolean;
|
|
10
|
+
ticker?: Ticker;
|
|
11
|
+
}): Spine;
|
|
12
|
+
/** Loads the Spine data referenced by a scene. Failed assets are left out for placeholder rendering. */
|
|
13
|
+
export declare function loadSceneSpines(document: ProjectDocument, sceneId: string, resolveFileUrl: FileUrlResolver, cache?: Map<string, SkeletonData>): Promise<Map<string, SkeletonData>>;
|
|
14
|
+
/** Loads one Spine asset, sharing parsed SkeletonData by skeleton file URI. */
|
|
15
|
+
export declare function loadSpineAsset(asset: Extract<Asset, {
|
|
16
|
+
type: "spine";
|
|
17
|
+
}>, resolveFileUrl: FileUrlResolver, cache?: Map<string, SkeletonData>): Promise<SkeletonData>;
|
|
18
|
+
//# sourceMappingURL=spine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spine.d.ts","sourceRoot":"","sources":["../../src/assets/spine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuC,KAAK,EAAgB,YAAY,EAAE,KAAK,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAC5I,OAAO,EAAE,KAAK,KAAK,EAAE,KAAK,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC1E,OAAO,EAAE,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,SAAS,CAAC;AAE/C,OAAO,EAAe,KAAK,eAAe,EAAE,MAAM,eAAe,CAAC;AAalE,wFAAwF;AACxF,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAMzG;AAED,6FAA6F;AAC7F,wBAAgB,eAAe,CAAC,YAAY,EAAE,YAAY,EAAE,SAAS,CAAC,EAAE,MAAM,EAAE,OAAO,GAAE;IAAE,UAAU,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,KAAK,CAI9I;AAED,wGAAwG;AACxG,wBAAsB,eAAe,CACnC,QAAQ,EAAE,eAAe,EACzB,OAAO,EAAE,MAAM,EACf,cAAc,EAAE,eAAe,EAC/B,KAAK,GAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAa,GAC3C,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAgBpC;AAED,+EAA+E;AAC/E,wBAAsB,cAAc,CAAC,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC,EAAE,cAAc,EAAE,eAAe,EAAE,KAAK,GAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAa,GAAG,OAAO,CAAC,YAAY,CAAC,CAyBnL"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { AtlasAttachmentLoader, SkeletonJson, Spine, SpineTexture, TextureAtlas } from "@esotericsoftware/spine-pixi-v8";
|
|
2
|
+
import { collectRenderedNodes } from "../scene.js";
|
|
3
|
+
import { loadTexture } from "./textures.js";
|
|
4
|
+
/** Matches spine-pixi-v8's "unknown timeline/attachment/constraint type" errors, thrown when a skeleton was exported by an incompatible Spine Editor version (e.g. pre-4.0 JSON, which names slot color timelines "color"/"twoColor" instead of the 4.x "rgba"/"rgba2"). */
|
|
5
|
+
const INCOMPATIBLE_SKELETON_FORMAT_PATTERN = /Invalid (?:timeline|attachment|constraint) type/;
|
|
6
|
+
function describeSkeletonParseError(error) {
|
|
7
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
8
|
+
if (INCOMPATIBLE_SKELETON_FORMAT_PATTERN.test(message)) {
|
|
9
|
+
return `Unsupported Spine export format (${message}). The skeleton was likely exported by a Spine Editor version incompatible with this runtime (spine-pixi-v8, Spine 4.x JSON). Re-export it from Spine Editor 4.1+.`;
|
|
10
|
+
}
|
|
11
|
+
return `Failed to parse skeleton data: ${message}`;
|
|
12
|
+
}
|
|
13
|
+
/** Assigns atlas pages by their exported image filename, never by their array index. */
|
|
14
|
+
export function assignAtlasPageTextures(atlas, textures) {
|
|
15
|
+
for (const page of atlas.pages) {
|
|
16
|
+
const texture = textures.get(page.name);
|
|
17
|
+
if (texture === undefined)
|
|
18
|
+
throw new Error(`Atlas page '${page.name}' has no matching texture file.`);
|
|
19
|
+
page.setTexture(SpineTexture.from(texture.source));
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/** Creates a Spine display object, optionally assigning it to a specific renderer ticker. */
|
|
23
|
+
export function createSpineView(skeletonData, animation, options = {}) {
|
|
24
|
+
const spine = new Spine({ skeletonData, autoUpdate: options.autoUpdate ?? true, ticker: options.ticker });
|
|
25
|
+
if (animation !== undefined && skeletonData.findAnimation(animation) !== null)
|
|
26
|
+
spine.state.setAnimation(0, animation, true);
|
|
27
|
+
return spine;
|
|
28
|
+
}
|
|
29
|
+
/** Loads the Spine data referenced by a scene. Failed assets are left out for placeholder rendering. */
|
|
30
|
+
export async function loadSceneSpines(document, sceneId, resolveFileUrl, cache = new Map()) {
|
|
31
|
+
const scene = document.scenes.find((candidate) => candidate.id === sceneId);
|
|
32
|
+
if (scene === undefined)
|
|
33
|
+
throw new Error(`Scene '${sceneId}' does not exist in the project document.`);
|
|
34
|
+
const assetsById = new Map(document.assets.map((asset) => [asset.id, asset]));
|
|
35
|
+
const spines = new Map();
|
|
36
|
+
for (const node of collectRenderedNodes(document, scene)) {
|
|
37
|
+
if (node.type !== "spine" || spines.has(node.assetId))
|
|
38
|
+
continue;
|
|
39
|
+
const asset = assetsById.get(node.assetId);
|
|
40
|
+
if (asset?.type !== "spine")
|
|
41
|
+
continue;
|
|
42
|
+
try {
|
|
43
|
+
spines.set(asset.id, await loadSpineAsset(asset, resolveFileUrl, cache));
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
console.warn(`Unable to load Spine asset '${asset.name}' (${asset.id}).`, error);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return spines;
|
|
50
|
+
}
|
|
51
|
+
/** Loads one Spine asset, sharing parsed SkeletonData by skeleton file URI. */
|
|
52
|
+
export async function loadSpineAsset(asset, resolveFileUrl, cache = new Map()) {
|
|
53
|
+
const cached = cache.get(asset.files.skeleton.uri);
|
|
54
|
+
if (cached !== undefined)
|
|
55
|
+
return cached;
|
|
56
|
+
const skeletonUrl = resolveFileUrl(asset.files.skeleton.uri);
|
|
57
|
+
const atlasUrl = resolveFileUrl(asset.files.atlas.uri);
|
|
58
|
+
if (skeletonUrl === undefined || atlasUrl === undefined)
|
|
59
|
+
throw new Error("A Spine file URL could not be resolved.");
|
|
60
|
+
const [skeletonText, atlasText] = await Promise.all([fetch(skeletonUrl).then((response) => response.text()), fetch(atlasUrl).then((response) => response.text())]);
|
|
61
|
+
const textures = new Map();
|
|
62
|
+
for (const file of asset.files.textures) {
|
|
63
|
+
const url = resolveFileUrl(file.uri);
|
|
64
|
+
if (url === undefined)
|
|
65
|
+
throw new Error(`Texture '${file.name}' could not be resolved.`);
|
|
66
|
+
textures.set(file.name, await loadTexture(url));
|
|
67
|
+
}
|
|
68
|
+
const atlas = new TextureAtlas(atlasText);
|
|
69
|
+
assignAtlasPageTextures(atlas, textures);
|
|
70
|
+
let skeletonData;
|
|
71
|
+
try {
|
|
72
|
+
skeletonData = new SkeletonJson(new AtlasAttachmentLoader(atlas)).readSkeletonData(skeletonText);
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
const description = describeSkeletonParseError(error);
|
|
76
|
+
console.error(`Spine asset '${asset.name}' (${asset.id}) could not be parsed: ${description}`);
|
|
77
|
+
throw new Error(description, { cause: error });
|
|
78
|
+
}
|
|
79
|
+
cache.set(asset.files.skeleton.uri, skeletonData);
|
|
80
|
+
return skeletonData;
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=spine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spine.js","sourceRoot":"","sources":["../../src/assets/spine.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type Asset, type ProjectDocument } from "@pixi-ui-editor/schema";
|
|
2
|
+
import { Spritesheet, Texture } from "pixi.js";
|
|
3
|
+
export type AssetUrlResolver = (asset: Asset) => string | undefined;
|
|
4
|
+
export type FileUrlResolver = (uri: string) => string | undefined;
|
|
5
|
+
type AtlasAsset = Extract<Asset, {
|
|
6
|
+
type: "atlas";
|
|
7
|
+
}>;
|
|
8
|
+
/** Loads one texture from a data URI or a regular URL. */
|
|
9
|
+
export declare function loadTexture(url: string): Promise<Texture>;
|
|
10
|
+
/** Loads and parses one atlas's Spritesheet, sharing the parse by the JSON file's URI. */
|
|
11
|
+
export declare function loadAtlasSpritesheet(asset: AtlasAsset, resolveFileUrl: FileUrlResolver, cache?: Map<string, Spritesheet>): Promise<Spritesheet>;
|
|
12
|
+
/** Loads textures for image nodes in a scene, resolving atlas frame ids through their Spritesheet. Leaves failed assets for placeholder rendering. */
|
|
13
|
+
export declare function loadSceneTextures(document: ProjectDocument, sceneId: string, resolveAssetUrl: AssetUrlResolver, resolveFileUrl: FileUrlResolver, cache?: Map<string, Texture>, spritesheetCache?: Map<string, Spritesheet>): Promise<Map<string, Texture>>;
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=textures.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"textures.d.ts","sourceRoot":"","sources":["../../src/assets/textures.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyB,KAAK,KAAK,EAAE,KAAK,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACjG,OAAO,EAAE,WAAW,EAAE,OAAO,EAAwB,MAAM,SAAS,CAAC;AAIrE,MAAM,MAAM,gBAAgB,GAAG,CAAC,KAAK,EAAE,KAAK,KAAK,MAAM,GAAG,SAAS,CAAC;AACpE,MAAM,MAAM,eAAe,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;AAClE,KAAK,UAAU,GAAG,OAAO,CAAC,KAAK,EAAE;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC,CAAC;AAEpD,0DAA0D;AAC1D,wBAAsB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAK/D;AAED,0FAA0F;AAC1F,wBAAsB,oBAAoB,CACxC,KAAK,EAAE,UAAU,EACjB,cAAc,EAAE,eAAe,EAC/B,KAAK,GAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAa,GAC1C,OAAO,CAAC,WAAW,CAAC,CAgBtB;AAED,sJAAsJ;AACtJ,wBAAsB,iBAAiB,CACrC,QAAQ,EAAE,eAAe,EACzB,OAAO,EAAE,MAAM,EACf,eAAe,EAAE,gBAAgB,EACjC,cAAc,EAAE,eAAe,EAC/B,KAAK,GAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAa,EACvC,gBAAgB,GAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAa,GACrD,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAgD/B"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { collectEffectAssetIds } from "@pixi-ui-editor/schema";
|
|
2
|
+
import { Spritesheet, Texture } from "pixi.js";
|
|
3
|
+
import { collectRenderedNodes } from "../scene.js";
|
|
4
|
+
import { collectNodeAssetIds } from "../views/createNodeView.js";
|
|
5
|
+
/** Loads one texture from a data URI or a regular URL. */
|
|
6
|
+
export async function loadTexture(url) {
|
|
7
|
+
const image = new Image();
|
|
8
|
+
image.src = url;
|
|
9
|
+
await image.decode();
|
|
10
|
+
return Texture.from(image);
|
|
11
|
+
}
|
|
12
|
+
/** Loads and parses one atlas's Spritesheet, sharing the parse by the JSON file's URI. */
|
|
13
|
+
export async function loadAtlasSpritesheet(asset, resolveFileUrl, cache = new Map()) {
|
|
14
|
+
const cached = cache.get(asset.files.json.uri);
|
|
15
|
+
if (cached !== undefined)
|
|
16
|
+
return cached;
|
|
17
|
+
const jsonUrl = resolveFileUrl(asset.files.json.uri);
|
|
18
|
+
const textureUrl = resolveFileUrl(asset.files.texture.uri);
|
|
19
|
+
if (jsonUrl === undefined || textureUrl === undefined)
|
|
20
|
+
throw new Error(`Unable to resolve file URLs for atlas asset '${asset.id}'.`);
|
|
21
|
+
const [data, texture] = await Promise.all([
|
|
22
|
+
fetch(jsonUrl).then((response) => response.json()),
|
|
23
|
+
loadTexture(textureUrl),
|
|
24
|
+
]);
|
|
25
|
+
const sheet = new Spritesheet(texture, data);
|
|
26
|
+
await sheet.parse();
|
|
27
|
+
cache.set(asset.files.json.uri, sheet);
|
|
28
|
+
return sheet;
|
|
29
|
+
}
|
|
30
|
+
/** Loads textures for image nodes in a scene, resolving atlas frame ids through their Spritesheet. Leaves failed assets for placeholder rendering. */
|
|
31
|
+
export async function loadSceneTextures(document, sceneId, resolveAssetUrl, resolveFileUrl, cache = new Map(), spritesheetCache = new Map()) {
|
|
32
|
+
const scene = document.scenes.find((candidate) => candidate.id === sceneId);
|
|
33
|
+
if (scene === undefined)
|
|
34
|
+
throw new Error(`Scene '${sceneId}' does not exist in the project document.`);
|
|
35
|
+
const assetsById = new Map(document.assets.map((asset) => [asset.id, asset]));
|
|
36
|
+
const framesById = new Map();
|
|
37
|
+
for (const asset of document.assets) {
|
|
38
|
+
if (asset.type !== "atlas")
|
|
39
|
+
continue;
|
|
40
|
+
for (const [frameName, frameId] of Object.entries(asset.frames))
|
|
41
|
+
framesById.set(frameId, { atlas: asset, frameName });
|
|
42
|
+
}
|
|
43
|
+
const textures = new Map();
|
|
44
|
+
for (const node of collectRenderedNodes(document, scene)) {
|
|
45
|
+
const effect = node.type === "particle-emitter" ? document.effects.find((candidate) => candidate.id === node.effectId) : undefined;
|
|
46
|
+
for (const assetId of [...collectNodeAssetIds(node), ...(effect === undefined ? [] : collectEffectAssetIds(effect))]) {
|
|
47
|
+
if (textures.has(assetId))
|
|
48
|
+
continue;
|
|
49
|
+
const asset = assetsById.get(assetId);
|
|
50
|
+
if (asset?.type === "image") {
|
|
51
|
+
const url = resolveAssetUrl(asset);
|
|
52
|
+
if (url === undefined)
|
|
53
|
+
continue;
|
|
54
|
+
try {
|
|
55
|
+
const texture = cache.get(asset.source.uri) ?? await loadTexture(url);
|
|
56
|
+
cache.set(asset.source.uri, texture);
|
|
57
|
+
textures.set(asset.id, texture);
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
console.warn(`Unable to load texture for asset '${asset.id}'.`, error);
|
|
61
|
+
}
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
// Spine и atlas-ассеты сюда тоже попадают: spine-данные грузит loadSceneSpines, а atlas-фреймы резолвятся ниже.
|
|
65
|
+
if (asset !== undefined)
|
|
66
|
+
continue;
|
|
67
|
+
const frame = framesById.get(assetId);
|
|
68
|
+
if (frame === undefined)
|
|
69
|
+
continue;
|
|
70
|
+
try {
|
|
71
|
+
const sheet = await loadAtlasSpritesheet(frame.atlas, resolveFileUrl, spritesheetCache);
|
|
72
|
+
const frameTexture = sheet.textures[frame.frameName];
|
|
73
|
+
if (frameTexture === undefined) {
|
|
74
|
+
console.warn(`Atlas '${frame.atlas.id}' has no frame '${frame.frameName}'.`);
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
textures.set(assetId, frameTexture);
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
console.warn(`Unable to load atlas frame texture for '${assetId}'.`, error);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return textures;
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=textures.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"textures.js","sourceRoot":"","sources":["../../src/assets/textures.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type SkeletonData } from "@esotericsoftware/spine-pixi-v8";
|
|
2
|
+
import { type ButtonStateKey } from "@pixi-ui-editor/schema";
|
|
3
|
+
import { Container } from "pixi.js";
|
|
4
|
+
/** Reads the current 1-based animation frame for an editor Spine node. */
|
|
5
|
+
export declare function getSpineViewPlayback(view: Container, skeletonData: SkeletonData, animation: string): {
|
|
6
|
+
current: number;
|
|
7
|
+
total: number;
|
|
8
|
+
} | undefined;
|
|
9
|
+
/** Seeks an editor Spine node to a 1-based animation frame without changing its serialized animation settings. */
|
|
10
|
+
export declare function setSpineViewFrame(view: Container, frame: number, skeletonData: SkeletonData, animation: string): void;
|
|
11
|
+
/** Forces an editor-only button state; the node's serialized `enabled` and states stay untouched. */
|
|
12
|
+
export declare function setButtonViewState(view: Container, state: ButtonStateKey): void;
|
|
13
|
+
/** Applies an editor-only slider preview value without touching the document. */
|
|
14
|
+
export declare function setSliderViewValue(view: Container, value: number): void;
|
|
15
|
+
/** Applies an editor-only progress preview without touching the document. */
|
|
16
|
+
export declare function setProgressBarViewProgress(view: Container, progress: number): void;
|
|
17
|
+
/** Enables or pauses editor-only automatic playback without affecting serialized node data. */
|
|
18
|
+
export declare function setSpineViewAutoplay(view: Container, autoplay: boolean): void;
|
|
19
|
+
//# sourceMappingURL=controls.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"controls.d.ts","sourceRoot":"","sources":["../src/controls.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,YAAY,EAAS,MAAM,iCAAiC,CAAC;AAC3E,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAUpC,0EAA0E;AAC1E,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,SAAS,EAAE,YAAY,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CASnJ;AAED,kHAAkH;AAClH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CASrH;AAED,qGAAqG;AACrG,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,cAAc,GAAG,IAAI,CAE/E;AAED,iFAAiF;AACjF,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAEvE;AAED,6EAA6E;AAC7E,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAElF;AAED,+FAA+F;AAC/F,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,GAAG,IAAI,CAG7E"}
|
package/dist/controls.js
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { Spine } from "@esotericsoftware/spine-pixi-v8";
|
|
2
|
+
import { ButtonNodeView } from "./views/ButtonNodeView.js";
|
|
3
|
+
import { NodeView } from "./views/NodeView.js";
|
|
4
|
+
import { ProgressBarNodeView, SliderNodeView } from "./views/ValueControlNodeViews.js";
|
|
5
|
+
function findSpineChild(view) {
|
|
6
|
+
if (view instanceof NodeView)
|
|
7
|
+
return view.getSpine();
|
|
8
|
+
return view instanceof Spine ? view : view.children.find((child) => child instanceof Spine);
|
|
9
|
+
}
|
|
10
|
+
/** Reads the current 1-based animation frame for an editor Spine node. */
|
|
11
|
+
export function getSpineViewPlayback(view, skeletonData, animation) {
|
|
12
|
+
const spine = findSpineChild(view);
|
|
13
|
+
const track = spine?.state.tracks[0];
|
|
14
|
+
const duration = skeletonData.findAnimation(animation)?.duration;
|
|
15
|
+
if (track === null || track === undefined || duration === undefined || duration <= 0)
|
|
16
|
+
return undefined;
|
|
17
|
+
const fps = skeletonData.fps && skeletonData.fps > 0 ? skeletonData.fps : 60;
|
|
18
|
+
const total = Math.max(1, Math.round(duration * fps));
|
|
19
|
+
const time = track.loop ? track.trackTime % duration : Math.min(track.trackTime, duration);
|
|
20
|
+
return { current: Math.min(total, Math.floor(time * fps) + 1), total };
|
|
21
|
+
}
|
|
22
|
+
/** Seeks an editor Spine node to a 1-based animation frame without changing its serialized animation settings. */
|
|
23
|
+
export function setSpineViewFrame(view, frame, skeletonData, animation) {
|
|
24
|
+
const spine = findSpineChild(view);
|
|
25
|
+
const track = spine?.state.tracks[0];
|
|
26
|
+
const duration = skeletonData.findAnimation(animation)?.duration;
|
|
27
|
+
if (track === null || track === undefined || duration === undefined || duration <= 0)
|
|
28
|
+
return;
|
|
29
|
+
const fps = skeletonData.fps && skeletonData.fps > 0 ? skeletonData.fps : 60;
|
|
30
|
+
const total = Math.max(1, Math.round(duration * fps));
|
|
31
|
+
track.trackTime = Math.min(total, Math.max(1, Math.round(frame)) - 1) / fps;
|
|
32
|
+
spine?.update(0);
|
|
33
|
+
}
|
|
34
|
+
/** Forces an editor-only button state; the node's serialized `enabled` and states stay untouched. */
|
|
35
|
+
export function setButtonViewState(view, state) {
|
|
36
|
+
if (view instanceof ButtonNodeView)
|
|
37
|
+
view.setState(state);
|
|
38
|
+
}
|
|
39
|
+
/** Applies an editor-only slider preview value without touching the document. */
|
|
40
|
+
export function setSliderViewValue(view, value) {
|
|
41
|
+
if (view instanceof SliderNodeView)
|
|
42
|
+
view.value = value;
|
|
43
|
+
}
|
|
44
|
+
/** Applies an editor-only progress preview without touching the document. */
|
|
45
|
+
export function setProgressBarViewProgress(view, progress) {
|
|
46
|
+
if (view instanceof ProgressBarNodeView)
|
|
47
|
+
view.progress = progress;
|
|
48
|
+
}
|
|
49
|
+
/** Enables or pauses editor-only automatic playback without affecting serialized node data. */
|
|
50
|
+
export function setSpineViewAutoplay(view, autoplay) {
|
|
51
|
+
const spine = findSpineChild(view);
|
|
52
|
+
if (spine !== undefined)
|
|
53
|
+
spine.autoUpdate = autoplay;
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=controls.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"controls.js","sourceRoot":"","sources":["../src/controls.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type ProjectDocument } from "@pixi-ui-editor/schema";
|
|
2
|
+
export declare class ProjectDocumentJsonParseError extends Error {
|
|
3
|
+
readonly code = "INVALID_JSON";
|
|
4
|
+
constructor(message: string, options?: ErrorOptions);
|
|
5
|
+
}
|
|
6
|
+
export declare function loadProjectDocument(input: unknown): ProjectDocument;
|
|
7
|
+
export declare function parseProjectDocumentJson(json: string): ProjectDocument;
|
|
8
|
+
//# sourceMappingURL=document.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"document.d.ts","sourceRoot":"","sources":["../src/document.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0B,KAAK,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAEtF,qBAAa,6BAA8B,SAAQ,KAAK;IACtD,QAAQ,CAAC,IAAI,kBAAkB;gBAEnB,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY;CAIpD;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,eAAe,CAEnE;AAED,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,CAOtE"}
|
package/dist/document.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { migrateProjectDocument } from "@pixi-ui-editor/schema";
|
|
2
|
+
export class ProjectDocumentJsonParseError extends Error {
|
|
3
|
+
code = "INVALID_JSON";
|
|
4
|
+
constructor(message, options) {
|
|
5
|
+
super(message, options);
|
|
6
|
+
this.name = "ProjectDocumentJsonParseError";
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
export function loadProjectDocument(input) {
|
|
10
|
+
return migrateProjectDocument(input);
|
|
11
|
+
}
|
|
12
|
+
export function parseProjectDocumentJson(json) {
|
|
13
|
+
try {
|
|
14
|
+
return loadProjectDocument(JSON.parse(json));
|
|
15
|
+
}
|
|
16
|
+
catch (error) {
|
|
17
|
+
if (error instanceof SyntaxError)
|
|
18
|
+
throw new ProjectDocumentJsonParseError("Unable to parse ProjectDocument JSON.", { cause: error });
|
|
19
|
+
throw error;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=document.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"document.js","sourceRoot":"","sources":["../src/document.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAwB,MAAM,wBAAwB,CAAC;AAEtF,MAAM,OAAO,6BAA8B,SAAQ,KAAK;IAC7C,IAAI,GAAG,cAAc,CAAC;IAE/B,YAAY,OAAe,EAAE,OAAsB;QACjD,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxB,IAAI,CAAC,IAAI,GAAG,+BAA+B,CAAC;IAC9C,CAAC;CACF;AAED,MAAM,UAAU,mBAAmB,CAAC,KAAc;IAChD,OAAO,sBAAsB,CAAC,KAAK,CAAC,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,IAAY;IACnD,IAAI,CAAC;QACH,OAAO,mBAAmB,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;IAC/C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,WAAW;YAAE,MAAM,IAAI,6BAA6B,CAAC,uCAAuC,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;QACrI,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC"}
|