Vibes DIY
Vibes DIY / Docs / Reference
creator docs · reference · generated

Maps — a world overview that opens with the app

This is the same document the Vibes code generator reads when it builds apps — rendered from prompts/pkg/llms/maps.md on every deploy, so it can't drift from what the platform actually does. Read it from your terminal any time with npx vibes-diy skills.

For world maps, travel journals, country comparisons and territory games, import shapes and geometry from @vibes.diy/geo. The platform bundles the data and geometry together. Draw the outlines on the first render. Keep the person's reply about what they can see and do: “Your places now appear on the world map.”

Use the platform geometry module for world outlines. The package exports countries and land as GeoJSON FeatureCollections, plus geoNaturalEarth1, geoPath, geoContains, geoDistance and geoArea. Coordinates are always [longitude, latitude]. Each country has properties.name and usually a numeric ISO ID string, such as "250" for France. Preserve IDs as strings. A few disputed or unassigned areas lack IDs; use the name as the key fallback.

Fit the projection to the sphere so every result uses the same world frame. Use theme-token fills and strokes, a responsive viewBox, and a visible legend. Match the highlighted countries to the places the person requested. Offer an ordinary country/place button list alongside the map so small islands and keyboard users can select the same results. Country geometry is already oriented for D3; keep its rings intact.

jsximport React, { useState } from "react";
import { Button } from "@vibes.diy/pouf";
import { countries, geoNaturalEarth1, geoPath } from "@vibes.diy/geo";

const projection = geoNaturalEarth1().fitExtent([[12, 12], [788, 408]], { type: "Sphere" });
const path = geoPath(projection);
// Connect these IDs to the app's real saved or computed results.
const matchingIds = new Set(["250", "392"]);

export default function App() {
  const [selected, setSelected] = useState(null);
  const matches = countries.features.filter(country => matchingIds.has(country.id));
  return <section className="space-y-4">
    <h2 className="text-xl font-semibold">Your places around the world</h2>
    <svg viewBox="0 0 800 420" className="w-full" role="img" aria-label="World map of matching countries">
      <path d={path({ type: "Sphere" })} className="fill-card stroke-border" />
      {countries.features.map(country => <path
        key={country.id || country.properties.name}
        d={path(country)}
        className={matchingIds.has(country.id) ? "fill-primary stroke-border cursor-pointer" : "fill-muted stroke-border"}
        onClick={matchingIds.has(country.id) ? () => setSelected(country.properties.name) : undefined}
      ><title>{country.properties.name}</title></path>)}
    </svg>
    <p className="text-sm"><span className="inline-block size-3 rounded-full bg-primary" /> Matching countries</p>
    <div className="flex flex-wrap gap-2">{matches.map(country =>
      <Button key={country.id} tone="info" variant="quiet"
        onClick={() => setSelected(country.properties.name)}>{country.properties.name}</Button>
    )}</div>
    <p aria-live="polite">{selected || "Choose a matching country to see its details."}</p>
    <p className="text-xs text-muted-foreground">Map data: Natural Earth</p>
  </section>;
}

For place markers, project the saved coordinates with projection([lng, lat]) and draw SVG circles at the resulting x/y. Give every marker a name and a corresponding accessible place button. A country can be found with countries.features.find(country => geoContains(country, [lng, lat])). At 1:110m resolution, small islands and coastal points may fall outside simplified polygons: retain the place marker and saved country association. A nearest-country or distance guess is not a reliable country assignment. Choropleths join to country IDs and display the units and range in their legend; missing data has its own fill and label.

World outlines come with the app; no runtime shape fetch is needed. The data is generalized Natural Earth 4.1.0 via world-atlas 2.0.2. It is appropriate for world overviews. Street-level zoom, routes and address lookup need a separate map provider with its own coverage, credentials and attribution. Keep that choice separate from a request to show results on a world map.

Verify the first preview at phone width: outlines, matching fills and place markers appear, tapping a result opens its details, the legend is readable, and no third-party shape or tile request occurs. A map is complete when the preview shows those results; the person does not need to arrange a data download.