@@ -19,6 +19,10 @@ export const WAYPOINT_CONFIG = {
1919 pixelSize : 50 ,
2020 paddingPx : 50 ,
2121 } ,
22+ // Default visual scale factor (can be overridden globally or per-waypoint)
23+ DEFAULT_VISUAL_SCALE : 1 ,
24+ // Default opacity (can be overridden globally or per-waypoint)
25+ DEFAULT_OPACITY : 1 ,
2226}
2327
2428export type WaypointSprite = {
@@ -51,14 +55,31 @@ export function createWaypointSprite (options: {
5155 // Y offset in world units used by updateScaleWorld only (screen-pixel API ignores this)
5256 labelYOffset ?: number ,
5357 metadata ?: any ,
58+ visualScale ?: number ,
59+ opacity ?: number ,
5460} ) : WaypointSprite {
5561 const color = options . color ?? 0xFF_00_00
5662 const depthTest = options . depthTest ?? false
5763 const labelYOffset = options . labelYOffset ?? 1.5
5864
65+ // Get visual scale from options, metadata, server metadata, or default
66+ // Priority: options.visualScale > metadata.visualScale > window.serverMetadata?.waypointVisualScale > DEFAULT
67+ const visualScale = options . visualScale
68+ ?? options . metadata ?. visualScale
69+ ?? ( typeof window === 'undefined' ? undefined : ( window as any ) . serverMetadata ?. waypointVisualScale )
70+ ?? WAYPOINT_CONFIG . DEFAULT_VISUAL_SCALE
71+
72+ // Get opacity from options, metadata, server metadata, or default
73+ // Priority: options.opacity > metadata.opacity > window.serverMetadata?.waypointOpacity > DEFAULT
74+ const opacity = options . opacity
75+ ?? options . metadata ?. opacity
76+ ?? ( typeof window === 'undefined' ? undefined : ( window as any ) . serverMetadata ?. waypointOpacity )
77+ ?? WAYPOINT_CONFIG . DEFAULT_OPACITY
78+
5979 // Build combined sprite
60- const sprite = createCombinedSprite ( color , options . label ?? '' , '0m' , depthTest )
80+ const sprite = createCombinedSprite ( color , options . label ?? '' , '0m' , depthTest , visualScale )
6181 sprite . renderOrder = 10
82+ sprite . material . opacity = opacity
6283 let currentLabel = options . label ?? ''
6384
6485 // Performance optimization: cache distance text to avoid unnecessary updates
@@ -79,7 +100,7 @@ export function createWaypointSprite (options: {
79100 group . position . set ( x , y , z )
80101
81102 function setColor ( newColor : number ) {
82- const canvas = drawCombinedCanvas ( newColor , currentLabel , '0m' )
103+ const canvas = drawCombinedCanvas ( newColor , currentLabel , '0m' , visualScale )
83104 const texture = new THREE . CanvasTexture ( canvas )
84105 const mat = sprite . material
85106 mat . map ?. dispose ( )
@@ -89,7 +110,7 @@ export function createWaypointSprite (options: {
89110
90111 function setLabel ( newLabel ?: string ) {
91112 currentLabel = newLabel ?? ''
92- const canvas = drawCombinedCanvas ( color , currentLabel , '0m' )
113+ const canvas = drawCombinedCanvas ( color , currentLabel , '0m' , visualScale )
93114 const texture = new THREE . CanvasTexture ( canvas )
94115 const mat = sprite . material
95116 mat . map ?. dispose ( )
@@ -104,7 +125,7 @@ export function createWaypointSprite (options: {
104125 }
105126 lastDistanceText = distanceText
106127
107- const canvas = drawCombinedCanvas ( color , label , distanceText )
128+ const canvas = drawCombinedCanvas ( color , label , distanceText , visualScale )
108129 const texture = new THREE . CanvasTexture ( canvas )
109130 const mat = sprite . material
110131 mat . map ?. dispose ( )
@@ -129,8 +150,8 @@ export function createWaypointSprite (options: {
129150 ) {
130151 const vFovRad = cameraFov * Math . PI / 180
131152 const worldUnitsPerScreenHeightAtDist = Math . tan ( vFovRad / 2 ) * 2 * distance
132- // Use configured target screen size
133- const scale = worldUnitsPerScreenHeightAtDist * ( WAYPOINT_CONFIG . TARGET_SCREEN_PX / viewportHeightPx )
153+ // Use configured target screen size with visual scale multiplier
154+ const scale = worldUnitsPerScreenHeightAtDist * ( WAYPOINT_CONFIG . TARGET_SCREEN_PX * visualScale / viewportHeightPx )
134155 sprite . scale . set ( scale , scale , 1 )
135156 }
136157
@@ -159,7 +180,7 @@ export function createWaypointSprite (options: {
159180 ctx . fill ( )
160181
161182 const texture = new THREE . CanvasTexture ( canvas )
162- const material = new THREE . SpriteMaterial ( { map : texture , transparent : true , depthTest : false , depthWrite : false } )
183+ const material = new THREE . SpriteMaterial ( { map : texture , transparent : true , depthTest : false , depthWrite : false , opacity } )
163184 arrowSprite = new THREE . Sprite ( material )
164185 arrowSprite . renderOrder = 12
165186 arrowSprite . visible = false
@@ -278,9 +299,9 @@ export function createWaypointSprite (options: {
278299 const angle = Math . atan2 ( ry , rx )
279300 arrowSprite . material . rotation = angle - Math . PI / 2
280301
281- // Constant pixel size for arrow (use fixed placement distance)
302+ // Constant pixel size for arrow (use fixed placement distance) with visual scale
282303 const worldUnitsPerScreenHeightAtDist = Math . tan ( vFovRad / 2 ) * 2 * placeDist
283- const sPx = worldUnitsPerScreenHeightAtDist * ( WAYPOINT_CONFIG . ARROW . pixelSize / viewportHeightPx )
304+ const sPx = worldUnitsPerScreenHeightAtDist * ( WAYPOINT_CONFIG . ARROW . pixelSize * visualScale / viewportHeightPx )
284305 arrowSprite . scale . set ( sPx , sPx , 1 )
285306 return false
286307 }
@@ -343,7 +364,7 @@ export function createWaypointSprite (options: {
343364}
344365
345366// Internal helpers
346- function drawCombinedCanvas ( color : number , id : string , distance : string ) : HTMLCanvasElement {
367+ function drawCombinedCanvas ( color : number , id : string , distance : string , visualScale = 1 ) : HTMLCanvasElement {
347368 const scale = WAYPOINT_CONFIG . CANVAS_SCALE * ( globalThis . devicePixelRatio || 1 )
348369 const size = WAYPOINT_CONFIG . CANVAS_SIZE * scale
349370 const canvas = document . createElement ( 'canvas' )
@@ -354,11 +375,11 @@ function drawCombinedCanvas (color: number, id: string, distance: string): HTMLC
354375 // Clear canvas
355376 ctx . clearRect ( 0 , 0 , size , size )
356377
357- // Draw dot
378+ // Draw dot with visual scale applied
358379 const centerX = size / 2
359380 const dotY = Math . round ( size * WAYPOINT_CONFIG . LAYOUT . DOT_Y )
360- const radius = Math . round ( size * 0.05 ) // Dot takes up ~12 % of canvas height
361- const borderWidth = Math . max ( 2 , Math . round ( 4 * scale ) )
381+ const radius = Math . round ( size * 0.05 * visualScale ) // Dot takes up ~5 % of canvas height, scaled
382+ const borderWidth = Math . max ( 2 , Math . round ( 4 * scale * visualScale ) )
362383
363384 // Outer border (black)
364385 ctx . beginPath ( )
@@ -376,21 +397,21 @@ function drawCombinedCanvas (color: number, id: string, distance: string): HTMLC
376397 ctx . textAlign = 'center'
377398 ctx . textBaseline = 'middle'
378399
379- // Title
380- const nameFontPx = Math . round ( size * 0.08 ) // ~8% of canvas height
381- const distanceFontPx = Math . round ( size * 0.06 ) // ~6% of canvas height
400+ // Title with visual scale applied
401+ const nameFontPx = Math . round ( size * 0.08 * visualScale ) // ~8% of canvas height, scaled
402+ const distanceFontPx = Math . round ( size * 0.06 * visualScale ) // ~6% of canvas height, scaled
382403 ctx . font = `bold ${ nameFontPx } px mojangles`
383- ctx . lineWidth = Math . max ( 2 , Math . round ( 3 * scale ) )
404+ ctx . lineWidth = Math . max ( 2 , Math . round ( 3 * scale * visualScale ) )
384405 const nameY = Math . round ( size * WAYPOINT_CONFIG . LAYOUT . NAME_Y )
385406
386407 ctx . strokeStyle = 'black'
387408 ctx . strokeText ( id , centerX , nameY )
388409 ctx . fillStyle = 'white'
389410 ctx . fillText ( id , centerX , nameY )
390411
391- // Distance
412+ // Distance with visual scale applied
392413 ctx . font = `bold ${ distanceFontPx } px mojangles`
393- ctx . lineWidth = Math . max ( 2 , Math . round ( 2 * scale ) )
414+ ctx . lineWidth = Math . max ( 2 , Math . round ( 2 * scale * visualScale ) )
394415 const distanceY = Math . round ( size * WAYPOINT_CONFIG . LAYOUT . DISTANCE_Y )
395416
396417 ctx . strokeStyle = 'black'
@@ -401,8 +422,8 @@ function drawCombinedCanvas (color: number, id: string, distance: string): HTMLC
401422 return canvas
402423}
403424
404- function createCombinedSprite ( color : number , id : string , distance : string , depthTest : boolean ) : THREE . Sprite {
405- const canvas = drawCombinedCanvas ( color , id , distance )
425+ function createCombinedSprite ( color : number , id : string , distance : string , depthTest : boolean , visualScale = 1 ) : THREE . Sprite {
426+ const canvas = drawCombinedCanvas ( color , id , distance , visualScale )
406427 const texture = new THREE . CanvasTexture ( canvas )
407428 texture . anisotropy = 1
408429 texture . magFilter = THREE . LinearFilter
0 commit comments