@a2f0/skyline 0.2.25 → 0.2.27
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/README.md +4 -3
- package/lib/models/colour-palette.d.ts +3 -2
- package/lib/models/colour-palette.js +3 -2
- package/lib/models/colour-reflections.js +9 -4
- package/lib/models/night-windows.js +9 -1
- package/package.json +1 -1
- package/site/models/colour-palette.js +3 -2
- package/site/models/colour-reflections.js +9 -4
- package/site/models/night-windows.js +9 -1
package/README.md
CHANGED
|
@@ -47,8 +47,9 @@ bun run deploy # publish to Cloudflare; needs Node.js 22+ and
|
|
|
47
47
|
|
|
48
48
|
[Development](docs/development.md) explains the checks, hooks, and PR workflow, and
|
|
49
49
|
[Deploying](docs/deploying.md) the release, its verification, and the gitignored `.secrets` link
|
|
50
|
-
(`ln -s ../matrix-secrets/skyline .secrets`) that Terraform reads
|
|
51
|
-
building or improve one, start with
|
|
52
|
-
[
|
|
50
|
+
(`ln -s ../matrix-secrets/skyline .secrets`) that Terraform reads its Cloudflare and R2 state
|
|
51
|
+
credentials through. To add a building or improve one, start with
|
|
52
|
+
[Adding a building](docs/adding-a-building.md) or the [fidelity queue](docs/building-fidelity.md).
|
|
53
|
+
Coding agents follow [`AGENTS.md`](AGENTS.md).
|
|
53
54
|
|
|
54
55
|
All documentation is indexed in [`docs/`](docs/README.md).
|
|
@@ -9,8 +9,9 @@ export declare const daylightColours: {
|
|
|
9
9
|
export declare const nightColours: {
|
|
10
10
|
readonly ambient: 10596296;
|
|
11
11
|
readonly fill: 9281469;
|
|
12
|
-
readonly window:
|
|
13
|
-
readonly windowWhite:
|
|
12
|
+
readonly window: 16761213;
|
|
13
|
+
readonly windowWhite: 16772570;
|
|
14
|
+
readonly windowCool: 14478079;
|
|
14
15
|
};
|
|
15
16
|
export declare const timeOfDayColours: readonly [{
|
|
16
17
|
readonly elevation: -18;
|
|
@@ -290,8 +290,9 @@ export const measuredColours = {
|
|
|
290
290
|
// above the horizon, each the median of a clear box of the same panorama (scripts/sample-colours.ts,
|
|
291
291
|
// the day study's sky), and the sun's warm white, chosen.
|
|
292
292
|
export const daylightColours = { sky: 0x9ebbdb, horizon: 0xc4d1e1, sun: 0xfff4e6 };
|
|
293
|
-
//
|
|
294
|
-
|
|
293
|
+
// Illustrated warm, neutral and cool white fixtures; not calibrated Kelvin values.
|
|
294
|
+
// DOE's white-tuning overview informs the range; see docs/viewer.md (time of day).
|
|
295
|
+
export const nightColours = { ambient: 0xa1afc8, fill: 0x8d9fbd, window: 0xffc17d, windowWhite: 0xffedda, windowCool: 0xdceaff };
|
|
295
296
|
// Illustrated clear-sky time previews. Solar elevation chooses the stops; these are
|
|
296
297
|
// artistic colours, separate from the photograph-calibrated daytime palette above.
|
|
297
298
|
export const timeOfDayColours = [
|
|
@@ -22,6 +22,7 @@ export function glassReflection(material, geometry, mask, windows = new Float32A
|
|
|
22
22
|
skylineWindowsSuppressed: { value: 0 },
|
|
23
23
|
skylineWindowWarm: { value: new THREE.Color(nightColours.window) },
|
|
24
24
|
skylineWindowWhite: { value: new THREE.Color(nightColours.windowWhite) },
|
|
25
|
+
skylineWindowCool: { value: new THREE.Color(nightColours.windowCool) },
|
|
25
26
|
};
|
|
26
27
|
const compile = (shader, renderer) => {
|
|
27
28
|
originalCompile.call(material, shader, renderer);
|
|
@@ -44,7 +45,8 @@ uniform float skylineDarkness;
|
|
|
44
45
|
uniform float skylineActivity;
|
|
45
46
|
uniform float skylineWindowsSuppressed;
|
|
46
47
|
uniform vec3 skylineWindowWarm;
|
|
47
|
-
uniform vec3 skylineWindowWhite
|
|
48
|
+
uniform vec3 skylineWindowWhite;
|
|
49
|
+
uniform vec3 skylineWindowCool;`).replace("#include <opaque_fragment>", `
|
|
48
50
|
if (vSkylineGlass > 0.0 && skylineReflecting > 0.0) {
|
|
49
51
|
vec3 eye = vec3(0.0);
|
|
50
52
|
eye.z = 1.0;
|
|
@@ -59,7 +61,10 @@ if (vSkylineWindow.z > 0.0 && skylineDarkness > 0.0) {
|
|
|
59
61
|
float occupied = 1.0 - smoothstep(skylineActivity - 0.05, skylineActivity + 0.05, vSkylineWindow.x);
|
|
60
62
|
float dusk = smoothstep(0.12 + 0.35 * vSkylineWindow.x, 0.45 + 0.35 * vSkylineWindow.x, skylineDarkness);
|
|
61
63
|
float light = vSkylineWindow.z > 1.5 ? skylineDarkness : occupied * dusk * (1.0 - skylineWindowsSuppressed);
|
|
62
|
-
|
|
64
|
+
float tint = vSkylineWindow.w;
|
|
65
|
+
vec3 lamp = tint < 0.5
|
|
66
|
+
? mix(skylineWindowWarm, skylineWindowWhite, tint * 2.0)
|
|
67
|
+
: mix(skylineWindowWhite, skylineWindowCool, (tint - 0.5) * 2.0);
|
|
63
68
|
outgoingLight += lamp * vSkylineWindow.y * light;
|
|
64
69
|
}
|
|
65
70
|
#include <opaque_fragment>`);
|
|
@@ -74,7 +79,7 @@ if (vSkylineWindow.z > 0.0 && skylineDarkness > 0.0) {
|
|
|
74
79
|
geometry.setAttribute("skylineGlass", attribute);
|
|
75
80
|
geometry.setAttribute("skylineWindow", windowAttribute);
|
|
76
81
|
material.onBeforeCompile = compile;
|
|
77
|
-
material.customProgramCacheKey = () => `${key}:skyline-facade-
|
|
82
|
+
material.customProgramCacheKey = () => `${key}:skyline-facade-v3`;
|
|
78
83
|
}
|
|
79
84
|
else {
|
|
80
85
|
material.onBeforeCompile = originalCompile;
|
|
@@ -99,7 +104,7 @@ if (vSkylineWindow.z > 0.0 && skylineDarkness > 0.0) {
|
|
|
99
104
|
uniforms.skylineDarkness.value = lighting?.darkness ?? 0;
|
|
100
105
|
uniforms.skylineWindowsSuppressed.value = celebration ? 1 : 0;
|
|
101
106
|
uniforms.skylineActivity.value = lighting?.activity ?? 0;
|
|
102
|
-
for (const [uniform, hex] of [[uniforms.skylineWindowWarm, nightColours.window], [uniforms.skylineWindowWhite, nightColours.windowWhite]]) {
|
|
107
|
+
for (const [uniform, hex] of [[uniforms.skylineWindowWarm, nightColours.window], [uniforms.skylineWindowWhite, nightColours.windowWhite], [uniforms.skylineWindowCool, nightColours.windowCool]]) {
|
|
103
108
|
uniform.value.setHex(hex);
|
|
104
109
|
if (!coloured) {
|
|
105
110
|
const { r, g, b } = uniform.value, grey = r * 0.2126 + g * 0.7152 + b * 0.0722;
|
|
@@ -29,6 +29,11 @@ const architectural = new Set(["lamp", "crown lights", "band lights", "sign lett
|
|
|
29
29
|
export function nightWindowMask(geometry, buildingId, materialOf) {
|
|
30
30
|
const positions = geometry.getAttribute("position"), normals = geometry.getAttribute("normal");
|
|
31
31
|
const mask = new Float32Array(positions.count * 4);
|
|
32
|
+
// A dominant fixture family per building, with smaller tenant-floor and room
|
|
33
|
+
// differences. Independent seeds keep colour from tracking occupancy/brightness.
|
|
34
|
+
// These are illustrated white-light mixes, not surveyed fixture temperatures.
|
|
35
|
+
const buildingTint = hash(`${buildingId}:fixture`);
|
|
36
|
+
const architecturalTint = 0.15 + 0.65 * hash(`${buildingId}:architectural-fixture`);
|
|
32
37
|
const samePoint = (a, b) => positions.getX(a) === positions.getX(b) && positions.getY(a) === positions.getY(b) && positions.getZ(a) === positions.getZ(b);
|
|
33
38
|
for (let first = 0; first < positions.count;) {
|
|
34
39
|
const name = materialOf(first), crown = architectural.has(name);
|
|
@@ -61,6 +66,9 @@ export function nightWindowMask(geometry, buildingId, materialOf) {
|
|
|
61
66
|
const floor = Math.round(y / count / 3.4), across = Math.floor(x / count / 7), depth = Math.floor(z / count / 7);
|
|
62
67
|
const room = hash(`${buildingId}:${floor}:${across}:${depth}`);
|
|
63
68
|
const brightness = hash(`${buildingId}:${floor}:${across}:${depth}:brightness`);
|
|
69
|
+
const tint = crown ? architecturalTint : 0.65 * buildingTint
|
|
70
|
+
+ 0.2 * hash(`${buildingId}:${floor}:fixture`)
|
|
71
|
+
+ 0.15 * hash(`${buildingId}:${floor}:${across}:${depth}:fixture`);
|
|
64
72
|
for (let vertex = first; vertex < end; vertex += 1) {
|
|
65
73
|
if (materialOf(vertex) !== name)
|
|
66
74
|
continue;
|
|
@@ -68,7 +76,7 @@ export function nightWindowMask(geometry, buildingId, materialOf) {
|
|
|
68
76
|
mask[vertex * 4] = rank;
|
|
69
77
|
mask[vertex * 4 + 1] = crown ? 0.3 : 0.25 + brightness * 0.45;
|
|
70
78
|
mask[vertex * 4 + 2] = crown ? 2 : 1;
|
|
71
|
-
mask[vertex * 4 + 3] =
|
|
79
|
+
mask[vertex * 4 + 3] = tint;
|
|
72
80
|
}
|
|
73
81
|
first = end;
|
|
74
82
|
}
|
package/package.json
CHANGED
|
@@ -290,8 +290,9 @@ export const measuredColours = {
|
|
|
290
290
|
// above the horizon, each the median of a clear box of the same panorama (scripts/sample-colours.ts,
|
|
291
291
|
// the day study's sky), and the sun's warm white, chosen.
|
|
292
292
|
export const daylightColours = { sky: 0x9ebbdb, horizon: 0xc4d1e1, sun: 0xfff4e6 };
|
|
293
|
-
//
|
|
294
|
-
|
|
293
|
+
// Illustrated warm, neutral and cool white fixtures; not calibrated Kelvin values.
|
|
294
|
+
// DOE's white-tuning overview informs the range; see docs/viewer.md (time of day).
|
|
295
|
+
export const nightColours = { ambient: 0xa1afc8, fill: 0x8d9fbd, window: 0xffc17d, windowWhite: 0xffedda, windowCool: 0xdceaff };
|
|
295
296
|
// Illustrated clear-sky time previews. Solar elevation chooses the stops; these are
|
|
296
297
|
// artistic colours, separate from the photograph-calibrated daytime palette above.
|
|
297
298
|
export const timeOfDayColours = [
|
|
@@ -22,6 +22,7 @@ export function glassReflection(material, geometry, mask, windows = new Float32A
|
|
|
22
22
|
skylineWindowsSuppressed: { value: 0 },
|
|
23
23
|
skylineWindowWarm: { value: new THREE.Color(nightColours.window) },
|
|
24
24
|
skylineWindowWhite: { value: new THREE.Color(nightColours.windowWhite) },
|
|
25
|
+
skylineWindowCool: { value: new THREE.Color(nightColours.windowCool) },
|
|
25
26
|
};
|
|
26
27
|
const compile = (shader, renderer) => {
|
|
27
28
|
originalCompile.call(material, shader, renderer);
|
|
@@ -44,7 +45,8 @@ uniform float skylineDarkness;
|
|
|
44
45
|
uniform float skylineActivity;
|
|
45
46
|
uniform float skylineWindowsSuppressed;
|
|
46
47
|
uniform vec3 skylineWindowWarm;
|
|
47
|
-
uniform vec3 skylineWindowWhite
|
|
48
|
+
uniform vec3 skylineWindowWhite;
|
|
49
|
+
uniform vec3 skylineWindowCool;`).replace("#include <opaque_fragment>", `
|
|
48
50
|
if (vSkylineGlass > 0.0 && skylineReflecting > 0.0) {
|
|
49
51
|
vec3 eye = vec3(0.0);
|
|
50
52
|
eye.z = 1.0;
|
|
@@ -59,7 +61,10 @@ if (vSkylineWindow.z > 0.0 && skylineDarkness > 0.0) {
|
|
|
59
61
|
float occupied = 1.0 - smoothstep(skylineActivity - 0.05, skylineActivity + 0.05, vSkylineWindow.x);
|
|
60
62
|
float dusk = smoothstep(0.12 + 0.35 * vSkylineWindow.x, 0.45 + 0.35 * vSkylineWindow.x, skylineDarkness);
|
|
61
63
|
float light = vSkylineWindow.z > 1.5 ? skylineDarkness : occupied * dusk * (1.0 - skylineWindowsSuppressed);
|
|
62
|
-
|
|
64
|
+
float tint = vSkylineWindow.w;
|
|
65
|
+
vec3 lamp = tint < 0.5
|
|
66
|
+
? mix(skylineWindowWarm, skylineWindowWhite, tint * 2.0)
|
|
67
|
+
: mix(skylineWindowWhite, skylineWindowCool, (tint - 0.5) * 2.0);
|
|
63
68
|
outgoingLight += lamp * vSkylineWindow.y * light;
|
|
64
69
|
}
|
|
65
70
|
#include <opaque_fragment>`);
|
|
@@ -74,7 +79,7 @@ if (vSkylineWindow.z > 0.0 && skylineDarkness > 0.0) {
|
|
|
74
79
|
geometry.setAttribute("skylineGlass", attribute);
|
|
75
80
|
geometry.setAttribute("skylineWindow", windowAttribute);
|
|
76
81
|
material.onBeforeCompile = compile;
|
|
77
|
-
material.customProgramCacheKey = () => `${key}:skyline-facade-
|
|
82
|
+
material.customProgramCacheKey = () => `${key}:skyline-facade-v3`;
|
|
78
83
|
}
|
|
79
84
|
else {
|
|
80
85
|
material.onBeforeCompile = originalCompile;
|
|
@@ -99,7 +104,7 @@ if (vSkylineWindow.z > 0.0 && skylineDarkness > 0.0) {
|
|
|
99
104
|
uniforms.skylineDarkness.value = lighting?.darkness ?? 0;
|
|
100
105
|
uniforms.skylineWindowsSuppressed.value = celebration ? 1 : 0;
|
|
101
106
|
uniforms.skylineActivity.value = lighting?.activity ?? 0;
|
|
102
|
-
for (const [uniform, hex] of [[uniforms.skylineWindowWarm, nightColours.window], [uniforms.skylineWindowWhite, nightColours.windowWhite]]) {
|
|
107
|
+
for (const [uniform, hex] of [[uniforms.skylineWindowWarm, nightColours.window], [uniforms.skylineWindowWhite, nightColours.windowWhite], [uniforms.skylineWindowCool, nightColours.windowCool]]) {
|
|
103
108
|
uniform.value.setHex(hex);
|
|
104
109
|
if (!coloured) {
|
|
105
110
|
const { r, g, b } = uniform.value, grey = r * 0.2126 + g * 0.7152 + b * 0.0722;
|
|
@@ -29,6 +29,11 @@ const architectural = new Set(["lamp", "crown lights", "band lights", "sign lett
|
|
|
29
29
|
export function nightWindowMask(geometry, buildingId, materialOf) {
|
|
30
30
|
const positions = geometry.getAttribute("position"), normals = geometry.getAttribute("normal");
|
|
31
31
|
const mask = new Float32Array(positions.count * 4);
|
|
32
|
+
// A dominant fixture family per building, with smaller tenant-floor and room
|
|
33
|
+
// differences. Independent seeds keep colour from tracking occupancy/brightness.
|
|
34
|
+
// These are illustrated white-light mixes, not surveyed fixture temperatures.
|
|
35
|
+
const buildingTint = hash(`${buildingId}:fixture`);
|
|
36
|
+
const architecturalTint = 0.15 + 0.65 * hash(`${buildingId}:architectural-fixture`);
|
|
32
37
|
const samePoint = (a, b) => positions.getX(a) === positions.getX(b) && positions.getY(a) === positions.getY(b) && positions.getZ(a) === positions.getZ(b);
|
|
33
38
|
for (let first = 0; first < positions.count;) {
|
|
34
39
|
const name = materialOf(first), crown = architectural.has(name);
|
|
@@ -61,6 +66,9 @@ export function nightWindowMask(geometry, buildingId, materialOf) {
|
|
|
61
66
|
const floor = Math.round(y / count / 3.4), across = Math.floor(x / count / 7), depth = Math.floor(z / count / 7);
|
|
62
67
|
const room = hash(`${buildingId}:${floor}:${across}:${depth}`);
|
|
63
68
|
const brightness = hash(`${buildingId}:${floor}:${across}:${depth}:brightness`);
|
|
69
|
+
const tint = crown ? architecturalTint : 0.65 * buildingTint
|
|
70
|
+
+ 0.2 * hash(`${buildingId}:${floor}:fixture`)
|
|
71
|
+
+ 0.15 * hash(`${buildingId}:${floor}:${across}:${depth}:fixture`);
|
|
64
72
|
for (let vertex = first; vertex < end; vertex += 1) {
|
|
65
73
|
if (materialOf(vertex) !== name)
|
|
66
74
|
continue;
|
|
@@ -68,7 +76,7 @@ export function nightWindowMask(geometry, buildingId, materialOf) {
|
|
|
68
76
|
mask[vertex * 4] = rank;
|
|
69
77
|
mask[vertex * 4 + 1] = crown ? 0.3 : 0.25 + brightness * 0.45;
|
|
70
78
|
mask[vertex * 4 + 2] = crown ? 2 : 1;
|
|
71
|
-
mask[vertex * 4 + 3] =
|
|
79
|
+
mask[vertex * 4 + 3] = tint;
|
|
72
80
|
}
|
|
73
81
|
first = end;
|
|
74
82
|
}
|