minerender 2.1.0-alpha.3 → 2.1.0-alpha.31

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.
@@ -23,14 +23,6 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
23
23
  isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
24
24
  mod
25
25
  ));
26
- var __decorateClass = (decorators, target, key, kind) => {
27
- var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
28
- for (var i = decorators.length - 1, decorator; i >= 0; i--)
29
- if (decorator = decorators[i])
30
- result = (kind ? decorator(target, key, result) : decorator(result)) || result;
31
- if (kind && result) __defProp(target, key, result);
32
- return result;
33
- };
34
26
 
35
27
  // ../../node_modules/ts-deepmerge/dist/index.js
36
28
  var require_dist = __commonJS({
@@ -40,8 +32,8 @@ var require_dist = __commonJS({
40
32
  __assign = Object.assign || function(t) {
41
33
  for (var s, i = 1, n = arguments.length; i < n; i++) {
42
34
  s = arguments[i];
43
- for (var p13 in s) if (Object.prototype.hasOwnProperty.call(s, p13))
44
- t[p13] = s[p13];
35
+ for (var p12 in s) if (Object.prototype.hasOwnProperty.call(s, p12))
36
+ t[p12] = s[p12];
45
37
  }
46
38
  return t;
47
39
  };
@@ -85,7 +77,7 @@ var require_dist = __commonJS({
85
77
  return false;
86
78
  };
87
79
  var PROTECTED_KEYS = ["__proto__"];
88
- var merge11 = function() {
80
+ var merge10 = function() {
89
81
  var objects = [];
90
82
  for (var _i = 0; _i < arguments.length; _i++) {
91
83
  objects[_i] = arguments[_i];
@@ -96,9 +88,9 @@ var require_dist = __commonJS({
96
88
  return;
97
89
  }
98
90
  if (Array.isArray(result[key]) && Array.isArray(current[key])) {
99
- result[key] = merge11.options.mergeArrays ? Array.from(new Set(result[key].concat(current[key]))) : current[key];
91
+ result[key] = merge10.options.mergeArrays ? Array.from(new Set(result[key].concat(current[key]))) : current[key];
100
92
  } else if (isObject(result[key]) && isObject(current[key])) {
101
- result[key] = merge11(result[key], current[key]);
93
+ result[key] = merge10(result[key], current[key]);
102
94
  } else {
103
95
  result[key] = current[key];
104
96
  }
@@ -109,18 +101,18 @@ var require_dist = __commonJS({
109
101
  var defaultOptions = {
110
102
  mergeArrays: true
111
103
  };
112
- merge11.options = defaultOptions;
113
- merge11.withOptions = function(options) {
104
+ merge10.options = defaultOptions;
105
+ merge10.withOptions = function(options) {
114
106
  var objects = [];
115
107
  for (var _i = 1; _i < arguments.length; _i++) {
116
108
  objects[_i - 1] = arguments[_i];
117
109
  }
118
- merge11.options = __assign({ mergeArrays: true }, options);
119
- var result = merge11.apply(void 0, __spreadArray([], __read(objects), false));
120
- merge11.options = defaultOptions;
110
+ merge10.options = __assign({ mergeArrays: true }, options);
111
+ var result = merge10.apply(void 0, __spreadArray([], __read(objects), false));
112
+ merge10.options = defaultOptions;
121
113
  return result;
122
114
  };
123
- exports.default = merge11;
115
+ exports.default = merge10;
124
116
  }
125
117
  });
126
118
 
@@ -149,25 +141,29 @@ var Env = class {
149
141
  };
150
142
 
151
143
  // src/cache/PersistentCache.ts
152
- var _PersistentCache = class _PersistentCache {
144
+ var PersistentCache = class _PersistentCache {
153
145
  constructor(backing) {
154
146
  this.backing = backing;
155
147
  }
148
+ static {
149
+ /** Bump to invalidate every persisted entry. */
150
+ this.VERSION = 2;
151
+ }
156
152
  static open(name) {
157
153
  return Env.provider.openCache(name, _PersistentCache.VERSION);
158
154
  }
155
+ /** Loads a missing entry and stores only non-nullish results. */
159
156
  async getOrLoad(key, loader) {
160
157
  let v = await this.get(key);
161
158
  if (typeof v === "undefined" || v === null) {
162
159
  v = await loader(key);
163
- await this.put(key, v);
160
+ if (typeof v !== "undefined" && v !== null) {
161
+ await this.put(key, v);
162
+ }
164
163
  }
165
164
  return v;
166
165
  }
167
166
  };
168
- /** Bump to invalidate every persisted entry. */
169
- _PersistentCache.VERSION = 1;
170
- var PersistentCache = _PersistentCache;
171
167
 
172
168
  // src/env/node/NodeCache.ts
173
169
  var NodeCache = class extends PersistentCache {
@@ -245,7 +241,7 @@ registerNodeEnv();
245
241
  // src/Axis.ts
246
242
  import { Vector3 } from "three";
247
243
  var Axis = /* @__PURE__ */ ((Axis3) => {
248
- Axis3["X"] = "X";
244
+ Axis3["X"] = "x";
249
245
  Axis3["Y"] = "y";
250
246
  Axis3["Z"] = "z";
251
247
  return Axis3;
@@ -253,7 +249,7 @@ var Axis = /* @__PURE__ */ ((Axis3) => {
253
249
  var AXES = Object.values(Axis);
254
250
  function axisToVec3(axis) {
255
251
  switch (axis) {
256
- case "X" /* X */:
252
+ case "x" /* X */:
257
253
  return new Vector3(1, 0, 0);
258
254
  case "y" /* Y */:
259
255
  return new Vector3(0, 1, 0);
@@ -341,8 +337,7 @@ function serializeImageKey(key) {
341
337
  return md5(key.src);
342
338
  }
343
339
  function serializeBoxGeometryKey(key) {
344
- var _a;
345
- return md5([key.width, key.height, key.depth, (_a = key.uv) == null ? void 0 : _a.join(":")].join("_"));
340
+ return md5([key.width, key.height, key.depth, key.uv?.join(":")].join("_"));
346
341
  }
347
342
  function serializeTextureKey(key) {
348
343
  return md5([key.src, key.format, key.rotation].join("$"));
@@ -357,7 +352,67 @@ function serializeMeshKey(key) {
357
352
  // src/cache/Caching.ts
358
353
  import { Caches } from "@inventivetalent/loading-cache";
359
354
  import { Time } from "@inventivetalent/time";
360
- var Caching = class {
355
+ var Caching = class _Caching {
356
+ static {
357
+ this.rawImageCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(5)).buildAsync();
358
+ }
359
+ static {
360
+ this.imageDataCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(10)).buildAsync();
361
+ }
362
+ static {
363
+ this.canvasImageDataCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(10)).buildAsync();
364
+ }
365
+ static {
366
+ this.wrappedImageCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(10)).buildAsync();
367
+ }
368
+ static {
369
+ this.boxGeometryCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(20)).build();
370
+ }
371
+ static {
372
+ this.textureCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).build();
373
+ }
374
+ static {
375
+ this.materialCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).build();
376
+ }
377
+ static {
378
+ this.boxMeshCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).build();
379
+ }
380
+ static {
381
+ this.textureAssetCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).buildAsync();
382
+ }
383
+ static {
384
+ this.textureMetaCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).buildAsync();
385
+ }
386
+ static {
387
+ this.rawModelCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).buildAsync();
388
+ }
389
+ static {
390
+ this.mergedModelCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).buildAsync();
391
+ }
392
+ static {
393
+ this.modelTextureAtlasCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).buildAsync();
394
+ }
395
+ static {
396
+ this.blockStateCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).buildAsync();
397
+ }
398
+ static {
399
+ this.listAssetCache = _Caching.createAssetCache();
400
+ }
401
+ static {
402
+ this.defaultBlockStatesCache = _Caching.createAssetCache();
403
+ }
404
+ static {
405
+ this.blockTintCache = _Caching.createAssetCache();
406
+ }
407
+ static {
408
+ this.entityModelCache = _Caching.createAssetCache();
409
+ }
410
+ static {
411
+ this.entityTextureCache = _Caching.createAssetCache();
412
+ }
413
+ static createAssetCache() {
414
+ return Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).buildAsync();
415
+ }
361
416
  /** Every cache above, so clear()/end() can never fall out of sync with the field list again. */
362
417
  static get all() {
363
418
  return [
@@ -374,7 +429,12 @@ var Caching = class {
374
429
  this.rawModelCache,
375
430
  this.mergedModelCache,
376
431
  this.modelTextureAtlasCache,
377
- this.blockStateCache
432
+ this.blockStateCache,
433
+ this.listAssetCache,
434
+ this.defaultBlockStatesCache,
435
+ this.blockTintCache,
436
+ this.entityModelCache,
437
+ this.entityTextureCache
378
438
  ];
379
439
  }
380
440
  static clear() {
@@ -385,8 +445,8 @@ var Caching = class {
385
445
  /**
386
446
  * Clears every cache and stops its expiry timer.
387
447
  *
388
- * loading-cache reschedules that timer indefinitely, so a Node process will not exit until
389
- * this is called - see {@link shutdown}.
448
+ * Expiry timers are unref'd in Node, so idle processes can exit without this cleanup.
449
+ * Use {@link shutdown} to also stop requests and the shared Ticker.
390
450
  */
391
451
  static end() {
392
452
  for (const cache of this.all) {
@@ -400,20 +460,6 @@ var Caching = class {
400
460
  };
401
461
  }
402
462
  };
403
- Caching.rawImageCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(5)).buildAsync();
404
- Caching.imageDataCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(10)).buildAsync();
405
- Caching.canvasImageDataCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(10)).buildAsync();
406
- Caching.wrappedImageCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(10)).buildAsync();
407
- Caching.boxGeometryCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(20)).build();
408
- Caching.textureCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).build();
409
- Caching.materialCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).build();
410
- Caching.boxMeshCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).build();
411
- Caching.textureAssetCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).buildAsync();
412
- Caching.textureMetaCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).buildAsync();
413
- Caching.rawModelCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).buildAsync();
414
- Caching.mergedModelCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).buildAsync();
415
- Caching.modelTextureAtlasCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).buildAsync();
416
- Caching.blockStateCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).buildAsync();
417
463
 
418
464
  // src/Geometries.ts
419
465
  var Geometries = class _Geometries {
@@ -441,6 +487,7 @@ import { CanvasTexture, Texture as Texture2 } from "three";
441
487
 
442
488
  // src/texture/TextureLoader.ts
443
489
  import { RGBAFormat, Texture } from "three";
490
+ import * as THREE from "three";
444
491
 
445
492
  // src/canvas/CanvasCompat.ts
446
493
  function createImage(width, height) {
@@ -451,9 +498,7 @@ function createCanvas2(width, height) {
451
498
  }
452
499
 
453
500
  // src/request/Requests.ts
454
- import axios from "axios";
455
- import { JobQueue } from "jobqu";
456
- import { Time as Time2 } from "@inventivetalent/time";
501
+ import { JobCancelledError, JobQueue } from "jobqu";
457
502
 
458
503
  // src/util/log.ts
459
504
  var Reset = "\x1B[0m";
@@ -463,198 +508,174 @@ function prefix(prefix2) {
463
508
  return `${FgGreen}MR${BgBlack}${prefix2 ?? ""}${Reset}`;
464
509
  }
465
510
 
466
- // src/util/BatchedExecutor.ts
467
- var BatchedExecutor = class {
468
- constructor(interval = 1, batch = 30) {
469
- this.interval = interval;
470
- this.batch = batch;
471
- this.queue = [];
472
- this.task = setInterval(() => this.run());
473
- }
474
- submit(task) {
475
- this.queue.push(task);
476
- }
477
- run() {
478
- for (let i = 0; i < this.batch; i++) {
479
- this.runNext();
480
- }
481
- }
482
- runNext() {
483
- let next = this.queue.shift();
484
- if (next) next();
511
+ // src/request/Requests.ts
512
+ var p = prefix("Requests");
513
+ var RequestError = class extends Error {
514
+ constructor(message, response, cause) {
515
+ super(message);
516
+ this.response = response;
517
+ this.cause = cause;
518
+ this.name = "RequestError";
485
519
  }
486
520
  };
487
-
488
- // src/util/model.ts
489
- import { AxesHelper, BoxGeometry as BoxGeometry2, EdgesGeometry, LineBasicMaterial, LineSegments, Vector3 as Vector32 } from "three";
490
- function applyElementRotation(rotation, geometry) {
491
- const origin = new Vector32(rotation.origin[0], rotation.origin[1], rotation.origin[2]);
492
- geometry.translate(-origin.x, -origin.y, -origin.z);
493
- switch (rotation.axis) {
494
- case "X" /* X */:
495
- geometry.rotateX(toRadians(rotation.angle));
496
- break;
497
- case "y" /* Y */:
498
- geometry.rotateY(toRadians(rotation.angle));
499
- break;
500
- case "z" /* Z */:
501
- geometry.rotateZ(toRadians(rotation.angle));
502
- break;
503
- }
504
- if (rotation.rescale) {
505
- if (Math.abs(rotation.angle) === 22.5) {
506
- const s = 1 / Math.cos(0.39269909262657166);
507
- geometry.scale(s, 1, s);
508
- } else {
509
- const s = 1 / Math.cos(0.7853981852531433);
510
- geometry.scale(s, 1, s);
521
+ async function fetchRequest(config, defaultBaseURL) {
522
+ const { url, baseURL = defaultBaseURL, timeout = 5e3, responseType = "json", signal, ...options } = config;
523
+ const target = baseURL && !/^([a-z][a-z\d+.-]*:|\/\/)/i.test(url) ? `${baseURL.replace(/\/+$/, "")}/${url.replace(/^\/+/, "")}` : url;
524
+ const headers = new Headers(options.headers);
525
+ if (typeof window === "undefined" && !headers.has("User-Agent")) {
526
+ headers.set("User-Agent", "MineRender");
527
+ }
528
+ const attemptSignal = AbortSignal.any([
529
+ ...signal ? [signal] : [],
530
+ ...timeout === 0 ? [] : [AbortSignal.timeout(timeout)]
531
+ ]);
532
+ const request = new Request(target, { ...options, headers, signal: attemptSignal });
533
+ attemptSignal.throwIfAborted();
534
+ try {
535
+ const response = await fetch(request);
536
+ const result = {
537
+ data: void 0,
538
+ status: response.status,
539
+ statusText: response.statusText,
540
+ headers: response.headers,
541
+ url: response.url
542
+ };
543
+ if (!response.ok) {
544
+ await response.body?.cancel().catch(() => {
545
+ });
546
+ throw new RequestError(`Request failed with status ${response.status}`, result);
511
547
  }
548
+ const emptyBody = request.method === "HEAD" || response.status === 204 || response.status === 205;
549
+ const data = responseType === "arraybuffer" ? await response.arrayBuffer() : emptyBody || response.body === null ? void 0 : await response.json();
550
+ return { ...result, data };
551
+ } catch (error) {
552
+ attemptSignal.throwIfAborted();
553
+ if (/^https?:/.test(request.url) && request.redirect !== "error" && error instanceof TypeError) {
554
+ throw new RequestError("Network request failed", void 0, error);
555
+ }
556
+ throw error;
512
557
  }
513
- geometry.translate(origin.x, origin.y, origin.z);
514
558
  }
515
- function applyModelPartRotation(modelPart, geometry) {
516
- const origin = new Vector32(modelPart.pivotX, modelPart.pivotY, modelPart.pivotZ);
517
- geometry.translate(-origin.x, -origin.y, -origin.z);
518
- geometry.rotateX(toRadians(modelPart.pitch));
519
- geometry.rotateY(toRadians(modelPart.yaw));
520
- geometry.rotateZ(toRadians(modelPart.roll));
521
- geometry.translate(origin.x, origin.y, origin.z);
522
- }
523
- function applyGenericRotation(axis, rotation, obj) {
524
- switch (axis) {
525
- case "X" /* X */:
526
- obj.rotateOnAxis(new Vector32(1, 0, 0), toRadians(rotation));
527
- break;
528
- case "y" /* Y */:
529
- obj.rotateOnAxis(new Vector32(0, 1, 0), toRadians(rotation));
530
- break;
531
- case "z" /* Z */:
532
- obj.rotateOnAxis(new Vector32(0, 0, 1), toRadians(rotation));
533
- break;
559
+ async function abortable(promise, signal) {
560
+ if (!signal) return promise;
561
+ let abort;
562
+ const cancelled = new Promise((_, reject) => {
563
+ abort = () => reject(signal.reason);
564
+ signal.addEventListener("abort", abort, { once: true });
565
+ if (signal.aborted) abort();
566
+ });
567
+ try {
568
+ return await Promise.race([promise, cancelled]);
569
+ } finally {
570
+ signal.removeEventListener("abort", abort);
534
571
  }
535
572
  }
536
- function addBox3WireframeToObject(box, obj, color = 16777215, w = 2) {
537
- let size = new Vector32();
538
- box.getSize(size);
539
- let boxGeo = new BoxGeometry2(size.x, size.y, size.z, 1, 1, 1);
540
- let wireGeo = new EdgesGeometry(boxGeo);
541
- let wireMat = new LineBasicMaterial({ color, linewidth: w });
542
- let wireframe = new LineSegments(wireGeo, wireMat);
543
- obj.add(wireframe);
544
- let axes = new AxesHelper(1);
545
- obj.add(axes);
546
- }
547
- function addWireframeToObject(obj, color = 16777215, w = 2) {
548
- let boxGeo = new BoxGeometry2(16, 16, 16, 1, 1, 1);
549
- let wireGeo = new EdgesGeometry(boxGeo);
550
- let wireMat = new LineBasicMaterial({ color, linewidth: w });
551
- let wireframe = new LineSegments(wireGeo, wireMat);
552
- obj.add(wireframe);
553
- let axes = new AxesHelper(1);
554
- obj.add(axes);
555
- }
556
- function addWireframeToMesh(geo, mesh, color = 16777215, w = 2) {
557
- let wireGeo = new EdgesGeometry(geo);
558
- let wireMat = new LineBasicMaterial({ color, linewidth: w });
559
- let wireframe = new LineSegments(wireGeo, wireMat);
560
- mesh.add(wireframe);
561
- let axes = new AxesHelper(1);
562
- mesh.add(axes);
563
- }
564
-
565
- // src/util/performance.ts
566
- function captureException(e, ...extra) {
567
- console.error(e, extra);
568
- }
569
- function timingStart(marker) {
570
- console.time(marker);
571
- }
572
- function timingEnd(marker) {
573
- console.timeEnd(marker);
574
- }
575
-
576
- // src/util/three.ts
577
- function isObject3D(obj) {
578
- return obj.isObject3D;
579
- }
580
- function isMesh(obj) {
581
- return obj.isMesh;
582
- }
583
- function isInstancedMesh(obj) {
584
- return obj.isInstancedMesh;
585
- }
586
- function isPerspectiveCamera(obj) {
587
- return obj.isPerspectiveCamera;
588
- }
589
- function isOrthographicCamera(obj) {
590
- return obj.isOrthographicCamera;
591
- }
592
-
593
- // src/request/Requests.ts
594
- var p = prefix("Requests");
595
- if (typeof window === "undefined") {
596
- axios.defaults.headers["User-Agent"] = "MineRender";
597
- }
598
- var _Requests = class _Requests {
599
- static genericRequest(request) {
600
- return this.genericQueue.add(request).catch(async (e) => {
601
- console.debug(p, "generic catch", e.code, e);
602
- if (this.shouldRetry(e, request)) {
603
- await sleep(100);
604
- return this.genericRequest(request);
605
- }
606
- throw e;
607
- });
608
- }
609
- static mcAssetRequest(request) {
610
- return this.mcAssetRequestQueue.add(request).catch((e) => {
611
- console.debug(p, "mcAssetRequest catch", e.code, e);
612
- throw e;
613
- });
573
+ var RequestQueue = class {
574
+ constructor() {
575
+ this.pendingRequests = 0;
576
+ this.stopped = new AbortController();
577
+ this.queue = new JobQueue(
578
+ (request) => fetchRequest(request, this.baseURL),
579
+ { interval: 10, maxPerRun: 1, maxActive: 8 }
580
+ );
614
581
  }
615
- static shouldRetry(e, request) {
616
- if ("code" in e) {
617
- if ("ECONNABORTED" === e.code) {
618
- if ("minerenderRetry" in request) {
619
- if (request["minerenderRetry"] > 0) {
620
- request["minerenderRetry"]--;
621
- return true;
582
+ async request(request) {
583
+ this.pendingRequests++;
584
+ const signal = request.signal;
585
+ try {
586
+ for (let retries = 0; ; retries++) {
587
+ signal?.throwIfAborted();
588
+ try {
589
+ return await abortable(this.queue.add(request), signal);
590
+ } catch (error) {
591
+ console.debug(p, "Request failed", error);
592
+ const delay = this.retryDelay(error, request, retries);
593
+ if (delay === void 0) {
594
+ throw error;
622
595
  }
623
- } else {
624
- request["minerenderRetry"] = 3;
625
- return true;
596
+ await this.waitForRetry(delay, signal);
626
597
  }
627
598
  }
599
+ } finally {
600
+ if (signal?.aborted) {
601
+ this.queue.remove(request);
602
+ }
603
+ this.pendingRequests--;
628
604
  }
629
- return false;
605
+ }
606
+ retryDelay(error, request, retries) {
607
+ if (this.stopped.signal.aborted || retries >= 3 || (request.method ?? "get").toLowerCase() !== "get" || request.signal?.aborted) {
608
+ return void 0;
609
+ }
610
+ if (error instanceof RequestError) {
611
+ const status = error.response?.status;
612
+ if (status !== void 0 && status !== 408 && status !== 429 && !(status >= 500 && status < 600)) return void 0;
613
+ } else if (!(error instanceof DOMException && error.name === "TimeoutError")) {
614
+ return void 0;
615
+ }
616
+ let delay = 100 * 2 ** retries;
617
+ const retryAfter = error instanceof RequestError ? error.response?.headers.get("Retry-After") : void 0;
618
+ if (retryAfter !== void 0 && retryAfter !== null) {
619
+ const seconds = Number(retryAfter);
620
+ if (!retryAfter.trim() || !Number.isFinite(seconds) || seconds < 0) {
621
+ return void 0;
622
+ }
623
+ delay = Math.max(delay, seconds * 1e3);
624
+ }
625
+ return delay;
626
+ }
627
+ async waitForRetry(delay, signal) {
628
+ let timer;
629
+ const waiting = new Promise((resolve) => {
630
+ timer = setTimeout(resolve, delay);
631
+ });
632
+ try {
633
+ await abortable(waiting, AbortSignal.any([this.stopped.signal, ...signal ? [signal] : []]));
634
+ } finally {
635
+ clearTimeout(timer);
636
+ }
637
+ }
638
+ get pendingSize() {
639
+ return this.pendingRequests;
640
+ }
641
+ end() {
642
+ this.queue.end();
643
+ this.stopped.abort(new JobCancelledError("ended"));
644
+ }
645
+ };
646
+ var Requests = class {
647
+ static {
648
+ this.genericQueue = new RequestQueue();
649
+ }
650
+ static {
651
+ this.mcAssetRequestQueue = new RequestQueue();
652
+ }
653
+ static genericRequest(request) {
654
+ return this.genericQueue.request(request);
655
+ }
656
+ static mcAssetRequest(request) {
657
+ return this.mcAssetRequestQueue.request(request);
630
658
  }
631
659
  static setMcAssetRoot(root) {
632
- this.mcAssetInstance.defaults.baseURL = root;
660
+ this.mcAssetRequestQueue.baseURL = root;
633
661
  }
662
+ /** Counts unsettled calls, including retry delays and requests still running after shutdown. */
634
663
  static get queueSizes() {
635
664
  return {
636
- generic: this.genericQueue.size,
637
- mcAsset: this.mcAssetRequestQueue.size
665
+ generic: this.genericQueue.pendingSize,
666
+ mcAsset: this.mcAssetRequestQueue.pendingSize
638
667
  };
639
668
  }
640
669
  /**
641
- * Stops both queue timers. jobqu reschedules itself indefinitely, so a Node process will not
642
- * exit until this is called - see {@link shutdown}.
670
+ * Permanently stops both queues and rejects waiting, retrying, and future requests.
671
+ * Requests already running can finish. Idle queues hold no timer, so Node can exit without
672
+ * this cleanup. See {@link shutdown}.
643
673
  */
644
674
  static end() {
645
675
  this.genericQueue.end();
646
676
  this.mcAssetRequestQueue.end();
647
677
  }
648
678
  };
649
- _Requests.axiosInstance = axios.create({
650
- timeout: 5e3
651
- });
652
- _Requests.mcAssetInstance = axios.create({
653
- timeout: 5e3
654
- });
655
- _Requests.genericQueue = new JobQueue((request) => _Requests.axiosInstance.request(request), Time2.millis(10), 1);
656
- _Requests.mcAssetRequestQueue = new JobQueue((request) => _Requests.mcAssetInstance.request(request), Time2.millis(10), 1);
657
- var Requests = _Requests;
658
679
 
659
680
  // src/WrappedImage.ts
660
681
  var WrappedImage = class {
@@ -692,10 +713,10 @@ var WrappedImage = class {
692
713
  return this.animated ? this.width : this.height;
693
714
  }
694
715
  get frameCount() {
695
- return this.height / this.width;
716
+ return this.height / this.frameHeight;
696
717
  }
697
718
  getFrameY(frame) {
698
- return this.height / this.frameCount * Math.max(0, Math.min(this.frameCount, frame));
719
+ return this.frameHeight * Math.max(0, Math.min(this.frameCount - 1, frame));
699
720
  }
700
721
  getSectionData(sx, sy, sw, sh) {
701
722
  return this.dta.data.getImageData(sx, sy, sw, sh);
@@ -705,7 +726,7 @@ var WrappedImage = class {
705
726
  }
706
727
  getFrameSectionData(frame) {
707
728
  const y = this.getFrameY(frame);
708
- return this.getSectionData(0, y, this.width, this.width + y);
729
+ return this.getSectionData(0, y, this.frameWidth, this.frameHeight);
709
730
  }
710
731
  };
711
732
 
@@ -719,29 +740,41 @@ var ImageLoader = class _ImageLoader {
719
740
  static async loadAsync(src) {
720
741
  return new Promise((resolve, reject) => {
721
742
  const image = this._createImage();
722
- image.src = src;
723
743
  image.onload = () => resolve(image);
724
- image.onerror = (err) => reject(err);
744
+ image.onerror = (err) => reject(err instanceof Error ? err : new Error("Failed to decode image"));
745
+ image.src = src;
725
746
  });
726
747
  }
727
748
  static loadElement(src, onload, onerr) {
728
749
  const image = this._createImage();
729
- image.src = src;
730
750
  if (onload)
731
751
  image.onload = onload;
732
752
  if (onerr)
733
753
  image.onerror = onerr;
754
+ image.src = src;
734
755
  return image;
735
756
  }
736
757
  static async loadData(src) {
737
758
  console.debug(p2, "loadData", src);
738
- return await this.infoToData(await this.getInfo(src));
759
+ const image = await this.loadCanvasData(src);
760
+ return image.data.getImageData(0, 0, image.width, image.height);
739
761
  }
740
762
  static async loadCanvasData(src) {
741
- return await this.infoToCanvasData(await this.getInfo(src));
763
+ const keyStr = serializeImageKey({ src });
764
+ const info = this.getInfo(src);
765
+ const cached = Caching.rawImageCache.getIfPresent(keyStr);
766
+ try {
767
+ return await this.infoToCanvasData(await info);
768
+ } catch (err) {
769
+ if (cached && Caching.rawImageCache.getIfPresent(keyStr) === cached) {
770
+ Caching.rawImageCache.invalidate(keyStr);
771
+ }
772
+ throw err;
773
+ }
742
774
  }
743
775
  static async infoToCanvasData(info) {
744
- const image = await _ImageLoader.loadAsync(info.src);
776
+ const type = info.type === "jpg" ? "jpeg" : info.type ?? "png";
777
+ const image = await _ImageLoader.loadAsync(`data:image/${type};base64,${info.data.toString("base64")}`);
745
778
  const canvas = createCanvas2(info.width, info.height);
746
779
  const context = canvas.getContext("2d");
747
780
  context.drawImage(image, 0, 0);
@@ -752,11 +785,8 @@ var ImageLoader = class _ImageLoader {
752
785
  };
753
786
  }
754
787
  static async infoToData(info) {
755
- const image = await _ImageLoader.loadAsync(info.src);
756
- const canvas = createCanvas2(info.width, info.height);
757
- const context = canvas.getContext("2d");
758
- context.drawImage(image, 0, 0);
759
- return context.getImageData(0, 0, canvas.width, canvas.height);
788
+ const image = await this.infoToCanvasData(info);
789
+ return image.data.getImageData(0, 0, image.width, image.height);
760
790
  }
761
791
  static async getData(src) {
762
792
  const keyStr = serializeImageKey({ src });
@@ -771,38 +801,25 @@ var ImageLoader = class _ImageLoader {
771
801
  });
772
802
  }
773
803
  static async processResponse(response) {
774
- const src = response.config.url;
804
+ const src = response.url;
775
805
  const data = Buffer2.from(response.data);
776
806
  const { width, height, type } = Env.provider.imageSize(data);
807
+ if (!width || !height) {
808
+ throw new Error("Invalid or unsupported image dimensions");
809
+ }
777
810
  return {
778
811
  src,
779
- width: width || 0,
780
- height: height || 0,
812
+ width,
813
+ height,
781
814
  type,
782
815
  data
783
816
  };
784
817
  }
785
818
  static async loadInfo(src) {
786
- if (src.startsWith("data:image/png;base64")) {
787
- return this.processResponse({
788
- config: {
789
- url: src
790
- },
791
- data: Buffer2.from(src.substr("data:image/png;base64,".length), "base64")
792
- });
793
- }
794
819
  return Requests.genericRequest({
795
820
  url: src,
796
821
  responseType: "arraybuffer"
797
- }).then(this.processResponse).catch((err) => {
798
- return {
799
- src,
800
- width: 0,
801
- height: 0,
802
- type: void 0,
803
- data: Buffer2.from([0])
804
- };
805
- });
822
+ }).then(this.processResponse);
806
823
  }
807
824
  static async getInfo(src) {
808
825
  const keyStr = serializeImageKey({ src });
@@ -824,15 +841,25 @@ var ImageLoader = class _ImageLoader {
824
841
 
825
842
  // src/texture/TextureLoader.ts
826
843
  var TextureLoader = class {
844
+ static {
845
+ this.failedTextures = /* @__PURE__ */ new WeakSet();
846
+ }
847
+ /** Reports whether image loading failed, so cached textures can be retried. */
848
+ static hasFailed(texture) {
849
+ return this.failedTextures.has(texture);
850
+ }
827
851
  static createTexture() {
828
852
  return new Texture();
829
853
  }
830
854
  static loadInBackground(src, format = RGBAFormat, rotation = 0) {
831
855
  const texture = this.createTexture();
832
- const image = ImageLoader.loadElement(src);
833
- image.onload = function() {
856
+ texture.colorSpace = THREE.SRGBColorSpace;
857
+ const image = ImageLoader.loadElement(src, () => {
834
858
  texture.needsUpdate = true;
835
- };
859
+ }, (error) => {
860
+ this.failedTextures.add(texture);
861
+ console.warn("Failed to load texture", src, error);
862
+ });
836
863
  texture.image = image;
837
864
  texture.format = format;
838
865
  texture.rotation = rotation;
@@ -840,9 +867,13 @@ var TextureLoader = class {
840
867
  }
841
868
  static load(src, format = RGBAFormat, rotation = 0) {
842
869
  const texture = new Texture();
870
+ texture.colorSpace = THREE.SRGBColorSpace;
843
871
  ImageLoader.getData(src).then((image) => {
844
- texture.needsUpdate = true;
845
872
  texture.image = image;
873
+ texture.needsUpdate = true;
874
+ }).catch((error) => {
875
+ this.failedTextures.add(texture);
876
+ console.warn("Failed to load texture", src, error);
846
877
  });
847
878
  texture.format = format;
848
879
  texture.rotation = rotation;
@@ -851,11 +882,11 @@ var TextureLoader = class {
851
882
  };
852
883
 
853
884
  // src/texture/Textures.ts
854
- import * as THREE from "three";
885
+ import * as THREE2 from "three";
855
886
  var Textures = class _Textures {
856
887
  static initTextureProps(texture) {
857
- texture.magFilter = THREE.NearestFilter;
858
- texture.minFilter = THREE.NearestFilter;
888
+ texture.magFilter = THREE2.NearestFilter;
889
+ texture.minFilter = THREE2.NearestFilter;
859
890
  texture.anisotropy = 0;
860
891
  return texture;
861
892
  }
@@ -866,10 +897,16 @@ var Textures = class _Textures {
866
897
  return new Texture2();
867
898
  }
868
899
  static createCanvasTexture(canvas) {
869
- return this.initTextureProps(new CanvasTexture(canvas));
900
+ const texture = new CanvasTexture(canvas);
901
+ texture.colorSpace = THREE2.SRGBColorSpace;
902
+ return this.initTextureProps(texture);
870
903
  }
871
904
  static getImage(key) {
872
905
  const keyStr = serializeTextureKey(key);
906
+ const cached = Caching.textureCache.peek(keyStr);
907
+ if (cached && TextureLoader.hasFailed(cached)) {
908
+ Caching.textureCache.invalidate(keyStr);
909
+ }
873
910
  return Caching.textureCache.get(keyStr, (k) => {
874
911
  return _Textures.createImage(key);
875
912
  });
@@ -877,7 +914,10 @@ var Textures = class _Textures {
877
914
  };
878
915
 
879
916
  // src/Materials.ts
880
- var _Materials = class _Materials {
917
+ var Materials = class _Materials {
918
+ static {
919
+ this.MISSING_TEXTURE_SRC = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABAAQMAAACQp+OdAAAABlBMVEX/AP8AAACfphTyAAAAFUlEQVQoz2MIhQKGVVAwKjIqQrwIAHRz/wFI17TEAAAAAElFTkSuQmCC";
920
+ }
881
921
  // resolved lazily: as a static field this decoded an image the moment the library was
882
922
  // imported, which needs both a DOM and an EnvProvider to already be in place
883
923
  static get MISSING_TEXTURE() {
@@ -913,6 +953,7 @@ var _Materials = class _Materials {
913
953
  uniform bool SHADE;
914
954
 
915
955
  varying vec2 vUv;
956
+ varying vec3 vTint;
916
957
  varying float light;
917
958
  varying float lift;
918
959
 
@@ -925,7 +966,11 @@ var _Materials = class _Materials {
925
966
 
926
967
  if (SHADE) {
927
968
 
928
- vec3 N = vec3( modelMatrix * instanceMatrix * vec4(normal, 0.0) );
969
+ #ifdef USE_INSTANCING
970
+ vec3 N = vec3( modelMatrix * instanceMatrix * vec4(normal, 0.0) );
971
+ #else
972
+ vec3 N = vec3( modelMatrix * vec4(normal, 0.0) );
973
+ #endif
929
974
 
930
975
  float yLight = (1.0+N.y) * 0.5;
931
976
  light = yLight * (1.0-AMBIENT) + N.x*N.x * XFAC + N.z*N.z * ZFAC + AMBIENT;
@@ -943,6 +988,7 @@ var _Materials = class _Materials {
943
988
  }
944
989
 
945
990
  vUv = uv;
991
+ vTint = color;
946
992
 
947
993
  #ifdef USE_INSTANCING
948
994
  gl_Position = projectionMatrix * viewMatrix * modelMatrix * instanceMatrix * vec4(position, 1.0);
@@ -964,12 +1010,14 @@ var _Materials = class _Materials {
964
1010
  uniform float BRIGHTNESS;
965
1011
 
966
1012
  varying vec2 vUv;
1013
+ varying vec3 vTint;
967
1014
  varying float light;
968
1015
  varying float lift;
969
1016
 
970
1017
  void main(void)
971
1018
  {
972
1019
  vec4 color = texture2D(map, vUv);
1020
+ color.rgb *= vTint;
973
1021
 
974
1022
  if (color.a < 0.01) discard;
975
1023
 
@@ -983,6 +1031,9 @@ var _Materials = class _Materials {
983
1031
  gl_FragColor = vec4(lift + color.rgb * light2, 1.0);
984
1032
 
985
1033
  }
1034
+
1035
+ #include <tonemapping_fragment>
1036
+ #include <colorspace_fragment>
986
1037
  }
987
1038
  `;
988
1039
  try {
@@ -1011,6 +1062,10 @@ var _Materials = class _Materials {
1011
1062
  }
1012
1063
  static getImage(key) {
1013
1064
  const keyStr = serializeMaterialKey(key);
1065
+ const map = Caching.materialCache.peek(keyStr)?.map;
1066
+ if (map && TextureLoader.hasFailed(map)) {
1067
+ Caching.materialCache.invalidate(keyStr);
1068
+ }
1014
1069
  return Caching.materialCache.get(keyStr, (k) => {
1015
1070
  return _Materials.createImage(key);
1016
1071
  });
@@ -1031,14 +1086,12 @@ var _Materials = class _Materials {
1031
1086
  }
1032
1087
  }
1033
1088
  };
1034
- _Materials.MISSING_TEXTURE_SRC = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABAAQMAAACQp+OdAAAABlBMVEX/AP8AAACfphTyAAAAFUlEQVQoz2MIhQKGVVAwKjIqQrwIAHRz/wFI17TEAAAAAElFTkSuQmCC";
1035
- var Materials = _Materials;
1036
1089
 
1037
1090
  // src/Meshes.ts
1038
- import { Mesh as Mesh2 } from "three";
1091
+ import { Mesh } from "three";
1039
1092
  var Meshes = class _Meshes {
1040
1093
  static createBox(key) {
1041
- return new Mesh2(Geometries.getBox(key.geometry), Materials.getImage(key.material));
1094
+ return new Mesh(Geometries.getBox(key.geometry), Materials.getImage(key.material));
1042
1095
  }
1043
1096
  static getBox(key) {
1044
1097
  const keyStr = serializeMeshKey(key);
@@ -1049,7 +1102,7 @@ var Meshes = class _Meshes {
1049
1102
  };
1050
1103
 
1051
1104
  // src/UVMapper.ts
1052
- import { Float32BufferAttribute as Float32BufferAttribute2, Vector2 } from "three";
1105
+ import { Float32BufferAttribute as Float32BufferAttribute2, Vector2, Vector3 as Vector34 } from "three";
1053
1106
 
1054
1107
  // src/model/ModelMerger.ts
1055
1108
  var import_ts_deepmerge = __toESM(require_dist());
@@ -1085,9 +1138,10 @@ var AssetKey = class _AssetKey extends BasicAssetKey {
1085
1138
  this.rootType = rootType;
1086
1139
  this.extension = extension;
1087
1140
  this.root = root;
1141
+ this.isAssetKey = true;
1088
1142
  }
1089
1143
  static parse(assetType, str, origin) {
1090
- let namespace = (origin == null ? void 0 : origin.namespace) || DEFAULT_NAMESPACE;
1144
+ let namespace = origin?.namespace || DEFAULT_NAMESPACE;
1091
1145
  if (str.includes(":")) {
1092
1146
  let split2 = str.split(":");
1093
1147
  namespace = split2[0];
@@ -1100,12 +1154,15 @@ var AssetKey = class _AssetKey extends BasicAssetKey {
1100
1154
  split.shift();
1101
1155
  }
1102
1156
  let path = split.join("/");
1103
- let extension = assetType === "textures" ? ".png" : (origin == null ? void 0 : origin.assetType) || ".json";
1104
- return new _AssetKey(namespace, path, assetType, type, "assets", extension, origin == null ? void 0 : origin.root);
1157
+ const extension = assetType === "textures" ? ".png" : origin?.extension ?? ".json";
1158
+ if (extension && path.endsWith(extension)) {
1159
+ path = path.slice(0, -extension.length);
1160
+ }
1161
+ return new _AssetKey(namespace, path, assetType, type, "assets", extension, origin?.root);
1105
1162
  }
1106
1163
  toString() {
1107
1164
  let a = [
1108
- typeof this.root !== "undefined" || AssetLoader.ROOT !== DEFAULT_ROOT ? this.root ?? AssetLoader.ROOT : "__root__",
1165
+ this.root ?? AssetLoader.ROOT,
1109
1166
  this.rootType ?? "__rootType__",
1110
1167
  this.assetType ?? "__assetType__",
1111
1168
  this.type ?? "__type__",
@@ -1115,12 +1172,12 @@ var AssetKey = class _AssetKey extends BasicAssetKey {
1115
1172
  return a.join("/");
1116
1173
  }
1117
1174
  getFullPath() {
1118
- let p13 = [];
1175
+ let p12 = [];
1119
1176
  if (this.type) {
1120
- p13.push(this.type);
1177
+ p12.push(this.type);
1121
1178
  }
1122
- p13.push(this.path);
1123
- return p13.join("/");
1179
+ p12.push(this.path);
1180
+ return p12.join("/");
1124
1181
  }
1125
1182
  toNamespacedString() {
1126
1183
  return this.namespace + ":" + this.getFullPath();
@@ -1130,22 +1187,84 @@ var AssetKey = class _AssetKey extends BasicAssetKey {
1130
1187
  }
1131
1188
  };
1132
1189
  function isBasicAssetKey(obj) {
1133
- return "namespace" in obj && "path" in obj;
1190
+ return obj !== null && typeof obj === "object" && typeof obj.namespace === "string" && typeof obj.path === "string";
1134
1191
  }
1135
1192
  function isAssetKey(obj) {
1136
- return isBasicAssetKey(obj) && "parse" in obj;
1193
+ return isBasicAssetKey(obj) && obj.isAssetKey === true;
1137
1194
  }
1138
1195
 
1196
+ // src/model/DisplayTransforms.ts
1197
+ import { Euler, Matrix4, Quaternion, Vector3 as Vector32 } from "three";
1198
+
1199
+ // src/model/DisplayPosition.ts
1200
+ var DisplayPosition = /* @__PURE__ */ ((DisplayPosition2) => {
1201
+ DisplayPosition2["THIRDPERSON_RIGHTHAND"] = "thirdperson_righthand";
1202
+ DisplayPosition2["THIRDPERSON_LEFTHAND"] = "thirdperson_lefthand";
1203
+ DisplayPosition2["FIRSTPERSON_RIGHTHAND"] = "firstperson_righthand";
1204
+ DisplayPosition2["FIRSTPERSON_LEFTHAND"] = "firstperson_lefthand";
1205
+ DisplayPosition2["GUI"] = "gui";
1206
+ DisplayPosition2["HEAD"] = "head";
1207
+ DisplayPosition2["GROUND"] = "ground";
1208
+ DisplayPosition2["FIXED"] = "fixed";
1209
+ DisplayPosition2["ON_SHELF"] = "on_shelf";
1210
+ return DisplayPosition2;
1211
+ })(DisplayPosition || {});
1212
+ var DISPLAY_POSITIONS = Object.values(DisplayPosition);
1213
+
1214
+ // src/model/DisplayTransforms.ts
1215
+ var DisplayTransforms = class {
1216
+ /** Resolve hand fallbacks within one model, before inheriting parent display entries. */
1217
+ static withHandFallbacks(display) {
1218
+ if (!display) return void 0;
1219
+ const resolved = { ...display };
1220
+ for (const [left, right] of [
1221
+ ["thirdperson_lefthand" /* THIRDPERSON_LEFTHAND */, "thirdperson_righthand" /* THIRDPERSON_RIGHTHAND */],
1222
+ ["firstperson_lefthand" /* FIRSTPERSON_LEFTHAND */, "firstperson_righthand" /* FIRSTPERSON_RIGHTHAND */]
1223
+ ]) {
1224
+ if (resolved[left] === void 0 && resolved[right] !== void 0) resolved[left] = resolved[right];
1225
+ }
1226
+ return resolved;
1227
+ }
1228
+ /** Build a display pose for geometry already centered at the model's [8, 8, 8] pivot. */
1229
+ static getMatrix(display, position) {
1230
+ const transform = this.withHandFallbacks(display)?.[position] ?? {};
1231
+ const left = position === "firstperson_lefthand" /* FIRSTPERSON_LEFTHAND */ || position === "thirdperson_lefthand" /* THIRDPERSON_LEFTHAND */;
1232
+ const sign = left ? -1 : 1;
1233
+ const [x, y, z] = transform.rotation ?? [0, 0, 0];
1234
+ const rotation = new Quaternion().setFromEuler(new Euler(toRadians(x), sign * toRadians(y), sign * toRadians(z), "XYZ"));
1235
+ const translation = new Vector32(...transform.translation ?? [0, 0, 0]).clampScalar(-80, 80);
1236
+ translation.x *= sign;
1237
+ const scale = new Vector32(...transform.scale ?? [1, 1, 1]).clampScalar(-4, 4);
1238
+ return new Matrix4().compose(translation, rotation, scale);
1239
+ }
1240
+ static apply(geometry, matrix) {
1241
+ geometry.applyMatrix4(matrix);
1242
+ if (matrix.determinant() < 0) {
1243
+ if (!geometry.index) geometry.setIndex(Array.from({ length: geometry.getAttribute("position").count }, (_, i) => i));
1244
+ const index = geometry.index;
1245
+ for (let i = 0; i < index.count; i += 3) {
1246
+ const second = index.getX(i + 1);
1247
+ index.setX(i + 1, index.getX(i + 2));
1248
+ index.setX(i + 2, second);
1249
+ }
1250
+ index.needsUpdate = true;
1251
+ }
1252
+ }
1253
+ };
1254
+
1139
1255
  // src/model/ModelMerger.ts
1140
1256
  var ModelMerger = class {
1141
1257
  static async mergeWithParents(model) {
1142
1258
  const models = await this.collectAllParents(model);
1143
1259
  let merged = {};
1144
- for (let parentModel of models) {
1145
- merged = (0, import_ts_deepmerge.default)(merged, parentModel);
1260
+ for (const source of [...models, model]) {
1261
+ const inheritedDisplay = merged.display;
1262
+ merged = import_ts_deepmerge.default.withOptions({ mergeArrays: false }, merged, source);
1263
+ if (source.display) {
1264
+ merged.display = { ...inheritedDisplay, ...DisplayTransforms.withHandFallbacks(source.display) };
1265
+ }
1146
1266
  }
1147
- merged = (0, import_ts_deepmerge.default)(merged, model);
1148
- merged.hierarchy = models.map((m) => m.parent).filter((p13) => `${p13}`);
1267
+ merged.hierarchy = models.map((m) => m.parent).filter((p12) => `${p12}`);
1149
1268
  merged.hierarchy.push(`${merged.parent}`);
1150
1269
  return merged;
1151
1270
  }
@@ -1155,6 +1274,7 @@ var ModelMerger = class {
1155
1274
  }
1156
1275
  const models = [];
1157
1276
  const parentKey = AssetKey.parse("models", model.parent);
1277
+ parentKey.root = model.key?.root;
1158
1278
  const parentModel = await Models.getRaw(parentKey);
1159
1279
  if (parentModel) {
1160
1280
  models.unshift(parentModel);
@@ -1164,9 +1284,6 @@ var ModelMerger = class {
1164
1284
  }
1165
1285
  };
1166
1286
 
1167
- // src/assets/Models.ts
1168
- import { Memoize } from "typescript-memoize";
1169
-
1170
1287
  // src/assets/source/parser/AssetParsers.ts
1171
1288
  var AssetParser = /* @__PURE__ */ ((AssetParser2) => {
1172
1289
  AssetParser2["MODEL"] = "model";
@@ -1180,30 +1297,65 @@ var AssetParser = /* @__PURE__ */ ((AssetParser2) => {
1180
1297
  })(AssetParser || {});
1181
1298
 
1182
1299
  // src/assets/Models.ts
1183
- var _Models = class _Models {
1300
+ var Models = class _Models {
1184
1301
  // opened lazily: touching the store at import time would hit IndexedDB/disk just for loading
1185
1302
  // the library, and would require an EnvProvider before any entry has had a chance to register
1186
1303
  static get PERSISTENT_CACHE() {
1187
1304
  return this._persistentCache ??= PersistentCache.open("minerender-models");
1188
1305
  }
1189
1306
  static async getItemList() {
1190
- return AssetLoader.get(new AssetKey(
1191
- DEFAULT_NAMESPACE,
1192
- "_list",
1193
- "models",
1194
- "item",
1195
- "assets",
1196
- ".json",
1197
- DEFAULT_ROOT
1198
- ), "list" /* LIST */).then((r) => (r == null ? void 0 : r.files) ?? []);
1307
+ const key = new AssetKey(DEFAULT_NAMESPACE, "_list", "items");
1308
+ const legacyKey = new AssetKey(DEFAULT_NAMESPACE, "_list", "models", "item");
1309
+ return Caching.listAssetCache.get(key.serialize(), async () => {
1310
+ return (await AssetLoader.getFirst([key, legacyKey], "list" /* LIST */))?.asset;
1311
+ }).then((r) => r?.files ?? []);
1199
1312
  }
1200
1313
  static async loadAndMerge(key) {
1201
- const model = await this.getRaw(key);
1314
+ const model = key.type === "item" ? await this.getItemModel(key) : await this.getRaw(key);
1202
1315
  if (!model) {
1203
1316
  return void 0;
1204
1317
  }
1205
1318
  return ModelMerger.mergeWithParents(model);
1206
1319
  }
1320
+ static async getItemModel(key) {
1321
+ const itemKey = new AssetKey(key.namespace, key.path, "items", void 0, key.rootType, ".json", key.root);
1322
+ const model = await this.PERSISTENT_CACHE.getOrLoad(AssetLoader.persistentKey(itemKey.serialize()), async () => {
1323
+ const result = await AssetLoader.getFirst([itemKey, key], "json" /* JSON */);
1324
+ if (!result) return void 0;
1325
+ if (result.key.assetType !== "items") return { ...result.asset, key };
1326
+ const reference = this.defaultItemModel(result.asset.model, key);
1327
+ const modelKey = AssetKey.parse("models", reference);
1328
+ modelKey.root = key.root;
1329
+ const model2 = await this.getRaw(modelKey);
1330
+ if (!model2) throw new Error(`Item ${key.toNamespacedString()} references missing model ${reference}`);
1331
+ return model2;
1332
+ });
1333
+ return model ? { ...model, key: Object.assign(new AssetKey("", ""), model.key) } : void 0;
1334
+ }
1335
+ // Item previews use the GUI context, false conditions, and zero numeric properties.
1336
+ static defaultItemModel(node, key) {
1337
+ if (!node || typeof node.type !== "string") {
1338
+ throw new Error(`Unsupported item model definition for ${key.toNamespacedString()}`);
1339
+ }
1340
+ switch (node.type.replace(/^minecraft:/, "")) {
1341
+ case "model":
1342
+ if (typeof node.model === "string" && node.model) return node.model;
1343
+ break;
1344
+ case "condition":
1345
+ return this.defaultItemModel(node.on_false, key);
1346
+ case "select": {
1347
+ const selected = node.property?.replace(/^minecraft:/, "") === "display_context" ? node.cases?.find((entry) => Array.isArray(entry.when) ? entry.when.includes("gui") : entry.when === "gui")?.model : void 0;
1348
+ return this.defaultItemModel(selected ?? node.fallback, key);
1349
+ }
1350
+ case "range_dispatch": {
1351
+ const selected = node.entries?.reduce((match, entry) => {
1352
+ return entry.threshold <= 0 && (!match || entry.threshold >= match.threshold) ? entry : match;
1353
+ }, void 0);
1354
+ return this.defaultItemModel(selected?.model ?? node.fallback, key);
1355
+ }
1356
+ }
1357
+ throw new Error(`Unsupported item model ${node?.type ?? "definition"} for ${key.toNamespacedString()}`);
1358
+ }
1207
1359
  static async getRaw(key) {
1208
1360
  if (!key.assetType) {
1209
1361
  key.assetType = "models";
@@ -1213,7 +1365,7 @@ var _Models = class _Models {
1213
1365
  }
1214
1366
  const keyStr = key.serialize();
1215
1367
  return Caching.rawModelCache.get(keyStr, (k) => {
1216
- return this.PERSISTENT_CACHE.getOrLoad(keyStr, (k1) => {
1368
+ return this.PERSISTENT_CACHE.getOrLoad(AssetLoader.persistentKey(keyStr), (k1) => {
1217
1369
  return AssetLoader.get(key, "model" /* MODEL */);
1218
1370
  });
1219
1371
  }).then((asset) => {
@@ -1242,31 +1394,32 @@ var _Models = class _Models {
1242
1394
  return this.PERSISTENT_CACHE.clear();
1243
1395
  }
1244
1396
  };
1245
- __decorateClass([
1246
- Memoize()
1247
- ], _Models, "getItemList", 1);
1248
- var Models = _Models;
1249
1397
 
1250
1398
  // src/assets/BlockStates.ts
1251
- import { Memoize as Memoize2 } from "typescript-memoize";
1252
1399
  var BlockStates = class {
1253
1400
  static get PERSISTENT_CACHE() {
1254
1401
  return this._persistentCache ??= PersistentCache.open("minerender-blockstates");
1255
1402
  }
1403
+ // BlockState names are hardcoded
1256
1404
  static async getList() {
1257
- return AssetLoader.get(new AssetKey(
1405
+ const key = new AssetKey(
1258
1406
  DEFAULT_NAMESPACE,
1259
1407
  "_list",
1260
1408
  "blockstates",
1261
1409
  void 0,
1262
1410
  "assets",
1263
1411
  ".json",
1264
- DEFAULT_ROOT
1265
- ), "list" /* LIST */).then((r) => (r == null ? void 0 : r.files) ?? []);
1412
+ AssetLoader.ROOT
1413
+ );
1414
+ return Caching.listAssetCache.get(key.serialize(), () => {
1415
+ return AssetLoader.get(key, "list" /* LIST */);
1416
+ }).then((r) => r?.files ?? []);
1266
1417
  }
1267
1418
  static async getDefaultStates() {
1268
1419
  const key = AssetKey.parse("blockstates", "minerender:defaultBlockStates");
1269
- return AssetLoader.get(key, "json" /* JSON */);
1420
+ return Caching.defaultBlockStatesCache.get(key.serialize(), () => {
1421
+ return AssetLoader.get(key, "json" /* JSON */);
1422
+ });
1270
1423
  }
1271
1424
  static async getDefaultState(key) {
1272
1425
  const defaultStates = await this.getDefaultStates();
@@ -1284,7 +1437,7 @@ var BlockStates = class {
1284
1437
  }
1285
1438
  const keyStr = key.serialize();
1286
1439
  return Caching.blockStateCache.get(keyStr, (k) => {
1287
- return this.PERSISTENT_CACHE.getOrLoad(keyStr, (k1) => {
1440
+ return this.PERSISTENT_CACHE.getOrLoad(AssetLoader.persistentKey(keyStr), (k1) => {
1288
1441
  return AssetLoader.get(key, "blockstate" /* BLOCKSTATE */);
1289
1442
  });
1290
1443
  }).then((asset) => {
@@ -1305,17 +1458,11 @@ var BlockStates = class {
1305
1458
  await this.PERSISTENT_CACHE.clear();
1306
1459
  }
1307
1460
  };
1308
- __decorateClass([
1309
- Memoize2()
1310
- ], BlockStates, "getList", 1);
1311
- __decorateClass([
1312
- Memoize2()
1313
- ], BlockStates, "getDefaultStates", 1);
1314
1461
  var DefaultBlockStates = class {
1315
1462
  };
1316
1463
 
1317
1464
  // src/assets/Assets.ts
1318
- var DEFAULT_ROOT = "https://assets.mcasset.cloud/1.17.1";
1465
+ var DEFAULT_ROOT = "https://assets.mcasset.cloud/1.21.11";
1319
1466
  var DEFAULT_NAMESPACE = "minecraft";
1320
1467
  var Assets = class {
1321
1468
  /**
@@ -1330,30 +1477,243 @@ var Assets = class {
1330
1477
  static async getBlockState(key) {
1331
1478
  return BlockStates.get(key);
1332
1479
  }
1333
- };
1334
-
1335
- // src/assets/source/AssetSource.ts
1336
- var AssetSource = class {
1337
- constructor() {
1480
+ };
1481
+
1482
+ // src/assets/source/AssetSource.ts
1483
+ var AssetSource = class {
1484
+ constructor() {
1485
+ }
1486
+ /**
1487
+ * Identifies this source's content across sessions for persistent caching. Sources that
1488
+ * cannot tell whether their content changed (an unnamed archive, for example) return
1489
+ * undefined, which keeps their results out of long-lived caches.
1490
+ */
1491
+ get cacheId() {
1492
+ return void 0;
1493
+ }
1494
+ };
1495
+ var AssetLoadError = class extends Error {
1496
+ constructor(source, key, path, cause) {
1497
+ super(`Failed to load ${key.toNamespacedString()} from ${path}${cause instanceof Error ? `: ${cause.message}` : ""}`);
1498
+ this.source = source;
1499
+ this.key = key;
1500
+ this.path = path;
1501
+ this.cause = cause;
1502
+ this.name = "AssetLoadError";
1503
+ }
1504
+ };
1505
+
1506
+ // src/util/BatchedExecutor.ts
1507
+ var BatchedExecutor = class {
1508
+ constructor(interval = 1, batch = 30) {
1509
+ this.interval = interval;
1510
+ this.batch = batch;
1511
+ this.queue = [];
1512
+ this.task = setInterval(() => this.run());
1513
+ }
1514
+ submit(task) {
1515
+ this.queue.push(task);
1516
+ }
1517
+ run() {
1518
+ for (let i = 0; i < this.batch; i++) {
1519
+ this.runNext();
1520
+ }
1521
+ }
1522
+ runNext() {
1523
+ let next = this.queue.shift();
1524
+ if (next) next();
1525
+ }
1526
+ };
1527
+
1528
+ // src/util/model.ts
1529
+ import { AxesHelper, BoxGeometry as BoxGeometry2, EdgesGeometry, LineBasicMaterial, LineSegments, Vector3 as Vector33 } from "three";
1530
+ function applyElementRotation(rotation, geometry) {
1531
+ const origin = new Vector33(rotation.origin[0], rotation.origin[1], rotation.origin[2]);
1532
+ geometry.translate(-origin.x, -origin.y, -origin.z);
1533
+ switch (rotation.axis) {
1534
+ case "x" /* X */:
1535
+ geometry.rotateX(toRadians(rotation.angle));
1536
+ break;
1537
+ case "y" /* Y */:
1538
+ geometry.rotateY(toRadians(rotation.angle));
1539
+ break;
1540
+ case "z" /* Z */:
1541
+ geometry.rotateZ(toRadians(rotation.angle));
1542
+ break;
1543
+ }
1544
+ if (rotation.rescale) {
1545
+ if (Math.abs(rotation.angle) === 22.5) {
1546
+ const s = 1 / Math.cos(0.39269909262657166);
1547
+ geometry.scale(s, 1, s);
1548
+ } else {
1549
+ const s = 1 / Math.cos(0.7853981852531433);
1550
+ geometry.scale(s, 1, s);
1551
+ }
1552
+ }
1553
+ geometry.translate(origin.x, origin.y, origin.z);
1554
+ }
1555
+ function applyGenericRotation(axis, rotation, obj) {
1556
+ switch (axis) {
1557
+ case "x" /* X */:
1558
+ obj.rotateOnAxis(new Vector33(1, 0, 0), toRadians(rotation));
1559
+ break;
1560
+ case "y" /* Y */:
1561
+ obj.rotateOnAxis(new Vector33(0, 1, 0), toRadians(rotation));
1562
+ break;
1563
+ case "z" /* Z */:
1564
+ obj.rotateOnAxis(new Vector33(0, 0, 1), toRadians(rotation));
1565
+ break;
1566
+ }
1567
+ }
1568
+ function addBox3WireframeToObject(box, obj, color = 16777215, w = 2) {
1569
+ let size = new Vector33();
1570
+ box.getSize(size);
1571
+ let boxGeo = new BoxGeometry2(size.x, size.y, size.z, 1, 1, 1);
1572
+ let wireGeo = new EdgesGeometry(boxGeo);
1573
+ let wireMat = new LineBasicMaterial({ color, linewidth: w });
1574
+ let wireframe = new LineSegments(wireGeo, wireMat);
1575
+ obj.add(wireframe);
1576
+ let axes = new AxesHelper(1);
1577
+ obj.add(axes);
1578
+ }
1579
+ function addWireframeToObject(obj, color = 16777215, w = 2) {
1580
+ let boxGeo = new BoxGeometry2(16, 16, 16, 1, 1, 1);
1581
+ let wireGeo = new EdgesGeometry(boxGeo);
1582
+ let wireMat = new LineBasicMaterial({ color, linewidth: w });
1583
+ let wireframe = new LineSegments(wireGeo, wireMat);
1584
+ obj.add(wireframe);
1585
+ let axes = new AxesHelper(1);
1586
+ obj.add(axes);
1587
+ }
1588
+ function addWireframeToMesh(geo, mesh, color = 16777215, w = 2) {
1589
+ let wireGeo = new EdgesGeometry(geo);
1590
+ let wireMat = new LineBasicMaterial({ color, linewidth: w });
1591
+ let wireframe = new LineSegments(wireGeo, wireMat);
1592
+ mesh.add(wireframe);
1593
+ let axes = new AxesHelper(1);
1594
+ mesh.add(axes);
1595
+ }
1596
+
1597
+ // src/util/performance.ts
1598
+ function captureException(e, ...extra) {
1599
+ console.error(e, extra);
1600
+ }
1601
+ function timingStart(marker) {
1602
+ console.time(marker);
1603
+ }
1604
+ function timingEnd(marker) {
1605
+ console.timeEnd(marker);
1606
+ }
1607
+
1608
+ // src/util/three.ts
1609
+ function isObject3D(obj) {
1610
+ return obj.isObject3D;
1611
+ }
1612
+ function isMesh(obj) {
1613
+ return obj.isMesh;
1614
+ }
1615
+ function isInstancedMesh(obj) {
1616
+ return obj.isInstancedMesh;
1617
+ }
1618
+ function isPerspectiveCamera(obj) {
1619
+ return obj.isPerspectiveCamera;
1620
+ }
1621
+ function isOrthographicCamera(obj) {
1622
+ return obj.isOrthographicCamera;
1623
+ }
1624
+
1625
+ // src/nbt/NBTHelper.ts
1626
+ var NBTHelper = class {
1627
+ static async fromBuffer(buffer) {
1628
+ const prismarineNbt = await import("prismarine-nbt");
1629
+ const { parsed, type, metadata } = await prismarineNbt.parse(buffer);
1630
+ return parsed;
1631
+ }
1632
+ };
1633
+
1634
+ // src/assets/source/HostedAssetSource.ts
1635
+ var import_ts_deepmerge2 = __toESM(require_dist());
1636
+ var p3 = prefix("HostedAssetSource");
1637
+ var DEFAULT_OPTIONS = {
1638
+ retryDefaults: true
1639
+ };
1640
+ var HostedAssetSource = class _HostedAssetSource extends AssetSource {
1641
+ static {
1642
+ this.MODEL = {
1643
+ config(request) {
1644
+ },
1645
+ parse(response) {
1646
+ return response.data;
1647
+ }
1648
+ };
1649
+ }
1650
+ static {
1651
+ this.BLOCKSTATE = {
1652
+ config(request) {
1653
+ },
1654
+ parse(response) {
1655
+ return response.data;
1656
+ }
1657
+ };
1658
+ }
1659
+ static {
1660
+ this.META = {
1661
+ config(request) {
1662
+ },
1663
+ parse(response) {
1664
+ return response.data;
1665
+ }
1666
+ };
1667
+ }
1668
+ static {
1669
+ this.NBT = {
1670
+ config(request) {
1671
+ request.responseType = "arraybuffer";
1672
+ },
1673
+ parse(response) {
1674
+ return NBTHelper.fromBuffer(Buffer.from(response.data));
1675
+ }
1676
+ };
1677
+ }
1678
+ static {
1679
+ this.IMAGE = {
1680
+ config(request) {
1681
+ request.responseType = "arraybuffer";
1682
+ },
1683
+ async parse(response) {
1684
+ return await ImageLoader.processResponse(response);
1685
+ }
1686
+ };
1687
+ }
1688
+ static {
1689
+ this.LIST = {
1690
+ config(request) {
1691
+ },
1692
+ parse(response) {
1693
+ return response.data;
1694
+ }
1695
+ };
1696
+ }
1697
+ static {
1698
+ this.JSON = {
1699
+ config(request) {
1700
+ },
1701
+ parse(response) {
1702
+ return response.data;
1703
+ }
1704
+ };
1338
1705
  }
1339
- };
1340
-
1341
- // src/nbt/NBTHelper.ts
1342
- var NBTHelper = class {
1343
- static async fromBuffer(buffer) {
1344
- const prismarineNbt = await import("prismarine-nbt");
1345
- const { parsed, type, metadata } = await prismarineNbt.parse(buffer);
1346
- return parsed;
1706
+ static {
1707
+ this.PARSER_MAP = /* @__PURE__ */ new Map([
1708
+ ["model" /* MODEL */, _HostedAssetSource.MODEL],
1709
+ ["blockstate" /* BLOCKSTATE */, _HostedAssetSource.BLOCKSTATE],
1710
+ ["meta" /* META */, _HostedAssetSource.META],
1711
+ ["nbt" /* NBT */, _HostedAssetSource.NBT],
1712
+ ["image" /* IMAGE */, _HostedAssetSource.IMAGE],
1713
+ ["list" /* LIST */, _HostedAssetSource.LIST],
1714
+ ["json" /* JSON */, _HostedAssetSource.JSON]
1715
+ ]);
1347
1716
  }
1348
- };
1349
-
1350
- // src/assets/source/HostedAssetSource.ts
1351
- var import_ts_deepmerge2 = __toESM(require_dist());
1352
- var p3 = prefix("HostedAssetSource");
1353
- var DEFAULT_OPTIONS = {
1354
- retryDefaults: true
1355
- };
1356
- var _HostedAssetSource = class _HostedAssetSource extends AssetSource {
1357
1717
  async loadOrRetryWithDefaults(key, parser) {
1358
1718
  const direct = await this.load(key, parser);
1359
1719
  if (typeof direct !== "undefined") {
@@ -1366,17 +1726,17 @@ var _HostedAssetSource = class _HostedAssetSource extends AssetSource {
1366
1726
  if (typeof namespaced !== "undefined") {
1367
1727
  return namespaced;
1368
1728
  }
1369
- if (typeof key.root !== "undefined" && key.root !== DEFAULT_ROOT || typeof this.root !== "undefined" && this.root !== DEFAULT_ROOT) {
1729
+ if (typeof key.root !== "undefined" && key.root !== AssetLoader.ROOT || typeof this.root !== "undefined" && this.root !== AssetLoader.ROOT) {
1370
1730
  console.info(p3, "Retrying", key, "with default root+namespace");
1371
- const namespacedRootedKey = new AssetKey(DEFAULT_NAMESPACE, key.path, key.assetType, key.type, key.rootType, key.extension, DEFAULT_ROOT);
1731
+ const namespacedRootedKey = new AssetKey(DEFAULT_NAMESPACE, key.path, key.assetType, key.type, key.rootType, key.extension, AssetLoader.ROOT);
1372
1732
  const namespacedRooted = await this.load(namespacedRootedKey, parser);
1373
1733
  if (typeof namespacedRooted !== "undefined") {
1374
1734
  return namespacedRooted;
1375
1735
  }
1376
1736
  }
1377
- } else if (typeof key.root !== "undefined" && key.root !== DEFAULT_ROOT || typeof this.root !== "undefined" && this.root !== DEFAULT_ROOT) {
1737
+ } else if (typeof key.root !== "undefined" && key.root !== AssetLoader.ROOT || typeof this.root !== "undefined" && this.root !== AssetLoader.ROOT) {
1378
1738
  console.info(p3, "Retrying", key, "with default root");
1379
- const rootKey = new AssetKey(key.namespace, key.path, key.assetType, key.type, key.rootType, key.extension, DEFAULT_ROOT);
1739
+ const rootKey = new AssetKey(key.namespace, key.path, key.assetType, key.type, key.rootType, key.extension, AssetLoader.ROOT);
1380
1740
  const rooted = await this.load(rootKey, parser);
1381
1741
  if (typeof rooted !== "undefined") {
1382
1742
  return rooted;
@@ -1388,31 +1748,25 @@ var _HostedAssetSource = class _HostedAssetSource extends AssetSource {
1388
1748
  console.info(p3, "Loading", key);
1389
1749
  const url = `${this.assetBasePath(key)}${key.type !== void 0 ? key.type + "/" : ""}${key.path}${key.extension}`;
1390
1750
  console.debug(p3, url);
1391
- let req = {
1392
- url
1393
- };
1394
- parser.config(req);
1395
- return await Requests.mcAssetRequest(req).then((response) => {
1396
- if (response && response.data) {
1397
- try {
1398
- return parser.parse(response);
1399
- } catch (e) {
1400
- console.warn("Parser failed to process response", response, e);
1401
- throw e;
1402
- }
1403
- }
1404
- return void 0;
1405
- }).catch((err) => {
1406
- if (err.response) {
1407
- let response = err.response;
1408
- if (response.status === 404) {
1409
- console.debug(p3, key, "not found");
1751
+ const request = { url };
1752
+ try {
1753
+ parser.config(request);
1754
+ let response;
1755
+ try {
1756
+ response = await Requests.mcAssetRequest(request);
1757
+ } catch (cause) {
1758
+ if (cause instanceof RequestError && cause.response?.status === 404) {
1410
1759
  return void 0;
1411
1760
  }
1761
+ throw cause;
1412
1762
  }
1413
- console.debug(p3, "Failed to load", key, err == null ? void 0 : err.message);
1414
- return void 0;
1415
- });
1763
+ if (response.data === void 0) {
1764
+ throw new Error("Asset response has no data");
1765
+ }
1766
+ return await parser.parse(response);
1767
+ } catch (cause) {
1768
+ throw new AssetLoadError(this, key, request.url, cause);
1769
+ }
1416
1770
  }
1417
1771
  assetBasePath(key) {
1418
1772
  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 + "/" : ""}`;
@@ -1425,6 +1779,9 @@ var _HostedAssetSource = class _HostedAssetSource extends AssetSource {
1425
1779
  get root() {
1426
1780
  return this._root;
1427
1781
  }
1782
+ get cacheId() {
1783
+ return `hosted:${this._root}`;
1784
+ }
1428
1785
  get options() {
1429
1786
  return this._options;
1430
1787
  }
@@ -1436,74 +1793,14 @@ var _HostedAssetSource = class _HostedAssetSource extends AssetSource {
1436
1793
  return this.load(key, responseParser);
1437
1794
  }
1438
1795
  };
1439
- _HostedAssetSource.MODEL = {
1440
- config(request) {
1441
- },
1442
- parse(response) {
1443
- return response.data;
1444
- }
1445
- };
1446
- _HostedAssetSource.BLOCKSTATE = {
1447
- config(request) {
1448
- },
1449
- parse(response) {
1450
- return response.data;
1451
- }
1452
- };
1453
- _HostedAssetSource.META = {
1454
- config(request) {
1455
- },
1456
- parse(response) {
1457
- return response.data;
1458
- }
1459
- };
1460
- _HostedAssetSource.NBT = {
1461
- config(request) {
1462
- request.responseType = "arraybuffer";
1463
- },
1464
- parse(response) {
1465
- return NBTHelper.fromBuffer(Buffer.from(response.data));
1466
- }
1467
- };
1468
- _HostedAssetSource.IMAGE = {
1469
- config(request) {
1470
- request.responseType = "arraybuffer";
1471
- },
1472
- async parse(response) {
1473
- return await ImageLoader.processResponse(response);
1474
- }
1475
- };
1476
- _HostedAssetSource.LIST = {
1477
- config(request) {
1478
- },
1479
- parse(response) {
1480
- return response.data;
1481
- }
1482
- };
1483
- _HostedAssetSource.JSON = {
1484
- config(request) {
1485
- },
1486
- parse(response) {
1487
- return response.data;
1488
- }
1489
- };
1490
- _HostedAssetSource.PARSER_MAP = /* @__PURE__ */ new Map([
1491
- ["model" /* MODEL */, _HostedAssetSource.MODEL],
1492
- ["blockstate" /* BLOCKSTATE */, _HostedAssetSource.BLOCKSTATE],
1493
- ["meta" /* META */, _HostedAssetSource.META],
1494
- ["nbt" /* NBT */, _HostedAssetSource.NBT],
1495
- ["image" /* IMAGE */, _HostedAssetSource.IMAGE],
1496
- ["list" /* LIST */, _HostedAssetSource.LIST],
1497
- ["json" /* JSON */, _HostedAssetSource.JSON]
1498
- ]);
1499
- var HostedAssetSource = _HostedAssetSource;
1500
1796
 
1501
1797
  // src/assets/source/archive/BrowserArchiveProxy.ts
1502
1798
  import { BlobReader, BlobWriter, ZipReader } from "@zip.js/zip.js";
1503
1799
  var BrowserArchiveProxy = class {
1504
- constructor(blob) {
1800
+ constructor(blob, id) {
1505
1801
  this._blob = blob;
1506
1802
  this._reader = new ZipReader(new BlobReader(this._blob));
1803
+ this.id = id ?? (typeof File !== "undefined" && blob instanceof File ? `${blob.name}:${blob.size}:${blob.lastModified}` : void 0);
1507
1804
  }
1508
1805
  async getEntries() {
1509
1806
  return (await this._reader.getEntries()).map((e) => {
@@ -1519,7 +1816,6 @@ var BrowserArchiveProxy = class {
1519
1816
  };
1520
1817
 
1521
1818
  // src/assets/source/archive/ArchiveAssetSource.ts
1522
- var p4 = prefix("ArchiveAssetSource");
1523
1819
  var ArchiveAssetSource = class _ArchiveAssetSource extends AssetSource {
1524
1820
  constructor(archiveProxy) {
1525
1821
  super();
@@ -1529,6 +1825,10 @@ var ArchiveAssetSource = class _ArchiveAssetSource extends AssetSource {
1529
1825
  static blob(blob) {
1530
1826
  return new _ArchiveAssetSource(new BrowserArchiveProxy(blob));
1531
1827
  }
1828
+ get cacheId() {
1829
+ const id = this._archiveProxy.id;
1830
+ return id === void 0 ? void 0 : `archive:${id}`;
1831
+ }
1532
1832
  async getEntries() {
1533
1833
  return this._archiveProxy.getEntries();
1534
1834
  }
@@ -1538,74 +1838,31 @@ var ArchiveAssetSource = class _ArchiveAssetSource extends AssetSource {
1538
1838
  }
1539
1839
  async get(key, parser) {
1540
1840
  const responseParser = HostedAssetSource.PARSER_MAP.get(parser);
1541
- console.log("ArchiveAssetSource.get", key, parser);
1542
- let entries = await this.getEntries();
1543
- const path = `${this.assetBasePath(key)}${key.type !== void 0 ? key.type + "/" : ""}${key.path}${key.extension}`;
1544
- console.log(path);
1545
- const entry = await this.getEntry(path);
1546
- console.log(entry);
1547
- if (!entry) {
1548
- return void 0;
1549
- }
1550
- let blob = await entry.getData();
1551
- const url = URL.createObjectURL(blob);
1552
- console.log(url);
1553
- let req = {
1554
- url
1555
- };
1556
- responseParser.config(req);
1557
- return Requests.genericRequest(req).then((response) => {
1558
- if (response && response.data) {
1559
- try {
1560
- return responseParser.parse(response);
1561
- } catch (e) {
1562
- console.warn("Parser failed to process response", response, e);
1563
- throw e;
1564
- }
1565
- }
1566
- return void 0;
1567
- }).catch((err) => {
1568
- if (err.response) {
1569
- let response = err.response;
1570
- if (response.status === 404) {
1571
- console.debug(p4, key, "not found");
1572
- return void 0;
1573
- }
1574
- }
1575
- console.debug(p4, "Failed to load", key, err == null ? void 0 : err.message);
1576
- return void 0;
1577
- });
1841
+ return this.load(key, responseParser);
1578
1842
  }
1579
- //TODO: abstract this
1580
1843
  async load(key, parser) {
1581
- console.info(p4, "Loading", key);
1582
- const url = `${this.assetBasePath(key)}${key.type !== void 0 ? key.type + "/" : ""}${key.path}${key.extension}`;
1583
- console.debug(p4, url);
1584
- let req = {
1585
- url
1586
- };
1587
- parser.config(req);
1588
- return await Requests.genericRequest(req).then((response) => {
1589
- if (response && response.data) {
1590
- try {
1591
- return parser.parse(response);
1592
- } catch (e) {
1593
- console.warn("Parser failed to process response", response, e);
1594
- throw e;
1595
- }
1844
+ const path = `${this.assetBasePath(key)}${key.type !== void 0 ? key.type + "/" : ""}${key.path}${key.extension}`;
1845
+ let url;
1846
+ try {
1847
+ const entry = await this.getEntry(path);
1848
+ if (!entry) {
1849
+ return void 0;
1596
1850
  }
1597
- return void 0;
1598
- }).catch((err) => {
1599
- if (err.response) {
1600
- let response = err.response;
1601
- if (response.status === 404) {
1602
- console.debug(p4, key, "not found");
1603
- return void 0;
1604
- }
1851
+ url = URL.createObjectURL(await entry.getData());
1852
+ const request = { url };
1853
+ parser.config(request);
1854
+ const response = await Requests.genericRequest(request);
1855
+ if (response.data === void 0) {
1856
+ throw new Error("Asset response has no data");
1605
1857
  }
1606
- console.debug(p4, "Failed to load", key, err == null ? void 0 : err.message);
1607
- return void 0;
1608
- });
1858
+ return await parser.parse(response);
1859
+ } catch (cause) {
1860
+ throw new AssetLoadError(this, key, path, cause);
1861
+ } finally {
1862
+ if (url !== void 0) {
1863
+ URL.revokeObjectURL(url);
1864
+ }
1865
+ }
1609
1866
  }
1610
1867
  assetBasePath(key) {
1611
1868
  return `${key.rootType !== void 0 ? key.rootType + "/" : ""}${key.namespace !== void 0 ? key.namespace + "/" : ""}${key.assetType !== void 0 ? key.assetType + "/" : ""}`;
@@ -1613,18 +1870,64 @@ var ArchiveAssetSource = class _ArchiveAssetSource extends AssetSource {
1613
1870
  };
1614
1871
 
1615
1872
  // src/assets/AssetLoader.ts
1616
- var import_ts_deepmerge3 = __toESM(require_dist());
1617
- var p5 = prefix("AssetLoader");
1618
- var _AssetLoader = class _AssetLoader {
1873
+ var p4 = prefix("AssetLoader");
1874
+ var FALLBACK_ROOT = "https://raw.githubusercontent.com/InventivetalentDev/minerender-fallback-assets/master";
1875
+ var AssetLoader = class {
1876
+ static {
1877
+ this.ROOT = DEFAULT_ROOT;
1878
+ }
1879
+ static {
1880
+ this._SOURCES = [];
1881
+ }
1882
+ static {
1883
+ /** Used when a registered source cannot identify its content, so nothing persists past this session. */
1884
+ this.SESSION_SCOPE = `session:${Date.now().toString(36)}:${Math.random().toString(36).slice(2)}`;
1885
+ }
1886
+ static get version() {
1887
+ return this.ROOT.substring(this.ROOT.lastIndexOf("/") + 1);
1888
+ }
1889
+ static setVersion(version) {
1890
+ this.ROOT = `https://assets.mcasset.cloud/${version}`;
1891
+ const source = new HostedAssetSource(this.ROOT, { retryDefaults: false });
1892
+ const index = this._SOURCES.findIndex((s) => s.key === "mcassets");
1893
+ if (index !== -1) {
1894
+ this._SOURCES[index] = { key: "mcassets", source };
1895
+ } else {
1896
+ this.addSource("mcassets", source);
1897
+ }
1898
+ Caching.clear();
1899
+ }
1900
+ /**
1901
+ * Scope for persistent cache keys. Empty with only the default vanilla sources, so their
1902
+ * entries stay valid across sessions; otherwise it names every added source (resource packs,
1903
+ * mirrors) so their results never masquerade as vanilla assets after a reload.
1904
+ */
1905
+ static get persistentScope() {
1906
+ const parts = [];
1907
+ for (const { key, source } of this._SOURCES) {
1908
+ const id = source.cacheId;
1909
+ if (key === "mcassets" && id === `hosted:${this.ROOT}`) continue;
1910
+ if (key === "mcassets-fallback" && id === `hosted:${FALLBACK_ROOT}`) continue;
1911
+ if (id === void 0) return this.SESSION_SCOPE;
1912
+ parts.push(`${key}=${id}`);
1913
+ }
1914
+ return parts.join("|");
1915
+ }
1916
+ /** Prefixes a persistent cache key with the current source scope. */
1917
+ static persistentKey(key) {
1918
+ const scope = this.persistentScope;
1919
+ return scope ? `${scope}
1920
+ ${key}` : key;
1921
+ }
1619
1922
  static addSource(key, source, override = true) {
1620
1923
  if (override) {
1621
1924
  const existing = this.removeSource(key);
1622
1925
  if (existing) {
1623
- console.log(p5, "Removed existing AssetSource", key);
1926
+ console.log(p4, "Removed existing AssetSource", key);
1624
1927
  }
1625
1928
  }
1626
1929
  this._SOURCES.unshift({ key, source });
1627
- console.log(p5, "Added AssetSource", key);
1930
+ console.log(p4, "Added AssetSource", key);
1628
1931
  }
1629
1932
  static removeSource(key) {
1630
1933
  const index = this._SOURCES.findIndex((s) => s.key === key);
@@ -1636,8 +1939,11 @@ var _AssetLoader = class _AssetLoader {
1636
1939
  }
1637
1940
  return void 0;
1638
1941
  }
1942
+ static {
1943
+ this.addSource("mcassets-fallback", new HostedAssetSource(FALLBACK_ROOT, { retryDefaults: false }));
1944
+ this.addSource("mcassets", new HostedAssetSource(this.ROOT, { retryDefaults: false }));
1945
+ }
1639
1946
  static async getAll(key, parser) {
1640
- console.log(this._SOURCES);
1641
1947
  let promises = [];
1642
1948
  for (const source of this._SOURCES) {
1643
1949
  promises.push(source.source.get(key, parser));
@@ -1646,31 +1952,36 @@ var _AssetLoader = class _AssetLoader {
1646
1952
  return results.filter((r) => r != void 0);
1647
1953
  });
1648
1954
  }
1955
+ /** Returns the first defined result in source-priority order, without merging assets. */
1649
1956
  static async get(key, parser) {
1650
- console.log(this._SOURCES);
1651
- let promises = [];
1652
- for (const source of this._SOURCES) {
1653
- promises.push(source.source.get(key, parser));
1654
- }
1655
- return Promise.all(promises).then((results) => {
1656
- const fallback = results[results.length - 1];
1657
- for (const result of results) {
1658
- if (result) {
1659
- if (fallback) {
1660
- return (0, import_ts_deepmerge3.default)({}, fallback, result);
1661
- }
1662
- return result;
1957
+ const keys = [key];
1958
+ if (key.rootType === "data" && (key.assetType === "structure" || key.assetType === "structures")) {
1959
+ keys.push(new AssetKey(
1960
+ key.namespace,
1961
+ key.path,
1962
+ key.assetType === "structure" ? "structures" : "structure",
1963
+ key.type,
1964
+ key.rootType,
1965
+ key.extension,
1966
+ key.root
1967
+ ));
1968
+ }
1969
+ return (await this.getFirst(keys, parser))?.asset;
1970
+ }
1971
+ /** Tries each path within a source before considering lower-priority sources. */
1972
+ static async getFirst(keys, parser) {
1973
+ const sources = [...this._SOURCES];
1974
+ for (const source of sources) {
1975
+ for (const key of keys) {
1976
+ const result = await source.source.get(key, parser);
1977
+ if (result !== void 0) {
1978
+ return { key, asset: result };
1663
1979
  }
1664
1980
  }
1665
- return void 0;
1666
- });
1981
+ }
1982
+ return void 0;
1667
1983
  }
1668
1984
  };
1669
- _AssetLoader.ROOT = DEFAULT_ROOT;
1670
- _AssetLoader._SOURCES = [];
1671
- _AssetLoader.addSource("mcassets-fallback", new HostedAssetSource("https://raw.githubusercontent.com/InventivetalentDev/minerender-fallback-assets/master", { retryDefaults: false }));
1672
- _AssetLoader.addSource("mcassets", new HostedAssetSource(DEFAULT_ROOT, { retryDefaults: false }));
1673
- var AssetLoader = _AssetLoader;
1674
1985
 
1675
1986
  // src/assets/ModelTextures.ts
1676
1987
  var ModelTextures = class {
@@ -1678,11 +1989,21 @@ var ModelTextures = class {
1678
1989
  return this._persistentMetaCache ??= PersistentCache.open("minerender-texturemeta");
1679
1990
  }
1680
1991
  static async get(key) {
1681
- const asset = await this.preload(key);
1682
- if (asset) {
1683
- return ImageLoader.infoToCanvasData(asset);
1992
+ const keyStr = key.serialize();
1993
+ const pending = this.preload(key);
1994
+ const cached = Caching.textureAssetCache.getIfPresent(keyStr);
1995
+ try {
1996
+ const asset = await pending;
1997
+ if (asset) {
1998
+ return await ImageLoader.infoToCanvasData(asset);
1999
+ }
2000
+ return void 0;
2001
+ } catch (err) {
2002
+ if (cached && Caching.textureAssetCache.getIfPresent(keyStr) === cached) {
2003
+ Caching.textureAssetCache.invalidate(keyStr);
2004
+ }
2005
+ throw err;
1684
2006
  }
1685
- return void 0;
1686
2007
  }
1687
2008
  static async preload(key) {
1688
2009
  const keyStr = key.serialize();
@@ -1701,7 +2022,7 @@ var ModelTextures = class {
1701
2022
  }
1702
2023
  const keyStr = key.serialize();
1703
2024
  return Caching.textureMetaCache.get(keyStr, (k) => {
1704
- return this.PERSISTENT_META_CACHE.getOrLoad(keyStr, (k1) => {
2025
+ return this.PERSISTENT_META_CACHE.getOrLoad(AssetLoader.persistentKey(keyStr), (k1) => {
1705
2026
  return AssetLoader.get(key, "meta" /* META */).then((asset) => {
1706
2027
  if (asset)
1707
2028
  asset.key = key;
@@ -1756,7 +2077,28 @@ var CanvasImage = class {
1756
2077
  };
1757
2078
 
1758
2079
  // src/Ticker.ts
1759
- var _Ticker = class _Ticker {
2080
+ var Ticker = class _Ticker {
2081
+ static {
2082
+ this.TPS = 20;
2083
+ }
2084
+ static {
2085
+ this.counter = 0;
2086
+ }
2087
+ static {
2088
+ this._tickers = /* @__PURE__ */ new Map();
2089
+ }
2090
+ static {
2091
+ this.oneSecondTps = 0;
2092
+ }
2093
+ static {
2094
+ this.oneSecondTicks = 0;
2095
+ }
2096
+ static {
2097
+ this.fiveSecondTps = 0;
2098
+ }
2099
+ static {
2100
+ this.fiveSecondTicks = 0;
2101
+ }
1760
2102
  static schedule(fn, ms) {
1761
2103
  const handle = setInterval(fn, ms);
1762
2104
  const unref = handle.unref;
@@ -1818,14 +2160,6 @@ var _Ticker = class _Ticker {
1818
2160
  this._tickers.clear();
1819
2161
  }
1820
2162
  };
1821
- _Ticker.TPS = 20;
1822
- _Ticker.counter = 0;
1823
- _Ticker._tickers = /* @__PURE__ */ new Map();
1824
- _Ticker.oneSecondTps = 0;
1825
- _Ticker.oneSecondTicks = 0;
1826
- _Ticker.fiveSecondTps = 0;
1827
- _Ticker.fiveSecondTicks = 0;
1828
- var Ticker = _Ticker;
1829
2163
 
1830
2164
  // src/texture/TextureAtlas.ts
1831
2165
  var TextureAtlas = class {
@@ -1851,18 +2185,24 @@ var TextureAtlas = class {
1851
2185
 
1852
2186
  // src/model/ModelGenerator.ts
1853
2187
  var ModelGenerator = class {
2188
+ static {
2189
+ this.ITEM_LAYERS = ["layer0", "layer1", "layer2", "layer3", "layer4"];
2190
+ }
1854
2191
  static generateItemModel(imageData, layer) {
2192
+ const tintindex = this.ITEM_LAYERS.indexOf(layer);
1855
2193
  const mainElement = {
1856
2194
  from: [0, 0, 7.5],
1857
2195
  to: [16, 16, 8.5],
1858
2196
  faces: {
1859
2197
  "south": {
1860
2198
  uv: [0, 0, 16, 16],
1861
- texture: `#${layer}`
2199
+ texture: `#${layer}`,
2200
+ tintindex
1862
2201
  },
1863
2202
  "north": {
1864
2203
  uv: [16, 0, 0, 16],
1865
- texture: `#${layer}`
2204
+ texture: `#${layer}`,
2205
+ tintindex
1866
2206
  }
1867
2207
  },
1868
2208
  shade: true
@@ -1870,14 +2210,21 @@ var ModelGenerator = class {
1870
2210
  return [mainElement];
1871
2211
  }
1872
2212
  };
1873
- ModelGenerator.ITEM_LAYERS = ["layer0", "layer1", "layer2", "layer3", "layer4"];
1874
2213
 
1875
2214
  // src/UVMapper.ts
1876
- var p6 = prefix("UVMapper");
2215
+ var p5 = prefix("UVMapper");
1877
2216
  var DEFAULT_UV = [0, 0, 16, 16];
1878
2217
  var X = 0;
1879
2218
  var Y = 1;
1880
2219
  var Z = 2;
2220
+ var FACE_UV_AXES = {
2221
+ east: [new Vector34(0, 0, -1), new Vector34(0, -1, 0)],
2222
+ west: [new Vector34(0, 0, 1), new Vector34(0, -1, 0)],
2223
+ up: [new Vector34(1, 0, 0), new Vector34(0, 0, 1)],
2224
+ down: [new Vector34(1, 0, 0), new Vector34(0, 0, -1)],
2225
+ south: [new Vector34(1, 0, 0), new Vector34(0, -1, 0)],
2226
+ north: [new Vector34(-1, 0, 0), new Vector34(0, -1, 0)]
2227
+ };
1881
2228
  var UVMapper = class {
1882
2229
  static makeUv(uvCoord, originalTextureSize, actualTextureSize) {
1883
2230
  if (uvCoord === 0) return 0;
@@ -1975,6 +2322,42 @@ var UVMapper = class {
1975
2322
  static facesToUv(faces, originalTextureSize, actualTextureSize) {
1976
2323
  return new Float32BufferAttribute2(this.facesToUvArray(faces, originalTextureSize, actualTextureSize), 2);
1977
2324
  }
2325
+ static lockUvs(geometry, faces, atlas, rotation) {
2326
+ const uv = geometry.getAttribute("uv");
2327
+ for (let faceIndex = 0; faceIndex < CUBE_FACES.length; faceIndex++) {
2328
+ const faceName = CUBE_FACES[faceIndex];
2329
+ const texture = faces[faceName]?.texture?.substring(1);
2330
+ const position = texture && atlas.positions[texture];
2331
+ const size = texture && atlas.sizes[texture];
2332
+ if (!position || !size) continue;
2333
+ const [sourceU, sourceV] = FACE_UV_AXES[faceName];
2334
+ const uAxis = sourceU.clone().applyEuler(rotation);
2335
+ const vAxis = sourceV.clone().applyEuler(rotation);
2336
+ const normal = vAxis.clone().cross(uAxis);
2337
+ const targetFace = CUBE_FACES.find((name) => {
2338
+ const [u, v] = FACE_UV_AXES[name];
2339
+ return v.clone().cross(u).dot(normal) > 0.5;
2340
+ });
2341
+ const [targetU, targetV] = FACE_UV_AXES[targetFace];
2342
+ const uu = Math.round(targetU.dot(uAxis));
2343
+ const uvCross = Math.round(targetU.dot(vAxis));
2344
+ const vu = Math.round(targetV.dot(uAxis));
2345
+ const vv = Math.round(targetV.dot(vAxis));
2346
+ for (let corner = 0; corner < 4; corner++) {
2347
+ const index = faceIndex * 4 + corner;
2348
+ const u = (uv.getX(index) * atlas.image.width - position[0]) / size[0] - 0.5;
2349
+ const v = ((1 - uv.getY(index)) * atlas.image.height - position[1]) / size[1] - 0.5;
2350
+ const lockedU = uu * u + uvCross * v + 0.5;
2351
+ const lockedV = vu * u + vv * v + 0.5;
2352
+ uv.setXY(
2353
+ index,
2354
+ (position[0] + lockedU * size[0]) / atlas.image.width,
2355
+ 1 - (position[1] + lockedV * size[1]) / atlas.image.height
2356
+ );
2357
+ }
2358
+ }
2359
+ uv.needsUpdate = true;
2360
+ }
1978
2361
  static async getAtlas(model) {
1979
2362
  const keyStr = model.key.serialize();
1980
2363
  return Caching.modelTextureAtlasCache.get(keyStr, (k) => {
@@ -2046,12 +2429,11 @@ var UVMapper = class {
2046
2429
  return [tl, tr, bl, br];
2047
2430
  }
2048
2431
  static async createAtlas(originalModel) {
2049
- var _a;
2050
2432
  const textureMap = {};
2051
2433
  const metaMap = {};
2052
2434
  const model = { ...originalModel };
2053
2435
  const isItemModel = !("elements" in model);
2054
- console.debug(p6, "Creating Atlas for", model.key);
2436
+ console.debug(p5, "Creating Atlas for", model.key);
2055
2437
  if (model.textures) {
2056
2438
  const promises = [];
2057
2439
  const uniqueTextureNames = [];
@@ -2065,7 +2447,7 @@ var UVMapper = class {
2065
2447
  const assetKey = AssetKey.parse("textures", textureValue, model.key);
2066
2448
  promises.push(ModelTextures.get(assetKey).then((asset) => {
2067
2449
  if (!asset) {
2068
- console.warn(p6, "Missing texture", assetKey);
2450
+ console.warn(p5, "Missing texture", assetKey);
2069
2451
  return;
2070
2452
  }
2071
2453
  textureMap[textureKey] = new WrappedImage(asset);
@@ -2077,7 +2459,7 @@ var UVMapper = class {
2077
2459
  }
2078
2460
  await Promise.all(promises);
2079
2461
  const textureCount = uniqueTextureNames.length;
2080
- console.debug(p6, "Creating Atlas for", textureCount, "textures");
2462
+ console.debug(p5, "Creating Atlas for", textureCount, "textures");
2081
2463
  this.fillMissingTextureKeys(model.textures, textureMap);
2082
2464
  this.fillMissingTextureKeys(model.textures, metaMap);
2083
2465
  const sizes = {};
@@ -2097,7 +2479,7 @@ var UVMapper = class {
2097
2479
  this.fillMissingTextureKeys(model.textures, sizes);
2098
2480
  const s = Math.ceil(Math.sqrt(textureCount + 1));
2099
2481
  const size = Math.ceil(s * maxWidth);
2100
- console.debug(p6, "Atlas size:", size);
2482
+ console.debug(p5, "Atlas size:", size);
2101
2483
  const squaredSize = size * size;
2102
2484
  const missing = await ImageLoader.getData("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABAAQMAAACQp+OdAAAABlBMVEX/AP8AAACfphTyAAAAFUlEQVQoz2MIhQKGVVAwKjIqQrwIAHRz/wFI17TEAAAAAElFTkSuQmCC");
2103
2485
  const empty = await ImageLoader.getData("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABAAQMAAACQp+OdAAAAA1BMVEUAAACnej3aAAAAAXRSTlMAQObYZgAAAA5JREFUKM9jGAWjgAIAAAJAAAFSSwuTAAAAAElFTkSuQmCC");
@@ -2126,16 +2508,15 @@ var UVMapper = class {
2126
2508
  if (texture.animated) {
2127
2509
  hasAnimation = true;
2128
2510
  const meta = metaMap[textureKey];
2129
- const frameTime = ((_a = meta == null ? void 0 : meta.animation) == null ? void 0 : _a.frametime) ?? 1;
2511
+ const frameTime = meta?.animation?.frametime ?? 1;
2130
2512
  console.log(meta);
2131
2513
  console.log(frameTime);
2132
2514
  let t = 0;
2133
2515
  let f = 0;
2134
2516
  animatorFunctions[textureKey] = () => {
2135
- var _a2;
2136
2517
  if (t++ >= frameTime) {
2137
2518
  t = 0;
2138
- const frames = (_a2 = meta == null ? void 0 : meta.animation) == null ? void 0 : _a2.frames;
2519
+ const frames = meta?.animation?.frames;
2139
2520
  const frame = frames ? frames[f] : f;
2140
2521
  image.putData(texture.getFrameSectionData(frame), x, y, 0, 0, maxWidth, maxWidth);
2141
2522
  f++;
@@ -2153,10 +2534,10 @@ var UVMapper = class {
2153
2534
  }
2154
2535
  }
2155
2536
  const atlasImageData = image.toDataURL();
2156
- console.log(p6, "Atlas Image for", model.key, atlasImageData);
2537
+ console.log(p5, "Atlas Image for", model.key, atlasImageData);
2157
2538
  this.fillMissingTextureKeys(model.textures, positions);
2158
2539
  if (isItemModel) {
2159
- console.debug(p6, "Generating item model for", model);
2540
+ console.debug(p5, "Generating item model for", model);
2160
2541
  model.elements = [];
2161
2542
  for (let layerName of ModelGenerator.ITEM_LAYERS) {
2162
2543
  const textureImage = textureMap[layerName];
@@ -2164,7 +2545,7 @@ var UVMapper = class {
2164
2545
  model.elements.push(...ModelGenerator.generateItemModel(textureImage.data, layerName));
2165
2546
  }
2166
2547
  }
2167
- console.debug(p6, "Item model elements", model.elements);
2548
+ console.debug(p5, "Item model elements", model.elements);
2168
2549
  }
2169
2550
  if (!model.elements) {
2170
2551
  }
@@ -2182,17 +2563,13 @@ var UVMapper = class {
2182
2563
  this.setCubeFaceUvInArray(uv, faceIndex * 4, [0, 1, 8 / size, (size - 8) / size]);
2183
2564
  continue;
2184
2565
  }
2566
+ if (!face.texture) continue;
2185
2567
  if (!face.uv) {
2186
2568
  face.uv = this.getFallbackUv(element, faceName);
2187
2569
  }
2188
- let faceTexture = face.texture;
2189
- let texPosition;
2190
- let texSize;
2191
- if (faceTexture) {
2192
- faceTexture = faceTexture.substr(1);
2193
- texPosition = positions[faceTexture] || [0, 0];
2194
- texSize = sizes[faceTexture] || [16, 16];
2195
- }
2570
+ const faceTexture = face.texture.substr(1);
2571
+ const texPosition = positions[faceTexture] || [0, 0];
2572
+ const texSize = sizes[faceTexture] || [16, 16];
2196
2573
  let texPosV = new Vector2(texPosition[0], texPosition[1]);
2197
2574
  const [tl, tr, bl, br] = this.expandAndRotateMcUvs(face.uv, face.rotation, texSize[0], texSize[1]);
2198
2575
  tl.add(texPosV);
@@ -2224,7 +2601,7 @@ var UVMapper = class {
2224
2601
  hasTransparency
2225
2602
  );
2226
2603
  } else {
2227
- console.warn(p6, "Model does not have any textures", model);
2604
+ console.warn(p5, "Model does not have any textures", model);
2228
2605
  }
2229
2606
  return void 0;
2230
2607
  }
@@ -2266,18 +2643,18 @@ var MinecraftCubeTexture = class {
2266
2643
  }
2267
2644
  getUvEast(w, h, l) {
2268
2645
  return [
2269
- [this.mapW(this.u), this.mapH(this.v + l + h)],
2270
- [this.mapW(this.u + l), this.mapH(this.v + l + h)],
2271
- [this.mapW(this.u), this.mapH(this.v + l)],
2272
- [this.mapW(this.u + l), this.mapH(this.v + l)]
2646
+ [this.mapW(this.u + l + w + l), this.mapH(this.v + l + h)],
2647
+ [this.mapW(this.u + l + w), this.mapH(this.v + l + h)],
2648
+ [this.mapW(this.u + l + w + l), this.mapH(this.v + l)],
2649
+ [this.mapW(this.u + l + w), this.mapH(this.v + l)]
2273
2650
  ];
2274
2651
  }
2275
2652
  getUvWest(w, h, l) {
2276
2653
  return [
2277
- [this.mapW(this.u + l + w), this.mapH(this.v + l + h)],
2278
- [this.mapW(this.u + l + w + l), this.mapH(this.v + l + h)],
2279
- [this.mapW(this.u + l + w), this.mapH(this.v + l)],
2280
- [this.mapW(this.u + l + w + l), this.mapH(this.v + l)]
2654
+ [this.mapW(this.u + l), this.mapH(this.v + l + h)],
2655
+ [this.mapW(this.u), this.mapH(this.v + l + h)],
2656
+ [this.mapW(this.u + l), this.mapH(this.v + l)],
2657
+ [this.mapW(this.u), this.mapH(this.v + l)]
2281
2658
  ];
2282
2659
  }
2283
2660
  getUvUp(w, h, l) {
@@ -2290,26 +2667,26 @@ var MinecraftCubeTexture = class {
2290
2667
  }
2291
2668
  getUvDown(w, h, l) {
2292
2669
  return [
2293
- [this.mapW(this.u + l), this.mapH(this.v + l)],
2294
- [this.mapW(this.u + l + w), this.mapH(this.v + l)],
2295
2670
  [this.mapW(this.u + l), this.mapH(this.v)],
2296
- [this.mapW(this.u + l + w), this.mapH(this.v)]
2671
+ [this.mapW(this.u + l + w), this.mapH(this.v)],
2672
+ [this.mapW(this.u + l), this.mapH(this.v + l)],
2673
+ [this.mapW(this.u + l + w), this.mapH(this.v + l)]
2297
2674
  ];
2298
2675
  }
2299
2676
  getUvSouth(w, h, l) {
2300
2677
  return [
2301
- [this.mapW(this.u + l + w + l), this.mapH(this.v + l + h)],
2302
2678
  [this.mapW(this.u + l + w + l + w), this.mapH(this.v + l + h)],
2303
- [this.mapW(this.u + l + w + l), this.mapH(this.v + l)],
2304
- [this.mapW(this.u + l + w + l + w), this.mapH(this.v + l)]
2679
+ [this.mapW(this.u + l + w + l), this.mapH(this.v + l + h)],
2680
+ [this.mapW(this.u + l + w + l + w), this.mapH(this.v + l)],
2681
+ [this.mapW(this.u + l + w + l), this.mapH(this.v + l)]
2305
2682
  ];
2306
2683
  }
2307
2684
  getUvNorth(w, h, l) {
2308
2685
  return [
2309
- [this.mapW(this.u + l), this.mapH(this.v + l + h)],
2310
2686
  [this.mapW(this.u + l + w), this.mapH(this.v + l + h)],
2311
- [this.mapW(this.u + l), this.mapH(this.v + l)],
2312
- [this.mapW(this.u + l + w), this.mapH(this.v + l)]
2687
+ [this.mapW(this.u + l), this.mapH(this.v + l + h)],
2688
+ [this.mapW(this.u + l + w), this.mapH(this.v + l)],
2689
+ [this.mapW(this.u + l), this.mapH(this.v + l)]
2313
2690
  ];
2314
2691
  }
2315
2692
  getFaceUv(face, w, h, l) {
@@ -2328,10 +2705,12 @@ var MinecraftCubeTexture = class {
2328
2705
  return this.getUvNorth(w, h, l);
2329
2706
  }
2330
2707
  }
2331
- toUvArray(w, h, l) {
2708
+ toUvArray(w, h, l, mirror = false) {
2332
2709
  const uv = [];
2333
2710
  for (let i = 0; i < CUBE_FACES.length; i++) {
2334
- UVMapper.setFaceUvInArray(uv, i * 4, this.getFaceUv(CUBE_FACES[i], w, h, l));
2711
+ const face = mirror && i < 2 ? CUBE_FACES[1 - i] : CUBE_FACES[i];
2712
+ const corners = this.getFaceUv(face, w, h, l);
2713
+ UVMapper.setFaceUvInArray(uv, i * 4, mirror ? [corners[1], corners[0], corners[3], corners[2]] : corners);
2335
2714
  }
2336
2715
  return uv;
2337
2716
  }
@@ -2361,76 +2740,85 @@ function shutdown() {
2361
2740
  Caching.end();
2362
2741
  }
2363
2742
 
2743
+ // src/error/MineRenderError.ts
2744
+ var MineRenderError = class _MineRenderError extends Error {
2745
+ constructor(msg) {
2746
+ super(msg);
2747
+ Object.setPrototypeOf(this, _MineRenderError.prototype);
2748
+ }
2749
+ get name() {
2750
+ return "MineRenderError";
2751
+ }
2752
+ };
2753
+
2364
2754
  // src/assets/Entities.ts
2365
- import { Memoize as Memoize3 } from "typescript-memoize";
2366
2755
  var Entities = class {
2367
- static async getBlockEntityModels() {
2368
- const key = AssetKey.parse("models", "minerender:blockEntityModels");
2369
- console.log(key);
2370
- return AssetLoader.get(key, "json" /* JSON */);
2371
- }
2372
- static async getEntityModels() {
2373
- const key = AssetKey.parse("models", "minerender:entityModels");
2374
- console.log(key);
2375
- return AssetLoader.get(key, "json" /* JSON */);
2376
- }
2377
- // BlockEntity names are hardcoded
2378
- static async getBlockList() {
2379
- const models = await this.getBlockEntityModels();
2380
- if (!models) {
2381
- return [];
2382
- }
2383
- return Object.keys(models);
2384
- }
2385
2756
  static async getEntityList() {
2386
- const models = await this.getEntityModels();
2387
- if (!models) {
2388
- return [];
2389
- }
2390
- return Object.keys(models);
2391
- }
2392
- static async getBlock(modelKey, textureKey) {
2393
- const models = await this.getBlockEntityModels();
2394
- if (!models) {
2395
- return void 0;
2396
- }
2397
- if (!textureKey) {
2398
- textureKey = modelKey;
2399
- }
2400
- const baseKey = modelKey.path.includes("/") ? new BasicAssetKey(modelKey.namespace, modelKey.path.split("/")[0]) : modelKey;
2401
- return {
2402
- key: textureKey,
2403
- parts: models[baseKey.toNamespacedString()]
2757
+ const collect = async (path) => {
2758
+ const prefix2 = path ? `${path}/` : "";
2759
+ const key = new AssetKey(DEFAULT_NAMESPACE, `${prefix2}_list`, void 0, void 0, "entity-models", ".json");
2760
+ const list = await Caching.listAssetCache.get(key.serialize(), () => AssetLoader.get(key, "list" /* LIST */));
2761
+ if (!list) return [];
2762
+ const files = list.files.filter((file) => file.endsWith(".json") && file !== "_list.json").map((file) => `${prefix2}${file.slice(0, -5)}`);
2763
+ const children = await Promise.all(list.directories.map((directory) => collect(`${prefix2}${directory}`)));
2764
+ return [...files, ...children.flat()];
2404
2765
  };
2766
+ return collect("");
2767
+ }
2768
+ static async getEntity(modelKey, textureKey, options) {
2769
+ const path = isAssetKey(modelKey) ? modelKey.getFullPath() : modelKey.path;
2770
+ const key = new AssetKey(modelKey.namespace, path, void 0, void 0, "entity-models", ".json");
2771
+ const model = await Caching.entityModelCache.get(key.serialize(), () => AssetLoader.get(key, "json" /* JSON */));
2772
+ if (!model) return void 0;
2773
+ const layerName = options?.layer ?? "main";
2774
+ const layer = model.layers[layerName];
2775
+ if (!layer) {
2776
+ throw new MineRenderError(`Entity ${model.id} has no layer "${layerName}". Available layers: ${Object.keys(model.layers).join(", ")}`);
2777
+ }
2778
+ let texture;
2779
+ if (textureKey) {
2780
+ const path2 = isAssetKey(textureKey) ? textureKey.getFullPath() : textureKey.path;
2781
+ texture = isAssetKey(textureKey) && textureKey.assetType === "textures" && path2.startsWith("entity/") ? textureKey : new AssetKey(textureKey.namespace, path2, "textures", "entity", "assets", ".png", isAssetKey(textureKey) ? textureKey.root : void 0);
2782
+ } else if (layer.textureLocation !== void 0) {
2783
+ texture = AssetKey.parse("textures", layer.textureLocation.replace(/^([^:]+:)?textures\//, "$1"));
2784
+ } else {
2785
+ texture = await this.resolveTexture(modelKey);
2786
+ }
2787
+ return { key: textureKey ?? modelKey, texture, layer, id: model.id };
2788
+ }
2789
+ static async resolveTexture(modelKey) {
2790
+ const path = isAssetKey(modelKey) ? modelKey.getFullPath() : modelKey.path;
2791
+ const key = new AssetKey(modelKey.namespace, path, void 0, void 0, "entity-models", ".json");
2792
+ return Caching.entityTextureCache.get(key.serialize(), async () => {
2793
+ const name = path.split("/").pop();
2794
+ for (const candidate of [path, `${path}/${name}`]) {
2795
+ const texture = new AssetKey(modelKey.namespace, candidate, "textures", "entity", "assets", ".png");
2796
+ if (await ModelTextures.get(texture)) return texture;
2797
+ }
2798
+ const listKey = new AssetKey(modelKey.namespace, "_list", `${name}_variant`, void 0, "data", ".json");
2799
+ const list = await AssetLoader.get(listKey, "list" /* LIST */);
2800
+ const files = list?.files.filter((file2) => file2.endsWith(".json") && file2 !== "_list.json");
2801
+ const file = files?.find((file2) => file2 === "temperate.json") ?? files?.[0];
2802
+ if (!file) return void 0;
2803
+ const variantKey = new AssetKey(modelKey.namespace, file.slice(0, -5), `${name}_variant`, void 0, "data", ".json");
2804
+ const variant = await AssetLoader.get(variantKey, "json" /* JSON */);
2805
+ const assets = variant?.assets;
2806
+ const textureId = variant?.asset_id ?? (typeof assets?.wild === "string" ? assets.wild : Object.values(assets ?? {}).find((value) => typeof value === "string"));
2807
+ return typeof textureId === "string" ? AssetKey.parse("textures", textureId) : void 0;
2808
+ });
2405
2809
  }
2406
- static async getEntity(modelKey, textureKey) {
2407
- const models = await this.getEntityModels();
2408
- if (!models) {
2409
- return void 0;
2410
- }
2411
- if (!textureKey) {
2412
- textureKey = modelKey;
2413
- }
2414
- const baseKey = modelKey.path.includes("/") ? new BasicAssetKey(modelKey.namespace, modelKey.path.split("/")[0]) : modelKey;
2415
- return {
2416
- key: textureKey,
2417
- parts: models[baseKey.toNamespacedString()]
2418
- };
2810
+ /** @deprecated Use getEntityList(); block entities share the entity dataset. */
2811
+ static getBlockList() {
2812
+ return this.getEntityList();
2813
+ }
2814
+ /** @deprecated Use getEntity(); block entities share the entity dataset. */
2815
+ static getBlock(modelKey, textureKey, options) {
2816
+ return this.getEntity(modelKey, textureKey, options);
2419
2817
  }
2420
- };
2421
- __decorateClass([
2422
- Memoize3()
2423
- ], Entities, "getBlockEntityModels", 1);
2424
- __decorateClass([
2425
- Memoize3()
2426
- ], Entities, "getEntityModels", 1);
2427
- var EntityModels = class {
2428
- };
2429
- var BlockEntityModels = class {
2430
2818
  };
2431
2819
 
2432
2820
  // src/renderer/SceneObject.ts
2433
- import { Euler, InstancedMesh, MathUtils, Matrix4 as Matrix42, Mesh as Mesh3, Object3D as Object3D2, Quaternion as Quaternion2, Vector3 as Vector33 } from "three";
2821
+ import { Euler as Euler3, InstancedMesh, MathUtils, Matrix4 as Matrix43, Mesh as Mesh3, Object3D as Object3D2, Quaternion as Quaternion3, Vector3 as Vector35 } from "three";
2434
2822
 
2435
2823
  // src/instance/InstanceReference.ts
2436
2824
  var InstanceReference = class {
@@ -2475,30 +2863,27 @@ function isInstanceReference(obj) {
2475
2863
  return obj.isInstanceReference;
2476
2864
  }
2477
2865
 
2478
- // src/error/MineRenderError.ts
2479
- var MineRenderError = class _MineRenderError extends Error {
2480
- constructor(msg) {
2481
- super(msg);
2482
- Object.setPrototypeOf(this, _MineRenderError.prototype);
2483
- }
2484
- get name() {
2485
- return "MineRenderError";
2486
- }
2487
- };
2488
-
2489
2866
  // src/renderer/SceneObject.ts
2490
- var import_ts_deepmerge4 = __toESM(require_dist());
2491
- var p7 = prefix("SceneObject");
2492
- var _SceneObject = class _SceneObject extends Object3D2 {
2867
+ var import_ts_deepmerge3 = __toESM(require_dist());
2868
+ var p6 = prefix("SceneObject");
2869
+ var SceneObject = class _SceneObject extends Object3D2 {
2493
2870
  constructor(options) {
2494
2871
  super();
2495
2872
  this.isSceneObject = true;
2496
2873
  this.materialCallbacks = {};
2497
2874
  this._isInstanced = false;
2498
2875
  this._instanceCounter = 0;
2499
- this.options = (0, import_ts_deepmerge4.default)({}, _SceneObject.DEFAULT_OPTIONS, options ?? {});
2876
+ this.options = (0, import_ts_deepmerge3.default)({}, _SceneObject.DEFAULT_OPTIONS, options ?? {});
2500
2877
  console.log("SceneObject options", this.options);
2501
2878
  }
2879
+ static {
2880
+ this.DEFAULT_OPTIONS = (0, import_ts_deepmerge3.default)({}, {
2881
+ instanceMeshes: true,
2882
+ maxInstanceCount: 50,
2883
+ mergeMeshes: true,
2884
+ wireframe: false
2885
+ });
2886
+ }
2502
2887
  set scene(scene) {
2503
2888
  if (!!this._scene) throw new MineRenderError("Scene already set");
2504
2889
  this._scene = scene;
@@ -2590,6 +2975,7 @@ var _SceneObject = class _SceneObject extends Object3D2 {
2590
2975
  }
2591
2976
  createInstancedMesh(name, geometry, material, count) {
2592
2977
  const mesh = new InstancedMesh(geometry, material, count);
2978
+ mesh.count = 0;
2593
2979
  if (name) {
2594
2980
  mesh.name = `mesh:${name}`;
2595
2981
  }
@@ -2610,15 +2996,8 @@ var _SceneObject = class _SceneObject extends Object3D2 {
2610
2996
  return this.toggleObjectVisibility(this.getMeshByName(name), visible);
2611
2997
  }
2612
2998
  iterateAllMeshes(cb) {
2613
- this.children.forEach((obj) => {
2614
- if (obj.isMesh) {
2615
- cb(obj);
2616
- }
2617
- obj.children.forEach((obj1) => {
2618
- if (obj1.isMesh) {
2619
- cb(obj1);
2620
- }
2621
- });
2999
+ this.traverse((obj) => {
3000
+ if (isMesh(obj)) cb(obj);
2622
3001
  });
2623
3002
  }
2624
3003
  //</editor-fold>
@@ -2666,10 +3045,14 @@ var _SceneObject = class _SceneObject extends Object3D2 {
2666
3045
  nextInstance() {
2667
3046
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
2668
3047
  const i = this._instanceCounter++;
2669
- this.setMatrixAt(i, new Matrix42());
2670
- console.debug(p7, "nextInstance " + i);
3048
+ this.setMatrixAt(i, new Matrix43());
3049
+ const mesh = this.children[0];
3050
+ if (mesh && isInstancedMesh(mesh)) {
3051
+ mesh.count = Math.min(this._instanceCounter, mesh.instanceMatrix.count);
3052
+ }
3053
+ console.debug(p6, "nextInstance " + i);
2671
3054
  if (i === this.options.maxInstanceCount) {
2672
- console.warn(p7, "Max instance count reached for " + this);
3055
+ console.warn(p6, "Max instance count reached for " + this);
2673
3056
  }
2674
3057
  if (this.scene) {
2675
3058
  this.scene.stats.instanceCount++;
@@ -2679,7 +3062,7 @@ var _SceneObject = class _SceneObject extends Object3D2 {
2679
3062
  }
2680
3063
  //</editor-fold>
2681
3064
  //<editor-fold desc="TRANSFORMATION">
2682
- getMatrixAt(index, matrix = new Matrix42()) {
3065
+ getMatrixAt(index, matrix = new Matrix43()) {
2683
3066
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
2684
3067
  const child = this.children[0];
2685
3068
  if (child && isInstancedMesh(child)) {
@@ -2698,16 +3081,16 @@ var _SceneObject = class _SceneObject extends Object3D2 {
2698
3081
  }
2699
3082
  setPositionRotationScaleAt(index, position, rotation, scale) {
2700
3083
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
2701
- const oldPosition = new Vector33();
2702
- const oldRotation = new Quaternion2();
2703
- const oldScale = new Vector33();
2704
- const matrix = new Matrix42();
3084
+ const oldPosition = new Vector35();
3085
+ const oldRotation = new Quaternion3();
3086
+ const oldScale = new Vector35();
3087
+ const matrix = new Matrix43();
2705
3088
  if (!scale || !rotation || !position) {
2706
3089
  this.getMatrixAt(index, matrix).decompose(oldPosition, oldRotation, oldScale);
2707
3090
  }
2708
3091
  matrix.compose(
2709
3092
  position ? position : oldPosition,
2710
- rotation ? new Quaternion2().setFromEuler(rotation) : oldRotation,
3093
+ rotation ? new Quaternion3().setFromEuler(rotation) : oldRotation,
2711
3094
  scale ? scale : oldScale
2712
3095
  );
2713
3096
  this.setMatrixAt(index, matrix);
@@ -2716,7 +3099,7 @@ var _SceneObject = class _SceneObject extends Object3D2 {
2716
3099
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
2717
3100
  this.setPositionRotationScaleAt(index, position);
2718
3101
  }
2719
- getPositionAt(index, vector = new Vector33()) {
3102
+ getPositionAt(index, vector = new Vector35()) {
2720
3103
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
2721
3104
  const matrix = this.getMatrixAt(index);
2722
3105
  vector.setFromMatrixPosition(matrix);
@@ -2726,7 +3109,7 @@ var _SceneObject = class _SceneObject extends Object3D2 {
2726
3109
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
2727
3110
  this.setPositionRotationScaleAt(index, void 0, rotation, void 0);
2728
3111
  }
2729
- getRotationAt(index, euler = new Euler()) {
3112
+ getRotationAt(index, euler = new Euler3()) {
2730
3113
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
2731
3114
  const matrix = this.getMatrixAt(index);
2732
3115
  euler.setFromRotationMatrix(matrix);
@@ -2736,7 +3119,7 @@ var _SceneObject = class _SceneObject extends Object3D2 {
2736
3119
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
2737
3120
  this.setPositionRotationScaleAt(index, void 0, void 0, scale);
2738
3121
  }
2739
- getScaleAt(index, vector = new Vector33()) {
3122
+ getScaleAt(index, vector = new Vector35()) {
2740
3123
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
2741
3124
  const matrix = this.getMatrixAt(index);
2742
3125
  vector.setFromMatrixScale(matrix);
@@ -2840,34 +3223,28 @@ var _SceneObject = class _SceneObject extends Object3D2 {
2840
3223
  this.notifyDirty();
2841
3224
  }
2842
3225
  removeFromScene() {
2843
- var _a;
2844
- (_a = this._scene) == null ? void 0 : _a.remove(this);
3226
+ this._scene?.remove(this);
2845
3227
  this.notifyDirty();
2846
3228
  }
2847
3229
  //</editor-fold>
2848
3230
  };
2849
- _SceneObject.DEFAULT_OPTIONS = (0, import_ts_deepmerge4.default)({}, {
2850
- instanceMeshes: true,
2851
- maxInstanceCount: 50,
2852
- mergeMeshes: true,
2853
- wireframe: false
2854
- });
2855
- var SceneObject = _SceneObject;
2856
3231
  function isSceneObject(obj) {
2857
3232
  return obj.isSceneObject;
2858
3233
  }
2859
3234
 
2860
3235
  // src/entity/scene/EntityObject.ts
2861
- var import_ts_deepmerge5 = __toESM(require_dist());
3236
+ var import_ts_deepmerge4 = __toESM(require_dist());
2862
3237
  import { Object3D as Object3D3 } from "three";
2863
- import * as THREE2 from "three";
2864
- var EntityObject = class extends SceneObject {
3238
+ var EntityObject = class _EntityObject extends SceneObject {
2865
3239
  constructor(entity, options) {
2866
3240
  super();
2867
3241
  this.entity = entity;
2868
3242
  this.isEntityObject = true;
2869
3243
  this.meshesCreated = false;
2870
- this.options = (0, import_ts_deepmerge5.default)({}, SceneObject.DEFAULT_OPTIONS, options ?? {});
3244
+ this.options = (0, import_ts_deepmerge4.default)({}, _EntityObject.DEFAULT_OPTIONS, options ?? {});
3245
+ }
3246
+ static {
3247
+ this.DEFAULT_OPTIONS = (0, import_ts_deepmerge4.default)({}, SceneObject.DEFAULT_OPTIONS, { flip: true });
2871
3248
  }
2872
3249
  async init() {
2873
3250
  this.createMeshes();
@@ -2876,67 +3253,76 @@ var EntityObject = class extends SceneObject {
2876
3253
  dispose() {
2877
3254
  super.dispose();
2878
3255
  }
2879
- async loadTextures() {
2880
- var _a;
2881
- this.imageData = await ModelTextures.get(new AssetKey(
2882
- ((_a = this.entity.key) == null ? void 0 : _a.namespace) ?? DEFAULT_NAMESPACE,
2883
- this.entity.key.path,
2884
- //TODO: texture may differ from entity name; most of them are in subdirectories for multiple variants etc.
3256
+ get textureKey() {
3257
+ if (this.entity.texture) return this.entity.texture;
3258
+ const key = this.entity.key;
3259
+ return new AssetKey(
3260
+ key.namespace,
3261
+ isAssetKey(key) ? key.getFullPath() : key.path,
2885
3262
  "textures",
2886
3263
  "entity",
2887
3264
  "assets",
2888
3265
  ".png"
2889
- ));
3266
+ );
3267
+ }
3268
+ async loadTextures() {
3269
+ this.imageData = await ModelTextures.get(this.textureKey);
2890
3270
  }
2891
- //TODO: abstract this, since extracted model data can be used for entities, blocks, players
2892
3271
  createMeshes(force = false) {
2893
3272
  if (this.meshesCreated && !force) return;
2894
- const mat = Materials.MISSING_TEXTURE;
2895
- for (let partName in this.entity.parts) {
2896
- const part = this.entity.parts[partName];
2897
- const texture = new MinecraftCubeTexture(part.textureOffsetU, part.textureOffsetV, part.textureWidth, part.textureHeight);
2898
- const partAnchor = new Object3D3();
2899
- partAnchor.position.x = part.pivotX;
2900
- partAnchor.position.y = part.pivotY;
2901
- partAnchor.position.z = part.pivotZ;
2902
- for (let cube of part.cubes) {
2903
- const w = cube.maxX - cube.minX;
2904
- const h = cube.maxY - cube.minY;
2905
- const l = cube.maxZ - cube.minZ;
2906
- const uv = texture.toUvArray(w, h, l);
2907
- const cubeGeo = this._getBoxGeometryForDimensionsAndUv(w, h, l, uv).clone();
2908
- cubeGeo.applyMatrix4(new THREE2.Matrix4().makeTranslation(w / 2, h / 2, l / 2));
2909
- cubeGeo.applyMatrix4(new THREE2.Matrix4().makeTranslation(cube.minX, cube.minY, cube.minZ));
2910
- applyModelPartRotation(part, cubeGeo);
2911
- const mesh = this.createMesh(partName, cubeGeo, mat);
2912
- partAnchor.add(mesh);
2913
- if (this.options.wireframe) {
2914
- addWireframeToMesh(cubeGeo, mesh);
2915
- }
2916
- }
2917
- this.add(partAnchor);
2918
- }
3273
+ const modelRoot = new Object3D3();
3274
+ if (this.options.flip) modelRoot.scale.set(-1, -1, 1);
3275
+ this.add(modelRoot);
3276
+ this.createPart("root", this.entity.layer.root, modelRoot, this.entity.layer.texture, Materials.MISSING_TEXTURE);
2919
3277
  this.meshesCreated = true;
2920
3278
  }
2921
- async applyTextures() {
2922
- var _a;
2923
- const textureAsset = await ModelTextures.preload(new AssetKey(
2924
- ((_a = this.entity.key) == null ? void 0 : _a.namespace) ?? DEFAULT_NAMESPACE,
2925
- this.entity.key.path,
2926
- "textures",
2927
- "entity",
2928
- "assets",
2929
- ".png"
2930
- ));
2931
- if (textureAsset) {
2932
- let mat = Materials.getImage({ texture: { src: textureAsset.src } });
2933
- this.iterateAllMeshes((mesh) => {
2934
- mesh.material = mat;
2935
- });
3279
+ createPart(name, part, parent, textureSize, material) {
3280
+ const anchor = this.createGroup(name);
3281
+ anchor.position.fromArray(part.pose.offset);
3282
+ anchor.rotation.set(...part.pose.rotation, "ZYX");
3283
+ anchor.scale.fromArray(part.pose.scale ?? [1, 1, 1]);
3284
+ parent.add(anchor);
3285
+ const size = part.texture ?? textureSize;
3286
+ for (const cube of part.cubes) {
3287
+ const [width, height, depth] = cube.size;
3288
+ const [growX, growY, growZ] = cube.grow ?? [0, 0, 0];
3289
+ const texture = new MinecraftCubeTexture(...cube.uv, ...size);
3290
+ const uv = size[0] === 0 || size[1] === 0 ? new Array(48).fill(0) : texture.toUvArray(width, height, depth, cube.mirror);
3291
+ const geometry = this._getBoxGeometryForDimensionsAndUv(
3292
+ width + growX * 2,
3293
+ height + growY * 2,
3294
+ depth + growZ * 2,
3295
+ uv
3296
+ ).clone();
3297
+ geometry.translate(cube.origin[0] + width / 2, cube.origin[1] + height / 2, cube.origin[2] + depth / 2);
3298
+ const mesh = this.createMesh(name, geometry, material);
3299
+ anchor.add(mesh);
3300
+ if (this.options.wireframe) addWireframeToMesh(geometry, mesh);
3301
+ }
3302
+ for (const [childName, child] of Object.entries(part.children)) {
3303
+ this.createPart(childName, child, anchor, size, material);
2936
3304
  }
2937
3305
  }
3306
+ async applyTextures() {
3307
+ const assetKeyStr = this.textureKey.serialize();
3308
+ const keyStr = `entity:${assetKeyStr}`;
3309
+ let mat = Caching.materialCache.getIfPresent(keyStr);
3310
+ if (!mat) {
3311
+ const pending = this.loadTextures();
3312
+ const cachedAsset = Caching.textureAssetCache.getIfPresent(assetKeyStr);
3313
+ await pending;
3314
+ if (!this.imageData) return;
3315
+ const canvas = this.imageData.data.canvas;
3316
+ const createMaterial = () => Materials.createBasicCanvasMaterial(canvas);
3317
+ mat = cachedAsset && Caching.textureAssetCache.getIfPresent(assetKeyStr) === cachedAsset ? Caching.materialCache.get(keyStr, createMaterial) : createMaterial();
3318
+ this.imageData = void 0;
3319
+ }
3320
+ this.iterateAllMeshes((mesh) => {
3321
+ mesh.material = mat;
3322
+ });
3323
+ this.notifyDirty();
3324
+ }
2938
3325
  };
2939
- EntityObject.DEFAULT_OPTIONS = (0, import_ts_deepmerge5.default)({}, SceneObject.DEFAULT_OPTIONS, {});
2940
3326
  function isEntityObject(obj) {
2941
3327
  return obj.isEntityObject;
2942
3328
  }
@@ -2948,7 +3334,7 @@ var GuiObject = class extends SceneObject {
2948
3334
 
2949
3335
  // src/inspector/SceneInspector.ts
2950
3336
  import { Raycaster, Vector2 as Vector22 } from "three";
2951
- var p8 = prefix("SceneInspector");
3337
+ var p7 = prefix("SceneInspector");
2952
3338
  var help = "<span>Ctrl+Click to Select<br/></span><br/>";
2953
3339
  var SceneInspector = class {
2954
3340
  constructor(renderer) {
@@ -2977,8 +3363,7 @@ var SceneInspector = class {
2977
3363
  return out;
2978
3364
  }
2979
3365
  onClick(event) {
2980
- var _a;
2981
- if (((_a = event.target) == null ? void 0 : _a.nodeName) !== "CANVAS") return;
3366
+ if (event.target?.nodeName !== "CANVAS") return;
2982
3367
  if (!event.ctrlKey) return;
2983
3368
  setTimeout(() => {
2984
3369
  this.mouse.x = event.clientX / window.innerWidth * 2 - 1;
@@ -3018,7 +3403,7 @@ var SceneInspector = class {
3018
3403
  }
3019
3404
  selectObject(targetObject, targetIntersection) {
3020
3405
  this.selectedObject = targetObject;
3021
- console.log(p8, "selected", targetObject);
3406
+ console.log(p7, "selected", targetObject);
3022
3407
  this.redraw(targetObject, targetIntersection);
3023
3408
  }
3024
3409
  redraw(targetObject, targetIntersection) {
@@ -3316,7 +3701,7 @@ var SceneStatsDisplay = class {
3316
3701
  };
3317
3702
 
3318
3703
  // src/instance/InstanceManager.ts
3319
- var p9 = prefix("InstanceManager");
3704
+ var p8 = prefix("InstanceManager");
3320
3705
  var InstanceManager = class {
3321
3706
  constructor() {
3322
3707
  this.isInstanceManager = true;
@@ -3324,7 +3709,7 @@ var InstanceManager = class {
3324
3709
  }
3325
3710
  async get(key) {
3326
3711
  if (key in this.instanceCache) {
3327
- console.debug(p9, "key in cache", key);
3712
+ console.debug(p8, "key in cache", key);
3328
3713
  return (await this.instanceCache[key]).nextInstance();
3329
3714
  }
3330
3715
  return void 0;
@@ -3333,13 +3718,17 @@ var InstanceManager = class {
3333
3718
  if (key in this.instanceCache) {
3334
3719
  return await this.get(key);
3335
3720
  }
3336
- console.debug(p9, "key not in cache", key);
3337
- this.instanceCache[key] = new Promise(async (resolve) => {
3338
- const obj = await supplier();
3339
- const instance = obj.nextInstance();
3340
- resolve(instance);
3341
- });
3342
- return await this.instanceCache[key];
3721
+ console.debug(p8, "key not in cache", key);
3722
+ const pending = Promise.resolve().then(supplier).then((obj) => obj.nextInstance());
3723
+ this.instanceCache[key] = pending;
3724
+ try {
3725
+ return await pending;
3726
+ } catch (error) {
3727
+ if (this.instanceCache[key] === pending) {
3728
+ delete this.instanceCache[key];
3729
+ }
3730
+ throw error;
3731
+ }
3343
3732
  }
3344
3733
  reset() {
3345
3734
  for (let instanceCacheKey in this.instanceCache) {
@@ -3356,20 +3745,6 @@ function isInstanceable(obj) {
3356
3745
  return "nextInstance" in obj;
3357
3746
  }
3358
3747
 
3359
- // src/model/DisplayPosition.ts
3360
- var DisplayPosition = /* @__PURE__ */ ((DisplayPosition2) => {
3361
- DisplayPosition2["THIRDPERSON_RIGHTHAND"] = "thirdperson_righthand";
3362
- DisplayPosition2["THIRDPERSON_LEFTHAND"] = "thirdperson_lefthand";
3363
- DisplayPosition2["FIRSTPERSON_RIGHTHAND"] = "firstperson_righthand";
3364
- DisplayPosition2["FIRSTPERSON_LEFTHAND"] = "firstperson_lefthand";
3365
- DisplayPosition2["GUI"] = "gui";
3366
- DisplayPosition2["HEAD"] = "head";
3367
- DisplayPosition2["GROUND"] = "ground";
3368
- DisplayPosition2["FIXED"] = "fixed";
3369
- return DisplayPosition2;
3370
- })(DisplayPosition || {});
3371
- var DISPLAY_POSITIONS = Object.values(DisplayPosition);
3372
-
3373
3748
  // src/model/GuiLight.ts
3374
3749
  var GuiLight = /* @__PURE__ */ ((GuiLight2) => {
3375
3750
  GuiLight2["FRONT"] = "front";
@@ -3392,8 +3767,93 @@ function isQuadArray(obj) {
3392
3767
  return Array.isArray(obj) && obj.length === 4;
3393
3768
  }
3394
3769
 
3770
+ // src/model/block/blockTints.json
3771
+ var blockTints_default = {
3772
+ "minecraft:large_fern": { source: "grass" },
3773
+ "minecraft:tall_grass": { source: "grass" },
3774
+ "minecraft:grass_block": { source: "grass" },
3775
+ "minecraft:fern": { source: "grass" },
3776
+ "minecraft:grass": { source: "grass" },
3777
+ "minecraft:short_grass": { source: "grass" },
3778
+ "minecraft:potted_fern": { source: "grass" },
3779
+ "minecraft:bush": { source: "grass" },
3780
+ "minecraft:pink_petals": { source: "grass", untinted: [0] },
3781
+ "minecraft:wildflowers": { source: "grass", untinted: [0] },
3782
+ "minecraft:spruce_leaves": { source: "constant", color: 6396257 },
3783
+ "minecraft:birch_leaves": { source: "constant", color: 8431445 },
3784
+ "minecraft:oak_leaves": { source: "constant", color: 4764952 },
3785
+ "minecraft:jungle_leaves": { source: "constant", color: 4764952 },
3786
+ "minecraft:acacia_leaves": { source: "constant", color: 4764952 },
3787
+ "minecraft:dark_oak_leaves": { source: "constant", color: 4764952 },
3788
+ "minecraft:vine": { source: "constant", color: 4764952 },
3789
+ "minecraft:mangrove_leaves": { source: "constant", color: 4764952 },
3790
+ "minecraft:leaf_litter": { source: "constant", color: 6044722 },
3791
+ "minecraft:water_cauldron": { source: "constant", color: 4159204 },
3792
+ "minecraft:redstone_wire": { source: "redstone" },
3793
+ "minecraft:attached_melon_stem": { source: "constant", color: 14731036 },
3794
+ "minecraft:attached_pumpkin_stem": { source: "constant", color: 14731036 },
3795
+ "minecraft:melon_stem": { source: "stem" },
3796
+ "minecraft:pumpkin_stem": { source: "stem" },
3797
+ "minecraft:lily_pad": { source: "constant", color: 7455580 }
3798
+ };
3799
+
3800
+ // src/model/block/BlockTints.ts
3801
+ var rules = blockTints_default;
3802
+ var BlockTints = class {
3803
+ /** Resolves block preview colors without biome context; explicit tints take precedence. */
3804
+ static async get(key, state, model, tints) {
3805
+ const rule = key && rules[key.toNamespacedString()];
3806
+ if (!key || !rule) return tints;
3807
+ const indices = /* @__PURE__ */ new Set();
3808
+ for (const element of model.elements ?? []) {
3809
+ for (const face of Object.values(element.faces)) {
3810
+ const index = face?.tintindex;
3811
+ if (index !== void 0 && index >= 0 && tints?.[index] === void 0 && !rule.untinted?.includes(index)) {
3812
+ indices.add(index);
3813
+ }
3814
+ }
3815
+ }
3816
+ if (!indices.size) return tints;
3817
+ let color;
3818
+ switch (rule.source) {
3819
+ case "constant":
3820
+ color = rule.color;
3821
+ break;
3822
+ case "grass":
3823
+ color = await this.grassColor(key);
3824
+ break;
3825
+ case "redstone": {
3826
+ const power = Number(state.power ?? 0) / 15;
3827
+ const red = power * 0.6 + (power > 0 ? 0.4 : 0.3);
3828
+ const green = Math.max(0, power * power * 0.7 - 0.5);
3829
+ const blue = Math.max(0, power * power * 0.6 - 0.7);
3830
+ color = Math.floor(red * 255) << 16 | Math.floor(green * 255) << 8 | Math.floor(blue * 255);
3831
+ break;
3832
+ }
3833
+ case "stem": {
3834
+ const age = Number(state.age ?? 0);
3835
+ color = age * 32 << 16 | 255 - age * 8 << 8 | age * 4;
3836
+ break;
3837
+ }
3838
+ }
3839
+ return { ...Object.fromEntries([...indices].map((index) => [index, color])), ...tints };
3840
+ }
3841
+ static async grassColor(origin) {
3842
+ const key = AssetKey.parse("textures", "minecraft:colormap/grass", origin);
3843
+ return await Caching.blockTintCache.get(key.serialize(), async () => {
3844
+ const image = await ModelTextures.get(key);
3845
+ if (!image) throw new MineRenderError(`Missing grass colormap: ${key.toNamespacedString()}`);
3846
+ if (image.width !== 256 || image.height !== 256) {
3847
+ throw new MineRenderError("Grass colormaps must be 256 \xD7 256 pixels");
3848
+ }
3849
+ const [red, green, blue] = image.data.getImageData(127, 127, 1, 1).data;
3850
+ return red << 16 | green << 8 | blue;
3851
+ });
3852
+ }
3853
+ };
3854
+
3395
3855
  // src/model/scene/ModelObject.ts
3396
- import { BoxGeometry as BoxGeometry5, Matrix4 as Matrix45 } from "three";
3856
+ import { BoxGeometry as BoxGeometry5, BufferAttribute as BufferAttribute4, Color as Color3, Euler as Euler4, Matrix4 as Matrix44 } from "three";
3397
3857
 
3398
3858
  // src/three/BufferGeometryUtils.js
3399
3859
  import {
@@ -3405,7 +3865,7 @@ import {
3405
3865
  TriangleFanDrawMode,
3406
3866
  TriangleStripDrawMode,
3407
3867
  TrianglesDrawMode,
3408
- Vector3 as Vector35
3868
+ Vector3 as Vector36
3409
3869
  } from "three";
3410
3870
  function computeTangents(geometry) {
3411
3871
  geometry.computeTangents();
@@ -3724,15 +4184,15 @@ function computeMorphedAttributes(object) {
3724
4184
  console.error("THREE.BufferGeometryUtils: Geometry is not of type BufferGeometry.");
3725
4185
  return null;
3726
4186
  }
3727
- const _vA = new Vector35();
3728
- const _vB = new Vector35();
3729
- const _vC = new Vector35();
3730
- const _tempA = new Vector35();
3731
- const _tempB = new Vector35();
3732
- const _tempC = new Vector35();
3733
- const _morphA = new Vector35();
3734
- const _morphB = new Vector35();
3735
- const _morphC = new Vector35();
4187
+ const _vA = new Vector36();
4188
+ const _vB = new Vector36();
4189
+ const _vC = new Vector36();
4190
+ const _tempA = new Vector36();
4191
+ const _tempB = new Vector36();
4192
+ const _tempC = new Vector36();
4193
+ const _morphA = new Vector36();
4194
+ const _morphB = new Vector36();
4195
+ const _morphC = new Vector36();
3736
4196
  function _calculateMorphedAttributeData(object2, material2, attribute, morphAttribute, morphTargetsRelative2, a2, b2, c2, modifiedAttributeArray) {
3737
4197
  _vA.fromBufferAttribute(attribute, a2);
3738
4198
  _vB.fromBufferAttribute(attribute, b2);
@@ -3938,26 +4398,29 @@ function computeMorphedAttributes(object) {
3938
4398
  }
3939
4399
 
3940
4400
  // src/model/scene/ModelObject.ts
3941
- var import_ts_deepmerge6 = __toESM(require_dist());
3942
- var p10 = prefix("ModelObject");
3943
- var _ModelObject = class _ModelObject extends SceneObject {
4401
+ var import_ts_deepmerge5 = __toESM(require_dist());
4402
+ var p9 = prefix("ModelObject");
4403
+ var ModelObject = class _ModelObject extends SceneObject {
3944
4404
  constructor(originalModel, options) {
3945
4405
  super(options);
3946
4406
  this.originalModel = originalModel;
3947
4407
  this.isModelObject = true;
3948
4408
  this.meshesCreated = false;
3949
- this.options = (0, import_ts_deepmerge6.default)({}, _ModelObject.DEFAULT_OPTIONS, options ?? {});
4409
+ this.options = (0, import_ts_deepmerge5.default)({}, _ModelObject.DEFAULT_OPTIONS, options ?? {});
4410
+ if (this.options.tints) this.options.tints = { ...this.options.tints };
3950
4411
  console.log("ModelObject options", this.options);
3951
4412
  }
4413
+ static {
4414
+ this.DEFAULT_OPTIONS = (0, import_ts_deepmerge5.default)({}, SceneObject.DEFAULT_OPTIONS, {});
4415
+ }
3952
4416
  async init() {
3953
4417
  await this.loadTextures();
3954
4418
  this.createMeshes();
3955
4419
  this.applyTextures();
3956
4420
  }
3957
4421
  dispose() {
3958
- var _a;
3959
4422
  super.dispose();
3960
- (_a = this.atlas) == null ? void 0 : _a.dispose();
4423
+ this.atlas?.dispose();
3961
4424
  }
3962
4425
  get textureAtlas() {
3963
4426
  return this.atlas;
@@ -3967,20 +4430,38 @@ var _ModelObject = class _ModelObject extends SceneObject {
3967
4430
  this.atlas = await UVMapper.getAtlas(this.originalModel);
3968
4431
  }
3969
4432
  createMeshes(force = false) {
3970
- var _a;
3971
4433
  if (this.meshesCreated && !force) return;
3972
4434
  const mat = Materials.MISSING_TEXTURE;
4435
+ const displayTransform = this.options.displayPosition ? DisplayTransforms.getMatrix(this.originalModel.display, this.options.displayPosition) : void 0;
3973
4436
  let allGeos = [];
3974
4437
  if (this.atlas) {
3975
4438
  if (this.atlas.model.elements) {
3976
- (_a = this.atlas.model.elements) == null ? void 0 : _a.forEach((el) => {
4439
+ this.atlas.model.elements?.forEach((el) => {
3977
4440
  const elGeo = this._getBoxGeometryFromElement(el).clone();
3978
- elGeo.applyMatrix4(new Matrix45().makeTranslation((el.to[0] - el.from[0]) / 2, (el.to[1] - el.from[1]) / 2, (el.to[2] - el.from[2]) / 2));
3979
- elGeo.applyMatrix4(new Matrix45().makeTranslation(el.from[0], el.from[1], el.from[2]));
4441
+ if (this.options.uvLockRotation) {
4442
+ UVMapper.lockUvs(elGeo, el.faces, this.atlas, new Euler4(...this.options.uvLockRotation));
4443
+ }
4444
+ if (this.options.tints) {
4445
+ const colors = new Float32Array(elGeo.getAttribute("position").count * 3).fill(1);
4446
+ for (const [faceIndex, faceName] of CUBE_FACES.entries()) {
4447
+ const tintIndex = el.faces[faceName]?.tintindex;
4448
+ if (tintIndex === void 0 || tintIndex < 0) continue;
4449
+ const tint = this.options.tints[tintIndex];
4450
+ if (tint === void 0) continue;
4451
+ const color = new Color3(tint);
4452
+ for (let vertex = 0; vertex < 4; vertex++) {
4453
+ color.toArray(colors, (faceIndex * 4 + vertex) * 3);
4454
+ }
4455
+ }
4456
+ elGeo.setAttribute("color", new BufferAttribute4(colors, 3));
4457
+ }
4458
+ elGeo.applyMatrix4(new Matrix44().makeTranslation((el.to[0] - el.from[0]) / 2, (el.to[1] - el.from[1]) / 2, (el.to[2] - el.from[2]) / 2));
4459
+ elGeo.applyMatrix4(new Matrix44().makeTranslation(el.from[0], el.from[1], el.from[2]));
3980
4460
  if (el.rotation) {
3981
4461
  applyElementRotation(el.rotation, elGeo);
3982
4462
  }
3983
- elGeo.applyMatrix4(new Matrix45().makeTranslation(-8, -8, -8));
4463
+ elGeo.applyMatrix4(new Matrix44().makeTranslation(-8, -8, -8));
4464
+ if (displayTransform) DisplayTransforms.apply(elGeo, displayTransform);
3984
4465
  if (this.options.mergeMeshes) {
3985
4466
  allGeos.push(elGeo);
3986
4467
  } else {
@@ -3991,10 +4472,10 @@ var _ModelObject = class _ModelObject extends SceneObject {
3991
4472
  }
3992
4473
  });
3993
4474
  } else {
3994
- console.debug(p10, this.atlas.model, "has no elements");
4475
+ console.debug(p9, this.atlas.model, "has no elements");
3995
4476
  }
3996
4477
  } else {
3997
- console.debug(p10, "Missing atlas for", this);
4478
+ console.debug(p9, "Missing atlas for", this);
3998
4479
  }
3999
4480
  if (this.options.mergeMeshes) {
4000
4481
  let combinedGeo;
@@ -4002,6 +4483,7 @@ var _ModelObject = class _ModelObject extends SceneObject {
4002
4483
  combinedGeo = mergeBufferGeometries(allGeos);
4003
4484
  } else {
4004
4485
  combinedGeo = new BoxGeometry5(16, 16, 16);
4486
+ if (displayTransform) DisplayTransforms.apply(combinedGeo, displayTransform);
4005
4487
  }
4006
4488
  combinedGeo.computeBoundingBox();
4007
4489
  let mesh;
@@ -4031,6 +4513,7 @@ var _ModelObject = class _ModelObject extends SceneObject {
4031
4513
  /*TODO: get this from render options*/
4032
4514
  );
4033
4515
  this.iterateAllMeshes((mesh) => {
4516
+ if (mesh.geometry.hasAttribute("color")) mat.vertexColors = true;
4034
4517
  mesh.material = mat;
4035
4518
  });
4036
4519
  if (this.atlas.hasAnimation) {
@@ -4046,17 +4529,25 @@ var _ModelObject = class _ModelObject extends SceneObject {
4046
4529
  }
4047
4530
  }
4048
4531
  };
4049
- _ModelObject.DEFAULT_OPTIONS = (0, import_ts_deepmerge6.default)({}, SceneObject.DEFAULT_OPTIONS, {});
4050
- var ModelObject = _ModelObject;
4051
4532
  function isModelObject(obj) {
4052
4533
  return obj.isModelObject;
4053
4534
  }
4054
4535
 
4055
4536
  // src/model/block/scene/BlockObject.ts
4056
- var import_ts_deepmerge7 = __toESM(require_dist());
4057
- import { Euler as Euler3, Matrix4 as Matrix46, Vector3 as Vector36 } from "three";
4058
- var p11 = prefix("BlockObject");
4059
- var _BlockObject = class _BlockObject extends SceneObject {
4537
+ var import_ts_deepmerge6 = __toESM(require_dist());
4538
+ import { Euler as Euler5, Matrix4 as Matrix45, Vector3 as Vector37 } from "three";
4539
+ var p10 = prefix("BlockObject");
4540
+ function matchesCondition(condition, state) {
4541
+ return Object.entries(condition).every(([key, value]) => {
4542
+ if (Array.isArray(value)) {
4543
+ if (key === "OR") return value.some((child) => matchesCondition(child, state));
4544
+ if (key === "AND") return value.every((child) => matchesCondition(child, state));
4545
+ return false;
4546
+ }
4547
+ return typeof value === "string" && state[key] !== void 0 && value.split("|").includes(`${state[key]}`);
4548
+ });
4549
+ }
4550
+ var BlockObject = class _BlockObject extends SceneObject {
4060
4551
  constructor(blockState, options) {
4061
4552
  super(options);
4062
4553
  this.blockState = blockState;
@@ -4069,11 +4560,16 @@ var _BlockObject = class _BlockObject extends SceneObject {
4069
4560
  this._instanceModel = [];
4070
4561
  this._variants = [];
4071
4562
  this._models = [];
4072
- this.options = (0, import_ts_deepmerge7.default)({}, _BlockObject.DEFAULT_OPTIONS, options ?? {});
4563
+ this.options = (0, import_ts_deepmerge6.default)({}, _BlockObject.DEFAULT_OPTIONS, options ?? {});
4564
+ }
4565
+ static {
4566
+ this.DEFAULT_OPTIONS = (0, import_ts_deepmerge6.default)({}, ModelObject.DEFAULT_OPTIONS, {
4567
+ applyDefaultState: true
4568
+ });
4073
4569
  }
4074
4570
  async init() {
4075
4571
  if (this.options.applyDefaultState) {
4076
- const defaultState = this.blockState.key ? BlockStates.getDefaultState(this.blockState.key) : void 0;
4572
+ const defaultState = this.blockState.key ? await BlockStates.getDefaultState(this.blockState.key) : void 0;
4077
4573
  if (defaultState && Object.keys(defaultState).length > 0) {
4078
4574
  const state = {};
4079
4575
  for (let k in defaultState) {
@@ -4084,15 +4580,9 @@ var _BlockObject = class _BlockObject extends SceneObject {
4084
4580
  if (this.blockState.variants) {
4085
4581
  await this.setState(Object.keys(this.blockState.variants)[0]);
4086
4582
  } else if (this.blockState.multipart) {
4087
- for (let part of this.blockState.multipart) {
4088
- if (part.when && !("OR" in part.when)) {
4089
- const k = Object.keys(part.when)[0];
4090
- if (k) {
4091
- await this.setState(k, part.when[k].split("|")[0]);
4092
- break;
4093
- }
4094
- }
4095
- }
4583
+ const condition = this.blockState.multipart.map((part) => part.when).find((when) => when !== void 0 && Object.values(when).every((value) => typeof value === "string"));
4584
+ const state = Object.fromEntries(Object.entries(condition ?? {}).map(([key, value]) => [key, value.split("|")[0]]));
4585
+ await this.setState(state);
4096
4586
  }
4097
4587
  }
4098
4588
  } else {
@@ -4107,7 +4597,7 @@ var _BlockObject = class _BlockObject extends SceneObject {
4107
4597
  if (isModelObject(model)) {
4108
4598
  model.removeFromScene();
4109
4599
  } else if (isInstanceReference(model)) {
4110
- model.setScale(new Vector36(0, 0, 0));
4600
+ model.setScale(new Vector37(0, 0, 0));
4111
4601
  }
4112
4602
  }
4113
4603
  super.removeFromScene();
@@ -4149,55 +4639,11 @@ var _BlockObject = class _BlockObject extends SceneObject {
4149
4639
  } else if (this.blockState.multipart) {
4150
4640
  for (let part of this.blockState.multipart) {
4151
4641
  if (!part.apply) {
4152
- console.debug(p11, "Missing apply for blockState part", part);
4642
+ console.debug(p10, "Missing apply for blockState part", part);
4153
4643
  continue;
4154
4644
  }
4155
- if (!part.when) {
4645
+ if (!part.when || matchesCondition(part.when, state)) {
4156
4646
  out.push(this.getSingleVariant(part.apply));
4157
- } else {
4158
- let matches = true;
4159
- if ("OR" in part.when) {
4160
- const or = part.when.OR;
4161
- let anyMatch = false;
4162
- for (let o of or) {
4163
- for (let k in o) {
4164
- const split = o[k].split("|");
4165
- let m = false;
4166
- for (let s of split) {
4167
- if (`${state[k]}` === `${s}`) {
4168
- m = true;
4169
- break;
4170
- }
4171
- }
4172
- if (m) {
4173
- anyMatch = true;
4174
- break;
4175
- }
4176
- }
4177
- }
4178
- if (!anyMatch) {
4179
- matches = false;
4180
- }
4181
- } else {
4182
- for (let k in part.when) {
4183
- const split = part.when[k].split("|");
4184
- let m = false;
4185
- for (let s of split) {
4186
- if (`${state[k]}` === `${s}`) {
4187
- m = true;
4188
- break;
4189
- }
4190
- }
4191
- if (!m) {
4192
- matches = false;
4193
- break;
4194
- }
4195
- }
4196
- }
4197
- if (matches) {
4198
- const variants = part.apply;
4199
- out.push(this.getSingleVariant(variants));
4200
- }
4201
4647
  }
4202
4648
  }
4203
4649
  }
@@ -4212,7 +4658,7 @@ var _BlockObject = class _BlockObject extends SceneObject {
4212
4658
  }
4213
4659
  for (let model of this._models) {
4214
4660
  if (isInstanceReference(model)) {
4215
- model.setScale(new Vector36(0, 0, 0));
4661
+ model.setScale(new Vector37(0, 0, 0));
4216
4662
  } else {
4217
4663
  model.dispose();
4218
4664
  }
@@ -4227,11 +4673,21 @@ var _BlockObject = class _BlockObject extends SceneObject {
4227
4673
  }
4228
4674
  }
4229
4675
  getSingleVariant(variants) {
4230
- if (Array.isArray(variants)) {
4231
- return variants[0];
4232
- } else {
4233
- return variants;
4234
- }
4676
+ if (!Array.isArray(variants)) return variants;
4677
+ if (!variants.length) throw new MineRenderError("Blockstate variant arrays must not be empty");
4678
+ const total = variants.reduce((sum, variant) => {
4679
+ const weight = variant.weight ?? 1;
4680
+ if (!Number.isInteger(weight) || weight < 1) {
4681
+ throw new MineRenderError(`Invalid blockstate variant weight: ${weight}`);
4682
+ }
4683
+ return sum + weight;
4684
+ }, 0);
4685
+ let choice = Math.random() * total;
4686
+ for (const variant of variants) {
4687
+ choice -= variant.weight ?? 1;
4688
+ if (choice < 0) return variant;
4689
+ }
4690
+ return variants[variants.length - 1];
4235
4691
  }
4236
4692
  // @deprecated
4237
4693
  async createAVariant(variants, instanceInfo) {
@@ -4239,28 +4695,27 @@ var _BlockObject = class _BlockObject extends SceneObject {
4239
4695
  await this.createVariant(variant);
4240
4696
  }
4241
4697
  async createVariant(variant) {
4242
- const model = await Models.getMerged(AssetKey.parse("models", variant.model));
4243
- const obj = await this.scene.addModel(model, this.options);
4244
- if (isInstanceReference(obj) || obj.isInstanced) {
4245
- this._isInstanced = true;
4246
- this._instanceCounter = 1;
4247
- }
4248
- let rotation = new Euler3(0, 0, 0);
4698
+ const rotation = new Euler5();
4249
4699
  if (typeof variant.x !== "undefined") {
4250
4700
  rotation.x = toRadians(clampRotationDegrees(variant.x));
4251
4701
  }
4252
4702
  if (typeof variant.y !== "undefined") {
4253
- if (typeof variant.x !== "undefined") {
4254
- rotation.y = toRadians(clampRotationDegrees(variant.y));
4255
- } else {
4256
- rotation.y = toRadians(clampRotationDegrees(360 - variant.y));
4257
- }
4703
+ rotation.y = toRadians(clampRotationDegrees(typeof variant.x !== "undefined" ? variant.y : 360 - variant.y));
4704
+ }
4705
+ const modelKey = AssetKey.parse("models", variant.model);
4706
+ modelKey.root = this.blockState.key?.root;
4707
+ const model = await Models.getMerged(modelKey);
4708
+ const options = {
4709
+ ...this.options,
4710
+ tints: model ? await BlockTints.get(this.blockState.key, this.state, model, this.options.tints) : this.options.tints,
4711
+ uvLockRotation: variant.uvlock && (rotation.x !== 0 || rotation.y !== 0) ? [rotation.x, rotation.y, rotation.z] : void 0
4712
+ };
4713
+ const obj = await this.scene.addModel(model, options);
4714
+ if (isInstanceReference(obj) || obj.isInstanced) {
4715
+ this._isInstanced = true;
4716
+ this._instanceCounter = 1;
4258
4717
  }
4259
4718
  obj.setRotation(rotation);
4260
- setTimeout(() => {
4261
- obj.setRotation(rotation);
4262
- }, 150);
4263
- console.log(obj);
4264
4719
  return obj;
4265
4720
  }
4266
4721
  async resetState() {
@@ -4329,7 +4784,7 @@ var _BlockObject = class _BlockObject extends SceneObject {
4329
4784
  setPositionRotationScaleAt(index, position, rotation, scale) {
4330
4785
  super.setPositionRotationScaleAt(index, position, rotation, scale);
4331
4786
  }
4332
- getMatrixAt(index, matrix = new Matrix46()) {
4787
+ getMatrixAt(index, matrix = new Matrix45()) {
4333
4788
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
4334
4789
  const child = this._models[0];
4335
4790
  if (child && isModelObject(child)) {
@@ -4350,18 +4805,15 @@ var _BlockObject = class _BlockObject extends SceneObject {
4350
4805
  }
4351
4806
  }
4352
4807
  setPosition(position) {
4353
- super.setPosition(position);
4808
+ this.position.copy(position);
4354
4809
  for (let model of this._models) {
4355
4810
  model.setPosition(position);
4356
4811
  }
4812
+ this.notifyDirty();
4357
4813
  }
4358
4814
  //TODO: should override rotation + scale methods
4359
4815
  //TODO
4360
4816
  };
4361
- _BlockObject.DEFAULT_OPTIONS = (0, import_ts_deepmerge7.default)({}, ModelObject.DEFAULT_OPTIONS, {
4362
- applyDefaultState: true
4363
- });
4364
- var BlockObject = _BlockObject;
4365
4817
  function isBlockObject(obj) {
4366
4818
  return obj.isBlockObject;
4367
4819
  }
@@ -4386,11 +4838,10 @@ var StructureParser = class {
4386
4838
  throw new MineRenderError("Structure does not have palette(s)");
4387
4839
  }
4388
4840
  const blocks = nbt.blocks.value.value.map((block) => {
4389
- var _a;
4390
4841
  const state = palette.value.value[block.state.value];
4391
4842
  if (state.Name.value === "minecraft:air") return void 0;
4392
4843
  const props = {};
4393
- for (let k in (_a = state.Properties) == null ? void 0 : _a.value) {
4844
+ for (let k in state.Properties?.value) {
4394
4845
  props[k] = state.Properties.value[k].value;
4395
4846
  }
4396
4847
  return {
@@ -4409,7 +4860,7 @@ var StructureParser = class {
4409
4860
 
4410
4861
  // src/renderer/MineRenderScene.ts
4411
4862
  import { Scene as Scene2 } from "three";
4412
- var import_ts_deepmerge9 = __toESM(require_dist());
4863
+ var import_ts_deepmerge8 = __toESM(require_dist());
4413
4864
 
4414
4865
  // src/skin/SkinPart.ts
4415
4866
  var SkinPart = /* @__PURE__ */ ((SkinPart2) => {
@@ -5027,90 +5478,80 @@ var baseSkinCoordinates = {
5027
5478
  ]
5028
5479
  },
5029
5480
  up: {
5030
- uv: [
5031
- 4,
5032
- 36,
5033
- 8,
5034
- 32
5035
- ]
5036
- },
5037
- down: {
5038
- uv: [
5039
- 8,
5040
- 32,
5041
- 12,
5042
- 36
5043
- ],
5044
- rotation: 180
5045
- }
5046
- },
5047
- cape: {
5048
- //TODO
5049
- east: {
5050
- uv: [
5051
- 0,
5052
- 36,
5053
- 4,
5054
- 48
5055
- ]
5056
- },
5057
- west: {
5058
5481
  uv: [
5059
5482
  8,
5060
5483
  36,
5061
- 12,
5062
- 48
5063
- ]
5064
- },
5065
- north: {
5066
- uv: [
5067
5484
  4,
5068
- 36,
5069
- 8,
5070
- 48
5485
+ 32
5071
5486
  ]
5072
5487
  },
5073
- south: {
5488
+ down: {
5074
5489
  uv: [
5075
5490
  12,
5076
- 36,
5077
- 16,
5078
- 48
5079
- ]
5080
- },
5081
- up: {
5082
- uv: [
5083
- 4,
5084
5491
  32,
5085
5492
  8,
5086
5493
  36
5087
- ]
5088
- },
5089
- down: {
5090
- uv: [
5091
- 8,
5092
- 32,
5093
- 12,
5094
- 36
5095
5494
  ],
5096
5495
  rotation: 180
5097
5496
  }
5497
+ },
5498
+ cape: {
5499
+ east: { uv: [0, 1, 1, 17] },
5500
+ west: { uv: [11, 1, 12, 17] },
5501
+ north: { uv: [1, 1, 11, 17] },
5502
+ south: { uv: [12, 1, 22, 17] },
5503
+ up: { uv: [11, 1, 1, 0] },
5504
+ down: { uv: [21, 0, 11, 1] }
5098
5505
  }
5099
5506
  };
5100
5507
  var classicSkinTextureCoordinates = {
5101
5508
  ...baseSkinCoordinates
5102
5509
  };
5103
- var slimSkinTextureCoordinates = { ...baseSkinCoordinates };
5510
+ var slimSkinTextureCoordinates = {
5511
+ ...baseSkinCoordinates,
5512
+ leftArm: {
5513
+ ...baseSkinCoordinates.leftArm,
5514
+ west: { uv: [39, 52, 43, 64] },
5515
+ north: { uv: [36, 52, 39, 64] },
5516
+ south: { uv: [43, 52, 46, 64] },
5517
+ up: { uv: [39, 52, 36, 48] },
5518
+ down: { uv: [42, 48, 39, 52] }
5519
+ },
5520
+ rightArm: {
5521
+ ...baseSkinCoordinates.rightArm,
5522
+ west: { uv: [47, 20, 51, 32] },
5523
+ north: { uv: [44, 20, 47, 32] },
5524
+ south: { uv: [51, 20, 54, 32] },
5525
+ up: { uv: [47, 20, 44, 16] },
5526
+ down: { uv: [50, 16, 47, 20] }
5527
+ },
5528
+ leftSleeve: {
5529
+ ...baseSkinCoordinates.leftSleeve,
5530
+ west: { uv: [55, 52, 59, 64] },
5531
+ north: { uv: [52, 52, 55, 64] },
5532
+ south: { uv: [59, 52, 62, 64] },
5533
+ up: { uv: [55, 52, 52, 48] },
5534
+ down: { uv: [58, 48, 55, 52], rotation: 180 }
5535
+ },
5536
+ rightSleeve: {
5537
+ ...baseSkinCoordinates.rightSleeve,
5538
+ west: { uv: [47, 36, 51, 48] },
5539
+ north: { uv: [44, 36, 47, 48] },
5540
+ south: { uv: [51, 36, 54, 48] },
5541
+ up: { uv: [47, 36, 44, 32] },
5542
+ down: { uv: [50, 32, 47, 36], rotation: 180 }
5543
+ }
5544
+ };
5104
5545
 
5105
5546
  // src/skin/SkinGeometries.ts
5106
5547
  var box8inner = [8, 8, 8];
5107
- var box8outer = [8.504, 8.504, 8.504];
5548
+ var box8outer = [9, 9, 9];
5108
5549
  var box8_12_4inner = [8, 12, 4];
5109
- var box8_12_4outer = [8.504, 12.504, 4.504];
5550
+ var box8_12_4outer = [8.5, 12.5, 4.5];
5110
5551
  var box4_12_4inner = [4, 12, 4];
5111
- var box4_12_4outer = [4.504, 12.504, 4.504];
5552
+ var box4_12_4outer = [4.5, 12.5, 4.5];
5112
5553
  var box3_12_4inner = [3, 12, 4];
5113
- var box3_12_4outer = [3.504, 12.504, 4.504];
5554
+ var box3_12_4outer = [3.5, 12.5, 4.5];
5114
5555
  var box10_16_1 = [10, 16, 1];
5115
5556
  var baseSkinGeometries = {
5116
5557
  head: box8inner,
@@ -5140,119 +5581,318 @@ var slimSkinGeometries = {
5140
5581
  };
5141
5582
 
5142
5583
  // src/skin/scene/SkinObject.ts
5143
- var import_ts_deepmerge8 = __toESM(require_dist());
5584
+ var import_ts_deepmerge7 = __toESM(require_dist());
5585
+
5586
+ // src/skin/SkinTextures.ts
5587
+ import { DataTexture, DoubleSide as DoubleSide2, FrontSide as FrontSide2, MeshBasicMaterial as MeshBasicMaterial3, SRGBColorSpace as SRGBColorSpace3 } from "three";
5588
+
5589
+ // src/skin/SkinImage.ts
5590
+ var SkinImage = class {
5591
+ static async getData(src) {
5592
+ const key = serializeImageKey({ src });
5593
+ return await Caching.imageDataCache.get(`skin:${key}`, async () => {
5594
+ const info = await ImageLoader.getInfo(src);
5595
+ if (info.type !== "png") return ImageLoader.getData(src);
5596
+ try {
5597
+ return await this.decodePng(info.data);
5598
+ } catch (error) {
5599
+ Caching.rawImageCache.invalidate(key);
5600
+ throw error;
5601
+ }
5602
+ });
5603
+ }
5604
+ static async decodePng(bytes) {
5605
+ const { decode, convertIndexedToRgb } = await import("fast-png");
5606
+ const png = decode(bytes);
5607
+ let { data, channels, depth } = png;
5608
+ if (channels === 1 && (png.palette || depth < 8)) {
5609
+ const max = (1 << depth) - 1;
5610
+ const palette = png.palette ?? Array.from({ length: max + 1 }, (_, value) => {
5611
+ const gray = value * 255 / max;
5612
+ return [gray, gray, gray, png.transparency?.[0] === value ? 0 : 255];
5613
+ });
5614
+ data = convertIndexedToRgb({ ...png, palette });
5615
+ channels = palette[0].length;
5616
+ depth = 8;
5617
+ }
5618
+ const pixels = new Uint8ClampedArray(png.width * png.height * 4);
5619
+ for (let pixel = 0; pixel < png.width * png.height; pixel++) {
5620
+ const source = pixel * channels;
5621
+ const target = pixel * 4;
5622
+ const sample = (channel) => depth === 16 ? data[source + channel] >>> 8 : data[source + channel];
5623
+ pixels[target] = sample(0);
5624
+ pixels[target + 1] = sample(channels < 3 ? 0 : 1);
5625
+ pixels[target + 2] = sample(channels < 3 ? 0 : 2);
5626
+ pixels[target + 3] = channels % 2 === 0 ? sample(channels - 1) : png.transparency?.every((value, channel) => data[source + channel] === value) ? 0 : 255;
5627
+ }
5628
+ return { width: png.width, height: png.height, data: pixels, colorSpace: "srgb" };
5629
+ }
5630
+ };
5631
+
5632
+ // src/skin/SkinTextures.ts
5633
+ var SkinTextures = class {
5634
+ static async get(src, legacy) {
5635
+ const image = await SkinImage.getData(src);
5636
+ const scale = image.width / 64;
5637
+ if (!Number.isInteger(scale) || scale < 1 || image.height !== image.width && image.height !== image.width / 2) {
5638
+ throw new MineRenderError(`Invalid skin dimensions ${image.width}x${image.height}; expected 64x64 or 64x32, or an integer-scaled equivalent`);
5639
+ }
5640
+ const isLegacy = legacy ?? image.height === image.width / 2;
5641
+ if (!isLegacy && image.height !== image.width) {
5642
+ throw new MineRenderError(`Invalid skin dimensions ${image.width}x${image.height}; non-legacy skins must be square`);
5643
+ }
5644
+ const slim = !isLegacy && this.isSlim(image, scale);
5645
+ const key = `skin:${serializeImageKey({ src })}:${isLegacy}`;
5646
+ const material = Caching.materialCache.get(key, () => {
5647
+ const pixels = isLegacy ? this.normalizeLegacy(image, scale) : new Uint8Array(image.data);
5648
+ this.makeBaseOpaque(pixels, image.width, scale);
5649
+ return this.createMaterial(pixels, image.width, image.width);
5650
+ });
5651
+ return { material, slim, legacy: isLegacy };
5652
+ }
5653
+ static async getCape(src, layout = "minecraft") {
5654
+ const image = await SkinImage.getData(src);
5655
+ const scale = image.width / 64;
5656
+ if (layout === "minecraft" && (!Number.isInteger(scale) || scale < 1 || image.height !== image.width / 2)) {
5657
+ throw new MineRenderError(`Invalid cape dimensions ${image.width}x${image.height}; expected 64x32 or an integer-scaled equivalent`);
5658
+ }
5659
+ return Caching.materialCache.get(`cape:${serializeImageKey({ src })}`, () => {
5660
+ return this.createMaterial(new Uint8Array(image.data), image.width, image.height, false);
5661
+ });
5662
+ }
5663
+ static createMaterial(pixels, width, height, transparent = true) {
5664
+ const texture = Textures.initTextureProps(new DataTexture(pixels, width, height));
5665
+ texture.colorSpace = SRGBColorSpace3;
5666
+ texture.flipY = true;
5667
+ texture.needsUpdate = true;
5668
+ return new MeshBasicMaterial3({ map: texture, transparent, side: transparent ? DoubleSide2 : FrontSide2, alphaTest: transparent ? 0.1 : 0 });
5669
+ }
5670
+ static isSlim(image, scale) {
5671
+ for (const [x, y] of [[46, 52], [54, 20]]) {
5672
+ for (let row = y * scale; row < (y + 12) * scale; row++) {
5673
+ for (let column = x * scale; column < (x + 1) * scale; column++) {
5674
+ if (image.data[(row * image.width + column) * 4 + 3] !== 0) return false;
5675
+ }
5676
+ }
5677
+ }
5678
+ return true;
5679
+ }
5680
+ static normalizeLegacy(image, scale) {
5681
+ const pixels = new Uint8Array(image.width * image.width * 4);
5682
+ pixels.set(image.data.subarray(0, image.width * image.width / 2 * 4));
5683
+ for (const [sx, sy, dx, dy, width, height] of [
5684
+ [4, 16, 20, 48, 4, 4],
5685
+ [8, 16, 24, 48, 4, 4],
5686
+ [0, 20, 24, 52, 4, 12],
5687
+ [4, 20, 20, 52, 4, 12],
5688
+ [8, 20, 16, 52, 4, 12],
5689
+ [12, 20, 28, 52, 4, 12],
5690
+ [44, 16, 36, 48, 4, 4],
5691
+ [48, 16, 40, 48, 4, 4],
5692
+ [40, 20, 40, 52, 4, 12],
5693
+ [44, 20, 36, 52, 4, 12],
5694
+ [48, 20, 32, 52, 4, 12],
5695
+ [52, 20, 44, 52, 4, 12]
5696
+ ]) {
5697
+ for (let y = 0; y < height * scale; y++) {
5698
+ for (let x = 0; x < width * scale; x++) {
5699
+ const source = ((sy * scale + y) * image.width + sx * scale + x) * 4;
5700
+ const target = ((dy * scale + y) * image.width + (dx + width) * scale - 1 - x) * 4;
5701
+ pixels.set(image.data.subarray(source, source + 4), target);
5702
+ }
5703
+ }
5704
+ }
5705
+ let clearHat = true;
5706
+ for (let y = 0; y < 32 * scale; y++) {
5707
+ for (let x = 32 * scale; x < image.width; x++) {
5708
+ if (pixels[(y * image.width + x) * 4 + 3] < 128) clearHat = false;
5709
+ }
5710
+ }
5711
+ if (clearHat) {
5712
+ for (let y = 0; y < 32 * scale; y++) {
5713
+ for (let x = 32 * scale; x < image.width; x++) {
5714
+ pixels[(y * image.width + x) * 4 + 3] = 0;
5715
+ }
5716
+ }
5717
+ }
5718
+ return pixels;
5719
+ }
5720
+ static makeBaseOpaque(pixels, width, scale) {
5721
+ for (const [x0, y0, x1, y1] of [[0, 0, 32, 16], [0, 16, 64, 32], [16, 48, 48, 64]]) {
5722
+ for (let y = y0 * scale; y < y1 * scale; y++) {
5723
+ for (let x = x0 * scale; x < x1 * scale; x++) pixels[(y * width + x) * 4 + 3] = 255;
5724
+ }
5725
+ }
5726
+ }
5727
+ };
5728
+
5729
+ // src/skin/CapeLayout.ts
5730
+ var capeTextureSizes = {
5731
+ minecraft: [64, 32],
5732
+ optifine: [46, 22],
5733
+ labymod: [22, 17]
5734
+ };
5735
+
5736
+ // src/skin/scene/SkinObject.ts
5144
5737
  var SkinObject = class extends SceneObject {
5145
5738
  constructor(options) {
5146
5739
  super();
5147
5740
  this.slim = false;
5148
- this.legacy = false;
5149
- this.skinTextureWidth = 64;
5150
- this.skinTextureHeight = 64;
5151
- this.options = (0, import_ts_deepmerge8.default)({}, SceneObject.DEFAULT_OPTIONS, options ?? {});
5741
+ this.detectedSlim = false;
5742
+ this.skinLoad = 0;
5743
+ this.capeLoad = 0;
5744
+ this.options = (0, import_ts_deepmerge7.default)({}, SceneObject.DEFAULT_OPTIONS, options ?? {});
5745
+ this.slim = this.options.slim ?? false;
5152
5746
  }
5153
5747
  async init() {
5748
+ const cape = this.getGroupByName("cape" /* CAPE */);
5154
5749
  this.createMeshes();
5750
+ if (cape) this.getGroupByName("body" /* BODY */).attach(cape);
5155
5751
  }
5156
5752
  removeMeshes() {
5157
5753
  }
5158
5754
  createMeshes() {
5159
- console.log("#createMeshes");
5160
- const mat = Materials.MISSING_TEXTURE;
5755
+ const mat = this.skinMaterial ?? Materials.MISSING_TEXTURE;
5161
5756
  {
5162
5757
  const headGroup = this.createAndAddGroup("head", 0, 28, 0, "y" /* Y */, -4);
5163
5758
  const headGeo = this.getBoxGeometry("head" /* HEAD */);
5164
5759
  const head = this.createAndAddMesh("head", headGroup, headGeo, mat, "y" /* Y */, 4);
5165
- if (!this.legacy) {
5166
- const hatGeo = this.getBoxGeometry("hat" /* HAT */);
5167
- const hat = this.createAndAddMesh("hat", headGroup, hatGeo, mat, "y" /* Y */, 4);
5168
- }
5760
+ const hatGeo = this.getBoxGeometry("hat" /* HAT */);
5761
+ const hat = this.createAndAddMesh("hat", headGroup, hatGeo, mat, "y" /* Y */, 4);
5169
5762
  }
5170
5763
  {
5171
- const bodyGroup = this.createAndAddGroup("body", 0, 18, 0);
5764
+ const bodyGroup = this.createAndAddGroup("body", 0, 24, 0);
5172
5765
  const bodyGeo = this.getBoxGeometry("body" /* BODY */);
5173
- const body = this.createAndAddMesh("body", bodyGroup, bodyGeo, mat);
5766
+ const body = this.createAndAddMesh("body", bodyGroup, bodyGeo, mat, "y" /* Y */, -6);
5174
5767
  const jacketGeo = this.getBoxGeometry("jacket" /* JACKET */);
5175
- const jacket = this.createAndAddMesh("jacket", bodyGroup, jacketGeo, mat);
5768
+ const jacket = this.createAndAddMesh("jacket", bodyGroup, jacketGeo, mat, "y" /* Y */, -6);
5176
5769
  }
5177
5770
  {
5178
5771
  {
5179
- const leftArmGroup = this.createAndAddGroup("leftArm", this.slim ? -5.5 : -6, 18, 0, "y" /* Y */, 4);
5772
+ const leftArmGroup = this.createAndAddGroup("leftArm", -5, 22, 0);
5180
5773
  const leftArmGeo = this.getBoxGeometry("leftArm" /* LEFT_ARM */);
5181
5774
  const leftArm = this.createAndAddMesh("leftArm", leftArmGroup, leftArmGeo, mat, "y" /* Y */, -4);
5775
+ leftArm.position.x = this.slim ? -0.5 : -1;
5182
5776
  const leftSleeveGeo = this.getBoxGeometry("leftSleeve" /* LEFT_SLEEVE */);
5183
5777
  const leftSleeve = this.createAndAddMesh("leftSleeve", leftArmGroup, leftSleeveGeo, mat, "y" /* Y */, -4);
5778
+ leftSleeve.position.x = this.slim ? -0.5 : -1;
5184
5779
  }
5185
5780
  {
5186
- const rightArmGroup = this.createAndAddGroup("rightArm", this.slim ? 5.5 : 6, 18, 0, "y" /* Y */, 4);
5781
+ const rightArmGroup = this.createAndAddGroup("rightArm", 5, 22, 0);
5187
5782
  const rightArmGeo = this.getBoxGeometry("rightArm" /* RIGHT_ARM */);
5188
5783
  const rightArm = this.createAndAddMesh("rightArm", rightArmGroup, rightArmGeo, mat, "y" /* Y */, -4);
5784
+ rightArm.position.x = this.slim ? 0.5 : 1;
5189
5785
  const rightSleeveGeo = this.getBoxGeometry("rightSleeve" /* RIGHT_SLEEVE */);
5190
5786
  const rightSleeve = this.createAndAddMesh("rightSleeve", rightArmGroup, rightSleeveGeo, mat, "y" /* Y */, -4);
5787
+ rightSleeve.position.x = this.slim ? 0.5 : 1;
5191
5788
  }
5192
5789
  }
5193
5790
  {
5194
5791
  {
5195
- const leftLegGroup = this.createAndAddGroup("leftLeg", -2, 6, 0, "y" /* Y */, 4);
5792
+ const leftLegGroup = this.createAndAddGroup("leftLeg", -1.9, 12, 0);
5196
5793
  const leftLegGeo = this.getBoxGeometry("leftLeg" /* LEFT_LEG */);
5197
- const leftLeg = this.createAndAddMesh("leftLeg", leftLegGroup, leftLegGeo, mat, "y" /* Y */, -4);
5794
+ const leftLeg = this.createAndAddMesh("leftLeg", leftLegGroup, leftLegGeo, mat, "y" /* Y */, -6);
5198
5795
  const leftTrousersGeo = this.getBoxGeometry("leftTrousers" /* LEFT_TROUSERS */);
5199
- const leftTrousers = this.createAndAddMesh("leftTrousers", leftLegGroup, leftTrousersGeo, mat, "y" /* Y */, -4);
5796
+ const leftTrousers = this.createAndAddMesh("leftTrousers", leftLegGroup, leftTrousersGeo, mat, "y" /* Y */, -6);
5200
5797
  }
5201
5798
  {
5202
- const rightLegGroup = this.createAndAddGroup("rightLeg", 2, 6, 0, "y" /* Y */, 4);
5799
+ const rightLegGroup = this.createAndAddGroup("rightLeg", 1.9, 12, 0);
5203
5800
  const rightLegGeo = this.getBoxGeometry("rightLeg" /* RIGHT_LEG */);
5204
- const rightLeg = this.createAndAddMesh("rightLeg", rightLegGroup, rightLegGeo, mat, "y" /* Y */, -4);
5801
+ const rightLeg = this.createAndAddMesh("rightLeg", rightLegGroup, rightLegGeo, mat, "y" /* Y */, -6);
5205
5802
  const rightTrousersGeo = this.getBoxGeometry("rightTrousers" /* RIGHT_TROUSERS */);
5206
- const rightTrousers = this.createAndAddMesh("rightTrousers", rightLegGroup, rightTrousersGeo, mat, "y" /* Y */, -4);
5803
+ const rightTrousers = this.createAndAddMesh("rightTrousers", rightLegGroup, rightTrousersGeo, mat, "y" /* Y */, -6);
5207
5804
  }
5208
5805
  }
5209
- console.log("#createMeshes done");
5210
5806
  }
5211
- setSkinTexture(src) {
5807
+ async setSkinTexture(src) {
5212
5808
  if (typeof src === "undefined") return;
5213
5809
  this.skinTextureSrc = src;
5214
- const mat = Materials.getImage({
5215
- texture: { src },
5216
- transparent: true
5217
- });
5218
- for (let part of SKIN_PARTS) {
5219
- let mesh = this.getMeshByName(part);
5810
+ const load = ++this.skinLoad;
5811
+ const texture = await SkinTextures.get(src, this.options.legacy);
5812
+ if (load !== this.skinLoad) return;
5813
+ this.skinMaterial = texture.material;
5814
+ this.detectedSlim = texture.slim;
5815
+ this.updateSlim(this.options.slim ?? this.detectedSlim);
5816
+ for (const part of SKIN_PARTS) {
5817
+ if (part === "cape" /* CAPE */) continue;
5818
+ const mesh = this.getMeshByName(part);
5220
5819
  if (mesh) {
5221
- mesh.material = mat;
5820
+ mesh.material = texture.material;
5222
5821
  }
5223
5822
  }
5823
+ this.notifyDirty();
5824
+ }
5825
+ /** Load a cape texture in the selected layout, or pass undefined to remove the cape. */
5826
+ async setCapeTexture(src, layout = "minecraft") {
5827
+ const load = ++this.capeLoad;
5828
+ if (src === void 0) {
5829
+ const group = this.getGroupByName("cape" /* CAPE */);
5830
+ group?.removeFromParent();
5831
+ this.notifyDirty();
5832
+ return;
5833
+ }
5834
+ const material = await SkinTextures.getCape(src, layout);
5835
+ if (load !== this.capeLoad) return;
5836
+ const size = capeTextureSizes[layout];
5837
+ const geometry = this._getBoxGeometryFromDimensions(
5838
+ classicSkinGeometries.cape,
5839
+ classicSkinTextureCoordinates.cape,
5840
+ size,
5841
+ size
5842
+ );
5843
+ const mesh = this.getMeshByName("cape" /* CAPE */);
5844
+ if (mesh) {
5845
+ mesh.material = material;
5846
+ mesh.geometry = geometry;
5847
+ } else {
5848
+ const body = this.getGroupByName("body" /* BODY */);
5849
+ const group = this.createGroup("cape" /* CAPE */, 0, body ? 0 : 24, 2);
5850
+ (body ?? this).add(group);
5851
+ group.rotation.set(toRadians(-6), Math.PI, 0);
5852
+ const cape = this.createAndAddMesh("cape" /* CAPE */, group, geometry, material);
5853
+ cape.position.set(0, -8, -0.5);
5854
+ }
5855
+ this.notifyDirty();
5224
5856
  }
5225
- //TODO: cape
5857
+ /** Select the arm model, or pass undefined to use texture detection. */
5226
5858
  setSlim(slim) {
5227
- console.log("#setSlim");
5228
- const changed = slim !== this.slim;
5859
+ this.options.slim = slim;
5860
+ this.updateSlim(slim ?? this.detectedSlim);
5861
+ }
5862
+ updateSlim(slim) {
5863
+ if (slim === this.slim) return;
5229
5864
  this.slim = slim;
5230
- if (changed) {
5231
- this.createMeshes();
5232
- }
5233
- if (changed) {
5234
- if (this.skinTextureSrc) {
5235
- this.setSkinTexture(this.skinTextureSrc);
5865
+ const offset = slim ? 0.5 : -0.5;
5866
+ for (const part of ["leftArm" /* LEFT_ARM */, "leftSleeve" /* LEFT_SLEEVE */, "rightArm" /* RIGHT_ARM */, "rightSleeve" /* RIGHT_SLEEVE */]) {
5867
+ const mesh = this.getMeshByName(part);
5868
+ if (mesh) {
5869
+ mesh.geometry = this.getBoxGeometry(part);
5870
+ mesh.position.x += part === "leftArm" /* LEFT_ARM */ || part === "leftSleeve" /* LEFT_SLEEVE */ ? offset : -offset;
5236
5871
  }
5237
5872
  }
5238
- console.log("#setSlim done");
5873
+ this.notifyDirty();
5239
5874
  }
5240
- setLegacy(legacy) {
5241
- if (legacy !== this.legacy) {
5242
- }
5243
- this.legacy = legacy;
5875
+ /** Select the texture layout, or pass undefined to detect it from image dimensions. */
5876
+ async setLegacy(legacy) {
5877
+ if (legacy === this.options.legacy) return;
5878
+ this.options.legacy = legacy;
5879
+ if (this.skinTextureSrc) await this.setSkinTexture(this.skinTextureSrc);
5880
+ }
5881
+ dispose() {
5882
+ this.skinLoad++;
5883
+ this.capeLoad++;
5884
+ super.dispose();
5244
5885
  }
5245
5886
  //TODO: layer toggles
5246
5887
  getBoxGeometry(part) {
5247
- console.log("slim", this.slim);
5248
5888
  const coordinates = this.slim ? slimSkinTextureCoordinates : classicSkinTextureCoordinates;
5249
5889
  const geometries = this.slim ? slimSkinGeometries : classicSkinGeometries;
5250
- return this._getBoxGeometryFromDimensions(geometries[part], coordinates[part], [64, 64], [this.skinTextureWidth, this.skinTextureHeight]);
5890
+ return this._getBoxGeometryFromDimensions(geometries[part], coordinates[part], [64, 64], [64, 64]);
5251
5891
  }
5252
5892
  };
5253
5893
 
5254
5894
  // src/renderer/MineRenderScene.ts
5255
- var _MineRenderScene = class _MineRenderScene extends Scene2 {
5895
+ var MineRenderScene = class _MineRenderScene extends Scene2 {
5256
5896
  constructor(options) {
5257
5897
  super();
5258
5898
  this.isMineRenderScene = true;
@@ -5261,12 +5901,14 @@ var _MineRenderScene = class _MineRenderScene extends Scene2 {
5261
5901
  this.dirty = true;
5262
5902
  this.observedObjects = /* @__PURE__ */ new Set();
5263
5903
  this.onObjectChange = (event) => {
5264
- var _a;
5265
- if (((_a = event.target) == null ? void 0 : _a.parent) === this) {
5904
+ if (event.target?.parent === this) {
5266
5905
  this.dirty = true;
5267
5906
  }
5268
5907
  };
5269
- this.options = (0, import_ts_deepmerge9.default)({}, _MineRenderScene.DEFAULT_OPTIONS, options ?? {});
5908
+ this.options = (0, import_ts_deepmerge8.default)({}, _MineRenderScene.DEFAULT_OPTIONS, options ?? {});
5909
+ }
5910
+ static {
5911
+ this.DEFAULT_OPTIONS = (0, import_ts_deepmerge8.default)({}, {});
5270
5912
  }
5271
5913
  add(...objects) {
5272
5914
  for (const object of objects) {
@@ -5274,7 +5916,7 @@ var _MineRenderScene = class _MineRenderScene extends Scene2 {
5274
5916
  try {
5275
5917
  super.add(object);
5276
5918
  } finally {
5277
- if ((object == null ? void 0 : object.isObject3D) && object !== this) {
5919
+ if (object?.isObject3D && object !== this) {
5278
5920
  this.updateObjectRegistration(object, object.parent === this);
5279
5921
  }
5280
5922
  }
@@ -5317,15 +5959,21 @@ var _MineRenderScene = class _MineRenderScene extends Scene2 {
5317
5959
  return this.add(...object);
5318
5960
  }
5319
5961
  async addSceneObject(asset, objectSupplier, _options, parent = this) {
5320
- var _a, _b;
5321
5962
  console.log("addSceneObject", asset);
5322
5963
  console.log("parent", parent);
5323
5964
  console.log(_options);
5324
5965
  this.dirty = true;
5325
5966
  const obj = await objectSupplier();
5326
- if (((_a = obj == null ? void 0 : obj.options) == null ? void 0 : _a.instanceMeshes) && asset.key && ((_b = asset.key) == null ? void 0 : _b.assetType) === "models") {
5967
+ if (obj?.options?.instanceMeshes && asset.key && asset.key?.assetType === "models") {
5327
5968
  console.log("instanceMeshes + key");
5328
- const key = asset.key.serialize();
5969
+ let key = asset.key.serialize();
5970
+ if (isModelObject(obj)) {
5971
+ const { displayPosition, uvLockRotation, tints } = obj.options;
5972
+ if (displayPosition) key += `|display:${displayPosition}`;
5973
+ if (uvLockRotation) key += `|uvlock:${uvLockRotation.join(",")}`;
5974
+ const palette = Object.entries(tints ?? {}).sort(([a], [b]) => Number(a) - Number(b));
5975
+ if (palette.length) key += `|tints:${JSON.stringify(palette)}`;
5976
+ }
5329
5977
  return this.instanceManager.getOrCreate(key, async () => {
5330
5978
  obj.scene = this;
5331
5979
  await obj.init();
@@ -5352,10 +6000,10 @@ var _MineRenderScene = class _MineRenderScene extends Scene2 {
5352
6000
  this.dirty = true;
5353
6001
  const obj = new SkinObject(options);
5354
6002
  obj.scene = this;
5355
- await obj.init();
5356
6003
  if (skin) {
5357
- obj.setSkinTexture(skin);
6004
+ await obj.setSkinTexture(skin);
5358
6005
  }
6006
+ await obj.init();
5359
6007
  parent.add(obj);
5360
6008
  return obj;
5361
6009
  }
@@ -5363,15 +6011,13 @@ var _MineRenderScene = class _MineRenderScene extends Scene2 {
5363
6011
  return this.addSceneObject(entity, () => new EntityObject(entity, options), options, parent);
5364
6012
  }
5365
6013
  };
5366
- _MineRenderScene.DEFAULT_OPTIONS = (0, import_ts_deepmerge9.default)({}, {});
5367
- var MineRenderScene = _MineRenderScene;
5368
6014
  function isMineRenderScene(obj) {
5369
6015
  return obj.isMineRenderScene;
5370
6016
  }
5371
6017
 
5372
6018
  // src/renderer/Renderer.ts
5373
- import { AxesHelper as AxesHelper3, GridHelper, LinearEncoding, OrthographicCamera, PCFSoftShadowMap, PerspectiveCamera, Vector3 as Vector38, WebGLRenderer } from "three";
5374
- var import_ts_deepmerge10 = __toESM(require_dist());
6019
+ import { AxesHelper as AxesHelper2, GridHelper, OrthographicCamera, PCFSoftShadowMap, PerspectiveCamera, SRGBColorSpace as SRGBColorSpace4, Vector3 as Vector39, WebGLRenderer } from "three";
6020
+ var import_ts_deepmerge9 = __toESM(require_dist());
5375
6021
  import Stats from "stats.js";
5376
6022
  import { EffectComposer, RenderPass } from "postprocessing";
5377
6023
 
@@ -5379,11 +6025,11 @@ import { EffectComposer, RenderPass } from "postprocessing";
5379
6025
  import {
5380
6026
  EventDispatcher,
5381
6027
  MOUSE,
5382
- Quaternion as Quaternion3,
6028
+ Quaternion as Quaternion4,
5383
6029
  Spherical,
5384
6030
  TOUCH,
5385
6031
  Vector2 as Vector23,
5386
- Vector3 as Vector37
6032
+ Vector3 as Vector38
5387
6033
  } from "three";
5388
6034
  var _changeEvent = { type: "change" };
5389
6035
  var _startEvent = { type: "start" };
@@ -5397,7 +6043,7 @@ var OrbitControls = class extends EventDispatcher {
5397
6043
  this.domElement = domElement;
5398
6044
  this.domElement.style.touchAction = "none";
5399
6045
  this.enabled = true;
5400
- this.target = new Vector37();
6046
+ this.target = new Vector38();
5401
6047
  this.minDistance = 0;
5402
6048
  this.maxDistance = Infinity;
5403
6049
  this.minZoom = 0;
@@ -5449,11 +6095,11 @@ var OrbitControls = class extends EventDispatcher {
5449
6095
  state = STATE.NONE;
5450
6096
  };
5451
6097
  this.update = function() {
5452
- const offset = new Vector37();
5453
- const quat = new Quaternion3().setFromUnitVectors(object.up, new Vector37(0, 1, 0));
6098
+ const offset = new Vector38();
6099
+ const quat = new Quaternion4().setFromUnitVectors(object.up, new Vector38(0, 1, 0));
5454
6100
  const quatInverse = quat.clone().invert();
5455
- const lastPosition = new Vector37();
5456
- const lastQuaternion = new Quaternion3();
6101
+ const lastPosition = new Vector38();
6102
+ const lastQuaternion = new Quaternion4();
5457
6103
  const twoPI = 2 * Math.PI;
5458
6104
  return function update() {
5459
6105
  const position = scope.object.position;
@@ -5542,7 +6188,7 @@ var OrbitControls = class extends EventDispatcher {
5542
6188
  const spherical = new Spherical();
5543
6189
  const sphericalDelta = new Spherical();
5544
6190
  let scale = 1;
5545
- const panOffset = new Vector37();
6191
+ const panOffset = new Vector38();
5546
6192
  let zoomChanged = false;
5547
6193
  const rotateStart = new Vector23();
5548
6194
  const rotateEnd = new Vector23();
@@ -5568,7 +6214,7 @@ var OrbitControls = class extends EventDispatcher {
5568
6214
  sphericalDelta.phi -= angle;
5569
6215
  }
5570
6216
  const panLeft = function() {
5571
- const v = new Vector37();
6217
+ const v = new Vector38();
5572
6218
  return function panLeft2(distance, objectMatrix) {
5573
6219
  v.setFromMatrixColumn(objectMatrix, 0);
5574
6220
  v.multiplyScalar(-distance);
@@ -5576,7 +6222,7 @@ var OrbitControls = class extends EventDispatcher {
5576
6222
  };
5577
6223
  }();
5578
6224
  const panUp = function() {
5579
- const v = new Vector37();
6225
+ const v = new Vector38();
5580
6226
  return function panUp2(distance, objectMatrix) {
5581
6227
  if (scope.screenSpacePanning === true) {
5582
6228
  v.setFromMatrixColumn(objectMatrix, 1);
@@ -5589,7 +6235,7 @@ var OrbitControls = class extends EventDispatcher {
5589
6235
  };
5590
6236
  }();
5591
6237
  const pan = function() {
5592
- const offset = new Vector37();
6238
+ const offset = new Vector38();
5593
6239
  return function pan2(deltaX, deltaY) {
5594
6240
  const element = scope.domElement;
5595
6241
  if (scope.object.isPerspectiveCamera) {
@@ -6026,11 +6672,9 @@ var MapControls = class extends OrbitControls {
6026
6672
  };
6027
6673
 
6028
6674
  // src/renderer/Renderer.ts
6029
- var _Renderer = class _Renderer {
6675
+ var Renderer = class _Renderer {
6030
6676
  constructor(options) {
6031
6677
  this._dirty = true;
6032
- this._animationTimer = void 0;
6033
- this._animationFrame = void 0;
6034
6678
  this._resizeListener = void 0;
6035
6679
  this._disposed = false;
6036
6680
  this._debugHelpers = [];
@@ -6038,9 +6682,9 @@ var _Renderer = class _Renderer {
6038
6682
  this._changeListener = () => {
6039
6683
  this._dirty = true;
6040
6684
  };
6041
- this.options = (0, import_ts_deepmerge10.default)({}, _Renderer.DEFAULT_OPTIONS, options ?? {});
6685
+ this.options = (0, import_ts_deepmerge9.default)({}, _Renderer.DEFAULT_OPTIONS, options ?? {});
6042
6686
  this._animationLoop = this.animate.bind(this);
6043
- this._fpsTimer = this.options.render.fpsLimit > 0 ? 1e3 / this.options.render.fpsLimit : void 0;
6687
+ this._frameInterval = this.options.render.fpsLimit > 0 ? 1e3 / this.options.render.fpsLimit : void 0;
6044
6688
  this._scene = this.createScene();
6045
6689
  this._camera = this.createCamera();
6046
6690
  this._renderer = this.createRenderer();
@@ -6052,6 +6696,45 @@ var _Renderer = class _Renderer {
6052
6696
  this.init();
6053
6697
  this._controls = this.createControls();
6054
6698
  }
6699
+ static {
6700
+ this.DEFAULT_OPTIONS = (0, import_ts_deepmerge9.default)({}, {
6701
+ camera: {
6702
+ type: "perspective",
6703
+ near: 1,
6704
+ far: 5e3,
6705
+ perspective: {
6706
+ aspect: void 0,
6707
+ fov: 50
6708
+ },
6709
+ orthographic: {
6710
+ left: void 0,
6711
+ right: void 0,
6712
+ top: void 0,
6713
+ bottom: void 0
6714
+ },
6715
+ position: new Vector39(50, 50, 50),
6716
+ lookingAt: new Vector39(0, 0, 0)
6717
+ },
6718
+ render: {
6719
+ fpsLimit: 60,
6720
+ stats: false,
6721
+ antialias: true,
6722
+ shade: true,
6723
+ autoResize: true,
6724
+ renderAlways: false
6725
+ },
6726
+ composer: {
6727
+ enabled: true
6728
+ },
6729
+ controls: {
6730
+ enabled: false
6731
+ },
6732
+ debug: {
6733
+ grid: false,
6734
+ axes: false
6735
+ }
6736
+ });
6737
+ }
6055
6738
  //<editor-fold desc="INIT">
6056
6739
  createScene() {
6057
6740
  return new MineRenderScene();
@@ -6087,20 +6770,19 @@ var _Renderer = class _Renderer {
6087
6770
  renderer.setClearColor(0, 0);
6088
6771
  renderer.shadowMap.enabled = true;
6089
6772
  renderer.shadowMap.type = PCFSoftShadowMap;
6090
- renderer.outputEncoding = LinearEncoding;
6773
+ renderer.outputColorSpace = SRGBColorSpace4;
6091
6774
  renderer.setSize(this.viewWidth, this.viewHeight);
6092
6775
  return renderer;
6093
6776
  }
6094
6777
  createComposer() {
6778
+ if (!this.options.composer.enabled) return void 0;
6095
6779
  const composer = new EffectComposer(this.renderer);
6096
- if (!this.options.composer.enabled) return composer;
6097
6780
  composer.setSize(this.viewWidth, this.viewHeight);
6098
6781
  composer.addPass(new RenderPass(this.scene, this.camera));
6099
6782
  return composer;
6100
6783
  }
6101
6784
  createControls() {
6102
- var _a;
6103
- if (!((_a = this.options.controls) == null ? void 0 : _a.enabled)) return void 0;
6785
+ if (!this.options.controls?.enabled) return void 0;
6104
6786
  const position = this.camera.position.clone();
6105
6787
  const controls = new OrbitControls(this.camera, this.renderer.domElement);
6106
6788
  this.camera.position.copy(position);
@@ -6135,7 +6817,7 @@ var _Renderer = class _Renderer {
6135
6817
  this.scene.add(gridHelper3);
6136
6818
  }
6137
6819
  if (this.options.debug.axes) {
6138
- const axesHelper = new AxesHelper3(64);
6820
+ const axesHelper = new AxesHelper2(64);
6139
6821
  this._debugHelpers.push(axesHelper);
6140
6822
  this.scene.add(axesHelper);
6141
6823
  }
@@ -6203,7 +6885,7 @@ var _Renderer = class _Renderer {
6203
6885
  this.camera.updateProjectionMatrix();
6204
6886
  }
6205
6887
  this.renderer.setSize(width, height);
6206
- this.composer.setSize(width, height);
6888
+ this.composer?.setSize(width, height);
6207
6889
  this._dirty = true;
6208
6890
  }
6209
6891
  //<editor-fold desc="RENDER">
@@ -6222,12 +6904,7 @@ var _Renderer = class _Renderer {
6222
6904
  stop() {
6223
6905
  if (this._disposed) return;
6224
6906
  this.renderer.setAnimationLoop(null);
6225
- if (this._animationTimer)
6226
- clearTimeout(this._animationTimer);
6227
- this._animationTimer = void 0;
6228
- if (this._animationFrame)
6229
- cancelAnimationFrame(this._animationFrame);
6230
- this._animationFrame = void 0;
6907
+ this._nextFrameTime = void 0;
6231
6908
  }
6232
6909
  /**
6233
6910
  * Stops rendering and releases owned resources. Repeated calls have no effect, and a disposed
@@ -6235,7 +6912,6 @@ var _Renderer = class _Renderer {
6235
6912
  * controls must be managed by their owners.
6236
6913
  */
6237
6914
  dispose() {
6238
- var _a;
6239
6915
  if (this._disposed) return;
6240
6916
  this.stop();
6241
6917
  this._disposed = true;
@@ -6249,7 +6925,7 @@ var _Renderer = class _Renderer {
6249
6925
  }
6250
6926
  }
6251
6927
  this._eventDispatchers.clear();
6252
- (_a = this._stats) == null ? void 0 : _a.dom.remove();
6928
+ this._stats?.dom.remove();
6253
6929
  this._stats = void 0;
6254
6930
  this.renderer.domElement.remove();
6255
6931
  this._element = void 0;
@@ -6268,26 +6944,30 @@ var _Renderer = class _Renderer {
6268
6944
  }
6269
6945
  }
6270
6946
  this._debugHelpers.length = 0;
6271
- this.composer.dispose();
6947
+ this.composer?.dispose();
6272
6948
  this.renderer.dispose();
6273
6949
  this.renderer.forceContextLoss();
6274
6950
  }
6275
- animate(t) {
6276
- var _a;
6951
+ animate(t = performance.now()) {
6277
6952
  if (this._disposed) return;
6278
- if (this._stats) {
6279
- this._stats.begin();
6280
- }
6281
- if ((_a = this._controls) == null ? void 0 : _a.enabled) {
6953
+ if (this._controls?.enabled) {
6282
6954
  this._controls.update();
6283
6955
  }
6284
6956
  if (this._disposed) return;
6285
- if (this.dirty || this.options.render.renderAlways) {
6286
- if (this.options.composer.enabled) {
6287
- this.composer.render();
6288
- } else {
6289
- this.renderer.render(this.scene, this.camera);
6290
- }
6957
+ if (!this.dirty && !this.options.render.renderAlways) return;
6958
+ const interval = this._frameInterval;
6959
+ if (interval) {
6960
+ const next = this._nextFrameTime;
6961
+ if (next !== void 0 && t + 0.1 < next) return;
6962
+ this._nextFrameTime = next !== void 0 && t - next < interval ? next + interval : t + interval;
6963
+ }
6964
+ if (this._stats) {
6965
+ this._stats.begin();
6966
+ }
6967
+ if (this.options.composer.enabled && this.composer) {
6968
+ this.composer.render();
6969
+ } else {
6970
+ this.renderer.render(this.scene, this.camera);
6291
6971
  }
6292
6972
  this.dirty = false;
6293
6973
  if (this._stats) {
@@ -6303,12 +6983,10 @@ var _Renderer = class _Renderer {
6303
6983
  return this.element === document.body;
6304
6984
  }
6305
6985
  get viewWidth() {
6306
- var _a;
6307
- return this.attachedToBody ? window.innerWidth : ((_a = this.element) == null ? void 0 : _a.offsetWidth) || 0;
6986
+ return this.attachedToBody ? window.innerWidth : this.element?.offsetWidth || 0;
6308
6987
  }
6309
6988
  get viewHeight() {
6310
- var _a;
6311
- return this.attachedToBody ? window.innerHeight : ((_a = this.element) == null ? void 0 : _a.offsetHeight) || 0;
6989
+ return this.attachedToBody ? window.innerHeight : this.element?.offsetHeight || 0;
6312
6990
  }
6313
6991
  get scene() {
6314
6992
  return this._scene;
@@ -6328,44 +7006,6 @@ var _Renderer = class _Renderer {
6328
7006
  }
6329
7007
  ///
6330
7008
  };
6331
- _Renderer.DEFAULT_OPTIONS = (0, import_ts_deepmerge10.default)({}, {
6332
- camera: {
6333
- type: "perspective",
6334
- near: 1,
6335
- far: 5e3,
6336
- perspective: {
6337
- aspect: void 0,
6338
- fov: 50
6339
- },
6340
- orthographic: {
6341
- left: void 0,
6342
- right: void 0,
6343
- top: void 0,
6344
- bottom: void 0
6345
- },
6346
- position: new Vector38(50, 50, 50),
6347
- lookingAt: new Vector38(0, 0, 0)
6348
- },
6349
- render: {
6350
- fpsLimit: 60,
6351
- stats: false,
6352
- antialias: true,
6353
- shade: true,
6354
- autoResize: true,
6355
- renderAlways: false
6356
- },
6357
- composer: {
6358
- enabled: true
6359
- },
6360
- controls: {
6361
- enabled: false
6362
- },
6363
- debug: {
6364
- grid: false,
6365
- axes: false
6366
- }
6367
- });
6368
- var Renderer = _Renderer;
6369
7009
 
6370
7010
  // src/skin/Skins.ts
6371
7011
  var Skins = class {
@@ -6377,7 +7017,7 @@ var Skins = class {
6377
7017
  return this.fromUsername(uuidOrUsername);
6378
7018
  }
6379
7019
  static async fromUuid(uuid) {
6380
- return this.getSkinProxySkinUrl(uuid);
7020
+ return this.getMcProxySkinUrl(uuid);
6381
7021
  }
6382
7022
  static async fromUsername(username) {
6383
7023
  return this.usernameToUuid(username).then((uuid) => {
@@ -6404,7 +7044,7 @@ var Skins = class {
6404
7044
  return this.capeFromUsername(uuidOrUsername);
6405
7045
  }
6406
7046
  static async capeFromUuid(uuid) {
6407
- return this.getSkinProxyCapeUrl(uuid);
7047
+ return this.getMcProxyCapeUrl(uuid);
6408
7048
  }
6409
7049
  static async capeFromUsername(username) {
6410
7050
  return this.usernameToUuid(username).then((uuid) => {
@@ -6414,19 +7054,31 @@ var Skins = class {
6414
7054
  return void 0;
6415
7055
  });
6416
7056
  }
6417
- static async capeFromCapesDev(uuid, capeType = "minecraft") {
6418
- return this.getCapesDev(uuid, capeType).then((cape) => {
6419
- if (cape) {
6420
- return cape == null ? void 0 : cape.stillImageUrl;
6421
- }
6422
- return void 0;
6423
- });
7057
+ /** Returns a full static cape texture for a username or UUID. */
7058
+ static async capeFromCapesDev(player, capeType = "minecraft") {
7059
+ const cape = await this.getCapesDev(player, capeType);
7060
+ return cape?.exists ? cape.imageUrls?.still?.full : void 0;
6424
7061
  }
6425
7062
  //</editor-fold>
6426
7063
  //<editor-fold desc="Helpers">
6427
7064
  static async usernameToUuid(username) {
6428
- return this.usernameToUuidSkinProxy(username);
7065
+ return this.usernameToUuidMcProxy(username);
7066
+ }
7067
+ static async usernameToUuidMcProxy(username) {
7068
+ return Requests.genericRequest({
7069
+ baseURL: "https://mcproxy.dev",
7070
+ url: "/uuid/" + username
7071
+ }).then((res) => {
7072
+ if (res.status === 200) {
7073
+ return res.data["data"]["id"];
7074
+ }
7075
+ return void 0;
7076
+ }).catch((err) => {
7077
+ console.warn(err);
7078
+ return void 0;
7079
+ });
6429
7080
  }
7081
+ /** @deprecated **/
6430
7082
  static async usernameToUuidSkinProxy(username) {
6431
7083
  return Requests.genericRequest({
6432
7084
  baseURL: "https://minecraft-skin-proxy.inventive.workers.dev",
@@ -6479,18 +7131,15 @@ var Skins = class {
6479
7131
  return void 0;
6480
7132
  });
6481
7133
  }
6482
- static async getCapesDev(uuid, type = "all") {
7134
+ static async getCapesDev(player, type = "all") {
6483
7135
  return Requests.genericRequest({
6484
7136
  baseURL: "https://api.capes.dev",
6485
- url: "/load/" + uuid + "/" + type
7137
+ url: "/load/" + encodeURIComponent(player) + "/" + encodeURIComponent(type)
6486
7138
  }).then((res) => {
6487
7139
  if (res.status === 200) {
6488
7140
  return res.data;
6489
7141
  }
6490
7142
  return void 0;
6491
- }).catch((err) => {
6492
- console.warn(err);
6493
- return void 0;
6494
7143
  });
6495
7144
  }
6496
7145
  static getCrafatarSkinUrl(uuid) {
@@ -6505,20 +7154,28 @@ var Skins = class {
6505
7154
  static getMineSkinPlayerSkinUrl(uuid) {
6506
7155
  return "https://mineskin.org/skin/player/" + uuid;
6507
7156
  }
7157
+ /** @deprecated **/
6508
7158
  static getSkinProxySkinUrl(uuid) {
6509
7159
  return "https://minecraft-skin-proxy.inventive.workers.dev/skin/" + uuid;
6510
7160
  }
7161
+ /** @deprecated **/
6511
7162
  static getSkinProxyCapeUrl(uuid) {
6512
7163
  return "https://minecraft-skin-proxy.inventive.workers.dev/cape/" + uuid;
6513
7164
  }
7165
+ static getMcProxySkinUrl(uuid) {
7166
+ return "https://mcproxy.dev/skin/" + uuid;
7167
+ }
7168
+ static getMcProxyCapeUrl(uuid) {
7169
+ return "https://mcproxy.dev/cape/" + uuid;
7170
+ }
6514
7171
  //</editor-fold>
6515
7172
  };
6516
7173
 
6517
7174
  // src/world/Chunk.ts
6518
- import { Box3 as Box32, Object3D as Object3D6, Vector3 as Vector310 } from "three";
7175
+ import { Box3 as Box32, Object3D as Object3D6, Vector3 as Vector311 } from "three";
6519
7176
 
6520
7177
  // src/world/MineRenderWorld.ts
6521
- import { Vector3 as Vector39 } from "three";
7178
+ import { Vector3 as Vector310 } from "three";
6522
7179
  var MineRenderWorld = class {
6523
7180
  constructor(scene) {
6524
7181
  this._size = 4;
@@ -6529,10 +7186,10 @@ var MineRenderWorld = class {
6529
7186
  }
6530
7187
  getBlockAt(posOrX, y, z) {
6531
7188
  if (typeof posOrX == "number") {
6532
- return this.getBlockAt(new Vector39(posOrX, y, z));
7189
+ return this.getBlockAt(new Vector310(posOrX, y, z));
6533
7190
  }
6534
7191
  if (isTripleArray(posOrX)) {
6535
- return this.getBlockAt(new Vector39(posOrX[0], posOrX[1], posOrX[2]));
7192
+ return this.getBlockAt(new Vector310(posOrX[0], posOrX[1], posOrX[2]));
6536
7193
  }
6537
7194
  const chunk = this.getChunkAt(posOrX);
6538
7195
  if (typeof chunk === "undefined") {
@@ -6543,10 +7200,10 @@ var MineRenderWorld = class {
6543
7200
  }
6544
7201
  async setBlockAt(posOrX, yOrBlock, z, block) {
6545
7202
  if (typeof posOrX == "number") {
6546
- return this.setBlockAt(new Vector39(posOrX, yOrBlock, z), block);
7203
+ return this.setBlockAt(new Vector310(posOrX, yOrBlock, z), block);
6547
7204
  }
6548
7205
  if (isTripleArray(posOrX)) {
6549
- return this.setBlockAt(new Vector39(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
7206
+ return this.setBlockAt(new Vector310(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
6550
7207
  }
6551
7208
  this.validatePosBounds(posOrX);
6552
7209
  const chunk = this.getOrCreateChunkAt(posOrX);
@@ -6574,7 +7231,7 @@ var MineRenderWorld = class {
6574
7231
  console.log("CHUNKS", this._chunks);
6575
7232
  for (let chunk of this._chunks.values()) {
6576
7233
  console.log("dispose chunk", chunk);
6577
- await (chunk == null ? void 0 : chunk.dispose());
7234
+ await chunk?.dispose();
6578
7235
  }
6579
7236
  this._chunks.clear();
6580
7237
  }
@@ -6592,14 +7249,14 @@ var MineRenderWorld = class {
6592
7249
  return this._chunks[index];
6593
7250
  }
6594
7251
  static worldToScenePosition(pos) {
6595
- return new Vector39(
7252
+ return new Vector310(
6596
7253
  pos.x * 16,
6597
7254
  pos.y * 16,
6598
7255
  pos.z * 16
6599
7256
  );
6600
7257
  }
6601
7258
  static sceneToWorldPosition(pos) {
6602
- return new Vector39(
7259
+ return new Vector310(
6603
7260
  pos.x / 16,
6604
7261
  pos.y / 16,
6605
7262
  pos.z / 16
@@ -6628,7 +7285,7 @@ var MineRenderWorld = class {
6628
7285
  };
6629
7286
 
6630
7287
  // src/world/Chunk.ts
6631
- var p12 = prefix("Chunk");
7288
+ var p11 = prefix("Chunk");
6632
7289
  var Chunk = class _Chunk {
6633
7290
  constructor(scene, x, y, z) {
6634
7291
  this._blocks = [];
@@ -6641,7 +7298,7 @@ var Chunk = class _Chunk {
6641
7298
  scene.add(anchor);
6642
7299
  anchor.position.set(this.x * 256 + 128 - 8, this.y * 256 + 128 - 8, this.z * 256 + 128 - 8);
6643
7300
  addBox3WireframeToObject(
6644
- new Box32(new Vector310(0, 0, 0), new Vector310(256, 256, 256)),
7301
+ new Box32(new Vector311(0, 0, 0), new Vector311(256, 256, 256)),
6645
7302
  anchor,
6646
7303
  16776960,
6647
7304
  4
@@ -6649,10 +7306,10 @@ var Chunk = class _Chunk {
6649
7306
  }
6650
7307
  getBlockAt(posOrX, y, z) {
6651
7308
  if (typeof posOrX == "number") {
6652
- return this.getBlockAt(new Vector310(posOrX, y, z));
7309
+ return this.getBlockAt(new Vector311(posOrX, y, z));
6653
7310
  }
6654
7311
  if (isTripleArray(posOrX)) {
6655
- return this.getBlockAt(new Vector310(posOrX[0], posOrX[1], posOrX[2]));
7312
+ return this.getBlockAt(new Vector311(posOrX[0], posOrX[1], posOrX[2]));
6656
7313
  }
6657
7314
  const pos = this.worldPosToChunkPos(posOrX);
6658
7315
  const index = _Chunk.chunkPosToBlockIndex(pos);
@@ -6660,10 +7317,10 @@ var Chunk = class _Chunk {
6660
7317
  }
6661
7318
  async setBlockAt(posOrX, yOrBlock, z, block) {
6662
7319
  if (typeof posOrX == "number") {
6663
- return this.setBlockAt(new Vector310(posOrX, yOrBlock, z), block);
7320
+ return this.setBlockAt(new Vector311(posOrX, yOrBlock, z), block);
6664
7321
  }
6665
7322
  if (isTripleArray(posOrX)) {
6666
- return this.setBlockAt(new Vector310(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
7323
+ return this.setBlockAt(new Vector311(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
6667
7324
  }
6668
7325
  const worldPos = posOrX;
6669
7326
  const pos = this.worldPosToChunkPos(worldPos);
@@ -6680,7 +7337,7 @@ var Chunk = class _Chunk {
6680
7337
  const index = _Chunk.chunkPosToBlockIndex(pos);
6681
7338
  const current = this._blocks[index];
6682
7339
  if (typeof current !== "undefined") {
6683
- console.debug(p12, "deleting existing block at", pos, worldPos, index);
7340
+ console.debug(p11, "deleting existing block at", pos, worldPos, index);
6684
7341
  current.object.removeFromScene();
6685
7342
  delete this._blocks[index];
6686
7343
  }
@@ -6709,7 +7366,7 @@ var Chunk = class _Chunk {
6709
7366
  }
6710
7367
  async clear() {
6711
7368
  let promises = [];
6712
- let pos = new Vector310();
7369
+ let pos = new Vector311();
6713
7370
  for (let x = 0; x < 16; x++) {
6714
7371
  for (let z = 0; z < 16; z++) {
6715
7372
  for (let y = 0; y < 16; y++) {
@@ -6728,14 +7385,14 @@ var Chunk = class _Chunk {
6728
7385
  return pos.y * 16 * 16 + pos.z * 16 + pos.x;
6729
7386
  }
6730
7387
  worldPosToChunkPos(pos) {
6731
- return new Vector310(
7388
+ return new Vector311(
6732
7389
  pos.x - this.x * 16,
6733
7390
  pos.y - this.y * 16,
6734
7391
  pos.z - this.z * 16
6735
7392
  );
6736
7393
  }
6737
7394
  chunkPosToWorldPos(pos) {
6738
- return new Vector310(
7395
+ return new Vector311(
6739
7396
  this.x * 16 + pos.x,
6740
7397
  this.y * 16 + pos.y,
6741
7398
  this.z * 16 + pos.z
@@ -6746,6 +7403,7 @@ export {
6746
7403
  AXES,
6747
7404
  ArchiveAssetSource,
6748
7405
  AssetKey,
7406
+ AssetLoadError,
6749
7407
  AssetLoader,
6750
7408
  AssetParser,
6751
7409
  AssetSource,
@@ -6755,9 +7413,9 @@ export {
6755
7413
  BUILTIN_GENERATED,
6756
7414
  BasicAssetKey,
6757
7415
  BatchedExecutor,
6758
- BlockEntityModels,
6759
7416
  BlockObject,
6760
7417
  BlockStates,
7418
+ BlockTints,
6761
7419
  BrowserArchiveProxy,
6762
7420
  CUBE_FACES,
6763
7421
  Caching,
@@ -6772,8 +7430,8 @@ export {
6772
7430
  DISPLAY_POSITIONS,
6773
7431
  DefaultBlockStates,
6774
7432
  DisplayPosition,
7433
+ DisplayTransforms,
6775
7434
  Entities,
6776
- EntityModels,
6777
7435
  EntityObject,
6778
7436
  Env,
6779
7437
  Geometries,
@@ -6803,6 +7461,7 @@ export {
6803
7461
  OrbitControls,
6804
7462
  PersistentCache,
6805
7463
  Renderer,
7464
+ RequestError,
6806
7465
  Requests,
6807
7466
  SKIN_PARTS,
6808
7467
  SceneInspector,
@@ -6810,8 +7469,10 @@ export {
6810
7469
  SceneStats,
6811
7470
  SceneStatsDisplay,
6812
7471
  SchematicParser,
7472
+ SkinImage,
6813
7473
  SkinObject,
6814
7474
  SkinPart,
7475
+ SkinTextures,
6815
7476
  Skins,
6816
7477
  StructureParser,
6817
7478
  TextureAtlas,
@@ -6826,10 +7487,10 @@ export {
6826
7487
  addWireframeToObject,
6827
7488
  applyElementRotation,
6828
7489
  applyGenericRotation,
6829
- applyModelPartRotation,
6830
7490
  axisToVec3,
6831
7491
  base64decode,
6832
7492
  base64encode,
7493
+ capeTextureSizes,
6833
7494
  captureException,
6834
7495
  changeEvent,
6835
7496
  clampRotationDegrees,