As far as I can see, that seems to me a compressed/encrypted/encoded version of the actual skeleton file. I don't know the reason about that, but I assume the website owner does not want those assets to be used outside their website.
Web Preview
is there a way to decrypt it?
You should try to reach gimkit owner
after I do that, I still need to set the animation loops
Unfortunately I didn't really understand the documentation, can you explain how to set an animation to loop for 2 seconds, start another for 2 seconds, then run one once and restart?
i found some stuff that might help with decoding, before I message the creator of Gimkit, any of these look like they could process the code decoding a certain way?
https://www.gimkit.com/index.f94d18b6.js
https://www.gimkit.com/App.bd3a6d62.js
https://www.gimkit.com/App.3d7597ef.js
https://www.gimkit.com/App.5c2d4074.js
Davide
also, rq before I message the owner of Gimkit I need to make sure it is something he would have actually had control over. He has been using spine through Https://www.Phaser.io, do you know if they format Spine differently?
Unfortunately, I didn't really understand the documentation. Can you explain how to set an animation to loop for 2 seconds, start another for 2 seconds, then run one once and restart?
Carefully read the Advanced Playback section. In the success
callback, you should call setAnimation
and addAnimation
, using the appropriate delay
parameter based on the mix duration you set.
I found some resources that might help with decoding. Before I contact the creator of Gimkit, do any of these seem relevant for processing code in a specific way?
https://www.gimkit.com/index.f94d18b6.js
https://www.gimkit.com/App.bd3a6d62.js
https://www.gimkit.com/App.3d7597ef.js
https://www.gimkit.com/App.5c2d4074.js
Sorry, but I won’t analyze that code for you.
Also, before I message the owner of Gimkit, I need to confirm whether it's something he would actually have control over. He has been using Spine through Phaser. Do you know if Phaser formats Spine differently?
All the Spine Phaser runtimes I’m aware of, including our spine-phaser
, use assets directly exported from the Spine Editor.
Davide I'm not great at coding, could you provide an example that uses multiple animations and the delay? I'm trying to plug stuff in, but it's not working right.
LeinadNoscaj We can help you identify why your code isn't working as you're intending. Could you provide us with an example of what you've tried so far?
- Изменено
Luke
stuff like
success: function (player) {
player.setAnimation("run", true);
delay: 5
player.addanimation("walk",true)
},
error: function (player, reason) {
alert(reason);
}
- Изменено
LeinadNoscaj In your call to setAnimation()
, you didn't provide it with a track index that you want the animation to play on. You can call setAnimation()
properly by writing code like player.setAnimation(0, "run", false);
.
It looks like you're missing parameters in your call to addAnimation()
. Here's the addAnimation function from AnimationState.ts:
EsotericSoftware/spine-runtimesblob/4.2/spine-ts/spine-core/src/AnimationState.ts#L563
The delay number is a parameter you pass to the function, like so: player.addAnimation(0, "walk", false, 5);
.
I would encourage you to check out the spine-ts runtime from our Github page and read through the examples.
Luke
how do I use the addAnimation function?
Do I have to paste the file into my HTML doc?
We are happy to help you as much as we can, but you'll need to learn coding, read our documentation, and go through the example projects. Your problem appears to be that you are jumping ahead without enough understanding. We cannot help you learn everything from scratch. Start over with the simplest possible setup (probably one of our examples), get that to work, understand it, and then make it more complex from there. Don't skip any steps.
Have you tried using AI? ChatGPT or DeepSeek can be a great resource. You can ask it Spine questions and usually it gives great answers.
Nate I've been trying with Google gemini
Unfortunately its been writing stuff even less correct then me
Aye, Gemini is not very good. I prefer ChatGPT. If you don't want to pay the $20/month, DeepSeek can be just as good. You might also try Claude.
Nate is Microsoft copilot any good?
I don't use it, but probably. Under the covers it is ChatGPT.
hey I know its been a while but I finally found out how the JSON was encoded
it was done using compress-json (beenotung/compress-json)
is there a way to plug the compress reverser into the spine runtime?
You would decompress it with that, giving you regular JSON, which you'd give to Spine as normal.
after a bunch of circulatory discussions with AI, I finally came up with the start of a solution
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Gimkit Spine Player (CodePen)</title>
<style>
body { margin: 0; }
#spine-player-container { width: 600px; height: 400px; border: 1px solid #ccc; }
</style>
<link href="https://unpkg.com/@esotericsoftware/spine-player@4.1/dist/spine-player.css" rel="stylesheet">
</head>
<body>
<div>
<label for="filenameInput">Enter Filename:</label>
<input type="text" id="filenameInput" value="snowman">
<button id="loadButton">Load Animation</button>
</div>
<div id="spine-player-container"></div>
<script src="https://unpkg.com/@esotericsoftware/spine-player@4.1/dist/iife/spine-player.js"></script>
<script src="https://cdn.jsdelivr.net/npm/compress-json@3/bundle.min.js"></script>
<script>
document.addEventListener('DOMContentLoaded', () => {
const filenameInput = document.getElementById('filenameInput');
const loadButton = document.getElementById('loadButton');
const GIMKIT_ASSET_BASE_URL = 'https://www.gimkit.com/assets/map/characters/spine/';
const CORS_PROXY_URL = 'https://api.allorigins.win/raw?url=';
loadButton.addEventListener('click', () => {
const filename = filenameInput.value.trim();
if (filename) {
encodeAssets(filename);
} else {
console.warn("Please enter a filename.");
}
});
async function encodeAssets(filename) {
const jsonUrl = GIMKIT_ASSET_BASE_URL + filename + '.json';
const proxiedJsonUrl = CORS_PROXY_URL + encodeURIComponent(jsonUrl);
const atlasUrl = GIMKIT_ASSET_BASE_URL + filename + '.atlas';
const proxiedAtlasUrl = CORS_PROXY_URL + encodeURIComponent(atlasUrl);
const pngUrl = GIMKIT_ASSET_BASE_URL + filename + '.png';
const proxiedPngUrl = CORS_PROXY_URL + encodeURIComponent(pngUrl);
try {
// Fetch and Base64 encode JSON
const jsonResponse = await fetch(proxiedJsonUrl);
if (!jsonResponse.ok) throw new Error(`Failed to fetch JSON: ${jsonResponse.status}`);
const compressedData = await jsonResponse.json();
const spineJsonData = compressJSON.decompress(compressedData);
const jsonString = JSON.stringify(spineJsonData);
const base64Json = btoa(jsonString);
console.log("Base64 JSON:", base64Json);
// Fetch and Base64 encode Atlas
const atlasResponse = await fetch(proxiedAtlasUrl);
if (!atlasResponse.ok) throw new Error(`Failed to fetch atlas: ${atlasResponse.status}`);
const atlasText = await atlasResponse.text();
const base64Atlas = btoa(atlasText);
console.log("Base64 Atlas:", base64Atlas);
// Fetch and Base64 encode PNG
const pngResponse = await fetch(proxiedPngUrl);
if (!pngResponse.ok) console.warn(`Failed to fetch PNG: ${pngResponse.status}`);
const pngBlob = await pngResponse.blob();
const reader = new FileReader();
const pngBase64 = await new Promise((resolve, reject) => {
reader.onloadend = () => {
const base64String = reader.result.split(',')[1]; // Extract the Base64 part
resolve(base64String);
};
reader.onerror = reject;
reader.readAsDataURL(pngBlob);
});
console.log("Base64 PNG:", pngBase64);
} catch (error) {
console.error("Error encoding assets:", error);
}
}
// Encode default on start
encodeAssets(filenameInput.value.trim());
});
</script>
</body>
</html>
I'm getting the JSON file decompressed, then base64 encoded. I can't for the life of me figure out how that works tho