
COBE is a lightweight WebGL library for generating an animated 3D globe with a dotted world map on an HTML canvas.
It supports custom markers, curved arcs between locations, color and camera controls, runtime updates, and DOM labels anchored to globe positions with CSS Anchor Positioning.
Features
- About 5KB with no runtime dependencies.
- Dotted 3D world map rendered with WebGL.
- Custom markers with configurable locations, sizes, and colors.
- Curved arcs between geographic locations.
- Configurable globe colors, opacity, scale, offset, rotation, and tilt.
- Runtime state updates through the
update()method. - DOM labels and tooltips anchored to markers and arcs with CSS Anchor Positioning.
- Custom WebGL context attributes.
How to use it
Installation
Install COBE from npm.
npm install cobe
Basic usage
Add a canvas element for the globe:
<canvas id="cobe" style="width: 500px; height: 500px;" ></canvas>
Import createGlobe and pass the canvas with the globe configuration:
import createGlobe from 'cobe'
const canvas = document.getElementById('cobe')
const dpr = window.devicePixelRatio || 1
const globe = createGlobe(canvas, {
devicePixelRatio: dpr,
width: 500,
height: 500,
phi: 0,
theta: 0.2,
dark: 0,
diffuse: 1.2,
mapSamples: 16000,
mapBrightness: 6,
baseColor: [0.3, 0.3, 0.3],
markerColor: [1, 0.5, 1],
glowColor: [1, 1, 1],
markers: [
{ location: [37.7595, -122.4367], size: 0.03 },
{ location: [40.7128, -74.006], size: 0.08, color: [1, 0, 0] },
],
})Rotate and update the globe
The current public instance API uses update() for runtime state changes. A requestAnimationFrame() loop can update phi for continuous rotation:
let phi = 0
function animate() {
phi += 0.005
globe.update({ phi })
requestAnimationFrame(animate)
}
animate()You can update other runtime values after initialization:
globe.update({
theta: 0.35,
dark: 1,
scale: 0.9,
})Add arcs between locations
Use arcs to connect two latitude and longitude pairs. When changing arc geometry at runtime, set arcWidth and arcHeight before submitting the arc list.
globe.update({
arcColor: [0.3, 0.6, 1],
arcWidth: 0.5,
arcHeight: 0.3,
})
globe.update({
arcs: [
{
from: [37.7595, -122.4367],
to: [35.6762, 139.6503],
color: [1, 0.5, 0.5],
},
],
})Attach DOM labels to markers and arcs
Give a marker or arc an id to expose CSS anchors and visibility variables for labels, tooltips, and other DOM content.
globe.update({
markers: [
{
location: [37.7595, -122.4367],
size: 0.03,
id: 'sf',
},
],
arcs: [
{
from: [37.7595, -122.4367],
to: [35.6762, 139.6503],
id: 'sf-tokyo',
},
],
})A marker ID such as sf exposes --cobe-sf and --cobe-visible-sf. An arc ID such as sf-tokyo exposes --cobe-arc-sf-tokyo and --cobe-visible-arc-sf-tokyo.
.marker-label {
position: absolute;
position-anchor: --cobe-sf;
bottom: anchor(top);
left: anchor(center);
opacity: var(--cobe-visible-sf, 0);
filter: blur(calc((1 - var(--cobe-visible-sf, 0)) * 8px));
transition: opacity 0.3s, filter 0.3s;
}
.arc-label {
position: absolute;
position-anchor: --cobe-arc-sf-tokyo;
bottom: anchor(top);
left: anchor(center);
opacity: var(--cobe-visible-arc-sf-tokyo, 0);
}All Configuration Options
width(number, required): Sets the globe canvas width before device pixel ratio scaling.height(number, required): Sets the globe canvas height before device pixel ratio scaling.phi(number, required): Sets horizontal globe rotation in radians.theta(number, required): Sets vertical globe rotation in radians.mapSamples(number, required): Sets the number of samples used for the dotted map.mapBrightness(number, required): Sets the brightness of the map dots.mapBaseBrightness(number, default0): Sets a minimum brightness value for the map texture.baseColor([number, number, number], required): Sets the RGB base color of the globe.markerColor([number, number, number], required): Sets the default RGB marker color.glowColor([number, number, number], required): Sets the RGB glow color around the globe.markers(Marker[], default[]): Sets the markers rendered on the globe.diffuse(number, required): Controls diffuse lighting across the globe surface.devicePixelRatio(number, required): Sets the pixel ratio used for the canvas drawing buffer.dark(number, required): Controls the dark rendering factor.opacity(number, default1): Sets globe opacity.offset([number, number], default[0, 0]): Offsets the globe from the canvas center.scale(number, default1): Scales the rendered globe.context(WebGLContextAttributes): Overrides the WebGL context attributes used during initialization.arcs(Arc[], default[]): Sets the arcs rendered between geographic locations.arcColor([number, number, number], default[0.3, 0.6, 1]): Sets the default RGB arc color.arcWidth(number, default1): Sets the global arc width.arcHeight(number, default0.2): Sets the global arc height above the globe.markerElevation(number, default0.05): Sets marker elevation above the globe surface.
Marker properties
location([number, number], required): Latitude and longitude in degrees.size(number, required): Marker size.color([number, number, number]): OverridesmarkerColorfor this marker.id(string): Creates CSS anchor and visibility variables for the marker.
Arc properties
from([number, number], required): Starting latitude and longitude in degrees.to([number, number], required): Ending latitude and longitude in degrees.color([number, number, number]): OverridesarcColorfor this arc.id(string): Creates CSS anchor and visibility variables for the arc.
API Methods
update(state): Updates runtime state values handled by the instance and renders the globe again.destroy(): Deletes the instance’s WebGL buffers and programs and removes generated anchor elements.
Related Resources
- Interactive SVG World Map Library
- SVG World Map With Countries, Provinces, And States
- jsvectormap: JavaScript Library For Interactive Vector Maps
- JavaScript & CSS World Map Resources
Changelog
v2 (09/19/2026)
- Updated







