From 9027099d89058ceac6dc8369ff224cbc77009b49 Mon Sep 17 00:00:00 2001 From: Richard Zink Date: Wed, 7 Oct 2026 21:50:31 +0200 Subject: [PATCH] Add #flight=N|NE|E|SE|S|SW|W|NW URL parameter for corridor direction Adds 8 compass directions for the tile-build axis. Camera position, corridor rotation, and refetch math all read from window.__flightDir. Test URLs: #flight=N north (default, +Z, current behaviour) #flight=E east (+X) #flight=S south (-Z) #flight=W west (-X) #flight=NE northeast (diagonal) #flight=SE southeast #flight=SW southwest #flight=NW northwest Renders with no hash unchanged. Each direction rotates the corridor so its long axis follows the chosen compass bearing, and the camera drifts along that bearing. --- background.html | 15 +++++++++++++++ vendor/clouds3d.js | 26 ++++++++++++++++++-------- 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/background.html b/background.html index 49ac6af..fedf31b 100644 --- a/background.html +++ b/background.html @@ -516,6 +516,21 @@ var noiseDataUri = 'data:image/png;base64,PLACEHOLDER'; // URL override for easy A/B testing: #renderer=clouds2d / #renderer=clouds3d var _urlRenderer = (location.hash.match(/renderer=(\w+)/) || [])[1]; var renderer = _urlRenderer || (window.CONFIG && window.CONFIG.renderer) || 'vanta'; + +// Flight direction for ground-tile corridor (N, NE, E, SE, S, SW, W, NW). +// Default 'N' (= +Z world) so behaviour is unchanged when hash is absent. +var _urlFlight = (location.hash.match(/flight=(\w+)/) || [])[1]; +var FLIGHT_DIRS = { + N: { cos: 0.0, sin: 1.0, dx: 0, dz: 1 }, + NE: { cos: 0.7071068, sin: 0.7071068, dx: 0.7071068, dz: 0.7071068 }, + E: { cos: 1.0, sin: 0.0, dx: 1, dz: 0 }, + SE: { cos: 0.7071068, sin:-0.7071068, dx: 0.7071068, dz:-0.7071068 }, + S: { cos: 0.0, sin:-1.0, dx: 0, dz:-1 }, + SW: { cos:-0.7071068, sin:-0.7071068, dx:-0.7071068, dz:-0.7071068 }, + W: { cos:-1.0, sin: 0.0, dx:-1, dz: 0 }, + NW: { cos:-0.7071068, sin: 0.7071068, dx:-0.7071068, dz: 0.7071068 } +}; +window.__flightDir = FLIGHT_DIRS[_urlFlight && FLIGHT_DIRS[_urlFlight.toUpperCase()] ? _urlFlight.toUpperCase() : 'N']; var useVanta = (renderer !== 'clouds2d' && renderer !== 'clouds3d'); var effect; if (useVanta && typeof VANTA !== 'undefined') { diff --git a/vendor/clouds3d.js b/vendor/clouds3d.js index c779ff5..e8e0fb4 100644 --- a/vendor/clouds3d.js +++ b/vendor/clouds3d.js @@ -139,7 +139,11 @@ var FRAG_SRC = [ 'float drift = uTime * uSpeed * 0.12;', // Fixed altitude well above the cloud ceiling (y=1.5). 'float camY = 2.2;', - 'vec3 ro = vec3(0.0, camY, drift);', + // Camera position follows window.__flightDir (set from URL #flight=...). + // Default: drift along +Z (north). For east: drift along +X. For south: -Z, etc. + 'float fdx = (window.__flightDir ? window.__flightDir.dx : 0.0);', + 'float fdz = (window.__flightDir ? window.__flightDir.dz : 1.0);', + 'vec3 ro = vec3(drift * fdx, camY, drift * fdz);', // Ray direction: tilt more downward so the visible ground fits // within the mosaic. At uv.y = 0 the ray goes ~26° below // horizontal, putting the visible ground at tGround < 5 @@ -281,10 +285,11 @@ function init(canvas) { var GROUND_TILE_URL = 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/'; var GROUND_TILE_Z = 11; var GROUND_TILE_SIZE = 256; -// Camera travels in +Z (forward) and looks in +Z (also forward). -// The corridor is aligned with both motion and look direction. -var GROUND_TRAVEL_COS = 0.0; // cos(90 deg) -var GROUND_TRAVEL_SIN = 1.0; // sin(90 deg) +// Camera flight direction. Set from window.__flightDir (URL: #flight=N|NE|E|...). +// Default is N (= +Z forward). Each flight direction rotates the +// corridor so its long axis follows the camera path. +var GROUND_TRAVEL_COS = (window.__flightDir && window.__flightDir.cos) || 0.0; +var GROUND_TRAVEL_SIN = (window.__flightDir && window.__flightDir.sin) || 1.0; var GROUND_CORRIDOR_LONG = 25; // tiles along travel direction (~3.5 min of flight at uSpeed=1) var GROUND_CORRIDOR_PERP = 5; // tiles perpendicular to travel var GROUND_BUFFER_LONG = 11; // refetch when this close to forward edge @@ -375,8 +380,13 @@ function rebuildGroundMosaic(centerTileX, centerTileY) { // Called periodically from the render loop with the camera world // position. Re-centres the mosaic if we're approaching its edge. function maybeRefetchGround(cameraWorldX, cameraWorldZ, gl) { - var cameraTileX = GROUND_BASE_X + Math.floor(cameraWorldX); - var cameraTileY = GROUND_BASE_Y + Math.floor(cameraWorldZ); + var fdx = (window.__flightDir && window.__flightDir.dx) || 0; + var fdz = (window.__flightDir && window.__flightDir.dz) || 1; + // Camera position in world (X, Z) from the dominant flight direction + var camX = (fdx !== 0) ? cameraWorldX * fdx : 0; + var camZ = (fdz !== 0) ? cameraWorldZ * fdz : 0; + var cameraTileX = GROUND_BASE_X + Math.floor(camX); + var cameraTileY = GROUND_BASE_Y + Math.floor(camZ); // Project camera offset onto the corridor's rotated axes. // With GROUND_TRAVEL_COS/SIN = (0, 1) the corridor runs along // +Z (camera's motion + look direction). @@ -536,7 +546,7 @@ window.clouds3dRender = function(target) { var drift = now * speed * 0.12; if (performance.now() - groundLastCheck > 1500) { groundLastCheck = performance.now(); - maybeRefetchGround(drift, drift * 0.7, gl); + maybeRefetchGround(drift, drift, gl); } gl.drawArrays(gl.TRIANGLES, 0, 3);