feat(federation): flat 2D-style top-down view on portrait/mobile
Portrait containers now render near top-down and near-orthographic (tilt -1.35, persp 16) so the map reads like the previous 2D radial layout — rings become circles with no perspective squash. Desktop keeps the 3D depth camera. Globe point-spheres unchanged on both. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
abb4c95337
commit
aea90984d6
@@ -111,7 +111,9 @@ let frame = 0
|
||||
let selfDots: GlobeDot[] = []
|
||||
let selfRadiusPx = 15
|
||||
|
||||
const PERSP = 3.2
|
||||
/** Perspective strength — measure() sets it per form factor: 3.2 gives the
|
||||
* desktop scene real depth; a large value is near-orthographic (flat). */
|
||||
let persp = 3.2
|
||||
let resizeObserver: ResizeObserver | null = null
|
||||
let intro: gsap.core.Timeline | null = null
|
||||
let spinTween: gsap.core.Tween | null = null
|
||||
@@ -155,7 +157,7 @@ function project(x: number, y: number, z: number) {
|
||||
const ct = Math.cos(cam.tilt), st = Math.sin(cam.tilt)
|
||||
const y2 = y * ct - z1 * st
|
||||
const z2 = y * st + z1 * ct
|
||||
const s = PERSP / (PERSP + z2)
|
||||
const s = persp / (persp + z2)
|
||||
return {
|
||||
x: width / 2 + x1 * unit * s * cam.zoom,
|
||||
y: centerY + y2 * unit * s * cam.zoom,
|
||||
@@ -554,10 +556,12 @@ function measure() {
|
||||
height = c.clientHeight
|
||||
svgRef.value?.setAttribute('viewBox', `0 0 ${width} ${height}`)
|
||||
|
||||
// Portrait (phone/companion): tilt the camera towards top-down so the
|
||||
// orbit becomes a tall ellipse that uses the vertical space — nodes and
|
||||
// labels spread out in two dimensions instead of stacking on a flat band.
|
||||
cam.tilt = height > width * 1.15 ? -0.95 : -0.5
|
||||
// Portrait (phone/companion): go near top-down and near-orthographic so
|
||||
// the map reads like the old 2D radial view — rings become circles, no
|
||||
// perspective squash, maximum label spread. Desktop keeps the 3D depth.
|
||||
const portrait = height > width
|
||||
cam.tilt = portrait ? -1.35 : -0.5
|
||||
persp = portrait ? 16 : 3.2
|
||||
|
||||
// Auto-fit: sample the outermost orbit through the real camera math
|
||||
// (rotation-invariant — a ring about the Y axis projects identically at any
|
||||
@@ -577,7 +581,7 @@ function measure() {
|
||||
for (const y of [-0.2, 0.2]) { // covers yJitter + sway/bob amplitude
|
||||
const y2 = y * ct - z * st
|
||||
const z2 = y * st + z * ct
|
||||
const s = PERSP / (PERSP + z2)
|
||||
const s = persp / (persp + z2)
|
||||
maxAbsX = Math.max(maxAbsX, Math.abs(x * s))
|
||||
yMin = Math.min(yMin, y2 * s)
|
||||
yMax = Math.max(yMax, y2 * s)
|
||||
|
||||
Reference in New Issue
Block a user