Skip to content
Back to skills

Map

ASecurity

Draw world and country maps with real geography: projections, highlighted countries, great-circle routes and a turning globe.

  • 21 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added October 1, 2026
ai-agentsgoreactangularawsgit

Works with

  • cli

Security analysis

A100/100

Pro scans all 2 files and shows the line behind each finding

Scanned October 1, 2026

npx -y skills add animspark/animspark --skill map --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Map?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Map
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/animspark-map/badge)](https://www.skillsdirectory.com/skills/animspark-map)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: map
description: "Draw world and country maps with real geography: projections, highlighted countries, great-circle routes and a turning globe."
---

Draw maps from real geographic data: d3-geo projections, world-atlas borders, topojson decoding.

Shapes and positions on the map come from the data, not from hand tracing; country names and numbers are laid out as page text at the positions the projection computes.

## Maps (geoPath)

| Item | Usage |
| --- | --- |
| Data | The package has no main entry; import files by subpath: `countries-110m.json` / `countries-50m.json` / `land-110m.json` / `land-50m.json`. 110m is enough for the whole world; switch to 50m only when a single country's coastline fills the frame. d3 comes as separate packages (`d3-geo` `d3-scale` `d3-shape`…); there is no whole `d3` package |
| Projection | A pure function; compute it once at module top level. Whole world: `geoNaturalEarth1` / `geoEqualEarth`; a single country: `projection.fitSize([w, h], feature)`; a globe: `geoOrthographic().rotate([-lon, -lat])`, where turning the longitude turns the globe (compute it from `t` every frame) |
| Countries | `countries.features[i].id` is the ISO 3166-1 numeric code as a **three-digit zero-padded string** (`'156'` China, `'840'` United States, `'008'` Albania; `#c-8` selects nothing and raises no error), and `properties.name` is the English name. One path per country; select it within the component's scope with `data-country={f.id}` |
| Other | Graticule `path(geoGraticule10())`; sphere `path({ type: 'Sphere' })`; a city `projection([lon, lat])` → `<circle>`; a line between two places `path({ type: 'LineString', coordinates: [[lon1, lat1], [lon2, lat2]] })` draws an arc along the great circle, drawn on stroke by stroke with DrawSVG; lay out country names and numbers in DOM at the pixel positions `projection` computes, instead of assembling small type from SVG `<text>` |

The `Example` below can go into the current MG scene as a child component.

```tsx
import world from 'world-atlas/countries-110m.json';
import * as topojson from 'topojson-client';
import { geoNaturalEarth1, geoEquirectangular, geoPath, geoGraticule10 } from 'd3-geo';
const countries = topojson.feature(world as any, (world as any).objects.countries) as any;
import { useRef } from 'react';
import { gsap } from 'gsap';
import { useGSAP } from '@gsap/react';
import { DrawSVGPlugin } from 'gsap/DrawSVGPlugin';
gsap.registerPlugin(DrawSVGPlugin);
const projection = geoNaturalEarth1().fitSize([1720, 880], countries);
const path = geoPath(projection);
const route = path({ type: 'LineString', coordinates: [[121.5, 31.2], [4.5, 51.9]] } as any) ?? '';   // Shanghai → Rotterdam, along the great circle
const [sx, sy] = projection([121.5, 31.2])!;
export function Example() {
  const ref = useRef<SVGSVGElement>(null);
  useGSAP(() => {
    gsap.timeline()
      .set('.route', { drawSVG: '0%' }, 0)
      .to('.route', { drawSVG: '100%', duration: 3, ease: 'none' }, 0);
  }, { scope: ref });
  return (
    <svg ref={ref} viewBox="0 0 1920 1080" style={{ position: 'absolute', inset: 0, width: '100%', height: '100%' }}>
      <g transform="translate(100 100)">
        <path d={path({ type: 'Sphere' } as any) ?? ''} fill="#141c30" />
        <path d={path(geoGraticule10()) ?? ''} fill="none" stroke="#2a3550" strokeWidth={0.5} />
        {countries.features.map((f: any, i: number) => <path key={`${f.id}-${i}`} data-country={f.id} d={path(f) ?? ''} fill={f.id === '156' ? '#4f7cff' : '#2a3550'} stroke="#7cd6ff" strokeWidth={0.7} />)}
        <path className="route" d={route} fill="none" stroke="#c6f24e" strokeWidth={4} />
        <circle cx={sx} cy={sy} r={8} fill="#c6f24e" />
      </g>
    </svg>
  );
}
```


Country borders come from the data version; they do not represent current disputed borders or historical borders. A historical map needs its era checked separately. A great circle is the shortest geographic line and must not pass for a real shipping route.

Files in this skill

  • SKILL.md3.9 KB
  • catalog.json266 B

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…