From 0f03e1759aaa6100b98357dafcc9bc134c3d262d Mon Sep 17 00:00:00 2001 From: Anton Afanasyeu Date: Wed, 5 Aug 2026 17:34:07 +0200 Subject: [PATCH] globe3d=11: v10 grid + visible-hemisphere continent wrap Sample ortho hub continents with grey-blue pixel test, mercator-flat fallback for rotated longitudes; same LIMB_Z cull as v10 grid ellipses. Co-authored-by: Cursor --- assets/hub-globe.js | 57 +++++++++++++++++++++++++++++++++++++++++---- index.php | 2 +- 2 files changed, 54 insertions(+), 5 deletions(-) diff --git a/assets/hub-globe.js b/assets/hub-globe.js index 36f9bee..59023a2 100644 --- a/assets/hub-globe.js +++ b/assets/hub-globe.js @@ -11,6 +11,7 @@ * globe3d=8: hub SVG ellipse trace (breaks under rotation — deprecated). * globe3d=9: v4 sphere grid only (thin E–W + N–S) — proper rotation baseline. * globe3d=10: v4 visible-arc → screen ellipse (hub ry), disk-clipped. + * globe3d=11: v10 grid + visible-hemisphere continent wrap (ortho hub + mercator flat). */ export const GLOBE_VIEW = { imgW: 1920, imgH: 1080, cx: 720, cy: 560, r: 322, rim: 330 }; @@ -830,7 +831,7 @@ function drawGlobeGrid(ctx, cx, cy, r, rotY, layoutScale, renderVersion) { drawSphereGrid(ctx, cx, cy, r, rotY, layoutScale, { parallelsOnly: false }); return; } - if (renderVersion === 10) { + if (renderVersion === 10 || renderVersion === 11) { drawSphereGridScreenStrip(ctx, cx, cy, r, rotY, layoutScale); return; } @@ -886,6 +887,24 @@ function isLandPixel(r, g, b, a) { return a > 10 && r > 100 && g < 140 && b < 140; } +/** hub-logo-continents-mercator-{globe,flat}.svg grey-blue fills (not red JPG extract). */ +function isHubContinentPixel(r, g, b, a) { + if (a < 12) { + return false; + } + if (r > 168 && g > 198 && b > 218) { + return false; + } + if (r < 48 && g < 58 && b < 82) { + return false; + } + const lum = r * 0.299 + g * 0.587 + b * 0.114; + if (lum < 92 || lum > 238) { + return false; + } + return b >= 100 && g >= 95 && r >= 68; +} + /** Light hub grid strokes baked into hub-logo-fragment-globe.svg (vector grid drawn separately). */ function isGridPixel(r, g, b, a) { if (a < 12) { @@ -950,6 +969,23 @@ function sampleLandRgbaMercator(mercFlat, tex) { return null; } +/** globe3d=11 — same visible hemisphere as v10 grid (z > LIMB_Z); ortho hub then mercator wrap. */ +function sampleLandVisibleHemisphere(continents, mercFlat, tex) { + if (tex.z <= LIMB_Z) { + return null; + } + const ortho = sampleHub(continents, tex); + if (isHubContinentPixel(ortho[0], ortho[1], ortho[2], ortho[3])) { + return [ortho[0], ortho[1], ortho[2], Math.min(255, ortho[3])]; + } + const ll = texLonLat(tex); + const flat = sampleMercFlat(mercFlat, ll.lon, ll.lat); + if (isHubContinentPixel(flat[0], flat[1], flat[2], flat[3])) { + return [flat[0], flat[1], flat[2], Math.min(255, flat[3])]; + } + return null; +} + function fillDiskRegion(ctx, cx, cy, r, rotY, fn) { const r2 = r * r; const x0 = Math.max(0, Math.floor(cx - r)); @@ -1153,6 +1189,17 @@ export async function mountHubGlobe(stage, opts) { return l || [0, 0, 0, 0]; }) ); + } else if (renderVersion >= 11) { + blitLayer( + ctx, + cx, + cy, + r, + fillDiskRegion(ctx, cx, cy, r, rotation, function (tex) { + const l = sampleLandVisibleHemisphere(continents, mercFlat, tex); + return l || [0, 0, 0, 0]; + }) + ); } drawGlobeGrid(ctx, cx, cy, r, rotation, layoutScale, renderVersion); drawOceanRim(ctx, globeImg, cx, cy, r, rim, layoutScale, renderVersion); @@ -1225,9 +1272,11 @@ export async function mountHubGlobe(stage, opts) { raf = requestAnimationFrame(tick); stage.dataset.globe3d = String(renderVersion); stage.dataset.globeAxis = - renderVersion === 10 - ? 'ew-sphere-ellipse' - : renderVersion === 9 + renderVersion === 11 + ? 'ew-sphere-ellipse-land' + : renderVersion === 10 + ? 'ew-sphere-ellipse' + : renderVersion === 9 ? 'ew-ns-sphere-v4' : renderVersion >= 8 ? 'ew-hub-ellipse-rot' diff --git a/index.php b/index.php index 03ec380..48befd2 100644 --- a/index.php +++ b/index.php @@ -187,7 +187,7 @@ function hub_h(string $s): string { var supportsLayout = !!(window.CSS && CSS.supports && CSS.supports('object-fit', 'cover')); var logoEnabled = !!(stage && supportsSvg && supportsLayout); - var logoBuild = '20260704globe13'; + var logoBuild = '20260704globe14'; function hubAsset(rel) { var link = document.querySelector('link[href*="hub.css"]');