228 lines
9.8 KiB
Markdown
228 lines
9.8 KiB
Markdown
# Animated Background
|
|
|
|
A browser-based animated desktop background: a WebGL flight scene over
|
|
real terrain, driven by the real sun, moon, stars, and live weather.
|
|
|
|
## Features
|
|
|
|
- **WebGL flight scene** (`vendor/clouds3d.js`): raymarched cloud deck,
|
|
3D terrain mesh from real elevation data (Copernicus DEM), satellite
|
|
or street basemap, figure-eight flight path around the configured
|
|
location with a vertical bob between **15 and 35 km** flight altitude.
|
|
- **Real day/night cycle** driven by the actual sun and moon position
|
|
(SunCalc) for the configured latitude/longitude — or an accelerated
|
|
24 h simulation (`CONFIG.day`) for wall-decoration purposes.
|
|
- **Realistic night sky**: ~8700 stars from the Yale Bright Star
|
|
Catalogue (crisp GL points, size by magnitude, colour by temperature),
|
|
rotated with the sidereal rate for the site's latitude, plus a Milky
|
|
Way band and a phase-correct moon.
|
|
- **Aircraft**: low-poly jets (CC0 model) cruising the region on curved
|
|
routes between real airfields, rolling a random destination at every
|
|
take-off - sun-lit silhouettes with contrails by day, strobing position
|
|
lights by night (all parameters in `CONFIG.flights`).
|
|
- **Night lights**: animated car lights along the real motorway/road
|
|
network and pale-yellow settlement lights (OSM place nodes; bigger
|
|
towns get more and brighter dots), optionally a NASA VIIRS night-lights
|
|
satellite overlay. All faded in from dusk, density shaped by a
|
|
rush-hour curve.
|
|
- **Live weather** (Open-Meteo): current conditions + 4-day forecast
|
|
widget; the weather code selects the scene's cloud density and colour
|
|
mood (sunny / cloudy / stormy / night).
|
|
- **Fully cached, offline-capable**: basemap tiles, elevation grid,
|
|
Overpass road/place data, star catalogue and the last weather payload
|
|
live permanently in IndexedDB. Once warm, the scene renders fully
|
|
offline; a configurable expiry (`CONFIG.tiles.expireDays`) can refresh
|
|
basemap tiles periodically.
|
|
- **Location-aware**: set `CONFIG.location.lat/lon`; everything
|
|
(flight anchor, terrain tiles, sun/moon, weather, star rotation) is
|
|
computed from it. If the location is omitted, browser geolocation is
|
|
tried, falling back to the built-in default (London).
|
|
- Units (°C/°F), six UI languages, CSS-swappable colour themes
|
|
(Ash/Gruvbox/Nord), configurable clock format, optional debug panel.
|
|
|
|
## Run with Docker (recommended)
|
|
|
|
```sh
|
|
docker compose up --build
|
|
```
|
|
|
|
Then open <http://localhost:58881/>.
|
|
|
|
The bundled nginx config (`default.conf`) is more than a file server: it
|
|
provides CORS proxies for the tile sources (`/esri/`, `/carto/`,
|
|
`/terrarium/`) that the scene needs for basemap and elevation data.
|
|
A plain static server without these proxies (e.g.
|
|
`python3 -m http.server 58881`) will run the UI but terrain and map
|
|
tiles will fail to load.
|
|
|
|
## Single-file build
|
|
|
|
`build.py` bundles everything into one self-contained HTML file
|
|
(`background-standalone.html`) — all scripts, the star catalogue and all
|
|
theme CSS are inlined, and theme switching keeps working:
|
|
|
|
```sh
|
|
python3 build.py # -> background-standalone.html (no sibling files needed)
|
|
```
|
|
|
|
Runtime *data* is still fetched at load (tiles, Overpass, weather): serve
|
|
the file from the Docker image for the full experience; opened via
|
|
`file://` or a proxy-less server it renders sky, clouds and UI with an
|
|
"OFFLINE"-labelled ground grid instead of basemap tiles.
|
|
|
|
## Configuration
|
|
|
|
Edit `config.js` and reload. All keys (with defaults):
|
|
|
|
```javascript
|
|
window.CONFIG = {
|
|
theme: 'ash', // 'ash' | 'gruvbox' | 'nord'
|
|
language: 'en', // 'en' | 'de' | 'it' | 'es' | 'fr' | 'ru'
|
|
timeFormat: 'DD. MMMM, YYYY \u2012 HH:mm:SS',
|
|
debug: 0, // 1 = show right-side debug panel
|
|
units: { temperature: 'C' }, // 'C' | 'F'
|
|
credits: true, // data-attribution block in info box
|
|
renderScale: 1, // 0.3..1 internal 3D resolution
|
|
|
|
location: { // drives scene anchor, sun/moon, weather
|
|
lat: 51.5074, // -90..+90, north positive
|
|
lon: -0.1278, // -180..+180, east positive
|
|
label: '' // optional name, skips reverse geocoding
|
|
},
|
|
|
|
day: {
|
|
simulation: false, // true: run 24 h in cycleSeconds;
|
|
cycleSeconds: 20, // false: real sun/moon positions
|
|
fixedTime: null // 'HH:MM' freezes the sim clock at
|
|
// that time of day (cars, clouds,
|
|
// weather keep moving); null = flow
|
|
},
|
|
weatherSim: false, // true: cycle weather themes, ignore API
|
|
weatherSimInterval: 30000, // ms per sim step
|
|
|
|
clouds: { top: 0.9, bottom: -0.3 },// cloud deck, world units
|
|
// (1 unit = ~12.9 km at z11 / 48.6 deg N)
|
|
|
|
orbit: { // null/omit = straight flight
|
|
radiusKm: 60, // lemniscate lobe tip (clamped ~190 km)
|
|
clockwise: true,
|
|
reorient: true, // random heading at each crossing
|
|
altBob: { // vertical bob, flight band 15-35 km
|
|
enabled: true, // false = constant 25 km
|
|
amp: 0.77, // half-band in world units
|
|
periodS: 90, // seconds per bob cycle
|
|
tilt: 0.3 // pitch reaction to climb/descent
|
|
}
|
|
},
|
|
fog: { distanceKm: 120 }, // ground haze; 0/false = off
|
|
|
|
terrain: {
|
|
enabled: true, // false = flat plane
|
|
exaggeration: 8, // vertical DEM scale factor
|
|
wireframe: false, // debug: orange mesh edges
|
|
nightLights: false, // NASA VIIRS city-lights overlay
|
|
carLights: true, // moving lights on real roads
|
|
cityLights: true // settlement glow dots
|
|
},
|
|
|
|
flights: { // see section above; all distances km
|
|
enabled: true,
|
|
altitudeKm: 14, climbKm: 100, // cruise / climb-descent run
|
|
count: 84, speedKmh: 850, speedVar: 0.18, minLegKm: 60,
|
|
holdMinS: 50, holdMaxS: 150, // ground hold at destination
|
|
wHub: 4, wField: 2, wStrip: 1, // destination roll weights
|
|
contrailChance: 0.6, // share of aircraft with a trail
|
|
contrailStartKm: 6, // formation altitude
|
|
contrailLifeS: 300, // visibility duration
|
|
contrailWidthM: 310 // full trail width
|
|
},
|
|
|
|
ground: { style: 'satellite' }, // 'satellite' | 'streets'
|
|
tiles: {
|
|
expireDays: null, // >0: re-fetch basemap tiles after n days
|
|
debug: false // tile borders + coords on the ground
|
|
}
|
|
};
|
|
```
|
|
|
|
## URL hash parameters
|
|
|
|
`http://host:58881/#flight=N&fetch=S`
|
|
|
|
- `flight=N|NE|E|SE|S|SW|W|NW` — heading of the straight flight corridor
|
|
(used when `CONFIG.orbit` is disabled)
|
|
- `fetch=N|NE|E|SE|S|SW|W|NW` — direction the tile mosaic is prefetched
|
|
ahead of the camera
|
|
|
|
## Time format tokens
|
|
|
|
```
|
|
YYYY 4-digit year (2026) MM month 01-12 (10)
|
|
DD day 01-31 (07) HH hour 00-23 (14)
|
|
mm minute 00-59 (35) ss second 00-59 (22)
|
|
sss millisecond 000-999 (456) a am/pm (pm)
|
|
A AM/PM (PM)
|
|
|
|
MMM month short name (Oct, Okt, Ott, ...)
|
|
MMMM month full name (October, Oktober, ...)
|
|
DDD weekday short name (Mon, Mo, Lu, ...)
|
|
dddd weekday full name (Monday, Montag, ...) lowercase!
|
|
|
|
Any other character is emitted verbatim (so a literal T in ISO-8601
|
|
needs no special token).
|
|
\n newline \t tab \\ literal backslash
|
|
```
|
|
|
|
## Adding a new language
|
|
|
|
Edit `i18n.js` and add entries for each existing key under your new
|
|
language code, e.g.:
|
|
|
|
```javascript
|
|
window.TRANSLATIONS['Sunrise']['xx'] = 'MyTranslation';
|
|
```
|
|
|
|
## Adding a new theme
|
|
|
|
Drop a new `*.css` file next to the others and add an entry to
|
|
`window.THEMES` in `config.js`:
|
|
|
|
```javascript
|
|
window.THEMES['mytheme'] = 'mytheme.css';
|
|
```
|
|
|
|
## Files
|
|
|
|
```
|
|
.
|
|
├── background.html the page (UI, weather, day/night driver)
|
|
├── config.js user-facing configuration
|
|
├── i18n.js translation strings (en/de/it/es/fr/ru)
|
|
├── ash.css default color theme
|
|
├── gruvbox.css alternative color theme
|
|
├── nord.css alternative color theme
|
|
├── vendor/
|
|
│ ├── clouds3d.js WebGL scene renderer (clouds, terrain, sky, lights)
|
|
│ ├── suncalc.js ISC (SunCalc by mourner)
|
|
│ ├── stars.json Yale Bright Star Catalogue subset
|
|
│ └── LICENSE per-library license attributions
|
|
├── default.conf nginx config: port 58881 + tile CORS proxies
|
|
├── build.py single-file HTML bundler (see "Single-file build")
|
|
├── Dockerfile builds nginx:alpine image
|
|
├── docker-compose.yml one-service Compose file
|
|
└── LICENSE MIT (application code)
|
|
```
|
|
|
|
## Licenses & data attribution
|
|
|
|
- **Background application code**: MIT (see `LICENSE`)
|
|
- **SunCalc** (vendored): ISC - <https://github.com/mourner/suncalc>
|
|
- **Open-Meteo** (weather API): CC BY 4.0 - <https://open-meteo.com/>
|
|
- **OpenStreetMap** (basemap tiles via ESRI/Carto, Overpass road and
|
|
place data): ODbL - <https://www.openstreetmap.org/copyright>
|
|
- **Copernicus DEM** (terrain via Mapzen terrarium tiles): open data
|
|
- **NASA GIBS VIIRS** (optional night-lights overlay): public domain
|
|
- **Yale Bright Star Catalogue** (star positions, via `vendor/stars.json`)
|
|
- **OpenStreetMap Nominatim** (reverse geocoding): ODbL -
|
|
<https://nominatim.org/release/>
|