npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

json-maps

v0.3.3

Published

Declarative map renderer — drop in a JSON spec, get a full interactive map

Readme

json-maps

Declarative map renderer — drop in a JSON spec, get a full interactive map.

Built on MapLibre GL with CARTO basemaps. No API keys required.

Docs · Playground

Install

npm install json-maps maplibre-gl lucide-react

Setup

CSS

Import the json-maps stylesheet in your CSS (includes MapLibre styles, theme variables, and component overrides):

@import "tailwindcss";
@import "json-maps/styles.css";

/* Tell Tailwind to scan json-maps for utility classes */
@source "../node_modules/json-maps/dist";

You can override the default theme by redefining CSS variables in your own :root block after the import.

Quick Start

"use client";
import { MapRenderer } from "json-maps";

const spec = {
  basemap: "dark",
  center: [77.59, 12.97],
  zoom: 12,
  pitch: 45,
  markers: {
    office: {
      coordinates: [77.59, 12.97],
      label: "Office",
      color: "#e74c3c",
      popup: { title: "HQ", description: "Main office" },
    },
  },
};

export default function MyMap() {
  return <MapRenderer spec={spec} className="h-screen" />;
}

Every field is optional. An empty {} gives you a light basemap at world view.

Spec

Viewport

| Field | Type | Description | |-------|------|-------------| | basemap | "light" | "dark" | "streets" | URL | Map style | | center | [lng, lat] | Map center | | zoom | number | Zoom level (0–24) | | pitch | number | Camera tilt (0–85) | | bearing | number | Compass rotation (-180–180) | | bounds | [west, south, east, north] | Fit to bounding box | | projection | "mercator" | "globe" | Map projection |

Markers

{
  "markers": {
    "tokyo-tower": {
      "coordinates": [139.7454, 35.6586],
      "icon": "landmark",
      "color": "#e74c3c",
      "label": "Tokyo Tower",
      "tooltip": "333m tall observation tower",
      "popup": { "title": "Tokyo Tower", "description": "Iconic landmark" },
      "draggable": true
    }
  }
}

21 built-in icons: map-pin star heart flag coffee utensils hotel building-2 tree-pine mountain plane train car ship bus church shopping-cart camera landmark tent truck

Need more? Override the Marker component slot with any icon library.

Layers

Seven layer types:

GeoJSON — points, lines, polygons from URL or inline data:

{
  "layers": {
    "quakes": {
      "type": "geojson",
      "data": "https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_week.geojson",
      "style": {
        "pointColor": { "type": "continuous", "attr": "mag", "palette": "OrYel", "domain": [0, 7] },
        "pointRadius": 4
      },
      "tooltip": ["place", "mag"],
      "cluster": true
    }
  }
}

GeoParquet — load .parquet files directly:

{ "type": "parquet", "data": "https://example.com/buildings.parquet" }

Route — driving/walking/cycling directions via OSRM:

{ "type": "route", "from": [-73.98, 40.75], "to": [-73.96, 40.78], "profile": "driving" }

Heatmap — point density visualization:

{ "type": "heatmap", "data": "https://example.com/points.geojson", "radius": 20, "intensity": 0.8 }

MVT — vector tiles:

{ "type": "mvt", "url": "https://tiles.example.com/{z}/{x}/{y}.pbf", "sourceLayer": "buildings" }

Raster — tile layers (satellite, terrain):

{ "type": "raster", "url": "https://tiles.example.com/{z}/{x}/{y}.png" }

PMTiles — self-hosted vector tile archives:

{ "type": "pmtiles", "url": "https://example.com/data.pmtiles", "sourceLayer": "buildings" }

Data-Driven Styling

Colors can be static or data-driven:

{
  "fillColor": { "type": "continuous", "attr": "population", "palette": "Sunset", "domain": [0, 1000000] },
  "pointColor": { "type": "categorical", "attr": "zone_type", "palette": "Bold" }
}

Point radius supports data-driven sizing too:

{ "pointRadius": { "type": "continuous", "attr": "mag", "domain": [0, 8], "range": [2, 12] } }

Available palettes: Burg RedOr OrYel Peach PinkYl Mint BluGrn DarkMint Emrld BluYl Teal Purp Sunset SunsetDark Magenta TealRose Geyser Temps Fall ArmyRose Tropic Bold Pastel Antique Vivid Prism Safe

Controls

{
  "controls": {
    "zoom": true,
    "compass": true,
    "fullscreen": true,
    "locate": true,
    "search": true,
    "basemapSwitcher": true,
    "layerSwitcher": true
  }
}

Legend

Auto-generated from data-driven layers:

{ "legend": { "pop": { "layer": "population", "title": "Population" } } }

Widgets

Stat cards overlaid on the map, with optional SQL-powered data via DuckDB-WASM:

{
  "widgets": {
    "stats": {
      "title": "Summary",
      "value": "1,234",
      "description": "Total events",
      "position": "top-right"
    }
  }
}

React API

Props

<MapRenderer
  spec={spec}
  className="h-screen"
  components={{ Marker: CustomMarker }}
  onMarkerClick={(id, coords) => {}}
  onMarkerDragEnd={(id, coords) => {}}
  onLayerClick={(layerId, coords) => {}}
  onViewportChange={(viewport) => {}}
/>

Component Slots

Replace built-in marker, popup, tooltip, or layer tooltip with your own:

import { MapRenderer, type MarkerComponentProps } from "json-maps";

function CustomMarker({ marker, color }: MarkerComponentProps) {
  return <div style={{ background: color, borderRadius: "50%", padding: 6 }}>
    <MyIcon name={marker.icon} />
  </div>;
}

<MapRenderer spec={spec} components={{ Marker: CustomMarker }} />

useMap Hook

Access the MapLibre instance programmatically:

import { useMap } from "json-maps";

function MyComponent() {
  const map = useMap();
  // map.flyTo({ center: [0, 0], zoom: 5 })
}

AI Integration

json-maps exports everything you need to build AI-powered map generation with streaming JSONL patches.

API Route (Next.js)

Create a streaming endpoint in two lines:

// app/api/generate/route.ts
import { createMapGenerateHandler } from "json-maps/api";

export const POST = createMapGenerateHandler();
export const maxDuration = 30;

Requires ai and @ai-sdk/anthropic as dependencies. Customize the model and temperature:

export const POST = createMapGenerateHandler({
  model: "claude-haiku-4-5-20251001",
  temperature: 0.7,
});

Client Hook

Use useMapStream to connect a text input to your streaming endpoint:

"use client";
import { MapRenderer, useMapStream } from "json-maps";

export default function Editor() {
  const { spec, isStreaming, send, stop } = useMapStream({
    api: "/api/generate",
  });

  return (
    <div>
      <button onClick={() => send("Show me Tokyo with landmarks")}>
        Generate
      </button>
      <MapRenderer spec={spec} className="h-screen" />
    </div>
  );
}

System Prompt & Catalog

For custom AI pipelines, use the prompt utilities directly:

import { generateSystemPrompt, buildUserPrompt } from "json-maps";

const systemPrompt = generateSystemPrompt();
const userPrompt = buildUserPrompt("Show me earthquakes", previousSpec);

Development

npm install
npm run dev        # docs site
npm run build:lib  # library build

License

MIT