Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
137 changes: 137 additions & 0 deletions WAYPOINT_IMPROVEMENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
# 🎯 Waypoint System Improvements

## Overview
This document outlines the improvements made to the waypoint system in the Minecraft Web Client, focusing on better visibility when out of sight and enhanced text clarity.

## ✨ Key Improvements

### 1. Directional Arrows When Out of Sight
- **Before**: Simple triangle arrows when waypoints were off-screen
- **After**: Full waypoint sprites with directional arrow overlays pointing toward the waypoint
- **Benefit**: Players can see the complete waypoint information even when out of sight, with clear directional guidance

### 2. Enhanced Text Clarity
- **Font Sizes**:
- Title font increased from 8% to 12% of canvas height
- Distance font increased from 6% to 9% of canvas height
- **Resolution**: Canvas size increased from 256x256 to 512x512 pixels
- **Scaling**: Canvas scale factor increased from 2x to 3x for device pixel ratio
- **Text Outlines**: Enhanced stroke width for better visibility and contrast

### 3. Improved Resolution
- **Canvas Size**: Doubled from 256x256 to 512x512 pixels
- **Scale Factor**: Increased from 2x to 3x for sharper text rendering
- **Result**: Much crisper, more readable text on all devices

## 🔧 Technical Changes

### Files Modified
1. **`renderer/viewer/three/waypointSprite.ts`**
- Updated `WAYPOINT_CONFIG` with higher resolution and scale
- Enhanced `ensureArrow()` function to show full waypoint sprite with directional overlay
- Improved `drawCombinedCanvas()` function with larger fonts and better outlines
- Modified arrow rotation logic to point in the correct direction

2. **`renderer/viewer/three/waypoints.ts`**
- Enabled offscreen arrows by default for all waypoints

3. **`renderer/viewer/three/graphicsBackend.ts`**
- Added global testing functions for easier waypoint testing

### Configuration Changes
```typescript
export const WAYPOINT_CONFIG = {
TARGET_SCREEN_PX: 150, // Unchanged
CANVAS_SIZE: 512, // Increased from 256
CANVAS_SCALE: 3, // Increased from 2
LAYOUT: { /* unchanged */ },
ARROW: {
enabledDefault: true, // Changed from false
pixelSize: 30, // Unchanged
paddingPx: 50, // Unchanged
},
}
```

### Font Size Improvements
```typescript
// Before
const nameFontPx = Math.round(size * 0.08) // 8% of canvas height
const distanceFontPx = Math.round(size * 0.06) // 6% of canvas height

// After
const nameFontPx = Math.round(size * 0.12) // 12% of canvas height
const distanceFontPx = Math.round(size * 0.09) // 9% of canvas height
```

## 🧪 Testing

### Console Commands
The following functions are now available in the browser console for testing:

```javascript
// Add test waypoints (green, yellow, blue)
testWaypoints()

// Add custom waypoint
addTestWaypoint('Home', 0, 70, 0, 0xFF0000, 'My Home')

// Remove specific waypoint
removeWaypoint('Test Point')

// List all active waypoints
listWaypoints()
```

### Test Instructions
1. Open the Minecraft Web Client
2. Wait for the world to load completely
3. Open browser console (F12 → Console)
4. Use the console commands above to test waypoints
5. Move around so waypoints go out of sight
6. Observe the improved directional arrows and text clarity

## 🎨 Visual Improvements

### Before vs After
- **Visibility**: Waypoints now maintain full appearance when off-screen
- **Direction**: Clear arrows indicate which way to go
- **Text**: Much more readable with larger fonts
- **Quality**: Higher resolution ensures crisp rendering
- **Contrast**: Better text outlines for improved visibility

### Arrow Design
- Shows the complete waypoint sprite (dot, name, distance)
- Overlays a white directional arrow with black outline
- Arrow size is 15% of canvas for good visibility
- Automatically rotates to point toward the waypoint

## 📱 Device Compatibility
- Higher resolution ensures crisp rendering on high-DPI displays
- Improved scaling handles various device pixel ratios
- Larger fonts remain readable on smaller screens
- Enhanced outlines provide better contrast in all lighting conditions

## 🚀 Performance Impact
- Minimal performance impact from increased canvas size
- Efficient texture management with proper disposal
- Optimized rendering with consistent scaling
- No additional memory overhead for arrow overlays

## 🔮 Future Enhancements
Potential areas for further improvement:
- Configurable arrow styles and colors
- Animated directional indicators
- Distance-based arrow sizing
- Custom waypoint icons
- Waypoint grouping and organization

## 📋 Summary
The waypoint system now provides:
1. **Better Navigation**: Clear directional guidance when out of sight
2. **Improved Readability**: Larger, sharper text with better contrast
3. **Enhanced Quality**: Higher resolution rendering for all devices
4. **Consistent Experience**: Same visual style whether visible or off-screen
5. **Easy Testing**: Built-in console commands for development and testing

These improvements make waypoints much more useful for navigation and provide a better user experience across all devices and viewing conditions.
55 changes: 55 additions & 0 deletions renderer/viewer/three/graphicsBackend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,61 @@
}
}

// Add global waypoint testing functions for easier testing
if (typeof window !== 'undefined') {
window.testWaypoints = () => {
if (worldRenderer?.waypoints) {

Check failure on line 59 in renderer/viewer/three/graphicsBackend.ts

View workflow job for this annotation

GitHub Actions / build-and-deploy

Cannot find name 'worldRenderer'.
worldRenderer.waypoints.testWaypoint()

Check failure on line 60 in renderer/viewer/three/graphicsBackend.ts

View workflow job for this annotation

GitHub Actions / build-and-deploy

Cannot find name 'worldRenderer'.
console.log('✅ Test waypoints added! Move around to see the improved directional arrows and text clarity.')
} else {
console.log('❌ World renderer not ready yet. Please wait for the world to load.')
}
}

window.addTestWaypoint = (id: string, x: number, y: number, z: number, color?: number, label?: string) => {
if (worldRenderer?.waypoints) {

Check failure on line 68 in renderer/viewer/three/graphicsBackend.ts

View workflow job for this annotation

GitHub Actions / build-and-deploy

Cannot find name 'worldRenderer'.
worldRenderer.waypoints.addWaypoint(id, x, y, z, {

Check failure on line 69 in renderer/viewer/three/graphicsBackend.ts

View workflow job for this annotation

GitHub Actions / build-and-deploy

Cannot find name 'worldRenderer'.
color: color || 0xFF_00_00,
label: label || id
})
console.log(`✅ Waypoint "${id}" added at (${x}, ${y}, ${z})`)
} else {
console.log('❌ World renderer not ready yet. Please wait for the world to load.')
}
}

window.removeWaypoint = (id: string) => {
if (worldRenderer?.waypoints) {

Check failure on line 80 in renderer/viewer/three/graphicsBackend.ts

View workflow job for this annotation

GitHub Actions / build-and-deploy

Cannot find name 'worldRenderer'.
worldRenderer.waypoints.removeWaypoint(id)

Check failure on line 81 in renderer/viewer/three/graphicsBackend.ts

View workflow job for this annotation

GitHub Actions / build-and-deploy

Cannot find name 'worldRenderer'.
console.log(`✅ Waypoint "${id}" removed`)
} else {
console.log('❌ World renderer not ready yet. Please wait for the world to load.')
}
}

window.listWaypoints = () => {
if (worldRenderer?.waypoints) {

Check failure on line 89 in renderer/viewer/three/graphicsBackend.ts

View workflow job for this annotation

GitHub Actions / build-and-deploy

Cannot find name 'worldRenderer'.
const waypoints = worldRenderer.waypoints.getAllWaypoints()

Check failure on line 90 in renderer/viewer/three/graphicsBackend.ts

View workflow job for this annotation

GitHub Actions / build-and-deploy

Cannot find name 'worldRenderer'.
if (waypoints.length === 0) {
console.log('📍 No waypoints currently active')
} else {
console.log('📍 Active waypoints:')
waypoints.forEach(wp => {
console.log(` - ${wp.id}: (${wp.x}, ${wp.y}, ${wp.z}) - Color: #${wp.color.toString(16).padStart(6, '0')}`)
})
}
} else {
console.log('❌ World renderer not ready yet. Please wait for the world to load.')
}
}

console.log('🎯 Waypoint testing functions added to window:')
console.log(' - testWaypoints() - Add test waypoints')
console.log(' - addTestWaypoint(id, x, y, z, color?, label?) - Add custom waypoint')
console.log(' - removeWaypoint(id) - Remove waypoint')
console.log(' - listWaypoints() - List all active waypoints')
}

export type ThreeJsBackendMethods = ReturnType<typeof getBackendMethods>

const createGraphicsBackend: GraphicsBackendLoader = (initOptions: GraphicsInitOptions) => {
Expand Down
132 changes: 80 additions & 52 deletions renderer/viewer/three/waypointSprite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,17 @@ export const WAYPOINT_CONFIG = {
// Target size in screen pixels (this controls the final sprite size)
TARGET_SCREEN_PX: 150,
// Canvas size for internal rendering (keep power of 2 for textures)
CANVAS_SIZE: 256,
CANVAS_SIZE: 512, // Increased from 256 for better resolution
// Relative positions in canvas (0-1)
LAYOUT: {
DOT_Y: 0.3,
NAME_Y: 0.45,
DISTANCE_Y: 0.55,
},
// Multiplier for canvas internal resolution to keep text crisp
CANVAS_SCALE: 2,
CANVAS_SCALE: 3, // Increased from 2 for sharper text
ARROW: {
enabledDefault: false,
enabledDefault: true, // Changed from false to true
pixelSize: 30,
paddingPx: 50,
},
Expand Down Expand Up @@ -125,22 +125,45 @@ export function createWaypointSprite (options: {

function ensureArrow () {
if (arrowSprite) return
const size = 128

// Create a canvas with the same waypoint sprite but with directional arrow overlay
const scale = WAYPOINT_CONFIG.CANVAS_SCALE * (globalThis.devicePixelRatio || 1)
const size = WAYPOINT_CONFIG.CANVAS_SIZE * scale
const canvas = document.createElement('canvas')
canvas.width = size
canvas.height = size
const ctx = canvas.getContext('2d')!
ctx.clearRect(0, 0, size, size)

// Draw the same waypoint sprite as the main one
drawCombinedCanvas(color, currentLabel, '0m', ctx, size)

// Add directional arrow overlay in the center
const arrowSize = Math.round(size * 0.15) // Arrow takes up ~15% of canvas
const centerX = size / 2
const centerY = size / 2

// Draw arrow pointing right (will be rotated based on direction)
ctx.save()
ctx.translate(centerX, centerY)

// Arrow shape (pointing right)
ctx.beginPath()
ctx.moveTo(size * 0.2, size * 0.5)
ctx.lineTo(size * 0.8, size * 0.5)
ctx.lineTo(size * 0.5, size * 0.2)
ctx.moveTo(-arrowSize * 0.3, 0)
ctx.lineTo(arrowSize * 0.3, 0)
ctx.lineTo(arrowSize * 0.1, -arrowSize * 0.2)
ctx.lineTo(arrowSize * 0.3, 0)
ctx.lineTo(arrowSize * 0.1, arrowSize * 0.2)
ctx.closePath()
ctx.lineWidth = 4
ctx.strokeStyle = 'black'
ctx.stroke()

// Fill with white and black outline
ctx.fillStyle = 'white'
ctx.fill()
ctx.lineWidth = Math.max(3, Math.round(4 * scale))
ctx.strokeStyle = 'black'
ctx.stroke()

ctx.restore()

const texture = new THREE.CanvasTexture(canvas)
const material = new THREE.SpriteMaterial({ map: texture, transparent: true, depthTest: false, depthWrite: false })
arrowSprite = new THREE.Sprite(material)
Expand Down Expand Up @@ -240,13 +263,18 @@ export function createWaypointSprite (options: {
arrowSprite.visible = true
arrowSprite.position.copy(pos)

// Angle for rotation relative to screen right/up (derived from camera up vector)
const angle = Math.atan2(ry, rx)
arrowSprite.material.rotation = angle - Math.PI / 2
// Calculate the direction vector from camera to waypoint
const direction = new THREE.Vector3(group.position.x, group.position.y, group.position.z).sub(camPos).normalize()

// Calculate the angle in the XZ plane (horizontal direction)
const horizontalAngle = Math.atan2(direction.x, direction.z)

// Rotate the arrow to point in the direction of the waypoint
arrowSprite.material.rotation = horizontalAngle

// Constant pixel size for arrow (use fixed placement distance)
// Use the same scale as the main waypoint sprite for consistency
const worldUnitsPerScreenHeightAtDist = Math.tan(vFovRad / 2) * 2 * placeDist
const sPx = worldUnitsPerScreenHeightAtDist * (WAYPOINT_CONFIG.ARROW.pixelSize / viewportHeightPx)
const sPx = worldUnitsPerScreenHeightAtDist * (WAYPOINT_CONFIG.TARGET_SCREEN_PX / viewportHeightPx)
arrowSprite.scale.set(sPx, sPx, 1)
return false
}
Expand Down Expand Up @@ -299,60 +327,60 @@ export function createWaypointSprite (options: {
}

// Internal helpers
function drawCombinedCanvas (color: number, id: string, distance: string): HTMLCanvasElement {
function drawCombinedCanvas (color: number, id: string, distance: string, ctx?: CanvasRenderingContext2D, size?: number): HTMLCanvasElement {
const scale = WAYPOINT_CONFIG.CANVAS_SCALE * (globalThis.devicePixelRatio || 1)
const size = WAYPOINT_CONFIG.CANVAS_SIZE * scale
const sizeCanvas = size || WAYPOINT_CONFIG.CANVAS_SIZE * scale
const canvas = document.createElement('canvas')
canvas.width = size
canvas.height = size
const ctx = canvas.getContext('2d')!
canvas.width = sizeCanvas
canvas.height = sizeCanvas
const ctxCanvas = ctx || canvas.getContext('2d')!
Comment on lines +389 to +395
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

🧩 Analysis chain

Texture size can exceed common GPU limits (DPR-multiplied 512×3 → 4608 on DPR=3). Clamp and cap DPR to prevent perf/alloc spikes.

Multiplying CANVAS_SIZE (512) by CANVAS_SCALE (3) and devicePixelRatio produces >4K canvases on high-DPR displays, risking stalls and OOM on some GPUs. Cap DPR and clamp to a safe max size:

-function drawCombinedCanvas (color: number, id: string, distance: string, ctx?: CanvasRenderingContext2D, size?: number): HTMLCanvasElement {
-  const scale = WAYPOINT_CONFIG.CANVAS_SCALE * (globalThis.devicePixelRatio || 1)
-  const sizeCanvas = size || WAYPOINT_CONFIG.CANVAS_SIZE * scale
+function drawCombinedCanvas (color: number, id: string, distance: string, ctx?: CanvasRenderingContext2D, size?: number): HTMLCanvasElement {
+  const deviceScale = Math.min(globalThis.devicePixelRatio || 1, 2) // cap DPR impact
+  const scale = WAYPOINT_CONFIG.CANVAS_SCALE * deviceScale
+  const baseSize = WAYPOINT_CONFIG.CANVAS_SIZE * scale
+  const MAX_TEX = 2048
+  const sizeCanvas = size || Math.min(baseSize, MAX_TEX)

Optionally consider reducing CANVAS_SCALE to 2 for mobile profiles.

Also applies to: 8-8, 16-16, 21-23


🏁 Script executed:

#!/bin/bash
set -euo pipefail
echo "Searching repository for drawCombinedCanvas, WAYPOINT_CONFIG, CANVAS_SIZE, CANVAS_SCALE, devicePixelRatio..."

if command -v rg >/dev/null 2>&1; then
  rg -n --hidden --no-ignore-vcs -S "drawCombinedCanvas|WAYPOINT_CONFIG|CANVAS_SIZE|CANVAS_SCALE|devicePixelRatio" || true
else
  echo "rg (ripgrep) not found; using find+grep fallback"
  find . -type f -name '*.ts' -o -name '*.js' -o -name '*.tsx' -o -name '*.jsx' | xargs grep -nH -E "drawCombinedCanvas|WAYPOINT_CONFIG|CANVAS_SIZE|CANVAS_SCALE|devicePixelRatio" || true
fi

# Show the waypointSprite file if present
WSP=$(rg -n --hidden --no-ignore-vcs -S "waypointSprite.ts" -l || true)
if [ -n "$WSP" ]; then
  echo "Found waypointSprite file(s):"
  echo "$WSP"
  for f in $WSP; do
    echo "---- $f (first 400 lines) ----"
    sed -n '1,400p' "$f" | nl -ba
  done
else
  echo "No waypointSprite.ts file found by name; trying to locate files containing drawCombinedCanvas..."
  FILES=$(rg -n --hidden --no-ignore-vcs -S "drawCombinedCanvas" -l || true)
  if [ -n "$FILES" ]; then
    echo "Files with drawCombinedCanvas:"
    echo "$FILES"
    for f in $FILES; do
      echo "---- $f (first 400 lines) ----"
      sed -n '1,400p' "$f" | nl -ba
    done
  else
    echo "No files contain drawCombinedCanvas."
  fi
fi

echo "Searching for definitions/values of CANVAS_SIZE / CANVAS_SCALE / WAYPOINT_CONFIG..."
CFGFILES=$(rg -n --hidden --no-ignore-vcs -S "CANVAS_SIZE|CANVAS_SCALE|WAYPOINT_CONFIG" -l || true)
if [ -n "$CFGFILES" ]; then
  for f in $CFGFILES; do
    echo "---- $f ----"
    rg -n --hidden --no-ignore-vcs -S "CANVAS_SIZE|CANVAS_SCALE|WAYPOINT_CONFIG" "$f" -n -C3 || true
    echo "File head:"
    sed -n '1,200p' "$f" | nl -ba
  done
else
  echo "No files found defining CANVAS_SIZE/CANVAS_SCALE/WAYPOINT_CONFIG."
fi

echo "Searching for raw uses of canvas.width/height and getContext..."
rg -n --hidden --no-ignore-vcs -S "canvas.width|canvas.height|getContext\\(" || true

echo "Done."

Length of output: 3105


Clamp DPR and cap canvas size to avoid >4K textures

WAYPOINT_CONFIG.CANVAS_SIZE = 512 and CANVAS_SCALE = 3 are multiplied by devicePixelRatio in drawCombinedCanvas — DPR=3 → 51233 = 4608px, which can cause GPU stalls/OOM. Cap DPR and clamp the computed canvas size.

Location: renderer/viewer/three/waypointSprite.ts (drawCombinedCanvas at ~lines 389–395; WAYPOINT_CONFIG at top ~lines 4–16)

-function drawCombinedCanvas (color: number, id: string, distance: string, ctx?: CanvasRenderingContext2D, size?: number): HTMLCanvasElement {
-  const scale = WAYPOINT_CONFIG.CANVAS_SCALE * (globalThis.devicePixelRatio || 1)
-  const sizeCanvas = size || WAYPOINT_CONFIG.CANVAS_SIZE * scale
+function drawCombinedCanvas (color: number, id: string, distance: string, ctx?: CanvasRenderingContext2D, size?: number): HTMLCanvasElement {
+  const deviceScale = Math.min(globalThis.devicePixelRatio || 1, 2) // cap DPR impact
+  const scale = WAYPOINT_CONFIG.CANVAS_SCALE * deviceScale
+  const baseSize = WAYPOINT_CONFIG.CANVAS_SIZE * scale
+  const MAX_TEX = 2048
+  const sizeCanvas = size || Math.min(baseSize, MAX_TEX)

Also review other drawCombinedCanvas call sites in this file to ensure they don’t force oversized textures.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function drawCombinedCanvas (color: number, id: string, distance: string, ctx?: CanvasRenderingContext2D, size?: number): HTMLCanvasElement {
const scale = WAYPOINT_CONFIG.CANVAS_SCALE * (globalThis.devicePixelRatio || 1)
const size = WAYPOINT_CONFIG.CANVAS_SIZE * scale
const sizeCanvas = size || WAYPOINT_CONFIG.CANVAS_SIZE * scale
const canvas = document.createElement('canvas')
canvas.width = size
canvas.height = size
const ctx = canvas.getContext('2d')!
canvas.width = sizeCanvas
canvas.height = sizeCanvas
const ctxCanvas = ctx || canvas.getContext('2d')!
function drawCombinedCanvas (color: number, id: string, distance: string, ctx?: CanvasRenderingContext2D, size?: number): HTMLCanvasElement {
const deviceScale = Math.min(globalThis.devicePixelRatio || 1, 2) // cap DPR impact
const scale = WAYPOINT_CONFIG.CANVAS_SCALE * deviceScale
const baseSize = WAYPOINT_CONFIG.CANVAS_SIZE * scale
const MAX_TEX = 2048
const sizeCanvas = size || Math.min(baseSize, MAX_TEX)
const canvas = document.createElement('canvas')
canvas.width = sizeCanvas
canvas.height = sizeCanvas
const ctxCanvas = ctx || canvas.getContext('2d')!
🤖 Prompt for AI Agents
In renderer/viewer/three/waypointSprite.ts around lines 389–395, drawing
multiplies WAYPOINT_CONFIG.CANVAS_SCALE by globalThis.devicePixelRatio which can
produce >4K canvases (e.g., 512*3*3=4608) and cause GPU/OOM; fix by clamping DPR
to a safe maximum (e.g., const dpr = Math.min(globalThis.devicePixelRatio || 1,
2)) and capping the computed canvas size to a MAX_CANVAS_SIZE (e.g., 4096)
before assigning canvas.width/height (use Math.min(sizeOrDefault * dpr,
MAX_CANVAS_SIZE) and ensure the result is an integer), and update any other
drawCombinedCanvas call sites in this file to avoid forcing oversized textures.


// Clear canvas
ctx.clearRect(0, 0, size, size)
ctxCanvas.clearRect(0, 0, sizeCanvas, sizeCanvas)

// Draw dot
const centerX = size / 2
const dotY = Math.round(size * WAYPOINT_CONFIG.LAYOUT.DOT_Y)
const radius = Math.round(size * 0.05) // Dot takes up ~12% of canvas height
const centerX = sizeCanvas / 2
const dotY = Math.round(sizeCanvas * WAYPOINT_CONFIG.LAYOUT.DOT_Y)
const radius = Math.round(sizeCanvas * 0.05) // Dot takes up ~12% of canvas height
const borderWidth = Math.max(2, Math.round(4 * scale))

// Outer border (black)
ctx.beginPath()
ctx.arc(centerX, dotY, radius + borderWidth, 0, Math.PI * 2)
ctx.fillStyle = 'black'
ctx.fill()
ctxCanvas.beginPath()
ctxCanvas.arc(centerX, dotY, radius + borderWidth, 0, Math.PI * 2)
ctxCanvas.fillStyle = 'black'
ctxCanvas.fill()

// Inner circle (colored)
ctx.beginPath()
ctx.arc(centerX, dotY, radius, 0, Math.PI * 2)
ctx.fillStyle = `#${color.toString(16).padStart(6, '0')}`
ctx.fill()
ctxCanvas.beginPath()
ctxCanvas.arc(centerX, dotY, radius, 0, Math.PI * 2)
ctxCanvas.fillStyle = `#${color.toString(16).padStart(6, '0')}`
ctxCanvas.fill()

// Text properties
ctx.textAlign = 'center'
ctx.textBaseline = 'middle'
ctxCanvas.textAlign = 'center'
ctxCanvas.textBaseline = 'middle'

// Title
const nameFontPx = Math.round(size * 0.08) // ~8% of canvas height
const distanceFontPx = Math.round(size * 0.06) // ~6% of canvas height
ctx.font = `bold ${nameFontPx}px mojangles`
ctx.lineWidth = Math.max(2, Math.round(3 * scale))
const nameY = Math.round(size * WAYPOINT_CONFIG.LAYOUT.NAME_Y)
const nameFontPx = Math.round(sizeCanvas * 0.12) // Increased from 0.08 (~12% of canvas height)
const distanceFontPx = Math.round(sizeCanvas * 0.09) // Increased from 0.06 (~9% of canvas height)
ctxCanvas.font = `bold ${nameFontPx}px mojangles`
ctxCanvas.lineWidth = Math.max(3, Math.round(4 * scale)) // Increased line width for better text outline
const nameY = Math.round(sizeCanvas * WAYPOINT_CONFIG.LAYOUT.NAME_Y)

ctx.strokeStyle = 'black'
ctx.strokeText(id, centerX, nameY)
ctx.fillStyle = 'white'
ctx.fillText(id, centerX, nameY)
ctxCanvas.strokeStyle = 'black'
ctxCanvas.strokeText(id, centerX, nameY)
ctxCanvas.fillStyle = 'white'
ctxCanvas.fillText(id, centerX, nameY)

// Distance
ctx.font = `bold ${distanceFontPx}px mojangles`
ctx.lineWidth = Math.max(2, Math.round(2 * scale))
const distanceY = Math.round(size * WAYPOINT_CONFIG.LAYOUT.DISTANCE_Y)

ctx.strokeStyle = 'black'
ctx.strokeText(distance, centerX, distanceY)
ctx.fillStyle = '#CCCCCC'
ctx.fillText(distance, centerX, distanceY)
ctxCanvas.font = `bold ${distanceFontPx}px mojangles`
ctxCanvas.lineWidth = Math.max(3, Math.round(3 * scale)) // Increased line width for better text outline
const distanceY = Math.round(sizeCanvas * WAYPOINT_CONFIG.LAYOUT.DISTANCE_Y)

ctxCanvas.strokeStyle = 'black'
ctxCanvas.strokeText(distance, centerX, distanceY)
ctxCanvas.fillStyle = '#CCCCCC'
ctxCanvas.fillText(distance, centerX, distanceY)

return canvas
}
Expand Down
Loading
Loading