mage-engine 3.23.38 → 3.23.40

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.
Files changed (2) hide show
  1. package/dist/mage.js +449 -219
  2. package/package.json +1 -1
package/dist/mage.js CHANGED
@@ -54641,7 +54641,8 @@ let Keyboard = /*#__PURE__*/function (_EventDispatcher) {
54641
54641
  TYPE: "CAMERA",
54642
54642
  SUBTYPES: {
54643
54643
  DEFAULT: "CAMERA.SUBTYPE.DEFAULT",
54644
- MAIN: "CAMERA.SUBTYPE.MAIN"
54644
+ MAIN: "CAMERA.SUBTYPE.MAIN",
54645
+ GAME: "CAMERA.SUBTYPE.GAME"
54645
54646
  }
54646
54647
  },
54647
54648
  MESH: {
@@ -54736,7 +54737,7 @@ let Keyboard = /*#__PURE__*/function (_EventDispatcher) {
54736
54737
  UNKNOWN: "UNKNOWN"
54737
54738
  };
54738
54739
  const FLAT_ENTITY_TYPES = [ENTITY_TYPES.SCENE.TYPE, ENTITY_TYPES.CAMERA.TYPE, ENTITY_TYPES.MESH.TYPE, ENTITY_TYPES.LABEL.TYPE, ENTITY_TYPES.LIGHT.TYPE, ENTITY_TYPES.AUDIO.TYPE, ENTITY_TYPES.MODEL.TYPE, ENTITY_TYPES.SPRITE.TYPE, ENTITY_TYPES.PARTICLE.TYPE, ENTITY_TYPES.SCENERY.TYPE, ENTITY_TYPES.HELPER.TYPE, ENTITY_TYPES.UNKNOWN];
54739
- const FLAT_ENTITY_SUBTYPES = [ENTITY_TYPES.SCENE.SUBTYPES.DEFAULT, ENTITY_TYPES.CAMERA.SUBTYPES.DEFAULT, ENTITY_TYPES.CAMERA.SUBTYPES.MAIN, ENTITY_TYPES.MESH.SUBTYPES.DEFAULT, ENTITY_TYPES.MESH.SUBTYPES.BOX, ENTITY_TYPES.MESH.SUBTYPES.SPHERE, ENTITY_TYPES.MESH.SUBTYPES.PLANE, ENTITY_TYPES.MESH.SUBTYPES.CYLINDER, ENTITY_TYPES.MESH.SUBTYPES.CONE, ENTITY_TYPES.MESH.SUBTYPES.CUBE, ENTITY_TYPES.MESH.SUBTYPES.LINE, ENTITY_TYPES.MESH.SUBTYPES.CURVE_LINE, ENTITY_TYPES.MESH.SUBTYPES.AXES, ENTITY_TYPES.MESH.SUBTYPES.GRID, ENTITY_TYPES.MESH.SUBTYPES.TARGET, ENTITY_TYPES.LABEL.SUBTYPES.DEFAULT, ENTITY_TYPES.LIGHT.SUBTYPES.DEFAULT, ENTITY_TYPES.LIGHT.SUBTYPES.AMBIENT, ENTITY_TYPES.LIGHT.SUBTYPES.SUN, ENTITY_TYPES.LIGHT.SUBTYPES.HEMISPHERE, ENTITY_TYPES.LIGHT.SUBTYPES.POINT, ENTITY_TYPES.LIGHT.SUBTYPES.SPOT, ENTITY_TYPES.AUDIO.SUBTYPES.DEFAULT, ENTITY_TYPES.AUDIO.SUBTYPES.DIRECTIONAL, ENTITY_TYPES.AUDIO.SUBTYPES.AMBIENT, ENTITY_TYPES.MODEL.SUBTYPES.DEFAULT, ENTITY_TYPES.SPRITE.SUBTYPES.DEFAULT, ENTITY_TYPES.SPRITE.SUBTYPES.ANIMATED_SPRITE, ENTITY_TYPES.PARTICLE.SUBTYPES.DEFAULT, ENTITY_TYPES.PARTICLE.SUBTYPES.EMITTER, ENTITY_TYPES.PARTICLE.SUBTYPES.SYSTEM, ENTITY_TYPES.PARTICLE.SUBTYPES.EMITTER_GROUP, ENTITY_TYPES.PARTICLE.SUBTYPES.PROTON_EMITTER, ENTITY_TYPES.SCENERY.SUBTYPES.DEFAULT, ENTITY_TYPES.SCENERY.SUBTYPES.SKY, ENTITY_TYPES.SCENERY.SUBTYPES.SKYBOX, ENTITY_TYPES.HELPER.SUBTYPES.GRID, ENTITY_TYPES.HELPER.SUBTYPES.AXES, ENTITY_TYPES.HELPER.SUBTYPES.HELPER_SPRITE];
54740
+ const FLAT_ENTITY_SUBTYPES = [ENTITY_TYPES.SCENE.SUBTYPES.DEFAULT, ENTITY_TYPES.CAMERA.SUBTYPES.DEFAULT, ENTITY_TYPES.CAMERA.SUBTYPES.MAIN, ENTITY_TYPES.CAMERA.SUBTYPES.GAME, ENTITY_TYPES.MESH.SUBTYPES.DEFAULT, ENTITY_TYPES.MESH.SUBTYPES.BOX, ENTITY_TYPES.MESH.SUBTYPES.SPHERE, ENTITY_TYPES.MESH.SUBTYPES.PLANE, ENTITY_TYPES.MESH.SUBTYPES.CYLINDER, ENTITY_TYPES.MESH.SUBTYPES.CONE, ENTITY_TYPES.MESH.SUBTYPES.CUBE, ENTITY_TYPES.MESH.SUBTYPES.LINE, ENTITY_TYPES.MESH.SUBTYPES.CURVE_LINE, ENTITY_TYPES.MESH.SUBTYPES.AXES, ENTITY_TYPES.MESH.SUBTYPES.GRID, ENTITY_TYPES.MESH.SUBTYPES.TARGET, ENTITY_TYPES.LABEL.SUBTYPES.DEFAULT, ENTITY_TYPES.LIGHT.SUBTYPES.DEFAULT, ENTITY_TYPES.LIGHT.SUBTYPES.AMBIENT, ENTITY_TYPES.LIGHT.SUBTYPES.SUN, ENTITY_TYPES.LIGHT.SUBTYPES.HEMISPHERE, ENTITY_TYPES.LIGHT.SUBTYPES.POINT, ENTITY_TYPES.LIGHT.SUBTYPES.SPOT, ENTITY_TYPES.AUDIO.SUBTYPES.DEFAULT, ENTITY_TYPES.AUDIO.SUBTYPES.DIRECTIONAL, ENTITY_TYPES.AUDIO.SUBTYPES.AMBIENT, ENTITY_TYPES.MODEL.SUBTYPES.DEFAULT, ENTITY_TYPES.SPRITE.SUBTYPES.DEFAULT, ENTITY_TYPES.SPRITE.SUBTYPES.ANIMATED_SPRITE, ENTITY_TYPES.PARTICLE.SUBTYPES.DEFAULT, ENTITY_TYPES.PARTICLE.SUBTYPES.EMITTER, ENTITY_TYPES.PARTICLE.SUBTYPES.SYSTEM, ENTITY_TYPES.PARTICLE.SUBTYPES.EMITTER_GROUP, ENTITY_TYPES.PARTICLE.SUBTYPES.PROTON_EMITTER, ENTITY_TYPES.SCENERY.SUBTYPES.DEFAULT, ENTITY_TYPES.SCENERY.SUBTYPES.SKY, ENTITY_TYPES.SCENERY.SUBTYPES.SKYBOX, ENTITY_TYPES.HELPER.SUBTYPES.GRID, ENTITY_TYPES.HELPER.SUBTYPES.AXES, ENTITY_TYPES.HELPER.SUBTYPES.HELPER_SPRITE];
54740
54741
  const ENTITY_EVENTS = {
54741
54742
  DISPOSE: "DISPOSE",
54742
54743
  STATE_MACHINE: {
@@ -55521,6 +55522,7 @@ const BEFORE_UNLOAD = "beforeunload";
55521
55522
  const HASH_CHANGE = "hashchange";
55522
55523
  const TAGS = {
55523
55524
  HELPER: "TAGS.HELPER",
55525
+ CAMERA_HELPER: "TAGS.CAMERA_HELPER",
55524
55526
  LIGHTS: {
55525
55527
  HOLDER: "TAGS.LIGHTS.HOLDER",
55526
55528
  HELPER: "TAGS.LIGHTS.HELPER",
@@ -55562,13 +55564,18 @@ const resolveSinglePath = path => {
55562
55564
  // If already a full URL or already contains the API path, return as-is
55563
55565
  if (isAlreadyResolved$2(path)) {
55564
55566
  return path;
55567
+ } // Root-relative paths (starting with /) are served from the public folder
55568
+ // and should not be modified with base URL
55569
+
55570
+
55571
+ if (path && path.startsWith("/")) {
55572
+ return path;
55565
55573
  }
55566
55574
 
55567
55575
  const baseUrl = env.MAGE_ASSETS_BASE_URL;
55568
55576
 
55569
55577
  if (baseUrl) {
55570
- const cleanPath = path.startsWith("/") ? path.slice(1) : path;
55571
- return `${baseUrl}/${cleanPath}`;
55578
+ return `${baseUrl}/${path}`;
55572
55579
  } // Warn if path contains colon (could be mistaken for protocol) and no base URL is set
55573
55580
 
55574
55581
 
@@ -56793,9 +56800,12 @@ var Physics$1 = new Physics();let Scene = /*#__PURE__*/function () {
56793
56800
  key: "getHierarchy",
56794
56801
  value: function getHierarchy() {
56795
56802
  let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
56803
+ const camera = this.getCamera(); // Only include camera in hierarchy if it's serializable (scene camera is not)
56804
+
56805
+ const cameraChildren = camera && camera.isSerializable() ? [camera.getHierarchy(options)] : [];
56796
56806
  return [{
56797
56807
  element: this.toJSON(options.parseJSON),
56798
- children: [this.getCamera().getHierarchy(options), ...this.elements.filter(e => !e.hasParent() && !e.isHelper() && e.isSerializable()).map(e => e.getHierarchy(options))]
56808
+ children: [...cameraChildren, ...this.elements.filter(e => !e.hasParent() && !e.isHelper() && e.isSerializable()).map(e => e.getHierarchy(options))]
56799
56809
  }];
56800
56810
  }
56801
56811
  }, {
@@ -58135,7 +58145,7 @@ function applyMiddleware() {
58135
58145
 
58136
58146
  var thunk = createThunkMiddleware();
58137
58147
  thunk.withExtraArgument = createThunkMiddleware;var name = "mage-engine";
58138
- var version$1 = "3.23.38";
58148
+ var version$1 = "3.23.40";
58139
58149
  var description = "A WebGL Javascript Game Engine, built on top of THREE.js and many other libraries.";
58140
58150
  var main = "dist/mage.js";
58141
58151
  var author$1 = {
@@ -62989,7 +62999,203 @@ let Element$1 = /*#__PURE__*/function (_Entity) {
62989
62999
  }]);
62990
63000
 
62991
63001
  return Element;
62992
- }(Entity);let Camera = /*#__PURE__*/function (_Entity) {
63002
+ }(Entity);const validateAnisotropy = anisotropy => {
63003
+ const max = Scene$1.getRenderer().capabilities.getMaxAnisotropy();
63004
+ return cap(anisotropy, max);
63005
+ };
63006
+
63007
+ let Sprite = /*#__PURE__*/function (_Element) {
63008
+ _inherits(Sprite, _Element);
63009
+
63010
+ var _super = _createSuper(Sprite);
63011
+
63012
+ function Sprite() {
63013
+ var _this;
63014
+
63015
+ let width = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 20;
63016
+ let height = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 20;
63017
+ let spriteTexture = arguments.length > 2 ? arguments[2] : undefined;
63018
+ let options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
63019
+
63020
+ _classCallCheck(this, Sprite);
63021
+
63022
+ _this = _super.call(this, {
63023
+ width,
63024
+ height,
63025
+ spriteTexture,
63026
+ ...options
63027
+ });
63028
+ const {
63029
+ anisotropy = 1,
63030
+ sizeAttenuation = true,
63031
+ depthTest = true,
63032
+ depthWrite = true,
63033
+ ...rest
63034
+ } = options;
63035
+ const texture = Images$1.get(spriteTexture);
63036
+
63037
+ _this.recordTexture(spriteTexture, TEXTURES.MAP);
63038
+
63039
+ _this.width = width;
63040
+ _this.height = height;
63041
+ _this.spriteTexture = spriteTexture;
63042
+ const material = new SpriteMaterial({
63043
+ map: texture,
63044
+ ...rest
63045
+ });
63046
+ const body = new Sprite$1(material);
63047
+
63048
+ _this.setBody({
63049
+ body
63050
+ });
63051
+
63052
+ _this.setAnisotropy(anisotropy);
63053
+
63054
+ _this.setWidth(width);
63055
+
63056
+ _this.setHeight(height);
63057
+
63058
+ _this.setSizeAttenuation(sizeAttenuation);
63059
+
63060
+ _this.setDepthTest(depthTest);
63061
+
63062
+ _this.setDepthWrite(depthWrite);
63063
+
63064
+ _this.setEntityType(ENTITY_TYPES.SPRITE.TYPE);
63065
+
63066
+ _this.setEntitySubtype(ENTITY_TYPES.SPRITE.SUBTYPES.DEFAULT);
63067
+
63068
+ return _this;
63069
+ }
63070
+
63071
+ _createClass(Sprite, [{
63072
+ key: "getRotation",
63073
+ value: function getRotation() {
63074
+ return this.getBody().material.rotation;
63075
+ }
63076
+ }, {
63077
+ key: "setRotation",
63078
+ value: function setRotation() {
63079
+ let rotation = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.getRotation();
63080
+ const numericRotation = Number(rotation) || 0;
63081
+ this.setData("rotation", numericRotation);
63082
+ this.getBody().material.rotation = numericRotation;
63083
+ }
63084
+ }, {
63085
+ key: "setWidth",
63086
+ value: function setWidth() {
63087
+ let width = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.width;
63088
+ const numericWidth = Number(width) || 1;
63089
+ this.setData("width", numericWidth);
63090
+ this.getBody().scale.x = numericWidth;
63091
+ }
63092
+ }, {
63093
+ key: "setHeight",
63094
+ value: function setHeight() {
63095
+ let height = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.height;
63096
+ const numericHeight = Number(height) || 1;
63097
+ this.setData("height", numericHeight);
63098
+ this.getBody().scale.y = numericHeight;
63099
+ }
63100
+ }, {
63101
+ key: "setAnisotropy",
63102
+ value: function setAnisotropy() {
63103
+ let anisotropy = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
63104
+ const numericAnisotropy = Number(anisotropy) || 1;
63105
+ this.setData("anisotropy", numericAnisotropy);
63106
+ this.getTexture(TEXTURES.MAP).anisotropy = validateAnisotropy(numericAnisotropy);
63107
+ }
63108
+ }, {
63109
+ key: "setSizeAttenuation",
63110
+ value: function setSizeAttenuation() {
63111
+ let attenuation = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
63112
+ this.setData("sizeAttenuation", attenuation);
63113
+ this.getBody().material.sizeAttenuation = attenuation;
63114
+ }
63115
+ }, {
63116
+ key: "setDepthTest",
63117
+ value: function setDepthTest() {
63118
+ let depthTest = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
63119
+ this.setData("depthTest", depthTest);
63120
+ this.getBody().material.depthTest = depthTest;
63121
+ }
63122
+ }, {
63123
+ key: "setDepthWrite",
63124
+ value: function setDepthWrite() {
63125
+ let depthWrite = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
63126
+ this.setData("depthWrite", depthWrite);
63127
+ this.getBody().material.depthWrite = depthWrite;
63128
+ }
63129
+ }, {
63130
+ key: "toJSON",
63131
+ value: function toJSON() {
63132
+ let parseJSON = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
63133
+
63134
+ if (this.isSerializable()) {
63135
+ return { ..._get(_getPrototypeOf(Sprite.prototype), "toJSON", this).call(this, parseJSON),
63136
+ width: this.width,
63137
+ height: this.height,
63138
+ spriteTexture: this.spriteTexture,
63139
+ anisotropy: this.getBody().material.anisotropy,
63140
+ sizeAttenuation: this.getBody().material.sizeAttenuation,
63141
+ depthTest: this.getBody().material.depthTest,
63142
+ depthWrite: this.getBody().material.depthWrite
63143
+ };
63144
+ }
63145
+ }
63146
+ }], [{
63147
+ key: "create",
63148
+ value: function create() {
63149
+ let data = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
63150
+ const {
63151
+ width,
63152
+ height,
63153
+ spriteTexture,
63154
+ options
63155
+ } = data;
63156
+ return new Sprite(width, height, spriteTexture, options);
63157
+ }
63158
+ }]);
63159
+
63160
+ return Sprite;
63161
+ }(Element$1);let HelperSprite = /*#__PURE__*/function (_Sprite) {
63162
+ _inherits(HelperSprite, _Sprite);
63163
+
63164
+ var _super = _createSuper(HelperSprite);
63165
+
63166
+ function HelperSprite() {
63167
+ var _this;
63168
+
63169
+ _classCallCheck(this, HelperSprite);
63170
+
63171
+ for (var _len = arguments.length, options = new Array(_len), _key = 0; _key < _len; _key++) {
63172
+ options[_key] = arguments[_key];
63173
+ }
63174
+
63175
+ _this = _super.call(this, ...options);
63176
+ _this.helperTarget = undefined;
63177
+
63178
+ _this.setEntityType(ENTITY_TYPES.HELPER.TYPE);
63179
+
63180
+ _this.setEntitySubtype(ENTITY_TYPES.HELPER.SUBTYPES.HELPER_SPRITE);
63181
+
63182
+ return _this;
63183
+ }
63184
+
63185
+ _createClass(HelperSprite, [{
63186
+ key: "setHelperTarget",
63187
+ value: function setHelperTarget(element) {
63188
+ this.helperTarget = element;
63189
+ }
63190
+ }, {
63191
+ key: "getHelperTarget",
63192
+ value: function getHelperTarget() {
63193
+ return this.helperTarget;
63194
+ }
63195
+ }]);
63196
+
63197
+ return HelperSprite;
63198
+ }(Sprite);let Camera = /*#__PURE__*/function (_Entity) {
62993
63199
  _inherits(Camera, _Entity);
62994
63200
 
62995
63201
  var _super = _createSuper(Camera);
@@ -63006,12 +63212,16 @@ let Element$1 = /*#__PURE__*/function (_Entity) {
63006
63212
  fov = Config$1.camera().fov,
63007
63213
  ratio = Config$1.screen().ratio,
63008
63214
  near = Config$1.camera().near,
63009
- far = Config$1.camera().far
63215
+ far = Config$1.camera().far,
63216
+ serializable = true
63010
63217
  } = options;
63011
63218
  _this = _super.call(this, {
63012
- name
63219
+ name,
63220
+ serializable
63013
63221
  });
63014
- _this.options = options;
63222
+
63223
+ _this.extendOptions(options);
63224
+
63015
63225
  const body = new PerspectiveCamera(fov, ratio, near, far);
63016
63226
 
63017
63227
  _this.setBody({
@@ -63022,15 +63232,73 @@ let Element$1 = /*#__PURE__*/function (_Entity) {
63022
63232
 
63023
63233
  _this.setEntitySubtype(ENTITY_TYPES.CAMERA.SUBTYPES.MAIN);
63024
63234
 
63025
- _this.setName(name);
63235
+ _this.setName(name); // Helper body for this camera
63236
+
63026
63237
 
63238
+ _this.isUsingHelper = false; // Holder body representing the camera (for selection in editor)
63239
+
63240
+ _this.holder = null; // THREE.js CameraHelper for visual feedback
63241
+
63242
+ _this.helper = null;
63027
63243
  return _this;
63028
63244
  }
63029
63245
 
63030
63246
  _createClass(Camera, [{
63247
+ key: "hasHolder",
63248
+ value: function hasHolder() {
63249
+ return !!this.holder;
63250
+ }
63251
+ }, {
63252
+ key: "usingHelper",
63253
+ value: function usingHelper() {
63254
+ return this.isUsingHelper;
63255
+ }
63256
+ }, {
63257
+ key: "addHolder",
63258
+ value: function addHolder() {
63259
+ let name = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : "cameraholder";
63260
+ let size = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0.05;
63261
+ const holderSprite = new HelperSprite(size, size, name, {
63262
+ name
63263
+ });
63264
+
63265
+ if (holderSprite) {
63266
+ holderSprite.setSizeAttenuation(false);
63267
+ holderSprite.setDepthTest(false);
63268
+ holderSprite.setDepthWrite(false);
63269
+ holderSprite.setSerializable(false);
63270
+ holderSprite.setPosition(this.getPosition());
63271
+ holderSprite.addTags([TAGS.HELPER, TAGS.CAMERA_HELPER, name]);
63272
+ holderSprite.setHelperTarget(this);
63273
+ this.holder = holderSprite;
63274
+ return true;
63275
+ }
63276
+
63277
+ console.warn("[Mage] Camera holder texture not found");
63278
+ return false;
63279
+ }
63280
+ }, {
63281
+ key: "addHelpers",
63282
+ value: function addHelpers() {
63283
+ let {
63284
+ holderName = "cameraholder",
63285
+ holderSize = 0.05
63286
+ } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
63287
+ // Add THREE.js CameraHelper for visual feedback
63288
+ this.helper = new CameraHelper(this.getBody());
63289
+ Scene$1.add(this.helper, null, false); // Add holder sprite for selection
63290
+
63291
+ this.addHolder(holderName, holderSize);
63292
+ this.isUsingHelper = true;
63293
+ }
63294
+ }, {
63031
63295
  key: "getPosition",
63032
63296
  value: function getPosition() {
63033
- return this.body.position;
63297
+ return {
63298
+ x: this.body.position.x,
63299
+ y: this.body.position.y,
63300
+ z: this.body.position.z
63301
+ };
63034
63302
  }
63035
63303
  }, {
63036
63304
  key: "getDirection",
@@ -63058,6 +63326,118 @@ let Element$1 = /*#__PURE__*/function (_Entity) {
63058
63326
  } = position;
63059
63327
  this.body.lookAt(x, y, z);
63060
63328
  }
63329
+ }, {
63330
+ key: "setPosition",
63331
+ value: function setPosition(where) {
63332
+ let {
63333
+ updateHolder = true
63334
+ } = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
63335
+ const currentPos = this.getPosition();
63336
+ const position = {
63337
+ x: currentPos.x,
63338
+ y: currentPos.y,
63339
+ z: currentPos.z,
63340
+ ...where
63341
+ };
63342
+ const {
63343
+ x,
63344
+ y,
63345
+ z
63346
+ } = position;
63347
+
63348
+ if (this.hasBody()) {
63349
+ this.body.position.set(x, y, z);
63350
+ }
63351
+
63352
+ if (this.hasHolder() && updateHolder) {
63353
+ this.holder.setPosition({
63354
+ x,
63355
+ y,
63356
+ z
63357
+ });
63358
+ }
63359
+ }
63360
+ }, {
63361
+ key: "update",
63362
+ value: function update(dt) {
63363
+ _get(_getPrototypeOf(Camera.prototype), "update", this) && _get(_getPrototypeOf(Camera.prototype), "update", this).call(this, dt); // Update the THREE.js CameraHelper
63364
+
63365
+ if (this.usingHelper() && this.helper) {
63366
+ this.helper.update();
63367
+ } // Sync camera position from holder (when user drags the holder)
63368
+
63369
+
63370
+ if (this.hasHolder()) {
63371
+ // Read directly from the holder's THREE.js body position
63372
+ const holderBody = this.holder.getBody();
63373
+ const holderPos = {
63374
+ x: holderBody.position.x,
63375
+ y: holderBody.position.y,
63376
+ z: holderBody.position.z
63377
+ };
63378
+ const cameraPos = this.getPosition(); // Only update if positions differ significantly
63379
+
63380
+ const threshold = 0.001;
63381
+
63382
+ if (Math.abs(holderPos.x - cameraPos.x) > threshold || Math.abs(holderPos.y - cameraPos.y) > threshold || Math.abs(holderPos.z - cameraPos.z) > threshold) {
63383
+ this.setPosition(holderPos, {
63384
+ updateHolder: false
63385
+ });
63386
+ }
63387
+ }
63388
+ }
63389
+ }, {
63390
+ key: "getFov",
63391
+ value: function getFov() {
63392
+ return this.getBody().fov;
63393
+ }
63394
+ }, {
63395
+ key: "setFov",
63396
+ value: function setFov(fov) {
63397
+ const num = Number(fov);
63398
+ const numericFov = Number.isFinite(num) ? num : 75;
63399
+ this.getBody().fov = numericFov;
63400
+ this.getBody().updateProjectionMatrix();
63401
+ }
63402
+ }, {
63403
+ key: "getNear",
63404
+ value: function getNear() {
63405
+ return this.getBody().near;
63406
+ }
63407
+ }, {
63408
+ key: "setNear",
63409
+ value: function setNear(near) {
63410
+ const num = Number(near);
63411
+ const numericNear = Number.isFinite(num) ? num : 0.1;
63412
+ this.getBody().near = numericNear;
63413
+ this.getBody().updateProjectionMatrix();
63414
+ }
63415
+ }, {
63416
+ key: "getFar",
63417
+ value: function getFar() {
63418
+ return this.getBody().far;
63419
+ }
63420
+ }, {
63421
+ key: "setFar",
63422
+ value: function setFar(far) {
63423
+ const num = Number(far);
63424
+ const numericFar = Number.isFinite(num) ? num : 3000000;
63425
+ this.getBody().far = numericFar;
63426
+ this.getBody().updateProjectionMatrix();
63427
+ }
63428
+ }, {
63429
+ key: "toJSON",
63430
+ value: function toJSON() {
63431
+ let parseJSON = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
63432
+
63433
+ if (this.isSerializable()) {
63434
+ return { ..._get(_getPrototypeOf(Camera.prototype), "toJSON", this).call(this, parseJSON),
63435
+ fov: this.getFov(),
63436
+ near: this.getNear(),
63437
+ far: this.getFar()
63438
+ };
63439
+ }
63440
+ }
63061
63441
  }]);
63062
63442
 
63063
63443
  return Camera;
@@ -63778,203 +64158,7 @@ let Plane = /*#__PURE__*/function (_Element) {
63778
64158
  }]);
63779
64159
 
63780
64160
  return Box;
63781
- }(Element$1);const validateAnisotropy = anisotropy => {
63782
- const max = Scene$1.getRenderer().capabilities.getMaxAnisotropy();
63783
- return cap(anisotropy, max);
63784
- };
63785
-
63786
- let Sprite = /*#__PURE__*/function (_Element) {
63787
- _inherits(Sprite, _Element);
63788
-
63789
- var _super = _createSuper(Sprite);
63790
-
63791
- function Sprite() {
63792
- var _this;
63793
-
63794
- let width = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 20;
63795
- let height = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 20;
63796
- let spriteTexture = arguments.length > 2 ? arguments[2] : undefined;
63797
- let options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
63798
-
63799
- _classCallCheck(this, Sprite);
63800
-
63801
- _this = _super.call(this, {
63802
- width,
63803
- height,
63804
- spriteTexture,
63805
- ...options
63806
- });
63807
- const {
63808
- anisotropy = 1,
63809
- sizeAttenuation = true,
63810
- depthTest = true,
63811
- depthWrite = true,
63812
- ...rest
63813
- } = options;
63814
- const texture = Images$1.get(spriteTexture);
63815
-
63816
- _this.recordTexture(spriteTexture, TEXTURES.MAP);
63817
-
63818
- _this.width = width;
63819
- _this.height = height;
63820
- _this.spriteTexture = spriteTexture;
63821
- const material = new SpriteMaterial({
63822
- map: texture,
63823
- ...rest
63824
- });
63825
- const body = new Sprite$1(material);
63826
-
63827
- _this.setBody({
63828
- body
63829
- });
63830
-
63831
- _this.setAnisotropy(anisotropy);
63832
-
63833
- _this.setWidth(width);
63834
-
63835
- _this.setHeight(height);
63836
-
63837
- _this.setSizeAttenuation(sizeAttenuation);
63838
-
63839
- _this.setDepthTest(depthTest);
63840
-
63841
- _this.setDepthWrite(depthWrite);
63842
-
63843
- _this.setEntityType(ENTITY_TYPES.SPRITE.TYPE);
63844
-
63845
- _this.setEntitySubtype(ENTITY_TYPES.SPRITE.SUBTYPES.DEFAULT);
63846
-
63847
- return _this;
63848
- }
63849
-
63850
- _createClass(Sprite, [{
63851
- key: "getRotation",
63852
- value: function getRotation() {
63853
- return this.getBody().material.rotation;
63854
- }
63855
- }, {
63856
- key: "setRotation",
63857
- value: function setRotation() {
63858
- let rotation = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.getRotation();
63859
- const numericRotation = Number(rotation) || 0;
63860
- this.setData("rotation", numericRotation);
63861
- this.getBody().material.rotation = numericRotation;
63862
- }
63863
- }, {
63864
- key: "setWidth",
63865
- value: function setWidth() {
63866
- let width = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.width;
63867
- const numericWidth = Number(width) || 1;
63868
- this.setData("width", numericWidth);
63869
- this.getBody().scale.x = numericWidth;
63870
- }
63871
- }, {
63872
- key: "setHeight",
63873
- value: function setHeight() {
63874
- let height = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.height;
63875
- const numericHeight = Number(height) || 1;
63876
- this.setData("height", numericHeight);
63877
- this.getBody().scale.y = numericHeight;
63878
- }
63879
- }, {
63880
- key: "setAnisotropy",
63881
- value: function setAnisotropy() {
63882
- let anisotropy = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
63883
- const numericAnisotropy = Number(anisotropy) || 1;
63884
- this.setData("anisotropy", numericAnisotropy);
63885
- this.getTexture(TEXTURES.MAP).anisotropy = validateAnisotropy(numericAnisotropy);
63886
- }
63887
- }, {
63888
- key: "setSizeAttenuation",
63889
- value: function setSizeAttenuation() {
63890
- let attenuation = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
63891
- this.setData("sizeAttenuation", attenuation);
63892
- this.getBody().material.sizeAttenuation = attenuation;
63893
- }
63894
- }, {
63895
- key: "setDepthTest",
63896
- value: function setDepthTest() {
63897
- let depthTest = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
63898
- this.setData("depthTest", depthTest);
63899
- this.getBody().material.depthTest = depthTest;
63900
- }
63901
- }, {
63902
- key: "setDepthWrite",
63903
- value: function setDepthWrite() {
63904
- let depthWrite = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
63905
- this.setData("depthWrite", depthWrite);
63906
- this.getBody().material.depthWrite = depthWrite;
63907
- }
63908
- }, {
63909
- key: "toJSON",
63910
- value: function toJSON() {
63911
- let parseJSON = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
63912
-
63913
- if (this.isSerializable()) {
63914
- return { ..._get(_getPrototypeOf(Sprite.prototype), "toJSON", this).call(this, parseJSON),
63915
- width: this.width,
63916
- height: this.height,
63917
- spriteTexture: this.spriteTexture,
63918
- anisotropy: this.getBody().material.anisotropy,
63919
- sizeAttenuation: this.getBody().material.sizeAttenuation,
63920
- depthTest: this.getBody().material.depthTest,
63921
- depthWrite: this.getBody().material.depthWrite
63922
- };
63923
- }
63924
- }
63925
- }], [{
63926
- key: "create",
63927
- value: function create() {
63928
- let data = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
63929
- const {
63930
- width,
63931
- height,
63932
- spriteTexture,
63933
- options
63934
- } = data;
63935
- return new Sprite(width, height, spriteTexture, options);
63936
- }
63937
- }]);
63938
-
63939
- return Sprite;
63940
- }(Element$1);let HelperSprite = /*#__PURE__*/function (_Sprite) {
63941
- _inherits(HelperSprite, _Sprite);
63942
-
63943
- var _super = _createSuper(HelperSprite);
63944
-
63945
- function HelperSprite() {
63946
- var _this;
63947
-
63948
- _classCallCheck(this, HelperSprite);
63949
-
63950
- for (var _len = arguments.length, options = new Array(_len), _key = 0; _key < _len; _key++) {
63951
- options[_key] = arguments[_key];
63952
- }
63953
-
63954
- _this = _super.call(this, ...options);
63955
- _this.helperTarget = undefined;
63956
-
63957
- _this.setEntityType(ENTITY_TYPES.HELPER.TYPE);
63958
-
63959
- _this.setEntitySubtype(ENTITY_TYPES.HELPER.SUBTYPES.HELPER_SPRITE);
63960
-
63961
- return _this;
63962
- }
63963
-
63964
- _createClass(HelperSprite, [{
63965
- key: "setHelperTarget",
63966
- value: function setHelperTarget(element) {
63967
- this.helperTarget = element;
63968
- }
63969
- }, {
63970
- key: "getHelperTarget",
63971
- value: function getHelperTarget() {
63972
- return this.helperTarget;
63973
- }
63974
- }]);
63975
-
63976
- return HelperSprite;
63977
- }(Sprite);var __awaiter$5 = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
64161
+ }(Element$1);var __awaiter$5 = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
63978
64162
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
63979
64163
  return new (P || (P = Promise))(function (resolve, reject) {
63980
64164
  function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
@@ -70234,6 +70418,7 @@ const isAlreadyResolved$1 = path => {
70234
70418
  /**
70235
70419
  * Resolves an asset path to a full URL.
70236
70420
  * If path is already an absolute URL or contains the API path, returns it as-is.
70421
+ * If path is root-relative (starts with /), returns it as-is (served from public folder).
70237
70422
  * If path is relative and MAGE_ASSETS_BASE_URL is set, prepends the base URL.
70238
70423
  * @param {string} path - The asset path (relative or absolute)
70239
70424
  * @returns {string} - The resolved full URL
@@ -70244,15 +70429,19 @@ const resolveAssetPath$1 = path => {
70244
70429
  // If already a full URL or already contains the API path, return as-is
70245
70430
  if (isAlreadyResolved$1(path)) {
70246
70431
  return path;
70432
+ } // Root-relative paths (starting with /) are served from the public folder
70433
+ // and should not be modified with base URL
70434
+
70435
+
70436
+ if (path && path.startsWith("/")) {
70437
+ return path;
70247
70438
  } // If MAGE_ASSETS_BASE_URL is set, prepend it to the relative path
70248
70439
 
70249
70440
 
70250
70441
  const baseUrl = env.MAGE_ASSETS_BASE_URL;
70251
70442
 
70252
70443
  if (baseUrl) {
70253
- // Remove leading slash from path if present to avoid double slashes
70254
- const cleanPath = path.startsWith("/") ? path.slice(1) : path;
70255
- return `${baseUrl}/${cleanPath}`;
70444
+ return `${baseUrl}/${path}`;
70256
70445
  } // Warn if path contains colon (could be mistaken for protocol) and no base URL is set
70257
70446
 
70258
70447
 
@@ -80751,6 +80940,7 @@ const isAlreadyResolved = path => {
80751
80940
  /**
80752
80941
  * Resolves an asset path to a full URL.
80753
80942
  * If path is already an absolute URL or contains the API path, returns it as-is.
80943
+ * If path is root-relative (starts with /), returns it as-is (served from public folder).
80754
80944
  * If path is relative and MAGE_ASSETS_BASE_URL is set, prepends the base URL.
80755
80945
  * @param {string} path - The asset path (relative or absolute)
80756
80946
  * @returns {string} - The resolved full URL
@@ -80761,15 +80951,19 @@ const resolveAssetPath = path => {
80761
80951
  // If already a full URL or already contains the API path, return as-is
80762
80952
  if (isAlreadyResolved(path)) {
80763
80953
  return path;
80954
+ } // Root-relative paths (starting with /) are served from the public folder
80955
+ // and should not be modified with base URL
80956
+
80957
+
80958
+ if (path && path.startsWith("/")) {
80959
+ return path;
80764
80960
  } // If MAGE_ASSETS_BASE_URL is set, prepend it to the relative path
80765
80961
 
80766
80962
 
80767
80963
  const baseUrl = env.MAGE_ASSETS_BASE_URL;
80768
80964
 
80769
80965
  if (baseUrl) {
80770
- // Remove leading slash from path if present to avoid double slashes
80771
- const cleanPath = path.startsWith("/") ? path.slice(1) : path;
80772
- return `${baseUrl}/${cleanPath}`;
80966
+ return `${baseUrl}/${path}`;
80773
80967
  } // Warn if path contains colon (could be mistaken for protocol) and no base URL is set
80774
80968
 
80775
80969
 
@@ -91145,8 +91339,11 @@ let Level = /*#__PURE__*/function (_EventDispatcher) {
91145
91339
  _defineProperty$1(_assertThisInitialized(_this), "cancelNextAnimationFrame", () => cancelAnimationFrame(_this.requestAnimationFrameId));
91146
91340
 
91147
91341
  _defineProperty$1(_assertThisInitialized(_this), "init", () => {
91148
- Scene$1.create(_this.getName());
91149
- Scene$1.createCamera(new Camera());
91342
+ Scene$1.create(_this.getName()); // Scene camera is for editor navigation, not serializable
91343
+
91344
+ Scene$1.createCamera(new Camera({
91345
+ serializable: false
91346
+ }));
91150
91347
  Physics$1.init().then(() => {
91151
91348
  Particles$1.init();
91152
91349
  PostProcessing$1.init();
@@ -94131,10 +94328,43 @@ let Sky = /*#__PURE__*/function (_Element) {
94131
94328
  elements = [],
94132
94329
  lights = [],
94133
94330
  audio = [],
94134
- sounds = []
94331
+ sounds = [],
94332
+ cameras = []
94135
94333
  } = data; // Support both 'audio' and 'sounds' keys for backwards compatibility
94136
94334
 
94137
- const allSounds = [...audio, ...sounds]; // Use for...of to properly await async completeElementCreation calls
94335
+ const allSounds = [...audio, ...sounds]; // Process cameras - create game camera entity and apply settings to scene camera
94336
+
94337
+ for (const cameraData of cameras) {
94338
+ if (cameraData.entitySubType === ENTITY_TYPES.CAMERA.SUBTYPES.GAME) {
94339
+ // Create a Camera entity that will appear in the hierarchy (for editor)
94340
+ const gameCamera = new Camera({
94341
+ name: cameraData.name || "Game Camera",
94342
+ fov: cameraData.fov || 75,
94343
+ near: cameraData.near || 0.1,
94344
+ far: cameraData.far || 3000000,
94345
+ serializable: true
94346
+ });
94347
+ gameCamera.setEntitySubtype(ENTITY_TYPES.CAMERA.SUBTYPES.GAME); // Set position and rotation
94348
+
94349
+ if (cameraData.position) gameCamera.setPosition(cameraData.position);
94350
+ if (cameraData.rotation) gameCamera.setRotation(cameraData.rotation); // Set uuid and name for persistence
94351
+
94352
+ if (cameraData.uuid) gameCamera.setUuid(cameraData.uuid);
94353
+ if (cameraData.name) gameCamera.setName(cameraData.name); // Add tags for selectability in editor
94354
+
94355
+ if (cameraData.tags) gameCamera.addTags(cameraData.tags); // Add to Scene.elements so it appears in hierarchy
94356
+
94357
+ Scene$1.add(gameCamera.getBody(), gameCamera); // Also apply to the scene's rendering camera (for deployed games)
94358
+
94359
+ const sceneCamera = Scene$1.getCamera();
94360
+ if (cameraData.position) sceneCamera.setPosition(cameraData.position);
94361
+ if (cameraData.rotation) sceneCamera.setRotation(cameraData.rotation);
94362
+ if (cameraData.fov) sceneCamera.setFov(cameraData.fov);
94363
+ if (cameraData.near) sceneCamera.setNear(cameraData.near);
94364
+ if (cameraData.far) sceneCamera.setFar(cameraData.far);
94365
+ }
94366
+ } // Use for...of to properly await async completeElementCreation calls
94367
+
94138
94368
 
94139
94369
  for (const elementData of elements) {
94140
94370
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mage-engine",
3
- "version": "3.23.38",
3
+ "version": "3.23.40",
4
4
  "description": "A WebGL Javascript Game Engine, built on top of THREE.js and many other libraries.",
5
5
  "main": "dist/mage.js",
6
6
  "author": {