entangled-worlds-orbiters-shared 1.0.6 → 1.0.8

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "entangled-worlds-orbiters-shared",
3
- "version": "1.0.6",
3
+ "version": "1.0.8",
4
4
  "description": "Shared library for entangled worlds orbiters - contains core world rendering, moons system, and UI components",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -35,15 +35,23 @@
35
35
  "three-stdlib": "^2.34.0"
36
36
  },
37
37
  "devDependencies": {
38
+ "@eslint/js": "^10.0.1",
39
+ "eslint": "^10.0.0",
40
+ "globals": "^17.3.0",
38
41
  "three": "^0.166.1",
39
42
  "three-stdlib": "^2.34.0"
40
43
  },
41
44
  "repository": {
42
45
  "type": "git",
43
- "url": "git@github.com:plantasia-space-org/entangled-worlds-orbiters-shared.git"
46
+ "url": "git+ssh://git@github.com/plantasia-space-org/entangled-worlds-orbiters-shared.git"
44
47
  },
45
48
  "bugs": {
46
49
  "url": "https://github.com/plantasia-space-org/entangled-worlds-orbiters-shared/issues"
47
50
  },
48
- "homepage": "https://github.com/plantasia-space-org/entangled-worlds-orbiters-shared#readme"
51
+ "homepage": "https://github.com/plantasia-space-org/entangled-worlds-orbiters-shared#readme",
52
+ "scripts": {
53
+ "lint": "eslint .",
54
+ "lint:strict": "eslint . --max-warnings=0",
55
+ "lint:fallback": "node scripts/lint.js"
56
+ }
49
57
  }
@@ -213,7 +213,7 @@ export default class GUI {
213
213
 
214
214
  }
215
215
 
216
- // eslint-disable-next-line no-console
216
+
217
217
  console.error( `gui.add failed
218
218
  property:`, property, `
219
219
  object:`, object, `
@@ -280,7 +280,7 @@ export default class NumberController extends Controller {
280
280
  const setValueFromX = clientX => {
281
281
  const rect = this.$slider.getBoundingClientRect();
282
282
  const x = Math.max( rect.left, Math.min( clientX, rect.right ) );
283
- let value = map( x, rect.left, rect.right, this._min, this._max );
283
+ const value = map( x, rect.left, rect.right, this._min, this._max );
284
284
  this._snapClampSetValue( value );
285
285
  };
286
286
 
@@ -4,7 +4,8 @@ export {
4
4
  getTextureOptions,
5
5
  getDefaultTexture,
6
6
  getSkyboxOptions,
7
- getDefaultSkybox
7
+ getDefaultSkybox,
8
+ getTextureFallbackUrl
8
9
  } from './textureConfig.js';
9
10
 
10
11
  // runtime base helpers
@@ -12,4 +13,4 @@ export {
12
13
  setPublicBase,
13
14
  getPublicBase,
14
15
  resolvePublicUrl
15
- } from './env.js';
16
+ } from './env.js';
@@ -4,6 +4,32 @@
4
4
  */
5
5
  import { resolvePublicUrl } from './env.js';
6
6
 
7
+ function buildTextureUrl(baseUrl, categoryPath, value) {
8
+ if (!value) return null;
9
+ if (/^https?:\/\//i.test(value)) return value;
10
+ if (value.startsWith('/')) return resolvePublicUrl(value);
11
+ const prefix = `${baseUrl || ''}${categoryPath || ''}`;
12
+ return resolvePublicUrl(`${prefix}/${value}`);
13
+ }
14
+
15
+ function findTextureItem(textureConfig, category, textureUrl) {
16
+ if (!textureUrl || !textureConfig) return null;
17
+ const categoryConfig = textureConfig.textures?.[category];
18
+ if (!categoryConfig || !categoryConfig.items) return null;
19
+ const baseUrl = textureConfig.baseUrl || '/default';
20
+ const categoryPath = categoryConfig.basePath || `/${category}`;
21
+
22
+ for (const item of categoryConfig.items) {
23
+ const resolved = buildTextureUrl(baseUrl, categoryPath, item.filename || item.id);
24
+ if (!resolved) continue;
25
+ if (resolved === textureUrl) {
26
+ return { item, baseUrl, categoryPath };
27
+ }
28
+ }
29
+
30
+ return null;
31
+ }
32
+
7
33
  let cachedConfig = null;
8
34
  let configPromise = null;
9
35
  let lastConfigUrl = null;
@@ -85,8 +111,10 @@ export async function getTextureOptions(category, config = null) {
85
111
 
86
112
  categoryConfig.items.forEach(item => {
87
113
  const key = item.label || item.id;
88
- const relativePath = `${baseUrl}${categoryPath}/${item.filename || item.id}`;
89
- options[key] = resolvePublicUrl(relativePath);
114
+ const resolved = buildTextureUrl(baseUrl, categoryPath, item.filename || item.id);
115
+ if (resolved) {
116
+ options[key] = resolved;
117
+ }
90
118
  });
91
119
 
92
120
  return options;
@@ -123,6 +151,21 @@ export async function getDefaultTexture(category, config = null) {
123
151
  return null;
124
152
  }
125
153
 
154
+ /**
155
+ * Return the configured fallback URL for a given texture if defined.
156
+ * @param {string} category - Texture category (clouds, moons, etc.)
157
+ * @param {string} textureUrl - Resolved texture URL
158
+ * @param {Object|null} config - Optional texture config override
159
+ * @returns {string|null} Resolved fallback texture URL or null
160
+ */
161
+ export function getTextureFallbackUrl(category, textureUrl, config = null) {
162
+ const textureConfig = config || cachedConfig;
163
+ if (!textureConfig) return null;
164
+ const found = findTextureItem(textureConfig, category, textureUrl);
165
+ if (!found || !found.item?.fallback) return null;
166
+ return buildTextureUrl(found.baseUrl, found.categoryPath, found.item.fallback);
167
+ }
168
+
126
169
  /**
127
170
  * Get texture by ID within a category
128
171
  * @param {string} category - Texture category
@@ -10,7 +10,7 @@ function getSharedKTX2Loader(renderer) {
10
10
  return loader;
11
11
  }
12
12
 
13
- export async function loadGLB(url, { retries = 3, signal, onProgress, applyFlags } = {}) {
13
+ export async function loadGLB(url, { retries = 3, signal, onProgress, applyFlags, withCredentials = false } = {}) {
14
14
  const renderer = window.__EW_RENDERER;
15
15
  if (!renderer) throw new Error('Renderer not ready for KTX2');
16
16
 
@@ -18,7 +18,8 @@ export async function loadGLB(url, { retries = 3, signal, onProgress, applyFlags
18
18
  while (attempt < retries) {
19
19
  try {
20
20
  const loader = new GLTFLoader()
21
- .setCrossOrigin('anonymous')
21
+ .setCrossOrigin(withCredentials ? 'use-credentials' : 'anonymous')
22
+ .setWithCredentials(Boolean(withCredentials))
22
23
  .setKTX2Loader(getSharedKTX2Loader(renderer));
23
24
 
24
25
  const root = await new Promise((resolve, reject) => {
@@ -13,6 +13,7 @@ export async function generateMoons({
13
13
  orbitRadius = 1.5,
14
14
  textureKTX2 = DEFAULT_MOON_TEX_KTX2,
15
15
  texturePNG = DEFAULT_MOON_TEX_PNG,
16
+ textureFallback = null,
16
17
  useTexture = true,
17
18
  // NEW: seed for deterministic positioning
18
19
  seed = null, // if provided, ensures consistent moon positions
@@ -90,8 +91,8 @@ export async function generateMoons({
90
91
  try { sharedTexture = await buildUvGridTexture(); usedUvGrid = true; } catch(_) {}
91
92
  } else if (useTexture) {
92
93
  // Use textureKey if provided, otherwise fall back to default textures
93
- let primaryTexture = textureKey ? resolvePublicUrl(textureKey) : textureKTX2;
94
- const fallbackTexture = texturePNG;
94
+ const primaryTexture = textureKey ? resolvePublicUrl(textureKey) : textureKTX2;
95
+ const fallbackTexture = textureFallback || texturePNG;
95
96
 
96
97
  try {
97
98
  sharedTexture = await loadTexture(primaryTexture);
@@ -29,6 +29,7 @@ export class MoonsManager {
29
29
  seed = null, // seed for deterministic positioning
30
30
  textureKey = null, // NEW: specific texture key/path to use
31
31
  moonColor = '#ffffff', // NEW: moon color
32
+ textureFallback = null,
32
33
  } = opts;
33
34
 
34
35
  let newGroup = null;
@@ -41,6 +42,7 @@ export class MoonsManager {
41
42
  useTexture,
42
43
  seed,
43
44
  textureKey, // Pass texture key for custom moon textures
45
+ textureFallback,
44
46
  moonColor, // Pass moon color to generator
45
47
  });
46
48
  } catch (e) {
@@ -1,7 +1,7 @@
1
1
  import { loadGLB } from '../loaders/glbLoader.js';
2
2
 
3
- export async function makeGLB({ modelUrl, flags, retries = 3 }) {
3
+ export async function makeGLB({ modelUrl, flags, retries = 3, withCredentials = false } = {}) {
4
4
  if (!modelUrl) throw new Error('modelUrl is required');
5
- const obj = await loadGLB(modelUrl, { retries, applyFlags: flags });
5
+ const obj = await loadGLB(modelUrl, { retries, applyFlags: flags, withCredentials });
6
6
  return obj;
7
7
  }
@@ -42,7 +42,11 @@ export class WorldManager {
42
42
  if (this.customCreators.has(mode)) {
43
43
  obj = await this.customCreators.get(mode)({ flags: this.flags, ...args });
44
44
  } else if (mode === 2) {
45
- obj = await makeGLB({ modelUrl: args.modelUrl, flags: this.flags });
45
+ obj = await makeGLB({
46
+ modelUrl: args.modelUrl,
47
+ flags: this.flags,
48
+ withCredentials: Boolean(args.withCredentials),
49
+ });
46
50
  } else if (mode === 3) {
47
51
  obj = await makeNormalSphere({ flags: this.flags, ...args });
48
52
  } else {
@@ -22,7 +22,7 @@ if (typeof window !== 'undefined') {
22
22
  }
23
23
  }
24
24
 
25
- let WT_LOGGED_FIRST_CALL = false;
25
+ const WT_LOGGED_FIRST_CALL = false;
26
26
 
27
27
  export const EARTH_RADIUS_UNITS = 0.5; // scene units
28
28