Skip to content

Commit 9530052

Browse files
committed
Content update
1 parent 28a0fd1 commit 9530052

16 files changed

Lines changed: 4353 additions & 115 deletions

File tree

vibecoded/games/landscape/README.md

Lines changed: 119 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,20 @@ then open <http://localhost:8000/>.
2323
| `Space` / `Ctrl` | ascend / descend |
2424
| `Shift` | boost |
2525
| wheel | field of view |
26+
27+
The panel's readout gives the live numbers behind the level of detail:
28+
altitude, viewing distance, the ground a screen pixel covers there, the
29+
switch distance in force next to what the screen alone would ask for,
30+
and the imagery level and span in use.
31+
32+
**Wind** adds drone-like drift: a slow attitude wobble, a slower
33+
positional sway, and a gust envelope that swells both. It sways the view
34+
only -- your position and heading are untouched, so it never blows you
35+
off course and never disturbs the imagery level of detail. At 0 it is
36+
skipped entirely.
37+
38+
The sun is set by compass bearing (0 = north, 90 = east). Caldera sits at
39+
latitude -27, so its light comes from the north.
2640
| `H` | hide the settings panel |
2741

2842
On a touch device the page switches to a movement joystick plus
@@ -37,6 +51,107 @@ and the sensors only work in a secure context, so a plain
3751
`http://192.168.x.x` address on your LAN will not get readings. Use
3852
HTTPS or a tunnel to try it on a real phone.
3953

54+
## Terrain
55+
56+
Two datasets, switchable in the panel.
57+
58+
**Caldera, Atacama** (default) is real elevation, 30.5 km of the
59+
Chilean coast around Caldera at 17 m per texel, sea level to 952 m.
60+
Position is reported as real latitude, longitude and altitude in metres.
61+
Regenerate it, or fetch anywhere else, with:
62+
63+
python3 tools/fetch-terrain.py --lat -27.0678 --lon -70.8231 --zoom 13
64+
65+
Zoom 13 is deliberate. Measured against a bilinear upsample of the level
66+
above it, z13 adds ~5 m RMS of genuine detail here while z14 adds
67+
0.1-0.4 m -- nothing. The underlying source is SRTM. Regions covered by
68+
national lidar (the US, via 3DEP) keep gaining real detail to z14-15, so
69+
the useful ceiling is a property of the region, not of the tileset.
70+
71+
Real terrain is much gentler than the synthetic map -- 957 m of relief
72+
over 30 km is 56 texels at true scale, against the 2010 map's 249 -- so
73+
a **vertical scale** control exaggerates it. The default is 3x. Heights
74+
are held in a float texture, so there is no 0-255 ceiling to clip
75+
against.
76+
77+
**Satellite imagery** drapes Esri World Imagery over the elevation.
78+
Esri's tiles use the same Web Mercator grid as the terrain tiles, so
79+
they register pixel-for-pixel with no reprojection -- measured alignment
80+
against the elevation-derived coastline is dx=0, dy=0. Because the grids
81+
nest, the imagery is taken one zoom finer than the terrain: z14, 8.5 m
82+
per pixel over 17 m terrain, a 3584px mosaic of 196 tiles (~1.3 MB).
83+
Touch devices stay at z13 to keep the texture a quarter of the size.
84+
Turn it off and the hypsometric elevation colouring comes back.
85+
86+
Detail is not capped at that, though. A second, smaller imagery texture
87+
follows the camera at a zoom picked from **how far away the terrain being
88+
looked at is** -- not from altitude, which is only the same thing when
89+
the camera points straight down -- cross-fading into the base at its
90+
edges and with distance. Fly low and roads and tracks
91+
resolve; climb and it steps back down, then switches off once the base
92+
is enough. The panel reports the level in use.
93+
94+
**Detail switch** sets the distance at which the finest level gives way
95+
to the next one down; every band below and above it follows by halving
96+
and doubling. Set it to 2.2 km and anything you look at inside 2.2 km
97+
gets z17, out to 4.4 km z16, and so on. The screen-derived figure (shown
98+
as `auto`) is where finer imagery stops being *resolvable*, which is not
99+
the same as where it stops being *worth fetching* -- so the slider
100+
defaults to 2.2 km, well past it.
101+
102+
**Tile grid + 1 km rings** is a debug overlay: alternate imagery tiles
103+
are tinted, so tile size against distance is visible and the detail
104+
rectangle shows up as a change of grid pitch, and range rings mark every
105+
kilometre with the switch distance in cyan. Off by default, `?grid=1`
106+
to pin it.
107+
108+
The slider runs to 8 km, and its upper end means *the finest level whose
109+
rectangle can cover what you are looking at*: the rectangle is finite,
110+
reaching 2.42 km at z17, 4.85 km at z16 and 9.69 km at z15 (half that on
111+
touch). When reach rather than the slider decides, the readout says
112+
`rect-limited`.
113+
114+
Note that **vertical scale moves the levels**. Heights are exaggerated
115+
but horizontal distance is not, so at the default 2.5x a camera reading
116+
500 m is looking 5.5 km at real ground when it looks near-level -- far
117+
enough that the base mosaic is already as fine as the screen resolves.
118+
z17 arrives from about 28 degrees down at 2.5x, 38 degrees at 3x, and
119+
straight away at 1x, where a readout of 500 m means the camera really is
120+
500 m up in the geometry the rays march. Fly lower, look down, or turn
121+
the exaggeration down.
122+
123+
Three bugs used to hide all of this. The shader faded the detail layer
124+
out with distance, on reasoning left over from an earlier
125+
altitude-driven version; the texture LOD used a constant that assumed a
126+
380px-tall window, so on a normal screen the detail layer was sampled at
127+
the base mosaic's own resolution; and the layer's height input divided
128+
the vertical exaggeration back out, which placed the rectangle at a
129+
third of the distance it needed and left every pixel on screen outside
130+
it. Between them, detail was only ever visible below about 200 m.
131+
132+
How far it can go depends on the region. Beyond its high-resolution
133+
coverage Esri serves a flat grey "Map data not yet available"
134+
placeholder rather than an error, so the demo probes one tile before
135+
loading a level and walks the ceiling down until it finds real imagery.
136+
At Caldera that ceiling is **z17, 1.06 m/px**; z18 and up are
137+
placeholders.
138+
139+
The imagery is fetched **at runtime**, not shipped in `assets/`. The
140+
terrain tiles are open data; Esri's imagery is not -- it is licensed
141+
under Esri's Master License Agreement. Fetching tiles live is the
142+
ordinary usage pattern that every web map follows, but caching a mosaic
143+
into a published repository would be redistribution.
144+
145+
**Original 2010 map** is the synthetic heightmap the demo shipped with,
146+
unchanged.
147+
148+
Elevation data: Tilezen terrain tiles via AWS Open Data, no API key
149+
required. Imagery: Esri, Maxar, Earthstar Geographics and the GIS User
150+
Community. Attribution for both is required and is shown in the panel;
151+
see
152+
`assets/terrain-*.json` and
153+
<https://github.com/tilezen/joerd/blob/master/docs/attribution.md>.
154+
40155
## The two modes
41156

42157
**Modern** is the default: filtered textures, slope-based sun
@@ -82,9 +197,9 @@ The original wrapped the world at `heightmap->w - 1` = 1791. The
82197
heightmap actually tiles seamlessly at 1792, so that left a
83198
one-column seam. Not reproduced.
84199

85-
`?x=&y=&z=&yaw=&pitch=&retro=&scale=&steps=&dist=&fov=&touch=` pin the
86-
camera and render settings from the URL, which is what makes
87-
screenshots reproducible.
200+
`?x=&y=&z=&yaw=&pitch=&retro=&scale=&steps=&dist=&detail=&grid=&wind=&fov=&touch=&terrain=&vs=&hud=`
201+
pin the camera and render settings from the URL, which is what makes
202+
screenshots reproducible. `hud=0` strips the overlay.
88203

89204
## Layout
90205

@@ -99,3 +214,4 @@ screenshots reproducible.
99214
src/gl.js shader/texture helpers
100215
src/shaders/ the ray march
101216
tools/convert-assets.py BMP -> PNG
217+
tools/fetch-terrain.py real elevation tiles -> mosaic + metadata

0 commit comments

Comments
 (0)