본문으로 건너뛰기
cccskills
무료GitHub에 공개

web-maps-mapbox

Mapbox GL JS interactive vector maps. Use when building a map with sources and layers, expressions, clustering, 3D terrain, geocoding or directions.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

설치 방법 보기

포함된 파일(6)

  • SKILL.md14.6 KB
  • examples/core.md10.2 KB
  • examples/interaction.md10.6 KB
  • examples/layers.md12.9 KB
  • metadata.yaml497 B
  • reference.md9.9 KB

SKILL.md(원문)

설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.

Mapbox GL JS Patterns

Quick Guide: Mapbox GL JS renders vector tiles on the GPU, and the whole mental model is sources hold data, layers visualize them, expressions make the visualization data-driven. One source can feed several layers, and a layer's appearance is decided by a JSON expression rather than by JavaScript touching features. Everything that adds data waits for the style — load or style.load — because the map has no style at construction. Clustering is a flag on a GeoJSON source, not a plugin. Current: v3, where the Standard style is the default and custom layers are placed into named slots rather than before a layer id.

Detailed Resources:

  • examples/core.md — map setup and cleanup, markers, popups, controls, camera animation, feature-state hover, custom controls
  • examples/layers.md — sources, every layer type, expressions, filters, clustering, safe removal
  • examples/interaction.md — 3D terrain, fog, fill-extrusion, heatmaps, geocoder and directions plugins, queryRenderedFeatures, image sources
  • reference.md — v3 migration, slots and configuration, layer and source tables, the full expression operator list, event table, performance tuning

Which path applies

  • The Standard style (v3's default, mapbox://styles/mapbox/standard) — place custom layers with slot: "bottom" | "middle" | "top", and change the basemap's own appearance through setConfigProperty rather than by editing its layers.
  • A classic or custom style — there are no slots; addLayer(layer, beforeId) positions a layer relative to an existing one, which means reading map.getStyle().layers to find the id.
  • Terrain, fog or anything that must survive a style switch — register it on style.load, which fires again on every setStyle, rather than on load, which fires once. See examples/interaction.md.

<critical_requirements>

Before writing Mapbox GL JS code

Add a source before any layer that references it. A layer naming a source that does not exist throws, and layers cannot be reordered around that.

Do source and layer work inside a load or style.load handler. The map has no style when the constructor returns, so addSource immediately after new mapboxgl.Map() fails with "Style is not done loading".

Call map.remove() when the map goes away. It releases the WebGL context, and browsers cap how many can exist at once — a leaked map makes the next one fail to initialize.

Style with expressions rather than by looping over features. An expression runs on the GPU for every feature at once; a JavaScript loop that sets styles individually gives up the rendering model the library exists for.

Put untrusted content through setText() or setDOMContent(). Popup.setHTML() renders what it is given without sanitizing it.

</critical_requirements>


Auto-detection: Mapbox, mapbox-gl, mapboxgl, mapboxgl.Map, mapboxgl.Marker, mapboxgl.Popup, NavigationControl, GeolocateControl, ScaleControl, addSource, addLayer, setPaintProperty, setLayoutProperty, setFilter, setFeatureState, queryRenderedFeatures, querySourceFeatures, getClusterExpansionZoom, fill-extrusion, raster-dem, setTerrain, setFog, setConfigProperty, mapbox://styles/mapbox/standard, @mapbox/mapbox-gl-geocoder, @mapbox/mapbox-gl-directions, @mapbox/mapbox-gl-draw

Applies to:

  • Interactive vector maps with custom styling
  • Point, line and polygon data styled from its own properties
  • Markers, popups and map controls, including custom ones through IControl
  • Large datasets through clustering, heatmaps and GPU-rendered layers
  • 3D — terrain, fog, extruded buildings
  • Camera animation and layer-scoped event handling
  • The Standard style's slot system and configuration API

Handled elsewhere:

  • Where the GeoJSON comes from — a source takes an object or a URL, and fetching, caching and paging it are not the map's concern
  • Sanitizing content before it reaches setHTML — the popup renders raw markup and cleans nothing
  • Provisioning and restricting the access token — the map reads a token, and where it is stored and what it is scoped to is a deployment decision
  • How markers, popups and controls look — the library supplies elements and class names, and the CSS in them is settled by whatever owns styling
  • Rendering a map as a static image server-side — this is a WebGL client

<philosophy>

Sources, layers, expressions, and the separation between them is the point:

  1. Sources hold data — GeoJSON, vector tiles, raster tiles, elevation, images
  2. Layers decide how a source is drawn — fill, line, circle, symbol, fill-extrusion, heatmap, raster
  3. Expressions make a layer data-driven — colour by property, size by zoom, filter by attribute

So one GeoJSON source can be a fill layer and a line layer at once, and restyling is a change to a layer's paint properties with the data untouched.

Styling is declarative and runs on the GPU. An expression is a JSON array evaluated per feature per frame by the renderer, which is why the same expression costs the same on ten features and on a hundred thousand.

The style is a document the map loads, and the Standard style in v3 is a live one: slots are the insertion points it publishes for your layers, and setConfigProperty is how you change what it draws without knowing what is inside it.

</philosophy>

<decision_framework>

Which layer type

Points
├─ Fewer than ~100, with custom HTML?   → Markers (DOM elements)
├─ Many, or styled from data?           → circle layer, or symbol for icons and labels
└─ Density rather than individuals?     → heatmap layer

Lines and routes                        → line layer
Polygons
├─ Flat areas?                          → fill layer
└─ Extruded?                            → fill-extrusion layer
Imagery                                 → raster layer

Which source type

GeoJSON, local or from an API   → type: "geojson"; setData() to replace, cluster: true past ~500 points
A tileset or third-party tiles  → type: "vector"; every layer needs "source-layer"
Elevation                       → type: "raster-dem", consumed by setTerrain
A georeferenced image           → type: "image", with its four corner coordinates

Markers or a circle layer

< 100, needing custom HTML or their own interaction   → Markers
100 – 10,000                                          → circle layer
10,000+                                               → circle layer, cluster: true on the source

Which expression

Same for every feature?         → a literal paint value
Discrete categories?            → "match"
A continuous range?             → "interpolate"
Conditional logic?              → "case"
Changing with zoom?             → "interpolate" over ["zoom"]
Hover or selection state?       → "case" over ["feature-state", ...], updated by setFeatureState

</decision_framework>


<patterns>

Core patterns

Pattern 1: Map initialization

import mapboxgl from "mapbox-gl";
import "mapbox-gl/dist/mapbox-gl.css";

mapboxgl.accessToken = process.env.MAPBOX_ACCESS_TOKEN!;

const map = new mapboxgl.Map({
  container: "map", // element id or the element itself
  style: "mapbox://styles/mapbox/standard",
  center: [-74.006, 40.7128], // [lng, lat]
  zoom: 12,
});

map.on("load", () => {
  // sources and layers from here
});

Full code, including teardown: examples/core.md


Pattern 2: Markers, popups and controls

A Marker is a DOM element pinned to a coordinate; a Popup is content anchored to one.

const popup = new mapboxgl.Popup({ offset: 25 }).setText("Description");

new mapboxgl.Marker({ color: "#e74c3c" })
  .setLngLat([-74.006, 40.7128])
  .setPopup(popup)
  .addTo(map);

map.addControl(new mapboxgl.NavigationControl(), "top-right");

Binding the popup to the marker is what makes it open and close on click without a handler.

Full code: examples/core.md


Pattern 3: Sources and layers

Add the source once; add as many layers over it as the visualization needs.

map.on("load", () => {
  map.addSource("parks", { type: "geojson", data: parksGeoJSON });

  map.addLayer({
    id: "parks-fill",
    type: "fill",
    source: "parks",
    slot: "middle", // Standard style placement
    paint: { "fill-color": "#2ecc71", "fill-opacity": 0.5 },
  });

  map.addLayer({
    id: "parks-outline",
    type: "line",
    source: "parks",
    slot: "middle",
    paint: { "line-color": "#27ae60", "line-width": 2 },
  });
});

Full code: examples/layers.md


Pattern 4: Data-driven styling with expressions

An expression is a JSON array the renderer evaluates per feature.

paint: {
  "circle-radius": ["interpolate", ["linear"], ["get", "population"],
    10_000, 5, 1_000_000, 30],
  "circle-color": ["match", ["get", "type"],
    "capital", "#e74c3c",
    "major", "#3498db",
    "#95a5a6"],  // the fallback is required, and covers missing properties
}

Full operator list in reference.md. Full code: examples/layers.md


Pattern 5: Clustering

Clustering is a property of the source, and the three layers over it split by whether a feature is a cluster.

map.addSource("earthquakes", {
  type: "geojson",
  data: "/data/earthquakes.geojson",
  cluster: true,
  clusterMaxZoom: 14,
  clusterRadius: 50,
});

The source then adds point_count and cluster_id to every cluster feature, which is what filter: ["has", "point_count"] selects on.

Full code, all three layers and click-to-expand: examples/layers.md


Pattern 6: Camera animation

map.flyTo({ center: [-122.4194, 37.7749], zoom: 15, essential: true });
map.easeTo({ center, zoom, duration: 2000, bearing: 45, pitch: 60 });
map.fitBounds([sw, ne], { padding: 50 });

flyTo arcs, easeTo is a direct transition, and fitBounds derives the camera from data extent. essential: true makes the animation ignore prefers-reduced-motion, so it belongs on navigation the user asked for and nowhere else.

Full code: examples/core.md


Pattern 7: Layer-scoped events

Passing a layer id scopes the handler to features in that layer and puts them on the event.

map.on("click", "parks-fill", (e) => {
  const feature = e.features?.[0];
  if (!feature) return;
  new mapboxgl.Popup()
    .setLngLat(e.lngLat)
    .setText(feature.properties?.name ?? "")
    .addTo(map);
});

map.on(
  "mouseenter",
  "parks-fill",
  () => (map.getCanvas().style.cursor = "pointer"),
);
map.on("mouseleave", "parks-fill", () => (map.getCanvas().style.cursor = ""));

Without the cursor change nothing tells the user the feature is clickable.

Full code, including feature-state hover: examples/core.md


Pattern 8: 3D terrain and fog

Elevation is a raster-dem source consumed by setTerrain; fog is what makes the horizon read as distance rather than as a cut-off.

map.on("style.load", () => {
  map.addSource("mapbox-dem", {
    type: "raster-dem",
    url: "mapbox://mapbox.mapbox-terrain-dem-v1",
    tileSize: 512,
    maxzoom: 14,
  });
  map.setTerrain({ source: "mapbox-dem", exaggeration: 1.5 });
  map.setFog({ range: [-1, 2], "horizon-blend": 0.3, color: "white" });
});

style.load rather than load, so terrain survives a setStyle.

Full code: examples/interaction.md


Pattern 9: Standard style configuration

Change what the basemap draws without replacing it or reaching into its layers.

new mapboxgl.Map({
  style: "mapbox://styles/mapbox/standard",
  config: {
    basemap: { lightPreset: "dusk", showPointOfInterestLabels: false },
  },
});

map.setConfigProperty("basemap", "lightPreset", "night");

Full property list in reference.md.

</patterns>

<red_flags>

Red flags

Breaks at runtime:

  • addSource/addLayer called before the style loads — "Style is not done loading" — move them into a load or style.load handler
  • A layer naming a source that has not been added — throws — add the source first
  • map.getSource(id) used without a guard — it returns undefined for an unknown id — check it, and narrow on source.type before calling setData
  • removeSource before removeLayer — a source cannot be removed while a layer references it — remove the layers first
  • No map.remove() on unmount — leaks the WebGL context, and browsers cap how many can exist, so a later map silently fails to initialize
  • Popup.setHTML() with user input — the content is rendered unsanitized — use setText(), or setDOMContent() with elements you built
  • A fill-extrusion layer with no fill-extrusion-height — the extrusions render flat, so the layer looks like it is not working

Surprising behaviour:

  • Coordinates are [longitude, latitude], the reverse of the [lat, lng] order most mapping code uses — a swapped pair lands in the wrong hemisphere rather than erroring
  • queryRenderedFeatures only sees what is currently drawn in the viewport; querySourceFeatures reaches the rest
  • setData() replaces the entire dataset and re-parses it — for visual state per feature use setFeatureState instead
  • style.load fires on every setStyle; load fires once — anything that has to survive a style switch belongs on the first
  • An expression reading a missing property yields null, so match, case and coalesce need their fallback branch
  • essential: true overrides prefers-reduced-motion — correct for navigation, wrong for decoration
  • A clustered source writes point_count and cluster_id onto cluster features; do not add properties by those names
  • getClusterExpansionZoom answers through a callback, so handle its error and check the map still exists before animating
  • slot is ignored outside the Standard style — a classic style positions layers with beforeId
  • Markers past a hundred or so points are DOM elements and cost like DOM elements; a circle layer renders on the GPU
  • map.on("click", handler) with no layer id fires on every click anywhere on the map, including clicks the user meant for a feature
  • @types/mapbox-gl is a deprecated stub — types ship inside mapbox-gl from v3

</red_flags>

리뷰

아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.

댓글

로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.

아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.

보내면 바로 공개됩니다. 이메일 주소나 전화번호 같은 개인 정보는 쓰지 마세요. URL은 2개까지입니다.

0 / 1,000자

이 양식은 reCAPTCHA로 보호되며 Google 개인정보처리방침 및 서비스 약관이 적용됩니다.

같은 저장소의 스킬

Hugging Face Inference SDK patterns for TypeScript/Node.js — InferenceClient setup, chat completion, text generation, streaming, embeddings, image generation, audio transcription, translation, summarization, and Inference Endpoints

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

agents-inc/skills252026년 10월 17일 업데이트

LiteLLM proxy server setup, TypeScript client patterns via OpenAI SDK, model routing, fallbacks, load balancing, spend tracking, virtual keys, and production deployment

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

agents-inc/skills252026년 10월 17일 업데이트

Serverless GPU compute platform for AI model deployment — web endpoints, GPU functions, model serving, and TypeScript client patterns

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

agents-inc/skills252026년 10월 17일 업데이트

Local LLM inference with the Ollama JavaScript client -- chat, streaming, tool calling, vision, embeddings, structured output, model management, and OpenAI-compatible endpoint

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

agents-inc/skills252026년 10월 17일 업데이트

Replicate SDK patterns for TypeScript/Node.js -- client setup, predictions, streaming, webhooks, file handling, model versioning, deployments, and training

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

agents-inc/skills252026년 10월 17일 업데이트

Together AI SDK patterns for TypeScript — client setup, chat completions, streaming, structured output, function calling, embeddings, image generation, fine-tuning, and OpenAI-compatible endpoints

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

agents-inc/skills252026년 10월 17일 업데이트

agents-inc의 스킬 모두 보기

이 스킬의 문제 신고