Added clip.

This commit is contained in:
Davide Tantillo 2024-08-30 18:26:01 +02:00
parent 034c6266e8
commit 847c152f2a
19 changed files with 10996 additions and 295 deletions

View File

@ -0,0 +1,435 @@
chibi-stickers-pma.png
size: 512, 128
filter: Linear, Linear
pma: true
scale: 0.5
common/angry-mark
bounds: 278, 85, 42, 41
common/big-purple-fear
bounds: 2, 54, 134, 72
common/big-tear
bounds: 138, 93, 33, 82
rotate: 90
common/eye-3
bounds: 226, 25, 15, 26
common/eye-closed-happy
bounds: 267, 7, 25, 9
rotate: 90
common/eye-dafault
bounds: 203, 20, 22, 21
rotate: 90
common/eye-equal
bounds: 308, 43, 25, 15
common/eye-fire
bounds: 278, 57, 26, 28
rotate: 90
common/eye-half-open
bounds: 138, 2, 26, 16
common/eye-heart
bounds: 308, 60, 26, 23
common/eye-reverse-v
bounds: 166, 2, 26, 16
common/eye-sideway-v
bounds: 336, 60, 21, 23
common/eye-slant-close
bounds: 194, 2, 23, 16
common/eye-small-dot
bounds: 119, 2, 15, 15
common/eye-sparkle
bounds: 372, 97, 30, 29
common/eye-star
bounds: 404, 99, 29, 27
common/eye-twirl
bounds: 226, 2, 21, 23
rotate: 90
common/eye-u
bounds: 2, 2, 24, 17
common/eye-x
bounds: 176, 20, 25, 22
common/lamp
bounds: 138, 44, 47, 65
rotate: 90
common/mouth-3
bounds: 89, 2, 15, 28
rotate: 90
common/mouth-bracket
bounds: 322, 85, 34, 11
common/mouth-doubt
bounds: 243, 34, 26, 15
common/mouth-fangs
bounds: 205, 52, 39, 14
rotate: 90
common/mouth-line
bounds: 435, 96, 36, 7
common/mouth-neutral
bounds: 245, 51, 27, 12
common/mouth-o-tall
bounds: 221, 53, 22, 33
common/mouth-open-smile
bounds: 138, 20, 36, 22
common/mouth-rectangle
bounds: 435, 105, 35, 21
common/mouth-reverse-v
bounds: 473, 95, 27, 10
common/mouth-s
bounds: 28, 8, 41, 11
common/mouth-smile-little
bounds: 117, 19, 33, 19
rotate: 90
common/mouth-toungue-sticking-out
bounds: 245, 65, 31, 21
common/mouth-u
bounds: 472, 107, 36, 19
common/mouth-v
bounds: 251, 5, 27, 14
rotate: 90
common/mouth-x
bounds: 335, 38, 21, 20
common/purple-fear-lines
bounds: 322, 98, 48, 28
common/shadow
bounds: 2, 21, 113, 31
common/small-dash
bounds: 404, 88, 9, 20
rotate: 90
common/small-drop-line
bounds: 71, 2, 16, 17
common/small-purple-fear
bounds: 222, 88, 54, 38
common/tear
bounds: 274, 36, 20, 19
chibi-stickers-pma_2.png
size: 1024, 256
filter: Linear, Linear
pma: true
scale: 0.5
erikari/arm
bounds: 981, 164, 28, 90
erikari/arm-shoulder-decoration
bounds: 790, 149, 32, 43
erikari/back-hair
bounds: 258, 113, 158, 141
erikari/back-hair-long
bounds: 2, 34, 220, 254
rotate: 90
erikari/blush
bounds: 981, 133, 29, 18
rotate: 90
erikari/body
bounds: 584, 115, 70, 98
erikari/bracelet
bounds: 1011, 221, 33, 11
rotate: 90
erikari/collar
bounds: 390, 48, 61, 62
erikari/ear
bounds: 258, 2, 34, 42
erikari/eyebrow
bounds: 453, 98, 20, 12
erikari/hair-front
bounds: 258, 46, 130, 65
erikari/hair-side
bounds: 656, 149, 43, 132
rotate: 90
erikari/hat-border
bounds: 418, 215, 254, 39
erikari/hat-top
bounds: 674, 194, 160, 60
erikari/head-base
bounds: 836, 129, 143, 125
erikari/leg
bounds: 2, 4, 28, 101
rotate: 90
erikari/leg-decoration
bounds: 770, 134, 36, 13
erikari/skirt
bounds: 418, 112, 164, 101
erikari/strawberries-decoration
bounds: 656, 91, 112, 56
chibi-stickers-pma_3.png
size: 512, 256
filter: Linear, Linear
pma: true
scale: 0.5
harri/arm
bounds: 147, 21, 28, 90
rotate: 90
harri/back-hair
bounds: 2, 107, 158, 141
harri/back-hair-long
bounds: 147, 51, 40, 80
rotate: 90
harri/beard
bounds: 2, 2, 10, 11
harri/blush
bounds: 265, 103, 29, 18
harri/body
bounds: 307, 94, 70, 98
rotate: 90
harri/body-decoration
bounds: 407, 97, 70, 67
harri/ear
bounds: 229, 57, 34, 42
rotate: 90
harri/eyebrow
bounds: 494, 226, 22, 12
rotate: 90
harri/hair-front
bounds: 2, 15, 143, 90
harri/head-base
bounds: 162, 123, 143, 125
harri/leg
bounds: 162, 93, 28, 101
rotate: 90
harri/sword
bounds: 307, 166, 185, 82
chibi-stickers-pma_4.png
size: 1024, 256
filter: Linear, Linear
pma: true
scale: 0.5
luke/arm
bounds: 930, 224, 28, 90
rotate: 90
luke/arm-shoulder-decoration
bounds: 581, 112, 31, 27
rotate: 90
luke/back-hair
bounds: 173, 111, 158, 141
luke/blush
bounds: 151, 68, 29, 18
rotate: 90
luke/body
bounds: 700, 123, 70, 98
rotate: 90
luke/eyebrow
bounds: 2, 2, 27, 12
luke/face-cover
bounds: 2, 99, 169, 153
luke/glasses-shadow
bounds: 2, 16, 147, 81
luke/hair-decoration
bounds: 478, 145, 130, 107
luke/hair-front
bounds: 700, 195, 122, 57
luke/head-base
bounds: 333, 127, 143, 125
luke/leg
bounds: 478, 115, 28, 101
rotate: 90
luke/shield
bounds: 610, 148, 88, 104
luke/skirt
bounds: 930, 191, 81, 31
luke/sword
bounds: 824, 181, 104, 71
chibi-stickers-pma_5.png
size: 512, 256
filter: Linear, Linear
pma: true
scale: 0.5
mario/arm
bounds: 244, 2, 28, 90
mario/back-hair
bounds: 2, 101, 168, 148
mario/back-hair-long
bounds: 151, 6, 86, 91
rotate: 90
mario/beard
bounds: 2, 6, 147, 93
mario/blush
bounds: 492, 220, 29, 18
rotate: 90
mario/body
bounds: 317, 111, 70, 98
rotate: 90
mario/ear
bounds: 456, 207, 34, 42
mario/eyebrow
bounds: 417, 164, 32, 17
mario/hair-front
bounds: 317, 183, 137, 66
mario/head-base
bounds: 172, 124, 143, 125
mario/leg
bounds: 172, 94, 28, 101
rotate: 90
chibi-stickers-pma_6.png
size: 1024, 256
filter: Linear, Linear
pma: true
scale: 0.5
misaki/arm
bounds: 609, 95, 28, 90
misaki/back-hair
bounds: 194, 105, 158, 141
misaki/back-hair-long
bounds: 2, 51, 190, 195
misaki/belt
bounds: 741, 190, 76, 26
misaki/blush
bounds: 844, 228, 29, 18
misaki/body
bounds: 641, 176, 70, 98
rotate: 90
misaki/ear
bounds: 144, 7, 34, 42
misaki/eyebrow
bounds: 194, 54, 30, 12
misaki/glasses
bounds: 194, 68, 141, 35
misaki/glasses-side
bounds: 354, 111, 8, 23
rotate: 90
misaki/hair-front
bounds: 499, 187, 140, 59
misaki/hair-side
bounds: 2, 2, 47, 140
rotate: 90
misaki/head-base
bounds: 354, 121, 143, 125
misaki/leg
bounds: 741, 218, 28, 101
rotate: 90
misaki/skirt
bounds: 499, 95, 108, 90
chibi-stickers-pma_7.png
size: 512, 256
filter: Linear, Linear
pma: true
scale: 0.5
nate/arm
bounds: 151, 65, 28, 90
rotate: 90
nate/back-hair
bounds: 2, 109, 158, 141
nate/beard
bounds: 2, 39, 147, 68
nate/blush
bounds: 407, 165, 29, 18
nate/body
bounds: 307, 113, 70, 98
rotate: 90
nate/ear
bounds: 451, 208, 34, 42
nate/eyebrow
bounds: 265, 111, 27, 12
nate/glasses
bounds: 2, 2, 141, 35
nate/glasses-side
bounds: 151, 47, 8, 16
nate/hair-front
bounds: 307, 185, 142, 65
nate/head-base
bounds: 162, 125, 143, 125
nate/leg
bounds: 162, 95, 28, 101
rotate: 90
chibi-stickers-pma_8.png
size: 512, 256
filter: Linear, Linear
pma: true
scale: 0.5
sinisa/arm
bounds: 147, 52, 28, 90
rotate: 90
sinisa/back-hair
bounds: 2, 96, 158, 141
sinisa/beard
bounds: 307, 192, 139, 45
sinisa/blush
bounds: 147, 32, 29, 18
sinisa/body
bounds: 307, 120, 70, 98
rotate: 90
sinisa/body-decoration
bounds: 265, 83, 27, 27
sinisa/ear
bounds: 448, 195, 34, 42
sinisa/eyebrow
bounds: 407, 171, 38, 19
sinisa/hair-front
bounds: 2, 2, 143, 92
sinisa/head-base
bounds: 162, 112, 143, 125
sinisa/leg
bounds: 162, 82, 28, 101
rotate: 90
chibi-stickers-pma_9.png
size: 512, 256
filter: Linear, Linear
pma: true
scale: 0.5
soeren/arm
bounds: 254, 47, 28, 90
soeren/back-hair
bounds: 2, 111, 150, 141
soeren/beard
bounds: 2, 41, 145, 68
soeren/blush
bounds: 284, 119, 29, 18
soeren/body
bounds: 154, 67, 70, 98
rotate: 90
soeren/ear
bounds: 200, 23, 34, 42
soeren/eyebrow
bounds: 460, 137, 27, 12
soeren/glasses
bounds: 2, 2, 152, 37
soeren/glasses-side
bounds: 490, 245, 7, 20
rotate: 90
soeren/glove
bounds: 156, 12, 42, 53
soeren/hair-front
bounds: 154, 139, 159, 113
soeren/head-base
bounds: 315, 127, 143, 125
soeren/leg
bounds: 460, 151, 28, 101
chibi-stickers-pma_10.png
size: 512, 256
filter: Linear, Linear
pma: true
scale: 0.5
spineboy/arm
bounds: 407, 97, 28, 90
rotate: 90
spineboy/arm-decoration
bounds: 307, 127, 32, 29
spineboy/arm-shoulder-decoration
bounds: 451, 72, 23, 23
spineboy/back-hair
bounds: 2, 106, 158, 141
spineboy/blush
bounds: 2, 2, 29, 18
spineboy/body
bounds: 307, 55, 70, 98
rotate: 90
spineboy/ear
bounds: 407, 61, 34, 42
rotate: 90
spineboy/eyebrow
bounds: 143, 77, 27, 12
rotate: 90
spineboy/glasses
bounds: 162, 158, 179, 89
spineboy/glasses-shadow
bounds: 2, 22, 139, 82
spineboy/hair-front
bounds: 343, 127, 145, 120
spineboy/head-base
bounds: 162, 31, 143, 125
spineboy/leg
bounds: 307, 24, 29, 101
rotate: 90

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

View File

@ -0,0 +1,425 @@
chibi-stickers.png
size: 512, 128
filter: Linear, Linear
scale: 0.5
common/angry-mark
bounds: 278, 85, 42, 41
common/big-purple-fear
bounds: 2, 54, 134, 72
common/big-tear
bounds: 138, 93, 33, 82
rotate: 90
common/eye-3
bounds: 226, 25, 15, 26
common/eye-closed-happy
bounds: 267, 7, 25, 9
rotate: 90
common/eye-dafault
bounds: 203, 20, 22, 21
rotate: 90
common/eye-equal
bounds: 308, 43, 25, 15
common/eye-fire
bounds: 278, 57, 26, 28
rotate: 90
common/eye-half-open
bounds: 138, 2, 26, 16
common/eye-heart
bounds: 308, 60, 26, 23
common/eye-reverse-v
bounds: 166, 2, 26, 16
common/eye-sideway-v
bounds: 336, 60, 21, 23
common/eye-slant-close
bounds: 194, 2, 23, 16
common/eye-small-dot
bounds: 119, 2, 15, 15
common/eye-sparkle
bounds: 372, 97, 30, 29
common/eye-star
bounds: 404, 99, 29, 27
common/eye-twirl
bounds: 226, 2, 21, 23
rotate: 90
common/eye-u
bounds: 2, 2, 24, 17
common/eye-x
bounds: 176, 20, 25, 22
common/lamp
bounds: 138, 44, 47, 65
rotate: 90
common/mouth-3
bounds: 89, 2, 15, 28
rotate: 90
common/mouth-bracket
bounds: 322, 85, 34, 11
common/mouth-doubt
bounds: 243, 34, 26, 15
common/mouth-fangs
bounds: 205, 52, 39, 14
rotate: 90
common/mouth-line
bounds: 435, 96, 36, 7
common/mouth-neutral
bounds: 245, 51, 27, 12
common/mouth-o-tall
bounds: 221, 53, 22, 33
common/mouth-open-smile
bounds: 138, 20, 36, 22
common/mouth-rectangle
bounds: 435, 105, 35, 21
common/mouth-reverse-v
bounds: 473, 95, 27, 10
common/mouth-s
bounds: 28, 8, 41, 11
common/mouth-smile-little
bounds: 117, 19, 33, 19
rotate: 90
common/mouth-toungue-sticking-out
bounds: 245, 65, 31, 21
common/mouth-u
bounds: 472, 107, 36, 19
common/mouth-v
bounds: 251, 5, 27, 14
rotate: 90
common/mouth-x
bounds: 335, 38, 21, 20
common/purple-fear-lines
bounds: 322, 98, 48, 28
common/shadow
bounds: 2, 21, 113, 31
common/small-dash
bounds: 404, 88, 9, 20
rotate: 90
common/small-drop-line
bounds: 71, 2, 16, 17
common/small-purple-fear
bounds: 222, 88, 54, 38
common/tear
bounds: 274, 36, 20, 19
chibi-stickers_2.png
size: 1024, 256
filter: Linear, Linear
scale: 0.5
erikari/arm
bounds: 981, 164, 28, 90
erikari/arm-shoulder-decoration
bounds: 790, 149, 32, 43
erikari/back-hair
bounds: 258, 113, 158, 141
erikari/back-hair-long
bounds: 2, 34, 220, 254
rotate: 90
erikari/blush
bounds: 981, 133, 29, 18
rotate: 90
erikari/body
bounds: 584, 115, 70, 98
erikari/bracelet
bounds: 1011, 221, 33, 11
rotate: 90
erikari/collar
bounds: 390, 48, 61, 62
erikari/ear
bounds: 258, 2, 34, 42
erikari/eyebrow
bounds: 453, 98, 20, 12
erikari/hair-front
bounds: 258, 46, 130, 65
erikari/hair-side
bounds: 656, 149, 43, 132
rotate: 90
erikari/hat-border
bounds: 418, 215, 254, 39
erikari/hat-top
bounds: 674, 194, 160, 60
erikari/head-base
bounds: 836, 129, 143, 125
erikari/leg
bounds: 2, 4, 28, 101
rotate: 90
erikari/leg-decoration
bounds: 770, 134, 36, 13
erikari/skirt
bounds: 418, 112, 164, 101
erikari/strawberries-decoration
bounds: 656, 91, 112, 56
chibi-stickers_3.png
size: 512, 256
filter: Linear, Linear
scale: 0.5
harri/arm
bounds: 147, 21, 28, 90
rotate: 90
harri/back-hair
bounds: 2, 107, 158, 141
harri/back-hair-long
bounds: 147, 51, 40, 80
rotate: 90
harri/beard
bounds: 2, 2, 10, 11
harri/blush
bounds: 265, 103, 29, 18
harri/body
bounds: 307, 94, 70, 98
rotate: 90
harri/body-decoration
bounds: 407, 97, 70, 67
harri/ear
bounds: 229, 57, 34, 42
rotate: 90
harri/eyebrow
bounds: 494, 226, 22, 12
rotate: 90
harri/hair-front
bounds: 2, 15, 143, 90
harri/head-base
bounds: 162, 123, 143, 125
harri/leg
bounds: 162, 93, 28, 101
rotate: 90
harri/sword
bounds: 307, 166, 185, 82
chibi-stickers_4.png
size: 1024, 256
filter: Linear, Linear
scale: 0.5
luke/arm
bounds: 930, 224, 28, 90
rotate: 90
luke/arm-shoulder-decoration
bounds: 581, 112, 31, 27
rotate: 90
luke/back-hair
bounds: 173, 111, 158, 141
luke/blush
bounds: 151, 68, 29, 18
rotate: 90
luke/body
bounds: 700, 123, 70, 98
rotate: 90
luke/eyebrow
bounds: 2, 2, 27, 12
luke/face-cover
bounds: 2, 99, 169, 153
luke/glasses-shadow
bounds: 2, 16, 147, 81
luke/hair-decoration
bounds: 478, 145, 130, 107
luke/hair-front
bounds: 700, 195, 122, 57
luke/head-base
bounds: 333, 127, 143, 125
luke/leg
bounds: 478, 115, 28, 101
rotate: 90
luke/shield
bounds: 610, 148, 88, 104
luke/skirt
bounds: 930, 191, 81, 31
luke/sword
bounds: 824, 181, 104, 71
chibi-stickers_5.png
size: 512, 256
filter: Linear, Linear
scale: 0.5
mario/arm
bounds: 244, 2, 28, 90
mario/back-hair
bounds: 2, 101, 168, 148
mario/back-hair-long
bounds: 151, 6, 86, 91
rotate: 90
mario/beard
bounds: 2, 6, 147, 93
mario/blush
bounds: 492, 220, 29, 18
rotate: 90
mario/body
bounds: 317, 111, 70, 98
rotate: 90
mario/ear
bounds: 456, 207, 34, 42
mario/eyebrow
bounds: 417, 164, 32, 17
mario/hair-front
bounds: 317, 183, 137, 66
mario/head-base
bounds: 172, 124, 143, 125
mario/leg
bounds: 172, 94, 28, 101
rotate: 90
chibi-stickers_6.png
size: 1024, 256
filter: Linear, Linear
scale: 0.5
misaki/arm
bounds: 609, 95, 28, 90
misaki/back-hair
bounds: 194, 105, 158, 141
misaki/back-hair-long
bounds: 2, 51, 190, 195
misaki/belt
bounds: 741, 190, 76, 26
misaki/blush
bounds: 844, 228, 29, 18
misaki/body
bounds: 641, 176, 70, 98
rotate: 90
misaki/ear
bounds: 144, 7, 34, 42
misaki/eyebrow
bounds: 194, 54, 30, 12
misaki/glasses
bounds: 194, 68, 141, 35
misaki/glasses-side
bounds: 354, 111, 8, 23
rotate: 90
misaki/hair-front
bounds: 499, 187, 140, 59
misaki/hair-side
bounds: 2, 2, 47, 140
rotate: 90
misaki/head-base
bounds: 354, 121, 143, 125
misaki/leg
bounds: 741, 218, 28, 101
rotate: 90
misaki/skirt
bounds: 499, 95, 108, 90
chibi-stickers_7.png
size: 512, 256
filter: Linear, Linear
scale: 0.5
nate/arm
bounds: 151, 65, 28, 90
rotate: 90
nate/back-hair
bounds: 2, 109, 158, 141
nate/beard
bounds: 2, 39, 147, 68
nate/blush
bounds: 407, 165, 29, 18
nate/body
bounds: 307, 113, 70, 98
rotate: 90
nate/ear
bounds: 451, 208, 34, 42
nate/eyebrow
bounds: 265, 111, 27, 12
nate/glasses
bounds: 2, 2, 141, 35
nate/glasses-side
bounds: 151, 47, 8, 16
nate/hair-front
bounds: 307, 185, 142, 65
nate/head-base
bounds: 162, 125, 143, 125
nate/leg
bounds: 162, 95, 28, 101
rotate: 90
chibi-stickers_8.png
size: 512, 256
filter: Linear, Linear
scale: 0.5
sinisa/arm
bounds: 147, 52, 28, 90
rotate: 90
sinisa/back-hair
bounds: 2, 96, 158, 141
sinisa/beard
bounds: 307, 192, 139, 45
sinisa/blush
bounds: 147, 32, 29, 18
sinisa/body
bounds: 307, 120, 70, 98
rotate: 90
sinisa/body-decoration
bounds: 265, 83, 27, 27
sinisa/ear
bounds: 448, 195, 34, 42
sinisa/eyebrow
bounds: 407, 171, 38, 19
sinisa/hair-front
bounds: 2, 2, 143, 92
sinisa/head-base
bounds: 162, 112, 143, 125
sinisa/leg
bounds: 162, 82, 28, 101
rotate: 90
chibi-stickers_9.png
size: 512, 256
filter: Linear, Linear
scale: 0.5
soeren/arm
bounds: 254, 47, 28, 90
soeren/back-hair
bounds: 2, 111, 150, 141
soeren/beard
bounds: 2, 41, 145, 68
soeren/blush
bounds: 284, 119, 29, 18
soeren/body
bounds: 154, 67, 70, 98
rotate: 90
soeren/ear
bounds: 200, 23, 34, 42
soeren/eyebrow
bounds: 460, 137, 27, 12
soeren/glasses
bounds: 2, 2, 152, 37
soeren/glasses-side
bounds: 490, 245, 7, 20
rotate: 90
soeren/glove
bounds: 156, 12, 42, 53
soeren/hair-front
bounds: 154, 139, 159, 113
soeren/head-base
bounds: 315, 127, 143, 125
soeren/leg
bounds: 460, 151, 28, 101
chibi-stickers_10.png
size: 512, 256
filter: Linear, Linear
scale: 0.5
spineboy/arm
bounds: 407, 97, 28, 90
rotate: 90
spineboy/arm-decoration
bounds: 307, 127, 32, 29
spineboy/arm-shoulder-decoration
bounds: 451, 72, 23, 23
spineboy/back-hair
bounds: 2, 106, 158, 141
spineboy/blush
bounds: 2, 2, 29, 18
spineboy/body
bounds: 307, 55, 70, 98
rotate: 90
spineboy/ear
bounds: 407, 61, 34, 42
rotate: 90
spineboy/eyebrow
bounds: 143, 77, 27, 12
rotate: 90
spineboy/glasses
bounds: 162, 158, 179, 89
spineboy/glasses-shadow
bounds: 2, 22, 139, 82
spineboy/hair-front
bounds: 343, 127, 145, 120
spineboy/head-base
bounds: 162, 31, 143, 125
spineboy/leg
bounds: 307, 24, 29, 101
rotate: 90

File diff suppressed because it is too large Load Diff

View File

@ -132,196 +132,78 @@
</head>
<body>
<!-- <div style="height: 1200px; flex-direction: column;">
</div> -->
<!--
/////////////////////
// start section 1 //
/////////////////////
-->
<div id="section1" class="section vertical-split">
<div class="split-top split">
<div class="split-left">
<spine-widget
atlas="assets/raptor-pma.atlas"
skeleton="assets/raptor-pro.skel"
animation="walk"
scale="3"
clip="true"
fit="fitHeight"
></spine-widget>
</div>
<div class="split-right">
<spine-widget
atlas="assets/spineboy-pma.atlas"
skeleton="assets/spineboy-pro.skel"
animation="walk"
scale="1.5"
fit="none"
clip="true"
></spine-widget>
</div>
<div class="split-right">
<spine-widget
atlas="assets/spineboy-pma.atlas"
skeleton="assets/spineboy-pro.skel"
animation="walk"
scale="1"
fit="none"
clip="true"
></spine-widget>
</div>
<!-- <div class="split-right">
<spine-widget
atlas="assets/cloud-pot-pma.atlas"
skeleton="assets/cloud-pot.skel"
animation="playing-in-the-rain"
draggable="true"
></spine-widget>
</div>
<div class="split-right">
<spine-widget
atlas="assets/celestial-circus-pma.atlas"
skeleton="assets/celestial-circus-pro.skel"
animation="wings-and-feet"
draggable="true"
></spine-widget>
</div> -->
</div>
</div>
<div style="height: 1200px; flex-direction: column;">
</div>
<!--
/////////////////////
// start section 7 //
// end section 1 //
/////////////////////
-->
<div id="section1" class="section vertical-split">
<div class="split" style="width: 100%; flex-direction: column;">
<div class="split-left" style="width: 80%; box-sizing: border-box;">
If you have many atlas pages, for example one for each skin, and you want to show only some of the skins,
pass to the <code>pages</code> the atlas pages you want to load as a comma concatenated list of indices.
</div>
<div class="skin-grid">
<div class="skin-grid-element">
<spine-widget
atlas="assets/chibi-stickers-pma.atlas"
skeleton="assets/chibi-stickers.skel"
animation="emotes/wave"
skin="nate"
pages="0,1,4,6"
></spine-widget>
</div>
</div>
</div>
<div class="skin-grid">
<div class="skin-grid-element">
<spine-widget
atlas="assets/chibi-stickers-pma.atlas"
skeleton="assets/chibi-stickers.skel"
animation="emotes/wave"
skin="erikari"
pages="0,1,4,6"
offscreen="update"
></spine-widget>
</div>
</div>
<div class="skin-grid">
<div class="skin-grid-element">
<spine-widget
atlas="assets/chibi-stickers-pma.atlas"
skeleton="assets/chibi-stickers.skel"
animation="emotes/wave"
skin="mario"
pages="0,1,4,6"
offscreen="pose"
></spine-widget>
</div>
</div>
</div>
<div class="split-bottom">
<pre><code id="code-display">
<script>
escapeHTMLandInject(`
<div class="skin-grid">
<div class="skin-grid-element">
<spine-widget
atlas="assets/chibi-stickers-pma.atlas"
skeleton="assets/chibi-stickers.skel"
animation="emotes/wave"
skin="nate"
pages="0,1,4,6"
></spine-widget>
</div>
<div class="skin-grid-element">
<spine-widget
atlas="assets/chibi-stickers-pma.atlas"
skeleton="assets/chibi-stickers.skel"
animation="movement/trot-left"
skin="nate"
pages="0,1,4,6"
></spine-widget>
</div>
<div class="skin-grid-element">
<spine-widget
atlas="assets/chibi-stickers-pma.atlas"
skeleton="assets/chibi-stickers.skel"
animation="emotes/idea"
skin="nate"
pages="0,1,4,6"
></spine-widget>
</div>
<div class="skin-grid-element">
<spine-widget
atlas="assets/chibi-stickers-pma.atlas"
skeleton="assets/chibi-stickers.skel"
animation="emotes/hooray"
skin="nate"
pages="0,1,4,6"
></spine-widget>
</div>
</div>
<div class="skin-grid">
<div class="skin-grid-element">
<spine-widget
atlas="assets/chibi-stickers-pma.atlas"
skeleton="assets/chibi-stickers.skel"
animation="emotes/wave"
skin="erikari"
pages="0,1,4,6"
></spine-widget>
</div>
<div class="skin-grid-element">
<spine-widget
atlas="assets/chibi-stickers-pma.atlas"
skeleton="assets/chibi-stickers.skel"
animation="movement/trot-left"
skin="erikari"
pages="0,1,4,6"
></spine-widget>
</div>
<div class="skin-grid-element">
<spine-widget
atlas="assets/chibi-stickers-pma.atlas"
skeleton="assets/chibi-stickers.skel"
animation="emotes/idea"
skin="erikari"
pages="0,1,4,6"
></spine-widget>
</div>
<div class="skin-grid-element">
<spine-widget
atlas="assets/chibi-stickers-pma.atlas"
skeleton="assets/chibi-stickers.skel"
animation="emotes/hooray"
skin="erikari"
pages="0,1,4,6"
></spine-widget>
</div>
</div>
<div class="skin-grid">
<div class="skin-grid-element">
<spine-widget
atlas="assets/chibi-stickers-pma.atlas"
skeleton="assets/chibi-stickers.skel"
animation="emotes/wave"
skin="mario"
pages="0,1,4,6"
></spine-widget>
</div>
<div class="skin-grid-element">
<spine-widget
atlas="assets/chibi-stickers-pma.atlas"
skeleton="assets/chibi-stickers.skel"
animation="movement/trot-left"
skin="mario"
pages="0,1,4,6"
></spine-widget>
</div>
<div class="skin-grid-element">
<spine-widget
atlas="assets/chibi-stickers-pma.atlas"
skeleton="assets/chibi-stickers.skel"
animation="emotes/idea"
skin="mario"
pages="0,1,4,6"
></spine-widget>
</div>
<div class="skin-grid-element">
<spine-widget
atlas="assets/chibi-stickers-pma.atlas"
skeleton="assets/chibi-stickers.skel"
animation="emotes/hooray"
skin="mario"
pages="0,1,4,6"
></spine-widget>
</div>
</div>`)
</script>
</code></pre>
</div>
</div>
<!--
/////////////////////
// end section 7 //
/////////////////////
-->
</body>

View File

@ -3,8 +3,8 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="../dist/iife/spine-webgl.js"></script>
<!-- <script src="./spine-webgl.min.js"></script> -->
<!-- <script src="../dist/iife/spine-webgl.js"></script> -->
<script src="./spine-webgl.min.js"></script>
<title>JS Library Showcase</title>
<style>
body {
@ -1558,6 +1558,200 @@ stretchyman.update = (canvas, delta, skeleton, state) => {
/////////////////////
-->
<!--
/////////////////////
// start section 8 //
/////////////////////
-->
<div id="section1" class="section vertical-split">
<div class="split" style="width: 100%; flex-direction: column;">
<div class="split-left" style="width: 80%; box-sizing: border-box;">
If for some reason your skeleton bounds go outside the div,
you can use the <code>clip</code> property to clip everything is outside the html container.
<br>
<br>
Be aware that this will break batching!
</div>
<div class="split-left" style="width: 80%; box-sizing: border-box; height: 150px;">
<spine-widget
identifier="tank2"
atlas="assets/tank-pma.atlas"
skeleton="assets/tank-pro.skel"
animation="drive"
></spine-widget>
</div>
<div class="split-left" style="width: 30%; box-sizing: border-box; height: 150px;">
<spine-widget
identifier="tank"
atlas="assets/tank-pma.atlas"
skeleton="assets/tank-pro.skel"
animation="drive"
fit="none"
clip="true"
></spine-widget>
</div>
<script>
(async () => {
const tank = spine.getSpineWidget("tank");
const tank2 = spine.getSpineWidget("tank2");
await tank.loadingPromise;
await tank2.loadingPromise;
tank.beforeUpdateWorldTransforms = (canvas, delta, skeleton, state) => {
if (!tank.onScreen) return;
tank.skeleton.scaleX = tank2.skeleton.scaleX;
tank.skeleton.scaleY = tank2.skeleton.scaleY;
}
})();
</script>
</div>
<div class="split-bottom">
<pre><code id="code-display">
<script>
escapeHTMLandInject(`
<div class="split-left" style="width: 80%; box-sizing: border-box; height: 150px;">
<spine-widget
identifier="tank2"
atlas="assets/tank-pma.atlas"
skeleton="assets/tank-pro.skel"
animation="drive"
></spine-widget>
</div>
<div class="split-left" style="width: 30%; box-sizing: border-box; height: 150px;">
<spine-widget
identifier="tank"
atlas="assets/tank-pma.atlas"
skeleton="assets/tank-pro.skel"
animation="drive"
fit="none"
clip="true"
></spine-widget>
</div>
...
(async () => {
const tank = spine.getSpineWidget("tank");
const tank2 = spine.getSpineWidget("tank2");
await tank.loadingPromise;
await tank2.loadingPromise;
// since we want the tank to overflow the div, we set fit to none
// then we "sync" the tank scale to the one of the tank above
tank.beforeUpdateWorldTransforms = (canvas, delta, skeleton, state) => {
if (!tank.onScreen) return;
tank.skeleton.scaleX = tank2.skeleton.scaleX;
tank.skeleton.scaleY = tank2.skeleton.scaleY;
}
})();`);
</script>
</code></pre>
</div>
</div>
<!--
/////////////////////
// end section 8 //
/////////////////////
-->
<!--
/////////////////////
// start section 8 //
/////////////////////
-->
<div id="section1" class="section vertical-split">
<div class="split" style="width: 100%; flex-direction: column;">
<div class="split-top split">
<div class="split-left">
<spine-widget
atlas="assets/spineboy-pma.atlas"
skeleton="assets/spineboy-pro.skel"
animation="walk"
scale="3"
fit="none"
clip="true"
></spine-widget>
</div>
<div class="split-right">
<spine-widget
atlas="assets/spineboy-pma.atlas"
skeleton="assets/spineboy-pro.skel"
animation="walk"
scale="1.5"
fit="none"
clip="true"
></spine-widget>
</div>
<div class="split-right">
<spine-widget
atlas="assets/spineboy-pma.atlas"
skeleton="assets/spineboy-pro.skel"
animation="walk"
scale="1"
fit="none"
clip="true"
></spine-widget>
</div>
<div class="split-right">
<spine-widget
atlas="assets/cloud-pot-pma.atlas"
skeleton="assets/cloud-pot.skel"
animation="playing-in-the-rain"
scale="0.5"
fit="none"
clip="true"
></spine-widget>
</div>
<div class="split-right">
<spine-widget
identifier="celeste"
atlas="assets/celestial-circus-pma.atlas"
skeleton="assets/celestial-circus-pro.skel"
animation="wings-and-feet"
clip="true"
></spine-widget>
<script>
(async () => {
const celeste = spine.getSpineWidget("celeste");
await celeste.loadingPromise;
celeste.state.setAnimation(0, "swing", true);
})();
</script>
</div>
</div>
</div>
<div class="split-bottom">
<pre><code id="code-display">
<script>
escapeHTMLandInject(`
...`);
</script>
</code></pre>
</div>
</div>
<!--
/////////////////////
// end section 8 //
/////////////////////
-->
<!--

File diff suppressed because it is too large Load Diff

View File

@ -470,6 +470,17 @@ export class SceneRenderer implements Disposable {
this.camera.update();
}
resize3 (width: number, height: number) {
console.log("resize gl")
let canvas = this.canvas;
const dpr = window.devicePixelRatio;
this.canvas.width = Math.round(width * dpr);
this.canvas.height = Math.round(height * dpr);
this.context.gl.viewport(0, 0, canvas.width, canvas.height);
this.camera.setViewport(canvas.width, canvas.height);
this.camera.update();
}
resize (resizeMode: ResizeMode) {
let canvas = this.canvas;
var dpr = window.devicePixelRatio || 1;

View File

@ -36,7 +36,7 @@ interface Rectangle {
height: number,
}
type UpdateSpineFunction = (canvas: SpineCanvas, delta: number, skeleton: Skeleton, state: AnimationState) => void;
type UpdateSpineWidgetFunction = (canvas: SpineCanvas, delta: number, skeleton: Skeleton, state: AnimationState) => void;
type OffScreenUpdateBehaviourType = "pause" | "update" | "pose";
function isOffScreenUpdateBehaviourType(value: string): value is OffScreenUpdateBehaviourType {
@ -97,6 +97,7 @@ interface WidgetInternalState {
dragY: number
}
// TODO: add missing assets to main assets folder (chibi)
class SpineWebComponentWidget extends HTMLElement implements WidgetLayoutOptions, WidgetInternalState, Partial<WidgetPublicState> {
@ -107,7 +108,9 @@ class SpineWebComponentWidget extends HTMLElement implements WidgetLayoutOptions
public animation?: string;
public skin?: string;
skeletonData?: SkeletonData; // TODO
update?: UpdateSpineFunction; // TODO
update?: UpdateSpineWidgetFunction;
beforeUpdateWorldTransforms: UpdateSpineWidgetFunction = () => {};
afterUpdateWorldTransforms: UpdateSpineWidgetFunction= () => {};
// layout options
public fit: FitType = "contain";
@ -125,6 +128,7 @@ class SpineWebComponentWidget extends HTMLElement implements WidgetLayoutOptions
public manualStart = false;
public pages?: Array<number>;
public offScreenUpdateBehaviour: OffScreenUpdateBehaviourType = "pause";
public clip = false;
// state
public skeleton?: Skeleton;
@ -135,14 +139,6 @@ class SpineWebComponentWidget extends HTMLElement implements WidgetLayoutOptions
public started = false;
public onScreenAtLeastOnce = false;
// TODO tomorrow: la onScreenFunction di default carica le textures quando il widget viene rivelato sullo schermo.
// capire se va bene come comportamento di default
// poi spiegare i tre case
// no manual loading, no pages: tutte le pagine vengono caricate subito
// no manual loading, si pages: solo le pagine specificate vengono caricate subito (le altre se ne deve occupare manualmente il tizio)
// manual loading, no pages: tutte le pagine vengono caricate solo quando il widget è nella viewport
// manual loading, si pages: le pagine specificate vengono caricate solo quando il widget è nella viewport
// magari capire se mettere un altro parametro, tipo: loadsOnViewport
public onScreenFunction: (widget: SpineWebComponentWidget) => void = async (widget) => {
if (widget.loading && !widget.onScreenAtLeastOnce) {
widget.onScreenAtLeastOnce = true;
@ -193,7 +189,8 @@ class SpineWebComponentWidget extends HTMLElement implements WidgetLayoutOptions
"manual-start",
"spinner",
"pages",
"offscreen"
"offscreen",
"clip",
];
}
@ -327,6 +324,10 @@ class SpineWebComponentWidget extends HTMLElement implements WidgetLayoutOptions
this.manualStart = Boolean(newValue);
}
if (name === "clip") {
this.clip = Boolean(newValue);
}
if (name === "pages") {
this.pages = newValue.split(",").reduce((acc, pageIndex) => {
const index = parseInt(pageIndex);
@ -591,6 +592,7 @@ class SpineWebComponentOverlay extends HTMLElement {
private resizeObserver:ResizeObserver;
private input: Input;
// TODO: the canvas is now beg as the screen - maybe we can reduce the enhancement of the canvas and just translate
// how many pixels to add to the edges to prevent "edge cuttin" on fast scrolling
// be aware that the canvas is already big as the display size
// making it bigger might reduce performance significantly
@ -623,6 +625,17 @@ class SpineWebComponentOverlay extends HTMLElement {
this.canvas.style.position = "absolute";
this.canvas.style.top = "0";
this.canvas.style.left = "0";
// sono per l'ennesima volta fermo alla dimensione del canvas.
// purtroppo la dimensione dello schermo non permette di determinare la posizione dei div container relativamente allo schermo
// se trovassimo un modo per farlo, sarebbe fatta. provare prima a investigare un pochino lì.
//
// alternativamente giocare ancora con i lvh o qualcosa del genere
// purtroppo ho già provato un po' e si hanno oggettivamente dei brevi flash allo scroll quando la dimensione del canvas
// ovvero quando compare o scompare la barra durante lo scroll da mobile
// this.canvas.style.width = "100lvw";
// this.canvas.style.height = "120lvh";
this.canvas.style.setProperty("pointer-events", "none");
this.canvas.style.transform =`translate(0px,0px)`;
// this.canvas.style.setProperty("will-change", "transform"); // performance seems to be even worse with this uncommented
@ -675,9 +688,10 @@ class SpineWebComponentOverlay extends HTMLElement {
const red = new Color(1, 0, 0, 1);
const green = new Color(0, 1, 0, 1);
const blue = new Color(0, 0, 1, 1);
const transparentWhite = new Color(1, 1, 1, .3);
return {
update: (canvas: SpineCanvas, delta: number) => {
this.skeletonList.forEach(({ skeleton, state, update, onScreen, offScreenUpdateBehaviour, skeletonPath }) => {
this.skeletonList.forEach(({ skeleton, state, update, onScreen, offScreenUpdateBehaviour, skeletonPath, beforeUpdateWorldTransforms, afterUpdateWorldTransforms }) => {
if (!skeleton || !state) return;
if (!onScreen && offScreenUpdateBehaviour === "pause") return;
if (update) update(canvas, delta, skeleton, state)
@ -688,7 +702,9 @@ class SpineWebComponentOverlay extends HTMLElement {
if (onScreen || (!onScreen && offScreenUpdateBehaviour === "pose") ) {
state.apply(skeleton);
beforeUpdateWorldTransforms(canvas, delta, skeleton, state);
skeleton.updateWorldTransform(Physics.update);
afterUpdateWorldTransforms(canvas, delta, skeleton, state);
}
}
});
@ -703,67 +719,106 @@ class SpineWebComponentOverlay extends HTMLElement {
const devicePixelRatio = window.devicePixelRatio;
const tempVector = new Vector3();
this.skeletonList.forEach((widget) => {
const { skeleton, bounds, mode, debug, offsetX, offsetY, xAxis, yAxis, dragX, dragY, fit, loadingSpinner, onScreen, loading } = widget;
const { skeleton, bounds, mode, debug, offsetX, offsetY, xAxis, yAxis, dragX, dragY, fit, loadingSpinner, onScreen, loading, clip } = widget;
if ((!onScreen && dragX === 0 && dragY === 0)) return;
const divBounds = widget.getHTMLElementReference().getBoundingClientRect();
divBounds.x += this.overflowLeftSize;
divBounds.y += this.overflowTopSize;
// get the desired point into the the div (center by default) in world coordinate
const divX = divBounds.x + divBounds.width * (xAxis + .5);
const divY = divBounds.y + divBounds.height * (-yAxis + .5);
this.screenToWorld(tempVector, divX, divY);
if (loading) {
if (loadingSpinner) {
if (!widget.loadingScreen) widget.loadingScreen = new LoadingScreenWidget(renderer);
widget.loadingScreen!.draw(true, tempVector.x, tempVector.y, divBounds.width * devicePixelRatio, divBounds.height * devicePixelRatio);
// TODO: drag does not work while clip is on
// TODO: now that the clip logic works, remove the code duplication
if (clip) {
const clipToBoundStart = (canvas: SpineCanvas, divBounds: Rectangle) => {
const renderer = canvas.renderer;
// break current batch and start a new one
renderer.end();
// set the new viewport to the div bound
const viewportWidth = divBounds.width * window.devicePixelRatio;
const viewporthHeight = divBounds.height * window.devicePixelRatio;
canvas.gl.viewport(
divBounds.x * window.devicePixelRatio,
this.canvas.height - (divBounds.y + divBounds.height) * window.devicePixelRatio,
viewportWidth,
viewporthHeight
);
renderer.camera.setViewport(viewportWidth, viewporthHeight);
renderer.camera.update();
// start the new batch that will be filled with only this skeleton
renderer.begin();
// TODO: debug - to remove
if (false) {
renderer.circle(true, -viewportWidth / 2, -viewporthHeight / 2, 20, red);
renderer.circle(true, viewportWidth / 2, -viewporthHeight / 2, 20, red);
renderer.circle(true, -viewportWidth / 2, viewporthHeight / 2, 20, red);
renderer.circle(true, viewportWidth / 2, viewporthHeight / 2, 20, red);
renderer.circle(true, 0, 0, 10, red);
renderer.rect(true, 0, 0, -viewportWidth, -viewporthHeight, transparentWhite);
renderer.rect(true, 0, 0, viewportWidth, viewporthHeight, transparentWhite);
}
}
return;
}
if (skeleton) {
let x = tempVector.x;
let y = tempVector.y;
if (mode === 'inside') {
let { x: ax, y: ay, width: aw, height: ah } = bounds!;
const clipToBoundEnd = () => {
// end clip batch
renderer.end();
// scale ratio
const scaleWidth = divBounds.width * devicePixelRatio / aw;
const scaleHeight = divBounds.height * devicePixelRatio / ah;
canvas.gl.viewport(0, 0, this.canvas.width, this.canvas.height);
canvas.renderer.camera.setViewport(this.canvas.width, this.canvas.height);
canvas.renderer.camera.update();
let ratioW = skeleton.scaleX;
let ratioH = skeleton.scaleY;
// start new normal batch
renderer.begin();
}
if (fit === "fill") { // Fill the target box by distorting the source's aspect ratio.
ratioW = scaleWidth;
ratioH = scaleHeight;
} else if (fit === "fitWidth") {
ratioW = scaleWidth;
ratioH = scaleWidth;
} else if (fit === "fitHeight") {
ratioW = scaleHeight;
ratioH = scaleHeight;
} else if (fit === "contain") {
// if scaled height is bigger than div height, use height ratio instead
if (ah * scaleWidth > divBounds.height * devicePixelRatio){
ratioW = scaleHeight;
clipToBoundStart(canvas, divBounds)
// get the desired point into the the div (center by default) in world coordinate
const divX = divBounds.x + divBounds.width * (xAxis + .5);
const divY = divBounds.y + divBounds.height * (-yAxis + .5);
this.screenToWorld(tempVector, divX, divY);
if (loading) {
if (loadingSpinner) {
if (!widget.loadingScreen) widget.loadingScreen = new LoadingScreenWidget(renderer);
widget.loadingScreen!.draw(true, tempVector.x, tempVector.y, divBounds.width * devicePixelRatio, divBounds.height * devicePixelRatio);
}
return;
}
if (skeleton) {
let x = tempVector.x;
let y = tempVector.y;
if (mode === 'inside') {
let { x: ax, y: ay, width: aw, height: ah } = bounds!;
// scale ratio
const scaleWidth = divBounds.width * devicePixelRatio / aw;
const scaleHeight = divBounds.height * devicePixelRatio / ah;
let ratioW = skeleton.scaleX;
let ratioH = skeleton.scaleY;
if (fit === "fill") { // Fill the target box by distorting the source's aspect ratio.
ratioW = scaleWidth;
ratioH = scaleHeight;
} else {
} else if (fit === "fitWidth") {
ratioW = scaleWidth;
ratioH = scaleWidth;
}
} else if (fit === "cover") {
if (ah * scaleWidth < divBounds.height * devicePixelRatio){
} else if (fit === "fitHeight") {
ratioW = scaleHeight;
ratioH = scaleHeight;
} else {
ratioW = scaleWidth;
ratioH = scaleWidth;
}
} else if (fit === "scaleDown") {
if (aw > divBounds.width * devicePixelRatio || ah > divBounds.height * devicePixelRatio) {
} else if (fit === "contain") {
// if scaled height is bigger than div height, use height ratio instead
if (ah * scaleWidth > divBounds.height * devicePixelRatio){
ratioW = scaleHeight;
ratioH = scaleHeight;
@ -771,66 +826,225 @@ class SpineWebComponentOverlay extends HTMLElement {
ratioW = scaleWidth;
ratioH = scaleWidth;
}
} else if (fit === "cover") {
if (ah * scaleWidth < divBounds.height * devicePixelRatio){
ratioW = scaleHeight;
ratioH = scaleHeight;
} else {
ratioW = scaleWidth;
ratioH = scaleWidth;
}
} else if (fit === "scaleDown") {
if (aw > divBounds.width * devicePixelRatio || ah > divBounds.height * devicePixelRatio) {
if (ah * scaleWidth > divBounds.height * devicePixelRatio){
ratioW = scaleHeight;
ratioH = scaleHeight;
} else {
ratioW = scaleWidth;
ratioH = scaleWidth;
}
}
}
// get the center of the bounds
const boundsX = (ax + aw / 2) * ratioW;
const boundsY = (ay + ah / 2) * ratioH;
// get vertices offset: calculate the distance between div center and bounds center
x = - boundsX;
y = - boundsY;
if (fit !== "none") {
// scale the skeleton
skeleton.scaleX = ratioW;
skeleton.scaleY = ratioH;
skeleton.updateWorldTransform(Physics.update);
}
}
// get the center of the bounds
const boundsX = (ax + aw / 2) * ratioW;
const boundsY = (ay + ah / 2) * ratioH;
widget.worldOffsetX = x + offsetX + dragX;
widget.worldOffsetY = y + offsetY + dragY;
// get vertices offset: calculate the distance between div center and bounds center
x = tempVector.x - boundsX;
y = tempVector.y - boundsY;
renderer.drawSkeleton(skeleton, true, -1, -1, (vertices, size, vertexSize) => {
for (let i = 0; i < size; i+=vertexSize) {
vertices[i] = vertices[i] + widget.worldOffsetX;
vertices[i+1] = vertices[i+1] + widget.worldOffsetY;
}
});
if (fit !== "none") {
// scale the skeleton
skeleton.scaleX = ratioW;
skeleton.scaleY = ratioH;
skeleton.updateWorldTransform(Physics.update);
// drawing debug stuff
if (debug) {
// if (true) {
let { x: ax, y: ay, width: aw, height: ah } = bounds!;
// show bounds and its center
renderer.rect(false,
ax * skeleton.scaleX + widget.worldOffsetX,
ay * skeleton.scaleY + widget.worldOffsetY,
aw * skeleton.scaleX,
ah * skeleton.scaleY,
blue);
const bbCenterX = (ax + aw / 2) * skeleton.scaleX + widget.worldOffsetX;
const bbCenterY = (ay + ah / 2) * skeleton.scaleY + widget.worldOffsetY;
renderer.circle(true, bbCenterX, bbCenterY, 10, blue);
// show skeleton root
const root = skeleton.getRootBone()!;
renderer.circle(true, root.x + widget.worldOffsetX, root.y + widget.worldOffsetY, 10, red);
// show shifted origin
const originX = widget.worldOffsetX - dragX - offsetX;
const originY = widget.worldOffsetY - dragY - offsetY;
renderer.circle(true, originX, originY, 10, green);
// show line from origin to bounds center
renderer.line(originX, originY, bbCenterX, bbCenterY, green);
}
}
widget.worldOffsetX = x + offsetX + dragX;
widget.worldOffsetY = y + offsetY + dragY;
renderer.drawSkeleton(skeleton, true, -1, -1, (vertices, size, vertexSize) => {
// console.log(vertices[0])
for (let i = 0; i < size; i+=vertexSize) {
vertices[i] = vertices[i] + widget.worldOffsetX;
vertices[i+1] = vertices[i+1] + widget.worldOffsetY;
}
});
// drawing debug stuff
if (debug) {
// if (true) {
let { x: ax, y: ay, width: aw, height: ah } = bounds!;
clipToBoundEnd();
// show bounds and its center
renderer.rect(false,
ax * skeleton.scaleX + widget.worldOffsetX,
ay * skeleton.scaleY + widget.worldOffsetY,
aw * skeleton.scaleX,
ah * skeleton.scaleY,
blue);
const bbCenterX = (ax + aw / 2) * skeleton.scaleX + widget.worldOffsetX;
const bbCenterY = (ay + ah / 2) * skeleton.scaleY + widget.worldOffsetY;
renderer.circle(true, bbCenterX, bbCenterY, 10, blue);
// show skeleton root
const root = skeleton.getRootBone()!;
renderer.circle(true, root.x + widget.worldOffsetX, root.y + widget.worldOffsetY, 10, red);
// show shifted origin
const originX = widget.worldOffsetX - dragX - offsetX;
const originY = widget.worldOffsetY - dragY - offsetY;
renderer.circle(true, originX, originY, 10, green);
// show line from origin to bounds center
renderer.line(originX, originY, bbCenterX, bbCenterY, green);
}
}
else {
// get the desired point into the the div (center by default) in world coordinate
const divX = divBounds.x + divBounds.width * (xAxis + .5);
const divY = divBounds.y + divBounds.height * (-yAxis + .5);
this.screenToWorld(tempVector, divX, divY);
if (loading) {
if (loadingSpinner) {
if (!widget.loadingScreen) widget.loadingScreen = new LoadingScreenWidget(renderer);
widget.loadingScreen!.draw(true, tempVector.x, tempVector.y, divBounds.width * devicePixelRatio, divBounds.height * devicePixelRatio);
}
return;
}
if (skeleton) {
let x = tempVector.x;
let y = tempVector.y;
if (mode === 'inside') {
let { x: ax, y: ay, width: aw, height: ah } = bounds!;
// scale ratio
const scaleWidth = divBounds.width * devicePixelRatio / aw;
const scaleHeight = divBounds.height * devicePixelRatio / ah;
let ratioW = skeleton.scaleX;
let ratioH = skeleton.scaleY;
if (fit === "fill") { // Fill the target box by distorting the source's aspect ratio.
ratioW = scaleWidth;
ratioH = scaleHeight;
} else if (fit === "fitWidth") {
ratioW = scaleWidth;
ratioH = scaleWidth;
} else if (fit === "fitHeight") {
ratioW = scaleHeight;
ratioH = scaleHeight;
} else if (fit === "contain") {
// if scaled height is bigger than div height, use height ratio instead
if (ah * scaleWidth > divBounds.height * devicePixelRatio){
ratioW = scaleHeight;
ratioH = scaleHeight;
} else {
ratioW = scaleWidth;
ratioH = scaleWidth;
}
} else if (fit === "cover") {
if (ah * scaleWidth < divBounds.height * devicePixelRatio){
ratioW = scaleHeight;
ratioH = scaleHeight;
} else {
ratioW = scaleWidth;
ratioH = scaleWidth;
}
} else if (fit === "scaleDown") {
if (aw > divBounds.width * devicePixelRatio || ah > divBounds.height * devicePixelRatio) {
if (ah * scaleWidth > divBounds.height * devicePixelRatio){
ratioW = scaleHeight;
ratioH = scaleHeight;
} else {
ratioW = scaleWidth;
ratioH = scaleWidth;
}
}
}
// get the center of the bounds
const boundsX = (ax + aw / 2) * ratioW;
const boundsY = (ay + ah / 2) * ratioH;
// get vertices offset: calculate the distance between div center and bounds center
x = tempVector.x - boundsX;
y = tempVector.y - boundsY;
if (fit !== "none") {
// scale the skeleton
skeleton.scaleX = ratioW;
skeleton.scaleY = ratioH;
skeleton.updateWorldTransform(Physics.update);
}
}
widget.worldOffsetX = x + offsetX + dragX;
widget.worldOffsetY = y + offsetY + dragY;
renderer.drawSkeleton(skeleton, true, -1, -1, (vertices, size, vertexSize) => {
for (let i = 0; i < size; i+=vertexSize) {
vertices[i] = vertices[i] + widget.worldOffsetX;
vertices[i+1] = vertices[i+1] + widget.worldOffsetY;
}
});
// drawing debug stuff
if (debug) {
// if (true) {
let { x: ax, y: ay, width: aw, height: ah } = bounds!;
// show bounds and its center
renderer.rect(false,
ax * skeleton.scaleX + widget.worldOffsetX,
ay * skeleton.scaleY + widget.worldOffsetY,
aw * skeleton.scaleX,
ah * skeleton.scaleY,
blue);
const bbCenterX = (ax + aw / 2) * skeleton.scaleX + widget.worldOffsetX;
const bbCenterY = (ay + ah / 2) * skeleton.scaleY + widget.worldOffsetY;
renderer.circle(true, bbCenterX, bbCenterY, 10, blue);
// show skeleton root
const root = skeleton.getRootBone()!;
renderer.circle(true, root.x + widget.worldOffsetX, root.y + widget.worldOffsetY, 10, red);
// show shifted origin
const originX = widget.worldOffsetX - dragX - offsetX;
const originY = widget.worldOffsetY - dragY - offsetY;
renderer.circle(true, originX, originY, 10, green);
// show line from origin to bounds center
renderer.line(originX, originY, bbCenterX, bbCenterY, green);
}
}
}
});
renderer.end();
@ -946,14 +1160,10 @@ class SpineWebComponentOverlay extends HTMLElement {
const totalWidth = width * (1 + (this.overflowLeft + this.overflowRight));
const totalHeight = height * (1 + (this.overflowTop + this.overflowBottom));
this.canvas.style.width = totalWidth + "px";
this.canvas.style.height = totalHeight + "px";
const dpr = window.devicePixelRatio;
this.canvas.width = Math.round(totalWidth * dpr);
this.canvas.height = Math.round(totalHeight * dpr);
this.spineCanvas.renderer.resize2();
this.spineCanvas.renderer.resize3(totalWidth, totalHeight);
}
}
@ -981,6 +1191,12 @@ class SpineWebComponentOverlay extends HTMLElement {
skeleton.scaleX = skeleton.scaleX / widget.currentScaleDpi * scale;
skeleton.scaleY = skeleton.scaleY / widget.currentScaleDpi * scale;
widget.currentScaleDpi = scale;
// TODO: improve this horrible thing
this.spineCanvas.renderer.resize3(
+this.canvas.style.width.substring(0, this.canvas.style.width.length - 2),
+this.canvas.style.height.substring(0, this.canvas.style.height.length - 2),
);
})
}