minerender 2.1.0-alpha.117 → 2.1.0-alpha.119

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.
@@ -87,6 +87,19 @@ var init_PersistentCache = __esm({
87
87
  }
88
88
  });
89
89
 
90
+ // src/util/log.ts
91
+ function prefix(prefix2) {
92
+ return `${FgGreen}MR${BgBlack}${prefix2 ?? ""}${Reset}`;
93
+ }
94
+ var Reset, FgGreen, BgBlack;
95
+ var init_log = __esm({
96
+ "src/util/log.ts"() {
97
+ Reset = "\x1B[0m";
98
+ FgGreen = "\x1B[32m";
99
+ BgBlack = "\x1B[40m";
100
+ }
101
+ });
102
+
90
103
  // src/Axis.ts
91
104
  function axisToVec3(axis) {
92
105
  switch (axis) {
@@ -377,19 +390,6 @@ var init_CanvasCompat = __esm({
377
390
  }
378
391
  });
379
392
 
380
- // src/util/log.ts
381
- function prefix(prefix2) {
382
- return `${FgGreen}MR${BgBlack}${prefix2 ?? ""}${Reset}`;
383
- }
384
- var Reset, FgGreen, BgBlack;
385
- var init_log = __esm({
386
- "src/util/log.ts"() {
387
- Reset = "\x1B[0m";
388
- FgGreen = "\x1B[32m";
389
- BgBlack = "\x1B[40m";
390
- }
391
- });
392
-
393
393
  // src/request/Requests.ts
394
394
  async function fetchRequest(config, defaultBaseURL) {
395
395
  const { url, baseURL = defaultBaseURL, timeout = 5e3, responseType = "json", signal, ...options } = config;
@@ -443,12 +443,12 @@ async function abortable(promise, signal) {
443
443
  signal.removeEventListener("abort", abort);
444
444
  }
445
445
  }
446
- var import_jobqu, p, RequestError, RequestQueue, Requests;
446
+ var import_jobqu, p2, RequestError, RequestQueue, Requests;
447
447
  var init_Requests = __esm({
448
448
  "src/request/Requests.ts"() {
449
449
  import_jobqu = require("jobqu");
450
450
  init_log();
451
- p = prefix("Requests");
451
+ p2 = prefix("Requests");
452
452
  RequestError = class extends Error {
453
453
  constructor(message, response, cause) {
454
454
  super(message);
@@ -475,7 +475,7 @@ var init_Requests = __esm({
475
475
  try {
476
476
  return await abortable(this.queue.add(request), signal);
477
477
  } catch (error) {
478
- console.debug(p, "Request failed", error);
478
+ console.debug(p2, "Request failed", error);
479
479
  const delay = this.retryDelay(error, request, retries);
480
480
  if (delay === void 0) {
481
481
  throw error;
@@ -639,7 +639,7 @@ var init_WrappedImage = __esm({
639
639
  });
640
640
 
641
641
  // src/image/ImageLoader.ts
642
- var import_buffer, p2, ImageLoader;
642
+ var import_buffer, p3, ImageLoader;
643
643
  var init_ImageLoader = __esm({
644
644
  "src/image/ImageLoader.ts"() {
645
645
  init_CanvasCompat();
@@ -650,7 +650,7 @@ var init_ImageLoader = __esm({
650
650
  init_WrappedImage();
651
651
  import_buffer = require("buffer");
652
652
  init_log();
653
- p2 = prefix("ImageLoader");
653
+ p3 = prefix("ImageLoader");
654
654
  ImageLoader = class _ImageLoader {
655
655
  static _createImage() {
656
656
  return createImage();
@@ -675,7 +675,7 @@ var init_ImageLoader = __esm({
675
675
  return image;
676
676
  }
677
677
  static async loadData(src) {
678
- console.debug(p2, "loadData", src);
678
+ console.debug(p3, "loadData", src);
679
679
  const image = await this.loadCanvasData(src);
680
680
  return image.data.getImageData(0, 0, image.width, image.height);
681
681
  }
@@ -1237,8 +1237,8 @@ var require_dist = __commonJS({
1237
1237
  __assign = Object.assign || function(t) {
1238
1238
  for (var s, i = 1, n = arguments.length; i < n; i++) {
1239
1239
  s = arguments[i];
1240
- for (var p10 in s) if (Object.prototype.hasOwnProperty.call(s, p10))
1241
- t[p10] = s[p10];
1240
+ for (var p11 in s) if (Object.prototype.hasOwnProperty.call(s, p11))
1241
+ t[p11] = s[p11];
1242
1242
  }
1243
1243
  return t;
1244
1244
  };
@@ -1419,12 +1419,12 @@ var init_AssetKey = __esm({
1419
1419
  }
1420
1420
  /** Joins the type subdirectory and path without adding a namespace or file extension. */
1421
1421
  getFullPath() {
1422
- let p10 = [];
1422
+ let p11 = [];
1423
1423
  if (this.type) {
1424
- p10.push(this.type);
1424
+ p11.push(this.type);
1425
1425
  }
1426
- p10.push(this.path);
1427
- return p10.join("/");
1426
+ p11.push(this.path);
1427
+ return p11.join("/");
1428
1428
  }
1429
1429
  toNamespacedString() {
1430
1430
  return this.namespace + ":" + this.getFullPath();
@@ -1530,7 +1530,7 @@ var init_ModelMerger = __esm({
1530
1530
  merged.display = { ...inheritedDisplay, ...DisplayTransforms.withHandFallbacks(source.display) };
1531
1531
  }
1532
1532
  }
1533
- merged.hierarchy = models.map((m) => m.parent).filter((p10) => `${p10}`);
1533
+ merged.hierarchy = models.map((m) => m.parent).filter((p11) => `${p11}`);
1534
1534
  merged.hierarchy.push(`${merged.parent}`);
1535
1535
  if (model.components) merged.components = model.components;
1536
1536
  return merged;
@@ -2723,7 +2723,7 @@ var init_parser = __esm({
2723
2723
  });
2724
2724
 
2725
2725
  // src/assets/source/HostedAssetSource.ts
2726
- var import_ts_deepmerge2, p3, DEFAULT_OPTIONS, _HostedAssetSource, HostedAssetSource;
2726
+ var import_ts_deepmerge2, p4, DEFAULT_OPTIONS, _HostedAssetSource, HostedAssetSource;
2727
2727
  var init_HostedAssetSource = __esm({
2728
2728
  "src/assets/source/HostedAssetSource.ts"() {
2729
2729
  init_AssetSource();
@@ -2736,7 +2736,7 @@ var init_HostedAssetSource = __esm({
2736
2736
  init_AssetLoader();
2737
2737
  init_parser();
2738
2738
  import_ts_deepmerge2 = __toESM(require_dist());
2739
- p3 = prefix("HostedAssetSource");
2739
+ p4 = prefix("HostedAssetSource");
2740
2740
  DEFAULT_OPTIONS = {
2741
2741
  retryDefaults: true
2742
2742
  };
@@ -2748,14 +2748,14 @@ var init_HostedAssetSource = __esm({
2748
2748
  return direct;
2749
2749
  }
2750
2750
  if (key.namespace !== DEFAULT_NAMESPACE) {
2751
- console.info(p3, "Retrying", key, "with default namespace");
2751
+ console.info(p4, "Retrying", key, "with default namespace");
2752
2752
  const namespaceKey = new AssetKey(DEFAULT_NAMESPACE, key.path, key.assetType, key.type, key.rootType, key.extension, key.root);
2753
2753
  const namespaced = await this.load(namespaceKey, parser);
2754
2754
  if (typeof namespaced !== "undefined") {
2755
2755
  return namespaced;
2756
2756
  }
2757
2757
  if (typeof key.root !== "undefined" && key.root !== AssetLoader.ROOT || typeof this.root !== "undefined" && this.root !== AssetLoader.ROOT) {
2758
- console.info(p3, "Retrying", key, "with default root+namespace");
2758
+ console.info(p4, "Retrying", key, "with default root+namespace");
2759
2759
  const namespacedRootedKey = new AssetKey(DEFAULT_NAMESPACE, key.path, key.assetType, key.type, key.rootType, key.extension, AssetLoader.ROOT);
2760
2760
  const namespacedRooted = await this.load(namespacedRootedKey, parser);
2761
2761
  if (typeof namespacedRooted !== "undefined") {
@@ -2763,7 +2763,7 @@ var init_HostedAssetSource = __esm({
2763
2763
  }
2764
2764
  }
2765
2765
  } else if (typeof key.root !== "undefined" && key.root !== AssetLoader.ROOT || typeof this.root !== "undefined" && this.root !== AssetLoader.ROOT) {
2766
- console.info(p3, "Retrying", key, "with default root");
2766
+ console.info(p4, "Retrying", key, "with default root");
2767
2767
  const rootKey = new AssetKey(key.namespace, key.path, key.assetType, key.type, key.rootType, key.extension, AssetLoader.ROOT);
2768
2768
  const rooted = await this.load(rootKey, parser);
2769
2769
  if (typeof rooted !== "undefined") {
@@ -2773,9 +2773,9 @@ var init_HostedAssetSource = __esm({
2773
2773
  return void 0;
2774
2774
  }
2775
2775
  async load(key, parser) {
2776
- console.info(p3, "Loading", key);
2776
+ console.info(p4, "Loading", key);
2777
2777
  const url = `${this.assetBasePath(key)}${key.type !== void 0 ? key.type + "/" : ""}${key.path}${key.extension}`;
2778
- console.debug(p3, url);
2778
+ console.debug(p4, url);
2779
2779
  const request = { url };
2780
2780
  try {
2781
2781
  parser.config(request);
@@ -3218,7 +3218,7 @@ var init_source = __esm({
3218
3218
  });
3219
3219
 
3220
3220
  // src/assets/AssetLoader.ts
3221
- var p4, _AssetLoader, AssetLoader;
3221
+ var p5, _AssetLoader, AssetLoader;
3222
3222
  var init_AssetLoader = __esm({
3223
3223
  "src/assets/AssetLoader.ts"() {
3224
3224
  init_Assets();
@@ -3226,7 +3226,7 @@ var init_AssetLoader = __esm({
3226
3226
  init_log();
3227
3227
  init_source();
3228
3228
  init_Caching();
3229
- p4 = prefix("AssetLoader");
3229
+ p5 = prefix("AssetLoader");
3230
3230
  _AssetLoader = class _AssetLoader {
3231
3231
  static get version() {
3232
3232
  return this.ROOT.substring(this.ROOT.lastIndexOf("/") + 1);
@@ -3275,11 +3275,11 @@ ${key}` : key;
3275
3275
  if (override) {
3276
3276
  const existing = this.removeSource(key);
3277
3277
  if (existing) {
3278
- console.log(p4, "Removed existing AssetSource", key);
3278
+ console.log(p5, "Removed existing AssetSource", key);
3279
3279
  }
3280
3280
  }
3281
3281
  this._SOURCES.unshift({ key, source });
3282
- console.log(p4, "Added AssetSource", key);
3282
+ console.log(p5, "Added AssetSource", key);
3283
3283
  }
3284
3284
  /** Removes and returns the first source with this name. Call {@link Caching.clear} to reload assets. */
3285
3285
  static removeSource(key) {
@@ -3670,7 +3670,7 @@ var init_ModelGenerator = __esm({
3670
3670
  });
3671
3671
 
3672
3672
  // src/UVMapper.ts
3673
- var import_three9, p5, DEFAULT_UV, X, Y, Z, FACE_UV_AXES, UVMapper, MinecraftFaceUV;
3673
+ var import_three9, p6, DEFAULT_UV, X, Y, Z, FACE_UV_AXES, UVMapper, MinecraftFaceUV;
3674
3674
  var init_UVMapper = __esm({
3675
3675
  "src/UVMapper.ts"() {
3676
3676
  import_three9 = require("three");
@@ -3684,7 +3684,7 @@ var init_UVMapper = __esm({
3684
3684
  init_AssetKey();
3685
3685
  init_ModelGenerator();
3686
3686
  init_log();
3687
- p5 = prefix("UVMapper");
3687
+ p6 = prefix("UVMapper");
3688
3688
  DEFAULT_UV = [0, 0, 16, 16];
3689
3689
  X = 0;
3690
3690
  Y = 1;
@@ -3945,7 +3945,7 @@ var init_UVMapper = __esm({
3945
3945
  model.elements = originalModel.elements.map((element) => ({ ...element }));
3946
3946
  }
3947
3947
  const isItemModel = !("elements" in model);
3948
- console.debug(p5, "Creating Atlas for", model.key);
3948
+ console.debug(p6, "Creating Atlas for", model.key);
3949
3949
  if (model.textures) {
3950
3950
  const promises = [];
3951
3951
  const uniqueTextureNames = [];
@@ -3959,7 +3959,7 @@ var init_UVMapper = __esm({
3959
3959
  const assetKey = AssetKey.parse("textures", textureValue, model.key);
3960
3960
  promises.push(ModelTextures.get(assetKey).then((asset2) => {
3961
3961
  if (!asset2) {
3962
- console.warn(p5, "Missing texture", assetKey);
3962
+ console.warn(p6, "Missing texture", assetKey);
3963
3963
  return;
3964
3964
  }
3965
3965
  textureMap[textureKey] = new WrappedImage(asset2);
@@ -3971,7 +3971,7 @@ var init_UVMapper = __esm({
3971
3971
  }
3972
3972
  await Promise.all(promises);
3973
3973
  const textureCount = uniqueTextureNames.length;
3974
- console.debug(p5, "Creating Atlas for", textureCount, "textures");
3974
+ console.debug(p6, "Creating Atlas for", textureCount, "textures");
3975
3975
  this.fillMissingTextureKeys(model.textures, textureMap);
3976
3976
  this.fillMissingTextureKeys(model.textures, metaMap);
3977
3977
  const sizes = {};
@@ -4002,7 +4002,7 @@ var init_UVMapper = __esm({
4002
4002
  this.fillMissingTextureKeys(model.textures, sizes);
4003
4003
  const s = Math.ceil(Math.sqrt(textureCount + 1));
4004
4004
  const size = Math.ceil(s * maxWidth);
4005
- console.debug(p5, "Atlas size:", size);
4005
+ console.debug(p6, "Atlas size:", size);
4006
4006
  const squaredSize = size * size;
4007
4007
  const image = new CanvasImage(size, size);
4008
4008
  const missing = Textures.getMissing().image;
@@ -4081,7 +4081,7 @@ var init_UVMapper = __esm({
4081
4081
  }
4082
4082
  this.fillMissingTextureKeys(model.textures, positions);
4083
4083
  if (isItemModel) {
4084
- console.debug(p5, "Generating item model for", model);
4084
+ console.debug(p6, "Generating item model for", model);
4085
4085
  model.elements = [];
4086
4086
  for (let layerName of ModelGenerator.ITEM_LAYERS) {
4087
4087
  const textureImage = textureMap[layerName];
@@ -4097,7 +4097,7 @@ var init_UVMapper = __esm({
4097
4097
  ), layerName));
4098
4098
  }
4099
4099
  }
4100
- console.debug(p5, "Item model elements", model.elements);
4100
+ console.debug(p6, "Item model elements", model.elements);
4101
4101
  }
4102
4102
  if (!model.elements) {
4103
4103
  }
@@ -4154,7 +4154,7 @@ var init_UVMapper = __esm({
4154
4154
  hasTranslucency
4155
4155
  );
4156
4156
  } else {
4157
- console.warn(p5, "Model does not have any textures", model);
4157
+ console.warn(p6, "Model does not have any textures", model);
4158
4158
  }
4159
4159
  return void 0;
4160
4160
  }
@@ -4673,7 +4673,7 @@ var init_InstanceReference = __esm({
4673
4673
  function isSceneObject(obj) {
4674
4674
  return obj.isSceneObject;
4675
4675
  }
4676
- var import_three12, import_ts_deepmerge3, p6, _SceneObject, SceneObject;
4676
+ var import_three12, import_ts_deepmerge3, p7, _SceneObject, SceneObject;
4677
4677
  var init_SceneObject = __esm({
4678
4678
  "src/renderer/SceneObject.ts"() {
4679
4679
  import_three12 = require("three");
@@ -4687,7 +4687,7 @@ var init_SceneObject = __esm({
4687
4687
  init_Disposable();
4688
4688
  import_ts_deepmerge3 = __toESM(require_dist());
4689
4689
  init_log();
4690
- p6 = prefix("SceneObject");
4690
+ p7 = prefix("SceneObject");
4691
4691
  _SceneObject = class _SceneObject extends import_three12.Object3D {
4692
4692
  constructor(options) {
4693
4693
  super();
@@ -6934,7 +6934,7 @@ var init_ItemGlint = __esm({
6934
6934
  function isModelObject(obj) {
6935
6935
  return obj.isModelObject;
6936
6936
  }
6937
- var import_three27, import_ts_deepmerge5, p7, _ModelObject, ModelObject;
6937
+ var import_three27, import_ts_deepmerge5, p8, _ModelObject, ModelObject;
6938
6938
  var init_ModelObject = __esm({
6939
6939
  "src/model/scene/ModelObject.ts"() {
6940
6940
  init_SceneObject();
@@ -6954,7 +6954,7 @@ var init_ModelObject = __esm({
6954
6954
  init_GuiLight();
6955
6955
  init_ItemTints();
6956
6956
  init_ItemGlint();
6957
- p7 = prefix("ModelObject");
6957
+ p8 = prefix("ModelObject");
6958
6958
  _ModelObject = class _ModelObject extends SceneObject {
6959
6959
  constructor(originalModel, options) {
6960
6960
  super(options);
@@ -7127,10 +7127,10 @@ var init_ModelObject = __esm({
7127
7127
  }
7128
7128
  });
7129
7129
  } else {
7130
- console.debug(p7, this.atlas.model, "has no elements");
7130
+ console.debug(p8, this.atlas.model, "has no elements");
7131
7131
  }
7132
7132
  } else {
7133
- console.debug(p7, "Missing atlas for", this);
7133
+ console.debug(p8, "Missing atlas for", this);
7134
7134
  }
7135
7135
  if (this.options.mergeMeshes) {
7136
7136
  let combinedGeo;
@@ -7571,6 +7571,7 @@ __export(index_browser_exports, {
7571
7571
  Renderer: () => Renderer,
7572
7572
  RequestError: () => RequestError,
7573
7573
  Requests: () => Requests,
7574
+ SCENE_DOCUMENT_MAX_BYTES: () => SCENE_DOCUMENT_MAX_BYTES,
7574
7575
  SKIN_PARTS: () => SKIN_PARTS,
7575
7576
  SceneDocumentLoader: () => SceneDocumentLoader,
7576
7577
  SceneExporter: () => SceneExporter,
@@ -7622,6 +7623,8 @@ __export(index_browser_exports, {
7622
7623
  createGuiTextGeometry: () => createGuiTextGeometry,
7623
7624
  createGuiTextureGeometry: () => createGuiTextureGeometry,
7624
7625
  createImage: () => createImage,
7626
+ decodeSceneDocument: () => decodeSceneDocument,
7627
+ encodeSceneDocument: () => encodeSceneDocument,
7625
7628
  entityAnimationTime: () => entityAnimationTime,
7626
7629
  estimateBytesUsed: () => estimateBytesUsed,
7627
7630
  fluidKindOf: () => fluidKindOf,
@@ -7696,32 +7699,53 @@ init_Env();
7696
7699
 
7697
7700
  // src/env/browser/BrowserCache.ts
7698
7701
  init_PersistentCache();
7702
+ init_log();
7703
+ var p = prefix("BrowserCache");
7699
7704
  var BrowserCache = class extends PersistentCache {
7700
7705
  constructor(backing) {
7701
7706
  super(backing);
7702
7707
  }
7708
+ async initialize() {
7709
+ try {
7710
+ await this.backing.ready();
7711
+ return true;
7712
+ } catch (error) {
7713
+ this.memory = /* @__PURE__ */ new Map();
7714
+ console.warn(p, "Could not open browser storage; using an in-memory store", error);
7715
+ return false;
7716
+ }
7717
+ }
7718
+ async run(operation, fallback) {
7719
+ if (await (this.initialized ?? (this.initialized = this.initialize()))) return operation();
7720
+ return fallback(this.memory);
7721
+ }
7703
7722
  get(key) {
7704
- return this.backing.getItem(key);
7723
+ return this.run(() => this.backing.getItem(key), (memory) => memory.get(key));
7705
7724
  }
7706
7725
  put(key, value) {
7707
- return this.backing.setItem(key, value);
7726
+ return this.run(() => this.backing.setItem(key, value), (memory) => {
7727
+ memory.set(key, value);
7728
+ return value;
7729
+ });
7708
7730
  }
7709
7731
  delete(key) {
7710
- return this.backing.removeItem(key);
7732
+ return this.run(() => this.backing.removeItem(key), (memory) => {
7733
+ memory.delete(key);
7734
+ });
7711
7735
  }
7712
7736
  clear() {
7713
- return this.backing.clear();
7737
+ return this.run(() => this.backing.clear(), (memory) => memory.clear());
7714
7738
  }
7715
7739
  length() {
7716
- return this.backing.length();
7740
+ return this.run(() => this.backing.length(), (memory) => memory.size);
7717
7741
  }
7718
7742
  keys() {
7719
- return this.backing.keys();
7743
+ return this.run(() => this.backing.keys(), (memory) => [...memory.keys()]);
7720
7744
  }
7721
7745
  forEach(callback) {
7722
- return this.backing.iterate((v, k) => {
7723
- callback(v, k);
7724
- });
7746
+ return this.run(() => this.backing.iterate((value, key) => {
7747
+ callback(value, key);
7748
+ }), (memory) => memory.forEach((value, key) => callback(value, key)));
7725
7749
  }
7726
7750
  };
7727
7751
 
@@ -7929,7 +7953,7 @@ function createPermutation() {
7929
7953
  return values;
7930
7954
  }
7931
7955
  function swampGrassColor(x, z) {
7932
- const p10 = permutation ?? (permutation = createPermutation());
7956
+ const p11 = permutation ?? (permutation = createPermutation());
7933
7957
  x *= 0.0225;
7934
7958
  z *= 0.0225;
7935
7959
  const s = (x + z) * skew;
@@ -7940,7 +7964,7 @@ function swampGrassColor(x, z) {
7940
7964
  const corner = (gx, gz, a, b) => {
7941
7965
  let falloff = 0.5 - a * a - b * b;
7942
7966
  if (falloff < 0) return 0;
7943
- const gradient = gradients[p10[gx + p10[gz & 255] & 255] % 12];
7967
+ const gradient = gradients[p11[gx + p11[gz & 255] & 255] % 12];
7944
7968
  falloff *= falloff;
7945
7969
  return falloff * falloff * (gradient[0] * a + gradient[1] * b);
7946
7970
  };
@@ -11903,7 +11927,7 @@ init_SceneObject();
11903
11927
  init_util();
11904
11928
  init_log();
11905
11929
  init_three();
11906
- var p8 = prefix("SceneInspector");
11930
+ var p9 = prefix("SceneInspector");
11907
11931
  var help = "<span>Ctrl/Cmd+Click to Select<br/></span><br/>";
11908
11932
  var SceneInspector = class {
11909
11933
  constructor(renderer) {
@@ -11997,7 +12021,7 @@ var SceneInspector = class {
11997
12021
  }
11998
12022
  selectObject(targetObject, targetIntersection, instance = this.getIntersectionInstance(targetIntersection)) {
11999
12023
  this.selectedObject = targetObject;
12000
- console.log(p8, "selected", targetObject);
12024
+ console.log(p9, "selected", targetObject);
12001
12025
  this.redraw(targetObject, targetIntersection, instance);
12002
12026
  }
12003
12027
  redraw(targetObject, targetIntersection, instance) {
@@ -12257,7 +12281,7 @@ var SceneStatsDisplay = class {
12257
12281
 
12258
12282
  // src/instance/InstanceManager.ts
12259
12283
  init_log();
12260
- var p9 = prefix("InstanceManager");
12284
+ var p10 = prefix("InstanceManager");
12261
12285
  var InstanceManager = class {
12262
12286
  constructor() {
12263
12287
  this.isInstanceManager = true;
@@ -12266,7 +12290,7 @@ var InstanceManager = class {
12266
12290
  /** Allocates a new placement of a cached model, or returns `undefined` if the key is unknown. */
12267
12291
  async get(key) {
12268
12292
  if (key in this.instanceCache) {
12269
- console.debug(p9, "key in cache", key);
12293
+ console.debug(p10, "key in cache", key);
12270
12294
  return (await this.instanceCache[key]).nextInstance();
12271
12295
  }
12272
12296
  return void 0;
@@ -12276,7 +12300,7 @@ var InstanceManager = class {
12276
12300
  if (key in this.instanceCache) {
12277
12301
  return await this.get(key);
12278
12302
  }
12279
- console.debug(p9, "key not in cache", key);
12303
+ console.debug(p10, "key not in cache", key);
12280
12304
  const pending = Promise.resolve().then(supplier).then((obj) => obj.nextInstance());
12281
12305
  this.instanceCache[key] = pending;
12282
12306
  try {
@@ -13387,6 +13411,8 @@ var import_three35 = require("three");
13387
13411
  var VANILLA_FLY_SPEED = 10.89;
13388
13412
  var PITCH_LIMIT = Math.PI / 2;
13389
13413
  var MOVE_EPSILON = 1e-6;
13414
+ var MAX_STEP_SECONDS = 0.1;
13415
+ var CLICK_SLOP_PIXELS = 4;
13390
13416
  var _euler = new import_three35.Euler(0, 0, 0, "YXZ");
13391
13417
  var _forward = new import_three35.Vector3();
13392
13418
  var _right = new import_three35.Vector3();
@@ -13421,7 +13447,8 @@ var FlyControls = class extends import_three35.Controls {
13421
13447
  right: ["KeyD", "ArrowRight"],
13422
13448
  up: ["Space"],
13423
13449
  down: ["ShiftLeft", "ShiftRight"],
13424
- sprint: ["ControlLeft", "ControlRight"]
13450
+ // Not Control: Ctrl+W closes the browser tab on Windows and Linux, and a page cannot block it.
13451
+ sprint: ["KeyR"]
13425
13452
  };
13426
13453
  this._pressed = /* @__PURE__ */ new Set();
13427
13454
  this._velocity = new import_three35.Vector3();
@@ -13429,8 +13456,12 @@ var FlyControls = class extends import_three35.Controls {
13429
13456
  this._lastQuaternion = new import_three35.Quaternion();
13430
13457
  this._position0 = new import_three35.Vector3();
13431
13458
  this._quaternion0 = new import_three35.Quaternion();
13459
+ this._dragX = 0;
13460
+ this._dragY = 0;
13432
13461
  this._dragMoved = false;
13462
+ this._dragTravel = 0;
13433
13463
  this._locked = false;
13464
+ this._madeFocusable = false;
13434
13465
  this._onKeyDown = (event) => this.handleKey(event, true);
13435
13466
  this._onKeyUp = (event) => this.handleKey(event, false);
13436
13467
  this._onPointerDown = (event) => this.handlePointerDown(event);
@@ -13460,7 +13491,10 @@ var FlyControls = class extends import_three35.Controls {
13460
13491
  element.addEventListener("wheel", this._onWheel, { passive: false });
13461
13492
  element.addEventListener("blur", this._onBlur);
13462
13493
  element.style.touchAction = "none";
13463
- if (element.tabIndex < 0) element.tabIndex = 0;
13494
+ if (element.tabIndex < 0) {
13495
+ element.tabIndex = 0;
13496
+ this._madeFocusable = true;
13497
+ }
13464
13498
  }
13465
13499
  disconnect() {
13466
13500
  const element = this.domElement;
@@ -13478,6 +13512,10 @@ var FlyControls = class extends import_three35.Controls {
13478
13512
  element.removeEventListener("wheel", this._onWheel);
13479
13513
  element.removeEventListener("blur", this._onBlur);
13480
13514
  element.style.touchAction = "auto";
13515
+ if (this._madeFocusable) {
13516
+ element.removeAttribute("tabindex");
13517
+ this._madeFocusable = false;
13518
+ }
13481
13519
  this.unlock();
13482
13520
  this._locked = false;
13483
13521
  this.releaseKeys();
@@ -13548,6 +13586,7 @@ var FlyControls = class extends import_three35.Controls {
13548
13586
  /**
13549
13587
  * Advances movement by `delta` seconds (measured since the previous call when omitted)
13550
13588
  * and dispatches `change` when the camera moved.
13589
+ * A step longer than 0.1 s is applied as 0.1 s.
13551
13590
  */
13552
13591
  update(delta) {
13553
13592
  if (delta === void 0) {
@@ -13559,7 +13598,7 @@ var FlyControls = class extends import_three35.Controls {
13559
13598
  this._velocity.set(0, 0, 0);
13560
13599
  return;
13561
13600
  }
13562
- if (delta > 0) this.move(delta);
13601
+ if (delta > 0) this.move(Math.min(delta, MAX_STEP_SECONDS));
13563
13602
  this.notifyChange();
13564
13603
  }
13565
13604
  move(delta) {
@@ -13606,15 +13645,21 @@ var FlyControls = class extends import_three35.Controls {
13606
13645
  this._pressed.clear();
13607
13646
  }
13608
13647
  handleKey(event, down) {
13648
+ if (event.code === "MetaLeft" || event.code === "MetaRight") this.releaseKeys();
13609
13649
  const action = this.actionFor(event.code);
13610
13650
  if (!action) return;
13611
13651
  const ownsInput = this.enabled && (this._locked || event.target === this.domElement);
13612
- if (down && !ownsInput) return;
13652
+ if (down && (!ownsInput || this.isBrowserShortcut(event))) return;
13613
13653
  const pressed = this._pressed.has(action);
13614
13654
  if (down) this._pressed.add(action);
13615
13655
  else this._pressed.delete(action);
13616
13656
  if (ownsInput || this.enabled && pressed) event.preventDefault();
13617
13657
  }
13658
+ /** A key pressed with Control, Alt, or Command stays a browser shortcut unless that modifier is bound to an action. */
13659
+ isBrowserShortcut(event) {
13660
+ const bound = (modifier) => Object.values(this.keys).some((codes) => codes.some((code) => code.startsWith(modifier)));
13661
+ return event.ctrlKey && !bound("Control") || event.altKey && !bound("Alt") || event.metaKey && !bound("Meta");
13662
+ }
13618
13663
  actionFor(code) {
13619
13664
  for (const action in this.keys) {
13620
13665
  if (this.keys[action].includes(code)) return action;
@@ -13634,7 +13679,10 @@ var FlyControls = class extends import_three35.Controls {
13634
13679
  if (this._dragPointer !== void 0) return;
13635
13680
  if (event.pointerType === "mouse" && event.button !== 0 && event.button !== 2) return;
13636
13681
  this._dragPointer = event.pointerId;
13682
+ this._dragX = event.clientX;
13683
+ this._dragY = event.clientY;
13637
13684
  this._dragMoved = false;
13685
+ this._dragTravel = 0;
13638
13686
  element.setPointerCapture?.(event.pointerId);
13639
13687
  }
13640
13688
  onJoystickSide(event) {
@@ -13650,8 +13698,20 @@ var FlyControls = class extends import_three35.Controls {
13650
13698
  return;
13651
13699
  }
13652
13700
  if (!this._locked && event.pointerId !== this._dragPointer) return;
13653
- const dx = event.movementX ?? 0;
13654
- const dy = event.movementY ?? 0;
13701
+ let dx, dy;
13702
+ if (this._locked) {
13703
+ dx = event.movementX ?? 0;
13704
+ dy = event.movementY ?? 0;
13705
+ } else {
13706
+ dx = event.clientX - this._dragX;
13707
+ dy = event.clientY - this._dragY;
13708
+ this._dragX = event.clientX;
13709
+ this._dragY = event.clientY;
13710
+ if (!this._dragMoved) {
13711
+ this._dragTravel += Math.hypot(dx, dy);
13712
+ if (this._dragTravel <= CLICK_SLOP_PIXELS) return;
13713
+ }
13714
+ }
13655
13715
  if (!dx && !dy) return;
13656
13716
  this._dragMoved = true;
13657
13717
  this.turn(dx, dy);
@@ -15561,6 +15621,7 @@ var _Renderer = class _Renderer {
15561
15621
  /**
15562
15622
  * Replaces renderer-owned controls with the selected mode, keeping the camera where it is.
15563
15623
  * Switching to orbit controls targets the point the camera looks at, at the previous orbit distance.
15624
+ * The previous controls object is disposed, so its listeners and settings do not carry over.
15564
15625
  * Returns the new controls, or undefined when controls were disabled at construction or after disposal.
15565
15626
  */
15566
15627
  setControlsMode(mode) {
@@ -16226,6 +16287,79 @@ function parseSceneDocument(value) {
16226
16287
  return JSON.parse(JSON.stringify(input));
16227
16288
  }
16228
16289
 
16290
+ // src/scene/SceneDocumentCodec.ts
16291
+ var SCENE_DOCUMENT_MAX_BYTES = 1024 * 1024;
16292
+ async function readBounded(stream, label) {
16293
+ const reader = stream.getReader();
16294
+ const chunks = [];
16295
+ let size = 0;
16296
+ try {
16297
+ while (true) {
16298
+ const { value, done } = await reader.read();
16299
+ if (done) break;
16300
+ size += value.byteLength;
16301
+ if (size > SCENE_DOCUMENT_MAX_BYTES) throw new RangeError(`${label} exceeds ${SCENE_DOCUMENT_MAX_BYTES} bytes`);
16302
+ chunks.push(value);
16303
+ }
16304
+ } catch (error) {
16305
+ await reader.cancel().catch(() => {
16306
+ });
16307
+ throw error;
16308
+ } finally {
16309
+ reader.releaseLock();
16310
+ }
16311
+ const bytes = new Uint8Array(size);
16312
+ let offset = 0;
16313
+ for (const chunk of chunks) {
16314
+ bytes.set(chunk, offset);
16315
+ offset += chunk.byteLength;
16316
+ }
16317
+ return bytes;
16318
+ }
16319
+ function encodeBase64(bytes) {
16320
+ let binary = "";
16321
+ for (let offset = 0; offset < bytes.length; offset += 32768) {
16322
+ binary += String.fromCharCode(...bytes.subarray(offset, offset + 32768));
16323
+ }
16324
+ return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
16325
+ }
16326
+ async function encodeSceneDocument(value) {
16327
+ const scene = parseSceneDocument(value);
16328
+ const bytes = new TextEncoder().encode(JSON.stringify(scene));
16329
+ if (bytes.byteLength > SCENE_DOCUMENT_MAX_BYTES) {
16330
+ throw new RangeError(`Scene document exceeds ${SCENE_DOCUMENT_MAX_BYTES} bytes`);
16331
+ }
16332
+ const compressed = await readBounded(new Blob([bytes]).stream().pipeThrough(new CompressionStream("deflate")), "Encoded scene");
16333
+ return `v1.${encodeBase64(compressed)}`;
16334
+ }
16335
+ async function decodeSceneDocument(value) {
16336
+ if (!value.startsWith("v1.")) throw new Error("Unsupported scene encoding version; expected v1");
16337
+ const encoded = value.slice(3);
16338
+ if (encoded.length > Math.ceil(SCENE_DOCUMENT_MAX_BYTES * 4 / 3)) {
16339
+ throw new RangeError(`Encoded scene exceeds ${SCENE_DOCUMENT_MAX_BYTES} bytes`);
16340
+ }
16341
+ if (!/^[A-Za-z0-9_-]+$/.test(encoded) || encoded.length % 4 === 1) {
16342
+ throw new Error("Invalid scene base64url encoding");
16343
+ }
16344
+ const binary = atob(encoded.replace(/-/g, "+").replace(/_/g, "/"));
16345
+ const compressed = Uint8Array.from(binary, (character) => character.charCodeAt(0));
16346
+ if (encodeBase64(compressed) !== encoded) throw new Error("Invalid scene base64url encoding");
16347
+ let bytes;
16348
+ try {
16349
+ bytes = await readBounded(new Blob([compressed]).stream().pipeThrough(new DecompressionStream("deflate")), "Scene document");
16350
+ } catch (error) {
16351
+ if (error instanceof RangeError) throw error;
16352
+ throw new Error("Invalid compressed scene document");
16353
+ }
16354
+ let json;
16355
+ try {
16356
+ json = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
16357
+ } catch {
16358
+ throw new Error("Invalid UTF-8 scene document");
16359
+ }
16360
+ return parseSceneDocument(json);
16361
+ }
16362
+
16229
16363
  // src/scene/SceneDocumentLoader.ts
16230
16364
  var import_three40 = require("three");
16231
16365
  init_AssetKey();