mapspinner 0.1.56 → 0.1.57

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.56",
3
+ "version": "0.1.57",
4
4
  "description": "WebGL2 Earth-scale terrain rendering SDK for interactive globe applications",
5
5
  "main": "src/index.js",
6
6
  "exports": {
package/src/gl-render.js CHANGED
@@ -787,7 +787,7 @@ export async function initMapspinnerRender(gl, opts = {}) {
787
787
  // out fall beyond the far plane and vanish. Dropping the horizon reference radius 500m below sea level
788
788
  // extends the horizon to tens of km at low altitude so near-shore relief stays in view (negligible
789
789
  // depth-precision cost: 500m vs R~6.37e6). Both the cull and the draw use this (single source).
790
- const RHORIZON = R - 500.0;
790
+ const RHORIZON = R - 250.0; // far brought in 500->250 (user 2026-06-14 'bring far plane in a bit'): deck horizon ~80km->~56km = more z-precision; still clears coastal mountains
791
791
  // UNDERWATER FAR-PLANE FIX (user 2026-06-14 'at -214m visible, at -500m it disappears'): when the
792
792
  // camera is more than 500m below sea level, camDist < RHORIZON so the sea-level horizon is imaginary
793
793
  // (-> 0) and alt is negative; the old max(horizon, alt*8) then collapsed the far plane to ~0 and the
@@ -797,7 +797,7 @@ export async function initMapspinnerRender(gl, opts = {}) {
797
797
  // MATCH render()'s near exactly (2026-06-14 jank fix): the cull frustum must use the SAME near
798
798
  // as the draw frustum, else behind-limb/screen-AABB culling diverges from what is actually drawn
799
799
  // at the deck (cull near was max(*0.1,0.1) while render used the <2m 0.05 branch).
800
- const near = altAboveTerrain < 2.0 ? 0.05 : Math.max(altAboveTerrain * 0.1, 0.05);
800
+ const near = altAboveTerrain < 2.0 ? 0.25 : Math.max(altAboveTerrain * 0.1, 0.25); // near nudged out 0.05->0.25 (user 2026-06-14 'improve on-ground'): more z-precision on the deck
801
801
  // FAR PLANE: horizon distance tracks the visible ground edge; blends toward camDist
802
802
  // above 500km for orbital views so the full planet is visible.
803
803
  const _fBlend = Math.min(1.0, Math.max(0.0, (alt - 500000.0) / 4500000.0));
@@ -835,14 +835,14 @@ export async function initMapspinnerRender(gl, opts = {}) {
835
835
  // out fall beyond the far plane and vanish. Dropping the horizon reference radius 500m below sea level
836
836
  // extends the horizon to tens of km at low altitude so near-shore relief stays in view (negligible
837
837
  // depth-precision cost: 500m vs R~6.37e6). Both the cull and the draw use this (single source).
838
- const RHORIZON = R - 500.0;
838
+ const RHORIZON = R - 250.0; // far brought in 500->250 (user 2026-06-14 'bring far plane in a bit'): deck horizon ~80km->~56km = more z-precision; still clears coastal mountains
839
839
  // UNDERWATER FAR-PLANE FIX (user 2026-06-14 'at -214m visible, at -500m it disappears'): when the
840
840
  // camera is more than 500m below sea level, camDist < RHORIZON so the sea-level horizon is imaginary
841
841
  // (-> 0) and alt is negative; the old max(horizon, alt*8) then collapsed the far plane to ~0 and the
842
842
  // whole scene vanished past -500m deep (= the 'ocean looks shallow/empty' when exploring). Floor the
843
843
  // far reach to 60km when submerged so the seabed + the underwater view stay visible.
844
844
  const horizon = (camDist > RHORIZON) ? Math.sqrt(camDist*camDist - RHORIZON*RHORIZON) : 60000.0;
845
- const near = altAboveTerrain < 2.0 ? 0.05 : Math.max(altAboveTerrain * 0.1, 0.05);
845
+ const near = altAboveTerrain < 2.0 ? 0.25 : Math.max(altAboveTerrain * 0.1, 0.25); // near nudged out 0.05->0.25 (user 2026-06-14 'improve on-ground'): more z-precision on the deck
846
846
  const _fBlend = Math.min(1.0, Math.max(0.0, (alt - 500000.0) / 4500000.0));
847
847
  const farGround = Math.max(horizon, alt * 8.0);
848
848
  const far = farGround * (1.0 - _fBlend) + camDist * _fBlend;
@@ -1249,7 +1249,13 @@ vec3 terrainAlbedo(float h, float slope, float rockSlope, highp vec3 worldPos) {
1249
1249
  } else {
1250
1250
  c = mix(bcShore, bcLowland, smoothstep(0.0, bandEdgesLo.x, h));
1251
1251
  c = mix(c, bcGrass, smoothstep(bandEdgesLo.x, bandEdgesLo.y, h));
1252
- float bandWarp = snoise3(normalize(worldPos) * 400.0) * 500.0;
1252
+ // BIOME-BAND WARP (user 2026-06-14 'hard bands between biomes ... make that more interesting'):
1253
+ // the single-octave warp made smooth wavy contour lines. A 3-octave domain-warped field breaks
1254
+ // the rock/snow boundaries into irregular fingers + patches (height-keyed band wobbles +/-~1.1km
1255
+ // over 1-15km scales), so the biome edge reads natural, not a band. highp dir for the lattice.
1256
+ highp vec3 bwd = normalize(worldPos);
1257
+ highp vec3 bww = bwd + vec3(snoise3(bwd * 130.0)) * 0.004; // domain warp -> non-parallel fingers
1258
+ float bandWarp = (snoise3(bww * 210.0) * 1.0 + snoise3(bww * 560.0) * 0.5 + snoise3(bww * 1450.0) * 0.25) * 720.0;
1253
1259
  c = mix(c, bcRock, smoothstep(bandEdgesHi.x + bandWarp, bandEdgesHi.y + bandWarp, h));
1254
1260
  c = mix(c, bcSnow, smoothstep(snowEdges.x + bandWarp, snowEdges.y + bandWarp, h));
1255
1261
  c = mix(c, bcRock, smoothstep(slopeRock.x, slopeRock.y, rockSlope) * step(0.0, h));
@@ -1778,10 +1784,19 @@ void main() {
1778
1784
  // beach->land crossover). 2-oct world-dir noise, 1/4 freq (~13km + ~5km waves). Computed once
1779
1785
  // here; the snow/rock bandWarp below reuses warpN. highp dir for the lattice precision.
1780
1786
  highp vec3 bwDir = normalize(vWorld);
1781
- float warpN = snoise3(bwDir * 3325.0) + 0.5 * snoise3(bwDir * 7750.0); // ~ +/-1.5
1787
+ // 3-oct (added the ~1km octave, user 2026-06-14 'make biome bands more interesting') -> the
1788
+ // texture-splat rock/snow/beach edges break into finer fingers as you approach, not a hard band.
1789
+ float warpN = snoise3(bwDir * 3325.0) + 0.5 * snoise3(bwDir * 7750.0) + 0.35 * snoise3(bwDir * 17000.0); // ~ +/-1.8
1782
1790
  // BEACH sand gate tied to uBeachTopM (so the sand TEXTURE scales with the wide beach, not a
1783
1791
  // hardcoded 80m strip) + the shared warp on its LAND edge so the beach->grass line is irregular.
1784
- float beachW = warpN * uBeachTopM * 0.30; // warp amplitude scales with the beach band height
1792
+ // FINE BREAK on the grass->sand line (user 2026-06-14 'still a hard straight grass-sand line up
1793
+ // close ... it must gain detail'): warpN breaks it at the km scale; add a high-freq (~80-200m)
1794
+ // octave so the line stays irregular/fingered when you walk right up to it instead of going
1795
+ // straight. Faded in WITH the close-up detail (detailFade-like, via pxWorld) so it never speckles
1796
+ // at distance where the macro band is smooth.
1797
+ float closeBreak = (1.0 - smoothstep(2.0, 40.0, pxWorld));
1798
+ float beachFine = (snoise3(bwDir * 42000.0) + 0.5 * snoise3(bwDir * 95000.0)) * uBeachTopM * 0.45 * closeBreak;
1799
+ float beachW = warpN * uBeachTopM * 0.30 + beachFine; // warp amplitude scales with the beach band height
1785
1800
  float beach = (1.0 - smoothstep(uBeachTopM * 0.12 + beachW, uBeachTopM + beachW, vH))
1786
1801
  * (1.0 - smoothstep(0.15, 0.42, slope));
1787
1802
  // SAND BLEED (2026-06-13): patchy sand spills above the main beach line, modulated by VS
@@ -1885,18 +1900,22 @@ void main() {
1885
1900
  // 2m'): the base photo tiles at uTexTileM (~2.4km = ~2.3m/texel, smeared at the deck). Sample the
1886
1901
  // SAME dominant material at 4x frequency (~0.6m/texel) and overlay its luminance + normal so
1887
1902
  // close-up the ground gains sub-metre structure. Faded out by ~12m px so it never moires far off.
1903
+ // LOW-FREQ = NORMALS ONLY, HIGH-FREQ = TEXTURE + STRONG NORMALS (user 2026-06-14): flatten the
1904
+ // base (2.4km) albedo to its luminance so the MACRO biome color carries the chroma -- the base
1905
+ // octave contributes only its NORMAL (relief), not color blotches. The 4x detail octave then
1906
+ // provides the albedo STRUCTURE + a strong normal.
1907
+ texAlb.rgb = vec3(dot(texAlb.rgb, vec3(0.299, 0.587, 0.114))); // low-freq: normals only (albedo -> flat luma)
1888
1908
  float detailFade = (1.0 - smoothstep(1.0, 12.0, pxWorld));
1889
1909
  if (detailFade > 0.01) {
1890
1910
  vec4 dA = surfTriTap(uSurfAlb, wt * 4.0, tw, lA);
1891
1911
  float dl = dot(dA.rgb, vec3(0.299, 0.587, 0.114));
1892
1912
  float bl = dot(texAlb.rgb, vec3(0.299, 0.587, 0.114));
1893
- texAlb.rgb *= mix(1.0, clamp(dl / max(bl, 0.04), 0.55, 1.7), detailFade * 0.6);
1894
- // detail NORMAL: surfTriNrm returns a PERTURBATION vector (texNrm feeds texDn = texNrm*uTexNrmK*k
1895
- // at the apply site, NOT a unit normal), so the detail is simply ADDED in the same space -- no
1896
- // normalize (normalizing the perturbation scrambled its magnitude = the 'weird highest-octave
1897
- // normals'). Half-weight so the fine octave textures relief without overpowering the base.
1913
+ texAlb.rgb *= mix(1.0, clamp(dl / max(bl, 0.04), 0.35, 2.4), detailFade * 1.3); // HIGH-FREQ albedo structure (heavier)
1914
+ // detail NORMAL: surfTriNrm returns a PERTURBATION vector (texNrm feeds texDn = texNrm*uTexNrmK*k,
1915
+ // NOT a unit normal), so the detail is simply ADDED in the same space -- no normalize (that
1916
+ // scrambled magnitudes = the 'weird highest-octave normals').
1898
1917
  vec3 dN = surfTriNrm(uSurfNrm, wt * 4.0, tw, lA, n);
1899
- texNrm = texNrm + dN * detailFade * 0.5;
1918
+ texNrm = texNrm + dN * detailFade * 1.4; // BIGGER normal effect for the high-freq octave (user 2026-06-14)
1900
1919
  }
1901
1920
  float k = uTexMix * texFarFade;
1902
1921
  // macro-tinted detail (user 2026-06-10 'the textured patch must be tinted to the same shade