[canvaskit] More examples.

This commit is contained in:
Mario Zechner 2024-07-08 16:35:42 +02:00
parent 67a0f4f37b
commit 32f43fbf5d
9 changed files with 520 additions and 3 deletions

View File

@ -226,3 +226,7 @@ ol {
.p-4 {
padding: 1em;
}
.mb-4 {
margin-bottom: 1em;
}

View File

@ -23,6 +23,8 @@
<li>CanvasKit</li>
<ul>
<li><a href="/spine-canvaskit/example">Example</a></li>
<li><a href="/spine-canvaskit/example/animation-state-events.html">Animation State Events</a></li>
<li><a href="/spine-canvaskit/example/mix-and-match.html">Skins Mix &amp; Match</a></li>
</ul>
<li>Pixi</li>
<ul>

View File

@ -0,0 +1,73 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="../../index.css">
<script src="https://unpkg.com/canvaskit-wasm@latest/bin/canvaskit.js"></script>
<script src="../dist/iife/spine-canvaskit.js"></script>
<style>
* {
margin: 0;
padding: 0;
}
</style>
</head>
<body class="p-4 flex flex-col items-center">
<h1>Animation State Events</h1>
<p class="mb-4">Open the console in the developer tools to view events logs.</p>
<canvas id=foo width=600 height=400 style="margin: 0 auto;"></canvas>
</body>
<script type="module">
async function readFile(path) {
const response = await fetch(path);
if (!response.ok) throw new Error("Could not load file " + path);
return await response.arrayBuffer();
}
const ck = await CanvasKitInit();
const surface = ck.MakeCanvasSurface('foo');
const atlas = await spine.loadTextureAtlas(ck, "assets/spineboy.atlas", readFile);
const skeletonData = await spine.loadSkeletonData("assets/spineboy-pro.skel", atlas, readFile);
const drawable = new spine.SkeletonDrawable(skeletonData);
drawable.skeleton.scaleX = drawable.skeleton.scaleY = 0.4;
drawable.skeleton.x = 300;
drawable.skeleton.y = 380;
// Set the default mix to 0.2 seconds, queue animations, and set listeners
const animationState = drawable.animationState;
animationState.data.defaultMix = 0.2;
animationState.setAnimation(0, "walk", true).listener = {
start: (entry) => console.log("Walk animation started"),
end: (entry) => console.log("Walk animation ended"),
};
animationState.addAnimation(0, "jump", false, 2);
animationState.addAnimation(0, "run", true, 0).listener = {
event: (entry, event) => console.log(`Custom event "${event.data.name}"`)
};
animationState.addListener({
completed: (entry) => console.log(`Animation ${entry.animation.name} completed`)
});
const renderer = new spine.SkeletonRenderer(ck);
let lastTime = performance.now();
function drawFrame(canvas) {
canvas.clear(ck.Color(52, 52, 54, 1));
const now = performance.now();
const deltaTime = (now - lastTime) / 1000;
lastTime = now;
drawable.update(deltaTime);
renderer.render(canvas, drawable);
surface.requestAnimationFrame(drawFrame);
}
surface.requestAnimationFrame(drawFrame);
</script>
</html>

View File

@ -0,0 +1,358 @@
mix-and-match.png
size: 1024, 512
filter: Linear, Linear
scale: 0.5
base-head
bounds: 118, 70, 95, 73
boy/arm-front
bounds: 831, 311, 36, 115
rotate: 90
boy/backpack
bounds: 249, 357, 119, 153
boy/backpack-pocket
bounds: 628, 193, 34, 62
rotate: 90
boy/backpack-strap-front
bounds: 330, 263, 38, 88
rotate: 90
boy/backpack-up
bounds: 482, 171, 21, 70
boy/body
bounds: 845, 413, 97, 132
rotate: 90
boy/boot-ribbon-front
bounds: 234, 304, 9, 11
boy/collar
bounds: 471, 243, 73, 29
rotate: 90
boy/ear
bounds: 991, 352, 19, 23
rotate: 90
boy/eye-back-low-eyelid
bounds: 66, 72, 17, 6
boy/eye-back-pupil
bounds: 694, 279, 8, 9
rotate: 90
boy/eye-back-up-eyelid
bounds: 460, 101, 23, 5
rotate: 90
boy/eye-back-up-eyelid-back
bounds: 979, 414, 19, 10
rotate: 90
boy/eye-front-low-eyelid
bounds: 1015, 203, 22, 7
rotate: 90
boy/eye-front-pupil
bounds: 309, 50, 9, 9
boy/eye-front-up-eyelid
bounds: 991, 373, 31, 6
boy/eye-front-up-eyelid-back
bounds: 107, 76, 26, 9
rotate: 90
boy/eye-iris-back
bounds: 810, 260, 17, 17
boy/eye-iris-front
bounds: 902, 230, 18, 18
boy/eye-white-back
bounds: 599, 179, 20, 12
boy/eye-white-front
bounds: 544, 183, 27, 13
boy/eyebrow-back
bounds: 1002, 225, 20, 11
rotate: 90
boy/eyebrow-front
bounds: 975, 234, 25, 11
boy/hair-back
bounds: 629, 289, 122, 81
rotate: 90
boy/hair-bangs
bounds: 505, 180, 70, 37
rotate: 90
boy/hair-side
bounds: 979, 435, 25, 43
rotate: 90
boy/hand-backfingers
bounds: 858, 183, 19, 21
boy/hand-front-fingers
bounds: 879, 183, 19, 21
boy/hat
bounds: 218, 121, 93, 56
boy/leg-front
bounds: 85, 104, 31, 158
boy/mouth-close
bounds: 467, 100, 21, 5
girl-blue-cape/mouth-close
bounds: 467, 100, 21, 5
girl-spring-dress/mouth-close
bounds: 467, 100, 21, 5
girl/mouth-close
bounds: 467, 100, 21, 5
boy/mouth-smile
bounds: 1015, 258, 29, 7
rotate: 90
boy/nose
bounds: 323, 79, 17, 10
boy/pompom
bounds: 979, 462, 48, 43
rotate: 90
boy/zip
bounds: 922, 231, 14, 23
rotate: 90
girl-blue-cape/back-eyebrow
bounds: 527, 106, 18, 12
rotate: 90
girl-blue-cape/body-dress
bounds: 2, 264, 109, 246
girl-blue-cape/body-ribbon
bounds: 576, 193, 50, 38
girl-blue-cape/cape-back
bounds: 113, 317, 134, 193
girl-blue-cape/cape-back-up
bounds: 504, 305, 123, 106
girl-blue-cape/cape-ribbon
bounds: 396, 118, 50, 18
rotate: 90
girl-blue-cape/cape-shoulder-back
bounds: 420, 243, 49, 59
girl-blue-cape/cape-shoulder-front
bounds: 2, 2, 62, 76
girl-blue-cape/cape-up-front
bounds: 118, 145, 98, 117
girl-blue-cape/ear
bounds: 837, 181, 19, 23
girl-spring-dress/ear
bounds: 837, 181, 19, 23
girl/ear
bounds: 837, 181, 19, 23
girl-blue-cape/eye-back-low-eyelid
bounds: 810, 252, 17, 6
girl-spring-dress/eye-back-low-eyelid
bounds: 810, 252, 17, 6
girl/eye-back-low-eyelid
bounds: 810, 252, 17, 6
girl-blue-cape/eye-back-pupil
bounds: 309, 40, 8, 9
rotate: 90
girl-spring-dress/eye-back-pupil
bounds: 309, 40, 8, 9
rotate: 90
girl/eye-back-pupil
bounds: 309, 40, 8, 9
rotate: 90
girl-blue-cape/eye-back-up-eyelid
bounds: 573, 179, 24, 12
girl-spring-dress/eye-back-up-eyelid
bounds: 573, 179, 24, 12
girl/eye-back-up-eyelid
bounds: 573, 179, 24, 12
girl-blue-cape/eye-back-up-eyelid-back
bounds: 380, 105, 17, 11
rotate: 90
girl-spring-dress/eye-back-up-eyelid-back
bounds: 380, 105, 17, 11
rotate: 90
girl/eye-back-up-eyelid-back
bounds: 380, 105, 17, 11
rotate: 90
girl-blue-cape/eye-front-low-eyelid
bounds: 1016, 353, 18, 6
rotate: 90
girl-spring-dress/eye-front-low-eyelid
bounds: 1016, 353, 18, 6
rotate: 90
girl/eye-front-low-eyelid
bounds: 1016, 353, 18, 6
rotate: 90
girl-blue-cape/eye-front-pupil
bounds: 363, 94, 9, 9
girl-spring-dress/eye-front-pupil
bounds: 363, 94, 9, 9
girl/eye-front-pupil
bounds: 363, 94, 9, 9
girl-blue-cape/eye-front-up-eyelid
bounds: 679, 413, 30, 14
rotate: 90
girl-spring-dress/eye-front-up-eyelid
bounds: 679, 413, 30, 14
rotate: 90
girl/eye-front-up-eyelid
bounds: 679, 413, 30, 14
rotate: 90
girl-blue-cape/eye-front-up-eyelid-back
bounds: 947, 234, 26, 11
girl-spring-dress/eye-front-up-eyelid-back
bounds: 947, 234, 26, 11
girl/eye-front-up-eyelid-back
bounds: 947, 234, 26, 11
girl-blue-cape/eye-iris-back
bounds: 323, 105, 17, 17
girl-blue-cape/eye-iris-front
bounds: 467, 107, 18, 18
girl-blue-cape/eye-white-back
bounds: 621, 175, 20, 16
girl-spring-dress/eye-white-back
bounds: 621, 175, 20, 16
girl-blue-cape/eye-white-front
bounds: 643, 175, 20, 16
girl-spring-dress/eye-white-front
bounds: 643, 175, 20, 16
girl/eye-white-front
bounds: 643, 175, 20, 16
girl-blue-cape/front-eyebrow
bounds: 309, 101, 18, 12
rotate: 90
girl-blue-cape/hair-back
bounds: 712, 317, 117, 98
girl-blue-cape/hair-bangs
bounds: 313, 170, 91, 40
rotate: 90
girl-blue-cape/hair-head-side-back
bounds: 544, 198, 30, 52
girl-blue-cape/hair-head-side-front
bounds: 466, 127, 41, 42
girl-blue-cape/hair-side
bounds: 175, 2, 36, 71
rotate: 90
girl-blue-cape/hand-front-fingers
bounds: 902, 207, 19, 21
girl-spring-dress/hand-front-fingers
bounds: 902, 207, 19, 21
girl-blue-cape/leg-front
bounds: 519, 413, 30, 158
rotate: 90
girl-blue-cape/mouth-smile
bounds: 1015, 227, 29, 7
rotate: 90
girl-spring-dress/mouth-smile
bounds: 1015, 227, 29, 7
rotate: 90
girl/mouth-smile
bounds: 1015, 227, 29, 7
rotate: 90
girl-blue-cape/nose
bounds: 342, 82, 11, 7
girl-spring-dress/nose
bounds: 342, 82, 11, 7
girl/nose
bounds: 342, 82, 11, 7
girl-blue-cape/sleeve-back
bounds: 416, 95, 42, 29
girl-blue-cape/sleeve-front
bounds: 249, 303, 52, 119
rotate: 90
girl-spring-dress/arm-front
bounds: 829, 292, 17, 111
rotate: 90
girl-spring-dress/back-eyebrow
bounds: 309, 81, 18, 12
rotate: 90
girl-spring-dress/body-up
bounds: 66, 2, 64, 66
girl-spring-dress/cloak-down
bounds: 758, 227, 50, 50
girl-spring-dress/cloak-up
bounds: 628, 229, 64, 58
girl-spring-dress/eye-iris-back
bounds: 342, 105, 17, 17
girl-spring-dress/eye-iris-front
bounds: 487, 107, 18, 18
girl-spring-dress/front-eyebrow
bounds: 323, 91, 18, 12
girl-spring-dress/hair-back
bounds: 370, 417, 147, 93
girl-spring-dress/hair-bangs
bounds: 829, 250, 91, 40
girl-spring-dress/hair-head-side-back
bounds: 509, 126, 30, 52
girl-spring-dress/hair-head-side-front
bounds: 816, 206, 41, 42
girl-spring-dress/hair-side
bounds: 248, 2, 36, 71
rotate: 90
girl-spring-dress/leg-front
bounds: 831, 381, 30, 158
rotate: 90
girl-spring-dress/neck
bounds: 85, 70, 20, 32
girl-spring-dress/shoulder-ribbon
bounds: 175, 44, 36, 24
girl-spring-dress/skirt
bounds: 2, 80, 182, 81
rotate: 90
girl-spring-dress/underskirt
bounds: 519, 445, 175, 65
girl/arm-front
bounds: 712, 279, 36, 115
rotate: 90
girl/back-eyebrow
bounds: 309, 61, 18, 12
rotate: 90
girl/bag-base
bounds: 694, 219, 62, 58
girl/bag-strap-front
bounds: 370, 304, 12, 96
rotate: 90
girl/bag-top
bounds: 765, 175, 49, 50
girl/body
bounds: 370, 318, 97, 132
rotate: 90
girl/boot-ribbon-front
bounds: 323, 64, 13, 13
girl/eye-iris-back
bounds: 361, 105, 17, 17
girl/eye-iris-front
bounds: 507, 106, 18, 18
girl/eye-white-back
bounds: 665, 175, 20, 16
girl/front-eyebrow
bounds: 343, 91, 18, 12
girl/hair-back
bounds: 696, 417, 147, 93
girl/hair-bangs
bounds: 922, 247, 91, 40
girl/hair-flap-down-front
bounds: 415, 171, 70, 65
rotate: 90
girl/hair-head-side-back
bounds: 991, 381, 30, 52
girl/hair-head-side-front
bounds: 859, 206, 41, 42
girl/hair-patch
bounds: 132, 2, 66, 41
rotate: 90
girl/hair-side
bounds: 692, 181, 36, 71
rotate: 90
girl/hair-strand-back-1
bounds: 948, 289, 58, 74
rotate: 90
girl/hair-strand-back-2
bounds: 355, 170, 91, 58
rotate: 90
girl/hair-strand-back-3
bounds: 215, 40, 92, 79
girl/hair-strand-front-1
bounds: 234, 263, 38, 94
rotate: 90
girl/hair-strand-front-2
bounds: 576, 233, 70, 50
rotate: 90
girl/hair-strand-front-3
bounds: 313, 124, 44, 81
rotate: 90
girl/hand-front-fingers
bounds: 923, 208, 19, 21
girl/hat
bounds: 218, 179, 93, 82
girl/leg-front
bounds: 831, 349, 30, 158
rotate: 90
girl/pompom
bounds: 416, 126, 48, 43
girl/scarf
bounds: 113, 264, 119, 51
girl/scarf-back
bounds: 502, 252, 72, 51
girl/zip
bounds: 816, 179, 19, 25

Binary file not shown.

After

Width:  |  Height:  |  Size: 341 KiB

View File

@ -1,7 +1,7 @@
import * as fs from "fs"
import { fileURLToPath } from 'url';
import path from 'path';
import CanvasKitInit from "canvaskit-wasm/bin/canvaskit.js";
import CanvasKitInit from "canvaskit-wasm";
import UPNG from "@pdf-lib/upng"
import {loadTextureAtlas, SkeletonRenderer, Skeleton, SkeletonBinary, AnimationState, AnimationStateData, AtlasAttachmentLoader, Physics, loadSkeletonData, SkeletonDrawable} from "../dist/index.js"
@ -17,7 +17,6 @@ async function main() {
const ck = await CanvasKitInit();
const surface = ck.MakeSurface(600, 400);
if (!surface) throw new Error();
const canvas = surface.getCanvas();
// Load atlas
const atlas = await loadTextureAtlas(ck, __dirname + "/assets/spineboy.atlas", async (path) => fs.readFileSync(path));
@ -47,6 +46,9 @@ async function main() {
const imageInfo = { width: 600, height: 400, colorType: ck.ColorType.RGBA_8888, alphaType: ck.AlphaType.Unpremul, colorSpace: ck.ColorSpace.SRGB };
const pixelArray = ck.Malloc(Uint8Array, imageInfo.width * imageInfo.height * 4);
for (let time = 0; time <= animationDuration; time += deltaTime) {
// Get the canvas object to render to the surface to
const canvas = surface.getCanvas();
// Clear the canvas
canvas.clear(ck.WHITE);

View File

@ -0,0 +1,78 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="../../index.css">
<script src="https://unpkg.com/canvaskit-wasm@latest/bin/canvaskit.js"></script>
<script src="../dist/iife/spine-canvaskit.js"></script>
<style>
* {
margin: 0;
padding: 0;
}
</style>
</head>
<body class="p-4 flex flex-col items-center">
<h1>Skins Mix &amp; Match Example</h1>
<canvas id=foo width=600 height=400 style="margin: 0 auto;"></canvas>
</body>
<script type="module">
async function readFile(path) {
const response = await fetch(path);
if (!response.ok) throw new Error("Could not load file " + path);
return await response.arrayBuffer();
}
const ck = await CanvasKitInit();
const surface = ck.MakeCanvasSurface('foo');
const atlas = await spine.loadTextureAtlas(ck, "assets/mix-and-match.atlas", readFile);
const skeletonData = await spine.loadSkeletonData("assets/mix-and-match-pro.skel", atlas, readFile);
const drawable = new spine.SkeletonDrawable(skeletonData);
drawable.skeleton.scaleX = drawable.skeleton.scaleY = 0.4;
drawable.skeleton.x = 300;
drawable.skeleton.y = 380;
drawable.animationState.setAnimation(0, "dance", true);
// Create a custom, empty skin
const skin = new spine.Skin("custom");
// Add other skins to the custom skin
skin.addSkin(skeletonData.findSkin("skin-base"));
skin.addSkin(skeletonData.findSkin("nose/short"));
skin.addSkin(skeletonData.findSkin("eyelids/girly"));
skin.addSkin(skeletonData.findSkin("eyes/violet"));
skin.addSkin(skeletonData.findSkin("hair/brown"));
skin.addSkin(skeletonData.findSkin("clothes/hoodie-orange"));
skin.addSkin(skeletonData.findSkin("legs/pants-jeans"));
skin.addSkin(skeletonData.findSkin("accessories/bag"));
skin.addSkin(skeletonData.findSkin("accessories/hat-red-yellow"));
// Set the skin and the skeleton to the setup pose
drawable.skeleton.setSkin(skin);
drawable.skeleton.setToSetupPose();
const renderer = new spine.SkeletonRenderer(ck);
let lastTime = performance.now();
function drawFrame(canvas) {
canvas.clear(ck.Color(52, 52, 54, 1));
const now = performance.now();
const deltaTime = (now - lastTime) / 1000;
lastTime = now;
drawable.update(deltaTime);
renderer.render(canvas, drawable);
surface.requestAnimationFrame(drawFrame);
}
surface.requestAnimationFrame(drawFrame);
</script>
</html>

View File

@ -51,7 +51,7 @@ class CanvasKitTexture extends Texture {
this._image = null;
}
static async fromFile(ck: CanvasKit, path: string, readFile: (path: string) => Promise<Buffer>): Promise<CanvasKitTexture> {
static async fromFile(ck: CanvasKit, path: string, readFile: (path: string) => Promise<any>): Promise<CanvasKitTexture> {
const imgData = await readFile(path);
if (!imgData) throw new Error(`Could not load image ${path}`);
const image = ck.MakeImageFromEncoded(imgData);