@navaramap/three-plugins 0.0.4 → 0.0.6

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.
package/dist/index.js CHANGED
@@ -1,11 +1,11 @@
1
- import { EventHandler as e, Plugin as t, convertWorldToScreen as n, degreeToRadian as r, eastNorthUpToFixedFrame as i, geodeticToVector3 as a, radianToDegree as o, vector3ToGeodetic as s } from "@navaramap/three";
2
- import { Matrix4 as c, Vector3 as l } from "three";
1
+ import { EventHandler as e, MAPBOX_ELEVATION_DECODER as t, Plugin as n, TERRARIUM_ELEVATION_DECODER as r, convertWorldToScreen as i, degreeToRadian as a, eastNorthUpToFixedFrame as o, geodeticToVector3 as s, radianToDegree as c, vector3ToGeodetic as l } from "@navaramap/three";
2
+ import { MathUtils as u, Matrix4 as d, Vector3 as f } from "three";
3
3
  //#region src/PersonViewPlugin.ts
4
- var u = {
4
+ var p = {
5
5
  x: 0,
6
6
  y: 0,
7
7
  z: 0
8
- }, d = {
8
+ }, m = {
9
9
  forward: ["KeyW"],
10
10
  backward: ["KeyS"],
11
11
  turnLeft: ["KeyA"],
@@ -19,12 +19,35 @@ var u = {
19
19
  dash: ["ShiftLeft", "ShiftRight"],
20
20
  orbitCamera: ["AltLeft", "AltRight"],
21
21
  toggleView: ["KeyV"]
22
- }, f = {
22
+ }, h = {
23
+ mode: "off",
24
+ groundOffset: 0,
25
+ alignToSlope: !0,
26
+ slopeSampleDistance: 4,
27
+ maxSlopeTilt: Math.PI / 4,
28
+ cameraSlopeFollow: 1
29
+ }, g = 10, _ = 6, v = Math.PI / 4, y = [
30
+ 0,
31
+ 1,
32
+ 2,
33
+ 3,
34
+ 4,
35
+ 5,
36
+ 6,
37
+ 7
38
+ ].map((e) => {
39
+ let t = e * Math.PI / 4;
40
+ return {
41
+ sin: Math.sin(t),
42
+ cos: Math.cos(t)
43
+ };
44
+ }), b = (e, t) => e > 0 && t > 0 ? 1 - Math.exp(-e * t) : 1, x = {
23
45
  allowCameraControl: !1,
24
46
  initialView: "tpv",
25
47
  moveSpeed: 50,
26
48
  rotationSpeed: 3,
27
49
  altSpeed: 30,
50
+ dashSpeedMultiplier: 2.5,
28
51
  minAlt: 50,
29
52
  maxAlt: 5e3,
30
53
  cameraDistance: 50,
@@ -37,20 +60,23 @@ var u = {
37
60
  startLng: 139.7671,
38
61
  startHeight: 500,
39
62
  startHeading: Math.PI * 1.3
40
- }, p = 3, m = 1e3, h = class extends t {
63
+ }, S = 3, C = 1e3, w = class extends n {
41
64
  view;
42
65
  config;
66
+ collision;
43
67
  character;
44
68
  keys;
45
69
  keyToAction;
46
70
  handle = null;
47
71
  modelRef = null;
48
72
  animId = null;
73
+ placed = !1;
49
74
  lastTime = 0;
50
75
  state;
51
76
  listeners = /* @__PURE__ */ new Set();
77
+ actionListeners = /* @__PURE__ */ new Set();
52
78
  heldActions = /* @__PURE__ */ new Set();
53
- dashMultiplier = 1;
79
+ dashHeld = !1;
54
80
  orbitKeyHeld = !1;
55
81
  orbitLatched = !1;
56
82
  currentAnimState;
@@ -60,21 +86,33 @@ var u = {
60
86
  movementSuppressed = !1;
61
87
  boundKeyDown;
62
88
  boundKeyUp;
63
- _curPos = new l();
64
- _east = new l();
65
- _north = new l();
66
- _worldForward = new l();
67
- _offset = new l();
68
- _headingMatrix = new c();
69
- _characterFrame = new c();
89
+ _curPos = new f();
90
+ _east = new f();
91
+ _north = new f();
92
+ _worldForward = new f();
93
+ _offset = new f();
94
+ _probePos = new f();
95
+ _headingMatrix = new d();
96
+ _tiltMatrix = new d();
97
+ _characterFrame = new d();
98
+ cameraSlopePitch = 0;
99
+ slopeGradEast = 0;
100
+ slopeGradNorth = 0;
101
+ lastGroundSample;
102
+ unabsorbedGroundShift = 0;
103
+ settleVelocity = 0;
104
+ groundSurfaceHeight;
70
105
  constructor(e = {}) {
71
106
  super();
72
- let { character: t, keys: n, ...r } = e;
107
+ let { character: t, keys: n, collision: r, ...i } = e;
73
108
  this.config = {
74
- ...f,
109
+ ...x,
110
+ ...i
111
+ }, this.collision = {
112
+ ...h,
75
113
  ...r
76
114
  }, this.character = t ? this.resolveCharacter(t) : null, this.keys = {
77
- ...d,
115
+ ...m,
78
116
  ...n
79
117
  }, this.keyToAction = this.buildKeyMap(this.keys), this.modelHeading = this.config.startHeading, this.cameraHeading = this.config.startHeading, this.viewMode = this.config.initialView, this.currentAnimState = this.character ? this.character.animation.idleClip : null, this.boundKeyDown = this.onKeyDown.bind(this), this.boundKeyUp = this.onKeyUp.bind(this);
80
118
  }
@@ -91,27 +129,31 @@ var u = {
91
129
  }
92
130
  start() {
93
131
  if (!this.view || this.animId != null) return;
94
- this.animId = -1;
95
- let { startLat: e, startLng: t, startHeight: n, startHeading: i } = this.config, o = a({
96
- lat: r(e),
97
- lng: r(t),
132
+ if (this.animId = -1, document.addEventListener("keydown", this.boundKeyDown), document.addEventListener("keyup", this.boundKeyUp), this.placed) {
133
+ this.resumeLoop(), this.placeChaseCamera(this.state.lat, this.state.lng, this.state.alt, this.cameraHeading), this.applyModelVisibility();
134
+ return;
135
+ }
136
+ this.placed = !0;
137
+ let { startLat: e, startLng: t, startHeight: n, startHeading: r } = this.config, i = s({
138
+ lat: a(e),
139
+ lng: a(t),
98
140
  height: n
99
141
  });
100
- if (this.modelHeading = i, this.cameraHeading = i, this.character) {
101
- let { animation: e, modelRotationOffset: t, modelScale: n, castShadow: r, receiveShadow: a } = this.character;
142
+ if (this.modelHeading = r, this.cameraHeading = r, this.character) {
143
+ let { animation: e, modelRotationOffset: t, modelScale: n, castShadow: a, receiveShadow: o } = this.character;
102
144
  this.handle = this.view.addMesh({
103
145
  gltfModel: {
104
146
  url: this.character.modelUrl,
105
- castShadow: r,
106
- receiveShadow: a,
147
+ castShadow: a,
148
+ receiveShadow: o,
107
149
  animationEnabled: !0,
108
150
  animationAutoPlay: !0,
109
151
  animationActiveClip: e.idleClip,
110
- animationSpeed: e.speed,
152
+ animationSpeed: this.clipSpeed(e.idleClip),
111
153
  animationLoop: !0,
112
154
  animationCrossfadeDuration: e.crossfadeDuration
113
155
  },
114
- matrixWorld: this.composeCharacterFrame(o, i),
156
+ matrixWorld: this.composeCharacterFrame(i, r),
115
157
  rotation: {
116
158
  x: t.x,
117
159
  y: t.y,
@@ -123,27 +165,46 @@ var u = {
123
165
  z: n
124
166
  }
125
167
  }), this.modelRef = this.handle.ref, this.modelRef.on("load", () => {
126
- this.view && (this.lastTime = performance.now(), this.animId = requestAnimationFrame(this.tick));
168
+ !this.view || this.animId == null || this.resumeLoop();
127
169
  });
128
- } else this.lastTime = performance.now(), this.animId = requestAnimationFrame(this.tick);
129
- this.applyInitialCamera(), this.applyModelVisibility(), document.addEventListener("keydown", this.boundKeyDown), document.addEventListener("keyup", this.boundKeyUp);
170
+ } else this.resumeLoop();
171
+ this.applyInitialCamera(), this.applyModelVisibility();
172
+ }
173
+ stop() {
174
+ if (this.animId == null) return;
175
+ this.releaseControl(), this.view?.cameraFollow(!1), this.view?.cameraFreeLook(!1), this.playAnimation(this.character?.animation.idleClip);
176
+ let e = {
177
+ ...this.state,
178
+ speed: 0,
179
+ animationState: this.currentAnimState
180
+ };
181
+ this.hasStateChanged(this.state, e) && (this.state = e, this.notify());
182
+ }
183
+ releaseControl() {
184
+ this.animId != null && this.animId >= 0 && cancelAnimationFrame(this.animId), this.animId = null, document.removeEventListener("keydown", this.boundKeyDown), document.removeEventListener("keyup", this.boundKeyUp), this.heldActions.clear(), this.orbitKeyHeld = !1, this.orbitLatched = !1, this.dashHeld = !1;
185
+ }
186
+ resumeLoop() {
187
+ this.lastTime = performance.now(), this.animId = requestAnimationFrame(this.tick);
130
188
  }
131
189
  teleport(e) {
132
190
  if (!this.view) return;
133
- let { lng: t, lat: n, alt: i } = e, o = e.heading == null ? this.cameraHeading : e.heading;
134
- if (this.handle && this.character) {
135
- let e = a({
136
- lat: r(n),
137
- lng: r(t),
138
- height: i
191
+ let { lng: t, lat: n } = e, r = e.heading == null ? this.cameraHeading : e.heading, i = {
192
+ lat: a(n),
193
+ lng: a(t)
194
+ }, o = this.resolveGroundHeight(i, i, e.alt, 0);
195
+ if (this.updateSlopeTilt(i.lat, i.lng, o, 0), this.handle && this.character) {
196
+ let e = s({
197
+ lat: i.lat,
198
+ lng: i.lng,
199
+ height: o
139
200
  });
140
- this.handle.update({ matrixWorld: this.composeCharacterFrame(e, o) });
201
+ this.handle.update({ matrixWorld: this.composeCharacterFrame(e, r) });
141
202
  }
142
- this.modelHeading = o, this.cameraHeading = o, this.placeChaseCamera(n, t, i, o), this.state = {
203
+ this.modelHeading = r, this.cameraHeading = r, this.placeChaseCamera(n, t, o, r), this.state = {
143
204
  lng: t,
144
205
  lat: n,
145
- alt: i,
146
- heading: o,
206
+ alt: o,
207
+ heading: r,
147
208
  speed: 0,
148
209
  animationState: this.currentAnimState,
149
210
  mode: this.viewMode
@@ -155,6 +216,9 @@ var u = {
155
216
  onStateChange(e) {
156
217
  return this.listeners.add(e), () => this.listeners.delete(e);
157
218
  }
219
+ onAction(e) {
220
+ return this.actionListeners.add(e), () => this.actionListeners.delete(e);
221
+ }
158
222
  setViewMode(e) {
159
223
  this.viewMode !== e && (this.viewMode = e, this.state = {
160
224
  ...this.state,
@@ -167,18 +231,27 @@ var u = {
167
231
  setAllowCameraControl(e) {
168
232
  this.config.allowCameraControl = e;
169
233
  }
234
+ setCollision(e) {
235
+ this.collision = {
236
+ ...this.collision,
237
+ ...e
238
+ };
239
+ }
240
+ getCollision() {
241
+ return this.collision;
242
+ }
170
243
  setHeading(e) {
171
244
  if (!this.view) return;
172
- let { lat: t, lng: n, alt: i } = this.state;
245
+ let { lat: t, lng: n, alt: r } = this.state;
173
246
  if (this.modelHeading = e, this.cameraHeading = e, this.handle && this.character) {
174
- let o = a({
175
- lat: r(t),
176
- lng: r(n),
177
- height: i
247
+ let i = s({
248
+ lat: a(t),
249
+ lng: a(n),
250
+ height: r
178
251
  });
179
- this.handle.update({ matrixWorld: this.composeCharacterFrame(o, e) });
252
+ this.handle.update({ matrixWorld: this.composeCharacterFrame(i, e) });
180
253
  }
181
- this.isFreeCamera() || this.placeChaseCamera(t, n, i, e), this.state = {
254
+ this.isFreeCamera() || this.placeChaseCamera(t, n, r, e), this.state = {
182
255
  ...this.state,
183
256
  heading: e
184
257
  }, this.notify();
@@ -204,18 +277,34 @@ var u = {
204
277
  getFpvHeightOffset() {
205
278
  return this.config.fpvHeightOffset;
206
279
  }
280
+ setAnimationSpeed(e) {
281
+ this.character && (this.character.animation.speed = e), this.modelRef?.setAnimationSpeed(this.clipSpeed(this.currentAnimState));
282
+ }
283
+ getAnimationSpeed() {
284
+ return this.character?.animation.speed ?? 1;
285
+ }
286
+ get model() {
287
+ return this.handle;
288
+ }
289
+ clipSpeed(e) {
290
+ let t = this.character?.animation;
291
+ return t ? e === t.dashClip ? t.dashSpeed ?? t.speed ?? 1 : t.walkClip != null && e === t.walkClip ? t.walkSpeed ?? t.speed ?? 1 : t.idleSpeed ?? t.speed ?? 1 : 1;
292
+ }
207
293
  dispose() {
208
- this.animId != null && cancelAnimationFrame(this.animId), this.animId = null, document.removeEventListener("keydown", this.boundKeyDown), document.removeEventListener("keyup", this.boundKeyUp), this.handle &&= (this.handle.delete(), null), this.modelRef = null, this.heldActions.clear(), this.listeners.clear(), this.orbitKeyHeld = !1, this.orbitLatched = !1, this.dashMultiplier = 1, this.view = void 0;
294
+ this.releaseControl(), this.handle &&= (this.handle.delete(), null), this.modelRef = null, this.placed = !1, this.listeners.clear(), this.actionListeners.clear(), this.view = void 0;
295
+ }
296
+ playAnimation(e) {
297
+ !e || !this.character || !this.modelRef || e !== this.currentAnimState && (this.modelRef.crossFadeAnimation(this.currentAnimState ?? "", e, this.character.animation.crossfadeDuration), this.modelRef.setAnimationSpeed(this.clipSpeed(e)), this.currentAnimState = e);
209
298
  }
210
299
  resolveCharacter(e) {
211
300
  return {
212
301
  modelUrl: e.modelUrl,
213
302
  animation: e.animation,
214
303
  modelRotationOffset: e.modelRotationOffset ? {
215
- ...u,
304
+ ...p,
216
305
  ...e.modelRotationOffset
217
- } : u,
218
- modelScale: e.modelScale ?? p,
306
+ } : p,
307
+ modelScale: e.modelScale ?? S,
219
308
  hideModelInFpv: e.hideModelInFpv ?? !0,
220
309
  castShadow: e.castShadow ?? !1,
221
310
  receiveShadow: e.receiveShadow ?? !1
@@ -242,51 +331,145 @@ var u = {
242
331
  let { startLat: e, startLng: t, startHeight: n, startHeading: r } = this.config;
243
332
  this.placeChaseCamera(e, t, n, r);
244
333
  }
245
- placeChaseCamera(e, t, n, r) {
334
+ placeChaseCamera(e, t, n, r, i = 0) {
246
335
  if (!this.view) return;
247
- let { cameraDistance: i, cameraPitch: a, fpvPitch: o, fpvHeightOffset: s, fpvForwardOffset: c } = this.config, l = this.viewMode === "fpv", u = n + s;
248
- if (l) {
249
- let n = m, i = c + m, a = Math.tan(o) * n, s = this.advanceLatLng(e, t, r, i);
250
- this._offset.set(-Math.sin(r) * n, -Math.cos(r) * n, a), this.view.cameraFollow(!0, {
251
- lat: s.lat,
252
- lng: s.lng,
253
- height: u - a
336
+ let { cameraDistance: a, fpvPitch: o, fpvForwardOffset: s } = this.config, c = this.viewMode === "fpv", l = this.eyeHeightAt(n);
337
+ if (c) {
338
+ let a = C, c = s + C, u = this.followSlopeWithPitch(o, e, t, n, r, i), d = Math.tan(u) * a, f = this.advanceLatLng(e, t, r, c);
339
+ this._offset.set(-Math.sin(r) * a, -Math.cos(r) * a, d), this.view.cameraFollow(!0, {
340
+ lat: f.lat,
341
+ lng: f.lng,
342
+ height: l - d
254
343
  }, this._offset);
255
344
  return;
256
345
  }
257
- let d = i * Math.cos(a), f = i * Math.sin(a);
346
+ let u = this.followSlopeWithPitch(this.config.cameraPitch, e, t, n, r, i), d = a * Math.cos(u), f = a * Math.sin(u);
258
347
  this._offset.set(-Math.sin(r) * d, -Math.cos(r) * d, f), this.view.cameraFollow(!0, {
259
348
  lat: e,
260
349
  lng: t,
261
- height: u
350
+ height: l
262
351
  }, this._offset);
263
352
  }
353
+ followSlopeWithPitch(e, t, n, r, i, a) {
354
+ let { cameraDistance: o, cameraLerpSpeed: s } = this.config, { mode: c, cameraSlopeFollow: l } = this.collision, d = 0;
355
+ if (c !== "off" && l > 0) {
356
+ let e = this.terrainAlong(t, n, i, o), a = this.terrainAlong(t, n, i + Math.PI, o);
357
+ e !== void 0 && a !== void 0 && (d = u.clamp(Math.atan2(e - a, 2 * o) * l * this.groundedFactor(r, o), -v, v));
358
+ }
359
+ return this.cameraSlopePitch += (d - this.cameraSlopePitch) * b(s, a), e - this.cameraSlopePitch;
360
+ }
361
+ groundedFactor(e, t) {
362
+ let n = this.groundSurfaceHeight;
363
+ return n === void 0 ? 0 : u.clamp(1 - (e - n) / t, 0, 1);
364
+ }
365
+ terrainAlong(e, t, n, r) {
366
+ let i = this.advanceLatLng(e, t, n, r);
367
+ return this.sampleTerrain(a(i.lat), a(i.lng));
368
+ }
264
369
  composeCharacterFrame(e, t) {
265
- let n = i(e);
266
- return this._headingMatrix.makeRotationZ(-t), this._characterFrame.multiplyMatrices(n, this._headingMatrix);
370
+ let n = o(e);
371
+ this._headingMatrix.makeRotationZ(-t), this._characterFrame.multiplyMatrices(n, this._headingMatrix);
372
+ let r = this.slopeGradEast, i = this.slopeGradNorth;
373
+ if (r !== 0 || i !== 0) {
374
+ let e = Math.sin(t), n = Math.cos(t), a = this.collision.maxSlopeTilt, o = u.clamp(Math.atan(r * e + i * n), -a, a), s = u.clamp(-Math.atan(r * n - i * e), -a, a);
375
+ this._tiltMatrix.makeRotationX(o), this._characterFrame.multiply(this._tiltMatrix), this._tiltMatrix.makeRotationY(s), this._characterFrame.multiply(this._tiltMatrix);
376
+ }
377
+ return this._characterFrame;
378
+ }
379
+ eyeHeightAt(e) {
380
+ return e + this.config.fpvHeightOffset;
381
+ }
382
+ sampleTerrain(e, t) {
383
+ return this.view?.sampleTerrainHeight({
384
+ lat: e,
385
+ lng: t,
386
+ height: 0
387
+ });
388
+ }
389
+ resolveGroundHeight(e, t, n, r) {
390
+ let { mode: i, groundOffset: a } = this.collision;
391
+ if (i === "off") return this.forgetGroundSamples(), n;
392
+ let o = this.sampleTerrain(e.lat, e.lng);
393
+ if (o === void 0) return this.forgetGroundSamples(), n;
394
+ this.groundSurfaceHeight = o + a;
395
+ let s = this.groundSurfaceHeight - this.absorbGroundDataShift(e, t, o, n, r);
396
+ return i === "ground" ? s : Math.max(n, s);
397
+ }
398
+ absorbGroundDataShift(e, t, n, r, i) {
399
+ let a = this.lastGroundSample, o;
400
+ if (a === void 0) o = (this.sampleTerrain(t.lat, t.lng) ?? n) + this.collision.groundOffset - r;
401
+ else {
402
+ let e = this.sampleTerrain(a.lat, a.lng);
403
+ o = e === void 0 ? 0 : e - a.height;
404
+ }
405
+ let s = this.unabsorbedGroundShift + o, c = Math.sign(s);
406
+ i > 0 && (c !== Math.sign(this.settleVelocity) && (this.settleVelocity = 0), this.settleVelocity += c * g * i);
407
+ let l = i > 0 ? Math.abs(this.settleVelocity) * i : Math.abs(s);
408
+ return this.unabsorbedGroundShift = c * Math.max(0, Math.abs(s) - l), this.unabsorbedGroundShift === 0 && (this.settleVelocity = 0), this.lastGroundSample = {
409
+ lat: e.lat,
410
+ lng: e.lng,
411
+ height: n
412
+ }, this.unabsorbedGroundShift;
413
+ }
414
+ forgetGroundSamples() {
415
+ this.lastGroundSample = void 0, this.unabsorbedGroundShift = 0, this.settleVelocity = 0, this.groundSurfaceHeight = void 0;
416
+ }
417
+ updateSlopeTilt(e, t, n, r) {
418
+ let { mode: i, alignToSlope: a, slopeSampleDistance: o } = this.collision, s = 0, c = 0;
419
+ if (i !== "off" && a) {
420
+ let r = this.measureSlopeGradient(e, t);
421
+ if (!r) return;
422
+ let i = this.groundedFactor(n, o);
423
+ s = r.east * i, c = r.north * i;
424
+ } else if (this.slopeGradEast === 0 && this.slopeGradNorth === 0) return;
425
+ let l = b(_, r);
426
+ this.slopeGradEast += (s - this.slopeGradEast) * l, this.slopeGradNorth += (c - this.slopeGradNorth) * l;
427
+ }
428
+ measureSlopeGradient(e, t) {
429
+ let n = this.collision.slopeSampleDistance, r = s({
430
+ lat: e,
431
+ lng: t,
432
+ height: 0
433
+ }), i = o(r);
434
+ this._east.setFromMatrixColumn(i, 0).normalize(), this._north.setFromMatrixColumn(i, 1).normalize();
435
+ let a = 0, c = 0;
436
+ for (let { sin: e, cos: t } of y) {
437
+ this._probePos.copy(r).addScaledVector(this._east, e * n).addScaledVector(this._north, t * n);
438
+ let i = l(this._probePos), o = this.sampleTerrain(i.lat, i.lng);
439
+ if (o === void 0) return;
440
+ a += o * e, c += o * t;
441
+ }
442
+ let u = 2 / (y.length * n);
443
+ return {
444
+ east: a * u,
445
+ north: c * u
446
+ };
267
447
  }
268
- advanceLatLng(e, t, n, c) {
269
- let l = a({
270
- lat: r(e),
271
- lng: r(t),
448
+ advanceLatLng(e, t, n, r) {
449
+ let i = s({
450
+ lat: a(e),
451
+ lng: a(t),
272
452
  height: 0
273
- }), u = i(l);
274
- this._east.setFromMatrixColumn(u, 0).normalize(), this._north.setFromMatrixColumn(u, 1).normalize(), this._worldForward.copy(this._east).multiplyScalar(Math.sin(n)).addScaledVector(this._north, Math.cos(n)), l.addScaledVector(this._worldForward, c);
275
- let d = s(l);
453
+ }), u = o(i);
454
+ this._east.setFromMatrixColumn(u, 0).normalize(), this._north.setFromMatrixColumn(u, 1).normalize(), this._worldForward.copy(this._east).multiplyScalar(Math.sin(n)).addScaledVector(this._north, Math.cos(n)), i.addScaledVector(this._worldForward, r);
455
+ let d = l(i);
276
456
  return {
277
- lat: o(d.lat),
278
- lng: o(d.lng)
457
+ lat: c(d.lat),
458
+ lng: c(d.lng)
279
459
  };
280
460
  }
281
461
  notify() {
282
462
  for (let e of this.listeners) e(this.state);
283
463
  }
464
+ emitAction(e) {
465
+ for (let t of this.actionListeners) t(e);
466
+ }
284
467
  onKeyDown(e) {
285
468
  let t = e.target;
286
469
  if (t.tagName === "INPUT" || t.tagName === "TEXTAREA" || t.isContentEditable) return;
287
470
  let n = this.keyToAction.get(e.code);
288
471
  if (n !== void 0) {
289
- if (n === "toggleView") {
472
+ if (e.repeat || this.emitAction(n), n === "toggleView") {
290
473
  if (e.repeat) return;
291
474
  this.toggleViewMode();
292
475
  return;
@@ -297,7 +480,7 @@ var u = {
297
480
  }
298
481
  if (!this.movementSuppressed) {
299
482
  if (n === "dash") {
300
- this.dashMultiplier = 2.5;
483
+ this.dashHeld = !0;
301
484
  return;
302
485
  }
303
486
  this.isMovementAction(n) && (this.orbitLatched = !1), this.heldActions.add(n);
@@ -312,73 +495,73 @@ var u = {
312
495
  return;
313
496
  }
314
497
  if (t === "dash") {
315
- this.dashMultiplier = 1;
498
+ this.dashHeld = !1;
316
499
  return;
317
500
  }
318
501
  this.heldActions.delete(t);
319
502
  }
320
503
  }
321
504
  tick = (e) => {
322
- if (!this.view) return;
505
+ if (!this.view || this.animId == null) return;
323
506
  this.animId = requestAnimationFrame(this.tick);
324
507
  let t = Math.min((e - this.lastTime) / 1e3, .1);
325
508
  this.lastTime = e;
326
- let n = 0, c = 0, l = 0;
327
- this.heldActions.has("forward") && (c += 1), this.heldActions.has("backward") && --c, this.heldActions.has("turnLeft") && --n, this.heldActions.has("turnRight") && (n += 1), this.heldActions.has("ascend") && (l += 1), this.heldActions.has("descend") && --l;
328
- let { moveSpeed: u, rotationSpeed: d, altSpeed: f, minAlt: p, maxAlt: m, cameraLerpSpeed: h } = this.config;
329
- n !== 0 && (this.modelHeading += r(d * n));
330
- let g = this._curPos;
509
+ let n = 0, r = 0, i = 0;
510
+ this.heldActions.has("forward") && (r += 1), this.heldActions.has("backward") && --r, this.heldActions.has("turnLeft") && --n, this.heldActions.has("turnRight") && (n += 1), this.heldActions.has("ascend") && (i += 1), this.heldActions.has("descend") && --i;
511
+ let { moveSpeed: d, rotationSpeed: f, altSpeed: p, minAlt: m, maxAlt: h, cameraLerpSpeed: g } = this.config, _ = this.dashHeld ? this.config.dashSpeedMultiplier : 1;
512
+ n !== 0 && (this.modelHeading += a(f * n));
513
+ let v = this._curPos;
331
514
  if (this.handle && this.modelRef) {
332
515
  let e = this.modelRef.getWorldPosition();
333
516
  if (!e) return;
334
- g.copy(e);
335
- } else g.copy(a({
336
- lat: r(this.state.lat),
337
- lng: r(this.state.lng),
517
+ v.copy(e);
518
+ } else v.copy(s({
519
+ lat: a(this.state.lat),
520
+ lng: a(this.state.lng),
338
521
  height: this.state.alt
339
522
  }));
340
- let _ = i(g);
341
- this._east.setFromMatrixColumn(_, 0).normalize(), this._north.setFromMatrixColumn(_, 1).normalize();
342
- let v = s(g);
343
- this._worldForward.copy(this._east).multiplyScalar(Math.sin(this.modelHeading)).addScaledVector(this._north, Math.cos(this.modelHeading)), c !== 0 && g.addScaledVector(this._worldForward, u * this.dashMultiplier * t * c);
344
- let y = s(g), b = v.height + l * f * t, x = Math.max(p, Math.min(m, b)), S = o(y.lat), C = o(y.lng), w = x;
345
- if (this.handle && this.character) {
346
- let e = a({
347
- lat: y.lat,
348
- lng: y.lng,
349
- height: x
523
+ let y = o(v);
524
+ this._east.setFromMatrixColumn(y, 0).normalize(), this._north.setFromMatrixColumn(y, 1).normalize();
525
+ let x = l(v);
526
+ this._worldForward.copy(this._east).multiplyScalar(Math.sin(this.modelHeading)).addScaledVector(this._north, Math.cos(this.modelHeading)), r !== 0 && v.addScaledVector(this._worldForward, d * _ * t * r);
527
+ let S = l(v), C = this.collision.mode === "ground" ? x.height : u.clamp(x.height + i * p * t, m, h), w = this.resolveGroundHeight(S, x, C, t), T = c(S.lat), E = c(S.lng), D = w;
528
+ if (this.updateSlopeTilt(S.lat, S.lng, w, t), this.handle && this.character) {
529
+ let e = s({
530
+ lat: S.lat,
531
+ lng: S.lng,
532
+ height: w
350
533
  });
351
534
  this.handle.update({ matrixWorld: this.composeCharacterFrame(e, this.modelHeading) });
352
535
  }
353
- let T = this.modelHeading - this.cameraHeading;
354
- if (T -= Math.round(T / (Math.PI * 2)) * (Math.PI * 2), this.cameraHeading += T * Math.min(t * h, 1), this.isFreeCamera()) if (this.viewMode === "fpv") {
355
- let e = this.advanceLatLng(S, C, this.cameraHeading, this.config.fpvForwardOffset);
536
+ let O = this.modelHeading - this.cameraHeading;
537
+ if (O -= Math.round(O / (Math.PI * 2)) * (Math.PI * 2), this.cameraHeading += O * b(g, t), this.isFreeCamera()) if (this.viewMode === "fpv") {
538
+ let e = this.advanceLatLng(T, E, this.cameraHeading, this.config.fpvForwardOffset);
356
539
  this.view.cameraFreeLook(!0, {
357
540
  lat: e.lat,
358
541
  lng: e.lng,
359
- height: w + this.config.fpvHeightOffset
542
+ height: this.eyeHeightAt(D)
360
543
  });
361
544
  } else this.view.cameraFollow(!0, {
362
- lat: S,
363
- lng: C,
364
- height: w + this.config.fpvHeightOffset
545
+ lat: T,
546
+ lng: E,
547
+ height: this.eyeHeightAt(D)
365
548
  });
366
- else this.placeChaseCamera(S, C, w, this.cameraHeading);
367
- let E = c !== 0 || n !== 0 || l !== 0, D = E && this.dashMultiplier > 1, O = this.currentAnimState;
368
- if (this.character && this.modelRef) {
369
- let { animation: e } = this.character, t = e.walkClip ?? e.idleClip, n;
370
- n = D ? e.dashClip : E ? t : e.idleClip, n !== this.currentAnimState && (this.modelRef.crossFadeAnimation(this.currentAnimState ?? "", n, e.crossfadeDuration), this.currentAnimState = n), O = n;
549
+ else this.placeChaseCamera(T, E, D, this.cameraHeading, t);
550
+ let k = r !== 0 || n !== 0 || i !== 0, A = k && this.dashHeld, j = this.currentAnimState;
551
+ if (this.character) {
552
+ let { animation: e } = this.character, t = e.walkClip ?? e.idleClip;
553
+ j = A ? e.dashClip : k ? t : e.idleClip, this.playAnimation(j);
371
554
  }
372
- let k = {
373
- lng: C,
374
- lat: S,
375
- alt: w,
555
+ let M = {
556
+ lng: E,
557
+ lat: T,
558
+ alt: D,
376
559
  heading: this.modelHeading,
377
- speed: u * this.dashMultiplier,
378
- animationState: O,
560
+ speed: d * _,
561
+ animationState: j,
379
562
  mode: this.viewMode
380
563
  };
381
- this.hasStateChanged(this.state, k) && (this.state = k, this.notify());
564
+ this.hasStateChanged(this.state, M) && (this.state = M, this.notify());
382
565
  };
383
566
  hasStateChanged(e, t) {
384
567
  return e.lng !== t.lng || e.lat !== t.lat || e.alt !== t.alt || e.heading !== t.heading || e.speed !== t.speed || e.animationState !== t.animationState || e.mode !== t.mode;
@@ -386,10 +569,10 @@ var u = {
386
569
  };
387
570
  //#endregion
388
571
  //#region src/OverlayPlugin.ts
389
- function g(e, t, n) {
572
+ function T(e, t, n) {
390
573
  e.style.transform = `translate(${t}px, ${n}px)`, e.style.willChange = "transform";
391
574
  }
392
- var _ = 1e5, v = class extends t {
575
+ var E = 1e5, D = class extends n {
393
576
  view;
394
577
  maxDistance;
395
578
  positions = [];
@@ -397,7 +580,7 @@ var _ = 1e5, v = class extends t {
397
580
  listeners = /* @__PURE__ */ new Set();
398
581
  boundHandler;
399
582
  constructor(e) {
400
- super(), this.maxDistance = e?.maxDistance ?? _, this.boundHandler = this.handlePreRender.bind(this);
583
+ super(), this.maxDistance = e?.maxDistance ?? E, this.boundHandler = this.handlePreRender.bind(this);
401
584
  }
402
585
  async init(e, t) {
403
586
  this.view = e, e.on("preRender", this.boundHandler);
@@ -411,47 +594,47 @@ var _ = 1e5, v = class extends t {
411
594
  dispose() {
412
595
  this.view && this.view.off("preRender", this.boundHandler), this.listeners.clear(), this.positions = [], this.projected.clear();
413
596
  }
414
- worldToScreen(e, t, i) {
597
+ worldToScreen(e, t, n) {
415
598
  if (!this.view) return null;
416
- let o = a({
417
- lng: r(e),
418
- lat: r(t),
419
- height: i
420
- }), s = n({
599
+ let r = s({
600
+ lng: a(e),
601
+ lat: a(t),
602
+ height: n
603
+ }), o = i({
421
604
  width: this.view.screenSize.x,
422
605
  height: this.view.screenSize.y,
423
606
  pixelRatio: this.view.pixelRatio
424
- }, this.view.camera.raw, o);
425
- return s ? {
426
- x: s.x,
427
- y: s.y
607
+ }, this.view.camera.raw, r);
608
+ return o ? {
609
+ x: o.x,
610
+ y: o.y
428
611
  } : null;
429
612
  }
430
613
  handlePreRender() {
431
614
  if (!this.view) return;
432
- let e = this.view.camera.positionGeographic, t = a({
433
- lng: r(e.lng),
434
- lat: r(e.lat),
615
+ let e = this.view.camera.positionGeographic, t = s({
616
+ lng: a(e.lng),
617
+ lat: a(e.lat),
435
618
  height: e.height
436
619
  }), n = /* @__PURE__ */ new Map();
437
620
  for (let e of this.positions) {
438
- let i = a({
439
- lng: r(e.lng),
440
- lat: r(e.lat),
621
+ let r = s({
622
+ lng: a(e.lng),
623
+ lat: a(e.lat),
441
624
  height: e.alt
442
- }), o = t.distanceTo(i);
443
- if (o > this.maxDistance) continue;
444
- let s = this.worldToScreen(e.lng, e.lat, e.alt);
445
- s && n.set(e.id, {
446
- ...s,
447
- distance: o
625
+ }), i = t.distanceTo(r);
626
+ if (i > this.maxDistance) continue;
627
+ let o = this.worldToScreen(e.lng, e.lat, e.alt);
628
+ o && n.set(e.id, {
629
+ ...o,
630
+ distance: i
448
631
  });
449
632
  }
450
633
  this.projected = n;
451
- let i = { projected: this.projected };
452
- for (let e of this.listeners) e(i);
634
+ let r = { projected: this.projected };
635
+ for (let e of this.listeners) e(r);
453
636
  }
454
- }, y = "https://api.cesium.com/v1/assets", b = class extends t {
637
+ }, O = "https://api.cesium.com/v1/assets", k = class extends n {
455
638
  view;
456
639
  config;
457
640
  endpoint;
@@ -460,7 +643,7 @@ var _ = 1e5, v = class extends t {
460
643
  }
461
644
  async init(e, t) {
462
645
  this.view = e;
463
- let { assetId: n, accessToken: r, endpoint: i = y } = this.config, a = `${i}/${encodeURIComponent(String(n))}/endpoint?access_token=${encodeURIComponent(r)}`, o = await fetch(a);
646
+ let { assetId: n, accessToken: r, endpoint: i = O } = this.config, a = `${i}/${encodeURIComponent(String(n))}/endpoint?access_token=${encodeURIComponent(r)}`, o = await fetch(a);
464
647
  if (!o.ok) throw Error(`CesiumIonPlugin: failed to fetch asset ${n} endpoint (${o.status} ${o.statusText})`);
465
648
  let s = await o.json();
466
649
  this.endpoint = {
@@ -489,12 +672,19 @@ var _ = 1e5, v = class extends t {
489
672
  });
490
673
  return l.once("deleted", () => c.delete()), l;
491
674
  }
492
- }, x = /^3\.\d+\.\d+$/;
493
- function S(e) {
494
- if (typeof e.tilejson != "string" || !x.test(e.tilejson)) throw Error(`TileJsonPlugin: invalid or missing "tilejson" version field (got ${JSON.stringify(e.tilejson)}).`);
675
+ }, A = /^3\.\d+\.\d+$/, j = 512, M = "mapbox";
676
+ function N(e) {
677
+ if (typeof e.tilejson != "string" || !A.test(e.tilejson)) throw Error(`TileJsonPlugin: invalid or missing "tilejson" version field (got ${JSON.stringify(e.tilejson)}).`);
495
678
  if (!Array.isArray(e.tiles) || e.tiles.length === 0) throw Error("TileJsonPlugin: \"tiles\" must be a non-empty array of URL templates.");
496
679
  }
497
- var C = class extends t {
680
+ function P(e) {
681
+ switch (e) {
682
+ case "mapbox": return t();
683
+ case "terrarium": return r();
684
+ default: throw Error(`TileJsonPlugin: unsupported raster-dem encoding ${JSON.stringify(e)}. Supported encodings: "mapbox", "terrarium".`);
685
+ }
686
+ }
687
+ var F = class extends n {
498
688
  view;
499
689
  events = new e();
500
690
  credits = [];
@@ -514,27 +704,34 @@ var C = class extends t {
514
704
  let t = this.view;
515
705
  if (!t) throw Error("TileJsonPlugin: addSource() must be called after view.init().");
516
706
  let n = await this.fetchTileJson(e.url);
517
- S(n);
707
+ N(n);
518
708
  let [r, ...i] = n.tiles;
519
709
  i.length > 0 && console.warn(`TileJsonPlugin: TileJSON at ${e.url} lists ${n.tiles.length} mirror tile endpoints; Navara sources use a single URL, so only the first is used.`);
520
- let { minzoom: a, maxzoom: o, scheme: s } = n, c = e.id, l = e.type === "raster-tile" ? t.addSource({
521
- type: "raster-tile",
710
+ let a = e.minzoom ?? n.minzoom, o = e.maxzoom ?? n.maxzoom, s = e.scheme ?? n.scheme, c = e.id, l = {
522
711
  url: r,
523
712
  ...c === void 0 ? {} : { id: c },
713
+ ...o === void 0 ? {} : { maxZoom: o }
714
+ }, u = {
715
+ ...l,
524
716
  ...a === void 0 ? {} : { minZoom: a },
525
- ...o === void 0 ? {} : { maxZoom: o },
526
717
  ...s === "tms" ? { tms: !0 } : {}
718
+ }, d;
719
+ return d = e.type === "raster-tile" ? t.addSource({
720
+ type: "raster-tile",
721
+ ...u
722
+ }) : e.type === "raster-dem" ? t.addSource({
723
+ type: "raster-dem",
724
+ ...u,
725
+ tileSize: e.tileSize ?? n.tileSize ?? j,
726
+ elevationDecoder: P(e.encoding ?? n.encoding ?? M)
527
727
  }) : t.addSource({
528
728
  type: "vector-tile",
529
- url: r,
530
- ...c === void 0 ? {} : { id: c },
531
- ...o === void 0 ? {} : { maxZoom: o }
532
- });
533
- return n.attribution && this.addCredit(n.attribution), this.events.emit("loaded", {
534
- source: l,
729
+ ...l
730
+ }), n.attribution && this.addCredit(n.attribution), this.events.emit("loaded", {
731
+ source: d,
535
732
  tilejson: n,
536
733
  attribution: n.attribution
537
- }), l;
734
+ }), d;
538
735
  }
539
736
  dispose() {
540
737
  let e = this.view?.attribution;
@@ -550,4 +747,4 @@ var C = class extends t {
550
747
  }
551
748
  };
552
749
  //#endregion
553
- export { b as CesiumIonPlugin, v as OverlayPlugin, h as PersonViewPlugin, C as TileJsonPlugin, g as moveOverlayElement };
750
+ export { k as CesiumIonPlugin, D as OverlayPlugin, w as PersonViewPlugin, F as TileJsonPlugin, T as moveOverlayElement };