minerender 2.1.0-alpha.51 → 2.1.0-alpha.53

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.
@@ -3535,48 +3535,6 @@ var init_SceneObject = __esm({
3535
3535
  }
3536
3536
  });
3537
3537
 
3538
- // src/model/ModelCulling.ts
3539
- var import_three22, ModelCulling;
3540
- var init_ModelCulling = __esm({
3541
- "src/model/ModelCulling.ts"() {
3542
- import_three22 = require("three");
3543
- init_CubeFace();
3544
- ModelCulling = class {
3545
- static toLocalMask(worldMask, rotation) {
3546
- let localMask = 0;
3547
- for (const [localFace, offset] of CUBE_FACE_OFFSETS.entries()) {
3548
- const normal = new import_three22.Vector3(...offset).applyEuler(rotation);
3549
- const worldFace = CUBE_FACE_OFFSETS.findIndex(([x, y, z]) => Math.abs(normal.x - x) < 1e-6 && Math.abs(normal.y - y) < 1e-6 && Math.abs(normal.z - z) < 1e-6);
3550
- if (worldFace < 0) return 0;
3551
- if (worldMask & 1 << worldFace) localMask |= 1 << localFace;
3552
- }
3553
- return localMask;
3554
- }
3555
- static isOpaqueFullCube(atlas) {
3556
- if (!atlas || atlas.hasTransparency !== false || atlas.model.elements?.length !== 1) return false;
3557
- const element = atlas.model.elements[0];
3558
- if (element.from.length !== 3 || !element.from.every((value) => value === 0) || element.to.length !== 3 || !element.to.every((value) => value === 16) || element.rotation && element.rotation.angle !== 0 || element.mappedUv?.length !== 48 || !element.mappedUv.every(Number.isFinite)) return false;
3559
- if (!(atlas.image.width > 0 && atlas.image.height > 0)) return false;
3560
- return CUBE_FACES.every((face, faceIndex) => {
3561
- const texture = element.faces[face]?.texture;
3562
- if (!texture?.startsWith("#")) return false;
3563
- const key = texture.slice(1);
3564
- const position = atlas.positions[key];
3565
- const size = atlas.sizes[key];
3566
- if (position?.length !== 2 || !position.every(Number.isFinite) || size?.length !== 2 || !size.every((value) => value > 0 && Number.isFinite(value))) return false;
3567
- for (let vertex = 0; vertex < 4; vertex++) {
3568
- const uvIndex = (faceIndex * 4 + vertex) * 2;
3569
- const x = element.mappedUv[uvIndex] * atlas.image.width;
3570
- const y = (1 - element.mappedUv[uvIndex + 1]) * atlas.image.height;
3571
- if (x < position[0] - 1e-6 || x > position[0] + size[0] + 1e-6 || y < position[1] - 1e-6 || y > position[1] + size[1] + 1e-6) return false;
3572
- }
3573
- return true;
3574
- });
3575
- }
3576
- };
3577
- }
3578
- });
3579
-
3580
3538
  // src/three/BufferGeometryUtils.js
3581
3539
  function computeTangents(geometry) {
3582
3540
  geometry.computeTangents();
@@ -3589,7 +3547,7 @@ function mergeBufferGeometries(geometries, useGroups = false) {
3589
3547
  const attributes = {};
3590
3548
  const morphAttributes = {};
3591
3549
  const morphTargetsRelative = geometries[0].morphTargetsRelative;
3592
- const mergedGeometry = new import_three24.BufferGeometry();
3550
+ const mergedGeometry = new import_three19.BufferGeometry();
3593
3551
  let offset = 0;
3594
3552
  for (let i = 0; i < geometries.length; ++i) {
3595
3553
  const geometry = geometries[i];
@@ -3713,7 +3671,7 @@ function mergeBufferAttributes(attributes) {
3713
3671
  array.set(attributes[i].array, offset);
3714
3672
  offset += attributes[i].array.length;
3715
3673
  }
3716
- return new import_three24.BufferAttribute(array, itemSize, normalized);
3674
+ return new import_three19.BufferAttribute(array, itemSize, normalized);
3717
3675
  }
3718
3676
  function interleaveAttributes(attributes) {
3719
3677
  let TypedArray;
@@ -3729,7 +3687,7 @@ function interleaveAttributes(attributes) {
3729
3687
  arrayLength += attribute.array.length;
3730
3688
  stride += attribute.itemSize;
3731
3689
  }
3732
- const interleavedBuffer = new import_three24.InterleavedBuffer(new TypedArray(arrayLength), stride);
3690
+ const interleavedBuffer = new import_three19.InterleavedBuffer(new TypedArray(arrayLength), stride);
3733
3691
  let offset = 0;
3734
3692
  const res = [];
3735
3693
  const getters = ["getX", "getY", "getZ", "getW"];
@@ -3738,7 +3696,7 @@ function interleaveAttributes(attributes) {
3738
3696
  const attribute = attributes[j];
3739
3697
  const itemSize = attribute.itemSize;
3740
3698
  const count = attribute.count;
3741
- const iba = new import_three24.InterleavedBufferAttribute(interleavedBuffer, itemSize, offset, attribute.normalized);
3699
+ const iba = new import_three19.InterleavedBufferAttribute(interleavedBuffer, itemSize, offset, attribute.normalized);
3742
3700
  res.push(iba);
3743
3701
  offset += itemSize;
3744
3702
  for (let c = 0; c < count; c++) {
@@ -3822,13 +3780,13 @@ function mergeVertices(geometry, tolerance = 1e-4) {
3822
3780
  const name = attributeNames[i];
3823
3781
  const oldAttribute = geometry.getAttribute(name);
3824
3782
  const buffer = new oldAttribute.array.constructor(attrArrays[name]);
3825
- const attribute = new import_three24.BufferAttribute(buffer, oldAttribute.itemSize, oldAttribute.normalized);
3783
+ const attribute = new import_three19.BufferAttribute(buffer, oldAttribute.itemSize, oldAttribute.normalized);
3826
3784
  result.setAttribute(name, attribute);
3827
3785
  if (name in morphAttrsArrays) {
3828
3786
  for (let j = 0; j < morphAttrsArrays[name].length; j++) {
3829
3787
  const oldMorphAttribute = geometry.morphAttributes[name][j];
3830
3788
  const buffer2 = new oldMorphAttribute.array.constructor(morphAttrsArrays[name][j]);
3831
- const morphAttribute = new import_three24.BufferAttribute(buffer2, oldMorphAttribute.itemSize, oldMorphAttribute.normalized);
3789
+ const morphAttribute = new import_three19.BufferAttribute(buffer2, oldMorphAttribute.itemSize, oldMorphAttribute.normalized);
3832
3790
  result.morphAttributes[name][j] = morphAttribute;
3833
3791
  }
3834
3792
  }
@@ -3837,11 +3795,11 @@ function mergeVertices(geometry, tolerance = 1e-4) {
3837
3795
  return result;
3838
3796
  }
3839
3797
  function toTrianglesDrawMode(geometry, drawMode) {
3840
- if (drawMode === import_three24.TrianglesDrawMode) {
3798
+ if (drawMode === import_three19.TrianglesDrawMode) {
3841
3799
  console.warn("THREE.BufferGeometryUtils.toTrianglesDrawMode(): Geometry already defined as triangles.");
3842
3800
  return geometry;
3843
3801
  }
3844
- if (drawMode === import_three24.TriangleFanDrawMode || drawMode === import_three24.TriangleStripDrawMode) {
3802
+ if (drawMode === import_three19.TriangleFanDrawMode || drawMode === import_three19.TriangleStripDrawMode) {
3845
3803
  let index = geometry.getIndex();
3846
3804
  if (index === null) {
3847
3805
  const indices = [];
@@ -3859,7 +3817,7 @@ function toTrianglesDrawMode(geometry, drawMode) {
3859
3817
  }
3860
3818
  const numberOfTriangles = index.count - 2;
3861
3819
  const newIndices = [];
3862
- if (drawMode === import_three24.TriangleFanDrawMode) {
3820
+ if (drawMode === import_three19.TriangleFanDrawMode) {
3863
3821
  for (let i = 1; i <= numberOfTriangles; i++) {
3864
3822
  newIndices.push(index.getX(0));
3865
3823
  newIndices.push(index.getX(i));
@@ -3895,15 +3853,15 @@ function computeMorphedAttributes(object) {
3895
3853
  console.error("THREE.BufferGeometryUtils: Geometry is not of type BufferGeometry.");
3896
3854
  return null;
3897
3855
  }
3898
- const _vA = new import_three24.Vector3();
3899
- const _vB = new import_three24.Vector3();
3900
- const _vC = new import_three24.Vector3();
3901
- const _tempA = new import_three24.Vector3();
3902
- const _tempB = new import_three24.Vector3();
3903
- const _tempC = new import_three24.Vector3();
3904
- const _morphA = new import_three24.Vector3();
3905
- const _morphB = new import_three24.Vector3();
3906
- const _morphC = new import_three24.Vector3();
3856
+ const _vA = new import_three19.Vector3();
3857
+ const _vB = new import_three19.Vector3();
3858
+ const _vC = new import_three19.Vector3();
3859
+ const _tempA = new import_three19.Vector3();
3860
+ const _tempB = new import_three19.Vector3();
3861
+ const _tempC = new import_three19.Vector3();
3862
+ const _morphA = new import_three19.Vector3();
3863
+ const _morphB = new import_three19.Vector3();
3864
+ const _morphC = new import_three19.Vector3();
3907
3865
  function _calculateMorphedAttributeData(object2, material2, attribute, morphAttribute, morphTargetsRelative2, a2, b2, c2, modifiedAttributeArray) {
3908
3866
  _vA.fromBufferAttribute(attribute, a2);
3909
3867
  _vB.fromBufferAttribute(attribute, b2);
@@ -4098,8 +4056,8 @@ function computeMorphedAttributes(object) {
4098
4056
  }
4099
4057
  }
4100
4058
  }
4101
- const morphedPositionAttribute = new import_three24.Float32BufferAttribute(modifiedPosition, 3);
4102
- const morphedNormalAttribute = new import_three24.Float32BufferAttribute(modifiedNormal, 3);
4059
+ const morphedPositionAttribute = new import_three19.Float32BufferAttribute(modifiedPosition, 3);
4060
+ const morphedNormalAttribute = new import_three19.Float32BufferAttribute(modifiedNormal, 3);
4103
4061
  return {
4104
4062
  positionAttribute,
4105
4063
  normalAttribute,
@@ -4107,10 +4065,52 @@ function computeMorphedAttributes(object) {
4107
4065
  morphedNormalAttribute
4108
4066
  };
4109
4067
  }
4110
- var import_three24;
4068
+ var import_three19;
4111
4069
  var init_BufferGeometryUtils = __esm({
4112
4070
  "src/three/BufferGeometryUtils.js"() {
4113
- import_three24 = require("three");
4071
+ import_three19 = require("three");
4072
+ }
4073
+ });
4074
+
4075
+ // src/model/ModelCulling.ts
4076
+ var import_three20, ModelCulling;
4077
+ var init_ModelCulling = __esm({
4078
+ "src/model/ModelCulling.ts"() {
4079
+ import_three20 = require("three");
4080
+ init_CubeFace();
4081
+ ModelCulling = class {
4082
+ static toLocalMask(worldMask, rotation) {
4083
+ let localMask = 0;
4084
+ for (const [localFace, offset] of CUBE_FACE_OFFSETS.entries()) {
4085
+ const normal = new import_three20.Vector3(...offset).applyEuler(rotation);
4086
+ const worldFace = CUBE_FACE_OFFSETS.findIndex(([x, y, z]) => Math.abs(normal.x - x) < 1e-6 && Math.abs(normal.y - y) < 1e-6 && Math.abs(normal.z - z) < 1e-6);
4087
+ if (worldFace < 0) return 0;
4088
+ if (worldMask & 1 << worldFace) localMask |= 1 << localFace;
4089
+ }
4090
+ return localMask;
4091
+ }
4092
+ static isOpaqueFullCube(atlas) {
4093
+ if (!atlas || atlas.hasTransparency !== false || atlas.model.elements?.length !== 1) return false;
4094
+ const element = atlas.model.elements[0];
4095
+ if (element.from.length !== 3 || !element.from.every((value) => value === 0) || element.to.length !== 3 || !element.to.every((value) => value === 16) || element.rotation && element.rotation.angle !== 0 || element.mappedUv?.length !== 48 || !element.mappedUv.every(Number.isFinite)) return false;
4096
+ if (!(atlas.image.width > 0 && atlas.image.height > 0)) return false;
4097
+ return CUBE_FACES.every((face, faceIndex) => {
4098
+ const texture = element.faces[face]?.texture;
4099
+ if (!texture?.startsWith("#")) return false;
4100
+ const key = texture.slice(1);
4101
+ const position = atlas.positions[key];
4102
+ const size = atlas.sizes[key];
4103
+ if (position?.length !== 2 || !position.every(Number.isFinite) || size?.length !== 2 || !size.every((value) => value > 0 && Number.isFinite(value))) return false;
4104
+ for (let vertex = 0; vertex < 4; vertex++) {
4105
+ const uvIndex = (faceIndex * 4 + vertex) * 2;
4106
+ const x = element.mappedUv[uvIndex] * atlas.image.width;
4107
+ const y = (1 - element.mappedUv[uvIndex + 1]) * atlas.image.height;
4108
+ if (x < position[0] - 1e-6 || x > position[0] + size[0] + 1e-6 || y < position[1] - 1e-6 || y > position[1] + size[1] + 1e-6) return false;
4109
+ }
4110
+ return true;
4111
+ });
4112
+ }
4113
+ };
4114
4114
  }
4115
4115
  });
4116
4116
 
@@ -4118,13 +4118,13 @@ var init_BufferGeometryUtils = __esm({
4118
4118
  function isModelObject(obj) {
4119
4119
  return obj.isModelObject;
4120
4120
  }
4121
- var import_three25, import_ts_deepmerge5, p9, ModelObject;
4121
+ var import_three21, import_ts_deepmerge5, p7, ModelObject;
4122
4122
  var init_ModelObject = __esm({
4123
4123
  "src/model/scene/ModelObject.ts"() {
4124
4124
  init_SceneObject();
4125
4125
  init_Materials();
4126
4126
  init_UVMapper();
4127
- import_three25 = require("three");
4127
+ import_three21 = require("three");
4128
4128
  init_BufferGeometryUtils();
4129
4129
  init_model();
4130
4130
  import_ts_deepmerge5 = __toESM(require_dist());
@@ -4132,7 +4132,7 @@ var init_ModelObject = __esm({
4132
4132
  init_CubeFace();
4133
4133
  init_DisplayTransforms();
4134
4134
  init_ModelCulling();
4135
- p9 = prefix("ModelObject");
4135
+ p7 = prefix("ModelObject");
4136
4136
  ModelObject = class _ModelObject extends SceneObject {
4137
4137
  constructor(originalModel, options) {
4138
4138
  super(options);
@@ -4181,7 +4181,7 @@ var init_ModelObject = __esm({
4181
4181
  elGeo.clearGroups();
4182
4182
  }
4183
4183
  if (this.options.uvLockRotation) {
4184
- UVMapper.lockUvs(elGeo, el.faces, this.atlas, new import_three25.Euler(...this.options.uvLockRotation));
4184
+ UVMapper.lockUvs(elGeo, el.faces, this.atlas, new import_three21.Euler(...this.options.uvLockRotation));
4185
4185
  }
4186
4186
  if (this.options.tints) {
4187
4187
  const colors = new Float32Array(elGeo.getAttribute("position").count * 3).fill(1);
@@ -4190,19 +4190,19 @@ var init_ModelObject = __esm({
4190
4190
  if (tintIndex === void 0 || tintIndex < 0) continue;
4191
4191
  const tint = this.options.tints[tintIndex];
4192
4192
  if (tint === void 0) continue;
4193
- const color = new import_three25.Color(tint);
4193
+ const color = new import_three21.Color(tint);
4194
4194
  for (let vertex = 0; vertex < 4; vertex++) {
4195
4195
  color.toArray(colors, (faceIndex * 4 + vertex) * 3);
4196
4196
  }
4197
4197
  }
4198
- elGeo.setAttribute("color", new import_three25.BufferAttribute(colors, 3));
4198
+ elGeo.setAttribute("color", new import_three21.BufferAttribute(colors, 3));
4199
4199
  }
4200
- elGeo.applyMatrix4(new import_three25.Matrix4().makeTranslation((el.to[0] - el.from[0]) / 2, (el.to[1] - el.from[1]) / 2, (el.to[2] - el.from[2]) / 2));
4201
- elGeo.applyMatrix4(new import_three25.Matrix4().makeTranslation(el.from[0], el.from[1], el.from[2]));
4200
+ elGeo.applyMatrix4(new import_three21.Matrix4().makeTranslation((el.to[0] - el.from[0]) / 2, (el.to[1] - el.from[1]) / 2, (el.to[2] - el.from[2]) / 2));
4201
+ elGeo.applyMatrix4(new import_three21.Matrix4().makeTranslation(el.from[0], el.from[1], el.from[2]));
4202
4202
  if (el.rotation) {
4203
4203
  applyElementRotation(el.rotation, elGeo);
4204
4204
  }
4205
- elGeo.applyMatrix4(new import_three25.Matrix4().makeTranslation(-8, -8, -8));
4205
+ elGeo.applyMatrix4(new import_three21.Matrix4().makeTranslation(-8, -8, -8));
4206
4206
  if (displayTransform) DisplayTransforms.apply(elGeo, displayTransform);
4207
4207
  if (this.options.mergeMeshes) {
4208
4208
  allGeos.push(elGeo);
@@ -4214,17 +4214,17 @@ var init_ModelObject = __esm({
4214
4214
  }
4215
4215
  });
4216
4216
  } else {
4217
- console.debug(p9, this.atlas.model, "has no elements");
4217
+ console.debug(p7, this.atlas.model, "has no elements");
4218
4218
  }
4219
4219
  } else {
4220
- console.debug(p9, "Missing atlas for", this);
4220
+ console.debug(p7, "Missing atlas for", this);
4221
4221
  }
4222
4222
  if (this.options.mergeMeshes) {
4223
4223
  let combinedGeo;
4224
4224
  if (allGeos.length > 0) {
4225
4225
  combinedGeo = mergeBufferGeometries(allGeos);
4226
4226
  } else {
4227
- combinedGeo = new import_three25.BoxGeometry(16, 16, 16);
4227
+ combinedGeo = new import_three21.BoxGeometry(16, 16, 16);
4228
4228
  if (displayTransform) DisplayTransforms.apply(combinedGeo, displayTransform);
4229
4229
  }
4230
4230
  combinedGeo.computeBoundingBox();
@@ -7712,19 +7712,31 @@ var GuiHelper = class {
7712
7712
  };
7713
7713
 
7714
7714
  // src/gui/scene/GuiObject.ts
7715
- var import_three19 = require("three");
7715
+ var import_three22 = require("three");
7716
7716
  init_AssetKey();
7717
7717
  init_ModelTextures();
7718
+ init_Models();
7718
7719
  init_Caching();
7719
7720
  init_SceneObject();
7720
7721
  init_Materials();
7722
+ init_ModelObject();
7723
+ init_DisplayPosition();
7724
+
7725
+ // src/model/GuiLight.ts
7726
+ var GuiLight = /* @__PURE__ */ ((GuiLight2) => {
7727
+ GuiLight2["FRONT"] = "front";
7728
+ GuiLight2["SIDE"] = "side";
7729
+ return GuiLight2;
7730
+ })(GuiLight || {});
7731
+
7732
+ // src/gui/scene/GuiObject.ts
7721
7733
  var GuiObject = class extends SceneObject {
7722
7734
  constructor(textureLayers, options) {
7723
7735
  super({ ...options, instanceMeshes: false, mergeMeshes: false });
7724
7736
  this.textureLayers = textureLayers;
7725
7737
  this.isGuiObject = true;
7726
7738
  /** Local bounds in GUI pixels, with y growing down from the origin. */
7727
- this.bounds = new import_three19.Box2();
7739
+ this.bounds = new import_three22.Box2();
7728
7740
  this.geometries = /* @__PURE__ */ new Set();
7729
7741
  this.ownedMaterials = /* @__PURE__ */ new Set();
7730
7742
  this.initialized = false;
@@ -7732,14 +7744,35 @@ var GuiObject = class extends SceneObject {
7732
7744
  async init() {
7733
7745
  if (this.initialized) return;
7734
7746
  try {
7747
+ let depth = 0;
7735
7748
  for (const [index, layer] of this.textureLayers.entries()) {
7749
+ const [x, y] = layer.position ?? [0, 0];
7750
+ if ("item" in layer) {
7751
+ const [width2, height2] = layer.size ?? [16, 16];
7752
+ const item = await this.createItem(layer, index);
7753
+ item.position.set(x + width2 / 2, -y - height2 / 2, 0);
7754
+ item.scale.set(width2 / 16, height2 / 16, width2 / 16);
7755
+ item.updateMatrix();
7756
+ const bounds = new import_three22.Box3();
7757
+ item.iterateAllMeshes((mesh2) => {
7758
+ mesh2.geometry.computeBoundingBox();
7759
+ bounds.union(mesh2.geometry.boundingBox);
7760
+ });
7761
+ bounds.applyMatrix4(item.matrix);
7762
+ item.position.z = depth - bounds.min.z;
7763
+ depth += bounds.max.z - bounds.min.z + 0.01;
7764
+ this.bounds.expandByPoint(new import_three22.Vector2(x, y));
7765
+ this.bounds.expandByPoint(new import_three22.Vector2(x + width2, y + height2));
7766
+ this.bounds.expandByPoint(new import_three22.Vector2(bounds.min.x, -bounds.max.y));
7767
+ this.bounds.expandByPoint(new import_three22.Vector2(bounds.max.x, -bounds.min.y));
7768
+ continue;
7769
+ }
7736
7770
  const key = typeof layer.texture === "string" ? AssetKey.parse("textures", layer.texture) : layer.texture;
7737
7771
  const material = await this.loadMaterial(key);
7738
7772
  const image = material.map.image;
7739
7773
  const [cropX, cropY, cropWidth, cropHeight] = layer.crop ?? [0, 0, image.width, image.height];
7740
7774
  const [width, height] = layer.size ?? [cropWidth, cropHeight];
7741
- const [x, y] = layer.position ?? [0, 0];
7742
- const geometry = new import_three19.PlaneGeometry(width, height);
7775
+ const geometry = new import_three22.PlaneGeometry(width, height);
7743
7776
  this.geometries.add(geometry);
7744
7777
  const uv = geometry.getAttribute("uv");
7745
7778
  for (let i = 0; i < uv.count; i++) {
@@ -7749,14 +7782,16 @@ var GuiObject = class extends SceneObject {
7749
7782
  1 - (cropY + (1 - uv.getY(i)) * cropHeight) / image.height
7750
7783
  );
7751
7784
  }
7752
- const mesh = new import_three19.Mesh(geometry, material);
7785
+ const mesh = new import_three22.Mesh(geometry, material);
7753
7786
  mesh.name = `mesh:${layer.name ?? index}`;
7754
- mesh.position.set(x + width / 2, -y - height / 2, 0);
7787
+ mesh.position.set(x + width / 2, -y - height / 2, depth);
7755
7788
  mesh.renderOrder = index;
7756
7789
  this.add(mesh);
7757
- this.bounds.expandByPoint(new import_three19.Vector2(x, y));
7758
- this.bounds.expandByPoint(new import_three19.Vector2(x + width, y + height));
7790
+ this.bounds.expandByPoint(new import_three22.Vector2(x, y));
7791
+ this.bounds.expandByPoint(new import_three22.Vector2(x + width, y + height));
7792
+ depth += 0.01;
7759
7793
  }
7794
+ for (const child of this.children) child.position.z -= depth - 0.01;
7760
7795
  this.initialized = true;
7761
7796
  this.notifyDirty();
7762
7797
  } catch (error) {
@@ -7764,6 +7799,32 @@ var GuiObject = class extends SceneObject {
7764
7799
  throw error;
7765
7800
  }
7766
7801
  }
7802
+ async createItem(layer, index) {
7803
+ const key = typeof layer.item === "string" ? AssetKey.parse("models", layer.item) : layer.item;
7804
+ const model = await Models.getMerged(key);
7805
+ if (!model) throw new Error(`Could not load GUI item ${key.toNamespacedString()}`);
7806
+ const item = new ModelObject(model, {
7807
+ displayPosition: "gui" /* GUI */,
7808
+ tints: layer.tints,
7809
+ instanceMeshes: false,
7810
+ mergeMeshes: true
7811
+ });
7812
+ item.name = `group:${layer.name ?? index}`;
7813
+ this.add(item);
7814
+ await item.init();
7815
+ item.iterateAllMeshes((mesh) => {
7816
+ this.geometries.add(mesh.geometry);
7817
+ mesh.name = `mesh:${layer.name ?? index}`;
7818
+ mesh.renderOrder = index;
7819
+ for (const material of Array.isArray(mesh.material) ? mesh.material : [mesh.material]) {
7820
+ material.transparent = true;
7821
+ if (model.gui_light === "front" /* FRONT */ && material.uniforms?.SHADE) {
7822
+ material.uniforms.SHADE.value = false;
7823
+ }
7824
+ }
7825
+ });
7826
+ return item;
7827
+ }
7767
7828
  async loadMaterial(key) {
7768
7829
  const assetKey = key.serialize();
7769
7830
  const materialKey = `gui:${assetKey}`;
@@ -7802,21 +7863,21 @@ function isGuiObject(obj) {
7802
7863
  init_image();
7803
7864
 
7804
7865
  // src/inspector/SceneInspector.ts
7805
- var import_three20 = require("three");
7866
+ var import_three23 = require("three");
7806
7867
  init_SceneObject();
7807
7868
  init_util();
7808
7869
  init_log();
7809
7870
  init_three();
7810
- var p7 = prefix("SceneInspector");
7871
+ var p8 = prefix("SceneInspector");
7811
7872
  var help = "<span>Ctrl/Cmd+Click to Select<br/></span><br/>";
7812
7873
  var SceneInspector = class {
7813
7874
  constructor(renderer) {
7814
7875
  this.renderer = renderer;
7815
- this.mouse = new import_three20.Vector2();
7876
+ this.mouse = new import_three23.Vector2();
7816
7877
  this.listeners = new AbortController();
7817
7878
  this.objectInfoContainer = document.createElement("div");
7818
7879
  this.objectControlsContainer = document.createElement("div");
7819
- this.raycaster = new import_three20.Raycaster();
7880
+ this.raycaster = new import_three23.Raycaster();
7820
7881
  this.init();
7821
7882
  }
7822
7883
  init() {
@@ -7901,7 +7962,7 @@ var SceneInspector = class {
7901
7962
  }
7902
7963
  selectObject(targetObject, targetIntersection, instance = this.getIntersectionInstance(targetIntersection)) {
7903
7964
  this.selectedObject = targetObject;
7904
- console.log(p7, "selected", targetObject);
7965
+ console.log(p8, "selected", targetObject);
7905
7966
  this.redraw(targetObject, targetIntersection, instance);
7906
7967
  }
7907
7968
  redraw(targetObject, targetIntersection, instance) {
@@ -8133,7 +8194,7 @@ var SceneStatsDisplay = class {
8133
8194
  }
8134
8195
  init() {
8135
8196
  this.statsContainer.classList.add("minerender-stats");
8136
- setInterval(() => {
8197
+ this.interval = setInterval(() => {
8137
8198
  for (let line of this.lines) {
8138
8199
  line.update();
8139
8200
  }
@@ -8142,6 +8203,13 @@ var SceneStatsDisplay = class {
8142
8203
  appendTo(el) {
8143
8204
  el.append(this.statsContainer);
8144
8205
  }
8206
+ dispose() {
8207
+ clearInterval(this.interval);
8208
+ this.interval = void 0;
8209
+ this.lines.length = 0;
8210
+ this.statsContainer.replaceChildren();
8211
+ this.statsContainer.remove();
8212
+ }
8145
8213
  add(line) {
8146
8214
  if (typeof line !== "undefined") {
8147
8215
  this.lines.push(line);
@@ -8153,7 +8221,7 @@ var SceneStatsDisplay = class {
8153
8221
 
8154
8222
  // src/instance/InstanceManager.ts
8155
8223
  init_log();
8156
- var p8 = prefix("InstanceManager");
8224
+ var p9 = prefix("InstanceManager");
8157
8225
  var InstanceManager = class {
8158
8226
  constructor() {
8159
8227
  this.isInstanceManager = true;
@@ -8161,7 +8229,7 @@ var InstanceManager = class {
8161
8229
  }
8162
8230
  async get(key) {
8163
8231
  if (key in this.instanceCache) {
8164
- console.debug(p8, "key in cache", key);
8232
+ console.debug(p9, "key in cache", key);
8165
8233
  return (await this.instanceCache[key]).nextInstance();
8166
8234
  }
8167
8235
  return void 0;
@@ -8170,7 +8238,7 @@ var InstanceManager = class {
8170
8238
  if (key in this.instanceCache) {
8171
8239
  return await this.get(key);
8172
8240
  }
8173
- console.debug(p8, "key not in cache", key);
8241
+ console.debug(p9, "key not in cache", key);
8174
8242
  const pending = Promise.resolve().then(supplier).then((obj) => obj.nextInstance());
8175
8243
  this.instanceCache[key] = pending;
8176
8244
  try {
@@ -8204,13 +8272,6 @@ function isInstanceable(obj) {
8204
8272
  init_DisplayPosition();
8205
8273
  init_DisplayTransforms();
8206
8274
 
8207
- // src/model/GuiLight.ts
8208
- var GuiLight = /* @__PURE__ */ ((GuiLight2) => {
8209
- GuiLight2["FRONT"] = "front";
8210
- GuiLight2["SIDE"] = "side";
8211
- return GuiLight2;
8212
- })(GuiLight || {});
8213
-
8214
8275
  // src/model/Model.ts
8215
8276
  var ITEM_GENERATED = "item/generated";
8216
8277
  var BUILTIN_GENERATED = "builtin/generated";
@@ -8232,7 +8293,7 @@ init_ModelGenerator();
8232
8293
  init_ModelMerger();
8233
8294
 
8234
8295
  // src/model/block/BlockStateResolver.ts
8235
- var import_three23 = require("three");
8296
+ var import_three25 = require("three");
8236
8297
  init_BlockStates();
8237
8298
  init_MineRenderError();
8238
8299
  init_util();
@@ -8310,7 +8371,7 @@ var BlockStateResolver = class {
8310
8371
  return variants[variants.length - 1];
8311
8372
  }
8312
8373
  static rotation(variant) {
8313
- const rotation = new import_three23.Euler();
8374
+ const rotation = new import_three25.Euler();
8314
8375
  if (typeof variant.x !== "undefined") {
8315
8376
  rotation.x = toRadians(clampRotationDegrees(variant.x));
8316
8377
  }
@@ -12381,7 +12442,10 @@ var Renderer = class _Renderer {
12381
12442
  constructor(options) {
12382
12443
  this._dirty = true;
12383
12444
  this._resizeListener = void 0;
12445
+ this._running = false;
12446
+ this._inAnimationLoop = false;
12384
12447
  this._disposed = false;
12448
+ this._frameCallbacks = /* @__PURE__ */ new Map();
12385
12449
  this._debugHelpers = [];
12386
12450
  this._eventDispatchers = /* @__PURE__ */ new Map();
12387
12451
  this._changeListener = () => {
@@ -12392,7 +12456,14 @@ var Renderer = class _Renderer {
12392
12456
  if (!Number.isFinite(pixelRatio) || pixelRatio <= 0) {
12393
12457
  throw new RangeError("render.pixelRatio must be a finite positive number");
12394
12458
  }
12395
- this._animationLoop = this.animate.bind(this);
12459
+ this._animationLoop = (time) => {
12460
+ this._inAnimationLoop = true;
12461
+ try {
12462
+ this.animate(time);
12463
+ } finally {
12464
+ this._inAnimationLoop = false;
12465
+ }
12466
+ };
12396
12467
  this._frameInterval = this.options.render.fpsLimit > 0 ? 1e3 / this.options.render.fpsLimit : void 0;
12397
12468
  this._scene = this.createScene();
12398
12469
  this._camera = this.createCamera();
@@ -12607,15 +12678,39 @@ var Renderer = class _Renderer {
12607
12678
  this._dirty = dirty;
12608
12679
  this.scene.dirty = dirty;
12609
12680
  }
12681
+ /**
12682
+ * Calls a synchronous animation update before each FPS-limited draw while started.
12683
+ * Subscriptions keep the scene drawing without manual dirty flags. Returns an unsubscribe function.
12684
+ * Registering the same callback twice has no effect. Image exports do not invoke callbacks.
12685
+ */
12686
+ onFrame(callback) {
12687
+ if (this._disposed) return () => {
12688
+ };
12689
+ const subscription = this._frameCallbacks.get(callback) ?? {};
12690
+ this._frameCallbacks.set(callback, subscription);
12691
+ return () => {
12692
+ if (this._frameCallbacks.get(callback) === subscription) this._frameCallbacks.delete(callback);
12693
+ };
12694
+ }
12610
12695
  start() {
12611
12696
  if (this._disposed) return;
12612
12697
  this.stop();
12613
- this.renderer.setAnimationLoop(this._animationLoop);
12698
+ this._running = true;
12699
+ if (!this._inAnimationLoop) this.renderer.setAnimationLoop(this._animationLoop);
12614
12700
  }
12615
12701
  stop() {
12616
12702
  if (this._disposed) return;
12617
- this.renderer.setAnimationLoop(null);
12703
+ this._running = false;
12704
+ if (this._inAnimationLoop) {
12705
+ queueMicrotask(() => {
12706
+ this.renderer.setAnimationLoop(null);
12707
+ if (this._running) this.renderer.setAnimationLoop(this._animationLoop);
12708
+ });
12709
+ } else {
12710
+ this.renderer.setAnimationLoop(null);
12711
+ }
12618
12712
  this._nextFrameTime = void 0;
12713
+ for (const subscription of this._frameCallbacks.values()) subscription.previous = void 0;
12619
12714
  }
12620
12715
  /**
12621
12716
  * Stops rendering and releases owned resources. Repeated calls have no effect, and a disposed
@@ -12626,6 +12721,7 @@ var Renderer = class _Renderer {
12626
12721
  if (this._disposed) return;
12627
12722
  this.stop();
12628
12723
  this._disposed = true;
12724
+ this._frameCallbacks.clear();
12629
12725
  if (this._resizeListener) {
12630
12726
  window.removeEventListener("resize", this._resizeListener);
12631
12727
  this._resizeListener = void 0;
@@ -12660,18 +12756,25 @@ var Renderer = class _Renderer {
12660
12756
  this.renderer.forceContextLoss();
12661
12757
  }
12662
12758
  animate(t = performance.now()) {
12663
- if (this._disposed) return;
12759
+ if (!this._running) return;
12664
12760
  if (this._controls?.enabled) {
12665
12761
  this._controls.update();
12666
12762
  }
12667
- if (this._disposed) return;
12668
- if (!this.dirty && !this.options.render.renderAlways) return;
12763
+ if (!this._running) return;
12764
+ if (!this.dirty && !this.options.render.renderAlways && !this._frameCallbacks.size) return;
12669
12765
  const interval = this._frameInterval;
12670
12766
  if (interval) {
12671
12767
  const next = this._nextFrameTime;
12672
12768
  if (next !== void 0 && t + 0.1 < next) return;
12673
12769
  this._nextFrameTime = next !== void 0 && t - next < interval ? next + interval : t + interval;
12674
12770
  }
12771
+ for (const [callback, subscription] of [...this._frameCallbacks]) {
12772
+ if (this._frameCallbacks.get(callback) !== subscription) continue;
12773
+ const previous = subscription.previous;
12774
+ subscription.previous = t;
12775
+ callback({ time: t / 1e3, delta: previous === void 0 ? 0 : (t - previous) / 1e3 });
12776
+ if (!this._running) return;
12777
+ }
12675
12778
  this.drawFrame();
12676
12779
  }
12677
12780
  drawFrame() {