krackedmaps 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.
- package/README.md +149 -0
- package/bin/cli.js +117 -0
- package/bin/mcp.js +99 -0
- package/dist/data.d.ts +27 -0
- package/dist/data.esm.js +1 -0
- package/dist/index.d.ts +92 -0
- package/dist/krackedmaps-districts.geojson +105880 -0
- package/dist/krackedmaps.cjs +19 -0
- package/dist/krackedmaps.css +219 -0
- package/dist/krackedmaps.esm.js +19 -0
- package/dist/krackedmaps.geojson +8593 -0
- package/dist/krackedmaps.umd.js +19 -0
- package/package.json +55 -0
package/README.md
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
# KrackedMaps · interactive map of Malaysia
|
|
2
|
+
|
|
3
|
+
A self-contained, themeable SVG map of Malaysia — **16 admin-1 regions** (13 states +
|
|
4
|
+
Kuala Lumpur, Putrajaya, Labuan) and **159 admin-2 *daerah*** — with **zero runtime
|
|
5
|
+
dependencies**. Use it as a live component, a CLI, an MCP server for Claude, an embeddable
|
|
6
|
+
iframe, or raw SVG / GeoJSON.
|
|
7
|
+
|
|
8
|
+
**Customize & export:** https://map.themasterofnone.xyz · **Live demo:** https://map.themasterofnone.xyz/demo.html
|
|
9
|
+
|
|
10
|
+
Two aligned layers from one shared projection: click a state to **drill in** (carve its
|
|
11
|
+
districts + info panel); hover a district for its name; press Esc to step back out. East
|
|
12
|
+
Malaysia is slid west to close the South China Sea gap for a compact frame.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Three ways in
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm i krackedmaps # library + CLI + MCP server, one package
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### 1. Library (browser / SSR)
|
|
23
|
+
|
|
24
|
+
```js
|
|
25
|
+
import { createMalaysiaMap } from "krackedmaps";
|
|
26
|
+
import "krackedmaps/css";
|
|
27
|
+
|
|
28
|
+
const map = createMalaysiaMap("#map", { theme: "blueprint" });
|
|
29
|
+
map.on("select", (slug) => console.log("selected", slug));
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
```js
|
|
33
|
+
// server-side string builders (no DOM)
|
|
34
|
+
import { renderSVG, project } from "krackedmaps";
|
|
35
|
+
const svg = renderSVG({ theme: "blueprint", withDistricts: true });
|
|
36
|
+
project(101.7117, 3.1578); // -> { x, y } in the SVG viewBox
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### 2. CLI — grab assets from the terminal
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
npx krackedmaps svg --theme blueprint --districts > malaysia.svg
|
|
43
|
+
npx krackedmaps geojson --districts > daerah.geojson
|
|
44
|
+
npx krackedmaps react --theme batik > MalaysiaMap.jsx
|
|
45
|
+
npx krackedmaps project 101.7117 3.1578 # -> {"x":…,"y":…}
|
|
46
|
+
npx krackedmaps states # list states
|
|
47
|
+
npx krackedmaps --help
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
| command | output |
|
|
51
|
+
|---|---|
|
|
52
|
+
| `svg [--theme] [--districts] [--out]` | themed, self-contained SVG |
|
|
53
|
+
| `geojson [--districts] [--out]` | GeoJSON (original lng/lat) |
|
|
54
|
+
| `json [--out]` | projected paths + projection params |
|
|
55
|
+
| `react [--theme] [--out]` | a `<MalaysiaMap>` component |
|
|
56
|
+
| `embed [--theme] [--districts] [--labels] [--static]` | iframe snippet |
|
|
57
|
+
| `project <lng> <lat>` | project real coords → SVG `{x,y}` |
|
|
58
|
+
| `states` · `districts [--state <slug>]` · `themes` | listings |
|
|
59
|
+
|
|
60
|
+
### 3. MCP server — use it inside Claude
|
|
61
|
+
|
|
62
|
+
Exposes tools (`krackedmaps_svg`, `krackedmaps_geojson`, `krackedmaps_project`,
|
|
63
|
+
`krackedmaps_states`, `krackedmaps_districts`, `krackedmaps_react`, `krackedmaps_embed`,
|
|
64
|
+
`krackedmaps_paths`) so any Claude conversation can pull the map + data.
|
|
65
|
+
|
|
66
|
+
**Claude Code:**
|
|
67
|
+
```bash
|
|
68
|
+
claude mcp add krackedmaps -- npx -y krackedmaps mcp
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
**Claude Desktop** (`claude_desktop_config.json`):
|
|
72
|
+
```json
|
|
73
|
+
{
|
|
74
|
+
"mcpServers": {
|
|
75
|
+
"krackedmaps": { "command": "npx", "args": ["-y", "krackedmaps", "mcp"] }
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Then ask Claude things like *"give me the Malaysia map as a blueprint SVG with districts"* or
|
|
81
|
+
*"what SVG coordinate is KLCC?"*.
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## `createMalaysiaMap(container, options)`
|
|
86
|
+
|
|
87
|
+
`container` is an `HTMLElement` or selector. Returns an **instance** — make as many as you
|
|
88
|
+
like; `destroy()` tears each one down cleanly.
|
|
89
|
+
|
|
90
|
+
| option | default | description |
|
|
91
|
+
|---|---|---|
|
|
92
|
+
| `theme` | `"blueprint"` | preset (`mono`, `flat-dark`, `light`, `blueprint`, `batik`) or `{cssVar: value}` |
|
|
93
|
+
| `panel` / `tooltip` | `true` | built-in info panel / hover tooltip |
|
|
94
|
+
| `showDistricts` | `true` | district drill-down layer |
|
|
95
|
+
| `interactive` | `true` | pointer / click / keyboard handlers |
|
|
96
|
+
| `zoom` | `true` | zoom-to-state on select (`false` keeps the full map framed) |
|
|
97
|
+
| `keyboard` | `true` | Escape steps back out (scoped, never global) |
|
|
98
|
+
| `labels` | `false` | start with state labels shown |
|
|
99
|
+
| `initialState` | `null` | slug to select after build |
|
|
100
|
+
| `meta` / `colors` / `renderPanel` | — | per-state info / choropleth ramp / custom panel |
|
|
101
|
+
|
|
102
|
+
```js
|
|
103
|
+
map.select("penang"); map.focus("sabah"); map.drillInto("sarawak");
|
|
104
|
+
map.addPin({ lng: 101.7117, lat: 3.1578, label: "KLCC" });
|
|
105
|
+
map.setData({ penang: 1.8, sabah: 3.4 }); // choropleth by slug
|
|
106
|
+
map.setTheme("batik"); map.toggleLabels(true);
|
|
107
|
+
map.on("select" | "hover" | "drill", cb); map.off(name, cb);
|
|
108
|
+
map.destroy();
|
|
109
|
+
map.STATES; map.DISTRICTS; map.project(lng, lat);
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Theming
|
|
113
|
+
|
|
114
|
+
Everything is CSS variables on the `.mmap` container — pass a `theme`, call `setTheme(...)`,
|
|
115
|
+
or override in your own CSS. Key vars: `--sea`, `--land`, `--land-hover`, `--land-active`,
|
|
116
|
+
`--stroke`, `--district`, `--carve`, `--district-hi`, `--label`, `--pin`, `--accent`.
|
|
117
|
+
|
|
118
|
+
## Data only (no engine)
|
|
119
|
+
|
|
120
|
+
```js
|
|
121
|
+
import { STATES, DISTRICTS, project } from "krackedmaps/data";
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Pre-generated files also live in [`exports/`](exports/) (served at `/exports/`): themed SVGs,
|
|
125
|
+
normalized GeoJSON, projected-paths JSON. See [`exports/README.md`](exports/README.md).
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## Develop
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
npm run dev # python3 -m http.server 4173 — open http://localhost:4173
|
|
133
|
+
npm run build # bundle dist/ for npm (esbuild) + copy GeoJSON
|
|
134
|
+
npm run bake # re-run data/bake.py + data/export.py after changing source data
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
| file | role |
|
|
138
|
+
|------|------|
|
|
139
|
+
| `src/engine.js` | `createMalaysiaMap` — render + interaction engine |
|
|
140
|
+
| `src/render.js` | pure SVG / snippet builders (shared by browser, CLI, MCP) |
|
|
141
|
+
| `src/data.js` / `src/themes.js` | baked geometry re-export / theme presets |
|
|
142
|
+
| `bin/cli.js` / `bin/mcp.js` | the CLI and the MCP server |
|
|
143
|
+
| `data/states.js` | **baked** paths + `project()` (auto-generated — don't hand-edit) |
|
|
144
|
+
| `index.html` / `playground.js` | the customize & export page (landing) |
|
|
145
|
+
| `demo.html` / `demo.js` | the live demo (dogfoods the engine) |
|
|
146
|
+
|
|
147
|
+
Provenance: states from codeforamerica/click_that_hood; districts (ADM2) + Labuan from
|
|
148
|
+
geoBoundaries gbOpen (MYS). Check each source's license before commercial redistribution.
|
|
149
|
+
MIT licensed.
|
package/bin/cli.js
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// KrackedMaps CLI — grab Malaysia map assets straight from the terminal.
|
|
3
|
+
import { readFileSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import {
|
|
6
|
+
renderSVG, reactComponent, embedSnippet, project,
|
|
7
|
+
STATES, DISTRICTS, PROJECTION, PRESETS,
|
|
8
|
+
} from "../dist/krackedmaps.esm.js";
|
|
9
|
+
|
|
10
|
+
const VERSION = "0.1.0";
|
|
11
|
+
const readGeo = (f) => readFileSync(fileURLToPath(new URL("../dist/" + f, import.meta.url)), "utf8");
|
|
12
|
+
|
|
13
|
+
// crude flag parser → { _: [positional], flag: value | true }
|
|
14
|
+
function parseArgs(argv) {
|
|
15
|
+
const out = { _: [] };
|
|
16
|
+
for (let i = 0; i < argv.length; i++) {
|
|
17
|
+
const a = argv[i];
|
|
18
|
+
if (a.startsWith("--")) {
|
|
19
|
+
const next = argv[i + 1];
|
|
20
|
+
if (next !== undefined && !next.startsWith("--")) { out[a.slice(2)] = next; i++; }
|
|
21
|
+
else out[a.slice(2)] = true;
|
|
22
|
+
} else out._.push(a);
|
|
23
|
+
}
|
|
24
|
+
return out;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function emit(text, args) {
|
|
28
|
+
if (typeof args.out === "string") {
|
|
29
|
+
writeFileSync(args.out, text.endsWith("\n") ? text : text + "\n");
|
|
30
|
+
process.stderr.write(`wrote ${args.out}\n`);
|
|
31
|
+
} else {
|
|
32
|
+
process.stdout.write(text.endsWith("\n") ? text : text + "\n");
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function fail(msg) { process.stderr.write("krackedmaps: " + msg + "\n"); process.exit(1); }
|
|
37
|
+
|
|
38
|
+
const HELP = `KrackedMaps ${VERSION} — interactive SVG map of Malaysia (16 states + 159 districts)
|
|
39
|
+
|
|
40
|
+
Usage: krackedmaps <command> [options]
|
|
41
|
+
|
|
42
|
+
Commands:
|
|
43
|
+
svg [--theme <name>] [--districts] [--out <file>] themed SVG
|
|
44
|
+
geojson [--districts] [--out <file>] GeoJSON (lng/lat)
|
|
45
|
+
json [--out <file>] projected paths JSON
|
|
46
|
+
react [--theme <name>] [--out <file>] React component
|
|
47
|
+
embed [--theme <name>] [--districts] [--labels] [--static] iframe snippet
|
|
48
|
+
project <lng> <lat> project coords -> {x,y}
|
|
49
|
+
states list states
|
|
50
|
+
districts [--state <slug>] list districts
|
|
51
|
+
themes list theme presets
|
|
52
|
+
mcp start the MCP server (stdio)
|
|
53
|
+
|
|
54
|
+
Themes: ${Object.keys(PRESETS).join(", ")}
|
|
55
|
+
Docs: https://map.themasterofnone.xyz`;
|
|
56
|
+
|
|
57
|
+
async function main() {
|
|
58
|
+
const [cmd, ...rest] = process.argv.slice(2);
|
|
59
|
+
const args = parseArgs(rest);
|
|
60
|
+
|
|
61
|
+
switch (cmd) {
|
|
62
|
+
case undefined:
|
|
63
|
+
case "help": case "-h": case "--help":
|
|
64
|
+
console.log(HELP); break;
|
|
65
|
+
case "version": case "-v": case "--version":
|
|
66
|
+
console.log(VERSION); break;
|
|
67
|
+
|
|
68
|
+
case "svg":
|
|
69
|
+
emit(renderSVG({ withDistricts: !!args.districts, theme: args.theme || "blueprint" }), args); break;
|
|
70
|
+
|
|
71
|
+
case "geojson":
|
|
72
|
+
emit(readGeo(args.districts ? "krackedmaps-districts.geojson" : "krackedmaps.geojson"), args); break;
|
|
73
|
+
|
|
74
|
+
case "json":
|
|
75
|
+
emit(JSON.stringify({
|
|
76
|
+
projection: PROJECTION,
|
|
77
|
+
viewBox: `0 0 ${PROJECTION.viewW} ${PROJECTION.viewH}`,
|
|
78
|
+
states: STATES, districts: DISTRICTS,
|
|
79
|
+
}, null, args.out ? 0 : 2), args); break;
|
|
80
|
+
|
|
81
|
+
case "react":
|
|
82
|
+
emit(reactComponent(args.theme || "blueprint"), args); break;
|
|
83
|
+
|
|
84
|
+
case "embed":
|
|
85
|
+
emit(embedSnippet({
|
|
86
|
+
theme: args.theme || "blueprint",
|
|
87
|
+
districts: !!args.districts, labels: !!args.labels, static: !!args.static,
|
|
88
|
+
}), args); break;
|
|
89
|
+
|
|
90
|
+
case "project": {
|
|
91
|
+
const [lng, lat] = args._.map(Number);
|
|
92
|
+
if (!Number.isFinite(lng) || !Number.isFinite(lat))
|
|
93
|
+
fail("project needs <lng> <lat>, e.g. krackedmaps project 101.7117 3.1578");
|
|
94
|
+
console.log(JSON.stringify(project(lng, lat))); break;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
case "states":
|
|
98
|
+
for (const s of STATES) console.log(`${s.slug}\t${s.name}\t${s.type}`); break;
|
|
99
|
+
|
|
100
|
+
case "districts": {
|
|
101
|
+
const list = args.state ? DISTRICTS.filter((d) => d.state === args.state) : DISTRICTS;
|
|
102
|
+
if (!list.length) fail(`no districts for state "${args.state}"`);
|
|
103
|
+
for (const d of list) console.log(`${d.state}/${d.slug}\t${d.name}`); break;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
case "themes":
|
|
107
|
+
for (const name of Object.keys(PRESETS)) console.log(name); break;
|
|
108
|
+
|
|
109
|
+
case "mcp":
|
|
110
|
+
await import("./mcp.js"); break;
|
|
111
|
+
|
|
112
|
+
default:
|
|
113
|
+
fail(`unknown command "${cmd}". Run: krackedmaps --help`);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
main().catch((e) => fail(e.message));
|
package/bin/mcp.js
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// KrackedMaps MCP server — exposes the Malaysia map to Claude over stdio.
|
|
3
|
+
// Zero-dependency, newline-delimited JSON-RPC 2.0 (MCP stdio transport).
|
|
4
|
+
import { readFileSync } from "node:fs";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
import {
|
|
7
|
+
renderSVG, reactComponent, embedSnippet, project,
|
|
8
|
+
STATES, DISTRICTS, PROJECTION, PRESETS,
|
|
9
|
+
} from "../dist/krackedmaps.esm.js";
|
|
10
|
+
|
|
11
|
+
const VERSION = "0.1.0";
|
|
12
|
+
const readGeo = (f) => readFileSync(fileURLToPath(new URL("../dist/" + f, import.meta.url)), "utf8");
|
|
13
|
+
const themeEnum = Object.keys(PRESETS);
|
|
14
|
+
|
|
15
|
+
const TOOLS = [
|
|
16
|
+
{ name: "krackedmaps_svg",
|
|
17
|
+
description: "Themed, self-contained SVG of Malaysia (16 states; optional 159 districts).",
|
|
18
|
+
inputSchema: { type: "object", properties: { theme: { type: "string", enum: themeEnum }, districts: { type: "boolean" } } },
|
|
19
|
+
run: (a) => renderSVG({ theme: a.theme || "blueprint", withDistricts: !!a.districts }) },
|
|
20
|
+
{ name: "krackedmaps_geojson",
|
|
21
|
+
description: "GeoJSON FeatureCollection (original lng/lat) of states or districts, with normalized props.",
|
|
22
|
+
inputSchema: { type: "object", properties: { level: { type: "string", enum: ["states", "districts"] } } },
|
|
23
|
+
run: (a) => readGeo(a.level === "districts" ? "krackedmaps-districts.geojson" : "krackedmaps.geojson") },
|
|
24
|
+
{ name: "krackedmaps_paths",
|
|
25
|
+
description: "Projected SVG paths + projection params (JSON) for custom rendering.",
|
|
26
|
+
inputSchema: { type: "object", properties: {} },
|
|
27
|
+
run: () => JSON.stringify({ projection: PROJECTION, viewBox: `0 0 ${PROJECTION.viewW} ${PROJECTION.viewH}`, states: STATES, districts: DISTRICTS }) },
|
|
28
|
+
{ name: "krackedmaps_project",
|
|
29
|
+
description: "Project a real-world lng/lat to the map's SVG coordinates (pins land exactly).",
|
|
30
|
+
inputSchema: { type: "object", properties: { lng: { type: "number" }, lat: { type: "number" } }, required: ["lng", "lat"] },
|
|
31
|
+
run: (a) => JSON.stringify(project(Number(a.lng), Number(a.lat))) },
|
|
32
|
+
{ name: "krackedmaps_states",
|
|
33
|
+
description: "List the 16 states/territories (slug, name, type).",
|
|
34
|
+
inputSchema: { type: "object", properties: {} },
|
|
35
|
+
run: () => JSON.stringify(STATES.map((s) => ({ slug: s.slug, name: s.name, type: s.type }))) },
|
|
36
|
+
{ name: "krackedmaps_districts",
|
|
37
|
+
description: "List the 159 districts (optionally filtered by parent state slug).",
|
|
38
|
+
inputSchema: { type: "object", properties: { state: { type: "string" } } },
|
|
39
|
+
run: (a) => JSON.stringify((a.state ? DISTRICTS.filter((d) => d.state === a.state) : DISTRICTS).map((d) => ({ slug: d.slug, name: d.name, state: d.state }))) },
|
|
40
|
+
{ name: "krackedmaps_react",
|
|
41
|
+
description: "A ready-to-paste React component using the krackedmaps npm package.",
|
|
42
|
+
inputSchema: { type: "object", properties: { theme: { type: "string", enum: themeEnum } } },
|
|
43
|
+
run: (a) => reactComponent(a.theme || "blueprint") },
|
|
44
|
+
{ name: "krackedmaps_embed",
|
|
45
|
+
description: "An iframe embed snippet for the hosted, interactive map.",
|
|
46
|
+
inputSchema: { type: "object", properties: { theme: { type: "string", enum: themeEnum }, districts: { type: "boolean" } } },
|
|
47
|
+
run: (a) => embedSnippet({ theme: a.theme || "blueprint", districts: !!a.districts }) },
|
|
48
|
+
];
|
|
49
|
+
|
|
50
|
+
const send = (msg) => process.stdout.write(JSON.stringify(msg) + "\n");
|
|
51
|
+
const reply = (id, result) => send({ jsonrpc: "2.0", id, result });
|
|
52
|
+
const errReply = (id, code, message) => send({ jsonrpc: "2.0", id, error: { code, message } });
|
|
53
|
+
|
|
54
|
+
function handle(msg) {
|
|
55
|
+
const { id, method, params } = msg;
|
|
56
|
+
switch (method) {
|
|
57
|
+
case "initialize":
|
|
58
|
+
return reply(id, {
|
|
59
|
+
protocolVersion: params?.protocolVersion || "2025-06-18",
|
|
60
|
+
capabilities: { tools: {} },
|
|
61
|
+
serverInfo: { name: "krackedmaps", version: VERSION },
|
|
62
|
+
});
|
|
63
|
+
case "notifications/initialized":
|
|
64
|
+
case "notifications/cancelled":
|
|
65
|
+
return; // notifications: no reply
|
|
66
|
+
case "ping":
|
|
67
|
+
return reply(id, {});
|
|
68
|
+
case "tools/list":
|
|
69
|
+
return reply(id, { tools: TOOLS.map(({ name, description, inputSchema }) => ({ name, description, inputSchema })) });
|
|
70
|
+
case "tools/call": {
|
|
71
|
+
const tool = TOOLS.find((t) => t.name === params?.name);
|
|
72
|
+
if (!tool) return errReply(id, -32602, `unknown tool: ${params?.name}`);
|
|
73
|
+
try {
|
|
74
|
+
return reply(id, { content: [{ type: "text", text: tool.run(params.arguments || {}) }] });
|
|
75
|
+
} catch (e) {
|
|
76
|
+
return reply(id, { content: [{ type: "text", text: "Error: " + e.message }], isError: true });
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
default:
|
|
80
|
+
if (id !== undefined) errReply(id, -32601, `method not found: ${method}`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
let buf = "";
|
|
85
|
+
process.stdin.setEncoding("utf8");
|
|
86
|
+
process.stdin.on("data", (chunk) => {
|
|
87
|
+
buf += chunk;
|
|
88
|
+
let nl;
|
|
89
|
+
while ((nl = buf.indexOf("\n")) >= 0) {
|
|
90
|
+
const line = buf.slice(0, nl).trim();
|
|
91
|
+
buf = buf.slice(nl + 1);
|
|
92
|
+
if (!line) continue;
|
|
93
|
+
let msg;
|
|
94
|
+
try { msg = JSON.parse(line); } catch { continue; }
|
|
95
|
+
try { handle(msg); } catch (e) { if (msg && msg.id !== undefined) errReply(msg.id, -32603, e.message); }
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
process.stdin.on("end", () => process.exit(0));
|
|
99
|
+
process.stderr.write(`krackedmaps MCP server ${VERSION} ready (stdio)\n`);
|
package/dist/data.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export interface Point { x: number; y: number; }
|
|
2
|
+
|
|
3
|
+
export interface StateFeature {
|
|
4
|
+
slug: string;
|
|
5
|
+
name: string;
|
|
6
|
+
type: "state" | "ft";
|
|
7
|
+
d: string;
|
|
8
|
+
centroid: Point;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface DistrictFeature {
|
|
12
|
+
slug: string;
|
|
13
|
+
name: string;
|
|
14
|
+
state: string;
|
|
15
|
+
d: string;
|
|
16
|
+
centroid: Point;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface Projection {
|
|
20
|
+
minx: number; maxy: number; scale: number; pad: number; eastLng: number;
|
|
21
|
+
shift: number; offX: number; offY: number; viewW: number; viewH: number;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export const STATES: StateFeature[];
|
|
25
|
+
export const DISTRICTS: DistrictFeature[];
|
|
26
|
+
export const PROJECTION: Projection;
|
|
27
|
+
export function project(lng: number, lat: number): Point;
|