clouds3d-only cleanup: drop Vanta/three.js/clouds2d, real-sky fixes, settlement lights, dynamic location anchor

This commit is contained in:
Richard Zink committed 2026-10-09 14:13:03 +02:00
1 parent e4170bee62
commit fbac24773a
17 files changed
+3217 -3411

No files matched your search

-2
View File
@@ -6,8 +6,6 @@ COPY nord.css /usr/share/nginx/html/nord.css
COPY config.js /usr/share/nginx/html/config.js
COPY i18n.js /usr/share/nginx/html/i18n.js
COPY background.html /usr/share/nginx/html/background.html
COPY noise.png /usr/share/nginx/html/noise.png
COPY ground.jpg /usr/share/nginx/html/ground.jpg
COPY vendor/ /usr/share/nginx/html/vendor/
EXPOSE 58881
CMD ["nginx", "-g", "daemon off;"]
+19 -9
View File
@@ -4,6 +4,10 @@ An animated desktop background that runs in a browser. Features:
- Time-of-day simulation with realistic color gradients driven by the
actual sun position (computed from latitude/longitude via SunCalc).
- WebGL flight scene (`vendor/clouds3d.js`): raymarched cloud deck, 3D
terrain from Copernicus DEM, real star sky (Yale BSC + Milky Way),
moon with phases, animated highway car lights and settlement lights
from OpenStreetMap/Overpass at night.
- Night brightness coupled to the moon phase (new moon = minimum, full
moon = maximum), with a configurable minimum so the night is never
pitch-black.
@@ -17,7 +21,7 @@ An animated desktop background that runs in a browser. Features:
to add a new theme.
- Customisable location: set `CONFIG.location.lat/lon`, or let the
browser's geolocation API pick one up automatically (falls back to
London).
the built-in default Passau).
- Optional custom location label (`CONFIG.location.label`) that
overrides the OpenStreetMap reverse-geocoding lookup.
- Configurable digital clock format string using ISO-8601-ish tokens
@@ -60,6 +64,11 @@ window.CONFIG = {
lon: 13.4319, // longitude, -180 to +180, east positive
label: '' // optional custom place name;
// if set, skips reverse-geocoding
},
orbit: { // omit/null = straight-line flight
radiusKm: 15, // circular flight around location;
// clamped to ~50 km at zoom 11
clockwise: true // turn direction
}
};
```
@@ -116,14 +125,13 @@ DDDD weekday full name (Monday, Montag, ...)
├── ash.css default color theme
├── gruvbox.css alternative color theme
├── nord.css alternative color theme
├── noise.png background noise texture for Vanta
├── vendor/ vendored third-party JS (no network needed)
│ ├── three.min.js MIT (three.js)
├── vendor/ vendored third-party files (no network needed)
│ ├── clouds3d.js WebGL scene: raymarched clouds, 3D terrain,
│ │ real sun/moon/stars, car + city lights
│ ├── suncalc.js ISC (SunCalc by mourner)
│ ├── vanta.clouds.min.js MIT (Vanta.js Clouds)
│ ├── vanta.clouds2.min.js MIT (Vanta.js Clouds2)
│ ├── stars.json Yale Bright Star Catalogue subset
│ └── LICENSE per-library license attributions
├── default.conf nginx server config (port 58881)
├── default.conf nginx server config (port 58881, tile CORS proxies)
├── Dockerfile builds nginx:alpine image
└── docker-compose.yml one-service Compose file
```
@@ -131,9 +139,11 @@ DDDD weekday full name (Monday, Montag, ...)
## Licenses
- **Background application code**: MIT
- **three.js** (vendored): MIT - <https://github.com/mrdoob/three.js>
- **SunCalc** (vendored): ISC - <https://github.com/mourner/suncalc>
- **Vanta.js** (vendored): MIT - <https://github.com/tengbao/vanta>
- **Open-Meteo** (weather API): CC BY 4.0 - <https://open-meteo.com/>
- **OpenStreetMap** (basemap tiles, Overpass road/place data): ODbL -
<https://www.openstreetmap.org/copyright>
- **Copernicus DEM** (terrain via terrarium tiles): open data
- **NASA GIBS VIIRS** (optional night-lights overlay): public domain
- **OpenStreetMap Nominatim** (reverse geocoding): ODbL -
<https://nominatim.org/release/>
File diff suppressed because it is too large. Load diff
+310 -110
View File
@@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Background Vanta Clouds2</title>
<title>Background Clouds3D</title>
<script src="config.js"></script>
<script src="i18n.js"></script>
<script>
@@ -18,7 +18,7 @@
<script src="vendor/suncalc.js"></script>
<style>
html, body { margin: 0; padding: 0; overflow: hidden; width: 100%; height: 100%; font-family: monospace; }
#vanta { width: 100vw; height: 100vh; position: fixed; top: 0; left: 0; }
#scene { width: 100vw; height: 100vh; position: fixed; top: 0; left: 0; }
#debug-panel {
position: fixed;
bottom: 2vh;
@@ -291,6 +291,14 @@
color: var(--icon);
line-height: 1.3;
}
.credits {
margin-top: 1.2vh;
font-size: 0.72em;
color: var(--gray);
opacity: 0.75;
line-height: 1.45;
text-align: center;
}
.weather-day {
margin-bottom: 0.6vh;
}
@@ -338,9 +346,9 @@
</style>
</head>
<body>
<div id="vanta" style="background: #1c1b1f;"></div>
<div id="scene"></div>
<div id="debug-panel">
<div class="debug-title expanded" onclick="toggleDebugPanel()">\n<span>DEBUG - Palette: <span id="dbg-palette-name">Ash</span></span><span class="debug-title-toggle" id="debug-toggle-icon">▼</span></div>
<div class="debug-title expanded" onclick="toggleDebugPanel()">\n<span>DEBUG · <span id="dbg-fps">--</span> fps</span><span class="debug-title-toggle" id="debug-toggle-icon">▼</span></div>
<div id="debug-content" class="debug-content">
<div class="debug-controls">
<select id="dbg-theme-select" class="debug-select" onchange="setDebugTheme(this.value)">
@@ -380,7 +388,7 @@
<div class="debug-row"><span class="libel">cloudColor</span> <div class="swatch" id="dbg-t-cloud"></div> <span class="hex" id="dbg-h-cloud">--</span></div>
<div class="debug-row"><span class="libel">lightColor</span> <div class="swatch" id="dbg-t-sunLight"></div> <span class="hex" id="dbg-h-sunLight">--</span></div>
<div class="debug-row"><span class="libel">bgColor</span> <div class="swatch" id="dbg-t-bg"></div> <span class="hex" id="dbg-h-bg">--</span></div>
<div class="debug-section">Vanta colors</div>
<div class="debug-section">Scene palette</div>
<div class="debug-row"><span class="libel">skyColor</span> <div class="swatch" id="dbg-v-sky"></div> <span class="hex" id="dbg-vh-sky">--</span></div>
<div class="debug-row"><span class="libel">cloudColor</span> <div class="swatch" id="dbg-v-cloud"></div> <span class="hex" id="dbg-vh-cloud">--</span></div>
<div class="debug-row"><span class="libel">lightColor</span> <div class="swatch" id="dbg-v-sunLight"></div> <span class="hex" id="dbg-vh-sunLight">--</span></div>
@@ -460,6 +468,13 @@
<line id="hour-hand" x1="140" y1="140" x2="140" y2="49" stroke="var(--bone)" stroke-width="7" stroke-linecap="round" opacity="0.7"/>
<line id="minute-hand" x1="140" y1="140" x2="140" y2="28" stroke="var(--bone)" stroke-width="5" stroke-linecap="round" opacity="0.7"/>
<line id="second-hand" x1="140" y1="140" x2="140" y2="20" stroke="var(--red)" stroke-width="2.5" stroke-linecap="round"/>
<!-- Flight-direction compass needle: north tip points where the
camera looks (driven by window.__flightBearing from clouds3d) -->
<g id="compass-needle" transform="rotate(0 140 140)" style="display:none">
<polygon points="140,103 134,140 140,146 146,140" fill="var(--red)" opacity="0.9"/>
<polygon points="140,177 134,140 140,134 146,140" fill="var(--stone)" opacity="0.6"/>
<circle cx="140" cy="140" r="6" fill="var(--dark)" stroke="var(--bone)" stroke-width="1.5"/>
</g>
<circle cx="140" cy="140" r="5" fill="var(--red)"/>
</svg>
<div id="digital-clock">00:00:00</div>
@@ -502,20 +517,14 @@
<div id="weather-divider" class="weather-divider"></div>
<div id="weather-current" class="weather-current"></div>
<div id="weather-forecast" class="weather-forecast"></div>
<div id="credits" class="credits"></div>
</div>
<script src="vendor/three.min.js"></script>
<script src="vendor/vanta.clouds.min.js"></script>
<script src="vendor/vanta.clouds2.min.js"></script>
<script src="vendor/clouds3d.js"></script>
<script src="vendor/clouds2d.js"></script>
<script>
window.__clouds2dStarted = true;
window.__cloudsStarted = true;
try {
window.__noiseDataUri = 'data:image/png;base64,PLACEHOLDER';
var noiseDataUri = 'data:image/png;base64,PLACEHOLDER';
// Parse URL hash params: #key=value&key=value...
// Supported: #renderer=clouds2d|clouds3d|vanta, #flight=N|NE|E|SE|S|SW|W|NW,
// #fetch=N|NE|E|SE|S|SW|W|NW
// Supported: #flight=N|NE|E|SE|S|SW|W|NW, #fetch=N|NE|E|SE|S|SW|W|NW
function _parseHashParams(hash) {
var out = {};
hash = (hash || '').replace(/^#/, '');
@@ -530,10 +539,6 @@ function _parseHashParams(hash) {
}
var _hashParams = _parseHashParams(location.hash);
// Renderer override
var _urlRenderer = _hashParams.renderer;
var renderer = _urlRenderer || (window.CONFIG && window.CONFIG.renderer) || 'vanta';
// Compass directions for flight and fetch (independent). Each direction
// has cos/sin (corridor rotation matrix) and dx/dz (camera motion unit vec).
var FLIGHT_DIRS = {
@@ -552,48 +557,20 @@ function _pickDir(key) {
}
window.__flightDir = _pickDir('flight');
window.__fetchDir = _pickDir('fetch');
var useVanta = (renderer !== 'clouds2d' && renderer !== 'clouds3d');
var effect;
if (useVanta && typeof VANTA !== 'undefined') {
effect = (VANTA.CLOUDS2 || VANTA.CLOUDS)({
el: "#vanta",
mouseControls: false,
touchControls: false,
gyroControls: false,
minHeight: 200.00,
minWidth: 200.00,
scale: 1.00,
scaleMobile: 4,
speed: 1.0,
backgroundColor: 0x1c1b1f,
backgroundAlpha: 1,
skyColor: 0x3a4458,
cloudColor: 0x6d6a63,
lightColor: 0xe6dfd1,
texturePath: noiseDataUri
}) || { setOptions: function() {} };
} else {
// Pick the right renderer based on CONFIG.renderer
var _renderFn = (renderer === 'clouds3d' && window.clouds3dRender)
? window.clouds3dRender
: window.clouds2dRender;
effect = { setOptions: function() {} };
function c2dRender() {
var c2dCanvas = document.getElementById('vanta');
if (!c2dCanvas) return;
if (typeof _renderFn === 'function') {
_renderFn(c2dCanvas);
}
// ---- WebGL scene (clouds3d.js) ------------------------------------------
var sceneEl = document.getElementById('scene');
function sceneRender() {
if (sceneEl && typeof window.clouds3dRender === 'function') {
window.clouds3dRender(sceneEl);
}
c2dRender();
window.addEventListener('resize', c2dRender);
// Continuously update animation via rAF
function c2dLoop() {
c2dRender();
window._clouds2dRaf = requestAnimationFrame(c2dLoop);
}
window._clouds2dRaf = requestAnimationFrame(c2dLoop);
}
sceneRender();
window.addEventListener('resize', sceneRender);
(function sceneLoop() {
sceneRender();
window._sceneRaf = requestAnimationFrame(sceneLoop);
})();
function hexToRgb(h) {
return [(h >> 16) & 255, (h >> 8) & 255, h & 255];
@@ -612,10 +589,26 @@ if (useVanta && typeof VANTA !== 'undefined') {
return t * t * (3 - 2 * t);
}
var CYCLE = 20000;
// Day simulation: CONFIG.day.simulation runs a full 24h cycle in
// CONFIG.day.cycleSeconds (sun rises east, culminates south, sets
// west). Off = real SunCalc positions.
var DAY_SIM = !!(window.CONFIG && window.CONFIG.day && window.CONFIG.day.simulation);
var CYCLE = ((window.CONFIG && window.CONFIG.day && window.CONFIG.day.cycleSeconds) || 20) * 1000;
// simulated sun altitude (rad): t=0 midnight, 0.25 sunrise, 0.5 noon
function simSunAlt(t) {
return Math.sin((t - 0.25) * Math.PI * 2) * 1.45;
}
// Virtual calendar for day-switching features (weather forecast):
// same wall clock as reality, but the DATE advances one day per
// simulated cycle. The visible clock hands/digital stay real.
function simNow() {
if (!DAY_SIM) return new Date();
return new Date(startTime + (Date.now() - startTime) * (86400000 / CYCLE));
}
var __simT = 0;
var PASSAU_LAT = (window.CONFIG && window.CONFIG.location && window.CONFIG.location.lat) || 48.5667;
var PASSAU_LON = (window.CONFIG && window.CONFIG.location && window.CONFIG.location.lon) || 13.4319;
var SITE_LAT = (window.CONFIG && window.CONFIG.location && window.CONFIG.location.lat) || 48.5667;
var SITE_LON = (window.CONFIG && window.CONFIG.location && window.CONFIG.location.lon) || 13.4319;
var realDayProgress = 0;
@@ -839,9 +832,13 @@ window.sunPalettes = [
}
function getColor(t) {
// t is no longer used - now uses real sun/moon
if (DAY_SIM) {
// t: 0 = Mitternacht, 0.25 Sonnenaufgang (Osten),
// 0.5 Mittag (Sueden), 0.75 Sonnenuntergang (Westen).
return getDayColor(simSunAlt(t));
}
var now = new Date();
var sunPos = SunCalc.getPosition(now, PASSAU_LAT, PASSAU_LON);
var sunPos = SunCalc.getPosition(now, SITE_LAT, SITE_LON);
var moonIllum = SunCalc.getMoonIllumination(now);
// The day palette covers sunAlt down to sunPalettes[0].alt
@@ -918,6 +915,7 @@ window.sunPalettes = [
var hourHand = document.getElementById('hour-hand');
var minuteHand = document.getElementById('minute-hand');
var secondHand = document.getElementById('second-hand');
var compassNeedle = document.getElementById('compass-needle');
var hourMarks = document.getElementById('hour-marks');
var rpgSunArc = document.getElementById('sun-arc');
var rpgMoonArc = document.getElementById('moon-arc');
@@ -1018,9 +1016,7 @@ window.sunPalettes = [
result += date.getFullYear();
i += 1;
} else if (ch === 'M' && format.substr(i, 4) === 'MMMM') {
var tMonthFull = t(monthKeys[date.getMonth()]);
console.log('MMMM token', date.getMonth(), '->', tMonthFull, 'lang=', window.CONFIG && window.CONFIG.language);
result += tMonthFull;
result += t(monthKeys[date.getMonth()]);
i += 4;
} else if (ch === 'M' && format.substr(i, 3) === 'MMM') {
result += t(monthKeys[date.getMonth()].substring(0, 3));
@@ -1279,7 +1275,10 @@ window.sunPalettes = [
// Calculate real day progress based on sun position
// 0% = midnight, 50% = noon, 100% = next midnight
var sunTimes = SunCalc.getTimes(now, PASSAU_LAT, PASSAU_LON);
if (DAY_SIM) {
realDayProgress = __simT;
} else {
var sunTimes = SunCalc.getTimes(now, SITE_LAT, SITE_LON);
var sunrise = sunTimes.sunrise;
var sunset = sunTimes.sunset;
if (now < sunrise) {
@@ -1290,7 +1289,8 @@ window.sunPalettes = [
} else {
realDayProgress = 0.5 + (now.getTime() - sunset.getTime()) / (sunrise.getTime() + 24 * 3600 * 1000 - sunset.getTime()) * 0.5;
}
realDayProgress = Math.max(0, Math.min(1, realDayProgress));
realDayProgress = Math.max(0, Math.min(1, realDayProgress));
}
// Real-time clock hands and digital
var h = now.getHours();
@@ -1308,9 +1308,9 @@ window.sunPalettes = [
secondHand.setAttribute('transform', 'rotate(' + secondAngle + ' 140 140)');
// Sun times
var sunTimes = SunCalc.getTimes(now, PASSAU_LAT, PASSAU_LON);
var sunriseNext = getNextEvent(sunTimes.sunrise, now, PASSAU_LAT, PASSAU_LON, 'sunrise');
var sunsetNext = getNextEvent(sunTimes.sunset, now, PASSAU_LAT, PASSAU_LON, 'sunset');
var sunTimes = SunCalc.getTimes(now, SITE_LAT, SITE_LON);
var sunriseNext = getNextEvent(sunTimes.sunrise, now, SITE_LAT, SITE_LON, 'sunrise');
var sunsetNext = getNextEvent(sunTimes.sunset, now, SITE_LAT, SITE_LON, 'sunset');
document.getElementById('sunrise-value').textContent = formatTimeHM(sunriseNext.date);
document.getElementById('sunrise-when').textContent = sunriseNext.label ? '· ' + sunriseNext.label : '';
@@ -1323,16 +1323,16 @@ window.sunPalettes = [
if (sunZenith <= now) {
var tomorrow = new Date(now);
tomorrow.setDate(tomorrow.getDate() + 1);
sunZenith = SunCalc.getTimes(tomorrow, PASSAU_LAT, PASSAU_LON).solarNoon;
sunZenith = SunCalc.getTimes(tomorrow, SITE_LAT, SITE_LON).solarNoon;
sunZenithWhen = formatDateLong(tomorrow);
}
document.getElementById('sun-zenith-value').textContent = formatTimeHM(sunZenith);
document.getElementById('sun-zenith-when').textContent = '· ' + sunZenithWhen;
// Moon times
var moonTimes = SunCalc.getMoonTimes(now, PASSAU_LAT, PASSAU_LON);
var moonriseNext = getNextEvent(moonTimes.rise, now, PASSAU_LAT, PASSAU_LON, 'moonrise');
var moonsetNext = getNextEvent(moonTimes.set, now, PASSAU_LAT, PASSAU_LON, 'moonset');
var moonTimes = SunCalc.getMoonTimes(now, SITE_LAT, SITE_LON);
var moonriseNext = getNextEvent(moonTimes.rise, now, SITE_LAT, SITE_LON, 'moonrise');
var moonsetNext = getNextEvent(moonTimes.set, now, SITE_LAT, SITE_LON, 'moonset');
document.getElementById('moonrise-value').textContent = formatTimeHM(moonriseNext.date);
document.getElementById('moonrise-when').textContent = moonriseNext.label ? '· ' + moonriseNext.label : '';
@@ -1388,7 +1388,7 @@ window.sunPalettes = [
sunSetArrow.setAttribute('transform', 'translate(' + ssP.x + ', ' + ssP.y + ')');
// Sun zenith marker (next occurrence)
var sunZenithDate = sunTimes.solarNoon > now ? sunTimes.solarNoon : SunCalc.getTimes(new Date(now.getTime() + 86400000), PASSAU_LAT, PASSAU_LON).solarNoon;
var sunZenithDate = sunTimes.solarNoon > now ? sunTimes.solarNoon : SunCalc.getTimes(new Date(now.getTime() + 86400000), SITE_LAT, SITE_LON).solarNoon;
var szP = pointOnCircle(sunZenithDate, SUN_ORBIT_RADIUS);
sunZenithMarker.setAttribute('transform', 'translate(' + szP.x + ', ' + szP.y + ')');
@@ -1494,7 +1494,7 @@ window.weatherThemes = {
// ---- Weather simulation -----------------------------------------
// Cycles through a list of weather states automatically. Useful
// for A/B testing the renderer against every theme without
// for A/B testing the scene against every theme without
// waiting on the open-meteo API.
var simWeathers = ['sunny', 'cloudy', 'stormy', 'night'];
var simIndex = 0;
@@ -1565,6 +1565,14 @@ window.weatherThemes = {
result[k] = targetThemeColors[k];
}
}
if (prevThemeColors && prevThemeColors.speed !== undefined &&
targetThemeColors.speed !== undefined) {
// ramp cloud speed with the colour transition instead of
// stepping it when the transition completes (a speed step
// reads as a sudden jump of the whole scene)
currentThemeSpeed = prevThemeColors.speed +
(targetThemeColors.speed - prevThemeColors.speed) * smoothT;
}
if (smoothT >= 1 && prevThemeColors !== targetThemeColors) {
prevThemeColors = targetThemeColors;
currentThemeSpeed = targetThemeColors.speed;
@@ -1572,6 +1580,29 @@ window.weatherThemes = {
return result;
}
// ---- Data credits (bottom of the info box, CONFIG.credits) ----
(function renderCredits() {
var el = document.getElementById('credits');
if (!el) return;
if (window.CONFIG && window.CONFIG.credits === false) {
el.style.display = 'none';
return;
}
var cfg = window.CONFIG || {};
var lines = [];
var style = (cfg.ground && cfg.ground.style) || 'streets';
lines.push('Basemap: ' + (style === 'satellite'
? 'Esri World Imagery' : 'Esri World Street Map'));
var t = cfg.terrain || {};
if (t.enabled !== false) {
lines.push('Terrain: Copernicus DEM via Mapzen Terrarium');
if (t.nightLights !== false) lines.push('Night lights: NASA GIBS VIIRS');
if (t.carLights !== false || t.cityLights !== false) lines.push('Roads: \u00a9 OpenStreetMap contributors (ODbL)');
}
lines.push('Weather: Open-Meteo');
el.innerHTML = lines.join('<br>');
})();
function applyWeatherTheme(c) {
var themeColors = getEffectiveThemeColors();
if (!themeColors) return c;
@@ -1579,8 +1610,9 @@ window.weatherThemes = {
// At night, weather only tints slightly - we don't want a
// 'cloudy' sky colour washing over deep night sky and
// making it look bright.
var _sunPos = SunCalc.getPosition(new Date(), PASSAU_LAT, PASSAU_LON);
var nightFactor = Math.max(0, Math.min(1, -_sunPos.altitude / 0.4));
var _sunAlt = DAY_SIM ? (window.__currentSunAlt || 0)
: SunCalc.getPosition(new Date(), SITE_LAT, SITE_LON).altitude;
var nightFactor = Math.max(0, Math.min(1, -_sunAlt / 0.4));
// Daytime: 40% weather mix (was 60%) — keeps day/night
// palette visible underneath, weather only adds tint.
var mix = 0.4 * (1 - nightFactor * 0.7);
@@ -1702,7 +1734,8 @@ window.weatherThemes = {
if (css && cssFile) css.href = cssFile;
setTimeout(function() {
rebuildFromColors();
document.getElementById('dbg-palette-name').textContent = theme.charAt(0).toUpperCase() + theme.slice(1);
var pal = document.getElementById('dbg-palette-name');
if (pal) pal.textContent = theme.charAt(0).toUpperCase() + theme.slice(1);
}, 50);
window.CONFIG.theme = theme;
}
@@ -1713,18 +1746,19 @@ window.weatherThemes = {
if (typeof fetchWeather === 'function') fetchWeather();
}
function updateDebug(t, palette, vantaColors, themeName, realDayProgress) {
function updateDebug(t, palette, sceneColors, themeName, realDayProgress) {
var now = new Date();
var hh = now.getHours(), mm = now.getMinutes(), ss = now.getSeconds();
document.getElementById('dbg-time').textContent =
(hh < 10 ? '0' : '') + hh + ':' + (mm < 10 ? '0' : '') + mm + ':' + (ss < 10 ? '0' : '') + ss;
document.getElementById('dbg-day').textContent = realDayProgress != null ? (realDayProgress * 100).toFixed(1) + '%' : (t * 100).toFixed(1) + '%';
document.getElementById('dbg-weather').textContent =
currentWeatherCode + ' (' + (window.weatherThemes[themeName] ? themeName : '?') + ')';
currentWeatherCode + ' (' + (window.weatherThemes[themeName] ? themeName : '?') + ')'
+ (window.__weatherStale ? ' cache' : '');
// RPG angles
var sunTimes = SunCalc.getTimes(now, PASSAU_LAT, PASSAU_LON);
var moonTimes = SunCalc.getMoonTimes(now, PASSAU_LAT, PASSAU_LON);
var sunTimes = SunCalc.getTimes(now, SITE_LAT, SITE_LON);
var moonTimes = SunCalc.getMoonTimes(now, SITE_LAT, SITE_LON);
document.getElementById('dbg-sun-rise-angle').textContent = (angleForTime(sunTimes.sunrise) * 180 / Math.PI).toFixed(1) + '°';
document.getElementById('dbg-sun-set-angle').textContent = (angleForTime(sunTimes.sunset) * 180 / Math.PI).toFixed(1) + '°';
document.getElementById('dbg-sun-now-angle').textContent = (angleForTime(now) * 180 / Math.PI).toFixed(1) + '°';
@@ -1755,12 +1789,12 @@ window.weatherThemes = {
}
}
if (vantaColors) {
if (sceneColors) {
var vKeys = ['sky', 'cloud', 'light', 'bg'];
var vKeyMap = {sky: 'sky', cloud: 'cloud', light: 'sunLight', bg: 'bg'};
for (var j = 0; j < vKeys.length; j++) {
var vk = vKeys[j];
var vc = vantaColors[vk];
var vc = sceneColors[vk];
var kk = vKeyMap[vk];
document.getElementById('dbg-v-' + kk).style.backgroundColor = '#' + ('00000' + vc.toString(16)).slice(-6);
document.getElementById('dbg-vh-' + kk).textContent = '#' + ('00000' + vc.toString(16)).slice(-6);
@@ -1794,7 +1828,12 @@ window.weatherThemes = {
tableHtml += '<span class="theme-table-speed">' + th.speed + '</span>';
tableHtml += '</div>';
}
document.getElementById('dbg-theme-table').innerHTML = tableHtml;
var __sigTheme = themeName + '|' + currentWeatherCode + '|' +
((window.CONFIG && window.CONFIG.theme) || '');
if (__sigTheme !== window.__dbgThemeSig) {
window.__dbgThemeSig = __sigTheme;
document.getElementById('dbg-theme-table').innerHTML = tableHtml;
}
// Color palette table - all colors from the palette
var colorKeys = [
@@ -1813,40 +1852,136 @@ window.weatherThemes = {
'<span class="theme-table-speed">' + cv + '</span>' +
'</div>';
}
document.getElementById('dbg-color-table').innerHTML = colorHtml;
var __sigPal = (window.CONFIG && window.CONFIG.theme) || '';
if (__sigPal !== window.__dbgPalSig) {
window.__dbgPalSig = __sigPal;
document.getElementById('dbg-color-table').innerHTML = colorHtml;
}
}
var __fpsCount = 0, __fpsT0 = performance.now(), __dbgT0 = 0;
function animate() {
var t = (Date.now() - startTime) / CYCLE % 1;
var c = getColor(t);
c = applyWeatherTheme(c);
// Expose current palette + weather info for the 2D renderer
// Expose current palette + weather info for the WebGL scene
window.__currentPalette = c;
window.__currentWeatherName = currentWeatherThemeName;
window.__currentDayProgress = realDayProgress;
window.__currentThemeSpeed = currentThemeSpeed;
// Sun altitude in radians. Negative = below horizon (night).
var _sunPos = SunCalc.getPosition(new Date(), PASSAU_LAT, PASSAU_LON);
window.__currentSunAlt = _sunPos.altitude;
effect.setOptions({
skyColor: c.sky,
cloudColor: c.cloud,
lightColor: c.light,
backgroundColor: c.bg,
backgroundAlpha: 0,
speed: currentThemeSpeed
});
document.body.style.backgroundColor = '#' + ('00000' + c.sky.toString(16)).slice(-6);
updateDebug(t, null, c, currentWeatherThemeName, realDayProgress);
if (DAY_SIM) {
__simT = t;
window.__currentDayProgress = t;
// virtual weekday: starts at the real one and advances with
// every simulated day, so weekends pass by in the 20s cycle
if (typeof window.__simDow !== 'number') {
window.__simDow = new Date().getDay();
window.__simLastT = t;
} else if (t < window.__simLastT) {
window.__simDow = (window.__simDow + 1) % 7;
}
window.__simLastT = t;
window.__flightDow = window.__simDow;
var _alt = simSunAlt(t);
window.__currentSunAlt = _alt;
// bearing: 6:00 (t=0.25) = east (pi/2), 12:00 = south (pi),
// 18:00 = west (3pi/2) -> bearing = 2*PI*t
var _sunBearing = t * Math.PI * 2;
window.__currentSunDir = [
-Math.cos(_alt) * Math.sin(_sunBearing),
Math.sin(_alt),
Math.cos(_alt) * Math.cos(_sunBearing)
];
} else {
var _sunPos = SunCalc.getPosition(new Date(), SITE_LAT, SITE_LON);
window.__currentSunAlt = _sunPos.altitude;
window.__flightDow = new Date().getDay();
// Unit vector towards the sun in world space (X east, Z north,
// Y up). SunCalc azimuth is measured from south, clockwise ->
// bearing from north = azimuth + PI.
var _sunBearingR = _sunPos.azimuth + Math.PI;
window.__currentSunDir = [
-Math.cos(_sunPos.altitude) * Math.sin(_sunBearingR),
Math.sin(_sunPos.altitude),
Math.cos(_sunPos.altitude) * Math.cos(_sunBearingR)
];
}
// ---- Moon direction ------------------------------------------
// Start elongation = real lunar phase (SunCalc: 0 new .. 0.5
// full); in day simulation the elongation advances 360/29.53
// deg per simulated day -> correct waxing/waning as cycles pass.
if (typeof window.__moonElong0 !== 'number') {
window.__moonElong0 = SunCalc.getMoonIllumination(new Date()).phase * Math.PI * 2;
window.__moonSimStartMs = Date.now();
}
var _simDays = DAY_SIM ? (Date.now() - window.__moonSimStartMs) / CYCLE : 0;
var _elong = window.__moonElong0 + _simDays * (Math.PI * 2 / 29.53);
var _sd = window.__currentSunDir;
var _cp = SITE_LAT * Math.PI / 180;
var _kp = [0, Math.sin(_cp), Math.cos(_cp)]; // celestial pole
var _ecs = Math.cos(_elong), _esn = Math.sin(_elong);
var _kdv = _kp[0]*_sd[0] + _kp[1]*_sd[1] + _kp[2]*_sd[2];
var _cx = _kp[1]*_sd[2] - _kp[2]*_sd[1];
var _cy = _kp[2]*_sd[0] - _kp[0]*_sd[2];
var _cz = _kp[0]*_sd[1] - _kp[1]*_sd[0];
window.__currentMoonDir = [
_sd[0]*_ecs + _cx*_esn + _kp[0]*_kdv*(1-_ecs),
_sd[1]*_ecs + _cy*_esn + _kp[1]*_kdv*(1-_ecs),
_sd[2]*_ecs + _cz*_esn + _kp[2]*_kdv*(1-_ecs)
];
var __skyHex = '#' + ('00000' + c.sky.toString(16)).slice(-6);
if (__skyHex !== window.__lastSkyHex) {
window.__lastSkyHex = __skyHex;
document.body.style.backgroundColor = __skyHex;
}
// Flight-direction compass needle (only while clouds3d feeds it)
if (compassNeedle) {
if (typeof window.__flightBearing === 'number') {
var _nd = (window.__flightBearing * 180 / Math.PI).toFixed(1);
if (_nd !== window.__lastNeedleDeg) {
window.__lastNeedleDeg = _nd;
compassNeedle.style.display = '';
compassNeedle.setAttribute('transform', 'rotate(' + _nd + ' 140 140)');
}
} else if (compassNeedle.style.display !== 'none') {
compassNeedle.style.display = 'none';
}
}
// FPS counter (rendered frames/second of the rAF loop)
__fpsCount++;
var __nowMs = performance.now();
if (__nowMs - __fpsT0 >= 1000) {
window.__fps = Math.round(__fpsCount * 1000 / (__nowMs - __fpsT0));
var __fpsEl = document.getElementById('dbg-fps');
if (__fpsEl) __fpsEl.textContent = window.__fps;
__fpsCount = 0;
__fpsT0 = __nowMs;
}
// Debug DOM writes are expensive; 4 Hz is plenty for readouts
if (__nowMs - __dbgT0 >= 250) {
__dbgT0 = __nowMs;
updateDebug(t, null, c, currentWeatherThemeName, realDayProgress);
}
requestAnimationFrame(animate);
}
var __lastWeatherHour = null;
function tick() {
try {
updateClockAndEvents();
} catch (e) {
console.error('Tick error:', e);
}
// simulated day/hour switch -> refresh the weather block
if (DAY_SIM && weatherData) {
var wh = Math.floor(simNow().getTime() / 3600000);
if (wh !== __lastWeatherHour) {
__lastWeatherHour = wh;
try { updateWeatherDisplay(); } catch (e) { console.error(e); }
}
}
setTimeout(tick, 1000);
}
@@ -1883,6 +2018,16 @@ window.weatherThemes = {
// set their own place name in CONFIG.location.label).
function reverseGeocode(lat, lon) {
if (window.CONFIG && window.CONFIG.location && window.CONFIG.location.label) return;
// cached label first: works offline and avoids hitting
// Nominatim on every start
if (window.BackgroundCache) {
window.BackgroundCache.get('meta/geolabel').then(function(rec) {
if (rec && rec.value && window.CONFIG && window.CONFIG.location &&
!window.CONFIG.location.label) {
window.CONFIG.location.label = rec.value;
}
});
}
var url = 'https://nominatim.openstreetmap.org/reverse?format=json&lat=' +
lat + '&lon=' + lon + '&zoom=10&addressdetails=1';
fetch(url, {
@@ -1897,6 +2042,9 @@ window.weatherThemes = {
if (window.CONFIG && window.CONFIG.location) {
window.CONFIG.location.label = name;
}
if (window.BackgroundCache) {
window.BackgroundCache.put('meta/geolabel', { value: name });
}
}
})
.catch(function() { /* ignore errors */ });
@@ -2002,12 +2150,29 @@ window.weatherThemes = {
.then(function(response) { return response.json(); })
.then(function(data) {
weatherData = data;
window.__weatherStale = false;
if (window.BackgroundCache) {
window.BackgroundCache.put('meta/weather', { json: data });
}
currentWeatherCode = data.current.weather_code;
setWeatherTheme(getWeatherThemeName(currentWeatherCode));
updateWeatherDisplay();
})
.catch(function(err) {
console.log('Weather fetch failed:', err);
// offline fallback: last stored payload keeps the
// widgets and weather-driven colours alive
if (window.BackgroundCache) {
window.BackgroundCache.get('meta/weather').then(function(rec) {
if (rec && rec.json && rec.json.current) {
weatherData = rec.json;
window.__weatherStale = true;
currentWeatherCode = rec.json.current.weather_code;
setWeatherTheme(getWeatherThemeName(currentWeatherCode));
updateWeatherDisplay();
}
});
}
});
}
@@ -2028,32 +2193,67 @@ window.weatherThemes = {
function updateWeatherDisplay() {
if (!weatherData) return;
var now = new Date();
var now = simNow(); // virtual calendar: real day-of-week start,
// one simulated day per CYCLE (clock stays real!)
var current = weatherData.current;
var hourly = weatherData.hourly;
var daily = weatherData.daily;
// how many simulated days have passed since the API's 'today' -
// wrapped into the 5-day forecast window, so an ever-advancing
// sim keeps cycling fresh-looking conditions instead of freezing
var firstDay = new Date(daily.time[0]);
var spanMs = daily.time.length * 86400000;
var eff = now;
var wrapGuard = 0;
while (DAY_SIM && eff.getTime() >= firstDay.getTime() + spanMs && wrapGuard++ < 2000) {
eff = new Date(eff.getTime() - spanMs);
}
if (DAY_SIM && eff.getTime() < firstDay.getTime()) eff = firstDay;
var dayOffset = DAY_SIM
? Math.max(0, Math.min(daily.time.length - 4,
Math.floor((eff - firstDay) / 86400000)))
: 0;
// "Current": in simulation mode use the hourly value at the
// simulated time; theme follows it too (unless the weather-sim
// button has manual control)
var curTemp = current.temperature_2m;
var curCode = current.weather_code;
if (DAY_SIM) {
var curIdx = findHourlyIndex(eff, hourly.time);
curTemp = hourly.temperature_2m[curIdx];
curCode = hourly.weather_code[curIdx];
if (!__weatherSimActive && curCode !== currentWeatherCode) {
currentWeatherCode = curCode;
setWeatherTheme(getWeatherThemeName(curCode));
}
}
// Current
var currentUnits = (window.CONFIG && window.CONFIG.units) || 'metric';
var tempDisplay = currentUnits === 'imperial'
? Math.round(current.temperature_2m * 9 / 5 + 32) + '\u00b0F'
: Math.round(current.temperature_2m) + '\u00b0C';
? Math.round(curTemp * 9 / 5 + 32) + '\u00b0F'
: Math.round(curTemp) + '\u00b0C';
var windDisplay = currentUnits === 'imperial'
? Math.round(current.wind_speed_10m * 0.621371) + ' mph'
: Math.round(current.wind_speed_10m) + ' km/h';
var currentHtml = '<div class="weather-current-icon">' + weatherSVG(current.weather_code) + '</div>' +
var currentHtml = '<div class="weather-current-icon">' + weatherSVG(curCode) + '</div>' +
'<div><div class="weather-current-temp"><span>' + tempDisplay + '</span><span class="weather-location" id="weather-location">' +
((window.CONFIG && window.CONFIG.location && (window.CONFIG.location.label || (window.CONFIG.location.lat.toFixed(2) + ',' + window.CONFIG.location.lon.toFixed(2)))) || '') + '</span></div>' +
'<div class="weather-current-detail">' +
t('Humidity') + ' ' + Math.round(current.relative_humidity_2m) + '% · ' + t('Wind') + ' ' + windDisplay + '</div></div>';
document.getElementById('weather-current').innerHTML = currentHtml;
// Forecast
// Forecast - window starts at the simulated "today" so the
// list shifts forward each simulated cycle (tomorrow becomes
// today, a new day enters at the end)
var forecastHtml = '';
for (var d = 0; d < 4; d++) {
for (var d = dayOffset; d < dayOffset + 4 && d < daily.time.length; d++) {
var dayDate = new Date(daily.time[d]);
var dayLabel = d === 0 ? t('today') : t('tomorrow');
if (d > 1) {
var dayLabel = d === dayOffset ? t('today')
: (d === dayOffset + 1 ? t('tomorrow') : '');
if (!dayLabel) {
var weekdayKey = ['Su.', 'Mo.', 'Tu.', 'We.', 'Th.', 'Fr.', 'Sa.'][dayDate.getDay()];
dayLabel = t(weekdayKey) + ' ' +
(dayDate.getDate() < 10 ? '0' : '') + dayDate.getDate() + '.' +
@@ -2123,7 +2323,7 @@ window.weatherThemes = {
setInterval(fetchWeather, 15 * 60 * 1000);
}
} catch (e) {
window.__clouds2dError = e.message || String(e);
window.__cloudsError = e.message || String(e);
console.error('Background init error:', e);
}
</script>
-96
View File
@@ -1,96 +0,0 @@
#!/usr/bin/env python3
"""
Build a single self-contained HTML file from the source files.
Usage:
python3 build.py [output.html]
If output is not given, defaults to 'background-final.html'.
This reads config.js to pick the active theme and inlines all CSS,
JS, and the noise.png texture into a single HTML document. After
building, the resulting standalone HTML can be opened directly in
a browser (file://) because all external resources are inlined.
"""
import base64
import os
import re
import sys
ROOT = os.path.dirname(os.path.abspath(__file__))
def read(path):
with open(os.path.join(ROOT, path), 'r', encoding='utf-8') as f:
return f.read()
def parse_config():
"""Extract window.CONFIG values from config.js."""
src = read('config.js')
out = {}
for key in ['debug', 'theme', 'units', 'language', 'timeFormat']:
m = re.search(r"\b%s\s*:\s*'([^']*)'" % key, src) or re.search(r'\b%s\s*:\s*(\d+)' % key, src)
if m:
out[key] = m.group(1)
m = re.search(r'lat\s*:\s*([\d.]+)', src)
if m:
out['lat'] = m.group(1)
m = re.search(r'lon\s*:\s*([-\d.]+)', src)
if m:
out['lon'] = m.group(1)
return out
def main():
out = sys.argv[1] if len(sys.argv) > 1 else 'background-final.html'
cfg = parse_config()
theme = cfg.get('theme', 'ash')
html = read('background.html')
# Read noise.png and inline as base64 data URI
with open(os.path.join(ROOT, 'noise.png'), 'rb') as f:
noise_b64 = base64.b64encode(f.read()).decode('ascii')
# Replace noiseDataUri placeholder with the actual data URI
html = html.replace(
"'data:image/png;base64,PLACEHOLDER'",
"'data:image/png;base64," + noise_b64 + "'"
)
# Resolve active theme css
theme_css = read(theme + '.css')
# Inline the active theme stylesheet at the end of <head>
html = html.replace('</head>',
'<style>\n' + theme_css + '\n</style>\n</head>',
1)
# Inline vendor scripts in the body, before the main script block
for _, path in [
('three', 'vendor/three.min.js'),
('suncalc', 'vendor/suncalc.js'),
('vanta2', 'vendor/vanta.clouds2.min.js'),
('clouds2d', 'vendor/clouds2d.js'),
('i18n', 'i18n.js'),
('config', 'config.js'),
]:
body = read(path)
html = html.replace('<script src="' + path + '"></script>',
'<script>\n' + body + '\n</script>',
1)
with open(os.path.join(ROOT, out), 'w', encoding='utf-8') as f:
f.write(html)
print('Wrote ' + out + ' (' + str(len(html)) + ' bytes)')
print('Config used:')
for k in ('debug', 'theme', 'units', 'language', 'timeFormat', 'lat', 'lon'):
if k in cfg:
print(' ' + k + ' = ' + cfg[k])
if __name__ == '__main__':
main()
+117 -7
View File
@@ -9,21 +9,54 @@
* timeFormat - Moment.js-compatible format string for the clock.
* debug - If 1, the right-side debug panel is shown.
* units - Object with 'temperature' ('C' or 'F').
* renderer - Background renderer: 'vanta' (default, GPU 3D volumetric
* raymarched clouds via three.js), 'clouds2d' (lightweight
* WebGL fragment shader, 2D fBm scrolling), or 'clouds3d'
* (volumetric raymarcher with camera fly-through).
* location - Geographic coordinates for sun/moon calculations. Used
* by SunCalc (https://github.com/mourner/suncalc). Object
* with 'lat' (latitude, -90 to +90) and 'lon' (longitude,
* -180 to +180). Positive lat = north, positive lon = east.
* Optionally add 'label' (string) to override the
* reverse-geocoded city name.
* Note: the height grid is axis-aligned (N up); terrain
* matches the 8-mode square mosaic and straight flights
* with fetch=N. Heights: Copernicus DEM via terrarium
* tiles (z9, ~200 m), fetched once per session.
* terrain - 3D ground from real elevation data. Object:
* enabled - true (default) / false = flat plane.
* exaggeration - vertical scale factor on the DEM
* (default 8; 1 would be physically
* true and nearly invisible at this
* horizontal scale).
* weatherSim - If true, ignore open-meteo and cycle through
* ['sunny','cloudy','stormy','night'] automatically every
* weatherSimInterval ms. Useful for A/B testing every
* theme without waiting on the API.
* weatherSimInterval - Sim cycle period in ms (default 30000).
* orbit - Figure-eight flight (Bernoulli lemniscate) around
* CONFIG.location instead of a straight drift. The
* eight's self-crossing sits exactly on the configured
* coordinate. Each time the aircraft crosses that point
* a new random orientation is picked and blended in
* over one lobe (spline through the crossing). Object:
* radiusKm - lobe tip reach from the centre in km
* (~13 km per tile at z11/48deg N).
* Clamped (~190 km) so tips + fog horizon
* fit inside the 43x43 tile mosaic.
* clockwise - travel direction along the eight.
* reorient - random re-aim at every crossing
* (default true; false keeps the bearing).
* Set to null (or remove) for the straight-line flight.
* fog - Ground fog / distance haze. Object with 'distanceKm'
* (visibility range at which terrain fully blends into
* a milky haze; default 120). false/0 disables fog.
* clouds - Vertical extent of the cloud deck in world units
* (1 unit = ~13 km at zoom 11; camera flies at y=2.2).
* Object with 'top' and 'bottom'. Default keeps the
* deck a bit below flight altitude.
* tiles - All downloads (street tiles, elevation grid, last
* weather payload, geo label) live permanently in
* IndexedDB and are never re-fetched once cached; a
* warm cache = fully offline rendering. Set
* expireDays (number > 0) to re-fetch street tiles
* periodically (e.g. 90).
*
* Time format tokens (subset):
* YYYY 4-digit year (2026)
@@ -42,19 +75,96 @@ window.CONFIG = {
theme: 'ash',
language: 'en',
timeFormat: 'DD. MMMM, YYYY ‒ HH:mm:SS',
debug: 1,
debug: 0,
units: {
temperature: 'C'
},
renderer: 'clouds3d', // 'vanta', 'clouds2d', or 'clouds3d'
// Data attribution at the bottom of the info box (auto text based on
// the enabled layers). false = ausgeblendet.
credits: true,
// Internal 3D resolution scale (0.3..1, default 1). Lower values
// render the clouds/map shader at reduced resolution and upscale
// via CSS - use it if fps is low (GPU-bound) despite a quiet CPU.
renderScale: 1,
location: {
// Latitude and longitude for sun/moon calculations
// Default: Passau, Germany
// Passau (vorher: Muenchen 48.1374/11.5755, Innsbruck 47.2692/11.4041)
lat: 48.5667,
lon: 13.4319
},
weatherSim: false,
weatherSimInterval: 30000,
// Alles Downloads (Strassenkacheln, Hoehengitter, Wetter-JSON,
// Geo-Label) bleibt dauerhaft im IndexedDB — kein erneuter
// Download. expireDays (Tage, >0) reaktiviert periodisches
// Auffrischen der Strassenkacheln.
tiles: {
expireDays: null,
// true = Kachel-Raender + N/S + x/y-Koords in die Boden-Textur
// malen (Debug-Orientierung). Aus = saubere Karte.
debug: false
},
// Boden-Bildquelle: 'satellite' = ESRI World_Imagery (Luftbild, ohne
// Beschriftung), 'streets' = ESRI World_Street_Map (mit Ortsnamen).
// Beide dauerhaft gecacht (eigener Cache- Praefix pro Stil).
ground: {
style: 'satellite'
},
// Achterkurs um location (lat/lon), ueberschneidungspunkt genau auf
// der Koordinate. null/entfernen = gerade Flugbahn.
orbit: {
radiusKm: 60, // Lappenspitze: max. Abstand vom Zentrum
clockwise: true,
reorient: true, // Zufalls-Ausrichtung an jedem Kreuzungs-Durchflug
// Langsames vertikales Wogen innerhalb der Flugband 15-35 km:
// Mitte 25 km (~1.93 Welt-Einheiten), amp = halbes Band
// (10 km ~ 0.77); harte Klemme ueber/unter die Bandgrenzen.
// periodS Sekunden pro Zyklus, tilt = Reaktion der Kamera-Nase
// auf Steig-/Sinkrate. enabled: false = konstant 25 km.
altBob: { enabled: true, amp: 0.77, periodS: 90, tilt: 0.3 }
},
// Bodennebel: Distanz-Haze. distanceKm = Sichtweite bis vollständige
// Nebelsaettigung (false/0 = aus).
fog: {
distanceKm: 120
},
// 3D-Boden aus echten Hoehendaten (Copernicus DEM, terrarium-Kacheln).
// enabled: false = flache Ebene. exaggeration: vertikale Ueberhoehung
// (1 = real, unsichtbar; default 8). wireframe: true = Mesh-Kanten
// als orange Linien zusaetzlich einblenden (Debug).
// nightLights: NASA-VIIRS-Stadtlichter-Layer, der ab Sonnenuntergang
// ueber ~1 h in die Tageskarte geblendet wird (dunkler Boden,
// leuchtende Staedte). Einmaliger Fetch (~49 Kacheln), persistent
// gecacht. false = kein Lichtoverlay, nachts bleibt die normale
// Textur deutlich heller (nur sanft abgedimmt).
// carLights: fahrende Lichter auf Autobahnen (OSM/Overpass-Kurven,
// nachts additiv ueber dem Gelaende). JSON einmalig, persistent gecacht.
// cityLights: Siedlungslichter — OSM-Ortsknoten (city/town/village/
// hamlet) als leicht gelbliche Glow-Punkte, ab Daemmerung statisch;
// je groesser die Siedlung (place-Klasse + population-Tag), desto
// mehr und hellere Punkte. Eine Overpass-Abfrage, persistent gecacht.
// Daten (c) OpenStreetMap-Mitwirkende, ODbL.
terrain: {
enabled: true,
exaggeration: 10,
wireframe: false,
nightLights: false,
carLights: true,
cityLights: true
},
// Tagessimulation: true = 24h-Zyklus wird in cycleSeconds durchlaufen
// (Sonne steigt im Osten, Mittag im Sueden, Untergang im Westen).
// false = echte Sonnen-/Mondposition via SunCalc.
day: {
simulation: false,
cycleSeconds: 20
},
// Wolkendecke in Welt-Einheiten (1 unit ~ 13 km bei Zoom 11;
// Kamera fliegt auf y=2.2). Decke etwas unter Flughohe.
clouds: {
top: 0.9,
bottom: -0.3
},
};
// List of available themes. The key is the theme id (used in config.theme),
+18
View File
@@ -8,6 +8,13 @@ server {
try_files $uri $uri/ =404;
}
# The background page runs as an iframe on other origins; a stray
# favicon request must not log 404s.
location = /favicon.ico {
return 204;
access_log off;
}
# CORS proxy for Carto basemaps (place names, OSM-derived).
# URL format: /carto/voyager/{z}/{x}/{y}.png
location ^~ /carto/ {
@@ -37,6 +44,17 @@ server {
add_header Access-Control-Max-Age 86400 always;
}
# CORS proxy for Mapzen/TILEZEN terrain-RGB "terrarium" elevation
# tiles (Copernicus DEM). URL format: /terrarium/{z}/{x}/{y}.png
location ^~ /terrarium/ {
resolver 1.1.1.1 8.8.8.8 ipv6=off valid=300s;
proxy_pass https://s3.amazonaws.com/elevation-tiles-prod/terrarium/;
proxy_ssl_server_name on;
proxy_set_header Host s3.amazonaws.com;
proxy_set_header User-Agent "Mozilla/5.0 (compatible; tile-proxy)";
add_header Access-Control-Allow-Origin "*" always;
}
# CORS preflight handler
location ~* \.(png|jpg)$ {
if ($request_method = 'OPTIONS') {
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 277 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 MiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

+7 -17
View File
@@ -1,25 +1,15 @@
three.min.js - three.js (r128)
Source: https://github.com/mrdoob/three.js
License: MIT (https://github.com/mrdoob/three.js/blob/dev/LICENSE)
Used under the terms of the MIT License.
suncalc.js - SunCalc (v1.9.0)
Source: https://github.com/mourner/suncalc
Original author: Vladimir Agafonkin (mourner)
License: ISC (https://github.com/mourner/suncalc/blob/master/LICENSE)
Used under the terms of the ISC License.
vanta.clouds.min.js - Vanta.js Clouds effect (v0.5.21)
Source: https://github.com/tengbao/vanta
Author: Teng Bao
License: MIT (https://github.com/tengbao/vanta/blob/master/LICENSE)
Used under the terms of the MIT License.
stars.json - star catalogue derived from the Yale Bright Star Catalogue
(5th ed., public catalogue data). Generated for this project; see the
real-sky notes in clouds3d.js.
vanta.clouds2.min.js - Vanta.js Clouds2 effect (v0.5.21)
Source: https://github.com/tengbao/vanta
Author: Teng Bao
License: MIT (https://github.com/tengbao/vanta/blob/master/LICENSE)
Used under the terms of the MIT License.
clouds3d.js - original code for this project (same license as the
repository root LICENSE).
These libraries are vendored locally so the application can run fully offline
without any external network dependencies.
These libraries/data files are vendored locally so the application can
run fully offline without any external network dependencies.
View File
Whitespace-only changes.
+2745 -277
View File
File diff suppressed because it is too large. Load diff
+1
View File
@@ -0,0 +1 @@
[[1.266,-0.503,6.29,5100],[1.334,-5.708,4.61,5000],[1.425,13.396,5.51,5500],[1.567,58.437,5.96,5500],[1.579,-49.075,5.7,5900],[1.61,64.196,5.59,12000],[1.653,29.021,6.13,5000],[1.709,-23.108,6.18,8250],[1.826,-17.386,6.19,8500],[1.934,-2.549,6.43,14000],[1.945,-22.509,5.94,9500],[2.015,-33.529,5.68,4850],[2.05,-2.448,6.07,4700],[2.097,29.091,2.06,14000],[2.072,-8.824,5.99,5200],[2.171,36.627,6.19,6300],[2.139,-17.578,6.06,3500],[2.218,25.463,6.23,5000],[2.334,79.715,6.01,8250],[2.295,59.15,2.27,7200],[2.26,18.212,5.53,5100],[2.26,-54.002,6.33,5600],[2.337,-27.988,5.42,7200],[2.353,-45.748,3.88,5000],[2.51,11.146,5.51,12000],[2.58,46.072,5.03,7200],[2.578,-5.249,5.84,4850],[2.509,-82.224,5.28,5200],[2.678,-12.58,5.85,5000],[2.816,-15.468,4.89,6450],[2.893,-27.8,5.41,4250],[2.933,-35.133,5.25,6900],[2.996,48.152,6.16,4400],[3.042,-17.938,5.25,4250],[3.309,15.184,2.83,26000],[3.35,26.987,6.3,6000],[3.378,41.035,5.72,7500],[3.425,-26.022,5.94,4250],[3.434,-26.285,6.31,4250],[3.51,33.206,6.25,9750],[3.651,20.207,4.8,3200],[3.615,-7.781,5.12,3050],[3.331,-84.994,5.77,3500],[3.66,-18.933,4.44,3050],[3.734,22.284,6.24,9750],[3.745,8.821,5.79,7500],[3.727,-9.57,5.75,12000],[3.779,31.536,6.45,4250],[3.794,27.283,6.35,9750],[3.743,-34.904,6.17,4550],[4.058,76.951,6.35,14000],[4.09,43.595,6.15,9500],[4.037,-31.446,5.67,4250],[3.98,-75.911,6.49,5200],[4.142,8.24,6.11,5200],[4.238,61.533,5.74,5200],[4.177,-20.211,6.47,14000],[4.288,47.947,5.89,16000],[4.273,38.682,4.61,9500],[4.429,51.433,6.14,30000],[4.386,-19.051,6.45,6900],[4.449,1.689,6.17,5000],[4.582,36.785,4.52,9500],[4.572,11.206,6.05,5000],[4.675,43.791,6.11,14000],[4.66,31.517,5.87,10000],[4.674,-8.053,6.46,6000],[4.677,-43.235,6.33,4700],[4.857,-8.824,3.56,4850],[4.923,40.73,6.33,4850],[5.022,48.865,6.52,10000],[5.018,-64.875,4.23,6150],[5.102,30.936,5.9,16000],[5.19,32.911,5.79,4250],[5.15,8.19,5.37,4550],[5.227,10.977,6.56,10000],[5.28,37.969,5.18,6750],[5.162,-69.625,5.51,12000],[5.38,-28.982,5.18,5500],[5.443,-20.058,5.12,2750],[5.606,13.482,6.23,4550],[5.369,-77.427,5.97,4550],[5.716,-12.209,6.39,5800],[5.803,-31.036,6.55,12000],[6.065,52.02,5.57,20000],[6.198,61.831,5.4,12000],[6.124,-2.219,6.07,4850],[6.277,53.047,5.74,12000],[6.351,1.94,5.77,5500],[6.438,-77.254,2.8,5800],[6.571,-42.306,2.39,5000],[6.551,-43.68,3.94,8250],[6.656,-0.05,6.19,5200],[6.811,-25.547,5.98,5200],[7.012,17.893,5.06,3050],[7.057,44.394,5.17,9500],[6.982,-33.007,4.81,2900],[7.053,16.445,6.06,4250],[7.084,10.19,6.04,6600],[7.088,-20.335,6.43,6000],[7.11,-39.915,5.43,3500],[7.236,36.9,6.26,5500],[7.18,-50.533,6.26,5000],[7.729,77.019,6.21,5000],[7.583,59.977,5.94,12000],[7.53,29.752,5.23,8250],[7.466,-14.864,6.14,7200],[7.454,-32.117,6.57,4400],[7.51,-3.957,5.72,3500],[7.595,-23.788,5.19,8750],[7.616,-40.939,6.19,7200],[7.609,-48.215,5.69,7200],[7.855,66.519,6.18,18000],[7.857,33.582,5.87,4850],[7.943,54.522,4.73,14000],[7.922,52.839,5.6,4700],[7.854,-48.804,4.77,10000],[7.886,-62.958,4.37,12000],[7.89,-62.966,4.54,9500],[8.33,70.982,6.42,10000],[8.25,62.932,4.16,28000],[8.148,20.294,5.38,5000],[8.099,6.956,5.67,12000],[8.205,28.28,6.3,5000],[8.293,54.895,5.93,5000],[8.182,-63.031,5.09,10000],[8.604,66.75,6.48,12000],[8.421,-29.558,5.55,4700],[8.347,-71.266,6.13,8250],[8.616,-52.373,5.57,7050],[8.73,13.371,6.4,5000],[8.812,-3.593,5.2,6300],[8.887,-0.506,5.93,6750],[9.035,54.169,5.08,16000],[8.978,13.207,6.41,6450],[9.114,60.326,5.79,9000],[8.921,-48.001,5.51,6600],[8.889,-54.822,6.06,5000],[9.083,27.255,6.5,14000],[9.012,-14.974,6.45,5100],[9.029,-22.842,6.06,8500],[9.194,44.489,5.13,4250],[9.243,53.897,3.66,26000],[9.22,33.719,4.36,20000],[9.197,15.232,5.89,26000],[9.28,24.014,6.47,4700],[9.338,35.399,5.48,5800],[9.947,82.494,6.4,6600],[9.336,-24.767,5.57,5200],[9.156,-65.125,6.42,4700],[9.377,3.135,6.39,4400],[9.325,-54.394,6.41,5000],[9.639,29.312,4.37,5400],[9.791,49.354,5.43,3950],[9.832,30.861,3.27,4550],[9.841,21.251,5.87,5000],[9.982,21.438,5.36,5000],[10.127,56.537,2.23,5000],[9.967,-44.797,6.01,4850],[10.119,-16.517,6.49,5500],[10.137,-23.804,6.14,5700],[10.177,-4.352,5.91,5000],[10.28,39.459,5.33,5200],[10.11,-59.454,5.89,5900],[10.514,66.148,5.83,5100],[10.4,24.629,6.04,8250],[10.516,50.513,4.8,26000],[10.332,-46.085,4.59,5200],[10.63,58.753,6.17,12000],[10.443,-56.502,5.7,8750],[10.867,47.025,4.94,8750],[10.679,-38.463,6.06,10000],[10.674,-60.263,5.98,4250],[10.618,-65.468,5.39,6600],[10.898,-17.987,2.04,5100],[11.11,47.864,5.67,20000],[10.959,-12.012,6.02,4700],[10.838,-57.463,4.36,10000],[11.412,74.988,5.66,9500],[11.181,48.284,4.54,20000],[11.047,-10.609,4.76,5000],[11.05,-38.422,5.9,4850],[11.322,55.222,5.42,9500],[11.185,-22.006,5.24,7350],[11.238,-42.677,5.94,7500],[11.135,-62.498,6.07,6750],[11.663,69.325,6.33,7050],[11.35,-4.629,6.15,3500],[11.25,-53.715,6.15,6450],[11.37,-12.881,6.15,6000],[11.563,55.305,6.52,9500],[11.545,44.861,6.05,12000],[11.424,-16.424,6.47,7350],[11.677,59.574,6.39,6000],[11.942,74.847,5.41,14000],[11.44,-47.552,5.8,5900],[11.549,-22.52Line truncated
-6
View File
@@ -1,6 +0,0 @@
/**
* @license
* Copyright 2010-2021 Three.js Authors
* SPDX-License-Identifier: MIT
*/
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).THREE={})}(this,(function(t){"use strict";const e="128",n=100,i=300,r=301,s=302,a=303,o=304,l=306,c=307,h=1e3,u=1001,d=1002,p=1003,m=1004,f=1005,g=1006,v=1007,y=1008,x=1009,_=1012,w=1014,b=1015,M=1016,S=1020,T=1022,E=1023,A=1026,L=1027,R=33776,C=33777,P=33778,D=33779,I=35840,N=35841,B=35842,z=35843,F=37492,O=37496,H=2300,G=2301,U=2302,k=2400,V=2401,W=2402,j=2500,q=2501,X=3e3,Y=3001,Z=3007,J=3002,Q=3004,K=3005,$=3006,tt=7680,et=35044,nt=35048,it="300 es";class rt{addEventListener(t,e){void 0===this._listeners&&(this._listeners={});const n=this._listeners;void 0===n[t]&&(n[t]=[]),-1===n[t].indexOf(e)&&n[t].push(e)}hasEventListener(t,e){if(void 0===this._listeners)return!1;const n=this._listeners;return void 0!==n[t]&&-1!==n[t].indexOf(e)}removeEventListener(t,e){if(void 0===this._listeners)return;const n=this._listeners[t];if(void 0!==n){const t=n.indexOf(e);-1!==t&&n.splice(t,1)}}dispatchEvent(t){if(void 0===this._listeners)return;const e=this._listeners[t.type];if(void 0!==e){t.target=this;const n=e.slice(0);for(let e=0,i=n.length;e<i;e++)n[e].call(this,t);t.target=null}}}const st=[];for(let t=0;t<256;t++)st[t]=(t<16?"0":"")+t.toString(16);let at=1234567;const ot=Math.PI/180,lt=180/Math.PI;function ct(){const t=4294967295*Math.random()|0,e=4294967295*Math.random()|0,n=4294967295*Math.random()|0,i=4294967295*Math.random()|0;return(st[255&t]+st[t>>8&255]+st[t>>16&255]+st[t>>24&255]+"-"+st[255&e]+st[e>>8&255]+"-"+st[e>>16&15|64]+st[e>>24&255]+"-"+st[63&n|128]+st[n>>8&255]+"-"+st[n>>16&255]+st[n>>24&255]+st[255&i]+st[i>>8&255]+st[i>>16&255]+st[i>>24&255]).toUpperCase()}function ht(t,e,n){return Math.max(e,Math.min(n,t))}function ut(t,e){return(t%e+e)%e}function dt(t,e,n){return(1-n)*t+n*e}function pt(t){return 0==(t&t-1)&&0!==t}function mt(t){return Math.pow(2,Math.ceil(Math.log(t)/Math.LN2))}function ft(t){return Math.pow(2,Math.floor(Math.log(t)/Math.LN2))}var gt=Object.freeze({__proto__:null,DEG2RAD:ot,RAD2DEG:lt,generateUUID:ct,clamp:ht,euclideanModulo:ut,mapLinear:function(t,e,n,i,r){return i+(t-e)*(r-i)/(n-e)},inverseLerp:function(t,e,n){return t!==e?(n-t)/(e-t):0},lerp:dt,damp:function(t,e,n,i){return dt(t,e,1-Math.exp(-n*i))},pingpong:function(t,e=1){return e-Math.abs(ut(t,2*e)-e)},smoothstep:function(t,e,n){return t<=e?0:t>=n?1:(t=(t-e)/(n-e))*t*(3-2*t)},smootherstep:function(t,e,n){return t<=e?0:t>=n?1:(t=(t-e)/(n-e))*t*t*(t*(6*t-15)+10)},randInt:function(t,e){return t+Math.floor(Math.random()*(e-t+1))},randFloat:function(t,e){return t+Math.random()*(e-t)},randFloatSpread:function(t){return t*(.5-Math.random())},seededRandom:function(t){return void 0!==t&&(at=t%2147483647),at=16807*at%2147483647,(at-1)/2147483646},degToRad:function(t){return t*ot},radToDeg:function(t){return t*lt},isPowerOfTwo:pt,ceilPowerOfTwo:mt,floorPowerOfTwo:ft,setQuaternionFromProperEuler:function(t,e,n,i,r){const s=Math.cos,a=Math.sin,o=s(n/2),l=a(n/2),c=s((e+i)/2),h=a((e+i)/2),u=s((e-i)/2),d=a((e-i)/2),p=s((i-e)/2),m=a((i-e)/2);switch(r){case"XYX":t.set(o*h,l*u,l*d,o*c);break;case"YZY":t.set(l*d,o*h,l*u,o*c);break;case"ZXZ":t.set(l*u,l*d,o*h,o*c);break;case"XZX":t.set(o*h,l*m,l*p,o*c);break;case"YXY":t.set(l*p,o*h,l*m,o*c);break;case"ZYZ":t.set(l*m,l*p,o*h,o*c);break;default:console.warn("THREE.MathUtils: .setQuaternionFromProperEuler() encountered an unknown order: "+r)}}});class vt{constructor(t=0,e=0){this.x=t,this.y=e}get width(){return this.x}set width(t){this.x=t}get height(){return this.y}set height(t){this.y=t}set(t,e){return this.x=t,this.y=e,this}setScalar(t){return this.x=t,this.y=t,this}setX(t){return this.x=t,this}setY(t){return this.y=t,this}setComponent(t,e){switch(t){case 0:this.x=e;break;case 1:this.y=e;break;default:throw new Error("index is out of range: "+t)}return this}getComponent(t){switch(t){case 0:return this.x;case 1:return this.y;default:throw new Error("index is out of range: "+t)}}clone(){return new this.constructor(this.x,this.y)}copy(t){return this.x=t.x,this.y=t.y,this}add(t,e){return void 0!==e?(console.warn("THREE.Vector2: .add() now only accepts one argument. Use .addVectors( a, b ) instead."),this.addVectors(t,e)):(this.x+=t.x,this.y+=t.y,this)}addScalar(t){return this.x+=t,this.y+=t,this}addVectors(t,e){return this.x=t.x+e.x,this.y=t.y+e.y,this}addScaledVector(t,e){return this.x+=t.x*e,this.y+=t.y*e,this}sub(t,e){return void 0!==e?(console.warn("THREE.Vector2: .sub() now only accepts one argument. Use .subVectors( a, b ) instead."),this.subVectors(t,e)):(this.x-=t.x,this.y-=t.y,this)}subScalar(t){return this.x-=t,this.y-=t,this}subVectors(t,e){return this.x=t.x-e.x,this.y=t.y-e.y,this}multiply(t){return this.x*=t.x,this.y*=t.y,this}multiplyScalar(t){return this.x*=t,this.y*=t,this}divide(t){return this.x/=t.x,this.y/=t.y,this}divideScalar(t){return this.multiplyScalar(1/t)}applyMatrix3(t){const e=tLine truncated
-1
View File
@@ -1 +0,0 @@
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports._vantaEffect=t():e._vantaEffect=t()}("undefined"!=typeof self?self:this,(function(){return function(e){var t={};function n(i){if(t[i])return t[i].exports;var o=t[i]={i:i,l:!1,exports:{}};return e[i].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=e,n.c=t,n.d=function(e,t,i){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:i})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var i=Object.create(null);if(n.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(i,o,function(t){return e[t]}.bind(null,o));return i},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=6)}([function(e,t,n){"use strict";function i(e,t){for(let n in t)t.hasOwnProperty(n)&&(e[n]=t[n]);return e}function o(){return"undefined"!=typeof navigator?/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)||window.innerWidth<600:null}n.d(t,"c",(function(){return i})),n.d(t,"e",(function(){return o})),n.d(t,"i",(function(){return s})),n.d(t,"h",(function(){return r})),n.d(t,"g",(function(){return a})),n.d(t,"f",(function(){return h})),n.d(t,"a",(function(){return c})),n.d(t,"b",(function(){return u})),n.d(t,"d",(function(){return l})),Number.prototype.clamp=function(e,t){return Math.min(Math.max(this,e),t)};const s=e=>e[Math.floor(Math.random()*e.length)];function r(e,t){return null==e&&(e=0),null==t&&(t=1),e+Math.random()*(t-e)}function a(e,t){return null==e&&(e=0),null==t&&(t=1),Math.floor(e+Math.random()*(t-e+1))}const h=e=>document.querySelector(e),c=e=>"number"==typeof e?"#"+("00000"+e.toString(16)).slice(-6):e,u=(e,t=1)=>{const n=c(e),i=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(n),o=i?{r:parseInt(i[1],16),g:parseInt(i[2],16),b:parseInt(i[3],16)}:null;return"rgba("+o.r+","+o.g+","+o.b+","+t+")"},l=e=>.299*e.r+.587*e.g+.114*e.b},function(e,t,n){"use strict";n.d(t,"a",(function(){return r}));var i=n(0);const o="object"==typeof window;let s=o&&window.THREE||{};o&&!window.VANTA&&(window.VANTA={});const r=o&&window.VANTA||{};r.register=(e,t)=>r[e]=e=>new t(e),r.version="0.5.21";const a=function(){return Array.prototype.unshift.call(arguments,"[VANTA]"),console.error.apply(this,arguments)};r.VantaBase=class{constructor(e={}){if(!o)return!1;r.current=this,this.windowMouseMoveWrapper=this.windowMouseMoveWrapper.bind(this),this.windowTouchWrapper=this.windowTouchWrapper.bind(this),this.windowGyroWrapper=this.windowGyroWrapper.bind(this),this.resize=this.resize.bind(this),this.animationLoop=this.animationLoop.bind(this),this.restart=this.restart.bind(this);const t="function"==typeof this.getDefaultOptions?this.getDefaultOptions():this.defaultOptions;if(this.options=Object(i.c)({mouseControls:!0,touchControls:!0,gyroControls:!1,minHeight:200,minWidth:200,scale:1,scaleMobile:1},t),(e instanceof HTMLElement||"string"==typeof e)&&(e={el:e}),Object(i.c)(this.options,e),this.options.THREE&&(s=this.options.THREE),this.el=this.options.el,null==this.el)a('Instance needs "el" param!');else if(!(this.options.el instanceof HTMLElement)){const e=this.el;if(this.el=Object(i.f)(e),!this.el)return void a("Cannot find element",e)}this.prepareEl(),this.initThree(),this.setSize();try{this.init()}catch(e){return a("Init error",e),this.renderer&&this.renderer.domElement&&this.el.removeChild(this.renderer.domElement),void(this.options.backgroundColor&&(console.log("[VANTA] Falling back to backgroundColor"),this.el.style.background=Object(i.a)(this.options.backgroundColor)))}this.initMouse(),this.resize(),this.animationLoop();const n=window.addEventListener;n("resize",this.resize),window.requestAnimationFrame(this.resize),this.options.mouseControls&&(n("scroll",this.windowMouseMoveWrapper),n("mousemove",this.windowMouseMoveWrapper)),this.options.touchControls&&(n("touchstart",this.windowTouchWrapper),n("touchmove",this.windowTouchWrapper)),this.options.gyroControls&&n("deviceorientation",this.windowGyroWrapper)}setOptions(e={}){Object(i.c)(this.options,e),this.triggerMouseMove()}prepareEl(){let e,t;if("undefined"!=typeof Node&&Node.TEXT_NODE)for(e=0;e<this.el.childNodes.length;e++){const t=this.el.childNodes[e];if(t.nodeType===Node.TEXT_NODE){const e=document.createElement("span");e.textContent=t.textContent,t.parentElement.insertBefore(e,t),t.remove()}}for(e=0;e<this.el.children.length;e++)t=this.el.children[e],"static"===getComputedStyle(t).position&&(t.style.position="relative"),"auto"===getComputedStyle(t).zIndex&&(t.style.zIndex=1);"Line truncated
-1
View File
@@ -1 +0,0 @@
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports._vantaEffect=t():e._vantaEffect=t()}("undefined"!=typeof self?self:this,(function(){return function(e){var t={};function i(o){if(t[o])return t[o].exports;var s=t[o]={i:o,l:!1,exports:{}};return e[o].call(s.exports,s,s.exports,i),s.l=!0,s.exports}return i.m=e,i.c=t,i.d=function(e,t,o){i.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:o})},i.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,t){if(1&t&&(e=i(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var o=Object.create(null);if(i.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var s in e)i.d(o,s,function(t){return e[t]}.bind(null,s));return o},i.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(t,"a",t),t},i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.p="",i(i.s=7)}([function(e,t,i){"use strict";function o(e,t){for(let i in t)t.hasOwnProperty(i)&&(e[i]=t[i]);return e}function s(){return"undefined"!=typeof navigator?/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)||window.innerWidth<600:null}i.d(t,"c",(function(){return o})),i.d(t,"e",(function(){return s})),i.d(t,"i",(function(){return n})),i.d(t,"h",(function(){return r})),i.d(t,"g",(function(){return h})),i.d(t,"f",(function(){return a})),i.d(t,"a",(function(){return u})),i.d(t,"b",(function(){return c})),i.d(t,"d",(function(){return l})),Number.prototype.clamp=function(e,t){return Math.min(Math.max(this,e),t)};const n=e=>e[Math.floor(Math.random()*e.length)];function r(e,t){return null==e&&(e=0),null==t&&(t=1),e+Math.random()*(t-e)}function h(e,t){return null==e&&(e=0),null==t&&(t=1),Math.floor(e+Math.random()*(t-e+1))}const a=e=>document.querySelector(e),u=e=>"number"==typeof e?"#"+("00000"+e.toString(16)).slice(-6):e,c=(e,t=1)=>{const i=u(e),o=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(i),s=o?{r:parseInt(o[1],16),g:parseInt(o[2],16),b:parseInt(o[3],16)}:null;return"rgba("+s.r+","+s.g+","+s.b+","+t+")"},l=e=>.299*e.r+.587*e.g+.114*e.b},function(e,t,i){"use strict";i.d(t,"a",(function(){return r}));var o=i(0);const s="object"==typeof window;let n=s&&window.THREE||{};s&&!window.VANTA&&(window.VANTA={});const r=s&&window.VANTA||{};r.register=(e,t)=>r[e]=e=>new t(e),r.version="0.5.21";const h=function(){return Array.prototype.unshift.call(arguments,"[VANTA]"),console.error.apply(this,arguments)};r.VantaBase=class{constructor(e={}){if(!s)return!1;r.current=this,this.windowMouseMoveWrapper=this.windowMouseMoveWrapper.bind(this),this.windowTouchWrapper=this.windowTouchWrapper.bind(this),this.windowGyroWrapper=this.windowGyroWrapper.bind(this),this.resize=this.resize.bind(this),this.animationLoop=this.animationLoop.bind(this),this.restart=this.restart.bind(this);const t="function"==typeof this.getDefaultOptions?this.getDefaultOptions():this.defaultOptions;if(this.options=Object(o.c)({mouseControls:!0,touchControls:!0,gyroControls:!1,minHeight:200,minWidth:200,scale:1,scaleMobile:1},t),(e instanceof HTMLElement||"string"==typeof e)&&(e={el:e}),Object(o.c)(this.options,e),this.options.THREE&&(n=this.options.THREE),this.el=this.options.el,null==this.el)h('Instance needs "el" param!');else if(!(this.options.el instanceof HTMLElement)){const e=this.el;if(this.el=Object(o.f)(e),!this.el)return void h("Cannot find element",e)}this.prepareEl(),this.initThree(),this.setSize();try{this.init()}catch(e){return h("Init error",e),this.renderer&&this.renderer.domElement&&this.el.removeChild(this.renderer.domElement),void(this.options.backgroundColor&&(console.log("[VANTA] Falling back to backgroundColor"),this.el.style.background=Object(o.a)(this.options.backgroundColor)))}this.initMouse(),this.resize(),this.animationLoop();const i=window.addEventListener;i("resize",this.resize),window.requestAnimationFrame(this.resize),this.options.mouseControls&&(i("scroll",this.windowMouseMoveWrapper),i("mousemove",this.windowMouseMoveWrapper)),this.options.touchControls&&(i("touchstart",this.windowTouchWrapper),i("touchmove",this.windowTouchWrapper)),this.options.gyroControls&&i("deviceorientation",this.windowGyroWrapper)}setOptions(e={}){Object(o.c)(this.options,e),this.triggerMouseMove()}prepareEl(){let e,t;if("undefined"!=typeof Node&&Node.TEXT_NODE)for(e=0;e<this.el.childNodes.length;e++){const t=this.el.childNodes[e];if(t.nodeType===Node.TEXT_NODE){const e=document.createElement("span");e.textContent=t.textContent,t.parentElement.insertBefore(e,t),t.remove()}}for(e=0;e<this.el.children.length;e++)t=this.el.children[e],"static"===getComputedStyle(t).position&&(t.style.position="relative"),"auto"===getComputedStyle(t).zIndex&&(t.style.zIndex=1);"Line truncated