{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "neon-map",
  "type": "registry:component",
  "title": "NeonMap",
  "description": "A real interactive vector map (pan/zoom/tilt) recolored into a neon nightscape, with a glowing arc and a pulsing pin. Tiles + style from OpenFreeMap — genuinely free, no API token or signup.",
  "dependencies": [
    "maplibre-gl"
  ],
  "registryDependencies": [],
  "tier": "pro",
  "note": "Requires the .neon-pin / neon-pulse styles from globals.css and the maplibre-gl CSS (imported in the component). Give it a sized container; render via next/dynamic ssr:false. Separate WebGL context from R3F — don't stack with heavy 3D scenes.",
  "files": [
    {
      "path": "components/prism/NeonMap.tsx",
      "content": "\"use client\";\n\nimport { useEffect, useRef } from \"react\";\nimport maplibregl from \"maplibre-gl\";\nimport \"maplibre-gl/dist/maplibre-gl.css\";\n\n/**\n * NeonMap — a REAL interactive vector map (actual streets, pan/zoom/tilt) styled\n * into a neon nightscape. Tiles + style come from OpenFreeMap (free, no API token,\n * no signup). The base 'dark' style is recolored on load and a glowing great-circle\n * arc + a pulsing pin are drawn on top. Separate WebGL context from R3F, so render\n * it on its own (not stacked with the flight). The `.neon-pin` styles live in globals.css.\n */\nfunction archedLine(a: [number, number], b: [number, number], n = 48, lift = 9) {\n  const pts: [number, number][] = [];\n  for (let i = 0; i <= n; i++) {\n    const t = i / n;\n    pts.push([a[0] + (b[0] - a[0]) * t, a[1] + (b[1] - a[1]) * t + Math.sin(Math.PI * t) * lift]);\n  }\n  return pts;\n}\n\nexport function NeonMap({\n  center = [-122.42, 37.77],\n  zoom = 11,\n}: {\n  center?: [number, number];\n  zoom?: number;\n}) {\n  const ref = useRef<HTMLDivElement>(null);\n  const mapRef = useRef<maplibregl.Map | null>(null);\n\n  useEffect(() => {\n    if (!ref.current || mapRef.current) return;\n    const map = new maplibregl.Map({\n      container: ref.current,\n      style: \"https://tiles.openfreemap.org/styles/dark\", // free, no token\n      center,\n      zoom,\n      pitch: 55,\n      bearing: -18,\n      attributionControl: { compact: true },\n    });\n    mapRef.current = map;\n\n    map.on(\"load\", () => {\n      const NEON = \"#1fd4e6\";\n      const MAGENTA = \"#ff3d81\";\n      try {\n        map.setPaintProperty(\"background\", \"background-color\", \"#05060a\");\n      } catch {}\n      for (const layer of map.getStyle().layers ?? []) {\n        const id = layer.id;\n        const type = layer.type;\n        if (/water/.test(id) && type === \"fill\") {\n          try {\n            map.setPaintProperty(id, \"fill-color\", \"#081018\");\n          } catch {}\n        }\n        if (/(road|street|highway|transportation)/.test(id) && type === \"line\") {\n          try {\n            map.setPaintProperty(id, \"line-color\", NEON);\n          } catch {}\n          try {\n            map.setPaintProperty(id, \"line-blur\", 0.6);\n          } catch {}\n        }\n        if (/building/.test(id) && (type === \"fill\" || type === \"fill-extrusion\")) {\n          try {\n            map.setPaintProperty(id, type === \"fill\" ? \"fill-color\" : \"fill-extrusion-color\", \"#0c1320\");\n          } catch {}\n        }\n      }\n\n      // glowing arc\n      const arc: GeoJSON.Feature = {\n        type: \"Feature\",\n        properties: {},\n        geometry: { type: \"LineString\", coordinates: archedLine(center, [center[0] + 0.06, center[1] + 0.05]) },\n      };\n      map.addSource(\"arc\", { type: \"geojson\", data: arc });\n      map.addLayer({\n        id: \"arc-glow\",\n        type: \"line\",\n        source: \"arc\",\n        paint: { \"line-color\": MAGENTA, \"line-width\": 4, \"line-blur\": 6, \"line-opacity\": 0.9 },\n      });\n      map.addLayer({\n        id: \"arc-core\",\n        type: \"line\",\n        source: \"arc\",\n        paint: { \"line-color\": \"#ffffff\", \"line-width\": 1.2 },\n      });\n\n      // pulsing pin\n      const el = document.createElement(\"div\");\n      el.className = \"neon-pin\";\n      new maplibregl.Marker({ element: el }).setLngLat(center).addTo(map);\n    });\n\n    // resize when the container becomes visible / changes size\n    const ro = new ResizeObserver(() => map.resize());\n    ro.observe(ref.current);\n\n    return () => {\n      ro.disconnect();\n      map.remove();\n      mapRef.current = null;\n    };\n  }, [center, zoom]);\n\n  return <div ref={ref} className=\"h-full w-full\" />;\n}\n",
      "type": "registry:component",
      "target": "components/prism/NeonMap.tsx"
    }
  ]
}