minerender 2.1.0-alpha.53 → 2.1.0-alpha.54

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.
@@ -843,7 +843,7 @@ var init_Textures = __esm({
843
843
  });
844
844
 
845
845
  // src/Materials.ts
846
- import { Color, DoubleSide, FrontSide, MeshBasicMaterial, MeshStandardMaterial, ShaderChunk, ShaderMaterial } from "three";
846
+ import { Color, CustomBlending, DoubleSide, OneFactor, RepeatWrapping, FrontSide, MeshBasicMaterial, MeshStandardMaterial, ShaderChunk, ShaderMaterial, ZeroFactor } from "three";
847
847
  var Materials;
848
848
  var init_Materials = __esm({
849
849
  "src/Materials.ts"() {
@@ -885,6 +885,71 @@ var init_Materials = __esm({
885
885
  alphaTest: 0.5
886
886
  });
887
887
  }
888
+ /** Whether vanilla's render type for the mode culls back faces. */
889
+ static entityModeCulls(mode = "cutout") {
890
+ return mode === "cutout_cull" || mode === "solid" || mode === "eyes" || mode === "water_mask";
891
+ }
892
+ /** UV offset per tick of entity age for the scrolling modes, as vanilla's texture matrix applies it. */
893
+ static entityModeScroll(mode = "cutout") {
894
+ if (mode === "energy_swirl") return [0.01, 0.01];
895
+ if (mode === "breeze_wind") return [0.02, 0];
896
+ return void 0;
897
+ }
898
+ /**
899
+ * Entity material for one of vanilla's render types. Entities are unlit here, so the lit and full-bright modes
900
+ * differ only in blending and depth state. Culling is not a material property: {@link entityModeCulls} decides
901
+ * whether the geometry gets inward faces.
902
+ */
903
+ static createEntityCanvasMaterial(canvas, mode = "cutout", tint) {
904
+ const material = _Materials.createBasicCanvasMaterial(canvas);
905
+ switch (mode) {
906
+ case "cutout":
907
+ case "cutout_cull":
908
+ break;
909
+ case "cutout_z_offset":
910
+ material.polygonOffset = true;
911
+ material.polygonOffsetFactor = -1;
912
+ material.polygonOffsetUnits = -10;
913
+ break;
914
+ case "solid":
915
+ material.alphaTest = 0;
916
+ break;
917
+ case "translucent":
918
+ case "breeze_wind":
919
+ material.transparent = true;
920
+ material.alphaTest = 0.1;
921
+ break;
922
+ case "translucent_emissive":
923
+ material.transparent = true;
924
+ material.alphaTest = 0.1;
925
+ material.depthWrite = false;
926
+ break;
927
+ case "eyes":
928
+ material.transparent = true;
929
+ material.alphaTest = 0;
930
+ material.depthWrite = false;
931
+ break;
932
+ case "energy_swirl":
933
+ material.transparent = true;
934
+ material.alphaTest = 0.1;
935
+ material.blending = CustomBlending;
936
+ material.blendSrc = OneFactor;
937
+ material.blendDst = OneFactor;
938
+ material.blendSrcAlpha = ZeroFactor;
939
+ material.blendDstAlpha = OneFactor;
940
+ material.color.set(8421504);
941
+ break;
942
+ case "water_mask":
943
+ material.alphaTest = 0;
944
+ material.colorWrite = false;
945
+ break;
946
+ }
947
+ if (_Materials.entityModeScroll(mode)) {
948
+ material.map.wrapS = material.map.wrapT = RepeatWrapping;
949
+ }
950
+ if (tint !== void 0) material.color.multiply(new Color(tint));
951
+ return material;
952
+ }
888
953
  static createGuiCanvasMaterial(canvas) {
889
954
  const material = new MeshBasicMaterial({
890
955
  map: Textures.createCanvasTexture(canvas),
@@ -4122,7 +4187,7 @@ var init_ModelCulling = __esm({
4122
4187
  });
4123
4188
 
4124
4189
  // src/model/scene/ModelObject.ts
4125
- import { BoxGeometry as BoxGeometry5, BufferAttribute as BufferAttribute5, Color as Color7, Euler as Euler5, Matrix4 as Matrix46 } from "three";
4190
+ import { BoxGeometry as BoxGeometry5, BufferAttribute as BufferAttribute5, Color as Color8, Euler as Euler6, Matrix4 as Matrix47 } from "three";
4126
4191
  function isModelObject(obj) {
4127
4192
  return obj.isModelObject;
4128
4193
  }
@@ -4188,7 +4253,7 @@ var init_ModelObject = __esm({
4188
4253
  elGeo.clearGroups();
4189
4254
  }
4190
4255
  if (this.options.uvLockRotation) {
4191
- UVMapper.lockUvs(elGeo, el.faces, this.atlas, new Euler5(...this.options.uvLockRotation));
4256
+ UVMapper.lockUvs(elGeo, el.faces, this.atlas, new Euler6(...this.options.uvLockRotation));
4192
4257
  }
4193
4258
  if (this.options.tints) {
4194
4259
  const colors = new Float32Array(elGeo.getAttribute("position").count * 3).fill(1);
@@ -4197,19 +4262,19 @@ var init_ModelObject = __esm({
4197
4262
  if (tintIndex === void 0 || tintIndex < 0) continue;
4198
4263
  const tint = this.options.tints[tintIndex];
4199
4264
  if (tint === void 0) continue;
4200
- const color = new Color7(tint);
4265
+ const color = new Color8(tint);
4201
4266
  for (let vertex = 0; vertex < 4; vertex++) {
4202
4267
  color.toArray(colors, (faceIndex * 4 + vertex) * 3);
4203
4268
  }
4204
4269
  }
4205
4270
  elGeo.setAttribute("color", new BufferAttribute5(colors, 3));
4206
4271
  }
4207
- elGeo.applyMatrix4(new Matrix46().makeTranslation((el.to[0] - el.from[0]) / 2, (el.to[1] - el.from[1]) / 2, (el.to[2] - el.from[2]) / 2));
4208
- elGeo.applyMatrix4(new Matrix46().makeTranslation(el.from[0], el.from[1], el.from[2]));
4272
+ elGeo.applyMatrix4(new Matrix47().makeTranslation((el.to[0] - el.from[0]) / 2, (el.to[1] - el.from[1]) / 2, (el.to[2] - el.from[2]) / 2));
4273
+ elGeo.applyMatrix4(new Matrix47().makeTranslation(el.from[0], el.from[1], el.from[2]));
4209
4274
  if (el.rotation) {
4210
4275
  applyElementRotation(el.rotation, elGeo);
4211
4276
  }
4212
- elGeo.applyMatrix4(new Matrix46().makeTranslation(-8, -8, -8));
4277
+ elGeo.applyMatrix4(new Matrix47().makeTranslation(-8, -8, -8));
4213
4278
  if (displayTransform) DisplayTransforms.apply(elGeo, displayTransform);
4214
4279
  if (this.options.mergeMeshes) {
4215
4280
  allGeos.push(elGeo);
@@ -4461,7 +4526,7 @@ __export(FluidModelObject_exports, {
4461
4526
  FluidModelObject: () => FluidModelObject,
4462
4527
  sampleFluid: () => sampleFluid
4463
4528
  });
4464
- import { BufferAttribute as BufferAttribute6, Color as Color8, DoubleSide as DoubleSide3 } from "three";
4529
+ import { BufferAttribute as BufferAttribute6, Color as Color9, DoubleSide as DoubleSide3 } from "three";
4465
4530
  function sampleFluid(kind, sample) {
4466
4531
  const cells = [];
4467
4532
  const key = [];
@@ -4512,7 +4577,7 @@ var init_FluidModelObject = __esm({
4512
4577
  }
4513
4578
  }
4514
4579
  geometry.clearGroups();
4515
- const color = new Color8(this.options.tints?.[0] ?? (this.kind === "water" ? 4159204 : 16777215));
4580
+ const color = new Color9(this.options.tints?.[0] ?? (this.kind === "water" ? 4159204 : 16777215));
4516
4581
  const colors = new Float32Array(geometry.getAttribute("position").count * 3);
4517
4582
  for (let i = 0; i < colors.length; i += 3) color.toArray(colors, i);
4518
4583
  geometry.setAttribute("color", new BufferAttribute6(colors, 3));
@@ -4809,32 +4874,44 @@ var Entities = class {
4809
4874
  static async getLayerList(modelKey) {
4810
4875
  return Object.keys((await this.getModelFile(modelKey))?.layers ?? {});
4811
4876
  }
4877
+ /** The dataset's extra draws on top of `main`; their `when` labels are the states `EntityModelOptions.when` can enable. */
4878
+ static async getPassList(modelKey) {
4879
+ return (await this.getModelFile(modelKey))?.passes ?? [];
4880
+ }
4812
4881
  static async getEntity(modelKey, textureKey, options) {
4813
4882
  const model = await this.getModelFile(modelKey);
4814
4883
  if (!model) return void 0;
4815
- const names = [...new Set(options?.layers ?? [options?.layer ?? "main"])];
4816
- if (names.length === 0) throw new MineRenderError(`Entity ${model.id} requires at least one layer`);
4817
- const selected = names.map((name) => {
4818
- const layer = model.layers[name];
4884
+ const passes = options?.layers || options?.layer !== void 0 ? [] : (model.passes ?? []).filter((pass) => pass.when === void 0 || options?.when?.includes(pass.when));
4885
+ const draws = [...new Set(options?.layers ?? [options?.layer ?? "main"])].map((layer) => ({ layer }));
4886
+ if (draws.length === 0) throw new MineRenderError(`Entity ${model.id} requires at least one layer`);
4887
+ draws.push(...passes);
4888
+ const names = [];
4889
+ const selected = draws.map((pass) => {
4890
+ const layer = model.layers[pass.layer];
4819
4891
  if (!layer) {
4820
- throw new MineRenderError(`Entity ${model.id} has no layer "${name}". Available layers: ${Object.keys(model.layers).join(", ")}`);
4892
+ throw new MineRenderError(`Entity ${model.id} has no layer "${pass.layer}". Available layers: ${Object.keys(model.layers).join(", ")}`);
4821
4893
  }
4822
- return { name, layer };
4894
+ let name = pass.layer;
4895
+ for (let n = 2; names.includes(name); n++) name = `${pass.layer}#${n}`;
4896
+ names.push(name);
4897
+ return { name, layer, pass };
4823
4898
  });
4824
- const layers = Object.fromEntries(await Promise.all(selected.map(async ({ name, layer }, index) => {
4899
+ const layers = Object.fromEntries(await Promise.all(selected.map(async ({ name, layer, pass }, index) => {
4825
4900
  const override = options?.textures?.[name] ?? (index === 0 ? textureKey : void 0);
4901
+ const textureLocation = pass.textureLocation ?? layer.textureLocation;
4826
4902
  let texture;
4827
4903
  if (override) {
4828
4904
  const path = isAssetKey(override) ? override.getFullPath() : override.path;
4829
4905
  texture = isAssetKey(override) && override.assetType === "textures" && path.startsWith("entity/") ? override : new AssetKey(override.namespace, path, "textures", "entity", "assets", ".png", isAssetKey(override) ? override.root : void 0);
4830
- } else if (layer.textureLocation !== void 0) {
4831
- texture = AssetKey.parse("textures", layer.textureLocation.replace(/^([^:]+:)?textures\//, "$1"));
4906
+ } else if (textureLocation !== void 0) {
4907
+ texture = AssetKey.parse("textures", textureLocation.replace(/^([^:]+:)?textures\//, "$1"));
4832
4908
  } else {
4833
4909
  texture = await this.resolveTexture(modelKey);
4834
4910
  }
4835
- return [name, { key: override ?? modelKey, texture, layer }];
4911
+ const render = pass.render ?? layer.render;
4912
+ return [name, { key: override ?? modelKey, texture, layer, ...render && { render }, ...pass.tint && { tint: pass.tint } }];
4836
4913
  })));
4837
- return { ...layers[names[0]], id: model.id, layers };
4914
+ return { ...layers[names[0]], id: model.id, layers, ...model.transform && { transform: model.transform } };
4838
4915
  }
4839
4916
  static async resolveTexture(modelKey) {
4840
4917
  const path = isAssetKey(modelKey) ? modelKey.getFullPath() : modelKey.path;
@@ -4916,11 +4993,12 @@ function trimCanvas(source) {
4916
4993
  init_SceneObject();
4917
4994
  init_Caching();
4918
4995
  var import_ts_deepmerge4 = __toESM(require_dist());
4996
+ init_Ticker();
4919
4997
  init_model();
4920
4998
  init_ModelTextures();
4921
4999
  init_AssetKey();
4922
5000
  init_Materials();
4923
- import { Object3D as Object3D3 } from "three";
5001
+ import { Color as Color3, Euler as Euler4, Matrix4 as Matrix44, Object3D as Object3D3 } from "three";
4924
5002
  init_three();
4925
5003
  var EntityObject = class _EntityObject extends SceneObject {
4926
5004
  constructor(entity, options) {
@@ -4928,10 +5006,14 @@ var EntityObject = class _EntityObject extends SceneObject {
4928
5006
  this.entity = entity;
4929
5007
  this.isEntityObject = true;
4930
5008
  this.meshesCreated = false;
5009
+ /** Scrolling materials are owned: their texture offset follows this entity's age. */
5010
+ this.scrollMaterials = [];
5011
+ /** Entity age in ticks, as vanilla's `ageInTicks`; drives the scrolling render modes. */
5012
+ this.age = 0;
4931
5013
  this.options = (0, import_ts_deepmerge4.default)({}, _EntityObject.DEFAULT_OPTIONS, options ?? {});
4932
5014
  }
4933
5015
  static {
4934
- this.DEFAULT_OPTIONS = (0, import_ts_deepmerge4.default)({}, SceneObject.DEFAULT_OPTIONS, { flip: true });
5016
+ this.DEFAULT_OPTIONS = (0, import_ts_deepmerge4.default)({}, SceneObject.DEFAULT_OPTIONS);
4935
5017
  }
4936
5018
  async init() {
4937
5019
  this.createMeshes();
@@ -4940,6 +5022,25 @@ var EntityObject = class _EntityObject extends SceneObject {
4940
5022
  dispose() {
4941
5023
  super.dispose();
4942
5024
  }
5025
+ disposeAndRemoveAllChildren() {
5026
+ this.clearScrollMaterials();
5027
+ super.disposeAndRemoveAllChildren();
5028
+ }
5029
+ clearScrollMaterials() {
5030
+ Ticker.remove(this.scrollTicker);
5031
+ this.scrollTicker = void 0;
5032
+ for (const { material } of this.scrollMaterials.splice(0)) {
5033
+ material.map?.dispose();
5034
+ material.dispose();
5035
+ }
5036
+ }
5037
+ /** Applies the entity age to the scrolling materials; the ticker calls this 20 times per second. */
5038
+ updateScroll() {
5039
+ for (const { offset, speed } of this.scrollMaterials) {
5040
+ offset.set(this.age * speed[0] % 1, 0 - this.age * speed[1] % 1);
5041
+ }
5042
+ this.notifyDirty();
5043
+ }
4943
5044
  getLayerGroup(name) {
4944
5045
  return super.getGroupByName(`layer:${name}`);
4945
5046
  }
@@ -4970,16 +5071,29 @@ var EntityObject = class _EntityObject extends SceneObject {
4970
5071
  createMeshes(force = false) {
4971
5072
  if (this.meshesCreated && !force) return;
4972
5073
  const modelRoot = new Object3D3();
4973
- if (this.options.flip) modelRoot.scale.set(-1, -1, 1);
5074
+ const transform = this.options.flip === void 0 ? this.entity.transform : void 0;
5075
+ if (transform) {
5076
+ for (const op of transform) {
5077
+ const matrix = new Matrix44();
5078
+ if ("scale" in op) matrix.makeScale(...op.scale);
5079
+ else if ("translate" in op) matrix.makeTranslation(...op.translate);
5080
+ else matrix.makeRotationFromEuler(new Euler4(...op.rotate, "ZYX"));
5081
+ modelRoot.matrix.multiply(matrix);
5082
+ }
5083
+ modelRoot.matrixAutoUpdate = false;
5084
+ } else if (this.options.flip ?? true) {
5085
+ modelRoot.scale.set(-1, -1, 1);
5086
+ }
4974
5087
  this.add(modelRoot);
4975
5088
  Object.entries(this.entityLayers).forEach(([name, layer], index) => {
4976
5089
  const group = this.createGroup(`layer:${name}`);
4977
5090
  modelRoot.add(group);
4978
- this.createPart("root", layer.layer.root, group, layer.layer.texture, Materials.MISSING_TEXTURE, index);
5091
+ const inward = !Materials.entityModeCulls(layer.render ?? layer.layer.render);
5092
+ this.createPart("root", layer.layer.root, group, layer.layer.texture, Materials.MISSING_TEXTURE, index, inward);
4979
5093
  });
4980
5094
  this.meshesCreated = true;
4981
5095
  }
4982
- createPart(name, part, parent, textureSize, material, renderOrder) {
5096
+ createPart(name, part, parent, textureSize, material, renderOrder, inward = true) {
4983
5097
  const anchor = this.createGroup(name);
4984
5098
  anchor.position.fromArray(part.pose.offset);
4985
5099
  anchor.rotation.set(...part.pose.rotation, "ZYX");
@@ -4998,7 +5112,7 @@ var EntityObject = class _EntityObject extends SceneObject {
4998
5112
  uv
4999
5113
  ).clone();
5000
5114
  geometry.translate(cube.origin[0] + width / 2, cube.origin[1] + height / 2, cube.origin[2] + depth / 2);
5001
- if (Math.min(width + growX * 2, height + growY * 2, depth + growZ * 2) > 0) {
5115
+ if (inward && Math.min(width + growX * 2, height + growY * 2, depth + growZ * 2) > 0) {
5002
5116
  const index = Array.from(geometry.getIndex().array);
5003
5117
  geometry.setIndex(index.concat(index.slice().reverse()));
5004
5118
  }
@@ -5008,26 +5122,42 @@ var EntityObject = class _EntityObject extends SceneObject {
5008
5122
  if (this.options.wireframe) addWireframeToMesh(geometry, mesh);
5009
5123
  }
5010
5124
  for (const [childName, child] of Object.entries(part.children)) {
5011
- this.createPart(childName, child, anchor, size, material, renderOrder);
5125
+ this.createPart(childName, child, anchor, size, material, renderOrder, inward);
5012
5126
  }
5013
5127
  }
5014
5128
  async applyTextures() {
5129
+ this.clearScrollMaterials();
5015
5130
  await Promise.all(Object.entries(this.entityLayers).map(async ([name, layer]) => {
5131
+ const mode = layer.render ?? layer.layer.render ?? "cutout";
5132
+ const tint = layer.tint === void 0 ? void 0 : this.options.tints?.[layer.tint];
5133
+ const scroll = Materials.entityModeScroll(mode);
5016
5134
  const assetKeyStr = this.getTextureKey(layer).serialize();
5017
- const keyStr = `entity:${assetKeyStr}`;
5018
- let mat = Caching.materialCache.getIfPresent(keyStr);
5135
+ const keyStr = `entity:${mode}:${tint === void 0 ? "" : new Color3(tint).getHexString()}:${assetKeyStr}`;
5136
+ let mat = scroll ? void 0 : Caching.materialCache.getIfPresent(keyStr);
5019
5137
  if (!mat) {
5020
5138
  const cachedAsset = Caching.textureAssetCache.getIfPresent(assetKeyStr);
5021
5139
  const imageData = await this.loadTextures(layer);
5022
5140
  if (!imageData) return;
5023
5141
  const canvas = imageData.data.canvas;
5024
- const createMaterial = () => Materials.createBasicCanvasMaterial(canvas);
5025
- mat = cachedAsset && Caching.textureAssetCache.getIfPresent(assetKeyStr) === cachedAsset ? Caching.materialCache.get(keyStr, createMaterial) : createMaterial();
5142
+ const createMaterial = () => Materials.createEntityCanvasMaterial(canvas, mode, tint);
5143
+ mat = !scroll && cachedAsset && Caching.textureAssetCache.getIfPresent(assetKeyStr) === cachedAsset ? Caching.materialCache.get(keyStr, createMaterial) : createMaterial();
5144
+ if (scroll) {
5145
+ this.scrollMaterials.push({ material: mat, offset: mat.map.offset, speed: scroll });
5146
+ }
5026
5147
  }
5027
5148
  this.getLayerGroup(name)?.traverse((object) => {
5028
5149
  if (isMesh(object)) object.material = mat;
5029
5150
  });
5030
5151
  }));
5152
+ if (!this.children.length) {
5153
+ this.clearScrollMaterials();
5154
+ } else if (this.scrollMaterials.length) {
5155
+ this.updateScroll();
5156
+ this.scrollTicker = Ticker.add(() => {
5157
+ this.age++;
5158
+ this.updateScroll();
5159
+ });
5160
+ }
5031
5161
  this.notifyDirty();
5032
5162
  }
5033
5163
  };
@@ -5039,11 +5169,11 @@ function isEntityObject(obj) {
5039
5169
  init_MineRenderError();
5040
5170
 
5041
5171
  // src/export/SceneExporter.ts
5042
- import { ClampToEdgeWrapping as ClampToEdgeWrapping2, Color as Color6, Float32BufferAttribute as Float32BufferAttribute3, Matrix4 as Matrix45, Mesh as Mesh5, MeshBasicMaterial as MeshBasicMaterial2, NearestFilter as NearestFilter3, RGBAFormat as RGBAFormat3, Scene as Scene4, Source as Source2, Texture as Texture4, UnsignedByteType } from "three";
5172
+ import { ClampToEdgeWrapping as ClampToEdgeWrapping2, Color as Color7, Float32BufferAttribute as Float32BufferAttribute3, Matrix4 as Matrix46, Mesh as Mesh5, MeshBasicMaterial as MeshBasicMaterial2, NearestFilter as NearestFilter3, RGBAFormat as RGBAFormat3, Scene as Scene4, Source as Source2, Texture as Texture4, UnsignedByteType } from "three";
5043
5173
 
5044
5174
  // ../../node_modules/three/examples/jsm/exporters/OBJExporter.js
5045
5175
  import {
5046
- Color as Color3,
5176
+ Color as Color4,
5047
5177
  Matrix3,
5048
5178
  Vector2 as Vector22,
5049
5179
  Vector3 as Vector36
@@ -5055,7 +5185,7 @@ var OBJExporter = class {
5055
5185
  let indexVertexUvs = 0;
5056
5186
  let indexNormals = 0;
5057
5187
  const vertex = new Vector36();
5058
- const color = new Color3();
5188
+ const color = new Color4();
5059
5189
  const normal = new Vector36();
5060
5190
  const uv = new Vector22();
5061
5191
  const face = [];
@@ -5186,7 +5316,7 @@ var OBJExporter = class {
5186
5316
  import {
5187
5317
  Matrix3 as Matrix32,
5188
5318
  Vector3 as Vector37,
5189
- Color as Color4
5319
+ Color as Color5
5190
5320
  } from "three";
5191
5321
  var PLYExporter = class {
5192
5322
  parse(object, onDone, options = {}) {
@@ -5244,7 +5374,7 @@ var PLYExporter = class {
5244
5374
  includeIndices = false;
5245
5375
  }
5246
5376
  });
5247
- const tempColor = new Color4();
5377
+ const tempColor = new Color5();
5248
5378
  includeIndices = includeIndices && excludeAttributes.indexOf("index") === -1;
5249
5379
  includeNormals = includeNormals && excludeAttributes.indexOf("normal") === -1;
5250
5380
  includeColors = includeColors && excludeAttributes.indexOf("color") === -1;
@@ -5456,7 +5586,7 @@ property list uchar int vertex_index
5456
5586
  import {
5457
5587
  BufferAttribute as BufferAttribute3,
5458
5588
  ClampToEdgeWrapping,
5459
- Color as Color5,
5589
+ Color as Color6,
5460
5590
  DoubleSide as DoubleSide2,
5461
5591
  InterpolateDiscrete,
5462
5592
  InterpolateLinear,
@@ -5465,14 +5595,14 @@ import {
5465
5595
  LinearMipmapLinearFilter,
5466
5596
  LinearMipmapNearestFilter,
5467
5597
  MathUtils as MathUtils2,
5468
- Matrix4 as Matrix44,
5598
+ Matrix4 as Matrix45,
5469
5599
  MirroredRepeatWrapping,
5470
5600
  NearestFilter as NearestFilter2,
5471
5601
  NearestMipmapLinearFilter,
5472
5602
  NearestMipmapNearestFilter,
5473
5603
  PropertyBinding,
5474
5604
  RGBAFormat as RGBAFormat2,
5475
- RepeatWrapping,
5605
+ RepeatWrapping as RepeatWrapping2,
5476
5606
  Scene as Scene3,
5477
5607
  Source,
5478
5608
  SRGBColorSpace as SRGBColorSpace4,
@@ -5690,7 +5820,7 @@ THREE_TO_WEBGL[LinearFilter] = WEBGL_CONSTANTS.LINEAR;
5690
5820
  THREE_TO_WEBGL[LinearMipmapNearestFilter] = WEBGL_CONSTANTS.LINEAR_MIPMAP_NEAREST;
5691
5821
  THREE_TO_WEBGL[LinearMipmapLinearFilter] = WEBGL_CONSTANTS.LINEAR_MIPMAP_LINEAR;
5692
5822
  THREE_TO_WEBGL[ClampToEdgeWrapping] = WEBGL_CONSTANTS.CLAMP_TO_EDGE;
5693
- THREE_TO_WEBGL[RepeatWrapping] = WEBGL_CONSTANTS.REPEAT;
5823
+ THREE_TO_WEBGL[RepeatWrapping2] = WEBGL_CONSTANTS.REPEAT;
5694
5824
  THREE_TO_WEBGL[MirroredRepeatWrapping] = WEBGL_CONSTANTS.MIRRORED_REPEAT;
5695
5825
  var PATH_PROPERTIES = {
5696
5826
  scale: "scale",
@@ -5698,7 +5828,7 @@ var PATH_PROPERTIES = {
5698
5828
  quaternion: "rotation",
5699
5829
  morphTargetInfluences: "weights"
5700
5830
  };
5701
- var DEFAULT_SPECULAR_COLOR = new Color5();
5831
+ var DEFAULT_SPECULAR_COLOR = new Color6();
5702
5832
  var GLB_HEADER_BYTES = 12;
5703
5833
  var GLB_HEADER_MAGIC = 1179937895;
5704
5834
  var GLB_VERSION = 2;
@@ -6755,7 +6885,7 @@ var GLTFWriter = class {
6755
6885
  if (rootJoint === void 0) return null;
6756
6886
  const joints = [];
6757
6887
  const inverseBindMatrices = new Float32Array(skeleton.bones.length * 16);
6758
- const temporaryBoneInverse = new Matrix44();
6888
+ const temporaryBoneInverse = new Matrix45();
6759
6889
  for (let i = 0; i < skeleton.bones.length; ++i) {
6760
6890
  joints.push(nodeMap.get(skeleton.bones[i]));
6761
6891
  temporaryBoneInverse.copy(skeleton.boneInverses[i]);
@@ -7221,7 +7351,7 @@ var GLTFMeshGpuInstancing = class {
7221
7351
  const translationAttr = new Float32Array(mesh.count * 3);
7222
7352
  const rotationAttr = new Float32Array(mesh.count * 4);
7223
7353
  const scaleAttr = new Float32Array(mesh.count * 3);
7224
- const matrix = new Matrix44();
7354
+ const matrix = new Matrix45();
7225
7355
  const position = new Vector38();
7226
7356
  const quaternion = new Quaternion4();
7227
7357
  const scale = new Vector38();
@@ -7395,7 +7525,7 @@ var SceneExporter = class {
7395
7525
  }
7396
7526
  };
7397
7527
  function localMatrix(object) {
7398
- return object.matrixAutoUpdate ? new Matrix45().compose(object.position, object.quaternion, object.scale) : object.matrix.clone();
7528
+ return object.matrixAutoUpdate ? new Matrix46().compose(object.position, object.quaternion, object.scale) : object.matrix.clone();
7399
7529
  }
7400
7530
  function createSnapshot(root, gltf, bakeColors = false) {
7401
7531
  const scene = new Scene4();
@@ -7480,7 +7610,7 @@ function createSnapshot(root, gltf, bakeColors = false) {
7480
7610
  const material = copyMaterial(sourceMaterial, geometry);
7481
7611
  if (!sourceMaterial.vertexColors) geometry.deleteAttribute("color");
7482
7612
  if (bakeColors || instanceColor) {
7483
- const tint = (material.color ?? new Color6()).clone();
7613
+ const tint = (material.color ?? new Color7()).clone();
7484
7614
  if (instanceColor) tint.multiply(instanceColor);
7485
7615
  if (bakeColors) {
7486
7616
  const original = geometry.getAttribute("color");
@@ -7507,9 +7637,9 @@ function createSnapshot(root, gltf, bakeColors = false) {
7507
7637
  const instanced = mesh;
7508
7638
  if (instanced.isInstancedMesh) {
7509
7639
  for (let i = 0; i < instanced.count; i++) {
7510
- const matrix = new Matrix45();
7640
+ const matrix = new Matrix46();
7511
7641
  instanced.getMatrixAt(i, matrix);
7512
- const color = instanced.instanceColor ? new Color6().fromBufferAttribute(instanced.instanceColor, i) : void 0;
7642
+ const color = instanced.instanceColor ? new Color7().fromBufferAttribute(instanced.instanceColor, i) : void 0;
7513
7643
  addMesh(mesh, world.clone().multiply(matrix), color);
7514
7644
  }
7515
7645
  } else {
@@ -7521,7 +7651,7 @@ function createSnapshot(root, gltf, bakeColors = false) {
7521
7651
  try {
7522
7652
  const ancestors = [];
7523
7653
  for (let parent = root.parent; parent; parent = parent.parent) ancestors.unshift(parent);
7524
- const world = new Matrix45();
7654
+ const world = new Matrix46();
7525
7655
  for (const ancestor of ancestors) {
7526
7656
  if (!ancestor.visible) return { scene, dispose };
7527
7657
  world.multiply(localMatrix(ancestor));
@@ -7588,11 +7718,69 @@ function copyDataTexture(source) {
7588
7718
  }
7589
7719
 
7590
7720
  // src/gui/GuiHelper.ts
7721
+ init_AssetKey();
7591
7722
  var GuiHelper = class {
7592
7723
  static inventorySlot(slot, origin = [0, 0], offset = [18, 18], rowSize = 9) {
7593
7724
  const [column, row] = typeof slot === "number" ? [slot % rowSize, Math.floor(slot / rowSize)] : slot;
7594
7725
  return [origin[0] + column * offset[0], origin[1] + row * offset[1]];
7595
7726
  }
7727
+ /** Creates crafting-table layers for ingredients and the result; stack counts are not drawn. */
7728
+ static recipe(recipe, options = {}) {
7729
+ const layers = [
7730
+ { name: "background", texture: "minecraft:gui/container/crafting_table", crop: [0, 0, 176, 166] }
7731
+ ];
7732
+ const itemKey = (ingredient) => {
7733
+ const item = typeof ingredient === "string" && !ingredient.startsWith("#") ? ingredient : typeof ingredient === "object" && "item" in ingredient ? ingredient.item : options.resolveIngredient?.(ingredient);
7734
+ if (isAssetKey(item)) return item;
7735
+ if (!item || item.startsWith("#")) {
7736
+ throw new Error(`Select a concrete item for recipe ingredient ${JSON.stringify(ingredient)}`);
7737
+ }
7738
+ const key = AssetKey.parse("models", item);
7739
+ return new AssetKey(key.namespace, key.getFullPath(), "models", "item");
7740
+ };
7741
+ const addIngredient = (ingredient, slot) => {
7742
+ layers.push({
7743
+ name: `ingredient-${slot}`,
7744
+ item: itemKey(ingredient),
7745
+ position: this.inventorySlot(slot, [30, 17], [18, 18], 3)
7746
+ });
7747
+ };
7748
+ switch (recipe.type) {
7749
+ case "minecraft:crafting_shaped":
7750
+ case "crafting_shaped": {
7751
+ const pattern = recipe.pattern;
7752
+ if (!pattern.length || pattern.length > 3 || !pattern[0].length || pattern[0].length > 3 || pattern.some((row) => row.length !== pattern[0].length)) {
7753
+ throw new Error("Crafting patterns must be rectangular, with 1\u20133 rows and columns");
7754
+ }
7755
+ const cells = pattern.flatMap((row, y) => row.split("").map((symbol, x) => ({ symbol, x, y }))).filter((cell) => cell.symbol !== " ");
7756
+ if (!cells.length) throw new Error("Crafting patterns must contain an ingredient");
7757
+ const minX = Math.min(...cells.map((cell) => cell.x)), maxX = Math.max(...cells.map((cell) => cell.x));
7758
+ const minY = Math.min(...cells.map((cell) => cell.y)), maxY = Math.max(...cells.map((cell) => cell.y));
7759
+ const offsetX = minX === maxX ? 1 : 0, offsetY = minY === maxY ? 1 : 0;
7760
+ for (const { symbol, x, y } of cells) {
7761
+ const ingredient = recipe.key[symbol];
7762
+ if (!ingredient) throw new Error(`Missing recipe ingredient for symbol ${JSON.stringify(symbol)}`);
7763
+ addIngredient(ingredient, (y - minY + offsetY) * 3 + x - minX + offsetX);
7764
+ }
7765
+ break;
7766
+ }
7767
+ case "minecraft:crafting_shapeless":
7768
+ case "crafting_shapeless":
7769
+ if (!recipe.ingredients.length || recipe.ingredients.length > 9) {
7770
+ throw new Error("Shapeless crafting recipes require 1\u20139 ingredients");
7771
+ }
7772
+ recipe.ingredients.forEach(addIngredient);
7773
+ break;
7774
+ default:
7775
+ throw new Error(`Unsupported crafting recipe type: ${recipe.type}`);
7776
+ }
7777
+ layers.push({
7778
+ name: "result",
7779
+ item: itemKey("id" in recipe.result ? recipe.result.id : recipe.result.item),
7780
+ position: [124, 35]
7781
+ });
7782
+ return layers;
7783
+ }
7596
7784
  };
7597
7785
 
7598
7786
  // src/gui/scene/GuiObject.ts
@@ -8180,7 +8368,7 @@ init_ModelMerger();
8180
8368
  init_BlockStates();
8181
8369
  init_MineRenderError();
8182
8370
  init_util();
8183
- import { Euler as Euler6 } from "three";
8371
+ import { Euler as Euler7 } from "three";
8184
8372
  function matchesCondition(condition, state) {
8185
8373
  return Object.entries(condition).every(([key, value]) => {
8186
8374
  if (Array.isArray(value)) {
@@ -8255,7 +8443,7 @@ var BlockStateResolver = class {
8255
8443
  return variants[variants.length - 1];
8256
8444
  }
8257
8445
  static rotation(variant) {
8258
- const rotation = new Euler6();
8446
+ const rotation = new Euler7();
8259
8447
  if (typeof variant.x !== "undefined") {
8260
8448
  rotation.x = toRadians(clampRotationDegrees(variant.x));
8261
8449
  }
@@ -8365,7 +8553,7 @@ var import_ts_deepmerge6 = __toESM(require_dist());
8365
8553
  init_MineRenderError();
8366
8554
  init_InstanceReference();
8367
8555
  init_AssetKey();
8368
- import { Euler as Euler7, Matrix4 as Matrix47, Quaternion as Quaternion5, Vector3 as Vector311 } from "three";
8556
+ import { Euler as Euler8, Matrix4 as Matrix48, Quaternion as Quaternion5, Vector3 as Vector311 } from "three";
8369
8557
  init_ModelCulling();
8370
8558
  init_FluidGeometry();
8371
8559
  var BlockObject = class _BlockObject extends SceneObject {
@@ -8436,7 +8624,7 @@ var BlockObject = class _BlockObject extends SceneObject {
8436
8624
  const scale = new Vector311();
8437
8625
  this.getModelMatrix(model).decompose(position, rotation, scale);
8438
8626
  if (position.distanceToSquared(this.position) > 1e-10 || scale.distanceToSquared(new Vector311(1, 1, 1)) > 1e-10) return 0;
8439
- return ModelCulling.toLocalMask(worldMask, new Euler7().setFromQuaternion(rotation));
8627
+ return ModelCulling.toLocalMask(worldMask, new Euler8().setFromQuaternion(rotation));
8440
8628
  }
8441
8629
  async setCullMask(worldMask) {
8442
8630
  worldMask &= 63;
@@ -8498,7 +8686,7 @@ var BlockObject = class _BlockObject extends SceneObject {
8498
8686
  () => new FluidModelObject2(kind, surface.sample, this.blockState.key, this.options)
8499
8687
  );
8500
8688
  const previous = this._fluidModel;
8501
- const matrix = previous ? this.getModelMatrix(previous) : new Matrix47().makeTranslation(...this.position.toArray());
8689
+ const matrix = previous ? this.getModelMatrix(previous) : new Matrix48().makeTranslation(...this.position.toArray());
8502
8690
  if (isInstanceReference(replacement)) replacement.setMatrix(matrix);
8503
8691
  else matrix.decompose(replacement.position, replacement.quaternion, replacement.scale);
8504
8692
  this._models = this._models.filter((model) => model !== previous);
@@ -8629,7 +8817,7 @@ var BlockObject = class _BlockObject extends SceneObject {
8629
8817
  setPositionRotationScaleAt(index, position, rotation, scale) {
8630
8818
  super.setPositionRotationScaleAt(index, position, rotation, scale);
8631
8819
  }
8632
- getMatrixAt(index, matrix = new Matrix47()) {
8820
+ getMatrixAt(index, matrix = new Matrix48()) {
8633
8821
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
8634
8822
  const child = this._models[0];
8635
8823
  if (child && isModelObject(child)) {
@@ -13191,7 +13379,7 @@ init_CubeFace();
13191
13379
  init_AssetKey();
13192
13380
  init_Models();
13193
13381
  init_CubeFace();
13194
- import { Matrix4 as Matrix48, Vector3 as Vector314 } from "three";
13382
+ import { Matrix4 as Matrix49, Vector3 as Vector314 } from "three";
13195
13383
  init_ModelCulling();
13196
13384
  init_ModelObject();
13197
13385
  init_UVMapper();
@@ -13254,7 +13442,7 @@ var SectionModels = class {
13254
13442
  });
13255
13443
  await object.init();
13256
13444
  const geometry = object.children[0].geometry;
13257
- geometry.applyMatrix4(new Matrix48().makeRotationFromEuler(rotation));
13445
+ geometry.applyMatrix4(new Matrix49().makeRotationFromEuler(rotation));
13258
13446
  object.clear();
13259
13447
  const cullFaces = CUBE_FACES.map((face) => {
13260
13448
  const local = CUBE_FACES.findIndex((name) => name === atlas.model.elements[0].faces[face]?.cullface);