An interactive globe that detects a visitor's timezone, language and location — so your app greets them right from the first second.
npm i @planetlogin/planetlogin Why PlanetLogin
One pick on a real 3D globe and you know who just arrived — no IP lookups, no consent banners, no third-party SDK.
Orthographic projection via d3-geo — proper hemisphere clipping, drag with inertia, wheel zoom, click a country.
Returns IANA timezone, BCP-47 language and ISO country from a single pick. ~150 countries mapped to a language.
Keyless geocoding (Open-Meteo + OSM Nominatim). No analytics, no cookies beyond your own. AGPL-3.0.
Ships as a standard Web Component, a class and a factory. React, Vue, Svelte, Angular or plain HTML. ~17 kB gzip.
Keyboard-controllable globe (arrows, +/-, Enter), focus ring, ARIA labels, and respects prefers-reduced-motion.
Typed API, ESM + UMD builds, and a tiny readable codebase you can fork and own.
Quickstart
Listen for one locale event and wire it into your i18n and date handling.
import '@planetlogin/planetlogin'; <!-- anywhere in your HTML --> <planet-login accent="#f6a13c"></planet-login> const el = document.querySelector('planet-login'); el.addEventListener('locale', (e) => { const { language, timezone, country } = e.detail; i18n.setLanguage(language); });
import { useEffect, useRef } from 'react'; import { createPlanetLogin } from '@planetlogin/planetlogin'; function GlobeLogin({ onLocale }) { const ref = useRef(null); useEffect(() => { const g = createPlanetLogin(ref.current, { onLocale }); return () => g.destroy(); }, []); return <div ref={ref} style={{ height: 440 }} />; }
import { onMounted, onBeforeUnmount, ref } from 'vue'; import { createPlanetLogin } from '@planetlogin/planetlogin'; const el = ref(); let g; onMounted(() => { g = createPlanetLogin(el.value, { onLocale: l => emit('locale', l) }); }); onBeforeUnmount(() => g?.destroy());
import { onDestroy } from 'svelte'; import { createPlanetLogin } from '@planetlogin/planetlogin'; let el, g; $: if (el && !g) g = createPlanetLogin(el, { onLocale }); onDestroy(() => g?.destroy());
The payload
Delivered three ways: the locale DOM event, the on('locale', …) listener, or the onLocale option.
interface PlanetLocale { lat: number; lon: number; country: string; // ISO 3166-1 alpha-2 timezone: string; // "Europe/Madrid" or "UTC±N" language: string; // "es" label: string; // "Barcelona, Spain" }
Open source
AGPL-3.0 with a small attribution term. Free for any use, including commercial. Issues and PRs welcome.