1
0
mirror of git://f0xx.org/ac/ac-be-hub synced 2026-08-09 20:59:23 +03:00

feat(globe3d=11): ?f= URL param for N-S latitude factor tuning

Default remains 0.66; exposed on #hub-logo-stage as data-globe-lat-factor.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Anton Afanasyeu
2026-08-05 19:27:56 +02:00
parent dbea1c53da
commit ae83a64042
2 changed files with 28 additions and 8 deletions

View File

@@ -12,6 +12,7 @@
* globe3d=9: v4 sphere grid only (thin EW + NS) — proper rotation baseline.
* globe3d=10: v4 visible-arc → screen ellipse (hub ry), disk-clipped.
* globe3d=11: v10 grid + geographic mercator-flat land (360° U-wrap).
* ?f=0.66 — NS latitude factor (default 0.66; lower = more squeeze).
*/
export const GLOBE_VIEW = { imgW: 1920, imgH: 1080, cx: 720, cy: 560, r: 322, rim: 330 };
@@ -29,8 +30,15 @@ const CONTINENT_INNER_SX = 1.2408477842003853;
const CONTINENT_INNER_SY = 1.2408477842003853;
/** Map plate center longitude (extract_red_polygons.py CENTER_LON). */
const MERCATOR_LON_CENTER = (12 * Math.PI) / 180;
/** NS latitude factor on mercator sample (0.75 = lat × 0.75). */
const CONTINENT_LAT_FACTOR = 0.66;
/** Default NS latitude factor (override with ?f= on globe3d=11). */
const CONTINENT_LAT_FACTOR_DEFAULT = 0.66;
function resolveContinentLatFactor(raw) {
if (typeof raw !== 'number' || !isFinite(raw)) {
return CONTINENT_LAT_FACTOR_DEFAULT;
}
return Math.max(0.05, Math.min(2, raw));
}
const RASTER_SCALE = 2;
const AXIS_STEPS = 160;
const SPHERE_AXIS_STEPS = 180;
@@ -953,10 +961,10 @@ function sampleFlatPlateFromHub(mercFlat, hpX, hpY) {
}
/** Sphere tex → mercator-flat plate (lon center + inverse Mercator Y). */
function sampleMercFlatFromTex(mercFlat, tex) {
function sampleMercFlatFromTex(mercFlat, tex, latFactor) {
const ll = texLonLat(tex);
const lon = wrapLon(ll.lon + MERCATOR_LON_CENTER);
const lat = Math.max(-1.52, Math.min(1.52, ll.lat * CONTINENT_LAT_FACTOR));
const lat = Math.max(-1.52, Math.min(1.52, ll.lat * latFactor));
return sampleMercFlat(mercFlat, lon, lat);
}
@@ -1069,11 +1077,11 @@ function sampleLandRgbaMercator(mercFlat, tex) {
}
/** globe3d=11 — geographic mercator wrap (360°); z > LIMB_Z only. */
function sampleLandVisibleHemisphere(mercFlat, tex) {
function sampleLandVisibleHemisphere(mercFlat, tex, latFactor) {
if (tex.z <= LIMB_Z) {
return null;
}
const flat = sampleMercFlatFromTex(mercFlat, tex);
const flat = sampleMercFlatFromTex(mercFlat, tex, latFactor);
if (isHubContinentPixel(flat[0], flat[1], flat[2], flat[3])) {
return hubContinentRgba(flat);
}
@@ -1179,6 +1187,7 @@ export async function mountHubGlobe(stage, opts) {
const build = opts.build || 'earth3d';
const reducedMotion = !!opts.reducedMotion;
const renderVersion = Math.max(1, parseInt(opts.renderVersion, 10) || 1);
const continentLatFactor = resolveContinentLatFactor(opts.continentLatFactor);
const canvas = document.createElement('canvas');
canvas.className = 'hub-globe-canvas';
@@ -1290,7 +1299,7 @@ export async function mountHubGlobe(stage, opts) {
cy,
r,
fillDiskRegion(ctx, cx, cy, r, rotation, function (tex) {
const l = sampleLandVisibleHemisphere(mercFlat, tex);
const l = sampleLandVisibleHemisphere(mercFlat, tex, continentLatFactor);
return l || [0, 0, 0, 0];
})
);
@@ -1365,6 +1374,9 @@ export async function mountHubGlobe(stage, opts) {
raf = requestAnimationFrame(tick);
stage.dataset.globe3d = String(renderVersion);
if (renderVersion >= 11) {
stage.dataset.globeLatFactor = String(continentLatFactor);
}
stage.dataset.globeAxis =
renderVersion === 11
? 'ew-sphere-ellipse-land'
@@ -1393,6 +1405,7 @@ export async function mountHubGlobe(stage, opts) {
canvas.remove();
delete stage.dataset.globe3d;
delete stage.dataset.globeAxis;
delete stage.dataset.globeLatFactor;
},
};
}