minerender 2.1.0-alpha.27 → 2.1.0-alpha.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1312,7 +1312,7 @@ var Models = class _Models {
1312
1312
  }
1313
1313
  static async getItemModel(key) {
1314
1314
  const itemKey = new AssetKey(key.namespace, key.path, "items", void 0, key.rootType, ".json", key.root);
1315
- const model = await this.PERSISTENT_CACHE.getOrLoad(itemKey.serialize(), async () => {
1315
+ const model = await this.PERSISTENT_CACHE.getOrLoad(AssetLoader.persistentKey(itemKey.serialize()), async () => {
1316
1316
  const result = await AssetLoader.getFirst([itemKey, key], "json" /* JSON */);
1317
1317
  if (!result) return void 0;
1318
1318
  if (result.key.assetType !== "items") return { ...result.asset, key };
@@ -1358,7 +1358,7 @@ var Models = class _Models {
1358
1358
  }
1359
1359
  const keyStr = key.serialize();
1360
1360
  return Caching.rawModelCache.get(keyStr, (k) => {
1361
- return this.PERSISTENT_CACHE.getOrLoad(keyStr, (k1) => {
1361
+ return this.PERSISTENT_CACHE.getOrLoad(AssetLoader.persistentKey(keyStr), (k1) => {
1362
1362
  return AssetLoader.get(key, "model" /* MODEL */);
1363
1363
  });
1364
1364
  }).then((asset) => {
@@ -1430,7 +1430,7 @@ var BlockStates = class {
1430
1430
  }
1431
1431
  const keyStr = key.serialize();
1432
1432
  return Caching.blockStateCache.get(keyStr, (k) => {
1433
- return this.PERSISTENT_CACHE.getOrLoad(keyStr, (k1) => {
1433
+ return this.PERSISTENT_CACHE.getOrLoad(AssetLoader.persistentKey(keyStr), (k1) => {
1434
1434
  return AssetLoader.get(key, "blockstate" /* BLOCKSTATE */);
1435
1435
  });
1436
1436
  }).then((asset) => {
@@ -1476,6 +1476,14 @@ var Assets = class {
1476
1476
  var AssetSource = class {
1477
1477
  constructor() {
1478
1478
  }
1479
+ /**
1480
+ * Identifies this source's content across sessions for persistent caching. Sources that
1481
+ * cannot tell whether their content changed (an unnamed archive, for example) return
1482
+ * undefined, which keeps their results out of long-lived caches.
1483
+ */
1484
+ get cacheId() {
1485
+ return void 0;
1486
+ }
1479
1487
  };
1480
1488
  var AssetLoadError = class extends Error {
1481
1489
  constructor(source, key, path, cause) {
@@ -1688,6 +1696,9 @@ var _HostedAssetSource = class _HostedAssetSource extends AssetSource {
1688
1696
  get root() {
1689
1697
  return this._root;
1690
1698
  }
1699
+ get cacheId() {
1700
+ return `hosted:${this._root}`;
1701
+ }
1691
1702
  get options() {
1692
1703
  return this._options;
1693
1704
  }
@@ -1764,9 +1775,10 @@ var HostedAssetSource = _HostedAssetSource;
1764
1775
  // src/assets/source/archive/BrowserArchiveProxy.ts
1765
1776
  import { BlobReader, BlobWriter, ZipReader } from "@zip.js/zip.js";
1766
1777
  var BrowserArchiveProxy = class {
1767
- constructor(blob) {
1778
+ constructor(blob, id) {
1768
1779
  this._blob = blob;
1769
1780
  this._reader = new ZipReader(new BlobReader(this._blob));
1781
+ this.id = id ?? (typeof File !== "undefined" && blob instanceof File ? `${blob.name}:${blob.size}:${blob.lastModified}` : void 0);
1770
1782
  }
1771
1783
  async getEntries() {
1772
1784
  return (await this._reader.getEntries()).map((e) => {
@@ -1791,6 +1803,10 @@ var ArchiveAssetSource = class _ArchiveAssetSource extends AssetSource {
1791
1803
  static blob(blob) {
1792
1804
  return new _ArchiveAssetSource(new BrowserArchiveProxy(blob));
1793
1805
  }
1806
+ get cacheId() {
1807
+ const id = this._archiveProxy.id;
1808
+ return id === void 0 ? void 0 : `archive:${id}`;
1809
+ }
1794
1810
  async getEntries() {
1795
1811
  return this._archiveProxy.getEntries();
1796
1812
  }
@@ -1833,6 +1849,7 @@ var ArchiveAssetSource = class _ArchiveAssetSource extends AssetSource {
1833
1849
 
1834
1850
  // src/assets/AssetLoader.ts
1835
1851
  var p4 = prefix("AssetLoader");
1852
+ var FALLBACK_ROOT = "https://raw.githubusercontent.com/InventivetalentDev/minerender-fallback-assets/master";
1836
1853
  var _AssetLoader = class _AssetLoader {
1837
1854
  static get version() {
1838
1855
  return this.ROOT.substring(this.ROOT.lastIndexOf("/") + 1);
@@ -1848,6 +1865,28 @@ var _AssetLoader = class _AssetLoader {
1848
1865
  }
1849
1866
  Caching.clear();
1850
1867
  }
1868
+ /**
1869
+ * Scope for persistent cache keys. Empty with only the default vanilla sources, so their
1870
+ * entries stay valid across sessions; otherwise it names every added source (resource packs,
1871
+ * mirrors) so their results never masquerade as vanilla assets after a reload.
1872
+ */
1873
+ static get persistentScope() {
1874
+ const parts = [];
1875
+ for (const { key, source } of this._SOURCES) {
1876
+ const id = source.cacheId;
1877
+ if (key === "mcassets" && id === `hosted:${this.ROOT}`) continue;
1878
+ if (key === "mcassets-fallback" && id === `hosted:${FALLBACK_ROOT}`) continue;
1879
+ if (id === void 0) return this.SESSION_SCOPE;
1880
+ parts.push(`${key}=${id}`);
1881
+ }
1882
+ return parts.join("|");
1883
+ }
1884
+ /** Prefixes a persistent cache key with the current source scope. */
1885
+ static persistentKey(key) {
1886
+ const scope = this.persistentScope;
1887
+ return scope ? `${scope}
1888
+ ${key}` : key;
1889
+ }
1851
1890
  static addSource(key, source, override = true) {
1852
1891
  if (override) {
1853
1892
  const existing = this.removeSource(key);
@@ -1909,7 +1948,9 @@ var _AssetLoader = class _AssetLoader {
1909
1948
  };
1910
1949
  _AssetLoader.ROOT = DEFAULT_ROOT;
1911
1950
  _AssetLoader._SOURCES = [];
1912
- _AssetLoader.addSource("mcassets-fallback", new HostedAssetSource("https://raw.githubusercontent.com/InventivetalentDev/minerender-fallback-assets/master", { retryDefaults: false }));
1951
+ /** Used when a registered source cannot identify its content, so nothing persists past this session. */
1952
+ _AssetLoader.SESSION_SCOPE = `session:${Date.now().toString(36)}:${Math.random().toString(36).slice(2)}`;
1953
+ _AssetLoader.addSource("mcassets-fallback", new HostedAssetSource(FALLBACK_ROOT, { retryDefaults: false }));
1913
1954
  _AssetLoader.addSource("mcassets", new HostedAssetSource(_AssetLoader.ROOT, { retryDefaults: false }));
1914
1955
  var AssetLoader = _AssetLoader;
1915
1956
 
@@ -1952,7 +1993,7 @@ var ModelTextures = class {
1952
1993
  }
1953
1994
  const keyStr = key.serialize();
1954
1995
  return Caching.textureMetaCache.get(keyStr, (k) => {
1955
- return this.PERSISTENT_META_CACHE.getOrLoad(keyStr, (k1) => {
1996
+ return this.PERSISTENT_META_CACHE.getOrLoad(AssetLoader.persistentKey(keyStr), (k1) => {
1956
1997
  return AssetLoader.get(key, "meta" /* META */).then((asset) => {
1957
1998
  if (asset)
1958
1999
  asset.key = key;
@@ -4609,7 +4650,9 @@ var _BlockObject = class _BlockObject extends SceneObject {
4609
4650
  if (typeof variant.y !== "undefined") {
4610
4651
  rotation.y = toRadians(clampRotationDegrees(typeof variant.x !== "undefined" ? variant.y : 360 - variant.y));
4611
4652
  }
4612
- const model = await Models.getMerged(AssetKey.parse("models", variant.model));
4653
+ const modelKey = AssetKey.parse("models", variant.model);
4654
+ modelKey.root = this.blockState.key?.root;
4655
+ const model = await Models.getMerged(modelKey);
4613
4656
  const options = {
4614
4657
  ...this.options,
4615
4658
  tints: model ? await BlockTints.get(this.blockState.key, this.state, model, this.options.tints) : this.options.tints,
@@ -5405,56 +5448,12 @@ var baseSkinCoordinates = {
5405
5448
  }
5406
5449
  },
5407
5450
  cape: {
5408
- //TODO
5409
- east: {
5410
- uv: [
5411
- 0,
5412
- 36,
5413
- 4,
5414
- 48
5415
- ]
5416
- },
5417
- west: {
5418
- uv: [
5419
- 8,
5420
- 36,
5421
- 12,
5422
- 48
5423
- ]
5424
- },
5425
- north: {
5426
- uv: [
5427
- 4,
5428
- 36,
5429
- 8,
5430
- 48
5431
- ]
5432
- },
5433
- south: {
5434
- uv: [
5435
- 12,
5436
- 36,
5437
- 16,
5438
- 48
5439
- ]
5440
- },
5441
- up: {
5442
- uv: [
5443
- 4,
5444
- 32,
5445
- 8,
5446
- 36
5447
- ]
5448
- },
5449
- down: {
5450
- uv: [
5451
- 8,
5452
- 32,
5453
- 12,
5454
- 36
5455
- ],
5456
- rotation: 180
5457
- }
5451
+ east: { uv: [0, 1, 1, 17] },
5452
+ west: { uv: [11, 1, 12, 17] },
5453
+ north: { uv: [1, 1, 11, 17] },
5454
+ south: { uv: [12, 1, 22, 17] },
5455
+ up: { uv: [11, 1, 1, 0] },
5456
+ down: { uv: [21, 0, 11, 1] }
5458
5457
  }
5459
5458
  };
5460
5459
  var classicSkinTextureCoordinates = {
@@ -5535,14 +5534,110 @@ var slimSkinGeometries = {
5535
5534
 
5536
5535
  // src/skin/scene/SkinObject.ts
5537
5536
  var import_ts_deepmerge7 = __toESM(require_dist());
5537
+
5538
+ // src/skin/SkinTextures.ts
5539
+ import { DataTexture, DoubleSide as DoubleSide2, FrontSide as FrontSide2, MeshBasicMaterial as MeshBasicMaterial3, SRGBColorSpace as SRGBColorSpace3 } from "three";
5540
+ var SkinTextures = class {
5541
+ static async get(src, legacy) {
5542
+ const image = await ImageLoader.getData(src);
5543
+ const scale = image.width / 64;
5544
+ if (!Number.isInteger(scale) || scale < 1 || image.height !== image.width && image.height !== image.width / 2) {
5545
+ throw new MineRenderError(`Invalid skin dimensions ${image.width}x${image.height}; expected 64x64 or 64x32, or an integer-scaled equivalent`);
5546
+ }
5547
+ const isLegacy = legacy ?? image.height === image.width / 2;
5548
+ if (!isLegacy && image.height !== image.width) {
5549
+ throw new MineRenderError(`Invalid skin dimensions ${image.width}x${image.height}; non-legacy skins must be square`);
5550
+ }
5551
+ const slim = !isLegacy && this.isSlim(image, scale);
5552
+ const key = `skin:${serializeImageKey({ src })}:${isLegacy}`;
5553
+ const material = Caching.materialCache.get(key, () => {
5554
+ const pixels = isLegacy ? this.normalizeLegacy(image, scale) : new Uint8Array(image.data);
5555
+ return this.createMaterial(pixels, image.width, image.width);
5556
+ });
5557
+ return { material, slim, legacy: isLegacy };
5558
+ }
5559
+ static async getCape(src) {
5560
+ const image = await ImageLoader.getData(src);
5561
+ const scale = image.width / 64;
5562
+ if (!Number.isInteger(scale) || scale < 1 || image.height !== image.width / 2) {
5563
+ throw new MineRenderError(`Invalid cape dimensions ${image.width}x${image.height}; expected 64x32 or an integer-scaled equivalent`);
5564
+ }
5565
+ return Caching.materialCache.get(`cape:${serializeImageKey({ src })}`, () => {
5566
+ return this.createMaterial(new Uint8Array(image.data), image.width, image.height, false);
5567
+ });
5568
+ }
5569
+ static createMaterial(pixels, width, height, transparent = true) {
5570
+ const texture = Textures.initTextureProps(new DataTexture(pixels, width, height));
5571
+ texture.colorSpace = SRGBColorSpace3;
5572
+ texture.flipY = true;
5573
+ texture.needsUpdate = true;
5574
+ return new MeshBasicMaterial3({ map: texture, transparent, side: transparent ? DoubleSide2 : FrontSide2, alphaTest: transparent ? 0.5 : 0 });
5575
+ }
5576
+ static isSlim(image, scale) {
5577
+ for (const [x, y] of [[46, 52], [54, 20]]) {
5578
+ for (let row = y * scale; row < (y + 12) * scale; row++) {
5579
+ for (let column = x * scale; column < (x + 1) * scale; column++) {
5580
+ if (image.data[(row * image.width + column) * 4 + 3] !== 0) return false;
5581
+ }
5582
+ }
5583
+ }
5584
+ return true;
5585
+ }
5586
+ static normalizeLegacy(image, scale) {
5587
+ const pixels = new Uint8Array(image.width * image.width * 4);
5588
+ pixels.set(image.data.subarray(0, image.width * image.width / 2 * 4));
5589
+ for (const [sx, sy, dx, dy, width, height] of [
5590
+ [4, 16, 20, 48, 4, 4],
5591
+ [8, 16, 24, 48, 4, 4],
5592
+ [0, 20, 24, 52, 4, 12],
5593
+ [4, 20, 20, 52, 4, 12],
5594
+ [8, 20, 16, 52, 4, 12],
5595
+ [12, 20, 28, 52, 4, 12],
5596
+ [44, 16, 36, 48, 4, 4],
5597
+ [48, 16, 40, 48, 4, 4],
5598
+ [40, 20, 40, 52, 4, 12],
5599
+ [44, 20, 36, 52, 4, 12],
5600
+ [48, 20, 32, 52, 4, 12],
5601
+ [52, 20, 44, 52, 4, 12]
5602
+ ]) {
5603
+ for (let y = 0; y < height * scale; y++) {
5604
+ for (let x = 0; x < width * scale; x++) {
5605
+ const source = ((sy * scale + y) * image.width + sx * scale + x) * 4;
5606
+ const target = ((dy * scale + y) * image.width + (dx + width) * scale - 1 - x) * 4;
5607
+ pixels.set(image.data.subarray(source, source + 4), target);
5608
+ }
5609
+ }
5610
+ }
5611
+ let clearHat = true;
5612
+ for (let y = 0; y < 32 * scale; y++) {
5613
+ for (let x = 32 * scale; x < image.width; x++) {
5614
+ if (pixels[(y * image.width + x) * 4 + 3] < 128) clearHat = false;
5615
+ }
5616
+ }
5617
+ for (let y = 0; y < image.width; y++) {
5618
+ for (let x = 0; x < image.width; x++) {
5619
+ const alpha = (y * image.width + x) * 4 + 3;
5620
+ if (x < 32 * scale && y < 16 * scale || y >= 16 * scale && y < 32 * scale || x >= 16 * scale && x < 48 * scale && y >= 48 * scale) {
5621
+ pixels[alpha] = 255;
5622
+ } else if (clearHat && x >= 32 * scale && y < 32 * scale) {
5623
+ pixels[alpha] = 0;
5624
+ }
5625
+ }
5626
+ }
5627
+ return pixels;
5628
+ }
5629
+ };
5630
+
5631
+ // src/skin/scene/SkinObject.ts
5538
5632
  var SkinObject = class extends SceneObject {
5539
5633
  constructor(options) {
5540
5634
  super();
5541
5635
  this.slim = false;
5542
- this.legacy = false;
5543
- this.skinTextureWidth = 64;
5544
- this.skinTextureHeight = 64;
5636
+ this.detectedSlim = false;
5637
+ this.skinLoad = 0;
5638
+ this.capeLoad = 0;
5545
5639
  this.options = (0, import_ts_deepmerge7.default)({}, SceneObject.DEFAULT_OPTIONS, options ?? {});
5640
+ this.slim = this.options.slim ?? false;
5546
5641
  }
5547
5642
  async init() {
5548
5643
  this.createMeshes();
@@ -5551,15 +5646,13 @@ var SkinObject = class extends SceneObject {
5551
5646
  }
5552
5647
  createMeshes() {
5553
5648
  console.log("#createMeshes");
5554
- const mat = Materials.MISSING_TEXTURE;
5649
+ const mat = this.skinMaterial ?? Materials.MISSING_TEXTURE;
5555
5650
  {
5556
5651
  const headGroup = this.createAndAddGroup("head", 0, 28, 0, "y" /* Y */, -4);
5557
5652
  const headGeo = this.getBoxGeometry("head" /* HEAD */);
5558
5653
  const head = this.createAndAddMesh("head", headGroup, headGeo, mat, "y" /* Y */, 4);
5559
- if (!this.legacy) {
5560
- const hatGeo = this.getBoxGeometry("hat" /* HAT */);
5561
- const hat = this.createAndAddMesh("hat", headGroup, hatGeo, mat, "y" /* Y */, 4);
5562
- }
5654
+ const hatGeo = this.getBoxGeometry("hat" /* HAT */);
5655
+ const hat = this.createAndAddMesh("hat", headGroup, hatGeo, mat, "y" /* Y */, 4);
5563
5656
  }
5564
5657
  {
5565
5658
  const bodyGroup = this.createAndAddGroup("body", 0, 18, 0);
@@ -5602,21 +5695,58 @@ var SkinObject = class extends SceneObject {
5602
5695
  }
5603
5696
  console.log("#createMeshes done");
5604
5697
  }
5605
- setSkinTexture(src) {
5698
+ async setSkinTexture(src) {
5606
5699
  if (typeof src === "undefined") return;
5607
- const mat = Materials.getImage({
5608
- texture: { src },
5609
- transparent: true
5610
- });
5611
- for (let part of SKIN_PARTS) {
5612
- let mesh = this.getMeshByName(part);
5700
+ this.skinTextureSrc = src;
5701
+ const load = ++this.skinLoad;
5702
+ const texture = await SkinTextures.get(src, this.options.legacy);
5703
+ if (load !== this.skinLoad) return;
5704
+ this.skinMaterial = texture.material;
5705
+ this.detectedSlim = texture.slim;
5706
+ this.updateSlim(this.options.slim ?? this.detectedSlim);
5707
+ for (const part of SKIN_PARTS) {
5708
+ if (part === "cape" /* CAPE */) continue;
5709
+ const mesh = this.getMeshByName(part);
5613
5710
  if (mesh) {
5614
- mesh.material = mat;
5711
+ mesh.material = texture.material;
5615
5712
  }
5616
5713
  }
5714
+ this.notifyDirty();
5715
+ }
5716
+ /** Load a vanilla cape texture, or pass undefined to remove the cape. */
5717
+ async setCapeTexture(src) {
5718
+ const load = ++this.capeLoad;
5719
+ if (src === void 0) {
5720
+ const group = this.getGroupByName("cape" /* CAPE */);
5721
+ if (group) this.remove(group);
5722
+ this.notifyDirty();
5723
+ return;
5724
+ }
5725
+ const material = await SkinTextures.getCape(src);
5726
+ if (load !== this.capeLoad) return;
5727
+ const mesh = this.getMeshByName("cape" /* CAPE */);
5728
+ if (mesh) {
5729
+ mesh.material = material;
5730
+ } else {
5731
+ const group = this.createAndAddGroup("cape" /* CAPE */, 0, 24, 2);
5732
+ group.rotation.set(toRadians(-6), Math.PI, 0);
5733
+ const geometry = this._getBoxGeometryFromDimensions(
5734
+ classicSkinGeometries.cape,
5735
+ classicSkinTextureCoordinates.cape,
5736
+ [64, 32],
5737
+ [64, 32]
5738
+ );
5739
+ const cape = this.createAndAddMesh("cape" /* CAPE */, group, geometry, material);
5740
+ cape.position.set(0, -8, -0.5);
5741
+ }
5742
+ this.notifyDirty();
5617
5743
  }
5618
- //TODO: cape
5744
+ /** Select the arm model, or pass undefined to use texture detection. */
5619
5745
  setSlim(slim) {
5746
+ this.options.slim = slim;
5747
+ this.updateSlim(slim ?? this.detectedSlim);
5748
+ }
5749
+ updateSlim(slim) {
5620
5750
  if (slim === this.slim) return;
5621
5751
  this.slim = slim;
5622
5752
  for (const part of ["leftArm" /* LEFT_ARM */, "leftSleeve" /* LEFT_SLEEVE */, "rightArm" /* RIGHT_ARM */, "rightSleeve" /* RIGHT_SLEEVE */]) {
@@ -5630,17 +5760,23 @@ var SkinObject = class extends SceneObject {
5630
5760
  if (rightArm) rightArm.position.x -= offset;
5631
5761
  this.notifyDirty();
5632
5762
  }
5633
- setLegacy(legacy) {
5634
- if (legacy !== this.legacy) {
5635
- }
5636
- this.legacy = legacy;
5763
+ /** Select the texture layout, or pass undefined to detect it from image dimensions. */
5764
+ async setLegacy(legacy) {
5765
+ if (legacy === this.options.legacy) return;
5766
+ this.options.legacy = legacy;
5767
+ if (this.skinTextureSrc) await this.setSkinTexture(this.skinTextureSrc);
5768
+ }
5769
+ dispose() {
5770
+ this.skinLoad++;
5771
+ this.capeLoad++;
5772
+ super.dispose();
5637
5773
  }
5638
5774
  //TODO: layer toggles
5639
5775
  getBoxGeometry(part) {
5640
5776
  console.log("slim", this.slim);
5641
5777
  const coordinates = this.slim ? slimSkinTextureCoordinates : classicSkinTextureCoordinates;
5642
5778
  const geometries = this.slim ? slimSkinGeometries : classicSkinGeometries;
5643
- return this._getBoxGeometryFromDimensions(geometries[part], coordinates[part], [64, 64], [this.skinTextureWidth, this.skinTextureHeight]);
5779
+ return this._getBoxGeometryFromDimensions(geometries[part], coordinates[part], [64, 64], [64, 64]);
5644
5780
  }
5645
5781
  };
5646
5782
 
@@ -5750,10 +5886,10 @@ var _MineRenderScene = class _MineRenderScene extends Scene2 {
5750
5886
  this.dirty = true;
5751
5887
  const obj = new SkinObject(options);
5752
5888
  obj.scene = this;
5753
- await obj.init();
5754
5889
  if (skin) {
5755
- obj.setSkinTexture(skin);
5890
+ await obj.setSkinTexture(skin);
5756
5891
  }
5892
+ await obj.init();
5757
5893
  parent.add(obj);
5758
5894
  return obj;
5759
5895
  }
@@ -5768,7 +5904,7 @@ function isMineRenderScene(obj) {
5768
5904
  }
5769
5905
 
5770
5906
  // src/renderer/Renderer.ts
5771
- import { AxesHelper as AxesHelper2, GridHelper, OrthographicCamera, PCFSoftShadowMap, PerspectiveCamera, SRGBColorSpace as SRGBColorSpace3, Vector3 as Vector39, WebGLRenderer } from "three";
5907
+ import { AxesHelper as AxesHelper2, GridHelper, OrthographicCamera, PCFSoftShadowMap, PerspectiveCamera, SRGBColorSpace as SRGBColorSpace4, Vector3 as Vector39, WebGLRenderer } from "three";
5772
5908
  var import_ts_deepmerge9 = __toESM(require_dist());
5773
5909
  import Stats from "stats.js";
5774
5910
  import { EffectComposer, RenderPass } from "postprocessing";
@@ -6483,7 +6619,7 @@ var _Renderer = class _Renderer {
6483
6619
  renderer.setClearColor(0, 0);
6484
6620
  renderer.shadowMap.enabled = true;
6485
6621
  renderer.shadowMap.type = PCFSoftShadowMap;
6486
- renderer.outputColorSpace = SRGBColorSpace3;
6622
+ renderer.outputColorSpace = SRGBColorSpace4;
6487
6623
  renderer.setSize(this.viewWidth, this.viewHeight);
6488
6624
  return renderer;
6489
6625
  }
@@ -7228,6 +7364,7 @@ export {
7228
7364
  SchematicParser,
7229
7365
  SkinObject,
7230
7366
  SkinPart,
7367
+ SkinTextures,
7231
7368
  Skins,
7232
7369
  StructureParser,
7233
7370
  TextureAtlas,