@@ -119,13 +119,14 @@ export class GlobeViewComponent implements AfterViewInit, OnDestroy, OnChanges {
119119 * Closest zoom allowed (globe.gl POV `altitude`; smaller = closer). No tile map — this
120120 * replaces the old map-mode threshold as a hard stop for zoom and interaction.
121121 */
122- private readonly minCameraAltitude = 0.25 ;
122+ private readonly minCameraAltitude = 0.006 ;
123123 /** Camera distance in globe radii; larger = more zoomed out */
124124 private readonly initialGlobeAltitude = 2.65 ;
125125 private readonly selectedFocusAltitude = 0.42 ;
126126 private readonly selectedFocusTransitionMs = 900 ;
127127 private readonly markerRadiusMax = 0.28 ;
128- private readonly markerRadiusMin = 0.005 ;
128+ /** Angular radius (deg) at `minCameraAltitude`; keeps bars slim when fully zoomed in. */
129+ private readonly markerRadiusMin = 0.0022 ;
129130 private readonly markerHoverScale = 1.45 ;
130131 /** Invisible pick mesh radius/height vs visible bar (easier hover/click). */
131132 private markerHitTargetRadiusFactor = 2.85 ;
@@ -269,6 +270,9 @@ export class GlobeViewComponent implements AfterViewInit, OnDestroy, OnChanges {
269270 ngOnChanges ( changes : SimpleChanges ) : void {
270271 this . syncAutoRotate ( ) ;
271272 this . syncSelectedMapFocus ( ) ;
273+ if ( changes [ 'selectedStream' ] || changes [ 'selectedRadio' ] ) {
274+ queueMicrotask ( ( ) => this . refreshMapMarkersOnGlobe ( ) ) ;
275+ }
272276 if ( changes [ 'sidebarOpen' ] ) {
273277 queueMicrotask ( ( ) => this . scheduleGlobeLayoutSync ( ) ) ;
274278 }
@@ -781,14 +785,31 @@ export class GlobeViewComponent implements AfterViewInit, OnDestroy, OnChanges {
781785 return group ;
782786 }
783787
788+ /** Hover or current sidebar selection — keeps glow on the active marker. */
789+ private streamMarkerHighlighted ( d : GlobeStreamPoint ) : boolean {
790+ return (
791+ d . channelLogin === this . hoveredMarkerId ||
792+ ( this . selectedStream !== null &&
793+ d . channelLogin === this . selectedStream . channelLogin )
794+ ) ;
795+ }
796+
797+ private radioMarkerHighlighted ( d : GlobeRadioPoint ) : boolean {
798+ return (
799+ d . markerId === this . hoveredMarkerId ||
800+ ( this . selectedRadio !== null &&
801+ d . markerId === this . selectedRadio . station . markerId )
802+ ) ;
803+ }
804+
784805 private applyRadioMarkerAppearance (
785806 mat : THREE . MeshLambertMaterial ,
786807 d : GlobeRadioPoint ,
787808 ) : void {
788- const hover = d . markerId === this . hoveredMarkerId ;
789- mat . color . set ( hover ? this . radioMarkerHoverColor : this . radioMarkerColor ) ;
809+ const hi = this . radioMarkerHighlighted ( d ) ;
810+ mat . color . set ( hi ? this . radioMarkerHoverColor : this . radioMarkerColor ) ;
790811 mat . emissive . copy ( mat . color ) ;
791- mat . emissiveIntensity = hover
812+ mat . emissiveIntensity = hi
792813 ? this . radioMarkerHoverEmissiveIntensity
793814 : this . radioMarkerEmissiveIntensity ;
794815 }
@@ -797,7 +818,7 @@ export class GlobeViewComponent implements AfterViewInit, OnDestroy, OnChanges {
797818 mat : THREE . MeshLambertMaterial ,
798819 d : GlobeStreamPoint ,
799820 ) : void {
800- const hover = d . channelLogin === this . hoveredMarkerId ;
821+ const highlighted = this . streamMarkerHighlighted ( d ) ;
801822 const p = ( d . platform ?? 'twitch' ) . toLowerCase ( ) ;
802823 const base =
803824 p === 'youtube'
@@ -811,9 +832,9 @@ export class GlobeViewComponent implements AfterViewInit, OnDestroy, OnChanges {
811832 : p === 'kick'
812833 ? this . streamMarkerHoverColorKick
813834 : this . streamMarkerHoverColorTwitch ;
814- mat . color . set ( hover ? hi : base ) ;
835+ mat . color . set ( highlighted ? hi : base ) ;
815836 mat . emissive . copy ( mat . color ) ;
816- mat . emissiveIntensity = hover
837+ mat . emissiveIntensity = highlighted
817838 ? this . streamMarkerHoverEmissiveIntensity
818839 : this . streamMarkerEmissiveIntensity ;
819840 }
@@ -854,7 +875,7 @@ export class GlobeViewComponent implements AfterViewInit, OnDestroy, OnChanges {
854875 group . lookAt ( this . tmpGlobeCenter ) ;
855876
856877 if ( isGlobeRadioPoint ( d ) ) {
857- const rDeg = d . markerId === this . hoveredMarkerId ? hoverR : baseR ;
878+ const rDeg = this . radioMarkerHighlighted ( d ) ? hoverR : baseR ;
858879 const rs = Math . min ( 30 , rDeg ) * pxPerDeg * this . radioMarkerRadiusScale ;
859880 const h = Math . max ( this . radioPointAltitude * globeRadius , 0.08 ) ;
860881 vis . scale . set ( rs , rs , h ) ;
@@ -865,7 +886,7 @@ export class GlobeViewComponent implements AfterViewInit, OnDestroy, OnChanges {
865886 ) ;
866887 } else {
867888 const alt = this . viewerCountToPointAltitude ( d . viewerCount ) ;
868- const rDeg = d . channelLogin === this . hoveredMarkerId ? hoverR : baseR ;
889+ const rDeg = this . streamMarkerHighlighted ( d ) ? hoverR : baseR ;
869890 const rs = Math . min ( 30 , rDeg ) * pxPerDeg ;
870891 const h = Math . max ( alt * globeRadius , 0.1 ) ;
871892 vis . scale . set ( rs , rs , h ) ;
@@ -995,10 +1016,15 @@ export class GlobeViewComponent implements AfterViewInit, OnDestroy, OnChanges {
9951016 }
9961017
9971018 private currentMarkerBaseRadius ( ) : number {
998- // Shrink continuously as camera altitude decreases, with a hard minimum radius.
999- const altMin = 0.08 ;
1019+ // Map POV altitude from closest zoom (`minCameraAltitude`) to default zoom-out — avoids a
1020+ // plateau (old altMin 0.08) where radii stopped shrinking while the camera moved closer.
1021+ const altMin = this . minCameraAltitude ;
10001022 const altMax = this . initialGlobeAltitude ;
1001- const t = THREE . MathUtils . clamp ( ( this . currentAltitude - altMin ) / ( altMax - altMin ) , 0 , 1 ) ;
1023+ const t = THREE . MathUtils . clamp (
1024+ ( this . currentAltitude - altMin ) / Math . max ( altMax - altMin , 1e-6 ) ,
1025+ 0 ,
1026+ 1 ,
1027+ ) ;
10021028 return this . markerRadiusMin + ( this . markerRadiusMax - this . markerRadiusMin ) * t ;
10031029 }
10041030
0 commit comments