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.
@@ -3452,48 +3452,6 @@ var init_SceneObject = __esm({
3452
3452
  }
3453
3453
  });
3454
3454
 
3455
- // src/model/ModelCulling.ts
3456
- var import_three22, ModelCulling;
3457
- var init_ModelCulling = __esm({
3458
- "src/model/ModelCulling.ts"() {
3459
- import_three22 = require("three");
3460
- init_CubeFace();
3461
- ModelCulling = class {
3462
- static toLocalMask(worldMask, rotation) {
3463
- let localMask = 0;
3464
- for (const [localFace, offset] of CUBE_FACE_OFFSETS.entries()) {
3465
- const normal = new import_three22.Vector3(...offset).applyEuler(rotation);
3466
- 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);
3467
- if (worldFace < 0) return 0;
3468
- if (worldMask & 1 << worldFace) localMask |= 1 << localFace;
3469
- }
3470
- return localMask;
3471
- }
3472
- static isOpaqueFullCube(atlas) {
3473
- if (!atlas || atlas.hasTransparency !== false || atlas.model.elements?.length !== 1) return false;
3474
- const element = atlas.model.elements[0];
3475
- 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;
3476
- if (!(atlas.image.width > 0 && atlas.image.height > 0)) return false;
3477
- return CUBE_FACES.every((face, faceIndex) => {
3478
- const texture = element.faces[face]?.texture;
3479
- if (!texture?.startsWith("#")) return false;
3480
- const key = texture.slice(1);
3481
- const position = atlas.positions[key];
3482
- const size = atlas.sizes[key];
3483
- if (position?.length !== 2 || !position.every(Number.isFinite) || size?.length !== 2 || !size.every((value) => value > 0 && Number.isFinite(value))) return false;
3484
- for (let vertex = 0; vertex < 4; vertex++) {
3485
- const uvIndex = (faceIndex * 4 + vertex) * 2;
3486
- const x = element.mappedUv[uvIndex] * atlas.image.width;
3487
- const y = (1 - element.mappedUv[uvIndex + 1]) * atlas.image.height;
3488
- 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;
3489
- }
3490
- return true;
3491
- });
3492
- }
3493
- };
3494
- }
3495
- });
3496
-
3497
3455
  // src/three/BufferGeometryUtils.js
3498
3456
  function computeTangents(geometry) {
3499
3457
  geometry.computeTangents();
@@ -3506,7 +3464,7 @@ function mergeBufferGeometries(geometries, useGroups = false) {
3506
3464
  const attributes = {};
3507
3465
  const morphAttributes = {};
3508
3466
  const morphTargetsRelative = geometries[0].morphTargetsRelative;
3509
- const mergedGeometry = new import_three24.BufferGeometry();
3467
+ const mergedGeometry = new import_three19.BufferGeometry();
3510
3468
  let offset = 0;
3511
3469
  for (let i = 0; i < geometries.length; ++i) {
3512
3470
  const geometry = geometries[i];
@@ -3630,7 +3588,7 @@ function mergeBufferAttributes(attributes) {
3630
3588
  array.set(attributes[i].array, offset);
3631
3589
  offset += attributes[i].array.length;
3632
3590
  }
3633
- return new import_three24.BufferAttribute(array, itemSize, normalized);
3591
+ return new import_three19.BufferAttribute(array, itemSize, normalized);
3634
3592
  }
3635
3593
  function interleaveAttributes(attributes) {
3636
3594
  let TypedArray;
@@ -3646,7 +3604,7 @@ function interleaveAttributes(attributes) {
3646
3604
  arrayLength += attribute.array.length;
3647
3605
  stride += attribute.itemSize;
3648
3606
  }
3649
- const interleavedBuffer = new import_three24.InterleavedBuffer(new TypedArray(arrayLength), stride);
3607
+ const interleavedBuffer = new import_three19.InterleavedBuffer(new TypedArray(arrayLength), stride);
3650
3608
  let offset = 0;
3651
3609
  const res = [];
3652
3610
  const getters = ["getX", "getY", "getZ", "getW"];
@@ -3655,7 +3613,7 @@ function interleaveAttributes(attributes) {
3655
3613
  const attribute = attributes[j];
3656
3614
  const itemSize = attribute.itemSize;
3657
3615
  const count = attribute.count;
3658
- const iba = new import_three24.InterleavedBufferAttribute(interleavedBuffer, itemSize, offset, attribute.normalized);
3616
+ const iba = new import_three19.InterleavedBufferAttribute(interleavedBuffer, itemSize, offset, attribute.normalized);
3659
3617
  res.push(iba);
3660
3618
  offset += itemSize;
3661
3619
  for (let c = 0; c < count; c++) {
@@ -3739,13 +3697,13 @@ function mergeVertices(geometry, tolerance = 1e-4) {
3739
3697
  const name = attributeNames[i];
3740
3698
  const oldAttribute = geometry.getAttribute(name);
3741
3699
  const buffer = new oldAttribute.array.constructor(attrArrays[name]);
3742
- const attribute = new import_three24.BufferAttribute(buffer, oldAttribute.itemSize, oldAttribute.normalized);
3700
+ const attribute = new import_three19.BufferAttribute(buffer, oldAttribute.itemSize, oldAttribute.normalized);
3743
3701
  result.setAttribute(name, attribute);
3744
3702
  if (name in morphAttrsArrays) {
3745
3703
  for (let j = 0; j < morphAttrsArrays[name].length; j++) {
3746
3704
  const oldMorphAttribute = geometry.morphAttributes[name][j];
3747
3705
  const buffer2 = new oldMorphAttribute.array.constructor(morphAttrsArrays[name][j]);
3748
- const morphAttribute = new import_three24.BufferAttribute(buffer2, oldMorphAttribute.itemSize, oldMorphAttribute.normalized);
3706
+ const morphAttribute = new import_three19.BufferAttribute(buffer2, oldMorphAttribute.itemSize, oldMorphAttribute.normalized);
3749
3707
  result.morphAttributes[name][j] = morphAttribute;
3750
3708
  }
3751
3709
  }
@@ -3754,11 +3712,11 @@ function mergeVertices(geometry, tolerance = 1e-4) {
3754
3712
  return result;
3755
3713
  }
3756
3714
  function toTrianglesDrawMode(geometry, drawMode) {
3757
- if (drawMode === import_three24.TrianglesDrawMode) {
3715
+ if (drawMode === import_three19.TrianglesDrawMode) {
3758
3716
  console.warn("THREE.BufferGeometryUtils.toTrianglesDrawMode(): Geometry already defined as triangles.");
3759
3717
  return geometry;
3760
3718
  }
3761
- if (drawMode === import_three24.TriangleFanDrawMode || drawMode === import_three24.TriangleStripDrawMode) {
3719
+ if (drawMode === import_three19.TriangleFanDrawMode || drawMode === import_three19.TriangleStripDrawMode) {
3762
3720
  let index = geometry.getIndex();
3763
3721
  if (index === null) {
3764
3722
  const indices = [];
@@ -3776,7 +3734,7 @@ function toTrianglesDrawMode(geometry, drawMode) {
3776
3734
  }
3777
3735
  const numberOfTriangles = index.count - 2;
3778
3736
  const newIndices = [];
3779
- if (drawMode === import_three24.TriangleFanDrawMode) {
3737
+ if (drawMode === import_three19.TriangleFanDrawMode) {
3780
3738
  for (let i = 1; i <= numberOfTriangles; i++) {
3781
3739
  newIndices.push(index.getX(0));
3782
3740
  newIndices.push(index.getX(i));
@@ -3812,15 +3770,15 @@ function computeMorphedAttributes(object) {
3812
3770
  console.error("THREE.BufferGeometryUtils: Geometry is not of type BufferGeometry.");
3813
3771
  return null;
3814
3772
  }
3815
- const _vA = new import_three24.Vector3();
3816
- const _vB = new import_three24.Vector3();
3817
- const _vC = new import_three24.Vector3();
3818
- const _tempA = new import_three24.Vector3();
3819
- const _tempB = new import_three24.Vector3();
3820
- const _tempC = new import_three24.Vector3();
3821
- const _morphA = new import_three24.Vector3();
3822
- const _morphB = new import_three24.Vector3();
3823
- const _morphC = new import_three24.Vector3();
3773
+ const _vA = new import_three19.Vector3();
3774
+ const _vB = new import_three19.Vector3();
3775
+ const _vC = new import_three19.Vector3();
3776
+ const _tempA = new import_three19.Vector3();
3777
+ const _tempB = new import_three19.Vector3();
3778
+ const _tempC = new import_three19.Vector3();
3779
+ const _morphA = new import_three19.Vector3();
3780
+ const _morphB = new import_three19.Vector3();
3781
+ const _morphC = new import_three19.Vector3();
3824
3782
  function _calculateMorphedAttributeData(object2, material2, attribute, morphAttribute, morphTargetsRelative2, a2, b2, c2, modifiedAttributeArray) {
3825
3783
  _vA.fromBufferAttribute(attribute, a2);
3826
3784
  _vB.fromBufferAttribute(attribute, b2);
@@ -4015,8 +3973,8 @@ function computeMorphedAttributes(object) {
4015
3973
  }
4016
3974
  }
4017
3975
  }
4018
- const morphedPositionAttribute = new import_three24.Float32BufferAttribute(modifiedPosition, 3);
4019
- const morphedNormalAttribute = new import_three24.Float32BufferAttribute(modifiedNormal, 3);
3976
+ const morphedPositionAttribute = new import_three19.Float32BufferAttribute(modifiedPosition, 3);
3977
+ const morphedNormalAttribute = new import_three19.Float32BufferAttribute(modifiedNormal, 3);
4020
3978
  return {
4021
3979
  positionAttribute,
4022
3980
  normalAttribute,
@@ -4024,10 +3982,52 @@ function computeMorphedAttributes(object) {
4024
3982
  morphedNormalAttribute
4025
3983
  };
4026
3984
  }
4027
- var import_three24;
3985
+ var import_three19;
4028
3986
  var init_BufferGeometryUtils = __esm({
4029
3987
  "src/three/BufferGeometryUtils.js"() {
4030
- import_three24 = require("three");
3988
+ import_three19 = require("three");
3989
+ }
3990
+ });
3991
+
3992
+ // src/model/ModelCulling.ts
3993
+ var import_three20, ModelCulling;
3994
+ var init_ModelCulling = __esm({
3995
+ "src/model/ModelCulling.ts"() {
3996
+ import_three20 = require("three");
3997
+ init_CubeFace();
3998
+ ModelCulling = class {
3999
+ static toLocalMask(worldMask, rotation) {
4000
+ let localMask = 0;
4001
+ for (const [localFace, offset] of CUBE_FACE_OFFSETS.entries()) {
4002
+ const normal = new import_three20.Vector3(...offset).applyEuler(rotation);
4003
+ 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);
4004
+ if (worldFace < 0) return 0;
4005
+ if (worldMask & 1 << worldFace) localMask |= 1 << localFace;
4006
+ }
4007
+ return localMask;
4008
+ }
4009
+ static isOpaqueFullCube(atlas) {
4010
+ if (!atlas || atlas.hasTransparency !== false || atlas.model.elements?.length !== 1) return false;
4011
+ const element = atlas.model.elements[0];
4012
+ 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;
4013
+ if (!(atlas.image.width > 0 && atlas.image.height > 0)) return false;
4014
+ return CUBE_FACES.every((face, faceIndex) => {
4015
+ const texture = element.faces[face]?.texture;
4016
+ if (!texture?.startsWith("#")) return false;
4017
+ const key = texture.slice(1);
4018
+ const position = atlas.positions[key];
4019
+ const size = atlas.sizes[key];
4020
+ if (position?.length !== 2 || !position.every(Number.isFinite) || size?.length !== 2 || !size.every((value) => value > 0 && Number.isFinite(value))) return false;
4021
+ for (let vertex = 0; vertex < 4; vertex++) {
4022
+ const uvIndex = (faceIndex * 4 + vertex) * 2;
4023
+ const x = element.mappedUv[uvIndex] * atlas.image.width;
4024
+ const y = (1 - element.mappedUv[uvIndex + 1]) * atlas.image.height;
4025
+ 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;
4026
+ }
4027
+ return true;
4028
+ });
4029
+ }
4030
+ };
4031
4031
  }
4032
4032
  });
4033
4033
 
@@ -4035,13 +4035,13 @@ var init_BufferGeometryUtils = __esm({
4035
4035
  function isModelObject(obj) {
4036
4036
  return obj.isModelObject;
4037
4037
  }
4038
- var import_three25, import_ts_deepmerge5, p9, _ModelObject, ModelObject;
4038
+ var import_three21, import_ts_deepmerge5, p7, _ModelObject, ModelObject;
4039
4039
  var init_ModelObject = __esm({
4040
4040
  "src/model/scene/ModelObject.ts"() {
4041
4041
  init_SceneObject();
4042
4042
  init_Materials();
4043
4043
  init_UVMapper();
4044
- import_three25 = require("three");
4044
+ import_three21 = require("three");
4045
4045
  init_BufferGeometryUtils();
4046
4046
  init_model();
4047
4047
  import_ts_deepmerge5 = __toESM(require_dist());
@@ -4049,7 +4049,7 @@ var init_ModelObject = __esm({
4049
4049
  init_CubeFace();
4050
4050
  init_DisplayTransforms();
4051
4051
  init_ModelCulling();
4052
- p9 = prefix("ModelObject");
4052
+ p7 = prefix("ModelObject");
4053
4053
  _ModelObject = class _ModelObject extends SceneObject {
4054
4054
  constructor(originalModel, options) {
4055
4055
  super(options);
@@ -4095,7 +4095,7 @@ var init_ModelObject = __esm({
4095
4095
  elGeo.clearGroups();
4096
4096
  }
4097
4097
  if (this.options.uvLockRotation) {
4098
- UVMapper.lockUvs(elGeo, el.faces, this.atlas, new import_three25.Euler(...this.options.uvLockRotation));
4098
+ UVMapper.lockUvs(elGeo, el.faces, this.atlas, new import_three21.Euler(...this.options.uvLockRotation));
4099
4099
  }
4100
4100
  if (this.options.tints) {
4101
4101
  const colors = new Float32Array(elGeo.getAttribute("position").count * 3).fill(1);
@@ -4104,19 +4104,19 @@ var init_ModelObject = __esm({
4104
4104
  if (tintIndex === void 0 || tintIndex < 0) continue;
4105
4105
  const tint = this.options.tints[tintIndex];
4106
4106
  if (tint === void 0) continue;
4107
- const color = new import_three25.Color(tint);
4107
+ const color = new import_three21.Color(tint);
4108
4108
  for (let vertex = 0; vertex < 4; vertex++) {
4109
4109
  color.toArray(colors, (faceIndex * 4 + vertex) * 3);
4110
4110
  }
4111
4111
  }
4112
- elGeo.setAttribute("color", new import_three25.BufferAttribute(colors, 3));
4112
+ elGeo.setAttribute("color", new import_three21.BufferAttribute(colors, 3));
4113
4113
  }
4114
- 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));
4115
- elGeo.applyMatrix4(new import_three25.Matrix4().makeTranslation(el.from[0], el.from[1], el.from[2]));
4114
+ 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));
4115
+ elGeo.applyMatrix4(new import_three21.Matrix4().makeTranslation(el.from[0], el.from[1], el.from[2]));
4116
4116
  if (el.rotation) {
4117
4117
  applyElementRotation(el.rotation, elGeo);
4118
4118
  }
4119
- elGeo.applyMatrix4(new import_three25.Matrix4().makeTranslation(-8, -8, -8));
4119
+ elGeo.applyMatrix4(new import_three21.Matrix4().makeTranslation(-8, -8, -8));
4120
4120
  if (displayTransform) DisplayTransforms.apply(elGeo, displayTransform);
4121
4121
  if (this.options.mergeMeshes) {
4122
4122
  allGeos.push(elGeo);
@@ -4128,17 +4128,17 @@ var init_ModelObject = __esm({
4128
4128
  }
4129
4129
  });
4130
4130
  } else {
4131
- console.debug(p9, this.atlas.model, "has no elements");
4131
+ console.debug(p7, this.atlas.model, "has no elements");
4132
4132
  }
4133
4133
  } else {
4134
- console.debug(p9, "Missing atlas for", this);
4134
+ console.debug(p7, "Missing atlas for", this);
4135
4135
  }
4136
4136
  if (this.options.mergeMeshes) {
4137
4137
  let combinedGeo;
4138
4138
  if (allGeos.length > 0) {
4139
4139
  combinedGeo = mergeBufferGeometries(allGeos);
4140
4140
  } else {
4141
- combinedGeo = new import_three25.BoxGeometry(16, 16, 16);
4141
+ combinedGeo = new import_three21.BoxGeometry(16, 16, 16);
4142
4142
  if (displayTransform) DisplayTransforms.apply(combinedGeo, displayTransform);
4143
4143
  }
4144
4144
  combinedGeo.computeBoundingBox();
@@ -7666,19 +7666,31 @@ var GuiHelper = class {
7666
7666
  };
7667
7667
 
7668
7668
  // src/gui/scene/GuiObject.ts
7669
- var import_three19 = require("three");
7669
+ var import_three22 = require("three");
7670
7670
  init_AssetKey();
7671
7671
  init_ModelTextures();
7672
+ init_Models();
7672
7673
  init_Caching();
7673
7674
  init_SceneObject();
7674
7675
  init_Materials();
7676
+ init_ModelObject();
7677
+ init_DisplayPosition();
7678
+
7679
+ // src/model/GuiLight.ts
7680
+ var GuiLight = /* @__PURE__ */ ((GuiLight2) => {
7681
+ GuiLight2["FRONT"] = "front";
7682
+ GuiLight2["SIDE"] = "side";
7683
+ return GuiLight2;
7684
+ })(GuiLight || {});
7685
+
7686
+ // src/gui/scene/GuiObject.ts
7675
7687
  var GuiObject = class extends SceneObject {
7676
7688
  constructor(textureLayers, options) {
7677
7689
  super({ ...options, instanceMeshes: false, mergeMeshes: false });
7678
7690
  this.textureLayers = textureLayers;
7679
7691
  this.isGuiObject = true;
7680
7692
  /** Local bounds in GUI pixels, with y growing down from the origin. */
7681
- this.bounds = new import_three19.Box2();
7693
+ this.bounds = new import_three22.Box2();
7682
7694
  this.geometries = /* @__PURE__ */ new Set();
7683
7695
  this.ownedMaterials = /* @__PURE__ */ new Set();
7684
7696
  this.initialized = false;
@@ -7686,14 +7698,35 @@ var GuiObject = class extends SceneObject {
7686
7698
  async init() {
7687
7699
  if (this.initialized) return;
7688
7700
  try {
7701
+ let depth = 0;
7689
7702
  for (const [index, layer] of this.textureLayers.entries()) {
7703
+ const [x, y] = layer.position ?? [0, 0];
7704
+ if ("item" in layer) {
7705
+ const [width2, height2] = layer.size ?? [16, 16];
7706
+ const item = await this.createItem(layer, index);
7707
+ item.position.set(x + width2 / 2, -y - height2 / 2, 0);
7708
+ item.scale.set(width2 / 16, height2 / 16, width2 / 16);
7709
+ item.updateMatrix();
7710
+ const bounds = new import_three22.Box3();
7711
+ item.iterateAllMeshes((mesh2) => {
7712
+ mesh2.geometry.computeBoundingBox();
7713
+ bounds.union(mesh2.geometry.boundingBox);
7714
+ });
7715
+ bounds.applyMatrix4(item.matrix);
7716
+ item.position.z = depth - bounds.min.z;
7717
+ depth += bounds.max.z - bounds.min.z + 0.01;
7718
+ this.bounds.expandByPoint(new import_three22.Vector2(x, y));
7719
+ this.bounds.expandByPoint(new import_three22.Vector2(x + width2, y + height2));
7720
+ this.bounds.expandByPoint(new import_three22.Vector2(bounds.min.x, -bounds.max.y));
7721
+ this.bounds.expandByPoint(new import_three22.Vector2(bounds.max.x, -bounds.min.y));
7722
+ continue;
7723
+ }
7690
7724
  const key = typeof layer.texture === "string" ? AssetKey.parse("textures", layer.texture) : layer.texture;
7691
7725
  const material = await this.loadMaterial(key);
7692
7726
  const image = material.map.image;
7693
7727
  const [cropX, cropY, cropWidth, cropHeight] = layer.crop ?? [0, 0, image.width, image.height];
7694
7728
  const [width, height] = layer.size ?? [cropWidth, cropHeight];
7695
- const [x, y] = layer.position ?? [0, 0];
7696
- const geometry = new import_three19.PlaneGeometry(width, height);
7729
+ const geometry = new import_three22.PlaneGeometry(width, height);
7697
7730
  this.geometries.add(geometry);
7698
7731
  const uv = geometry.getAttribute("uv");
7699
7732
  for (let i = 0; i < uv.count; i++) {
@@ -7703,14 +7736,16 @@ var GuiObject = class extends SceneObject {
7703
7736
  1 - (cropY + (1 - uv.getY(i)) * cropHeight) / image.height
7704
7737
  );
7705
7738
  }
7706
- const mesh = new import_three19.Mesh(geometry, material);
7739
+ const mesh = new import_three22.Mesh(geometry, material);
7707
7740
  mesh.name = `mesh:${layer.name ?? index}`;
7708
- mesh.position.set(x + width / 2, -y - height / 2, 0);
7741
+ mesh.position.set(x + width / 2, -y - height / 2, depth);
7709
7742
  mesh.renderOrder = index;
7710
7743
  this.add(mesh);
7711
- this.bounds.expandByPoint(new import_three19.Vector2(x, y));
7712
- this.bounds.expandByPoint(new import_three19.Vector2(x + width, y + height));
7744
+ this.bounds.expandByPoint(new import_three22.Vector2(x, y));
7745
+ this.bounds.expandByPoint(new import_three22.Vector2(x + width, y + height));
7746
+ depth += 0.01;
7713
7747
  }
7748
+ for (const child of this.children) child.position.z -= depth - 0.01;
7714
7749
  this.initialized = true;
7715
7750
  this.notifyDirty();
7716
7751
  } catch (error) {
@@ -7718,6 +7753,32 @@ var GuiObject = class extends SceneObject {
7718
7753
  throw error;
7719
7754
  }
7720
7755
  }
7756
+ async createItem(layer, index) {
7757
+ const key = typeof layer.item === "string" ? AssetKey.parse("models", layer.item) : layer.item;
7758
+ const model = await Models.getMerged(key);
7759
+ if (!model) throw new Error(`Could not load GUI item ${key.toNamespacedString()}`);
7760
+ const item = new ModelObject(model, {
7761
+ displayPosition: "gui" /* GUI */,
7762
+ tints: layer.tints,
7763
+ instanceMeshes: false,
7764
+ mergeMeshes: true
7765
+ });
7766
+ item.name = `group:${layer.name ?? index}`;
7767
+ this.add(item);
7768
+ await item.init();
7769
+ item.iterateAllMeshes((mesh) => {
7770
+ this.geometries.add(mesh.geometry);
7771
+ mesh.name = `mesh:${layer.name ?? index}`;
7772
+ mesh.renderOrder = index;
7773
+ for (const material of Array.isArray(mesh.material) ? mesh.material : [mesh.material]) {
7774
+ material.transparent = true;
7775
+ if (model.gui_light === "front" /* FRONT */ && material.uniforms?.SHADE) {
7776
+ material.uniforms.SHADE.value = false;
7777
+ }
7778
+ }
7779
+ });
7780
+ return item;
7781
+ }
7721
7782
  async loadMaterial(key) {
7722
7783
  const assetKey = key.serialize();
7723
7784
  const materialKey = `gui:${assetKey}`;
@@ -7756,21 +7817,21 @@ function isGuiObject(obj) {
7756
7817
  init_image();
7757
7818
 
7758
7819
  // src/inspector/SceneInspector.ts
7759
- var import_three20 = require("three");
7820
+ var import_three23 = require("three");
7760
7821
  init_SceneObject();
7761
7822
  init_util();
7762
7823
  init_log();
7763
7824
  init_three();
7764
- var p7 = prefix("SceneInspector");
7825
+ var p8 = prefix("SceneInspector");
7765
7826
  var help = "<span>Ctrl/Cmd+Click to Select<br/></span><br/>";
7766
7827
  var SceneInspector = class {
7767
7828
  constructor(renderer) {
7768
7829
  this.renderer = renderer;
7769
- this.mouse = new import_three20.Vector2();
7830
+ this.mouse = new import_three23.Vector2();
7770
7831
  this.listeners = new AbortController();
7771
7832
  this.objectInfoContainer = document.createElement("div");
7772
7833
  this.objectControlsContainer = document.createElement("div");
7773
- this.raycaster = new import_three20.Raycaster();
7834
+ this.raycaster = new import_three23.Raycaster();
7774
7835
  this.init();
7775
7836
  }
7776
7837
  init() {
@@ -7855,7 +7916,7 @@ var SceneInspector = class {
7855
7916
  }
7856
7917
  selectObject(targetObject, targetIntersection, instance = this.getIntersectionInstance(targetIntersection)) {
7857
7918
  this.selectedObject = targetObject;
7858
- console.log(p7, "selected", targetObject);
7919
+ console.log(p8, "selected", targetObject);
7859
7920
  this.redraw(targetObject, targetIntersection, instance);
7860
7921
  }
7861
7922
  redraw(targetObject, targetIntersection, instance) {
@@ -8087,7 +8148,7 @@ var SceneStatsDisplay = class {
8087
8148
  }
8088
8149
  init() {
8089
8150
  this.statsContainer.classList.add("minerender-stats");
8090
- setInterval(() => {
8151
+ this.interval = setInterval(() => {
8091
8152
  for (let line of this.lines) {
8092
8153
  line.update();
8093
8154
  }
@@ -8096,6 +8157,13 @@ var SceneStatsDisplay = class {
8096
8157
  appendTo(el) {
8097
8158
  el.append(this.statsContainer);
8098
8159
  }
8160
+ dispose() {
8161
+ clearInterval(this.interval);
8162
+ this.interval = void 0;
8163
+ this.lines.length = 0;
8164
+ this.statsContainer.replaceChildren();
8165
+ this.statsContainer.remove();
8166
+ }
8099
8167
  add(line) {
8100
8168
  if (typeof line !== "undefined") {
8101
8169
  this.lines.push(line);
@@ -8107,7 +8175,7 @@ var SceneStatsDisplay = class {
8107
8175
 
8108
8176
  // src/instance/InstanceManager.ts
8109
8177
  init_log();
8110
- var p8 = prefix("InstanceManager");
8178
+ var p9 = prefix("InstanceManager");
8111
8179
  var InstanceManager = class {
8112
8180
  constructor() {
8113
8181
  this.isInstanceManager = true;
@@ -8115,7 +8183,7 @@ var InstanceManager = class {
8115
8183
  }
8116
8184
  async get(key) {
8117
8185
  if (key in this.instanceCache) {
8118
- console.debug(p8, "key in cache", key);
8186
+ console.debug(p9, "key in cache", key);
8119
8187
  return (await this.instanceCache[key]).nextInstance();
8120
8188
  }
8121
8189
  return void 0;
@@ -8124,7 +8192,7 @@ var InstanceManager = class {
8124
8192
  if (key in this.instanceCache) {
8125
8193
  return await this.get(key);
8126
8194
  }
8127
- console.debug(p8, "key not in cache", key);
8195
+ console.debug(p9, "key not in cache", key);
8128
8196
  const pending = Promise.resolve().then(supplier).then((obj) => obj.nextInstance());
8129
8197
  this.instanceCache[key] = pending;
8130
8198
  try {
@@ -8158,13 +8226,6 @@ function isInstanceable(obj) {
8158
8226
  init_DisplayPosition();
8159
8227
  init_DisplayTransforms();
8160
8228
 
8161
- // src/model/GuiLight.ts
8162
- var GuiLight = /* @__PURE__ */ ((GuiLight2) => {
8163
- GuiLight2["FRONT"] = "front";
8164
- GuiLight2["SIDE"] = "side";
8165
- return GuiLight2;
8166
- })(GuiLight || {});
8167
-
8168
8229
  // src/model/Model.ts
8169
8230
  var ITEM_GENERATED = "item/generated";
8170
8231
  var BUILTIN_GENERATED = "builtin/generated";
@@ -8186,7 +8247,7 @@ init_ModelGenerator();
8186
8247
  init_ModelMerger();
8187
8248
 
8188
8249
  // src/model/block/BlockStateResolver.ts
8189
- var import_three23 = require("three");
8250
+ var import_three25 = require("three");
8190
8251
  init_BlockStates();
8191
8252
  init_MineRenderError();
8192
8253
  init_util();
@@ -8264,7 +8325,7 @@ var BlockStateResolver = class {
8264
8325
  return variants[variants.length - 1];
8265
8326
  }
8266
8327
  static rotation(variant) {
8267
- const rotation = new import_three23.Euler();
8328
+ const rotation = new import_three25.Euler();
8268
8329
  if (typeof variant.x !== "undefined") {
8269
8330
  rotation.x = toRadians(clampRotationDegrees(variant.x));
8270
8331
  }
@@ -12333,7 +12394,10 @@ var _Renderer = class _Renderer {
12333
12394
  constructor(options) {
12334
12395
  this._dirty = true;
12335
12396
  this._resizeListener = void 0;
12397
+ this._running = false;
12398
+ this._inAnimationLoop = false;
12336
12399
  this._disposed = false;
12400
+ this._frameCallbacks = /* @__PURE__ */ new Map();
12337
12401
  this._debugHelpers = [];
12338
12402
  this._eventDispatchers = /* @__PURE__ */ new Map();
12339
12403
  this._changeListener = () => {
@@ -12344,7 +12408,14 @@ var _Renderer = class _Renderer {
12344
12408
  if (!Number.isFinite(pixelRatio) || pixelRatio <= 0) {
12345
12409
  throw new RangeError("render.pixelRatio must be a finite positive number");
12346
12410
  }
12347
- this._animationLoop = this.animate.bind(this);
12411
+ this._animationLoop = (time) => {
12412
+ this._inAnimationLoop = true;
12413
+ try {
12414
+ this.animate(time);
12415
+ } finally {
12416
+ this._inAnimationLoop = false;
12417
+ }
12418
+ };
12348
12419
  this._frameInterval = this.options.render.fpsLimit > 0 ? 1e3 / this.options.render.fpsLimit : void 0;
12349
12420
  this._scene = this.createScene();
12350
12421
  this._camera = this.createCamera();
@@ -12519,15 +12590,39 @@ var _Renderer = class _Renderer {
12519
12590
  this._dirty = dirty;
12520
12591
  this.scene.dirty = dirty;
12521
12592
  }
12593
+ /**
12594
+ * Calls a synchronous animation update before each FPS-limited draw while started.
12595
+ * Subscriptions keep the scene drawing without manual dirty flags. Returns an unsubscribe function.
12596
+ * Registering the same callback twice has no effect. Image exports do not invoke callbacks.
12597
+ */
12598
+ onFrame(callback) {
12599
+ if (this._disposed) return () => {
12600
+ };
12601
+ const subscription = this._frameCallbacks.get(callback) ?? {};
12602
+ this._frameCallbacks.set(callback, subscription);
12603
+ return () => {
12604
+ if (this._frameCallbacks.get(callback) === subscription) this._frameCallbacks.delete(callback);
12605
+ };
12606
+ }
12522
12607
  start() {
12523
12608
  if (this._disposed) return;
12524
12609
  this.stop();
12525
- this.renderer.setAnimationLoop(this._animationLoop);
12610
+ this._running = true;
12611
+ if (!this._inAnimationLoop) this.renderer.setAnimationLoop(this._animationLoop);
12526
12612
  }
12527
12613
  stop() {
12528
12614
  if (this._disposed) return;
12529
- this.renderer.setAnimationLoop(null);
12615
+ this._running = false;
12616
+ if (this._inAnimationLoop) {
12617
+ queueMicrotask(() => {
12618
+ this.renderer.setAnimationLoop(null);
12619
+ if (this._running) this.renderer.setAnimationLoop(this._animationLoop);
12620
+ });
12621
+ } else {
12622
+ this.renderer.setAnimationLoop(null);
12623
+ }
12530
12624
  this._nextFrameTime = void 0;
12625
+ for (const subscription of this._frameCallbacks.values()) subscription.previous = void 0;
12531
12626
  }
12532
12627
  /**
12533
12628
  * Stops rendering and releases owned resources. Repeated calls have no effect, and a disposed
@@ -12538,6 +12633,7 @@ var _Renderer = class _Renderer {
12538
12633
  if (this._disposed) return;
12539
12634
  this.stop();
12540
12635
  this._disposed = true;
12636
+ this._frameCallbacks.clear();
12541
12637
  if (this._resizeListener) {
12542
12638
  window.removeEventListener("resize", this._resizeListener);
12543
12639
  this._resizeListener = void 0;
@@ -12572,18 +12668,25 @@ var _Renderer = class _Renderer {
12572
12668
  this.renderer.forceContextLoss();
12573
12669
  }
12574
12670
  animate(t = performance.now()) {
12575
- if (this._disposed) return;
12671
+ if (!this._running) return;
12576
12672
  if (this._controls?.enabled) {
12577
12673
  this._controls.update();
12578
12674
  }
12579
- if (this._disposed) return;
12580
- if (!this.dirty && !this.options.render.renderAlways) return;
12675
+ if (!this._running) return;
12676
+ if (!this.dirty && !this.options.render.renderAlways && !this._frameCallbacks.size) return;
12581
12677
  const interval = this._frameInterval;
12582
12678
  if (interval) {
12583
12679
  const next = this._nextFrameTime;
12584
12680
  if (next !== void 0 && t + 0.1 < next) return;
12585
12681
  this._nextFrameTime = next !== void 0 && t - next < interval ? next + interval : t + interval;
12586
12682
  }
12683
+ for (const [callback, subscription] of [...this._frameCallbacks]) {
12684
+ if (this._frameCallbacks.get(callback) !== subscription) continue;
12685
+ const previous = subscription.previous;
12686
+ subscription.previous = t;
12687
+ callback({ time: t / 1e3, delta: previous === void 0 ? 0 : (t - previous) / 1e3 });
12688
+ if (!this._running) return;
12689
+ }
12587
12690
  this.drawFrame();
12588
12691
  }
12589
12692
  drawFrame() {