@scenography/plugin-sky 0.2.0

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.
@@ -0,0 +1,21 @@
1
+ import { isFiniteNumber, isNonNegativeNumber, isNumberInRange, propIs, validate } from "@scenography/scene";
2
+ //#region src/data/validate.ts
3
+ const validateSky = (sky) => validate([
4
+ propIs("time", isNumberInRange(0, 24), "time must be between 0 and 24."),
5
+ propIs("azimuth", isFiniteNumber, "azimuth must be a finite number."),
6
+ propIs("turbidity", isNonNegativeNumber, "turbidity must be a non-negative number."),
7
+ propIs("rayleigh", isNonNegativeNumber, "rayleigh must be a non-negative number."),
8
+ propIs("fog", isNonNegativeNumber, "fog must be a non-negative number.")
9
+ ])(sky);
10
+ //#endregion
11
+ //#region src/data/plugin.ts
12
+ /** The data half of the sky plugin: owns the `sky` scene key (a singleton). */
13
+ const skyData = {
14
+ kind: "sky",
15
+ cardinality: "single",
16
+ validate: (sky) => validateSky(sky)
17
+ };
18
+ //#endregion
19
+ export { validateSky as n, skyData as t };
20
+
21
+ //# sourceMappingURL=data-BY6HfW4z.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data-BY6HfW4z.mjs","names":[],"sources":["../src/data/validate.ts","../src/data/plugin.ts"],"sourcesContent":["import {\n isFiniteNumber,\n isNonNegativeNumber,\n isNumberInRange,\n propIs,\n validate,\n type ValidationResult,\n} from \"@scenography/scene\";\nimport type { Sky } from \"./sky\";\n\nexport const validateSky = (sky: Sky): ValidationResult =>\n validate<Sky>([\n propIs(\"time\", isNumberInRange(0, 24), \"time must be between 0 and 24.\"),\n propIs(\"azimuth\", isFiniteNumber, \"azimuth must be a finite number.\"),\n propIs(\"turbidity\", isNonNegativeNumber, \"turbidity must be a non-negative number.\"),\n propIs(\"rayleigh\", isNonNegativeNumber, \"rayleigh must be a non-negative number.\"),\n propIs(\"fog\", isNonNegativeNumber, \"fog must be a non-negative number.\"),\n ])(sky);\n","import type { DataPlugin } from \"@scenography/scene\";\n\nimport { validateSky } from \"./validate\";\nimport type { Sky } from \"./sky\";\n\n/** The data half of the sky plugin: owns the `sky` scene key (a singleton). */\nexport const skyData: DataPlugin<Sky> = {\n kind: \"sky\",\n cardinality: \"single\",\n validate: (sky) => validateSky(sky),\n};\n"],"mappings":";;AAUA,MAAa,eAAe,QAC1B,SAAc;CACZ,OAAO,QAAQ,gBAAgB,GAAG,EAAE,GAAG,gCAAgC;CACvE,OAAO,WAAW,gBAAgB,kCAAkC;CACpE,OAAO,aAAa,qBAAqB,0CAA0C;CACnF,OAAO,YAAY,qBAAqB,yCAAyC;CACjF,OAAO,OAAO,qBAAqB,oCAAoC;AACzE,CAAC,CAAC,CAAC,GAAG;;;;ACXR,MAAa,UAA2B;CACtC,MAAM;CACN,aAAa;CACb,WAAW,QAAQ,YAAY,GAAG;AACpC"}
@@ -0,0 +1,32 @@
1
+ let _scenography_scene = require("@scenography/scene");
2
+ //#region src/data/validate.ts
3
+ const validateSky = (sky) => (0, _scenography_scene.validate)([
4
+ (0, _scenography_scene.propIs)("time", (0, _scenography_scene.isNumberInRange)(0, 24), "time must be between 0 and 24."),
5
+ (0, _scenography_scene.propIs)("azimuth", _scenography_scene.isFiniteNumber, "azimuth must be a finite number."),
6
+ (0, _scenography_scene.propIs)("turbidity", _scenography_scene.isNonNegativeNumber, "turbidity must be a non-negative number."),
7
+ (0, _scenography_scene.propIs)("rayleigh", _scenography_scene.isNonNegativeNumber, "rayleigh must be a non-negative number."),
8
+ (0, _scenography_scene.propIs)("fog", _scenography_scene.isNonNegativeNumber, "fog must be a non-negative number.")
9
+ ])(sky);
10
+ //#endregion
11
+ //#region src/data/plugin.ts
12
+ /** The data half of the sky plugin: owns the `sky` scene key (a singleton). */
13
+ const skyData = {
14
+ kind: "sky",
15
+ cardinality: "single",
16
+ validate: (sky) => validateSky(sky)
17
+ };
18
+ //#endregion
19
+ Object.defineProperty(exports, "skyData", {
20
+ enumerable: true,
21
+ get: function() {
22
+ return skyData;
23
+ }
24
+ });
25
+ Object.defineProperty(exports, "validateSky", {
26
+ enumerable: true,
27
+ get: function() {
28
+ return validateSky;
29
+ }
30
+ });
31
+
32
+ //# sourceMappingURL=data-DM9PlHyL.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data-DM9PlHyL.cjs","names":["isFiniteNumber","isNonNegativeNumber"],"sources":["../src/data/validate.ts","../src/data/plugin.ts"],"sourcesContent":["import {\n isFiniteNumber,\n isNonNegativeNumber,\n isNumberInRange,\n propIs,\n validate,\n type ValidationResult,\n} from \"@scenography/scene\";\nimport type { Sky } from \"./sky\";\n\nexport const validateSky = (sky: Sky): ValidationResult =>\n validate<Sky>([\n propIs(\"time\", isNumberInRange(0, 24), \"time must be between 0 and 24.\"),\n propIs(\"azimuth\", isFiniteNumber, \"azimuth must be a finite number.\"),\n propIs(\"turbidity\", isNonNegativeNumber, \"turbidity must be a non-negative number.\"),\n propIs(\"rayleigh\", isNonNegativeNumber, \"rayleigh must be a non-negative number.\"),\n propIs(\"fog\", isNonNegativeNumber, \"fog must be a non-negative number.\"),\n ])(sky);\n","import type { DataPlugin } from \"@scenography/scene\";\n\nimport { validateSky } from \"./validate\";\nimport type { Sky } from \"./sky\";\n\n/** The data half of the sky plugin: owns the `sky` scene key (a singleton). */\nexport const skyData: DataPlugin<Sky> = {\n kind: \"sky\",\n cardinality: \"single\",\n validate: (sky) => validateSky(sky),\n};\n"],"mappings":";;AAUA,MAAa,eAAe,SAAA,GAAA,mBAAA,SAAA,CACZ;gCACL,SAAA,GAAA,mBAAA,gBAAA,CAAwB,GAAG,EAAE,GAAG,gCAAgC;gCAChE,WAAWA,mBAAAA,gBAAgB,kCAAkC;gCAC7D,aAAaC,mBAAAA,qBAAqB,0CAA0C;gCAC5E,YAAYA,mBAAAA,qBAAqB,yCAAyC;gCAC1E,OAAOA,mBAAAA,qBAAqB,oCAAoC;AACzE,CAAC,CAAC,CAAC,GAAG;;;;ACXR,MAAa,UAA2B;CACtC,MAAM;CACN,aAAa;CACb,WAAW,QAAQ,YAAY,GAAG;AACpC"}
package/dist/data.cjs ADDED
@@ -0,0 +1,4 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_data = require("./data-DM9PlHyL.cjs");
3
+ exports.skyData = require_data.skyData;
4
+ exports.validateSky = require_data.validateSky;
@@ -0,0 +1,2 @@
1
+ import { n as validateSky, r as Sky, t as skyData } from "./index-GwVhqXni.cjs";
2
+ export { type Sky, skyData, validateSky };
@@ -0,0 +1,2 @@
1
+ import { n as validateSky, r as Sky, t as skyData } from "./index-GwVhqXni.mjs";
2
+ export { type Sky, skyData, validateSky };
package/dist/data.mjs ADDED
@@ -0,0 +1,2 @@
1
+ import { n as validateSky, t as skyData } from "./data-BY6HfW4z.mjs";
2
+ export { skyData, validateSky };
@@ -0,0 +1,37 @@
1
+ import { DataPlugin, ValidationResult } from "@scenography/scene";
2
+
3
+ //#region src/data/sky.d.ts
4
+ /**
5
+ * A procedural sky driven by the time of day. The runtime renders an atmospheric
6
+ * sky dome, moves a sun light along its daily arc, and fades in stars at night —
7
+ * all from `time`. Always clear (no weather). Distinct from `Environment` (a
8
+ * static HDRI): a scene uses one or the other for its background.
9
+ */
10
+ interface Sky {
11
+ /** Hour of day, `0`..`24` (`6` sunrise, `12` noon, `18` sunset, `0`/`24` midnight). Default `12`. */
12
+ time?: number;
13
+ /** Compass offset (degrees) that rotates the sun's daily arc — orient the scene to the sun. Default `0`. */
14
+ azimuth?: number;
15
+ /** Atmospheric haze; higher is hazier/whiter. Default `4`. */
16
+ turbidity?: number;
17
+ /** Rayleigh scattering; higher is a deeper blue. Default `2`. */
18
+ rayleigh?: number;
19
+ /** Exponential fog density tinted to the sky (fades the horizon). `0` = none. Default `0`. */
20
+ fog?: number;
21
+ }
22
+ declare module "@scenography/scene" {
23
+ interface Scene {
24
+ /** Procedural time-of-day sky — provided by `@scenography/plugin-sky`. */
25
+ sky?: Sky;
26
+ }
27
+ }
28
+ //#endregion
29
+ //#region src/data/validate.d.ts
30
+ declare const validateSky: (sky: Sky) => ValidationResult;
31
+ //#endregion
32
+ //#region src/data/plugin.d.ts
33
+ /** The data half of the sky plugin: owns the `sky` scene key (a singleton). */
34
+ declare const skyData: DataPlugin<Sky>;
35
+ //#endregion
36
+ export { validateSky as n, Sky as r, skyData as t };
37
+ //# sourceMappingURL=index-GwVhqXni.d.cts.map
@@ -0,0 +1,37 @@
1
+ import { DataPlugin, ValidationResult } from "@scenography/scene";
2
+
3
+ //#region src/data/sky.d.ts
4
+ /**
5
+ * A procedural sky driven by the time of day. The runtime renders an atmospheric
6
+ * sky dome, moves a sun light along its daily arc, and fades in stars at night —
7
+ * all from `time`. Always clear (no weather). Distinct from `Environment` (a
8
+ * static HDRI): a scene uses one or the other for its background.
9
+ */
10
+ interface Sky {
11
+ /** Hour of day, `0`..`24` (`6` sunrise, `12` noon, `18` sunset, `0`/`24` midnight). Default `12`. */
12
+ time?: number;
13
+ /** Compass offset (degrees) that rotates the sun's daily arc — orient the scene to the sun. Default `0`. */
14
+ azimuth?: number;
15
+ /** Atmospheric haze; higher is hazier/whiter. Default `4`. */
16
+ turbidity?: number;
17
+ /** Rayleigh scattering; higher is a deeper blue. Default `2`. */
18
+ rayleigh?: number;
19
+ /** Exponential fog density tinted to the sky (fades the horizon). `0` = none. Default `0`. */
20
+ fog?: number;
21
+ }
22
+ declare module "@scenography/scene" {
23
+ interface Scene {
24
+ /** Procedural time-of-day sky — provided by `@scenography/plugin-sky`. */
25
+ sky?: Sky;
26
+ }
27
+ }
28
+ //#endregion
29
+ //#region src/data/validate.d.ts
30
+ declare const validateSky: (sky: Sky) => ValidationResult;
31
+ //#endregion
32
+ //#region src/data/plugin.d.ts
33
+ /** The data half of the sky plugin: owns the `sky` scene key (a singleton). */
34
+ declare const skyData: DataPlugin<Sky>;
35
+ //#endregion
36
+ export { validateSky as n, Sky as r, skyData as t };
37
+ //# sourceMappingURL=index-GwVhqXni.d.mts.map
package/dist/index.cjs ADDED
@@ -0,0 +1,226 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_data = require("./data-DM9PlHyL.cjs");
3
+ let three = require("three");
4
+ //#region src/SkyController.ts
5
+ const clamp01 = (x) => Math.min(Math.max(x, 0), 1);
6
+ const lerp = (a, b, t) => a + (b - a) * t;
7
+ const DOME = 4500;
8
+ const STAR_COUNT = 1500;
9
+ const SUN_DISTANCE = 2e3;
10
+ const MAX_ELEVATION = 60;
11
+ const ENV_THROTTLE_MS = 150;
12
+ const SUNSET = new three.Color("#ff7a3c");
13
+ const DAYLIGHT = new three.Color("#fff4e6");
14
+ const NIGHT_FOG = new three.Color("#0a1222");
15
+ const DAY_FOG = new three.Color("#bcd3e0");
16
+ /**
17
+ * Owns the procedural time-of-day sky: an atmospheric dome (three's `Sky`
18
+ * addon), a sun `DirectionalLight` riding its daily arc, a hemisphere fill, and a
19
+ * star field that fades in at night. `setTime(hour)` drives everything; the
20
+ * dome loads on demand (own chunk) and catches up to the latest time.
21
+ */
22
+ var SkyController = class {
23
+ scene;
24
+ sun = new three.DirectionalLight(16777215, 0);
25
+ hemi = new three.HemisphereLight(8961023, 5917238, 0);
26
+ stars;
27
+ dome = null;
28
+ def = null;
29
+ time = 12;
30
+ azimuth = 0;
31
+ hash = null;
32
+ renderer;
33
+ pmrem;
34
+ envRT = null;
35
+ envDirty = false;
36
+ envTimer = 0;
37
+ constructor(scene, renderer) {
38
+ this.scene = scene;
39
+ this.renderer = renderer;
40
+ this.pmrem = new three.PMREMGenerator(renderer);
41
+ this.sun.castShadow = true;
42
+ this.sun.shadow.mapSize.set(2048, 2048);
43
+ const cam = this.sun.shadow.camera;
44
+ cam.left = cam.bottom = -1500;
45
+ cam.right = cam.top = 1500;
46
+ cam.near = 1;
47
+ cam.far = SUN_DISTANCE * 2;
48
+ this.stars = this.buildStars();
49
+ }
50
+ reconcile(def) {
51
+ const hash = def ? JSON.stringify(def) : null;
52
+ if (hash === this.hash) return;
53
+ this.hash = hash;
54
+ if (!def) {
55
+ this.clear();
56
+ return;
57
+ }
58
+ if (!this.def) {
59
+ this.scene.add(this.sun, this.sun.target, this.hemi, this.stars);
60
+ this.ensureDome();
61
+ }
62
+ this.def = def;
63
+ this.azimuth = def.azimuth ?? 0;
64
+ this.applyAtmosphere();
65
+ this.setTime(def.time ?? 12);
66
+ }
67
+ /** Set the hour of day (0..24) and update sun, sky, fill and stars live. */
68
+ setTime(hour) {
69
+ this.time = hour;
70
+ const elevation = Math.sin((hour - 6) / 12 * Math.PI) * MAX_ELEVATION;
71
+ const azimuth = 90 + (hour - 6) / 12 * 180 + this.azimuth;
72
+ const dir = new three.Vector3().setFromSphericalCoords(1, three.MathUtils.degToRad(90 - elevation), three.MathUtils.degToRad(azimuth));
73
+ if (this.dome) this.dome.material.uniforms.sunPosition.value.copy(dir);
74
+ this.sun.position.copy(dir).multiplyScalar(SUN_DISTANCE);
75
+ const day = clamp01(elevation / 6);
76
+ this.sun.intensity = day * 3;
77
+ this.sun.color.copy(SUNSET).lerp(DAYLIGHT, clamp01(elevation / 20));
78
+ this.hemi.intensity = lerp(.04, .6, clamp01((elevation + 6) / 12));
79
+ const night = clamp01(-elevation / 6);
80
+ const starMat = this.stars.material;
81
+ starMat.opacity = night;
82
+ this.stars.visible = night > 0;
83
+ const fogDensity = this.def?.fog ?? 0;
84
+ if (fogDensity > 0) {
85
+ const fog = this.scene.fog instanceof three.FogExp2 ? this.scene.fog : new three.FogExp2(0, fogDensity);
86
+ fog.density = fogDensity;
87
+ fog.color.copy(NIGHT_FOG).lerp(DAY_FOG, clamp01((elevation + 4) / 16));
88
+ const lowSun = clamp01(1 - elevation / 12) * clamp01(elevation / 3 + .4);
89
+ fog.color.lerp(SUNSET, lowSun * .4);
90
+ this.scene.fog = fog;
91
+ } else if (this.scene.fog instanceof three.FogExp2) this.scene.fog = null;
92
+ this.envDirty = true;
93
+ }
94
+ /** Current hour of day. */
95
+ getTime() {
96
+ return this.time;
97
+ }
98
+ /** Set the sun's compass offset (degrees) and re-place the sun. */
99
+ setAzimuth(degrees) {
100
+ this.azimuth = degrees;
101
+ this.setTime(this.time);
102
+ }
103
+ /** Current sun compass offset (degrees). */
104
+ getAzimuth() {
105
+ return this.azimuth;
106
+ }
107
+ /** Advance throttled work (IBL regeneration). Call once per frame. */
108
+ update(deltaMs) {
109
+ if (!this.envDirty || !this.dome) return;
110
+ this.envTimer += deltaMs;
111
+ if (this.envTimer < ENV_THROTTLE_MS) return;
112
+ this.envTimer = 0;
113
+ this.envDirty = false;
114
+ this.regenerateEnvironment();
115
+ }
116
+ /** Render just the dome to a PMREM and use it as the scene's IBL. */
117
+ regenerateEnvironment() {
118
+ if (!this.dome) return;
119
+ this.scene.remove(this.dome);
120
+ const envScene = new three.Scene();
121
+ envScene.add(this.dome);
122
+ const rt = this.pmrem.fromScene(envScene);
123
+ envScene.remove(this.dome);
124
+ this.scene.add(this.dome);
125
+ this.envRT?.dispose();
126
+ this.envRT = rt;
127
+ this.scene.environment = rt.texture;
128
+ }
129
+ applyAtmosphere() {
130
+ if (!this.dome || !this.def) return;
131
+ const u = this.dome.material.uniforms;
132
+ u.turbidity.value = this.def.turbidity ?? 4;
133
+ u.rayleigh.value = this.def.rayleigh ?? 2;
134
+ u.mieCoefficient.value = .005;
135
+ u.mieDirectionalG.value = .8;
136
+ }
137
+ ensureDome() {
138
+ if (this.dome) return;
139
+ import("three/examples/jsm/objects/Sky.js").then(({ Sky }) => {
140
+ if (!this.def) return;
141
+ const dome = new Sky();
142
+ dome.scale.setScalar(DOME);
143
+ this.dome = dome;
144
+ this.scene.add(dome);
145
+ this.applyAtmosphere();
146
+ this.setTime(this.time);
147
+ });
148
+ }
149
+ buildStars() {
150
+ const positions = new Float32Array(STAR_COUNT * 3);
151
+ for (let i = 0; i < STAR_COUNT; i++) {
152
+ const theta = Math.random() * Math.PI * 2;
153
+ const phi = Math.acos(Math.random());
154
+ const r = DOME * .9;
155
+ positions[i * 3] = r * Math.sin(phi) * Math.cos(theta);
156
+ positions[i * 3 + 1] = r * Math.cos(phi);
157
+ positions[i * 3 + 2] = r * Math.sin(phi) * Math.sin(theta);
158
+ }
159
+ const geometry = new three.BufferGeometry();
160
+ geometry.setAttribute("position", new three.Float32BufferAttribute(positions, 3));
161
+ const stars = new three.Points(geometry, new three.PointsMaterial({
162
+ color: 16777215,
163
+ size: 12,
164
+ sizeAttenuation: true,
165
+ transparent: true,
166
+ opacity: 0,
167
+ depthWrite: false
168
+ }));
169
+ stars.visible = false;
170
+ return stars;
171
+ }
172
+ clear() {
173
+ if (!this.def) return;
174
+ this.scene.remove(this.sun, this.sun.target, this.hemi, this.stars);
175
+ if (this.dome) {
176
+ this.scene.remove(this.dome);
177
+ this.dome = null;
178
+ }
179
+ if (this.scene.fog instanceof three.FogExp2) this.scene.fog = null;
180
+ this.scene.environment = null;
181
+ this.envRT?.dispose();
182
+ this.envRT = null;
183
+ this.envDirty = false;
184
+ this.def = null;
185
+ }
186
+ dispose() {
187
+ this.clear();
188
+ this.stars.geometry.dispose();
189
+ this.stars.material.dispose();
190
+ this.pmrem.dispose();
191
+ this.hash = null;
192
+ }
193
+ };
194
+ //#endregion
195
+ //#region src/plugin.ts
196
+ /**
197
+ * Procedural time-of-day sky — a *system* plugin. It renders an atmospheric sky
198
+ * dome, moves a sun light along its arc, fades in stars at night and drives the
199
+ * image-based lighting, all from `scene.sky`. Exposes `ctx.sky` (setTime/…). It
200
+ * manages its own objects, so it takes the scene graph and renderer (for IBL).
201
+ */
202
+ const sky = () => ({
203
+ name: "sky",
204
+ setup: (ctx) => {
205
+ const controller = new SkyController(ctx.scene3d, ctx.renderer);
206
+ controller.reconcile(ctx.scene.sky);
207
+ return {
208
+ update: (deltaMs) => controller.update(deltaMs),
209
+ setScene: (scene) => controller.reconcile(scene.sky),
210
+ dispose: () => controller.dispose(),
211
+ api: {
212
+ setTime: (hour) => controller.setTime(hour),
213
+ getTime: () => controller.getTime(),
214
+ setAzimuth: (degrees) => controller.setAzimuth(degrees),
215
+ getAzimuth: () => controller.getAzimuth()
216
+ }
217
+ };
218
+ }
219
+ });
220
+ //#endregion
221
+ exports.SkyController = SkyController;
222
+ exports.sky = sky;
223
+ exports.skyData = require_data.skyData;
224
+ exports.validateSky = require_data.validateSky;
225
+
226
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","names":["Color","DirectionalLight","HemisphereLight","PMREMGenerator","Vector3","MathUtils","FogExp2","Scene","BufferGeometry","Float32BufferAttribute","Points","PointsMaterial"],"sources":["../src/SkyController.ts","../src/plugin.ts"],"sourcesContent":["import {\n BufferGeometry,\n Color,\n DirectionalLight,\n Float32BufferAttribute,\n FogExp2,\n HemisphereLight,\n MathUtils,\n PMREMGenerator,\n Points,\n PointsMaterial,\n Scene,\n Vector3,\n type Object3D,\n type Scene as ThreeScene,\n type WebGLRenderer,\n type WebGLRenderTarget,\n} from \"three\";\nimport type { Sky as SkyDef } from \"./data\";\n\nconst clamp01 = (x: number): number => Math.min(Math.max(x, 0), 1);\nconst lerp = (a: number, b: number, t: number): number => a + (b - a) * t;\n\n// Sky dome radius (within the camera far plane) and star shell radius.\nconst DOME = 4500;\nconst STAR_COUNT = 1500;\nconst SUN_DISTANCE = 2000;\nconst MAX_ELEVATION = 60; // noon sun angle (less than zenith for longer shadows)\nconst ENV_THROTTLE_MS = 150; // min gap between IBL regenerations\n\nconst SUNSET = new Color(\"#ff7a3c\");\nconst DAYLIGHT = new Color(\"#fff4e6\");\nconst NIGHT_FOG = new Color(\"#0a1222\");\nconst DAY_FOG = new Color(\"#bcd3e0\");\n\n/** Minimal shape of the Sky addon's material uniforms we touch. */\ninterface SkyMaterial {\n uniforms: {\n turbidity: { value: number };\n rayleigh: { value: number };\n mieCoefficient: { value: number };\n mieDirectionalG: { value: number };\n sunPosition: { value: Vector3 };\n };\n}\n\n/**\n * Owns the procedural time-of-day sky: an atmospheric dome (three's `Sky`\n * addon), a sun `DirectionalLight` riding its daily arc, a hemisphere fill, and a\n * star field that fades in at night. `setTime(hour)` drives everything; the\n * dome loads on demand (own chunk) and catches up to the latest time.\n */\nexport class SkyController {\n private readonly scene: ThreeScene;\n private readonly sun = new DirectionalLight(0xffffff, 0);\n private readonly hemi = new HemisphereLight(0x88bbff, 0x5a4a36, 0);\n private readonly stars: Points;\n private dome: (Object3D & { material: SkyMaterial }) | null = null;\n private def: SkyDef | null = null;\n private time = 12;\n private azimuth = 0;\n private hash: string | null = null;\n\n // Image-based lighting: a PMREM of the sky dome, regenerated (throttled) when\n // the sky changes, so the water reflects the sky and PBR picks up its color.\n private readonly renderer: WebGLRenderer;\n private readonly pmrem: PMREMGenerator;\n private envRT: WebGLRenderTarget | null = null;\n private envDirty = false;\n private envTimer = 0;\n\n constructor(scene: ThreeScene, renderer: WebGLRenderer) {\n this.scene = scene;\n this.renderer = renderer;\n this.pmrem = new PMREMGenerator(renderer);\n this.sun.castShadow = true;\n this.sun.shadow.mapSize.set(2048, 2048);\n const cam = this.sun.shadow.camera;\n cam.left = cam.bottom = -1500;\n cam.right = cam.top = 1500;\n cam.near = 1;\n cam.far = SUN_DISTANCE * 2;\n this.stars = this.buildStars();\n }\n\n reconcile(def: SkyDef | undefined): void {\n const hash = def ? JSON.stringify(def) : null;\n if (hash === this.hash) return;\n this.hash = hash;\n\n if (!def) {\n this.clear();\n return;\n }\n if (!this.def) {\n this.scene.add(this.sun, this.sun.target, this.hemi, this.stars);\n this.ensureDome();\n }\n this.def = def;\n this.azimuth = def.azimuth ?? 0;\n this.applyAtmosphere();\n this.setTime(def.time ?? 12);\n }\n\n /** Set the hour of day (0..24) and update sun, sky, fill and stars live. */\n setTime(hour: number): void {\n this.time = hour;\n\n // Sun along its arc: elevation peaks at noon, dips below at night.\n const elevation = Math.sin(((hour - 6) / 12) * Math.PI) * MAX_ELEVATION;\n const azimuth = 90 + ((hour - 6) / 12) * 180 + this.azimuth;\n const dir = new Vector3().setFromSphericalCoords(\n 1,\n MathUtils.degToRad(90 - elevation),\n MathUtils.degToRad(azimuth),\n );\n\n if (this.dome) this.dome.material.uniforms.sunPosition.value.copy(dir);\n this.sun.position.copy(dir).multiplyScalar(SUN_DISTANCE);\n\n // Intensity/colour: bright white high up, dim warm at the horizon, off below.\n const day = clamp01(elevation / 6);\n this.sun.intensity = day * 3;\n this.sun.color.copy(SUNSET).lerp(DAYLIGHT, clamp01(elevation / 20));\n this.hemi.intensity = lerp(0.04, 0.6, clamp01((elevation + 6) / 12));\n\n // Stars fade in once the sun is below the horizon.\n const night = clamp01(-elevation / 6);\n const starMat = this.stars.material as PointsMaterial;\n starMat.opacity = night;\n this.stars.visible = night > 0;\n\n // Fog tinted to the sky, fading the horizon (off when density is 0).\n const fogDensity = this.def?.fog ?? 0;\n if (fogDensity > 0) {\n const fog = this.scene.fog instanceof FogExp2 ? this.scene.fog : new FogExp2(0x000000, fogDensity);\n fog.density = fogDensity;\n fog.color.copy(NIGHT_FOG).lerp(DAY_FOG, clamp01((elevation + 4) / 16));\n const lowSun = clamp01(1 - elevation / 12) * clamp01(elevation / 3 + 0.4);\n fog.color.lerp(SUNSET, lowSun * 0.4);\n this.scene.fog = fog;\n } else if (this.scene.fog instanceof FogExp2) {\n this.scene.fog = null;\n }\n\n // The sky changed; refresh the IBL (throttled in update()).\n this.envDirty = true;\n }\n\n /** Current hour of day. */\n getTime(): number {\n return this.time;\n }\n\n /** Set the sun's compass offset (degrees) and re-place the sun. */\n setAzimuth(degrees: number): void {\n this.azimuth = degrees;\n this.setTime(this.time);\n }\n\n /** Current sun compass offset (degrees). */\n getAzimuth(): number {\n return this.azimuth;\n }\n\n /** Advance throttled work (IBL regeneration). Call once per frame. */\n update(deltaMs: number): void {\n if (!this.envDirty || !this.dome) return;\n this.envTimer += deltaMs;\n if (this.envTimer < ENV_THROTTLE_MS) return;\n this.envTimer = 0;\n this.envDirty = false;\n this.regenerateEnvironment();\n }\n\n /** Render just the dome to a PMREM and use it as the scene's IBL. */\n private regenerateEnvironment(): void {\n if (!this.dome) return;\n this.scene.remove(this.dome);\n const envScene = new Scene();\n envScene.add(this.dome);\n const rt = this.pmrem.fromScene(envScene);\n envScene.remove(this.dome);\n this.scene.add(this.dome);\n this.envRT?.dispose();\n this.envRT = rt;\n this.scene.environment = rt.texture;\n }\n\n private applyAtmosphere(): void {\n if (!this.dome || !this.def) return;\n const u = this.dome.material.uniforms;\n u.turbidity.value = this.def.turbidity ?? 4;\n u.rayleigh.value = this.def.rayleigh ?? 2;\n u.mieCoefficient.value = 0.005;\n u.mieDirectionalG.value = 0.8;\n }\n\n private ensureDome(): void {\n if (this.dome) return;\n void import(\"three/examples/jsm/objects/Sky.js\").then(({ Sky }) => {\n if (!this.def) return; // reconciled away before it loaded\n const dome = new Sky() as unknown as Object3D & { material: SkyMaterial };\n dome.scale.setScalar(DOME);\n this.dome = dome;\n this.scene.add(dome);\n this.applyAtmosphere();\n this.setTime(this.time);\n });\n }\n\n private buildStars(): Points {\n const positions = new Float32Array(STAR_COUNT * 3);\n for (let i = 0; i < STAR_COUNT; i++) {\n // Upper hemisphere shell.\n const theta = Math.random() * Math.PI * 2;\n const phi = Math.acos(Math.random()); // 0..90° from zenith\n const r = DOME * 0.9;\n positions[i * 3] = r * Math.sin(phi) * Math.cos(theta);\n positions[i * 3 + 1] = r * Math.cos(phi);\n positions[i * 3 + 2] = r * Math.sin(phi) * Math.sin(theta);\n }\n const geometry = new BufferGeometry();\n geometry.setAttribute(\"position\", new Float32BufferAttribute(positions, 3));\n const material = new PointsMaterial({\n color: 0xffffff,\n size: 12,\n sizeAttenuation: true,\n transparent: true,\n opacity: 0,\n depthWrite: false,\n });\n const stars = new Points(geometry, material);\n stars.visible = false;\n return stars;\n }\n\n private clear(): void {\n if (!this.def) return;\n this.scene.remove(this.sun, this.sun.target, this.hemi, this.stars);\n if (this.dome) {\n this.scene.remove(this.dome);\n this.dome = null;\n }\n if (this.scene.fog instanceof FogExp2) this.scene.fog = null;\n this.scene.environment = null;\n this.envRT?.dispose();\n this.envRT = null;\n this.envDirty = false;\n this.def = null;\n }\n\n dispose(): void {\n this.clear();\n this.stars.geometry.dispose();\n (this.stars.material as PointsMaterial).dispose();\n this.pmrem.dispose();\n this.hash = null;\n }\n}\n","import type { SkyApi, SystemPlugin } from \"@scenography/engine\";\n\nimport { SkyController } from \"./SkyController\";\n\n/**\n * Procedural time-of-day sky — a *system* plugin. It renders an atmospheric sky\n * dome, moves a sun light along its arc, fades in stars at night and drives the\n * image-based lighting, all from `scene.sky`. Exposes `ctx.sky` (setTime/…). It\n * manages its own objects, so it takes the scene graph and renderer (for IBL).\n */\nexport const sky = (): SystemPlugin<SkyApi> => ({\n name: \"sky\",\n setup: (ctx) => {\n const controller = new SkyController(ctx.scene3d, ctx.renderer);\n controller.reconcile(ctx.scene.sky);\n return {\n update: (deltaMs) => controller.update(deltaMs),\n setScene: (scene) => controller.reconcile(scene.sky),\n dispose: () => controller.dispose(),\n api: {\n setTime: (hour) => controller.setTime(hour),\n getTime: () => controller.getTime(),\n setAzimuth: (degrees) => controller.setAzimuth(degrees),\n getAzimuth: () => controller.getAzimuth(),\n },\n };\n },\n});\n"],"mappings":"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"}
@@ -0,0 +1,58 @@
1
+ import { n as validateSky, r as Sky, t as skyData } from "./index-GwVhqXni.cjs";
2
+ import { SkyApi, SystemPlugin } from "@scenography/engine";
3
+ import { Scene, WebGLRenderer } from "three";
4
+
5
+ //#region src/plugin.d.ts
6
+ /**
7
+ * Procedural time-of-day sky — a *system* plugin. It renders an atmospheric sky
8
+ * dome, moves a sun light along its arc, fades in stars at night and drives the
9
+ * image-based lighting, all from `scene.sky`. Exposes `ctx.sky` (setTime/…). It
10
+ * manages its own objects, so it takes the scene graph and renderer (for IBL).
11
+ */
12
+ declare const sky: () => SystemPlugin<SkyApi>;
13
+ //#endregion
14
+ //#region src/SkyController.d.ts
15
+ /**
16
+ * Owns the procedural time-of-day sky: an atmospheric dome (three's `Sky`
17
+ * addon), a sun `DirectionalLight` riding its daily arc, a hemisphere fill, and a
18
+ * star field that fades in at night. `setTime(hour)` drives everything; the
19
+ * dome loads on demand (own chunk) and catches up to the latest time.
20
+ */
21
+ declare class SkyController {
22
+ private readonly scene;
23
+ private readonly sun;
24
+ private readonly hemi;
25
+ private readonly stars;
26
+ private dome;
27
+ private def;
28
+ private time;
29
+ private azimuth;
30
+ private hash;
31
+ private readonly renderer;
32
+ private readonly pmrem;
33
+ private envRT;
34
+ private envDirty;
35
+ private envTimer;
36
+ constructor(scene: Scene, renderer: WebGLRenderer);
37
+ reconcile(def: Sky | undefined): void;
38
+ /** Set the hour of day (0..24) and update sun, sky, fill and stars live. */
39
+ setTime(hour: number): void;
40
+ /** Current hour of day. */
41
+ getTime(): number;
42
+ /** Set the sun's compass offset (degrees) and re-place the sun. */
43
+ setAzimuth(degrees: number): void;
44
+ /** Current sun compass offset (degrees). */
45
+ getAzimuth(): number;
46
+ /** Advance throttled work (IBL regeneration). Call once per frame. */
47
+ update(deltaMs: number): void;
48
+ /** Render just the dome to a PMREM and use it as the scene's IBL. */
49
+ private regenerateEnvironment;
50
+ private applyAtmosphere;
51
+ private ensureDome;
52
+ private buildStars;
53
+ private clear;
54
+ dispose(): void;
55
+ }
56
+ //#endregion
57
+ export { type Sky, SkyController, sky, skyData, validateSky };
58
+ //# sourceMappingURL=index.d.cts.map
@@ -0,0 +1,58 @@
1
+ import { n as validateSky, r as Sky, t as skyData } from "./index-GwVhqXni.mjs";
2
+ import { Scene, WebGLRenderer } from "three";
3
+ import { SkyApi, SystemPlugin } from "@scenography/engine";
4
+
5
+ //#region src/plugin.d.ts
6
+ /**
7
+ * Procedural time-of-day sky — a *system* plugin. It renders an atmospheric sky
8
+ * dome, moves a sun light along its arc, fades in stars at night and drives the
9
+ * image-based lighting, all from `scene.sky`. Exposes `ctx.sky` (setTime/…). It
10
+ * manages its own objects, so it takes the scene graph and renderer (for IBL).
11
+ */
12
+ declare const sky: () => SystemPlugin<SkyApi>;
13
+ //#endregion
14
+ //#region src/SkyController.d.ts
15
+ /**
16
+ * Owns the procedural time-of-day sky: an atmospheric dome (three's `Sky`
17
+ * addon), a sun `DirectionalLight` riding its daily arc, a hemisphere fill, and a
18
+ * star field that fades in at night. `setTime(hour)` drives everything; the
19
+ * dome loads on demand (own chunk) and catches up to the latest time.
20
+ */
21
+ declare class SkyController {
22
+ private readonly scene;
23
+ private readonly sun;
24
+ private readonly hemi;
25
+ private readonly stars;
26
+ private dome;
27
+ private def;
28
+ private time;
29
+ private azimuth;
30
+ private hash;
31
+ private readonly renderer;
32
+ private readonly pmrem;
33
+ private envRT;
34
+ private envDirty;
35
+ private envTimer;
36
+ constructor(scene: Scene, renderer: WebGLRenderer);
37
+ reconcile(def: Sky | undefined): void;
38
+ /** Set the hour of day (0..24) and update sun, sky, fill and stars live. */
39
+ setTime(hour: number): void;
40
+ /** Current hour of day. */
41
+ getTime(): number;
42
+ /** Set the sun's compass offset (degrees) and re-place the sun. */
43
+ setAzimuth(degrees: number): void;
44
+ /** Current sun compass offset (degrees). */
45
+ getAzimuth(): number;
46
+ /** Advance throttled work (IBL regeneration). Call once per frame. */
47
+ update(deltaMs: number): void;
48
+ /** Render just the dome to a PMREM and use it as the scene's IBL. */
49
+ private regenerateEnvironment;
50
+ private applyAtmosphere;
51
+ private ensureDome;
52
+ private buildStars;
53
+ private clear;
54
+ dispose(): void;
55
+ }
56
+ //#endregion
57
+ export { type Sky, SkyController, sky, skyData, validateSky };
58
+ //# sourceMappingURL=index.d.mts.map
package/dist/index.mjs ADDED
@@ -0,0 +1,222 @@
1
+ import { n as validateSky, t as skyData } from "./data-BY6HfW4z.mjs";
2
+ import { BufferGeometry, Color, DirectionalLight, Float32BufferAttribute, FogExp2, HemisphereLight, MathUtils, PMREMGenerator, Points, PointsMaterial, Scene, Vector3 } from "three";
3
+ //#region src/SkyController.ts
4
+ const clamp01 = (x) => Math.min(Math.max(x, 0), 1);
5
+ const lerp = (a, b, t) => a + (b - a) * t;
6
+ const DOME = 4500;
7
+ const STAR_COUNT = 1500;
8
+ const SUN_DISTANCE = 2e3;
9
+ const MAX_ELEVATION = 60;
10
+ const ENV_THROTTLE_MS = 150;
11
+ const SUNSET = new Color("#ff7a3c");
12
+ const DAYLIGHT = new Color("#fff4e6");
13
+ const NIGHT_FOG = new Color("#0a1222");
14
+ const DAY_FOG = new Color("#bcd3e0");
15
+ /**
16
+ * Owns the procedural time-of-day sky: an atmospheric dome (three's `Sky`
17
+ * addon), a sun `DirectionalLight` riding its daily arc, a hemisphere fill, and a
18
+ * star field that fades in at night. `setTime(hour)` drives everything; the
19
+ * dome loads on demand (own chunk) and catches up to the latest time.
20
+ */
21
+ var SkyController = class {
22
+ scene;
23
+ sun = new DirectionalLight(16777215, 0);
24
+ hemi = new HemisphereLight(8961023, 5917238, 0);
25
+ stars;
26
+ dome = null;
27
+ def = null;
28
+ time = 12;
29
+ azimuth = 0;
30
+ hash = null;
31
+ renderer;
32
+ pmrem;
33
+ envRT = null;
34
+ envDirty = false;
35
+ envTimer = 0;
36
+ constructor(scene, renderer) {
37
+ this.scene = scene;
38
+ this.renderer = renderer;
39
+ this.pmrem = new PMREMGenerator(renderer);
40
+ this.sun.castShadow = true;
41
+ this.sun.shadow.mapSize.set(2048, 2048);
42
+ const cam = this.sun.shadow.camera;
43
+ cam.left = cam.bottom = -1500;
44
+ cam.right = cam.top = 1500;
45
+ cam.near = 1;
46
+ cam.far = SUN_DISTANCE * 2;
47
+ this.stars = this.buildStars();
48
+ }
49
+ reconcile(def) {
50
+ const hash = def ? JSON.stringify(def) : null;
51
+ if (hash === this.hash) return;
52
+ this.hash = hash;
53
+ if (!def) {
54
+ this.clear();
55
+ return;
56
+ }
57
+ if (!this.def) {
58
+ this.scene.add(this.sun, this.sun.target, this.hemi, this.stars);
59
+ this.ensureDome();
60
+ }
61
+ this.def = def;
62
+ this.azimuth = def.azimuth ?? 0;
63
+ this.applyAtmosphere();
64
+ this.setTime(def.time ?? 12);
65
+ }
66
+ /** Set the hour of day (0..24) and update sun, sky, fill and stars live. */
67
+ setTime(hour) {
68
+ this.time = hour;
69
+ const elevation = Math.sin((hour - 6) / 12 * Math.PI) * MAX_ELEVATION;
70
+ const azimuth = 90 + (hour - 6) / 12 * 180 + this.azimuth;
71
+ const dir = new Vector3().setFromSphericalCoords(1, MathUtils.degToRad(90 - elevation), MathUtils.degToRad(azimuth));
72
+ if (this.dome) this.dome.material.uniforms.sunPosition.value.copy(dir);
73
+ this.sun.position.copy(dir).multiplyScalar(SUN_DISTANCE);
74
+ const day = clamp01(elevation / 6);
75
+ this.sun.intensity = day * 3;
76
+ this.sun.color.copy(SUNSET).lerp(DAYLIGHT, clamp01(elevation / 20));
77
+ this.hemi.intensity = lerp(.04, .6, clamp01((elevation + 6) / 12));
78
+ const night = clamp01(-elevation / 6);
79
+ const starMat = this.stars.material;
80
+ starMat.opacity = night;
81
+ this.stars.visible = night > 0;
82
+ const fogDensity = this.def?.fog ?? 0;
83
+ if (fogDensity > 0) {
84
+ const fog = this.scene.fog instanceof FogExp2 ? this.scene.fog : new FogExp2(0, fogDensity);
85
+ fog.density = fogDensity;
86
+ fog.color.copy(NIGHT_FOG).lerp(DAY_FOG, clamp01((elevation + 4) / 16));
87
+ const lowSun = clamp01(1 - elevation / 12) * clamp01(elevation / 3 + .4);
88
+ fog.color.lerp(SUNSET, lowSun * .4);
89
+ this.scene.fog = fog;
90
+ } else if (this.scene.fog instanceof FogExp2) this.scene.fog = null;
91
+ this.envDirty = true;
92
+ }
93
+ /** Current hour of day. */
94
+ getTime() {
95
+ return this.time;
96
+ }
97
+ /** Set the sun's compass offset (degrees) and re-place the sun. */
98
+ setAzimuth(degrees) {
99
+ this.azimuth = degrees;
100
+ this.setTime(this.time);
101
+ }
102
+ /** Current sun compass offset (degrees). */
103
+ getAzimuth() {
104
+ return this.azimuth;
105
+ }
106
+ /** Advance throttled work (IBL regeneration). Call once per frame. */
107
+ update(deltaMs) {
108
+ if (!this.envDirty || !this.dome) return;
109
+ this.envTimer += deltaMs;
110
+ if (this.envTimer < ENV_THROTTLE_MS) return;
111
+ this.envTimer = 0;
112
+ this.envDirty = false;
113
+ this.regenerateEnvironment();
114
+ }
115
+ /** Render just the dome to a PMREM and use it as the scene's IBL. */
116
+ regenerateEnvironment() {
117
+ if (!this.dome) return;
118
+ this.scene.remove(this.dome);
119
+ const envScene = new Scene();
120
+ envScene.add(this.dome);
121
+ const rt = this.pmrem.fromScene(envScene);
122
+ envScene.remove(this.dome);
123
+ this.scene.add(this.dome);
124
+ this.envRT?.dispose();
125
+ this.envRT = rt;
126
+ this.scene.environment = rt.texture;
127
+ }
128
+ applyAtmosphere() {
129
+ if (!this.dome || !this.def) return;
130
+ const u = this.dome.material.uniforms;
131
+ u.turbidity.value = this.def.turbidity ?? 4;
132
+ u.rayleigh.value = this.def.rayleigh ?? 2;
133
+ u.mieCoefficient.value = .005;
134
+ u.mieDirectionalG.value = .8;
135
+ }
136
+ ensureDome() {
137
+ if (this.dome) return;
138
+ import("three/examples/jsm/objects/Sky.js").then(({ Sky }) => {
139
+ if (!this.def) return;
140
+ const dome = new Sky();
141
+ dome.scale.setScalar(DOME);
142
+ this.dome = dome;
143
+ this.scene.add(dome);
144
+ this.applyAtmosphere();
145
+ this.setTime(this.time);
146
+ });
147
+ }
148
+ buildStars() {
149
+ const positions = new Float32Array(STAR_COUNT * 3);
150
+ for (let i = 0; i < STAR_COUNT; i++) {
151
+ const theta = Math.random() * Math.PI * 2;
152
+ const phi = Math.acos(Math.random());
153
+ const r = DOME * .9;
154
+ positions[i * 3] = r * Math.sin(phi) * Math.cos(theta);
155
+ positions[i * 3 + 1] = r * Math.cos(phi);
156
+ positions[i * 3 + 2] = r * Math.sin(phi) * Math.sin(theta);
157
+ }
158
+ const geometry = new BufferGeometry();
159
+ geometry.setAttribute("position", new Float32BufferAttribute(positions, 3));
160
+ const stars = new Points(geometry, new PointsMaterial({
161
+ color: 16777215,
162
+ size: 12,
163
+ sizeAttenuation: true,
164
+ transparent: true,
165
+ opacity: 0,
166
+ depthWrite: false
167
+ }));
168
+ stars.visible = false;
169
+ return stars;
170
+ }
171
+ clear() {
172
+ if (!this.def) return;
173
+ this.scene.remove(this.sun, this.sun.target, this.hemi, this.stars);
174
+ if (this.dome) {
175
+ this.scene.remove(this.dome);
176
+ this.dome = null;
177
+ }
178
+ if (this.scene.fog instanceof FogExp2) this.scene.fog = null;
179
+ this.scene.environment = null;
180
+ this.envRT?.dispose();
181
+ this.envRT = null;
182
+ this.envDirty = false;
183
+ this.def = null;
184
+ }
185
+ dispose() {
186
+ this.clear();
187
+ this.stars.geometry.dispose();
188
+ this.stars.material.dispose();
189
+ this.pmrem.dispose();
190
+ this.hash = null;
191
+ }
192
+ };
193
+ //#endregion
194
+ //#region src/plugin.ts
195
+ /**
196
+ * Procedural time-of-day sky — a *system* plugin. It renders an atmospheric sky
197
+ * dome, moves a sun light along its arc, fades in stars at night and drives the
198
+ * image-based lighting, all from `scene.sky`. Exposes `ctx.sky` (setTime/…). It
199
+ * manages its own objects, so it takes the scene graph and renderer (for IBL).
200
+ */
201
+ const sky = () => ({
202
+ name: "sky",
203
+ setup: (ctx) => {
204
+ const controller = new SkyController(ctx.scene3d, ctx.renderer);
205
+ controller.reconcile(ctx.scene.sky);
206
+ return {
207
+ update: (deltaMs) => controller.update(deltaMs),
208
+ setScene: (scene) => controller.reconcile(scene.sky),
209
+ dispose: () => controller.dispose(),
210
+ api: {
211
+ setTime: (hour) => controller.setTime(hour),
212
+ getTime: () => controller.getTime(),
213
+ setAzimuth: (degrees) => controller.setAzimuth(degrees),
214
+ getAzimuth: () => controller.getAzimuth()
215
+ }
216
+ };
217
+ }
218
+ });
219
+ //#endregion
220
+ export { SkyController, sky, skyData, validateSky };
221
+
222
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/SkyController.ts","../src/plugin.ts"],"sourcesContent":["import {\n BufferGeometry,\n Color,\n DirectionalLight,\n Float32BufferAttribute,\n FogExp2,\n HemisphereLight,\n MathUtils,\n PMREMGenerator,\n Points,\n PointsMaterial,\n Scene,\n Vector3,\n type Object3D,\n type Scene as ThreeScene,\n type WebGLRenderer,\n type WebGLRenderTarget,\n} from \"three\";\nimport type { Sky as SkyDef } from \"./data\";\n\nconst clamp01 = (x: number): number => Math.min(Math.max(x, 0), 1);\nconst lerp = (a: number, b: number, t: number): number => a + (b - a) * t;\n\n// Sky dome radius (within the camera far plane) and star shell radius.\nconst DOME = 4500;\nconst STAR_COUNT = 1500;\nconst SUN_DISTANCE = 2000;\nconst MAX_ELEVATION = 60; // noon sun angle (less than zenith for longer shadows)\nconst ENV_THROTTLE_MS = 150; // min gap between IBL regenerations\n\nconst SUNSET = new Color(\"#ff7a3c\");\nconst DAYLIGHT = new Color(\"#fff4e6\");\nconst NIGHT_FOG = new Color(\"#0a1222\");\nconst DAY_FOG = new Color(\"#bcd3e0\");\n\n/** Minimal shape of the Sky addon's material uniforms we touch. */\ninterface SkyMaterial {\n uniforms: {\n turbidity: { value: number };\n rayleigh: { value: number };\n mieCoefficient: { value: number };\n mieDirectionalG: { value: number };\n sunPosition: { value: Vector3 };\n };\n}\n\n/**\n * Owns the procedural time-of-day sky: an atmospheric dome (three's `Sky`\n * addon), a sun `DirectionalLight` riding its daily arc, a hemisphere fill, and a\n * star field that fades in at night. `setTime(hour)` drives everything; the\n * dome loads on demand (own chunk) and catches up to the latest time.\n */\nexport class SkyController {\n private readonly scene: ThreeScene;\n private readonly sun = new DirectionalLight(0xffffff, 0);\n private readonly hemi = new HemisphereLight(0x88bbff, 0x5a4a36, 0);\n private readonly stars: Points;\n private dome: (Object3D & { material: SkyMaterial }) | null = null;\n private def: SkyDef | null = null;\n private time = 12;\n private azimuth = 0;\n private hash: string | null = null;\n\n // Image-based lighting: a PMREM of the sky dome, regenerated (throttled) when\n // the sky changes, so the water reflects the sky and PBR picks up its color.\n private readonly renderer: WebGLRenderer;\n private readonly pmrem: PMREMGenerator;\n private envRT: WebGLRenderTarget | null = null;\n private envDirty = false;\n private envTimer = 0;\n\n constructor(scene: ThreeScene, renderer: WebGLRenderer) {\n this.scene = scene;\n this.renderer = renderer;\n this.pmrem = new PMREMGenerator(renderer);\n this.sun.castShadow = true;\n this.sun.shadow.mapSize.set(2048, 2048);\n const cam = this.sun.shadow.camera;\n cam.left = cam.bottom = -1500;\n cam.right = cam.top = 1500;\n cam.near = 1;\n cam.far = SUN_DISTANCE * 2;\n this.stars = this.buildStars();\n }\n\n reconcile(def: SkyDef | undefined): void {\n const hash = def ? JSON.stringify(def) : null;\n if (hash === this.hash) return;\n this.hash = hash;\n\n if (!def) {\n this.clear();\n return;\n }\n if (!this.def) {\n this.scene.add(this.sun, this.sun.target, this.hemi, this.stars);\n this.ensureDome();\n }\n this.def = def;\n this.azimuth = def.azimuth ?? 0;\n this.applyAtmosphere();\n this.setTime(def.time ?? 12);\n }\n\n /** Set the hour of day (0..24) and update sun, sky, fill and stars live. */\n setTime(hour: number): void {\n this.time = hour;\n\n // Sun along its arc: elevation peaks at noon, dips below at night.\n const elevation = Math.sin(((hour - 6) / 12) * Math.PI) * MAX_ELEVATION;\n const azimuth = 90 + ((hour - 6) / 12) * 180 + this.azimuth;\n const dir = new Vector3().setFromSphericalCoords(\n 1,\n MathUtils.degToRad(90 - elevation),\n MathUtils.degToRad(azimuth),\n );\n\n if (this.dome) this.dome.material.uniforms.sunPosition.value.copy(dir);\n this.sun.position.copy(dir).multiplyScalar(SUN_DISTANCE);\n\n // Intensity/colour: bright white high up, dim warm at the horizon, off below.\n const day = clamp01(elevation / 6);\n this.sun.intensity = day * 3;\n this.sun.color.copy(SUNSET).lerp(DAYLIGHT, clamp01(elevation / 20));\n this.hemi.intensity = lerp(0.04, 0.6, clamp01((elevation + 6) / 12));\n\n // Stars fade in once the sun is below the horizon.\n const night = clamp01(-elevation / 6);\n const starMat = this.stars.material as PointsMaterial;\n starMat.opacity = night;\n this.stars.visible = night > 0;\n\n // Fog tinted to the sky, fading the horizon (off when density is 0).\n const fogDensity = this.def?.fog ?? 0;\n if (fogDensity > 0) {\n const fog = this.scene.fog instanceof FogExp2 ? this.scene.fog : new FogExp2(0x000000, fogDensity);\n fog.density = fogDensity;\n fog.color.copy(NIGHT_FOG).lerp(DAY_FOG, clamp01((elevation + 4) / 16));\n const lowSun = clamp01(1 - elevation / 12) * clamp01(elevation / 3 + 0.4);\n fog.color.lerp(SUNSET, lowSun * 0.4);\n this.scene.fog = fog;\n } else if (this.scene.fog instanceof FogExp2) {\n this.scene.fog = null;\n }\n\n // The sky changed; refresh the IBL (throttled in update()).\n this.envDirty = true;\n }\n\n /** Current hour of day. */\n getTime(): number {\n return this.time;\n }\n\n /** Set the sun's compass offset (degrees) and re-place the sun. */\n setAzimuth(degrees: number): void {\n this.azimuth = degrees;\n this.setTime(this.time);\n }\n\n /** Current sun compass offset (degrees). */\n getAzimuth(): number {\n return this.azimuth;\n }\n\n /** Advance throttled work (IBL regeneration). Call once per frame. */\n update(deltaMs: number): void {\n if (!this.envDirty || !this.dome) return;\n this.envTimer += deltaMs;\n if (this.envTimer < ENV_THROTTLE_MS) return;\n this.envTimer = 0;\n this.envDirty = false;\n this.regenerateEnvironment();\n }\n\n /** Render just the dome to a PMREM and use it as the scene's IBL. */\n private regenerateEnvironment(): void {\n if (!this.dome) return;\n this.scene.remove(this.dome);\n const envScene = new Scene();\n envScene.add(this.dome);\n const rt = this.pmrem.fromScene(envScene);\n envScene.remove(this.dome);\n this.scene.add(this.dome);\n this.envRT?.dispose();\n this.envRT = rt;\n this.scene.environment = rt.texture;\n }\n\n private applyAtmosphere(): void {\n if (!this.dome || !this.def) return;\n const u = this.dome.material.uniforms;\n u.turbidity.value = this.def.turbidity ?? 4;\n u.rayleigh.value = this.def.rayleigh ?? 2;\n u.mieCoefficient.value = 0.005;\n u.mieDirectionalG.value = 0.8;\n }\n\n private ensureDome(): void {\n if (this.dome) return;\n void import(\"three/examples/jsm/objects/Sky.js\").then(({ Sky }) => {\n if (!this.def) return; // reconciled away before it loaded\n const dome = new Sky() as unknown as Object3D & { material: SkyMaterial };\n dome.scale.setScalar(DOME);\n this.dome = dome;\n this.scene.add(dome);\n this.applyAtmosphere();\n this.setTime(this.time);\n });\n }\n\n private buildStars(): Points {\n const positions = new Float32Array(STAR_COUNT * 3);\n for (let i = 0; i < STAR_COUNT; i++) {\n // Upper hemisphere shell.\n const theta = Math.random() * Math.PI * 2;\n const phi = Math.acos(Math.random()); // 0..90° from zenith\n const r = DOME * 0.9;\n positions[i * 3] = r * Math.sin(phi) * Math.cos(theta);\n positions[i * 3 + 1] = r * Math.cos(phi);\n positions[i * 3 + 2] = r * Math.sin(phi) * Math.sin(theta);\n }\n const geometry = new BufferGeometry();\n geometry.setAttribute(\"position\", new Float32BufferAttribute(positions, 3));\n const material = new PointsMaterial({\n color: 0xffffff,\n size: 12,\n sizeAttenuation: true,\n transparent: true,\n opacity: 0,\n depthWrite: false,\n });\n const stars = new Points(geometry, material);\n stars.visible = false;\n return stars;\n }\n\n private clear(): void {\n if (!this.def) return;\n this.scene.remove(this.sun, this.sun.target, this.hemi, this.stars);\n if (this.dome) {\n this.scene.remove(this.dome);\n this.dome = null;\n }\n if (this.scene.fog instanceof FogExp2) this.scene.fog = null;\n this.scene.environment = null;\n this.envRT?.dispose();\n this.envRT = null;\n this.envDirty = false;\n this.def = null;\n }\n\n dispose(): void {\n this.clear();\n this.stars.geometry.dispose();\n (this.stars.material as PointsMaterial).dispose();\n this.pmrem.dispose();\n this.hash = null;\n }\n}\n","import type { SkyApi, SystemPlugin } from \"@scenography/engine\";\n\nimport { SkyController } from \"./SkyController\";\n\n/**\n * Procedural time-of-day sky — a *system* plugin. It renders an atmospheric sky\n * dome, moves a sun light along its arc, fades in stars at night and drives the\n * image-based lighting, all from `scene.sky`. Exposes `ctx.sky` (setTime/…). It\n * manages its own objects, so it takes the scene graph and renderer (for IBL).\n */\nexport const sky = (): SystemPlugin<SkyApi> => ({\n name: \"sky\",\n setup: (ctx) => {\n const controller = new SkyController(ctx.scene3d, ctx.renderer);\n controller.reconcile(ctx.scene.sky);\n return {\n update: (deltaMs) => controller.update(deltaMs),\n setScene: (scene) => controller.reconcile(scene.sky),\n dispose: () => controller.dispose(),\n api: {\n setTime: (hour) => controller.setTime(hour),\n getTime: () => controller.getTime(),\n setAzimuth: (degrees) => controller.setAzimuth(degrees),\n getAzimuth: () => controller.getAzimuth(),\n },\n };\n },\n});\n"],"mappings":";;;AAoBA,MAAM,WAAW,MAAsB,KAAK,IAAI,KAAK,IAAI,GAAG,CAAC,GAAG,CAAC;AACjE,MAAM,QAAQ,GAAW,GAAW,MAAsB,KAAK,IAAI,KAAK;AAGxE,MAAM,OAAO;AACb,MAAM,aAAa;AACnB,MAAM,eAAe;AACrB,MAAM,gBAAgB;AACtB,MAAM,kBAAkB;AAExB,MAAM,SAAS,IAAI,MAAM,SAAS;AAClC,MAAM,WAAW,IAAI,MAAM,SAAS;AACpC,MAAM,YAAY,IAAI,MAAM,SAAS;AACrC,MAAM,UAAU,IAAI,MAAM,SAAS;;;;;;;AAmBnC,IAAa,gBAAb,MAA2B;CACzB;CACA,MAAuB,IAAI,iBAAiB,UAAU,CAAC;CACvD,OAAwB,IAAI,gBAAgB,SAAU,SAAU,CAAC;CACjE;CACA,OAA8D;CAC9D,MAA6B;CAC7B,OAAe;CACf,UAAkB;CAClB,OAA8B;CAI9B;CACA;CACA,QAA0C;CAC1C,WAAmB;CACnB,WAAmB;CAEnB,YAAY,OAAmB,UAAyB;EACtD,KAAK,QAAQ;EACb,KAAK,WAAW;EAChB,KAAK,QAAQ,IAAI,eAAe,QAAQ;EACxC,KAAK,IAAI,aAAa;EACtB,KAAK,IAAI,OAAO,QAAQ,IAAI,MAAM,IAAI;EACtC,MAAM,MAAM,KAAK,IAAI,OAAO;EAC5B,IAAI,OAAO,IAAI,SAAS;EACxB,IAAI,QAAQ,IAAI,MAAM;EACtB,IAAI,OAAO;EACX,IAAI,MAAM,eAAe;EACzB,KAAK,QAAQ,KAAK,WAAW;CAC/B;CAEA,UAAU,KAA+B;EACvC,MAAM,OAAO,MAAM,KAAK,UAAU,GAAG,IAAI;EACzC,IAAI,SAAS,KAAK,MAAM;EACxB,KAAK,OAAO;EAEZ,IAAI,CAAC,KAAK;GACR,KAAK,MAAM;GACX;EACF;EACA,IAAI,CAAC,KAAK,KAAK;GACb,KAAK,MAAM,IAAI,KAAK,KAAK,KAAK,IAAI,QAAQ,KAAK,MAAM,KAAK,KAAK;GAC/D,KAAK,WAAW;EAClB;EACA,KAAK,MAAM;EACX,KAAK,UAAU,IAAI,WAAW;EAC9B,KAAK,gBAAgB;EACrB,KAAK,QAAQ,IAAI,QAAQ,EAAE;CAC7B;;CAGA,QAAQ,MAAoB;EAC1B,KAAK,OAAO;EAGZ,MAAM,YAAY,KAAK,KAAM,OAAO,KAAK,KAAM,KAAK,EAAE,IAAI;EAC1D,MAAM,UAAU,MAAO,OAAO,KAAK,KAAM,MAAM,KAAK;EACpD,MAAM,MAAM,IAAI,QAAQ,CAAC,CAAC,uBACxB,GACA,UAAU,SAAS,KAAK,SAAS,GACjC,UAAU,SAAS,OAAO,CAC5B;EAEA,IAAI,KAAK,MAAM,KAAK,KAAK,SAAS,SAAS,YAAY,MAAM,KAAK,GAAG;EACrE,KAAK,IAAI,SAAS,KAAK,GAAG,CAAC,CAAC,eAAe,YAAY;EAGvD,MAAM,MAAM,QAAQ,YAAY,CAAC;EACjC,KAAK,IAAI,YAAY,MAAM;EAC3B,KAAK,IAAI,MAAM,KAAK,MAAM,CAAC,CAAC,KAAK,UAAU,QAAQ,YAAY,EAAE,CAAC;EAClE,KAAK,KAAK,YAAY,KAAK,KAAM,IAAK,SAAS,YAAY,KAAK,EAAE,CAAC;EAGnE,MAAM,QAAQ,QAAQ,CAAC,YAAY,CAAC;EACpC,MAAM,UAAU,KAAK,MAAM;EAC3B,QAAQ,UAAU;EAClB,KAAK,MAAM,UAAU,QAAQ;EAG7B,MAAM,aAAa,KAAK,KAAK,OAAO;EACpC,IAAI,aAAa,GAAG;GAClB,MAAM,MAAM,KAAK,MAAM,eAAe,UAAU,KAAK,MAAM,MAAM,IAAI,QAAQ,GAAU,UAAU;GACjG,IAAI,UAAU;GACd,IAAI,MAAM,KAAK,SAAS,CAAC,CAAC,KAAK,SAAS,SAAS,YAAY,KAAK,EAAE,CAAC;GACrE,MAAM,SAAS,QAAQ,IAAI,YAAY,EAAE,IAAI,QAAQ,YAAY,IAAI,EAAG;GACxE,IAAI,MAAM,KAAK,QAAQ,SAAS,EAAG;GACnC,KAAK,MAAM,MAAM;EACnB,OAAO,IAAI,KAAK,MAAM,eAAe,SACnC,KAAK,MAAM,MAAM;EAInB,KAAK,WAAW;CAClB;;CAGA,UAAkB;EAChB,OAAO,KAAK;CACd;;CAGA,WAAW,SAAuB;EAChC,KAAK,UAAU;EACf,KAAK,QAAQ,KAAK,IAAI;CACxB;;CAGA,aAAqB;EACnB,OAAO,KAAK;CACd;;CAGA,OAAO,SAAuB;EAC5B,IAAI,CAAC,KAAK,YAAY,CAAC,KAAK,MAAM;EAClC,KAAK,YAAY;EACjB,IAAI,KAAK,WAAW,iBAAiB;EACrC,KAAK,WAAW;EAChB,KAAK,WAAW;EAChB,KAAK,sBAAsB;CAC7B;;CAGA,wBAAsC;EACpC,IAAI,CAAC,KAAK,MAAM;EAChB,KAAK,MAAM,OAAO,KAAK,IAAI;EAC3B,MAAM,WAAW,IAAI,MAAM;EAC3B,SAAS,IAAI,KAAK,IAAI;EACtB,MAAM,KAAK,KAAK,MAAM,UAAU,QAAQ;EACxC,SAAS,OAAO,KAAK,IAAI;EACzB,KAAK,MAAM,IAAI,KAAK,IAAI;EACxB,KAAK,OAAO,QAAQ;EACpB,KAAK,QAAQ;EACb,KAAK,MAAM,cAAc,GAAG;CAC9B;CAEA,kBAAgC;EAC9B,IAAI,CAAC,KAAK,QAAQ,CAAC,KAAK,KAAK;EAC7B,MAAM,IAAI,KAAK,KAAK,SAAS;EAC7B,EAAE,UAAU,QAAQ,KAAK,IAAI,aAAa;EAC1C,EAAE,SAAS,QAAQ,KAAK,IAAI,YAAY;EACxC,EAAE,eAAe,QAAQ;EACzB,EAAE,gBAAgB,QAAQ;CAC5B;CAEA,aAA2B;EACzB,IAAI,KAAK,MAAM;EACf,OAAY,oCAAoC,CAAC,MAAM,EAAE,UAAU;GACjE,IAAI,CAAC,KAAK,KAAK;GACf,MAAM,OAAO,IAAI,IAAI;GACrB,KAAK,MAAM,UAAU,IAAI;GACzB,KAAK,OAAO;GACZ,KAAK,MAAM,IAAI,IAAI;GACnB,KAAK,gBAAgB;GACrB,KAAK,QAAQ,KAAK,IAAI;EACxB,CAAC;CACH;CAEA,aAA6B;EAC3B,MAAM,YAAY,IAAI,aAAa,aAAa,CAAC;EACjD,KAAK,IAAI,IAAI,GAAG,IAAI,YAAY,KAAK;GAEnC,MAAM,QAAQ,KAAK,OAAO,IAAI,KAAK,KAAK;GACxC,MAAM,MAAM,KAAK,KAAK,KAAK,OAAO,CAAC;GACnC,MAAM,IAAI,OAAO;GACjB,UAAU,IAAI,KAAK,IAAI,KAAK,IAAI,GAAG,IAAI,KAAK,IAAI,KAAK;GACrD,UAAU,IAAI,IAAI,KAAK,IAAI,KAAK,IAAI,GAAG;GACvC,UAAU,IAAI,IAAI,KAAK,IAAI,KAAK,IAAI,GAAG,IAAI,KAAK,IAAI,KAAK;EAC3D;EACA,MAAM,WAAW,IAAI,eAAe;EACpC,SAAS,aAAa,YAAY,IAAI,uBAAuB,WAAW,CAAC,CAAC;EAS1E,MAAM,QAAQ,IAAI,OAAO,UAAU,IARd,eAAe;GAClC,OAAO;GACP,MAAM;GACN,iBAAiB;GACjB,aAAa;GACb,SAAS;GACT,YAAY;EACd,CAC0C,CAAC;EAC3C,MAAM,UAAU;EAChB,OAAO;CACT;CAEA,QAAsB;EACpB,IAAI,CAAC,KAAK,KAAK;EACf,KAAK,MAAM,OAAO,KAAK,KAAK,KAAK,IAAI,QAAQ,KAAK,MAAM,KAAK,KAAK;EAClE,IAAI,KAAK,MAAM;GACb,KAAK,MAAM,OAAO,KAAK,IAAI;GAC3B,KAAK,OAAO;EACd;EACA,IAAI,KAAK,MAAM,eAAe,SAAS,KAAK,MAAM,MAAM;EACxD,KAAK,MAAM,cAAc;EACzB,KAAK,OAAO,QAAQ;EACpB,KAAK,QAAQ;EACb,KAAK,WAAW;EAChB,KAAK,MAAM;CACb;CAEA,UAAgB;EACd,KAAK,MAAM;EACX,KAAK,MAAM,SAAS,QAAQ;EAC5B,KAAM,MAAM,SAA4B,QAAQ;EAChD,KAAK,MAAM,QAAQ;EACnB,KAAK,OAAO;CACd;AACF;;;;;;;;;ACzPA,MAAa,aAAmC;CAC9C,MAAM;CACN,QAAQ,QAAQ;EACd,MAAM,aAAa,IAAI,cAAc,IAAI,SAAS,IAAI,QAAQ;EAC9D,WAAW,UAAU,IAAI,MAAM,GAAG;EAClC,OAAO;GACL,SAAS,YAAY,WAAW,OAAO,OAAO;GAC9C,WAAW,UAAU,WAAW,UAAU,MAAM,GAAG;GACnD,eAAe,WAAW,QAAQ;GAClC,KAAK;IACH,UAAU,SAAS,WAAW,QAAQ,IAAI;IAC1C,eAAe,WAAW,QAAQ;IAClC,aAAa,YAAY,WAAW,WAAW,OAAO;IACtD,kBAAkB,WAAW,WAAW;GAC1C;EACF;CACF;AACF"}
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "@scenography/plugin-sky",
3
+ "version": "0.2.0",
4
+ "description": "Sky plugin for scenography: procedural time-of-day sky (sun, atmosphere, stars, IBL) with ctx.sky runtime control.",
5
+ "license": "MIT",
6
+ "files": [
7
+ "dist"
8
+ ],
9
+ "type": "module",
10
+ "main": "./dist/index.cjs",
11
+ "module": "./dist/index.mjs",
12
+ "types": "./dist/index.d.cts",
13
+ "exports": {
14
+ ".": {
15
+ "import": {
16
+ "types": "./dist/index.d.mts",
17
+ "default": "./dist/index.mjs"
18
+ },
19
+ "require": {
20
+ "types": "./dist/index.d.cts",
21
+ "default": "./dist/index.cjs"
22
+ }
23
+ },
24
+ "./data": {
25
+ "import": {
26
+ "types": "./dist/data.d.mts",
27
+ "default": "./dist/data.mjs"
28
+ },
29
+ "require": {
30
+ "types": "./dist/data.d.cts",
31
+ "default": "./dist/data.cjs"
32
+ }
33
+ }
34
+ },
35
+ "dependencies": {
36
+ "@scenography/scene": "0.2.0"
37
+ },
38
+ "devDependencies": {
39
+ "@types/three": "^0.160.0",
40
+ "three": "^0.160.0",
41
+ "@scenography/engine": "0.2.0"
42
+ },
43
+ "peerDependencies": {
44
+ "three": ">=0.160.0",
45
+ "@scenography/engine": "0.2.0"
46
+ },
47
+ "scripts": {
48
+ "build": "tsdown",
49
+ "dev": "tsdown --watch",
50
+ "typecheck": "tsc --noEmit"
51
+ }
52
+ }