minerender 2.1.0-alpha.74 → 2.1.0-alpha.76

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.
@@ -65,6 +65,7 @@ var init_PersistentCache = __esm({
65
65
  constructor(backing) {
66
66
  this.backing = backing;
67
67
  }
68
+ /** Opens a named store in the active environment using the current cache schema version. */
68
69
  static open(name) {
69
70
  return Env.provider.openCache(name, _PersistentCache.VERSION);
70
71
  }
@@ -263,6 +264,7 @@ var init_Caching = __esm({
263
264
  this.fontCache
264
265
  ];
265
266
  }
267
+ /** Invalidates in-memory entries so later lookups reload them. Persisted entries are retained. */
266
268
  static clear() {
267
269
  for (const cache of this.all) {
268
270
  cache.invalidateAll();
@@ -328,6 +330,7 @@ var init_Geometries = __esm({
328
330
  }
329
331
  return geometry;
330
332
  }
333
+ /** Returns shared geometry. Use {@link createBox} when the caller needs to modify or dispose it independently. */
331
334
  static getBox(key) {
332
335
  const keyStr = serializeBoxGeometryKey(key);
333
336
  return Caching.boxGeometryCache.get(keyStr, (k) => {
@@ -505,12 +508,15 @@ var init_Requests = __esm({
505
508
  }
506
509
  };
507
510
  Requests = class {
511
+ /** Queues a general request. Set `request.signal` to cancel it and `request.timeout` to limit each attempt. */
508
512
  static genericRequest(request) {
509
513
  return this.genericQueue.request(request);
510
514
  }
515
+ /** Queues a request separately from general traffic, using the configured asset base URL for relative paths. */
511
516
  static mcAssetRequest(request) {
512
517
  return this.mcAssetRequestQueue.request(request);
513
518
  }
519
+ /** Sets the base URL for relative asset requests. Use {@link AssetLoader.setVersion} to change Minecraft versions. */
514
520
  static setMcAssetRoot(root) {
515
521
  this.mcAssetRequestQueue.baseURL = root;
516
522
  }
@@ -565,6 +571,7 @@ var init_WrappedImage = __esm({
565
571
  }
566
572
  return false;
567
573
  }
574
+ /** Whether the dimensions form a vertical strip of square frames, without consulting `.mcmeta`. */
568
575
  get animated() {
569
576
  return this.height > this.width && this.height % this.width === 0;
570
577
  }
@@ -611,6 +618,7 @@ var init_ImageLoader = __esm({
611
618
  static _createImage() {
612
619
  return createImage();
613
620
  }
621
+ /** Resolves when an image URL has decoded, or rejects if decoding fails. */
614
622
  static async loadAsync(src) {
615
623
  return new Promise((resolve, reject) => {
616
624
  const image = this._createImage();
@@ -619,6 +627,7 @@ var init_ImageLoader = __esm({
619
627
  image.src = src;
620
628
  });
621
629
  }
630
+ /** Returns an image immediately. Use the callbacks to observe loading, or await {@link loadAsync}. */
622
631
  static loadElement(src, onload, onerr) {
623
632
  const image = this._createImage();
624
633
  if (onload)
@@ -646,6 +655,7 @@ var init_ImageLoader = __esm({
646
655
  throw err;
647
656
  }
648
657
  }
658
+ /** Decodes the supplied bytes into a canvas without fetching the source URL again. */
649
659
  static async infoToCanvasData(info) {
650
660
  const type = info.type === "jpg" ? "jpeg" : info.type ?? "png";
651
661
  const image = await _ImageLoader.loadAsync(`data:image/${type};base64,${info.data.toString("base64")}`);
@@ -662,12 +672,14 @@ var init_ImageLoader = __esm({
662
672
  const image = await this.infoToCanvasData(info);
663
673
  return image.data.getImageData(0, 0, image.width, image.height);
664
674
  }
675
+ /** Returns cached RGBA pixels for an image URL or data URL. Failed loads can be retried. */
665
676
  static async getData(src) {
666
677
  const keyStr = serializeImageKey({ src });
667
678
  return await Caching.imageDataCache.get(keyStr, (k) => {
668
679
  return _ImageLoader.loadData(src);
669
680
  });
670
681
  }
682
+ /** Returns a cached canvas context and dimensions for an image URL or data URL. */
671
683
  static async getCanvasData(src) {
672
684
  const keyStr = serializeImageKey({ src });
673
685
  return await Caching.canvasImageDataCache.get(keyStr, (k) => {
@@ -764,6 +776,7 @@ var init_TextureLoader = __esm({
764
776
  texture.rotation = rotation;
765
777
  return Textures.initTextureProps(texture);
766
778
  }
779
+ /** Loads image pixels in the background. `rotation` is in radians. Check {@link hasFailed} for load failures. */
767
780
  static load(src, format2 = import_three3.RGBAFormat, rotation = 0) {
768
781
  const texture = new import_three3.Texture();
769
782
  texture.colorSpace = THREE.SRGBColorSpace;
@@ -813,6 +826,7 @@ var init_Textures = __esm({
813
826
  return this.initTextureProps(texture);
814
827
  });
815
828
  }
829
+ /** Sets nearest-neighbor filters without changing the texture's color space. Returns the same texture. */
816
830
  static initTextureProps(texture) {
817
831
  texture.magFilter = THREE2.NearestFilter;
818
832
  texture.minFilter = THREE2.NearestFilter;
@@ -825,11 +839,13 @@ var init_Textures = __esm({
825
839
  static createAsset(key) {
826
840
  return new import_three4.Texture();
827
841
  }
842
+ /** Creates an sRGB color texture from a canvas. */
828
843
  static createCanvasTexture(canvas) {
829
844
  const texture = new import_three4.CanvasTexture(canvas);
830
845
  texture.colorSpace = THREE2.SRGBColorSpace;
831
846
  return this.initTextureProps(texture);
832
847
  }
848
+ /** Returns a shared texture immediately and loads its image asynchronously. Failed cached loads are retried. */
833
849
  static getImage(key) {
834
850
  const keyStr = serializeTextureKey(key);
835
851
  const cached2 = Caching.textureCache.peek(keyStr);
@@ -854,6 +870,7 @@ var init_Materials = __esm({
854
870
  init_TextureLoader();
855
871
  init_Caching();
856
872
  Materials = class _Materials {
873
+ /** Shared checkerboard material, created on first access. */
857
874
  static get MISSING_TEXTURE() {
858
875
  return Caching.materialCache.get("builtin:missing-texture", () => new import_three5.MeshBasicMaterial({
859
876
  map: Textures.getMissing(),
@@ -957,6 +974,7 @@ var init_Materials = __esm({
957
974
  if (tint !== void 0) material.color.multiply(new import_three5.Color(tint));
958
975
  return material;
959
976
  }
977
+ /** Creates an unlit, transparent GUI material without depth writes or tone mapping. */
960
978
  static createGuiCanvasMaterial(canvas) {
961
979
  const material = new import_three5.MeshBasicMaterial({
962
980
  map: Textures.createCanvasTexture(canvas),
@@ -1123,6 +1141,7 @@ var init_Materials = __esm({
1123
1141
  }
1124
1142
  return this.createBasicCanvasMaterial(canvas, transparent, shade);
1125
1143
  }
1144
+ /** Returns a shared image material. Use {@link createImage} for a separate material instance. */
1126
1145
  static getImage(key) {
1127
1146
  const keyStr = serializeMaterialKey(key);
1128
1147
  const map = Caching.materialCache.peek(keyStr)?.map;
@@ -1297,6 +1316,14 @@ var init_AssetKey = __esm({
1297
1316
  }
1298
1317
  };
1299
1318
  AssetKey = class _AssetKey extends BasicAssetKey {
1319
+ /**
1320
+ * Creates a key from separate path components. Use {@link parse} for a combined reference.
1321
+ *
1322
+ * @param assetType - Asset directory, such as `models`, `textures`, or `blockstates`.
1323
+ * @param type - Subdirectory, such as `block` or `item`.
1324
+ * @param rootType - Top-level directory, usually `assets` or `data`.
1325
+ * @param root - Base URL override for hosted asset sources.
1326
+ */
1300
1327
  constructor(namespace, path, assetType, type, rootType = "assets", extension = ".json", root) {
1301
1328
  super(namespace, path);
1302
1329
  this.namespace = namespace;
@@ -1308,6 +1335,16 @@ var init_AssetKey = __esm({
1308
1335
  this.root = root;
1309
1336
  this.isAssetKey = true;
1310
1337
  }
1338
+ /**
1339
+ * Parses an asset reference such as `minecraft:block/stone`.
1340
+ * A missing namespace defaults to the origin's namespace or `minecraft`.
1341
+ *
1342
+ * @param assetType - Asset category, such as `models` or `textures`.
1343
+ * @param str - Path with an optional namespace and file extension.
1344
+ * @param origin - Supplies the asset root, default namespace, and non-texture extension.
1345
+ * @returns A key with the matching extension removed from its path. Textures use `.png`;
1346
+ * other assets use the origin's extension or `.json`.
1347
+ */
1311
1348
  static parse(assetType, str, origin) {
1312
1349
  let namespace = origin?.namespace || DEFAULT_NAMESPACE;
1313
1350
  if (str.includes(":")) {
@@ -1339,6 +1376,7 @@ var init_AssetKey = __esm({
1339
1376
  ];
1340
1377
  return a.join("/");
1341
1378
  }
1379
+ /** Joins the type subdirectory and path without adding a namespace or file extension. */
1342
1380
  getFullPath() {
1343
1381
  let p10 = [];
1344
1382
  if (this.type) {
@@ -1350,6 +1388,7 @@ var init_AssetKey = __esm({
1350
1388
  toNamespacedString() {
1351
1389
  return this.namespace + ":" + this.getFullPath();
1352
1390
  }
1391
+ /** Returns a cache identifier that includes the explicit root or {@link AssetLoader.ROOT}. */
1353
1392
  serialize() {
1354
1393
  return this.toString();
1355
1394
  }
@@ -1409,6 +1448,7 @@ var init_DisplayTransforms = __esm({
1409
1448
  const scale = new import_three7.Vector3(...transform.scale ?? [1, 1, 1]).clampScalar(-4, 4);
1410
1449
  return new import_three7.Matrix4().compose(translation, rotation, scale);
1411
1450
  }
1451
+ /** Transforms geometry in place and reverses triangle winding when the matrix reflects it. */
1412
1452
  static apply(geometry, matrix) {
1413
1453
  geometry.applyMatrix4(matrix);
1414
1454
  if (matrix.determinant() < 0) {
@@ -1436,6 +1476,7 @@ var init_ModelMerger = __esm({
1436
1476
  init_AssetKey();
1437
1477
  init_DisplayTransforms();
1438
1478
  ModelMerger = class {
1479
+ /** Loads the parent chain and returns a merged model without modifying the supplied definition. */
1439
1480
  static async mergeWithParents(model) {
1440
1481
  const models = await this.collectAllParents(model);
1441
1482
  let merged = {};
@@ -1503,6 +1544,7 @@ var init_Models = __esm({
1503
1544
  static get PERSISTENT_CACHE() {
1504
1545
  return this._persistentCache ?? (this._persistentCache = PersistentCache.open("minerender-models"));
1505
1546
  }
1547
+ /** Lists item filenames from the asset source's `_list.json`, with a legacy model-directory fallback. */
1506
1548
  static async getItemList() {
1507
1549
  const key = new AssetKey(DEFAULT_NAMESPACE, "_list", "items");
1508
1550
  const legacyKey = new AssetKey(DEFAULT_NAMESPACE, "_list", "models", "item");
@@ -1573,6 +1615,7 @@ var init_Models = __esm({
1573
1615
  }
1574
1616
  throw new Error(`Unsupported item model ${node?.type ?? "definition"} for ${key.toNamespacedString()}`);
1575
1617
  }
1618
+ /** Loads one model file without resolving its parents. Returns `undefined` when the file is missing. */
1576
1619
  static async getRaw(key) {
1577
1620
  if (!key.assetType) {
1578
1621
  key.assetType = "models";
@@ -1592,6 +1635,12 @@ var init_Models = __esm({
1592
1635
  return asset;
1593
1636
  });
1594
1637
  }
1638
+ /**
1639
+ * Loads a model and resolves its parent chain. Returns `undefined` when the model is missing.
1640
+ * Item keys use GUI context, false conditions, and zero numeric properties.
1641
+ *
1642
+ * @param key - Model key, for example `AssetKey.parse("models", "minecraft:item/diamond_sword")`.
1643
+ */
1595
1644
  static async getMerged(key) {
1596
1645
  if (!key.assetType) {
1597
1646
  key.assetType = "models";
@@ -1604,9 +1653,11 @@ var init_Models = __esm({
1604
1653
  return _Models.loadAndMerge(key);
1605
1654
  });
1606
1655
  }
1656
+ /** Alias for {@link getMerged}. */
1607
1657
  static async get(key) {
1608
1658
  return this.getMerged(key);
1609
1659
  }
1660
+ /** Clears persisted models. Use {@link Caching.clear} to also discard in-memory assets. */
1610
1661
  static async clearCache() {
1611
1662
  return this.PERSISTENT_CACHE.clear();
1612
1663
  }
@@ -1629,6 +1680,7 @@ var init_BlockStates = __esm({
1629
1680
  return this._persistentCache ?? (this._persistentCache = PersistentCache.open("minerender-blockstates"));
1630
1681
  }
1631
1682
  // BlockState names are hardcoded
1683
+ /** Returns blockstate filenames from the selected version's `_list.json`, or an empty list. */
1632
1684
  static async getList() {
1633
1685
  const key = new AssetKey(
1634
1686
  DEFAULT_NAMESPACE,
@@ -1649,6 +1701,7 @@ var init_BlockStates = __esm({
1649
1701
  return AssetLoader.get(key, "json" /* JSON */);
1650
1702
  });
1651
1703
  }
1704
+ /** Looks up vanilla property definitions for the key's block path, or returns `undefined`. */
1652
1705
  static async getDefaultState(key) {
1653
1706
  const defaultStates = await this.getDefaultStates();
1654
1707
  if (!defaultStates) {
@@ -1656,6 +1709,7 @@ var init_BlockStates = __esm({
1656
1709
  }
1657
1710
  return defaultStates["minecraft:" + key.path];
1658
1711
  }
1712
+ /** Loads a cached blockstate definition for {@link MineRenderScene.addBlock}, or returns `undefined`. */
1659
1713
  static async get(key) {
1660
1714
  if (!key.assetType) {
1661
1715
  key.assetType = "blockstates";
@@ -1682,6 +1736,7 @@ var init_BlockStates = __esm({
1682
1736
  }
1683
1737
  return Promise.all(promises);
1684
1738
  }
1739
+ /** Clears persisted blockstates. Use {@link Caching.clear} to also discard in-memory assets. */
1685
1740
  static async clearCache() {
1686
1741
  await this.PERSISTENT_CACHE.clear();
1687
1742
  }
@@ -1707,9 +1762,11 @@ var init_Assets = __esm({
1707
1762
  static parseAssetKey(assetType, str, origin) {
1708
1763
  return AssetKey.parse(assetType, str, origin);
1709
1764
  }
1765
+ /** Loads a model with its parent chain resolved. See {@link Models.getMerged}. */
1710
1766
  static async getModel(key) {
1711
1767
  return Models.getMerged(key);
1712
1768
  }
1769
+ /** Loads a blockstate definition. See {@link BlockStates.get}. */
1713
1770
  static async getBlockState(key) {
1714
1771
  return BlockStates.get(key);
1715
1772
  }
@@ -1756,6 +1813,10 @@ var init_BatchedExecutor = __esm({
1756
1813
  "src/util/BatchedExecutor.ts"() {
1757
1814
  import_jobqu2 = require("jobqu");
1758
1815
  BatchedExecutor = class {
1816
+ /**
1817
+ * @param interval - Delay between queue runs, in milliseconds.
1818
+ * @param batch - Maximum tasks started per run and maximum tasks active at once.
1819
+ */
1759
1820
  constructor(interval = 1, batch = 30) {
1760
1821
  if (!Number.isFinite(interval) || interval < 0) throw new RangeError("Batch interval must be finite and nonnegative");
1761
1822
  if (!Number.isInteger(batch) || batch < 1) throw new RangeError("Batch size must be a positive integer");
@@ -1763,9 +1824,11 @@ var init_BatchedExecutor = __esm({
1763
1824
  this.batch = batch;
1764
1825
  this.queue = new import_jobqu2.JobQueue(async (task) => task(), { interval, maxPerRun: batch, maxActive: batch });
1765
1826
  }
1827
+ /** Queues a task and resolves with its result, or rejects with its error. */
1766
1828
  submit(task) {
1767
1829
  return this.queue.add(() => task());
1768
1830
  }
1831
+ /** Rejects queued and future tasks. Tasks already running are allowed to finish. */
1769
1832
  stop() {
1770
1833
  this.queue.end();
1771
1834
  }
@@ -1908,6 +1971,7 @@ var init_NBTHelper = __esm({
1908
1971
  "src/nbt/NBTHelper.ts"() {
1909
1972
  import_buffer2 = require("buffer");
1910
1973
  NBTHelper = class {
1974
+ /** Parses NBT bytes and preserves format and compression metadata. Omit `format` for automatic detection. */
1911
1975
  static async fromBuffer(data, format2) {
1912
1976
  const buffer = import_buffer2.Buffer.from(data instanceof Uint8Array ? data : new Uint8Array(data));
1913
1977
  const prismarineNbt = await import("prismarine-nbt");
@@ -1976,6 +2040,7 @@ var init_HostedAssetSource = __esm({
1976
2040
  retryDefaults: true
1977
2041
  };
1978
2042
  _HostedAssetSource = class _HostedAssetSource extends AssetSource {
2043
+ /** Retries missing assets with the `minecraft` namespace and default root. Other failures reject. */
1979
2044
  async loadOrRetryWithDefaults(key, parser) {
1980
2045
  const direct = await this.load(key, parser);
1981
2046
  if (typeof direct !== "undefined") {
@@ -2033,6 +2098,10 @@ var init_HostedAssetSource = __esm({
2033
2098
  assetBasePath(key) {
2034
2099
  return `${key.root ?? this.root ?? AssetLoader.ROOT}/${key.rootType !== void 0 ? key.rootType + "/" : ""}${key.namespace !== void 0 ? key.namespace + "/" : ""}${key.assetType !== void 0 ? key.assetType + "/" : ""}`;
2035
2100
  }
2101
+ /**
2102
+ * Creates a hosted source for {@link AssetLoader.addSource}.
2103
+ * Set `options.retryDefaults` to `false` to restrict lookups to the requested namespace and root.
2104
+ */
2036
2105
  constructor(root, options) {
2037
2106
  super();
2038
2107
  this._root = root;
@@ -2125,6 +2194,11 @@ var init_BrowserArchiveProxy = __esm({
2125
2194
  "src/assets/source/archive/BrowserArchiveProxy.ts"() {
2126
2195
  import_zip = require("@zip.js/zip.js");
2127
2196
  BrowserArchiveProxy = class {
2197
+ /**
2198
+ * Opens a ZIP for asset lookup.
2199
+ * @param id - Cache identity for this content. Change it when the pack changes.
2200
+ * A File supplies an identity from its name, size, and modification time when omitted.
2201
+ */
2128
2202
  constructor(blob, id) {
2129
2203
  this._blob = blob;
2130
2204
  this._reader = new import_zip.ZipReader(new import_zip.BlobReader(this._blob));
@@ -2322,6 +2396,7 @@ var init_ArchiveAssetSource = __esm({
2322
2396
  dataPackFormat: copyFormat(options.dataPackFormat)
2323
2397
  };
2324
2398
  }
2399
+ /** Creates a browser ZIP source from a Blob or File. */
2325
2400
  static blob(blob, options) {
2326
2401
  return new _ArchiveAssetSource(new BrowserArchiveProxy(blob), options);
2327
2402
  }
@@ -2456,6 +2531,7 @@ var init_AssetLoader = __esm({
2456
2531
  static get version() {
2457
2532
  return this.ROOT.substring(this.ROOT.lastIndexOf("/") + 1);
2458
2533
  }
2534
+ /** Selects an mcasset.cloud version, updates the vanilla source, and clears in-memory caches. */
2459
2535
  static setVersion(version) {
2460
2536
  this.ROOT = `https://assets.mcasset.cloud/${version}`;
2461
2537
  const source = new HostedAssetSource(this.ROOT, { retryDefaults: false });
@@ -2489,6 +2565,13 @@ var init_AssetLoader = __esm({
2489
2565
  return scope ? `${scope}
2490
2566
  ${key}` : key;
2491
2567
  }
2568
+ /**
2569
+ * Registers a source at the highest priority.
2570
+ * Call {@link Caching.clear} after changing sources to discard previously loaded assets.
2571
+ *
2572
+ * @param key - Name used to replace or remove this source.
2573
+ * @param override - Removes the first source with this name before adding the new one.
2574
+ */
2492
2575
  static addSource(key, source, override = true) {
2493
2576
  if (override) {
2494
2577
  const existing = this.removeSource(key);
@@ -2499,6 +2582,7 @@ ${key}` : key;
2499
2582
  this._SOURCES.unshift({ key, source });
2500
2583
  console.log(p4, "Added AssetSource", key);
2501
2584
  }
2585
+ /** Removes and returns the first source with this name. Call {@link Caching.clear} to reload assets. */
2502
2586
  static removeSource(key) {
2503
2587
  const index = this._SOURCES.findIndex((s) => s.key === key);
2504
2588
  if (index != -1) {
@@ -2509,6 +2593,7 @@ ${key}` : key;
2509
2593
  }
2510
2594
  return void 0;
2511
2595
  }
2596
+ /** Loads from all sources and returns defined results in priority order. Any source failure rejects the call. */
2512
2597
  static async getAll(key, parser) {
2513
2598
  const sources = [...this._SOURCES];
2514
2599
  const results = [];
@@ -2553,6 +2638,7 @@ ${key}` : key;
2553
2638
  return void 0;
2554
2639
  }
2555
2640
  };
2641
+ /** Default asset base URL. Use {@link setVersion} to select a Minecraft version. */
2556
2642
  _AssetLoader.ROOT = DEFAULT_ROOT;
2557
2643
  _AssetLoader._SOURCES = [];
2558
2644
  /** Used when a registered source cannot identify its content, so nothing persists past this session. */
@@ -2577,6 +2663,7 @@ var init_ModelTextures = __esm({
2577
2663
  static get PERSISTENT_META_CACHE() {
2578
2664
  return this._persistentMetaCache ?? (this._persistentMetaCache = PersistentCache.open("minerender-texturemeta"));
2579
2665
  }
2666
+ /** Loads and decodes a texture into a readable canvas, or returns `undefined` when missing. */
2580
2667
  static async get(key) {
2581
2668
  const keyStr = key.serialize();
2582
2669
  const pending = this.preload(key);
@@ -2594,6 +2681,7 @@ var init_ModelTextures = __esm({
2594
2681
  throw err;
2595
2682
  }
2596
2683
  }
2684
+ /** Fetches and caches encoded texture bytes without decoding the pixels. */
2597
2685
  static async preload(key) {
2598
2686
  const keyStr = key.serialize();
2599
2687
  return Caching.textureAssetCache.get(keyStr, (k) => {
@@ -2604,6 +2692,7 @@ var init_ModelTextures = __esm({
2604
2692
  });
2605
2693
  });
2606
2694
  }
2695
+ /** Loads a texture's `.mcmeta` file, or returns `undefined` when no metadata file exists. */
2607
2696
  static async getMeta(key) {
2608
2697
  if (!key.extension || !key.extension.endsWith(".mcmeta")) {
2609
2698
  key = Object.assign(new AssetKey("", ""), key);
@@ -2620,6 +2709,7 @@ var init_ModelTextures = __esm({
2620
2709
  });
2621
2710
  });
2622
2711
  }
2712
+ /** Clears persisted texture metadata. Use {@link Caching.clear} to discard in-memory textures and metadata. */
2623
2713
  static async clearCache() {
2624
2714
  await this.PERSISTENT_META_CACHE.clear();
2625
2715
  }
@@ -2686,6 +2776,7 @@ var init_Ticker = __esm({
2686
2776
  }
2687
2777
  return handle;
2688
2778
  }
2779
+ /** Starts or resumes the shared tick loop. Repeated calls have no effect. */
2689
2780
  static start() {
2690
2781
  if (this.interval) return;
2691
2782
  this.interval = this.schedule(() => {
@@ -2708,6 +2799,7 @@ var init_Ticker = __esm({
2708
2799
  _Ticker.fiveSecondTicks = 0;
2709
2800
  }, 1e3 * 5);
2710
2801
  }
2802
+ /** Pauses the loop while retaining callbacks for a later {@link start}. */
2711
2803
  static stop() {
2712
2804
  if (this.interval) clearInterval(this.interval);
2713
2805
  if (this.oneSecondTicksTracker) clearInterval(this.oneSecondTicksTracker);
@@ -2716,12 +2808,14 @@ var init_Ticker = __esm({
2716
2808
  this.oneSecondTicksTracker = void 0;
2717
2809
  this.fiveSecondTicksTracker = void 0;
2718
2810
  }
2811
+ /** Registers a callback, starts the loop if needed, and returns an ID for {@link remove}. */
2719
2812
  static add(tick) {
2720
2813
  this.start();
2721
2814
  const c = this.counter++;
2722
2815
  this._tickers.set(c, tick);
2723
2816
  return c;
2724
2817
  }
2818
+ /** Removes a callback by ID and stops the timers when no callbacks remain. */
2725
2819
  static remove(c) {
2726
2820
  if (typeof c === "number") this._tickers.delete(c);
2727
2821
  if (!this._tickers.size) this.stop();
@@ -2735,6 +2829,7 @@ var init_Ticker = __esm({
2735
2829
  static get tpsFiveSeconds() {
2736
2830
  return this.fiveSecondTps;
2737
2831
  }
2832
+ /** Stops the loop and removes all registered callbacks. */
2738
2833
  static dispose() {
2739
2834
  this.stop();
2740
2835
  this._tickers.clear();
@@ -2789,6 +2884,7 @@ var init_TextureAtlas = __esm({
2789
2884
  }
2790
2885
  };
2791
2886
  }
2887
+ /** Copies pixels for a texture variable from its current atlas rectangle. */
2792
2888
  getData(texture) {
2793
2889
  const pos = this.positions[texture];
2794
2890
  const size = this.sizes[texture];
@@ -3066,6 +3162,7 @@ var init_UVMapper = __esm({
3066
3162
  }
3067
3163
  uv.needsUpdate = true;
3068
3164
  }
3165
+ /** Returns the shared atlas for a keyed, merged model, creating it on first use. */
3069
3166
  static async getAtlas(model) {
3070
3167
  const keyStr = model.key.serialize();
3071
3168
  return Caching.modelTextureAtlasCache.get(keyStr, (k) => {
@@ -3136,6 +3233,11 @@ var init_UVMapper = __esm({
3136
3233
  }
3137
3234
  return [tl, tr, bl, br];
3138
3235
  }
3236
+ /**
3237
+ * Combines model textures and animation metadata into an atlas.
3238
+ * Mapped UVs are stored on copies of the model's elements, available through the returned atlas.
3239
+ * Returns `undefined` for models without a texture map.
3240
+ */
3139
3241
  static async createAtlas(originalModel) {
3140
3242
  const textureMap = {};
3141
3243
  const metaMap = {};
@@ -3500,6 +3602,7 @@ var init_Entities = __esm({
3500
3602
  init_MineRenderError();
3501
3603
  init_ModelTextures();
3502
3604
  Entities = class {
3605
+ /** Lists model paths in the `minecraft` namespace, including subdirectories and excluding `.json`. */
3503
3606
  static async getEntityList() {
3504
3607
  const collect = async (path) => {
3505
3608
  const prefix2 = path ? `${path}/` : "";
@@ -3517,6 +3620,7 @@ var init_Entities = __esm({
3517
3620
  const key = new AssetKey(modelKey.namespace, path, void 0, void 0, "entity-models", ".json", isAssetKey(modelKey) ? modelKey.root : void 0);
3518
3621
  return Caching.entityModelCache.get(key.serialize(), () => AssetLoader.get(key, "json" /* JSON */));
3519
3622
  }
3623
+ /** Returns selectable geometry-layer names, or an empty list when the model is missing. */
3520
3624
  static async getLayerList(modelKey) {
3521
3625
  return Object.keys((await this.getModelFile(modelKey))?.layers ?? {});
3522
3626
  }
@@ -3524,6 +3628,15 @@ var init_Entities = __esm({
3524
3628
  static async getPassList(modelKey) {
3525
3629
  return (await this.getModelFile(modelKey))?.passes ?? [];
3526
3630
  }
3631
+ /**
3632
+ * Loads the layers and textures to pass to {@link MineRenderScene.addEntity}.
3633
+ * By default, selects `main`, unconditional passes, and passes enabled by `options.when`.
3634
+ *
3635
+ * @param modelKey - Dataset model, such as `new BasicAssetKey("minecraft", "zombie")`.
3636
+ * @param textureKey - Texture override for the first selected layer.
3637
+ * @param options - Layer selection, conditional passes, and per-layer texture overrides.
3638
+ * @returns The selected model, or `undefined` when its dataset file is missing.
3639
+ */
3527
3640
  static async getEntity(modelKey, textureKey, options) {
3528
3641
  const model = await this.getModelFile(modelKey);
3529
3642
  if (!model) return void 0;
@@ -3569,6 +3682,7 @@ var init_Entities = __esm({
3569
3682
  const file = await Caching.entityAnimationCache.get(key.serialize(), () => AssetLoader.get(key, "json" /* JSON */));
3570
3683
  return file?.animations;
3571
3684
  }
3685
+ /** Finds a fallback texture using the model path, its directory, and vanilla variant data. */
3572
3686
  static async resolveTexture(modelKey) {
3573
3687
  const path = isAssetKey(modelKey) ? modelKey.getFullPath() : modelKey.path;
3574
3688
  const root = isAssetKey(modelKey) ? modelKey.root : void 0;
@@ -3729,12 +3843,14 @@ var init_EntityAnimationPlayer = __esm({
3729
3843
  this._animation = void 0;
3730
3844
  this._time = 0;
3731
3845
  }
3846
+ /** Applies the pose at an absolute playback time. Returns `false` when no clip is active. */
3732
3847
  setTime(seconds) {
3733
3848
  if (!this._animation) return false;
3734
3849
  this._time = seconds;
3735
3850
  this.apply();
3736
3851
  return true;
3737
3852
  }
3853
+ /** Advances playback by elapsed seconds multiplied by the speed passed to {@link play}. */
3738
3854
  advance(deltaSeconds) {
3739
3855
  return this.setTime(this._time + deltaSeconds * this.speed);
3740
3856
  }
@@ -3772,6 +3888,7 @@ var init_InstanceReference = __esm({
3772
3888
  if (!this.instanceable.isInstanceActive(this.index, this)) throw new MineRenderError("Instance has been removed");
3773
3889
  return this.instanceable;
3774
3890
  }
3891
+ /** Releases this placement's slot for reuse. Repeated calls have no effect. */
3775
3892
  removeFromScene() {
3776
3893
  if (this.instanceable.isInstanceActive(this.index, this)) this.instanceable.removeInstanceAt(this.index);
3777
3894
  }
@@ -3784,9 +3901,11 @@ var init_InstanceReference = __esm({
3784
3901
  setMatrix(matrix) {
3785
3902
  this.activeInstanceable.setMatrixAt(this.index, matrix);
3786
3903
  }
3904
+ /** Hides or restores this placement while preserving its transform and allocated slot. */
3787
3905
  setVisible(visible) {
3788
3906
  this.activeInstanceable.setInstanceVisibleAt(this.index, visible);
3789
3907
  }
3908
+ /** Updates the supplied transform components. Positions use scene units and rotations use radians. */
3790
3909
  setPositionRotationScale(position, rotation, scale) {
3791
3910
  this.activeInstanceable.setPositionRotationScaleAt(this.index, position, rotation, scale);
3792
3911
  }
@@ -3855,6 +3974,7 @@ var init_SceneObject = __esm({
3855
3974
  }
3856
3975
  async init() {
3857
3976
  }
3977
+ /** Marks ancestor scenes for redraw and emits a `change` event. */
3858
3978
  notifyDirty() {
3859
3979
  this.traverseAncestors((parent) => {
3860
3980
  const scene = parent;
@@ -3890,15 +4010,17 @@ var init_SceneObject = __esm({
3890
4010
  return obj;
3891
4011
  }
3892
4012
  /**
3893
- * Get a group by its name
4013
+ * Finds a named part, such as `head`, without the internal `group:` prefix.
4014
+ * Returns `undefined` when the group does not exist.
3894
4015
  */
3895
4016
  getGroupByName(name) {
3896
4017
  return this.getObjectByName(`group:${name}`);
3897
4018
  }
3898
4019
  /**
3899
- * Toggle visibility of a group
3900
- * @param name name of the group
3901
- * @param visible set the visibility directly, if not set toggles it
4020
+ * Changes a named group's visibility and requests a redraw.
4021
+ * @param name - Part name without the `group:` prefix.
4022
+ * @param visible - Visibility to assign. Omit it to toggle the current value.
4023
+ * @returns The resulting visibility, or `false` if the group does not exist.
3902
4024
  */
3903
4025
  toggleGroupVisibility(name, visible) {
3904
4026
  return this.toggleObjectVisibility(this.getGroupByName(name), visible);
@@ -3949,15 +4071,16 @@ var init_SceneObject = __esm({
3949
4071
  return mesh;
3950
4072
  }
3951
4073
  /**
3952
- * Get a mesh by its name
4074
+ * Finds a named mesh without the internal `mesh:` prefix, or returns `undefined`.
3953
4075
  */
3954
4076
  getMeshByName(name) {
3955
4077
  return this.getObjectByName(`mesh:${name}`);
3956
4078
  }
3957
4079
  /**
3958
- * Toggle visibility of a mesh
3959
- * @param name name of the mesh
3960
- * @param visible set the visibility directly, if not set toggles it
4080
+ * Changes a named mesh's visibility and requests a redraw.
4081
+ * @param name - Mesh name without the `mesh:` prefix.
4082
+ * @param visible - Visibility to assign. Omit it to toggle the current value.
4083
+ * @returns The resulting visibility, or `false` if the mesh does not exist.
3961
4084
  */
3962
4085
  toggleMeshVisibility(name, visible) {
3963
4086
  return this.toggleObjectVisibility(this.getMeshByName(name), visible);
@@ -4003,12 +4126,14 @@ var init_SceneObject = __esm({
4003
4126
  get isInstanced() {
4004
4127
  return this._isInstanced;
4005
4128
  }
4129
+ /** Number of live placements, excluding released instance slots. */
4006
4130
  get instanceCounter() {
4007
4131
  return this._instanceCounter;
4008
4132
  }
4009
4133
  constructInstanceReference(i) {
4010
4134
  return new InstanceReference(this, i);
4011
4135
  }
4136
+ /** Allocates a placement of this instanced object, reusing a released slot when available. */
4012
4137
  nextInstance() {
4013
4138
  const mesh = this.instanceMesh;
4014
4139
  if (!mesh) throw new MineRenderError("Object is not instanced");
@@ -4155,6 +4280,7 @@ var init_SceneObject = __esm({
4155
4280
  vector.setFromMatrixScale(matrix);
4156
4281
  return vector;
4157
4282
  }
4283
+ /** Updates supplied transform components. For a shared model, affects every live instance. */
4158
4284
  setPositionRotationScale(position, rotation, scale) {
4159
4285
  if (this.isInstanced) {
4160
4286
  for (const i of this.activeInstanceIndices()) {
@@ -4173,6 +4299,7 @@ var init_SceneObject = __esm({
4173
4299
  }
4174
4300
  this.notifyDirty();
4175
4301
  }
4302
+ /** Sets position in scene units. For a shared model, updates every live instance. */
4176
4303
  setPosition(position) {
4177
4304
  if (this.isInstanced) {
4178
4305
  for (const i of this.activeInstanceIndices()) {
@@ -4190,6 +4317,7 @@ var init_SceneObject = __esm({
4190
4317
  return this.position;
4191
4318
  }
4192
4319
  }
4320
+ /** Sets rotation in radians. For a shared model, updates every live instance. */
4193
4321
  setRotation(rotation) {
4194
4322
  if (this.isInstanced) {
4195
4323
  for (const i of this.activeInstanceIndices()) {
@@ -4207,6 +4335,7 @@ var init_SceneObject = __esm({
4207
4335
  return this.rotation;
4208
4336
  }
4209
4337
  }
4338
+ /** Sets scale factors. For a shared model, updates every live instance. */
4210
4339
  setScale(scale) {
4211
4340
  if (this.isInstanced) {
4212
4341
  for (const i of this.activeInstanceIndices()) {
@@ -4244,6 +4373,7 @@ var init_SceneObject = __esm({
4244
4373
  this.notifyDirty();
4245
4374
  super.dispose();
4246
4375
  }
4376
+ /** Releases instance slots and removes children, disposing children that implement Disposable. */
4247
4377
  disposeAndRemoveAllChildren() {
4248
4378
  if (this.instanceMesh) {
4249
4379
  if (this._scene) this._scene.stats.instanceCount -= this.instanceReferences.size;
@@ -4266,6 +4396,7 @@ var init_SceneObject = __esm({
4266
4396
  }
4267
4397
  this.notifyDirty();
4268
4398
  }
4399
+ /** Detaches the object from its parent and requests a redraw. */
4269
4400
  removeFromScene() {
4270
4401
  this.notifyDirty();
4271
4402
  this.removeFromParent();
@@ -4421,12 +4552,15 @@ var init_EntityObject = __esm({
4421
4552
  if (this.animationPlayers.length) this.notifyDirty();
4422
4553
  }
4423
4554
  //</editor-fold>
4555
+ /** Finds a selected draw by its layer key, such as `main` or `main#2`, or returns `undefined`. */
4424
4556
  getLayerGroup(name) {
4425
4557
  return super.getGroupByName(`layer:${name}`);
4426
4558
  }
4559
+ /** Finds a part name without `group:`. Supply `layerName` to restrict the search to one draw. */
4427
4560
  getGroupByName(name, layerName) {
4428
4561
  return layerName === void 0 ? super.getGroupByName(name) : this.getLayerGroup(layerName)?.getObjectByName(`group:${name}`);
4429
4562
  }
4563
+ /** Finds a mesh name without `mesh:`. Supply `layerName` to restrict the search to one draw. */
4430
4564
  getMeshByName(name, layerName) {
4431
4565
  return layerName === void 0 ? super.getMeshByName(name) : this.getLayerGroup(layerName)?.getObjectByName(`mesh:${name}`);
4432
4566
  }
@@ -5090,6 +5224,7 @@ var init_ModelCulling = __esm({
5090
5224
  import_three23 = require("three");
5091
5225
  init_CubeFace();
5092
5226
  ModelCulling = class {
5227
+ /** Rotates a world-direction bit mask into model space. Bits follow {@link CUBE_FACES}. */
5093
5228
  static toLocalMask(worldMask, rotation) {
5094
5229
  let localMask = 0;
5095
5230
  for (const [localFace, offset] of CUBE_FACE_OFFSETS.entries()) {
@@ -5100,6 +5235,7 @@ var init_ModelCulling = __esm({
5100
5235
  }
5101
5236
  return localMask;
5102
5237
  }
5238
+ /** Whether a model fills one block with opaque faces and can hide adjacent block faces. */
5103
5239
  static isOpaqueFullCube(atlas) {
5104
5240
  if (!atlas || atlas.hasTransparency !== false || atlas.model.elements?.length !== 1) return false;
5105
5241
  const element = atlas.model.elements[0];
@@ -6105,6 +6241,7 @@ var Meshes = class _Meshes {
6105
6241
  static createBox(key) {
6106
6242
  return new import_three6.Mesh(Geometries.getBox(key.geometry), Materials.getImage(key.material));
6107
6243
  }
6244
+ /** Returns a shared Mesh object. Use {@link createBox} for a mesh with its own transform and parent. */
6108
6245
  static getBox(key) {
6109
6246
  const keyStr = serializeMeshKey(key);
6110
6247
  return Caching.boxMeshCache.get(keyStr, (k) => {
@@ -6217,6 +6354,7 @@ init_AssetParsers();
6217
6354
  init_ModelTextures();
6218
6355
  init_Caching();
6219
6356
  var Fonts = class {
6357
+ /** Combines font definitions in source-priority order. Unsupported Unihex and TrueType providers are skipped. */
6220
6358
  static async get(key = "minecraft:default") {
6221
6359
  const fontKey = typeof key === "string" ? AssetKey.parse("font", key) : key;
6222
6360
  return await Caching.fontCache.get(fontKey.serialize(), () => this.load(fontKey, []));
@@ -9392,6 +9530,13 @@ var GuiHelper = class {
9392
9530
  });
9393
9531
  return layers;
9394
9532
  }
9533
+ /**
9534
+ * Calculates a slot's top-left position in GUI pixels.
9535
+ * @param slot - Zero-based slot index, or `[column, row]`.
9536
+ * @param origin - Position of the first slot.
9537
+ * @param offset - Horizontal and vertical spacing between slot origins, in pixels.
9538
+ * @param rowSize - Slots per row when `slot` is an index.
9539
+ */
9395
9540
  static inventorySlot(slot, origin = [0, 0], offset = [18, 18], rowSize = 9) {
9396
9541
  const [column, row] = typeof slot === "number" ? [slot % rowSize, Math.floor(slot / rowSize)] : slot;
9397
9542
  return [origin[0] + column * offset[0], origin[1] + row * offset[1]];
@@ -10049,6 +10194,7 @@ var SceneStatsDisplay = class {
10049
10194
  appendTo(el) {
10050
10195
  el.append(this.statsContainer);
10051
10196
  }
10197
+ /** Stops the refresh timer and removes the panel from the page. */
10052
10198
  dispose() {
10053
10199
  clearInterval(this.interval);
10054
10200
  this.interval = void 0;
@@ -10073,6 +10219,7 @@ var InstanceManager = class {
10073
10219
  this.isInstanceManager = true;
10074
10220
  this.instanceCache = {};
10075
10221
  }
10222
+ /** Allocates a new placement of a cached model, or returns `undefined` if the key is unknown. */
10076
10223
  async get(key) {
10077
10224
  if (key in this.instanceCache) {
10078
10225
  console.debug(p9, "key in cache", key);
@@ -10080,6 +10227,7 @@ var InstanceManager = class {
10080
10227
  }
10081
10228
  return void 0;
10082
10229
  }
10230
+ /** Allocates a placement, calling the supplier once when the shared model is first needed. */
10083
10231
  async getOrCreate(key, supplier) {
10084
10232
  if (key in this.instanceCache) {
10085
10233
  return await this.get(key);
@@ -10096,6 +10244,7 @@ var InstanceManager = class {
10096
10244
  throw error;
10097
10245
  }
10098
10246
  }
10247
+ /** Forgets cached models without disposing them or releasing their existing placements. */
10099
10248
  reset() {
10100
10249
  for (let instanceCacheKey in this.instanceCache) {
10101
10250
  delete this.instanceCache[instanceCacheKey];
@@ -10141,6 +10290,7 @@ function matchesCondition(condition, state) {
10141
10290
  });
10142
10291
  }
10143
10292
  var BlockStateResolver = class {
10293
+ /** Loads vanilla property defaults, falling back to preview values inferred from the blockstate file. */
10144
10294
  static async defaults(blockState) {
10145
10295
  const defaults = blockState.key ? await BlockStates.getDefaultState(blockState.key) : void 0;
10146
10296
  const state = {};
@@ -10160,9 +10310,11 @@ var BlockStateResolver = class {
10160
10310
  }
10161
10311
  return state;
10162
10312
  }
10313
+ /** Selects matching models. Supply `choose` to control selection within each alternatives array. */
10163
10314
  static select(blockState, state, choose = this.choose) {
10164
10315
  return this.matching(blockState, state).map(choose);
10165
10316
  }
10317
+ /** Returns matching model groups before choosing weighted alternatives. */
10166
10318
  static matching(blockState, state) {
10167
10319
  const out = [];
10168
10320
  if (blockState.variants) {
@@ -10186,6 +10338,7 @@ var BlockStateResolver = class {
10186
10338
  }
10187
10339
  return out;
10188
10340
  }
10341
+ /** Selects a random alternative using positive integer weights, each defaulting to 1. */
10189
10342
  static choose(variants) {
10190
10343
  if (!Array.isArray(variants)) return variants;
10191
10344
  if (!variants.length) throw new MineRenderError("Blockstate variant arrays must not be empty");
@@ -10203,6 +10356,7 @@ var BlockStateResolver = class {
10203
10356
  }
10204
10357
  return variants[variants.length - 1];
10205
10358
  }
10359
+ /** Converts blockstate rotations in degrees into the Euler rotation used by model rendering. */
10206
10360
  static rotation(variant) {
10207
10361
  const rotation = new import_three29.Euler();
10208
10362
  if (typeof variant.x !== "undefined") {
@@ -10484,6 +10638,7 @@ var _BlockObject = class _BlockObject extends SceneObject {
10484
10638
  }
10485
10639
  this.notifyDirty();
10486
10640
  }
10641
+ /** Selected property values. Use {@link setState} to change properties and rebuild the rendered models. */
10487
10642
  get state() {
10488
10643
  return this._state;
10489
10644
  }
@@ -10583,6 +10738,7 @@ var _BlockObject = class _BlockObject extends SceneObject {
10583
10738
  obj.setPosition(this.position);
10584
10739
  return obj;
10585
10740
  }
10741
+ /** Clears selected properties and rebuilds models without reapplying property defaults. */
10586
10742
  async resetState() {
10587
10743
  this._previousState = this._state;
10588
10744
  this._state = {};
@@ -12486,6 +12642,11 @@ function compoundList(tags, name) {
12486
12642
  // src/model/multiblock/StructureParser.ts
12487
12643
  init_MineRenderError();
12488
12644
  var StructureParser = class {
12645
+ /**
12646
+ * Parses decoded NBT, omitting air blocks.
12647
+ * @param _nbt - Structure data decoded by {@link NBTHelper.fromBuffer}.
12648
+ * @param paletteIndex - Palette to select when the structure has several. Defaults to 0.
12649
+ */
12489
12650
  static async parse(_nbt, paletteIndex) {
12490
12651
  const nbt = _nbt.value;
12491
12652
  let palette;
@@ -13320,6 +13481,7 @@ var SkinImage = class {
13320
13481
  // src/skin/SkinTextures.ts
13321
13482
  init_Textures();
13322
13483
  var SkinTextures = class {
13484
+ /** Loads a skin URL. Pass `legacy` to override layout detection from the image dimensions. */
13323
13485
  static async get(src, legacy) {
13324
13486
  const image = await SkinImage.getData(src);
13325
13487
  const scale = image.width / 64;
@@ -13493,6 +13655,14 @@ var SkinObject = class extends SceneObject {
13493
13655
  }
13494
13656
  }
13495
13657
  }
13658
+ /**
13659
+ * Loads a skin texture, detecting slim arms and legacy layouts by default.
13660
+ * To override detection, set `slim` or `legacy` in the options passed to
13661
+ * `new SkinObject(options)` or `scene.addSkin(src, options)`.
13662
+ * Use {@link setSlim} or {@link setLegacy} to change these settings later.
13663
+ *
13664
+ * @param src - URL of the skin texture.
13665
+ */
13496
13666
  async setSkinTexture(src) {
13497
13667
  if (typeof src === "undefined") return;
13498
13668
  this.skinTextureSrc = src;
@@ -13641,6 +13811,7 @@ var _MineRenderScene = class _MineRenderScene extends import_three34.Scene {
13641
13811
  this.stats.sceneObjectCount += change;
13642
13812
  }
13643
13813
  }
13814
+ /** Initializes each object before attaching it to the scene. */
13644
13815
  async initAndAdd(...object2) {
13645
13816
  this.dirty = true;
13646
13817
  for (let obj of object2) {
@@ -13676,13 +13847,33 @@ var _MineRenderScene = class _MineRenderScene extends import_three34.Scene {
13676
13847
  return obj;
13677
13848
  }
13678
13849
  }
13850
+ /**
13851
+ * Adds a model loaded with {@link Models.getMerged}.
13852
+ * Set `options.instanceMeshes` to `false` to create a separate ModelObject.
13853
+ *
13854
+ * @param parent - Object to attach the model to. Defaults to this scene.
13855
+ * @returns The model, or a reference to one placement of a shared model.
13856
+ */
13679
13857
  async addModel(model, options, parent = this) {
13680
13858
  options = { ...options, tints: await ItemTints.get(model, options?.tints) };
13681
13859
  return this.addSceneObject(model, () => new ModelObject(model, options), options, parent);
13682
13860
  }
13861
+ /**
13862
+ * Adds the models selected by a blockstate loaded with {@link BlockStates.get}.
13863
+ * Set `options.initialState` to choose block properties such as `facing` or `axis`.
13864
+ * Use the returned object's `setPosition` method to move all of its model parts.
13865
+ */
13683
13866
  async addBlock(blockState, options, parent = this) {
13684
13867
  return this.addSceneObject(blockState, () => new BlockObject(blockState, options), options, parent);
13685
13868
  }
13869
+ /**
13870
+ * Loads a skin and adds an initialized player model.
13871
+ *
13872
+ * @param skin - Texture URL, such as one returned by {@link Skins.fromUuidOrUsername}.
13873
+ * Omit it to assign a texture later with {@link SkinObject.setSkinTexture}.
13874
+ * @param options - Player settings, including `slim` and `legacy` detection overrides.
13875
+ * @param parent - Object to attach the player to. Defaults to this scene.
13876
+ */
13686
13877
  async addSkin(skin, options, parent = this) {
13687
13878
  this.dirty = true;
13688
13879
  const obj = new SkinObject(options);
@@ -13694,9 +13885,14 @@ var _MineRenderScene = class _MineRenderScene extends import_three34.Scene {
13694
13885
  parent.add(obj);
13695
13886
  return obj;
13696
13887
  }
13888
+ /** Adds an entity loaded with {@link Entities.getEntity}, using its selected layers and textures. */
13697
13889
  async addEntity(entity, options, parent = this) {
13698
13890
  return this.addSceneObject(entity, () => new EntityObject(entity, options), options, parent);
13699
13891
  }
13892
+ /**
13893
+ * Adds GUI layers in draw order. One GUI pixel equals one scene unit.
13894
+ * Layer positions start at the top left, with positive GUI y pointing down.
13895
+ */
13700
13896
  async addGui(layers, options, parent = this) {
13701
13897
  const obj = new GuiObject(layers, options);
13702
13898
  obj.scene = this;
@@ -14513,6 +14709,7 @@ var _Renderer = class _Renderer {
14513
14709
  get element() {
14514
14710
  return this._element;
14515
14711
  }
14712
+ /** Attaches the canvas to an element and sizes it to that element's dimensions. */
14516
14713
  appendTo(element) {
14517
14714
  if (this._disposed) return;
14518
14715
  this._element = element;
@@ -14540,6 +14737,7 @@ var _Renderer = class _Renderer {
14540
14737
  events.add(changeEvent2);
14541
14738
  dispatcher.addEventListener(changeEvent2, this._changeListener);
14542
14739
  }
14740
+ /** Updates the camera and canvas size. Width and height are in CSS pixels. */
14543
14741
  resize(width, height) {
14544
14742
  if (this._disposed) return;
14545
14743
  if (isPerspectiveCamera(this.camera)) {
@@ -14578,12 +14776,14 @@ var _Renderer = class _Renderer {
14578
14776
  if (this._frameCallbacks.get(callback) === subscription) this._frameCallbacks.delete(callback);
14579
14777
  };
14580
14778
  }
14779
+ /** Starts or resumes the animation loop and registered frame callbacks. */
14581
14780
  start() {
14582
14781
  if (this._disposed) return;
14583
14782
  this.stop();
14584
14783
  this._running = true;
14585
14784
  if (!this._inAnimationLoop) this.renderer.setAnimationLoop(this._animationLoop);
14586
14785
  }
14786
+ /** Pauses rendering and frame callbacks. Call {@link start} to resume. */
14587
14787
  stop() {
14588
14788
  if (this._disposed) return;
14589
14789
  this._running = false;
@@ -14692,12 +14892,15 @@ var _Renderer = class _Renderer {
14692
14892
  const canvas = trim ? trimCanvas(this.renderer.domElement) : this.renderer.domElement;
14693
14893
  return canvas.toDataURL(mime, quality);
14694
14894
  }
14895
+ /** Exports visible scene meshes as OBJ text, without texture images. */
14695
14896
  toObj() {
14696
14897
  return SceneExporter.toObj(this.scene);
14697
14898
  }
14899
+ /** Exports visible scene meshes as PLY. Set `options.binary` for an ArrayBuffer. */
14698
14900
  toPLY(options) {
14699
14901
  return SceneExporter.toPLY(this.scene, options);
14700
14902
  }
14903
+ /** Exports a static textured scene in the browser. Set `options.binary` for GLB output. */
14701
14904
  toGLTF(options) {
14702
14905
  return SceneExporter.toGLTF(this.scene, options);
14703
14906
  }
@@ -14779,12 +14982,14 @@ init_request();
14779
14982
  init_Requests();
14780
14983
  var Skins = class {
14781
14984
  //<editor-fold desc="Skins">
14985
+ /** Returns a skin URL for {@link MineRenderScene.addSkin}, or `undefined` if name lookup fails. */
14782
14986
  static async fromUuidOrUsername(uuidOrUsername) {
14783
14987
  if (uuidOrUsername.length === 32 || uuidOrUsername.length === 36) {
14784
14988
  return this.fromUuid(uuidOrUsername);
14785
14989
  }
14786
14990
  return this.fromUsername(uuidOrUsername);
14787
14991
  }
14992
+ /** Builds a proxy URL for a UUID without downloading or checking the skin. */
14788
14993
  static async fromUuid(uuid) {
14789
14994
  return this.getMcProxySkinUrl(uuid);
14790
14995
  }
@@ -14796,6 +15001,7 @@ var Skins = class {
14796
15001
  return void 0;
14797
15002
  });
14798
15003
  }
15004
+ /** Looks up a saved MineSkin skin and returns its texture URL, or `undefined` on lookup failure. */
14799
15005
  static async fromMineSkin(mineskinId) {
14800
15006
  return this.getMineSkin(mineskinId).then((mineskin) => {
14801
15007
  if (mineskin) {
@@ -14806,12 +15012,14 @@ var Skins = class {
14806
15012
  }
14807
15013
  //</editor-fold>
14808
15014
  //<editor-fold desc="Capes">
15015
+ /** Resolves a player's Minecraft cape URL for {@link SkinObject.setCapeTexture}. */
14809
15016
  static async capeFromUuidOrUsername(uuidOrUsername) {
14810
15017
  if (uuidOrUsername.length === 32 || uuidOrUsername.length === 36) {
14811
15018
  return this.capeFromUuid(uuidOrUsername);
14812
15019
  }
14813
15020
  return this.capeFromUsername(uuidOrUsername);
14814
15021
  }
15022
+ /** Builds a proxy URL without checking whether the player has a cape. */
14815
15023
  static async capeFromUuid(uuid) {
14816
15024
  return this.getMcProxyCapeUrl(uuid);
14817
15025
  }
@@ -14966,16 +15174,19 @@ var ChunkData = class _ChunkData {
14966
15174
  this.freeIds = [];
14967
15175
  this.nbt = /* @__PURE__ */ new Map();
14968
15176
  }
15177
+ /** Returns a detached copy of a cell, or `undefined` for air. Indices range from 0 to 4095. */
14969
15178
  get(index) {
14970
15179
  _ChunkData.validateIndex(index);
14971
15180
  const entry = this.palette[this.indices[index]];
14972
15181
  return entry ? _ChunkData.copyBlock(entry.state, this.nbt.get(index)) : void 0;
14973
15182
  }
15183
+ /** Captures a cell's data and returns a copy-producing reader that survives later cell changes. */
14974
15184
  snapshot(index) {
14975
15185
  _ChunkData.validateIndex(index);
14976
15186
  const entry = this.palette[this.indices[index]];
14977
15187
  return entry ? _ChunkData.copyBlock.bind(void 0, entry.state, this.nbt.get(index)) : void 0;
14978
15188
  }
15189
+ /** Copies block data into a cell. An omitted block or an air block clears the cell. */
14979
15190
  set(index, block) {
14980
15191
  _ChunkData.validateIndex(index);
14981
15192
  let state;
@@ -15040,15 +15251,23 @@ var ChunkData = class _ChunkData {
15040
15251
 
15041
15252
  // src/world/AnvilParser.ts
15042
15253
  var AnvilParser = class {
15254
+ /** Lists occupied chunk positions within the region, using local coordinates from 0 to 31. */
15043
15255
  static getChunkList(data) {
15044
15256
  return this.locations(this.bytes(data)).map(({ x, z }) => ({ x, z }));
15045
15257
  }
15258
+ /** Decodes all stored chunks. Gzip, zlib, and uncompressed payloads are supported. */
15046
15259
  static async parse(data) {
15047
15260
  const bytes = this.bytes(data);
15048
15261
  const chunks = [];
15049
15262
  for (const location of this.locations(bytes)) chunks.push(await this.readChunk(bytes, location));
15050
15263
  return { chunks };
15051
15264
  }
15265
+ /**
15266
+ * Decodes one chunk for {@link MineRenderWorld.placeChunk}.
15267
+ * @param localX - Chunk x within the region, from 0 to 31.
15268
+ * @param localZ - Chunk z within the region, from 0 to 31.
15269
+ * @returns The chunk with absolute coordinates, or `undefined` if the region has no chunk there.
15270
+ */
15052
15271
  static async parseChunk(data, localX, localZ) {
15053
15272
  if (![localX, localZ].every((value) => Number.isInteger(value) && value >= 0 && value < 32)) {
15054
15273
  throw new RangeError("Region-local chunk coordinates must be integers from 0 to 31");
@@ -15253,6 +15472,7 @@ var SectionModels = class {
15253
15472
  this.templates = /* @__PURE__ */ new Set();
15254
15473
  if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError("maxAtlasSize must be a positive integer");
15255
15474
  }
15475
+ /** Returns a cube template, or `undefined` when the block requires an individual render object. */
15256
15476
  async get(blockState, properties = {}) {
15257
15477
  if (!blockState.variants || blockState.multipart) return void 0;
15258
15478
  let states = this.states.get(blockState);
@@ -15306,6 +15526,7 @@ var SectionModels = class {
15306
15526
  }
15307
15527
  return { variants, templates };
15308
15528
  }
15529
+ /** Disposes prepared geometry and clears this world's template caches. */
15309
15530
  clear() {
15310
15531
  for (const template of this.templates) template.geometry.dispose();
15311
15532
  this.templates.clear();
@@ -15356,6 +15577,13 @@ var MineRenderWorld = class {
15356
15577
  this.validatePosBounds(posOrX);
15357
15578
  await this.getChunkAt(posOrX)?.setBlockVisibleAt(posOrX, yOrVisible);
15358
15579
  }
15580
+ /**
15581
+ * Places a structure's blocks at their stored positions, then refreshes neighboring faces.
15582
+ * Entity NBT is retained by the structure but is not rendered.
15583
+ *
15584
+ * @param useBatches - Uses bounded batches by default. Set to `false` for sequential placement.
15585
+ * @param executor - Optional queue for batched placement. The caller remains responsible for stopping it.
15586
+ */
15359
15587
  async placeMultiBlock(multiblock, useBatches = true, executor) {
15360
15588
  const changes = /* @__PURE__ */ new Map();
15361
15589
  try {
@@ -15407,13 +15635,7 @@ var MineRenderWorld = class {
15407
15635
  async placeChunk(chunk, executor) {
15408
15636
  const changes = /* @__PURE__ */ new Map();
15409
15637
  try {
15410
- const previous = [...this._chunks.entries()].filter(([, section]) => section.x === chunk.x && section.z === chunk.z);
15411
- for (const [key, section] of previous) {
15412
- this._chunks.delete(key);
15413
- await section.clear(async (positions) => {
15414
- for (const pos of positions) changes.set(pos.toArray().join(","), pos);
15415
- });
15416
- }
15638
+ await this.clearChunkColumn(chunk.x, chunk.z, changes);
15417
15639
  for (const section of chunk.sections) {
15418
15640
  const blocks = [];
15419
15641
  for (let index = 0; index < 4096; index++) {
@@ -15433,6 +15655,32 @@ var MineRenderWorld = class {
15433
15655
  await this.updateCulling([...changes.values()]);
15434
15656
  }
15435
15657
  }
15658
+ /**
15659
+ * Removes all sections at integer chunk-column coordinates, then refreshes neighboring faces and fluids.
15660
+ * Coordinates match AnvilChunk.x/z, not block positions. Missing columns are ignored.
15661
+ */
15662
+ async unloadChunkColumn(x, z) {
15663
+ if (!Number.isInteger(x) || !Number.isInteger(z)) {
15664
+ throw new RangeError("Chunk column coordinates must be integers");
15665
+ }
15666
+ await this.culling;
15667
+ const changes = /* @__PURE__ */ new Map();
15668
+ try {
15669
+ await this.clearChunkColumn(x, z, changes);
15670
+ } finally {
15671
+ await this.updateCulling([...changes.values()]);
15672
+ }
15673
+ }
15674
+ async clearChunkColumn(x, z, changes) {
15675
+ const previous = [...this._chunks.entries()].filter(([, section]) => section.x === x && section.z === z);
15676
+ for (const [key, section] of previous) {
15677
+ this._chunks.delete(key);
15678
+ await section.clear(async (positions) => {
15679
+ for (const pos of positions) changes.set(pos.toArray().join(","), pos);
15680
+ });
15681
+ }
15682
+ }
15683
+ /** Removes all chunks and releases their block placements and section meshes. */
15436
15684
  async clear() {
15437
15685
  await this.culling;
15438
15686
  const chunks = [...this._chunks.values()];
@@ -15518,9 +15766,11 @@ var MineRenderWorld = class {
15518
15766
  }
15519
15767
  return chunk;
15520
15768
  }
15769
+ /** Returns the loaded chunk containing a world block position, without creating a chunk. */
15521
15770
  getChunkAt(pos) {
15522
15771
  return this._chunks.get(this.worldPosToChunkKey(pos));
15523
15772
  }
15773
+ /** Converts block coordinates to scene units by multiplying each component by 16. */
15524
15774
  static worldToScenePosition(pos) {
15525
15775
  return new import_three39.Vector3(
15526
15776
  pos.x * 16,
@@ -15528,6 +15778,7 @@ var MineRenderWorld = class {
15528
15778
  pos.z * 16
15529
15779
  );
15530
15780
  }
15781
+ /** Converts scene units to block coordinates without rounding to an integer block. */
15531
15782
  static sceneToWorldPosition(pos) {
15532
15783
  return new import_three39.Vector3(
15533
15784
  pos.x / 16,
@@ -15560,6 +15811,7 @@ var SectionMesh = class _SectionMesh extends import_three40.Group {
15560
15811
  super(...arguments);
15561
15812
  this.ownedMeshes = [];
15562
15813
  }
15814
+ /** Builds section-local meshes from visible cube faces. `maxAtlasSize` limits each atlas dimension in pixels. */
15563
15815
  static build(entries, maxAtlasSize = 2048) {
15564
15816
  if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError("Section atlas size must be a positive integer");
15565
15817
  const visible = entries.filter((entry) => entry.template.cullFaces.some((direction) => !(entry.cullMask & direction)));
@@ -15704,7 +15956,7 @@ var Chunk = class _Chunk {
15704
15956
  return this.setBlockInChunkAt(pos, block, worldPos);
15705
15957
  }
15706
15958
  /**
15707
- * Set a block at integer chunk-local coordinates from 0 to 15.
15959
+ * Places a block at integer chunk-local coordinates from 0 to 15.
15708
15960
  */
15709
15961
  async setBlockInChunkAt(pos, block, worldPos, onBlocksChanged = this.onBlocksChanged) {
15710
15962
  if (typeof worldPos === "undefined") {
@@ -15753,6 +16005,7 @@ var Chunk = class _Chunk {
15753
16005
  await onBlocksChanged?.([worldPos]);
15754
16006
  }
15755
16007
  }
16008
+ /** Changes visibility at world block coordinates while preserving the block's data. */
15756
16009
  async setBlockVisibleAt(pos, visible) {
15757
16010
  const index = _Chunk.chunkPosToBlockIndex(this.worldPosToChunkPos(pos));
15758
16011
  const block = this.renderedBlocks.get(index);
@@ -15806,6 +16059,7 @@ var Chunk = class _Chunk {
15806
16059
  this.scene.dirty = true;
15807
16060
  this.meshDirty = false;
15808
16061
  }
16062
+ /** Removes stored blocks and their render objects, then notifies the owning world of changed positions. */
15809
16063
  async clear(onBlocksChanged = this.onBlocksChanged) {
15810
16064
  const positions = [...this.renderedBlocks.keys()].map((index) => this.chunkPosToWorldPos(
15811
16065
  new import_three41.Vector3(index % 16, Math.floor(index / 256), Math.floor(index / 16) % 16)
@@ -15826,6 +16080,7 @@ var Chunk = class _Chunk {
15826
16080
  static isAir(block) {
15827
16081
  return ChunkData.isAir(block);
15828
16082
  }
16083
+ /** Maps chunk-local coordinates from 0 to 15 to a storage index, with x varying fastest, then z, then y. */
15829
16084
  static chunkPosToBlockIndex(pos) {
15830
16085
  if ([pos.x, pos.y, pos.z].some((value) => !Number.isInteger(value) || value < 0 || value >= 16)) {
15831
16086
  throw new RangeError("Block coordinates must be integers from 0 to 15 within a chunk");