@motioncomplex/cosmos-lib 1.0.9

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 (47) hide show
  1. package/README.md +125 -0
  2. package/dist/api.d.ts +246 -0
  3. package/dist/cache.d.ts +11 -0
  4. package/dist/clock.d.ts +181 -0
  5. package/dist/constants.d.ts +43 -0
  6. package/dist/data/constellations.d.ts +58 -0
  7. package/dist/data/cutouts.d.ts +70 -0
  8. package/dist/data/deep-sky.d.ts +27 -0
  9. package/dist/data/images.d.ts +147 -0
  10. package/dist/data/index.d.ts +422 -0
  11. package/dist/data/messier.d.ts +61 -0
  12. package/dist/data/ps1-files.d.ts +11 -0
  13. package/dist/data/showers.d.ts +62 -0
  14. package/dist/data/solar-system.d.ts +34 -0
  15. package/dist/data/stars.d.ts +57 -0
  16. package/dist/data/textures.d.ts +67 -0
  17. package/dist/eclipse.d.ts +176 -0
  18. package/dist/index.cjs +1 -0
  19. package/dist/index.d.ts +237 -0
  20. package/dist/index.js +713 -0
  21. package/dist/math.d.ts +532 -0
  22. package/dist/media-DVOcIMa1.js +252 -0
  23. package/dist/media-DlE7RKBL.cjs +1 -0
  24. package/dist/media.d.ts +217 -0
  25. package/dist/moon.d.ts +170 -0
  26. package/dist/planner.d.ts +224 -0
  27. package/dist/react/index.cjs +1 -0
  28. package/dist/react/index.d.ts +167 -0
  29. package/dist/react/index.js +163 -0
  30. package/dist/skymap-hittest.d.ts +69 -0
  31. package/dist/skymap-interactive-CLg6FA0X.js +6377 -0
  32. package/dist/skymap-interactive-D2OZFwJ7.cjs +1 -0
  33. package/dist/skymap-interactive.d.ts +153 -0
  34. package/dist/skymap.d.ts +172 -0
  35. package/dist/sun.d.ts +119 -0
  36. package/dist/three/factories.d.ts +160 -0
  37. package/dist/three/flight.d.ts +116 -0
  38. package/dist/three/index.cjs +20 -0
  39. package/dist/three/index.d.ts +21 -0
  40. package/dist/three/index.js +404 -0
  41. package/dist/three/lod.d.ts +100 -0
  42. package/dist/three/shaders.d.ts +22 -0
  43. package/dist/three/types.d.ts +169 -0
  44. package/dist/transitions.d.ts +246 -0
  45. package/dist/types.d.ts +730 -0
  46. package/dist/units.d.ts +132 -0
  47. package/package.json +93 -0
@@ -0,0 +1,116 @@
1
+ import type * as THREE from 'three';
2
+ import type { FlightOptions, OrbitAroundOptions } from './types.js';
3
+ type OrbitControls = {
4
+ target: THREE.Vector3;
5
+ update: () => void;
6
+ enablePan: boolean;
7
+ enableZoom: boolean;
8
+ enableRotate: boolean;
9
+ };
10
+ type StopHandle = {
11
+ stop: () => void;
12
+ };
13
+ /**
14
+ * Smooth camera flight controller.
15
+ *
16
+ * Animates both camera position and `OrbitControls` target simultaneously
17
+ * using a pure cubic Bezier easing curve -- no GSAP or tween library required.
18
+ * Supports one-shot flights ({@link flyTo}) and continuous orbits
19
+ * ({@link orbitAround}).
20
+ *
21
+ * @example
22
+ * ```ts
23
+ * import * as THREE from 'three'
24
+ * import { OrbitControls } from 'three/addons/controls/OrbitControls.js'
25
+ * import { CameraFlight } from '@motioncomplex/cosmos-lib/three'
26
+ *
27
+ * const camera = new THREE.PerspectiveCamera(60, w / h, 0.1, 100_000)
28
+ * const controls = new OrbitControls(camera, renderer.domElement)
29
+ * const flight = new CameraFlight(camera, controls, THREE)
30
+ *
31
+ * // Fly to Mars
32
+ * flight.flyTo(
33
+ * { x: 200, y: 50, z: 200 },
34
+ * { x: 180, y: 0, z: 0 },
35
+ * { duration: 3000, easing: 'inOut', onDone: () => console.log('arrived') },
36
+ * )
37
+ *
38
+ * // Orbit around a planet
39
+ * const handle = flight.orbitAround(
40
+ * { x: 180, y: 0, z: 0 },
41
+ * { radius: 40, speed: 0.0008 },
42
+ * )
43
+ * // Stop orbiting later
44
+ * handle.stop()
45
+ * ```
46
+ */
47
+ export declare class CameraFlight {
48
+ private _camera;
49
+ private _controls;
50
+ private _THREE;
51
+ private _active;
52
+ private _orbitHandles;
53
+ /**
54
+ * @param camera - The Three.js camera to animate.
55
+ * @param controls - An `OrbitControls`-compatible object whose `target` is
56
+ * updated in sync with the camera position.
57
+ * @param THREE - The Three.js module, passed at runtime to avoid a hard
58
+ * dependency on `three` in the library bundle.
59
+ */
60
+ constructor(camera: THREE.Camera, controls: OrbitControls, THREE: typeof import('three'));
61
+ /**
62
+ * Fly the camera to a world-space position while smoothly re-targeting the
63
+ * look-at point. The animation uses `requestAnimationFrame` internally and
64
+ * is frame-rate independent.
65
+ *
66
+ * Only one flight can be active at a time; starting a new flight implicitly
67
+ * cancels any in-progress one.
68
+ *
69
+ * @param toPosition - Destination camera position in world coordinates.
70
+ * @param toTarget - Destination look-at point (`OrbitControls.target`).
71
+ * @param opts - Animation options (duration, easing curve, completion callback).
72
+ * @returns `void` -- listen for completion via `opts.onDone`.
73
+ */
74
+ flyTo(toPosition: {
75
+ x: number;
76
+ y: number;
77
+ z: number;
78
+ }, toTarget: {
79
+ x: number;
80
+ y: number;
81
+ z: number;
82
+ }, opts?: FlightOptions): void;
83
+ /**
84
+ * Continuously orbit the camera around a world-space point.
85
+ *
86
+ * Uses delta-time for frame-rate independent rotation. Multiple orbits
87
+ * can be active simultaneously; each returns an independent stop handle.
88
+ * All active orbits are terminated when {@link dispose} is called.
89
+ *
90
+ * @param center - The world-space point to orbit around.
91
+ * @param opts - Orbit configuration (radius, angular speed, elevation).
92
+ * @returns A `{ stop }` handle. Call `handle.stop()` to halt the orbit.
93
+ */
94
+ orbitAround(center: {
95
+ x: number;
96
+ y: number;
97
+ z: number;
98
+ }, opts?: OrbitAroundOptions): StopHandle;
99
+ /**
100
+ * Cancel any in-progress {@link flyTo} animation.
101
+ *
102
+ * Active {@link orbitAround} loops are **not** affected -- use
103
+ * {@link dispose} to stop everything.
104
+ */
105
+ cancel(): void;
106
+ /**
107
+ * Stop all active orbits and cancel any in-progress flight.
108
+ *
109
+ * Call this when tearing down the scene or when the `CameraFlight`
110
+ * instance is no longer needed to ensure no lingering `requestAnimationFrame`
111
+ * callbacks remain.
112
+ */
113
+ dispose(): void;
114
+ private _makeEase;
115
+ }
116
+ export {};
@@ -0,0 +1,20 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const b=require("../media-DlE7RKBL.cjs"),y={atmosphereVert:`
2
+ varying vec3 vNormal;
3
+ varying vec3 vViewDir;
4
+ void main() {
5
+ vec4 worldPos = modelMatrix * vec4(position, 1.0);
6
+ vViewDir = normalize(cameraPosition - worldPos.xyz);
7
+ vNormal = normalize(normalMatrix * normal);
8
+ gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
9
+ }
10
+ `,atmosphereFrag:`
11
+ uniform vec3 uAtmColor;
12
+ uniform float uIntensity;
13
+ varying vec3 vNormal;
14
+ varying vec3 vViewDir;
15
+ void main() {
16
+ float rim = 1.0 - abs(dot(vNormal, vViewDir));
17
+ float alpha = pow(rim, 3.0) * uIntensity;
18
+ gl_FragColor = vec4(uAtmColor * alpha, alpha);
19
+ }
20
+ `};function D(r,e){var h,u;const t=new e.Group,i=new e.TextureLoader,n=[];(h=i.setCrossOrigin)==null||h.call(i,"anonymous");let s;if(r.isBlackHole)s=new e.MeshBasicMaterial({color:0});else{const o=new e.MeshStandardMaterial({color:r.color??16777215,roughness:.8,metalness:.1});if((u=r.textureUrls)!=null&&u.length)b.Media.chainLoad(r.textureUrls).then(a=>{const d=i.load(a);d.colorSpace=e.SRGBColorSpace,o.map=d,o.needsUpdate=!0,n.push(d)}).catch(()=>{});else if(r.textureUrl){const a=i.load(r.textureUrl);a.colorSpace=e.SRGBColorSpace,o.map=a,n.push(a)}if(r.bumpUrl){const a=i.load(r.bumpUrl);o.bumpMap=a,o.bumpScale=.025,n.push(a)}r.emissive!==void 0&&(o.emissive=new e.Color(r.emissive),o.emissiveIntensity=r.emissiveIntensity??1),s=o}n.push(s);const c=new e.SphereGeometry(r.radius,64,64),l=new e.Mesh(c,s);if(t.add(l),n.push(c),r.atmosphere&&!r.isBlackHole){const o=x(r.radius,r.atmosphere.color,e,r.atmosphere.intensity??1.2);t.add(o),(o.userData._toDispose??[]).forEach(a=>n.push(a))}if(r.rings){const{inner:o,outer:a,color:d,opacity:m,tilt:p=0}=r.rings,f=new e.RingGeometry(r.radius*o,r.radius*a,128),g=f.attributes.position,w=f.attributes.uv,M=new e.Vector3;for(let v=0;v<g.count;v++){M.fromBufferAttribute(g,v);const A=(M.length()-r.radius*o)/(r.radius*(a-o));w.setXY(v,A,.5)}w.needsUpdate=!0,f.rotateX(-Math.PI/2);const _=new e.MeshStandardMaterial({color:d,transparent:!0,opacity:m,side:e.DoubleSide}),S=new e.Mesh(f,_);S.rotation.x=p,t.add(S),n.push(f,_)}return{group:t,mesh:l,dispose:()=>n.forEach(o=>o.dispose())}}function B(r,e){var u;const t=new e.Group,i=new e.TextureLoader;(u=i.setCrossOrigin)==null||u.call(i,"anonymous");const n=new e.SpriteMaterial({transparent:!0,blending:e.AdditiveBlending,opacity:r.opacity??.85,depthWrite:!1,color:16777215});b.Media.chainLoad(r.textureUrls).then(o=>{i.load(o,a=>{a.colorSpace=e.SRGBColorSpace,n.map=a,n.needsUpdate=!0})}).catch(()=>{});const s=new e.Sprite(n);s.scale.set(r.radius*(r.aspect??1),r.radius,1),s.renderOrder=100,t.add(s);const c=new e.SphereGeometry(r.radius*.5,16,16),l=new e.MeshBasicMaterial({visible:!1}),h=new e.Mesh(c,l);return t.add(h),{group:t,sprite:s,hitMesh:h,dispose:()=>{var o;(o=n.map)==null||o.dispose(),n.dispose(),c.dispose(),l.dispose()}}}function x(r,e,t,i=1.2){const n=new t.SphereGeometry(r*1.06,64,64),s=new t.ShaderMaterial({uniforms:{uAtmColor:{value:new t.Color(e)},uIntensity:{value:i}},vertexShader:y.atmosphereVert,fragmentShader:y.atmosphereFrag,side:t.BackSide,blending:t.AdditiveBlending,transparent:!0,depthWrite:!1}),c=new t.Mesh(n,s);return c.userData._toDispose=[n,s],c}function C(r={},e){const{count:t=4e4,minRadius:i=3e4,maxRadius:n=15e4,sizeMin:s=1.5,sizeMax:c=4,opacity:l=.7}=r,h=new Float32Array(t*3),u=new Float32Array(t*3);for(let m=0;m<t;m++){const p=i+Math.random()*(n-i),f=2*Math.PI*Math.random(),g=Math.acos(2*Math.random()-1);h[m*3]=p*Math.sin(g)*Math.cos(f),h[m*3+1]=p*Math.sin(g)*Math.sin(f),h[m*3+2]=p*Math.cos(g);const w=Math.random(),M=new e.Color(w>.7?11193599:w>.5?16768426:16777215),_=.5+Math.random()*.5;u[m*3]=M.r*_,u[m*3+1]=M.g*_,u[m*3+2]=M.b*_}const o=new e.BufferGeometry;o.setAttribute("position",new e.BufferAttribute(h,3)),o.setAttribute("color",new e.BufferAttribute(u,3));const a=new e.PointsMaterial({size:(s+c)/2,vertexColors:!0,transparent:!0,opacity:l,sizeAttenuation:!0}),d=new e.Points(o,a);return d.userData.dispose=()=>{o.dispose(),a.dispose()},d}function O(r,e={},t){const{color:i=16777215,opacity:n=.1,segments:s=128}=e,c=[];for(let o=0;o<=s;o++){const a=o/s*Math.PI*2;c.push(Math.cos(a)*r,0,Math.sin(a)*r)}const l=new t.BufferGeometry;l.setAttribute("position",new t.Float32BufferAttribute(c,3));const h=new t.LineBasicMaterial({color:i,transparent:!0,opacity:n}),u=new t.Line(l,h);return u.userData.dispose=()=>{l.dispose(),h.dispose()},u}class G{constructor(e,t={}){var i,n;this._entries=[],this._THREE=e,this._loader=new e.TextureLoader,(n=(i=this._loader).setCrossOrigin)==null||n.call(i,"anonymous"),this._opts=t}register(e,t,i,n){const s=this._THREE,c=this._loader.load(t);c.colorSpace=s.SRGBColorSpace;const l=e.material;l.map=c,l.needsUpdate=!0,this._entries.push({mesh:e,lodDistance:n,lowUrl:t,highUrl:i,currentLOD:"low",loading:!1,lowTex:c,highTex:null})}unregister(e){var n,s;const t=this._entries.findIndex(c=>c.mesh===e);if(t===-1)return;const i=this._entries[t];(n=i.lowTex)==null||n.dispose(),(s=i.highTex)==null||s.dispose(),this._entries.splice(t,1)}update(e){var n;const t=this._THREE,i=e.position;for(const s of this._entries){const c=new t.Vector3;s.mesh.getWorldPosition(c);const l=i.distanceTo(c);if(l<s.lodDistance&&s.currentLOD==="low"&&!s.loading){s.loading=!0;let h=!1,u=null;this._opts.timeout&&this._opts.timeout>0&&(u=setTimeout(()=>{var o,a;h=!0,s.loading=!1,(a=(o=this._opts).onError)==null||a.call(o,s.mesh,new Error(`Texture load timed out after ${this._opts.timeout}ms`))},this._opts.timeout)),this._loader.load(s.highUrl,o=>{if(h){o.dispose();return}u&&clearTimeout(u),o.colorSpace=t.SRGBColorSpace,s.highTex=o;const a=s.mesh.material;a.map=o,a.needsUpdate=!0,s.currentLOD="high",s.loading=!1},void 0,o=>{var a,d;h||(u&&clearTimeout(u),s.loading=!1,(d=(a=this._opts).onError)==null||d.call(a,s.mesh,o))})}if(l>s.lodDistance*1.6&&s.currentLOD==="high"){const h=s.mesh.material;h.map=s.lowTex,h.needsUpdate=!0,(n=s.highTex)==null||n.dispose(),s.highTex=null,s.currentLOD="low"}}}dispose(){var e,t;for(const i of this._entries)(e=i.lowTex)==null||e.dispose(),(t=i.highTex)==null||t.dispose();this._entries=[]}}class P{constructor(e,t,i){this._active=!1,this._orbitHandles=new Set,this._camera=e,this._controls=t,this._THREE=i}flyTo(e,t,i={}){const{duration:n=2e3,easing:s="inOut",onDone:c}=i,l=this._THREE,h=this._camera.position.clone(),u=this._controls.target.clone(),o=new l.Vector3(e.x,e.y,e.z),a=new l.Vector3(t.x,t.y,t.z),d=this._makeEase(s),m=performance.now();this._active=!0;const p=f=>{if(!this._active)return;const g=Math.min((f-m)/n,1),w=d(g);this._camera.position.lerpVectors(h,o,w),this._controls.target.lerpVectors(u,a,w),this._controls.update(),g<1?requestAnimationFrame(p):(this._active=!1,c==null||c())};requestAnimationFrame(p)}orbitAround(e,t={}){const{radius:i=200,speed:n=5e-4,elevation:s=.2}=t,c=this._THREE,l=new c.Vector3(e.x,e.y,e.z);let h=0,u=!0,o=performance.now();const a={stop:()=>{u=!1,this._orbitHandles.delete(a)}};this._orbitHandles.add(a);const d=m=>{if(!u)return;const p=(m-o)/1e3;o=m,h+=n*p*60,this._camera.position.set(l.x+Math.cos(h)*i,l.y+s*i,l.z+Math.sin(h)*i),this._camera.lookAt(l),this._controls.target.copy(l),requestAnimationFrame(d)};return requestAnimationFrame(d),a}cancel(){this._active=!1}dispose(){this.cancel();for(const e of this._orbitHandles)e.stop();this._orbitHandles.clear()}_makeEase(e){switch(e){case"in":return t=>t*t*t;case"out":return t=>1-(1-t)**3;default:return t=>t<.5?4*t**3:1-(-2*t+2)**3/2}}}exports.CameraFlight=P;exports.LODTextureManager=G;exports.SHADERS=y;exports.createAtmosphere=x;exports.createNebula=B;exports.createOrbit=O;exports.createPlanet=D;exports.createStarField=C;
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Optional Three.js integration layer for `@motioncomplex/cosmos-lib`.
3
+ *
4
+ * Import from the `/three` sub-path to access scene-object factories,
5
+ * camera flight controls, LOD texture management, and built-in GLSL shaders:
6
+ *
7
+ * ```ts
8
+ * import { createPlanet, CameraFlight, LODTextureManager } from '@motioncomplex/cosmos-lib/three'
9
+ * ```
10
+ *
11
+ * All factory functions accept the Three.js module as a runtime parameter
12
+ * (`THREE`) so that this package does **not** bundle or depend on `three`
13
+ * directly -- consumers supply their own Three.js instance.
14
+ *
15
+ * @packageDocumentation
16
+ */
17
+ export { createPlanet, createNebula, createAtmosphere, createStarField, createOrbit } from './factories.js';
18
+ export { LODTextureManager } from './lod.js';
19
+ export { CameraFlight } from './flight.js';
20
+ export { SHADERS } from './shaders.js';
21
+ export type { PlanetOptions, PlanetResult, NebulaOptions, NebulaResult, StarFieldOptions, OrbitOptions, FlightOptions, OrbitAroundOptions, } from './types.js';
@@ -0,0 +1,404 @@
1
+ import { M as S } from "../media-DVOcIMa1.js";
2
+ const x = {
3
+ atmosphereVert: (
4
+ /* glsl */
5
+ `
6
+ varying vec3 vNormal;
7
+ varying vec3 vViewDir;
8
+ void main() {
9
+ vec4 worldPos = modelMatrix * vec4(position, 1.0);
10
+ vViewDir = normalize(cameraPosition - worldPos.xyz);
11
+ vNormal = normalize(normalMatrix * normal);
12
+ gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
13
+ }
14
+ `
15
+ ),
16
+ atmosphereFrag: (
17
+ /* glsl */
18
+ `
19
+ uniform vec3 uAtmColor;
20
+ uniform float uIntensity;
21
+ varying vec3 vNormal;
22
+ varying vec3 vViewDir;
23
+ void main() {
24
+ float rim = 1.0 - abs(dot(vNormal, vViewDir));
25
+ float alpha = pow(rim, 3.0) * uIntensity;
26
+ gl_FragColor = vec4(uAtmColor * alpha, alpha);
27
+ }
28
+ `
29
+ )
30
+ };
31
+ function C(r, e) {
32
+ var h, u;
33
+ const t = new e.Group(), i = new e.TextureLoader(), a = [];
34
+ (h = i.setCrossOrigin) == null || h.call(i, "anonymous");
35
+ let s;
36
+ if (r.isBlackHole)
37
+ s = new e.MeshBasicMaterial({ color: 0 });
38
+ else {
39
+ const o = new e.MeshStandardMaterial({
40
+ color: r.color ?? 16777215,
41
+ roughness: 0.8,
42
+ metalness: 0.1
43
+ });
44
+ if ((u = r.textureUrls) != null && u.length)
45
+ S.chainLoad(r.textureUrls).then((n) => {
46
+ const d = i.load(n);
47
+ d.colorSpace = e.SRGBColorSpace, o.map = d, o.needsUpdate = !0, a.push(d);
48
+ }).catch(() => {
49
+ });
50
+ else if (r.textureUrl) {
51
+ const n = i.load(r.textureUrl);
52
+ n.colorSpace = e.SRGBColorSpace, o.map = n, a.push(n);
53
+ }
54
+ if (r.bumpUrl) {
55
+ const n = i.load(r.bumpUrl);
56
+ o.bumpMap = n, o.bumpScale = 0.025, a.push(n);
57
+ }
58
+ r.emissive !== void 0 && (o.emissive = new e.Color(r.emissive), o.emissiveIntensity = r.emissiveIntensity ?? 1), s = o;
59
+ }
60
+ a.push(s);
61
+ const c = new e.SphereGeometry(r.radius, 64, 64), l = new e.Mesh(c, s);
62
+ if (t.add(l), a.push(c), r.atmosphere && !r.isBlackHole) {
63
+ const o = A(
64
+ r.radius,
65
+ r.atmosphere.color,
66
+ e,
67
+ r.atmosphere.intensity ?? 1.2
68
+ );
69
+ t.add(o), (o.userData._toDispose ?? []).forEach((n) => a.push(n));
70
+ }
71
+ if (r.rings) {
72
+ const { inner: o, outer: n, color: d, opacity: m, tilt: p = 0 } = r.rings, f = new e.RingGeometry(r.radius * o, r.radius * n, 128), w = f.attributes.position, g = f.attributes.uv, M = new e.Vector3();
73
+ for (let v = 0; v < w.count; v++) {
74
+ M.fromBufferAttribute(w, v);
75
+ const b = (M.length() - r.radius * o) / (r.radius * (n - o));
76
+ g.setXY(v, b, 0.5);
77
+ }
78
+ g.needsUpdate = !0, f.rotateX(-Math.PI / 2);
79
+ const _ = new e.MeshStandardMaterial({
80
+ color: d,
81
+ transparent: !0,
82
+ opacity: m,
83
+ side: e.DoubleSide
84
+ }), y = new e.Mesh(f, _);
85
+ y.rotation.x = p, t.add(y), a.push(f, _);
86
+ }
87
+ return {
88
+ group: t,
89
+ mesh: l,
90
+ dispose: () => a.forEach((o) => o.dispose())
91
+ };
92
+ }
93
+ function G(r, e) {
94
+ var u;
95
+ const t = new e.Group(), i = new e.TextureLoader();
96
+ (u = i.setCrossOrigin) == null || u.call(i, "anonymous");
97
+ const a = new e.SpriteMaterial({
98
+ transparent: !0,
99
+ blending: e.AdditiveBlending,
100
+ opacity: r.opacity ?? 0.85,
101
+ depthWrite: !1,
102
+ color: 16777215
103
+ });
104
+ S.chainLoad(r.textureUrls).then((o) => {
105
+ i.load(o, (n) => {
106
+ n.colorSpace = e.SRGBColorSpace, a.map = n, a.needsUpdate = !0;
107
+ });
108
+ }).catch(() => {
109
+ });
110
+ const s = new e.Sprite(a);
111
+ s.scale.set(r.radius * (r.aspect ?? 1), r.radius, 1), s.renderOrder = 100, t.add(s);
112
+ const c = new e.SphereGeometry(r.radius * 0.5, 16, 16), l = new e.MeshBasicMaterial({ visible: !1 }), h = new e.Mesh(c, l);
113
+ return t.add(h), {
114
+ group: t,
115
+ sprite: s,
116
+ hitMesh: h,
117
+ dispose: () => {
118
+ var o;
119
+ (o = a.map) == null || o.dispose(), a.dispose(), c.dispose(), l.dispose();
120
+ }
121
+ };
122
+ }
123
+ function A(r, e, t, i = 1.2) {
124
+ const a = new t.SphereGeometry(r * 1.06, 64, 64), s = new t.ShaderMaterial({
125
+ uniforms: {
126
+ uAtmColor: { value: new t.Color(e) },
127
+ uIntensity: { value: i }
128
+ },
129
+ vertexShader: x.atmosphereVert,
130
+ fragmentShader: x.atmosphereFrag,
131
+ side: t.BackSide,
132
+ blending: t.AdditiveBlending,
133
+ transparent: !0,
134
+ depthWrite: !1
135
+ }), c = new t.Mesh(a, s);
136
+ return c.userData._toDispose = [a, s], c;
137
+ }
138
+ function U(r = {}, e) {
139
+ const {
140
+ count: t = 4e4,
141
+ minRadius: i = 3e4,
142
+ maxRadius: a = 15e4,
143
+ sizeMin: s = 1.5,
144
+ sizeMax: c = 4,
145
+ opacity: l = 0.7
146
+ } = r, h = new Float32Array(t * 3), u = new Float32Array(t * 3);
147
+ for (let m = 0; m < t; m++) {
148
+ const p = i + Math.random() * (a - i), f = 2 * Math.PI * Math.random(), w = Math.acos(2 * Math.random() - 1);
149
+ h[m * 3] = p * Math.sin(w) * Math.cos(f), h[m * 3 + 1] = p * Math.sin(w) * Math.sin(f), h[m * 3 + 2] = p * Math.cos(w);
150
+ const g = Math.random(), M = new e.Color(g > 0.7 ? 11193599 : g > 0.5 ? 16768426 : 16777215), _ = 0.5 + Math.random() * 0.5;
151
+ u[m * 3] = M.r * _, u[m * 3 + 1] = M.g * _, u[m * 3 + 2] = M.b * _;
152
+ }
153
+ const o = new e.BufferGeometry();
154
+ o.setAttribute("position", new e.BufferAttribute(h, 3)), o.setAttribute("color", new e.BufferAttribute(u, 3));
155
+ const n = new e.PointsMaterial({
156
+ size: (s + c) / 2,
157
+ vertexColors: !0,
158
+ transparent: !0,
159
+ opacity: l,
160
+ sizeAttenuation: !0
161
+ }), d = new e.Points(o, n);
162
+ return d.userData.dispose = () => {
163
+ o.dispose(), n.dispose();
164
+ }, d;
165
+ }
166
+ function V(r, e = {}, t) {
167
+ const { color: i = 16777215, opacity: a = 0.1, segments: s = 128 } = e, c = [];
168
+ for (let o = 0; o <= s; o++) {
169
+ const n = o / s * Math.PI * 2;
170
+ c.push(Math.cos(n) * r, 0, Math.sin(n) * r);
171
+ }
172
+ const l = new t.BufferGeometry();
173
+ l.setAttribute("position", new t.Float32BufferAttribute(c, 3));
174
+ const h = new t.LineBasicMaterial({ color: i, transparent: !0, opacity: a }), u = new t.Line(l, h);
175
+ return u.userData.dispose = () => {
176
+ l.dispose(), h.dispose();
177
+ }, u;
178
+ }
179
+ class L {
180
+ /**
181
+ * @param THREE - The Three.js module, passed at runtime to avoid a hard
182
+ * dependency on `three` in the library bundle.
183
+ * @param opts - Optional error and timeout configuration.
184
+ */
185
+ constructor(e, t = {}) {
186
+ var i, a;
187
+ this._entries = [], this._THREE = e, this._loader = new e.TextureLoader(), (a = (i = this._loader).setCrossOrigin) == null || a.call(i, "anonymous"), this._opts = t;
188
+ }
189
+ /**
190
+ * Register a mesh for LOD texture management.
191
+ *
192
+ * The low-res texture is loaded immediately and applied to the mesh's
193
+ * material. The high-res texture is loaded lazily the first time the camera
194
+ * comes within `lodDistance` of the mesh.
195
+ *
196
+ * @param mesh - Target mesh whose material will be swapped. Must use a
197
+ * `MeshStandardMaterial` (or compatible) with a `map` slot.
198
+ * @param lowResUrl - URL for the low-resolution texture, loaded eagerly.
199
+ * @param highResUrl - URL for the high-resolution texture, loaded on demand.
200
+ * @param lodDistance - Camera distance threshold (in scene units) at which the
201
+ * high-res texture is loaded and applied.
202
+ */
203
+ register(e, t, i, a) {
204
+ const s = this._THREE, c = this._loader.load(t);
205
+ c.colorSpace = s.SRGBColorSpace;
206
+ const l = e.material;
207
+ l.map = c, l.needsUpdate = !0, this._entries.push({
208
+ mesh: e,
209
+ lodDistance: a,
210
+ lowUrl: t,
211
+ highUrl: i,
212
+ currentLOD: "low",
213
+ loading: !1,
214
+ lowTex: c,
215
+ highTex: null
216
+ });
217
+ }
218
+ /**
219
+ * Unregister a mesh from LOD management and dispose its textures.
220
+ *
221
+ * After calling this, the mesh's material `map` will still reference the
222
+ * last-applied texture, but the texture GPU memory is freed. Assign a new
223
+ * texture or remove the mesh from the scene as needed.
224
+ *
225
+ * @param mesh - The mesh previously passed to {@link register}. If the mesh
226
+ * was never registered, this is a no-op.
227
+ */
228
+ unregister(e) {
229
+ var a, s;
230
+ const t = this._entries.findIndex((c) => c.mesh === e);
231
+ if (t === -1) return;
232
+ const i = this._entries[t];
233
+ (a = i.lowTex) == null || a.dispose(), (s = i.highTex) == null || s.dispose(), this._entries.splice(t, 1);
234
+ }
235
+ /**
236
+ * Evaluate all registered meshes and swap textures as needed.
237
+ *
238
+ * Call this once per frame inside your render loop. For each mesh the
239
+ * manager checks the camera-to-mesh distance and:
240
+ * - loads the high-res texture when the camera enters `lodDistance`, and
241
+ * - reverts to the low-res texture when the camera moves beyond
242
+ * `lodDistance * 1.6` (hysteresis to prevent thrashing).
243
+ *
244
+ * @param camera - The active Three.js camera used for distance checks.
245
+ */
246
+ update(e) {
247
+ var a;
248
+ const t = this._THREE, i = e.position;
249
+ for (const s of this._entries) {
250
+ const c = new t.Vector3();
251
+ s.mesh.getWorldPosition(c);
252
+ const l = i.distanceTo(c);
253
+ if (l < s.lodDistance && s.currentLOD === "low" && !s.loading) {
254
+ s.loading = !0;
255
+ let h = !1, u = null;
256
+ this._opts.timeout && this._opts.timeout > 0 && (u = setTimeout(() => {
257
+ var o, n;
258
+ h = !0, s.loading = !1, (n = (o = this._opts).onError) == null || n.call(o, s.mesh, new Error(`Texture load timed out after ${this._opts.timeout}ms`));
259
+ }, this._opts.timeout)), this._loader.load(
260
+ s.highUrl,
261
+ (o) => {
262
+ if (h) {
263
+ o.dispose();
264
+ return;
265
+ }
266
+ u && clearTimeout(u), o.colorSpace = t.SRGBColorSpace, s.highTex = o;
267
+ const n = s.mesh.material;
268
+ n.map = o, n.needsUpdate = !0, s.currentLOD = "high", s.loading = !1;
269
+ },
270
+ void 0,
271
+ (o) => {
272
+ var n, d;
273
+ h || (u && clearTimeout(u), s.loading = !1, (d = (n = this._opts).onError) == null || d.call(n, s.mesh, o));
274
+ }
275
+ );
276
+ }
277
+ if (l > s.lodDistance * 1.6 && s.currentLOD === "high") {
278
+ const h = s.mesh.material;
279
+ h.map = s.lowTex, h.needsUpdate = !0, (a = s.highTex) == null || a.dispose(), s.highTex = null, s.currentLOD = "low";
280
+ }
281
+ }
282
+ }
283
+ /**
284
+ * Dispose all registered textures (both low- and high-res) and clear the
285
+ * internal registry.
286
+ *
287
+ * After calling this, no further {@link update} calls will have any effect
288
+ * until new meshes are registered.
289
+ */
290
+ dispose() {
291
+ var e, t;
292
+ for (const i of this._entries)
293
+ (e = i.lowTex) == null || e.dispose(), (t = i.highTex) == null || t.dispose();
294
+ this._entries = [];
295
+ }
296
+ }
297
+ class O {
298
+ /**
299
+ * @param camera - The Three.js camera to animate.
300
+ * @param controls - An `OrbitControls`-compatible object whose `target` is
301
+ * updated in sync with the camera position.
302
+ * @param THREE - The Three.js module, passed at runtime to avoid a hard
303
+ * dependency on `three` in the library bundle.
304
+ */
305
+ constructor(e, t, i) {
306
+ this._active = !1, this._orbitHandles = /* @__PURE__ */ new Set(), this._camera = e, this._controls = t, this._THREE = i;
307
+ }
308
+ /**
309
+ * Fly the camera to a world-space position while smoothly re-targeting the
310
+ * look-at point. The animation uses `requestAnimationFrame` internally and
311
+ * is frame-rate independent.
312
+ *
313
+ * Only one flight can be active at a time; starting a new flight implicitly
314
+ * cancels any in-progress one.
315
+ *
316
+ * @param toPosition - Destination camera position in world coordinates.
317
+ * @param toTarget - Destination look-at point (`OrbitControls.target`).
318
+ * @param opts - Animation options (duration, easing curve, completion callback).
319
+ * @returns `void` -- listen for completion via `opts.onDone`.
320
+ */
321
+ flyTo(e, t, i = {}) {
322
+ const { duration: a = 2e3, easing: s = "inOut", onDone: c } = i, l = this._THREE, h = this._camera.position.clone(), u = this._controls.target.clone(), o = new l.Vector3(e.x, e.y, e.z), n = new l.Vector3(t.x, t.y, t.z), d = this._makeEase(s), m = performance.now();
323
+ this._active = !0;
324
+ const p = (f) => {
325
+ if (!this._active) return;
326
+ const w = Math.min((f - m) / a, 1), g = d(w);
327
+ this._camera.position.lerpVectors(h, o, g), this._controls.target.lerpVectors(u, n, g), this._controls.update(), w < 1 ? requestAnimationFrame(p) : (this._active = !1, c == null || c());
328
+ };
329
+ requestAnimationFrame(p);
330
+ }
331
+ /**
332
+ * Continuously orbit the camera around a world-space point.
333
+ *
334
+ * Uses delta-time for frame-rate independent rotation. Multiple orbits
335
+ * can be active simultaneously; each returns an independent stop handle.
336
+ * All active orbits are terminated when {@link dispose} is called.
337
+ *
338
+ * @param center - The world-space point to orbit around.
339
+ * @param opts - Orbit configuration (radius, angular speed, elevation).
340
+ * @returns A `{ stop }` handle. Call `handle.stop()` to halt the orbit.
341
+ */
342
+ orbitAround(e, t = {}) {
343
+ const { radius: i = 200, speed: a = 5e-4, elevation: s = 0.2 } = t, c = this._THREE, l = new c.Vector3(e.x, e.y, e.z);
344
+ let h = 0, u = !0, o = performance.now();
345
+ const n = {
346
+ stop: () => {
347
+ u = !1, this._orbitHandles.delete(n);
348
+ }
349
+ };
350
+ this._orbitHandles.add(n);
351
+ const d = (m) => {
352
+ if (!u) return;
353
+ const p = (m - o) / 1e3;
354
+ o = m, h += a * p * 60, this._camera.position.set(
355
+ l.x + Math.cos(h) * i,
356
+ l.y + s * i,
357
+ l.z + Math.sin(h) * i
358
+ ), this._camera.lookAt(l), this._controls.target.copy(l), requestAnimationFrame(d);
359
+ };
360
+ return requestAnimationFrame(d), n;
361
+ }
362
+ /**
363
+ * Cancel any in-progress {@link flyTo} animation.
364
+ *
365
+ * Active {@link orbitAround} loops are **not** affected -- use
366
+ * {@link dispose} to stop everything.
367
+ */
368
+ cancel() {
369
+ this._active = !1;
370
+ }
371
+ /**
372
+ * Stop all active orbits and cancel any in-progress flight.
373
+ *
374
+ * Call this when tearing down the scene or when the `CameraFlight`
375
+ * instance is no longer needed to ensure no lingering `requestAnimationFrame`
376
+ * callbacks remain.
377
+ */
378
+ dispose() {
379
+ this.cancel();
380
+ for (const e of this._orbitHandles) e.stop();
381
+ this._orbitHandles.clear();
382
+ }
383
+ // ── Private ───────────────────────────────────────────────────────────────
384
+ _makeEase(e) {
385
+ switch (e) {
386
+ case "in":
387
+ return (t) => t * t * t;
388
+ case "out":
389
+ return (t) => 1 - (1 - t) ** 3;
390
+ default:
391
+ return (t) => t < 0.5 ? 4 * t ** 3 : 1 - (-2 * t + 2) ** 3 / 2;
392
+ }
393
+ }
394
+ }
395
+ export {
396
+ O as CameraFlight,
397
+ L as LODTextureManager,
398
+ x as SHADERS,
399
+ A as createAtmosphere,
400
+ G as createNebula,
401
+ V as createOrbit,
402
+ C as createPlanet,
403
+ U as createStarField
404
+ };
@@ -0,0 +1,100 @@
1
+ import type * as THREE from 'three';
2
+ export interface LODOptions {
3
+ /** Callback when a high-res texture fails to load. */
4
+ onError?: (mesh: THREE.Mesh, error: unknown) => void;
5
+ /** Timeout in milliseconds for texture loads (0 = no timeout). */
6
+ timeout?: number;
7
+ }
8
+ /**
9
+ * Manages texture resolution for a set of meshes based on camera distance.
10
+ *
11
+ * Register objects with low- and high-resolution texture URLs via
12
+ * {@link register}. Low-res textures are loaded eagerly; high-res textures
13
+ * are loaded lazily the first time the camera enters the threshold distance.
14
+ * A 1.6x hysteresis factor prevents texture thrashing when the camera
15
+ * hovers near the boundary.
16
+ *
17
+ * Call {@link update} once per frame in your render loop.
18
+ *
19
+ * @example
20
+ * ```ts
21
+ * import * as THREE from 'three'
22
+ * import { LODTextureManager } from '@motioncomplex/cosmos-lib/three'
23
+ *
24
+ * const lod = new LODTextureManager(THREE, {
25
+ * timeout: 8000,
26
+ * onError: (mesh, err) => console.warn('LOD load failed', mesh.name, err),
27
+ * })
28
+ *
29
+ * lod.register(earthMesh, '/tex/earth-1k.jpg', '/tex/earth-8k.jpg', 500)
30
+ * lod.register(marsMesh, '/tex/mars-1k.jpg', '/tex/mars-8k.jpg', 400)
31
+ *
32
+ * // In render loop:
33
+ * function animate() {
34
+ * lod.update(camera)
35
+ * renderer.render(scene, camera)
36
+ * requestAnimationFrame(animate)
37
+ * }
38
+ *
39
+ * // On teardown:
40
+ * lod.dispose()
41
+ * ```
42
+ */
43
+ export declare class LODTextureManager {
44
+ private _THREE;
45
+ private _loader;
46
+ private _entries;
47
+ private _opts;
48
+ /**
49
+ * @param THREE - The Three.js module, passed at runtime to avoid a hard
50
+ * dependency on `three` in the library bundle.
51
+ * @param opts - Optional error and timeout configuration.
52
+ */
53
+ constructor(THREE: typeof import('three'), opts?: LODOptions);
54
+ /**
55
+ * Register a mesh for LOD texture management.
56
+ *
57
+ * The low-res texture is loaded immediately and applied to the mesh's
58
+ * material. The high-res texture is loaded lazily the first time the camera
59
+ * comes within `lodDistance` of the mesh.
60
+ *
61
+ * @param mesh - Target mesh whose material will be swapped. Must use a
62
+ * `MeshStandardMaterial` (or compatible) with a `map` slot.
63
+ * @param lowResUrl - URL for the low-resolution texture, loaded eagerly.
64
+ * @param highResUrl - URL for the high-resolution texture, loaded on demand.
65
+ * @param lodDistance - Camera distance threshold (in scene units) at which the
66
+ * high-res texture is loaded and applied.
67
+ */
68
+ register(mesh: THREE.Mesh, lowResUrl: string, highResUrl: string, lodDistance: number): void;
69
+ /**
70
+ * Unregister a mesh from LOD management and dispose its textures.
71
+ *
72
+ * After calling this, the mesh's material `map` will still reference the
73
+ * last-applied texture, but the texture GPU memory is freed. Assign a new
74
+ * texture or remove the mesh from the scene as needed.
75
+ *
76
+ * @param mesh - The mesh previously passed to {@link register}. If the mesh
77
+ * was never registered, this is a no-op.
78
+ */
79
+ unregister(mesh: THREE.Mesh): void;
80
+ /**
81
+ * Evaluate all registered meshes and swap textures as needed.
82
+ *
83
+ * Call this once per frame inside your render loop. For each mesh the
84
+ * manager checks the camera-to-mesh distance and:
85
+ * - loads the high-res texture when the camera enters `lodDistance`, and
86
+ * - reverts to the low-res texture when the camera moves beyond
87
+ * `lodDistance * 1.6` (hysteresis to prevent thrashing).
88
+ *
89
+ * @param camera - The active Three.js camera used for distance checks.
90
+ */
91
+ update(camera: THREE.Camera): void;
92
+ /**
93
+ * Dispose all registered textures (both low- and high-res) and clear the
94
+ * internal registry.
95
+ *
96
+ * After calling this, no further {@link update} calls will have any effect
97
+ * until new meshes are registered.
98
+ */
99
+ dispose(): void;
100
+ }