Canvas

Globe

A Fresnel-lit globe with rim glow, haloed atmosphere, land mesh detail, and marker layers for data storytelling.


Installation

Install the component

Run the following command to install the component and its dependencies:
npx @motion-core/cli add globe

Import the component

Import the component into your Svelte file:
import { Globe } from "$lib/motion-core";
import { Globe } from "$lib/motion-core";

Usage

<script lang="ts">
	import {
		Globe,
		type GlobeMarker,
		type GlobeMarkerTooltipContext,
	} from "motion-core";
	import { cn } from "$lib/utils/cn";

	const locations: (GlobeMarker & { name: string })[] = [
		{
			name: "Warsaw",
			location: [52.2297, 21.0122],
			label: "Warsaw",
			color: "#4fb7ff",
		},
		{
			name: "New York",
			location: [40.7128, -74.006],
			label: "New York",
			color: "#4fb7ff",
		},
		{
			name: "Tokyo",
			location: [35.6762, 139.6503],
			label: "Tokyo",
			color: "#4fb7ff",
		},
	];

	let focusOn = $state<[number, number] | null>(null);
</script>

{#snippet markerTooltip(ctx: GlobeMarkerTooltipContext)}
	<div
		class="pointer-events-none relative rounded-xs bg-foreground px-1.5 py-0.75 font-mono text-[10px] font-medium tracking-wide whitespace-nowrap text-background uppercase"
	>
		{ctx.marker.label}
		<span
			class="absolute top-[calc(100%-1px)] left-1/2 h-0 w-0 -translate-x-1/2 border-x-[5px] border-t-[5px] border-x-transparent border-t-foreground"
		></span>
	</div>
{/snippet}

<Globe
	pointCount={25000}
	class="h-full min-h-96 w-full"
	markers={locations}
	{markerTooltip}
	{focusOn}
	autoRotate={!focusOn}
	lockedPolarAngle={false}
/>
<div
	class="absolute bottom-4 left-1/2 z-10 flex w-fit -translate-x-1/2 justify-center gap-1 rounded-sm bg-background-inset p-1 inset-shadow"
>
	<button
		class={cn(
			"gap-1.5 rounded-xs px-3 py-1 text-xs font-medium tracking-wide whitespace-nowrap uppercase transition-all duration-150 ease-out",
			focusOn === null
				? "light:text-card bg-background-muted  shadow-md card dark:text-foreground"
				: "text-foreground-muted hover:text-foreground",
		)}
		onclick={() => (focusOn = null)}
	>
		Auto Rotate
	</button>
	{#each locations as loc (loc.name)}
		<button
			class={cn(
				"gap-1.5 rounded-xs px-3 py-1 text-xs font-medium tracking-wide whitespace-nowrap uppercase transition-colors duration-150 ease-out",
				focusOn?.[0] === loc.location[0] && focusOn?.[1] === loc.location[1]
					? "light:text-card bg-background-muted  shadow-md card dark:text-foreground"
					: "text-foreground-muted hover:text-foreground",
			)}
			onclick={() => (focusOn = loc.location)}
		>
			{loc.name}
		</button>
	{/each}
</div>

Props

Globe

PropTypeDefault
radius
number 2
fresnelConfig
FresnelConfig Default Fresnel
atmosphereConfig
AtmosphereConfig Default Atmosphere
pointCount
number 15000
landPointColor
stringnumberreadonly [number, number, number]{ r: number; g: number; b: number } "#f77114"
pointSize
number 0.05
autoRotate
boolean true
lockedPolarAngle
boolean true
markers
GlobeMarker[] []
markerTooltip
Snippet<[GlobeMarkerTooltipContext]> undefined
focusOn
[number, number]null null
class
string ""

GlobeMarkerTooltipContext

KeyTypeDefault
marker
GlobeMarker -
index
number -
visibility
number -

FresnelConfig

KeyTypeDefault
color
stringnumberreadonly [number, number, number]{ r: number; g: number; b: number } "#17181A"
rimColor
stringnumberreadonly [number, number, number]{ r: number; g: number; b: number } "#FF6900"
rimPower
number 6
rimIntensity
number 1.5

AtmosphereConfig

KeyTypeDefault
color
stringnumberreadonly [number, number, number]{ r: number; g: number; b: number } "#FF6900"
scale
number 1.1
power
number 12.0
coefficient
number 0.9
intensity
number 1.1

GlobeMarker

KeyTypeDefault
location
[number, number] -
size
number 0.05
color
string "#ffffff"
label
string undefined