fix: lint fixes

This commit is contained in:
Calum H. authored and Alejandro González committed 2025-06-14 17:41:57 +02:00
1 parent b558a0f0e6
commit 77796e8761
15 files changed
+1708 -268

No files matched your search

+1
View File
@@ -30,6 +30,7 @@
"ofetch": "^1.3.4",
"pinia": "^2.1.7",
"posthog-js": "^1.158.2",
"three": "^0.172.0",
"vite-svg-loader": "^5.1.0",
"vue": "^3.5.13",
"vue-multiselect": "3.0.0",
+92 -1
View File
@@ -1 +1,92 @@
{"asset":{"version":"2.0","generator":"Blockbench 4.12.4 glTF exporter"},"scenes":[{"nodes":[1],"name":"blockbench_export"}],"scene":0,"nodes":[{"rotation":[0,0,0.19509032201612825,0.9807852804032304],"translation":[0.15625,1,0],"name":"Cape","mesh":0},{"children":[0]}],"bufferViews":[{"buffer":0,"byteOffset":0,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":288,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":576,"byteLength":192,"target":34962,"byteStride":8},{"buffer":0,"byteOffset":768,"byteLength":72,"target":34963}],"buffers":[{"byteLength":840,"uri":"data:application/octet-stream;base64,AAAAPQAAAAAAAKA+AAAAPQAAAAAAAKC+AAAAPQAAgL8AAKA+AAAAPQAAgL8AAKC+AAAAvQAAAAAAAKC+AAAAvQAAAAAAAKA+AAAAvQAAgL8AAKC+AAAAvQAAgL8AAKA+AAAAvQAAAAAAAKC+AAAAPQAAAAAAAKC+AAAAvQAAAAAAAKA+AAAAPQAAAAAAAKA+AAAAvQAAgL8AAKA+AAAAPQAAgL8AAKA+AAAAvQAAgL8AAKC+AAAAPQAAgL8AAKC+AAAAvQAAAAAAAKA+AAAAPQAAAAAAAKA+AAAAvQAAgL8AAKA+AAAAPQAAgL8AAKA+AAAAPQAAAAAAAKC+AAAAvQAAAAAAAKC+AAAAPQAAgL8AAKC+AAAAvQAAgL8AAKC+AACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AACAPAAAgD0AADA+AACAPQAAgDwAAAg/AAAwPgAACD8AAEA+AACAPQAAsD4AAIA9AABAPgAACD8AALA+AAAIPwAAgDwAAAA9AACAPAAAgD0AADA+AAAAPQAAMD4AAIA9AAAwPgAAAD0AAKg+AAAAPQAAMD4AAAAAAACoPgAAAAAAAEA+AACAPQAAMD4AAIA9AABAPgAACD8AADA+AAAIPwAAAAAAAIA9AACAPAAAgD0AAAAAAAAIPwAAgDwAAAg/AAACAAEAAgADAAEABAAGAAUABgAHAAUACAAKAAkACgALAAkADAAOAA0ADgAPAA0AEAASABEAEgATABEAFAAWABUAFgAXABUA"}],"accessors":[{"bufferView":0,"componentType":5126,"count":24,"max":[0.03125,0,0.3125],"min":[-0.03125,-1,-0.3125],"type":"VEC3"},{"bufferView":1,"componentType":5126,"count":24,"max":[1,1,1],"min":[-1,-1,-1],"type":"VEC3"},{"bufferView":2,"componentType":5126,"count":24,"max":[0.34375,0.53125],"min":[0,0],"type":"VEC2"},{"bufferView":3,"componentType":5123,"count":36,"max":[23],"min":[0],"type":"SCALAR"}],"materials":[{"pbrMetallicRoughness":{"metallicFactor":0,"roughnessFactor":1,"baseColorTexture":{"index":0}},"alphaMode":"MASK","alphaCutoff":0.05,"doubleSided":true}],"textures":[{"sampler":0,"source":0,"name":"cape.png"}],"samplers":[{"magFilter":9728,"minFilter":9728,"wrapS":33071,"wrapT":33071}],"images":[{"mimeType":"image/png","uri":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAAAgCAYAAACinX6EAAAAAXNSR0IArs4c6QAABCRJREFUaEPtlktoE1EUhm/sIzFpYsBgHyn2oRZt0C5ESxWFYutKNyKIWBBR6kpBd3Ur2J0FRdCiuKmIIG4qLnzgQqTUXSlVqdoXTU0lljRpYtOHI/8dznBnOm1mphMwJWeTzJ0795zznf/cex2MMXam2S/ht38siJ8V1lgd5mOBARerc3rZnmK37rwvCyk2nE6wezMRh+4EncH9B1ql+fkU64rPsaBz5bqh4T7Daxn1Kc5zVNeEePJIci0Aq71bzenY6JChwAnA0OBHQ/OtJLnWNwqAy61R1tO3k891ueRKoDKwtqbv7MGbgCnfRgHQoqG9hyX4hc/yiho+/HNqVPFtdj2jwTpQgd/RKT7/0ZUku/o4qAJw50KYXbzr4e+3BioYzc3kwGzAUCLWFw2+UBiCb3bNTDHiPQeAP3CGNmg/6VcSBpDu3hhvDQpOCwABwrQKsRIsqYAChy/EQAXwlPiZ3a3igNPkXIyTjr8o5L7PPdzGf59c+sV/faeWeIIIAHPJ8M3kc7l1K09LKghWAIgqoPZ7djPFTlxb4D6yAgBOQfntrUVWVeRk44tplXJorOVGkVIJTBCTpw9ECFYBIEkyMfmsAXh3u1qi5MlxbbGX/x1ZSCjBAAwgfPr6h49R5UVavk0FXC2wju5p07s6iqEF0PtqSlEf+bKzDRwdgaDU7AkoySJ5Oo/D6ZRq/H0yyuJ/lxkSheG/FgCNm7kL0BoEAG32sqtY1YIHd2/mGzTMVgD3y2slqjgW9xY6ma9AThAARIMiBtOpjADwTWc0bEkB+FZsSTxTW0KBsGPXx0yvrUpEeHAAQIM7wBJLcu8DwHaP/H8i6VSND6SiSjBlRW4WWUypVIBbIgzjVgB0tpdKqLReS0KVPTMTfH0ra2cEgAmAAEd+l1z52LybqwBQYAQAyZPh6gtDW4jjuC4fHx8wXSm0JDbeI95SRYHiFZlUaWVtPQiKAugl5E8ASAUYiy8vc0C474uGasPE5PHc4g0wK/f4obom6UNimol7kTZwQLANwOuqBokqDEeQf4lfvvnNxZJcBTBAGZplWQcQ3tcgwY9oWlXinRW4ugoAgNAWWe6ocn1QvgyRTUb4RZFVljlY/3hSBYCqb6cCZo8ekuATVRZPI/gQW8FWAI1VHganVgDQUajdA6y2gAgAcZFBjTBSpG0AcAqc3VVmCMDTbxGWZvIRCaMNkJ7pFMCzVQD4liCQ8kRFUlvaBkCvL+wYw2ZmNUgCgLajFhRPJlv3ADuS1VtjPQCk823S574ffN/x1dQqy8dHR5SN2Spcbaymz2mjwNYDAD4IQn3TDpVLQIAqNjwAANRrAdoI/3sAOF7Xe1khCNQGVH1bL0JGJb1R52VtD8gVYHkAuVKpbMWZV0C2yObKunkF5EqlshVnXgHZIpsr6/4DlbxcPydnT74AAAAASUVORK5CYII="}],"meshes":[{"primitives":[{"mode":4,"attributes":{"POSITION":0,"NORMAL":1,"TEXCOORD_0":2},"indices":3,"material":0}]}]}
{
"asset": { "version": "2.0", "generator": "Blockbench 4.12.4 glTF exporter" },
"scenes": [{ "nodes": [1], "name": "blockbench_export" }],
"scene": 0,
"nodes": [
{
"rotation": [0, 0, 0.19509032201612825, 0.9807852804032304],
"translation": [0.15625, 1, 0],
"name": "Cape",
"mesh": 0
},
{ "children": [0] }
],
"bufferViews": [
{ "buffer": 0, "byteOffset": 0, "byteLength": 288, "target": 34962, "byteStride": 12 },
{ "buffer": 0, "byteOffset": 288, "byteLength": 288, "target": 34962, "byteStride": 12 },
{ "buffer": 0, "byteOffset": 576, "byteLength": 192, "target": 34962, "byteStride": 8 },
{ "buffer": 0, "byteOffset": 768, "byteLength": 72, "target": 34963 }
],
"buffers": [
{
"byteLength": 840,
"uri": "data:application/octet-stream;base64,AAAAPQAAAAAAAKA+AAAAPQAAAAAAAKC+AAAAPQAAgL8AAKA+AAAAPQAAgL8AAKC+AAAAvQAAAAAAAKC+AAAAvQAAAAAAAKA+AAAAvQAAgL8AAKC+AAAAvQAAgL8AAKA+AAAAvQAAAAAAAKC+AAAAPQAAAAAAAKC+AAAAvQAAAAAAAKA+AAAAPQAAAAAAAKA+AAAAvQAAgL8AAKA+AAAAPQAAgL8AAKA+AAAAvQAAgL8AAKC+AAAAPQAAgL8AAKC+AAAAvQAAAAAAAKA+AAAAPQAAAAAAAKA+AAAAvQAAgL8AAKA+AAAAPQAAgL8AAKA+AAAAPQAAAAAAAKC+AAAAvQAAAAAAAKC+AAAAPQAAgL8AAKC+AAAAvQAAgL8AAKC+AACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AACAPAAAgD0AADA+AACAPQAAgDwAAAg/AAAwPgAACD8AAEA+AACAPQAAsD4AAIA9AABAPgAACD8AALA+AAAIPwAAgDwAAAA9AACAPAAAgD0AADA+AAAAPQAAMD4AAIA9AAAwPgAAAD0AAKg+AAAAPQAAMD4AAAAAAACoPgAAAAAAAEA+AACAPQAAMD4AAIA9AABAPgAACD8AADA+AAAIPwAAAAAAAIA9AACAPAAAgD0AAAAAAAAIPwAAgDwAAAg/AAACAAEAAgADAAEABAAGAAUABgAHAAUACAAKAAkACgALAAkADAAOAA0ADgAPAA0AEAASABEAEgATABEAFAAWABUAFgAXABUA"
}
],
"accessors": [
{
"bufferView": 0,
"componentType": 5126,
"count": 24,
"max": [0.03125, 0, 0.3125],
"min": [-0.03125, -1, -0.3125],
"type": "VEC3"
},
{
"bufferView": 1,
"componentType": 5126,
"count": 24,
"max": [1, 1, 1],
"min": [-1, -1, -1],
"type": "VEC3"
},
{
"bufferView": 2,
"componentType": 5126,
"count": 24,
"max": [0.34375, 0.53125],
"min": [0, 0],
"type": "VEC2"
},
{
"bufferView": 3,
"componentType": 5123,
"count": 36,
"max": [23],
"min": [0],
"type": "SCALAR"
}
],
"materials": [
{
"pbrMetallicRoughness": {
"metallicFactor": 0,
"roughnessFactor": 1,
"baseColorTexture": { "index": 0 }
},
"alphaMode": "MASK",
"alphaCutoff": 0.05,
"doubleSided": true
}
],
"textures": [{ "sampler": 0, "source": 0, "name": "cape.png" }],
"samplers": [{ "magFilter": 9728, "minFilter": 9728, "wrapS": 33071, "wrapT": 33071 }],
"images": [
{
"mimeType": "image/png",
"uri": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAAAgCAYAAACinX6EAAAAAXNSR0IArs4c6QAABCRJREFUaEPtlktoE1EUhm/sIzFpYsBgHyn2oRZt0C5ESxWFYutKNyKIWBBR6kpBd3Ur2J0FRdCiuKmIIG4qLnzgQqTUXSlVqdoXTU0lljRpYtOHI/8dznBnOm1mphMwJWeTzJ0795zznf/cex2MMXam2S/ht38siJ8V1lgd5mOBARerc3rZnmK37rwvCyk2nE6wezMRh+4EncH9B1ql+fkU64rPsaBz5bqh4T7Daxn1Kc5zVNeEePJIci0Aq71bzenY6JChwAnA0OBHQ/OtJLnWNwqAy61R1tO3k891ueRKoDKwtqbv7MGbgCnfRgHQoqG9hyX4hc/yiho+/HNqVPFtdj2jwTpQgd/RKT7/0ZUku/o4qAJw50KYXbzr4e+3BioYzc3kwGzAUCLWFw2+UBiCb3bNTDHiPQeAP3CGNmg/6VcSBpDu3hhvDQpOCwABwrQKsRIsqYAChy/EQAXwlPiZ3a3igNPkXIyTjr8o5L7PPdzGf59c+sV/faeWeIIIAHPJ8M3kc7l1K09LKghWAIgqoPZ7djPFTlxb4D6yAgBOQfntrUVWVeRk44tplXJorOVGkVIJTBCTpw9ECFYBIEkyMfmsAXh3u1qi5MlxbbGX/x1ZSCjBAAwgfPr6h49R5UVavk0FXC2wju5p07s6iqEF0PtqSlEf+bKzDRwdgaDU7AkoySJ5Oo/D6ZRq/H0yyuJ/lxkSheG/FgCNm7kL0BoEAG32sqtY1YIHd2/mGzTMVgD3y2slqjgW9xY6ma9AThAARIMiBtOpjADwTWc0bEkB+FZsSTxTW0KBsGPXx0yvrUpEeHAAQIM7wBJLcu8DwHaP/H8i6VSND6SiSjBlRW4WWUypVIBbIgzjVgB0tpdKqLReS0KVPTMTfH0ra2cEgAmAAEd+l1z52LybqwBQYAQAyZPh6gtDW4jjuC4fHx8wXSm0JDbeI95SRYHiFZlUaWVtPQiKAugl5E8ASAUYiy8vc0C474uGasPE5PHc4g0wK/f4obom6UNimol7kTZwQLANwOuqBokqDEeQf4lfvvnNxZJcBTBAGZplWQcQ3tcgwY9oWlXinRW4ugoAgNAWWe6ocn1QvgyRTUb4RZFVljlY/3hSBYCqb6cCZo8ekuATVRZPI/gQW8FWAI1VHganVgDQUajdA6y2gAgAcZFBjTBSpG0AcAqc3VVmCMDTbxGWZvIRCaMNkJ7pFMCzVQD4liCQ8kRFUlvaBkCvL+wYw2ZmNUgCgLajFhRPJlv3ADuS1VtjPQCk823S574ffN/x1dQqy8dHR5SN2Spcbaymz2mjwNYDAD4IQn3TDpVLQIAqNjwAANRrAdoI/3sAOF7Xe1khCNQGVH1bL0JGJb1R52VtD8gVYHkAuVKpbMWZV0C2yObKunkF5EqlshVnXgHZIpsr6/4DlbxcPydnT74AAAAASUVORK5CYII="
}
],
"meshes": [
{
"primitives": [
{
"mode": 4,
"attributes": { "POSITION": 0, "NORMAL": 1, "TEXCOORD_0": 2 },
"indices": 3,
"material": 0
}
]
}
]
}
@@ -1 +1,641 @@
{"asset":{"version":"2.0","generator":"Blockbench 4.12.4 glTF exporter"},"scenes":[{"nodes":[18],"name":"blockbench_export"}],"scene":0,"nodes":[{"translation":[0,-1.5,0],"name":"Head","mesh":0},{"translation":[0,-1.5,0],"name":"Hat Layer","mesh":1},{"rotation":[0.05228614400929896,-0.043559608510925024,0.002282862348496242,0.997679060715675],"translation":[0,1.5,0],"name":"Head","children":[0,1]},{"translation":[0,-1.5,0],"name":"Body","mesh":2},{"translation":[0,-1.5,0],"name":"Body Layer","mesh":3},{"translation":[0,1.5,0],"name":"Body","children":[3,4]},{"translation":[-0.3125,-1.375,0],"name":"Right Arm","mesh":4},{"translation":[-0.3125,-1.375,0],"name":"Right Arm Layer","mesh":5},{"rotation":[0.08715574274765817,0,0,0.9961946980917455],"translation":[0.3125,1.375,0],"name":"Right Arm","children":[6,7]},{"translation":[0.3125,-1.375,0],"name":"Left Arm","mesh":6},{"translation":[0.3125,-1.375,0],"name":"Left Arm Layer","mesh":7},{"rotation":[-0.10452846326765346,0,0,0.9945218953682733],"translation":[-0.3125,1.375,0],"name":"Left Arm","children":[9,10]},{"translation":[-0.11875,-0.75,0],"name":"Right Leg","mesh":8},{"translation":[-0.11875,-0.75,0],"name":"Right Leg Layer","mesh":9},{"rotation":[-0.09583115474787583,-0.0016727390282702394,0.01737205902003089,0.9952445947048578],"translation":[0.11875,0.75,0],"name":"Right Leg","children":[12,13]},{"translation":[0.11875,-0.75,0],"name":"Left Leg","mesh":10},{"translation":[0.11875,-0.75,0],"name":"Left Leg Layer","mesh":11},{"rotation":[0.08714246850588939,-0.0015210774457754552,-0.017385994761764084,0.9960429728140489],"translation":[-0.11875,0.75,0],"name":"Left Leg","children":[15,16]},{"children":[2,5,8,11,14,17]}],"bufferViews":[{"buffer":0,"byteOffset":0,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":288,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":576,"byteLength":192,"target":34962,"byteStride":8},{"buffer":0,"byteOffset":768,"byteLength":72,"target":34963},{"buffer":0,"byteOffset":840,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":1128,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":1416,"byteLength":192,"target":34962,"byteStride":8},{"buffer":0,"byteOffset":1608,"byteLength":72,"target":34963},{"buffer":0,"byteOffset":1680,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":1968,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":2256,"byteLength":192,"target":34962,"byteStride":8},{"buffer":0,"byteOffset":2448,"byteLength":72,"target":34963},{"buffer":0,"byteOffset":2520,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":2808,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":3096,"byteLength":192,"target":34962,"byteStride":8},{"buffer":0,"byteOffset":3288,"byteLength":72,"target":34963},{"buffer":0,"byteOffset":3360,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":3648,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":3936,"byteLength":192,"target":34962,"byteStride":8},{"buffer":0,"byteOffset":4128,"byteLength":72,"target":34963},{"buffer":0,"byteOffset":4200,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":4488,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":4776,"byteLength":192,"target":34962,"byteStride":8},{"buffer":0,"byteOffset":4968,"byteLength":72,"target":34963},{"buffer":0,"byteOffset":5040,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":5328,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":5616,"byteLength":192,"target":34962,"byteStride":8},{"buffer":0,"byteOffset":5808,"byteLength":72,"target":34963},{"buffer":0,"byteOffset":5880,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":6168,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":6456,"byteLength":192,"target":34962,"byteStride":8},{"buffer":0,"byteOffset":6648,"byteLength":72,"target":34963},{"buffer":0,"byteOffset":6720,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":7008,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":7296,"byteLength":192,"target":34962,"byteStride":8},{"buffer":0,"byteOffset":7488,"byteLength":72,"target":34963},{"buffer":0,"byteOffset":7560,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":7848,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":8136,"byteLength":192,"target":34962,"byteStride":8},{"buffer":0,"byteOffset":8328,"byteLength":72,"target":34963},{"buffer":0,"byteOffset":8400,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":8688,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":8976,"byteLength":192,"target":34962,"byteStride":8},{"buffer":0,"byteOffset":9168,"byteLength":72,"target":34963},{"buffer"Line truncated
{
"asset": { "version": "2.0", "generator": "Blockbench 4.12.4 glTF exporter" },
"scenes": [{ "nodes": [18], "name": "blockbench_export" }],
"scene": 0,
"nodes": [
{ "translation": [0, -1.5, 0], "name": "Head", "mesh": 0 },
{ "translation": [0, -1.5, 0], "name": "Hat Layer", "mesh": 1 },
{
"rotation": [
0.05228614400929896, -0.043559608510925024, 0.002282862348496242, 0.997679060715675
],
"translation": [0, 1.5, 0],
"name": "Head",
"children": [0, 1]
},
{ "translation": [0, -1.5, 0], "name": "Body", "mesh": 2 },
{ "translation": [0, -1.5, 0], "name": "Body Layer", "mesh": 3 },
{ "translation": [0, 1.5, 0], "name": "Body", "children": [3, 4] },
{ "translation": [-0.3125, -1.375, 0], "name": "Right Arm", "mesh": 4 },
{ "translation": [-0.3125, -1.375, 0], "name": "Right Arm Layer", "mesh": 5 },
{
"rotation": [0.08715574274765817, 0, 0, 0.9961946980917455],
"translation": [0.3125, 1.375, 0],
"name": "Right Arm",
"children": [6, 7]
},
{ "translation": [0.3125, -1.375, 0], "name": "Left Arm", "mesh": 6 },
{ "translation": [0.3125, -1.375, 0], "name": "Left Arm Layer", "mesh": 7 },
{
"rotation": [-0.10452846326765346, 0, 0, 0.9945218953682733],
"translation": [-0.3125, 1.375, 0],
"name": "Left Arm",
"children": [9, 10]
},
{ "translation": [-0.11875, -0.75, 0], "name": "Right Leg", "mesh": 8 },
{ "translation": [-0.11875, -0.75, 0], "name": "Right Leg Layer", "mesh": 9 },
{
"rotation": [
-0.09583115474787583, -0.0016727390282702394, 0.01737205902003089, 0.9952445947048578
],
"translation": [0.11875, 0.75, 0],
"name": "Right Leg",
"children": [12, 13]
},
{ "translation": [0.11875, -0.75, 0], "name": "Left Leg", "mesh": 10 },
{ "translation": [0.11875, -0.75, 0], "name": "Left Leg Layer", "mesh": 11 },
{
"rotation": [
0.08714246850588939, -0.0015210774457754552, -0.017385994761764084, 0.9960429728140489
],
"translation": [-0.11875, 0.75, 0],
"name": "Left Leg",
"children": [15, 16]
},
{ "children": [2, 5, 8, 11, 14, 17] }
],
"bufferViews": [
{ "buffer": 0, "byteOffset": 0, "byteLength": 288, "target": 34962, "byteStride": 12 },
{ "buffer": 0, "byteOffset": 288, "byteLength": 288, "target": 34962, "byteStride": 12 },
{ "buffer": 0, "byteOffset": 576, "byteLength": 192, "target": 34962, "byteStride": 8 },
{ "buffer": 0, "byteOffset": 768, "byteLength": 72, "target": 34963 },
{ "buffer": 0, "byteOffset": 840, "byteLength": 288, "target": 34962, "byteStride": 12 },
{ "buffer": 0, "byteOffset": 1128, "byteLength": 288, "target": 34962, "byteStride": 12 },
{ "buffer": 0, "byteOffset": 1416, "byteLength": 192, "target": 34962, "byteStride": 8 },
{ "buffer": 0, "byteOffset": 1608, "byteLength": 72, "target": 34963 },
{ "buffer": 0, "byteOffset": 1680, "byteLength": 288, "target": 34962, "byteStride": 12 },
{ "buffer": 0, "byteOffset": 1968, "byteLength": 288, "target": 34962, "byteStride": 12 },
{ "buffer": 0, "byteOffset": 2256, "byteLength": 192, "target": 34962, "byteStride": 8 },
{ "buffer": 0, "byteOffset": 2448, "byteLength": 72, "target": 34963 },
{ "buffer": 0, "byteOffset": 2520, "byteLength": 288, "target": 34962, "byteStride": 12 },
{ "buffer": 0, "byteOffset": 2808, "byteLength": 288, "target": 34962, "byteStride": 12 },
{ "buffer": 0, "byteOffset": 3096, "byteLength": 192, "target": 34962, "byteStride": 8 },
{ "buffer": 0, "byteOffset": 3288, "byteLength": 72, "target": 34963 },
{ "buffer": 0, "byteOffset": 3360, "byteLength": 288, "target": 34962, "byteStride": 12 },
{ "buffer": 0, "byteOffset": 3648, "byteLength": 288, "target": 34962, "byteStride": 12 },
{ "buffer": 0, "byteOffset": 3936, "byteLength": 192, "target": 34962, "byteStride": 8 },
{ "buffer": 0, "byteOffset": 4128, "byteLength": 72, "target": 34963 },
{ "buffer": 0, "byteOffset": 4200, "byteLength": 288, "target": 34962, "byteStride": 12 },
{ "buffer": 0, "byteOffset": 4488, "byteLength": 288, "target": 34962, "byteStride": 12 },
{ "buffer": 0, "byteOffset": 4776, "byteLength": 192, "target": 34962, "byteStride": 8 },
{ "buffer": 0, "byteOffset": 4968, "byteLength": 72, "target": 34963 },
{ "buffer": 0, "byteOffset": 5040, "byteLength": 288, "target": 34962, "byteStride": 12 },
{ "buffer": 0, "byteOffset": 5328, "byteLength": 288, "target": 34962, "byteStride": 12 },
{ "buffer": 0, "byteOffset": 5616, "byteLength": 192, "target": 34962, "byteStride": 8 },
{ "buffer": 0, "byteOffset": 5808, "byteLength": 72, "target": 34963 },
{ "buffer": 0, "byteOffset": 5880, "byteLength": 288, "target": 34962, "byteStride": 12 },
{ "buffer": 0, "byteOffset": 6168, "byteLength": 288, "target": 34962, "byteStride": 12 },
{ "buffer": 0, "byteOffset": 6456, "byteLength": 192, "target": 34962, "byteStride": 8 },
{ "buffer": 0, "byteOffset": 6648, "byteLength": 72, "target": 34963 },
{ "buffer": 0, "byteOffset": 6720, "byteLength": 288, "target": 34962, "byteStride": 12 },
{ "buffer": 0, "byteOffset": 7008, "byteLength": 288, "target": 34962, "byteStride": 12 },
{ "buffer": 0, "byteOffset": 7296, "byteLength": 192, "target": 34962, "byteStride": 8 },
{ "buffer": 0, "byteOffset": 7488, "byteLength": 72, "target": 34963 },
{ "buffer": 0, "byteOffset": 7560, "byteLength": 288, "target": 34962, "byteStride": 12 },
{ "buffer": 0, "byteOffset": 7848, "byteLength": 288, "target": 34962, "byteStride": 12 },
{ "buffer": 0, "byteOffset": 8136, "byteLength": 192, "target": 34962, "byteStride": 8 },
{ "buffer": 0, "byteOffset": 8328, "byteLength": 72, "target": 34963 },
{ "buffer": 0, "byteOffset": 8400, "byteLength": 288, "target": 34962, "byteStride": 12 },
{ "buffer": 0, "byteOffset": 8688, "byteLength": 288, "target": 34962, "byteStride": 12 },
{ "buffer": 0, "byteOffset": 8976, "byteLength": 192, "target": 34962, "byteStride": 8 },
{ "buffer": 0, "byteOffset": 9168, "byteLength": 72, "target": 34963 },
{ "buffer": 0, "byteOffset": 9240, "byteLength": 288, "target": 34962, "byteStride": 12 },
{ "buffer": 0, "byteOffset": 9528, "byteLength": 288, "target": 34962, "byteStride": 12 },
{ "buffer": 0, "byteOffset": 9816, "byteLength": 192, "target": 34962, "byteStride": 8 },
{ "buffer": 0, "byteOffset": 10008, "byteLength": 72, "target": 34963 }
],
"buffers": [
{
"byteLength": 10080,
"uri": "data:application/octet-stream;base64,AACAPgAAAEAAAIA+AACAPgAAAEAAAIC+AACAPgAAwD8AAIA+AACAPgAAwD8AAIC+AACAvgAAAEAAAIC+AACAvgAAAEAAAIA+AACAvgAAwD8AAIC+AACAvgAAwD8AAIA+AACAvgAAAEAAAIC+AACAPgAAAEAAAIC+AACAvgAAAEAAAIA+AACAPgAAAEAAAIA+AACAvgAAwD8AAIA+AACAPgAAwD8AAIA+AACAvgAAwD8AAIC+AACAPgAAwD8AAIC+AACAvgAAAEAAAIA+AACAPgAAAEAAAIA+AACAvgAAwD8AAIA+AACAPgAAwD8AAIA+AACAPgAAAEAAAIC+AACAvgAAAEAAAIC+AACAPgAAwD8AAIC+AACAvgAAwD8AAIC+AACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AACAOQBAAD4AgP89AEAAPgAAgDkAwH8+AID/PQDAfz4AIIA+AEAAPgDgvz4AQAA+ACCAPgDAfz4A4L8+AMB/PgDAfz4AgP89AEAAPgCA/z0AwH8+AACAOQBAAD4AAIA5AOC/PgAAgDkAIIA+AACAOQDgvz4AgP89ACCAPgCA/z0AIMA+AEAAPgDg/z4AQAA+ACDAPgDAfz4A4P8+AMB/PgBAAD4AQAA+AMB/PgBAAD4AQAA+AMB/PgDAfz4AwH8+AAACAAEAAgADAAEABAAGAAUABgAHAAUACAAKAAkACgALAAkADAAOAA0ADgAPAA0AEAASABEAEgATABEAFAAWABUAFgAXABUAAACQPgAAAkAAAJA+AACQPgAAAkAAAJC+AACQPgAAvD8AAJA+AACQPgAAvD8AAJC+AACQvgAAAkAAAJC+AACQvgAAAkAAAJA+AACQvgAAvD8AAJC+AACQvgAAvD8AAJA+AACQvgAAAkAAAJC+AACQPgAAAkAAAJC+AACQvgAAAkAAAJA+AACQPgAAAkAAAJA+AACQvgAAvD8AAJA+AACQPgAAvD8AAJA+AACQvgAAvD8AAJC+AACQPgAAvD8AAJC+AACQvgAAAkAAAJA+AACQPgAAAkAAAJA+AACQvgAAvD8AAJA+AACQPgAAvD8AAJA+AACQPgAAAkAAAJC+AACQvgAAAkAAAJC+AACQPgAAvD8AAJC+AACQvgAAvD8AAJC+AACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/ABAAPwBAAD4A8B8/AEAAPgAQAD8AwH8+APAfPwDAfz4AEEA/AEAAPgDwXz8AQAA+ABBAPwDAfz4A8F8/AMB/PgDwPz8AgP89ABAgPwCA/z0A8D8/AACAOQAQID8AAIA5APBfPwAAgDkAEEA/AACAOQDwXz8AgP89ABBAPwCA/z0AEGA/AEAAPgDwfz8AQAA+ABBgPwDAfz4A8H8/AMB/PgAQID8AQAA+APA/PwBAAD4AECA/AMB/PgDwPz8AwH8+AAACAAEAAgADAAEABAAGAAUABgAHAAUACAAKAAkACgALAAkADAAOAA0ADgAPAA0AEAASABEAEgATABEAFAAWABUAFgAXABUAAACAPgAAwD8AAAA+AACAPgAAwD8AAAC+AACAPgAAQD8AAAA+AACAPgAAQD8AAAC+AACAvgAAwD8AAAC+AACAvgAAwD8AAAA+AACAvgAAQD8AAAC+AACAvgAAQD8AAAA+AACAvgAAwD8AAAC+AACAPgAAwD8AAAC+AACAvgAAwD8AAAA+AACAPgAAwD8AAAA+AACAvgAAQD8AAAA+AACAPgAAQD8AAAA+AACAvgAAQD8AAAC+AACAPgAAQD8AAAC+AACAvgAAwD8AAAA+AACAPgAAwD8AAAA+AACAvgAAQD8AAAA+AACAPgAAQD8AAAA+AACAPgAAwD8AAAC+AACAvgAAwD8AAAC+AACAPgAAQD8AAAC+AACAvgAAQD8AAAC+AACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/ACCAPgAgoD4A4J8+ACCgPgAggD4A4P8+AOCfPgDg/z4AIOA+ACCgPgDg/z4AIKA+ACDgPgDg/z4A4P8+AOD/PgDg3z4A4J8+ACCgPgDgnz4A4N8+ACCAPgAgoD4AIIA+APAPPwAggD4AIOA+ACCAPgDwDz8A4J8+ACDgPgDgnz4AEAA/ACCgPgDwHz8AIKA+ABAAPwDg/z4A8B8/AOD/PgAgoD4AIKA+AODfPgAgoD4AIKA+AOD/PgDg3z4A4P8+AAACAAEAAgADAAEABAAGAAUABgAHAAUACAAKAAkACgALAAkADAAOAA0ADgAPAA0AEAASABEAEgATABEAFAAWABUAFgAXABUAAACIPgAAwj8AABA+AACIPgAAwj8AABC+AACIPgAAPD8AABA+AACIPgAAPD8AABC+AACIvgAAwj8AABC+AACIvgAAwj8AABA+AACIvgAAPD8AABC+AACIvgAAPD8AABA+AACIvgAAwj8AABC+AACIPgAAwj8AABC+AACIvgAAwj8AABA+AACIPgAAwj8AABA+AACIvgAAPD8AABA+AACIPgAAPD8AABA+AACIvgAAPD8AABC+AACIPgAAPD8AABC+AACIvgAAwj8AABA+AACIPgAAwj8AABA+AACIvgAAPD8AABA+AACIPgAAPD8AABA+AACIPgAAwj8AABC+AACIvgAAwj8AABC+AACIPgAAPD8AABC+AACIvgAAPD8AABC+AACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/ACCAPgAQED8A4J8+ABAQPwAggD4A8D8/AOCfPgDwPz8AIOA+ABAQPwDg/z4AEBA/ACDgPgDwPz8A4P8+APA/PwDg3z4A8A8/ACCgPgDwDz8A4N8+ABAAPwAgoD4AEAA/APAPPwAQAD8AIOA+ABAAPwDwDz8A8A8/ACDgPgDwDz8AEAA/ABAQPwDwHz8AEBA/ABAAPwDwPz8A8B8/APA/PwAgoD4AEBA/AODfPgAQED8AIKA+APA/PwDg3z4A8D8/AAACAAEAAgADAAEABAAGAAUABgAHAAUACAAKAAkACgALAAkADAAOAA0ADgAPAA0AEAASABEAEgATABEAFAAWABUAFgAXABUAAAAAPwAAwD8AAAA+AAAAPwAAwD8AAAC+AAAAPwAAQD8AAAA+AAAAPwAAQD8AAAC+AACAPgAAwD8AAAC+AACAPgAAwD8AAAA+AACAPgAAQD8AAAC+AACAPgAAQD8AAAA+AACAPgAAwD8AAAC+AAAAPwAAwD8AAAC+AACAPgAAwD8AAAA+AAAAPwAAwD8AAAA+AACAPgAAQD8AAAA+AAAAPwAAQD8AAAA+AACAPgAAQD8AAAC+AAAAPwAAQD8AAAC+AACAPgAAwD8AAAA+AAAAPwAAwD8AAAA+AACAPgAAQD8AAAA+AAAAPwAAQD8AAAA+AAAAPwAAwD8AAAC+AACAPgAAwD8AAAC+AAAAPwAAQD8AAAC+AACAPgAAQD8AAAC+AACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAvwAAAAAAAAAAAACALine truncated
}
],
"accessors": [
{
"bufferView": 0,
"componentType": 5126,
"count": 24,
"max": [0.25, 2, 0.25],
"min": [-0.25, 1.5, -0.25],
"type": "VEC3"
},
{
"bufferView": 1,
"componentType": 5126,
"count": 24,
"max": [1, 1, 1],
"min": [-1, -1, -1],
"type": "VEC3"
},
{
"bufferView": 2,
"componentType": 5126,
"count": 24,
"max": [0.499755859375, 0.249755859375],
"min": [0.000244140625, 0.000244140625],
"type": "VEC2"
},
{
"bufferView": 3,
"componentType": 5123,
"count": 36,
"max": [23],
"min": [0],
"type": "SCALAR"
},
{
"bufferView": 4,
"componentType": 5126,
"count": 24,
"max": [0.28125, 2.03125, 0.28125],
"min": [-0.28125, 1.46875, -0.28125],
"type": "VEC3"
},
{
"bufferView": 5,
"componentType": 5126,
"count": 24,
"max": [1, 1, 1],
"min": [-1, -1, -1],
"type": "VEC3"
},
{
"bufferView": 6,
"componentType": 5126,
"count": 24,
"max": [0.999755859375, 0.249755859375],
"min": [0.500244140625, 0.000244140625],
"type": "VEC2"
},
{
"bufferView": 7,
"componentType": 5123,
"count": 36,
"max": [23],
"min": [0],
"type": "SCALAR"
},
{
"bufferView": 8,
"componentType": 5126,
"count": 24,
"max": [0.25, 1.5, 0.125],
"min": [-0.25, 0.75, -0.125],
"type": "VEC3"
},
{
"bufferView": 9,
"componentType": 5126,
"count": 24,
"max": [1, 1, 1],
"min": [-1, -1, -1],
"type": "VEC3"
},
{
"bufferView": 10,
"componentType": 5126,
"count": 24,
"max": [0.624755859375, 0.499755859375],
"min": [0.250244140625, 0.250244140625],
"type": "VEC2"
},
{
"bufferView": 11,
"componentType": 5123,
"count": 36,
"max": [23],
"min": [0],
"type": "SCALAR"
},
{
"bufferView": 12,
"componentType": 5126,
"count": 24,
"max": [0.265625, 1.515625, 0.140625],
"min": [-0.265625, 0.734375, -0.140625],
"type": "VEC3"
},
{
"bufferView": 13,
"componentType": 5126,
"count": 24,
"max": [1, 1, 1],
"min": [-1, -1, -1],
"type": "VEC3"
},
{
"bufferView": 14,
"componentType": 5126,
"count": 24,
"max": [0.624755859375, 0.749755859375],
"min": [0.250244140625, 0.500244140625],
"type": "VEC2"
},
{
"bufferView": 15,
"componentType": 5123,
"count": 36,
"max": [23],
"min": [0],
"type": "SCALAR"
},
{
"bufferView": 16,
"componentType": 5126,
"count": 24,
"max": [0.5, 1.5, 0.125],
"min": [0.25, 0.75, -0.125],
"type": "VEC3"
},
{
"bufferView": 17,
"componentType": 5126,
"count": 24,
"max": [1, 1, 1],
"min": [-1, -1, -1],
"type": "VEC3"
},
{
"bufferView": 18,
"componentType": 5126,
"count": 24,
"max": [0.874755859375, 0.499755859375],
"min": [0.625244140625, 0.250244140625],
"type": "VEC2"
},
{
"bufferView": 19,
"componentType": 5123,
"count": 36,
"max": [23],
"min": [0],
"type": "SCALAR"
},
{
"bufferView": 20,
"componentType": 5126,
"count": 24,
"max": [0.515625, 1.515625, 0.140625],
"min": [0.234375, 0.734375, -0.140625],
"type": "VEC3"
},
{
"bufferView": 21,
"componentType": 5126,
"count": 24,
"max": [1, 1, 1],
"min": [-1, -1, -1],
"type": "VEC3"
},
{
"bufferView": 22,
"componentType": 5126,
"count": 24,
"max": [0.874755859375, 0.749755859375],
"min": [0.625244140625, 0.500244140625],
"type": "VEC2"
},
{
"bufferView": 23,
"componentType": 5123,
"count": 36,
"max": [23],
"min": [0],
"type": "SCALAR"
},
{
"bufferView": 24,
"componentType": 5126,
"count": 24,
"max": [-0.25, 1.5, 0.125],
"min": [-0.5, 0.75, -0.125],
"type": "VEC3"
},
{
"bufferView": 25,
"componentType": 5126,
"count": 24,
"max": [1, 1, 1],
"min": [-1, -1, -1],
"type": "VEC3"
},
{
"bufferView": 26,
"componentType": 5126,
"count": 24,
"max": [0.749755859375, 0.999755859375],
"min": [0.500244140625, 0.750244140625],
"type": "VEC2"
},
{
"bufferView": 27,
"componentType": 5123,
"count": 36,
"max": [23],
"min": [0],
"type": "SCALAR"
},
{
"bufferView": 28,
"componentType": 5126,
"count": 24,
"max": [-0.234375, 1.515625, 0.140625],
"min": [-0.515625, 0.734375, -0.140625],
"type": "VEC3"
},
{
"bufferView": 29,
"componentType": 5126,
"count": 24,
"max": [1, 1, 1],
"min": [-1, -1, -1],
"type": "VEC3"
},
{
"bufferView": 30,
"componentType": 5126,
"count": 24,
"max": [0.999755859375, 0.999755859375],
"min": [0.750244140625, 0.750244140625],
"type": "VEC2"
},
{
"bufferView": 31,
"componentType": 5123,
"count": 36,
"max": [23],
"min": [0],
"type": "SCALAR"
},
{
"bufferView": 32,
"componentType": 5126,
"count": 24,
"max": [0.24375000596046448, 0.75, 0.125],
"min": [-0.0062500000931322575, 0, -0.125],
"type": "VEC3"
},
{
"bufferView": 33,
"componentType": 5126,
"count": 24,
"max": [1, 1, 1],
"min": [-1, -1, -1],
"type": "VEC3"
},
{
"bufferView": 34,
"componentType": 5126,
"count": 24,
"max": [0.249755859375, 0.499755859375],
"min": [0.000244140625, 0.250244140625],
"type": "VEC2"
},
{
"bufferView": 35,
"componentType": 5123,
"count": 36,
"max": [23],
"min": [0],
"type": "SCALAR"
},
{
"bufferView": 36,
"componentType": 5126,
"count": 24,
"max": [0.2593750059604645, 0.765625, 0.140625],
"min": [-0.02187499962747097, -0.015625, -0.140625],
"type": "VEC3"
},
{
"bufferView": 37,
"componentType": 5126,
"count": 24,
"max": [1, 1, 1],
"min": [-1, -1, -1],
"type": "VEC3"
},
{
"bufferView": 38,
"componentType": 5126,
"count": 24,
"max": [0.249755859375, 0.749755859375],
"min": [0.000244140625, 0.500244140625],
"type": "VEC2"
},
{
"bufferView": 39,
"componentType": 5123,
"count": 36,
"max": [23],
"min": [0],
"type": "SCALAR"
},
{
"bufferView": 40,
"componentType": 5126,
"count": 24,
"max": [0.0062500000931322575, 0.75, 0.125],
"min": [-0.24375000596046448, 0, -0.125],
"type": "VEC3"
},
{
"bufferView": 41,
"componentType": 5126,
"count": 24,
"max": [1, 1, 1],
"min": [-1, -1, -1],
"type": "VEC3"
},
{
"bufferView": 42,
"componentType": 5126,
"count": 24,
"max": [0.499755859375, 0.999755859375],
"min": [0.250244140625, 0.750244140625],
"type": "VEC2"
},
{
"bufferView": 43,
"componentType": 5123,
"count": 36,
"max": [23],
"min": [0],
"type": "SCALAR"
},
{
"bufferView": 44,
"componentType": 5126,
"count": 24,
"max": [0.02187499962747097, 0.765625, 0.140625],
"min": [-0.2593750059604645, -0.015625, -0.140625],
"type": "VEC3"
},
{
"bufferView": 45,
"componentType": 5126,
"count": 24,
"max": [1, 1, 1],
"min": [-1, -1, -1],
"type": "VEC3"
},
{
"bufferView": 46,
"componentType": 5126,
"count": 24,
"max": [0.249755859375, 0.999755859375],
"min": [0.000244140625, 0.750244140625],
"type": "VEC2"
},
{
"bufferView": 47,
"componentType": 5123,
"count": 36,
"max": [23],
"min": [0],
"type": "SCALAR"
}
],
"materials": [
{
"pbrMetallicRoughness": {
"metallicFactor": 0,
"roughnessFactor": 1,
"baseColorTexture": { "index": 0 }
},
"alphaMode": "MASK",
"alphaCutoff": 0.05,
"doubleSided": true
}
],
"textures": [{ "sampler": 0, "source": 0 }],
"samplers": [{ "magFilter": 9728, "minFilter": 9728, "wrapS": 33071, "wrapT": 33071 }],
"images": [
{
"mimeType": "image/png",
"uri": "data:image/png;base64,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"
}
],
"meshes": [
{
"primitives": [
{
"mode": 4,
"attributes": { "POSITION": 0, "NORMAL": 1, "TEXCOORD_0": 2 },
"indices": 3,
"material": 0
}
]
},
{
"primitives": [
{
"mode": 4,
"attributes": { "POSITION": 4, "NORMAL": 5, "TEXCOORD_0": 6 },
"indices": 7,
"material": 0
}
]
},
{
"primitives": [
{
"mode": 4,
"attributes": { "POSITION": 8, "NORMAL": 9, "TEXCOORD_0": 10 },
"indices": 11,
"material": 0
}
]
},
{
"primitives": [
{
"mode": 4,
"attributes": { "POSITION": 12, "NORMAL": 13, "TEXCOORD_0": 14 },
"indices": 15,
"material": 0
}
]
},
{
"primitives": [
{
"mode": 4,
"attributes": { "POSITION": 16, "NORMAL": 17, "TEXCOORD_0": 18 },
"indices": 19,
"material": 0
}
]
},
{
"primitives": [
{
"mode": 4,
"attributes": { "POSITION": 20, "NORMAL": 21, "TEXCOORD_0": 22 },
"indices": 23,
"material": 0
}
]
},
{
"primitives": [
{
"mode": 4,
"attributes": { "POSITION": 24, "NORMAL": 25, "TEXCOORD_0": 26 },
"indices": 27,
"material": 0
}
]
},
{
"primitives": [
{
"mode": 4,
"attributes": { "POSITION": 28, "NORMAL": 29, "TEXCOORD_0": 30 },
"indices": 31,
"material": 0
}
]
},
{
"primitives": [
{
"mode": 4,
"attributes": { "POSITION": 32, "NORMAL": 33, "TEXCOORD_0": 34 },
"indices": 35,
"material": 0
}
]
},
{
"primitives": [
{
"mode": 4,
"attributes": { "POSITION": 36, "NORMAL": 37, "TEXCOORD_0": 38 },
"indices": 39,
"material": 0
}
]
},
{
"primitives": [
{
"mode": 4,
"attributes": { "POSITION": 40, "NORMAL": 41, "TEXCOORD_0": 42 },
"indices": 43,
"material": 0
}
]
},
{
"primitives": [
{
"mode": 4,
"attributes": { "POSITION": 44, "NORMAL": 45, "TEXCOORD_0": 46 },
"indices": 47,
"material": 0
}
]
}
]
}
@@ -1 +1,641 @@
{"asset":{"version":"2.0","generator":"Blockbench 4.12.4 glTF exporter"},"scenes":[{"nodes":[18],"name":"blockbench_export"}],"scene":0,"nodes":[{"translation":[0,-1.5,0],"name":"Head","mesh":0},{"translation":[0,-1.5,0],"name":"Hat Layer","mesh":1},{"rotation":[0.05228614400929896,-0.043559608510925024,0.002282862348496242,0.997679060715675],"translation":[0,1.5,0],"name":"Head","children":[0,1]},{"translation":[0,-1.5,0],"name":"Body","mesh":2},{"translation":[0,-1.5,0],"name":"Body Layer","mesh":3},{"translation":[0,1.5,0],"name":"Body","children":[3,4]},{"translation":[-0.3125,-1.375,0],"name":"Right Arm","mesh":4},{"translation":[-0.3125,-1.375,0],"name":"Right Arm Layer","mesh":5},{"rotation":[0.08715574274765817,0,0,0.9961946980917455],"translation":[0.3125,1.375,0],"name":"Right Arm","children":[6,7]},{"translation":[0.3125,-1.375,0],"name":"Left Arm","mesh":6},{"translation":[0.3125,-1.375,0],"name":"Left Arm Layer","mesh":7},{"rotation":[-0.10452846326765346,0,0,0.9945218953682733],"translation":[-0.3125,1.375,0],"name":"Left Arm","children":[9,10]},{"translation":[-0.11875,-0.75,0],"name":"Right Leg","mesh":8},{"translation":[-0.11875,-0.75,0],"name":"Right Leg Layer","mesh":9},{"rotation":[-0.09583115474787583,-0.0016727390282702394,0.01737205902003089,0.9952445947048578],"translation":[0.11875,0.75,0],"name":"Right Leg","children":[12,13]},{"translation":[0.11875,-0.75,0],"name":"Left Leg","mesh":10},{"translation":[0.11875,-0.75,0],"name":"Left Leg Layer","mesh":11},{"rotation":[0.08714246850588939,-0.0015210774457754552,-0.017385994761764084,0.9960429728140489],"translation":[-0.11875,0.75,0],"name":"Left Leg","children":[15,16]},{"children":[2,5,8,11,14,17]}],"bufferViews":[{"buffer":0,"byteOffset":0,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":288,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":576,"byteLength":192,"target":34962,"byteStride":8},{"buffer":0,"byteOffset":768,"byteLength":72,"target":34963},{"buffer":0,"byteOffset":840,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":1128,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":1416,"byteLength":192,"target":34962,"byteStride":8},{"buffer":0,"byteOffset":1608,"byteLength":72,"target":34963},{"buffer":0,"byteOffset":1680,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":1968,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":2256,"byteLength":192,"target":34962,"byteStride":8},{"buffer":0,"byteOffset":2448,"byteLength":72,"target":34963},{"buffer":0,"byteOffset":2520,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":2808,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":3096,"byteLength":192,"target":34962,"byteStride":8},{"buffer":0,"byteOffset":3288,"byteLength":72,"target":34963},{"buffer":0,"byteOffset":3360,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":3648,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":3936,"byteLength":192,"target":34962,"byteStride":8},{"buffer":0,"byteOffset":4128,"byteLength":72,"target":34963},{"buffer":0,"byteOffset":4200,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":4488,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":4776,"byteLength":192,"target":34962,"byteStride":8},{"buffer":0,"byteOffset":4968,"byteLength":72,"target":34963},{"buffer":0,"byteOffset":5040,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":5328,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":5616,"byteLength":192,"target":34962,"byteStride":8},{"buffer":0,"byteOffset":5808,"byteLength":72,"target":34963},{"buffer":0,"byteOffset":5880,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":6168,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":6456,"byteLength":192,"target":34962,"byteStride":8},{"buffer":0,"byteOffset":6648,"byteLength":72,"target":34963},{"buffer":0,"byteOffset":6720,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":7008,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":7296,"byteLength":192,"target":34962,"byteStride":8},{"buffer":0,"byteOffset":7488,"byteLength":72,"target":34963},{"buffer":0,"byteOffset":7560,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":7848,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":8136,"byteLength":192,"target":34962,"byteStride":8},{"buffer":0,"byteOffset":8328,"byteLength":72,"target":34963},{"buffer":0,"byteOffset":8400,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":8688,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":8976,"byteLength":192,"target":34962,"byteStride":8},{"buffer":0,"byteOffset":9168,"byteLength":72,"target":34963},{"buffer"Line truncated
{
"asset": { "version": "2.0", "generator": "Blockbench 4.12.4 glTF exporter" },
"scenes": [{ "nodes": [18], "name": "blockbench_export" }],
"scene": 0,
"nodes": [
{ "translation": [0, -1.5, 0], "name": "Head", "mesh": 0 },
{ "translation": [0, -1.5, 0], "name": "Hat Layer", "mesh": 1 },
{
"rotation": [
0.05228614400929896, -0.043559608510925024, 0.002282862348496242, 0.997679060715675
],
"translation": [0, 1.5, 0],
"name": "Head",
"children": [0, 1]
},
{ "translation": [0, -1.5, 0], "name": "Body", "mesh": 2 },
{ "translation": [0, -1.5, 0], "name": "Body Layer", "mesh": 3 },
{ "translation": [0, 1.5, 0], "name": "Body", "children": [3, 4] },
{ "translation": [-0.3125, -1.375, 0], "name": "Right Arm", "mesh": 4 },
{ "translation": [-0.3125, -1.375, 0], "name": "Right Arm Layer", "mesh": 5 },
{
"rotation": [0.08715574274765817, 0, 0, 0.9961946980917455],
"translation": [0.3125, 1.375, 0],
"name": "Right Arm",
"children": [6, 7]
},
{ "translation": [0.3125, -1.375, 0], "name": "Left Arm", "mesh": 6 },
{ "translation": [0.3125, -1.375, 0], "name": "Left Arm Layer", "mesh": 7 },
{
"rotation": [-0.10452846326765346, 0, 0, 0.9945218953682733],
"translation": [-0.3125, 1.375, 0],
"name": "Left Arm",
"children": [9, 10]
},
{ "translation": [-0.11875, -0.75, 0], "name": "Right Leg", "mesh": 8 },
{ "translation": [-0.11875, -0.75, 0], "name": "Right Leg Layer", "mesh": 9 },
{
"rotation": [
-0.09583115474787583, -0.0016727390282702394, 0.01737205902003089, 0.9952445947048578
],
"translation": [0.11875, 0.75, 0],
"name": "Right Leg",
"children": [12, 13]
},
{ "translation": [0.11875, -0.75, 0], "name": "Left Leg", "mesh": 10 },
{ "translation": [0.11875, -0.75, 0], "name": "Left Leg Layer", "mesh": 11 },
{
"rotation": [
0.08714246850588939, -0.0015210774457754552, -0.017385994761764084, 0.9960429728140489
],
"translation": [-0.11875, 0.75, 0],
"name": "Left Leg",
"children": [15, 16]
},
{ "children": [2, 5, 8, 11, 14, 17] }
],
"bufferViews": [
{ "buffer": 0, "byteOffset": 0, "byteLength": 288, "target": 34962, "byteStride": 12 },
{ "buffer": 0, "byteOffset": 288, "byteLength": 288, "target": 34962, "byteStride": 12 },
{ "buffer": 0, "byteOffset": 576, "byteLength": 192, "target": 34962, "byteStride": 8 },
{ "buffer": 0, "byteOffset": 768, "byteLength": 72, "target": 34963 },
{ "buffer": 0, "byteOffset": 840, "byteLength": 288, "target": 34962, "byteStride": 12 },
{ "buffer": 0, "byteOffset": 1128, "byteLength": 288, "target": 34962, "byteStride": 12 },
{ "buffer": 0, "byteOffset": 1416, "byteLength": 192, "target": 34962, "byteStride": 8 },
{ "buffer": 0, "byteOffset": 1608, "byteLength": 72, "target": 34963 },
{ "buffer": 0, "byteOffset": 1680, "byteLength": 288, "target": 34962, "byteStride": 12 },
{ "buffer": 0, "byteOffset": 1968, "byteLength": 288, "target": 34962, "byteStride": 12 },
{ "buffer": 0, "byteOffset": 2256, "byteLength": 192, "target": 34962, "byteStride": 8 },
{ "buffer": 0, "byteOffset": 2448, "byteLength": 72, "target": 34963 },
{ "buffer": 0, "byteOffset": 2520, "byteLength": 288, "target": 34962, "byteStride": 12 },
{ "buffer": 0, "byteOffset": 2808, "byteLength": 288, "target": 34962, "byteStride": 12 },
{ "buffer": 0, "byteOffset": 3096, "byteLength": 192, "target": 34962, "byteStride": 8 },
{ "buffer": 0, "byteOffset": 3288, "byteLength": 72, "target": 34963 },
{ "buffer": 0, "byteOffset": 3360, "byteLength": 288, "target": 34962, "byteStride": 12 },
{ "buffer": 0, "byteOffset": 3648, "byteLength": 288, "target": 34962, "byteStride": 12 },
{ "buffer": 0, "byteOffset": 3936, "byteLength": 192, "target": 34962, "byteStride": 8 },
{ "buffer": 0, "byteOffset": 4128, "byteLength": 72, "target": 34963 },
{ "buffer": 0, "byteOffset": 4200, "byteLength": 288, "target": 34962, "byteStride": 12 },
{ "buffer": 0, "byteOffset": 4488, "byteLength": 288, "target": 34962, "byteStride": 12 },
{ "buffer": 0, "byteOffset": 4776, "byteLength": 192, "target": 34962, "byteStride": 8 },
{ "buffer": 0, "byteOffset": 4968, "byteLength": 72, "target": 34963 },
{ "buffer": 0, "byteOffset": 5040, "byteLength": 288, "target": 34962, "byteStride": 12 },
{ "buffer": 0, "byteOffset": 5328, "byteLength": 288, "target": 34962, "byteStride": 12 },
{ "buffer": 0, "byteOffset": 5616, "byteLength": 192, "target": 34962, "byteStride": 8 },
{ "buffer": 0, "byteOffset": 5808, "byteLength": 72, "target": 34963 },
{ "buffer": 0, "byteOffset": 5880, "byteLength": 288, "target": 34962, "byteStride": 12 },
{ "buffer": 0, "byteOffset": 6168, "byteLength": 288, "target": 34962, "byteStride": 12 },
{ "buffer": 0, "byteOffset": 6456, "byteLength": 192, "target": 34962, "byteStride": 8 },
{ "buffer": 0, "byteOffset": 6648, "byteLength": 72, "target": 34963 },
{ "buffer": 0, "byteOffset": 6720, "byteLength": 288, "target": 34962, "byteStride": 12 },
{ "buffer": 0, "byteOffset": 7008, "byteLength": 288, "target": 34962, "byteStride": 12 },
{ "buffer": 0, "byteOffset": 7296, "byteLength": 192, "target": 34962, "byteStride": 8 },
{ "buffer": 0, "byteOffset": 7488, "byteLength": 72, "target": 34963 },
{ "buffer": 0, "byteOffset": 7560, "byteLength": 288, "target": 34962, "byteStride": 12 },
{ "buffer": 0, "byteOffset": 7848, "byteLength": 288, "target": 34962, "byteStride": 12 },
{ "buffer": 0, "byteOffset": 8136, "byteLength": 192, "target": 34962, "byteStride": 8 },
{ "buffer": 0, "byteOffset": 8328, "byteLength": 72, "target": 34963 },
{ "buffer": 0, "byteOffset": 8400, "byteLength": 288, "target": 34962, "byteStride": 12 },
{ "buffer": 0, "byteOffset": 8688, "byteLength": 288, "target": 34962, "byteStride": 12 },
{ "buffer": 0, "byteOffset": 8976, "byteLength": 192, "target": 34962, "byteStride": 8 },
{ "buffer": 0, "byteOffset": 9168, "byteLength": 72, "target": 34963 },
{ "buffer": 0, "byteOffset": 9240, "byteLength": 288, "target": 34962, "byteStride": 12 },
{ "buffer": 0, "byteOffset": 9528, "byteLength": 288, "target": 34962, "byteStride": 12 },
{ "buffer": 0, "byteOffset": 9816, "byteLength": 192, "target": 34962, "byteStride": 8 },
{ "buffer": 0, "byteOffset": 10008, "byteLength": 72, "target": 34963 }
],
"buffers": [
{
"byteLength": 10080,
"uri": "data:application/octet-stream;base64,AACAPgAAAEAAAIA+AACAPgAAAEAAAIC+AACAPgAAwD8AAIA+AACAPgAAwD8AAIC+AACAvgAAAEAAAIC+AACAvgAAAEAAAIA+AACAvgAAwD8AAIC+AACAvgAAwD8AAIA+AACAvgAAAEAAAIC+AACAPgAAAEAAAIC+AACAvgAAAEAAAIA+AACAPgAAAEAAAIA+AACAvgAAwD8AAIA+AACAPgAAwD8AAIA+AACAvgAAwD8AAIC+AACAPgAAwD8AAIC+AACAvgAAAEAAAIA+AACAPgAAAEAAAIA+AACAvgAAwD8AAIA+AACAPgAAwD8AAIA+AACAPgAAAEAAAIC+AACAvgAAAEAAAIC+AACAPgAAwD8AAIC+AACAvgAAwD8AAIC+AACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AACAOQBAAD4AgP89AEAAPgAAgDkAwH8+AID/PQDAfz4AIIA+AEAAPgDgvz4AQAA+ACCAPgDAfz4A4L8+AMB/PgDAfz4AgP89AEAAPgCA/z0AwH8+AACAOQBAAD4AAIA5AOC/PgAAgDkAIIA+AACAOQDgvz4AgP89ACCAPgCA/z0AIMA+AEAAPgDg/z4AQAA+ACDAPgDAfz4A4P8+AMB/PgBAAD4AQAA+AMB/PgBAAD4AQAA+AMB/PgDAfz4AwH8+AAACAAEAAgADAAEABAAGAAUABgAHAAUACAAKAAkACgALAAkADAAOAA0ADgAPAA0AEAASABEAEgATABEAFAAWABUAFgAXABUAAACQPgAAAkAAAJA+AACQPgAAAkAAAJC+AACQPgAAvD8AAJA+AACQPgAAvD8AAJC+AACQvgAAAkAAAJC+AACQvgAAAkAAAJA+AACQvgAAvD8AAJC+AACQvgAAvD8AAJA+AACQvgAAAkAAAJC+AACQPgAAAkAAAJC+AACQvgAAAkAAAJA+AACQPgAAAkAAAJA+AACQvgAAvD8AAJA+AACQPgAAvD8AAJA+AACQvgAAvD8AAJC+AACQPgAAvD8AAJC+AACQvgAAAkAAAJA+AACQPgAAAkAAAJA+AACQvgAAvD8AAJA+AACQPgAAvD8AAJA+AACQPgAAAkAAAJC+AACQvgAAAkAAAJC+AACQPgAAvD8AAJC+AACQvgAAvD8AAJC+AACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/ABAAPwBAAD4A8B8/AEAAPgAQAD8AwH8+APAfPwDAfz4AEEA/AEAAPgDwXz8AQAA+ABBAPwDAfz4A8F8/AMB/PgDwPz8AgP89ABAgPwCA/z0A8D8/AACAOQAQID8AAIA5APBfPwAAgDkAEEA/AACAOQDwXz8AgP89ABBAPwCA/z0AEGA/AEAAPgDwfz8AQAA+ABBgPwDAfz4A8H8/AMB/PgAQID8AQAA+APA/PwBAAD4AECA/AMB/PgDwPz8AwH8+AAACAAEAAgADAAEABAAGAAUABgAHAAUACAAKAAkACgALAAkADAAOAA0ADgAPAA0AEAASABEAEgATABEAFAAWABUAFgAXABUAAACAPgAAwD8AAAA+AACAPgAAwD8AAAC+AACAPgAAQD8AAAA+AACAPgAAQD8AAAC+AACAvgAAwD8AAAC+AACAvgAAwD8AAAA+AACAvgAAQD8AAAC+AACAvgAAQD8AAAA+AACAvgAAwD8AAAC+AACAPgAAwD8AAAC+AACAvgAAwD8AAAA+AACAPgAAwD8AAAA+AACAvgAAQD8AAAA+AACAPgAAQD8AAAA+AACAvgAAQD8AAAC+AACAPgAAQD8AAAC+AACAvgAAwD8AAAA+AACAPgAAwD8AAAA+AACAvgAAQD8AAAA+AACAPgAAQD8AAAA+AACAPgAAwD8AAAC+AACAvgAAwD8AAAC+AACAPgAAQD8AAAC+AACAvgAAQD8AAAC+AACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/ACCAPgAgoD4A4J8+ACCgPgAggD4A4P8+AOCfPgDg/z4AIOA+ACCgPgDg/z4AIKA+ACDgPgDg/z4A4P8+AOD/PgDg3z4A4J8+ACCgPgDgnz4A4N8+ACCAPgAgoD4AIIA+APAPPwAggD4AIOA+ACCAPgDwDz8A4J8+ACDgPgDgnz4AEAA/ACCgPgDwHz8AIKA+ABAAPwDg/z4A8B8/AOD/PgAgoD4AIKA+AODfPgAgoD4AIKA+AOD/PgDg3z4A4P8+AAACAAEAAgADAAEABAAGAAUABgAHAAUACAAKAAkACgALAAkADAAOAA0ADgAPAA0AEAASABEAEgATABEAFAAWABUAFgAXABUAAACIPgAAwj8AABA+AACIPgAAwj8AABC+AACIPgAAPD8AABA+AACIPgAAPD8AABC+AACIvgAAwj8AABC+AACIvgAAwj8AABA+AACIvgAAPD8AABC+AACIvgAAPD8AABA+AACIvgAAwj8AABC+AACIPgAAwj8AABC+AACIvgAAwj8AABA+AACIPgAAwj8AABA+AACIvgAAPD8AABA+AACIPgAAPD8AABA+AACIvgAAPD8AABC+AACIPgAAPD8AABC+AACIvgAAwj8AABA+AACIPgAAwj8AABA+AACIvgAAPD8AABA+AACIPgAAPD8AABA+AACIPgAAwj8AABC+AACIvgAAwj8AABC+AACIPgAAPD8AABC+AACIvgAAPD8AABC+AACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/ACCAPgAQED8A4J8+ABAQPwAggD4A8D8/AOCfPgDwPz8AIOA+ABAQPwDg/z4AEBA/ACDgPgDwPz8A4P8+APA/PwDg3z4A8A8/ACCgPgDwDz8A4N8+ABAAPwAgoD4AEAA/APAPPwAQAD8AIOA+ABAAPwDwDz8A8A8/ACDgPgDwDz8AEAA/ABAQPwDwHz8AEBA/ABAAPwDwPz8A8B8/APA/PwAgoD4AEBA/AODfPgAQED8AIKA+APA/PwDg3z4A8D8/AAACAAEAAgADAAEABAAGAAUABgAHAAUACAAKAAkACgALAAkADAAOAA0ADgAPAA0AEAASABEAEgATABEAFAAWABUAFgAXABUAAADgPgAAwD8AAAA+AADgPgAAwD8AAAC+AADgPgAAQD8AAAA+AADgPgAAQD8AAAC+AACAPgAAwD8AAAC+AACAPgAAwD8AAAA+AACAPgAAQD8AAAC+AACAPgAAQD8AAAA+AACAPgAAwD8AAAC+AADgPgAAwD8AAAC+AACAPgAAwD8AAAA+AADgPgAAwD8AAAA+AACAPgAAQD8AAAA+AADgPgAAQD8AAAA+AACAPgAAQD8AAAC+AADgPgAAQD8AAAC+AACAPgAAwD8AAAA+AADgPgAAwD8AAAA+AACAPgAAQD8AAAA+AADgPgAAQD8AAAA+AADgPgAAwD8AAAC+AACAPgAAwD8AAAC+AADgPgAAQD8AAAC+AACAPgAAQD8AAAC+AACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAvwAAAAAAAAAAAACALine truncated
}
],
"accessors": [
{
"bufferView": 0,
"componentType": 5126,
"count": 24,
"max": [0.25, 2, 0.25],
"min": [-0.25, 1.5, -0.25],
"type": "VEC3"
},
{
"bufferView": 1,
"componentType": 5126,
"count": 24,
"max": [1, 1, 1],
"min": [-1, -1, -1],
"type": "VEC3"
},
{
"bufferView": 2,
"componentType": 5126,
"count": 24,
"max": [0.499755859375, 0.249755859375],
"min": [0.000244140625, 0.000244140625],
"type": "VEC2"
},
{
"bufferView": 3,
"componentType": 5123,
"count": 36,
"max": [23],
"min": [0],
"type": "SCALAR"
},
{
"bufferView": 4,
"componentType": 5126,
"count": 24,
"max": [0.28125, 2.03125, 0.28125],
"min": [-0.28125, 1.46875, -0.28125],
"type": "VEC3"
},
{
"bufferView": 5,
"componentType": 5126,
"count": 24,
"max": [1, 1, 1],
"min": [-1, -1, -1],
"type": "VEC3"
},
{
"bufferView": 6,
"componentType": 5126,
"count": 24,
"max": [0.999755859375, 0.249755859375],
"min": [0.500244140625, 0.000244140625],
"type": "VEC2"
},
{
"bufferView": 7,
"componentType": 5123,
"count": 36,
"max": [23],
"min": [0],
"type": "SCALAR"
},
{
"bufferView": 8,
"componentType": 5126,
"count": 24,
"max": [0.25, 1.5, 0.125],
"min": [-0.25, 0.75, -0.125],
"type": "VEC3"
},
{
"bufferView": 9,
"componentType": 5126,
"count": 24,
"max": [1, 1, 1],
"min": [-1, -1, -1],
"type": "VEC3"
},
{
"bufferView": 10,
"componentType": 5126,
"count": 24,
"max": [0.624755859375, 0.499755859375],
"min": [0.250244140625, 0.250244140625],
"type": "VEC2"
},
{
"bufferView": 11,
"componentType": 5123,
"count": 36,
"max": [23],
"min": [0],
"type": "SCALAR"
},
{
"bufferView": 12,
"componentType": 5126,
"count": 24,
"max": [0.265625, 1.515625, 0.140625],
"min": [-0.265625, 0.734375, -0.140625],
"type": "VEC3"
},
{
"bufferView": 13,
"componentType": 5126,
"count": 24,
"max": [1, 1, 1],
"min": [-1, -1, -1],
"type": "VEC3"
},
{
"bufferView": 14,
"componentType": 5126,
"count": 24,
"max": [0.624755859375, 0.749755859375],
"min": [0.250244140625, 0.500244140625],
"type": "VEC2"
},
{
"bufferView": 15,
"componentType": 5123,
"count": 36,
"max": [23],
"min": [0],
"type": "SCALAR"
},
{
"bufferView": 16,
"componentType": 5126,
"count": 24,
"max": [0.4375, 1.5, 0.125],
"min": [0.25, 0.75, -0.125],
"type": "VEC3"
},
{
"bufferView": 17,
"componentType": 5126,
"count": 24,
"max": [1, 1, 1],
"min": [-1, -1, -1],
"type": "VEC3"
},
{
"bufferView": 18,
"componentType": 5126,
"count": 24,
"max": [0.843505859375, 0.499755859375],
"min": [0.625244140625, 0.250244140625],
"type": "VEC2"
},
{
"bufferView": 19,
"componentType": 5123,
"count": 36,
"max": [23],
"min": [0],
"type": "SCALAR"
},
{
"bufferView": 20,
"componentType": 5126,
"count": 24,
"max": [0.453125, 1.515625, 0.140625],
"min": [0.234375, 0.734375, -0.140625],
"type": "VEC3"
},
{
"bufferView": 21,
"componentType": 5126,
"count": 24,
"max": [1, 1, 1],
"min": [-1, -1, -1],
"type": "VEC3"
},
{
"bufferView": 22,
"componentType": 5126,
"count": 24,
"max": [0.843505859375, 0.749755859375],
"min": [0.625244140625, 0.500244140625],
"type": "VEC2"
},
{
"bufferView": 23,
"componentType": 5123,
"count": 36,
"max": [23],
"min": [0],
"type": "SCALAR"
},
{
"bufferView": 24,
"componentType": 5126,
"count": 24,
"max": [-0.25, 1.5, 0.125],
"min": [-0.4375, 0.75, -0.125],
"type": "VEC3"
},
{
"bufferView": 25,
"componentType": 5126,
"count": 24,
"max": [1, 1, 1],
"min": [-1, -1, -1],
"type": "VEC3"
},
{
"bufferView": 26,
"componentType": 5126,
"count": 24,
"max": [0.718505859375, 0.999755859375],
"min": [0.500244140625, 0.750244140625],
"type": "VEC2"
},
{
"bufferView": 27,
"componentType": 5123,
"count": 36,
"max": [23],
"min": [0],
"type": "SCALAR"
},
{
"bufferView": 28,
"componentType": 5126,
"count": 24,
"max": [-0.234375, 1.515625, 0.140625],
"min": [-0.453125, 0.734375, -0.140625],
"type": "VEC3"
},
{
"bufferView": 29,
"componentType": 5126,
"count": 24,
"max": [1, 1, 1],
"min": [-1, -1, -1],
"type": "VEC3"
},
{
"bufferView": 30,
"componentType": 5126,
"count": 24,
"max": [0.968505859375, 0.999755859375],
"min": [0.750244140625, 0.750244140625],
"type": "VEC2"
},
{
"bufferView": 31,
"componentType": 5123,
"count": 36,
"max": [23],
"min": [0],
"type": "SCALAR"
},
{
"bufferView": 32,
"componentType": 5126,
"count": 24,
"max": [0.24375000596046448, 0.75, 0.125],
"min": [-0.0062500000931322575, 0, -0.125],
"type": "VEC3"
},
{
"bufferView": 33,
"componentType": 5126,
"count": 24,
"max": [1, 1, 1],
"min": [-1, -1, -1],
"type": "VEC3"
},
{
"bufferView": 34,
"componentType": 5126,
"count": 24,
"max": [0.249755859375, 0.499755859375],
"min": [0.000244140625, 0.250244140625],
"type": "VEC2"
},
{
"bufferView": 35,
"componentType": 5123,
"count": 36,
"max": [23],
"min": [0],
"type": "SCALAR"
},
{
"bufferView": 36,
"componentType": 5126,
"count": 24,
"max": [0.2593750059604645, 0.765625, 0.140625],
"min": [-0.02187499962747097, -0.015625, -0.140625],
"type": "VEC3"
},
{
"bufferView": 37,
"componentType": 5126,
"count": 24,
"max": [1, 1, 1],
"min": [-1, -1, -1],
"type": "VEC3"
},
{
"bufferView": 38,
"componentType": 5126,
"count": 24,
"max": [0.249755859375, 0.749755859375],
"min": [0.000244140625, 0.500244140625],
"type": "VEC2"
},
{
"bufferView": 39,
"componentType": 5123,
"count": 36,
"max": [23],
"min": [0],
"type": "SCALAR"
},
{
"bufferView": 40,
"componentType": 5126,
"count": 24,
"max": [0.0062500000931322575, 0.75, 0.125],
"min": [-0.24375000596046448, 0, -0.125],
"type": "VEC3"
},
{
"bufferView": 41,
"componentType": 5126,
"count": 24,
"max": [1, 1, 1],
"min": [-1, -1, -1],
"type": "VEC3"
},
{
"bufferView": 42,
"componentType": 5126,
"count": 24,
"max": [0.499755859375, 0.999755859375],
"min": [0.250244140625, 0.750244140625],
"type": "VEC2"
},
{
"bufferView": 43,
"componentType": 5123,
"count": 36,
"max": [23],
"min": [0],
"type": "SCALAR"
},
{
"bufferView": 44,
"componentType": 5126,
"count": 24,
"max": [0.02187499962747097, 0.765625, 0.140625],
"min": [-0.2593750059604645, -0.015625, -0.140625],
"type": "VEC3"
},
{
"bufferView": 45,
"componentType": 5126,
"count": 24,
"max": [1, 1, 1],
"min": [-1, -1, -1],
"type": "VEC3"
},
{
"bufferView": 46,
"componentType": 5126,
"count": 24,
"max": [0.249755859375, 0.999755859375],
"min": [0.000244140625, 0.750244140625],
"type": "VEC2"
},
{
"bufferView": 47,
"componentType": 5123,
"count": 36,
"max": [23],
"min": [0],
"type": "SCALAR"
}
],
"materials": [
{
"pbrMetallicRoughness": {
"metallicFactor": 0,
"roughnessFactor": 1,
"baseColorTexture": { "index": 0 }
},
"alphaMode": "MASK",
"alphaCutoff": 0.05,
"doubleSided": true
}
],
"textures": [{ "sampler": 0, "source": 0 }],
"samplers": [{ "magFilter": 9728, "minFilter": 9728, "wrapS": 33071, "wrapT": 33071 }],
"images": [
{
"mimeType": "image/png",
"uri": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAAXNSR0IArs4c6QAACklJREFUeF7tW2+IXFcVP7Pb3ZmdZLPTzaYhiZGubtxI6X5Iol/S0gZFQtS0UqMgKWKKLcVGbcCi3YK02FYU0kQRsdCA1C8ag7ZgiKLQpg2IpvmwUEgaKwaaf83sZHY3mT+73X3yu++dt+edue/dNzMbs4m9EObt/XPuvb/zO+eee95Lhhxl5/PbvcLyZVQen4z05LpqtZIo4dAzf8245khqf2jflz1uf+m7vzeybHWtzuFc3GMv7vTqtRmqXq0SNo0CMHqW9FA210Xn37tAPT156/wAp10AWt1Y2nFOAMAAFgYAGAyuq9bmGbB8+XJTPT4+Hs5/6On2GJB2I632SwUANl6t16jD6wzngfbBhNLFUnRuSAwhIzq8703nHK0ufiHGORcHBoDutgKzKL0vABAbp0Dy4RducADYBwAAaB0mIEupOE/3/gHfBGTdDe8DtBOUDhHPj64for6B9TRRPEnZ/G0GgHrl/bBuw+eedbJsIajcqgzn4r75s68aYoPubAp8IkgA0KdW8c0hl+83vwBl0QOw88fbvUL/MiqXJqknH2/r2JAEQP4t0QeilUqVjMzxScoH/gN1+UC+fJ6dmyU+31vVYtw4GS+gjy2OyAAANGJx0oex0Feffc08/ukPT9Iv//GGeX7003fT57/0nHnePnpvZH6mFDYJgS4AXvz2b50sXGhgIgoDAKwZNJiFyyJQyfZ0+zZenZ7voZavZdlky7rrDsC2PXeZLfbf5tst02BqYj70nal9QGs+tsb4Aab+2X+fpa7cLSEQvX1+lGhKhiLH40duX2OqGVwG4L3/nKXDe+3HJK8rrp2n2va4v/5Wj9vMAz/8rNcQynpEP7j7M2YOODQ4s6cOvx4hxo+23WM8PTu+59/4W7h57sj3hKRQGYDrdsQWzW4IQIRKDBaQZn4DAC8YC6lW/ND2J/d/PdwwNgkgpJfnOu70xB9/7bMj798LjJzAPFwAyPlb2bxkA0DQF7Sk+TNMNbP43pwxgepUjX7+4CPWYw39oHkUCcjul3/lj8/443XR2gkjSOFjMB5jpfbffnO/d8dd37E6St0GFrCMtPNHGGAGBQD89IEdodb5XNfnvGTG9w4dDAFo2H0gN6yX21FHjw0AzP/xDQ9GQHj3xMse5pfgMADW+Ymo0F8wTeVS2boUU8nHIvfIZn3Pj1KvT9Nvvv9q4rElx/NYjNNFymXZ+HXJx9ne0dFJ1eC0yua6qV6bl+8ar9fRsJlrDYDeuF7QS4/7SY+4AgDkhkMAwKSMG8CWAJgqXzHjunu6nRo68ZenbPFUOO8v3j6ZtD9adABMV6fNxlHw/LunjyRqyAXA3hNjRlY7JmBlQABr0yagKZ+onhSNezaMUN/AME0UT0V6cx0DYBXF3OGkSsYHqrPTT8TMzs4amksAGuSoyNV1z8g89MJ80pGF2ZxWnBPTfRkA9J8ovmOG9Q18wvwCFBsAzIaOYKNz2GjgdG0A4KSKXWMAAIftLQHAk8cpXJ8Msp8EoFYpmqZcfiAVABFNX28AkkBI8uTfumO9MQEUGwBJTlADwMA2YwJYmzERmE+u23nVzjwcJDykFo2tBRpIYgEWxn25X9MAiCTqQgBg1hEciTcGACkcq2ZAGh9wXRngO77hiAnwqeCKA2x4tAJAaid4rUwA9s/Oj58BggYA3jzOp3BbUwAEJnBTAYA9hf7GFQc06wNscYArHnDF80/ec5+hv2bAc6+/ksLiG7s0xQARTKVygjYAZOxvW3ESAEzbPZ/aHAFg7z+PmeDFNtZWL+uaAqBZE9AAYPMy9udnCYQLAPSNi/V1PTaHXKGtv6mz3DwSQ2Gx0FQM0BretWuXNzU1RfxveHg4fEbdsWPH2kpja/mYv7e3N/x34MCBRPl6fLvraZjsQwA+ZMD/mQls3rzZgw2yza9evdo8o/Av2yj+xvO6devo0qVLtGLFCrpw4ULoRtB+7tw5GhsbM6b1Lt3qVcijO6ls/h4ZGfHgU7hI+Ty/9Ak8n+x/9epVmpmZoUqlYta3adOmiLxTp05FfMqRI8kJnMzWrVsjAMjN2gDAbAwSA8e/aMMCGICTdKv3L5qlL9BkBADZnzccB4BsxzMA1wBIecePH28OgB07djQFAGtFbl4yCAxAH4Dwdyp4S4gMA6B99AMDZP80gMv+GoAtW7ZE5C0qAP5My7wRuoVWUenmBUBTFAxg/wEWvEUF7xsjHzVaYvORlHUxgBnH5lir1ahcLodmIBnFJijjioMHDybGFZl2TcBmwzYnqgMe6XQlxbUTlADguaurKxYAdsJNAaCdIBycXJC2eb1AGUnyxuUJwu3MAP7lPi4GaPkAAIVZsHbt2sgpINcL2a7IMqOPQe2kQGl9DOpFa0onMUBTuplTAGMHBwdpYmIiBKBQKIQK06CmAoC9M4T39/fjrKbz588bqp05c8ac60kAaA2BQUkMsLEkyQQ0YxgAZsGSJThn/KK1j7H79+9P9gEbN270cK7mcjmT4ERwIzUYB4DUnGQAX54kCJL+HKjIOXRcIGUfPXqUisUiLV261CRFoJiLFy+a9XZ0dBhniPFYe71ep3w+b9Y/NzdnQBkaGkoGIJfLeRAEgfiHCA+/EASPy4KkpuUzGCMLR3pS07wh/AIAqbE4uVzPQZWrX6vtmd27d3vT09MGwStXrlBfX59BFs/ZbDakPycl8CE0kEYfaGNsbMz84m+Ep9AIp68gCwCyxtCPNQQZaNf0LZVKZk7MjT7tXnddwDTQg50i272OrV1e1fauUSY7XG9/eTwnQ/SLUNerLr1+13oXLQDI/SOzawAInqHNGxIAvFY3fqCw1Pn+P2TQzQJAs98XxJkA8nvXhAE6EJIeG35AH4NDQ0PmlIDDw4kxcO/8N0Quh9NUu6C9GSfS3dIv1N/KRhyp9lk6juDjmUPxhnwAAxB3ZUWwxHGDC4A02eM4UNgJdnYEH0fMzYYvPTUAMo7Q12EZxOnNA4SGy5ALAG5nBOMY4Hp5AjlJH2KkBaD7nYHEfIDtbsNrv2YApNl8IgDiKw8wAH/OCQaYscGncYsaAA6eNM39sLXx28GwnwUAtJlPZ4KDmwGAD5AmoH2AZKwMukIfoPMBC2ECzIB2AOC3u1gPPoyUAMT5AFs+QJusvurHJkW5Y9xlKMkHLAgAOPYCbbsA0JqVCRF9++SEbsgAW1pcek5JKQzSTsXmBP+XABRfm07MB7ACGYgGAGQ+gDfId3pQ+PTp0+GV0wbA4Bf9/yony0IAAHlsBpoB0gkCAMkAqX0869sn3iNEToHBwcEwLS7tn589zzMJEhTc5JCBkXf5ka/dHgtAQ4OqSPrWz0R+MSYgAXjmK/vMbRQ3RzhXbBq5A6x55cqVRnmoRxZp1apVJrfAvgm30Uxvb2/k216OnHBFxiBEfUnlvtEtDc0y9k8amxYAdoS2U6DZT2P1ejKjo6MeI3L58mWanJwMN41wF+gi7YQkJO7ouN/LfMHsJy9HZOrYHxeguOL6IpXjfz2+nc/jtaz/Apk7Nu+SlQ41AAAAAElFTkSuQmCC"
}
],
"meshes": [
{
"primitives": [
{
"mode": 4,
"attributes": { "POSITION": 0, "NORMAL": 1, "TEXCOORD_0": 2 },
"indices": 3,
"material": 0
}
]
},
{
"primitives": [
{
"mode": 4,
"attributes": { "POSITION": 4, "NORMAL": 5, "TEXCOORD_0": 6 },
"indices": 7,
"material": 0
}
]
},
{
"primitives": [
{
"mode": 4,
"attributes": { "POSITION": 8, "NORMAL": 9, "TEXCOORD_0": 10 },
"indices": 11,
"material": 0
}
]
},
{
"primitives": [
{
"mode": 4,
"attributes": { "POSITION": 12, "NORMAL": 13, "TEXCOORD_0": 14 },
"indices": 15,
"material": 0
}
]
},
{
"primitives": [
{
"mode": 4,
"attributes": { "POSITION": 16, "NORMAL": 17, "TEXCOORD_0": 18 },
"indices": 19,
"material": 0
}
]
},
{
"primitives": [
{
"mode": 4,
"attributes": { "POSITION": 20, "NORMAL": 21, "TEXCOORD_0": 22 },
"indices": 23,
"material": 0
}
]
},
{
"primitives": [
{
"mode": 4,
"attributes": { "POSITION": 24, "NORMAL": 25, "TEXCOORD_0": 26 },
"indices": 27,
"material": 0
}
]
},
{
"primitives": [
{
"mode": 4,
"attributes": { "POSITION": 28, "NORMAL": 29, "TEXCOORD_0": 30 },
"indices": 31,
"material": 0
}
]
},
{
"primitives": [
{
"mode": 4,
"attributes": { "POSITION": 32, "NORMAL": 33, "TEXCOORD_0": 34 },
"indices": 35,
"material": 0
}
]
},
{
"primitives": [
{
"mode": 4,
"attributes": { "POSITION": 36, "NORMAL": 37, "TEXCOORD_0": 38 },
"indices": 39,
"material": 0
}
]
},
{
"primitives": [
{
"mode": 4,
"attributes": { "POSITION": 40, "NORMAL": 41, "TEXCOORD_0": 42 },
"indices": 43,
"material": 0
}
]
},
{
"primitives": [
{
"mode": 4,
"attributes": { "POSITION": 44, "NORMAL": 45, "TEXCOORD_0": 46 },
"indices": 47,
"material": 0
}
]
}
]
}
@@ -1,5 +1,5 @@
<script setup lang="ts">
import { ref, useTemplateRef } from 'vue'
import { useTemplateRef } from 'vue'
import { NewModal as Modal } from '@modrinth/ui'
import { show_ads_window, hide_ads_window } from '@/helpers/ads.js'
import { useTheming } from '@/store/theme.ts'
@@ -59,7 +59,10 @@ watch(
<div class="mt-4 flex items-center justify-between">
<div>
<h2 class="m-0 text-lg font-extrabold text-contrast">Hide Nametag</h2>
<p class="m-0 mt-1">Allows you to disable the nametag that appears above the main preview on the skin management page.</p>
<p class="m-0 mt-1">
Allows you to disable the nametag that appears above the main preview on the skin management
page.
</p>
</div>
<Toggle id="hide-nametag-skins-page" v-model="settings.hide_nametag_skins_page" />
</div>
@@ -14,7 +14,8 @@
wide-model-src="/src/assets/models/classic_player.gltf"
:variant="variant"
:texture-src="previewSkin"
:scale="1.4" :fov="50"
:scale="1.4"
:fov="50"
class="h-full w-full"
/>
</div>
@@ -34,17 +35,19 @@
<UploadIcon aria-hidden="true" />
</FileInput>
<div class="flex items-center gap-2" v-if="fileName || mode === 'new'">
<div v-if="fileName || mode === 'new'" class="flex items-center gap-2">
<InfoIcon v-if="!fileName" class="text-brand-blue" />
<CheckCircleIcon v-else class="text-brand-green" />
<small class="truncate" v-tooltip="fileName">{{ fileName || 'No skin uploaded yet.' }}</small>
<small v-tooltip="fileName" class="truncate">{{
fileName || 'No skin uploaded yet.'
}}</small>
</div>
</Card>
</section>
<section>
<h2 class="text-base font-semibold mb-2">Arm style</h2>
<RadioButtons v-model="variant" :items="['CLASSIC','SLIM']">
<RadioButtons v-model="variant" :items="['CLASSIC', 'SLIM']">
<template #default="{ item }">
{{ item === 'CLASSIC' ? 'Wide' : 'Slim' }}
</template>
@@ -56,15 +59,19 @@
<div class="flex gap-2">
<CapeButton
v-for="cape in firstThreeCapes"
:key="cape.id"
:id="cape.id"
:key="cape.id"
:texture="cape.texture"
:name="cape.name || 'Cape'"
:selected="selectedCape?.id === cape.id"
@select="selectCape(cape)"
/>
<CapeLikeTextButton v-if="capes?.length ?? 0 > 3" tooltip="View more capes" @click="viewMoreCapes">
<template #icon><ChevronRightIcon/></template>
<CapeLikeTextButton
v-if="capes?.length ?? 0 > 3"
tooltip="View more capes"
@click="viewMoreCapes"
>
<template #icon><ChevronRightIcon /></template>
<span>More</span>
</CapeLikeTextButton>
</div>
@@ -74,14 +81,18 @@
<div class="flex gap-2 mt-6">
<ButtonStyled color="brand" :disabled="disableSave">
<Button @click="save" :disabled="disableSave" v-tooltip="disableSave && 'Upload a skin first!'">
<Button
v-tooltip="disableSave && 'Upload a skin first!'"
:disabled="disableSave"
@click="save"
>
<CheckIcon v-if="mode === 'new'" /><SaveIcon v-else />
{{ mode === 'new' ? 'Add skin' : 'Save skin' }}
</Button>
</ButtonStyled>
<Button @click="hide"><XIcon/>Cancel</Button>
<ButtonStyled color="red" v-if="mode==='edit'">
<Button @click="handleDelete"><TrashIcon/>Delete</Button>
<Button @click="hide"><XIcon />Cancel</Button>
<ButtonStyled v-if="mode === 'edit'" color="red">
<Button @click="handleDelete"><TrashIcon />Delete</Button>
</ButtonStyled>
</div>
</ModalWrapper>
@@ -91,29 +102,41 @@
import { ref, computed, watch, useTemplateRef } from 'vue'
import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue'
import {
Card, FileInput, SkinPreviewRenderer,
Button, RadioButtons, CapeButton, CapeLikeTextButton, ButtonStyled
Card,
FileInput,
SkinPreviewRenderer,
Button,
RadioButtons,
CapeButton,
CapeLikeTextButton,
ButtonStyled,
} from '@modrinth/ui'
import {
add_and_equip_custom_skin,
remove_custom_skin,
equip_skin,
unequip_skin,
get_available_skins,
type Skin, type Cape, type SkinModel
type Skin,
type Cape,
type SkinModel,
} from '@/helpers/skins.ts'
import { handleError } from '@/store/notifications'
import {
CheckCircleIcon, InfoIcon, UploadIcon,
CheckIcon, SaveIcon, XIcon, TrashIcon, ChevronRightIcon
CheckCircleIcon,
InfoIcon,
UploadIcon,
CheckIcon,
SaveIcon,
XIcon,
TrashIcon,
ChevronRightIcon,
} from '@modrinth/assets'
const modal = useTemplateRef('modal')
const mode = ref<'new'|'edit'>('new')
const currentSkin = ref<Skin|null>(null)
const mode = ref<'new' | 'edit'>('new')
const currentSkin = ref<Skin | null>(null)
const fileUploadTextureBlob = ref<Uint8Array|null>(null)
const fileName = ref<string|null>(null)
const fileUploadTextureBlob = ref<Uint8Array | null>(null)
const fileName = ref<string | null>(null)
watch(fileUploadTextureBlob, () => {
if (fileName.value === null && fileUploadTextureBlob.value) {
fileName.value = 'New upload'
@@ -121,11 +144,11 @@ watch(fileUploadTextureBlob, () => {
})
const variant = ref<SkinModel>('CLASSIC')
const selectedCape = ref<Cape|undefined>(undefined)
const selectedCape = ref<Cape | undefined>(undefined)
const props = defineProps<{ capes?: Cape[] }>()
const firstThreeCapes = computed(() => props.capes?.slice(0,3) ?? [])
const firstThreeCapes = computed(() => props.capes?.slice(0, 3) ?? [])
const localPreviewUrl = ref<string|null>(null)
const localPreviewUrl = ref<string | null>(null)
watch(fileUploadTextureBlob, (blob, prev) => {
if (prev && localPreviewUrl.value) URL.revokeObjectURL(localPreviewUrl.value)
if (blob) localPreviewUrl.value = URL.createObjectURL(new Blob([blob]))
@@ -137,9 +160,7 @@ const previewSkin = computed(() => {
return '/src/assets/skins/steve.png'
})
const disableSave = computed(() =>
mode.value==='new' && !fileUploadTextureBlob.value
)
const disableSave = computed(() => mode.value === 'new' && !fileUploadTextureBlob.value)
function resetState() {
mode.value = 'new'
@@ -159,7 +180,7 @@ function show(e: MouseEvent, skin?: Skin) {
currentSkin.value = skin ?? null
if (skin) {
variant.value = skin.variant
selectedCape.value = props.capes?.find(c=>c.id===skin.cape_id)
selectedCape.value = props.capes?.find((c) => c.id === skin.cape_id)
} else {
variant.value = 'CLASSIC'
selectedCape.value = undefined
@@ -172,7 +193,7 @@ function hide() {
resetState()
}
async function onTextureSelected(files: FileList|null) {
async function onTextureSelected(files: FileList | null) {
if (!files?.length) return
const file = files[0]
fileName.value = file.name
@@ -180,9 +201,10 @@ async function onTextureSelected(files: FileList|null) {
fileUploadTextureBlob.value = new Uint8Array(buf)
}
function changeVariant(v: SkinModel){ variant.value = v }
function selectCape(c: Cape|undefined){ selectedCape.value = c }
function viewMoreCapes(){
function selectCape(c: Cape | undefined) {
selectedCape.value = c
}
function viewMoreCapes() {
// TODO: later
}
@@ -211,7 +233,7 @@ async function save() {
blob = new Uint8Array(buf)
}
await unequip_skin();
await unequip_skin()
if (mode.value === 'new') {
await add_and_equip_custom_skin(blob, variant.value, selectedCape.value)
@@ -229,8 +251,7 @@ async function save() {
}
const emit = defineEmits<{
(e:'saved'):void
(e:'deleted'):void
(e: 'saved' | 'deleted'): void
}>()
defineExpose({ show, hide })
@@ -2,8 +2,14 @@
import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue'
import { useTemplateRef, ref, computed } from 'vue'
import type { Cape, SkinModel } from '@/helpers/skins.ts'
import {ButtonStyled, ScrollablePanel, CapeButton, CapeLikeTextButton, SkinPreviewRenderer} from '@modrinth/ui'
import { CheckIcon, XIcon} from '@modrinth/assets'
import {
ButtonStyled,
ScrollablePanel,
CapeButton,
CapeLikeTextButton,
SkinPreviewRenderer,
} from '@modrinth/ui'
import { CheckIcon, XIcon } from '@modrinth/assets'
const modal = useTemplateRef('modal')
@@ -12,7 +18,7 @@ const emit = defineEmits<{
}>()
defineProps<{
capes: Cape[];
capes: Cape[]
}>()
const currentSkinId = ref<string | undefined>()
@@ -21,9 +27,16 @@ const currentSkinVariant = ref<SkinModel>('CLASSIC')
const currentCapeTexture = computed<string | undefined>(() => currentCape.value?.texture)
const currentCape = ref<Cape | undefined>()
function show(e: MouseEvent, skinId?: string, selected?: Cape, skinTexture?: string, variant?: SkinModel) {
function show(
e: MouseEvent,
skinId?: string,
selected?: Cape,
skinTexture?: string,
variant?: SkinModel,
) {
currentSkinId.value = skinId
currentSkinTexture.value = skinTexture || (skinId ? `https://vzge.me/processedskin/${skinId}.png` : '')
currentSkinTexture.value =
skinTexture || (skinId ? `https://vzge.me/processedskin/${skinId}.png` : '')
currentSkinVariant.value = variant || 'CLASSIC'
currentCape.value = selected
modal.value?.show(e)
@@ -86,10 +99,10 @@ defineExpose({
</CapeLikeTextButton>
<CapeButton
v-for="cape in capes"
:id="cape.id"
:key="cape.id"
:name="cape.name"
:texture="cape.texture"
:id="cape.id"
:selected="currentCape?.id === cape.id"
@select="updateSelectedCape(cape)"
/>
@@ -1,258 +1,273 @@
import * as THREE from 'three';
import { GLTFLoader, GLTF } from 'three/examples/jsm/loaders/GLTFLoader.js';
import {Skin, determineModelType, Cape} from '../skins';
import { reactive } from "vue";
import * as THREE from 'three'
import type { GLTF } from 'three/examples/jsm/loaders/GLTFLoader.js'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'
import type { Skin, Cape } from '../skins'
import { determineModelType } from '../skins'
import { reactive } from 'vue'
export interface RenderResult {
forwards: string;
backwards: string;
forwards: string
backwards: string
}
class BatchSkinRenderer {
private renderer: THREE.WebGLRenderer;
private readonly scene: THREE.Scene;
private readonly camera: THREE.PerspectiveCamera;
private modelCache: Map<string, GLTF> = new Map();
private textureCache: Map<string, THREE.Texture> = new Map();
private currentModel: THREE.Group | null = null;
private capeModel: THREE.Object3D | null = null;
private bodyNode: THREE.Object3D | null = null;
private capeAttached: boolean = false;
private renderer: THREE.WebGLRenderer
private readonly scene: THREE.Scene
private readonly camera: THREE.PerspectiveCamera
private modelCache: Map<string, GLTF> = new Map()
private textureCache: Map<string, THREE.Texture> = new Map()
private currentModel: THREE.Group | null = null
private capeModel: THREE.Object3D | null = null
private bodyNode: THREE.Object3D | null = null
private capeAttached: boolean = false
constructor(width: number = 215, height: number = 215*2) {
const canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
constructor(width: number = 215, height: number = 215 * 2) {
const canvas = document.createElement('canvas')
canvas.width = width
canvas.height = height
this.renderer = new THREE.WebGLRenderer({
canvas: canvas,
antialias: true,
alpha: true,
preserveDrawingBuffer: true
});
preserveDrawingBuffer: true,
})
this.renderer.outputColorSpace = THREE.SRGBColorSpace;
this.renderer.toneMapping = THREE.NoToneMapping;
this.renderer.setClearColor(0x000000, 0);
this.renderer.setSize(width, height);
this.renderer.outputColorSpace = THREE.SRGBColorSpace
this.renderer.toneMapping = THREE.NoToneMapping
this.renderer.setClearColor(0x000000, 0)
this.renderer.setSize(width, height)
this.scene = new THREE.Scene();
this.camera = new THREE.PerspectiveCamera(20, width/height, 0.4, 1000);
this.scene = new THREE.Scene()
this.camera = new THREE.PerspectiveCamera(20, width / height, 0.4, 1000)
const ambientLight = new THREE.AmbientLight(0xffffff, 2);
this.scene.add(ambientLight);
const ambientLight = new THREE.AmbientLight(0xffffff, 2)
this.scene.add(ambientLight)
}
private async loadModel(modelUrl: string): Promise<GLTF> {
if (this.modelCache.has(modelUrl)) {
return this.modelCache.get(modelUrl)!;
return this.modelCache.get(modelUrl)!
}
const loader = new GLTFLoader();
const loader = new GLTFLoader()
return new Promise<GLTF>((resolve, reject) => {
loader.load(
modelUrl,
(gltf) => {
this.modelCache.set(modelUrl, gltf);
resolve(gltf);
this.modelCache.set(modelUrl, gltf)
resolve(gltf)
},
undefined,
reject
);
});
reject,
)
})
}
private async loadTexture(textureUrl: string): Promise<THREE.Texture> {
if (this.textureCache.has(textureUrl)) {
return this.textureCache.get(textureUrl)!;
return this.textureCache.get(textureUrl)!
}
return new Promise<THREE.Texture>((resolve) => {
const textureLoader = new THREE.TextureLoader();
const textureLoader = new THREE.TextureLoader()
textureLoader.load(textureUrl, (texture) => {
texture.colorSpace = THREE.SRGBColorSpace;
texture.flipY = false;
texture.magFilter = THREE.NearestFilter;
texture.minFilter = THREE.NearestFilter;
texture.colorSpace = THREE.SRGBColorSpace
texture.flipY = false
texture.magFilter = THREE.NearestFilter
texture.minFilter = THREE.NearestFilter
this.textureCache.set(textureUrl, texture);
resolve(texture);
});
});
this.textureCache.set(textureUrl, texture)
resolve(texture)
})
})
}
private applyTexture(model: THREE.Object3D, texture: THREE.Texture): void {
model.traverse(child => {
model.traverse((child) => {
if ((child as THREE.Mesh).isMesh) {
const mesh = child as THREE.Mesh;
const mesh = child as THREE.Mesh
if (mesh.name === "Cape") return;
if (mesh.name === 'Cape') return
const materials = Array.isArray(mesh.material) ? mesh.material : [mesh.material];
const materials = Array.isArray(mesh.material) ? mesh.material : [mesh.material]
materials.forEach((mat: THREE.Material) => {
if (mat instanceof THREE.MeshStandardMaterial) {
mat.map = texture;
mat.metalness = 0;
mat.color.set(0xffffff);
mat.toneMapped = false;
mat.roughness = 1;
mat.needsUpdate = true;
mat.map = texture
mat.metalness = 0
mat.color.set(0xffffff)
mat.toneMapped = false
mat.roughness = 1
mat.needsUpdate = true
}
});
})
}
});
})
}
private applyCapeTexture(model: THREE.Object3D, texture: THREE.Texture): void {
model.traverse(child => {
model.traverse((child) => {
if ((child as THREE.Mesh).isMesh) {
const mesh = child as THREE.Mesh;
const materials = Array.isArray(mesh.material) ? mesh.material : [mesh.material];
const mesh = child as THREE.Mesh
const materials = Array.isArray(mesh.material) ? mesh.material : [mesh.material]
materials.forEach((mat: THREE.Material) => {
if (mat instanceof THREE.MeshStandardMaterial) {
mat.map = texture;
mat.metalness = 0;
mat.color.set(0xffffff);
mat.toneMapped = false;
mat.roughness = 1;
mat.side = THREE.DoubleSide;
mat.needsUpdate = true;
mat.map = texture
mat.metalness = 0
mat.color.set(0xffffff)
mat.toneMapped = false
mat.roughness = 1
mat.side = THREE.DoubleSide
mat.needsUpdate = true
}
});
})
}
});
})
}
private attachCapeToBody(): void {
if (!this.bodyNode || !this.capeModel || this.capeAttached) return;
if (!this.bodyNode || !this.capeModel || this.capeAttached) return
if (this.capeModel.parent) {
this.capeModel.parent.remove(this.capeModel);
this.capeModel.parent.remove(this.capeModel)
}
this.capeModel.position.set(0, -1, -0.01);
this.capeModel.rotation.set(0, -Math.PI / 2, 0);
this.capeModel.position.set(0, -1, -0.01)
this.capeModel.rotation.set(0, -Math.PI / 2, 0)
this.bodyNode.add(this.capeModel);
this.capeAttached = true;
this.bodyNode.add(this.capeModel)
this.capeAttached = true
}
public async renderSkin(textureUrl: string, modelUrl: string, capeUrl?: string, capeModelUrl?: string): Promise<RenderResult> {
await this.setupModel(modelUrl, textureUrl, capeModelUrl, capeUrl);
public async renderSkin(
textureUrl: string,
modelUrl: string,
capeUrl?: string,
capeModelUrl?: string,
): Promise<RenderResult> {
await this.setupModel(modelUrl, textureUrl, capeModelUrl, capeUrl)
const headPart = this.currentModel!.getObjectByName('Head');
let lookAtTarget: [number, number, number];
const headPart = this.currentModel!.getObjectByName('Head')
let lookAtTarget: [number, number, number]
if (headPart) {
const headPosition = new THREE.Vector3();
headPart.getWorldPosition(headPosition);
lookAtTarget = [headPosition.x, headPosition.y, headPosition.z];
const headPosition = new THREE.Vector3()
headPart.getWorldPosition(headPosition)
lookAtTarget = [headPosition.x, headPosition.y, headPosition.z]
} else {
throw new Error("Failed to find 'Head' object in model.")
}
const frontCameraPos: [number, number, number] = [2, 1, -2.5];
const backCameraPos: [number, number, number] = [2, 1, 6.0];
const frontCameraPos: [number, number, number] = [2, 1, -2.5]
const backCameraPos: [number, number, number] = [2, 1, 6.0]
const forwards = await this.renderView(frontCameraPos, lookAtTarget);
const backwards = await this.renderView(backCameraPos, lookAtTarget);
const forwards = await this.renderView(frontCameraPos, lookAtTarget)
const backwards = await this.renderView(backCameraPos, lookAtTarget)
return { forwards, backwards };
return { forwards, backwards }
}
private async renderView(cameraPosition: [number, number, number], lookAtPosition: [number, number, number]): Promise<string> {
this.camera.position.set(...cameraPosition);
this.camera.lookAt(...lookAtPosition);
private async renderView(
cameraPosition: [number, number, number],
lookAtPosition: [number, number, number],
): Promise<string> {
this.camera.position.set(...cameraPosition)
this.camera.lookAt(...lookAtPosition)
this.renderer.render(this.scene, this.camera);
this.renderer.render(this.scene, this.camera)
return new Promise<string>((resolve, reject) => {
this.renderer.domElement.toBlob((blob) => {
if (blob) {
const url = URL.createObjectURL(blob);
resolve(url);
const url = URL.createObjectURL(blob)
resolve(url)
} else {
reject(new Error("Failed to create blob from canvas"));
reject(new Error('Failed to create blob from canvas'))
}
}, 'image/png');
});
}, 'image/png')
})
}
private async setupModel(modelUrl: string, textureUrl: string, capeModelUrl?: string, capeUrl?: string): Promise<void> {
private async setupModel(
modelUrl: string,
textureUrl: string,
capeModelUrl?: string,
capeUrl?: string,
): Promise<void> {
if (this.currentModel) {
this.scene.remove(this.currentModel);
this.scene.remove(this.currentModel)
}
this.bodyNode = null;
this.capeAttached = false;
this.bodyNode = null
this.capeAttached = false
const [gltf, texture] = await Promise.all([
this.loadModel(modelUrl),
this.loadTexture(textureUrl)
]);
this.loadTexture(textureUrl),
])
const model = gltf.scene.clone();
this.applyTexture(model, texture);
const model = gltf.scene.clone()
this.applyTexture(model, texture)
model.traverse(node => {
model.traverse((node) => {
if (node.name === 'Body') {
this.bodyNode = node;
this.bodyNode = node
}
});
})
const group = new THREE.Group();
group.add(model);
group.position.set(0, -0.5, 1.95);
group.scale.set(0.8, 0.8, 0.8);
const group = new THREE.Group()
group.add(model)
group.position.set(0, -0.5, 1.95)
group.scale.set(0.8, 0.8, 0.8)
this.scene.add(group);
this.currentModel = group;
this.scene.add(group)
this.currentModel = group
if (capeModelUrl && capeUrl) {
const [capeGltf, capeTexture] = await Promise.all([
this.loadModel(capeModelUrl),
this.loadTexture(capeUrl)
]);
this.loadTexture(capeUrl),
])
this.capeModel = capeGltf.scene.clone();
this.applyCapeTexture(this.capeModel, capeTexture);
this.capeModel = capeGltf.scene.clone()
this.applyCapeTexture(this.capeModel, capeTexture)
if (this.bodyNode && this.capeModel) {
this.attachCapeToBody();
this.attachCapeToBody()
}
}
}
public dispose(): void {
Array.from(this.textureCache.values()).forEach(texture => {
texture.dispose();
});
Array.from(this.textureCache.values()).forEach((texture) => {
texture.dispose()
})
this.renderer.dispose();
this.textureCache.clear();
this.modelCache.clear();
this.renderer.dispose()
this.textureCache.clear()
this.modelCache.clear()
}
}
function getModelUrlForVariant(variant: string): string {
switch (variant) {
case 'SLIM':
return '/src/assets/models/slim_player.gltf';
return '/src/assets/models/slim_player.gltf'
case 'CLASSIC':
case 'UNKNOWN':
default:
return '/src/assets/models/classic_player.gltf';
return '/src/assets/models/classic_player.gltf'
}
}
export const map = reactive(new Map<string, RenderResult>());
const DEBUG_MODE = false;
export const map = reactive(new Map<string, RenderResult>())
const DEBUG_MODE = false
export async function generateSkinPreviews(skins: Skin[], capes: Cape[]): Promise<void> {
const renderer = new BatchSkinRenderer();
const capeModelUrl = '/src/assets/models/cape.gltf';
const renderer = new BatchSkinRenderer()
const capeModelUrl = '/src/assets/models/cape.gltf'
try {
for (const skin of skins) {
@@ -264,31 +279,31 @@ export async function generateSkinPreviews(skins: Skin[], capes: Cape[]): Promis
URL.revokeObjectURL(result.forwards)
URL.revokeObjectURL(result.backwards)
map.delete(key)
} else continue;
} else continue
}
let variant = skin.variant;
let variant = skin.variant
if (variant === 'UNKNOWN') {
try {
variant = await determineModelType(skin.texture);
variant = await determineModelType(skin.texture)
} catch (error) {
console.error(`Failed to determine model type for skin ${key}:`, error);
variant = 'CLASSIC';
console.error(`Failed to determine model type for skin ${key}:`, error)
variant = 'CLASSIC'
}
}
const modelUrl = getModelUrlForVariant(variant);
const cape: Cape | undefined = capes.find(_cape => _cape.id === skin.cape_id);
const modelUrl = getModelUrlForVariant(variant)
const cape: Cape | undefined = capes.find((_cape) => _cape.id === skin.cape_id)
const renderResult = await renderer.renderSkin(
skin.texture,
modelUrl,
cape?.texture,
capeModelUrl
);
capeModelUrl,
)
map.set(key, renderResult);
map.set(key, renderResult)
}
} finally {
renderer.dispose();
renderer.dispose()
}
}
+33 -37
View File
@@ -1,5 +1,5 @@
import {invoke} from '@tauri-apps/api/core'
import {handleError} from "@/store/notifications";
import { invoke } from '@tauri-apps/api/core'
import { handleError } from '@/store/notifications'
export interface Cape {
id: string
@@ -37,70 +37,66 @@ export const DEFAULT_MODELS: Record<string, SkinModel> = {
}
export function filterSavedSkins(list: Skin[]) {
const customSkins = list.filter((s) => s.source !== 'default');
fixUnknownSkins(customSkins).catch(handleError);
return customSkins;
const customSkins = list.filter((s) => s.source !== 'default')
fixUnknownSkins(customSkins).catch(handleError)
return customSkins
}
export async function determineModelType(texture: string): Promise<'SLIM' | 'CLASSIC'> {
return new Promise((resolve, reject) => {
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
const canvas = document.createElement('canvas')
const context = canvas.getContext('2d')
if (!context) {
return reject(new Error('Failed to create canvas rendering context.'));
return reject(new Error('Failed to create canvas rendering context.'))
}
const image = new Image();
image.crossOrigin = 'anonymous';
image.src = texture;
const image = new Image()
image.crossOrigin = 'anonymous'
image.src = texture
image.onload = () => {
canvas.width = image.width;
canvas.height = image.height;
canvas.width = image.width
canvas.height = image.height
context.drawImage(image, 0, 0);
context.drawImage(image, 0, 0)
const armX = 44;
const armY = 16;
const armWidth = 4;
const armHeight = 12;
const armX = 44
const armY = 16
const armWidth = 4
const armHeight = 12
const imageData = context.getImageData(armX, armY, armWidth, armHeight).data;
const imageData = context.getImageData(armX, armY, armWidth, armHeight).data
for (let y = 0; y < armHeight; y++) {
const alphaIndex = (3 + y * armWidth) * 4 + 3;
const alphaIndex = (3 + y * armWidth) * 4 + 3
if (imageData[alphaIndex] !== 0) {
resolve('CLASSIC');
return;
resolve('CLASSIC')
return
}
}
canvas.remove();
resolve('SLIM');
};
canvas.remove()
resolve('SLIM')
}
image.onerror = () => {
canvas.remove();
reject(new Error('Failed to load the image.'));
};
});
canvas.remove()
reject(new Error('Failed to load the image.'))
}
})
}
export async function fixUnknownSkins(list: Skin[]) {
const unknownSkins = list.filter((s) => s.variant === "UNKNOWN");
for (let unknownSkin of unknownSkins) {
unknownSkin.variant = await determineModelType(unknownSkin.texture);
const unknownSkins = list.filter((s) => s.variant === 'UNKNOWN')
for (const unknownSkin of unknownSkins) {
unknownSkin.variant = await determineModelType(unknownSkin.texture)
}
}
export function filterDefaultSkins(list: Skin[]) {
return list
.filter(
(s) =>
s.source === 'default' &&
(!s.name || s.variant === DEFAULT_MODELS[s.name]),
)
.filter((s) => s.source === 'default' && (!s.name || s.variant === DEFAULT_MODELS[s.name]))
.sort((a, b) => {
const aIndex = a.name ? DEFAULT_MODEL_SORTING.indexOf(a.name) : -1
const bIndex = b.name ? DEFAULT_MODEL_SORTING.indexOf(b.name) : -1
+8 -6
View File
@@ -83,13 +83,15 @@ async function refreshFeaturedProjects() {
await fetchInstances()
await refreshFeaturedProjects()
const unlistenProfile = await profile_listener(async (e: { event: string; profile_path_id: string }) => {
await fetchInstances()
const unlistenProfile = await profile_listener(
async (e: { event: string; profile_path_id: string }) => {
await fetchInstances()
if (e.event === 'added' || e.event === 'created' || e.event === 'removed') {
await refreshFeaturedProjects()
}
})
if (e.event === 'added' || e.event === 'created' || e.event === 'removed') {
await refreshFeaturedProjects()
}
},
)
onUnmounted(() => {
unlistenProfile()
+45 -30
View File
@@ -1,7 +1,7 @@
<script setup lang="ts">
import { UpdatedIcon, PlusIcon } from '@modrinth/assets'
import { ButtonStyled, SkinPreviewRenderer, SkinButton, SkinLikeTextButton } from '@modrinth/ui'
import {ref, computed, useTemplateRef, watch} from 'vue'
import { ref, computed, useTemplateRef, watch } from 'vue'
import EditSkinModal from '@/components/ui/skin/EditSkinModal.vue'
import SelectCapeModal from '@/components/ui/skin/SelectCapeModal.vue'
import { handleError } from '@/store/notifications'
@@ -9,12 +9,15 @@ import {
get_available_skins,
get_available_capes,
filterSavedSkins,
filterDefaultSkins, equip_skin, set_default_cape
filterDefaultSkins,
equip_skin,
set_default_cape,
} from '@/helpers/skins.ts'
import { get as getSettings } from '@/helpers/settings.ts'
import type { Cape, Skin } from '@/helpers/skins.ts'
import {get_default_user, users} from "@/helpers/auth";
import {generateSkinPreviews, map, RenderResult} from "@/helpers/rendering/batchSkinRenderer.ts";
import { get_default_user, users } from '@/helpers/auth'
import type { RenderResult } from '@/helpers/rendering/batchSkinRenderer.ts'
import { generateSkinPreviews, map } from '@/helpers/rendering/batchSkinRenderer.ts'
const editSkinModal = useTemplateRef('editSkinModal')
const selectCapeModal = useTemplateRef('selectCapeModal')
@@ -30,7 +33,7 @@ const defaultCape = ref<Cape>()
const forceSkinRefreshKey = ref(0)
const previewSkin = computed(() =>
selectedSkin.value ? `https://vzge.me/processedskin/${selectedSkin.value.texture_key}.png` : ''
selectedSkin.value ? `https://vzge.me/processedskin/${selectedSkin.value.texture_key}.png` : '',
)
const savedSkins = computed(() => filterSavedSkins(skins.value))
@@ -38,7 +41,7 @@ const defaultSkins = computed(() => filterDefaultSkins(skins.value))
const currentCape = computed(() => {
if (selectedSkin.value?.cape_id) {
const overrideCape = capes.value.find(c => c.id === selectedSkin.value?.cape_id)
const overrideCape = capes.value.find((c) => c.id === selectedSkin.value?.cape_id)
if (overrideCape) {
return overrideCape
}
@@ -56,10 +59,10 @@ async function loadCapes() {
async function loadSkins() {
skins.value = (await get_available_skins().catch(handleError)) ?? []
generateSkinPreviews(skins.value, capes.value);
generateSkinPreviews(skins.value, capes.value)
const previousSkinId = selectedSkin.value?.texture_key
selectedSkin.value = skins.value.find((s) => s.is_equipped) ?? null;
selectedSkin.value = skins.value.find((s) => s.is_equipped) ?? null
if (previousSkinId && selectedSkin.value?.texture_key === previousSkinId) {
forceSkinRefreshKey.value++
@@ -67,25 +70,25 @@ async function loadSkins() {
}
async function changeSkin(newSkin: Skin) {
await equip_skin(newSkin).catch(handleError);
await loadSkins();
await equip_skin(newSkin).catch(handleError)
await loadSkins()
}
async function handleCapeSelected(cape: Cape | undefined) {
await set_default_cape(cape).catch(handleError);
await loadSkins();
await loadCapes();
await set_default_cape(cape).catch(handleError)
await loadSkins()
await loadCapes()
}
async function onSkinSaved() {
await Promise.all([loadCapes(), loadSkins()]);
await Promise.all([loadCapes(), loadSkins()])
}
async function loadUsername() {
try {
const defaultId = await get_default_user()
const allAccounts = await users();
const current = allAccounts.find(acc => acc.profile.id === defaultId)
const allAccounts = await users()
const current = allAccounts.find((acc) => acc.profile.id === defaultId)
username.value = current?.profile?.name ?? undefined
} catch (e) {
handleError(e)
@@ -94,13 +97,16 @@ async function loadUsername() {
}
function getBakedSkinTextures(skin: Skin): RenderResult | undefined {
const key = `${skin.texture_key}+${skin.variant}+${skin.cape_id ?? 'no-cape'}`;
return map.get(key);
const key = `${skin.texture_key}+${skin.variant}+${skin.cape_id ?? 'no-cape'}`
return map.get(key)
}
watch(() => selectedSkin.value?.cape_id, () => {
forceSkinRefreshKey.value++
})
watch(
() => selectedSkin.value?.cape_id,
() => {
forceSkinRefreshKey.value++
},
)
</script>
<template>
@@ -110,17 +116,22 @@ watch(() => selectedSkin.value?.cape_id, () => {
@saved="onSkinSaved"
@deleted="() => loadSkins()"
/>
<SelectCapeModal ref="selectCapeModal" :capes="capes" @select="handleCapeSelected"/>
<SelectCapeModal ref="selectCapeModal" :capes="capes" @select="handleCapeSelected" />
<div class="p-6 grid grid-cols-[300px_1fr] xl:grid-cols-[3fr_5fr] gap-6">
<div class="sticky top-6 self-start">
<div class="flex justify-between gap-4">
<h1 class="m-0 text-2xl font-bold">Skins</h1>
<ButtonStyled :disabled="!!selectedSkin?.cape_id">
<button
v-tooltip="selectedSkin?.cape_id ? 'The equipped skin is overriding the default cape.' : undefined"
v-tooltip="
selectedSkin?.cape_id
? 'The equipped skin is overriding the default cape.'
: undefined
"
:disabled="!!selectedSkin?.cape_id"
@click="(e: MouseEvent) =>
selectCapeModal?.show(e, selectedSkin?.texture_key, currentCape)"
@click="
(e: MouseEvent) => selectCapeModal?.show(e, selectedSkin?.texture_key, currentCape)
"
>
<UpdatedIcon />
Change cape
@@ -145,7 +156,11 @@ watch(() => selectedSkin.value?.cape_id, () => {
<section class="flex flex-col gap-3">
<h2 class="text-lg font-bold m-0 text-primary">Saved skins</h2>
<div class="flex flex-row flex-wrap gap-2">
<SkinLikeTextButton @click="editSkinModal?.show" class="flex-none w-[8vw] h-[15vw] max-w-[8rem] max-h-[15rem]" tooltip="Add a skin">
<SkinLikeTextButton
class="flex-none w-[8vw] h-[15vw] max-w-[8rem] max-h-[15rem]"
tooltip="Add a skin"
@click="editSkinModal?.show"
>
<template #icon>
<PlusIcon />
</template>
@@ -154,14 +169,14 @@ watch(() => selectedSkin.value?.cape_id, () => {
<SkinButton
v-for="skin in savedSkins"
class="flex-none w-[8vw] h-[15vw] max-w-[8rem] max-h-[15rem]"
:key="`saved-skin-${skin.texture_key}`"
class="flex-none w-[8vw] h-[15vw] max-w-[8rem] max-h-[15rem]"
editable
:forward-image-src="getBakedSkinTextures(skin)?.forwards"
:backward-image-src="getBakedSkinTextures(skin)?.backwards"
:selected="selectedSkin === skin"
@select="changeSkin(skin)"
@edit="e => editSkinModal?.show(e, skin)"
@edit="(e) => editSkinModal?.show(e, skin)"
/>
</div>
</section>
@@ -171,14 +186,14 @@ watch(() => selectedSkin.value?.cape_id, () => {
<div class="flex flex-row flex-wrap gap-2">
<SkinButton
v-for="skin in defaultSkins"
class="flex-none w-[8vw] h-[15vw] max-w-[8rem] max-h-[15rem]"
:key="`default-skin-${skin.texture_key}`"
class="flex-none w-[8vw] h-[15vw] max-w-[8rem] max-h-[15rem]"
:forward-image-src="getBakedSkinTextures(skin)?.forwards"
:backward-image-src="getBakedSkinTextures(skin)?.backwards"
:selected="selectedSkin === skin"
:tooltip="skin.name"
@select="changeSkin(skin)"
@edit="e => editSkinModal?.show(e, skin)"
@edit="(e) => editSkinModal?.show(e, skin)"
/>
</div>
</section>
@@ -34,6 +34,7 @@ function onImageLoad(type: 'forward' | 'backward') {
<template>
<div
v-tooltip="tooltip ?? undefined"
class="skin-button__parent group flex relative border-2 border-solid transform-3d rotate-y-90 transition-all p-0 bg-transparent rounded-xl overflow-hidden"
:class="[
selected ? `border-brand` : 'border-transparent',
@@ -41,7 +42,6 @@ function onImageLoad(type: 'forward' | 'backward') {
'scale-95': pressed,
},
]"
v-tooltip="tooltip ?? undefined"
>
<button
class="absolute inset-0 rounded-xl cursor-pointer p-0 border-none group-hover:brightness-125"
@@ -13,14 +13,14 @@
shadows
alpha
:antialias="antialias"
:renderer-options="{
outputColorSpace: THREE.SRGBColorSpace,
toneMapping: THREE.NoToneMapping
}"
@pointerdown="onPointerDown"
@pointermove="onPointerMove"
@pointerup="onPointerUp"
@pointerleave="onPointerUp"
:rendererOptions="{
outputColorSpace: THREE.SRGBColorSpace,
toneMapping: THREE.NoToneMapping
}"
>
<Suspense>
<Group>
@@ -55,7 +55,7 @@
</Suspense>
<TresPerspectiveCamera
:makeDefault="true"
:make-default="true"
:fov="fov"
:position="[0, 1.5, -3.25]"
:look-at="target"
+3
View File
@@ -95,6 +95,9 @@ importers:
posthog-js:
specifier: ^1.158.2
version: 1.158.2
three:
specifier: ^0.172.0
version: 0.172.0
vite-svg-loader:
specifier: ^5.1.0
version: 5.1.0(vue@3.5.13(typescript@5.5.4))