entangled-worlds-orbiters-shared 1.0.1 → 1.0.3
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
|
@@ -18,12 +18,10 @@ let configPromise = null;
|
|
|
18
18
|
*/
|
|
19
19
|
export async function loadTextureConfig(configUrl = DEFAULT_CONFIG_URL, useCache = true) {
|
|
20
20
|
if (useCache && cachedConfig) {
|
|
21
|
-
console.log('[TextureConfig] Using cached config');
|
|
22
21
|
return cachedConfig;
|
|
23
22
|
}
|
|
24
23
|
|
|
25
24
|
if (configPromise) {
|
|
26
|
-
console.log('[TextureConfig] Using in-flight request');
|
|
27
25
|
return configPromise;
|
|
28
26
|
}
|
|
29
27
|
|
|
@@ -31,7 +29,6 @@ export async function loadTextureConfig(configUrl = DEFAULT_CONFIG_URL, useCache
|
|
|
31
29
|
try {
|
|
32
30
|
// Resolve config URL against public base if it's a relative path
|
|
33
31
|
const resolvedConfigUrl = /^https?:\/\//i.test(configUrl) ? configUrl : resolvePublicUrl(configUrl);
|
|
34
|
-
console.log('[TextureConfig] Loading from:', resolvedConfigUrl);
|
|
35
32
|
const response = await fetch(resolvedConfigUrl);
|
|
36
33
|
|
|
37
34
|
if (!response.ok) {
|
|
@@ -46,19 +43,12 @@ export async function loadTextureConfig(configUrl = DEFAULT_CONFIG_URL, useCache
|
|
|
46
43
|
}
|
|
47
44
|
|
|
48
45
|
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
46
|
return config;
|
|
56
47
|
} catch (error) {
|
|
57
48
|
console.error('[TextureConfig] Failed to load config:', error);
|
|
58
49
|
|
|
59
50
|
// If primary URL fails and it's not already the fallback, try fallback
|
|
60
51
|
if (configUrl !== FALLBACK_CONFIG_URL) {
|
|
61
|
-
console.log('[TextureConfig] Trying fallback endpoint...');
|
|
62
52
|
try {
|
|
63
53
|
return await loadTextureConfig(FALLBACK_CONFIG_URL, false);
|
|
64
54
|
} catch (fallbackError) {
|
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);
|
package/src/world/worldNormal.js
CHANGED
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
import * as THREE from 'three';
|
|
3
3
|
import { EARTH_RADIUS_UNITS } from './worldTexture.js';
|
|
4
4
|
import { applyFlagsToMaterial } from '../utils/materials.js';
|
|
5
|
+
import { getLightFresnel } from '../core/lightFresnel.js';
|
|
6
|
+
import { createCloudShell } from './cloudShell.js';
|
|
7
|
+
import { resolvePublicUrl } from '../config/env.js';
|
|
5
8
|
|
|
6
9
|
/**
|
|
7
10
|
* Create a simple sphere using THREE.MeshNormalMaterial.
|
|
@@ -12,6 +15,18 @@ export async function makeNormalSphere({
|
|
|
12
15
|
sphereWidthSegments,
|
|
13
16
|
sphereHeightSegments,
|
|
14
17
|
flags,
|
|
18
|
+
glow, // halo (glow) enabled
|
|
19
|
+
glowScale = 1.18,
|
|
20
|
+
glowRimHex = 0x66ccff,
|
|
21
|
+
glowFacingHex = 0x000000,
|
|
22
|
+
glowBias = 0.02,
|
|
23
|
+
glowFresnelScale = 1.0,
|
|
24
|
+
glowPower = 3.5,
|
|
25
|
+
cloudsEnabled,
|
|
26
|
+
cloudsTextureUrl = '/assets/texture/2k_earth_clouds.jpg',
|
|
27
|
+
cloudsColor = 0xffffff,
|
|
28
|
+
cloudsOpacity = 0.6,
|
|
29
|
+
cloudsSpeed = 0.015,
|
|
15
30
|
} = {}) {
|
|
16
31
|
const radius = typeof sphereRadius === 'number' ? Math.max(0.0001, sphereRadius) : EARTH_RADIUS_UNITS;
|
|
17
32
|
const widthSegs = Number.isFinite(sphereWidthSegments) ? Math.max(3, Math.floor(sphereWidthSegments)) : 64;
|
|
@@ -21,5 +36,36 @@ export async function makeNormalSphere({
|
|
|
21
36
|
if (flags) applyFlagsToMaterial(material, flags);
|
|
22
37
|
const mesh = new THREE.Mesh(geometry, material);
|
|
23
38
|
mesh.name = 'worldNormalSphere';
|
|
39
|
+
|
|
40
|
+
// Attach halo (glow) effect if enabled
|
|
41
|
+
if (glow) {
|
|
42
|
+
const fresnelMat = getLightFresnel({ rimHex: glowRimHex, facingHex: glowFacingHex });
|
|
43
|
+
fresnelMat.uniforms.fresnelBias.value = glowBias;
|
|
44
|
+
fresnelMat.uniforms.fresnelScale.value = glowFresnelScale;
|
|
45
|
+
fresnelMat.uniforms.fresnelPower.value = glowPower;
|
|
46
|
+
|
|
47
|
+
const glowGeom = geometry.clone();
|
|
48
|
+
const fresnelMesh = new THREE.Mesh(glowGeom, fresnelMat);
|
|
49
|
+
fresnelMesh.scale.set(glowScale, glowScale, glowScale);
|
|
50
|
+
fresnelMesh.renderOrder = 999;
|
|
51
|
+
fresnelMesh.name = 'worldNormalGlow';
|
|
52
|
+
mesh.add(fresnelMesh);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Attach clouds effect if enabled
|
|
56
|
+
if (cloudsEnabled) {
|
|
57
|
+
const cloudMesh = await createCloudShell({
|
|
58
|
+
baseGeometry: geometry,
|
|
59
|
+
baseRadius: radius,
|
|
60
|
+
widthSegments: widthSegs,
|
|
61
|
+
heightSegments: heightSegs,
|
|
62
|
+
textureUrl: resolvePublicUrl(cloudsTextureUrl),
|
|
63
|
+
color: cloudsColor,
|
|
64
|
+
opacity: cloudsOpacity,
|
|
65
|
+
speed: cloudsSpeed,
|
|
66
|
+
});
|
|
67
|
+
mesh.add(cloudMesh);
|
|
68
|
+
}
|
|
69
|
+
|
|
24
70
|
return mesh;
|
|
25
71
|
}
|
|
@@ -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) {
|