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.
package/dist/bundle.js CHANGED
@@ -4056,6 +4056,7 @@ var MineRender = (() => {
4056
4056
  constructor(backing) {
4057
4057
  this.backing = backing;
4058
4058
  }
4059
+ /** Opens a named store in the active environment using the current cache schema version. */
4059
4060
  static open(name2) {
4060
4061
  return Env.provider.openCache(name2, _PersistentCache.VERSION);
4061
4062
  }
@@ -41425,6 +41426,7 @@ void main() {
41425
41426
  this.fontCache
41426
41427
  ];
41427
41428
  }
41429
+ /** Invalidates in-memory entries so later lookups reload them. Persisted entries are retained. */
41428
41430
  static clear() {
41429
41431
  for (const cache of this.all) {
41430
41432
  cache.invalidateAll();
@@ -41493,6 +41495,7 @@ void main() {
41493
41495
  }
41494
41496
  return geometry;
41495
41497
  }
41498
+ /** Returns shared geometry. Use {@link createBox} when the caller needs to modify or dispose it independently. */
41496
41499
  static getBox(key) {
41497
41500
  const keyStr = serializeBoxGeometryKey(key);
41498
41501
  return Caching.boxGeometryCache.get(keyStr, (k4) => {
@@ -42047,12 +42050,15 @@ void main() {
42047
42050
  }
42048
42051
  };
42049
42052
  Requests = class {
42053
+ /** Queues a general request. Set `request.signal` to cancel it and `request.timeout` to limit each attempt. */
42050
42054
  static genericRequest(request) {
42051
42055
  return this.genericQueue.request(request);
42052
42056
  }
42057
+ /** Queues a request separately from general traffic, using the configured asset base URL for relative paths. */
42053
42058
  static mcAssetRequest(request) {
42054
42059
  return this.mcAssetRequestQueue.request(request);
42055
42060
  }
42061
+ /** Sets the base URL for relative asset requests. Use {@link AssetLoader.setVersion} to change Minecraft versions. */
42056
42062
  static setMcAssetRoot(root) {
42057
42063
  this.mcAssetRequestQueue.baseURL = root;
42058
42064
  }
@@ -42110,6 +42116,7 @@ void main() {
42110
42116
  }
42111
42117
  return false;
42112
42118
  }
42119
+ /** Whether the dimensions form a vertical strip of square frames, without consulting `.mcmeta`. */
42113
42120
  get animated() {
42114
42121
  return this.height > this.width && this.height % this.width === 0;
42115
42122
  }
@@ -42159,6 +42166,7 @@ void main() {
42159
42166
  static _createImage() {
42160
42167
  return createImage();
42161
42168
  }
42169
+ /** Resolves when an image URL has decoded, or rejects if decoding fails. */
42162
42170
  static async loadAsync(src) {
42163
42171
  return new Promise((resolve, reject) => {
42164
42172
  const image = this._createImage();
@@ -42167,6 +42175,7 @@ void main() {
42167
42175
  image.src = src;
42168
42176
  });
42169
42177
  }
42178
+ /** Returns an image immediately. Use the callbacks to observe loading, or await {@link loadAsync}. */
42170
42179
  static loadElement(src, onload, onerr) {
42171
42180
  const image = this._createImage();
42172
42181
  if (onload)
@@ -42194,6 +42203,7 @@ void main() {
42194
42203
  throw err2;
42195
42204
  }
42196
42205
  }
42206
+ /** Decodes the supplied bytes into a canvas without fetching the source URL again. */
42197
42207
  static async infoToCanvasData(info) {
42198
42208
  const type = info.type === "jpg" ? "jpeg" : info.type ?? "png";
42199
42209
  const image = await _ImageLoader.loadAsync(`data:image/${type};base64,${info.data.toString("base64")}`);
@@ -42210,12 +42220,14 @@ void main() {
42210
42220
  const image = await this.infoToCanvasData(info);
42211
42221
  return image.data.getImageData(0, 0, image.width, image.height);
42212
42222
  }
42223
+ /** Returns cached RGBA pixels for an image URL or data URL. Failed loads can be retried. */
42213
42224
  static async getData(src) {
42214
42225
  const keyStr = serializeImageKey({ src });
42215
42226
  return await Caching.imageDataCache.get(keyStr, (k4) => {
42216
42227
  return _ImageLoader.loadData(src);
42217
42228
  });
42218
42229
  }
42230
+ /** Returns a cached canvas context and dimensions for an image URL or data URL. */
42219
42231
  static async getCanvasData(src) {
42220
42232
  const keyStr = serializeImageKey({ src });
42221
42233
  return await Caching.canvasImageDataCache.get(keyStr, (k4) => {
@@ -42315,6 +42327,7 @@ void main() {
42315
42327
  texture.rotation = rotation;
42316
42328
  return Textures.initTextureProps(texture);
42317
42329
  }
42330
+ /** Loads image pixels in the background. `rotation` is in radians. Check {@link hasFailed} for load failures. */
42318
42331
  static load(src, format3 = RGBAFormat, rotation = 0) {
42319
42332
  const texture = new Texture();
42320
42333
  texture.colorSpace = SRGBColorSpace;
@@ -42367,6 +42380,7 @@ void main() {
42367
42380
  return this.initTextureProps(texture);
42368
42381
  });
42369
42382
  }
42383
+ /** Sets nearest-neighbor filters without changing the texture's color space. Returns the same texture. */
42370
42384
  static initTextureProps(texture) {
42371
42385
  texture.magFilter = NearestFilter;
42372
42386
  texture.minFilter = NearestFilter;
@@ -42379,11 +42393,13 @@ void main() {
42379
42393
  static createAsset(key) {
42380
42394
  return new Texture();
42381
42395
  }
42396
+ /** Creates an sRGB color texture from a canvas. */
42382
42397
  static createCanvasTexture(canvas) {
42383
42398
  const texture = new CanvasTexture(canvas);
42384
42399
  texture.colorSpace = SRGBColorSpace;
42385
42400
  return this.initTextureProps(texture);
42386
42401
  }
42402
+ /** Returns a shared texture immediately and loads its image asynchronously. Failed cached loads are retried. */
42387
42403
  static getImage(key) {
42388
42404
  const keyStr = serializeTextureKey(key);
42389
42405
  const cached2 = Caching.textureCache.peek(keyStr);
@@ -42411,6 +42427,7 @@ void main() {
42411
42427
  init_TextureLoader();
42412
42428
  init_Caching();
42413
42429
  Materials = class _Materials {
42430
+ /** Shared checkerboard material, created on first access. */
42414
42431
  static get MISSING_TEXTURE() {
42415
42432
  return Caching.materialCache.get("builtin:missing-texture", () => new MeshBasicMaterial({
42416
42433
  map: Textures.getMissing(),
@@ -42514,6 +42531,7 @@ void main() {
42514
42531
  if (tint !== void 0) material.color.multiply(new Color(tint));
42515
42532
  return material;
42516
42533
  }
42534
+ /** Creates an unlit, transparent GUI material without depth writes or tone mapping. */
42517
42535
  static createGuiCanvasMaterial(canvas) {
42518
42536
  const material = new MeshBasicMaterial({
42519
42537
  map: Textures.createCanvasTexture(canvas),
@@ -42680,6 +42698,7 @@ void main() {
42680
42698
  }
42681
42699
  return this.createBasicCanvasMaterial(canvas, transparent, shade);
42682
42700
  }
42701
+ /** Returns a shared image material. Use {@link createImage} for a separate material instance. */
42683
42702
  static getImage(key) {
42684
42703
  const keyStr = serializeMaterialKey(key);
42685
42704
  const map = Caching.materialCache.peek(keyStr)?.map;
@@ -42863,6 +42882,14 @@ void main() {
42863
42882
  }
42864
42883
  };
42865
42884
  AssetKey = class _AssetKey extends BasicAssetKey {
42885
+ /**
42886
+ * Creates a key from separate path components. Use {@link parse} for a combined reference.
42887
+ *
42888
+ * @param assetType - Asset directory, such as `models`, `textures`, or `blockstates`.
42889
+ * @param type - Subdirectory, such as `block` or `item`.
42890
+ * @param rootType - Top-level directory, usually `assets` or `data`.
42891
+ * @param root - Base URL override for hosted asset sources.
42892
+ */
42866
42893
  constructor(namespace, path, assetType, type, rootType = "assets", extension = ".json", root) {
42867
42894
  super(namespace, path);
42868
42895
  this.namespace = namespace;
@@ -42874,6 +42901,16 @@ void main() {
42874
42901
  this.root = root;
42875
42902
  this.isAssetKey = true;
42876
42903
  }
42904
+ /**
42905
+ * Parses an asset reference such as `minecraft:block/stone`.
42906
+ * A missing namespace defaults to the origin's namespace or `minecraft`.
42907
+ *
42908
+ * @param assetType - Asset category, such as `models` or `textures`.
42909
+ * @param str - Path with an optional namespace and file extension.
42910
+ * @param origin - Supplies the asset root, default namespace, and non-texture extension.
42911
+ * @returns A key with the matching extension removed from its path. Textures use `.png`;
42912
+ * other assets use the origin's extension or `.json`.
42913
+ */
42877
42914
  static parse(assetType, str, origin) {
42878
42915
  let namespace = origin?.namespace || DEFAULT_NAMESPACE;
42879
42916
  if (str.includes(":")) {
@@ -42905,6 +42942,7 @@ void main() {
42905
42942
  ];
42906
42943
  return a4.join("/");
42907
42944
  }
42945
+ /** Joins the type subdirectory and path without adding a namespace or file extension. */
42908
42946
  getFullPath() {
42909
42947
  let p13 = [];
42910
42948
  if (this.type) {
@@ -42916,6 +42954,7 @@ void main() {
42916
42954
  toNamespacedString() {
42917
42955
  return this.namespace + ":" + this.getFullPath();
42918
42956
  }
42957
+ /** Returns a cache identifier that includes the explicit root or {@link AssetLoader.ROOT}. */
42919
42958
  serialize() {
42920
42959
  return this.toString();
42921
42960
  }
@@ -42981,6 +43020,7 @@ void main() {
42981
43020
  const scale = new Vector3(...transform.scale ?? [1, 1, 1]).clampScalar(-4, 4);
42982
43021
  return new Matrix4().compose(translation, rotation, scale);
42983
43022
  }
43023
+ /** Transforms geometry in place and reverses triangle winding when the matrix reflects it. */
42984
43024
  static apply(geometry, matrix) {
42985
43025
  geometry.applyMatrix4(matrix);
42986
43026
  if (matrix.determinant() < 0) {
@@ -43011,6 +43051,7 @@ void main() {
43011
43051
  init_AssetKey();
43012
43052
  init_DisplayTransforms();
43013
43053
  ModelMerger = class {
43054
+ /** Loads the parent chain and returns a merged model without modifying the supplied definition. */
43014
43055
  static async mergeWithParents(model) {
43015
43056
  const models = await this.collectAllParents(model);
43016
43057
  let merged = {};
@@ -43084,6 +43125,7 @@ void main() {
43084
43125
  static get PERSISTENT_CACHE() {
43085
43126
  return this._persistentCache ?? (this._persistentCache = PersistentCache.open("minerender-models"));
43086
43127
  }
43128
+ /** Lists item filenames from the asset source's `_list.json`, with a legacy model-directory fallback. */
43087
43129
  static async getItemList() {
43088
43130
  const key = new AssetKey(DEFAULT_NAMESPACE, "_list", "items");
43089
43131
  const legacyKey = new AssetKey(DEFAULT_NAMESPACE, "_list", "models", "item");
@@ -43154,6 +43196,7 @@ void main() {
43154
43196
  }
43155
43197
  throw new Error(`Unsupported item model ${node?.type ?? "definition"} for ${key.toNamespacedString()}`);
43156
43198
  }
43199
+ /** Loads one model file without resolving its parents. Returns `undefined` when the file is missing. */
43157
43200
  static async getRaw(key) {
43158
43201
  if (!key.assetType) {
43159
43202
  key.assetType = "models";
@@ -43173,6 +43216,12 @@ void main() {
43173
43216
  return asset;
43174
43217
  });
43175
43218
  }
43219
+ /**
43220
+ * Loads a model and resolves its parent chain. Returns `undefined` when the model is missing.
43221
+ * Item keys use GUI context, false conditions, and zero numeric properties.
43222
+ *
43223
+ * @param key - Model key, for example `AssetKey.parse("models", "minecraft:item/diamond_sword")`.
43224
+ */
43176
43225
  static async getMerged(key) {
43177
43226
  if (!key.assetType) {
43178
43227
  key.assetType = "models";
@@ -43185,9 +43234,11 @@ void main() {
43185
43234
  return _Models.loadAndMerge(key);
43186
43235
  });
43187
43236
  }
43237
+ /** Alias for {@link getMerged}. */
43188
43238
  static async get(key) {
43189
43239
  return this.getMerged(key);
43190
43240
  }
43241
+ /** Clears persisted models. Use {@link Caching.clear} to also discard in-memory assets. */
43191
43242
  static async clearCache() {
43192
43243
  return this.PERSISTENT_CACHE.clear();
43193
43244
  }
@@ -43213,6 +43264,7 @@ void main() {
43213
43264
  return this._persistentCache ?? (this._persistentCache = PersistentCache.open("minerender-blockstates"));
43214
43265
  }
43215
43266
  // BlockState names are hardcoded
43267
+ /** Returns blockstate filenames from the selected version's `_list.json`, or an empty list. */
43216
43268
  static async getList() {
43217
43269
  const key = new AssetKey(
43218
43270
  DEFAULT_NAMESPACE,
@@ -43233,6 +43285,7 @@ void main() {
43233
43285
  return AssetLoader.get(key, "json" /* JSON */);
43234
43286
  });
43235
43287
  }
43288
+ /** Looks up vanilla property definitions for the key's block path, or returns `undefined`. */
43236
43289
  static async getDefaultState(key) {
43237
43290
  const defaultStates = await this.getDefaultStates();
43238
43291
  if (!defaultStates) {
@@ -43240,6 +43293,7 @@ void main() {
43240
43293
  }
43241
43294
  return defaultStates["minecraft:" + key.path];
43242
43295
  }
43296
+ /** Loads a cached blockstate definition for {@link MineRenderScene.addBlock}, or returns `undefined`. */
43243
43297
  static async get(key) {
43244
43298
  if (!key.assetType) {
43245
43299
  key.assetType = "blockstates";
@@ -43266,6 +43320,7 @@ void main() {
43266
43320
  }
43267
43321
  return Promise.all(promises);
43268
43322
  }
43323
+ /** Clears persisted blockstates. Use {@link Caching.clear} to also discard in-memory assets. */
43269
43324
  static async clearCache() {
43270
43325
  await this.PERSISTENT_CACHE.clear();
43271
43326
  }
@@ -43294,9 +43349,11 @@ void main() {
43294
43349
  static parseAssetKey(assetType, str, origin) {
43295
43350
  return AssetKey.parse(assetType, str, origin);
43296
43351
  }
43352
+ /** Loads a model with its parent chain resolved. See {@link Models.getMerged}. */
43297
43353
  static async getModel(key) {
43298
43354
  return Models.getMerged(key);
43299
43355
  }
43356
+ /** Loads a blockstate definition. See {@link BlockStates.get}. */
43300
43357
  static async getBlockState(key) {
43301
43358
  return BlockStates.get(key);
43302
43359
  }
@@ -43349,6 +43406,10 @@ void main() {
43349
43406
  init_process2();
43350
43407
  import_jobqu2 = __toESM(require_src());
43351
43408
  BatchedExecutor = class {
43409
+ /**
43410
+ * @param interval - Delay between queue runs, in milliseconds.
43411
+ * @param batch - Maximum tasks started per run and maximum tasks active at once.
43412
+ */
43352
43413
  constructor(interval = 1, batch = 30) {
43353
43414
  if (!Number.isFinite(interval) || interval < 0) throw new RangeError("Batch interval must be finite and nonnegative");
43354
43415
  if (!Number.isInteger(batch) || batch < 1) throw new RangeError("Batch size must be a positive integer");
@@ -43356,9 +43417,11 @@ void main() {
43356
43417
  this.batch = batch;
43357
43418
  this.queue = new import_jobqu2.JobQueue(async (task) => task(), { interval, maxPerRun: batch, maxActive: batch });
43358
43419
  }
43420
+ /** Queues a task and resolves with its result, or rejects with its error. */
43359
43421
  submit(task) {
43360
43422
  return this.queue.add(() => task());
43361
43423
  }
43424
+ /** Rejects queued and future tasks. Tasks already running are allowed to finish. */
43362
43425
  stop() {
43363
43426
  this.queue.end();
43364
43427
  }
@@ -77161,6 +77224,7 @@ return ${compiler2.callType("value", tagType)}
77161
77224
  init_process2();
77162
77225
  init_buffer();
77163
77226
  NBTHelper = class {
77227
+ /** Parses NBT bytes and preserves format and compression metadata. Omit `format` for automatic detection. */
77164
77228
  static async fromBuffer(data, format3) {
77165
77229
  const buffer2 = Buffer.from(data instanceof Uint8Array ? data : new Uint8Array(data));
77166
77230
  const prismarineNbt = await Promise.resolve().then(() => __toESM(require_nbt2()));
@@ -77247,6 +77311,7 @@ return ${compiler2.callType("value", tagType)}
77247
77311
  retryDefaults: true
77248
77312
  };
77249
77313
  _HostedAssetSource = class _HostedAssetSource extends AssetSource {
77314
+ /** Retries missing assets with the `minecraft` namespace and default root. Other failures reject. */
77250
77315
  async loadOrRetryWithDefaults(key, parser) {
77251
77316
  const direct = await this.load(key, parser);
77252
77317
  if (typeof direct !== "undefined") {
@@ -77304,6 +77369,10 @@ return ${compiler2.callType("value", tagType)}
77304
77369
  assetBasePath(key) {
77305
77370
  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 + "/" : ""}`;
77306
77371
  }
77372
+ /**
77373
+ * Creates a hosted source for {@link AssetLoader.addSource}.
77374
+ * Set `options.retryDefaults` to `false` to restrict lookups to the requested namespace and root.
77375
+ */
77307
77376
  constructor(root, options) {
77308
77377
  super();
77309
77378
  this._root = root;
@@ -87008,6 +87077,11 @@ return ${compiler2.callType("value", tagType)}
87008
87077
  init_process2();
87009
87078
  init_zip();
87010
87079
  BrowserArchiveProxy = class {
87080
+ /**
87081
+ * Opens a ZIP for asset lookup.
87082
+ * @param id - Cache identity for this content. Change it when the pack changes.
87083
+ * A File supplies an identity from its name, size, and modification time when omitted.
87084
+ */
87011
87085
  constructor(blob, id) {
87012
87086
  this._blob = blob;
87013
87087
  this._reader = new ZipReader(new BlobReader(this._blob));
@@ -87214,6 +87288,7 @@ return ${compiler2.callType("value", tagType)}
87214
87288
  dataPackFormat: copyFormat(options.dataPackFormat)
87215
87289
  };
87216
87290
  }
87291
+ /** Creates a browser ZIP source from a Blob or File. */
87217
87292
  static blob(blob, options) {
87218
87293
  return new _ArchiveAssetSource(new BrowserArchiveProxy(blob), options);
87219
87294
  }
@@ -87363,6 +87438,7 @@ return ${compiler2.callType("value", tagType)}
87363
87438
  static get version() {
87364
87439
  return this.ROOT.substring(this.ROOT.lastIndexOf("/") + 1);
87365
87440
  }
87441
+ /** Selects an mcasset.cloud version, updates the vanilla source, and clears in-memory caches. */
87366
87442
  static setVersion(version2) {
87367
87443
  this.ROOT = `https://assets.mcasset.cloud/${version2}`;
87368
87444
  const source = new HostedAssetSource(this.ROOT, { retryDefaults: false });
@@ -87396,6 +87472,13 @@ return ${compiler2.callType("value", tagType)}
87396
87472
  return scope ? `${scope}
87397
87473
  ${key}` : key;
87398
87474
  }
87475
+ /**
87476
+ * Registers a source at the highest priority.
87477
+ * Call {@link Caching.clear} after changing sources to discard previously loaded assets.
87478
+ *
87479
+ * @param key - Name used to replace or remove this source.
87480
+ * @param override - Removes the first source with this name before adding the new one.
87481
+ */
87399
87482
  static addSource(key, source, override = true) {
87400
87483
  if (override) {
87401
87484
  const existing = this.removeSource(key);
@@ -87406,6 +87489,7 @@ ${key}` : key;
87406
87489
  this._SOURCES.unshift({ key, source });
87407
87490
  console.log(p7, "Added AssetSource", key);
87408
87491
  }
87492
+ /** Removes and returns the first source with this name. Call {@link Caching.clear} to reload assets. */
87409
87493
  static removeSource(key) {
87410
87494
  const index = this._SOURCES.findIndex((s4) => s4.key === key);
87411
87495
  if (index != -1) {
@@ -87416,6 +87500,7 @@ ${key}` : key;
87416
87500
  }
87417
87501
  return void 0;
87418
87502
  }
87503
+ /** Loads from all sources and returns defined results in priority order. Any source failure rejects the call. */
87419
87504
  static async getAll(key, parser) {
87420
87505
  const sources = [...this._SOURCES];
87421
87506
  const results = [];
@@ -87460,6 +87545,7 @@ ${key}` : key;
87460
87545
  return void 0;
87461
87546
  }
87462
87547
  };
87548
+ /** Default asset base URL. Use {@link setVersion} to select a Minecraft version. */
87463
87549
  _AssetLoader.ROOT = DEFAULT_ROOT;
87464
87550
  _AssetLoader._SOURCES = [];
87465
87551
  /** Used when a registered source cannot identify its content, so nothing persists past this session. */
@@ -87487,6 +87573,7 @@ ${key}` : key;
87487
87573
  static get PERSISTENT_META_CACHE() {
87488
87574
  return this._persistentMetaCache ?? (this._persistentMetaCache = PersistentCache.open("minerender-texturemeta"));
87489
87575
  }
87576
+ /** Loads and decodes a texture into a readable canvas, or returns `undefined` when missing. */
87490
87577
  static async get(key) {
87491
87578
  const keyStr = key.serialize();
87492
87579
  const pending = this.preload(key);
@@ -87504,6 +87591,7 @@ ${key}` : key;
87504
87591
  throw err2;
87505
87592
  }
87506
87593
  }
87594
+ /** Fetches and caches encoded texture bytes without decoding the pixels. */
87507
87595
  static async preload(key) {
87508
87596
  const keyStr = key.serialize();
87509
87597
  return Caching.textureAssetCache.get(keyStr, (k4) => {
@@ -87514,6 +87602,7 @@ ${key}` : key;
87514
87602
  });
87515
87603
  });
87516
87604
  }
87605
+ /** Loads a texture's `.mcmeta` file, or returns `undefined` when no metadata file exists. */
87517
87606
  static async getMeta(key) {
87518
87607
  if (!key.extension || !key.extension.endsWith(".mcmeta")) {
87519
87608
  key = Object.assign(new AssetKey("", ""), key);
@@ -87530,6 +87619,7 @@ ${key}` : key;
87530
87619
  });
87531
87620
  });
87532
87621
  }
87622
+ /** Clears persisted texture metadata. Use {@link Caching.clear} to discard in-memory textures and metadata. */
87533
87623
  static async clearCache() {
87534
87624
  await this.PERSISTENT_META_CACHE.clear();
87535
87625
  }
@@ -87602,6 +87692,7 @@ ${key}` : key;
87602
87692
  }
87603
87693
  return handle;
87604
87694
  }
87695
+ /** Starts or resumes the shared tick loop. Repeated calls have no effect. */
87605
87696
  static start() {
87606
87697
  if (this.interval) return;
87607
87698
  this.interval = this.schedule(() => {
@@ -87624,6 +87715,7 @@ ${key}` : key;
87624
87715
  _Ticker.fiveSecondTicks = 0;
87625
87716
  }, 1e3 * 5);
87626
87717
  }
87718
+ /** Pauses the loop while retaining callbacks for a later {@link start}. */
87627
87719
  static stop() {
87628
87720
  if (this.interval) clearInterval(this.interval);
87629
87721
  if (this.oneSecondTicksTracker) clearInterval(this.oneSecondTicksTracker);
@@ -87632,12 +87724,14 @@ ${key}` : key;
87632
87724
  this.oneSecondTicksTracker = void 0;
87633
87725
  this.fiveSecondTicksTracker = void 0;
87634
87726
  }
87727
+ /** Registers a callback, starts the loop if needed, and returns an ID for {@link remove}. */
87635
87728
  static add(tick) {
87636
87729
  this.start();
87637
87730
  const c4 = this.counter++;
87638
87731
  this._tickers.set(c4, tick);
87639
87732
  return c4;
87640
87733
  }
87734
+ /** Removes a callback by ID and stops the timers when no callbacks remain. */
87641
87735
  static remove(c4) {
87642
87736
  if (typeof c4 === "number") this._tickers.delete(c4);
87643
87737
  if (!this._tickers.size) this.stop();
@@ -87651,6 +87745,7 @@ ${key}` : key;
87651
87745
  static get tpsFiveSeconds() {
87652
87746
  return this.fiveSecondTps;
87653
87747
  }
87748
+ /** Stops the loop and removes all registered callbacks. */
87654
87749
  static dispose() {
87655
87750
  this.stop();
87656
87751
  this._tickers.clear();
@@ -87708,6 +87803,7 @@ ${key}` : key;
87708
87803
  }
87709
87804
  };
87710
87805
  }
87806
+ /** Copies pixels for a texture variable from its current atlas rectangle. */
87711
87807
  getData(texture) {
87712
87808
  const pos = this.positions[texture];
87713
87809
  const size = this.sizes[texture];
@@ -87991,6 +88087,7 @@ ${key}` : key;
87991
88087
  }
87992
88088
  uv.needsUpdate = true;
87993
88089
  }
88090
+ /** Returns the shared atlas for a keyed, merged model, creating it on first use. */
87994
88091
  static async getAtlas(model) {
87995
88092
  const keyStr = model.key.serialize();
87996
88093
  return Caching.modelTextureAtlasCache.get(keyStr, (k4) => {
@@ -88061,6 +88158,11 @@ ${key}` : key;
88061
88158
  }
88062
88159
  return [tl, tr, bl, br];
88063
88160
  }
88161
+ /**
88162
+ * Combines model textures and animation metadata into an atlas.
88163
+ * Mapped UVs are stored on copies of the model's elements, available through the returned atlas.
88164
+ * Returns `undefined` for models without a texture map.
88165
+ */
88064
88166
  static async createAtlas(originalModel) {
88065
88167
  const textureMap = {};
88066
88168
  const metaMap = {};
@@ -88434,6 +88536,7 @@ ${key}` : key;
88434
88536
  init_MineRenderError();
88435
88537
  init_ModelTextures();
88436
88538
  Entities = class {
88539
+ /** Lists model paths in the `minecraft` namespace, including subdirectories and excluding `.json`. */
88437
88540
  static async getEntityList() {
88438
88541
  const collect = async (path) => {
88439
88542
  const prefix2 = path ? `${path}/` : "";
@@ -88451,6 +88554,7 @@ ${key}` : key;
88451
88554
  const key = new AssetKey(modelKey.namespace, path, void 0, void 0, "entity-models", ".json", isAssetKey(modelKey) ? modelKey.root : void 0);
88452
88555
  return Caching.entityModelCache.get(key.serialize(), () => AssetLoader.get(key, "json" /* JSON */));
88453
88556
  }
88557
+ /** Returns selectable geometry-layer names, or an empty list when the model is missing. */
88454
88558
  static async getLayerList(modelKey) {
88455
88559
  return Object.keys((await this.getModelFile(modelKey))?.layers ?? {});
88456
88560
  }
@@ -88458,6 +88562,15 @@ ${key}` : key;
88458
88562
  static async getPassList(modelKey) {
88459
88563
  return (await this.getModelFile(modelKey))?.passes ?? [];
88460
88564
  }
88565
+ /**
88566
+ * Loads the layers and textures to pass to {@link MineRenderScene.addEntity}.
88567
+ * By default, selects `main`, unconditional passes, and passes enabled by `options.when`.
88568
+ *
88569
+ * @param modelKey - Dataset model, such as `new BasicAssetKey("minecraft", "zombie")`.
88570
+ * @param textureKey - Texture override for the first selected layer.
88571
+ * @param options - Layer selection, conditional passes, and per-layer texture overrides.
88572
+ * @returns The selected model, or `undefined` when its dataset file is missing.
88573
+ */
88461
88574
  static async getEntity(modelKey, textureKey, options) {
88462
88575
  const model = await this.getModelFile(modelKey);
88463
88576
  if (!model) return void 0;
@@ -88503,6 +88616,7 @@ ${key}` : key;
88503
88616
  const file = await Caching.entityAnimationCache.get(key.serialize(), () => AssetLoader.get(key, "json" /* JSON */));
88504
88617
  return file?.animations;
88505
88618
  }
88619
+ /** Finds a fallback texture using the model path, its directory, and vanilla variant data. */
88506
88620
  static async resolveTexture(modelKey) {
88507
88621
  const path = isAssetKey(modelKey) ? modelKey.getFullPath() : modelKey.path;
88508
88622
  const root = isAssetKey(modelKey) ? modelKey.root : void 0;
@@ -88669,12 +88783,14 @@ ${key}` : key;
88669
88783
  this._animation = void 0;
88670
88784
  this._time = 0;
88671
88785
  }
88786
+ /** Applies the pose at an absolute playback time. Returns `false` when no clip is active. */
88672
88787
  setTime(seconds) {
88673
88788
  if (!this._animation) return false;
88674
88789
  this._time = seconds;
88675
88790
  this.apply();
88676
88791
  return true;
88677
88792
  }
88793
+ /** Advances playback by elapsed seconds multiplied by the speed passed to {@link play}. */
88678
88794
  advance(deltaSeconds) {
88679
88795
  return this.setTime(this._time + deltaSeconds * this.speed);
88680
88796
  }
@@ -88715,6 +88831,7 @@ ${key}` : key;
88715
88831
  if (!this.instanceable.isInstanceActive(this.index, this)) throw new MineRenderError("Instance has been removed");
88716
88832
  return this.instanceable;
88717
88833
  }
88834
+ /** Releases this placement's slot for reuse. Repeated calls have no effect. */
88718
88835
  removeFromScene() {
88719
88836
  if (this.instanceable.isInstanceActive(this.index, this)) this.instanceable.removeInstanceAt(this.index);
88720
88837
  }
@@ -88727,9 +88844,11 @@ ${key}` : key;
88727
88844
  setMatrix(matrix) {
88728
88845
  this.activeInstanceable.setMatrixAt(this.index, matrix);
88729
88846
  }
88847
+ /** Hides or restores this placement while preserving its transform and allocated slot. */
88730
88848
  setVisible(visible) {
88731
88849
  this.activeInstanceable.setInstanceVisibleAt(this.index, visible);
88732
88850
  }
88851
+ /** Updates the supplied transform components. Positions use scene units and rotations use radians. */
88733
88852
  setPositionRotationScale(position, rotation, scale) {
88734
88853
  this.activeInstanceable.setPositionRotationScaleAt(this.index, position, rotation, scale);
88735
88854
  }
@@ -88801,6 +88920,7 @@ ${key}` : key;
88801
88920
  }
88802
88921
  async init() {
88803
88922
  }
88923
+ /** Marks ancestor scenes for redraw and emits a `change` event. */
88804
88924
  notifyDirty() {
88805
88925
  this.traverseAncestors((parent) => {
88806
88926
  const scene = parent;
@@ -88836,15 +88956,17 @@ ${key}` : key;
88836
88956
  return obj;
88837
88957
  }
88838
88958
  /**
88839
- * Get a group by its name
88959
+ * Finds a named part, such as `head`, without the internal `group:` prefix.
88960
+ * Returns `undefined` when the group does not exist.
88840
88961
  */
88841
88962
  getGroupByName(name2) {
88842
88963
  return this.getObjectByName(`group:${name2}`);
88843
88964
  }
88844
88965
  /**
88845
- * Toggle visibility of a group
88846
- * @param name name of the group
88847
- * @param visible set the visibility directly, if not set toggles it
88966
+ * Changes a named group's visibility and requests a redraw.
88967
+ * @param name - Part name without the `group:` prefix.
88968
+ * @param visible - Visibility to assign. Omit it to toggle the current value.
88969
+ * @returns The resulting visibility, or `false` if the group does not exist.
88848
88970
  */
88849
88971
  toggleGroupVisibility(name2, visible) {
88850
88972
  return this.toggleObjectVisibility(this.getGroupByName(name2), visible);
@@ -88895,15 +89017,16 @@ ${key}` : key;
88895
89017
  return mesh;
88896
89018
  }
88897
89019
  /**
88898
- * Get a mesh by its name
89020
+ * Finds a named mesh without the internal `mesh:` prefix, or returns `undefined`.
88899
89021
  */
88900
89022
  getMeshByName(name2) {
88901
89023
  return this.getObjectByName(`mesh:${name2}`);
88902
89024
  }
88903
89025
  /**
88904
- * Toggle visibility of a mesh
88905
- * @param name name of the mesh
88906
- * @param visible set the visibility directly, if not set toggles it
89026
+ * Changes a named mesh's visibility and requests a redraw.
89027
+ * @param name - Mesh name without the `mesh:` prefix.
89028
+ * @param visible - Visibility to assign. Omit it to toggle the current value.
89029
+ * @returns The resulting visibility, or `false` if the mesh does not exist.
88907
89030
  */
88908
89031
  toggleMeshVisibility(name2, visible) {
88909
89032
  return this.toggleObjectVisibility(this.getMeshByName(name2), visible);
@@ -88949,12 +89072,14 @@ ${key}` : key;
88949
89072
  get isInstanced() {
88950
89073
  return this._isInstanced;
88951
89074
  }
89075
+ /** Number of live placements, excluding released instance slots. */
88952
89076
  get instanceCounter() {
88953
89077
  return this._instanceCounter;
88954
89078
  }
88955
89079
  constructInstanceReference(i4) {
88956
89080
  return new InstanceReference(this, i4);
88957
89081
  }
89082
+ /** Allocates a placement of this instanced object, reusing a released slot when available. */
88958
89083
  nextInstance() {
88959
89084
  const mesh = this.instanceMesh;
88960
89085
  if (!mesh) throw new MineRenderError("Object is not instanced");
@@ -89101,6 +89226,7 @@ ${key}` : key;
89101
89226
  vector.setFromMatrixScale(matrix);
89102
89227
  return vector;
89103
89228
  }
89229
+ /** Updates supplied transform components. For a shared model, affects every live instance. */
89104
89230
  setPositionRotationScale(position, rotation, scale) {
89105
89231
  if (this.isInstanced) {
89106
89232
  for (const i4 of this.activeInstanceIndices()) {
@@ -89119,6 +89245,7 @@ ${key}` : key;
89119
89245
  }
89120
89246
  this.notifyDirty();
89121
89247
  }
89248
+ /** Sets position in scene units. For a shared model, updates every live instance. */
89122
89249
  setPosition(position) {
89123
89250
  if (this.isInstanced) {
89124
89251
  for (const i4 of this.activeInstanceIndices()) {
@@ -89136,6 +89263,7 @@ ${key}` : key;
89136
89263
  return this.position;
89137
89264
  }
89138
89265
  }
89266
+ /** Sets rotation in radians. For a shared model, updates every live instance. */
89139
89267
  setRotation(rotation) {
89140
89268
  if (this.isInstanced) {
89141
89269
  for (const i4 of this.activeInstanceIndices()) {
@@ -89153,6 +89281,7 @@ ${key}` : key;
89153
89281
  return this.rotation;
89154
89282
  }
89155
89283
  }
89284
+ /** Sets scale factors. For a shared model, updates every live instance. */
89156
89285
  setScale(scale) {
89157
89286
  if (this.isInstanced) {
89158
89287
  for (const i4 of this.activeInstanceIndices()) {
@@ -89190,6 +89319,7 @@ ${key}` : key;
89190
89319
  this.notifyDirty();
89191
89320
  super.dispose();
89192
89321
  }
89322
+ /** Releases instance slots and removes children, disposing children that implement Disposable. */
89193
89323
  disposeAndRemoveAllChildren() {
89194
89324
  if (this.instanceMesh) {
89195
89325
  if (this._scene) this._scene.stats.instanceCount -= this.instanceReferences.size;
@@ -89212,6 +89342,7 @@ ${key}` : key;
89212
89342
  }
89213
89343
  this.notifyDirty();
89214
89344
  }
89345
+ /** Detaches the object from its parent and requests a redraw. */
89215
89346
  removeFromScene() {
89216
89347
  this.notifyDirty();
89217
89348
  this.removeFromParent();
@@ -89370,12 +89501,15 @@ ${key}` : key;
89370
89501
  if (this.animationPlayers.length) this.notifyDirty();
89371
89502
  }
89372
89503
  //</editor-fold>
89504
+ /** Finds a selected draw by its layer key, such as `main` or `main#2`, or returns `undefined`. */
89373
89505
  getLayerGroup(name2) {
89374
89506
  return super.getGroupByName(`layer:${name2}`);
89375
89507
  }
89508
+ /** Finds a part name without `group:`. Supply `layerName` to restrict the search to one draw. */
89376
89509
  getGroupByName(name2, layerName) {
89377
89510
  return layerName === void 0 ? super.getGroupByName(name2) : this.getLayerGroup(layerName)?.getObjectByName(`group:${name2}`);
89378
89511
  }
89512
+ /** Finds a mesh name without `mesh:`. Supply `layerName` to restrict the search to one draw. */
89379
89513
  getMeshByName(name2, layerName) {
89380
89514
  return layerName === void 0 ? super.getMeshByName(name2) : this.getLayerGroup(layerName)?.getObjectByName(`mesh:${name2}`);
89381
89515
  }
@@ -90044,6 +90178,7 @@ ${key}` : key;
90044
90178
  init_three_module();
90045
90179
  init_CubeFace();
90046
90180
  ModelCulling = class {
90181
+ /** Rotates a world-direction bit mask into model space. Bits follow {@link CUBE_FACES}. */
90047
90182
  static toLocalMask(worldMask, rotation) {
90048
90183
  let localMask = 0;
90049
90184
  for (const [localFace, offset] of CUBE_FACE_OFFSETS.entries()) {
@@ -90054,6 +90189,7 @@ ${key}` : key;
90054
90189
  }
90055
90190
  return localMask;
90056
90191
  }
90192
+ /** Whether a model fills one block with opaque faces and can hide adjacent block faces. */
90057
90193
  static isOpaqueFullCube(atlas) {
90058
90194
  if (!atlas || atlas.hasTransparency !== false || atlas.model.elements?.length !== 1) return false;
90059
90195
  const element = atlas.model.elements[0];
@@ -93935,6 +94071,7 @@ ${shader.fragmentShader}`.replace(
93935
94071
  static createBox(key) {
93936
94072
  return new Mesh(Geometries.getBox(key.geometry), Materials.getImage(key.material));
93937
94073
  }
94074
+ /** Returns a shared Mesh object. Use {@link createBox} for a mesh with its own transform and parent. */
93938
94075
  static getBox(key) {
93939
94076
  const keyStr = serializeMeshKey(key);
93940
94077
  return Caching.boxMeshCache.get(keyStr, (k4) => {
@@ -94083,6 +94220,7 @@ ${shader.fragmentShader}`.replace(
94083
94220
  init_ModelTextures();
94084
94221
  init_Caching();
94085
94222
  var Fonts = class {
94223
+ /** Combines font definitions in source-priority order. Unsupported Unihex and TrueType providers are skipped. */
94086
94224
  static async get(key = "minecraft:default") {
94087
94225
  const fontKey = typeof key === "string" ? AssetKey.parse("font", key) : key;
94088
94226
  return await Caching.fontCache.get(fontKey.serialize(), () => this.load(fontKey, []));
@@ -97334,6 +97472,13 @@ property list uchar int vertex_index
97334
97472
  });
97335
97473
  return layers;
97336
97474
  }
97475
+ /**
97476
+ * Calculates a slot's top-left position in GUI pixels.
97477
+ * @param slot - Zero-based slot index, or `[column, row]`.
97478
+ * @param origin - Position of the first slot.
97479
+ * @param offset - Horizontal and vertical spacing between slot origins, in pixels.
97480
+ * @param rowSize - Slots per row when `slot` is an index.
97481
+ */
97337
97482
  static inventorySlot(slot, origin = [0, 0], offset = [18, 18], rowSize = 9) {
97338
97483
  const [column, row] = typeof slot === "number" ? [slot % rowSize, Math.floor(slot / rowSize)] : slot;
97339
97484
  return [origin[0] + column * offset[0], origin[1] + row * offset[1]];
@@ -98018,6 +98163,7 @@ property list uchar int vertex_index
98018
98163
  appendTo(el) {
98019
98164
  el.append(this.statsContainer);
98020
98165
  }
98166
+ /** Stops the refresh timer and removes the panel from the page. */
98021
98167
  dispose() {
98022
98168
  clearInterval(this.interval);
98023
98169
  this.interval = void 0;
@@ -98050,6 +98196,7 @@ property list uchar int vertex_index
98050
98196
  this.isInstanceManager = true;
98051
98197
  this.instanceCache = {};
98052
98198
  }
98199
+ /** Allocates a new placement of a cached model, or returns `undefined` if the key is unknown. */
98053
98200
  async get(key) {
98054
98201
  if (key in this.instanceCache) {
98055
98202
  console.debug(p12, "key in cache", key);
@@ -98057,6 +98204,7 @@ property list uchar int vertex_index
98057
98204
  }
98058
98205
  return void 0;
98059
98206
  }
98207
+ /** Allocates a placement, calling the supplier once when the shared model is first needed. */
98060
98208
  async getOrCreate(key, supplier) {
98061
98209
  if (key in this.instanceCache) {
98062
98210
  return await this.get(key);
@@ -98073,6 +98221,7 @@ property list uchar int vertex_index
98073
98221
  throw error2;
98074
98222
  }
98075
98223
  }
98224
+ /** Forgets cached models without disposing them or releasing their existing placements. */
98076
98225
  reset() {
98077
98226
  for (let instanceCacheKey in this.instanceCache) {
98078
98227
  delete this.instanceCache[instanceCacheKey];
@@ -98161,6 +98310,7 @@ property list uchar int vertex_index
98161
98310
  });
98162
98311
  }
98163
98312
  var BlockStateResolver = class {
98313
+ /** Loads vanilla property defaults, falling back to preview values inferred from the blockstate file. */
98164
98314
  static async defaults(blockState) {
98165
98315
  const defaults = blockState.key ? await BlockStates.getDefaultState(blockState.key) : void 0;
98166
98316
  const state = {};
@@ -98180,9 +98330,11 @@ property list uchar int vertex_index
98180
98330
  }
98181
98331
  return state;
98182
98332
  }
98333
+ /** Selects matching models. Supply `choose` to control selection within each alternatives array. */
98183
98334
  static select(blockState, state, choose = this.choose) {
98184
98335
  return this.matching(blockState, state).map(choose);
98185
98336
  }
98337
+ /** Returns matching model groups before choosing weighted alternatives. */
98186
98338
  static matching(blockState, state) {
98187
98339
  const out = [];
98188
98340
  if (blockState.variants) {
@@ -98206,6 +98358,7 @@ property list uchar int vertex_index
98206
98358
  }
98207
98359
  return out;
98208
98360
  }
98361
+ /** Selects a random alternative using positive integer weights, each defaulting to 1. */
98209
98362
  static choose(variants) {
98210
98363
  if (!Array.isArray(variants)) return variants;
98211
98364
  if (!variants.length) throw new MineRenderError("Blockstate variant arrays must not be empty");
@@ -98223,6 +98376,7 @@ property list uchar int vertex_index
98223
98376
  }
98224
98377
  return variants[variants.length - 1];
98225
98378
  }
98379
+ /** Converts blockstate rotations in degrees into the Euler rotation used by model rendering. */
98226
98380
  static rotation(variant) {
98227
98381
  const rotation = new Euler();
98228
98382
  if (typeof variant.x !== "undefined") {
@@ -98515,6 +98669,7 @@ property list uchar int vertex_index
98515
98669
  }
98516
98670
  this.notifyDirty();
98517
98671
  }
98672
+ /** Selected property values. Use {@link setState} to change properties and rebuild the rendered models. */
98518
98673
  get state() {
98519
98674
  return this._state;
98520
98675
  }
@@ -98614,6 +98769,7 @@ property list uchar int vertex_index
98614
98769
  obj.setPosition(this.position);
98615
98770
  return obj;
98616
98771
  }
98772
+ /** Clears selected properties and rebuilds models without reapplying property defaults. */
98617
98773
  async resetState() {
98618
98774
  this._previousState = this._state;
98619
98775
  this._state = {};
@@ -100536,6 +100692,11 @@ property list uchar int vertex_index
100536
100692
  init_process2();
100537
100693
  init_MineRenderError();
100538
100694
  var StructureParser = class {
100695
+ /**
100696
+ * Parses decoded NBT, omitting air blocks.
100697
+ * @param _nbt - Structure data decoded by {@link NBTHelper.fromBuffer}.
100698
+ * @param paletteIndex - Palette to select when the structure has several. Defaults to 0.
100699
+ */
100539
100700
  static async parse(_nbt, paletteIndex) {
100540
100701
  const nbt = _nbt.value;
100541
100702
  let palette;
@@ -101399,6 +101560,7 @@ property list uchar int vertex_index
101399
101560
  // src/skin/SkinTextures.ts
101400
101561
  init_Textures();
101401
101562
  var SkinTextures = class {
101563
+ /** Loads a skin URL. Pass `legacy` to override layout detection from the image dimensions. */
101402
101564
  static async get(src, legacy) {
101403
101565
  const image = await SkinImage.getData(src);
101404
101566
  const scale = image.width / 64;
@@ -101575,6 +101737,14 @@ property list uchar int vertex_index
101575
101737
  }
101576
101738
  }
101577
101739
  }
101740
+ /**
101741
+ * Loads a skin texture, detecting slim arms and legacy layouts by default.
101742
+ * To override detection, set `slim` or `legacy` in the options passed to
101743
+ * `new SkinObject(options)` or `scene.addSkin(src, options)`.
101744
+ * Use {@link setSlim} or {@link setLegacy} to change these settings later.
101745
+ *
101746
+ * @param src - URL of the skin texture.
101747
+ */
101578
101748
  async setSkinTexture(src) {
101579
101749
  if (typeof src === "undefined") return;
101580
101750
  this.skinTextureSrc = src;
@@ -101723,6 +101893,7 @@ property list uchar int vertex_index
101723
101893
  this.stats.sceneObjectCount += change;
101724
101894
  }
101725
101895
  }
101896
+ /** Initializes each object before attaching it to the scene. */
101726
101897
  async initAndAdd(...object2) {
101727
101898
  this.dirty = true;
101728
101899
  for (let obj of object2) {
@@ -101758,13 +101929,33 @@ property list uchar int vertex_index
101758
101929
  return obj;
101759
101930
  }
101760
101931
  }
101932
+ /**
101933
+ * Adds a model loaded with {@link Models.getMerged}.
101934
+ * Set `options.instanceMeshes` to `false` to create a separate ModelObject.
101935
+ *
101936
+ * @param parent - Object to attach the model to. Defaults to this scene.
101937
+ * @returns The model, or a reference to one placement of a shared model.
101938
+ */
101761
101939
  async addModel(model, options, parent = this) {
101762
101940
  options = { ...options, tints: await ItemTints.get(model, options?.tints) };
101763
101941
  return this.addSceneObject(model, () => new ModelObject(model, options), options, parent);
101764
101942
  }
101943
+ /**
101944
+ * Adds the models selected by a blockstate loaded with {@link BlockStates.get}.
101945
+ * Set `options.initialState` to choose block properties such as `facing` or `axis`.
101946
+ * Use the returned object's `setPosition` method to move all of its model parts.
101947
+ */
101765
101948
  async addBlock(blockState, options, parent = this) {
101766
101949
  return this.addSceneObject(blockState, () => new BlockObject(blockState, options), options, parent);
101767
101950
  }
101951
+ /**
101952
+ * Loads a skin and adds an initialized player model.
101953
+ *
101954
+ * @param skin - Texture URL, such as one returned by {@link Skins.fromUuidOrUsername}.
101955
+ * Omit it to assign a texture later with {@link SkinObject.setSkinTexture}.
101956
+ * @param options - Player settings, including `slim` and `legacy` detection overrides.
101957
+ * @param parent - Object to attach the player to. Defaults to this scene.
101958
+ */
101768
101959
  async addSkin(skin, options, parent = this) {
101769
101960
  this.dirty = true;
101770
101961
  const obj = new SkinObject(options);
@@ -101776,9 +101967,14 @@ property list uchar int vertex_index
101776
101967
  parent.add(obj);
101777
101968
  return obj;
101778
101969
  }
101970
+ /** Adds an entity loaded with {@link Entities.getEntity}, using its selected layers and textures. */
101779
101971
  async addEntity(entity, options, parent = this) {
101780
101972
  return this.addSceneObject(entity, () => new EntityObject(entity, options), options, parent);
101781
101973
  }
101974
+ /**
101975
+ * Adds GUI layers in draw order. One GUI pixel equals one scene unit.
101976
+ * Layer positions start at the top left, with positive GUI y pointing down.
101977
+ */
101782
101978
  async addGui(layers, options, parent = this) {
101783
101979
  const obj = new GuiObject(layers, options);
101784
101980
  obj.scene = this;
@@ -104580,6 +104776,7 @@ gl_FragDepth=readDepth(vUv);
104580
104776
  get element() {
104581
104777
  return this._element;
104582
104778
  }
104779
+ /** Attaches the canvas to an element and sizes it to that element's dimensions. */
104583
104780
  appendTo(element) {
104584
104781
  if (this._disposed) return;
104585
104782
  this._element = element;
@@ -104607,6 +104804,7 @@ gl_FragDepth=readDepth(vUv);
104607
104804
  events.add(changeEvent2);
104608
104805
  dispatcher.addEventListener(changeEvent2, this._changeListener);
104609
104806
  }
104807
+ /** Updates the camera and canvas size. Width and height are in CSS pixels. */
104610
104808
  resize(width, height) {
104611
104809
  if (this._disposed) return;
104612
104810
  if (isPerspectiveCamera(this.camera)) {
@@ -104645,12 +104843,14 @@ gl_FragDepth=readDepth(vUv);
104645
104843
  if (this._frameCallbacks.get(callback) === subscription) this._frameCallbacks.delete(callback);
104646
104844
  };
104647
104845
  }
104846
+ /** Starts or resumes the animation loop and registered frame callbacks. */
104648
104847
  start() {
104649
104848
  if (this._disposed) return;
104650
104849
  this.stop();
104651
104850
  this._running = true;
104652
104851
  if (!this._inAnimationLoop) this.renderer.setAnimationLoop(this._animationLoop);
104653
104852
  }
104853
+ /** Pauses rendering and frame callbacks. Call {@link start} to resume. */
104654
104854
  stop() {
104655
104855
  if (this._disposed) return;
104656
104856
  this._running = false;
@@ -104759,12 +104959,15 @@ gl_FragDepth=readDepth(vUv);
104759
104959
  const canvas = trim ? trimCanvas(this.renderer.domElement) : this.renderer.domElement;
104760
104960
  return canvas.toDataURL(mime, quality);
104761
104961
  }
104962
+ /** Exports visible scene meshes as OBJ text, without texture images. */
104762
104963
  toObj() {
104763
104964
  return SceneExporter.toObj(this.scene);
104764
104965
  }
104966
+ /** Exports visible scene meshes as PLY. Set `options.binary` for an ArrayBuffer. */
104765
104967
  toPLY(options) {
104766
104968
  return SceneExporter.toPLY(this.scene, options);
104767
104969
  }
104970
+ /** Exports a static textured scene in the browser. Set `options.binary` for GLB output. */
104768
104971
  toGLTF(options) {
104769
104972
  return SceneExporter.toGLTF(this.scene, options);
104770
104973
  }
@@ -104859,12 +105062,14 @@ gl_FragDepth=readDepth(vUv);
104859
105062
  init_Requests();
104860
105063
  var Skins = class {
104861
105064
  //<editor-fold desc="Skins">
105065
+ /** Returns a skin URL for {@link MineRenderScene.addSkin}, or `undefined` if name lookup fails. */
104862
105066
  static async fromUuidOrUsername(uuidOrUsername) {
104863
105067
  if (uuidOrUsername.length === 32 || uuidOrUsername.length === 36) {
104864
105068
  return this.fromUuid(uuidOrUsername);
104865
105069
  }
104866
105070
  return this.fromUsername(uuidOrUsername);
104867
105071
  }
105072
+ /** Builds a proxy URL for a UUID without downloading or checking the skin. */
104868
105073
  static async fromUuid(uuid) {
104869
105074
  return this.getMcProxySkinUrl(uuid);
104870
105075
  }
@@ -104876,6 +105081,7 @@ gl_FragDepth=readDepth(vUv);
104876
105081
  return void 0;
104877
105082
  });
104878
105083
  }
105084
+ /** Looks up a saved MineSkin skin and returns its texture URL, or `undefined` on lookup failure. */
104879
105085
  static async fromMineSkin(mineskinId) {
104880
105086
  return this.getMineSkin(mineskinId).then((mineskin) => {
104881
105087
  if (mineskin) {
@@ -104886,12 +105092,14 @@ gl_FragDepth=readDepth(vUv);
104886
105092
  }
104887
105093
  //</editor-fold>
104888
105094
  //<editor-fold desc="Capes">
105095
+ /** Resolves a player's Minecraft cape URL for {@link SkinObject.setCapeTexture}. */
104889
105096
  static async capeFromUuidOrUsername(uuidOrUsername) {
104890
105097
  if (uuidOrUsername.length === 32 || uuidOrUsername.length === 36) {
104891
105098
  return this.capeFromUuid(uuidOrUsername);
104892
105099
  }
104893
105100
  return this.capeFromUsername(uuidOrUsername);
104894
105101
  }
105102
+ /** Builds a proxy URL without checking whether the player has a cape. */
104895
105103
  static async capeFromUuid(uuid) {
104896
105104
  return this.getMcProxyCapeUrl(uuid);
104897
105105
  }
@@ -105068,16 +105276,19 @@ gl_FragDepth=readDepth(vUv);
105068
105276
  this.freeIds = [];
105069
105277
  this.nbt = /* @__PURE__ */ new Map();
105070
105278
  }
105279
+ /** Returns a detached copy of a cell, or `undefined` for air. Indices range from 0 to 4095. */
105071
105280
  get(index) {
105072
105281
  _ChunkData.validateIndex(index);
105073
105282
  const entry = this.palette[this.indices[index]];
105074
105283
  return entry ? _ChunkData.copyBlock(entry.state, this.nbt.get(index)) : void 0;
105075
105284
  }
105285
+ /** Captures a cell's data and returns a copy-producing reader that survives later cell changes. */
105076
105286
  snapshot(index) {
105077
105287
  _ChunkData.validateIndex(index);
105078
105288
  const entry = this.palette[this.indices[index]];
105079
105289
  return entry ? _ChunkData.copyBlock.bind(void 0, entry.state, this.nbt.get(index)) : void 0;
105080
105290
  }
105291
+ /** Copies block data into a cell. An omitted block or an air block clears the cell. */
105081
105292
  set(index, block) {
105082
105293
  _ChunkData.validateIndex(index);
105083
105294
  let state;
@@ -105142,15 +105353,23 @@ gl_FragDepth=readDepth(vUv);
105142
105353
 
105143
105354
  // src/world/AnvilParser.ts
105144
105355
  var AnvilParser = class {
105356
+ /** Lists occupied chunk positions within the region, using local coordinates from 0 to 31. */
105145
105357
  static getChunkList(data) {
105146
105358
  return this.locations(this.bytes(data)).map(({ x: x4, z: z4 }) => ({ x: x4, z: z4 }));
105147
105359
  }
105360
+ /** Decodes all stored chunks. Gzip, zlib, and uncompressed payloads are supported. */
105148
105361
  static async parse(data) {
105149
105362
  const bytes = this.bytes(data);
105150
105363
  const chunks = [];
105151
105364
  for (const location of this.locations(bytes)) chunks.push(await this.readChunk(bytes, location));
105152
105365
  return { chunks };
105153
105366
  }
105367
+ /**
105368
+ * Decodes one chunk for {@link MineRenderWorld.placeChunk}.
105369
+ * @param localX - Chunk x within the region, from 0 to 31.
105370
+ * @param localZ - Chunk z within the region, from 0 to 31.
105371
+ * @returns The chunk with absolute coordinates, or `undefined` if the region has no chunk there.
105372
+ */
105154
105373
  static async parseChunk(data, localX, localZ) {
105155
105374
  if (![localX, localZ].every((value) => Number.isInteger(value) && value >= 0 && value < 32)) {
105156
105375
  throw new RangeError("Region-local chunk coordinates must be integers from 0 to 31");
@@ -105369,6 +105588,7 @@ gl_FragDepth=readDepth(vUv);
105369
105588
  this.templates = /* @__PURE__ */ new Set();
105370
105589
  if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError("maxAtlasSize must be a positive integer");
105371
105590
  }
105591
+ /** Returns a cube template, or `undefined` when the block requires an individual render object. */
105372
105592
  async get(blockState, properties = {}) {
105373
105593
  if (!blockState.variants || blockState.multipart) return void 0;
105374
105594
  let states = this.states.get(blockState);
@@ -105422,6 +105642,7 @@ gl_FragDepth=readDepth(vUv);
105422
105642
  }
105423
105643
  return { variants, templates };
105424
105644
  }
105645
+ /** Disposes prepared geometry and clears this world's template caches. */
105425
105646
  clear() {
105426
105647
  for (const template of this.templates) template.geometry.dispose();
105427
105648
  this.templates.clear();
@@ -105472,6 +105693,13 @@ gl_FragDepth=readDepth(vUv);
105472
105693
  this.validatePosBounds(posOrX);
105473
105694
  await this.getChunkAt(posOrX)?.setBlockVisibleAt(posOrX, yOrVisible);
105474
105695
  }
105696
+ /**
105697
+ * Places a structure's blocks at their stored positions, then refreshes neighboring faces.
105698
+ * Entity NBT is retained by the structure but is not rendered.
105699
+ *
105700
+ * @param useBatches - Uses bounded batches by default. Set to `false` for sequential placement.
105701
+ * @param executor - Optional queue for batched placement. The caller remains responsible for stopping it.
105702
+ */
105475
105703
  async placeMultiBlock(multiblock, useBatches = true, executor) {
105476
105704
  const changes = /* @__PURE__ */ new Map();
105477
105705
  try {
@@ -105523,13 +105751,7 @@ gl_FragDepth=readDepth(vUv);
105523
105751
  async placeChunk(chunk, executor) {
105524
105752
  const changes = /* @__PURE__ */ new Map();
105525
105753
  try {
105526
- const previous = [...this._chunks.entries()].filter(([, section]) => section.x === chunk.x && section.z === chunk.z);
105527
- for (const [key, section] of previous) {
105528
- this._chunks.delete(key);
105529
- await section.clear(async (positions) => {
105530
- for (const pos of positions) changes.set(pos.toArray().join(","), pos);
105531
- });
105532
- }
105754
+ await this.clearChunkColumn(chunk.x, chunk.z, changes);
105533
105755
  for (const section of chunk.sections) {
105534
105756
  const blocks = [];
105535
105757
  for (let index = 0; index < 4096; index++) {
@@ -105549,6 +105771,32 @@ gl_FragDepth=readDepth(vUv);
105549
105771
  await this.updateCulling([...changes.values()]);
105550
105772
  }
105551
105773
  }
105774
+ /**
105775
+ * Removes all sections at integer chunk-column coordinates, then refreshes neighboring faces and fluids.
105776
+ * Coordinates match AnvilChunk.x/z, not block positions. Missing columns are ignored.
105777
+ */
105778
+ async unloadChunkColumn(x4, z4) {
105779
+ if (!Number.isInteger(x4) || !Number.isInteger(z4)) {
105780
+ throw new RangeError("Chunk column coordinates must be integers");
105781
+ }
105782
+ await this.culling;
105783
+ const changes = /* @__PURE__ */ new Map();
105784
+ try {
105785
+ await this.clearChunkColumn(x4, z4, changes);
105786
+ } finally {
105787
+ await this.updateCulling([...changes.values()]);
105788
+ }
105789
+ }
105790
+ async clearChunkColumn(x4, z4, changes) {
105791
+ const previous = [...this._chunks.entries()].filter(([, section]) => section.x === x4 && section.z === z4);
105792
+ for (const [key, section] of previous) {
105793
+ this._chunks.delete(key);
105794
+ await section.clear(async (positions) => {
105795
+ for (const pos of positions) changes.set(pos.toArray().join(","), pos);
105796
+ });
105797
+ }
105798
+ }
105799
+ /** Removes all chunks and releases their block placements and section meshes. */
105552
105800
  async clear() {
105553
105801
  await this.culling;
105554
105802
  const chunks = [...this._chunks.values()];
@@ -105634,9 +105882,11 @@ gl_FragDepth=readDepth(vUv);
105634
105882
  }
105635
105883
  return chunk;
105636
105884
  }
105885
+ /** Returns the loaded chunk containing a world block position, without creating a chunk. */
105637
105886
  getChunkAt(pos) {
105638
105887
  return this._chunks.get(this.worldPosToChunkKey(pos));
105639
105888
  }
105889
+ /** Converts block coordinates to scene units by multiplying each component by 16. */
105640
105890
  static worldToScenePosition(pos) {
105641
105891
  return new Vector3(
105642
105892
  pos.x * 16,
@@ -105644,6 +105894,7 @@ gl_FragDepth=readDepth(vUv);
105644
105894
  pos.z * 16
105645
105895
  );
105646
105896
  }
105897
+ /** Converts scene units to block coordinates without rounding to an integer block. */
105647
105898
  static sceneToWorldPosition(pos) {
105648
105899
  return new Vector3(
105649
105900
  pos.x / 16,
@@ -105679,6 +105930,7 @@ gl_FragDepth=readDepth(vUv);
105679
105930
  super(...arguments);
105680
105931
  this.ownedMeshes = [];
105681
105932
  }
105933
+ /** Builds section-local meshes from visible cube faces. `maxAtlasSize` limits each atlas dimension in pixels. */
105682
105934
  static build(entries, maxAtlasSize = 2048) {
105683
105935
  if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError("Section atlas size must be a positive integer");
105684
105936
  const visible = entries.filter((entry) => entry.template.cullFaces.some((direction) => !(entry.cullMask & direction)));
@@ -105823,7 +106075,7 @@ gl_FragDepth=readDepth(vUv);
105823
106075
  return this.setBlockInChunkAt(pos, block, worldPos);
105824
106076
  }
105825
106077
  /**
105826
- * Set a block at integer chunk-local coordinates from 0 to 15.
106078
+ * Places a block at integer chunk-local coordinates from 0 to 15.
105827
106079
  */
105828
106080
  async setBlockInChunkAt(pos, block, worldPos, onBlocksChanged = this.onBlocksChanged) {
105829
106081
  if (typeof worldPos === "undefined") {
@@ -105872,6 +106124,7 @@ gl_FragDepth=readDepth(vUv);
105872
106124
  await onBlocksChanged?.([worldPos]);
105873
106125
  }
105874
106126
  }
106127
+ /** Changes visibility at world block coordinates while preserving the block's data. */
105875
106128
  async setBlockVisibleAt(pos, visible) {
105876
106129
  const index = _Chunk.chunkPosToBlockIndex(this.worldPosToChunkPos(pos));
105877
106130
  const block = this.renderedBlocks.get(index);
@@ -105925,6 +106178,7 @@ gl_FragDepth=readDepth(vUv);
105925
106178
  this.scene.dirty = true;
105926
106179
  this.meshDirty = false;
105927
106180
  }
106181
+ /** Removes stored blocks and their render objects, then notifies the owning world of changed positions. */
105928
106182
  async clear(onBlocksChanged = this.onBlocksChanged) {
105929
106183
  const positions = [...this.renderedBlocks.keys()].map((index) => this.chunkPosToWorldPos(
105930
106184
  new Vector3(index % 16, Math.floor(index / 256), Math.floor(index / 16) % 16)
@@ -105945,6 +106199,7 @@ gl_FragDepth=readDepth(vUv);
105945
106199
  static isAir(block) {
105946
106200
  return ChunkData.isAir(block);
105947
106201
  }
106202
+ /** Maps chunk-local coordinates from 0 to 15 to a storage index, with x varying fastest, then z, then y. */
105948
106203
  static chunkPosToBlockIndex(pos) {
105949
106204
  if ([pos.x, pos.y, pos.z].some((value) => !Number.isInteger(value) || value < 0 || value >= 16)) {
105950
106205
  throw new RangeError("Block coordinates must be integers from 0 to 15 within a chunk");