mapspinner 0.1.72 → 0.1.74

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mapspinner",
3
- "version": "0.1.72",
3
+ "version": "0.1.74",
4
4
  "description": "WebGL2 Earth-scale terrain rendering SDK for interactive globe applications",
5
5
  "main": "src/index.js",
6
6
  "exports": {
@@ -223,7 +223,7 @@ uniform float uMtnBandWide; // widen mtn=smoothstep(16.8,18.6,ele
223
223
  uniform float uClimateRelief; // widen wetLowFlat(0.66,0.9,humid) + coldFlat(0.18,0.34,temp) reliefMul gates
224
224
  uniform float uIsleWide; // widen isleZone seaBias gates (50,350)+(900,1600) -> (30,600)+(600,2200)
225
225
  uniform float uCarveWide; // widen the river/canyon/lake/dune CLIMATE gates so carve depth fades in over a wide span
226
- float canyonRidgeField(vec3 dir){ return inciseRidgeField(normalize(dir) + vec3(13.7, -4.2, 8.9), 380.0, 2.07); } // phase offset matches FS canyonMask. baseFreq 380 = ~100km gorge network (user 2026-06-14: doubled 380->760 to restore deck-visible canyons after a 380->96 regression that put gorges ~400km apart = 'missing', then HALVED 760->380 back to the ~100km baseline). Shared VS carve + FS mask -> congruent by construction.
226
+ float canyonRidgeField(vec3 dir){ return inciseRidgeField(normalize(dir) + vec3(13.7, -4.2, 8.9), 190.0, 2.07); } // phase offset matches FS canyonMask. baseFreq 190 = ~200km gorge network (user 2026-06-14: HALVED 380->190 = fewer, wider-spaced gorges, easier for the coarse grid to represent). Shared VS carve + FS mask -> congruent by construction.
227
227
  // CANYON cross-section now reads as a CANYON, not a V-notch: STEEP WALLS + a FLAT FLOOR.
228
228
  // wall = a sharp smoothstep band -> the carve drops fast over a narrow ridge interval (the cliff
229
229
  // walls), instead of the old gentle bench+gorge blend that made shallow V-troughs.
@@ -235,9 +235,12 @@ float canyonCarveM(vec3 dir, out float depth){
235
235
  // WIDENED bands (user 2026-06-02 deepen+widen): the old .78/.86/.905/.93 intervals were a very
236
236
  // narrow ridge slice -> thin hairline gorges. Widen so the canyon reads as a BROAD gorge: a wide
237
237
  // eroded rim shoulder, a steep but visible wall, and a wide flat floor that the gorge bottoms out on.
238
- float bench = smoothstep(0.62, 0.78, ridge); // wide eroded rim shoulder
239
- float wall = smoothstep(0.70, 0.86, ridge); // STEEP cliff wall (wider band)
240
- float floorF= smoothstep(0.80, 0.93, ridge); // reach the flat gorge floor, then clamp
238
+ // GENTLER WALLS (user 2026-06-14 'make canyon slopes more gentle, easier for the rough grid to
239
+ // represent'): widen every band so the same depth descends over a wider ridge interval = lower
240
+ // gradient -> the coarse LOD grid samples the wall without aliasing the cliff.
241
+ float bench = smoothstep(0.50, 0.74, ridge); // wide eroded rim shoulder
242
+ float wall = smoothstep(0.58, 0.90, ridge); // gentle cliff wall (wide band)
243
+ float floorF= smoothstep(0.72, 0.96, ridge); // reach the flat gorge floor, then clamp
241
244
  depth = max(wall, floorF);
242
245
  // 0.18 rim shoulder + 0.82 wall-to-floor; floorF clamps so the bottom is flat (no infinite V).
243
246
  float profile = 0.18 * bench + 0.82 * max(wall, floorF);
@@ -703,7 +706,11 @@ highp float composeHeight(vec3 dir0, highp vec2 faceLocal, float tileM){ // W7
703
706
  h += cliffCarveV;
704
707
  // FLAT RIVER WATER
705
708
  float riverWetLine = riverWetMask * riverWet * step(0.0, h);
706
- if (riverWetLine > 0.0) { float rWaterLevel = h - 20.0; h = mix(h, rWaterLevel, riverWetLine); vDisp *= (1.0 - riverWetLine); }
709
+ // DEEPER, GENTLER-APPROACH CHANNEL WATER (user 2026-06-14 'water in canyons very shallow, base flat,
710
+ // angle of approach to the base far too sharp'): drop the channel bed 20->70m so the water is deep
711
+ // enough to read, and use riverWetLine^0.6 as the carve weight so the bed eases DOWN over a wider
712
+ // margin (concave approach) instead of plunging at the wet edge.
713
+ if (riverWetLine > 0.0) { float rw = pow(riverWetLine, 0.6); float rWaterLevel = h - 70.0; h = mix(h, rWaterLevel, rw); vDisp *= (1.0 - rw); }
707
714
  // DUNES on the low sand desert
708
715
  float duneSand = smoothstep(mix(0.62, 0.50, uCarveWide), mix(0.85, 0.95, uCarveWide), 1.0 - hpf0.a) * smoothstep(mix(0.40, 0.30, uCarveWide), mix(0.58, 0.68, uCarveWide), hpf0.b) * (1.0 - smoothstep(40.0, 160.0, h));
709
716
  float duneCrest; float duneV = duneFieldM(dir0, duneCrest) * duneSand * step(0.0, h);
@@ -753,6 +760,7 @@ out float vLakeWet; // lake open-water mask (carve basin)
753
760
  out float vRiverWet; // river thalweg wet line
754
761
  out float vWaterDepth; // metres the flat inland-water plane sits ABOVE the local terrain floor (>0 = submerged)
755
762
  out float vCanyonDep; // canyon gorge depth [0,1]
763
+ out float vConcavity; // height-field Laplacian / step^2 (1/m, +ve = concave valley/pit) -- ELEVATION AO signal (free from the normal central-diff taps)
756
764
  out float vCliffFace; // cliff/escarpment riser face [0,1] (1 = steep terrace face)
757
765
  out float vDuneCrest; // dune crest [0,1]
758
766
  out float vLevel; // quad LOD level (per-instance iOffset.w) for the patches debug view
@@ -938,12 +946,14 @@ void main() {
938
946
  // water level + suppress the micro-displacement on the wet line. riverWetMask is the thalweg mask.
939
947
  float riverWetLine = riverWetMask * riverWet * step(0.0, vH);
940
948
  if (riverWetLine > 0.0) {
941
- highp float rWaterLevel = vH - 20.0; // W7: metres
949
+ // MIRROR of composeHeight (deeper 20->70m channel + pow(.,0.6) gentler concave approach)
950
+ float rw = pow(riverWetLine, 0.6);
951
+ highp float rWaterLevel = vH - 70.0; // W7: metres
942
952
  highp float rFloorBefore = vH;
943
- vH = mix(vH, rWaterLevel, riverWetLine);
944
- vDisp *= (1.0 - riverWetLine); // no micro-bumps on the river surface
953
+ vH = mix(vH, rWaterLevel, rw);
954
+ vDisp *= (1.0 - rw); // no micro-bumps on the river surface
945
955
  // record the deeper/stronger of lake|river as the water surface for vWaterDepth
946
- if (riverWetLine > haveWater) { waterPlane = rWaterLevel; floorBefore = rFloorBefore; haveWater = riverWetLine; }
956
+ if (rw > haveWater) { waterPlane = rWaterLevel; floorBefore = rFloorBefore; haveWater = rw; }
947
957
  }
948
958
  // DUNES on the SAND DESERT (very dry + warm + LOW land): rolling dune relief replaces harsh rock
949
959
  // here (ref: webgl-dunes). Gated opposite to canyons (which want elevated arid plateaus) -- dunes
@@ -994,6 +1004,7 @@ void main() {
994
1004
  // sides of a seam share the same dir0/tangent frame -> consistent normals, no row artifact.
995
1005
  highp float hN0 = 0.0;
996
1006
  highp vec3 vN = dir0;
1007
+ highp float concavRaw = 0.0; // height Laplacian / step^2 (+ve = concave) -- set in the land branches, free from the normal taps
997
1008
  if (uIsWater < 0.5 && uThc > 0.5) {
998
1009
  // THC FAST PATH: height + symmetric central-diff normal from the baked pool. 5 bilinear texture
999
1010
  // taps replace 5 full composeHeight evals (the VS-bound cost). The 4 normal taps use the SAME
@@ -1049,6 +1060,23 @@ void main() {
1049
1060
  vN = normalize(cross(wPU - wMU, wPV - wMV));
1050
1061
  if (dot(vN, dir0) < 0.0) vN = -vN; // keep it outward (terrain has no overhangs)
1051
1062
  }
1063
+ // ELEVATION-AO CONCAVITY at LARGE scale (user 2026-06-14 'AO is focused on features too small, must
1064
+ // AO the larger features'): the 300m normal-step Laplacian keyed on small/sharp relief (canyons). Take
1065
+ // the Laplacian of broadShapeLowM (the cheap 8-oct LARGE-SCALE shape, no small carves) over a WIDE ~2km
1066
+ // step instead, so the AO darkens broad valleys/basins. broadShapeLowM is the same field the mesa
1067
+ // slope gate uses at a 1.2km step -> a known-cheap large-feature probe. Land only (water needs none).
1068
+ if (uIsWater < 0.5) {
1069
+ const highp float ecM = 2000.0; // wide finite-diff step = large-feature scale
1070
+ highp vec3 ux = normalize(cross(abs(dir0.y) < 0.99 ? vec3(0.0,1.0,0.0) : vec3(1.0,0.0,0.0), dir0));
1071
+ highp vec3 uy = cross(dir0, ux);
1072
+ highp float h0c = broadShapeLowM(dir0);
1073
+ highp float hxp = broadShapeLowM(normalize(dir0 + ux * (ecM / defRadius)));
1074
+ highp float hxm = broadShapeLowM(normalize(dir0 - ux * (ecM / defRadius)));
1075
+ highp float hyp = broadShapeLowM(normalize(dir0 + uy * (ecM / defRadius)));
1076
+ highp float hym = broadShapeLowM(normalize(dir0 - uy * (ecM / defRadius)));
1077
+ concavRaw = (hxp + hxm + hyp + hym - 4.0 * h0c) / (ecM * ecM); // 1/m large-scale curvature, +ve = broad valley/basin
1078
+ }
1079
+ vConcavity = concavRaw;
1052
1080
  highp float h = hN0;
1053
1081
  // OCEAN TOP = A SEPARATE, ELEVATION-BASED SURFACE (user 2026-06-10: 'terrain should extend into
1054
1082
  // the ocean, the ocean top separate and elevation based'). composeHeight keeps carrying the TRUE
@@ -1126,6 +1154,7 @@ in float vLakeWet; // carve masks computed in the VS, interpolated (no per-pi
1126
1154
  in float vRiverWet;
1127
1155
  in float vWaterDepth; // metres of submerged water (>0 = real open inland water at the flat plane)
1128
1156
  in float vCanyonDep;
1157
+ in float vConcavity; // elevation-AO concavity (1/m, +ve = valley/pit)
1129
1158
  in float vCliffFace;
1130
1159
  in float vDuneCrest;
1131
1160
  in float vLevel; // quad LOD level (patches view)
@@ -1912,7 +1941,7 @@ void main() {
1912
1941
  // 3 normal octaves (user 2026-06-14 'add an even lower freq octave, displacement/normals only,
1913
1942
  // 4x less frequent'): wt4 high (detail) + wt low (2.4km) + wt*0.25 VERY-low (9.6km) -- the very-
1914
1943
  // low one breaks the far repetition even more. Normals/displacement only (no albedo).
1915
- vec3 nA = surfTriNrm(uSurfNrm, wt4, tw, lA, n) * 1.4 + surfTriNrm(uSurfNrm, wt, tw, lA, n) * 0.8 + surfTriNrm(uSurfNrm, wt * 0.25, tw, lA, n) * 0.55;
1944
+ vec3 nA = surfTriNrm(uSurfNrm, wt4, tw, lA, n) * 2.0 + surfTriNrm(uSurfNrm, wt, tw, lA, n) * 0.9 + surfTriNrm(uSurfNrm, wt * 0.25, tw, lA, n) * 1.1; // REBALANCED (user 2026-06-14 'higher octaves appear gone'): very-low 2.4 swamped the detail -> high (wt4) UP to 2.0 (dominant detail), very-low DOWN to 1.1 (still visible broad) (user 2026-06-14 'dont really see the lower freq octave yet'): at a 9.6km period its slope is gentle, so it needs more weight to read as broad undulation
1916
1945
  float dispA = albA.a;
1917
1946
  // NO BIOME COLOR INHERITANCE (user 2026-06-14 'take away all biome color inheritance, it will
1918
1947
  // speed it up' -- and fixes 'sand near grass tinted green'): each layer wears its OWN material
@@ -1924,7 +1953,7 @@ void main() {
1924
1953
  if (wB > 0.02) { // second layer only where a real transition exists
1925
1954
  vec4 albB = surfTriTap(uSurfAlb, wt4, tw, lB);
1926
1955
  vec3 cB = vec3(dot(albB.rgb, LUMA));
1927
- vec3 nB = surfTriNrm(uSurfNrm, wt4, tw, lB, n) * 1.4 + surfTriNrm(uSurfNrm, wt, tw, lB, n) * 0.8 + surfTriNrm(uSurfNrm, wt * 0.25, tw, lB, n) * 0.55; // + very-low octave
1956
+ vec3 nB = surfTriNrm(uSurfNrm, wt4, tw, lB, n) * 2.0 + surfTriNrm(uSurfNrm, wt, tw, lB, n) * 0.9 + surfTriNrm(uSurfNrm, wt * 0.25, tw, lB, n) * 1.1; // REBALANCED (match nA)
1928
1957
  float dispB = albB.a;
1929
1958
  // HEIGHT-BLEND POKE-THROUGH (user 'each texture's higher areas should poke through the other,
1930
1959
  // offset by the ramp'): height = displacement + a weight-ramp offset (gate positions the
@@ -2012,13 +2041,27 @@ void main() {
2012
2041
  // base = flat MATERIAL color (far/low-k); near = structured detail. The macro biome albedo is no
2013
2042
  // longer the base, so NO biome color bleeds into the ground (user 'take away all biome inheritance').
2014
2043
  albedo = clamp(mix(texMatColor, detail, k), 0.0, 1.0);
2015
- albedo = mix(albedo, biomeC, 0.16); // subtle climate/biome tint back on top of the material color (deserts tanner, forests greener) -- at all distances for landscape variety
2044
+ albedo = mix(albedo, biomeC, 0.68); // climate/biome tint back on top of the material color (deserts tanner, forests greener) -- UP 0.16->0.68 (user 2026-06-14 x2 'tinting-according-to-landscape can be intensified, not really visible yet')
2016
2045
  // FAKE MIDDAY AO from the displacement (user 2026-06-14 'darken the deepest parts of the
2017
2046
  // displacement textures a little'): the texture's LOWEST displacement = crevices/pits; darken
2018
2047
  // them ~18% so the surface reads as sunlit-from-above with soft self-occlusion in the lows.
2019
2048
  // Faded by k so the far field (where the texture mips out) is untouched.
2020
- float texAO = mix(1.0, mix(0.82, 1.0, smoothstep(0.0, 0.5, texAlb.a)), k);
2049
+ // STRONGER fake-midday AO (user 2026-06-14 'should be more intense, we dont really see it'):
2050
+ // darken the recesses harder (0.82->0.5 = up to 50%) over a wider low-displacement range so the
2051
+ // crevices/pits read clearly. Still faded by k so the mipped far field is untouched.
2052
+ float texAO = mix(1.0, mix(0.5, 1.0, smoothstep(0.05, 0.6, texAlb.a)), k);
2021
2053
  albedo *= texAO;
2054
+ // ELEVATION AO (user 2026-06-14 x3 'similar AO on elevation / still not visible'): the screen-space
2055
+ // curvature of vNrm was ~0 (vNrm is a per-vertex analytic normal, linearly interpolated -> its
2056
+ // fwidth is tiny on the coarse grid = invisible). Replaced with vConcavity = the height-field
2057
+ // LAPLACIAN computed FREE from the VS normal central-diff taps (1/m, +ve = concave valley/pit),
2058
+ // a real object-space relief signal that survives interpolation. Darken concavities up to 65%.
2059
+ // VERY GRADUAL response (user 2026-06-14 'ao works but not gradiated, must be very gradual'): the
2060
+ // hard clamp(.,0.6) flat-topped every valley past a threshold = a visible AO edge + no gradation
2061
+ // between medium and deep concavity. Exponential SOFT saturation instead -- monotonic, smooth
2062
+ // onset AND smooth approach to the 0.6 floor, so darkening grades continuously with depth, no edge.
2063
+ float elevAO = 1.0 - 0.6 * (1.0 - exp(-max(vConcavity, 0.0) * 2500.0)); // concavRaw ~=1/Rc of the LARGE shape (~3-7e-4 for km-scale basins): broad valley eases in, asymptotes to -60%
2064
+ albedo *= elevAO;
2022
2065
  // displacement-normal relief: WORLD-SPACE UDN perturbation from surfTriNrm (each projection
2023
2066
  // plane's tangent axes, not the radial frame). Amplitude capped low (scramble lesson d262b5e);
2024
2067
  // applied AFTER the uReliefShade exaggeration below so the exaggeration never amplifies it.