entangled-worlds-orbiters-shared 1.0.2 → 1.0.4
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,38 +1,41 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Texture Configuration Loader
|
|
3
|
-
* Loads texture definitions from
|
|
3
|
+
* Loads texture definitions from remote endpoint or uses passed config
|
|
4
4
|
*/
|
|
5
5
|
import { resolvePublicUrl } from './env.js';
|
|
6
6
|
|
|
7
|
-
const DEFAULT_CONFIG_URL = '/config/textures.json';
|
|
8
|
-
const FALLBACK_CONFIG_URL = 'https://api.entangled-worlds.com/config/textures.json'; // Future endpoint
|
|
9
|
-
|
|
10
7
|
let cachedConfig = null;
|
|
11
8
|
let configPromise = null;
|
|
9
|
+
let lastConfigUrl = null;
|
|
12
10
|
|
|
13
11
|
/**
|
|
14
|
-
* Load texture configuration from
|
|
15
|
-
* @param {string} configUrl - Override
|
|
12
|
+
* Load texture configuration from remote endpoint or use passed config
|
|
13
|
+
* @param {string} configUrl - Override config URL
|
|
16
14
|
* @param {boolean} useCache - Whether to use cached config if available
|
|
17
15
|
* @returns {Promise<Object>} Texture configuration object
|
|
18
16
|
*/
|
|
19
|
-
export async function loadTextureConfig(configUrl =
|
|
17
|
+
export async function loadTextureConfig(configUrl = null, useCache = true) {
|
|
20
18
|
if (useCache && cachedConfig) {
|
|
21
|
-
console.log('[TextureConfig] Using cached config');
|
|
22
19
|
return cachedConfig;
|
|
23
20
|
}
|
|
24
21
|
|
|
25
22
|
if (configPromise) {
|
|
26
|
-
console.log('[TextureConfig] Using in-flight request');
|
|
27
23
|
return configPromise;
|
|
28
24
|
}
|
|
29
25
|
|
|
26
|
+
if (configUrl) {
|
|
27
|
+
lastConfigUrl = configUrl;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const targetUrl = configUrl || lastConfigUrl;
|
|
31
|
+
|
|
30
32
|
configPromise = (async () => {
|
|
31
33
|
try {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
if (!targetUrl) {
|
|
35
|
+
throw new Error('No texture config URL provided');
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const response = await fetch(targetUrl);
|
|
36
39
|
|
|
37
40
|
if (!response.ok) {
|
|
38
41
|
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
@@ -46,29 +49,13 @@ export async function loadTextureConfig(configUrl = DEFAULT_CONFIG_URL, useCache
|
|
|
46
49
|
}
|
|
47
50
|
|
|
48
51
|
cachedConfig = config;
|
|
49
|
-
console.log('[TextureConfig] Loaded successfully:', {
|
|
50
|
-
version: config.version,
|
|
51
|
-
categories: Object.keys(config.textures),
|
|
52
|
-
lastUpdated: config.lastUpdated
|
|
53
|
-
});
|
|
54
|
-
|
|
55
52
|
return config;
|
|
56
53
|
} catch (error) {
|
|
57
54
|
console.error('[TextureConfig] Failed to load config:', error);
|
|
58
|
-
|
|
59
|
-
// If primary URL fails and it's not already the fallback, try fallback
|
|
60
|
-
if (configUrl !== FALLBACK_CONFIG_URL) {
|
|
61
|
-
console.log('[TextureConfig] Trying fallback endpoint...');
|
|
62
|
-
try {
|
|
63
|
-
return await loadTextureConfig(FALLBACK_CONFIG_URL, false);
|
|
64
|
-
} catch (fallbackError) {
|
|
65
|
-
console.error('[TextureConfig] Fallback also failed:', fallbackError);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// Return minimal fallback configuration
|
|
55
|
+
// Return minimal fallback configuration when loading fails
|
|
70
56
|
console.warn('[TextureConfig] Using hardcoded fallback config');
|
|
71
|
-
|
|
57
|
+
cachedConfig = getHardcodedFallback();
|
|
58
|
+
return cachedConfig;
|
|
72
59
|
} finally {
|
|
73
60
|
configPromise = null;
|
|
74
61
|
}
|
|
@@ -277,10 +264,10 @@ function getHardcodedFallback() {
|
|
|
277
264
|
* @param {string} configUrl - Override config URL
|
|
278
265
|
* @returns {Promise<Object>} Fresh configuration object
|
|
279
266
|
*/
|
|
280
|
-
export async function reloadTextureConfig(configUrl =
|
|
267
|
+
export async function reloadTextureConfig(configUrl = null) {
|
|
281
268
|
cachedConfig = null;
|
|
282
269
|
configPromise = null;
|
|
283
|
-
return loadTextureConfig(configUrl, false);
|
|
270
|
+
return loadTextureConfig(configUrl || lastConfigUrl, false);
|
|
284
271
|
}
|
|
285
272
|
|
|
286
273
|
/**
|
package/src/loaders/glbLoader.js
CHANGED
|
@@ -51,7 +51,6 @@ export async function loadGLB(url, { retries = 3, signal, onProgress, applyFlags
|
|
|
51
51
|
child.material.emissive.setHex(0x888888);
|
|
52
52
|
child.material.emissiveMap = child.material.map;
|
|
53
53
|
child.material.emissiveIntensity = 1.0;
|
|
54
|
-
console.log('✅ KTX2 texture loaded:', child.material.map.constructor.name, `${child.material.map.image.width}x${child.material.map.image.height}`);
|
|
55
54
|
}
|
|
56
55
|
child.material.needsUpdate = true;
|
|
57
56
|
child.castShadow = false;
|
|
@@ -64,16 +64,6 @@ export async function generateMoons({
|
|
|
64
64
|
return Math.random(); // Use regular random if no seed
|
|
65
65
|
};
|
|
66
66
|
|
|
67
|
-
// Log the seed being used for debugging
|
|
68
|
-
if (debug) {
|
|
69
|
-
console.log('[Moons] Using seed for deterministic positioning:', {
|
|
70
|
-
originalSeed: seed,
|
|
71
|
-
seedValue: seedValue,
|
|
72
|
-
seedType: typeof seed,
|
|
73
|
-
isSeeded: seedValue !== null
|
|
74
|
-
});
|
|
75
|
-
}
|
|
76
|
-
|
|
77
67
|
const moonGeometry = new THREE.SphereGeometry(0.1, geometryWidthSegments, geometryHeightSegments);
|
|
78
68
|
|
|
79
69
|
// Optional UV grid override
|
|
@@ -106,20 +96,16 @@ export async function generateMoons({
|
|
|
106
96
|
// Resolve textureKey to absolute URL if it's relative
|
|
107
97
|
if (textureKey && textureKey.startsWith('/')) {
|
|
108
98
|
primaryTexture = `${HERBARIUM_BASE}${textureKey}`;
|
|
109
|
-
if (debug) console.log('[Moons] Using custom texture key:', textureKey, '-> resolved:', primaryTexture);
|
|
110
99
|
} else if (textureKey) {
|
|
111
100
|
primaryTexture = textureKey; // already absolute
|
|
112
|
-
if (debug) console.log('[Moons] Using absolute texture URL:', primaryTexture);
|
|
113
101
|
}
|
|
114
102
|
|
|
115
103
|
try {
|
|
116
104
|
sharedTexture = await loadTexture(primaryTexture);
|
|
117
|
-
if (debug) console.log('[Moons] Loaded texture from:', primaryTexture);
|
|
118
105
|
} catch (eKTX) {
|
|
119
106
|
if (debug) console.warn('[Moons] Primary texture failed, trying fallback:', eKTX);
|
|
120
107
|
try {
|
|
121
108
|
sharedTexture = await loadTexture(fallbackTexture);
|
|
122
|
-
if (debug) console.log('[Moons] Fallback texture loaded from:', fallbackTexture);
|
|
123
109
|
} catch (ePNG) {
|
|
124
110
|
if (debug) console.warn('[Moons] Both primary and fallback texture loading failed');
|
|
125
111
|
}
|
|
@@ -16,13 +16,11 @@ export class WorldManager {
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
setFlags(flags) {
|
|
19
|
-
console.log('[WorldManager] setFlags:', flags);
|
|
20
19
|
this.flags = { ...this.flags, ...flags };
|
|
21
20
|
}
|
|
22
21
|
|
|
23
22
|
disposeCurrent() {
|
|
24
23
|
if (this.current) {
|
|
25
|
-
console.log('[WorldManager] disposeCurrent:', this.current?.name || this.current);
|
|
26
24
|
disposeObject3D(this.current);
|
|
27
25
|
this.scene.remove(this.current);
|
|
28
26
|
this.current = null;
|
|
@@ -36,39 +34,31 @@ export class WorldManager {
|
|
|
36
34
|
|
|
37
35
|
async setMode(mode, args = {}) {
|
|
38
36
|
const myToken = ++this.token;
|
|
39
|
-
console.log('[WorldManager] setMode request:', { mode, args });
|
|
40
37
|
this.onLoadStart?.();
|
|
41
38
|
try {
|
|
42
39
|
let obj;
|
|
43
40
|
|
|
44
41
|
// Check for custom creators first
|
|
45
42
|
if (this.customCreators.has(mode)) {
|
|
46
|
-
console.log(`[WorldManager] -> custom creator for mode ${mode}`);
|
|
47
43
|
obj = await this.customCreators.get(mode)({ flags: this.flags, ...args });
|
|
48
44
|
} else if (mode === 2) {
|
|
49
|
-
console.log('[WorldManager] -> makeGLB');
|
|
50
45
|
obj = await makeGLB({ modelUrl: args.modelUrl, flags: this.flags });
|
|
51
46
|
} else if (mode === 3) {
|
|
52
|
-
console.log('[WorldManager] -> makeNormalSphere');
|
|
53
47
|
obj = await makeNormalSphere({ flags: this.flags, ...args });
|
|
54
48
|
} else {
|
|
55
|
-
console.log('[WorldManager] -> makeSphere (textured)');
|
|
56
49
|
obj = await makeSphere({ textureUrl: args.textureUrl, flags: this.flags, ...args });
|
|
57
50
|
}
|
|
58
51
|
|
|
59
52
|
if (this.token !== myToken) {
|
|
60
|
-
console.log('[WorldManager] setMode superseded, abandoning result');
|
|
61
53
|
return;
|
|
62
54
|
}
|
|
63
55
|
this.disposeCurrent();
|
|
64
56
|
this.scene.add(obj);
|
|
65
57
|
this.current = obj;
|
|
66
|
-
console.log('[WorldManager] setMode applied. current:', obj?.name || obj);
|
|
67
58
|
|
|
68
59
|
// If the object exposes a frame updater, run a render-time loop
|
|
69
60
|
if (obj && obj.userData && typeof obj.userData.update === 'function' && window.__EW_RENDERER) {
|
|
70
61
|
const updater = obj.userData.update;
|
|
71
|
-
console.log('[WorldManager] update loop started for', obj.name || obj);
|
|
72
62
|
const tick = () => {
|
|
73
63
|
if (this.current === obj) {
|
|
74
64
|
try {
|
|
@@ -77,8 +67,6 @@ export class WorldManager {
|
|
|
77
67
|
console.warn('[WorldManager] update loop error:', e);
|
|
78
68
|
}
|
|
79
69
|
requestAnimationFrame(tick);
|
|
80
|
-
} else {
|
|
81
|
-
console.log('[WorldManager] update loop stopped (object replaced)');
|
|
82
70
|
}
|
|
83
71
|
};
|
|
84
72
|
requestAnimationFrame(tick);
|
|
@@ -109,10 +109,15 @@ export async function makeSphere({
|
|
|
109
109
|
try {
|
|
110
110
|
const tex = await loadTexture(chosenTexture);
|
|
111
111
|
tex.colorSpace = THREE.SRGBColorSpace;
|
|
112
|
-
tex.generateMipmaps = true;
|
|
113
112
|
tex.anisotropy = 8;
|
|
114
113
|
if (typeof flipY === 'boolean') tex.flipY = flipY;
|
|
115
114
|
|
|
115
|
+
// Only enable mipmaps for non-compressed, power-of-two textures
|
|
116
|
+
const isCompressed = tex.isCompressedTexture;
|
|
117
|
+
const img = tex.image;
|
|
118
|
+
const isPowerOfTwo = img && ((img.width & (img.width - 1)) === 0) && ((img.height & (img.height - 1)) === 0);
|
|
119
|
+
tex.generateMipmaps = !isCompressed && isPowerOfTwo;
|
|
120
|
+
|
|
116
121
|
// Decide mapping approach
|
|
117
122
|
let shouldMirrorDuplicate = mirrorDuplicateX;
|
|
118
123
|
if (tex.image) {
|