Skip to content

ohwhen/CobeKit

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

CobeKit

CobeKit demo

A pure Swift/Metal port of cobe — the lightweight WebGL globe library by Shu Ding. Renders a beautiful interactive 3D globe with dotted land masses, markers, and arcs, all running on the GPU via Metal shaders.

Credit: This project is a faithful port of cobe's rendering pipeline to Apple's Metal framework. The Fibonacci lattice dot algorithm, rotation math, and world map texture are directly derived from cobe. All credit for the original concept and implementation goes to Shu Ding and the cobe contributors.

Features

  • Metal GPU rendering — Fibonacci lattice dot algorithm ported from cobe's GLSL shaders
  • Cobe's actual world map — the same base64-encoded equirectangular PNG texture
  • Markers — glowing circles at geographic coordinates with back-face culling
  • Arcs — quadratic Bezier curves connecting two points, elevated above the surface
  • Drag to rotate — pan gesture with momentum/inertia and auto-rotation
  • Dark & light modes — matching cobe's dark parameter for both aesthetics
  • SwiftUI native — simple GlobeView(configuration:) API
  • Cross-platform — iOS 16+ and macOS 13+
  • Zero dependencies — pure Swift Package, no external libraries
  • Runtime shader compilation — no .metal files needed, works with SPM out of the box

Quick Start

Swift Package Manager

Add to your Package.swift dependencies:

.package(url: "https://github.com/ohwhen/CobeKit.git", from: "1.0.0")

Or in Xcode: File → Add Package Dependencies → paste the repo URL.

Usage

import SwiftUI
import CobeKit

struct ContentView: View {
    @State private var config = GlobeConfiguration()

    var body: some View {
        GlobeView(configuration: $config)
            .frame(width: 400, height: 400)
            .onAppear {
                config.theta = 0.3
                config.dark = 1.0
                config.baseColor = SIMD3(0.3, 0.3, 0.6)
                config.glowColor = SIMD3(0.1, 0.1, 0.6)
            }
    }
}

Adding Markers

config.markers = [
    GlobeMarker(location: SIMD2(40.71, -74.01), size: 0.08, color: SIMD3(1, 0.5, 0.1)),  // NYC
    GlobeMarker(location: SIMD2(51.51, -0.13), size: 0.06, color: SIMD3(1, 0.5, 0.1)),   // London
    GlobeMarker(location: SIMD2(35.68, 139.69), size: 0.07, color: SIMD3(1, 0.5, 0.1)),  // Tokyo
]

Adding Arcs

config.arcs = [
    GlobeArc(from: SIMD2(40.64, -73.78), to: SIMD2(51.47, -0.46), color: SIMD3(0.3, 0.7, 1)),  // JFK → LHR
    GlobeArc(from: SIMD2(51.47, -0.46), to: SIMD2(25.25, 55.36), color: SIMD3(0.3, 0.7, 1)),   // LHR → DXB
]

Configuration

Property Type Default Description
phi Float 0 Horizontal rotation (radians)
theta Float 0.3 Vertical tilt (radians)
mapSamples Float 16000 Number of dots on the globe
mapBrightness Float 6.0 Dot brightness multiplier
mapBaseBrightness Float 0.05 Minimum dot brightness (ocean visibility)
baseColor SIMD3<Float> (0.3, 0.3, 0.6) Globe surface color
glowColor SIMD3<Float> (0.3, 0.3, 0.8) Atmospheric glow color
markerColor SIMD3<Float> (1.0, 0.5, 0.2) Default marker color
arcColor SIMD3<Float> (0.3, 0.6, 1.0) Default arc color
diffuse Float 1.2 Diffuse lighting intensity
dark Float 1.0 Dark mode (1.0) vs light mode (0.0)
opacity Float 1.0 Globe opacity
scale Float 1.0 Zoom factor
autoRotateSpeed Float 0.005 Auto-rotation speed (0 to disable)
dragEnabled Bool true Enable drag-to-rotate gesture

Examples

The Example/ directory contains a full iOS app with 5 demo tabs:

  1. Dark Globe — classic dark blue cobe aesthetic
  2. Neon — cyberpunk hot pink glow with green base
  3. Markers — 10 city markers with tap-to-rotate
  4. Flights — airport markers with arc connections (SFO → JFK → AMS → DXB → SYD)
  5. Whop — branded landing page hero with animated entrance

Running the Example

cd Example
xcodegen generate   # requires xcodegen
open CobeKitExample.xcodeproj

Then select an iPhone simulator and run.

Architecture

Sources/CobeKit/
├── GlobeView.swift            # SwiftUI wrapper + drag/inertia coordinator
├── GlobeRenderer.swift        # Metal renderer (MTKViewDelegate)
├── GlobeConfiguration.swift   # Public config API, markers, arcs
└── ShaderSource.swift         # Metal shaders (compiled at runtime)

Rendering Pipeline

Three Metal render passes per frame, matching cobe's WebGL architecture:

  1. Globe pass — full-screen triangle, fragment shader does ray-sphere intersection + Fibonacci lattice dot placement + texture lookup + lighting/glow
  2. Marker pass — instanced quads positioned at geographic coordinates, back-face culled
  3. Arc pass — instanced triangle strips along quadratic Bezier curves

Metal vs WebGL

The main porting challenge was Metal's fragment coordinate system (y=0 at top) vs WebGL's (y=0 at bottom). This affects:

  • The globe's view-space Y direction (inverted in Metal)
  • Marker/arc vertex shaders need to negate Y when converting view-space → clip-space
  • Vertical drag direction is negated to compensate

Acknowledgments

This project would not exist without cobe by Shu Ding. The Fibonacci lattice algorithm, van der Corput bit-reversal sequence, rotation math, lighting model, and world map texture are all faithfully ported from cobe's original GLSL shaders. Thank you for creating such an elegant and beautiful library.

License

MIT

About

A pure Swift/Metal port of cobe — interactive 3D globe with dotted land masses, markers, and arcs for iOS & macOS

Topics

Resources

License

Stars

Watchers

Forks

Contributors

Languages