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.
@@ -86,6 +86,19 @@ var init_PersistentCache = __esm({
86
86
  }
87
87
  });
88
88
 
89
+ // src/util/log.ts
90
+ function prefix(prefix2) {
91
+ return `${FgGreen}MR${BgBlack}${prefix2 ?? ""}${Reset}`;
92
+ }
93
+ var Reset, FgGreen, BgBlack;
94
+ var init_log = __esm({
95
+ "src/util/log.ts"() {
96
+ Reset = "\x1B[0m";
97
+ FgGreen = "\x1B[32m";
98
+ BgBlack = "\x1B[40m";
99
+ }
100
+ });
101
+
89
102
  // src/Axis.ts
90
103
  import { Vector3 } from "three";
91
104
  function axisToVec3(axis) {
@@ -376,19 +389,6 @@ var init_CanvasCompat = __esm({
376
389
  }
377
390
  });
378
391
 
379
- // src/util/log.ts
380
- function prefix(prefix2) {
381
- return `${FgGreen}MR${BgBlack}${prefix2 ?? ""}${Reset}`;
382
- }
383
- var Reset, FgGreen, BgBlack;
384
- var init_log = __esm({
385
- "src/util/log.ts"() {
386
- Reset = "\x1B[0m";
387
- FgGreen = "\x1B[32m";
388
- BgBlack = "\x1B[40m";
389
- }
390
- });
391
-
392
392
  // src/request/Requests.ts
393
393
  import { JobCancelledError, JobQueue } from "jobqu";
394
394
  async function fetchRequest(config, defaultBaseURL) {
@@ -443,11 +443,11 @@ async function abortable(promise, signal) {
443
443
  signal.removeEventListener("abort", abort);
444
444
  }
445
445
  }
446
- var p, RequestError, RequestQueue, Requests;
446
+ var p2, RequestError, RequestQueue, Requests;
447
447
  var init_Requests = __esm({
448
448
  "src/request/Requests.ts"() {
449
449
  init_log();
450
- p = prefix("Requests");
450
+ p2 = prefix("Requests");
451
451
  RequestError = class extends Error {
452
452
  constructor(message, response, cause) {
453
453
  super(message);
@@ -474,7 +474,7 @@ var init_Requests = __esm({
474
474
  try {
475
475
  return await abortable(this.queue.add(request), signal);
476
476
  } catch (error) {
477
- console.debug(p, "Request failed", error);
477
+ console.debug(p2, "Request failed", error);
478
478
  const delay = this.retryDelay(error, request, retries);
479
479
  if (delay === void 0) {
480
480
  throw error;
@@ -639,7 +639,7 @@ var init_WrappedImage = __esm({
639
639
 
640
640
  // src/image/ImageLoader.ts
641
641
  import { Buffer as Buffer2 } from "buffer";
642
- var p2, ImageLoader;
642
+ var p3, ImageLoader;
643
643
  var init_ImageLoader = __esm({
644
644
  "src/image/ImageLoader.ts"() {
645
645
  init_CanvasCompat();
@@ -649,7 +649,7 @@ var init_ImageLoader = __esm({
649
649
  init_Requests();
650
650
  init_WrappedImage();
651
651
  init_log();
652
- p2 = prefix("ImageLoader");
652
+ p3 = prefix("ImageLoader");
653
653
  ImageLoader = class _ImageLoader {
654
654
  static _createImage() {
655
655
  return createImage();
@@ -674,7 +674,7 @@ var init_ImageLoader = __esm({
674
674
  return image;
675
675
  }
676
676
  static async loadData(src) {
677
- console.debug(p2, "loadData", src);
677
+ console.debug(p3, "loadData", src);
678
678
  const image = await this.loadCanvasData(src);
679
679
  return image.data.getImageData(0, 0, image.width, image.height);
680
680
  }
@@ -1236,8 +1236,8 @@ var require_dist = __commonJS({
1236
1236
  __assign = Object.assign || function(t) {
1237
1237
  for (var s, i = 1, n = arguments.length; i < n; i++) {
1238
1238
  s = arguments[i];
1239
- for (var p10 in s) if (Object.prototype.hasOwnProperty.call(s, p10))
1240
- t[p10] = s[p10];
1239
+ for (var p11 in s) if (Object.prototype.hasOwnProperty.call(s, p11))
1240
+ t[p11] = s[p11];
1241
1241
  }
1242
1242
  return t;
1243
1243
  };
@@ -1418,12 +1418,12 @@ var init_AssetKey = __esm({
1418
1418
  }
1419
1419
  /** Joins the type subdirectory and path without adding a namespace or file extension. */
1420
1420
  getFullPath() {
1421
- let p10 = [];
1421
+ let p11 = [];
1422
1422
  if (this.type) {
1423
- p10.push(this.type);
1423
+ p11.push(this.type);
1424
1424
  }
1425
- p10.push(this.path);
1426
- return p10.join("/");
1425
+ p11.push(this.path);
1426
+ return p11.join("/");
1427
1427
  }
1428
1428
  toNamespacedString() {
1429
1429
  return this.namespace + ":" + this.getFullPath();
@@ -1529,7 +1529,7 @@ var init_ModelMerger = __esm({
1529
1529
  merged.display = { ...inheritedDisplay, ...DisplayTransforms.withHandFallbacks(source.display) };
1530
1530
  }
1531
1531
  }
1532
- merged.hierarchy = models.map((m) => m.parent).filter((p10) => `${p10}`);
1532
+ merged.hierarchy = models.map((m) => m.parent).filter((p11) => `${p11}`);
1533
1533
  merged.hierarchy.push(`${merged.parent}`);
1534
1534
  if (model.components) merged.components = model.components;
1535
1535
  return merged;
@@ -2721,7 +2721,7 @@ var init_parser = __esm({
2721
2721
  });
2722
2722
 
2723
2723
  // src/assets/source/HostedAssetSource.ts
2724
- var import_ts_deepmerge2, p3, DEFAULT_OPTIONS, _HostedAssetSource, HostedAssetSource;
2724
+ var import_ts_deepmerge2, p4, DEFAULT_OPTIONS, _HostedAssetSource, HostedAssetSource;
2725
2725
  var init_HostedAssetSource = __esm({
2726
2726
  "src/assets/source/HostedAssetSource.ts"() {
2727
2727
  init_AssetSource();
@@ -2734,7 +2734,7 @@ var init_HostedAssetSource = __esm({
2734
2734
  init_AssetLoader();
2735
2735
  init_parser();
2736
2736
  import_ts_deepmerge2 = __toESM(require_dist());
2737
- p3 = prefix("HostedAssetSource");
2737
+ p4 = prefix("HostedAssetSource");
2738
2738
  DEFAULT_OPTIONS = {
2739
2739
  retryDefaults: true
2740
2740
  };
@@ -2746,14 +2746,14 @@ var init_HostedAssetSource = __esm({
2746
2746
  return direct;
2747
2747
  }
2748
2748
  if (key.namespace !== DEFAULT_NAMESPACE) {
2749
- console.info(p3, "Retrying", key, "with default namespace");
2749
+ console.info(p4, "Retrying", key, "with default namespace");
2750
2750
  const namespaceKey = new AssetKey(DEFAULT_NAMESPACE, key.path, key.assetType, key.type, key.rootType, key.extension, key.root);
2751
2751
  const namespaced = await this.load(namespaceKey, parser);
2752
2752
  if (typeof namespaced !== "undefined") {
2753
2753
  return namespaced;
2754
2754
  }
2755
2755
  if (typeof key.root !== "undefined" && key.root !== AssetLoader.ROOT || typeof this.root !== "undefined" && this.root !== AssetLoader.ROOT) {
2756
- console.info(p3, "Retrying", key, "with default root+namespace");
2756
+ console.info(p4, "Retrying", key, "with default root+namespace");
2757
2757
  const namespacedRootedKey = new AssetKey(DEFAULT_NAMESPACE, key.path, key.assetType, key.type, key.rootType, key.extension, AssetLoader.ROOT);
2758
2758
  const namespacedRooted = await this.load(namespacedRootedKey, parser);
2759
2759
  if (typeof namespacedRooted !== "undefined") {
@@ -2761,7 +2761,7 @@ var init_HostedAssetSource = __esm({
2761
2761
  }
2762
2762
  }
2763
2763
  } else if (typeof key.root !== "undefined" && key.root !== AssetLoader.ROOT || typeof this.root !== "undefined" && this.root !== AssetLoader.ROOT) {
2764
- console.info(p3, "Retrying", key, "with default root");
2764
+ console.info(p4, "Retrying", key, "with default root");
2765
2765
  const rootKey = new AssetKey(key.namespace, key.path, key.assetType, key.type, key.rootType, key.extension, AssetLoader.ROOT);
2766
2766
  const rooted = await this.load(rootKey, parser);
2767
2767
  if (typeof rooted !== "undefined") {
@@ -2771,9 +2771,9 @@ var init_HostedAssetSource = __esm({
2771
2771
  return void 0;
2772
2772
  }
2773
2773
  async load(key, parser) {
2774
- console.info(p3, "Loading", key);
2774
+ console.info(p4, "Loading", key);
2775
2775
  const url = `${this.assetBasePath(key)}${key.type !== void 0 ? key.type + "/" : ""}${key.path}${key.extension}`;
2776
- console.debug(p3, url);
2776
+ console.debug(p4, url);
2777
2777
  const request = { url };
2778
2778
  try {
2779
2779
  parser.config(request);
@@ -3216,7 +3216,7 @@ var init_source = __esm({
3216
3216
  });
3217
3217
 
3218
3218
  // src/assets/AssetLoader.ts
3219
- var p4, _AssetLoader, AssetLoader;
3219
+ var p5, _AssetLoader, AssetLoader;
3220
3220
  var init_AssetLoader = __esm({
3221
3221
  "src/assets/AssetLoader.ts"() {
3222
3222
  init_Assets();
@@ -3224,7 +3224,7 @@ var init_AssetLoader = __esm({
3224
3224
  init_log();
3225
3225
  init_source();
3226
3226
  init_Caching();
3227
- p4 = prefix("AssetLoader");
3227
+ p5 = prefix("AssetLoader");
3228
3228
  _AssetLoader = class _AssetLoader {
3229
3229
  static get version() {
3230
3230
  return this.ROOT.substring(this.ROOT.lastIndexOf("/") + 1);
@@ -3273,11 +3273,11 @@ ${key}` : key;
3273
3273
  if (override) {
3274
3274
  const existing = this.removeSource(key);
3275
3275
  if (existing) {
3276
- console.log(p4, "Removed existing AssetSource", key);
3276
+ console.log(p5, "Removed existing AssetSource", key);
3277
3277
  }
3278
3278
  }
3279
3279
  this._SOURCES.unshift({ key, source });
3280
- console.log(p4, "Added AssetSource", key);
3280
+ console.log(p5, "Added AssetSource", key);
3281
3281
  }
3282
3282
  /** Removes and returns the first source with this name. Call {@link Caching.clear} to reload assets. */
3283
3283
  static removeSource(key) {
@@ -3669,7 +3669,7 @@ var init_ModelGenerator = __esm({
3669
3669
 
3670
3670
  // src/UVMapper.ts
3671
3671
  import { Float32BufferAttribute as Float32BufferAttribute2, Vector2, Vector3 as Vector34 } from "three";
3672
- var p5, DEFAULT_UV, X, Y, Z, FACE_UV_AXES, UVMapper, MinecraftFaceUV;
3672
+ var p6, DEFAULT_UV, X, Y, Z, FACE_UV_AXES, UVMapper, MinecraftFaceUV;
3673
3673
  var init_UVMapper = __esm({
3674
3674
  "src/UVMapper.ts"() {
3675
3675
  init_CubeFace();
@@ -3682,7 +3682,7 @@ var init_UVMapper = __esm({
3682
3682
  init_AssetKey();
3683
3683
  init_ModelGenerator();
3684
3684
  init_log();
3685
- p5 = prefix("UVMapper");
3685
+ p6 = prefix("UVMapper");
3686
3686
  DEFAULT_UV = [0, 0, 16, 16];
3687
3687
  X = 0;
3688
3688
  Y = 1;
@@ -3943,7 +3943,7 @@ var init_UVMapper = __esm({
3943
3943
  model.elements = originalModel.elements.map((element) => ({ ...element }));
3944
3944
  }
3945
3945
  const isItemModel = !("elements" in model);
3946
- console.debug(p5, "Creating Atlas for", model.key);
3946
+ console.debug(p6, "Creating Atlas for", model.key);
3947
3947
  if (model.textures) {
3948
3948
  const promises = [];
3949
3949
  const uniqueTextureNames = [];
@@ -3957,7 +3957,7 @@ var init_UVMapper = __esm({
3957
3957
  const assetKey = AssetKey.parse("textures", textureValue, model.key);
3958
3958
  promises.push(ModelTextures.get(assetKey).then((asset2) => {
3959
3959
  if (!asset2) {
3960
- console.warn(p5, "Missing texture", assetKey);
3960
+ console.warn(p6, "Missing texture", assetKey);
3961
3961
  return;
3962
3962
  }
3963
3963
  textureMap[textureKey] = new WrappedImage(asset2);
@@ -3969,7 +3969,7 @@ var init_UVMapper = __esm({
3969
3969
  }
3970
3970
  await Promise.all(promises);
3971
3971
  const textureCount = uniqueTextureNames.length;
3972
- console.debug(p5, "Creating Atlas for", textureCount, "textures");
3972
+ console.debug(p6, "Creating Atlas for", textureCount, "textures");
3973
3973
  this.fillMissingTextureKeys(model.textures, textureMap);
3974
3974
  this.fillMissingTextureKeys(model.textures, metaMap);
3975
3975
  const sizes = {};
@@ -4000,7 +4000,7 @@ var init_UVMapper = __esm({
4000
4000
  this.fillMissingTextureKeys(model.textures, sizes);
4001
4001
  const s = Math.ceil(Math.sqrt(textureCount + 1));
4002
4002
  const size = Math.ceil(s * maxWidth);
4003
- console.debug(p5, "Atlas size:", size);
4003
+ console.debug(p6, "Atlas size:", size);
4004
4004
  const squaredSize = size * size;
4005
4005
  const image = new CanvasImage(size, size);
4006
4006
  const missing = Textures.getMissing().image;
@@ -4079,7 +4079,7 @@ var init_UVMapper = __esm({
4079
4079
  }
4080
4080
  this.fillMissingTextureKeys(model.textures, positions);
4081
4081
  if (isItemModel) {
4082
- console.debug(p5, "Generating item model for", model);
4082
+ console.debug(p6, "Generating item model for", model);
4083
4083
  model.elements = [];
4084
4084
  for (let layerName of ModelGenerator.ITEM_LAYERS) {
4085
4085
  const textureImage = textureMap[layerName];
@@ -4095,7 +4095,7 @@ var init_UVMapper = __esm({
4095
4095
  ), layerName));
4096
4096
  }
4097
4097
  }
4098
- console.debug(p5, "Item model elements", model.elements);
4098
+ console.debug(p6, "Item model elements", model.elements);
4099
4099
  }
4100
4100
  if (!model.elements) {
4101
4101
  }
@@ -4152,7 +4152,7 @@ var init_UVMapper = __esm({
4152
4152
  hasTranslucency
4153
4153
  );
4154
4154
  } else {
4155
- console.warn(p5, "Model does not have any textures", model);
4155
+ console.warn(p6, "Model does not have any textures", model);
4156
4156
  }
4157
4157
  return void 0;
4158
4158
  }
@@ -4672,7 +4672,7 @@ import { Color as Color2, Euler as Euler4, InstancedBufferAttribute, InstancedMe
4672
4672
  function isSceneObject(obj) {
4673
4673
  return obj.isSceneObject;
4674
4674
  }
4675
- var import_ts_deepmerge3, p6, _SceneObject, SceneObject;
4675
+ var import_ts_deepmerge3, p7, _SceneObject, SceneObject;
4676
4676
  var init_SceneObject = __esm({
4677
4677
  "src/renderer/SceneObject.ts"() {
4678
4678
  init_Geometries();
@@ -4685,7 +4685,7 @@ var init_SceneObject = __esm({
4685
4685
  init_Disposable();
4686
4686
  import_ts_deepmerge3 = __toESM(require_dist());
4687
4687
  init_log();
4688
- p6 = prefix("SceneObject");
4688
+ p7 = prefix("SceneObject");
4689
4689
  _SceneObject = class _SceneObject extends Object3D2 {
4690
4690
  constructor(options) {
4691
4691
  super();
@@ -6942,7 +6942,7 @@ import { BoxGeometry as BoxGeometry5, BufferAttribute as BufferAttribute5, Color
6942
6942
  function isModelObject(obj) {
6943
6943
  return obj.isModelObject;
6944
6944
  }
6945
- var import_ts_deepmerge5, p7, _ModelObject, ModelObject;
6945
+ var import_ts_deepmerge5, p8, _ModelObject, ModelObject;
6946
6946
  var init_ModelObject = __esm({
6947
6947
  "src/model/scene/ModelObject.ts"() {
6948
6948
  init_SceneObject();
@@ -6961,7 +6961,7 @@ var init_ModelObject = __esm({
6961
6961
  init_GuiLight();
6962
6962
  init_ItemTints();
6963
6963
  init_ItemGlint();
6964
- p7 = prefix("ModelObject");
6964
+ p8 = prefix("ModelObject");
6965
6965
  _ModelObject = class _ModelObject extends SceneObject {
6966
6966
  constructor(originalModel, options) {
6967
6967
  super(options);
@@ -7134,10 +7134,10 @@ var init_ModelObject = __esm({
7134
7134
  }
7135
7135
  });
7136
7136
  } else {
7137
- console.debug(p7, this.atlas.model, "has no elements");
7137
+ console.debug(p8, this.atlas.model, "has no elements");
7138
7138
  }
7139
7139
  } else {
7140
- console.debug(p7, "Missing atlas for", this);
7140
+ console.debug(p8, "Missing atlas for", this);
7141
7141
  }
7142
7142
  if (this.options.mergeMeshes) {
7143
7143
  let combinedGeo;
@@ -7490,32 +7490,53 @@ import localforage from "localforage";
7490
7490
 
7491
7491
  // src/env/browser/BrowserCache.ts
7492
7492
  init_PersistentCache();
7493
+ init_log();
7494
+ var p = prefix("BrowserCache");
7493
7495
  var BrowserCache = class extends PersistentCache {
7494
7496
  constructor(backing) {
7495
7497
  super(backing);
7496
7498
  }
7499
+ async initialize() {
7500
+ try {
7501
+ await this.backing.ready();
7502
+ return true;
7503
+ } catch (error) {
7504
+ this.memory = /* @__PURE__ */ new Map();
7505
+ console.warn(p, "Could not open browser storage; using an in-memory store", error);
7506
+ return false;
7507
+ }
7508
+ }
7509
+ async run(operation, fallback) {
7510
+ if (await (this.initialized ?? (this.initialized = this.initialize()))) return operation();
7511
+ return fallback(this.memory);
7512
+ }
7497
7513
  get(key) {
7498
- return this.backing.getItem(key);
7514
+ return this.run(() => this.backing.getItem(key), (memory) => memory.get(key));
7499
7515
  }
7500
7516
  put(key, value) {
7501
- return this.backing.setItem(key, value);
7517
+ return this.run(() => this.backing.setItem(key, value), (memory) => {
7518
+ memory.set(key, value);
7519
+ return value;
7520
+ });
7502
7521
  }
7503
7522
  delete(key) {
7504
- return this.backing.removeItem(key);
7523
+ return this.run(() => this.backing.removeItem(key), (memory) => {
7524
+ memory.delete(key);
7525
+ });
7505
7526
  }
7506
7527
  clear() {
7507
- return this.backing.clear();
7528
+ return this.run(() => this.backing.clear(), (memory) => memory.clear());
7508
7529
  }
7509
7530
  length() {
7510
- return this.backing.length();
7531
+ return this.run(() => this.backing.length(), (memory) => memory.size);
7511
7532
  }
7512
7533
  keys() {
7513
- return this.backing.keys();
7534
+ return this.run(() => this.backing.keys(), (memory) => [...memory.keys()]);
7514
7535
  }
7515
7536
  forEach(callback) {
7516
- return this.backing.iterate((v, k) => {
7517
- callback(v, k);
7518
- });
7537
+ return this.run(() => this.backing.iterate((value, key) => {
7538
+ callback(value, key);
7539
+ }), (memory) => memory.forEach((value, key) => callback(value, key)));
7519
7540
  }
7520
7541
  };
7521
7542
 
@@ -7722,7 +7743,7 @@ function createPermutation() {
7722
7743
  return values;
7723
7744
  }
7724
7745
  function swampGrassColor(x, z) {
7725
- const p10 = permutation ?? (permutation = createPermutation());
7746
+ const p11 = permutation ?? (permutation = createPermutation());
7726
7747
  x *= 0.0225;
7727
7748
  z *= 0.0225;
7728
7749
  const s = (x + z) * skew;
@@ -7733,7 +7754,7 @@ function swampGrassColor(x, z) {
7733
7754
  const corner = (gx, gz, a, b) => {
7734
7755
  let falloff = 0.5 - a * a - b * b;
7735
7756
  if (falloff < 0) return 0;
7736
- const gradient = gradients[p10[gx + p10[gz & 255] & 255] % 12];
7757
+ const gradient = gradients[p11[gx + p11[gz & 255] & 255] % 12];
7737
7758
  falloff *= falloff;
7738
7759
  return falloff * falloff * (gradient[0] * a + gradient[1] * b);
7739
7760
  };
@@ -11737,7 +11758,7 @@ init_util();
11737
11758
  import { Raycaster, Vector2 as Vector25 } from "three";
11738
11759
  init_log();
11739
11760
  init_three();
11740
- var p8 = prefix("SceneInspector");
11761
+ var p9 = prefix("SceneInspector");
11741
11762
  var help = "<span>Ctrl/Cmd+Click to Select<br/></span><br/>";
11742
11763
  var SceneInspector = class {
11743
11764
  constructor(renderer) {
@@ -11831,7 +11852,7 @@ var SceneInspector = class {
11831
11852
  }
11832
11853
  selectObject(targetObject, targetIntersection, instance = this.getIntersectionInstance(targetIntersection)) {
11833
11854
  this.selectedObject = targetObject;
11834
- console.log(p8, "selected", targetObject);
11855
+ console.log(p9, "selected", targetObject);
11835
11856
  this.redraw(targetObject, targetIntersection, instance);
11836
11857
  }
11837
11858
  redraw(targetObject, targetIntersection, instance) {
@@ -12091,7 +12112,7 @@ var SceneStatsDisplay = class {
12091
12112
 
12092
12113
  // src/instance/InstanceManager.ts
12093
12114
  init_log();
12094
- var p9 = prefix("InstanceManager");
12115
+ var p10 = prefix("InstanceManager");
12095
12116
  var InstanceManager = class {
12096
12117
  constructor() {
12097
12118
  this.isInstanceManager = true;
@@ -12100,7 +12121,7 @@ var InstanceManager = class {
12100
12121
  /** Allocates a new placement of a cached model, or returns `undefined` if the key is unknown. */
12101
12122
  async get(key) {
12102
12123
  if (key in this.instanceCache) {
12103
- console.debug(p9, "key in cache", key);
12124
+ console.debug(p10, "key in cache", key);
12104
12125
  return (await this.instanceCache[key]).nextInstance();
12105
12126
  }
12106
12127
  return void 0;
@@ -12110,7 +12131,7 @@ var InstanceManager = class {
12110
12131
  if (key in this.instanceCache) {
12111
12132
  return await this.get(key);
12112
12133
  }
12113
- console.debug(p9, "key not in cache", key);
12134
+ console.debug(p10, "key not in cache", key);
12114
12135
  const pending = Promise.resolve().then(supplier).then((obj) => obj.nextInstance());
12115
12136
  this.instanceCache[key] = pending;
12116
12137
  try {
@@ -13221,6 +13242,8 @@ import { Controls, Euler as Euler11, MathUtils as MathUtils2, Quaternion as Quat
13221
13242
  var VANILLA_FLY_SPEED = 10.89;
13222
13243
  var PITCH_LIMIT = Math.PI / 2;
13223
13244
  var MOVE_EPSILON = 1e-6;
13245
+ var MAX_STEP_SECONDS = 0.1;
13246
+ var CLICK_SLOP_PIXELS = 4;
13224
13247
  var _euler = new Euler11(0, 0, 0, "YXZ");
13225
13248
  var _forward = new Vector313();
13226
13249
  var _right = new Vector313();
@@ -13255,7 +13278,8 @@ var FlyControls = class extends Controls {
13255
13278
  right: ["KeyD", "ArrowRight"],
13256
13279
  up: ["Space"],
13257
13280
  down: ["ShiftLeft", "ShiftRight"],
13258
- sprint: ["ControlLeft", "ControlRight"]
13281
+ // Not Control: Ctrl+W closes the browser tab on Windows and Linux, and a page cannot block it.
13282
+ sprint: ["KeyR"]
13259
13283
  };
13260
13284
  this._pressed = /* @__PURE__ */ new Set();
13261
13285
  this._velocity = new Vector313();
@@ -13263,8 +13287,12 @@ var FlyControls = class extends Controls {
13263
13287
  this._lastQuaternion = new Quaternion6();
13264
13288
  this._position0 = new Vector313();
13265
13289
  this._quaternion0 = new Quaternion6();
13290
+ this._dragX = 0;
13291
+ this._dragY = 0;
13266
13292
  this._dragMoved = false;
13293
+ this._dragTravel = 0;
13267
13294
  this._locked = false;
13295
+ this._madeFocusable = false;
13268
13296
  this._onKeyDown = (event) => this.handleKey(event, true);
13269
13297
  this._onKeyUp = (event) => this.handleKey(event, false);
13270
13298
  this._onPointerDown = (event) => this.handlePointerDown(event);
@@ -13294,7 +13322,10 @@ var FlyControls = class extends Controls {
13294
13322
  element.addEventListener("wheel", this._onWheel, { passive: false });
13295
13323
  element.addEventListener("blur", this._onBlur);
13296
13324
  element.style.touchAction = "none";
13297
- if (element.tabIndex < 0) element.tabIndex = 0;
13325
+ if (element.tabIndex < 0) {
13326
+ element.tabIndex = 0;
13327
+ this._madeFocusable = true;
13328
+ }
13298
13329
  }
13299
13330
  disconnect() {
13300
13331
  const element = this.domElement;
@@ -13312,6 +13343,10 @@ var FlyControls = class extends Controls {
13312
13343
  element.removeEventListener("wheel", this._onWheel);
13313
13344
  element.removeEventListener("blur", this._onBlur);
13314
13345
  element.style.touchAction = "auto";
13346
+ if (this._madeFocusable) {
13347
+ element.removeAttribute("tabindex");
13348
+ this._madeFocusable = false;
13349
+ }
13315
13350
  this.unlock();
13316
13351
  this._locked = false;
13317
13352
  this.releaseKeys();
@@ -13382,6 +13417,7 @@ var FlyControls = class extends Controls {
13382
13417
  /**
13383
13418
  * Advances movement by `delta` seconds (measured since the previous call when omitted)
13384
13419
  * and dispatches `change` when the camera moved.
13420
+ * A step longer than 0.1 s is applied as 0.1 s.
13385
13421
  */
13386
13422
  update(delta) {
13387
13423
  if (delta === void 0) {
@@ -13393,7 +13429,7 @@ var FlyControls = class extends Controls {
13393
13429
  this._velocity.set(0, 0, 0);
13394
13430
  return;
13395
13431
  }
13396
- if (delta > 0) this.move(delta);
13432
+ if (delta > 0) this.move(Math.min(delta, MAX_STEP_SECONDS));
13397
13433
  this.notifyChange();
13398
13434
  }
13399
13435
  move(delta) {
@@ -13440,15 +13476,21 @@ var FlyControls = class extends Controls {
13440
13476
  this._pressed.clear();
13441
13477
  }
13442
13478
  handleKey(event, down) {
13479
+ if (event.code === "MetaLeft" || event.code === "MetaRight") this.releaseKeys();
13443
13480
  const action = this.actionFor(event.code);
13444
13481
  if (!action) return;
13445
13482
  const ownsInput = this.enabled && (this._locked || event.target === this.domElement);
13446
- if (down && !ownsInput) return;
13483
+ if (down && (!ownsInput || this.isBrowserShortcut(event))) return;
13447
13484
  const pressed = this._pressed.has(action);
13448
13485
  if (down) this._pressed.add(action);
13449
13486
  else this._pressed.delete(action);
13450
13487
  if (ownsInput || this.enabled && pressed) event.preventDefault();
13451
13488
  }
13489
+ /** A key pressed with Control, Alt, or Command stays a browser shortcut unless that modifier is bound to an action. */
13490
+ isBrowserShortcut(event) {
13491
+ const bound = (modifier) => Object.values(this.keys).some((codes) => codes.some((code) => code.startsWith(modifier)));
13492
+ return event.ctrlKey && !bound("Control") || event.altKey && !bound("Alt") || event.metaKey && !bound("Meta");
13493
+ }
13452
13494
  actionFor(code) {
13453
13495
  for (const action in this.keys) {
13454
13496
  if (this.keys[action].includes(code)) return action;
@@ -13468,7 +13510,10 @@ var FlyControls = class extends Controls {
13468
13510
  if (this._dragPointer !== void 0) return;
13469
13511
  if (event.pointerType === "mouse" && event.button !== 0 && event.button !== 2) return;
13470
13512
  this._dragPointer = event.pointerId;
13513
+ this._dragX = event.clientX;
13514
+ this._dragY = event.clientY;
13471
13515
  this._dragMoved = false;
13516
+ this._dragTravel = 0;
13472
13517
  element.setPointerCapture?.(event.pointerId);
13473
13518
  }
13474
13519
  onJoystickSide(event) {
@@ -13484,8 +13529,20 @@ var FlyControls = class extends Controls {
13484
13529
  return;
13485
13530
  }
13486
13531
  if (!this._locked && event.pointerId !== this._dragPointer) return;
13487
- const dx = event.movementX ?? 0;
13488
- const dy = event.movementY ?? 0;
13532
+ let dx, dy;
13533
+ if (this._locked) {
13534
+ dx = event.movementX ?? 0;
13535
+ dy = event.movementY ?? 0;
13536
+ } else {
13537
+ dx = event.clientX - this._dragX;
13538
+ dy = event.clientY - this._dragY;
13539
+ this._dragX = event.clientX;
13540
+ this._dragY = event.clientY;
13541
+ if (!this._dragMoved) {
13542
+ this._dragTravel += Math.hypot(dx, dy);
13543
+ if (this._dragTravel <= CLICK_SLOP_PIXELS) return;
13544
+ }
13545
+ }
13489
13546
  if (!dx && !dy) return;
13490
13547
  this._dragMoved = true;
13491
13548
  this.turn(dx, dy);
@@ -15403,6 +15460,7 @@ var _Renderer = class _Renderer {
15403
15460
  /**
15404
15461
  * Replaces renderer-owned controls with the selected mode, keeping the camera where it is.
15405
15462
  * Switching to orbit controls targets the point the camera looks at, at the previous orbit distance.
15463
+ * The previous controls object is disposed, so its listeners and settings do not carry over.
15406
15464
  * Returns the new controls, or undefined when controls were disabled at construction or after disposal.
15407
15465
  */
15408
15466
  setControlsMode(mode) {
@@ -16068,6 +16126,79 @@ function parseSceneDocument(value) {
16068
16126
  return JSON.parse(JSON.stringify(input));
16069
16127
  }
16070
16128
 
16129
+ // src/scene/SceneDocumentCodec.ts
16130
+ var SCENE_DOCUMENT_MAX_BYTES = 1024 * 1024;
16131
+ async function readBounded(stream, label) {
16132
+ const reader = stream.getReader();
16133
+ const chunks = [];
16134
+ let size = 0;
16135
+ try {
16136
+ while (true) {
16137
+ const { value, done } = await reader.read();
16138
+ if (done) break;
16139
+ size += value.byteLength;
16140
+ if (size > SCENE_DOCUMENT_MAX_BYTES) throw new RangeError(`${label} exceeds ${SCENE_DOCUMENT_MAX_BYTES} bytes`);
16141
+ chunks.push(value);
16142
+ }
16143
+ } catch (error) {
16144
+ await reader.cancel().catch(() => {
16145
+ });
16146
+ throw error;
16147
+ } finally {
16148
+ reader.releaseLock();
16149
+ }
16150
+ const bytes = new Uint8Array(size);
16151
+ let offset = 0;
16152
+ for (const chunk of chunks) {
16153
+ bytes.set(chunk, offset);
16154
+ offset += chunk.byteLength;
16155
+ }
16156
+ return bytes;
16157
+ }
16158
+ function encodeBase64(bytes) {
16159
+ let binary = "";
16160
+ for (let offset = 0; offset < bytes.length; offset += 32768) {
16161
+ binary += String.fromCharCode(...bytes.subarray(offset, offset + 32768));
16162
+ }
16163
+ return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
16164
+ }
16165
+ async function encodeSceneDocument(value) {
16166
+ const scene = parseSceneDocument(value);
16167
+ const bytes = new TextEncoder().encode(JSON.stringify(scene));
16168
+ if (bytes.byteLength > SCENE_DOCUMENT_MAX_BYTES) {
16169
+ throw new RangeError(`Scene document exceeds ${SCENE_DOCUMENT_MAX_BYTES} bytes`);
16170
+ }
16171
+ const compressed = await readBounded(new Blob([bytes]).stream().pipeThrough(new CompressionStream("deflate")), "Encoded scene");
16172
+ return `v1.${encodeBase64(compressed)}`;
16173
+ }
16174
+ async function decodeSceneDocument(value) {
16175
+ if (!value.startsWith("v1.")) throw new Error("Unsupported scene encoding version; expected v1");
16176
+ const encoded = value.slice(3);
16177
+ if (encoded.length > Math.ceil(SCENE_DOCUMENT_MAX_BYTES * 4 / 3)) {
16178
+ throw new RangeError(`Encoded scene exceeds ${SCENE_DOCUMENT_MAX_BYTES} bytes`);
16179
+ }
16180
+ if (!/^[A-Za-z0-9_-]+$/.test(encoded) || encoded.length % 4 === 1) {
16181
+ throw new Error("Invalid scene base64url encoding");
16182
+ }
16183
+ const binary = atob(encoded.replace(/-/g, "+").replace(/_/g, "/"));
16184
+ const compressed = Uint8Array.from(binary, (character) => character.charCodeAt(0));
16185
+ if (encodeBase64(compressed) !== encoded) throw new Error("Invalid scene base64url encoding");
16186
+ let bytes;
16187
+ try {
16188
+ bytes = await readBounded(new Blob([compressed]).stream().pipeThrough(new DecompressionStream("deflate")), "Scene document");
16189
+ } catch (error) {
16190
+ if (error instanceof RangeError) throw error;
16191
+ throw new Error("Invalid compressed scene document");
16192
+ }
16193
+ let json;
16194
+ try {
16195
+ json = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
16196
+ } catch {
16197
+ throw new Error("Invalid UTF-8 scene document");
16198
+ }
16199
+ return parseSceneDocument(json);
16200
+ }
16201
+
16071
16202
  // src/scene/SceneDocumentLoader.ts
16072
16203
  init_AssetKey();
16073
16204
  init_AssetLoader();
@@ -18989,6 +19120,7 @@ export {
18989
19120
  Renderer,
18990
19121
  RequestError,
18991
19122
  Requests,
19123
+ SCENE_DOCUMENT_MAX_BYTES,
18992
19124
  SKIN_PARTS,
18993
19125
  SceneDocumentLoader,
18994
19126
  SceneExporter,
@@ -19040,6 +19172,8 @@ export {
19040
19172
  createGuiTextGeometry,
19041
19173
  createGuiTextureGeometry,
19042
19174
  createImage,
19175
+ decodeSceneDocument,
19176
+ encodeSceneDocument,
19043
19177
  entityAnimationTime,
19044
19178
  estimateBytesUsed,
19045
19179
  fluidKindOf,