COBE: The 5KB WebGL globe
Add cobe@latest (https://cobe.vercel.app) to my app.Copyimport createGlobe from 'cobe'
const globe = createGlobe(canvas, {
devicePixelRatio: 2,
width: 600 * 2,
height: 600 * 2,
phi: 0,
theta: 0.2,
dark: 0,
diffuse: 1.2,
mapSamples: 16000,
mapBrightness: 6,
baseColor: [1, 1, 1],
markerColor: [0.2, 0.4, 1],
glowColor: [1, 1, 1],
markers: [
{ location: [37.78, -122.44], size: 0.03, id: 'sf' },
{ location: [40.71, -74.01], size: 0.03, id: 'nyc' },
],
arcs: [
{ from: [37.78, -122.44], to: [40.71, -74.01] },
],
arcColor: [0.3, 0.5, 1],
arcWidth: 0.5,
arcHeight: 0.3,
})
// Animate the globe
let phi = 0
function animate() {
phi += 0.005
globe.update({ phi })
requestAnimationFrame(animate)
}
animate()Works with any framework: React, Vue, Svelte, or vanilla JS.
createGlobe(canvas, options) returns an object with update() and destroy() methods.
widthnumberrequiredheightnumberrequiredphinumberrequiredthetanumberrequireddarknumberrequireddiffusenumberrequiredmapSamplesnumberrequiredmapBrightnessnumberrequiredmapBaseBrightnessnumberbaseColor[r,g,b]markerColor[r,g,b]glowColor[r,g,b]markersMarker[]arcsArc[]arcColor[r,g,b]arcWidthnumberarcHeightnumbermarkerElevationnumberscalenumberoffset[x,y]opacitynumberdevicePixelRationumbercontextWebGLContextAttributesupdate(state)functiondestroy()functionconst globe = createGlobe(canvas, { phi: 0, ... })
let phi = 0
function animate() {
phi += 0.005 // Adjust speed as needed
globe.update({ phi })
requestAnimationFrame(animate)
}
animate()Call globe.update() in a requestAnimationFrame loop for continuous rotation. Use smaller values (0.001-0.003) for subtle movement, larger values (0.01+) for faster spins.
markers: [
// Basic marker
{ location: [37.78, -122.44], size: 0.03 },
// With custom color (RGB 0-1)
{ location: [51.51, -0.13], size: 0.05, color: [1, 0, 0] },
// With id for CSS anchoring
{ location: [35.68, 139.65], size: 0.04, id: 'tokyo' }
]Place dots on the globe using [latitude, longitude]. Size is relative to globe radius (0.01-0.1). Colors override the global markerColor.
Use CSS Anchor Positioning to attach labels, tooltips, or any DOM element to markers and arcs.
// 1. Define markers with IDs
const markers = [
{ id: 'sf', location: [37.78, -122.44], label: 'San Francisco' },
{ id: 'tokyo', location: [35.68, 139.65], label: 'Tokyo' },
]
// 2. Pass to COBE (label is your custom property)
createGlobe(canvas, {
markers: markers.map(m => ({
location: m.location, size: 0.03, id: m.id
})),
})
// 3. Render labels anchored to markers
{markers.map(m => (
<div
key={m.id}
className="marker-label"
style={{
positionAnchor: `--cobe-${m.id}`,
opacity: `var(--cobe-visible-${m.id}, 0)`
}}
>
{m.label}
</div>
))}.marker-label {
position: absolute;
bottom: anchor(top);
left: anchor(center);
translate: -50% 0;
margin-bottom: 8px;
padding: 0.25rem 0.5rem;
background: #1a1a1a;
color: #fff;
font-size: 0.75rem;
border-radius: 4px;
white-space: nowrap;
pointer-events: none;
transition: opacity 0.3s;
}COBE creates --cobe-{id} anchor and --cobe-visible-{id} visibility variable for each marker with an ID. The visibility is 1 when facing the camera, 0 when hidden.
Experiment with different options in real-time. Adjust the controls below to see how they affect the globe.