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

@particle-academy/fancy-map

v0.1.2

Published

Engine-agnostic Map component for the Fancy UI suite — one <Map> API over swappable providers (OpenStreetMap via Leaflet, Google Maps), live position tracking, and a Human+ MCP bridge for cohabited human/agent maps.

Readme

@particle-academy/fancy-map

Engine-agnostic Map component for the Fancy UI suite — one <Map> API over swappable providers, live position tracking, and a Human+ MCP bridge so a human and an agent can share the same map.

  • One API, many engines. Render with OpenStreetMap (via Leaflet) or Google Maps today; swapping is a one-line provider change. Adding MapLibre / Mapbox GL later is just another provider.
  • Controlled + JSON-friendly. view + markers + selectedId are controlled props; markers are a plain JSON array an agent can emit directly.
  • Live tracking. Feed markers new positions and they move; follow keeps the camera on a moving marker; useGeolocationTrack wires up the browser's live position.
  • Human+ ready. Every marker has a stable data-map-marker-id handle, and registerMapBridge (in @particle-academy/agent-integrations) lets an agent pan, drop pins, fit bounds, and follow a track over MCP — no DOM scraping.
  • SSR-safe. Renders a sized placeholder on the server; the engine mounts in an effect. No hydration mismatch under Inertia / Next.

Install

npm install @particle-academy/fancy-map

# then the engine(s) you want:
npm install leaflet                      # for the OpenStreetMap / Leaflet provider
npm install @googlemaps/js-api-loader    # for the Google Maps provider

The core has no map-engine dependency — you only install the engine for the provider you use (both are optional peer deps).

Quick start — OpenStreetMap (Leaflet)

import { useState } from "react";
import "leaflet/dist/leaflet.css"; // required once, anywhere in your app
import { Map } from "@particle-academy/fancy-map";
import { leafletProvider } from "@particle-academy/fancy-map/leaflet";

const provider = leafletProvider(); // OpenStreetMap tiles by default

export function StorePicker() {
  const [view, setView] = useState({ center: { lat: 43.0389, lng: -87.9065 }, zoom: 12 });
  const [selected, setSelected] = useState<string | null>(null);
  const markers = [
    { id: "a", position: { lat: 43.0389, lng: -87.9065 }, icon: "🌮", color: "#D6482B", label: "Taquería" },
    { id: "b", position: { lat: 43.05, lng: -87.92 }, icon: "☕", color: "#6F4E37", label: "Coffee" },
  ];

  // Give the map a container with a real height.
  return (
    <div style={{ height: 480 }}>
      <Map provider={provider} view={view} onViewChange={setView}
           markers={markers} selectedId={selected} onSelect={setSelected} />
    </div>
  );
}

The map container needs a height (height: 480, 100% of a sized parent, or a flex child with min-height) — like every map library, Leaflet/Google measure their container to lay out tiles.

Any XYZ raster source works — pass a tileUrl:

leafletProvider({
  tileUrl: "https://tiles.stadiamaps.com/tiles/alidade_smooth/{z}/{x}/{y}{r}.png",
  attribution: "© Stadia Maps © OpenStreetMap",
});

Quick start — Google Maps

import { Map } from "@particle-academy/fancy-map";
import { googleProvider } from "@particle-academy/fancy-map/google";

const provider = googleProvider({ apiKey: import.meta.env.VITE_GOOGLE_MAPS_KEY });

<div style={{ height: 480 }}>
  <Map provider={provider} view={view} onViewChange={setView} markers={markers} />
</div>;

The Google Maps JavaScript SDK is loaded over the network at mount time (nothing Google-specific enters your SSR bundle). Requires a Google Maps JS API key.

Live tracking

import { Map, useGeolocationTrack } from "@particle-academy/fancy-map";

function LiveMe() {
  const { position } = useGeolocationTrack(); // watches navigator.geolocation
  const [view, setView] = useState({ center: { lat: 43.04, lng: -87.9 }, zoom: 14 });
  const markers = position ? [{ id: "me", position, icon: "📍", color: "#2563eb" }] : [];
  // follow="me" keeps the camera centered as you move.
  return (
    <div style={{ height: 420 }}>
      <Map provider={provider} view={view} onViewChange={setView} markers={markers} follow="me" />
    </div>
  );
}

Any position source works the same way — a websocket / Laravel Echo channel pushing a vehicle's coordinates, or an agent updating a marker over the bridge. The component just re-renders from controlled markers; the followed marker animates and the camera keeps up.

Human+ — a map a human and an agent share

Mount the bridge from @particle-academy/agent-integrations against the same state you pass to <Map>:

import { registerMapBridge } from "@particle-academy/agent-integrations/bridges/map";

registerMapBridge(server, {
  adapter: {
    getView: () => view, setView,
    getMarkers: () => markers, setMarkers,
    getSelected: () => selected, setSelected,
    fitBounds: (pts) => handle?.fitBounds(pts), // handle from <Map onReady>
  },
  agent: { id: "assistant", name: "Assistant", color: "#7c3aed" },
});

The agent gets map_set_view, map_pan, map_zoom, map_add_marker, map_update_marker, map_remove_marker, map_select, map_fit_bounds, map_start_track, map_stop_track — every mutation broadcasts AgentActivity and is undoable, so the human sees what the agent does and can step back.

API

<Map>

| Prop | Type | Notes | |---|---|---| | provider | MapProvider | Required. leafletProvider() / googleProvider({apiKey}). | | view | MapView | Controlled camera { center: {lat,lng}, zoom, bearing?, pitch? }. | | onViewChange | (view) => void | Fires on user pan/zoom. | | markers | MapMarker[] | Controlled; { id, position, label?, color?, icon?, draggable?, data? }. | | selectedId | string \| null | Controlled selection. | | onSelect | (id, marker?) => void | Marker clicked. | | onMarkerDragEnd | (id, position) => void | Draggable marker released. | | onMapClick | (position) => void | Background clicked. | | follow | string \| null | Keep this marker centered as it moves. | | fitTo | LatLng[] | One-shot: fit the camera to these points. | | onReady | (handle) => void | Grab the imperative MapHandle (e.g. for the bridge's fitBounds). |

Writing a provider

A provider is { name, mount(host, opts) => MapHandle }. The MapHandle implements setView / getView / setMarkers / setSelected / fitBounds / on / destroy. See src/leaflet.ts for a ~180-line reference implementation.

Documentation

Full guide: docs/Map.md.

License

MIT

⭐ Star Fancy UI

If this helps, a star on github.com/Particle-Academy/fancy-map helps the kit grow.