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.
@@ -13104,6 +13104,321 @@ init_ModelObject();
13104
13104
  // src/index.ts
13105
13105
  init_nbt();
13106
13106
 
13107
+ // src/renderer/FlyControls.ts
13108
+ import { Controls, Euler as Euler11, MathUtils as MathUtils2, Quaternion as Quaternion6, Vector3 as Vector313 } from "three";
13109
+ var VANILLA_FLY_SPEED = 10.89;
13110
+ var PITCH_LIMIT = Math.PI / 2;
13111
+ var MOVE_EPSILON = 1e-6;
13112
+ var _euler = new Euler11(0, 0, 0, "YXZ");
13113
+ var _forward = new Vector313();
13114
+ var _right = new Vector313();
13115
+ var _targetVelocity = new Vector313();
13116
+ var FlyControls = class extends Controls {
13117
+ constructor(camera, domElement) {
13118
+ super(camera, domElement ?? null);
13119
+ this.isFlyControls = true;
13120
+ /** Horizontal and vertical speed in scene units per second; vanilla creative flight by default. */
13121
+ this.movementSpeed = 16 * VANILLA_FLY_SPEED;
13122
+ /** Speed multiplier while the sprint key is held. */
13123
+ this.sprintMultiplier = 2;
13124
+ /** Radians per pixel of pointer movement. */
13125
+ this.lookSpeed = 2e-3;
13126
+ /** Smooth acceleration and deceleration, approximating vanilla flight momentum. */
13127
+ this.enableDamping = true;
13128
+ /** Portion of the remaining velocity change applied per 60 Hz frame (0–1) when damping is enabled. */
13129
+ this.dampingFactor = 0.25;
13130
+ /** Capture the pointer on click so the mouse turns the camera without dragging; dragging works regardless. */
13131
+ this.pointerLock = true;
13132
+ /** Scroll the wheel to change `movementSpeed` within `speedRange`. */
13133
+ this.enableWheelSpeed = true;
13134
+ /** Minimum and maximum `movementSpeed` reachable with the wheel. */
13135
+ this.speedRange = [16, 16 * 500];
13136
+ /** Touch joystick travel in CSS pixels for full speed. */
13137
+ this.joystickRadius = 64;
13138
+ /** Key bindings by `KeyboardEvent.code`. */
13139
+ this.keys = {
13140
+ forward: ["KeyW", "ArrowUp"],
13141
+ back: ["KeyS", "ArrowDown"],
13142
+ left: ["KeyA", "ArrowLeft"],
13143
+ right: ["KeyD", "ArrowRight"],
13144
+ up: ["Space"],
13145
+ down: ["ShiftLeft", "ShiftRight"],
13146
+ sprint: ["ControlLeft", "ControlRight"]
13147
+ };
13148
+ this._pressed = /* @__PURE__ */ new Set();
13149
+ this._velocity = new Vector313();
13150
+ this._lastPosition = new Vector313();
13151
+ this._lastQuaternion = new Quaternion6();
13152
+ this._position0 = new Vector313();
13153
+ this._quaternion0 = new Quaternion6();
13154
+ this._dragMoved = false;
13155
+ this._locked = false;
13156
+ this._onKeyDown = (event) => this.handleKey(event, true);
13157
+ this._onKeyUp = (event) => this.handleKey(event, false);
13158
+ this._onPointerDown = (event) => this.handlePointerDown(event);
13159
+ this._onPointerMove = (event) => this.handlePointerMove(event);
13160
+ this._onPointerUp = (event) => this.handlePointerUp(event);
13161
+ this._onPointerLockChange = () => this.handlePointerLockChange();
13162
+ this._onContextMenu = (event) => event.preventDefault();
13163
+ this._onWheel = (event) => this.handleWheel(event);
13164
+ this._onBlur = () => this.releaseKeys();
13165
+ this._lastPosition.copy(camera.position);
13166
+ this._lastQuaternion.copy(camera.quaternion);
13167
+ this.saveState();
13168
+ if (domElement) this.connect(domElement);
13169
+ }
13170
+ connect(element) {
13171
+ super.connect(element);
13172
+ const document2 = element.ownerDocument;
13173
+ document2.addEventListener("keydown", this._onKeyDown);
13174
+ document2.addEventListener("keyup", this._onKeyUp);
13175
+ document2.addEventListener("pointerlockchange", this._onPointerLockChange);
13176
+ document2.defaultView?.addEventListener("blur", this._onBlur);
13177
+ element.addEventListener("pointerdown", this._onPointerDown);
13178
+ element.addEventListener("pointermove", this._onPointerMove);
13179
+ element.addEventListener("pointerup", this._onPointerUp);
13180
+ element.addEventListener("pointercancel", this._onPointerUp);
13181
+ element.addEventListener("contextmenu", this._onContextMenu);
13182
+ element.addEventListener("wheel", this._onWheel, { passive: false });
13183
+ element.addEventListener("blur", this._onBlur);
13184
+ element.style.touchAction = "none";
13185
+ if (element.tabIndex < 0) element.tabIndex = 0;
13186
+ }
13187
+ disconnect() {
13188
+ const element = this.domElement;
13189
+ if (!element) return;
13190
+ const document2 = element.ownerDocument;
13191
+ document2.removeEventListener("keydown", this._onKeyDown);
13192
+ document2.removeEventListener("keyup", this._onKeyUp);
13193
+ document2.removeEventListener("pointerlockchange", this._onPointerLockChange);
13194
+ document2.defaultView?.removeEventListener("blur", this._onBlur);
13195
+ element.removeEventListener("pointerdown", this._onPointerDown);
13196
+ element.removeEventListener("pointermove", this._onPointerMove);
13197
+ element.removeEventListener("pointerup", this._onPointerUp);
13198
+ element.removeEventListener("pointercancel", this._onPointerUp);
13199
+ element.removeEventListener("contextmenu", this._onContextMenu);
13200
+ element.removeEventListener("wheel", this._onWheel);
13201
+ element.removeEventListener("blur", this._onBlur);
13202
+ element.style.touchAction = "auto";
13203
+ this.unlock();
13204
+ this._locked = false;
13205
+ this.releaseKeys();
13206
+ this._dragPointer = void 0;
13207
+ this._joystick = void 0;
13208
+ }
13209
+ dispose() {
13210
+ this.disconnect();
13211
+ }
13212
+ /** Whether mouse look currently owns the pointer. */
13213
+ get locked() {
13214
+ return this._locked;
13215
+ }
13216
+ /** Requests pointer capture; browsers only allow this from a user gesture. */
13217
+ lock() {
13218
+ const element = this.domElement;
13219
+ if (!element || this._locked || typeof element.requestPointerLock !== "function") return;
13220
+ try {
13221
+ const result = element.requestPointerLock();
13222
+ if (result instanceof Promise) result.catch(() => void 0);
13223
+ } catch {
13224
+ }
13225
+ }
13226
+ /** Releases a captured pointer. */
13227
+ unlock() {
13228
+ const document2 = this.domElement?.ownerDocument;
13229
+ if (document2?.pointerLockElement && document2.pointerLockElement === this.domElement) {
13230
+ document2.exitPointerLock();
13231
+ }
13232
+ }
13233
+ /** Stores the camera pose that {@link reset} restores. */
13234
+ saveState() {
13235
+ this._position0.copy(this.object.position);
13236
+ this._quaternion0.copy(this.object.quaternion);
13237
+ }
13238
+ /** Restores the saved camera pose and stops movement. */
13239
+ reset() {
13240
+ this.object.position.copy(this._position0);
13241
+ this.object.quaternion.copy(this._quaternion0);
13242
+ this._velocity.set(0, 0, 0);
13243
+ this.notifyChange();
13244
+ }
13245
+ /** Horizontal yaw in radians, where zero looks toward -Z. */
13246
+ get yaw() {
13247
+ return _euler.setFromQuaternion(this.object.quaternion).y;
13248
+ }
13249
+ /** Vertical pitch in radians, positive looking up. */
13250
+ get pitch() {
13251
+ return _euler.setFromQuaternion(this.object.quaternion).x;
13252
+ }
13253
+ /** Turns the camera; pitch is clamped to straight up and down. */
13254
+ setRotation(yaw, pitch) {
13255
+ _euler.set(MathUtils2.clamp(pitch, -PITCH_LIMIT, PITCH_LIMIT), yaw, 0);
13256
+ this.object.quaternion.setFromEuler(_euler);
13257
+ this.notifyChange();
13258
+ }
13259
+ /** Points the camera at a position without rolling it. */
13260
+ lookAt(target) {
13261
+ _forward.copy(target).sub(this.object.position);
13262
+ if (_forward.lengthSq() < MOVE_EPSILON) return;
13263
+ _forward.normalize();
13264
+ this.setRotation(Math.atan2(-_forward.x, -_forward.z), Math.asin(MathUtils2.clamp(_forward.y, -1, 1)));
13265
+ }
13266
+ /** Whether an action's key is held. */
13267
+ isPressed(action) {
13268
+ return this._pressed.has(action);
13269
+ }
13270
+ /**
13271
+ * Advances movement by `delta` seconds (measured since the previous call when omitted)
13272
+ * and dispatches `change` when the camera moved.
13273
+ */
13274
+ update(delta) {
13275
+ if (delta === void 0) {
13276
+ const now = typeof performance !== "undefined" ? performance.now() : Date.now();
13277
+ delta = this._lastTime === void 0 ? 0 : (now - this._lastTime) / 1e3;
13278
+ this._lastTime = now;
13279
+ }
13280
+ if (!this.enabled) {
13281
+ this._velocity.set(0, 0, 0);
13282
+ return;
13283
+ }
13284
+ if (delta > 0) this.move(delta);
13285
+ this.notifyChange();
13286
+ }
13287
+ move(delta) {
13288
+ const camera = this.object;
13289
+ let forward = (this._pressed.has("forward") ? 1 : 0) - (this._pressed.has("back") ? 1 : 0);
13290
+ let strafe = (this._pressed.has("right") ? 1 : 0) - (this._pressed.has("left") ? 1 : 0);
13291
+ const climb = (this._pressed.has("up") ? 1 : 0) - (this._pressed.has("down") ? 1 : 0);
13292
+ const joystick = this._joystick;
13293
+ if (joystick) {
13294
+ const radius = Math.max(this.joystickRadius, 1);
13295
+ forward = MathUtils2.clamp(forward + (joystick.originY - joystick.y) / radius, -1, 1);
13296
+ strafe = MathUtils2.clamp(strafe + (joystick.x - joystick.originX) / radius, -1, 1);
13297
+ }
13298
+ _euler.setFromQuaternion(camera.quaternion);
13299
+ const yaw = _euler.y;
13300
+ _forward.set(-Math.sin(yaw), 0, -Math.cos(yaw));
13301
+ _right.set(Math.cos(yaw), 0, -Math.sin(yaw));
13302
+ _targetVelocity.set(0, 0, 0);
13303
+ if (forward || strafe || climb) {
13304
+ _targetVelocity.addScaledVector(_forward, forward).addScaledVector(_right, strafe);
13305
+ if (_targetVelocity.lengthSq() > 1) _targetVelocity.normalize();
13306
+ _targetVelocity.y = climb;
13307
+ const speed = this.movementSpeed * (this._pressed.has("sprint") ? this.sprintMultiplier : 1);
13308
+ _targetVelocity.multiplyScalar(speed);
13309
+ }
13310
+ if (this.enableDamping) {
13311
+ const blend = 1 - Math.pow(1 - MathUtils2.clamp(this.dampingFactor, 0, 1), delta * 60);
13312
+ this._velocity.lerp(_targetVelocity, blend);
13313
+ if (_targetVelocity.lengthSq() === 0 && this._velocity.lengthSq() < MOVE_EPSILON) this._velocity.set(0, 0, 0);
13314
+ } else {
13315
+ this._velocity.copy(_targetVelocity);
13316
+ }
13317
+ camera.position.addScaledVector(this._velocity, delta);
13318
+ }
13319
+ notifyChange() {
13320
+ const camera = this.object;
13321
+ if (this._lastPosition.distanceToSquared(camera.position) > MOVE_EPSILON || 8 * (1 - this._lastQuaternion.dot(camera.quaternion)) > MOVE_EPSILON) {
13322
+ this._lastPosition.copy(camera.position);
13323
+ this._lastQuaternion.copy(camera.quaternion);
13324
+ this.dispatchEvent({ type: "change" });
13325
+ }
13326
+ }
13327
+ releaseKeys() {
13328
+ this._pressed.clear();
13329
+ }
13330
+ handleKey(event, down) {
13331
+ const action = this.actionFor(event.code);
13332
+ if (!action) return;
13333
+ const ownsInput = this.enabled && (this._locked || event.target === this.domElement);
13334
+ if (down && !ownsInput) return;
13335
+ const pressed = this._pressed.has(action);
13336
+ if (down) this._pressed.add(action);
13337
+ else this._pressed.delete(action);
13338
+ if (ownsInput || this.enabled && pressed) event.preventDefault();
13339
+ }
13340
+ actionFor(code) {
13341
+ for (const action in this.keys) {
13342
+ if (this.keys[action].includes(code)) return action;
13343
+ }
13344
+ return void 0;
13345
+ }
13346
+ handlePointerDown(event) {
13347
+ const element = this.domElement;
13348
+ if (!this.enabled || !element) return;
13349
+ element.focus?.({ preventScroll: true });
13350
+ if (this._locked) return;
13351
+ if (event.pointerType === "touch" && !this._joystick && this.onJoystickSide(event)) {
13352
+ this._joystick = { id: event.pointerId, originX: event.clientX, originY: event.clientY, x: event.clientX, y: event.clientY };
13353
+ element.setPointerCapture?.(event.pointerId);
13354
+ return;
13355
+ }
13356
+ if (this._dragPointer !== void 0) return;
13357
+ if (event.pointerType === "mouse" && event.button !== 0 && event.button !== 2) return;
13358
+ this._dragPointer = event.pointerId;
13359
+ this._dragMoved = false;
13360
+ element.setPointerCapture?.(event.pointerId);
13361
+ }
13362
+ onJoystickSide(event) {
13363
+ const rect = this.domElement?.getBoundingClientRect?.();
13364
+ return !!rect && event.clientX < rect.left + rect.width / 2;
13365
+ }
13366
+ handlePointerMove(event) {
13367
+ if (!this.enabled) return;
13368
+ const joystick = this._joystick;
13369
+ if (joystick && event.pointerId === joystick.id) {
13370
+ joystick.x = event.clientX;
13371
+ joystick.y = event.clientY;
13372
+ return;
13373
+ }
13374
+ if (!this._locked && event.pointerId !== this._dragPointer) return;
13375
+ const dx = event.movementX ?? 0;
13376
+ const dy = event.movementY ?? 0;
13377
+ if (!dx && !dy) return;
13378
+ this._dragMoved = true;
13379
+ this.turn(dx, dy);
13380
+ }
13381
+ handlePointerUp(event) {
13382
+ if (this._joystick?.id === event.pointerId) {
13383
+ this._joystick = void 0;
13384
+ this.domElement?.releasePointerCapture?.(event.pointerId);
13385
+ return;
13386
+ }
13387
+ if (event.pointerId !== this._dragPointer) return;
13388
+ this._dragPointer = void 0;
13389
+ this.domElement?.releasePointerCapture?.(event.pointerId);
13390
+ if (this.enabled && this.pointerLock && !this._dragMoved && event.pointerType === "mouse" && event.button === 0) {
13391
+ this.lock();
13392
+ }
13393
+ }
13394
+ handleWheel(event) {
13395
+ if (!this.enabled || !this.enableWheelSpeed) return;
13396
+ event.preventDefault();
13397
+ const steps = event.deltaMode === 0 ? event.deltaY / 100 : event.deltaY;
13398
+ const [min, max] = this.speedRange;
13399
+ this.movementSpeed = MathUtils2.clamp(this.movementSpeed * Math.pow(1.15, -steps), Math.min(min, max), Math.max(min, max));
13400
+ }
13401
+ handlePointerLockChange() {
13402
+ const document2 = this.domElement?.ownerDocument;
13403
+ const locked = !!document2 && document2.pointerLockElement === this.domElement;
13404
+ if (locked === this._locked) return;
13405
+ this._locked = locked;
13406
+ if (!locked) this.releaseKeys();
13407
+ this.dispatchEvent({ type: locked ? "lock" : "unlock" });
13408
+ }
13409
+ turn(dx, dy) {
13410
+ _euler.setFromQuaternion(this.object.quaternion);
13411
+ _euler.y -= dx * this.lookSpeed;
13412
+ _euler.x = MathUtils2.clamp(_euler.x - dy * this.lookSpeed, -PITCH_LIMIT, PITCH_LIMIT);
13413
+ _euler.z = 0;
13414
+ this.object.quaternion.setFromEuler(_euler);
13415
+ this.notifyChange();
13416
+ }
13417
+ };
13418
+ function isFlyControls(obj) {
13419
+ return obj?.isFlyControls === true;
13420
+ }
13421
+
13107
13422
  // src/renderer/MineRenderScene.ts
13108
13423
  init_SceneObject();
13109
13424
  var import_ts_deepmerge8 = __toESM(require_dist());
@@ -14170,7 +14485,7 @@ function isMineRenderScene(obj) {
14170
14485
  }
14171
14486
 
14172
14487
  // src/renderer/Renderer.ts
14173
- import { AxesHelper as AxesHelper2, GridHelper, OrthographicCamera, PCFShadowMap, PerspectiveCamera, SRGBColorSpace as SRGBColorSpace7, Vector3 as Vector314, WebGLRenderer } from "three";
14488
+ import { AxesHelper as AxesHelper2, GridHelper, OrthographicCamera, PCFShadowMap, PerspectiveCamera, SRGBColorSpace as SRGBColorSpace7, Vector3 as Vector315, WebGLRenderer } from "three";
14174
14489
  var import_ts_deepmerge9 = __toESM(require_dist());
14175
14490
  init_util();
14176
14491
  init_Model();
@@ -14182,11 +14497,11 @@ import { EffectComposer, RenderPass } from "postprocessing";
14182
14497
  import {
14183
14498
  EventDispatcher,
14184
14499
  MOUSE,
14185
- Quaternion as Quaternion6,
14500
+ Quaternion as Quaternion7,
14186
14501
  Spherical,
14187
14502
  TOUCH,
14188
14503
  Vector2 as Vector26,
14189
- Vector3 as Vector313
14504
+ Vector3 as Vector314
14190
14505
  } from "three";
14191
14506
  var _changeEvent = { type: "change" };
14192
14507
  var _startEvent = { type: "start" };
@@ -14200,7 +14515,7 @@ var OrbitControls = class extends EventDispatcher {
14200
14515
  this.domElement = domElement;
14201
14516
  this.domElement.style.touchAction = "none";
14202
14517
  this.enabled = true;
14203
- this.target = new Vector313();
14518
+ this.target = new Vector314();
14204
14519
  this.minDistance = 0;
14205
14520
  this.maxDistance = Infinity;
14206
14521
  this.minZoom = 0;
@@ -14252,11 +14567,11 @@ var OrbitControls = class extends EventDispatcher {
14252
14567
  state = STATE.NONE;
14253
14568
  };
14254
14569
  this.update = function() {
14255
- const offset = new Vector313();
14256
- const quat = new Quaternion6().setFromUnitVectors(object4.up, new Vector313(0, 1, 0));
14570
+ const offset = new Vector314();
14571
+ const quat = new Quaternion7().setFromUnitVectors(object4.up, new Vector314(0, 1, 0));
14257
14572
  const quatInverse = quat.clone().invert();
14258
- const lastPosition = new Vector313();
14259
- const lastQuaternion = new Quaternion6();
14573
+ const lastPosition = new Vector314();
14574
+ const lastQuaternion = new Quaternion7();
14260
14575
  const twoPI = 2 * Math.PI;
14261
14576
  return function update() {
14262
14577
  const position = scope.object.position;
@@ -14345,7 +14660,7 @@ var OrbitControls = class extends EventDispatcher {
14345
14660
  const spherical = new Spherical();
14346
14661
  const sphericalDelta = new Spherical();
14347
14662
  let scale = 1;
14348
- const panOffset = new Vector313();
14663
+ const panOffset = new Vector314();
14349
14664
  let zoomChanged = false;
14350
14665
  const rotateStart = new Vector26();
14351
14666
  const rotateEnd = new Vector26();
@@ -14371,7 +14686,7 @@ var OrbitControls = class extends EventDispatcher {
14371
14686
  sphericalDelta.phi -= angle;
14372
14687
  }
14373
14688
  const panLeft = function() {
14374
- const v = new Vector313();
14689
+ const v = new Vector314();
14375
14690
  return function panLeft2(distance, objectMatrix) {
14376
14691
  v.setFromMatrixColumn(objectMatrix, 0);
14377
14692
  v.multiplyScalar(-distance);
@@ -14379,7 +14694,7 @@ var OrbitControls = class extends EventDispatcher {
14379
14694
  };
14380
14695
  }();
14381
14696
  const panUp = function() {
14382
- const v = new Vector313();
14697
+ const v = new Vector314();
14383
14698
  return function panUp2(distance, objectMatrix) {
14384
14699
  if (scope.screenSpacePanning === true) {
14385
14700
  v.setFromMatrixColumn(objectMatrix, 1);
@@ -14392,7 +14707,7 @@ var OrbitControls = class extends EventDispatcher {
14392
14707
  };
14393
14708
  }();
14394
14709
  const pan = function() {
14395
- const offset = new Vector313();
14710
+ const offset = new Vector314();
14396
14711
  return function pan2(deltaX, deltaY) {
14397
14712
  const element = scope.domElement;
14398
14713
  if (scope.object.isPerspectiveCamera) {
@@ -14947,20 +15262,77 @@ var _Renderer = class _Renderer {
14947
15262
  }
14948
15263
  createControls() {
14949
15264
  if (!this.options.controls?.enabled) return void 0;
14950
- const position = this.camera.position.clone();
14951
- const controls = new OrbitControls(this.camera, this.renderer.domElement);
14952
- this.camera.position.copy(position);
15265
+ return this.createControlsFor(this.options.controls.mode ?? "orbit", this.initialTarget());
15266
+ }
15267
+ initialTarget() {
14953
15268
  const target = this.options.camera.lookingAt;
14954
- if (isVector3(target)) {
15269
+ if (isVector3(target)) return target.clone();
15270
+ if (isTripleArray(target)) return new Vector315(target[0], target[1], target[2]);
15271
+ return new Vector315();
15272
+ }
15273
+ createControlsFor(mode, target) {
15274
+ let controls;
15275
+ if (mode === "fly") {
15276
+ controls = new FlyControls(this.camera, this.renderer.domElement);
15277
+ controls.lookAt(target);
15278
+ controls.saveState();
15279
+ } else {
15280
+ const position = this.camera.position.clone();
15281
+ controls = new OrbitControls(this.camera, this.renderer.domElement);
15282
+ this.camera.position.copy(position);
14955
15283
  controls.target.copy(target);
14956
- } else if (isTripleArray(target)) {
14957
- controls.target.set(target[0], target[1], target[2]);
15284
+ controls.update();
15285
+ controls.saveState();
14958
15286
  }
14959
- controls.update();
14960
- controls.saveState();
15287
+ this._controlsTime = void 0;
14961
15288
  this.registerEventDispatcher(controls);
14962
15289
  return controls;
14963
15290
  }
15291
+ /**
15292
+ * Replaces renderer-owned controls with the selected mode, keeping the camera where it is.
15293
+ * Switching to orbit controls targets the point the camera looks at, at the previous orbit distance.
15294
+ * Returns the new controls, or undefined when controls were disabled at construction or after disposal.
15295
+ */
15296
+ setControlsMode(mode) {
15297
+ const current = this._controls;
15298
+ if (this._disposed || !current) return void 0;
15299
+ if (this.controlsMode === mode) return current;
15300
+ let target;
15301
+ if (isFlyControls(current)) {
15302
+ const distance = this._orbitDistance ?? (this.camera.position.distanceTo(this.initialTarget()) || 1);
15303
+ target = new Vector315(0, 0, -distance).applyQuaternion(this.camera.quaternion).add(this.camera.position);
15304
+ } else {
15305
+ target = current.target.clone();
15306
+ this._orbitDistance = this.camera.position.distanceTo(target);
15307
+ }
15308
+ const enabled = current.enabled;
15309
+ this.disposeControls(current);
15310
+ this._controls = this.createControlsFor(mode, target);
15311
+ this._controls.enabled = enabled;
15312
+ this.dirty = true;
15313
+ return this._controls;
15314
+ }
15315
+ disposeControls(controls) {
15316
+ this._controls = void 0;
15317
+ this.unregisterEventDispatcher(controls);
15318
+ controls.enabled = false;
15319
+ controls.dispose();
15320
+ }
15321
+ /** Advances owned controls; without a frame time, flight movement does not progress. */
15322
+ updateControls(time) {
15323
+ const controls = this._controls;
15324
+ if (!controls?.enabled) {
15325
+ this._controlsTime = void 0;
15326
+ return;
15327
+ }
15328
+ if (!isFlyControls(controls)) {
15329
+ controls.update();
15330
+ return;
15331
+ }
15332
+ const previous = this._controlsTime;
15333
+ if (time !== void 0) this._controlsTime = time;
15334
+ controls.update(time === void 0 || previous === void 0 ? 0 : (time - previous) / 1e3);
15335
+ }
14964
15336
  //</editor-fold>
14965
15337
  init() {
14966
15338
  if (this._disposed) return;
@@ -15037,6 +15409,12 @@ var _Renderer = class _Renderer {
15037
15409
  events.add(changeEvent2);
15038
15410
  dispatcher.addEventListener(changeEvent2, this._changeListener);
15039
15411
  }
15412
+ unregisterEventDispatcher(dispatcher) {
15413
+ const events = this._eventDispatchers.get(dispatcher);
15414
+ if (!events) return;
15415
+ for (const event of events) dispatcher.removeEventListener(event, this._changeListener);
15416
+ this._eventDispatchers.delete(dispatcher);
15417
+ }
15040
15418
  /** Updates the camera and canvas size. Width and height are in CSS pixels. */
15041
15419
  resize(width, height) {
15042
15420
  if (this._disposed) return;
@@ -15113,6 +15491,7 @@ var _Renderer = class _Renderer {
15113
15491
  this.renderer.setAnimationLoop(null);
15114
15492
  }
15115
15493
  this._nextFrameTime = void 0;
15494
+ this._controlsTime = void 0;
15116
15495
  for (const subscription of this._frameCallbacks.values()) subscription.previous = void 0;
15117
15496
  }
15118
15497
  /**
@@ -15142,10 +15521,7 @@ var _Renderer = class _Renderer {
15142
15521
  }
15143
15522
  this._element = void 0;
15144
15523
  if (this._controls) {
15145
- const controls = this._controls;
15146
- this._controls = void 0;
15147
- controls.enabled = false;
15148
- controls.dispose();
15524
+ this.disposeControls(this._controls);
15149
15525
  }
15150
15526
  this.scene.clear();
15151
15527
  for (const helper of this._debugHelpers) {
@@ -15162,9 +15538,7 @@ var _Renderer = class _Renderer {
15162
15538
  }
15163
15539
  animate(t = performance.now()) {
15164
15540
  if (!this._running) return;
15165
- if (this._controls?.enabled) {
15166
- this._controls.update();
15167
- }
15541
+ this.updateControls(t);
15168
15542
  if (!this._running) return;
15169
15543
  if (!this.dirty && !this.options.render.renderAlways && !this._frameCallbacks.size && !this._videoExporter) return;
15170
15544
  const interval = this._frameInterval;
@@ -15201,7 +15575,7 @@ var _Renderer = class _Renderer {
15201
15575
  /** Draws a fresh frame without starting the animation loop or invoking frame callbacks. */
15202
15576
  renderOnce() {
15203
15577
  if (this._disposed) throw new Error("Cannot render a disposed renderer");
15204
- if (this._controls?.enabled) this._controls.update();
15578
+ this.updateControls();
15205
15579
  this.drawFrame();
15206
15580
  }
15207
15581
  /**
@@ -15231,7 +15605,7 @@ var _Renderer = class _Renderer {
15231
15605
  try {
15232
15606
  if (!wasRunning) this.start();
15233
15607
  this._videoExporter = exporter;
15234
- if (this._controls?.enabled) this._controls.update();
15608
+ this.updateControls();
15235
15609
  this.drawFrame();
15236
15610
  } catch (error) {
15237
15611
  exporter.cancel(error);
@@ -15282,6 +15656,19 @@ var _Renderer = class _Renderer {
15282
15656
  get controls() {
15283
15657
  return this._controls;
15284
15658
  }
15659
+ /** Renderer-owned OrbitControls, or undefined in fly mode or without controls. */
15660
+ get orbitControls() {
15661
+ return this._controls && !isFlyControls(this._controls) ? this._controls : void 0;
15662
+ }
15663
+ /** Renderer-owned {@link FlyControls}, or undefined in orbit mode or without controls. */
15664
+ get flyControls() {
15665
+ return isFlyControls(this._controls) ? this._controls : void 0;
15666
+ }
15667
+ /** The active renderer-owned controls mode, or undefined without controls. */
15668
+ get controlsMode() {
15669
+ if (!this._controls) return void 0;
15670
+ return isFlyControls(this._controls) ? "fly" : "orbit";
15671
+ }
15285
15672
  ///
15286
15673
  };
15287
15674
  _Renderer.DEFAULT_OPTIONS = (0, import_ts_deepmerge9.default)({}, {
@@ -15299,8 +15686,8 @@ _Renderer.DEFAULT_OPTIONS = (0, import_ts_deepmerge9.default)({}, {
15299
15686
  top: void 0,
15300
15687
  bottom: void 0
15301
15688
  },
15302
- position: new Vector314(50, 50, 50),
15303
- lookingAt: new Vector314(0, 0, 0)
15689
+ position: new Vector315(50, 50, 50),
15690
+ lookingAt: new Vector315(0, 0, 0)
15304
15691
  },
15305
15692
  render: {
15306
15693
  fpsLimit: 60,
@@ -15315,7 +15702,8 @@ _Renderer.DEFAULT_OPTIONS = (0, import_ts_deepmerge9.default)({}, {
15315
15702
  enabled: true
15316
15703
  },
15317
15704
  controls: {
15318
- enabled: false
15705
+ enabled: false,
15706
+ mode: "orbit"
15319
15707
  },
15320
15708
  debug: {
15321
15709
  grid: false,
@@ -16548,14 +16936,14 @@ var AnvilWorldSource = class {
16548
16936
  };
16549
16937
 
16550
16938
  // src/world/Chunk.ts
16551
- import { Vector3 as Vector317 } from "three";
16939
+ import { Vector3 as Vector318 } from "three";
16552
16940
  init_BlockStates();
16553
16941
  init_AssetKey();
16554
16942
 
16555
16943
  // src/world/MineRenderWorld.ts
16556
16944
  init_Model();
16557
16945
  init_util();
16558
- import { Vector3 as Vector316 } from "three";
16946
+ import { Vector3 as Vector317 } from "three";
16559
16947
  init_AssetKey();
16560
16948
  init_BlockStates();
16561
16949
  init_CubeFace();
@@ -16564,7 +16952,7 @@ init_CubeFace();
16564
16952
  init_AssetKey();
16565
16953
  init_Models();
16566
16954
  init_CubeFace();
16567
- import { BufferAttribute as BufferAttribute7, BufferGeometry as BufferGeometry8, Matrix4 as Matrix412, Vector3 as Vector315 } from "three";
16955
+ import { BufferAttribute as BufferAttribute7, BufferGeometry as BufferGeometry8, Matrix4 as Matrix412, Vector3 as Vector316 } from "three";
16568
16956
  init_ModelCulling();
16569
16957
  init_ModelObject();
16570
16958
  init_UVMapper();
@@ -16685,7 +17073,7 @@ var SectionModels = class {
16685
17073
  cullFaces.push(0);
16686
17074
  continue;
16687
17075
  }
16688
- const normal = new Vector315(...CUBE_FACE_OFFSETS[local]).applyEuler(rotation);
17076
+ const normal = new Vector316(...CUBE_FACE_OFFSETS[local]).applyEuler(rotation);
16689
17077
  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);
16690
17078
  cullFaces.push(world < 0 ? 0 : 1 << world);
16691
17079
  }
@@ -16881,17 +17269,17 @@ var MineRenderWorld = class {
16881
17269
  }
16882
17270
  getBlockAt(posOrX, y, z) {
16883
17271
  if (typeof posOrX == "number") {
16884
- return this.getBlockAt(new Vector316(posOrX, y, z));
17272
+ return this.getBlockAt(new Vector317(posOrX, y, z));
16885
17273
  }
16886
17274
  if (isTripleArray(posOrX)) {
16887
- return this.getBlockAt(new Vector316(posOrX[0], posOrX[1], posOrX[2]));
17275
+ return this.getBlockAt(new Vector317(posOrX[0], posOrX[1], posOrX[2]));
16888
17276
  }
16889
17277
  this.validatePosBounds(posOrX);
16890
17278
  return this.getChunkAt(posOrX)?.getBlockAt(posOrX);
16891
17279
  }
16892
17280
  getBiomeAt(posOrX, y, z) {
16893
- if (typeof posOrX === "number") return this.getBiomeAt(new Vector316(posOrX, y, z));
16894
- if (isTripleArray(posOrX)) return this.getBiomeAt(new Vector316(...posOrX));
17281
+ if (typeof posOrX === "number") return this.getBiomeAt(new Vector317(posOrX, y, z));
17282
+ if (isTripleArray(posOrX)) return this.getBiomeAt(new Vector317(...posOrX));
16895
17283
  this.validatePosBounds(posOrX);
16896
17284
  const cx = Math.floor(posOrX.x / 16), cy = Math.floor(posOrX.y / 16), cz = Math.floor(posOrX.z / 16);
16897
17285
  const lx = posOrX.x - cx * 16, ly = posOrX.y - cy * 16, lz = posOrX.z - cz * 16;
@@ -16899,10 +17287,10 @@ var MineRenderWorld = class {
16899
17287
  }
16900
17288
  async setBlockAt(posOrX, yOrBlock, z, block) {
16901
17289
  if (typeof posOrX == "number") {
16902
- return this.setBlockAt(new Vector316(posOrX, yOrBlock, z), block);
17290
+ return this.setBlockAt(new Vector317(posOrX, yOrBlock, z), block);
16903
17291
  }
16904
17292
  if (isTripleArray(posOrX)) {
16905
- return this.setBlockAt(new Vector316(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
17293
+ return this.setBlockAt(new Vector317(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
16906
17294
  }
16907
17295
  return this.placeBlock(posOrX, yOrBlock);
16908
17296
  }
@@ -16913,10 +17301,10 @@ var MineRenderWorld = class {
16913
17301
  }
16914
17302
  async setBlockVisibleAt(posOrX, yOrVisible, z, visible) {
16915
17303
  if (typeof posOrX === "number") {
16916
- return this.setBlockVisibleAt(new Vector316(posOrX, yOrVisible, z), visible);
17304
+ return this.setBlockVisibleAt(new Vector317(posOrX, yOrVisible, z), visible);
16917
17305
  }
16918
17306
  if (isTripleArray(posOrX)) {
16919
- return this.setBlockVisibleAt(new Vector316(...posOrX), yOrVisible);
17307
+ return this.setBlockVisibleAt(new Vector317(...posOrX), yOrVisible);
16920
17308
  }
16921
17309
  this.validatePosBounds(posOrX);
16922
17310
  await this.getChunkAt(posOrX)?.setBlockVisibleAt(posOrX, yOrVisible);
@@ -16942,7 +17330,7 @@ var MineRenderWorld = class {
16942
17330
  const collect = async (positions2) => {
16943
17331
  for (const pos of positions2) changes.set(pos.toArray().join(","), pos);
16944
17332
  };
16945
- const place = (block) => this.placeBlock(new Vector316(...block.position), block, collect);
17333
+ const place = (block) => this.placeBlock(new Vector317(...block.position), block, collect);
16946
17334
  const keys = /* @__PURE__ */ new Map();
16947
17335
  const types = /* @__PURE__ */ new Set();
16948
17336
  for (const block of multiblock.blocks) {
@@ -16958,7 +17346,7 @@ var MineRenderWorld = class {
16958
17346
  }
16959
17347
  if (!executor) {
16960
17348
  const groups2 = /* @__PURE__ */ new Map();
16961
- const position = new Vector316();
17349
+ const position = new Vector317();
16962
17350
  for (const block of multiblock.blocks) {
16963
17351
  const [x, y, z] = block.position;
16964
17352
  this.validatePosBounds(position.set(x, y, z));
@@ -16998,7 +17386,7 @@ var MineRenderWorld = class {
16998
17386
  try {
16999
17387
  positions = await chunk.placeBlocks(blocks);
17000
17388
  } finally {
17001
- positions ?? (positions = blocks.map(({ index }) => new Vector316(
17389
+ positions ?? (positions = blocks.map(({ index }) => new Vector317(
17002
17390
  chunk.x * 16 + index % 16,
17003
17391
  chunk.y * 16 + Math.floor(index / 256),
17004
17392
  chunk.z * 16 + Math.floor(index / 16) % 16
@@ -17037,7 +17425,7 @@ var MineRenderWorld = class {
17037
17425
  let sliceStart = performance.now();
17038
17426
  for (const section of chunk.sections) {
17039
17427
  if (section.biomes) {
17040
- const position = new Vector316(chunk.x * 16, section.y * 16, chunk.z * 16);
17428
+ const position = new Vector317(chunk.x * 16, section.y * 16, chunk.z * 16);
17041
17429
  this.validatePosBounds(position);
17042
17430
  const copy = [...section.biomes];
17043
17431
  if (copy.length !== 64 || !copy.every((id) => typeof id === "string" && id.length > 0)) {
@@ -17050,7 +17438,7 @@ var MineRenderWorld = class {
17050
17438
  }
17051
17439
  if (!executor) {
17052
17440
  if (!occupiedSections.has(section.y)) continue;
17053
- const position = new Vector316(chunk.x * 16, section.y * 16, chunk.z * 16);
17441
+ const position = new Vector317(chunk.x * 16, section.y * 16, chunk.z * 16);
17054
17442
  this.validatePosBounds(position);
17055
17443
  const target = this.getOrCreateChunkAt(position);
17056
17444
  try {
@@ -17144,7 +17532,7 @@ var MineRenderWorld = class {
17144
17532
  this.sectionModels?.clear();
17145
17533
  }
17146
17534
  updateCulling(positions) {
17147
- const neighbor = new Vector316();
17535
+ const neighbor = new Vector317();
17148
17536
  for (const pos of positions) {
17149
17537
  const cx = Math.floor(pos.x / 16), cy = Math.floor(pos.y / 16), cz = Math.floor(pos.z / 16);
17150
17538
  const chunk = this._chunks.get(`${cx}_${cy}_${cz}`);
@@ -17236,7 +17624,7 @@ var MineRenderWorld = class {
17236
17624
  }
17237
17625
  /** Converts block coordinates to scene units by multiplying each component by 16. */
17238
17626
  static worldToScenePosition(pos) {
17239
- return new Vector316(
17627
+ return new Vector317(
17240
17628
  pos.x * 16,
17241
17629
  pos.y * 16,
17242
17630
  pos.z * 16
@@ -17244,7 +17632,7 @@ var MineRenderWorld = class {
17244
17632
  }
17245
17633
  /** Converts scene units to block coordinates without rounding to an integer block. */
17246
17634
  static sceneToWorldPosition(pos) {
17247
- return new Vector316(
17635
+ return new Vector317(
17248
17636
  pos.x / 16,
17249
17637
  pos.y / 16,
17250
17638
  pos.z / 16
@@ -17680,7 +18068,7 @@ var Chunk = class _Chunk {
17680
18068
  this.sectionBlocks = /* @__PURE__ */ new Map();
17681
18069
  this.hiddenBlocks = /* @__PURE__ */ new Set();
17682
18070
  this.fluidCells = new Uint8Array(4096);
17683
- this.blockPosition = new Vector317();
18071
+ this.blockPosition = new Vector318();
17684
18072
  this.meshDirty = false;
17685
18073
  this.meshGeneration = 0;
17686
18074
  this.scene = scene;
@@ -17690,10 +18078,10 @@ var Chunk = class _Chunk {
17690
18078
  }
17691
18079
  getBlockAt(posOrX, y, z) {
17692
18080
  if (typeof posOrX == "number") {
17693
- return this.getBlockAt(new Vector317(posOrX, y, z));
18081
+ return this.getBlockAt(new Vector318(posOrX, y, z));
17694
18082
  }
17695
18083
  if (isTripleArray(posOrX)) {
17696
- return this.getBlockAt(new Vector317(posOrX[0], posOrX[1], posOrX[2]));
18084
+ return this.getBlockAt(new Vector318(posOrX[0], posOrX[1], posOrX[2]));
17697
18085
  }
17698
18086
  const pos = this.blockPosition.set(posOrX.x - this.x * 16, posOrX.y - this.y * 16, posOrX.z - this.z * 16);
17699
18087
  const index = _Chunk.chunkPosToBlockIndex(pos);
@@ -17701,10 +18089,10 @@ var Chunk = class _Chunk {
17701
18089
  }
17702
18090
  async setBlockAt(posOrX, yOrBlock, z, block) {
17703
18091
  if (typeof posOrX == "number") {
17704
- return this.setBlockAt(new Vector317(posOrX, yOrBlock, z), block);
18092
+ return this.setBlockAt(new Vector318(posOrX, yOrBlock, z), block);
17705
18093
  }
17706
18094
  if (isTripleArray(posOrX)) {
17707
- return this.setBlockAt(new Vector317(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
18095
+ return this.setBlockAt(new Vector318(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
17708
18096
  }
17709
18097
  const worldPos = posOrX;
17710
18098
  const pos = this.worldPosToChunkPos(worldPos);
@@ -17757,7 +18145,7 @@ var Chunk = class _Chunk {
17757
18145
  if (this.fluidCells[index]) this.meshDirty = true;
17758
18146
  this.fluidCells[index] = 0;
17759
18147
  this.renderedBlocks.delete(index);
17760
- const worldPos = new Vector317(
18148
+ const worldPos = new Vector318(
17761
18149
  this.x * 16 + index % 16,
17762
18150
  this.y * 16 + Math.floor(index / 256),
17763
18151
  this.z * 16 + Math.floor(index / 16) % 16
@@ -17882,7 +18270,7 @@ var Chunk = class _Chunk {
17882
18270
  this.z * 16 + Math.floor(index / 16) % 16
17883
18271
  ]
17884
18272
  });
17885
- object4.setPosition(new Vector317(
18273
+ object4.setPosition(new Vector318(
17886
18274
  this.x * 256 + index % 16 * 16,
17887
18275
  this.y * 256 + Math.floor(index / 256) * 16,
17888
18276
  this.z * 256 + Math.floor(index / 16) % 16 * 16
@@ -18033,7 +18421,7 @@ var Chunk = class _Chunk {
18033
18421
  /** Removes stored blocks and render objects. Set `notify` to false to skip the owning world's update. */
18034
18422
  async clear(notify = true) {
18035
18423
  const positions = notify && this.onBlocksChanged ? [...this.renderedBlocks.keys()].map((index) => this.chunkPosToWorldPos(
18036
- new Vector317(index % 16, Math.floor(index / 256), Math.floor(index / 16) % 16)
18424
+ new Vector318(index % 16, Math.floor(index / 256), Math.floor(index / 16) % 16)
18037
18425
  )) : [];
18038
18426
  for (const info of this.renderedBlocks.values()) info.object?.removeFromScene();
18039
18427
  this.sectionBlocks.clear();
@@ -18061,14 +18449,14 @@ var Chunk = class _Chunk {
18061
18449
  return pos.y * 16 * 16 + pos.z * 16 + pos.x;
18062
18450
  }
18063
18451
  worldPosToChunkPos(pos) {
18064
- return new Vector317(
18452
+ return new Vector318(
18065
18453
  pos.x - this.x * 16,
18066
18454
  pos.y - this.y * 16,
18067
18455
  pos.z - this.z * 16
18068
18456
  );
18069
18457
  }
18070
18458
  chunkPosToWorldPos(pos) {
18071
- return new Vector317(
18459
+ return new Vector318(
18072
18460
  this.x * 16 + pos.x,
18073
18461
  this.y * 16 + pos.y,
18074
18462
  this.z * 16 + pos.z
@@ -18299,6 +18687,7 @@ export {
18299
18687
  EntityObject,
18300
18688
  Env,
18301
18689
  FluidModelObject,
18690
+ FlyControls,
18302
18691
  Fonts,
18303
18692
  GUI_CONTAINER_LAYOUTS,
18304
18693
  Geometries,
@@ -18401,6 +18790,7 @@ export {
18401
18790
  isDisposable,
18402
18791
  isDoubleArray,
18403
18792
  isEntityObject,
18793
+ isFlyControls,
18404
18794
  isGuiObject,
18405
18795
  isInstanceManager,
18406
18796
  isInstanceReference,