@morphemeris/armilla-core 0.1.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.
Files changed (54) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +75 -0
  3. package/dist/armilla.d.ts +41 -0
  4. package/dist/armilla.js +98 -0
  5. package/dist/armilla.test.d.ts +1 -0
  6. package/dist/armilla.test.js +160 -0
  7. package/dist/basemap.generated.d.ts +8 -0
  8. package/dist/basemap.generated.js +9 -0
  9. package/dist/basemap.test.d.ts +1 -0
  10. package/dist/basemap.test.js +21 -0
  11. package/dist/index.d.ts +11 -0
  12. package/dist/index.js +11 -0
  13. package/dist/index.test.d.ts +1 -0
  14. package/dist/index.test.js +14 -0
  15. package/dist/index.web.d.ts +3 -0
  16. package/dist/index.web.js +24 -0
  17. package/dist/runtime.d.ts +13 -0
  18. package/dist/runtime.js +20 -0
  19. package/dist/surface.d.ts +10 -0
  20. package/dist/surface.js +9 -0
  21. package/dist/types.d.ts +55 -0
  22. package/dist/types.generated.d.ts +1274 -0
  23. package/dist/types.generated.js +4 -0
  24. package/dist/types.js +24 -0
  25. package/dist/vocabulary.generated.d.ts +8 -0
  26. package/dist/vocabulary.generated.js +9 -0
  27. package/dist/vocabulary.test.d.ts +1 -0
  28. package/dist/vocabulary.test.js +36 -0
  29. package/dist/wasm-types.d.ts +19 -0
  30. package/dist/wasm-types.js +1 -0
  31. package/dist/wasm.d.ts +2 -0
  32. package/dist/wasm.js +16 -0
  33. package/dist/web.test.d.ts +1 -0
  34. package/dist/web.test.js +34 -0
  35. package/dist/workspace.test.d.ts +1 -0
  36. package/dist/workspace.test.js +43 -0
  37. package/docs/changelog.md +37 -0
  38. package/docs/coordinates.md +52 -0
  39. package/docs/themes.md +111 -0
  40. package/docs/vocabulary.json +1501 -0
  41. package/docs/vocabulary.md +86 -0
  42. package/package.json +73 -0
  43. package/wasm/README.md +21 -0
  44. package/wasm/armilla_wasm.d.ts +104 -0
  45. package/wasm/armilla_wasm.js +497 -0
  46. package/wasm/armilla_wasm_bg.wasm +0 -0
  47. package/wasm/armilla_wasm_bg.wasm.d.ts +21 -0
  48. package/wasm/package.json +23 -0
  49. package/wasm-web/README.md +21 -0
  50. package/wasm-web/armilla_wasm.d.ts +150 -0
  51. package/wasm-web/armilla_wasm.js +583 -0
  52. package/wasm-web/armilla_wasm_bg.wasm +0 -0
  53. package/wasm-web/armilla_wasm_bg.wasm.d.ts +21 -0
  54. package/wasm-web/package.json +27 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Morgan C. Benton
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,75 @@
1
+ # @morphemeris/armilla-core
2
+
3
+ The armilla layout core as a TypeScript package: astrological chart data + a theme + a view
4
+ state produce a **tagged scene description** — pure, deterministic, no DOM — and a painter
5
+ renders the scene to an SVG string. The layout engine is Rust compiled to WASM; this package
6
+ is the typed binding, dual-target for Node and the browser from one API.
7
+
8
+ Chart wheels (single through quadwheel), 90/45/30/72° dials, modulus strips, declination
9
+ graphs, aspect grids and tallies, transit time maps, midpoint trees and sorts, dispositor
10
+ graphs, astro calendars, graphic ephemerides, cycle and aspect-orb curves, time-lord
11
+ timelines, astrocartography maps, and data-table row models — all from one document contract.
12
+
13
+ ## Install
14
+
15
+ ```sh
16
+ npm install @morphemeris/armilla-core
17
+ ```
18
+
19
+ Node uses the package synchronously. In the browser (or any bundler build), initialize the
20
+ WASM once first:
21
+
22
+ ```ts
23
+ import { init, layout, paintSvg, defaultTheme } from '@morphemeris/armilla-core';
24
+
25
+ await init(); // no-op on Node; loads the WASM in the browser
26
+
27
+ const scene = layout(chartInput, [], view, environment, { kind: 'wheel' });
28
+ const svg = paintSvg(scene, []);
29
+ ```
30
+
31
+ `init()` defaults to the package's own `.wasm` asset (bundlers rewrite the URL); pass a
32
+ custom source for CDN hosting.
33
+
34
+ ## The model
35
+
36
+ Everything is a validated JSON document with a `schema_version`:
37
+
38
+ - **Chart input** — positions, houses, aspects, and richer upstream-computed records
39
+ (events, periods, almanac, samples, ACG lines). The
40
+ [Morphemeris API](https://morphemeris.com) returns this shape directly: wrap a response as
41
+ `{ schema_version: 1, charts: { natal: data } }` and lay it out.
42
+ - **Theme** — colors, weights, band geometry, glyph pack, styling rules. Themes chain
43
+ (`extends`), and `defaultTheme()` is always the root.
44
+ - **View state** — what to show: treatment rules (`hide`/`show`/`dim`/`emphasize`) as
45
+ **predicates over semantic tags** (every mark carries tags like `body=mars`,
46
+ `aspect_class=hard`, `scope=inter`), plus frame, bands, modulus, window, cursor.
47
+ - **Environment** — medium, scheme, contrast, density, motion.
48
+
49
+ The scene's marks keep their identity, tags, and resolved styles, so hosts can hit-test,
50
+ attribute (`explain`), and re-render without re-deriving anything.
51
+
52
+ ## Surface
53
+
54
+ | Function | Does |
55
+ | ------------------------------------------------------------- | ------------------------------------------------------------------------------------ |
56
+ | `layout(input, themes, view, env, options)` | The pipeline: documents → tagged scene |
57
+ | `paintSvg(scene, packs)` | Scene → SVG string (marks carry `id` + `data-*` tags) |
58
+ | `defaultTheme()` / `lint(theme)` | The root theme; theme findings |
59
+ | `explain(scene, themes, markId, property)` | Which rule set a mark's property |
60
+ | `bookmark(view)` / `unbookmark(str)` | View state ⇄ compact shareable string |
61
+ | `tableRows(input, view, env, options)` | Positions/cusps/aspects as a host-rendered row model |
62
+ | `mapLines(input, view, env)` | Astrocartography lines for tiled-map hosts (see `@morphemeris/armilla-map-maplibre`) |
63
+ | `migrate(kind, doc)` / `validateWorkspace(doc)` / `version()` | Document upkeep |
64
+ | `vocabulary` / `naturalEarth110m` | The predicate vocabulary as data; the shipped basemap |
65
+
66
+ ## Docs
67
+
68
+ Shipped in `docs/`: the tag [vocabulary reference](./docs/vocabulary.md), the
69
+ [theme guide](./docs/themes.md), the [coordinate mapping](./docs/coordinates.md), and the
70
+ [schema changelog](./docs/changelog.md).
71
+
72
+ ## License
73
+
74
+ MIT. The package ships the compiled WASM and typed wrappers; the source repository is
75
+ private.
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Typed wrappers over the WASM exports (spec §13.5). Every wrapper
3
+ * stringifies its arguments, forwards, and parses the result; failures
4
+ * arrive as the §15 error record and are rethrown as {@link ArmillaError}.
5
+ * No logic lives here.
6
+ */
7
+ import type { ChartInputDoc, EnvironmentDoc, ErrorRecord, Explanation, Finding, LayoutOptionsDoc, MapLinesModel, PackManifestDoc, Scene, TableModel, TableOptions, ThemeDoc, ViewStateDoc, Workspace, WorkspaceDoc } from './types.js';
8
+ /** A core failure: the spec §15 error record as a JavaScript error. */
9
+ export declare class ArmillaError extends Error {
10
+ /** Error category (`SHAPE`, `VERSION`, `LIMIT`, ...). */
11
+ readonly code: string;
12
+ /** JSON pointer into the offending document. */
13
+ readonly path: string;
14
+ /** Which document the path points into. */
15
+ readonly document: string;
16
+ constructor(record: ErrorRecord);
17
+ }
18
+ /** Lay out a chart (spec §13.5 `layout`); throws {@link ArmillaError}. */
19
+ export declare function layout(chartInput: ChartInputDoc, themeChain: readonly ThemeDoc[], viewState: ViewStateDoc, environment: EnvironmentDoc, options: LayoutOptionsDoc): Scene;
20
+ /** Lint a theme chain (spec §10.7); throws {@link ArmillaError}. */
21
+ export declare function lint(themeChain: readonly ThemeDoc[]): readonly Finding[];
22
+ /** Migrate a document forward (spec §4.2); throws {@link ArmillaError}. */
23
+ export declare function migrate(kind: 'theme' | 'view_state' | 'workspace', doc: unknown): unknown;
24
+ /** Encode a view state as a URL-safe string (spec §11.5). */
25
+ export declare function bookmark(viewState: ViewStateDoc): string;
26
+ /** Decode a bookmark back into a view state (spec §11.5). */
27
+ export declare function unbookmark(s: string): ViewStateDoc;
28
+ /** Report which rule set a property (spec §13.4). */
29
+ export declare function explain(scene: Scene, themeChain: readonly ThemeDoc[], markId: string, property: string): Explanation;
30
+ /** Validate a workspace, returning it normalized (spec §12). */
31
+ export declare function validateWorkspace(workspace: WorkspaceDoc): Workspace;
32
+ /** The compiled-in default theme (spec §10.2). */
33
+ export declare function defaultTheme(): ThemeDoc;
34
+ /** Build a table panel's row model (spec §12.1). */
35
+ export declare function tableRows(chartInput: ChartInputDoc, viewState: ViewStateDoc, environment: EnvironmentDoc, options: TableOptions): TableModel;
36
+ /** Build the map panels' line model (spec §12.2). */
37
+ export declare function mapLines(chartInput: ChartInputDoc, viewState: ViewStateDoc, environment: EnvironmentDoc): MapLinesModel;
38
+ /** Paint a scene as an SVG document string (spec §14). */
39
+ export declare function paintSvg(scene: Scene, packManifests: readonly PackManifestDoc[]): string;
40
+ /** The core version, for provenance and binding checks. */
41
+ export declare function version(): string;
@@ -0,0 +1,98 @@
1
+ import { wasm } from './runtime.js';
2
+ /** A core failure: the spec §15 error record as a JavaScript error. */
3
+ export class ArmillaError extends Error {
4
+ /** Error category (`SHAPE`, `VERSION`, `LIMIT`, ...). */
5
+ code;
6
+ /** JSON pointer into the offending document. */
7
+ path;
8
+ /** Which document the path points into. */
9
+ document;
10
+ constructor(record) {
11
+ super(record.message);
12
+ this.name = 'ArmillaError';
13
+ this.code = record.code;
14
+ this.path = record.path;
15
+ this.document = record.document;
16
+ }
17
+ }
18
+ /** Rethrow a thrown WASM value as a typed {@link ArmillaError}. */
19
+ function rethrow(thrown) {
20
+ if (typeof thrown === 'string') {
21
+ let record;
22
+ try {
23
+ record = JSON.parse(thrown);
24
+ }
25
+ catch {
26
+ record = undefined;
27
+ }
28
+ if (record !== undefined)
29
+ throw new ArmillaError(record);
30
+ }
31
+ throw thrown instanceof Error ? thrown : new Error(String(thrown));
32
+ }
33
+ function call(f) {
34
+ try {
35
+ return JSON.parse(f());
36
+ }
37
+ catch (error) {
38
+ rethrow(error);
39
+ }
40
+ }
41
+ /** Lay out a chart (spec §13.5 `layout`); throws {@link ArmillaError}. */
42
+ export function layout(chartInput, themeChain, viewState, environment, options) {
43
+ return call(() => wasm().layout(JSON.stringify(chartInput), JSON.stringify(themeChain), JSON.stringify(viewState), JSON.stringify(environment), JSON.stringify(options)));
44
+ }
45
+ /** Lint a theme chain (spec §10.7); throws {@link ArmillaError}. */
46
+ export function lint(themeChain) {
47
+ return call(() => wasm().lint(JSON.stringify(themeChain)));
48
+ }
49
+ /** Migrate a document forward (spec §4.2); throws {@link ArmillaError}. */
50
+ export function migrate(kind, doc) {
51
+ return call(() => wasm().migrate(kind, JSON.stringify(doc)));
52
+ }
53
+ /** Encode a view state as a URL-safe string (spec §11.5). */
54
+ export function bookmark(viewState) {
55
+ try {
56
+ return wasm().bookmark(JSON.stringify(viewState));
57
+ }
58
+ catch (error) {
59
+ rethrow(error);
60
+ }
61
+ }
62
+ /** Decode a bookmark back into a view state (spec §11.5). */
63
+ export function unbookmark(s) {
64
+ return call(() => wasm().unbookmark(s));
65
+ }
66
+ /** Report which rule set a property (spec §13.4). */
67
+ export function explain(scene, themeChain, markId, property) {
68
+ return call(() => wasm().explain(JSON.stringify(scene), JSON.stringify(themeChain), markId, property));
69
+ }
70
+ /** Validate a workspace, returning it normalized (spec §12). */
71
+ export function validateWorkspace(workspace) {
72
+ return call(() => wasm().validate_workspace(JSON.stringify(workspace)));
73
+ }
74
+ /** The compiled-in default theme (spec §10.2). */
75
+ export function defaultTheme() {
76
+ return call(() => wasm().default_theme());
77
+ }
78
+ /** Build a table panel's row model (spec §12.1). */
79
+ export function tableRows(chartInput, viewState, environment, options) {
80
+ return call(() => wasm().table_rows(JSON.stringify(chartInput), JSON.stringify(viewState), JSON.stringify(environment), JSON.stringify(options)));
81
+ }
82
+ /** Build the map panels' line model (spec §12.2). */
83
+ export function mapLines(chartInput, viewState, environment) {
84
+ return call(() => wasm().map_lines(JSON.stringify(chartInput), JSON.stringify(viewState), JSON.stringify(environment)));
85
+ }
86
+ /** Paint a scene as an SVG document string (spec §14). */
87
+ export function paintSvg(scene, packManifests) {
88
+ try {
89
+ return wasm().paint_svg(JSON.stringify(scene), JSON.stringify(packManifests));
90
+ }
91
+ catch (error) {
92
+ rethrow(error);
93
+ }
94
+ }
95
+ /** The core version, for provenance and binding checks. */
96
+ export function version() {
97
+ return wasm().version();
98
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,160 @@
1
+ /**
2
+ * The binding against the real WASM artifact (spec §13.5). Build it first:
3
+ * `pnpm build:wasm`.
4
+ */
5
+ import { readFileSync } from 'node:fs';
6
+ import { describe, expect, it } from 'vitest';
7
+ import { ArmillaError, bookmark, defaultTheme, explain, isScene, layout, lint, mapLines, migrate, paintSvg, tableRows, unbookmark, version, } from './index.js';
8
+ const acg = JSON.parse(readFileSync(new URL('../../../fixtures/charts/acg.json', import.meta.url), 'utf-8'));
9
+ const natal = JSON.parse(readFileSync(new URL('../../../fixtures/charts/natal_timed.json', import.meta.url), 'utf-8'));
10
+ const environment = {
11
+ medium: 'screen',
12
+ scheme: 'light',
13
+ contrast: 'normal',
14
+ motion: 'full',
15
+ density: 'normal',
16
+ };
17
+ const emptyView = { schema_version: 1 };
18
+ describe('layout', () => {
19
+ it('lays out a wheel scene from JSON documents', () => {
20
+ const scene = layout(natal, [], emptyView, environment, { kind: 'wheel' });
21
+ expect(isScene(scene)).toBe(true);
22
+ expect(scene.marks.length).toBeGreaterThan(0);
23
+ expect(scene.tracks[0]?.kind).toBe('wheel');
24
+ expect(scene.provenance.theme_chain).toEqual([['default', '0.1.0']]);
25
+ });
26
+ it('honors the panel options', () => {
27
+ const scene = layout(natal, [], emptyView, environment, {
28
+ kind: 'strip',
29
+ width: 800,
30
+ height: 320,
31
+ });
32
+ expect(scene.tracks[0]?.kind).toBe('strip');
33
+ expect(scene.space).toEqual({ width: 800, height: 320 });
34
+ });
35
+ it('lays out the curve kinds over sampled sky positions (§6.14–§6.15)', () => {
36
+ const sampled = {
37
+ ...natal,
38
+ ephemeris: [
39
+ { timestamp: '2026-01-01', body: 'jupiter', longitude: 100.0 },
40
+ { timestamp: '2026-02-01', body: 'jupiter', longitude: 103.0 },
41
+ { timestamp: '2026-01-01', body: 'saturn', longitude: 20.0 },
42
+ { timestamp: '2026-02-01', body: 'saturn', longitude: 21.0 },
43
+ ],
44
+ };
45
+ const ephemeris = layout(sampled, [], emptyView, environment, { kind: 'ephemeris' });
46
+ expect(ephemeris.tracks[0]?.kind).toBe('ephemeris');
47
+ expect(ephemeris.tracks[0]?.modulus).toBe(90);
48
+ expect(ephemeris.marks.some((m) => m.role === 'curve')).toBe(true);
49
+ expect(ephemeris.marks.some((m) => m.role === 'ref_line')).toBe(true);
50
+ const cycles = layout(sampled, [], emptyView, environment, { kind: 'cycles' });
51
+ expect(cycles.tracks[0]?.kind).toBe('cycles');
52
+ expect(cycles.marks.some((m) => m.id === '-/separation:jupiter-saturn/curve#0')).toBe(true);
53
+ });
54
+ it('lays out the period timelines over time-lord records (§6.16)', () => {
55
+ const lords = {
56
+ ...natal,
57
+ periods: [
58
+ {
59
+ technique: 'profections',
60
+ level: 1,
61
+ lord: 'mars',
62
+ start: '2000-01-01T12:00:00Z',
63
+ end: '2000-12-31T17:48:46Z',
64
+ sign: 'aries',
65
+ house: 1,
66
+ age: 0,
67
+ },
68
+ ],
69
+ };
70
+ const scene = layout(lords, [], emptyView, environment, { kind: 'periods' });
71
+ expect(scene.tracks[0]?.kind).toBe('periods');
72
+ expect(scene.marks.some((m) => m.id === 'natal/period:profections:1:2000-01-01T12:00:00Z/period_block')).toBe(true);
73
+ });
74
+ it('throws a typed ArmillaError for a bad document', () => {
75
+ expect.assertions(3);
76
+ try {
77
+ layout({ schema_version: 99, charts: {} }, [], emptyView, environment, { kind: 'wheel' });
78
+ }
79
+ catch (error) {
80
+ expect(error).toBeInstanceOf(ArmillaError);
81
+ const e = error;
82
+ expect(e.code).toBe('VERSION');
83
+ expect(e.document).toBe('chart_input');
84
+ }
85
+ });
86
+ });
87
+ describe('paintSvg', () => {
88
+ it('renders a scene as a single SVG document', () => {
89
+ const scene = layout(natal, [], emptyView, environment, { kind: 'wheel' });
90
+ const svg = paintSvg(scene, []);
91
+ expect(svg.startsWith('<svg ')).toBe(true);
92
+ expect(svg.endsWith('</svg>')).toBe(true);
93
+ expect(svg).toContain('natal/jupiter/body_glyph');
94
+ });
95
+ });
96
+ describe('tableRows', () => {
97
+ it('builds a positions listing that honors view predicates', () => {
98
+ const m = tableRows(natal, emptyView, environment, { kind: 'positions' });
99
+ expect(m.kind).toBe('positions');
100
+ expect(m.rows).toHaveLength(11);
101
+ expect(m.rows[0]?.id).toBe('natal/sun/table_row');
102
+ expect(m.rows[0]?.cells[1]?.text).toContain('Cap');
103
+ const pruned = tableRows(natal, { schema_version: 1, rules: [{ when: 'motion=retrograde', treat: 'hide' }] }, environment, { kind: 'positions' });
104
+ expect(pruned.rows).toHaveLength(9);
105
+ });
106
+ });
107
+ describe('mapLines', () => {
108
+ it('hands geographic lines that honor view predicates (§12.2)', () => {
109
+ const m = mapLines(acg, emptyView, environment);
110
+ expect(m.chart).toBe('natal');
111
+ expect(m.lines).toHaveLength(50);
112
+ const sunMc = m.lines.find((l) => l.id === 'natal/acg:sun:mc:zodiacal/acg_line');
113
+ expect(sunMc?.designation).toBe('MC');
114
+ expect(sunMc?.glyph).toBe('sun');
115
+ expect(sunMc?.segments[0]?.[0]?.[0]).toBeCloseTo(0.821, 2);
116
+ const pruned = mapLines(acg, { schema_version: 1, rules: [{ when: 'mode=mundane', treat: 'hide' }] }, environment);
117
+ expect(pruned.lines).toHaveLength(46);
118
+ });
119
+ });
120
+ describe('lint', () => {
121
+ it('returns an empty finding list for the empty chain', () => {
122
+ expect(lint([])).toEqual([]);
123
+ });
124
+ });
125
+ describe('migrate', () => {
126
+ it('passes a current view state through unchanged', () => {
127
+ const doc = { schema_version: 1, rules: [{ when: 'body=pluto', treat: 'hide' }] };
128
+ expect(migrate('view_state', doc)).toEqual(doc);
129
+ });
130
+ });
131
+ describe('bookmarks', () => {
132
+ it('round-trips a view state through a URL-safe string', () => {
133
+ const view = {
134
+ schema_version: 1,
135
+ rules: [{ when: 'body=pluto', treat: 'hide' }],
136
+ indicator: 42.5,
137
+ };
138
+ const b = bookmark(view);
139
+ expect(/^[A-Za-z0-9_-]+$/.test(b)).toBe(true);
140
+ expect(unbookmark(b)).toMatchObject({ schema_version: 1, indicator: 42.5 });
141
+ });
142
+ });
143
+ describe('explain', () => {
144
+ it('names the default theme for an untouched property', () => {
145
+ const scene = layout(natal, [], emptyView, environment, { kind: 'wheel' });
146
+ const e = explain(scene, [], 'natal/jupiter/body_glyph', 'fill');
147
+ expect(e.theme_id).toBe('default');
148
+ expect(e.rule_index).toBeGreaterThanOrEqual(0);
149
+ });
150
+ });
151
+ describe('defaultTheme and version', () => {
152
+ it('exposes the compiled default theme', () => {
153
+ const theme = defaultTheme();
154
+ expect(theme.id).toBe('default');
155
+ expect(theme.schema_version).toBe(1);
156
+ });
157
+ it('reports a version string', () => {
158
+ expect(version()).toMatch(/^\d+\.\d+\.\d+/);
159
+ });
160
+ });
@@ -0,0 +1,8 @@
1
+ import type { Basemap } from './types.generated.js';
2
+ /**
3
+ * The canonical shipped geography (spec �6.17, �13.5): Natural Earth
4
+ * 1:110m land rings and internal country borders, quantized to 3
5
+ * decimals. `JSON.parse` keeps type-checking and parsing fast; the
6
+ * document is data, not code.
7
+ */
8
+ export declare const naturalEarth110m: Basemap;