cobe Documentation

TypeScript library by @shuding focused on globe, webgl. Includes documentation and AI agent context with 6.0k stars.

5,991 stars TypeScript TypeScript 1 file ยท ~1,452 tokens #globe#webgl
RAW Doc

File: README.md


Quick Start

html
<canvas
  id="cobe"
  style="width: 500px; height: 500px;"
  width="1000"
  height="1000"
></canvas>
js
import createGlobe from 'cobe'

let phi = 0
let canvas = document.getElementById("cobe")

const globe = createGlobe(canvas, {
  devicePixelRatio: 2,
  width: 1000,
  height: 1000,
  phi: 0,
  theta: 0,
  dark: 0,
  diffuse: 1.2,
  scale: 1,
  mapSamples: 16000,
  mapBrightness: 6,
  baseColor: [0.3, 0.3, 0.3],
  markerColor: [1, 0.5, 1],
  glowColor: [1, 1, 1],
  offset: [0, 0],
  markers: [
    { location: [37.7595, -122.4367], size: 0.03 },
    { location: [40.7128, -74.006], size: 0.1, color: [1, 0, 0] }, // custom color
  ],
  arcs: [
    {
      from: [37.7595, -122.4367],
      to: [40.7128, -74.006],
      color: [1, 0.5, 0.5], // custom color (optional)
    },
  ],
  arcColor: [1, 0.5, 1],
  arcWidth: 0.5,
  arcHeight: 0.3,
  markerElevation: 0.02,
  onRender: (state) => {
    // Called on every animation frame.
    // `state` will be an empty object, return updated params.
    state.phi = phi
    phi += 0.01
  },
})

// To destroy the instance and bindings:
// `globe.destroy()`

Arcs

Arcs connect two locations on the globe:

js
arcs: [
  {
    from: [37.7595, -122.4367],
    to: [35.6762, 139.6503],
    color: [1, 0.5, 0.5], // optional, uses arcColor if not set
  },
]

Bindable Markers & Arcs

Markers and arcs can have an id property for CSS Anchor Positioning:

js
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' },
]
css
.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);
}

The globe exposes:

  • --cobe-{id} / --cobe-arc-{id} โ€” CSS anchor names for positioning
  • --cobe-visible-{id} / --cobe-visible-arc-{id} โ€” visibility variable (0 when behind globe, 1 when visible)

Use the visibility variable to drive opacity, blur, scale, or any CSS property for smooth transitions.

Acknowledgment

This project is inspired & based on the great work of:

World map asset from:

License

The MIT License.


File: package.json

{
"name": "cobe",
"version": "2.0.1",
"type": "module",
"main": "./dist/index.esm.js",
"files": [
"dist/**"
],
"types": "./dist/index.d.ts",
"repository": "shuding/cobe",
"license": "MIT",
"scripts": {
"build": "node scripts/build.js && cp src/index.d.ts dist/index.d.ts",
"chrome:debug": "open -na "Google Chrome" --args --new-window --disable-frame-rate-limit --user-data-dir="/tmp/chrome_dev_session" --disable-web-security http://localhost:3000/playground"
},
"devDependencies": {
"esbuild": "^0.13.14",
"glslx": "^0.3.0",
"next": "^12.2.4",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"terser": "^5.46.0",
"typescript": "^4.5.4"
},
"packageManager": "[email protected]+sha512.1d61f8c10e8a5a5dbfbddea0f1f5efb7dbd5177223073aec953cf230aa46416884b9427a6421dba78f28ad0f93fbede38ba57083237b350243de6b1e3a8ce71d"
}


File: pnpm-workspace.yaml

packages:

  • 'website'

File: tsconfig.json

{
"compilerOptions": {
"target": "ES2018",
"lib": ["ESNext", "DOM"],
"module": "CommonJS",
"moduleResolution": "Node",
"strict": true,
"forceConsistentCasingInFileNames": true,
"noImplicitReturns": true,
"noUnusedParameters": true,
"resolveJsonModule": true,
"allowJs": true,
"declaration": true,
"sourceMap": true,
"outDir": "dist",
"rootDir": "src"
},
"exclude": ["dist", "node_modules", "scripts"]
}


File: website/package.json

{
"name": "cobe-site",
"version": "1.0.0",
"description": "",
"dependencies": {
"cobe": "workspace:*",
"geist": "^1.4.1",
"leva": "^0.9.34",
"next": "^16.1.6",
"react": "^18.0.0",
"react-dom": "^18.0.0",
"react-spring": "^9.4.4",
"sugar-high": "^0.9.5"
},
"devDependencies": {
"@types/react": "^18.0.0",
"@types/react-dom": "^18.0.0",
"typescript": "^5.0.0"
},
"scripts": {
"build": "next build",
"dev": "next dev",
"start": "next start"
},
"author": "Shu Ding [email protected]",
"license": "MIT"
}


File: website/tsconfig.json

{
"compilerOptions": {
"target": "ES2017",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "react-jsx",
"incremental": true,
"plugins": [
{
"name": "next"
}
]
},
"include": [
"next-env.d.ts",
"/*.ts",
"
/.tsx",
".next/types/**/
.ts",
".next/dev/types/**/*.ts"
],
"exclude": [
"node_modules"
]
}