entangled-worlds-orbiters-shared 6.0.0 → 6.0.2
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/shortcuts/catalogue.d.ts +2 -2
- package/dist/shortcuts/catalogue.js +1 -1
- package/dist/world/cloudShell.d.ts +8 -0
- package/dist/world/cloudShell.js +23 -4
- package/dist/world/worldNormal.js +11 -2
- package/dist/world/worldTexture.js +11 -2
- package/package.json +1 -1
- package/src/shortcuts/catalogue.ts +2 -2
- package/src/world/cloudShell.ts +23 -5
- package/src/world/worldNormal.ts +9 -2
- package/src/world/worldTexture.ts +9 -2
|
@@ -12,7 +12,7 @@ export interface ShortcutSheetRow extends ShortcutNamed {
|
|
|
12
12
|
export interface ShortcutSheetColumn extends ShortcutNamed {
|
|
13
13
|
readonly rows: readonly ShortcutSheetRow[];
|
|
14
14
|
}
|
|
15
|
-
/** One surface's keys (`orbiters-play`, `ew-studio`, `
|
|
15
|
+
/** One surface's keys (`orbiters-play`, `ew-clip-studio`, `root`). Two actions clash only inside a section. */
|
|
16
16
|
export interface ShortcutSection {
|
|
17
17
|
readonly id: string;
|
|
18
18
|
/** The app it belongs to (`orbiters`) and that app's name. */
|
|
@@ -54,7 +54,7 @@ export declare function localName(item: {
|
|
|
54
54
|
}, locale?: string): string;
|
|
55
55
|
/** A section's app name in a language. */
|
|
56
56
|
export declare function localAppName(section: Pick<ShortcutSection, 'appLabel' | 'appNames'>, locale?: string): string;
|
|
57
|
-
/** A section's part name (`Play`, `Studio`) in a language; `undefined` when it has none. */
|
|
57
|
+
/** A section's part name (`Play`, `Orbiter Studio`) in a language; `undefined` when it has none. */
|
|
58
58
|
export declare function localPartName(section: Pick<ShortcutSection, 'part' | 'partNames'>, locale?: string): string | undefined;
|
|
59
59
|
/** The apps the catalogue has, in its order. */
|
|
60
60
|
export declare function shortcutApps(catalogue: ShortcutCatalogue): ReadonlyArray<{
|
|
@@ -82,7 +82,7 @@ export function localName(item, locale) {
|
|
|
82
82
|
export function localAppName(section, locale) {
|
|
83
83
|
return localName({ label: section.appLabel, names: section.appNames }, locale);
|
|
84
84
|
}
|
|
85
|
-
/** A section's part name (`Play`, `Studio`) in a language; `undefined` when it has none. */
|
|
85
|
+
/** A section's part name (`Play`, `Orbiter Studio`) in a language; `undefined` when it has none. */
|
|
86
86
|
export function localPartName(section, locale) {
|
|
87
87
|
return section.part === undefined ? undefined : localName({ label: section.part, names: section.partNames }, locale);
|
|
88
88
|
}
|
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
import * as THREE from 'three';
|
|
2
|
+
/**
|
|
3
|
+
* The cloud texture could not be loaded (offline, gone from the CDN, or not decodable). Its own type
|
|
4
|
+
* so the world builders can drop just the clouds on THIS failure and still let any other error out.
|
|
5
|
+
* `cause` is what the loader threw.
|
|
6
|
+
*/
|
|
7
|
+
export declare class CloudTextureError extends Error {
|
|
8
|
+
constructor(url: string, cause: unknown);
|
|
9
|
+
}
|
|
2
10
|
/**
|
|
3
11
|
* `baseGeometry` is cloned for the shell; when absent a sphere is built from `baseRadius` (0.5) and
|
|
4
12
|
* the segment counts (64 × 64). Defaults: `color` 0xffffff, `opacity` 0.6, `speed` 0.015.
|
package/dist/world/cloudShell.js
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
import * as THREE from 'three';
|
|
2
2
|
import { loadTexture } from '../loaders/bodyTextureLoader.js';
|
|
3
|
+
/**
|
|
4
|
+
* The cloud texture could not be loaded (offline, gone from the CDN, or not decodable). Its own type
|
|
5
|
+
* so the world builders can drop just the clouds on THIS failure and still let any other error out.
|
|
6
|
+
* `cause` is what the loader threw.
|
|
7
|
+
*/
|
|
8
|
+
export class CloudTextureError extends Error {
|
|
9
|
+
constructor(url, cause) {
|
|
10
|
+
super(`Cloud texture could not be loaded: ${url}`, { cause });
|
|
11
|
+
this.name = 'CloudTextureError';
|
|
12
|
+
}
|
|
13
|
+
}
|
|
3
14
|
// Texture-only clouds material (alpha mask + tint), UV-scrolled
|
|
4
15
|
async function makeTextureMaterial({ color = 0xffffff, opacity = 0.6, textureUrl, speed = 0.015, renderer = null, } = {}) {
|
|
5
16
|
// Diffuse-only (Lambert): the star's key light costs no specular pass.
|
|
@@ -15,7 +26,14 @@ async function makeTextureMaterial({ color = 0xffffff, opacity = 0.6, textureUrl
|
|
|
15
26
|
if (textureUrl) {
|
|
16
27
|
// Thread the owning view's renderer: KTX2 cloud textures must transcode against the caller's
|
|
17
28
|
// context, not the global fallback (which shared-renderer pages don't publish at all).
|
|
18
|
-
|
|
29
|
+
let tex;
|
|
30
|
+
try {
|
|
31
|
+
tex = await loadTexture(textureUrl, { renderer });
|
|
32
|
+
}
|
|
33
|
+
catch (cause) {
|
|
34
|
+
mat.dispose();
|
|
35
|
+
throw new CloudTextureError(textureUrl, cause);
|
|
36
|
+
}
|
|
19
37
|
tex.wrapS = THREE.RepeatWrapping;
|
|
20
38
|
tex.wrapT = THREE.RepeatWrapping;
|
|
21
39
|
// Use linear space for alpha masks if available
|
|
@@ -48,9 +66,7 @@ async function makeTextureMaterial({ color = 0xffffff, opacity = 0.6, textureUrl
|
|
|
48
66
|
* the segment counts (64 × 64). Defaults: `color` 0xffffff, `opacity` 0.6, `speed` 0.015.
|
|
49
67
|
*/
|
|
50
68
|
export async function createCloudShell({ baseGeometry, baseRadius = 0.5, widthSegments = 64, heightSegments = 64, textureUrl = '/assets/texture/2k_earth_clouds.jpg', color = 0xffffff, opacity = 0.6, speed = 0.015, renderer = null, } = {}) {
|
|
51
|
-
|
|
52
|
-
? baseGeometry.clone()
|
|
53
|
-
: new THREE.SphereGeometry(baseRadius, widthSegments, heightSegments);
|
|
69
|
+
// The texture first: when it cannot be loaded this throws before any geometry exists to leak.
|
|
54
70
|
const material = await makeTextureMaterial({
|
|
55
71
|
color,
|
|
56
72
|
opacity,
|
|
@@ -58,6 +74,9 @@ export async function createCloudShell({ baseGeometry, baseRadius = 0.5, widthSe
|
|
|
58
74
|
speed,
|
|
59
75
|
renderer,
|
|
60
76
|
});
|
|
77
|
+
const geom = baseGeometry
|
|
78
|
+
? baseGeometry.clone()
|
|
79
|
+
: new THREE.SphereGeometry(baseRadius, widthSegments, heightSegments);
|
|
61
80
|
const mesh = new THREE.Mesh(geom, material);
|
|
62
81
|
const s = 1.001; // fixed scale
|
|
63
82
|
mesh.scale.set(s, s, s);
|
|
@@ -3,7 +3,7 @@ import * as THREE from 'three';
|
|
|
3
3
|
import { EARTH_RADIUS_UNITS } from './worldTexture.js';
|
|
4
4
|
import { applyFlagsToMaterial } from '../utils/materials.js';
|
|
5
5
|
import { getLightFresnel } from '../core/lightFresnel.js';
|
|
6
|
-
import { createCloudShell } from './cloudShell.js';
|
|
6
|
+
import { CloudTextureError, createCloudShell } from './cloudShell.js';
|
|
7
7
|
import { resolvePublicUrl } from '../config/env.js';
|
|
8
8
|
/**
|
|
9
9
|
* Create a simple sphere using THREE.MeshNormalMaterial.
|
|
@@ -51,8 +51,17 @@ glowScale = 1.18, glowRimHex = 0x66ccff, glowFacingHex = 0x000000, glowBias = 0.
|
|
|
51
51
|
opacity: cloudsOpacity,
|
|
52
52
|
speed: cloudsSpeed,
|
|
53
53
|
renderer,
|
|
54
|
+
}).catch((e) => {
|
|
55
|
+
// Clouds are an optional layer: a texture that cannot be loaded (offline, or gone from the
|
|
56
|
+
// CDN) costs the clouds, never the planet — the same way a failed surface texture does. Only
|
|
57
|
+
// that: any other error building the shell is a bug and still fails the build.
|
|
58
|
+
if (!(e instanceof CloudTextureError))
|
|
59
|
+
throw e;
|
|
60
|
+
console.warn('[worldNormal] Failed to load clouds, drawing the world without them:', e.cause);
|
|
61
|
+
return null;
|
|
54
62
|
});
|
|
55
|
-
|
|
63
|
+
if (cloudMesh)
|
|
64
|
+
mesh.add(cloudMesh);
|
|
56
65
|
}
|
|
57
66
|
return mesh;
|
|
58
67
|
}
|
|
@@ -2,7 +2,7 @@ import * as THREE from 'three';
|
|
|
2
2
|
import { loadTexture } from '../loaders/bodyTextureLoader.js';
|
|
3
3
|
import { applyFlagsToMaterial } from '../utils/materials.js';
|
|
4
4
|
import { getLightFresnel } from '../core/lightFresnel.js';
|
|
5
|
-
import { createCloudShell } from './cloudShell.js';
|
|
5
|
+
import { CloudTextureError, createCloudShell } from './cloudShell.js';
|
|
6
6
|
import { resolvePublicUrl } from '../config/env.js';
|
|
7
7
|
// Debug tag so you can verify the loaded file version in console
|
|
8
8
|
export const WORLD_TEXTURE_DEBUG_TAG = 'WT:vFlipGeom-r3@2025-10-28T17:22:00Z';
|
|
@@ -287,8 +287,17 @@ cloudsEnabled = false, cloudsTextureUrl = '/assets/texture/2k_earth_clouds.jpg',
|
|
|
287
287
|
opacity: cloudsOpacity,
|
|
288
288
|
speed: cloudsSpeed,
|
|
289
289
|
renderer,
|
|
290
|
+
}).catch((e) => {
|
|
291
|
+
// Clouds are an optional layer: a texture that cannot be loaded (offline, or gone from the
|
|
292
|
+
// CDN) costs the clouds, never the planet — the same way a failed surface texture does. Only
|
|
293
|
+
// that: any other error building the shell is a bug and still fails the build.
|
|
294
|
+
if (!(e instanceof CloudTextureError))
|
|
295
|
+
throw e;
|
|
296
|
+
console.warn('[worldTexture] Failed to load clouds, drawing the world without them:', e.cause);
|
|
297
|
+
return null;
|
|
290
298
|
});
|
|
291
|
-
|
|
299
|
+
if (cloudMesh)
|
|
300
|
+
mesh.add(cloudMesh);
|
|
292
301
|
}
|
|
293
302
|
// Optionally add glow as a child of the mesh so it follows transforms
|
|
294
303
|
if (glow) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "entangled-worlds-orbiters-shared",
|
|
3
|
-
"version": "6.0.
|
|
3
|
+
"version": "6.0.2",
|
|
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": "dist/index.js",
|
|
@@ -20,7 +20,7 @@ export interface ShortcutSheetColumn extends ShortcutNamed {
|
|
|
20
20
|
readonly rows: readonly ShortcutSheetRow[]
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
/** One surface's keys (`orbiters-play`, `ew-studio`, `
|
|
23
|
+
/** One surface's keys (`orbiters-play`, `ew-clip-studio`, `root`). Two actions clash only inside a section. */
|
|
24
24
|
export interface ShortcutSection {
|
|
25
25
|
readonly id: string
|
|
26
26
|
/** The app it belongs to (`orbiters`) and that app's name. */
|
|
@@ -135,7 +135,7 @@ export function localAppName(section: Pick<ShortcutSection, 'appLabel' | 'appNam
|
|
|
135
135
|
return localName({ label: section.appLabel, names: section.appNames }, locale)
|
|
136
136
|
}
|
|
137
137
|
|
|
138
|
-
/** A section's part name (`Play`, `Studio`) in a language; `undefined` when it has none. */
|
|
138
|
+
/** A section's part name (`Play`, `Orbiter Studio`) in a language; `undefined` when it has none. */
|
|
139
139
|
export function localPartName(section: Pick<ShortcutSection, 'part' | 'partNames'>, locale?: string): string | undefined {
|
|
140
140
|
return section.part === undefined ? undefined : localName({ label: section.part, names: section.partNames }, locale)
|
|
141
141
|
}
|
package/src/world/cloudShell.ts
CHANGED
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
import * as THREE from 'three';
|
|
2
2
|
import { loadTexture } from '../loaders/bodyTextureLoader.js';
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* The cloud texture could not be loaded (offline, gone from the CDN, or not decodable). Its own type
|
|
6
|
+
* so the world builders can drop just the clouds on THIS failure and still let any other error out.
|
|
7
|
+
* `cause` is what the loader threw.
|
|
8
|
+
*/
|
|
9
|
+
export class CloudTextureError extends Error {
|
|
10
|
+
constructor(url: string, cause: unknown) {
|
|
11
|
+
super(`Cloud texture could not be loaded: ${url}`, { cause });
|
|
12
|
+
this.name = 'CloudTextureError';
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
4
16
|
// Texture-only clouds material (alpha mask + tint), UV-scrolled
|
|
5
17
|
async function makeTextureMaterial({
|
|
6
18
|
color = 0xffffff,
|
|
@@ -29,7 +41,13 @@ async function makeTextureMaterial({
|
|
|
29
41
|
if (textureUrl) {
|
|
30
42
|
// Thread the owning view's renderer: KTX2 cloud textures must transcode against the caller's
|
|
31
43
|
// context, not the global fallback (which shared-renderer pages don't publish at all).
|
|
32
|
-
|
|
44
|
+
let tex: THREE.Texture;
|
|
45
|
+
try {
|
|
46
|
+
tex = await loadTexture(textureUrl, { renderer });
|
|
47
|
+
} catch (cause) {
|
|
48
|
+
mat.dispose();
|
|
49
|
+
throw new CloudTextureError(textureUrl, cause);
|
|
50
|
+
}
|
|
33
51
|
tex.wrapS = THREE.RepeatWrapping;
|
|
34
52
|
tex.wrapT = THREE.RepeatWrapping;
|
|
35
53
|
// Use linear space for alpha masks if available
|
|
@@ -84,10 +102,7 @@ export async function createCloudShell({
|
|
|
84
102
|
speed?: number | undefined;
|
|
85
103
|
renderer?: THREE.WebGLRenderer | null | undefined;
|
|
86
104
|
} = {}) {
|
|
87
|
-
|
|
88
|
-
? baseGeometry.clone()
|
|
89
|
-
: new THREE.SphereGeometry(baseRadius, widthSegments, heightSegments);
|
|
90
|
-
|
|
105
|
+
// The texture first: when it cannot be loaded this throws before any geometry exists to leak.
|
|
91
106
|
const material = await makeTextureMaterial({
|
|
92
107
|
color,
|
|
93
108
|
opacity,
|
|
@@ -95,6 +110,9 @@ export async function createCloudShell({
|
|
|
95
110
|
speed,
|
|
96
111
|
renderer,
|
|
97
112
|
});
|
|
113
|
+
const geom = baseGeometry
|
|
114
|
+
? baseGeometry.clone()
|
|
115
|
+
: new THREE.SphereGeometry(baseRadius, widthSegments, heightSegments);
|
|
98
116
|
|
|
99
117
|
const mesh = new THREE.Mesh(geom, material);
|
|
100
118
|
const s = 1.001; // fixed scale
|
package/src/world/worldNormal.ts
CHANGED
|
@@ -3,7 +3,7 @@ import * as THREE from 'three';
|
|
|
3
3
|
import { EARTH_RADIUS_UNITS } from './worldTexture.js';
|
|
4
4
|
import { applyFlagsToMaterial } from '../utils/materials.js';
|
|
5
5
|
import { getLightFresnel } from '../core/lightFresnel.js';
|
|
6
|
-
import { createCloudShell } from './cloudShell.js';
|
|
6
|
+
import { CloudTextureError, createCloudShell } from './cloudShell.js';
|
|
7
7
|
import { resolvePublicUrl } from '../config/env.js';
|
|
8
8
|
|
|
9
9
|
/**
|
|
@@ -89,8 +89,15 @@ export async function makeNormalSphere({
|
|
|
89
89
|
opacity: cloudsOpacity,
|
|
90
90
|
speed: cloudsSpeed,
|
|
91
91
|
renderer,
|
|
92
|
+
}).catch((e: unknown) => {
|
|
93
|
+
// Clouds are an optional layer: a texture that cannot be loaded (offline, or gone from the
|
|
94
|
+
// CDN) costs the clouds, never the planet — the same way a failed surface texture does. Only
|
|
95
|
+
// that: any other error building the shell is a bug and still fails the build.
|
|
96
|
+
if (!(e instanceof CloudTextureError)) throw e;
|
|
97
|
+
console.warn('[worldNormal] Failed to load clouds, drawing the world without them:', e.cause);
|
|
98
|
+
return null;
|
|
92
99
|
});
|
|
93
|
-
mesh.add(cloudMesh);
|
|
100
|
+
if (cloudMesh) mesh.add(cloudMesh);
|
|
94
101
|
}
|
|
95
102
|
|
|
96
103
|
return mesh;
|
|
@@ -2,7 +2,7 @@ import * as THREE from 'three';
|
|
|
2
2
|
import { loadTexture } from '../loaders/bodyTextureLoader.js';
|
|
3
3
|
import { applyFlagsToMaterial } from '../utils/materials.js';
|
|
4
4
|
import { getLightFresnel } from '../core/lightFresnel.js';
|
|
5
|
-
import { createCloudShell } from './cloudShell.js';
|
|
5
|
+
import { CloudTextureError, createCloudShell } from './cloudShell.js';
|
|
6
6
|
import { resolvePublicUrl } from '../config/env.js';
|
|
7
7
|
|
|
8
8
|
// Debug tag so you can verify the loaded file version in console
|
|
@@ -374,8 +374,15 @@ export async function makeSphere({
|
|
|
374
374
|
opacity: cloudsOpacity,
|
|
375
375
|
speed: cloudsSpeed,
|
|
376
376
|
renderer,
|
|
377
|
+
}).catch((e: unknown) => {
|
|
378
|
+
// Clouds are an optional layer: a texture that cannot be loaded (offline, or gone from the
|
|
379
|
+
// CDN) costs the clouds, never the planet — the same way a failed surface texture does. Only
|
|
380
|
+
// that: any other error building the shell is a bug and still fails the build.
|
|
381
|
+
if (!(e instanceof CloudTextureError)) throw e;
|
|
382
|
+
console.warn('[worldTexture] Failed to load clouds, drawing the world without them:', e.cause);
|
|
383
|
+
return null;
|
|
377
384
|
});
|
|
378
|
-
mesh.add(cloudMesh);
|
|
385
|
+
if (cloudMesh) mesh.add(cloudMesh);
|
|
379
386
|
}
|
|
380
387
|
|
|
381
388
|
// Optionally add glow as a child of the mesh so it follows transforms
|