@a2f0/skyline 0.2.11 → 0.2.12

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.
@@ -1,6 +1,6 @@
1
1
  import type { BuildingModel } from "./building-kit.js";
2
2
  import type { Daylight } from "../study-types.js";
3
- export declare const materialNames: readonly ["neutral", "glass", "green glass", "blue-green glass", "bronze glass", "lit window", "dim window", "lamp", "limestone", "marble", "white granite", "granite", "dark granite", "slate", "white terracotta", "pink terracotta", "green tile", "brick", "common brick", "orange brick", "brown brick", "buff brick", "glazed brick", "concrete", "precast", "copper", "maroon", "blue enamel", "bronze", "dark metal", "aluminium", "stainless", "crown glass", "crown lights", "screen", "band lights", "sign board", "sign letters", "cap lights"];
3
+ export declare const materialNames: readonly ["neutral", "glass", "green glass", "blue-green glass", "bronze glass", "lit window", "dim window", "lamp", "limestone", "marble", "white granite", "granite", "dark granite", "slate", "white terracotta", "pink terracotta", "green tile", "brick", "common brick", "orange brick", "brown brick", "buff brick", "glazed brick", "concrete", "precast", "copper", "maroon", "blue enamel", "bronze", "dark metal", "aluminium", "stainless", "opaque spandrel", "crown glass", "crown lights", "screen", "band lights", "sign board", "sign letters", "cap lights"];
4
4
  export type MaterialName = (typeof materialNames)[number];
5
5
  export type Tones = Readonly<Record<number, MaterialName>>;
6
6
  export type Batch = readonly [material: MaterialName, tones?: Tones];
@@ -12,7 +12,7 @@ export const materialNames = [
12
12
  "neutral", "glass", "green glass", "blue-green glass", "bronze glass", "lit window", "dim window", "lamp",
13
13
  "limestone", "marble", "white granite", "granite", "dark granite", "slate",
14
14
  "white terracotta", "pink terracotta", "green tile", "brick", "common brick", "orange brick", "brown brick", "buff brick", "glazed brick",
15
- "concrete", "precast", "copper", "maroon", "blue enamel", "bronze", "dark metal", "aluminium", "stainless",
15
+ "concrete", "precast", "copper", "maroon", "blue enamel", "bronze", "dark metal", "aluminium", "stainless", "opaque spandrel",
16
16
  // Parts the photographs show on their own, named as the night first showed them: crown glass
17
17
  // and crown lights, an emblem screen and the lights in its bands, a sign's board and letters,
18
18
  // and a lit cap.
@@ -35,6 +35,7 @@ export const colourMaterials = {
35
35
  "building-kemper": {
36
36
  "marble shell": ["marble"],
37
37
  "mullions and bands": ["marble"],
38
+ "opaque spandrels": ["opaque spandrel"],
38
39
  "crown glazing": ["glass"],
39
40
  "crown fins": ["aluminium"],
40
41
  "roof cap": ["marble"],
@@ -89,6 +89,7 @@ export const measuredColours = {
89
89
  marble: 0xc3c0b6,
90
90
  ...glass(0x535455),
91
91
  aluminium: null,
92
+ "opaque spandrel": null,
92
93
  },
93
94
  // docs/north-wabash-reference.md, 2026-10-09 — Daytime colours from Chicago.jpg.
94
95
  "building-330-north-wabash": {
@@ -4,7 +4,8 @@ import { createBuilder, inside, line, polygonOf } from "./building-kit.js";
4
4
  // outlines; the 159 m top is OSM's height tag (522 ft in the 1962 record).
5
5
  // The marble shell, window bays, raised mullions, dark crown band with light
6
6
  // fins, and projecting cap reuse the fitted model's vocabulary at meter scale.
7
- // Window-row, bay, and crown spacings are estimates; see
7
+ // Window-column and pane proportions follow a 2012 photograph; bay counts,
8
+ // window-row and crown spacings remain estimates. See
8
9
  // docs/kemper-geographic-reference.md. Units are meters; +x is east, +z south.
9
10
  export const kemperGeographicLevels = Object.freeze({
10
11
  podium: 7.8, // OSM way 685494067: two floors at the tower's average floor height
@@ -25,6 +26,7 @@ export function createKemperGeographicBuilding(record, projectPlan, offset) {
25
26
  // with scattered lit units, pale mullions and fins.
26
27
  const marble = kit.batch("Kemper · marble shell", kit.material(0x929292));
27
28
  const mullions = kit.batch("Kemper · mullions and bands", kit.material(0x9b9b9b));
29
+ const spandrels = kit.batch("Kemper · opaque spandrels", kit.material(0x626262));
28
30
  const crownGlass = kit.batch("Kemper · crown glazing", kit.material(0x1c1c1c));
29
31
  const crownFins = kit.batch("Kemper · crown fins", kit.material(0xa3a3a3));
30
32
  const cap = kit.batch("Kemper · roof cap", kit.material(0xa8a8a8));
@@ -58,21 +60,25 @@ export function createKemperGeographicBuilding(record, projectPlan, offset) {
58
60
  return;
59
61
  kit.box(batch, run.at((from + to) / 2), run.normal(0), (to - from) / 2, back, front, y0, y1);
60
62
  };
61
- // Tower facade: one pane per bay per row between full-height mullions, with
62
- // a spandrel at each floor line. Mullions stand proudest of the tower detail.
63
+ // FID-KEM-002: the 2012 north-face photograph gives openings about 48% of
64
+ // each bay and glass about 52% of each floor pitch. Opaque panels continue
65
+ // the narrow columns between windows; the marble piers stay uninterrupted.
63
66
  tower.forEach((run, side) => {
64
67
  const bays = Math.max(1, Math.round(run.length / 3.1));
65
68
  const width = run.length / bays;
69
+ const inset = width * 0.26;
70
+ for (let bay = 0; bay < bays; bay += 1) {
71
+ strip(spandrels, run, bay * width + inset, (bay + 1) * width - inset, h.podium, crownBase, 0.01, 0.04);
72
+ }
66
73
  for (let floor = 3; floor <= 39; floor += 1) {
67
74
  const bottom = floorHeight(floor), top = floorHeight(floor + 1);
68
75
  for (let bay = 0; bay < bays; bay += 1) {
69
- strip(paneTone(floor, bay, side), run, bay * width + 0.16, (bay + 1) * width - 0.16, bottom + 0.26, top - 0.24, 0.02, 0.07);
76
+ strip(paneTone(floor, bay, side), run, bay * width + inset + 0.01, (bay + 1) * width - inset - 0.01, bottom + pitch * 0.24, top - pitch * 0.24, 0.02, 0.07);
70
77
  }
71
- strip(mullions, run, 0.015, run.length - 0.015, top - 0.15, top + 0.05, 0.03, 0.12);
72
78
  }
73
79
  for (let i = 0; i <= bays; i += 1) {
74
80
  const s = Math.max(0.18, Math.min(run.length - 0.18, i * width));
75
- strip(mullions, run, s - 0.06, s + 0.06, h.podium + 0.02, crownBase - 0.05, 0.05, 0.16);
81
+ strip(mullions, run, s - inset, s + inset, h.podium + 0.02, crownBase - 0.05, 0.05, 0.16);
76
82
  }
77
83
  strip(mullions, run, 0.015, run.length - 0.015, h.podium - 0.05, h.podium + 0.35, 0.06, 0.18);
78
84
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@a2f0/skyline",
3
- "version": "0.2.11",
3
+ "version": "0.2.12",
4
4
  "description": "Interactive Chicago skyline viewer and reusable Three.js building models",
5
5
  "license": "UNLICENSED",
6
6
  "repository": {
@@ -12,7 +12,7 @@ export const materialNames = [
12
12
  "neutral", "glass", "green glass", "blue-green glass", "bronze glass", "lit window", "dim window", "lamp",
13
13
  "limestone", "marble", "white granite", "granite", "dark granite", "slate",
14
14
  "white terracotta", "pink terracotta", "green tile", "brick", "common brick", "orange brick", "brown brick", "buff brick", "glazed brick",
15
- "concrete", "precast", "copper", "maroon", "blue enamel", "bronze", "dark metal", "aluminium", "stainless",
15
+ "concrete", "precast", "copper", "maroon", "blue enamel", "bronze", "dark metal", "aluminium", "stainless", "opaque spandrel",
16
16
  // Parts the photographs show on their own, named as the night first showed them: crown glass
17
17
  // and crown lights, an emblem screen and the lights in its bands, a sign's board and letters,
18
18
  // and a lit cap.
@@ -35,6 +35,7 @@ export const colourMaterials = {
35
35
  "building-kemper": {
36
36
  "marble shell": ["marble"],
37
37
  "mullions and bands": ["marble"],
38
+ "opaque spandrels": ["opaque spandrel"],
38
39
  "crown glazing": ["glass"],
39
40
  "crown fins": ["aluminium"],
40
41
  "roof cap": ["marble"],
@@ -89,6 +89,7 @@ export const measuredColours = {
89
89
  marble: 0xc3c0b6,
90
90
  ...glass(0x535455),
91
91
  aluminium: null,
92
+ "opaque spandrel": null,
92
93
  },
93
94
  // docs/north-wabash-reference.md, 2026-10-09 — Daytime colours from Chicago.jpg.
94
95
  "building-330-north-wabash": {
@@ -4,7 +4,8 @@ import { createBuilder, inside, line, polygonOf } from "./building-kit.js";
4
4
  // outlines; the 159 m top is OSM's height tag (522 ft in the 1962 record).
5
5
  // The marble shell, window bays, raised mullions, dark crown band with light
6
6
  // fins, and projecting cap reuse the fitted model's vocabulary at meter scale.
7
- // Window-row, bay, and crown spacings are estimates; see
7
+ // Window-column and pane proportions follow a 2012 photograph; bay counts,
8
+ // window-row and crown spacings remain estimates. See
8
9
  // docs/kemper-geographic-reference.md. Units are meters; +x is east, +z south.
9
10
  export const kemperGeographicLevels = Object.freeze({
10
11
  podium: 7.8, // OSM way 685494067: two floors at the tower's average floor height
@@ -25,6 +26,7 @@ export function createKemperGeographicBuilding(record, projectPlan, offset) {
25
26
  // with scattered lit units, pale mullions and fins.
26
27
  const marble = kit.batch("Kemper · marble shell", kit.material(0x929292));
27
28
  const mullions = kit.batch("Kemper · mullions and bands", kit.material(0x9b9b9b));
29
+ const spandrels = kit.batch("Kemper · opaque spandrels", kit.material(0x626262));
28
30
  const crownGlass = kit.batch("Kemper · crown glazing", kit.material(0x1c1c1c));
29
31
  const crownFins = kit.batch("Kemper · crown fins", kit.material(0xa3a3a3));
30
32
  const cap = kit.batch("Kemper · roof cap", kit.material(0xa8a8a8));
@@ -58,21 +60,25 @@ export function createKemperGeographicBuilding(record, projectPlan, offset) {
58
60
  return;
59
61
  kit.box(batch, run.at((from + to) / 2), run.normal(0), (to - from) / 2, back, front, y0, y1);
60
62
  };
61
- // Tower facade: one pane per bay per row between full-height mullions, with
62
- // a spandrel at each floor line. Mullions stand proudest of the tower detail.
63
+ // FID-KEM-002: the 2012 north-face photograph gives openings about 48% of
64
+ // each bay and glass about 52% of each floor pitch. Opaque panels continue
65
+ // the narrow columns between windows; the marble piers stay uninterrupted.
63
66
  tower.forEach((run, side) => {
64
67
  const bays = Math.max(1, Math.round(run.length / 3.1));
65
68
  const width = run.length / bays;
69
+ const inset = width * 0.26;
70
+ for (let bay = 0; bay < bays; bay += 1) {
71
+ strip(spandrels, run, bay * width + inset, (bay + 1) * width - inset, h.podium, crownBase, 0.01, 0.04);
72
+ }
66
73
  for (let floor = 3; floor <= 39; floor += 1) {
67
74
  const bottom = floorHeight(floor), top = floorHeight(floor + 1);
68
75
  for (let bay = 0; bay < bays; bay += 1) {
69
- strip(paneTone(floor, bay, side), run, bay * width + 0.16, (bay + 1) * width - 0.16, bottom + 0.26, top - 0.24, 0.02, 0.07);
76
+ strip(paneTone(floor, bay, side), run, bay * width + inset + 0.01, (bay + 1) * width - inset - 0.01, bottom + pitch * 0.24, top - pitch * 0.24, 0.02, 0.07);
70
77
  }
71
- strip(mullions, run, 0.015, run.length - 0.015, top - 0.15, top + 0.05, 0.03, 0.12);
72
78
  }
73
79
  for (let i = 0; i <= bays; i += 1) {
74
80
  const s = Math.max(0.18, Math.min(run.length - 0.18, i * width));
75
- strip(mullions, run, s - 0.06, s + 0.06, h.podium + 0.02, crownBase - 0.05, 0.05, 0.16);
81
+ strip(mullions, run, s - inset, s + inset, h.podium + 0.02, crownBase - 0.05, 0.05, 0.16);
76
82
  }
77
83
  strip(mullions, run, 0.015, run.length - 0.015, h.podium - 0.05, h.podium + 0.35, 0.06, 0.18);
78
84
  });