Skip to content

Latest commit

ย 

History

71 Commits

Folders and files

NameName
Last commit message
Last commit date
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

geo-clock-card

GitHub Release License HACS Maintenance

Add Repository

A Home Assistant Lovelace card that turns one of your dashboards into a live world clock, modeled on the Geochronยฎ style (no affiliation). NASA Blue Marble (day) and Black Marble (night) imagery, a real day/night terminator computed from solar geometry, and DST-aware hover popups for every IANA time zone on the planet.

๐ŸŒ Live demo: https://geoclock.world

๐Ÿงฉ Chrome new-tab extension: a standalone, fully-offline build of the same card that replaces your new-tab page โ€” see chrome-extension/.

preview

What it does

  • World map โ€” NASA Blue Marble + Black Marble imagery, with the live day/night boundary recomputed from the subsolar point. 24 daylight composites (start + mid of each month, sampled from NASA SVS daily frames) swap automatically through the year so vegetation and snow cover follow the seasons.
  • Twilight glow โ€” warm sunrise/sunset rim along the terminator, screen- blended over the day side.
  • Hour band โ€” 25 column meridians at every 15ยฐ of longitude, with the current local hour highlighted at noon and midnight.
  • Time-zone overlay:
    • 25 visible 15ยฐ offset bands across the globe.
    • 419 IANA polygons sitting invisibly on top โ€” hover (or tap on mobile) and a popup shows DST-aware live time, the long zone name (EDT vs EST auto-switches), the current offset, the IANA tzid, the local date (handy when the remote zone has rolled to a different day), and the hovered region outlines itself for visual feedback.
    • Time and date follow the browser's locale (24-hour vs AM/PM, weekday/month language).
    • Open ocean / Antarctic strips with no IANA polygon fall through to the offset band's popup.
  • Centering modes โ€” sun (default, subsolar point โ€” the daylit hemisphere stays in the middle and the map slowly drifts), home (your HA-configured longitude), longitude (any numeric value), or entity (follow a zone / person / device-tracker entity). All non-sun modes fall back to Greenwich (lon=0ยฐ) with a console warning when their data isn't available โ€” so a misconfigured mode looks visibly different from sun instead of silently behaving the same.
  • Home marker โ€” optional dot at your HA-configured location that tracks the map's drift, with an opt-in label + current local time beneath it.
  • Location markers โ€” pin any list of HA entities (zones, persons, device-trackers) on the map; each shows the entity's label and the current local time at that zone (DST-aware, looked up from its longitude/latitude). Labels are always-visible by default; flip to hover-only if you'd rather keep the map tidy. The weekday is appended to the time so a marker on the far side of the planet whose date has rolled over is obvious at a glance โ€” toggle off if you want time-only. Per-marker color, or a card-wide default that themes can override via --geo-marker-color.
  • Main-clock time source โ€” the wall-clock readout can read from your HA location (default), the viewing device, or any HA entity with a longitude/latitude. (Breaking change in v0.2.0: pre-0.2.0 cards behaved as if the source was the viewing device. Set mainTimeSource: device to keep the old behavior.)
  • Time scrubbing โ€” freeze the clock at any UTC moment via now: โ€ฆ for screenshots or to preview the look at, say, the December solstice.
  • Installable PWA (geoclock.world only) โ€” install the demo as an app (header button on Chrome/Edge; Share โ†’ Add to Home Screen on iOS). A service worker caches everything โ€” all 24 monthly imagery variants included โ€” so the map, clocks, markers, and planner work fully offline; only place-name search needs a connection.
  • Meeting planner (geoclock.world only) โ€” a strip under the live demo's map scores the next 48 h across your markers (green: everyone in work hours; yellow: everyone awake; red: someone asleep โ€” worst participant wins), suggests the best windows, and lets you scrub or type a time to time-travel the whole map there. Powered by the card's public previewNow property + resolvedMarkers/tzReady getters and the bundle-exported helpers from src/meeting-plan.ts.
  • Visual editor โ€” opens automatically when adding the card; advanced visual knobs collapse into an expansion panel so the form stays clean.
  • Tunable โ€” twilight band size, glow color/opacity, day brightness, night contrast, time-zone line color, all via card config or CSS variables.
  • Cheap โ€” clock readout ticks every second; the map only recomputes when the subsolar point would have moved โ‰ฅ 0.5 px on a 4K display (โ‰ˆ every 10.5 s). When the card is off-screen or the browser tab is backgrounded the timer drops to a 30-minute cadence; refreshes immediately when the card becomes visible again.

Install

HACS (recommended)

Add Repository

  1. Click the badge above (it deep-links to your HA instance) โ€” or manually go HACS โ†’ โ‹ฎ โ†’ Custom repositories โ†’ add https://github.com/jpettitt/geo-clock-card, category Lovelace.

  2. Install Geo Clock Card from HACS.

  3. Refresh the browser. HACS adds the resource for you; otherwise: Settings โ†’ Dashboards โ†’ โ‹ฎ โ†’ Resources โ†’ add /hacsfiles/geo-clock-card/geo-clock-card.js as a JavaScript Module.

  4. Add a card to your dashboard:

    type: custom:geo-clock-card

Manual

  1. Clone the repo and build:

    git clone https://github.com/jpettitt/geo-clock-card
    cd geo-clock-card
    npm install
    npm run fetch-assets   # downloads NASA imagery + IANA TZ polygons
    npm run build
  2. Copy the entire dist/ directory into your Home Assistant config:

    <config>/www/community/geo-clock-card/
        geo-clock-card.js
        blue-marble-*-2048.jpg
        black-marble-2048.jpg
        timezones.json
        timezones-iana.json
    
  3. Add the resource: Settings โ†’ Dashboards โ†’ โ‹ฎ โ†’ Resources โ†’ /local/community/geo-clock-card/geo-clock-card.js, type JavaScript Module.

  4. Add the card with type: custom:geo-clock-card.

Configuration

A visual editor opens automatically when you add the card from the Lovelace picker. Every option is also settable in YAML:

type: custom:geo-clock-card

# Map centering โ€” sun (default) | home | longitude | entity
center: sun
centerLongitude: -119       # required when center: longitude. -180..180.
centerEntity: zone.home     # required when center: entity. Must expose a longitude attribute.
showHomeMarker: false       # render a dot at hass.config.latitude/longitude
showHomeMarkerLabel: false  # also show home name + current local time under the dot

# Imagery + atmosphere (under "Advanced visual settings" in the editor)
dayBrightness: 1.15         # CSS brightness() on the day layer (0.5..2.0)
nightContrast: 1.0          # CSS contrast() on the night layer (0.5..3.0)
twilightDegrees: 8          # half-band of the day/night fade, sun-elevation degrees (1..18)
twilightColor: "#463701"    # hex / rgb / rgba / hsl / named color
twilightOpacity: 0.26       # 0..1
timezoneLineColor: "rgba(255, 255, 255, 0.18)"  # any CSS color string

# Time
updateInterval: 1           # seconds between clock-readout ticks (1..600).
                            # The map repaints on a separate auto-throttled timer;
                            # both drop to 30 minutes when the card is off-screen.
now: "2024-12-21T09:21:00Z" # freeze the clock at this moment (omit for live)

# Main-clock time source โ€” home (default) | device | entity
# - 'home'   reads hass.config.time_zone (the HA-configured zone)
# - 'device' uses the viewing browser's zone (pre-0.2.0 behavior)
# - 'entity' picks the IANA zone of an HA entity's lat/lon
mainTimeSource: home
mainTimeEntity: zone.work   # required when mainTimeSource: entity

# Location markers โ€” list of HA entities to pin on the map.
# Each entity must expose numeric `latitude` and `longitude` attributes.
markers:
  - entity: zone.work
    label: Office            # optional โ€” defaults to the entity's friendly_name
    color: "#3da9fc"         # optional โ€” defaults to markerColor
  - entity: person.alice
    dayColor: "#ff9933"      # optional day/night pair โ€” this marker recolors
    nightColor: "#3da9fc"    # live as the terminator crosses its location
markerLabelMode: auto       # auto | always | compact | hover
                            # auto (default): full name+time labels, degrading to
                            # compact (small time-only, tap for full info) when the
                            # card renders narrower than ~520px โ€” phones, narrow
                            # dashboard columns. always/compact pin either form.
markerColor: "#3da9fc"      # default fill for markers without their own color
                            # โ€” omit (or unset) to let `--geo-marker-color` win
markerDayColor: "#ff9933"   # card-wide day/night defaults; setting either opts
markerNightColor: "#3da9fc" # every marker into day/night mode (per-marker wins)
markerShowDay: true         # append weekday after the time (e.g. "12:22 PM Friday")

# Overlays
showClock: true             # main clock readout + date (off for embedders
                            # that draw their own live clock, e.g. screensavers)
showTimezoneBand: true      # hour-of-day numbers across the top
showTimezoneBoundaries: true # IANA hover/identify popup hit layer
showTimezoneRegions: true   # 15ยฐ offset rectangle bands (defaults to
                            # showTimezoneBoundaries; set independently to
                            # show the bands as chrome without the popup)
showTimezonePopup: true     # live-time popup on hover/tap
showUTC: true               # UTC time below the local clock

# Localization (optional; defaults to the browser/runtime locale)
locale: ""                  # BCP-47 tag, e.g. "fr-FR" or "ja-JP".
                            # Governs the popup's localized timezone
                            # name, the clock readout, marker times, and
                            # the 12/24-hour choice. Empty = follow the
                            # viewer's browser language.

# Bundle resolution (rarely needed; not exposed in the visual editor)
imageryBase: ""             # override the assets URL (e.g. host on a CDN)

Centering modes

  • sun (default) โ€” centered on the current subsolar longitude. The map drifts westward as the sun moves; the daylit hemisphere stays in the middle.
  • home โ€” centered on hass.config.longitude. Falls back to Greenwich (0ยฐ) with a console.warn if HA hasn't reported a longitude.
  • longitude โ€” centered on a numeric centerLongitude value. Falls back to Greenwich (0ยฐ) if the value is missing or non-numeric.
  • entity โ€” centered on the longitude attribute of an HA entity. Works with zone.*, person.*, and most device_tracker.* entities. Falls back to Greenwich (0ยฐ) if the entity is missing or has no numeric longitude.

The Greenwich fallback is deliberate โ€” it's visually distinct from sun mode so a misconfiguration doesn't silently look right. Watch the browser console for a one-off warn line that names the broken field.

Theme via CSS variables

The card respects HA dashboard themes via custom-element CSS variables. Drop these in your theme YAML (or use card-mod) to override without touching the card config:

geo-clock-card:
  --geo-day-brightness: 1.2
  --geo-night-contrast: 1.0
  --geo-twilight-color: "#5a4a1a"
  --geo-twilight-opacity: 0.3
  --geo-tz-bg: rgba(8, 14, 28, 0.85)
  --geo-tz-noon: "#ffd866"
  --geo-tz-mid: "#6ab0ff"
  --geo-tz-line: rgba(255, 255, 255, 0.18)
  --geo-home-marker: var(--accent-color, "#ff7a3d")
  --geo-marker-color: "#3da9fc"

Most of these have a matching named config option (e.g. dayBrightness โ†’ --geo-day-brightness); set in YAML when you're tweaking a single card, or in a theme when you want every dashboard's geo-clock to match.

Imagery sources (all public domain)

Layer Source Resolution
Day (Blue Marble) NASA SVS dataset 3523, daily frames interpolating monthly Blue Marble Next Generation composites 2048 ร— 1024 JPEG, 24 frames (start + mid of each month)
Night (Black Marble) NASA "Earth at Night" 2012 composite 2048 ร— 1024 JPEG
Time-zone offsets Generated as 25 ร— 15ยฐ rectangle bands 8 KB GeoJSON
Time-zone IANA timezone-boundary-builder 2026b, simplified to 1% retention ~960 KB GeoJSON

Develop

npm install
npm run fetch-assets    # one-time: pulls + resizes imagery, downloads + simplifies TZ data
npm test                # vitest โ€” solar math, projection, polygon, IANA helpers
npm run build           # rollup โ†’ dist/geo-clock-card.js + copies assets
npm run dev             # rollup --watch

A standalone preview lives at dev/index.html. Run a static server from the repo root (python3 -m http.server 8765) and open http://localhost:8765/dev/index.html. The preview gives you sliders for twilight band, day brightness, night contrast, twilight color/opacity, center mode, time-scrubbing with solstice/equinox presets, etc.

How the pieces fit together

  • src/sun.ts โ€” subsolar point + sun-elevation math (USNO low-precision formulas).
  • src/terminator.ts โ€” terminator polygon and curve, parameterized by center longitude.
  • src/projection.ts โ€” equirectangular projection with arbitrary center.
  • src/timezones.ts โ€” offset overlay (25 rectangle bands + popup data).
  • src/timezones-iana.ts โ€” IANA polygon hit-testing layer + DST-aware Intl.DateTimeFormat wrapper.
  • src/timezone-band.ts โ€” top-of-map hour band + tick lines.
  • src/day-image.ts โ€” picks the right monthly daylight image for a given date.
  • src/marker-color.ts โ€” day/night marker color selection from sun elevation.
  • src/config-utils.ts โ€” pure config sanitizers (colors, locale, imagery base, numeric guards), unit-tested in isolation.
  • src/geo-clock-card.ts โ€” the Lit element that wires it all together.
  • src/geo-clock-card-editor.ts โ€” visual config editor (HA ha-textfield / ha-switch / ha-formfield / ha-selector / ha-expansion-panel, plus native <select> for the centering / time-source / marker-mode dropdowns where ha-select was unreliable). Awaits loadCardHelpers() before rendering so the entity selectors register correctly. Lazy-loaded by the card via getConfigElement() and bundled inline.

The original design notes are in DESIGN.md.

License

MIT for the code. NASA imagery is public domain. timezone-boundary-builder data is ODbL.

Geochronยฎ is a registered trademark of Geochron Enterprises Inc.; this project is not affiliated with or endorsed by them.

About

A live world clock modeled after Geochron

Topics

Resources

Stars

10 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages