@motionscript/geo 0.0.0-stage → 0.1.0-alpha.3
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/CHANGELOG.md +21 -0
- package/LICENSE +201 -0
- package/dist/border/format.d.ts +73 -0
- package/dist/border/format.d.ts.map +1 -0
- package/dist/border/format.js +68 -0
- package/dist/border/format.js.map +1 -0
- package/dist/border/geo-border.d.ts +44 -0
- package/dist/border/geo-border.d.ts.map +1 -0
- package/dist/border/geo-border.js +234 -0
- package/dist/border/geo-border.js.map +1 -0
- package/dist/border/geometry.d.ts +40 -0
- package/dist/border/geometry.d.ts.map +1 -0
- package/dist/border/geometry.js +382 -0
- package/dist/border/geometry.js.map +1 -0
- package/dist/border/index.d.ts +15 -0
- package/dist/border/index.d.ts.map +1 -0
- package/dist/border/index.js +15 -0
- package/dist/border/index.js.map +1 -0
- package/dist/border/loader.d.ts +31 -0
- package/dist/border/loader.d.ts.map +1 -0
- package/dist/border/loader.js +87 -0
- package/dist/border/loader.js.map +1 -0
- package/dist/border/registry.d.ts +64 -0
- package/dist/border/registry.d.ts.map +1 -0
- package/dist/border/registry.js +152 -0
- package/dist/border/registry.js.map +1 -0
- package/dist/border/selection.d.ts +21 -0
- package/dist/border/selection.d.ts.map +1 -0
- package/dist/border/selection.js +86 -0
- package/dist/border/selection.js.map +1 -0
- package/dist/border/simplify.d.ts +12 -0
- package/dist/border/simplify.d.ts.map +1 -0
- package/dist/border/simplify.js +116 -0
- package/dist/border/simplify.js.map +1 -0
- package/dist/browser/index.js +25 -0
- package/dist/browser/index.js.map +7 -0
- package/dist/browser/manifest.json +11 -0
- package/dist/globe/atmosphere.d.ts +38 -0
- package/dist/globe/atmosphere.d.ts.map +1 -0
- package/dist/globe/atmosphere.js +91 -0
- package/dist/globe/atmosphere.js.map +1 -0
- package/dist/globe/borders.d.ts +39 -0
- package/dist/globe/borders.d.ts.map +1 -0
- package/dist/globe/borders.js +116 -0
- package/dist/globe/borders.js.map +1 -0
- package/dist/globe/data/ne-110m.d.ts +25 -0
- package/dist/globe/data/ne-110m.d.ts.map +1 -0
- package/dist/globe/data/ne-110m.js +198 -0
- package/dist/globe/data/ne-110m.js.map +1 -0
- package/dist/globe/globe-places.d.ts +140 -0
- package/dist/globe/globe-places.d.ts.map +1 -0
- package/dist/globe/globe-places.js +262 -0
- package/dist/globe/globe-places.js.map +1 -0
- package/dist/globe/globe.d.ts +193 -0
- package/dist/globe/globe.d.ts.map +1 -0
- package/dist/globe/globe.js +435 -0
- package/dist/globe/globe.js.map +1 -0
- package/dist/globe/index.d.ts +17 -0
- package/dist/globe/index.d.ts.map +1 -0
- package/dist/globe/index.js +17 -0
- package/dist/globe/index.js.map +1 -0
- package/dist/globe/places.d.ts +69 -0
- package/dist/globe/places.d.ts.map +1 -0
- package/dist/globe/places.js +94 -0
- package/dist/globe/places.js.map +1 -0
- package/dist/globe/projection.d.ts +182 -0
- package/dist/globe/projection.d.ts.map +1 -0
- package/dist/globe/projection.js +215 -0
- package/dist/globe/projection.js.map +1 -0
- package/dist/globe/world-map.d.ts +83 -0
- package/dist/globe/world-map.d.ts.map +1 -0
- package/dist/globe/world-map.js +169 -0
- package/dist/globe/world-map.js.map +1 -0
- package/dist/globe/world.d.ts +46 -0
- package/dist/globe/world.d.ts.map +1 -0
- package/dist/globe/world.js +71 -0
- package/dist/globe/world.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/nodes.d.ts +19 -0
- package/dist/nodes.d.ts.map +1 -0
- package/dist/nodes.js +19 -0
- package/dist/nodes.js.map +1 -0
- package/package.json +69 -3
- package/registry.json +31 -0
- package/src/border/format.ts +147 -0
- package/src/border/geo-border.ts +260 -0
- package/src/border/geometry.ts +463 -0
- package/src/border/index.ts +14 -0
- package/src/border/loader.ts +97 -0
- package/src/border/registry.ts +191 -0
- package/src/border/selection.ts +95 -0
- package/src/border/simplify.ts +110 -0
- package/src/globe/atmosphere.ts +98 -0
- package/src/globe/borders.ts +166 -0
- package/src/globe/data/ne-110m.ts +214 -0
- package/src/globe/globe-places.ts +352 -0
- package/src/globe/globe.ts +552 -0
- package/src/globe/index.ts +16 -0
- package/src/globe/places.ts +132 -0
- package/src/globe/projection.ts +261 -0
- package/src/globe/world-map.ts +227 -0
- package/src/globe/world.ts +111 -0
- package/src/index.ts +5 -0
- package/src/nodes.ts +19 -0
- package/README.md +0 -4
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What an author places on a Globe — the marked points, and the arcs between
|
|
3
|
+
* them — as the panel edits them and the stored field holds them.
|
|
4
|
+
*
|
|
5
|
+
* Beside `graph-equations.ts` and shaped like it, because it is the same
|
|
6
|
+
* problem: an appearance value is `number | string | boolean`, so a *list* has
|
|
7
|
+
* to arrive as one string that a mapper reads. What lives here is the authored
|
|
8
|
+
* shape and its serialization, shared by the inspector's tiles and the node's
|
|
9
|
+
* builder; what a frame actually draws is `nodes/globe/impl/places.ts`, which
|
|
10
|
+
* resolves this into coordinates and clamps it to what the render can use.
|
|
11
|
+
*
|
|
12
|
+
* The split matters in one direction: **reading must be faithful and must not
|
|
13
|
+
* mint identity**. The panel reads on every render and the builder on every
|
|
14
|
+
* rebuild, so a random id here would be a different id every time — and two
|
|
15
|
+
* things key off it (a tile's React key, and which arc endpoint points at which
|
|
16
|
+
* marker). {@link createMarker} mints ids; the readers derive a positional one
|
|
17
|
+
* and never invent.
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* A marked point on the surface.
|
|
21
|
+
*
|
|
22
|
+
* `label` is **not drawn**. It names the tile in the inspector and the entries
|
|
23
|
+
* in an arc's endpoint menus, which is the whole of its job today — a label
|
|
24
|
+
* rendered against the globe is a separate problem (it has to face the camera,
|
|
25
|
+
* hide when it rotates behind the planet, and not collide with its neighbours),
|
|
26
|
+
* and storing the text now is what lets that arrive without a migration.
|
|
27
|
+
*/
|
|
28
|
+
export interface GlobeMarker {
|
|
29
|
+
/** Identity across list edits — a tween matches like with like. */
|
|
30
|
+
id: string;
|
|
31
|
+
/** A name for this place. Editor-facing only; see the note above. */
|
|
32
|
+
label: string;
|
|
33
|
+
/** Degrees north, −90…90. */
|
|
34
|
+
lat: number;
|
|
35
|
+
/** Degrees east, −180…180. */
|
|
36
|
+
lon: number;
|
|
37
|
+
/** Any colour string the fill parser takes. Empty means the palette entry. */
|
|
38
|
+
color: string;
|
|
39
|
+
/** Radius as a fraction of the globe's own. */
|
|
40
|
+
size: number;
|
|
41
|
+
/** 0–1. A fade, unlike {@link enabled}, which is a switch. */
|
|
42
|
+
opacity: number;
|
|
43
|
+
/** Whether it draws. Off keeps the tile in place, editable, with its colour. */
|
|
44
|
+
enabled: boolean;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* One end of an arc: a marker it is pinned to, or a place of its own.
|
|
48
|
+
*
|
|
49
|
+
* The pinned form is the one the tile offers first, and it is not merely
|
|
50
|
+
* convenient — an arc between two *marked* places moves when the place does,
|
|
51
|
+
* where a copied pair of coordinates silently stops matching the dot it was
|
|
52
|
+
* drawn to. That is the same reasoning a state machine's connection names its
|
|
53
|
+
* ends by state id rather than by position.
|
|
54
|
+
*
|
|
55
|
+
* The free form stays because not every end wants a dot on it, and because a
|
|
56
|
+
* list written by hand or by an agent reaches for a coordinate pair first.
|
|
57
|
+
*/
|
|
58
|
+
export type ArcEnd = {
|
|
59
|
+
readonly kind: "marker";
|
|
60
|
+
readonly markerId: string;
|
|
61
|
+
} | {
|
|
62
|
+
readonly kind: "place";
|
|
63
|
+
readonly lat: number;
|
|
64
|
+
readonly lon: number;
|
|
65
|
+
};
|
|
66
|
+
/** A great-circle path between two ends. */
|
|
67
|
+
export interface GlobeArc {
|
|
68
|
+
id: string;
|
|
69
|
+
from: ArcEnd;
|
|
70
|
+
to: ArcEnd;
|
|
71
|
+
color: string;
|
|
72
|
+
/** Tube radius as a fraction of the globe's own. */
|
|
73
|
+
width: number;
|
|
74
|
+
/** How far the middle lifts off the surface, as a fraction of the radius. */
|
|
75
|
+
lift: number;
|
|
76
|
+
/**
|
|
77
|
+
* How much of the path is drawn, 0–1 — a line that draws itself on.
|
|
78
|
+
*
|
|
79
|
+
* A fraction of the *path* rather than a time, so it means the same thing
|
|
80
|
+
* whatever the arc's length and is the author's to tween from wherever they
|
|
81
|
+
* like. Zero draws nothing and is not an error.
|
|
82
|
+
*/
|
|
83
|
+
progress: number;
|
|
84
|
+
enabled: boolean;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* The palette an uncoloured marker takes its colour from, by position.
|
|
88
|
+
*
|
|
89
|
+
* Warm-to-cool rather than a spectrum: markers are read against a dark ocean and
|
|
90
|
+
* usually mean something ranked — the first is the subject and the rest are
|
|
91
|
+
* context — so the order runs from the one that carries furthest to the one that
|
|
92
|
+
* recedes. Six, then it wraps; a seventh place that has to stand out sets its
|
|
93
|
+
* own colour.
|
|
94
|
+
*/
|
|
95
|
+
export declare const DEFAULT_MARKER_COLORS: readonly ["#ff3b30", "#ff9f0a", "#ffd60a", "#30d158", "#5ac8fa", "#bf5af2"];
|
|
96
|
+
/** The colour a marker at `index` is drawn in when it names none. */
|
|
97
|
+
export declare function markerColorAt(index: number): string;
|
|
98
|
+
/** The colour an arc falls back to. */
|
|
99
|
+
export declare const DEFAULT_ARC_COLOR = "#ffd60a";
|
|
100
|
+
/** A new marker tile: showing, opaque, and at the given place. */
|
|
101
|
+
export declare function createMarker(at?: {
|
|
102
|
+
lat: number;
|
|
103
|
+
lon: number;
|
|
104
|
+
}): GlobeMarker;
|
|
105
|
+
/** A new arc tile, between two ends. */
|
|
106
|
+
export declare function createArc(from: ArcEnd, to: ArcEnd): GlobeArc;
|
|
107
|
+
/** An end pinned to a marker. */
|
|
108
|
+
export declare function markerEnd(markerId: string): ArcEnd;
|
|
109
|
+
/** An end at a place of its own. */
|
|
110
|
+
export declare function placeEnd(lat: number, lon: number): ArcEnd;
|
|
111
|
+
/**
|
|
112
|
+
* Reads a stored marker list, defensively.
|
|
113
|
+
*
|
|
114
|
+
* Never throws, and drops only what it genuinely cannot place: the field is
|
|
115
|
+
* edited a keystroke at a time by hand as well as through the tiles, so it is
|
|
116
|
+
* invalid far more often than it is valid, and a reader that threw would blank
|
|
117
|
+
* the canvas on the way from `[` to `[{`.
|
|
118
|
+
*
|
|
119
|
+
* A row with **no position at all** is the one thing that is dropped rather than
|
|
120
|
+
* defaulted. Every other field has an honest default; a latitude does not, and
|
|
121
|
+
* putting an unplaced marker on the equator would draw a dot somewhere nobody
|
|
122
|
+
* asked for and call it the author's.
|
|
123
|
+
*/
|
|
124
|
+
export declare function markersOf(value: unknown): GlobeMarker[];
|
|
125
|
+
/** Reads a stored arc list, on the same terms as {@link markersOf}. */
|
|
126
|
+
export declare function arcsOf(value: unknown): GlobeArc[];
|
|
127
|
+
/** Serializes a marker list into the stored string form. */
|
|
128
|
+
export declare function markersToValue(markers: readonly GlobeMarker[]): string;
|
|
129
|
+
/**
|
|
130
|
+
* Serializes an arc list, writing each end back in the shape it was authored in.
|
|
131
|
+
*
|
|
132
|
+
* A pinned end is a bare **string** and a free one a `[lat, lon]` **pair**,
|
|
133
|
+
* rather than the tagged union this module works in. Two reasons, and the second
|
|
134
|
+
* is the load-bearing one: those are the two shapes somebody writing this list
|
|
135
|
+
* by hand reaches for, and a stored document is read by whatever version opens
|
|
136
|
+
* it later — so the wire form is public API and a discriminant that only exists
|
|
137
|
+
* to make the TypeScript convenient does not belong in it.
|
|
138
|
+
*/
|
|
139
|
+
export declare function arcsToValue(arcs: readonly GlobeArc[]): string;
|
|
140
|
+
//# sourceMappingURL=globe-places.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"globe-places.d.ts","sourceRoot":"","sources":["../../src/globe/globe-places.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH;;;;;;;;GAQG;AACH,MAAM,WAAW,WAAW;IAC1B,mEAAmE;IACnE,EAAE,EAAE,MAAM,CAAA;IACV,qEAAqE;IACrE,KAAK,EAAE,MAAM,CAAA;IACb,6BAA6B;IAC7B,GAAG,EAAE,MAAM,CAAA;IACX,8BAA8B;IAC9B,GAAG,EAAE,MAAM,CAAA;IACX,8EAA8E;IAC9E,KAAK,EAAE,MAAM,CAAA;IACb,+CAA+C;IAC/C,IAAI,EAAE,MAAM,CAAA;IACZ,8DAA8D;IAC9D,OAAO,EAAE,MAAM,CAAA;IACf,gFAAgF;IAChF,OAAO,EAAE,OAAO,CAAA;CACjB;AAED;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,MAAM,GACd;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GACtD;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAA;AAE1E,4CAA4C;AAC5C,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,oDAAoD;IACpD,KAAK,EAAE,MAAM,CAAA;IACb,6EAA6E;IAC7E,IAAI,EAAE,MAAM,CAAA;IACZ;;;;;;OAMG;IACH,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,OAAO,CAAA;CACjB;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,qBAAqB,6EAOxB,CAAA;AAEV,qEAAqE;AACrE,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAGnD;AAED,uCAAuC;AACvC,eAAO,MAAM,iBAAiB,YAAY,CAAA;AAuB1C,kEAAkE;AAClE,wBAAgB,YAAY,CAC1B,EAAE,GAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAuB,GACpD,WAAW,CAWb;AAED,wCAAwC;AACxC,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,QAAQ,CAW5D;AAED,iCAAiC;AACjC,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAElD;AAED,oCAAoC;AACpC,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAEzD;AAID;;;;;;;;;;;;GAYG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,OAAO,GAAG,WAAW,EAAE,CAoBvD;AAED,uEAAuE;AACvE,wBAAgB,MAAM,CAAC,KAAK,EAAE,OAAO,GAAG,QAAQ,EAAE,CAkBjD;AAED,4DAA4D;AAC5D,wBAAgB,cAAc,CAAC,OAAO,EAAE,SAAS,WAAW,EAAE,GAAG,MAAM,CAEtE;AAED;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,SAAS,QAAQ,EAAE,GAAG,MAAM,CAI7D"}
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What an author places on a Globe — the marked points, and the arcs between
|
|
3
|
+
* them — as the panel edits them and the stored field holds them.
|
|
4
|
+
*
|
|
5
|
+
* Beside `graph-equations.ts` and shaped like it, because it is the same
|
|
6
|
+
* problem: an appearance value is `number | string | boolean`, so a *list* has
|
|
7
|
+
* to arrive as one string that a mapper reads. What lives here is the authored
|
|
8
|
+
* shape and its serialization, shared by the inspector's tiles and the node's
|
|
9
|
+
* builder; what a frame actually draws is `nodes/globe/impl/places.ts`, which
|
|
10
|
+
* resolves this into coordinates and clamps it to what the render can use.
|
|
11
|
+
*
|
|
12
|
+
* The split matters in one direction: **reading must be faithful and must not
|
|
13
|
+
* mint identity**. The panel reads on every render and the builder on every
|
|
14
|
+
* rebuild, so a random id here would be a different id every time — and two
|
|
15
|
+
* things key off it (a tile's React key, and which arc endpoint points at which
|
|
16
|
+
* marker). {@link createMarker} mints ids; the readers derive a positional one
|
|
17
|
+
* and never invent.
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* The palette an uncoloured marker takes its colour from, by position.
|
|
21
|
+
*
|
|
22
|
+
* Warm-to-cool rather than a spectrum: markers are read against a dark ocean and
|
|
23
|
+
* usually mean something ranked — the first is the subject and the rest are
|
|
24
|
+
* context — so the order runs from the one that carries furthest to the one that
|
|
25
|
+
* recedes. Six, then it wraps; a seventh place that has to stand out sets its
|
|
26
|
+
* own colour.
|
|
27
|
+
*/
|
|
28
|
+
export const DEFAULT_MARKER_COLORS = [
|
|
29
|
+
"#ff3b30",
|
|
30
|
+
"#ff9f0a",
|
|
31
|
+
"#ffd60a",
|
|
32
|
+
"#30d158",
|
|
33
|
+
"#5ac8fa",
|
|
34
|
+
"#bf5af2",
|
|
35
|
+
];
|
|
36
|
+
/** The colour a marker at `index` is drawn in when it names none. */
|
|
37
|
+
export function markerColorAt(index) {
|
|
38
|
+
const palette = DEFAULT_MARKER_COLORS;
|
|
39
|
+
return palette[((index % palette.length) + palette.length) % palette.length];
|
|
40
|
+
}
|
|
41
|
+
/** The colour an arc falls back to. */
|
|
42
|
+
export const DEFAULT_ARC_COLOR = "#ffd60a";
|
|
43
|
+
const DEFAULT_MARKER_SIZE = 0.02;
|
|
44
|
+
const DEFAULT_ARC_WIDTH = 0.004;
|
|
45
|
+
const DEFAULT_ARC_LIFT = 0.25;
|
|
46
|
+
/**
|
|
47
|
+
* A fresh id for a tile.
|
|
48
|
+
*
|
|
49
|
+
* A counter plus a short random suffix rather than `crypto.randomUUID`, exactly
|
|
50
|
+
* as `graph-equations.ts` explains: this package loads in a bare Node process
|
|
51
|
+
* with no DOM and no assumed globals, and an id only has to be unique within one
|
|
52
|
+
* node's list. The suffix is what stops two clients editing the same scene
|
|
53
|
+
* colliding on `mk-3`.
|
|
54
|
+
*
|
|
55
|
+
* Never called during a build — only when an author adds a tile.
|
|
56
|
+
*/
|
|
57
|
+
let placeSeq = 0;
|
|
58
|
+
function nextId(prefix) {
|
|
59
|
+
placeSeq += 1;
|
|
60
|
+
return `${prefix}-${placeSeq}-${Math.random().toString(36).slice(2, 8)}`;
|
|
61
|
+
}
|
|
62
|
+
/** A new marker tile: showing, opaque, and at the given place. */
|
|
63
|
+
export function createMarker(at = { lat: 0, lon: 0 }) {
|
|
64
|
+
return {
|
|
65
|
+
id: nextId("mk"),
|
|
66
|
+
label: "",
|
|
67
|
+
lat: at.lat,
|
|
68
|
+
lon: at.lon,
|
|
69
|
+
color: "",
|
|
70
|
+
size: DEFAULT_MARKER_SIZE,
|
|
71
|
+
opacity: 1,
|
|
72
|
+
enabled: true,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
/** A new arc tile, between two ends. */
|
|
76
|
+
export function createArc(from, to) {
|
|
77
|
+
return {
|
|
78
|
+
id: nextId("arc"),
|
|
79
|
+
from,
|
|
80
|
+
to,
|
|
81
|
+
color: DEFAULT_ARC_COLOR,
|
|
82
|
+
width: DEFAULT_ARC_WIDTH,
|
|
83
|
+
lift: DEFAULT_ARC_LIFT,
|
|
84
|
+
progress: 1,
|
|
85
|
+
enabled: true,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
/** An end pinned to a marker. */
|
|
89
|
+
export function markerEnd(markerId) {
|
|
90
|
+
return { kind: "marker", markerId };
|
|
91
|
+
}
|
|
92
|
+
/** An end at a place of its own. */
|
|
93
|
+
export function placeEnd(lat, lon) {
|
|
94
|
+
return { kind: "place", lat, lon };
|
|
95
|
+
}
|
|
96
|
+
// --- Reading ---------------------------------------------------------------
|
|
97
|
+
/**
|
|
98
|
+
* Reads a stored marker list, defensively.
|
|
99
|
+
*
|
|
100
|
+
* Never throws, and drops only what it genuinely cannot place: the field is
|
|
101
|
+
* edited a keystroke at a time by hand as well as through the tiles, so it is
|
|
102
|
+
* invalid far more often than it is valid, and a reader that threw would blank
|
|
103
|
+
* the canvas on the way from `[` to `[{`.
|
|
104
|
+
*
|
|
105
|
+
* A row with **no position at all** is the one thing that is dropped rather than
|
|
106
|
+
* defaulted. Every other field has an honest default; a latitude does not, and
|
|
107
|
+
* putting an unplaced marker on the equator would draw a dot somewhere nobody
|
|
108
|
+
* asked for and call it the author's.
|
|
109
|
+
*/
|
|
110
|
+
export function markersOf(value) {
|
|
111
|
+
return rowsOf(value).flatMap((row, index) => {
|
|
112
|
+
const lat = finite(row.lat ?? row.latitude);
|
|
113
|
+
const lon = finite(row.lon ?? row.lng ?? row.longitude);
|
|
114
|
+
if (lat === null || lon === null)
|
|
115
|
+
return [];
|
|
116
|
+
return [
|
|
117
|
+
{
|
|
118
|
+
id: idOf(row.id, `mk:${index}`),
|
|
119
|
+
label: text(row.label ?? row.name) ?? "",
|
|
120
|
+
lat: clamp(lat, -90, 90),
|
|
121
|
+
lon: wrapLongitude(lon),
|
|
122
|
+
color: text(row.color) ?? "",
|
|
123
|
+
size: positive(row.size, DEFAULT_MARKER_SIZE),
|
|
124
|
+
opacity: unit(row.opacity),
|
|
125
|
+
// Absent means on, as everywhere else a switch is stored: only an
|
|
126
|
+
// explicit `false` turns a tile off.
|
|
127
|
+
enabled: row.enabled !== false,
|
|
128
|
+
},
|
|
129
|
+
];
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
/** Reads a stored arc list, on the same terms as {@link markersOf}. */
|
|
133
|
+
export function arcsOf(value) {
|
|
134
|
+
return rowsOf(value).flatMap((row, index) => {
|
|
135
|
+
const from = endOf(row.from);
|
|
136
|
+
const to = endOf(row.to);
|
|
137
|
+
if (!from || !to)
|
|
138
|
+
return [];
|
|
139
|
+
return [
|
|
140
|
+
{
|
|
141
|
+
id: idOf(row.id, `arc:${index}`),
|
|
142
|
+
from,
|
|
143
|
+
to,
|
|
144
|
+
color: text(row.color) ?? DEFAULT_ARC_COLOR,
|
|
145
|
+
width: positive(row.width, DEFAULT_ARC_WIDTH),
|
|
146
|
+
lift: clamp(finite(row.lift) ?? DEFAULT_ARC_LIFT, 0, 4),
|
|
147
|
+
progress: unit(row.progress),
|
|
148
|
+
enabled: row.enabled !== false,
|
|
149
|
+
},
|
|
150
|
+
];
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
/** Serializes a marker list into the stored string form. */
|
|
154
|
+
export function markersToValue(markers) {
|
|
155
|
+
return JSON.stringify(markers);
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Serializes an arc list, writing each end back in the shape it was authored in.
|
|
159
|
+
*
|
|
160
|
+
* A pinned end is a bare **string** and a free one a `[lat, lon]` **pair**,
|
|
161
|
+
* rather than the tagged union this module works in. Two reasons, and the second
|
|
162
|
+
* is the load-bearing one: those are the two shapes somebody writing this list
|
|
163
|
+
* by hand reaches for, and a stored document is read by whatever version opens
|
|
164
|
+
* it later — so the wire form is public API and a discriminant that only exists
|
|
165
|
+
* to make the TypeScript convenient does not belong in it.
|
|
166
|
+
*/
|
|
167
|
+
export function arcsToValue(arcs) {
|
|
168
|
+
return JSON.stringify(arcs.map((arc) => ({ ...arc, from: endToValue(arc.from), to: endToValue(arc.to) })));
|
|
169
|
+
}
|
|
170
|
+
function endToValue(end) {
|
|
171
|
+
return end.kind === "marker" ? end.markerId : [end.lat, end.lon];
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* One end, from any of the three shapes a stored list holds it in.
|
|
175
|
+
*
|
|
176
|
+
* A **string** is a marker id; a **pair** is `[lat, lon]`, which is how a
|
|
177
|
+
* coordinate is written everywhere outside a program; an **object** with `lat`
|
|
178
|
+
* and `lon` is the long form. Refusing any of them would make the field's most
|
|
179
|
+
* obvious content its most surprising failure.
|
|
180
|
+
*/
|
|
181
|
+
function endOf(value) {
|
|
182
|
+
if (typeof value === "string") {
|
|
183
|
+
return value.trim() === "" ? null : markerEnd(value);
|
|
184
|
+
}
|
|
185
|
+
if (Array.isArray(value)) {
|
|
186
|
+
const lat = finite(value[0]);
|
|
187
|
+
const lon = finite(value[1]);
|
|
188
|
+
return lat === null || lon === null
|
|
189
|
+
? null
|
|
190
|
+
: placeEnd(clamp(lat, -90, 90), wrapLongitude(lon));
|
|
191
|
+
}
|
|
192
|
+
if (typeof value !== "object" || value === null)
|
|
193
|
+
return null;
|
|
194
|
+
const row = value;
|
|
195
|
+
if (typeof row.markerId === "string")
|
|
196
|
+
return markerEnd(row.markerId);
|
|
197
|
+
const lat = finite(row.lat ?? row.latitude);
|
|
198
|
+
const lon = finite(row.lon ?? row.lng ?? row.longitude);
|
|
199
|
+
return lat === null || lon === null
|
|
200
|
+
? null
|
|
201
|
+
: placeEnd(clamp(lat, -90, 90), wrapLongitude(lon));
|
|
202
|
+
}
|
|
203
|
+
function rowsOf(value) {
|
|
204
|
+
if (typeof value !== "string" || value.trim() === "")
|
|
205
|
+
return [];
|
|
206
|
+
try {
|
|
207
|
+
const parsed = JSON.parse(value);
|
|
208
|
+
if (!Array.isArray(parsed))
|
|
209
|
+
return [];
|
|
210
|
+
return parsed.filter((row) => typeof row === "object" && row !== null);
|
|
211
|
+
}
|
|
212
|
+
catch {
|
|
213
|
+
return [];
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* A row's identity, or one derived from where it sits.
|
|
218
|
+
*
|
|
219
|
+
* Positional rather than random, and the difference is the whole point: a random
|
|
220
|
+
* id here would be a different one on every read, and both the tile's React key
|
|
221
|
+
* and an arc's pin to a marker would change under the author's hands.
|
|
222
|
+
*/
|
|
223
|
+
function idOf(value, positional) {
|
|
224
|
+
return text(value) ?? positional;
|
|
225
|
+
}
|
|
226
|
+
function text(value) {
|
|
227
|
+
return typeof value === "string" && value.trim() !== "" ? value : null;
|
|
228
|
+
}
|
|
229
|
+
function finite(value) {
|
|
230
|
+
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
231
|
+
}
|
|
232
|
+
/** A stored 0–1 value; anything unreadable is fully on. */
|
|
233
|
+
function unit(value) {
|
|
234
|
+
const n = finite(value);
|
|
235
|
+
return n === null ? 1 : clamp(n, 0, 1);
|
|
236
|
+
}
|
|
237
|
+
/** A stored size, which must be above zero to draw at all. */
|
|
238
|
+
function positive(value, fallback) {
|
|
239
|
+
const n = finite(value);
|
|
240
|
+
return n === null || n <= 0 ? fallback : n;
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* A longitude into −180…180.
|
|
244
|
+
*
|
|
245
|
+
* Wrapped rather than clamped, unlike latitude: 190°E is a real place (170°W)
|
|
246
|
+
* and clamping would put it on the antimeridian, where there is nothing north of
|
|
247
|
+
* the north pole for a latitude to mean.
|
|
248
|
+
*
|
|
249
|
+
* A value already in range is returned untouched — the modulo round-trip is not
|
|
250
|
+
* exact in binary floating point (139.7 comes back as 139.70000000000005), and a
|
|
251
|
+
* stored longitude that differs from the one the author typed shows up later as
|
|
252
|
+
* a diff nobody made.
|
|
253
|
+
*/
|
|
254
|
+
function wrapLongitude(value) {
|
|
255
|
+
if (value >= -180 && value <= 180)
|
|
256
|
+
return value;
|
|
257
|
+
return ((((value + 180) % 360) + 360) % 360) - 180;
|
|
258
|
+
}
|
|
259
|
+
function clamp(value, min, max) {
|
|
260
|
+
return value < min ? min : value > max ? max : value;
|
|
261
|
+
}
|
|
262
|
+
//# sourceMappingURL=globe-places.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"globe-places.js","sourceRoot":"","sources":["../../src/globe/globe-places.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * What an author places on a Globe — the marked points, and the arcs between\n * them — as the panel edits them and the stored field holds them.\n *\n * Beside `graph-equations.ts` and shaped like it, because it is the same\n * problem: an appearance value is `number | string | boolean`, so a *list* has\n * to arrive as one string that a mapper reads. What lives here is the authored\n * shape and its serialization, shared by the inspector's tiles and the node's\n * builder; what a frame actually draws is `nodes/globe/impl/places.ts`, which\n * resolves this into coordinates and clamps it to what the render can use.\n *\n * The split matters in one direction: **reading must be faithful and must not\n * mint identity**. The panel reads on every render and the builder on every\n * rebuild, so a random id here would be a different id every time — and two\n * things key off it (a tile's React key, and which arc endpoint points at which\n * marker). {@link createMarker} mints ids; the readers derive a positional one\n * and never invent.\n */\n\n/**\n * A marked point on the surface.\n *\n * `label` is **not drawn**. It names the tile in the inspector and the entries\n * in an arc's endpoint menus, which is the whole of its job today — a label\n * rendered against the globe is a separate problem (it has to face the camera,\n * hide when it rotates behind the planet, and not collide with its neighbours),\n * and storing the text now is what lets that arrive without a migration.\n */\nexport interface GlobeMarker {\n /** Identity across list edits — a tween matches like with like. */\n id: string\n /** A name for this place. Editor-facing only; see the note above. */\n label: string\n /** Degrees north, −90…90. */\n lat: number\n /** Degrees east, −180…180. */\n lon: number\n /** Any colour string the fill parser takes. Empty means the palette entry. */\n color: string\n /** Radius as a fraction of the globe's own. */\n size: number\n /** 0–1. A fade, unlike {@link enabled}, which is a switch. */\n opacity: number\n /** Whether it draws. Off keeps the tile in place, editable, with its colour. */\n enabled: boolean\n}\n\n/**\n * One end of an arc: a marker it is pinned to, or a place of its own.\n *\n * The pinned form is the one the tile offers first, and it is not merely\n * convenient — an arc between two *marked* places moves when the place does,\n * where a copied pair of coordinates silently stops matching the dot it was\n * drawn to. That is the same reasoning a state machine's connection names its\n * ends by state id rather than by position.\n *\n * The free form stays because not every end wants a dot on it, and because a\n * list written by hand or by an agent reaches for a coordinate pair first.\n */\nexport type ArcEnd =\n | { readonly kind: \"marker\"; readonly markerId: string }\n | { readonly kind: \"place\"; readonly lat: number; readonly lon: number }\n\n/** A great-circle path between two ends. */\nexport interface GlobeArc {\n id: string\n from: ArcEnd\n to: ArcEnd\n color: string\n /** Tube radius as a fraction of the globe's own. */\n width: number\n /** How far the middle lifts off the surface, as a fraction of the radius. */\n lift: number\n /**\n * How much of the path is drawn, 0–1 — a line that draws itself on.\n *\n * A fraction of the *path* rather than a time, so it means the same thing\n * whatever the arc's length and is the author's to tween from wherever they\n * like. Zero draws nothing and is not an error.\n */\n progress: number\n enabled: boolean\n}\n\n/**\n * The palette an uncoloured marker takes its colour from, by position.\n *\n * Warm-to-cool rather than a spectrum: markers are read against a dark ocean and\n * usually mean something ranked — the first is the subject and the rest are\n * context — so the order runs from the one that carries furthest to the one that\n * recedes. Six, then it wraps; a seventh place that has to stand out sets its\n * own colour.\n */\nexport const DEFAULT_MARKER_COLORS = [\n \"#ff3b30\",\n \"#ff9f0a\",\n \"#ffd60a\",\n \"#30d158\",\n \"#5ac8fa\",\n \"#bf5af2\",\n] as const\n\n/** The colour a marker at `index` is drawn in when it names none. */\nexport function markerColorAt(index: number): string {\n const palette = DEFAULT_MARKER_COLORS\n return palette[((index % palette.length) + palette.length) % palette.length]!\n}\n\n/** The colour an arc falls back to. */\nexport const DEFAULT_ARC_COLOR = \"#ffd60a\"\n\nconst DEFAULT_MARKER_SIZE = 0.02\nconst DEFAULT_ARC_WIDTH = 0.004\nconst DEFAULT_ARC_LIFT = 0.25\n\n/**\n * A fresh id for a tile.\n *\n * A counter plus a short random suffix rather than `crypto.randomUUID`, exactly\n * as `graph-equations.ts` explains: this package loads in a bare Node process\n * with no DOM and no assumed globals, and an id only has to be unique within one\n * node's list. The suffix is what stops two clients editing the same scene\n * colliding on `mk-3`.\n *\n * Never called during a build — only when an author adds a tile.\n */\nlet placeSeq = 0\nfunction nextId(prefix: string): string {\n placeSeq += 1\n return `${prefix}-${placeSeq}-${Math.random().toString(36).slice(2, 8)}`\n}\n\n/** A new marker tile: showing, opaque, and at the given place. */\nexport function createMarker(\n at: { lat: number; lon: number } = { lat: 0, lon: 0 }\n): GlobeMarker {\n return {\n id: nextId(\"mk\"),\n label: \"\",\n lat: at.lat,\n lon: at.lon,\n color: \"\",\n size: DEFAULT_MARKER_SIZE,\n opacity: 1,\n enabled: true,\n }\n}\n\n/** A new arc tile, between two ends. */\nexport function createArc(from: ArcEnd, to: ArcEnd): GlobeArc {\n return {\n id: nextId(\"arc\"),\n from,\n to,\n color: DEFAULT_ARC_COLOR,\n width: DEFAULT_ARC_WIDTH,\n lift: DEFAULT_ARC_LIFT,\n progress: 1,\n enabled: true,\n }\n}\n\n/** An end pinned to a marker. */\nexport function markerEnd(markerId: string): ArcEnd {\n return { kind: \"marker\", markerId }\n}\n\n/** An end at a place of its own. */\nexport function placeEnd(lat: number, lon: number): ArcEnd {\n return { kind: \"place\", lat, lon }\n}\n\n// --- Reading ---------------------------------------------------------------\n\n/**\n * Reads a stored marker list, defensively.\n *\n * Never throws, and drops only what it genuinely cannot place: the field is\n * edited a keystroke at a time by hand as well as through the tiles, so it is\n * invalid far more often than it is valid, and a reader that threw would blank\n * the canvas on the way from `[` to `[{`.\n *\n * A row with **no position at all** is the one thing that is dropped rather than\n * defaulted. Every other field has an honest default; a latitude does not, and\n * putting an unplaced marker on the equator would draw a dot somewhere nobody\n * asked for and call it the author's.\n */\nexport function markersOf(value: unknown): GlobeMarker[] {\n return rowsOf(value).flatMap((row, index) => {\n const lat = finite(row.lat ?? row.latitude)\n const lon = finite(row.lon ?? row.lng ?? row.longitude)\n if (lat === null || lon === null) return []\n return [\n {\n id: idOf(row.id, `mk:${index}`),\n label: text(row.label ?? row.name) ?? \"\",\n lat: clamp(lat, -90, 90),\n lon: wrapLongitude(lon),\n color: text(row.color) ?? \"\",\n size: positive(row.size, DEFAULT_MARKER_SIZE),\n opacity: unit(row.opacity),\n // Absent means on, as everywhere else a switch is stored: only an\n // explicit `false` turns a tile off.\n enabled: row.enabled !== false,\n },\n ]\n })\n}\n\n/** Reads a stored arc list, on the same terms as {@link markersOf}. */\nexport function arcsOf(value: unknown): GlobeArc[] {\n return rowsOf(value).flatMap((row, index) => {\n const from = endOf(row.from)\n const to = endOf(row.to)\n if (!from || !to) return []\n return [\n {\n id: idOf(row.id, `arc:${index}`),\n from,\n to,\n color: text(row.color) ?? DEFAULT_ARC_COLOR,\n width: positive(row.width, DEFAULT_ARC_WIDTH),\n lift: clamp(finite(row.lift) ?? DEFAULT_ARC_LIFT, 0, 4),\n progress: unit(row.progress),\n enabled: row.enabled !== false,\n },\n ]\n })\n}\n\n/** Serializes a marker list into the stored string form. */\nexport function markersToValue(markers: readonly GlobeMarker[]): string {\n return JSON.stringify(markers)\n}\n\n/**\n * Serializes an arc list, writing each end back in the shape it was authored in.\n *\n * A pinned end is a bare **string** and a free one a `[lat, lon]` **pair**,\n * rather than the tagged union this module works in. Two reasons, and the second\n * is the load-bearing one: those are the two shapes somebody writing this list\n * by hand reaches for, and a stored document is read by whatever version opens\n * it later — so the wire form is public API and a discriminant that only exists\n * to make the TypeScript convenient does not belong in it.\n */\nexport function arcsToValue(arcs: readonly GlobeArc[]): string {\n return JSON.stringify(\n arcs.map((arc) => ({ ...arc, from: endToValue(arc.from), to: endToValue(arc.to) }))\n )\n}\n\nfunction endToValue(end: ArcEnd): string | [number, number] {\n return end.kind === \"marker\" ? end.markerId : [end.lat, end.lon]\n}\n\n/**\n * One end, from any of the three shapes a stored list holds it in.\n *\n * A **string** is a marker id; a **pair** is `[lat, lon]`, which is how a\n * coordinate is written everywhere outside a program; an **object** with `lat`\n * and `lon` is the long form. Refusing any of them would make the field's most\n * obvious content its most surprising failure.\n */\nfunction endOf(value: unknown): ArcEnd | null {\n if (typeof value === \"string\") {\n return value.trim() === \"\" ? null : markerEnd(value)\n }\n if (Array.isArray(value)) {\n const lat = finite(value[0])\n const lon = finite(value[1])\n return lat === null || lon === null\n ? null\n : placeEnd(clamp(lat, -90, 90), wrapLongitude(lon))\n }\n if (typeof value !== \"object\" || value === null) return null\n const row = value as Record<string, unknown>\n if (typeof row.markerId === \"string\") return markerEnd(row.markerId)\n const lat = finite(row.lat ?? row.latitude)\n const lon = finite(row.lon ?? row.lng ?? row.longitude)\n return lat === null || lon === null\n ? null\n : placeEnd(clamp(lat, -90, 90), wrapLongitude(lon))\n}\n\n// --- Reading helpers -------------------------------------------------------\n\ntype Row = Record<string, unknown>\n\nfunction rowsOf(value: unknown): Row[] {\n if (typeof value !== \"string\" || value.trim() === \"\") return []\n try {\n const parsed: unknown = JSON.parse(value)\n if (!Array.isArray(parsed)) return []\n return parsed.filter(\n (row): row is Row => typeof row === \"object\" && row !== null\n )\n } catch {\n return []\n }\n}\n\n/**\n * A row's identity, or one derived from where it sits.\n *\n * Positional rather than random, and the difference is the whole point: a random\n * id here would be a different one on every read, and both the tile's React key\n * and an arc's pin to a marker would change under the author's hands.\n */\nfunction idOf(value: unknown, positional: string): string {\n return text(value) ?? positional\n}\n\nfunction text(value: unknown): string | null {\n return typeof value === \"string\" && value.trim() !== \"\" ? value : null\n}\n\nfunction finite(value: unknown): number | null {\n return typeof value === \"number\" && Number.isFinite(value) ? value : null\n}\n\n/** A stored 0–1 value; anything unreadable is fully on. */\nfunction unit(value: unknown): number {\n const n = finite(value)\n return n === null ? 1 : clamp(n, 0, 1)\n}\n\n/** A stored size, which must be above zero to draw at all. */\nfunction positive(value: unknown, fallback: number): number {\n const n = finite(value)\n return n === null || n <= 0 ? fallback : n\n}\n\n/**\n * A longitude into −180…180.\n *\n * Wrapped rather than clamped, unlike latitude: 190°E is a real place (170°W)\n * and clamping would put it on the antimeridian, where there is nothing north of\n * the north pole for a latitude to mean.\n *\n * A value already in range is returned untouched — the modulo round-trip is not\n * exact in binary floating point (139.7 comes back as 139.70000000000005), and a\n * stored longitude that differs from the one the author typed shows up later as\n * a diff nobody made.\n */\nfunction wrapLongitude(value: number): number {\n if (value >= -180 && value <= 180) return value\n return ((((value + 180) % 360) + 360) % 360) - 180\n}\n\nfunction clamp(value: number, min: number, max: number): number {\n return value < min ? min : value > max ? max : value\n}\n"]}
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { type Command, type CommandArgs, Canvas3D, Scene3D, type Canvas3DProps, type Color, type NodeConfig } from "@motionscript/sdk";
|
|
2
|
+
import { type OrbitTarget } from "@motionscript/sdk/component";
|
|
3
|
+
export interface GlobeProps extends Canvas3DProps {
|
|
4
|
+
resolution: number;
|
|
5
|
+
ocean: Color;
|
|
6
|
+
land: Color;
|
|
7
|
+
border: Color;
|
|
8
|
+
borderWidth: number;
|
|
9
|
+
graticule: boolean;
|
|
10
|
+
graticuleColor: Color;
|
|
11
|
+
graticuleStep: number;
|
|
12
|
+
graticuleWidth: number;
|
|
13
|
+
orbit: number;
|
|
14
|
+
elevation: number;
|
|
15
|
+
zoom: number;
|
|
16
|
+
fov: number;
|
|
17
|
+
ambientIntensity: number;
|
|
18
|
+
ambientColor: Color;
|
|
19
|
+
keyIntensity: number;
|
|
20
|
+
keyColor: Color;
|
|
21
|
+
atmosphere: boolean;
|
|
22
|
+
atmosphereColor: Color;
|
|
23
|
+
atmosphereSize: number;
|
|
24
|
+
atmosphereFalloff: number;
|
|
25
|
+
atmosphereIntensity: number;
|
|
26
|
+
markers: string;
|
|
27
|
+
arcs: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* A globe: country boundaries on a lit sphere, flown by an orbit camera.
|
|
31
|
+
*
|
|
32
|
+
* <Globe width="fill" height="fill" orbit={20} elevation={25} zoom={2.6} />
|
|
33
|
+
*
|
|
34
|
+
* Like the Protein and unlike the Canvas 3D viewport, it draws **one subject**
|
|
35
|
+
* derived from its own props rather than being a room the author fills. Four
|
|
36
|
+
* things about it are worth knowing before reading the parts:
|
|
37
|
+
*
|
|
38
|
+
* **The map is a texture, drawn in 2D.** See `world-map.ts`: a WebGL line
|
|
39
|
+
* ignores any width above one pixel, so borders drawn as 3D lines are hairlines
|
|
40
|
+
* forever. Baked, a border is an ordinary Skia stroke at any weight.
|
|
41
|
+
*
|
|
42
|
+
* **That texture is cached against its style, and the cache is not an
|
|
43
|
+
* optimisation.** motion-script re-rasterizes a surface every frame unless the
|
|
44
|
+
* descriptor says otherwise, and re-rasterizing this one means redrawing ten
|
|
45
|
+
* thousand paths, stalling on a GPU read-back and re-uploading a few megabytes —
|
|
46
|
+
* sixty times a second, for an identical image. {@link bakedMap} holds one
|
|
47
|
+
* descriptor per style and marks it `static`; the schema then refuses to animate
|
|
48
|
+
* any field that style is made of, so an export cannot mint a raster per frame.
|
|
49
|
+
*
|
|
50
|
+
* **The camera is three tweenable numbers, and two of them are places.** `orbit`
|
|
51
|
+
* is a longitude and `elevation` is a latitude — see `projection.ts`, which is
|
|
52
|
+
* where that convention is established and defended. There is no `OrbitControls`
|
|
53
|
+
* here for the reason the other 3D nodes have none: a rendered timeline has no
|
|
54
|
+
* pointer, and every frame has to be reproducible under scrubbing and export.
|
|
55
|
+
*
|
|
56
|
+
* **Markers and arcs are real 3D, never baked.** They are the animated content;
|
|
57
|
+
* putting them in the texture would run every frame of a marker's fade through a
|
|
58
|
+
* full re-rasterize.
|
|
59
|
+
*/
|
|
60
|
+
export declare class Globe extends Canvas3D<GlobeProps> {
|
|
61
|
+
/**
|
|
62
|
+
* Texture width in pixels; the height is half of it.
|
|
63
|
+
*
|
|
64
|
+
* Structural, and capped in the schema rather than here. The buffer is
|
|
65
|
+
* re-uploaded to the GPU every frame even when its pixels are cached, so this
|
|
66
|
+
* is a per-frame bandwidth number as much as a sharpness one — 2048 is 8 MB a
|
|
67
|
+
* frame and already finer than the 110m boundaries it draws.
|
|
68
|
+
*/
|
|
69
|
+
resolution: number;
|
|
70
|
+
ocean: Color;
|
|
71
|
+
land: Color;
|
|
72
|
+
/**
|
|
73
|
+
* The colour of every coast and border.
|
|
74
|
+
*
|
|
75
|
+
* Alpha works. It did not while the country paths carried the stroke — a
|
|
76
|
+
* border belongs to two countries, so it was drawn twice and came out at
|
|
77
|
+
* double density beside the coastlines. `borders.ts` deduplicates the lines
|
|
78
|
+
* and `world-map.ts` strokes them once.
|
|
79
|
+
*/
|
|
80
|
+
border: Color;
|
|
81
|
+
borderWidth: number;
|
|
82
|
+
graticule: boolean;
|
|
83
|
+
graticuleColor: Color;
|
|
84
|
+
graticuleStep: number;
|
|
85
|
+
graticuleWidth: number;
|
|
86
|
+
/**
|
|
87
|
+
* The camera's heading, in degrees, in exactly the sense every other 3D node
|
|
88
|
+
* uses it — which is what keeps the canvas drag consistent with them.
|
|
89
|
+
*
|
|
90
|
+
* It is *not* a longitude: a camera at heading θ is centred over longitude −θ
|
|
91
|
+
* (see `orbitForLongitude` in `projection.ts`). Unbounded, like every other
|
|
92
|
+
* viewport's, because the drag wraps it into `[0, 360)` and a range here would
|
|
93
|
+
* clamp half of them.
|
|
94
|
+
*/
|
|
95
|
+
orbit: number;
|
|
96
|
+
/**
|
|
97
|
+
* Degrees above the equator, which on a globe *is* the latitude the camera
|
|
98
|
+
* stands over — no conversion, unlike the heading. Held short of the poles by
|
|
99
|
+
* the schema, as every orbit camera's is.
|
|
100
|
+
*/
|
|
101
|
+
elevation: number;
|
|
102
|
+
/** Distance from the centre, as a multiple of the globe's radius. */
|
|
103
|
+
zoom: number;
|
|
104
|
+
fov: number;
|
|
105
|
+
ambientIntensity: number;
|
|
106
|
+
ambientColor: Color;
|
|
107
|
+
keyIntensity: number;
|
|
108
|
+
keyColor: Color;
|
|
109
|
+
atmosphere: boolean;
|
|
110
|
+
atmosphereColor: Color;
|
|
111
|
+
/** The shell's radius as a multiple of the globe's. */
|
|
112
|
+
atmosphereSize: number;
|
|
113
|
+
/** How tightly the glow hugs the edge. Higher is a thinner rim. */
|
|
114
|
+
atmosphereFalloff: number;
|
|
115
|
+
atmosphereIntensity: number;
|
|
116
|
+
markers: string;
|
|
117
|
+
arcs: string;
|
|
118
|
+
constructor(props?: NodeConfig<Globe, GlobeProps>);
|
|
119
|
+
/**
|
|
120
|
+
* Frame the scene at a spherical camera placement. Every axis is optional,
|
|
121
|
+
* so "pull back" and "spin round" stay separate intentions — see
|
|
122
|
+
* {@link OrbitTarget}.
|
|
123
|
+
*/
|
|
124
|
+
orbitTo(args: CommandArgs<{
|
|
125
|
+
target: OrbitTarget;
|
|
126
|
+
}> & {
|
|
127
|
+
duration: number;
|
|
128
|
+
}): Command<GlobeProps>;
|
|
129
|
+
/**
|
|
130
|
+
* Fly the camera to a place on the globe. `latitude`/`longitude` are the
|
|
131
|
+
* point to bring under the camera and `framing` the distance to settle at.
|
|
132
|
+
*
|
|
133
|
+
* **`arc` is what makes it a flight rather than a pan** — above `0` the
|
|
134
|
+
* distance bows outward at the midpoint by that fraction, so a long journey
|
|
135
|
+
* rises off the surface and settles back down rather than scraping the
|
|
136
|
+
* horizon the whole way. Longitude takes the **short way round**.
|
|
137
|
+
*/
|
|
138
|
+
flyTo(args: CommandArgs<{
|
|
139
|
+
latitude: number;
|
|
140
|
+
longitude: number;
|
|
141
|
+
framing?: number;
|
|
142
|
+
arc?: number;
|
|
143
|
+
}> & {
|
|
144
|
+
duration?: number;
|
|
145
|
+
}): Command<GlobeProps>;
|
|
146
|
+
protected buildScene3D(): Scene3D;
|
|
147
|
+
/** The sphere, wearing the baked map. */
|
|
148
|
+
private addPlanet;
|
|
149
|
+
/** The halo. A shell, kept for its back faces — see `atmosphere.ts`. */
|
|
150
|
+
private addAtmosphere;
|
|
151
|
+
/**
|
|
152
|
+
* The markers, as one instanced draw.
|
|
153
|
+
*
|
|
154
|
+
* Instanced rather than a mesh apiece because a marker list is the one thing
|
|
155
|
+
* here with no ceiling — a network map is thousands of points, and a draw call
|
|
156
|
+
* each would not keep up. One geometry, one material, one upload.
|
|
157
|
+
*
|
|
158
|
+
* Note the material carries **no** `vertexColors`: an instanced mesh that asks
|
|
159
|
+
* for it makes the shader read a per-vertex `color` attribute the geometry does
|
|
160
|
+
* not have, gets zeroes, and every marker renders black. The per-instance
|
|
161
|
+
* colours ride the `colors` option instead, which is a different channel.
|
|
162
|
+
*/
|
|
163
|
+
private addMarkers;
|
|
164
|
+
/** The arcs, one swept tube each. */
|
|
165
|
+
private addArcs;
|
|
166
|
+
/**
|
|
167
|
+
* The baked map, and the descriptor that lets it be baked once.
|
|
168
|
+
*
|
|
169
|
+
* Two caches are being kept in step here, and the key is what keeps them in
|
|
170
|
+
* step. This one holds the `Graphics2D` and its descriptor so the node hands
|
|
171
|
+
* the renderer the *same object* every frame — surface identity is object
|
|
172
|
+
* identity, so a fresh one each frame would defeat the texture cache and
|
|
173
|
+
* orphan a GPU texture per frame. The renderer's own `staticRasters` holds the
|
|
174
|
+
* rasterized pixels against the `identity` string below.
|
|
175
|
+
*
|
|
176
|
+
* They share one key, which is the point: edit a colour and this cache misses
|
|
177
|
+
* (a new `Graphics2D`) *and* that one misses (a new identity string). Derive
|
|
178
|
+
* the identity from anything else — a counter, the node id — and a colour
|
|
179
|
+
* change would serve the old pixels forever, because nothing invalidates
|
|
180
|
+
* `staticRasters` short of tearing down the render context.
|
|
181
|
+
*
|
|
182
|
+
* The descriptor is written out rather than built with `Tex.surface` because
|
|
183
|
+
* the builder's options do not include `static` or `identity`. Handing a bare
|
|
184
|
+
* `Graphics2D` to `fill` instead takes `resolveFill3D`'s surface path, which
|
|
185
|
+
* sets neither — and that is the per-frame read-back this whole arrangement
|
|
186
|
+
* exists to avoid.
|
|
187
|
+
*/
|
|
188
|
+
private cache;
|
|
189
|
+
private bakedMap;
|
|
190
|
+
/** The style props as the one value the baker takes. Also the cache key. */
|
|
191
|
+
private mapStyle;
|
|
192
|
+
}
|
|
193
|
+
//# sourceMappingURL=globe.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"globe.d.ts","sourceRoot":"","sources":["../../src/globe/globe.ts"],"names":[],"mappings":"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"}
|