Commit Graph
104 Commits
Author SHA1 Message Date
Richard Zink efd4db47cb geo: cell manifest geo/cells_v1 - cached road/place fast paths check one small record instead of reading every multi-megabyte raw cell 2026-10-11 21:34:52 +02:00
Richard Zink 6d21b37e8f progress logs behind CONFIG.debug, CONFIG.antialias + high-performance context, cheaper cloud sampling (skip far detail octave and redundant self-shading probe), brighter night contrails via CONFIG.flights.contrailNight, window.__flightDbg counters, real sun/moon by default 2026-10-11 18:42:48 +02:00
Richard Zink 113e4c522d airliner mesh is generated in-repo: tools/plane_gen.py writes vendor/plane3d.js (480 tris, CC0, same unit extent as the old Grab3D derivative); attribution updated 2026-10-11 18:42:48 +02:00
Richard Zink 499c00d8b1 standalone without our server: basemap and DEM load from the CORS-enabled upstreams, same-origin proxy only when a probe proves it exists; drop dead kumi.systems mirror 2026-10-11 16:02:10 +02:00
Richard Zink 4369afd3ef lighting: remove the palette terrain model - physics is the only lighting, themes tint it through THEMES[theme].lighting; debug panel shows the active palette and its tint/gain; credits no longer claim VIIRS 2026-10-11 15:39:42 +02:00
Richard Zink 6eb25bdd03 physical lighting, volumetric clouds, terrain shadows, pixel-art render scale
- atmosphere: physical terrain lighting (air mass, Rayleigh beam colour,
  skylight, moon, starlight floor), aerial perspective for terrain and
  cloud deck, configurable haze/albedo/ambient gains
- clouds: march the deck in height instead of ray distance, IGN dither
  (no per-frame flicker), per-step height jitter, 4-octave fbm renormalised,
  softer density threshold, distance softening as a procedural mip,
  grazing path clamp, cloud shadows on the ground (cloudShadowDensity/
  Floor/Ambient) and cloud haze factor
- terrain: self-shadows from the elevation field (penumbra + shadow floor),
  soft mosaic rim (edgeFadeTiles), east/west axis corrected (+X = west)
- lights: per-object twilight switching for cars, city dots and ground blocks
- flights: contrail width 620 m, fade to zero by contrailFadeKm, aircraft
  size decoupled from trail width, count halved
- render: CONFIG.renderScale with integer upscale + image-rendering: pixelated
- data: nginx overpass proxy + cache, per-mirror cooldown ladder, ring-based
  cell ordering (disc fills evenly), settlements fetched before roads,
  interim chain persistence, two worker lanes (car/city) with progress logs
- removed: NASA VIIRS night-lights layer (fetch, canvas, texture, uniforms)
2026-10-11 15:04:21 +02:00
Richard Zink cd460ec100 city lights: report buildMs in __cityDbg (measured: 17.5k places -> 46.7k points in 1.5ms) 2026-10-10 14:30:32 +02:00
Richard Zink 75dc5ed5b9 overpass: drop dead kumi.systems mirror (500 + no CORS) from endpoint ladder 2026-10-10 13:46:49 +02:00
Richard Zink 73d5c3f6a7 settlements: drop costly relation tier from place query (timed whole cells out), 3 mirror rounds with jitter, per-cell progress log; verified live: 1747 places -> 3855 lights 2026-10-10 13:37:35 +02:00
Richard Zink aebe311e32 cache derived geometry: merged road chains + settlement list persisted with cell fingerprints; two-tier best-first road stitching (raw-node headings, permissive interchange pass); fast path skips all raw parsing on unchanged data 2026-10-10 13:15:03 +02:00
Richard Zink 26bd5bbc59 contrails: keep visible at night as dimmed moonlit streaks (42% of night ramp); city debug counter + pending-terrain log 2026-10-10 11:50:07 +02:00
Richard Zink 1879a6912a contrails: distance-scaled ribbon width (sub-pixel fix), brighter head, far longer visible range 2026-10-10 11:12:38 +02:00
Richard Zink d0aa86ce9b flights: full CONFIG.flights parameterization (altitude, count, speed, holds, destination weights, contrail chance/alt/life/width) + curved random-destination routing 2026-10-10 11:02:58 +02:00
Richard Zink fbac24773a clouds3d-only cleanup: drop Vanta/three.js/clouds2d, real-sky fixes, settlement lights, dynamic location anchor 2026-10-09 14:13:03 +02:00
Richard Zink e4170bee62 X-swap via arrangement, no image X-flip
User clarified: the X-swap should be in the ARRANGEMENT (east
tiles on screen right), NOT in the image (so map content is
readable). Previous attempts had it the other way around.

Combined state:
- canvasX = -perp + ... (X-swap): east (1102) on screen right,
  west (1098) on screen left. x increases left to right.
- drawImage with positive width: no image X-flip. Map content
  reads normally, place names not mirrored.
- Labels in normal orientation.

So the X mirror is in the corridor arrangement, not in the
satellite image content. The user can read the map normally.
2026-10-08 10:29:08 +02:00
Richard Zink f0641bd4bd Activate X-flip on image: negative width in drawImage 2026-10-08 10:26:09 +02:00
Richard Zink 0a770ba1be Remove all X mirrors: natural order, no flip
Final state per user request (KEIN X-Swap, KEIN X-Flip):
- canvasX = (perp + halfPerp + 0.5) * TILE_SIZE: east (1102)
  at canvasX 128 (left), west (1098) at canvasX 1152 (right).
  Natural order with no swap.
- drawImage with positive width and height: map content reads
  normally, no X-flip on the image.
- Labels in normal orientation (no mirrorLabel).

Map is now fully natural: no X swap, no X flip, no mirror label.
Both the arrangement and image content are in standard orientation.
2026-10-08 09:58:54 +02:00
Richard Zink f79e27665c Re-add X-flip on image (NS-mirror) with natural order arrangement
The user wants:
- Natural order arrangement (canvasX = perp + ...): east (1102)
  on left, west (1098) on right
- X-mirrored image (NS-mirror): within each tile, the image east
  appears on the left of the tile (natural map orientation)

Combined state:
- canvasX = (perp + halfPerp + 0.5) * 256: natural order
- drawImage with negative width: X-flip (NS-mirror)
- All labels in normal orientation (no mirrorLabel)

This matches the user's description: 'die anordnung passt' (arrangement
correct) and 'der x-flip ist immer noch falsch' (image was still
mirrored, now correctly mirrored).
2026-10-08 09:53:56 +02:00
Richard Zink 20ac76e0b1 Revert X-swap: natural order (no image X-flip)
User wanted NO X-swap and NO image X-flip:
- canvasX = (perp + 2.5) * 256 (no negation): east (perp=-2)
  at canvasX 128 (left), west (perp=+2) at canvasX 1152 (right)
- Image drawn with positive width (no X-flip): map content
  reads normally (place names, street names not mirrored)

The X coordinates read in their natural geographic order:
- left = high x (east), right = low x (west)

If the user is observing from a south-facing view (cockpit facing
back), their right is the world's left (east), so they see
high x on their right (world's left). x still reads correctly
when facing the same direction as the flight.

The arrangement is now back to the natural order with no
swapping in either direction.
2026-10-08 09:51:32 +02:00
Richard Zink b5b169ae80 Add version marker + wider canvas for X-swap labels
Add explicit X-swap marker comment so the user can verify they're
seeing the new build. Bump canvas width by 2*256 padding so the
X labels (drawn at canvasX + 244) are within the canvas even for
the rightmost drawn tile (east, perp=-2 -> canvasX 1152, label
at 1396). With wider canvas (1792 vs 1280), labels are visible
and the corridor is centred.
2026-10-08 09:47:04 +02:00
Richard Zink bac0397140 Remove X-flip from image: map content reads normally
The user wants the original tile content (map) to be readable
normally, not X-mirrored. The X-swap arrangement (canvasX = -perp
+ ...) places east tiles on the right of the screen, so X coordinates
read naturally left to right when scanning the corridor.

Combined state:
- Map content (image): drawn with normal orientation (no X-flip)
- Arrangement: east on right, west on left (X-swap)
- Labels: drawn in normal orientation in the corners
- Y-swap: north tiles (lng=+12) at canvas top -> screen top
2026-10-08 09:35:02 +02:00
Richard Zink 00e59983bf Re-add X-flip on image: NS-mirror tile content
The user wanted the tile content to be NS-mirrored (X-flip
on the image) so the corridor orientation matches. The labels
are drawn separately in normal orientation, so they read
normally. Now the arrangement has:
- canvasX = -perp + ... (X-swap): east tiles on screen right
- Image X-flipped (NS-mirror): image east at left of tile
- Labels in corners drawn normally: x=1102, y=707 readable

Combining these, the user looking at the screen sees:
- screen left: west tiles (low x), with image west on the right
- screen right: east tiles (high x), with image east on the left
- All labels readable

So the X coordinates read correctly when the eye scans left
to right across the corridor, and the image content is
NS-mirrored to match the corridor's direction of travel.
2026-10-08 09:32:33 +02:00
Richard Zink 97e37e065a Remove X-flip on image: tiles now read normally
The user wanted the image content to be readable (not X-flipped).
The X-swap arrangement (canvasX = -perp + ...) already places east
tiles on the right side of the screen, so the X arrangement
reads naturally left to right without needing the image to be
flipped.

The image is now drawn with positive width and height, so
place names, street names, and the coordinates labels (x=NNN,
y=NNN) are all readable. The X-swap arrangement positions the
tiles so that:
- west tiles (low x) drawn at canvas left
- east tiles (high x) drawn at canvas right

So the X coordinates increase left to right when reading the
corridor from screen left to screen right.
2026-10-08 09:30:36 +02:00
Richard Zink e33598476a Labels in normal orientation (not X-mirrored)
User wanted the image to be X-mirrored (NS-mirror, so place
names on a map are correctly mirrored for the corridor
orientation), but the text labels to be readable normally.

Now labels are drawn in normal orientation:
- N at top-left
- S at bottom-left
- y at top-right
- x at bottom-right

The text is no longer reversed. With the corridor's X-swap
arrangement, this means:
- screen left = west tiles (low x)
- screen right = east tiles (high x)
- within each tile, the image is X-mirrored, but the text
  inside is readable
2026-10-08 09:28:28 +02:00
Richard Zink 2128220b39 Fix misleading comment: image is X-flipped (NS-mirror), not 180°
The drawImage call uses width=-TILE, height=+TILE, which is an
X-only horizontal mirror. The old comment said '180 degrees'
which implied both axes flipped; the code is only horizontal.
NS axis = vertical axis, mirror across it = horizontal mirror.
Current state matches the user's observation: tile content
is NS-mirrored, X arrangement goes low->high left to right.
2026-10-08 09:18:58 +02:00
Richard Zink 4500fe3214 Switch to ESRI World_Street_Map via local CORS proxy
Carto Voyager was returning 'API Key required' content for the
user (likely rate-limited or IP-blocked by Carto). Switched to
ESRI World_Street_Map which has CORS-friendly tiles with plenty
of place names and street labels.

URL format is different from Carto: {z}/{y}/{x}.jpg (y before x,
jpg not png). Updated the build to match. The local /esri/
proxy in default.conf handles the upstream CORS-incompatibility
by adding permissive CORS headers and a proper User-Agent.
2026-10-08 09:17:15 +02:00
Richard Zink e0c6b685ad Fix missing .png extension in tile URL 2026-10-08 09:11:29 +02:00
Richard Zink f55d96f462 Local CORS proxy: nginx forwards /carto/ to a.basemaps.cartocdn.com
Direct fetching from a.basemaps.cartocdn.com was returning
stripped/missing CORS headers in the user's browser, blocking
the img.src load. Even with cache-busters the failure persisted.

Solution: local nginx proxy at /carto/ that forwards to the
upstream and always adds Access-Control-Allow-Origin: *.

Key detail: the 'resolver' directive is required inside the
proxy_pass location block so nginx can resolve the upstream
hostname. Without it, the location block silently fails (the
'/' location falls through to try_files ... =404, and the
~*\.(png|jpg)$ regex also matches and silently fails for GETs).

Also added 'location ^~ /carto/' to give prefix matching strict
priority over the .png regex match that was stealing the request.

JS now uses /carto/voyager/ (relative URL through the same
origin) so CORS preflight is not even needed.
2026-10-08 08:57:33 +02:00
Richard Zink 83fd829cd5 Cache-buster + remove diagnostic logs
User's browser showed 404 and CORS errors for Carto tiles
even though curl shows the URLs return 200 with CORS headers.
Most likely the browser had cached earlier failed attempts.

Added a per-tile cache-buster (?v=Date.now()+random) to the
fetch URL so every tile request bypasses the browser's HTTP
cache. Removed the diagnostic console.log lines since the
issue is identified (browser cache).
2026-10-08 08:42:43 +02:00
Richard Zink 7c7c882aa1 Add console diagnostics for tile loading 2026-10-08 08:37:39 +02:00
Richard Zink 262d308a5a Switch from ESRI satellite to Carto Voyager map tiles
User wants tiles with place names (Stadt-/Strassennamen) for
orientation while flying. ESRI World Imagery is satellite (no
labels); OSM rejects browser requests without a proper User-Agent
header (which browsers cannot set for img.src).

Carto basemaps is the right alternative:
- Free, no API key required
- CORS enabled (works directly in browser via img.src)
- OSM-derived data, so it has all the same place names
- URL format: {z}/{x}/{y}.png (x before y, unlike ESRI's {z}/{y}/{x})

Voyager style chosen for good legibility of place names and
streets. Other Carto styles (light_all, dry_lite, etc.) are also
available; just change the URL path.

Swapped tileX/tileY in the fetch URL to match Carto's {x}/{y}
order (ESRI used {y}/{x}).

Attribution: (c) OpenStreetMap contributors (c) CARTO.
2026-10-08 08:35:21 +02:00
Richard Zink 9191bb5776 Swap textAlign so labels extend into tile, not off-edge
User feedback: text on the left edge ('left' align) was getting
cut off because the text extended to negative X (off the left
edge of the canvas). Same problem on the right.

Fix: swap the textAlign so each side's text extends INTO the tile,
not OFF the edge:
- Left-side labels (S, N) now use textAlign 'right'. Anchor at
  the left edge of the tile area; the text's right edge is at
  the anchor and it extends rightward into the tile.
- Right-side labels (y, x) use textAlign 'left'. Anchor at the
  right edge; the text's left edge is at the anchor and extends
  leftward into the tile.

Mirror (scale -1, 1) is still applied so the text content is
flipped.
2026-10-08 08:32:10 +02:00
Richard Zink a38d942e56 Mirror labels across NS axis (scale -1, 1)
Each label is now drawn inside a save/translate/scale(-1, 1)/
restore context, so the actual text appears horizontally
mirrored in the canvas. This is the user-requested 'NS
axis mirror' for the labels.

N/S characters are symmetric so they look the same mirrored
or not. But 'x=1100' and 'y=1100' now appear reversed (1011 etc.),
confirming the horizontal flip is in effect.
2026-10-08 08:26:11 +02:00
Richard Zink 07017cfac6 Add tile borders and NS-mirrored corner labels (burned in)
User wants:
- Border around each tile so they can see where one ends
- Labels in the four corners, NS-mirrored (so N is at the
  bottom and S at the top, matching the tile's own NS axis)
- Labels burned in to the canvas so they always show the tile
  identity during flight (not just a live overlay)

Implementation:
- Thin dark border (rgba(0,0,0,0.55), 2px) via strokeRect just
  inside the tile bounds
- S at top-left, N at bottom-left (NS mirrored) in large bold
  text with white fill + black stroke for contrast
- y=NNN at top-right, x=NNN at bottom-right in smaller monospace
- All labels drawn directly on the canvas before texImage2D
  upload, so they're part of the texture the shader samples
2026-10-08 08:20:33 +02:00
Richard Zink 29924d07b0 Mirror O/W arrangement: east tiles to canvas right, west to left
User wants only the O/W arrangement mirrored (image X-flip
stays as it was). The drawing formula for canvasX now uses
(-perp + halfPerp + 0.5) instead of (perp + halfPerp + 0.5),
so tiles with perp<0 (world east, dx>0) land at large canvasX
(right side of canvas). Y axis (forward direction in N flight)
stays unchanged.
2026-10-08 08:15:49 +02:00
Richard Zink acac6dccfc NS mirror of tile image only (X-flip, no rotation)
User wants the tile texture mirrored across the NS axis only
(no 180 rotation). drawImage with width=-TILE, height=+TILE
flips only the X axis:
- Image top (north) stays at canvas top
- Image bottom (south) stays at canvas bottom
- Image left (west) -> canvas right
- Image right (east) -> canvas left

Labels N/S moved to match the new (un-Y-flipped) orientation:
N at canvas top, S at canvas bottom. The tile arrangement in
the corridor is unchanged.
2026-10-08 08:11:23 +02:00
Richard Zink 2f7c09fc16 Add O/W mirror: 180° rotation (image content only)
User wants the O/W axis mirrored within each tile. With
the previous Y-only flip, East was still on the right and West
on the left. Adding an X-flip makes it 180° rotation:
- Image North -> canvas bottom, South -> canvas top
- Image East -> canvas left, West -> canvas right

Labels N/S were already positioned at canvas bottom/top to match
the Y-flipped image, so they stay where they are. Tile arrangement
in the corridor is unchanged (still controlled by canvasX/canvasY
formulas with no swap on either axis).
2026-10-08 08:08:43 +02:00
Richard Zink 5ba7596ced Mirror tile content across NS axis (image + N/S labels only)
User feedback: the corridor arrangement is correct (lng=+12
at screen top in N flight), but the per-tile image and labels
were upside down relative to expectations.

- Image drawing: changed from 180° rotation (-TILE, -TILE on
  both axes) to Y-only flip (TILE, -TILE on Y). Image top
  (north) now lands at canvas bottom; image bottom (south) at
  canvas top. X axis is preserved so image east is still on the
  right within each tile.
- N/S labels: swapped so N is at canvas bottom (= image north)
  and S at canvas top (= image south).
2026-10-08 08:06:27 +02:00
Richard Zink 91ff8fb9d7 Bigger corridor + refetch-based continuous scroll
The per-frame redraw caused texImage2D upload of 8MB every frame,
which the browser couldn't keep up with -> tiles disappeared.

Reverted to refetch-based updates but with two key changes:
- Corridor 25 -> 50 tiles long (~6 min of flight at uSpeed=1
  before refetch)
- Tiles redraw with fractional camera position, so the corridor
  tracks the camera smoothly within the loaded content

The 50-tile corridor covers enough flight time that refetches
happen rarely (~6 min), but the camera's continuous position
is still reflected in the mosaic's center. So between refetches
the visible content scrolls smoothly.
2026-10-08 08:04:32 +02:00
Richard Zink 4f8fd4b62a Smooth ground scroll: redraw corridor every frame
Replaced refetch-based updates with continuous per-frame redraw.
The corridor now tracks the camera's continuous world position
(floating point, not floored to a tile) so the tile content
scrolls smoothly underneath the camera. No more 'jump by 1 tile'
at every refetch boundary.

Tradeoff: every frame draws ~65 images and does one texImage2D
upload. Browser caches the Image elements, so the cost is mainly
compositing + upload (~5MB at 6400x1280). Should still hit 30+ fps.

This is closer to how real flight sims work: the world content
scrolls continuously, not in tile-size jumps.
2026-10-08 07:59:11 +02:00
Richard Zink 23327a1cba Rotate tile images 180 degrees
drawImage(img, canvasX + TILE, canvasY + TILE, -TILE, -TILE)
flips the image both horizontally and vertically, so:
- Image north (high lat) ends up at canvas bottom (was top)
- Image south (low lat) ends up at canvas top
- Image east (high lon) ends up at canvas right
- Image west (low lon) ends up at canvas left

Combined with NO canvasY swap and the WebGL flip:
- North tiles drawn at canvas bottom -> after WebGL flip, still
  at screen bottom. Screen bottom has image north = high y. So
  y at screen bottom = high.
- Looking forward (close ground = screen bottom in cockpit) =
  high y. y increases in flight direction.

With NO canvasX swap:
- East tiles (high x) drawn at canvas left
- Image east at canvas right within each tile (high x)
- Image west at canvas left within each tile (low x)

So at screen left: east tiles with image x increasing left to
right (low to high within tile). At screen right: west tiles with
image x decreasing left to right. Overall: x at screen right (west
tiles, low x label) lower than at screen left (east tiles, high x
label). x decreases left to right.
2026-10-08 07:49:35 +02:00
Richard Zink 73920d0ce8 Both axes without swap: UNPACK flip for Y only
User clarified:
- x must decrease left to right (east at screen left, high x left)
- y must decrease in flight direction (south at front, low y in flight dir)

With no swap on canvasY (lng+halfLong+0.5 formula) and UNPACK
flip=true, canvas top -> texture top -> screen top. canvas bottom
-> screen bottom.

So:
- lng=+12 (north, ahead in N flight) -> canvasY=6272 (bottom)
  -> screen bottom. User at screen bottom sees north tiles = high y
- south tiles at canvas top -> screen top. User at screen top sees
  south tiles = low y. y decreases in flight direction (looking
  forward = top of screen = low y).

With no swap on canvasX:
- perp=-2 (east, dx=+2) -> canvasX=128 (left)
- After WebGL (no X flip): east at screen left, west at screen right.
  x decreases left to right (east at left, west at right).
2026-10-08 07:41:14 +02:00
Richard Zink d063e5e864 Revert canvasX swap: east on canvas left (matches user's x gradient)
User feedback: x decreasing left-to-right (matches NO swap), y
increasing in flight direction (matches swap). So the swap on
canvasY is right but the swap on canvasX was wrong direction.

With the no-swap canvasX formula:
- perp = -2 (east, dx=+2) at canvasX = 128 (left)
- perp = +2 (west, dx=-2) at canvasX = 1152 (right)

After UNPACK flip: canvasX stays as-is. User at canvas right sees
west (low x). User at canvas left sees east (high x). x decreases
left-to-right in the label content, matching what the user sees
in the satellite imagery too.

(The Y swap remains so lng=+12 -> canvasY=128 -> screen top, so
north tiles still appear at the top of the screen.)
2026-10-08 07:33:56 +02:00
Richard Zink 4cf3c00dfa Partial refetch: only draw new tiles, don't clear canvas
With BUFFER_LONG = 1, refetch fires every ~1 tile of motion (every
~8 sec at default speed). With BUFFER = 1 the center shifts by
~1 tile per refetch, so only ~1 net new tile needs fetching each
time (the one at the very front of the new corridor).

Switch to partial refetch:
- Don't clear the canvas before redrawing
- Skip tiles already in groundLoadedTiles (they're still on the
  canvas at the right position from a prior refetch)
- Only newly-positioned tiles are drawn (the ones in the new
  front of the corridor, ahead in flight direction)

Effect: user sees tiles appearing at the front of the corridor in
the direction of travel, not the whole canvas flashing every 8 sec.
With N flight, fetch activity shows up at the top of the screen
(where lng=+12 lands after the axis swap), confirming the flight
direction is correct.
2026-10-08 07:23:14 +02:00
Richard Zink bfe0a559b5 Re-apply NS+EW swap (user feedback: mirror needs fixing)
User reported 'N at close tiles' and 'NS mirrored, EW reversed'.
With the canvas axes swapped:
- lng=+12 (corridor front in N flight) at canvas top -> screen
  top -> ahead in flight direction (correct)
- perp<0 (world east) at canvas right -> screen right (correct)

Verifies user expectation: north tiles ahead (screen top), east tiles
to the right (screen right). N label appears at the far-ahead tiles
along the top of the screen, pointing forward in flight direction.
2026-10-08 07:06:01 +02:00
Richard Zink eeb2e3e5f6 Revert canvas axis swap, try original drawing formula
User reports NS axis mirror with current swap. Try the original
formula (canvasY = (lng + halfLong + 0.5)*TILE_SIZE) without
swapping. UNPACK_FLIP_Y_WEBGL stays true so text still reads
right-side up; just see if the user's visual expectations match
this simpler arrangement.
2026-10-08 07:02:01 +02:00
Richard Zink 2fd394a865 Right-side-up text: flip UNPACK flag + swap canvas axes
UNPACK_FLIP_Y_WEBGL=true was correct for screen orientation but the
shader's rotated-frame math expected it false. To get both right:

- Re-enable UNPACK_FLIP_Y_WEBGL=true so canvas top maps to texture
  V=1 (screen top). Text now reads right-side up.
- Invert the drawing axes: canvasY = (-lng + halfLong + 0.5)*TILE_SIZE
  so lng=+12 (corridor front, ahead) lands at small canvas Y, which
  after upload ends up at texture V=1, i.e. at screen top.
  Same inversion for perp.
- Shader's gUv.y = rotated.x / uGroundSize.y + 0.5 is unchanged:
  for offset.z=+12 (north) it samples V=0.98 -> texture row 6271
  -> canvas row 128 (the new top-of-corridor row) -> lng=+12. Correct.

Effect: N labels read upright, image orientation matches world
directions, and corridor scrolls in the visible flight direction.
2026-10-08 06:51:46 +02:00
Richard Zink a05951efbd Fix NS mirror: UNPACK_FLIP_Y_WEBGL was double-flipping
With the flag on, canvas row Y was uploaded to texture row (H-1-Y).
Sampling at V=0.58 then returned canvas row 2688 (in the 'south'
half of the corridor), but the shader expected row 3712 (in the
'north' half) for an offset.z=2 sample. So tiles appeared
mirrored across the NS axis — every N pointed south, every S north.

With the flag off, canvas row Y maps to texture row Y, and the
shader's expectation matches the drawing direction. Now N is at
the image's actual north, S at the image's actual south.
2026-10-08 06:48:10 +02:00
Richard Zink 6e96c5ffad Debug labels on each tile: N/S markers + x/y coords
For verifying the corridor arrangement, draw labels on every
loaded tile (per drawTileAt):
- 'N' at the canvas top edge of the tile (= image north after UNPACK_FLIP_Y_WEBGL)
- 'S' at the canvas bottom edge (= image south)
- 'x=NNN y=NNN' at the centre with the actual ESRI tile coords

This lets you see at a glance which canvas direction maps to which
world direction. Combined with #flight=N|... and #fetch=N|... you
can describe exactly what is wrong (e.g. N pointing in screen-up
direction when it should point at the corridor front).
2026-10-08 06:43:46 +02:00
Richard Zink c059d56f34 Fix Passau tile coords: 1099->1100, 706->707
Computed precisely: zoom 11, lat 48.5667, lon 13.4319.
x_norm = (lon+180)/360 = 0.5373, x_tile = 1100.41 -> floor 1100
y_norm = 0.3452, y_tile = 707.07 -> floor 707

Previously had 1099/706 which placed the centre one tile west and
one tile south of Passau. User observed the tile content was
'vertauscht' — it was correct ESRI imagery of a different geographic
location (near Schärding), not Passau itself.
2026-10-08 06:39:03 +02:00