minerender 2.1.0-beta.5 → 2.1.0-beta.6

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.
Files changed (43) hide show
  1. package/dist/browser/esm/Materials.mjs +3 -2
  2. package/dist/browser/esm/Materials.mjs.map +1 -1
  3. package/dist/browser/esm/assets/Fonts.mjs +31 -4
  4. package/dist/browser/esm/assets/Fonts.mjs.map +1 -1
  5. package/dist/browser/esm/assets/_fonts/Unihex.mjs +166 -0
  6. package/dist/browser/esm/assets/_fonts/Unihex.mjs.map +1 -0
  7. package/dist/browser/esm/assets/source/HostedAssetSource.mjs +12 -1
  8. package/dist/browser/esm/assets/source/HostedAssetSource.mjs.map +1 -1
  9. package/dist/browser/esm/assets/source/parser/AssetParsers.mjs +1 -0
  10. package/dist/browser/esm/assets/source/parser/AssetParsers.mjs.map +1 -1
  11. package/dist/browser/esm/cache/Caching.mjs +2 -0
  12. package/dist/browser/esm/cache/Caching.mjs.map +1 -1
  13. package/dist/browser/esm/entity/scene/EntityAnimationPlayer.mjs +62 -11
  14. package/dist/browser/esm/entity/scene/EntityAnimationPlayer.mjs.map +1 -1
  15. package/dist/browser/esm/entity/scene/EntityObject.mjs +53 -20
  16. package/dist/browser/esm/entity/scene/EntityObject.mjs.map +1 -1
  17. package/dist/browser/esm/env/browser/section.worker.mjs +5 -3
  18. package/dist/browser/esm/env/browser/section.worker.mjs.map +1 -1
  19. package/dist/browser/esm/gui/GuiText.mjs +4 -3
  20. package/dist/browser/esm/gui/GuiText.mjs.map +1 -1
  21. package/dist/browser/esm/index.browser.d.mts +52 -10
  22. package/dist/browser/esm/model/scene/ModelObject.mjs +4 -0
  23. package/dist/browser/esm/model/scene/ModelObject.mjs.map +1 -1
  24. package/dist/browser/esm/util/model.mjs +7 -7
  25. package/dist/browser/esm/util/model.mjs.map +1 -1
  26. package/dist/browser/esm/world/SectionGeometry.mjs +5 -3
  27. package/dist/browser/esm/world/SectionGeometry.mjs.map +1 -1
  28. package/dist/browser/esm/world/SectionMesh.mjs +4 -0
  29. package/dist/browser/esm/world/SectionMesh.mjs.map +1 -1
  30. package/dist/browser/esm/world/SectionModels.mjs +2 -2
  31. package/dist/browser/esm/world/SectionModels.mjs.map +1 -1
  32. package/dist/browser/index.d.ts +52 -10
  33. package/dist/browser/index.js +382 -73
  34. package/dist/browser/index.js.map +1 -1
  35. package/dist/bundle.js +425 -73
  36. package/dist/bundle.js.map +1 -1
  37. package/dist/node/index.d.mts +52 -10
  38. package/dist/node/index.d.ts +52 -10
  39. package/dist/node/index.js +387 -73
  40. package/dist/node/index.js.map +1 -1
  41. package/dist/node/index.mjs +386 -73
  42. package/dist/node/index.mjs.map +1 -1
  43. package/package.json +1 -1
package/dist/bundle.js CHANGED
@@ -35632,6 +35632,7 @@ void main() {
35632
35632
  this.entityAnimationCache,
35633
35633
  this.blockEntityIndexCache,
35634
35634
  this.fontCache,
35635
+ this.unihexCache,
35635
35636
  this.bannerPatternCache,
35636
35637
  this.mineRenderDataCache,
35637
35638
  this.usernameUuidCache,
@@ -35685,6 +35686,7 @@ void main() {
35685
35686
  _Caching.entityTextureCache = _Caching.createAssetCache();
35686
35687
  _Caching.entityAnimationCache = _Caching.createAssetCache();
35687
35688
  _Caching.blockEntityIndexCache = _Caching.createAssetCache();
35689
+ _Caching.unihexCache = _Caching.createAssetCache();
35688
35690
  _Caching.fontCache = _Caching.createAssetCache();
35689
35691
  _Caching.bannerPatternCache = _Caching.createAssetCache();
35690
35692
  _Caching.mineRenderDataCache = _Caching.createAssetCache();
@@ -36796,6 +36798,7 @@ void main() {
36796
36798
  static createShadedCanvasMaterial(canvas, transparent = false, shade = false, boundUvs = false) {
36797
36799
  const vertShader = `
36798
36800
  uniform bool SHADE;
36801
+ attribute float shade;
36799
36802
 
36800
36803
  // Keep MSAA edge pixels from sampling outside the face's atlas region.
36801
36804
  #if __VERSION__ >= 300
@@ -36818,7 +36821,7 @@ void main() {
36818
36821
  void main()
36819
36822
  {
36820
36823
 
36821
- if (SHADE) {
36824
+ if (SHADE && shade > 0.5) {
36822
36825
 
36823
36826
  #ifdef USE_INSTANCING
36824
36827
  vec3 N = vec3( modelMatrix * instanceMatrix * vec4(normal, 0.0) );
@@ -36927,7 +36930,7 @@ void main() {
36927
36930
  side: transparent ? DoubleSide : FrontSide,
36928
36931
  alphaTest: 0.5
36929
36932
  });
36930
- Object.assign(material.defaultAttributeValues, { uvBounds: [0, 0, 1, 1] });
36933
+ Object.assign(material.defaultAttributeValues, { shade: [1], uvBounds: [0, 0, 1, 1] });
36931
36934
  return material;
36932
36935
  } catch (e6) {
36933
36936
  console.warn(e6);
@@ -37098,6 +37101,7 @@ void main() {
37098
37101
  AssetParser2["IMAGE"] = "image";
37099
37102
  AssetParser2["LIST"] = "list";
37100
37103
  AssetParser2["JSON"] = "json";
37104
+ AssetParser2["BINARY"] = "binary";
37101
37105
  return AssetParser2;
37102
37106
  })(AssetParser || {});
37103
37107
  }
@@ -38432,13 +38436,13 @@ ${key}` : key, async () => {
38432
38436
  break;
38433
38437
  }
38434
38438
  if (rotation.rescale) {
38435
- if (Math.abs(rotation.angle) === 22.5) {
38436
- const s4 = 1 / Math.cos(0.39269909262657166);
38437
- geometry.scale(s4, 1, s4);
38438
- } else {
38439
- const s4 = 1 / Math.cos(0.7853981852531433);
38440
- geometry.scale(s4, 1, s4);
38441
- }
38439
+ const angle = toRadians(rotation.angle);
38440
+ const s4 = 1 / Math.max(Math.abs(Math.cos(angle)), Math.abs(Math.sin(angle)));
38441
+ geometry.scale(
38442
+ rotation.axis === "x" /* X */ ? 1 : s4,
38443
+ rotation.axis === "y" /* Y */ ? 1 : s4,
38444
+ rotation.axis === "z" /* Z */ ? 1 : s4
38445
+ );
38442
38446
  }
38443
38447
  geometry.translate(origin.x, origin.y, origin.z);
38444
38448
  }
@@ -73063,7 +73067,7 @@ return ${compiler2.callType("value", tagType)}
73063
73067
  });
73064
73068
 
73065
73069
  // src/assets/source/HostedAssetSource.ts
73066
- var p7, DEFAULT_OPTIONS2, _HostedAssetSource, HostedAssetSource;
73070
+ var BINARY_TIMEOUT, p7, DEFAULT_OPTIONS2, _HostedAssetSource, HostedAssetSource;
73067
73071
  var init_HostedAssetSource = __esm({
73068
73072
  "src/assets/source/HostedAssetSource.ts"() {
73069
73073
  init_dirname();
@@ -73079,6 +73083,7 @@ return ${compiler2.callType("value", tagType)}
73079
73083
  init_AssetLoader();
73080
73084
  init_parser();
73081
73085
  init_merge();
73086
+ BINARY_TIMEOUT = 6e4;
73082
73087
  p7 = prefix("HostedAssetSource");
73083
73088
  DEFAULT_OPTIONS2 = {
73084
73089
  retryDefaults: true
@@ -73219,6 +73224,15 @@ return ${compiler2.callType("value", tagType)}
73219
73224
  return response.data;
73220
73225
  }
73221
73226
  };
73227
+ _HostedAssetSource.BINARY = {
73228
+ config(request) {
73229
+ request.timeout = BINARY_TIMEOUT;
73230
+ request.responseType = "arraybuffer";
73231
+ },
73232
+ parse(response) {
73233
+ return { data: new Uint8Array(response.data) };
73234
+ }
73235
+ };
73222
73236
  _HostedAssetSource.PARSER_MAP = /* @__PURE__ */ new Map([
73223
73237
  ["model" /* MODEL */, _HostedAssetSource.MODEL],
73224
73238
  ["blockstate" /* BLOCKSTATE */, _HostedAssetSource.BLOCKSTATE],
@@ -73226,7 +73240,8 @@ return ${compiler2.callType("value", tagType)}
73226
73240
  ["nbt" /* NBT */, _HostedAssetSource.NBT],
73227
73241
  ["image" /* IMAGE */, _HostedAssetSource.IMAGE],
73228
73242
  ["list" /* LIST */, _HostedAssetSource.LIST],
73229
- ["json" /* JSON */, _HostedAssetSource.JSON]
73243
+ ["json" /* JSON */, _HostedAssetSource.JSON],
73244
+ ["binary" /* BINARY */, _HostedAssetSource.BINARY]
73230
73245
  ]);
73231
73246
  HostedAssetSource = _HostedAssetSource;
73232
73247
  }
@@ -81841,7 +81856,7 @@ return ${compiler2.callType("value", tagType)}
81841
81856
  function readUint8Array(reader, offset, size, diskNumber) {
81842
81857
  return reader.readUint8Array(offset, size, diskNumber);
81843
81858
  }
81844
- var ERR_ITERATOR_COMPLETED_TOO_SOON, HTTP_HEADER_CONTENT_TYPE, DEFAULT_CHUNK_SIZE, PROPERTY_NAME_WRITABLE, Stream, Reader, BlobReader, BlobWriter, SplitDataReader, SplitDataWriter;
81859
+ var ERR_ITERATOR_COMPLETED_TOO_SOON, HTTP_HEADER_CONTENT_TYPE, DEFAULT_CHUNK_SIZE, PROPERTY_NAME_WRITABLE, Stream, Reader, BlobReader, BlobWriter, TextWriter, Uint8ArrayReader, SplitDataReader, SplitDataWriter;
81845
81860
  var init_io = __esm({
81846
81861
  "../../node_modules/@zip.js/zip.js/lib/core/io.js"() {
81847
81862
  init_dirname();
@@ -81924,6 +81939,46 @@ return ${compiler2.callType("value", tagType)}
81924
81939
  return this.blob;
81925
81940
  }
81926
81941
  };
81942
+ TextWriter = class extends BlobWriter {
81943
+ constructor(encoding) {
81944
+ super(encoding);
81945
+ Object.assign(this, {
81946
+ encoding,
81947
+ utf8: !encoding || encoding.toLowerCase() == "utf-8"
81948
+ });
81949
+ }
81950
+ async getData() {
81951
+ const {
81952
+ encoding,
81953
+ utf8
81954
+ } = this;
81955
+ const blob = await super.getData();
81956
+ if (blob.text && utf8) {
81957
+ return blob.text();
81958
+ } else {
81959
+ const reader = new FileReader();
81960
+ return new Promise((resolve, reject) => {
81961
+ Object.assign(reader, {
81962
+ onload: ({ target }) => resolve(target.result),
81963
+ onerror: () => reject(reader.error)
81964
+ });
81965
+ reader.readAsText(blob, encoding);
81966
+ });
81967
+ }
81968
+ }
81969
+ };
81970
+ Uint8ArrayReader = class extends Reader {
81971
+ constructor(array) {
81972
+ super();
81973
+ Object.assign(this, {
81974
+ array,
81975
+ size: array.length
81976
+ });
81977
+ }
81978
+ readUint8Array(index, length) {
81979
+ return this.array.slice(index, index + length);
81980
+ }
81981
+ };
81927
81982
  SplitDataReader = class extends Reader {
81928
81983
  constructor(readers) {
81929
81984
  super();
@@ -84682,6 +84737,181 @@ ${key}` : key;
84682
84737
  }
84683
84738
  });
84684
84739
 
84740
+ // src/assets/_fonts/Unihex.ts
84741
+ var Unihex_exports = {};
84742
+ __export(Unihex_exports, {
84743
+ loadUnihex: () => loadUnihex
84744
+ });
84745
+ function readHex(text2, filename, glyphs) {
84746
+ const lines = text2.split("\n");
84747
+ if (lines[lines.length - 1] === "") lines.pop();
84748
+ lines.forEach((line, index) => {
84749
+ const match = /^([0-9A-F]{4,6}):([0-9A-F]+)$/.exec(line);
84750
+ if (!match || ![32, 64, 96, 128].includes(match[2].length)) {
84751
+ throw new Error(`Invalid Unihex record in ${filename} at line ${index + 1}`);
84752
+ }
84753
+ const codepoint = parseInt(match[1], 16);
84754
+ if (codepoint > 1114111) throw new Error(`Invalid Unihex codepoint in ${filename} at line ${index + 1}`);
84755
+ const bitWidth = match[2].length / 4;
84756
+ const rowLength = bitWidth / 4;
84757
+ const rows = new Uint32Array(GLYPH_HEIGHT);
84758
+ let mask = 0;
84759
+ for (let y5 = 0; y5 < GLYPH_HEIGHT; y5++) {
84760
+ rows[y5] = parseInt(match[2].slice(y5 * rowLength, (y5 + 1) * rowLength), 16);
84761
+ mask |= rows[y5];
84762
+ }
84763
+ let left = 0, right = bitWidth;
84764
+ if (mask) {
84765
+ while (!(mask >>> bitWidth - left - 1 & 1)) left++;
84766
+ right = bitWidth - 1;
84767
+ while (!(mask >>> bitWidth - right - 1 & 1)) right--;
84768
+ }
84769
+ glyphs.set(codepoint, { rows, bitWidth, left, right });
84770
+ });
84771
+ }
84772
+ async function parseUnihex(key) {
84773
+ try {
84774
+ const asset2 = await AssetLoader.get(key, "binary" /* BINARY */);
84775
+ if (!asset2) throw new Error(`Could not load Unihex archive ${key.toNamespacedString()}`);
84776
+ const records = /* @__PURE__ */ new Map();
84777
+ const reader = new ZipReader(new Uint8ArrayReader(asset2.data), { useWebWorkers: false, useCompressionStream: false });
84778
+ try {
84779
+ for (const entry of await reader.getEntries()) {
84780
+ if (!entry.directory && entry.filename.endsWith(".hex")) {
84781
+ readHex(await entry.getData(new TextWriter(), { checkSignature: true }), entry.filename, records);
84782
+ }
84783
+ }
84784
+ } finally {
84785
+ await reader.close();
84786
+ }
84787
+ const indices = new Int32Array(1114112).fill(-1);
84788
+ const rows = new Uint32Array(records.size * GLYPH_HEIGHT), metrics = new Uint8Array(records.size * 3);
84789
+ let index = 0;
84790
+ for (const [codepoint, record] of records) {
84791
+ indices[codepoint] = index;
84792
+ rows.set(record.rows, index * GLYPH_HEIGHT);
84793
+ metrics.set([record.bitWidth, record.left, record.right], index * 3);
84794
+ index++;
84795
+ }
84796
+ return { indices, rows, metrics };
84797
+ } catch (error2) {
84798
+ console.warn(`Could not load Unihex file ${key.toNamespacedString()}`, error2);
84799
+ return void 0;
84800
+ }
84801
+ }
84802
+ async function loadUnihex(provider, fontKey, characters) {
84803
+ const origin = new AssetKey(DEFAULT_NAMESPACE, "", void 0, void 0, "assets", "", fontKey.root);
84804
+ const key = AssetKey.parse("font", provider.hex_file, origin);
84805
+ key.assetType = void 0;
84806
+ const glyphs = /* @__PURE__ */ new Map();
84807
+ let overrides;
84808
+ try {
84809
+ overrides = (provider.size_overrides ?? []).map((override) => {
84810
+ const from = override.from.codePointAt(0), to = override.to.codePointAt(0);
84811
+ if ([...override.from].length !== 1 || [...override.to].length !== 1 || from >= to || !Number.isInteger(override.left) || !Number.isInteger(override.right) || override.right < override.left) {
84812
+ throw new Error(`Invalid Unihex size override in font ${fontKey.toNamespacedString()}`);
84813
+ }
84814
+ return { ...override, from, to };
84815
+ });
84816
+ } catch (error2) {
84817
+ console.warn(`Could not load Unihex file ${key.toNamespacedString()}`, error2);
84818
+ return glyphs;
84819
+ }
84820
+ const file = await Caching.unihexCache.get(key.serialize(), () => parseUnihex(key));
84821
+ if (!file) return glyphs;
84822
+ let atlas = atlases.get(provider);
84823
+ if (!atlas) {
84824
+ atlas = new UnihexAtlas();
84825
+ atlases.set(provider, atlas);
84826
+ }
84827
+ for (const character of characters) {
84828
+ const codepoint = character.codePointAt(0), index = file.indices[codepoint];
84829
+ if (index < 0) continue;
84830
+ const record = {
84831
+ rows: file.rows.subarray(index * GLYPH_HEIGHT, (index + 1) * GLYPH_HEIGHT),
84832
+ bitWidth: file.metrics[index * 3],
84833
+ left: file.metrics[index * 3 + 1],
84834
+ right: file.metrics[index * 3 + 2]
84835
+ };
84836
+ const override = overrides.find((range) => codepoint >= range.from && codepoint <= range.to);
84837
+ if (override) {
84838
+ record.left = override.left;
84839
+ record.right = override.right;
84840
+ }
84841
+ const width = record.right - record.left + 1;
84842
+ let rendered;
84843
+ const render = () => rendered ?? (rendered = atlas.draw(record));
84844
+ glyphs.set(character, {
84845
+ get image() {
84846
+ return render().image;
84847
+ },
84848
+ get x() {
84849
+ return render().x;
84850
+ },
84851
+ get y() {
84852
+ return render().y;
84853
+ },
84854
+ width,
84855
+ height: GLYPH_HEIGHT,
84856
+ scale: 0.5,
84857
+ ascent: 7,
84858
+ advance: Math.floor(width / 2) + 1,
84859
+ boldOffset: 0.5,
84860
+ shadowOffset: 0.5
84861
+ });
84862
+ }
84863
+ return glyphs;
84864
+ }
84865
+ var ATLAS_SIZE, GLYPH_HEIGHT, UnihexAtlas, atlases;
84866
+ var init_Unihex = __esm({
84867
+ "src/assets/_fonts/Unihex.ts"() {
84868
+ init_dirname();
84869
+ init_buffer2();
84870
+ init_process2();
84871
+ init_zip();
84872
+ init_AssetKey();
84873
+ init_AssetLoader();
84874
+ init_Assets();
84875
+ init_Caching();
84876
+ init_AssetParsers();
84877
+ init_CanvasCompat();
84878
+ ATLAS_SIZE = 512;
84879
+ GLYPH_HEIGHT = 16;
84880
+ UnihexAtlas = class {
84881
+ constructor() {
84882
+ this.x = 0;
84883
+ this.y = 0;
84884
+ }
84885
+ draw(glyph) {
84886
+ const width = glyph.right - glyph.left + 1;
84887
+ if (this.image && this.x + width > this.image.width) {
84888
+ this.x = 0;
84889
+ this.y += GLYPH_HEIGHT;
84890
+ }
84891
+ if (!this.image || this.y + GLYPH_HEIGHT > this.image.height || width > this.image.width) {
84892
+ this.image = createCanvas(Math.max(ATLAS_SIZE, width), ATLAS_SIZE);
84893
+ this.x = 0;
84894
+ this.y = 0;
84895
+ }
84896
+ const context = this.image.getContext("2d");
84897
+ const pixels = context.createImageData(width, GLYPH_HEIGHT);
84898
+ for (let y5 = 0; y5 < GLYPH_HEIGHT; y5++) {
84899
+ for (let x4 = 0; x4 < width; x4++) {
84900
+ const column = glyph.left + x4;
84901
+ if (column < 0 || column >= glyph.bitWidth || !(glyph.rows[y5] >>> glyph.bitWidth - column - 1 & 1)) continue;
84902
+ pixels.data.fill(255, (y5 * width + x4) * 4, (y5 * width + x4 + 1) * 4);
84903
+ }
84904
+ }
84905
+ const result = { image: this.image, x: this.x, y: this.y };
84906
+ context.putImageData(pixels, this.x, this.y);
84907
+ this.x += width;
84908
+ return result;
84909
+ }
84910
+ };
84911
+ atlases = /* @__PURE__ */ new WeakMap();
84912
+ }
84913
+ });
84914
+
84685
84915
  // src/assets/Fonts.ts
84686
84916
  var Fonts;
84687
84917
  var init_Fonts = __esm({
@@ -84695,7 +84925,7 @@ ${key}` : key;
84695
84925
  init_ModelTextures();
84696
84926
  init_Caching();
84697
84927
  Fonts = class {
84698
- /** Combines font definitions in source-priority order. Unsupported Unihex and TrueType providers are skipped. */
84928
+ /** Combines font definitions in source-priority order. TrueType providers are skipped. */
84699
84929
  static async get(key = "minecraft:default") {
84700
84930
  const fontKey = typeof key === "string" ? AssetKey.parse("font", key) : key;
84701
84931
  return await Caching.fontCache.get(fontKey.serialize(), () => this.load(fontKey, []));
@@ -84711,6 +84941,7 @@ ${key}` : key;
84711
84941
  const stack = await AssetLoader.getAll(key, "json" /* JSON */);
84712
84942
  if (stack.length === 0) throw new Error(`Could not load font ${key.toNamespacedString()}`);
84713
84943
  const glyphs = /* @__PURE__ */ new Map();
84944
+ const providers = [];
84714
84945
  for (const asset2 of stack) {
84715
84946
  for (const provider of asset2.providers) {
84716
84947
  if (provider.filter?.uniform || provider.filter?.jp) continue;
@@ -84729,17 +84960,43 @@ ${key}` : key;
84729
84960
  break;
84730
84961
  case "reference":
84731
84962
  case "minecraft:reference":
84732
- provided = (await this.load(this.relatedKey("font", provider.id, key), [...parents, serialized])).glyphs;
84963
+ const reference = await this.load(this.relatedKey("font", provider.id, key), [...parents, serialized]);
84964
+ if (reference.resolve) {
84965
+ providers.push(async (characters) => {
84966
+ await reference.resolve(characters);
84967
+ return reference.glyphs;
84968
+ });
84969
+ continue;
84970
+ }
84971
+ provided = reference.glyphs;
84733
84972
  break;
84973
+ case "unihex":
84974
+ case "minecraft:unihex":
84975
+ providers.push(async (characters) => (await Promise.resolve().then(() => (init_Unihex(), Unihex_exports))).loadUnihex(provider, key, characters));
84976
+ continue;
84734
84977
  default:
84735
84978
  continue;
84736
84979
  }
84737
- for (const [character, glyph] of provided) {
84980
+ if (providers.every((provider2) => provider2 instanceof Map)) for (const [character, glyph] of provided) {
84738
84981
  if (character !== "\0" && !glyphs.has(character)) glyphs.set(character, glyph);
84739
84982
  }
84983
+ providers.push(provided);
84740
84984
  }
84741
84985
  }
84742
- return { glyphs };
84986
+ return { glyphs, resolve: providers.every((provider) => provider instanceof Map) ? void 0 : async (characters) => {
84987
+ const remaining = new Set([...characters].filter((character) => character !== "\0" && character !== "\n" && character !== "\r" && !glyphs.has(character)));
84988
+ for (const provider of providers) {
84989
+ if (!remaining.size) break;
84990
+ const provided = provider instanceof Map ? provider : await provider([...remaining].join(""));
84991
+ for (const character of remaining) {
84992
+ const glyph = provided.get(character);
84993
+ if (glyph) {
84994
+ glyphs.set(character, glyph);
84995
+ remaining.delete(character);
84996
+ }
84997
+ }
84998
+ }
84999
+ } };
84743
85000
  }
84744
85001
  static async bitmap(provider, fontKey) {
84745
85002
  const rows = provider.chars.map((row) => [...row]);
@@ -84835,6 +85092,13 @@ ${key}` : key;
84835
85092
  });
84836
85093
 
84837
85094
  // src/entity/scene/EntityAnimationPlayer.ts
85095
+ function validateAnimationWeights(weights, count) {
85096
+ const values = Array.from(weights);
85097
+ if (values.length !== count || values.some((weight) => !Number.isFinite(weight) || weight < 0)) {
85098
+ throw new Error("Animation weights must match the clip count and contain only finite nonnegative numbers");
85099
+ }
85100
+ return values;
85101
+ }
84838
85102
  var ZERO, EntityAnimationPlayer;
84839
85103
  var init_EntityAnimationPlayer = __esm({
84840
85104
  "src/entity/scene/EntityAnimationPlayer.ts"() {
@@ -84847,12 +85111,20 @@ ${key}` : key;
84847
85111
  EntityAnimationPlayer = class {
84848
85112
  constructor() {
84849
85113
  this.parts = [];
85114
+ this._animations = [];
85115
+ this._weights = [];
85116
+ this.loops = [];
84850
85117
  this._time = 0;
84851
- this.loop = false;
84852
85118
  this.speed = 1;
84853
85119
  }
84854
85120
  get animation() {
84855
- return this._animation;
85121
+ return this._animations[0];
85122
+ }
85123
+ get animations() {
85124
+ return this._animations.slice();
85125
+ }
85126
+ get weights() {
85127
+ return this._weights.slice();
84856
85128
  }
84857
85129
  get time() {
84858
85130
  return this._time;
@@ -84862,10 +85134,20 @@ ${key}` : key;
84862
85134
  * without them, the current pose is used. Stopping restores the pose from before playback.
84863
85135
  */
84864
85136
  play(layers, animation, options = {}, poses) {
85137
+ this.playAnimations(layers, [animation], options, poses);
85138
+ }
85139
+ /**
85140
+ * Starts clips on matching parts with a shared clock. Weighted offsets add to the supplied baked poses
85141
+ * or, without poses, to each animated part's pose when playback starts.
85142
+ */
85143
+ playAnimations(layers, animations, options = {}, poses) {
85144
+ const weights = validateAnimationWeights(options.weights ?? animations.map(() => 1), animations.length);
84865
85145
  this.stop();
84866
- this._animation = animation;
85146
+ this._animations = animations.slice();
85147
+ this._weights = weights;
85148
+ if (!animations.length) return;
84867
85149
  this._time = options.time ?? 0;
84868
- this.loop = options.loop ?? animation.loop;
85150
+ this.loops = animations.map((animation) => options.loop ?? animation.loop);
84869
85151
  this.speed = options.speed ?? 1;
84870
85152
  for (const layer of layers) {
84871
85153
  const objects = [];
@@ -84874,7 +85156,8 @@ ${key}` : key;
84874
85156
  if (poses.has(object4)) objects.push(object4);
84875
85157
  });
84876
85158
  } else {
84877
- for (const bone of Object.keys(animation.bones)) {
85159
+ const bones = new Set(animations.flatMap((animation) => Object.keys(animation.bones)));
85160
+ for (const bone of bones) {
84878
85161
  const object4 = layer.getObjectByName(`group:${bone}`);
84879
85162
  if (object4) objects.push(object4);
84880
85163
  }
@@ -84898,7 +85181,7 @@ ${key}` : key;
84898
85181
  }
84899
85182
  /** Restores the poses from before playback. Returns whether an animation was active. */
84900
85183
  stop() {
84901
- if (!this._animation) return false;
85184
+ if (!this._animations.length) return false;
84902
85185
  for (const part of this.parts) {
84903
85186
  part.object.position.copy(part.position);
84904
85187
  part.object.rotation.copy(part.rotation);
@@ -84910,12 +85193,14 @@ ${key}` : key;
84910
85193
  /** Forgets the animation without touching the parts, for parts that no longer exist. */
84911
85194
  clear() {
84912
85195
  this.parts = [];
84913
- this._animation = void 0;
85196
+ this._animations = [];
85197
+ this._weights = [];
85198
+ this.loops = [];
84914
85199
  this._time = 0;
84915
85200
  }
84916
85201
  /** Applies the pose at an absolute playback time. Returns `false` when no clip is active. */
84917
85202
  setTime(seconds) {
84918
- if (!this._animation) return false;
85203
+ if (!this._animations.length) return false;
84919
85204
  this._time = seconds;
84920
85205
  this.apply();
84921
85206
  return true;
@@ -84924,8 +85209,30 @@ ${key}` : key;
84924
85209
  advance(deltaSeconds) {
84925
85210
  return this.setTime(this._time + deltaSeconds * this.speed);
84926
85211
  }
85212
+ /** Changes weights in clip order and reapplies the current time without restarting playback. */
85213
+ setWeights(weights) {
85214
+ if (!this._animations.length) return false;
85215
+ const validated = validateAnimationWeights(weights, this._animations.length);
85216
+ this._weights = validated;
85217
+ this.apply();
85218
+ return true;
85219
+ }
84927
85220
  apply() {
84928
- const pose = sampleEntityAnimation(this._animation, this._time, this.loop);
85221
+ const pose = /* @__PURE__ */ Object.create(null);
85222
+ for (let i4 = 0; i4 < this._animations.length; i4++) {
85223
+ const weight = this._weights[i4];
85224
+ if (weight === 0) continue;
85225
+ const sampled = sampleEntityAnimation(this._animations[i4], this._time, this.loops[i4]);
85226
+ for (const [bone, channels] of Object.entries(sampled)) {
85227
+ const blended = pose[bone] ?? (pose[bone] = {});
85228
+ for (const channel of ENTITY_ANIMATION_CHANNELS) {
85229
+ const value = channels[channel];
85230
+ if (!value) continue;
85231
+ const target = blended[channel] ?? (blended[channel] = [0, 0, 0]);
85232
+ for (let axis = 0; axis < 3; axis++) target[axis] += value[axis] * weight;
85233
+ }
85234
+ }
85235
+ }
84929
85236
  for (const part of this.parts) {
84930
85237
  const { position = ZERO, rotation = ZERO, scale = ZERO } = pose[part.bone] ?? {};
84931
85238
  part.object.position.set(part.basePosition.x + position[0], part.basePosition.y + position[1], part.basePosition.z + position[2]);
@@ -85554,7 +85861,7 @@ ${key}` : key;
85554
85861
  for (const geometry of this.geometries) geometry.dispose();
85555
85862
  this.geometries.clear();
85556
85863
  for (const dispose of this.disposeWireframes.splice(0)) dispose();
85557
- for (const player of this.animationPlayers.splice(0)) player.clear();
85864
+ for (const { player } of this.animationPlayers.splice(0)) player.clear();
85558
85865
  this.partPoses.clear();
85559
85866
  super.disposeAndRemoveAllChildren();
85560
85867
  }
@@ -85589,15 +85896,31 @@ ${key}` : key;
85589
85896
  //<editor-fold desc="ANIMATION">
85590
85897
  /** The first active clip, until playback is stopped or the object is disposed. */
85591
85898
  get animation() {
85592
- return this.animationPlayers[0]?.animation;
85899
+ return this.animationPlayers[0]?.player.animation;
85593
85900
  }
85594
- /** Clips playing together, each targeting a separate geometry layer. */
85901
+ /** Clips playing together, in the order passed to {@link playAnimations}. */
85595
85902
  get activeAnimations() {
85596
- return this.animationPlayers.map((player) => player.animation);
85903
+ const animations = [];
85904
+ for (const { player, indices } of this.animationPlayers) {
85905
+ player.animations.forEach((animation, i4) => {
85906
+ animations[indices[i4]] = animation;
85907
+ });
85908
+ }
85909
+ return animations;
85910
+ }
85911
+ /** Weights of the active clips, in the same order as {@link activeAnimations}. */
85912
+ get animationWeights() {
85913
+ const weights = [];
85914
+ for (const { player, indices } of this.animationPlayers) {
85915
+ player.weights.forEach((weight, i4) => {
85916
+ weights[indices[i4]] = weight;
85917
+ });
85918
+ }
85919
+ return weights;
85597
85920
  }
85598
85921
  /** Seconds since the animation started, before looping. */
85599
85922
  get animationTime() {
85600
- return this.animationPlayers[0]?.time ?? 0;
85923
+ return this.animationPlayers[0]?.player.time ?? 0;
85601
85924
  }
85602
85925
  /**
85603
85926
  * Plays a clip from {@link Entities.getAnimations}, replacing all active clips.
@@ -85608,42 +85931,59 @@ ${key}` : key;
85608
85931
  playAnimation(animation, options) {
85609
85932
  this.playAnimations([animation], options);
85610
85933
  }
85611
- /** Plays clips with a shared clock and no blending. Selected layers without their own clip follow `main`. */
85934
+ /**
85935
+ * Plays clips with a shared clock, adding their weighted offsets within each geometry layer.
85936
+ * Weights default to 1 and are not normalized. Selected layers without their own clip follow `main`.
85937
+ */
85612
85938
  playAnimations(animations, options) {
85613
- const targets = /* @__PURE__ */ new Set();
85614
- const selections = animations.map((animation) => {
85939
+ const weights = validateAnimationWeights(options?.weights ?? animations.map(() => 1), animations.length);
85940
+ const selections = /* @__PURE__ */ new Map();
85941
+ animations.forEach((animation, index) => {
85615
85942
  const layer = animation.layer ?? "main";
85616
- if (targets.has(layer)) throw new Error(`Multiple animations target layer "${layer}"`);
85617
- targets.add(layer);
85618
85943
  const names = Object.keys(this.entityLayers).filter((name2) => name2.split("#")[0] === layer);
85619
85944
  if (!names.length) throw new Error(`Entity ${this.entity.id} has no selected animation layer "${layer}"`);
85620
- return { animation, names };
85945
+ let selection = selections.get(layer);
85946
+ if (!selection) selections.set(layer, selection = { animations: [], names, indices: [] });
85947
+ selection.animations.push(animation);
85948
+ selection.indices.push(index);
85621
85949
  });
85622
- const main = selections.find(({ animation }) => (animation.layer ?? "main") === "main");
85623
- if (main) main.names.push(...Object.keys(this.entityLayers).filter((name2) => !targets.has(name2.split("#")[0])));
85950
+ const main = selections.get("main");
85951
+ if (main) main.names.push(...Object.keys(this.entityLayers).filter((name2) => !selections.has(name2.split("#")[0])));
85624
85952
  this.createMeshes();
85625
85953
  this.stopAnimation();
85626
- for (const { animation, names } of selections) {
85954
+ for (const { animations: clips, names, indices } of selections.values()) {
85627
85955
  const player = new EntityAnimationPlayer();
85628
- player.play(names.map((name2) => this.getLayerGroup(name2)), animation, options, this.partPoses);
85629
- this.animationPlayers.push(player);
85956
+ player.playAnimations(
85957
+ names.map((name2) => this.getLayerGroup(name2)),
85958
+ clips,
85959
+ { ...options, weights: indices.map((index) => weights[index]) },
85960
+ this.partPoses
85961
+ );
85962
+ this.animationPlayers.push({ player, indices });
85630
85963
  }
85631
85964
  this.notifyDirty();
85632
85965
  }
85966
+ /** Changes weights in active clip order, notifying the scene without restarting the shared clock. Has no effect without an animation. */
85967
+ setAnimationWeights(weights) {
85968
+ if (!this.animationPlayers.length) return;
85969
+ const values = validateAnimationWeights(weights, this.activeAnimations.length);
85970
+ for (const { player, indices } of this.animationPlayers) player.setWeights(indices.map((index) => values[index]));
85971
+ this.notifyDirty();
85972
+ }
85633
85973
  /** Stops all clips and restores the poses from before playback. */
85634
85974
  stopAnimation() {
85635
85975
  const players = this.animationPlayers.splice(0);
85636
- for (const player of players) player.stop();
85976
+ for (const { player } of players) player.stop();
85637
85977
  if (players.length) this.notifyDirty();
85638
85978
  }
85639
85979
  /** Poses the object at an explicit time in seconds. Has no effect without an animation. */
85640
85980
  setAnimationTime(seconds) {
85641
- for (const player of this.animationPlayers) player.setTime(seconds);
85981
+ for (const { player } of this.animationPlayers) player.setTime(seconds);
85642
85982
  if (this.animationPlayers.length) this.notifyDirty();
85643
85983
  }
85644
85984
  /** Advances the animation by a frame delta in seconds, scaled by its speed. Has no effect without an animation. */
85645
85985
  advanceAnimation(deltaSeconds) {
85646
- for (const player of this.animationPlayers) player.advance(deltaSeconds);
85986
+ for (const { player } of this.animationPlayers) player.advance(deltaSeconds);
85647
85987
  if (this.animationPlayers.length) this.notifyDirty();
85648
85988
  }
85649
85989
  //</editor-fold>
@@ -87881,6 +88221,7 @@ ${key}` : key;
87881
88221
  }
87882
88222
  const font = await Fonts.get(options.font);
87883
88223
  const runs = typeof text2 === "string" ? [{ text: text2 }] : text2;
88224
+ await font.resolve?.(runs.map((run) => run.text).join(""));
87884
88225
  const glyphs = [], lineWidths = [];
87885
88226
  let line = [], width = 0;
87886
88227
  let trailingNewline = false;
@@ -87907,7 +88248,7 @@ ${key}` : key;
87907
88248
  continue;
87908
88249
  }
87909
88250
  const glyph = font.glyphs.get(character);
87910
- const advance = (glyph?.advance ?? 6) + (style.bold ? 1 : 0);
88251
+ const advance = (glyph?.advance ?? 6) + (style.bold ? glyph?.boldOffset ?? 1 : 0);
87911
88252
  line.push({ character, glyph, advance, style, x: 0, y: 0 });
87912
88253
  width += advance;
87913
88254
  while (width > maxWidth && line.length > 1) {
@@ -87935,7 +88276,7 @@ ${key}` : key;
87935
88276
  batches.push(batch);
87936
88277
  }
87937
88278
  const color3 = new Color(isShadow ? (style.color & 16579836) >> 2 : style.color);
87938
- const offset = isShadow ? 1 : 0;
88279
+ const offset = isShadow ? glyph?.shadowOffset ?? 1 : 0;
87939
88280
  const top = glyph ? 7 - glyph.ascent : 0;
87940
88281
  const height = glyph ? glyph.height * glyph.scale : 8;
87941
88282
  const width = glyph ? glyph.width * glyph.scale : 5;
@@ -87965,7 +88306,7 @@ ${key}` : key;
87965
88306
  for (let i4 = 0; i4 < 4; i4++) batch.colors.push(color3.r, color3.g, color3.b);
87966
88307
  batch.indices.push(base, base + 2, base + 1, base + 2, base + 3, base + 1);
87967
88308
  };
87968
- for (const boldOffset of style.bold ? [0, 1] : [0]) {
88309
+ for (const boldOffset of style.bold ? [0, glyph?.boldOffset ?? 1] : [0]) {
87969
88310
  if (glyph) quad(0, top, width, top + height, boldOffset);
87970
88311
  else {
87971
88312
  quad(0, 0, 5, 1, boldOffset);
@@ -92503,6 +92844,10 @@ ${shader.fragmentShader}`.replace(
92503
92844
  this.atlas.model.elements?.forEach((el) => {
92504
92845
  const elGeo = this._getBoxGeometryFromElement(el).clone();
92505
92846
  this.geometries.add(elGeo);
92847
+ elGeo.setAttribute("shade", new BufferAttribute(
92848
+ new Float32Array(elGeo.getAttribute("position").count).fill(!this.originalModel.itemId && el.shade === false ? 0 : 1),
92849
+ 1
92850
+ ));
92506
92851
  if (this.options.cullMask) {
92507
92852
  const indices = Array.from(elGeo.getIndex().array);
92508
92853
  elGeo.setIndex(indices.filter((_4, index) => {
@@ -94105,6 +94450,7 @@ ${shader.fragmentShader}`.replace(
94105
94450
  toRadians: () => toRadians,
94106
94451
  toTrianglesDrawMode: () => toTrianglesDrawMode,
94107
94452
  trimCanvas: () => trimCanvas,
94453
+ validateAnimationWeights: () => validateAnimationWeights,
94108
94454
  yieldToEventLoop: () => yieldToEventLoop
94109
94455
  });
94110
94456
  init_dirname();
@@ -102794,9 +103140,9 @@ gl_FragDepth=readDepth(vUv);
102794
103140
  function compactQuads(geometry, keep) {
102795
103141
  const quads = keep.flatMap((kept, index) => kept ? [index] : []);
102796
103142
  const compact = new BufferGeometry();
102797
- for (const [name2, size] of Object.entries({ position: 3, normal: 3, uv: 2, uvBounds: 4, color: 3 })) {
103143
+ for (const [name2, size] of Object.entries({ position: 3, normal: 3, uv: 2, uvBounds: 4, color: 3, shade: 1 })) {
102798
103144
  const source2 = geometry.getAttribute(name2);
102799
- const defaults = name2 === "uvBounds" ? [0, 0, 1, 1] : name2 === "color" ? [1, 1, 1] : void 0;
103145
+ const defaults = name2 === "uvBounds" ? [0, 0, 1, 1] : name2 === "color" ? [1, 1, 1] : name2 === "shade" ? [1] : void 0;
102800
103146
  const values = new Float32Array(quads.length * 4 * size);
102801
103147
  for (let q3 = 0; q3 < quads.length; q3++) {
102802
103148
  for (let vertex2 = 0; vertex2 < 4; vertex2++) {
@@ -104074,7 +104420,7 @@ gl_FragDepth=readDepth(vUv);
104074
104420
 
104075
104421
  // src/world/SectionGeometry.ts
104076
104422
  function buildSectionGeometry(input) {
104077
- const { count, indices, templates, cullMasks, templateData, atlases, maxAtlasSize, fluids, light, ambientLight, ambientOcclusion, biomeTints } = input;
104423
+ const { count, indices, templates, cullMasks, templateData, atlases: atlases2, maxAtlasSize, fluids, light, ambientLight, ambientOcclusion, biomeTints } = input;
104078
104424
  if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError("Section atlas size must be a positive integer");
104079
104425
  if (count > indices.length || count > templates.length || count > cullMasks.length) throw new RangeError("Section entry count exceeds its arrays");
104080
104426
  if (biomeTints && biomeTints.length !== count * 3) throw new RangeError("Section biome tints must contain RGB for each placement");
@@ -104092,7 +104438,7 @@ gl_FragDepth=readDepth(vUv);
104092
104438
  const cornerBrightness2 = ambientOcclusion ? new Float32Array(4) : void 0;
104093
104439
  for (const template of templateData) {
104094
104440
  const { quads } = template;
104095
- if (template.positions.length !== quads * 12 || template.normals.length !== quads * 12 || template.uvs.length !== quads * 8 || template.uvBounds.length !== quads * 16 || template.colors.length !== quads * 12 || template.indices.length !== quads * 6 || template.cullFaces.length !== quads || template.biomeTint && template.biomeTint.length !== quads) {
104441
+ if (template.positions.length !== quads * 12 || template.normals.length !== quads * 12 || template.uvs.length !== quads * 8 || template.uvBounds.length !== quads * 16 || template.colors.length !== quads * 12 || template.indices.length !== quads * 6 || template.cullFaces.length !== quads || template.shade && template.shade.length !== quads * 4 || template.biomeTint && template.biomeTint.length !== quads) {
104096
104442
  throw new RangeError("Section template arrays do not match its quad count");
104097
104443
  }
104098
104444
  }
@@ -104109,8 +104455,8 @@ gl_FragDepth=readDepth(vUv);
104109
104455
  const locations = /* @__PURE__ */ new Map();
104110
104456
  for (const [layer, layerAtlases] of [...visibleAtlases].sort(([a4], [b4]) => a4 - b4)) {
104111
104457
  const firstPage = pages.length;
104112
- for (const atlas of [...layerAtlases].sort((a4, b4) => Number(atlases[a4].animated) - Number(atlases[b4].animated) || (atlases[a4].animated ? a4 - b4 : atlases[b4].height - atlases[a4].height))) {
104113
- const { width, height, animated } = atlases[atlas];
104458
+ for (const atlas of [...layerAtlases].sort((a4, b4) => Number(atlases2[a4].animated) - Number(atlases2[b4].animated) || (atlases2[a4].animated ? a4 - b4 : atlases2[b4].height - atlases2[a4].height))) {
104459
+ const { width, height, animated } = atlases2[atlas];
104114
104460
  if (width > maxAtlasSize || height > maxAtlasSize) throw new RangeError("Model atlas exceeds the section atlas size limit");
104115
104461
  let selected = -1;
104116
104462
  for (let i4 = firstPage; !animated && i4 < pages.length; i4++) {
@@ -104153,7 +104499,7 @@ gl_FragDepth=readDepth(vUv);
104153
104499
  });
104154
104500
  if (!quads.sprites.length) continue;
104155
104501
  if (!fluidPages.has(fluid)) {
104156
- const { width, height } = atlases[data.atlas];
104502
+ const { width, height } = atlases2[data.atlas];
104157
104503
  if (width > maxAtlasSize || height > maxAtlasSize) throw new RangeError("Model atlas exceeds the section atlas size limit");
104158
104504
  fluidPages.set(fluid, {
104159
104505
  layer: 2,
@@ -104171,7 +104517,7 @@ gl_FragDepth=readDepth(vUv);
104171
104517
  const tint = fluid === "water" && fluids.waterTints ? fluids.waterTints.subarray(tintIndex, tintIndex + 3) : data.tint;
104172
104518
  fluidPages.get(fluid).fluids.push({ quads, x: x4, y: y5, z: z4, data, tint });
104173
104519
  }
104174
- pages.push(...[...fluidPages.values()].sort((a4, b4) => Number(atlases[a4.placements[0].atlas].animated) - Number(atlases[b4.placements[0].atlas].animated) || a4.placements[0].atlas - b4.placements[0].atlas));
104520
+ pages.push(...[...fluidPages.values()].sort((a4, b4) => Number(atlases2[a4.placements[0].atlas].animated) - Number(atlases2[b4.placements[0].atlas].animated) || a4.placements[0].atlas - b4.placements[0].atlas));
104175
104521
  }
104176
104522
  return pages.map((page) => {
104177
104523
  let faces = page.fluids.reduce((sum, fluid) => sum + fluid.quads.sprites.length, 0);
@@ -104183,12 +104529,13 @@ gl_FragDepth=readDepth(vUv);
104183
104529
  }
104184
104530
  const positions = new Float32Array(faces * 12), normals = new Float32Array(faces * 12);
104185
104531
  const uvs = new Float32Array(faces * 8), uvBounds = new Float32Array(faces * 16), colors = new Float32Array(faces * 12);
104532
+ const shade = new Float32Array(faces * 4).fill(1);
104186
104533
  const outputIndices = new Uint32Array(faces * 6);
104187
104534
  const blockIndices = new Uint16Array(faces);
104188
104535
  let vertex2 = 0, indexOffset = 0;
104189
104536
  for (const entry of page.entries) {
104190
104537
  const template = templateData[templates[entry]];
104191
- const atlas = atlases[template.atlas];
104538
+ const atlas = atlases2[template.atlas];
104192
104539
  const placement = locations.get(template.atlas);
104193
104540
  const mapU = (u4) => (placement.x + u4 * atlas.width) / page.width;
104194
104541
  const mapV = (v5) => 1 - (placement.y + (1 - v5) * atlas.height) / page.height;
@@ -104212,6 +104559,7 @@ gl_FragDepth=readDepth(vUv);
104212
104559
  normals[vertex2 * 3] = template.normals[source * 3];
104213
104560
  normals[vertex2 * 3 + 1] = template.normals[source * 3 + 1];
104214
104561
  normals[vertex2 * 3 + 2] = template.normals[source * 3 + 2];
104562
+ shade[vertex2] = template.shade?.[source] ?? 1;
104215
104563
  uvs[vertex2 * 2] = mapU(template.uvs[source * 2]);
104216
104564
  uvs[vertex2 * 2 + 1] = mapV(template.uvs[source * 2 + 1]);
104217
104565
  uvBounds[vertex2 * 4] = mapU(template.uvBounds[source * 4]);
@@ -104227,7 +104575,7 @@ gl_FragDepth=readDepth(vUv);
104227
104575
  }
104228
104576
  }
104229
104577
  for (const { quads, x: x4, y: y5, z: z4, data, tint } of page.fluids) {
104230
- const atlas = atlases[data.atlas];
104578
+ const atlas = atlases2[data.atlas];
104231
104579
  const placement = page.placements[0];
104232
104580
  const mapU = (u4) => (placement.x + u4 * atlas.width) / page.width;
104233
104581
  const mapV = (v5) => 1 - (placement.y + (1 - v5) * atlas.height) / page.height;
@@ -104264,11 +104612,11 @@ gl_FragDepth=readDepth(vUv);
104264
104612
  indexOffset += 6;
104265
104613
  }
104266
104614
  }
104267
- return { layer: page.layer, width: page.width, height: page.height, placements: page.placements, positions, normals, uvs, uvBounds, colors, indices: outputIndices, blockIndices };
104615
+ return { layer: page.layer, width: page.width, height: page.height, placements: page.placements, positions, normals, uvs, uvBounds, colors, shade, indices: outputIndices, blockIndices };
104268
104616
  });
104269
104617
  }
104270
104618
  function sectionGeometryTransferables(pages) {
104271
- return pages.flatMap((page) => [page.positions.buffer, page.normals.buffer, page.uvs.buffer, page.uvBounds.buffer, page.colors.buffer, page.indices.buffer, page.blockIndices.buffer]);
104619
+ return pages.flatMap((page) => [page.positions.buffer, page.normals.buffer, page.uvs.buffer, page.uvBounds.buffer, page.colors.buffer, page.shade.buffer, page.indices.buffer, page.blockIndices.buffer]);
104272
104620
  }
104273
104621
 
104274
104622
  // src/world/SectionWorker.ts
@@ -104331,7 +104679,7 @@ gl_FragDepth=readDepth(vUv);
104331
104679
  var WATER_TINT = new Color(4159204).toArray();
104332
104680
  function toInput(entries, maxAtlasSize, fluids, lighting) {
104333
104681
  if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError("Section atlas size must be a positive integer");
104334
- const atlases = [];
104682
+ const atlases2 = [];
104335
104683
  const atlasIds = /* @__PURE__ */ new Map();
104336
104684
  const templateIds = /* @__PURE__ */ new Map();
104337
104685
  const input = {
@@ -104354,9 +104702,9 @@ gl_FragDepth=readDepth(vUv);
104354
104702
  if (id === void 0) {
104355
104703
  let atlas = atlasIds.get(template.atlas);
104356
104704
  if (atlas === void 0) {
104357
- atlas = atlases.length;
104705
+ atlas = atlases2.length;
104358
104706
  atlasIds.set(template.atlas, atlas);
104359
- atlases.push(template.atlas);
104707
+ atlases2.push(template.atlas);
104360
104708
  input.atlases.push({ width: template.atlas.image.width, height: template.atlas.image.height, animated: template.atlas.hasAnimation });
104361
104709
  }
104362
104710
  let data = templateCache.get(template);
@@ -104374,6 +104722,7 @@ gl_FragDepth=readDepth(vUv);
104374
104722
  uvs: new Float32Array(quads * 8),
104375
104723
  uvBounds: new Float32Array(quads * 16),
104376
104724
  colors: new Float32Array(quads * 12),
104725
+ shade: new Float32Array(quads * 4),
104377
104726
  indices: new Uint16Array(quads * 6),
104378
104727
  cullFaces: new Uint8Array(template.cullFaces),
104379
104728
  biomeTint: template.biomeTint ? new Uint8Array(template.biomeTint) : void 0,
@@ -104385,6 +104734,7 @@ gl_FragDepth=readDepth(vUv);
104385
104734
  const uv = template.geometry.getAttribute("uv");
104386
104735
  const bounds = template.geometry.getAttribute("uvBounds");
104387
104736
  const color3 = template.geometry.getAttribute("color");
104737
+ const shade = template.geometry.getAttribute("shade");
104388
104738
  for (let vertex2 = 0; vertex2 < quads * 4; vertex2++) {
104389
104739
  data.positions.set([position.getX(vertex2), position.getY(vertex2), position.getZ(vertex2)], vertex2 * 3);
104390
104740
  data.normals.set([normal.getX(vertex2), normal.getY(vertex2), normal.getZ(vertex2)], vertex2 * 3);
@@ -104396,6 +104746,7 @@ gl_FragDepth=readDepth(vUv);
104396
104746
  bounds?.getW(vertex2) ?? 1
104397
104747
  ], vertex2 * 4);
104398
104748
  data.colors.set([color3?.getX(vertex2) ?? 1, color3?.getY(vertex2) ?? 1, color3?.getZ(vertex2) ?? 1], vertex2 * 3);
104749
+ data.shade[vertex2] = shade?.getX(vertex2) ?? 1;
104399
104750
  }
104400
104751
  for (let i5 = 0; i5 < data.indices.length; i5++) data.indices[i5] = indices.getX(i5) - 4 * Math.floor(i5 / 6);
104401
104752
  templateCache.set(template, data);
@@ -104415,9 +104766,9 @@ gl_FragDepth=readDepth(vUv);
104415
104766
  if (!atlas) continue;
104416
104767
  let id = atlasIds.get(atlas);
104417
104768
  if (id === void 0) {
104418
- id = atlases.length;
104769
+ id = atlases2.length;
104419
104770
  atlasIds.set(atlas, id);
104420
- atlases.push(atlas);
104771
+ atlases2.push(atlas);
104421
104772
  input.atlases.push({ width: atlas.image.width, height: atlas.image.height, animated: atlas.hasAnimation });
104422
104773
  }
104423
104774
  input.fluids[kind] = {
@@ -104428,7 +104779,7 @@ gl_FragDepth=readDepth(vUv);
104428
104779
  };
104429
104780
  }
104430
104781
  }
104431
- return { input, atlases };
104782
+ return { input, atlases: atlases2 };
104432
104783
  }
104433
104784
  var SectionMesh = class _SectionMesh extends Group {
104434
104785
  constructor() {
@@ -104443,23 +104794,23 @@ gl_FragDepth=readDepth(vUv);
104443
104794
  }
104444
104795
  /** Builds section-local meshes from visible quads. `maxAtlasSize` limits each atlas dimension in pixels. */
104445
104796
  static build(entries, maxAtlasSize = 2048, fluids, lighting) {
104446
- const { input, atlases } = toInput(entries, maxAtlasSize, fluids, lighting);
104447
- return this.fromPages(buildSectionGeometry(input), atlases);
104797
+ const { input, atlases: atlases2 } = toInput(entries, maxAtlasSize, fluids, lighting);
104798
+ return this.fromPages(buildSectionGeometry(input), atlases2);
104448
104799
  }
104449
104800
  /** Builds section-local meshes in a browser worker when available, with synchronous fallback. */
104450
104801
  static async buildAsync(entries, maxAtlasSize = 2048, fluids, lighting) {
104451
- const { input, atlases } = toInput(entries, maxAtlasSize, fluids, lighting);
104802
+ const { input, atlases: atlases2 } = toInput(entries, maxAtlasSize, fluids, lighting);
104452
104803
  const worker = SectionWorker.shared();
104453
104804
  const pages = worker ? await worker.build(input).catch(() => buildSectionGeometry(input)) : buildSectionGeometry(input);
104454
- return this.fromPages(pages, atlases);
104805
+ return this.fromPages(pages, atlases2);
104455
104806
  }
104456
- static fromPages(pages, atlases) {
104807
+ static fromPages(pages, atlases2) {
104457
104808
  const section = new _SectionMesh();
104458
104809
  for (const page of pages) {
104459
104810
  const canvas = createCanvas(page.width, page.height);
104460
104811
  const context = canvas.getContext("2d");
104461
104812
  for (const { atlas, x: x4, y: y5 } of page.placements) {
104462
- context.drawImage(atlases[atlas].image.canvas, x4, y5);
104813
+ context.drawImage(atlases2[atlas].image.canvas, x4, y5);
104463
104814
  }
104464
104815
  const geometry = new BufferGeometry();
104465
104816
  geometry.setAttribute("position", new Float32BufferAttribute(page.positions.buffer, 3));
@@ -104467,10 +104818,11 @@ gl_FragDepth=readDepth(vUv);
104467
104818
  geometry.setAttribute("uv", new Float32BufferAttribute(page.uvs.buffer, 2));
104468
104819
  geometry.setAttribute("uvBounds", new Float32BufferAttribute(page.uvBounds.buffer, 4));
104469
104820
  geometry.setAttribute("color", new Float32BufferAttribute(page.colors.buffer, 3));
104821
+ geometry.setAttribute("shade", new Float32BufferAttribute(page.shade.buffer, 1));
104470
104822
  geometry.setIndex(new Uint32BufferAttribute(page.indices.buffer, 1));
104471
104823
  geometry.computeBoundingBox();
104472
104824
  geometry.computeBoundingSphere();
104473
- const transparent = page.layer === 2 ? atlases[page.placements[0].atlas].hasTranslucency : page.layer === 1;
104825
+ const transparent = page.layer === 2 ? atlases2[page.placements[0].atlas].hasTranslucency : page.layer === 1;
104474
104826
  const material = Materials.createShadedCanvasMaterial(canvas, transparent, false, true);
104475
104827
  material.side = FrontSide;
104476
104828
  if (page.layer === 2) {
@@ -104485,7 +104837,7 @@ gl_FragDepth=readDepth(vUv);
104485
104837
  section.blockIndices.set(mesh, page.blockIndices);
104486
104838
  const unsubscribe = [];
104487
104839
  for (const { atlas: id, x: x4, y: y5 } of page.placements) {
104488
- const atlas = atlases[id];
104840
+ const atlas = atlases2[id];
104489
104841
  if (!atlas.hasAnimation) continue;
104490
104842
  unsubscribe.push(atlas.subscribe(() => {
104491
104843
  context.clearRect(x4, y5, atlas.image.width, atlas.image.height);