minerender 2.1.0-alpha.114 → 2.1.0-alpha.115

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.
@@ -13157,6 +13157,321 @@ init_ModelObject();
13157
13157
  // src/index.ts
13158
13158
  init_nbt();
13159
13159
 
13160
+ // src/renderer/FlyControls.ts
13161
+ import { Controls, Euler as Euler11, MathUtils as MathUtils2, Quaternion as Quaternion6, Vector3 as Vector313 } from "three";
13162
+ var VANILLA_FLY_SPEED = 10.89;
13163
+ var PITCH_LIMIT = Math.PI / 2;
13164
+ var MOVE_EPSILON = 1e-6;
13165
+ var _euler = new Euler11(0, 0, 0, "YXZ");
13166
+ var _forward = new Vector313();
13167
+ var _right = new Vector313();
13168
+ var _targetVelocity = new Vector313();
13169
+ var FlyControls = class extends Controls {
13170
+ constructor(camera, domElement) {
13171
+ super(camera, domElement ?? null);
13172
+ this.isFlyControls = true;
13173
+ /** Horizontal and vertical speed in scene units per second; vanilla creative flight by default. */
13174
+ this.movementSpeed = 16 * VANILLA_FLY_SPEED;
13175
+ /** Speed multiplier while the sprint key is held. */
13176
+ this.sprintMultiplier = 2;
13177
+ /** Radians per pixel of pointer movement. */
13178
+ this.lookSpeed = 2e-3;
13179
+ /** Smooth acceleration and deceleration, approximating vanilla flight momentum. */
13180
+ this.enableDamping = true;
13181
+ /** Portion of the remaining velocity change applied per 60 Hz frame (0–1) when damping is enabled. */
13182
+ this.dampingFactor = 0.25;
13183
+ /** Capture the pointer on click so the mouse turns the camera without dragging; dragging works regardless. */
13184
+ this.pointerLock = true;
13185
+ /** Scroll the wheel to change `movementSpeed` within `speedRange`. */
13186
+ this.enableWheelSpeed = true;
13187
+ /** Minimum and maximum `movementSpeed` reachable with the wheel. */
13188
+ this.speedRange = [16, 16 * 500];
13189
+ /** Touch joystick travel in CSS pixels for full speed. */
13190
+ this.joystickRadius = 64;
13191
+ /** Key bindings by `KeyboardEvent.code`. */
13192
+ this.keys = {
13193
+ forward: ["KeyW", "ArrowUp"],
13194
+ back: ["KeyS", "ArrowDown"],
13195
+ left: ["KeyA", "ArrowLeft"],
13196
+ right: ["KeyD", "ArrowRight"],
13197
+ up: ["Space"],
13198
+ down: ["ShiftLeft", "ShiftRight"],
13199
+ sprint: ["ControlLeft", "ControlRight"]
13200
+ };
13201
+ this._pressed = /* @__PURE__ */ new Set();
13202
+ this._velocity = new Vector313();
13203
+ this._lastPosition = new Vector313();
13204
+ this._lastQuaternion = new Quaternion6();
13205
+ this._position0 = new Vector313();
13206
+ this._quaternion0 = new Quaternion6();
13207
+ this._dragMoved = false;
13208
+ this._locked = false;
13209
+ this._onKeyDown = (event) => this.handleKey(event, true);
13210
+ this._onKeyUp = (event) => this.handleKey(event, false);
13211
+ this._onPointerDown = (event) => this.handlePointerDown(event);
13212
+ this._onPointerMove = (event) => this.handlePointerMove(event);
13213
+ this._onPointerUp = (event) => this.handlePointerUp(event);
13214
+ this._onPointerLockChange = () => this.handlePointerLockChange();
13215
+ this._onContextMenu = (event) => event.preventDefault();
13216
+ this._onWheel = (event) => this.handleWheel(event);
13217
+ this._onBlur = () => this.releaseKeys();
13218
+ this._lastPosition.copy(camera.position);
13219
+ this._lastQuaternion.copy(camera.quaternion);
13220
+ this.saveState();
13221
+ if (domElement) this.connect(domElement);
13222
+ }
13223
+ connect(element) {
13224
+ super.connect(element);
13225
+ const document2 = element.ownerDocument;
13226
+ document2.addEventListener("keydown", this._onKeyDown);
13227
+ document2.addEventListener("keyup", this._onKeyUp);
13228
+ document2.addEventListener("pointerlockchange", this._onPointerLockChange);
13229
+ document2.defaultView?.addEventListener("blur", this._onBlur);
13230
+ element.addEventListener("pointerdown", this._onPointerDown);
13231
+ element.addEventListener("pointermove", this._onPointerMove);
13232
+ element.addEventListener("pointerup", this._onPointerUp);
13233
+ element.addEventListener("pointercancel", this._onPointerUp);
13234
+ element.addEventListener("contextmenu", this._onContextMenu);
13235
+ element.addEventListener("wheel", this._onWheel, { passive: false });
13236
+ element.addEventListener("blur", this._onBlur);
13237
+ element.style.touchAction = "none";
13238
+ if (element.tabIndex < 0) element.tabIndex = 0;
13239
+ }
13240
+ disconnect() {
13241
+ const element = this.domElement;
13242
+ if (!element) return;
13243
+ const document2 = element.ownerDocument;
13244
+ document2.removeEventListener("keydown", this._onKeyDown);
13245
+ document2.removeEventListener("keyup", this._onKeyUp);
13246
+ document2.removeEventListener("pointerlockchange", this._onPointerLockChange);
13247
+ document2.defaultView?.removeEventListener("blur", this._onBlur);
13248
+ element.removeEventListener("pointerdown", this._onPointerDown);
13249
+ element.removeEventListener("pointermove", this._onPointerMove);
13250
+ element.removeEventListener("pointerup", this._onPointerUp);
13251
+ element.removeEventListener("pointercancel", this._onPointerUp);
13252
+ element.removeEventListener("contextmenu", this._onContextMenu);
13253
+ element.removeEventListener("wheel", this._onWheel);
13254
+ element.removeEventListener("blur", this._onBlur);
13255
+ element.style.touchAction = "auto";
13256
+ this.unlock();
13257
+ this._locked = false;
13258
+ this.releaseKeys();
13259
+ this._dragPointer = void 0;
13260
+ this._joystick = void 0;
13261
+ }
13262
+ dispose() {
13263
+ this.disconnect();
13264
+ }
13265
+ /** Whether mouse look currently owns the pointer. */
13266
+ get locked() {
13267
+ return this._locked;
13268
+ }
13269
+ /** Requests pointer capture; browsers only allow this from a user gesture. */
13270
+ lock() {
13271
+ const element = this.domElement;
13272
+ if (!element || this._locked || typeof element.requestPointerLock !== "function") return;
13273
+ try {
13274
+ const result = element.requestPointerLock();
13275
+ if (result instanceof Promise) result.catch(() => void 0);
13276
+ } catch {
13277
+ }
13278
+ }
13279
+ /** Releases a captured pointer. */
13280
+ unlock() {
13281
+ const document2 = this.domElement?.ownerDocument;
13282
+ if (document2?.pointerLockElement && document2.pointerLockElement === this.domElement) {
13283
+ document2.exitPointerLock();
13284
+ }
13285
+ }
13286
+ /** Stores the camera pose that {@link reset} restores. */
13287
+ saveState() {
13288
+ this._position0.copy(this.object.position);
13289
+ this._quaternion0.copy(this.object.quaternion);
13290
+ }
13291
+ /** Restores the saved camera pose and stops movement. */
13292
+ reset() {
13293
+ this.object.position.copy(this._position0);
13294
+ this.object.quaternion.copy(this._quaternion0);
13295
+ this._velocity.set(0, 0, 0);
13296
+ this.notifyChange();
13297
+ }
13298
+ /** Horizontal yaw in radians, where zero looks toward -Z. */
13299
+ get yaw() {
13300
+ return _euler.setFromQuaternion(this.object.quaternion).y;
13301
+ }
13302
+ /** Vertical pitch in radians, positive looking up. */
13303
+ get pitch() {
13304
+ return _euler.setFromQuaternion(this.object.quaternion).x;
13305
+ }
13306
+ /** Turns the camera; pitch is clamped to straight up and down. */
13307
+ setRotation(yaw, pitch) {
13308
+ _euler.set(MathUtils2.clamp(pitch, -PITCH_LIMIT, PITCH_LIMIT), yaw, 0);
13309
+ this.object.quaternion.setFromEuler(_euler);
13310
+ this.notifyChange();
13311
+ }
13312
+ /** Points the camera at a position without rolling it. */
13313
+ lookAt(target) {
13314
+ _forward.copy(target).sub(this.object.position);
13315
+ if (_forward.lengthSq() < MOVE_EPSILON) return;
13316
+ _forward.normalize();
13317
+ this.setRotation(Math.atan2(-_forward.x, -_forward.z), Math.asin(MathUtils2.clamp(_forward.y, -1, 1)));
13318
+ }
13319
+ /** Whether an action's key is held. */
13320
+ isPressed(action) {
13321
+ return this._pressed.has(action);
13322
+ }
13323
+ /**
13324
+ * Advances movement by `delta` seconds (measured since the previous call when omitted)
13325
+ * and dispatches `change` when the camera moved.
13326
+ */
13327
+ update(delta) {
13328
+ if (delta === void 0) {
13329
+ const now = typeof performance !== "undefined" ? performance.now() : Date.now();
13330
+ delta = this._lastTime === void 0 ? 0 : (now - this._lastTime) / 1e3;
13331
+ this._lastTime = now;
13332
+ }
13333
+ if (!this.enabled) {
13334
+ this._velocity.set(0, 0, 0);
13335
+ return;
13336
+ }
13337
+ if (delta > 0) this.move(delta);
13338
+ this.notifyChange();
13339
+ }
13340
+ move(delta) {
13341
+ const camera = this.object;
13342
+ let forward = (this._pressed.has("forward") ? 1 : 0) - (this._pressed.has("back") ? 1 : 0);
13343
+ let strafe = (this._pressed.has("right") ? 1 : 0) - (this._pressed.has("left") ? 1 : 0);
13344
+ const climb = (this._pressed.has("up") ? 1 : 0) - (this._pressed.has("down") ? 1 : 0);
13345
+ const joystick = this._joystick;
13346
+ if (joystick) {
13347
+ const radius = Math.max(this.joystickRadius, 1);
13348
+ forward = MathUtils2.clamp(forward + (joystick.originY - joystick.y) / radius, -1, 1);
13349
+ strafe = MathUtils2.clamp(strafe + (joystick.x - joystick.originX) / radius, -1, 1);
13350
+ }
13351
+ _euler.setFromQuaternion(camera.quaternion);
13352
+ const yaw = _euler.y;
13353
+ _forward.set(-Math.sin(yaw), 0, -Math.cos(yaw));
13354
+ _right.set(Math.cos(yaw), 0, -Math.sin(yaw));
13355
+ _targetVelocity.set(0, 0, 0);
13356
+ if (forward || strafe || climb) {
13357
+ _targetVelocity.addScaledVector(_forward, forward).addScaledVector(_right, strafe);
13358
+ if (_targetVelocity.lengthSq() > 1) _targetVelocity.normalize();
13359
+ _targetVelocity.y = climb;
13360
+ const speed = this.movementSpeed * (this._pressed.has("sprint") ? this.sprintMultiplier : 1);
13361
+ _targetVelocity.multiplyScalar(speed);
13362
+ }
13363
+ if (this.enableDamping) {
13364
+ const blend = 1 - Math.pow(1 - MathUtils2.clamp(this.dampingFactor, 0, 1), delta * 60);
13365
+ this._velocity.lerp(_targetVelocity, blend);
13366
+ if (_targetVelocity.lengthSq() === 0 && this._velocity.lengthSq() < MOVE_EPSILON) this._velocity.set(0, 0, 0);
13367
+ } else {
13368
+ this._velocity.copy(_targetVelocity);
13369
+ }
13370
+ camera.position.addScaledVector(this._velocity, delta);
13371
+ }
13372
+ notifyChange() {
13373
+ const camera = this.object;
13374
+ if (this._lastPosition.distanceToSquared(camera.position) > MOVE_EPSILON || 8 * (1 - this._lastQuaternion.dot(camera.quaternion)) > MOVE_EPSILON) {
13375
+ this._lastPosition.copy(camera.position);
13376
+ this._lastQuaternion.copy(camera.quaternion);
13377
+ this.dispatchEvent({ type: "change" });
13378
+ }
13379
+ }
13380
+ releaseKeys() {
13381
+ this._pressed.clear();
13382
+ }
13383
+ handleKey(event, down) {
13384
+ const action = this.actionFor(event.code);
13385
+ if (!action) return;
13386
+ const ownsInput = this.enabled && (this._locked || event.target === this.domElement);
13387
+ if (down && !ownsInput) return;
13388
+ const pressed = this._pressed.has(action);
13389
+ if (down) this._pressed.add(action);
13390
+ else this._pressed.delete(action);
13391
+ if (ownsInput || this.enabled && pressed) event.preventDefault();
13392
+ }
13393
+ actionFor(code) {
13394
+ for (const action in this.keys) {
13395
+ if (this.keys[action].includes(code)) return action;
13396
+ }
13397
+ return void 0;
13398
+ }
13399
+ handlePointerDown(event) {
13400
+ const element = this.domElement;
13401
+ if (!this.enabled || !element) return;
13402
+ element.focus?.({ preventScroll: true });
13403
+ if (this._locked) return;
13404
+ if (event.pointerType === "touch" && !this._joystick && this.onJoystickSide(event)) {
13405
+ this._joystick = { id: event.pointerId, originX: event.clientX, originY: event.clientY, x: event.clientX, y: event.clientY };
13406
+ element.setPointerCapture?.(event.pointerId);
13407
+ return;
13408
+ }
13409
+ if (this._dragPointer !== void 0) return;
13410
+ if (event.pointerType === "mouse" && event.button !== 0 && event.button !== 2) return;
13411
+ this._dragPointer = event.pointerId;
13412
+ this._dragMoved = false;
13413
+ element.setPointerCapture?.(event.pointerId);
13414
+ }
13415
+ onJoystickSide(event) {
13416
+ const rect = this.domElement?.getBoundingClientRect?.();
13417
+ return !!rect && event.clientX < rect.left + rect.width / 2;
13418
+ }
13419
+ handlePointerMove(event) {
13420
+ if (!this.enabled) return;
13421
+ const joystick = this._joystick;
13422
+ if (joystick && event.pointerId === joystick.id) {
13423
+ joystick.x = event.clientX;
13424
+ joystick.y = event.clientY;
13425
+ return;
13426
+ }
13427
+ if (!this._locked && event.pointerId !== this._dragPointer) return;
13428
+ const dx = event.movementX ?? 0;
13429
+ const dy = event.movementY ?? 0;
13430
+ if (!dx && !dy) return;
13431
+ this._dragMoved = true;
13432
+ this.turn(dx, dy);
13433
+ }
13434
+ handlePointerUp(event) {
13435
+ if (this._joystick?.id === event.pointerId) {
13436
+ this._joystick = void 0;
13437
+ this.domElement?.releasePointerCapture?.(event.pointerId);
13438
+ return;
13439
+ }
13440
+ if (event.pointerId !== this._dragPointer) return;
13441
+ this._dragPointer = void 0;
13442
+ this.domElement?.releasePointerCapture?.(event.pointerId);
13443
+ if (this.enabled && this.pointerLock && !this._dragMoved && event.pointerType === "mouse" && event.button === 0) {
13444
+ this.lock();
13445
+ }
13446
+ }
13447
+ handleWheel(event) {
13448
+ if (!this.enabled || !this.enableWheelSpeed) return;
13449
+ event.preventDefault();
13450
+ const steps = event.deltaMode === 0 ? event.deltaY / 100 : event.deltaY;
13451
+ const [min, max] = this.speedRange;
13452
+ this.movementSpeed = MathUtils2.clamp(this.movementSpeed * Math.pow(1.15, -steps), Math.min(min, max), Math.max(min, max));
13453
+ }
13454
+ handlePointerLockChange() {
13455
+ const document2 = this.domElement?.ownerDocument;
13456
+ const locked = !!document2 && document2.pointerLockElement === this.domElement;
13457
+ if (locked === this._locked) return;
13458
+ this._locked = locked;
13459
+ if (!locked) this.releaseKeys();
13460
+ this.dispatchEvent({ type: locked ? "lock" : "unlock" });
13461
+ }
13462
+ turn(dx, dy) {
13463
+ _euler.setFromQuaternion(this.object.quaternion);
13464
+ _euler.y -= dx * this.lookSpeed;
13465
+ _euler.x = MathUtils2.clamp(_euler.x - dy * this.lookSpeed, -PITCH_LIMIT, PITCH_LIMIT);
13466
+ _euler.z = 0;
13467
+ this.object.quaternion.setFromEuler(_euler);
13468
+ this.notifyChange();
13469
+ }
13470
+ };
13471
+ function isFlyControls(obj) {
13472
+ return obj?.isFlyControls === true;
13473
+ }
13474
+
13160
13475
  // src/renderer/MineRenderScene.ts
13161
13476
  init_SceneObject();
13162
13477
  var import_ts_deepmerge8 = __toESM(require_dist());
@@ -14224,7 +14539,7 @@ function isMineRenderScene(obj) {
14224
14539
  }
14225
14540
 
14226
14541
  // src/renderer/Renderer.ts
14227
- import { AxesHelper as AxesHelper2, GridHelper, OrthographicCamera, PCFShadowMap, PerspectiveCamera, SRGBColorSpace as SRGBColorSpace7, Vector3 as Vector314, WebGLRenderer } from "three";
14542
+ import { AxesHelper as AxesHelper2, GridHelper, OrthographicCamera, PCFShadowMap, PerspectiveCamera, SRGBColorSpace as SRGBColorSpace7, Vector3 as Vector315, WebGLRenderer } from "three";
14228
14543
  var import_ts_deepmerge9 = __toESM(require_dist());
14229
14544
  init_util();
14230
14545
  init_Model();
@@ -14236,11 +14551,11 @@ import { EffectComposer, RenderPass } from "postprocessing";
14236
14551
  import {
14237
14552
  EventDispatcher,
14238
14553
  MOUSE,
14239
- Quaternion as Quaternion6,
14554
+ Quaternion as Quaternion7,
14240
14555
  Spherical,
14241
14556
  TOUCH,
14242
14557
  Vector2 as Vector26,
14243
- Vector3 as Vector313
14558
+ Vector3 as Vector314
14244
14559
  } from "three";
14245
14560
  var _changeEvent = { type: "change" };
14246
14561
  var _startEvent = { type: "start" };
@@ -14254,7 +14569,7 @@ var OrbitControls = class extends EventDispatcher {
14254
14569
  this.domElement = domElement;
14255
14570
  this.domElement.style.touchAction = "none";
14256
14571
  this.enabled = true;
14257
- this.target = new Vector313();
14572
+ this.target = new Vector314();
14258
14573
  this.minDistance = 0;
14259
14574
  this.maxDistance = Infinity;
14260
14575
  this.minZoom = 0;
@@ -14306,11 +14621,11 @@ var OrbitControls = class extends EventDispatcher {
14306
14621
  state = STATE.NONE;
14307
14622
  };
14308
14623
  this.update = function() {
14309
- const offset = new Vector313();
14310
- const quat = new Quaternion6().setFromUnitVectors(object4.up, new Vector313(0, 1, 0));
14624
+ const offset = new Vector314();
14625
+ const quat = new Quaternion7().setFromUnitVectors(object4.up, new Vector314(0, 1, 0));
14311
14626
  const quatInverse = quat.clone().invert();
14312
- const lastPosition = new Vector313();
14313
- const lastQuaternion = new Quaternion6();
14627
+ const lastPosition = new Vector314();
14628
+ const lastQuaternion = new Quaternion7();
14314
14629
  const twoPI = 2 * Math.PI;
14315
14630
  return function update() {
14316
14631
  const position = scope.object.position;
@@ -14399,7 +14714,7 @@ var OrbitControls = class extends EventDispatcher {
14399
14714
  const spherical = new Spherical();
14400
14715
  const sphericalDelta = new Spherical();
14401
14716
  let scale = 1;
14402
- const panOffset = new Vector313();
14717
+ const panOffset = new Vector314();
14403
14718
  let zoomChanged = false;
14404
14719
  const rotateStart = new Vector26();
14405
14720
  const rotateEnd = new Vector26();
@@ -14425,7 +14740,7 @@ var OrbitControls = class extends EventDispatcher {
14425
14740
  sphericalDelta.phi -= angle;
14426
14741
  }
14427
14742
  const panLeft = function() {
14428
- const v = new Vector313();
14743
+ const v = new Vector314();
14429
14744
  return function panLeft2(distance, objectMatrix) {
14430
14745
  v.setFromMatrixColumn(objectMatrix, 0);
14431
14746
  v.multiplyScalar(-distance);
@@ -14433,7 +14748,7 @@ var OrbitControls = class extends EventDispatcher {
14433
14748
  };
14434
14749
  }();
14435
14750
  const panUp = function() {
14436
- const v = new Vector313();
14751
+ const v = new Vector314();
14437
14752
  return function panUp2(distance, objectMatrix) {
14438
14753
  if (scope.screenSpacePanning === true) {
14439
14754
  v.setFromMatrixColumn(objectMatrix, 1);
@@ -14446,7 +14761,7 @@ var OrbitControls = class extends EventDispatcher {
14446
14761
  };
14447
14762
  }();
14448
14763
  const pan = function() {
14449
- const offset = new Vector313();
14764
+ const offset = new Vector314();
14450
14765
  return function pan2(deltaX, deltaY) {
14451
14766
  const element = scope.domElement;
14452
14767
  if (scope.object.isPerspectiveCamera) {
@@ -14957,8 +15272,8 @@ var Renderer = class _Renderer {
14957
15272
  top: void 0,
14958
15273
  bottom: void 0
14959
15274
  },
14960
- position: new Vector314(50, 50, 50),
14961
- lookingAt: new Vector314(0, 0, 0)
15275
+ position: new Vector315(50, 50, 50),
15276
+ lookingAt: new Vector315(0, 0, 0)
14962
15277
  },
14963
15278
  render: {
14964
15279
  fpsLimit: 60,
@@ -14973,7 +15288,8 @@ var Renderer = class _Renderer {
14973
15288
  enabled: true
14974
15289
  },
14975
15290
  controls: {
14976
- enabled: false
15291
+ enabled: false,
15292
+ mode: "orbit"
14977
15293
  },
14978
15294
  debug: {
14979
15295
  grid: false,
@@ -15041,20 +15357,77 @@ var Renderer = class _Renderer {
15041
15357
  }
15042
15358
  createControls() {
15043
15359
  if (!this.options.controls?.enabled) return void 0;
15044
- const position = this.camera.position.clone();
15045
- const controls = new OrbitControls(this.camera, this.renderer.domElement);
15046
- this.camera.position.copy(position);
15360
+ return this.createControlsFor(this.options.controls.mode ?? "orbit", this.initialTarget());
15361
+ }
15362
+ initialTarget() {
15047
15363
  const target = this.options.camera.lookingAt;
15048
- if (isVector3(target)) {
15364
+ if (isVector3(target)) return target.clone();
15365
+ if (isTripleArray(target)) return new Vector315(target[0], target[1], target[2]);
15366
+ return new Vector315();
15367
+ }
15368
+ createControlsFor(mode, target) {
15369
+ let controls;
15370
+ if (mode === "fly") {
15371
+ controls = new FlyControls(this.camera, this.renderer.domElement);
15372
+ controls.lookAt(target);
15373
+ controls.saveState();
15374
+ } else {
15375
+ const position = this.camera.position.clone();
15376
+ controls = new OrbitControls(this.camera, this.renderer.domElement);
15377
+ this.camera.position.copy(position);
15049
15378
  controls.target.copy(target);
15050
- } else if (isTripleArray(target)) {
15051
- controls.target.set(target[0], target[1], target[2]);
15379
+ controls.update();
15380
+ controls.saveState();
15052
15381
  }
15053
- controls.update();
15054
- controls.saveState();
15382
+ this._controlsTime = void 0;
15055
15383
  this.registerEventDispatcher(controls);
15056
15384
  return controls;
15057
15385
  }
15386
+ /**
15387
+ * Replaces renderer-owned controls with the selected mode, keeping the camera where it is.
15388
+ * Switching to orbit controls targets the point the camera looks at, at the previous orbit distance.
15389
+ * Returns the new controls, or undefined when controls were disabled at construction or after disposal.
15390
+ */
15391
+ setControlsMode(mode) {
15392
+ const current = this._controls;
15393
+ if (this._disposed || !current) return void 0;
15394
+ if (this.controlsMode === mode) return current;
15395
+ let target;
15396
+ if (isFlyControls(current)) {
15397
+ const distance = this._orbitDistance ?? (this.camera.position.distanceTo(this.initialTarget()) || 1);
15398
+ target = new Vector315(0, 0, -distance).applyQuaternion(this.camera.quaternion).add(this.camera.position);
15399
+ } else {
15400
+ target = current.target.clone();
15401
+ this._orbitDistance = this.camera.position.distanceTo(target);
15402
+ }
15403
+ const enabled = current.enabled;
15404
+ this.disposeControls(current);
15405
+ this._controls = this.createControlsFor(mode, target);
15406
+ this._controls.enabled = enabled;
15407
+ this.dirty = true;
15408
+ return this._controls;
15409
+ }
15410
+ disposeControls(controls) {
15411
+ this._controls = void 0;
15412
+ this.unregisterEventDispatcher(controls);
15413
+ controls.enabled = false;
15414
+ controls.dispose();
15415
+ }
15416
+ /** Advances owned controls; without a frame time, flight movement does not progress. */
15417
+ updateControls(time) {
15418
+ const controls = this._controls;
15419
+ if (!controls?.enabled) {
15420
+ this._controlsTime = void 0;
15421
+ return;
15422
+ }
15423
+ if (!isFlyControls(controls)) {
15424
+ controls.update();
15425
+ return;
15426
+ }
15427
+ const previous = this._controlsTime;
15428
+ if (time !== void 0) this._controlsTime = time;
15429
+ controls.update(time === void 0 || previous === void 0 ? 0 : (time - previous) / 1e3);
15430
+ }
15058
15431
  //</editor-fold>
15059
15432
  init() {
15060
15433
  if (this._disposed) return;
@@ -15131,6 +15504,12 @@ var Renderer = class _Renderer {
15131
15504
  events.add(changeEvent2);
15132
15505
  dispatcher.addEventListener(changeEvent2, this._changeListener);
15133
15506
  }
15507
+ unregisterEventDispatcher(dispatcher) {
15508
+ const events = this._eventDispatchers.get(dispatcher);
15509
+ if (!events) return;
15510
+ for (const event of events) dispatcher.removeEventListener(event, this._changeListener);
15511
+ this._eventDispatchers.delete(dispatcher);
15512
+ }
15134
15513
  /** Updates the camera and canvas size. Width and height are in CSS pixels. */
15135
15514
  resize(width, height) {
15136
15515
  if (this._disposed) return;
@@ -15207,6 +15586,7 @@ var Renderer = class _Renderer {
15207
15586
  this.renderer.setAnimationLoop(null);
15208
15587
  }
15209
15588
  this._nextFrameTime = void 0;
15589
+ this._controlsTime = void 0;
15210
15590
  for (const subscription of this._frameCallbacks.values()) subscription.previous = void 0;
15211
15591
  }
15212
15592
  /**
@@ -15236,10 +15616,7 @@ var Renderer = class _Renderer {
15236
15616
  }
15237
15617
  this._element = void 0;
15238
15618
  if (this._controls) {
15239
- const controls = this._controls;
15240
- this._controls = void 0;
15241
- controls.enabled = false;
15242
- controls.dispose();
15619
+ this.disposeControls(this._controls);
15243
15620
  }
15244
15621
  this.scene.clear();
15245
15622
  for (const helper of this._debugHelpers) {
@@ -15256,9 +15633,7 @@ var Renderer = class _Renderer {
15256
15633
  }
15257
15634
  animate(t = performance.now()) {
15258
15635
  if (!this._running) return;
15259
- if (this._controls?.enabled) {
15260
- this._controls.update();
15261
- }
15636
+ this.updateControls(t);
15262
15637
  if (!this._running) return;
15263
15638
  if (!this.dirty && !this.options.render.renderAlways && !this._frameCallbacks.size && !this._videoExporter) return;
15264
15639
  const interval = this._frameInterval;
@@ -15295,7 +15670,7 @@ var Renderer = class _Renderer {
15295
15670
  /** Draws a fresh frame without starting the animation loop or invoking frame callbacks. */
15296
15671
  renderOnce() {
15297
15672
  if (this._disposed) throw new Error("Cannot render a disposed renderer");
15298
- if (this._controls?.enabled) this._controls.update();
15673
+ this.updateControls();
15299
15674
  this.drawFrame();
15300
15675
  }
15301
15676
  /**
@@ -15325,7 +15700,7 @@ var Renderer = class _Renderer {
15325
15700
  try {
15326
15701
  if (!wasRunning) this.start();
15327
15702
  this._videoExporter = exporter;
15328
- if (this._controls?.enabled) this._controls.update();
15703
+ this.updateControls();
15329
15704
  this.drawFrame();
15330
15705
  } catch (error) {
15331
15706
  exporter.cancel(error);
@@ -15376,6 +15751,19 @@ var Renderer = class _Renderer {
15376
15751
  get controls() {
15377
15752
  return this._controls;
15378
15753
  }
15754
+ /** Renderer-owned OrbitControls, or undefined in fly mode or without controls. */
15755
+ get orbitControls() {
15756
+ return this._controls && !isFlyControls(this._controls) ? this._controls : void 0;
15757
+ }
15758
+ /** Renderer-owned {@link FlyControls}, or undefined in orbit mode or without controls. */
15759
+ get flyControls() {
15760
+ return isFlyControls(this._controls) ? this._controls : void 0;
15761
+ }
15762
+ /** The active renderer-owned controls mode, or undefined without controls. */
15763
+ get controlsMode() {
15764
+ if (!this._controls) return void 0;
15765
+ return isFlyControls(this._controls) ? "fly" : "orbit";
15766
+ }
15379
15767
  ///
15380
15768
  };
15381
15769
 
@@ -16603,14 +16991,14 @@ var AnvilWorldSource = class {
16603
16991
  };
16604
16992
 
16605
16993
  // src/world/Chunk.ts
16606
- import { Vector3 as Vector317 } from "three";
16994
+ import { Vector3 as Vector318 } from "three";
16607
16995
  init_BlockStates();
16608
16996
  init_AssetKey();
16609
16997
 
16610
16998
  // src/world/MineRenderWorld.ts
16611
16999
  init_Model();
16612
17000
  init_util();
16613
- import { Vector3 as Vector316 } from "three";
17001
+ import { Vector3 as Vector317 } from "three";
16614
17002
  init_AssetKey();
16615
17003
  init_BlockStates();
16616
17004
  init_CubeFace();
@@ -16619,7 +17007,7 @@ init_CubeFace();
16619
17007
  init_AssetKey();
16620
17008
  init_Models();
16621
17009
  init_CubeFace();
16622
- import { BufferAttribute as BufferAttribute7, BufferGeometry as BufferGeometry8, Matrix4 as Matrix412, Vector3 as Vector315 } from "three";
17010
+ import { BufferAttribute as BufferAttribute7, BufferGeometry as BufferGeometry8, Matrix4 as Matrix412, Vector3 as Vector316 } from "three";
16623
17011
  init_ModelCulling();
16624
17012
  init_ModelObject();
16625
17013
  init_UVMapper();
@@ -16740,7 +17128,7 @@ var SectionModels = class {
16740
17128
  cullFaces.push(0);
16741
17129
  continue;
16742
17130
  }
16743
- const normal = new Vector315(...CUBE_FACE_OFFSETS[local]).applyEuler(rotation);
17131
+ const normal = new Vector316(...CUBE_FACE_OFFSETS[local]).applyEuler(rotation);
16744
17132
  const world = CUBE_FACE_OFFSETS.findIndex(([x, y, z]) => Math.abs(normal.x - x) < 1e-6 && Math.abs(normal.y - y) < 1e-6 && Math.abs(normal.z - z) < 1e-6);
16745
17133
  cullFaces.push(world < 0 ? 0 : 1 << world);
16746
17134
  }
@@ -16936,17 +17324,17 @@ var MineRenderWorld = class {
16936
17324
  }
16937
17325
  getBlockAt(posOrX, y, z) {
16938
17326
  if (typeof posOrX == "number") {
16939
- return this.getBlockAt(new Vector316(posOrX, y, z));
17327
+ return this.getBlockAt(new Vector317(posOrX, y, z));
16940
17328
  }
16941
17329
  if (isTripleArray(posOrX)) {
16942
- return this.getBlockAt(new Vector316(posOrX[0], posOrX[1], posOrX[2]));
17330
+ return this.getBlockAt(new Vector317(posOrX[0], posOrX[1], posOrX[2]));
16943
17331
  }
16944
17332
  this.validatePosBounds(posOrX);
16945
17333
  return this.getChunkAt(posOrX)?.getBlockAt(posOrX);
16946
17334
  }
16947
17335
  getBiomeAt(posOrX, y, z) {
16948
- if (typeof posOrX === "number") return this.getBiomeAt(new Vector316(posOrX, y, z));
16949
- if (isTripleArray(posOrX)) return this.getBiomeAt(new Vector316(...posOrX));
17336
+ if (typeof posOrX === "number") return this.getBiomeAt(new Vector317(posOrX, y, z));
17337
+ if (isTripleArray(posOrX)) return this.getBiomeAt(new Vector317(...posOrX));
16950
17338
  this.validatePosBounds(posOrX);
16951
17339
  const cx = Math.floor(posOrX.x / 16), cy = Math.floor(posOrX.y / 16), cz = Math.floor(posOrX.z / 16);
16952
17340
  const lx = posOrX.x - cx * 16, ly = posOrX.y - cy * 16, lz = posOrX.z - cz * 16;
@@ -16954,10 +17342,10 @@ var MineRenderWorld = class {
16954
17342
  }
16955
17343
  async setBlockAt(posOrX, yOrBlock, z, block) {
16956
17344
  if (typeof posOrX == "number") {
16957
- return this.setBlockAt(new Vector316(posOrX, yOrBlock, z), block);
17345
+ return this.setBlockAt(new Vector317(posOrX, yOrBlock, z), block);
16958
17346
  }
16959
17347
  if (isTripleArray(posOrX)) {
16960
- return this.setBlockAt(new Vector316(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
17348
+ return this.setBlockAt(new Vector317(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
16961
17349
  }
16962
17350
  return this.placeBlock(posOrX, yOrBlock);
16963
17351
  }
@@ -16968,10 +17356,10 @@ var MineRenderWorld = class {
16968
17356
  }
16969
17357
  async setBlockVisibleAt(posOrX, yOrVisible, z, visible) {
16970
17358
  if (typeof posOrX === "number") {
16971
- return this.setBlockVisibleAt(new Vector316(posOrX, yOrVisible, z), visible);
17359
+ return this.setBlockVisibleAt(new Vector317(posOrX, yOrVisible, z), visible);
16972
17360
  }
16973
17361
  if (isTripleArray(posOrX)) {
16974
- return this.setBlockVisibleAt(new Vector316(...posOrX), yOrVisible);
17362
+ return this.setBlockVisibleAt(new Vector317(...posOrX), yOrVisible);
16975
17363
  }
16976
17364
  this.validatePosBounds(posOrX);
16977
17365
  await this.getChunkAt(posOrX)?.setBlockVisibleAt(posOrX, yOrVisible);
@@ -16997,7 +17385,7 @@ var MineRenderWorld = class {
16997
17385
  const collect = async (positions2) => {
16998
17386
  for (const pos of positions2) changes.set(pos.toArray().join(","), pos);
16999
17387
  };
17000
- const place = (block) => this.placeBlock(new Vector316(...block.position), block, collect);
17388
+ const place = (block) => this.placeBlock(new Vector317(...block.position), block, collect);
17001
17389
  const keys = /* @__PURE__ */ new Map();
17002
17390
  const types = /* @__PURE__ */ new Set();
17003
17391
  for (const block of multiblock.blocks) {
@@ -17013,7 +17401,7 @@ var MineRenderWorld = class {
17013
17401
  }
17014
17402
  if (!executor) {
17015
17403
  const groups2 = /* @__PURE__ */ new Map();
17016
- const position = new Vector316();
17404
+ const position = new Vector317();
17017
17405
  for (const block of multiblock.blocks) {
17018
17406
  const [x, y, z] = block.position;
17019
17407
  this.validatePosBounds(position.set(x, y, z));
@@ -17053,7 +17441,7 @@ var MineRenderWorld = class {
17053
17441
  try {
17054
17442
  positions = await chunk.placeBlocks(blocks);
17055
17443
  } finally {
17056
- positions ??= blocks.map(({ index }) => new Vector316(
17444
+ positions ??= blocks.map(({ index }) => new Vector317(
17057
17445
  chunk.x * 16 + index % 16,
17058
17446
  chunk.y * 16 + Math.floor(index / 256),
17059
17447
  chunk.z * 16 + Math.floor(index / 16) % 16
@@ -17092,7 +17480,7 @@ var MineRenderWorld = class {
17092
17480
  let sliceStart = performance.now();
17093
17481
  for (const section of chunk.sections) {
17094
17482
  if (section.biomes) {
17095
- const position = new Vector316(chunk.x * 16, section.y * 16, chunk.z * 16);
17483
+ const position = new Vector317(chunk.x * 16, section.y * 16, chunk.z * 16);
17096
17484
  this.validatePosBounds(position);
17097
17485
  const copy = [...section.biomes];
17098
17486
  if (copy.length !== 64 || !copy.every((id) => typeof id === "string" && id.length > 0)) {
@@ -17105,7 +17493,7 @@ var MineRenderWorld = class {
17105
17493
  }
17106
17494
  if (!executor) {
17107
17495
  if (!occupiedSections.has(section.y)) continue;
17108
- const position = new Vector316(chunk.x * 16, section.y * 16, chunk.z * 16);
17496
+ const position = new Vector317(chunk.x * 16, section.y * 16, chunk.z * 16);
17109
17497
  this.validatePosBounds(position);
17110
17498
  const target = this.getOrCreateChunkAt(position);
17111
17499
  try {
@@ -17199,7 +17587,7 @@ var MineRenderWorld = class {
17199
17587
  this.sectionModels?.clear();
17200
17588
  }
17201
17589
  updateCulling(positions) {
17202
- const neighbor = new Vector316();
17590
+ const neighbor = new Vector317();
17203
17591
  for (const pos of positions) {
17204
17592
  const cx = Math.floor(pos.x / 16), cy = Math.floor(pos.y / 16), cz = Math.floor(pos.z / 16);
17205
17593
  const chunk = this._chunks.get(`${cx}_${cy}_${cz}`);
@@ -17291,7 +17679,7 @@ var MineRenderWorld = class {
17291
17679
  }
17292
17680
  /** Converts block coordinates to scene units by multiplying each component by 16. */
17293
17681
  static worldToScenePosition(pos) {
17294
- return new Vector316(
17682
+ return new Vector317(
17295
17683
  pos.x * 16,
17296
17684
  pos.y * 16,
17297
17685
  pos.z * 16
@@ -17299,7 +17687,7 @@ var MineRenderWorld = class {
17299
17687
  }
17300
17688
  /** Converts scene units to block coordinates without rounding to an integer block. */
17301
17689
  static sceneToWorldPosition(pos) {
17302
- return new Vector316(
17690
+ return new Vector317(
17303
17691
  pos.x / 16,
17304
17692
  pos.y / 16,
17305
17693
  pos.z / 16
@@ -17736,7 +18124,7 @@ var Chunk = class _Chunk {
17736
18124
  this.sectionBlocks = /* @__PURE__ */ new Map();
17737
18125
  this.hiddenBlocks = /* @__PURE__ */ new Set();
17738
18126
  this.fluidCells = new Uint8Array(4096);
17739
- this.blockPosition = new Vector317();
18127
+ this.blockPosition = new Vector318();
17740
18128
  this.meshDirty = false;
17741
18129
  this.meshGeneration = 0;
17742
18130
  this.scene = scene;
@@ -17746,10 +18134,10 @@ var Chunk = class _Chunk {
17746
18134
  }
17747
18135
  getBlockAt(posOrX, y, z) {
17748
18136
  if (typeof posOrX == "number") {
17749
- return this.getBlockAt(new Vector317(posOrX, y, z));
18137
+ return this.getBlockAt(new Vector318(posOrX, y, z));
17750
18138
  }
17751
18139
  if (isTripleArray(posOrX)) {
17752
- return this.getBlockAt(new Vector317(posOrX[0], posOrX[1], posOrX[2]));
18140
+ return this.getBlockAt(new Vector318(posOrX[0], posOrX[1], posOrX[2]));
17753
18141
  }
17754
18142
  const pos = this.blockPosition.set(posOrX.x - this.x * 16, posOrX.y - this.y * 16, posOrX.z - this.z * 16);
17755
18143
  const index = _Chunk.chunkPosToBlockIndex(pos);
@@ -17757,10 +18145,10 @@ var Chunk = class _Chunk {
17757
18145
  }
17758
18146
  async setBlockAt(posOrX, yOrBlock, z, block) {
17759
18147
  if (typeof posOrX == "number") {
17760
- return this.setBlockAt(new Vector317(posOrX, yOrBlock, z), block);
18148
+ return this.setBlockAt(new Vector318(posOrX, yOrBlock, z), block);
17761
18149
  }
17762
18150
  if (isTripleArray(posOrX)) {
17763
- return this.setBlockAt(new Vector317(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
18151
+ return this.setBlockAt(new Vector318(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
17764
18152
  }
17765
18153
  const worldPos = posOrX;
17766
18154
  const pos = this.worldPosToChunkPos(worldPos);
@@ -17813,7 +18201,7 @@ var Chunk = class _Chunk {
17813
18201
  if (this.fluidCells[index]) this.meshDirty = true;
17814
18202
  this.fluidCells[index] = 0;
17815
18203
  this.renderedBlocks.delete(index);
17816
- const worldPos = new Vector317(
18204
+ const worldPos = new Vector318(
17817
18205
  this.x * 16 + index % 16,
17818
18206
  this.y * 16 + Math.floor(index / 256),
17819
18207
  this.z * 16 + Math.floor(index / 16) % 16
@@ -17938,7 +18326,7 @@ var Chunk = class _Chunk {
17938
18326
  this.z * 16 + Math.floor(index / 16) % 16
17939
18327
  ]
17940
18328
  });
17941
- object4.setPosition(new Vector317(
18329
+ object4.setPosition(new Vector318(
17942
18330
  this.x * 256 + index % 16 * 16,
17943
18331
  this.y * 256 + Math.floor(index / 256) * 16,
17944
18332
  this.z * 256 + Math.floor(index / 16) % 16 * 16
@@ -18089,7 +18477,7 @@ var Chunk = class _Chunk {
18089
18477
  /** Removes stored blocks and render objects. Set `notify` to false to skip the owning world's update. */
18090
18478
  async clear(notify = true) {
18091
18479
  const positions = notify && this.onBlocksChanged ? [...this.renderedBlocks.keys()].map((index) => this.chunkPosToWorldPos(
18092
- new Vector317(index % 16, Math.floor(index / 256), Math.floor(index / 16) % 16)
18480
+ new Vector318(index % 16, Math.floor(index / 256), Math.floor(index / 16) % 16)
18093
18481
  )) : [];
18094
18482
  for (const info of this.renderedBlocks.values()) info.object?.removeFromScene();
18095
18483
  this.sectionBlocks.clear();
@@ -18117,14 +18505,14 @@ var Chunk = class _Chunk {
18117
18505
  return pos.y * 16 * 16 + pos.z * 16 + pos.x;
18118
18506
  }
18119
18507
  worldPosToChunkPos(pos) {
18120
- return new Vector317(
18508
+ return new Vector318(
18121
18509
  pos.x - this.x * 16,
18122
18510
  pos.y - this.y * 16,
18123
18511
  pos.z - this.z * 16
18124
18512
  );
18125
18513
  }
18126
18514
  chunkPosToWorldPos(pos) {
18127
- return new Vector317(
18515
+ return new Vector318(
18128
18516
  this.x * 16 + pos.x,
18129
18517
  this.y * 16 + pos.y,
18130
18518
  this.z * 16 + pos.z
@@ -18517,6 +18905,7 @@ export {
18517
18905
  EntityObject,
18518
18906
  Env,
18519
18907
  FluidModelObject,
18908
+ FlyControls,
18520
18909
  Fonts,
18521
18910
  GUI_CONTAINER_LAYOUTS,
18522
18911
  Geometries,
@@ -18622,6 +19011,7 @@ export {
18622
19011
  isDisposable,
18623
19012
  isDoubleArray,
18624
19013
  isEntityObject,
19014
+ isFlyControls,
18625
19015
  isGuiObject,
18626
19016
  isInstanceManager,
18627
19017
  isInstanceReference,