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.
@@ -64,6 +64,7 @@ var init_PersistentCache = __esm({
64
64
  constructor(backing) {
65
65
  this.backing = backing;
66
66
  }
67
+ /** Opens a named store in the active environment using the current cache schema version. */
67
68
  static open(name) {
68
69
  return Env.provider.openCache(name, _PersistentCache.VERSION);
69
70
  }
@@ -262,6 +263,7 @@ var init_Caching = __esm({
262
263
  this.fontCache
263
264
  ];
264
265
  }
266
+ /** Invalidates in-memory entries so later lookups reload them. Persisted entries are retained. */
265
267
  static clear() {
266
268
  for (const cache of this.all) {
267
269
  cache.invalidateAll();
@@ -327,6 +329,7 @@ var init_Geometries = __esm({
327
329
  }
328
330
  return geometry;
329
331
  }
332
+ /** Returns shared geometry. Use {@link createBox} when the caller needs to modify or dispose it independently. */
330
333
  static getBox(key) {
331
334
  const keyStr = serializeBoxGeometryKey(key);
332
335
  return Caching.boxGeometryCache.get(keyStr, (k) => {
@@ -504,12 +507,15 @@ var init_Requests = __esm({
504
507
  }
505
508
  };
506
509
  Requests = class {
510
+ /** Queues a general request. Set `request.signal` to cancel it and `request.timeout` to limit each attempt. */
507
511
  static genericRequest(request) {
508
512
  return this.genericQueue.request(request);
509
513
  }
514
+ /** Queues a request separately from general traffic, using the configured asset base URL for relative paths. */
510
515
  static mcAssetRequest(request) {
511
516
  return this.mcAssetRequestQueue.request(request);
512
517
  }
518
+ /** Sets the base URL for relative asset requests. Use {@link AssetLoader.setVersion} to change Minecraft versions. */
513
519
  static setMcAssetRoot(root) {
514
520
  this.mcAssetRequestQueue.baseURL = root;
515
521
  }
@@ -564,6 +570,7 @@ var init_WrappedImage = __esm({
564
570
  }
565
571
  return false;
566
572
  }
573
+ /** Whether the dimensions form a vertical strip of square frames, without consulting `.mcmeta`. */
567
574
  get animated() {
568
575
  return this.height > this.width && this.height % this.width === 0;
569
576
  }
@@ -610,6 +617,7 @@ var init_ImageLoader = __esm({
610
617
  static _createImage() {
611
618
  return createImage();
612
619
  }
620
+ /** Resolves when an image URL has decoded, or rejects if decoding fails. */
613
621
  static async loadAsync(src) {
614
622
  return new Promise((resolve, reject) => {
615
623
  const image = this._createImage();
@@ -618,6 +626,7 @@ var init_ImageLoader = __esm({
618
626
  image.src = src;
619
627
  });
620
628
  }
629
+ /** Returns an image immediately. Use the callbacks to observe loading, or await {@link loadAsync}. */
621
630
  static loadElement(src, onload, onerr) {
622
631
  const image = this._createImage();
623
632
  if (onload)
@@ -645,6 +654,7 @@ var init_ImageLoader = __esm({
645
654
  throw err;
646
655
  }
647
656
  }
657
+ /** Decodes the supplied bytes into a canvas without fetching the source URL again. */
648
658
  static async infoToCanvasData(info) {
649
659
  const type = info.type === "jpg" ? "jpeg" : info.type ?? "png";
650
660
  const image = await _ImageLoader.loadAsync(`data:image/${type};base64,${info.data.toString("base64")}`);
@@ -661,12 +671,14 @@ var init_ImageLoader = __esm({
661
671
  const image = await this.infoToCanvasData(info);
662
672
  return image.data.getImageData(0, 0, image.width, image.height);
663
673
  }
674
+ /** Returns cached RGBA pixels for an image URL or data URL. Failed loads can be retried. */
664
675
  static async getData(src) {
665
676
  const keyStr = serializeImageKey({ src });
666
677
  return await Caching.imageDataCache.get(keyStr, (k) => {
667
678
  return _ImageLoader.loadData(src);
668
679
  });
669
680
  }
681
+ /** Returns a cached canvas context and dimensions for an image URL or data URL. */
670
682
  static async getCanvasData(src) {
671
683
  const keyStr = serializeImageKey({ src });
672
684
  return await Caching.canvasImageDataCache.get(keyStr, (k) => {
@@ -763,6 +775,7 @@ var init_TextureLoader = __esm({
763
775
  texture.rotation = rotation;
764
776
  return Textures.initTextureProps(texture);
765
777
  }
778
+ /** Loads image pixels in the background. `rotation` is in radians. Check {@link hasFailed} for load failures. */
766
779
  static load(src, format2 = RGBAFormat, rotation = 0) {
767
780
  const texture = new Texture();
768
781
  texture.colorSpace = THREE.SRGBColorSpace;
@@ -812,6 +825,7 @@ var init_Textures = __esm({
812
825
  return this.initTextureProps(texture);
813
826
  });
814
827
  }
828
+ /** Sets nearest-neighbor filters without changing the texture's color space. Returns the same texture. */
815
829
  static initTextureProps(texture) {
816
830
  texture.magFilter = THREE2.NearestFilter;
817
831
  texture.minFilter = THREE2.NearestFilter;
@@ -824,11 +838,13 @@ var init_Textures = __esm({
824
838
  static createAsset(key) {
825
839
  return new Texture2();
826
840
  }
841
+ /** Creates an sRGB color texture from a canvas. */
827
842
  static createCanvasTexture(canvas) {
828
843
  const texture = new CanvasTexture(canvas);
829
844
  texture.colorSpace = THREE2.SRGBColorSpace;
830
845
  return this.initTextureProps(texture);
831
846
  }
847
+ /** Returns a shared texture immediately and loads its image asynchronously. Failed cached loads are retried. */
832
848
  static getImage(key) {
833
849
  const keyStr = serializeTextureKey(key);
834
850
  const cached2 = Caching.textureCache.peek(keyStr);
@@ -853,6 +869,7 @@ var init_Materials = __esm({
853
869
  init_TextureLoader();
854
870
  init_Caching();
855
871
  Materials = class _Materials {
872
+ /** Shared checkerboard material, created on first access. */
856
873
  static get MISSING_TEXTURE() {
857
874
  return Caching.materialCache.get("builtin:missing-texture", () => new MeshBasicMaterial({
858
875
  map: Textures.getMissing(),
@@ -956,6 +973,7 @@ var init_Materials = __esm({
956
973
  if (tint !== void 0) material.color.multiply(new Color(tint));
957
974
  return material;
958
975
  }
976
+ /** Creates an unlit, transparent GUI material without depth writes or tone mapping. */
959
977
  static createGuiCanvasMaterial(canvas) {
960
978
  const material = new MeshBasicMaterial({
961
979
  map: Textures.createCanvasTexture(canvas),
@@ -1122,6 +1140,7 @@ var init_Materials = __esm({
1122
1140
  }
1123
1141
  return this.createBasicCanvasMaterial(canvas, transparent, shade);
1124
1142
  }
1143
+ /** Returns a shared image material. Use {@link createImage} for a separate material instance. */
1125
1144
  static getImage(key) {
1126
1145
  const keyStr = serializeMaterialKey(key);
1127
1146
  const map = Caching.materialCache.peek(keyStr)?.map;
@@ -1296,6 +1315,14 @@ var init_AssetKey = __esm({
1296
1315
  }
1297
1316
  };
1298
1317
  AssetKey = class _AssetKey extends BasicAssetKey {
1318
+ /**
1319
+ * Creates a key from separate path components. Use {@link parse} for a combined reference.
1320
+ *
1321
+ * @param assetType - Asset directory, such as `models`, `textures`, or `blockstates`.
1322
+ * @param type - Subdirectory, such as `block` or `item`.
1323
+ * @param rootType - Top-level directory, usually `assets` or `data`.
1324
+ * @param root - Base URL override for hosted asset sources.
1325
+ */
1299
1326
  constructor(namespace, path, assetType, type, rootType = "assets", extension = ".json", root) {
1300
1327
  super(namespace, path);
1301
1328
  this.namespace = namespace;
@@ -1307,6 +1334,16 @@ var init_AssetKey = __esm({
1307
1334
  this.root = root;
1308
1335
  this.isAssetKey = true;
1309
1336
  }
1337
+ /**
1338
+ * Parses an asset reference such as `minecraft:block/stone`.
1339
+ * A missing namespace defaults to the origin's namespace or `minecraft`.
1340
+ *
1341
+ * @param assetType - Asset category, such as `models` or `textures`.
1342
+ * @param str - Path with an optional namespace and file extension.
1343
+ * @param origin - Supplies the asset root, default namespace, and non-texture extension.
1344
+ * @returns A key with the matching extension removed from its path. Textures use `.png`;
1345
+ * other assets use the origin's extension or `.json`.
1346
+ */
1310
1347
  static parse(assetType, str, origin) {
1311
1348
  let namespace = origin?.namespace || DEFAULT_NAMESPACE;
1312
1349
  if (str.includes(":")) {
@@ -1338,6 +1375,7 @@ var init_AssetKey = __esm({
1338
1375
  ];
1339
1376
  return a.join("/");
1340
1377
  }
1378
+ /** Joins the type subdirectory and path without adding a namespace or file extension. */
1341
1379
  getFullPath() {
1342
1380
  let p10 = [];
1343
1381
  if (this.type) {
@@ -1349,6 +1387,7 @@ var init_AssetKey = __esm({
1349
1387
  toNamespacedString() {
1350
1388
  return this.namespace + ":" + this.getFullPath();
1351
1389
  }
1390
+ /** Returns a cache identifier that includes the explicit root or {@link AssetLoader.ROOT}. */
1352
1391
  serialize() {
1353
1392
  return this.toString();
1354
1393
  }
@@ -1408,6 +1447,7 @@ var init_DisplayTransforms = __esm({
1408
1447
  const scale = new Vector32(...transform.scale ?? [1, 1, 1]).clampScalar(-4, 4);
1409
1448
  return new Matrix4().compose(translation, rotation, scale);
1410
1449
  }
1450
+ /** Transforms geometry in place and reverses triangle winding when the matrix reflects it. */
1411
1451
  static apply(geometry, matrix) {
1412
1452
  geometry.applyMatrix4(matrix);
1413
1453
  if (matrix.determinant() < 0) {
@@ -1435,6 +1475,7 @@ var init_ModelMerger = __esm({
1435
1475
  init_AssetKey();
1436
1476
  init_DisplayTransforms();
1437
1477
  ModelMerger = class {
1478
+ /** Loads the parent chain and returns a merged model without modifying the supplied definition. */
1438
1479
  static async mergeWithParents(model) {
1439
1480
  const models = await this.collectAllParents(model);
1440
1481
  let merged = {};
@@ -1502,6 +1543,7 @@ var init_Models = __esm({
1502
1543
  static get PERSISTENT_CACHE() {
1503
1544
  return this._persistentCache ?? (this._persistentCache = PersistentCache.open("minerender-models"));
1504
1545
  }
1546
+ /** Lists item filenames from the asset source's `_list.json`, with a legacy model-directory fallback. */
1505
1547
  static async getItemList() {
1506
1548
  const key = new AssetKey(DEFAULT_NAMESPACE, "_list", "items");
1507
1549
  const legacyKey = new AssetKey(DEFAULT_NAMESPACE, "_list", "models", "item");
@@ -1572,6 +1614,7 @@ var init_Models = __esm({
1572
1614
  }
1573
1615
  throw new Error(`Unsupported item model ${node?.type ?? "definition"} for ${key.toNamespacedString()}`);
1574
1616
  }
1617
+ /** Loads one model file without resolving its parents. Returns `undefined` when the file is missing. */
1575
1618
  static async getRaw(key) {
1576
1619
  if (!key.assetType) {
1577
1620
  key.assetType = "models";
@@ -1591,6 +1634,12 @@ var init_Models = __esm({
1591
1634
  return asset;
1592
1635
  });
1593
1636
  }
1637
+ /**
1638
+ * Loads a model and resolves its parent chain. Returns `undefined` when the model is missing.
1639
+ * Item keys use GUI context, false conditions, and zero numeric properties.
1640
+ *
1641
+ * @param key - Model key, for example `AssetKey.parse("models", "minecraft:item/diamond_sword")`.
1642
+ */
1594
1643
  static async getMerged(key) {
1595
1644
  if (!key.assetType) {
1596
1645
  key.assetType = "models";
@@ -1603,9 +1652,11 @@ var init_Models = __esm({
1603
1652
  return _Models.loadAndMerge(key);
1604
1653
  });
1605
1654
  }
1655
+ /** Alias for {@link getMerged}. */
1606
1656
  static async get(key) {
1607
1657
  return this.getMerged(key);
1608
1658
  }
1659
+ /** Clears persisted models. Use {@link Caching.clear} to also discard in-memory assets. */
1609
1660
  static async clearCache() {
1610
1661
  return this.PERSISTENT_CACHE.clear();
1611
1662
  }
@@ -1628,6 +1679,7 @@ var init_BlockStates = __esm({
1628
1679
  return this._persistentCache ?? (this._persistentCache = PersistentCache.open("minerender-blockstates"));
1629
1680
  }
1630
1681
  // BlockState names are hardcoded
1682
+ /** Returns blockstate filenames from the selected version's `_list.json`, or an empty list. */
1631
1683
  static async getList() {
1632
1684
  const key = new AssetKey(
1633
1685
  DEFAULT_NAMESPACE,
@@ -1648,6 +1700,7 @@ var init_BlockStates = __esm({
1648
1700
  return AssetLoader.get(key, "json" /* JSON */);
1649
1701
  });
1650
1702
  }
1703
+ /** Looks up vanilla property definitions for the key's block path, or returns `undefined`. */
1651
1704
  static async getDefaultState(key) {
1652
1705
  const defaultStates = await this.getDefaultStates();
1653
1706
  if (!defaultStates) {
@@ -1655,6 +1708,7 @@ var init_BlockStates = __esm({
1655
1708
  }
1656
1709
  return defaultStates["minecraft:" + key.path];
1657
1710
  }
1711
+ /** Loads a cached blockstate definition for {@link MineRenderScene.addBlock}, or returns `undefined`. */
1658
1712
  static async get(key) {
1659
1713
  if (!key.assetType) {
1660
1714
  key.assetType = "blockstates";
@@ -1681,6 +1735,7 @@ var init_BlockStates = __esm({
1681
1735
  }
1682
1736
  return Promise.all(promises);
1683
1737
  }
1738
+ /** Clears persisted blockstates. Use {@link Caching.clear} to also discard in-memory assets. */
1684
1739
  static async clearCache() {
1685
1740
  await this.PERSISTENT_CACHE.clear();
1686
1741
  }
@@ -1706,9 +1761,11 @@ var init_Assets = __esm({
1706
1761
  static parseAssetKey(assetType, str, origin) {
1707
1762
  return AssetKey.parse(assetType, str, origin);
1708
1763
  }
1764
+ /** Loads a model with its parent chain resolved. See {@link Models.getMerged}. */
1709
1765
  static async getModel(key) {
1710
1766
  return Models.getMerged(key);
1711
1767
  }
1768
+ /** Loads a blockstate definition. See {@link BlockStates.get}. */
1712
1769
  static async getBlockState(key) {
1713
1770
  return BlockStates.get(key);
1714
1771
  }
@@ -1755,6 +1812,10 @@ var BatchedExecutor;
1755
1812
  var init_BatchedExecutor = __esm({
1756
1813
  "src/util/BatchedExecutor.ts"() {
1757
1814
  BatchedExecutor = class {
1815
+ /**
1816
+ * @param interval - Delay between queue runs, in milliseconds.
1817
+ * @param batch - Maximum tasks started per run and maximum tasks active at once.
1818
+ */
1758
1819
  constructor(interval = 1, batch = 30) {
1759
1820
  if (!Number.isFinite(interval) || interval < 0) throw new RangeError("Batch interval must be finite and nonnegative");
1760
1821
  if (!Number.isInteger(batch) || batch < 1) throw new RangeError("Batch size must be a positive integer");
@@ -1762,9 +1823,11 @@ var init_BatchedExecutor = __esm({
1762
1823
  this.batch = batch;
1763
1824
  this.queue = new JobQueue2(async (task) => task(), { interval, maxPerRun: batch, maxActive: batch });
1764
1825
  }
1826
+ /** Queues a task and resolves with its result, or rejects with its error. */
1765
1827
  submit(task) {
1766
1828
  return this.queue.add(() => task());
1767
1829
  }
1830
+ /** Rejects queued and future tasks. Tasks already running are allowed to finish. */
1768
1831
  stop() {
1769
1832
  this.queue.end();
1770
1833
  }
@@ -1906,6 +1969,7 @@ var NBTHelper;
1906
1969
  var init_NBTHelper = __esm({
1907
1970
  "src/nbt/NBTHelper.ts"() {
1908
1971
  NBTHelper = class {
1972
+ /** Parses NBT bytes and preserves format and compression metadata. Omit `format` for automatic detection. */
1909
1973
  static async fromBuffer(data, format2) {
1910
1974
  const buffer = Buffer3.from(data instanceof Uint8Array ? data : new Uint8Array(data));
1911
1975
  const prismarineNbt = await import("prismarine-nbt");
@@ -1974,6 +2038,7 @@ var init_HostedAssetSource = __esm({
1974
2038
  retryDefaults: true
1975
2039
  };
1976
2040
  _HostedAssetSource = class _HostedAssetSource extends AssetSource {
2041
+ /** Retries missing assets with the `minecraft` namespace and default root. Other failures reject. */
1977
2042
  async loadOrRetryWithDefaults(key, parser) {
1978
2043
  const direct = await this.load(key, parser);
1979
2044
  if (typeof direct !== "undefined") {
@@ -2031,6 +2096,10 @@ var init_HostedAssetSource = __esm({
2031
2096
  assetBasePath(key) {
2032
2097
  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 + "/" : ""}`;
2033
2098
  }
2099
+ /**
2100
+ * Creates a hosted source for {@link AssetLoader.addSource}.
2101
+ * Set `options.retryDefaults` to `false` to restrict lookups to the requested namespace and root.
2102
+ */
2034
2103
  constructor(root, options) {
2035
2104
  super();
2036
2105
  this._root = root;
@@ -2123,6 +2192,11 @@ var BrowserArchiveProxy;
2123
2192
  var init_BrowserArchiveProxy = __esm({
2124
2193
  "src/assets/source/archive/BrowserArchiveProxy.ts"() {
2125
2194
  BrowserArchiveProxy = class {
2195
+ /**
2196
+ * Opens a ZIP for asset lookup.
2197
+ * @param id - Cache identity for this content. Change it when the pack changes.
2198
+ * A File supplies an identity from its name, size, and modification time when omitted.
2199
+ */
2126
2200
  constructor(blob, id) {
2127
2201
  this._blob = blob;
2128
2202
  this._reader = new ZipReader(new BlobReader(this._blob));
@@ -2320,6 +2394,7 @@ var init_ArchiveAssetSource = __esm({
2320
2394
  dataPackFormat: copyFormat(options.dataPackFormat)
2321
2395
  };
2322
2396
  }
2397
+ /** Creates a browser ZIP source from a Blob or File. */
2323
2398
  static blob(blob, options) {
2324
2399
  return new _ArchiveAssetSource(new BrowserArchiveProxy(blob), options);
2325
2400
  }
@@ -2454,6 +2529,7 @@ var init_AssetLoader = __esm({
2454
2529
  static get version() {
2455
2530
  return this.ROOT.substring(this.ROOT.lastIndexOf("/") + 1);
2456
2531
  }
2532
+ /** Selects an mcasset.cloud version, updates the vanilla source, and clears in-memory caches. */
2457
2533
  static setVersion(version) {
2458
2534
  this.ROOT = `https://assets.mcasset.cloud/${version}`;
2459
2535
  const source = new HostedAssetSource(this.ROOT, { retryDefaults: false });
@@ -2487,6 +2563,13 @@ var init_AssetLoader = __esm({
2487
2563
  return scope ? `${scope}
2488
2564
  ${key}` : key;
2489
2565
  }
2566
+ /**
2567
+ * Registers a source at the highest priority.
2568
+ * Call {@link Caching.clear} after changing sources to discard previously loaded assets.
2569
+ *
2570
+ * @param key - Name used to replace or remove this source.
2571
+ * @param override - Removes the first source with this name before adding the new one.
2572
+ */
2490
2573
  static addSource(key, source, override = true) {
2491
2574
  if (override) {
2492
2575
  const existing = this.removeSource(key);
@@ -2497,6 +2580,7 @@ ${key}` : key;
2497
2580
  this._SOURCES.unshift({ key, source });
2498
2581
  console.log(p4, "Added AssetSource", key);
2499
2582
  }
2583
+ /** Removes and returns the first source with this name. Call {@link Caching.clear} to reload assets. */
2500
2584
  static removeSource(key) {
2501
2585
  const index = this._SOURCES.findIndex((s) => s.key === key);
2502
2586
  if (index != -1) {
@@ -2507,6 +2591,7 @@ ${key}` : key;
2507
2591
  }
2508
2592
  return void 0;
2509
2593
  }
2594
+ /** Loads from all sources and returns defined results in priority order. Any source failure rejects the call. */
2510
2595
  static async getAll(key, parser) {
2511
2596
  const sources = [...this._SOURCES];
2512
2597
  const results = [];
@@ -2551,6 +2636,7 @@ ${key}` : key;
2551
2636
  return void 0;
2552
2637
  }
2553
2638
  };
2639
+ /** Default asset base URL. Use {@link setVersion} to select a Minecraft version. */
2554
2640
  _AssetLoader.ROOT = DEFAULT_ROOT;
2555
2641
  _AssetLoader._SOURCES = [];
2556
2642
  /** Used when a registered source cannot identify its content, so nothing persists past this session. */
@@ -2575,6 +2661,7 @@ var init_ModelTextures = __esm({
2575
2661
  static get PERSISTENT_META_CACHE() {
2576
2662
  return this._persistentMetaCache ?? (this._persistentMetaCache = PersistentCache.open("minerender-texturemeta"));
2577
2663
  }
2664
+ /** Loads and decodes a texture into a readable canvas, or returns `undefined` when missing. */
2578
2665
  static async get(key) {
2579
2666
  const keyStr = key.serialize();
2580
2667
  const pending = this.preload(key);
@@ -2592,6 +2679,7 @@ var init_ModelTextures = __esm({
2592
2679
  throw err;
2593
2680
  }
2594
2681
  }
2682
+ /** Fetches and caches encoded texture bytes without decoding the pixels. */
2595
2683
  static async preload(key) {
2596
2684
  const keyStr = key.serialize();
2597
2685
  return Caching.textureAssetCache.get(keyStr, (k) => {
@@ -2602,6 +2690,7 @@ var init_ModelTextures = __esm({
2602
2690
  });
2603
2691
  });
2604
2692
  }
2693
+ /** Loads a texture's `.mcmeta` file, or returns `undefined` when no metadata file exists. */
2605
2694
  static async getMeta(key) {
2606
2695
  if (!key.extension || !key.extension.endsWith(".mcmeta")) {
2607
2696
  key = Object.assign(new AssetKey("", ""), key);
@@ -2618,6 +2707,7 @@ var init_ModelTextures = __esm({
2618
2707
  });
2619
2708
  });
2620
2709
  }
2710
+ /** Clears persisted texture metadata. Use {@link Caching.clear} to discard in-memory textures and metadata. */
2621
2711
  static async clearCache() {
2622
2712
  await this.PERSISTENT_META_CACHE.clear();
2623
2713
  }
@@ -2684,6 +2774,7 @@ var init_Ticker = __esm({
2684
2774
  }
2685
2775
  return handle;
2686
2776
  }
2777
+ /** Starts or resumes the shared tick loop. Repeated calls have no effect. */
2687
2778
  static start() {
2688
2779
  if (this.interval) return;
2689
2780
  this.interval = this.schedule(() => {
@@ -2706,6 +2797,7 @@ var init_Ticker = __esm({
2706
2797
  _Ticker.fiveSecondTicks = 0;
2707
2798
  }, 1e3 * 5);
2708
2799
  }
2800
+ /** Pauses the loop while retaining callbacks for a later {@link start}. */
2709
2801
  static stop() {
2710
2802
  if (this.interval) clearInterval(this.interval);
2711
2803
  if (this.oneSecondTicksTracker) clearInterval(this.oneSecondTicksTracker);
@@ -2714,12 +2806,14 @@ var init_Ticker = __esm({
2714
2806
  this.oneSecondTicksTracker = void 0;
2715
2807
  this.fiveSecondTicksTracker = void 0;
2716
2808
  }
2809
+ /** Registers a callback, starts the loop if needed, and returns an ID for {@link remove}. */
2717
2810
  static add(tick) {
2718
2811
  this.start();
2719
2812
  const c = this.counter++;
2720
2813
  this._tickers.set(c, tick);
2721
2814
  return c;
2722
2815
  }
2816
+ /** Removes a callback by ID and stops the timers when no callbacks remain. */
2723
2817
  static remove(c) {
2724
2818
  if (typeof c === "number") this._tickers.delete(c);
2725
2819
  if (!this._tickers.size) this.stop();
@@ -2733,6 +2827,7 @@ var init_Ticker = __esm({
2733
2827
  static get tpsFiveSeconds() {
2734
2828
  return this.fiveSecondTps;
2735
2829
  }
2830
+ /** Stops the loop and removes all registered callbacks. */
2736
2831
  static dispose() {
2737
2832
  this.stop();
2738
2833
  this._tickers.clear();
@@ -2787,6 +2882,7 @@ var init_TextureAtlas = __esm({
2787
2882
  }
2788
2883
  };
2789
2884
  }
2885
+ /** Copies pixels for a texture variable from its current atlas rectangle. */
2790
2886
  getData(texture) {
2791
2887
  const pos = this.positions[texture];
2792
2888
  const size = this.sizes[texture];
@@ -3064,6 +3160,7 @@ var init_UVMapper = __esm({
3064
3160
  }
3065
3161
  uv.needsUpdate = true;
3066
3162
  }
3163
+ /** Returns the shared atlas for a keyed, merged model, creating it on first use. */
3067
3164
  static async getAtlas(model) {
3068
3165
  const keyStr = model.key.serialize();
3069
3166
  return Caching.modelTextureAtlasCache.get(keyStr, (k) => {
@@ -3134,6 +3231,11 @@ var init_UVMapper = __esm({
3134
3231
  }
3135
3232
  return [tl, tr, bl, br];
3136
3233
  }
3234
+ /**
3235
+ * Combines model textures and animation metadata into an atlas.
3236
+ * Mapped UVs are stored on copies of the model's elements, available through the returned atlas.
3237
+ * Returns `undefined` for models without a texture map.
3238
+ */
3137
3239
  static async createAtlas(originalModel) {
3138
3240
  const textureMap = {};
3139
3241
  const metaMap = {};
@@ -3498,6 +3600,7 @@ var init_Entities = __esm({
3498
3600
  init_MineRenderError();
3499
3601
  init_ModelTextures();
3500
3602
  Entities = class {
3603
+ /** Lists model paths in the `minecraft` namespace, including subdirectories and excluding `.json`. */
3501
3604
  static async getEntityList() {
3502
3605
  const collect = async (path) => {
3503
3606
  const prefix2 = path ? `${path}/` : "";
@@ -3515,6 +3618,7 @@ var init_Entities = __esm({
3515
3618
  const key = new AssetKey(modelKey.namespace, path, void 0, void 0, "entity-models", ".json", isAssetKey(modelKey) ? modelKey.root : void 0);
3516
3619
  return Caching.entityModelCache.get(key.serialize(), () => AssetLoader.get(key, "json" /* JSON */));
3517
3620
  }
3621
+ /** Returns selectable geometry-layer names, or an empty list when the model is missing. */
3518
3622
  static async getLayerList(modelKey) {
3519
3623
  return Object.keys((await this.getModelFile(modelKey))?.layers ?? {});
3520
3624
  }
@@ -3522,6 +3626,15 @@ var init_Entities = __esm({
3522
3626
  static async getPassList(modelKey) {
3523
3627
  return (await this.getModelFile(modelKey))?.passes ?? [];
3524
3628
  }
3629
+ /**
3630
+ * Loads the layers and textures to pass to {@link MineRenderScene.addEntity}.
3631
+ * By default, selects `main`, unconditional passes, and passes enabled by `options.when`.
3632
+ *
3633
+ * @param modelKey - Dataset model, such as `new BasicAssetKey("minecraft", "zombie")`.
3634
+ * @param textureKey - Texture override for the first selected layer.
3635
+ * @param options - Layer selection, conditional passes, and per-layer texture overrides.
3636
+ * @returns The selected model, or `undefined` when its dataset file is missing.
3637
+ */
3525
3638
  static async getEntity(modelKey, textureKey, options) {
3526
3639
  const model = await this.getModelFile(modelKey);
3527
3640
  if (!model) return void 0;
@@ -3567,6 +3680,7 @@ var init_Entities = __esm({
3567
3680
  const file = await Caching.entityAnimationCache.get(key.serialize(), () => AssetLoader.get(key, "json" /* JSON */));
3568
3681
  return file?.animations;
3569
3682
  }
3683
+ /** Finds a fallback texture using the model path, its directory, and vanilla variant data. */
3570
3684
  static async resolveTexture(modelKey) {
3571
3685
  const path = isAssetKey(modelKey) ? modelKey.getFullPath() : modelKey.path;
3572
3686
  const root = isAssetKey(modelKey) ? modelKey.root : void 0;
@@ -3727,12 +3841,14 @@ var init_EntityAnimationPlayer = __esm({
3727
3841
  this._animation = void 0;
3728
3842
  this._time = 0;
3729
3843
  }
3844
+ /** Applies the pose at an absolute playback time. Returns `false` when no clip is active. */
3730
3845
  setTime(seconds) {
3731
3846
  if (!this._animation) return false;
3732
3847
  this._time = seconds;
3733
3848
  this.apply();
3734
3849
  return true;
3735
3850
  }
3851
+ /** Advances playback by elapsed seconds multiplied by the speed passed to {@link play}. */
3736
3852
  advance(deltaSeconds) {
3737
3853
  return this.setTime(this._time + deltaSeconds * this.speed);
3738
3854
  }
@@ -3770,6 +3886,7 @@ var init_InstanceReference = __esm({
3770
3886
  if (!this.instanceable.isInstanceActive(this.index, this)) throw new MineRenderError("Instance has been removed");
3771
3887
  return this.instanceable;
3772
3888
  }
3889
+ /** Releases this placement's slot for reuse. Repeated calls have no effect. */
3773
3890
  removeFromScene() {
3774
3891
  if (this.instanceable.isInstanceActive(this.index, this)) this.instanceable.removeInstanceAt(this.index);
3775
3892
  }
@@ -3782,9 +3899,11 @@ var init_InstanceReference = __esm({
3782
3899
  setMatrix(matrix) {
3783
3900
  this.activeInstanceable.setMatrixAt(this.index, matrix);
3784
3901
  }
3902
+ /** Hides or restores this placement while preserving its transform and allocated slot. */
3785
3903
  setVisible(visible) {
3786
3904
  this.activeInstanceable.setInstanceVisibleAt(this.index, visible);
3787
3905
  }
3906
+ /** Updates the supplied transform components. Positions use scene units and rotations use radians. */
3788
3907
  setPositionRotationScale(position, rotation, scale) {
3789
3908
  this.activeInstanceable.setPositionRotationScaleAt(this.index, position, rotation, scale);
3790
3909
  }
@@ -3853,6 +3972,7 @@ var init_SceneObject = __esm({
3853
3972
  }
3854
3973
  async init() {
3855
3974
  }
3975
+ /** Marks ancestor scenes for redraw and emits a `change` event. */
3856
3976
  notifyDirty() {
3857
3977
  this.traverseAncestors((parent) => {
3858
3978
  const scene = parent;
@@ -3888,15 +4008,17 @@ var init_SceneObject = __esm({
3888
4008
  return obj;
3889
4009
  }
3890
4010
  /**
3891
- * Get a group by its name
4011
+ * Finds a named part, such as `head`, without the internal `group:` prefix.
4012
+ * Returns `undefined` when the group does not exist.
3892
4013
  */
3893
4014
  getGroupByName(name) {
3894
4015
  return this.getObjectByName(`group:${name}`);
3895
4016
  }
3896
4017
  /**
3897
- * Toggle visibility of a group
3898
- * @param name name of the group
3899
- * @param visible set the visibility directly, if not set toggles it
4018
+ * Changes a named group's visibility and requests a redraw.
4019
+ * @param name - Part name without the `group:` prefix.
4020
+ * @param visible - Visibility to assign. Omit it to toggle the current value.
4021
+ * @returns The resulting visibility, or `false` if the group does not exist.
3900
4022
  */
3901
4023
  toggleGroupVisibility(name, visible) {
3902
4024
  return this.toggleObjectVisibility(this.getGroupByName(name), visible);
@@ -3947,15 +4069,16 @@ var init_SceneObject = __esm({
3947
4069
  return mesh;
3948
4070
  }
3949
4071
  /**
3950
- * Get a mesh by its name
4072
+ * Finds a named mesh without the internal `mesh:` prefix, or returns `undefined`.
3951
4073
  */
3952
4074
  getMeshByName(name) {
3953
4075
  return this.getObjectByName(`mesh:${name}`);
3954
4076
  }
3955
4077
  /**
3956
- * Toggle visibility of a mesh
3957
- * @param name name of the mesh
3958
- * @param visible set the visibility directly, if not set toggles it
4078
+ * Changes a named mesh's visibility and requests a redraw.
4079
+ * @param name - Mesh name without the `mesh:` prefix.
4080
+ * @param visible - Visibility to assign. Omit it to toggle the current value.
4081
+ * @returns The resulting visibility, or `false` if the mesh does not exist.
3959
4082
  */
3960
4083
  toggleMeshVisibility(name, visible) {
3961
4084
  return this.toggleObjectVisibility(this.getMeshByName(name), visible);
@@ -4001,12 +4124,14 @@ var init_SceneObject = __esm({
4001
4124
  get isInstanced() {
4002
4125
  return this._isInstanced;
4003
4126
  }
4127
+ /** Number of live placements, excluding released instance slots. */
4004
4128
  get instanceCounter() {
4005
4129
  return this._instanceCounter;
4006
4130
  }
4007
4131
  constructInstanceReference(i) {
4008
4132
  return new InstanceReference(this, i);
4009
4133
  }
4134
+ /** Allocates a placement of this instanced object, reusing a released slot when available. */
4010
4135
  nextInstance() {
4011
4136
  const mesh = this.instanceMesh;
4012
4137
  if (!mesh) throw new MineRenderError("Object is not instanced");
@@ -4153,6 +4278,7 @@ var init_SceneObject = __esm({
4153
4278
  vector.setFromMatrixScale(matrix);
4154
4279
  return vector;
4155
4280
  }
4281
+ /** Updates supplied transform components. For a shared model, affects every live instance. */
4156
4282
  setPositionRotationScale(position, rotation, scale) {
4157
4283
  if (this.isInstanced) {
4158
4284
  for (const i of this.activeInstanceIndices()) {
@@ -4171,6 +4297,7 @@ var init_SceneObject = __esm({
4171
4297
  }
4172
4298
  this.notifyDirty();
4173
4299
  }
4300
+ /** Sets position in scene units. For a shared model, updates every live instance. */
4174
4301
  setPosition(position) {
4175
4302
  if (this.isInstanced) {
4176
4303
  for (const i of this.activeInstanceIndices()) {
@@ -4188,6 +4315,7 @@ var init_SceneObject = __esm({
4188
4315
  return this.position;
4189
4316
  }
4190
4317
  }
4318
+ /** Sets rotation in radians. For a shared model, updates every live instance. */
4191
4319
  setRotation(rotation) {
4192
4320
  if (this.isInstanced) {
4193
4321
  for (const i of this.activeInstanceIndices()) {
@@ -4205,6 +4333,7 @@ var init_SceneObject = __esm({
4205
4333
  return this.rotation;
4206
4334
  }
4207
4335
  }
4336
+ /** Sets scale factors. For a shared model, updates every live instance. */
4208
4337
  setScale(scale) {
4209
4338
  if (this.isInstanced) {
4210
4339
  for (const i of this.activeInstanceIndices()) {
@@ -4242,6 +4371,7 @@ var init_SceneObject = __esm({
4242
4371
  this.notifyDirty();
4243
4372
  super.dispose();
4244
4373
  }
4374
+ /** Releases instance slots and removes children, disposing children that implement Disposable. */
4245
4375
  disposeAndRemoveAllChildren() {
4246
4376
  if (this.instanceMesh) {
4247
4377
  if (this._scene) this._scene.stats.instanceCount -= this.instanceReferences.size;
@@ -4264,6 +4394,7 @@ var init_SceneObject = __esm({
4264
4394
  }
4265
4395
  this.notifyDirty();
4266
4396
  }
4397
+ /** Detaches the object from its parent and requests a redraw. */
4267
4398
  removeFromScene() {
4268
4399
  this.notifyDirty();
4269
4400
  this.removeFromParent();
@@ -4419,12 +4550,15 @@ var init_EntityObject = __esm({
4419
4550
  if (this.animationPlayers.length) this.notifyDirty();
4420
4551
  }
4421
4552
  //</editor-fold>
4553
+ /** Finds a selected draw by its layer key, such as `main` or `main#2`, or returns `undefined`. */
4422
4554
  getLayerGroup(name) {
4423
4555
  return super.getGroupByName(`layer:${name}`);
4424
4556
  }
4557
+ /** Finds a part name without `group:`. Supply `layerName` to restrict the search to one draw. */
4425
4558
  getGroupByName(name, layerName) {
4426
4559
  return layerName === void 0 ? super.getGroupByName(name) : this.getLayerGroup(layerName)?.getObjectByName(`group:${name}`);
4427
4560
  }
4561
+ /** Finds a mesh name without `mesh:`. Supply `layerName` to restrict the search to one draw. */
4428
4562
  getMeshByName(name, layerName) {
4429
4563
  return layerName === void 0 ? super.getMeshByName(name) : this.getLayerGroup(layerName)?.getObjectByName(`mesh:${name}`);
4430
4564
  }
@@ -5097,6 +5231,7 @@ var init_ModelCulling = __esm({
5097
5231
  "src/model/ModelCulling.ts"() {
5098
5232
  init_CubeFace();
5099
5233
  ModelCulling = class {
5234
+ /** Rotates a world-direction bit mask into model space. Bits follow {@link CUBE_FACES}. */
5100
5235
  static toLocalMask(worldMask, rotation) {
5101
5236
  let localMask = 0;
5102
5237
  for (const [localFace, offset] of CUBE_FACE_OFFSETS.entries()) {
@@ -5107,6 +5242,7 @@ var init_ModelCulling = __esm({
5107
5242
  }
5108
5243
  return localMask;
5109
5244
  }
5245
+ /** Whether a model fills one block with opaque faces and can hide adjacent block faces. */
5110
5246
  static isOpaqueFullCube(atlas) {
5111
5247
  if (!atlas || atlas.hasTransparency !== false || atlas.model.elements?.length !== 1) return false;
5112
5248
  const element = atlas.model.elements[0];
@@ -5928,6 +6064,7 @@ var Meshes = class _Meshes {
5928
6064
  static createBox(key) {
5929
6065
  return new Mesh(Geometries.getBox(key.geometry), Materials.getImage(key.material));
5930
6066
  }
6067
+ /** Returns a shared Mesh object. Use {@link createBox} for a mesh with its own transform and parent. */
5931
6068
  static getBox(key) {
5932
6069
  const keyStr = serializeMeshKey(key);
5933
6070
  return Caching.boxMeshCache.get(keyStr, (k) => {
@@ -6040,6 +6177,7 @@ init_AssetParsers();
6040
6177
  init_ModelTextures();
6041
6178
  init_Caching();
6042
6179
  var Fonts = class {
6180
+ /** Combines font definitions in source-priority order. Unsupported Unihex and TrueType providers are skipped. */
6043
6181
  static async get(key = "minecraft:default") {
6044
6182
  const fontKey = typeof key === "string" ? AssetKey.parse("font", key) : key;
6045
6183
  return await Caching.fontCache.get(fontKey.serialize(), () => this.load(fontKey, []));
@@ -9256,6 +9394,13 @@ var GuiHelper = class {
9256
9394
  });
9257
9395
  return layers;
9258
9396
  }
9397
+ /**
9398
+ * Calculates a slot's top-left position in GUI pixels.
9399
+ * @param slot - Zero-based slot index, or `[column, row]`.
9400
+ * @param origin - Position of the first slot.
9401
+ * @param offset - Horizontal and vertical spacing between slot origins, in pixels.
9402
+ * @param rowSize - Slots per row when `slot` is an index.
9403
+ */
9259
9404
  static inventorySlot(slot, origin = [0, 0], offset = [18, 18], rowSize = 9) {
9260
9405
  const [column, row] = typeof slot === "number" ? [slot % rowSize, Math.floor(slot / rowSize)] : slot;
9261
9406
  return [origin[0] + column * offset[0], origin[1] + row * offset[1]];
@@ -9913,6 +10058,7 @@ var SceneStatsDisplay = class {
9913
10058
  appendTo(el) {
9914
10059
  el.append(this.statsContainer);
9915
10060
  }
10061
+ /** Stops the refresh timer and removes the panel from the page. */
9916
10062
  dispose() {
9917
10063
  clearInterval(this.interval);
9918
10064
  this.interval = void 0;
@@ -9937,6 +10083,7 @@ var InstanceManager = class {
9937
10083
  this.isInstanceManager = true;
9938
10084
  this.instanceCache = {};
9939
10085
  }
10086
+ /** Allocates a new placement of a cached model, or returns `undefined` if the key is unknown. */
9940
10087
  async get(key) {
9941
10088
  if (key in this.instanceCache) {
9942
10089
  console.debug(p9, "key in cache", key);
@@ -9944,6 +10091,7 @@ var InstanceManager = class {
9944
10091
  }
9945
10092
  return void 0;
9946
10093
  }
10094
+ /** Allocates a placement, calling the supplier once when the shared model is first needed. */
9947
10095
  async getOrCreate(key, supplier) {
9948
10096
  if (key in this.instanceCache) {
9949
10097
  return await this.get(key);
@@ -9960,6 +10108,7 @@ var InstanceManager = class {
9960
10108
  throw error;
9961
10109
  }
9962
10110
  }
10111
+ /** Forgets cached models without disposing them or releasing their existing placements. */
9963
10112
  reset() {
9964
10113
  for (let instanceCacheKey in this.instanceCache) {
9965
10114
  delete this.instanceCache[instanceCacheKey];
@@ -10005,6 +10154,7 @@ function matchesCondition(condition, state) {
10005
10154
  });
10006
10155
  }
10007
10156
  var BlockStateResolver = class {
10157
+ /** Loads vanilla property defaults, falling back to preview values inferred from the blockstate file. */
10008
10158
  static async defaults(blockState) {
10009
10159
  const defaults = blockState.key ? await BlockStates.getDefaultState(blockState.key) : void 0;
10010
10160
  const state = {};
@@ -10024,9 +10174,11 @@ var BlockStateResolver = class {
10024
10174
  }
10025
10175
  return state;
10026
10176
  }
10177
+ /** Selects matching models. Supply `choose` to control selection within each alternatives array. */
10027
10178
  static select(blockState, state, choose = this.choose) {
10028
10179
  return this.matching(blockState, state).map(choose);
10029
10180
  }
10181
+ /** Returns matching model groups before choosing weighted alternatives. */
10030
10182
  static matching(blockState, state) {
10031
10183
  const out = [];
10032
10184
  if (blockState.variants) {
@@ -10050,6 +10202,7 @@ var BlockStateResolver = class {
10050
10202
  }
10051
10203
  return out;
10052
10204
  }
10205
+ /** Selects a random alternative using positive integer weights, each defaulting to 1. */
10053
10206
  static choose(variants) {
10054
10207
  if (!Array.isArray(variants)) return variants;
10055
10208
  if (!variants.length) throw new MineRenderError("Blockstate variant arrays must not be empty");
@@ -10067,6 +10220,7 @@ var BlockStateResolver = class {
10067
10220
  }
10068
10221
  return variants[variants.length - 1];
10069
10222
  }
10223
+ /** Converts blockstate rotations in degrees into the Euler rotation used by model rendering. */
10070
10224
  static rotation(variant) {
10071
10225
  const rotation = new Euler8();
10072
10226
  if (typeof variant.x !== "undefined") {
@@ -10348,6 +10502,7 @@ var _BlockObject = class _BlockObject extends SceneObject {
10348
10502
  }
10349
10503
  this.notifyDirty();
10350
10504
  }
10505
+ /** Selected property values. Use {@link setState} to change properties and rebuild the rendered models. */
10351
10506
  get state() {
10352
10507
  return this._state;
10353
10508
  }
@@ -10447,6 +10602,7 @@ var _BlockObject = class _BlockObject extends SceneObject {
10447
10602
  obj.setPosition(this.position);
10448
10603
  return obj;
10449
10604
  }
10605
+ /** Clears selected properties and rebuilds models without reapplying property defaults. */
10450
10606
  async resetState() {
10451
10607
  this._previousState = this._state;
10452
10608
  this._state = {};
@@ -12350,6 +12506,11 @@ function compoundList(tags, name) {
12350
12506
  // src/model/multiblock/StructureParser.ts
12351
12507
  init_MineRenderError();
12352
12508
  var StructureParser = class {
12509
+ /**
12510
+ * Parses decoded NBT, omitting air blocks.
12511
+ * @param _nbt - Structure data decoded by {@link NBTHelper.fromBuffer}.
12512
+ * @param paletteIndex - Palette to select when the structure has several. Defaults to 0.
12513
+ */
12353
12514
  static async parse(_nbt, paletteIndex) {
12354
12515
  const nbt = _nbt.value;
12355
12516
  let palette;
@@ -13184,6 +13345,7 @@ var SkinImage = class {
13184
13345
  // src/skin/SkinTextures.ts
13185
13346
  init_Textures();
13186
13347
  var SkinTextures = class {
13348
+ /** Loads a skin URL. Pass `legacy` to override layout detection from the image dimensions. */
13187
13349
  static async get(src, legacy) {
13188
13350
  const image = await SkinImage.getData(src);
13189
13351
  const scale = image.width / 64;
@@ -13357,6 +13519,14 @@ var SkinObject = class extends SceneObject {
13357
13519
  }
13358
13520
  }
13359
13521
  }
13522
+ /**
13523
+ * Loads a skin texture, detecting slim arms and legacy layouts by default.
13524
+ * To override detection, set `slim` or `legacy` in the options passed to
13525
+ * `new SkinObject(options)` or `scene.addSkin(src, options)`.
13526
+ * Use {@link setSlim} or {@link setLegacy} to change these settings later.
13527
+ *
13528
+ * @param src - URL of the skin texture.
13529
+ */
13360
13530
  async setSkinTexture(src) {
13361
13531
  if (typeof src === "undefined") return;
13362
13532
  this.skinTextureSrc = src;
@@ -13505,6 +13675,7 @@ var _MineRenderScene = class _MineRenderScene extends Scene4 {
13505
13675
  this.stats.sceneObjectCount += change;
13506
13676
  }
13507
13677
  }
13678
+ /** Initializes each object before attaching it to the scene. */
13508
13679
  async initAndAdd(...object2) {
13509
13680
  this.dirty = true;
13510
13681
  for (let obj of object2) {
@@ -13540,13 +13711,33 @@ var _MineRenderScene = class _MineRenderScene extends Scene4 {
13540
13711
  return obj;
13541
13712
  }
13542
13713
  }
13714
+ /**
13715
+ * Adds a model loaded with {@link Models.getMerged}.
13716
+ * Set `options.instanceMeshes` to `false` to create a separate ModelObject.
13717
+ *
13718
+ * @param parent - Object to attach the model to. Defaults to this scene.
13719
+ * @returns The model, or a reference to one placement of a shared model.
13720
+ */
13543
13721
  async addModel(model, options, parent = this) {
13544
13722
  options = { ...options, tints: await ItemTints.get(model, options?.tints) };
13545
13723
  return this.addSceneObject(model, () => new ModelObject(model, options), options, parent);
13546
13724
  }
13725
+ /**
13726
+ * Adds the models selected by a blockstate loaded with {@link BlockStates.get}.
13727
+ * Set `options.initialState` to choose block properties such as `facing` or `axis`.
13728
+ * Use the returned object's `setPosition` method to move all of its model parts.
13729
+ */
13547
13730
  async addBlock(blockState, options, parent = this) {
13548
13731
  return this.addSceneObject(blockState, () => new BlockObject(blockState, options), options, parent);
13549
13732
  }
13733
+ /**
13734
+ * Loads a skin and adds an initialized player model.
13735
+ *
13736
+ * @param skin - Texture URL, such as one returned by {@link Skins.fromUuidOrUsername}.
13737
+ * Omit it to assign a texture later with {@link SkinObject.setSkinTexture}.
13738
+ * @param options - Player settings, including `slim` and `legacy` detection overrides.
13739
+ * @param parent - Object to attach the player to. Defaults to this scene.
13740
+ */
13550
13741
  async addSkin(skin, options, parent = this) {
13551
13742
  this.dirty = true;
13552
13743
  const obj = new SkinObject(options);
@@ -13558,9 +13749,14 @@ var _MineRenderScene = class _MineRenderScene extends Scene4 {
13558
13749
  parent.add(obj);
13559
13750
  return obj;
13560
13751
  }
13752
+ /** Adds an entity loaded with {@link Entities.getEntity}, using its selected layers and textures. */
13561
13753
  async addEntity(entity, options, parent = this) {
13562
13754
  return this.addSceneObject(entity, () => new EntityObject(entity, options), options, parent);
13563
13755
  }
13756
+ /**
13757
+ * Adds GUI layers in draw order. One GUI pixel equals one scene unit.
13758
+ * Layer positions start at the top left, with positive GUI y pointing down.
13759
+ */
13564
13760
  async addGui(layers, options, parent = this) {
13565
13761
  const obj = new GuiObject(layers, options);
13566
13762
  obj.scene = this;
@@ -14385,6 +14581,7 @@ var _Renderer = class _Renderer {
14385
14581
  get element() {
14386
14582
  return this._element;
14387
14583
  }
14584
+ /** Attaches the canvas to an element and sizes it to that element's dimensions. */
14388
14585
  appendTo(element) {
14389
14586
  if (this._disposed) return;
14390
14587
  this._element = element;
@@ -14412,6 +14609,7 @@ var _Renderer = class _Renderer {
14412
14609
  events.add(changeEvent2);
14413
14610
  dispatcher.addEventListener(changeEvent2, this._changeListener);
14414
14611
  }
14612
+ /** Updates the camera and canvas size. Width and height are in CSS pixels. */
14415
14613
  resize(width, height) {
14416
14614
  if (this._disposed) return;
14417
14615
  if (isPerspectiveCamera(this.camera)) {
@@ -14450,12 +14648,14 @@ var _Renderer = class _Renderer {
14450
14648
  if (this._frameCallbacks.get(callback) === subscription) this._frameCallbacks.delete(callback);
14451
14649
  };
14452
14650
  }
14651
+ /** Starts or resumes the animation loop and registered frame callbacks. */
14453
14652
  start() {
14454
14653
  if (this._disposed) return;
14455
14654
  this.stop();
14456
14655
  this._running = true;
14457
14656
  if (!this._inAnimationLoop) this.renderer.setAnimationLoop(this._animationLoop);
14458
14657
  }
14658
+ /** Pauses rendering and frame callbacks. Call {@link start} to resume. */
14459
14659
  stop() {
14460
14660
  if (this._disposed) return;
14461
14661
  this._running = false;
@@ -14564,12 +14764,15 @@ var _Renderer = class _Renderer {
14564
14764
  const canvas = trim ? trimCanvas(this.renderer.domElement) : this.renderer.domElement;
14565
14765
  return canvas.toDataURL(mime, quality);
14566
14766
  }
14767
+ /** Exports visible scene meshes as OBJ text, without texture images. */
14567
14768
  toObj() {
14568
14769
  return SceneExporter.toObj(this.scene);
14569
14770
  }
14771
+ /** Exports visible scene meshes as PLY. Set `options.binary` for an ArrayBuffer. */
14570
14772
  toPLY(options) {
14571
14773
  return SceneExporter.toPLY(this.scene, options);
14572
14774
  }
14775
+ /** Exports a static textured scene in the browser. Set `options.binary` for GLB output. */
14573
14776
  toGLTF(options) {
14574
14777
  return SceneExporter.toGLTF(this.scene, options);
14575
14778
  }
@@ -14651,12 +14854,14 @@ init_request();
14651
14854
  init_Requests();
14652
14855
  var Skins = class {
14653
14856
  //<editor-fold desc="Skins">
14857
+ /** Returns a skin URL for {@link MineRenderScene.addSkin}, or `undefined` if name lookup fails. */
14654
14858
  static async fromUuidOrUsername(uuidOrUsername) {
14655
14859
  if (uuidOrUsername.length === 32 || uuidOrUsername.length === 36) {
14656
14860
  return this.fromUuid(uuidOrUsername);
14657
14861
  }
14658
14862
  return this.fromUsername(uuidOrUsername);
14659
14863
  }
14864
+ /** Builds a proxy URL for a UUID without downloading or checking the skin. */
14660
14865
  static async fromUuid(uuid) {
14661
14866
  return this.getMcProxySkinUrl(uuid);
14662
14867
  }
@@ -14668,6 +14873,7 @@ var Skins = class {
14668
14873
  return void 0;
14669
14874
  });
14670
14875
  }
14876
+ /** Looks up a saved MineSkin skin and returns its texture URL, or `undefined` on lookup failure. */
14671
14877
  static async fromMineSkin(mineskinId) {
14672
14878
  return this.getMineSkin(mineskinId).then((mineskin) => {
14673
14879
  if (mineskin) {
@@ -14678,12 +14884,14 @@ var Skins = class {
14678
14884
  }
14679
14885
  //</editor-fold>
14680
14886
  //<editor-fold desc="Capes">
14887
+ /** Resolves a player's Minecraft cape URL for {@link SkinObject.setCapeTexture}. */
14681
14888
  static async capeFromUuidOrUsername(uuidOrUsername) {
14682
14889
  if (uuidOrUsername.length === 32 || uuidOrUsername.length === 36) {
14683
14890
  return this.capeFromUuid(uuidOrUsername);
14684
14891
  }
14685
14892
  return this.capeFromUsername(uuidOrUsername);
14686
14893
  }
14894
+ /** Builds a proxy URL without checking whether the player has a cape. */
14687
14895
  static async capeFromUuid(uuid) {
14688
14896
  return this.getMcProxyCapeUrl(uuid);
14689
14897
  }
@@ -14838,16 +15046,19 @@ var ChunkData = class _ChunkData {
14838
15046
  this.freeIds = [];
14839
15047
  this.nbt = /* @__PURE__ */ new Map();
14840
15048
  }
15049
+ /** Returns a detached copy of a cell, or `undefined` for air. Indices range from 0 to 4095. */
14841
15050
  get(index) {
14842
15051
  _ChunkData.validateIndex(index);
14843
15052
  const entry = this.palette[this.indices[index]];
14844
15053
  return entry ? _ChunkData.copyBlock(entry.state, this.nbt.get(index)) : void 0;
14845
15054
  }
15055
+ /** Captures a cell's data and returns a copy-producing reader that survives later cell changes. */
14846
15056
  snapshot(index) {
14847
15057
  _ChunkData.validateIndex(index);
14848
15058
  const entry = this.palette[this.indices[index]];
14849
15059
  return entry ? _ChunkData.copyBlock.bind(void 0, entry.state, this.nbt.get(index)) : void 0;
14850
15060
  }
15061
+ /** Copies block data into a cell. An omitted block or an air block clears the cell. */
14851
15062
  set(index, block) {
14852
15063
  _ChunkData.validateIndex(index);
14853
15064
  let state;
@@ -14912,15 +15123,23 @@ var ChunkData = class _ChunkData {
14912
15123
 
14913
15124
  // src/world/AnvilParser.ts
14914
15125
  var AnvilParser = class {
15126
+ /** Lists occupied chunk positions within the region, using local coordinates from 0 to 31. */
14915
15127
  static getChunkList(data) {
14916
15128
  return this.locations(this.bytes(data)).map(({ x, z }) => ({ x, z }));
14917
15129
  }
15130
+ /** Decodes all stored chunks. Gzip, zlib, and uncompressed payloads are supported. */
14918
15131
  static async parse(data) {
14919
15132
  const bytes = this.bytes(data);
14920
15133
  const chunks = [];
14921
15134
  for (const location of this.locations(bytes)) chunks.push(await this.readChunk(bytes, location));
14922
15135
  return { chunks };
14923
15136
  }
15137
+ /**
15138
+ * Decodes one chunk for {@link MineRenderWorld.placeChunk}.
15139
+ * @param localX - Chunk x within the region, from 0 to 31.
15140
+ * @param localZ - Chunk z within the region, from 0 to 31.
15141
+ * @returns The chunk with absolute coordinates, or `undefined` if the region has no chunk there.
15142
+ */
14924
15143
  static async parseChunk(data, localX, localZ) {
14925
15144
  if (![localX, localZ].every((value) => Number.isInteger(value) && value >= 0 && value < 32)) {
14926
15145
  throw new RangeError("Region-local chunk coordinates must be integers from 0 to 31");
@@ -15125,6 +15344,7 @@ var SectionModels = class {
15125
15344
  this.templates = /* @__PURE__ */ new Set();
15126
15345
  if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError("maxAtlasSize must be a positive integer");
15127
15346
  }
15347
+ /** Returns a cube template, or `undefined` when the block requires an individual render object. */
15128
15348
  async get(blockState, properties = {}) {
15129
15349
  if (!blockState.variants || blockState.multipart) return void 0;
15130
15350
  let states = this.states.get(blockState);
@@ -15178,6 +15398,7 @@ var SectionModels = class {
15178
15398
  }
15179
15399
  return { variants, templates };
15180
15400
  }
15401
+ /** Disposes prepared geometry and clears this world's template caches. */
15181
15402
  clear() {
15182
15403
  for (const template of this.templates) template.geometry.dispose();
15183
15404
  this.templates.clear();
@@ -15228,6 +15449,13 @@ var MineRenderWorld = class {
15228
15449
  this.validatePosBounds(posOrX);
15229
15450
  await this.getChunkAt(posOrX)?.setBlockVisibleAt(posOrX, yOrVisible);
15230
15451
  }
15452
+ /**
15453
+ * Places a structure's blocks at their stored positions, then refreshes neighboring faces.
15454
+ * Entity NBT is retained by the structure but is not rendered.
15455
+ *
15456
+ * @param useBatches - Uses bounded batches by default. Set to `false` for sequential placement.
15457
+ * @param executor - Optional queue for batched placement. The caller remains responsible for stopping it.
15458
+ */
15231
15459
  async placeMultiBlock(multiblock, useBatches = true, executor) {
15232
15460
  const changes = /* @__PURE__ */ new Map();
15233
15461
  try {
@@ -15279,13 +15507,7 @@ var MineRenderWorld = class {
15279
15507
  async placeChunk(chunk, executor) {
15280
15508
  const changes = /* @__PURE__ */ new Map();
15281
15509
  try {
15282
- const previous = [...this._chunks.entries()].filter(([, section]) => section.x === chunk.x && section.z === chunk.z);
15283
- for (const [key, section] of previous) {
15284
- this._chunks.delete(key);
15285
- await section.clear(async (positions) => {
15286
- for (const pos of positions) changes.set(pos.toArray().join(","), pos);
15287
- });
15288
- }
15510
+ await this.clearChunkColumn(chunk.x, chunk.z, changes);
15289
15511
  for (const section of chunk.sections) {
15290
15512
  const blocks = [];
15291
15513
  for (let index = 0; index < 4096; index++) {
@@ -15305,6 +15527,32 @@ var MineRenderWorld = class {
15305
15527
  await this.updateCulling([...changes.values()]);
15306
15528
  }
15307
15529
  }
15530
+ /**
15531
+ * Removes all sections at integer chunk-column coordinates, then refreshes neighboring faces and fluids.
15532
+ * Coordinates match AnvilChunk.x/z, not block positions. Missing columns are ignored.
15533
+ */
15534
+ async unloadChunkColumn(x, z) {
15535
+ if (!Number.isInteger(x) || !Number.isInteger(z)) {
15536
+ throw new RangeError("Chunk column coordinates must be integers");
15537
+ }
15538
+ await this.culling;
15539
+ const changes = /* @__PURE__ */ new Map();
15540
+ try {
15541
+ await this.clearChunkColumn(x, z, changes);
15542
+ } finally {
15543
+ await this.updateCulling([...changes.values()]);
15544
+ }
15545
+ }
15546
+ async clearChunkColumn(x, z, changes) {
15547
+ const previous = [...this._chunks.entries()].filter(([, section]) => section.x === x && section.z === z);
15548
+ for (const [key, section] of previous) {
15549
+ this._chunks.delete(key);
15550
+ await section.clear(async (positions) => {
15551
+ for (const pos of positions) changes.set(pos.toArray().join(","), pos);
15552
+ });
15553
+ }
15554
+ }
15555
+ /** Removes all chunks and releases their block placements and section meshes. */
15308
15556
  async clear() {
15309
15557
  await this.culling;
15310
15558
  const chunks = [...this._chunks.values()];
@@ -15390,9 +15638,11 @@ var MineRenderWorld = class {
15390
15638
  }
15391
15639
  return chunk;
15392
15640
  }
15641
+ /** Returns the loaded chunk containing a world block position, without creating a chunk. */
15393
15642
  getChunkAt(pos) {
15394
15643
  return this._chunks.get(this.worldPosToChunkKey(pos));
15395
15644
  }
15645
+ /** Converts block coordinates to scene units by multiplying each component by 16. */
15396
15646
  static worldToScenePosition(pos) {
15397
15647
  return new Vector316(
15398
15648
  pos.x * 16,
@@ -15400,6 +15650,7 @@ var MineRenderWorld = class {
15400
15650
  pos.z * 16
15401
15651
  );
15402
15652
  }
15653
+ /** Converts scene units to block coordinates without rounding to an integer block. */
15403
15654
  static sceneToWorldPosition(pos) {
15404
15655
  return new Vector316(
15405
15656
  pos.x / 16,
@@ -15432,6 +15683,7 @@ var SectionMesh = class _SectionMesh extends Group2 {
15432
15683
  super(...arguments);
15433
15684
  this.ownedMeshes = [];
15434
15685
  }
15686
+ /** Builds section-local meshes from visible cube faces. `maxAtlasSize` limits each atlas dimension in pixels. */
15435
15687
  static build(entries, maxAtlasSize = 2048) {
15436
15688
  if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError("Section atlas size must be a positive integer");
15437
15689
  const visible = entries.filter((entry) => entry.template.cullFaces.some((direction) => !(entry.cullMask & direction)));
@@ -15576,7 +15828,7 @@ var Chunk = class _Chunk {
15576
15828
  return this.setBlockInChunkAt(pos, block, worldPos);
15577
15829
  }
15578
15830
  /**
15579
- * Set a block at integer chunk-local coordinates from 0 to 15.
15831
+ * Places a block at integer chunk-local coordinates from 0 to 15.
15580
15832
  */
15581
15833
  async setBlockInChunkAt(pos, block, worldPos, onBlocksChanged = this.onBlocksChanged) {
15582
15834
  if (typeof worldPos === "undefined") {
@@ -15625,6 +15877,7 @@ var Chunk = class _Chunk {
15625
15877
  await onBlocksChanged?.([worldPos]);
15626
15878
  }
15627
15879
  }
15880
+ /** Changes visibility at world block coordinates while preserving the block's data. */
15628
15881
  async setBlockVisibleAt(pos, visible) {
15629
15882
  const index = _Chunk.chunkPosToBlockIndex(this.worldPosToChunkPos(pos));
15630
15883
  const block = this.renderedBlocks.get(index);
@@ -15678,6 +15931,7 @@ var Chunk = class _Chunk {
15678
15931
  this.scene.dirty = true;
15679
15932
  this.meshDirty = false;
15680
15933
  }
15934
+ /** Removes stored blocks and their render objects, then notifies the owning world of changed positions. */
15681
15935
  async clear(onBlocksChanged = this.onBlocksChanged) {
15682
15936
  const positions = [...this.renderedBlocks.keys()].map((index) => this.chunkPosToWorldPos(
15683
15937
  new Vector317(index % 16, Math.floor(index / 256), Math.floor(index / 16) % 16)
@@ -15698,6 +15952,7 @@ var Chunk = class _Chunk {
15698
15952
  static isAir(block) {
15699
15953
  return ChunkData.isAir(block);
15700
15954
  }
15955
+ /** Maps chunk-local coordinates from 0 to 15 to a storage index, with x varying fastest, then z, then y. */
15701
15956
  static chunkPosToBlockIndex(pos) {
15702
15957
  if ([pos.x, pos.y, pos.z].some((value) => !Number.isInteger(value) || value < 0 || value >= 16)) {
15703
15958
  throw new RangeError("Block coordinates must be integers from 0 to 15 within a chunk");