Skip to content

Conversation

zardoy
Copy link
Owner

@zardoy zardoy commented Sep 19, 2025

Add metadataJson to waypoints to enable onlyLeftRight arrow positioning and enhance offscreen arrow visibility with increased size and waypoint-colored fill.


Open in Cursor Open in Web

Summary by CodeRabbit

  • New Features
    • Waypoint arrows are larger, with a refined shape and thicker outline for clearer direction.
    • Arrow fill now matches the waypoint color instead of white.
    • Optional metadata can be attached to waypoints (including via incoming packets).
    • New metadata option to constrain off-screen arrows to left/right edges for clearer guidance.
    • Arrows start hidden until needed and render above other elements.

Copy link

cursor bot commented Sep 19, 2025

Cursor Agent can help with this pull request. Just @cursor in comments and I'll start working on changes in this branch.
Learn more about Cursor Agents

Copy link

coderabbitai bot commented Sep 19, 2025

Walkthrough

Adds optional metadata propagation for waypoint creation via the custom channel, extends sprite creation to accept metadata, introduces onlyLeftRight clamping for offscreen arrows, changes arrow visuals (size, stroke, shape, fill derived from waypoint color), and sets arrow sprite renderOrder/initial visibility.

Changes

Cohort / File(s) Summary of Changes
Rendering: Arrow sprite updates
renderer/viewer/three/waypointSprite.ts
Increased WAYPOINT_CONFIG.ARROW.pixelSize 30→50; stroke width 4→6; adjusted arrow vertex coordinates; arrow fill now uses waypoint color (computed hex) while stroke remains black; arrowSprite.renderOrder = 12, initial visible = false; createWaypointSprite options extended to accept metadata; added onlyLeftRight logic to constrain offscreen arrow to horizontal/vertical edges.
Waypoints plumbing
renderer/viewer/three/waypoints.ts
WaypointOptions now includes metadata?: any; addWaypoint extracts metadata from options and forwards it to createWaypointSprite (label handling unchanged); metadata not persisted in internal waypoint map.
Networking: waypoint-add channel
src/customChannels.ts
Packet structure minecraft-web-client:waypoint-add extended with metadataJson (['pstring', { countType: 'i16' }]); handler parses metadataJson (with try/catch, warns on failure) and passes parsed object (or {}) as metadata to renderer addWaypoint.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant S as Game Server
  participant C as Client Channel Handler
  participant R as Renderer (Waypoints)
  participant F as Sprite Factory

  rect rgba(230,240,255,0.5)
    Note over S,C: minecraft-web-client:waypoint-add
    S->>C: Packet { id, position, color, metadataJson? }
    C->>C: Parse metadataJson (try/catch)
    C->>R: addWaypoint({ id, position, color, metadata })
    R->>F: createWaypointSprite({ color, label, metadata })
    F-->>R: Waypoint sprite (arrow styled by color)
  end

  rect rgba(240,230,255,0.5)
    Note over R,F: Offscreen indicator update
    R->>F: updateOffscreenArrow(...)
    alt metadata.onlyLeftRight == true
      F->>F: Clamp direction to horizontal/vertical edge (onlyLeftRight)
    else Default behavior
      F->>F: Use full directional vector for placement
    end
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

I hop through packets, ears held high,
A JSON whisper flits on by.
It paints my arrow, bold and bright—
Left or right, I choose the light.
With metadata tucked in tow,
I mark the path and off I go! 🐇➡️

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title "feat: make arrows colorful and metadata" succinctly captures the two principal changes in the PR: visual updates to waypoint/offscreen arrows (colorized fill and size/stroke adjustments) and the addition of metadata support (metadataJson/metadata?: any and onlyLeftRight behavior). It is concise, relevant, and would be understandable to a teammate scanning commit history. The phrasing is slightly generic about the metadata detail but still accurately reflects the changeset.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch cursor/update-waypoint-offscreen-arrows-based-on-metadata-40c2

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@zardoy zardoy marked this pull request as ready for review September 19, 2025 05:09
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (8)
renderer/viewer/three/waypoints.ts (2)

16-21: Type metadata explicitly (avoid any).

Define a narrow type (e.g., WaypointMetadata { onlyLeftRight?: boolean }) and use it here to prevent shape drift.

Apply this diff:

 interface WaypointOptions {
   color?: number
   label?: string
   minDistance?: number
-  metadata?: any
+  metadata?: { onlyLeftRight?: boolean }
 }

78-83: Align initial sprite position with stored (+0.5) coordinates.

Prevents a first-frame “jump” when the update loop runs.

Apply this diff:

   const sprite = createWaypointSprite({
-      position: new THREE.Vector3(x, y, z),
+      position: new THREE.Vector3(x + 0.5, y + 0.5, z + 0.5),
       color,
       label: (label || id),
       metadata,
     })
src/customChannels.ts (2)

94-103: Harden JSON parsing and shape.

If metadataJson parses to a non-object (string/array), coerce to {} to avoid surprises downstream.

Apply this diff:

   let metadata: any = {}
   if (data.metadataJson && data.metadataJson.trim() !== '') {
     try {
-      metadata = JSON.parse(data.metadataJson)
+      const parsed = JSON.parse(data.metadataJson)
+      metadata = parsed && typeof parsed === 'object' && !Array.isArray(parsed) ? parsed : {}
     } catch (error) {
       console.warn('Failed to parse waypoint metadataJson:', error)
     }
   }

104-109: Ensure addWaypoint options include typed metadata.onlyLeftRight
WaypointOptions.metadata is currently typed as any — change it to metadata?: { onlyLeftRight?: boolean } (also update createWaypointSprite's options) so ThreeJsBackendMethods.addWaypoint (ReturnType of getBackendMethods in renderer/viewer/three/graphicsBackend.ts) exposes the correct type.
renderer/viewer/three/waypoints.ts; renderer/viewer/three/waypointSprite.ts.

renderer/viewer/three/waypointSprite.ts (4)

53-54: Type metadata explicitly.

Prefer a concrete shape to avoid accidental overreach.

Apply this diff:

-  metadata?: any,
+  metadata?: { onlyLeftRight?: boolean },

Optionally add a shared type alias if reused.


135-151: Fix trailing whitespace (CI failing).

CI reports “Trailing spaces not allowed” at Lines 135, 142, 150. Trim blank-line spaces.

Apply this diff:

-    
+ 
@@
-    
+ 
@@
-    
+ 

179-181: onlyLeftRight behavior: tie-breaker refinement.

When rx ≈ 0 and vertical is dominant, code always selects right. Consider using the world-space x sign (or last arrow side) to avoid bias/jitter.

Example tweak:

// inside the onlyLeftRight block
if (Math.abs(rx) > Math.abs(ry)) {
  ry = 0
} else {
  // use world-space x sign as tie-breaker when rx ~ 0
  const sign = Math.sign(x) || 1
  rx = sign > 0 ? 1 : -1
  ry = 0
}

Also applies to: 226-238


299-308: Remove arrow sprite from scene on dispose.

Dispose frees material but leaves the sprite in the scene graph.

Add:

if (arrowSprite?.parent) {
  arrowSprite.parent.remove(arrowSprite)
}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 636a7fd and 0e82a64.

📒 Files selected for processing (3)
  • renderer/viewer/three/waypointSprite.ts (5 hunks)
  • renderer/viewer/three/waypoints.ts (2 hunks)
  • src/customChannels.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
src/**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/vars-usage.mdc)

src/**/*.ts: You may use the global variable bot directly in any file under the src/ directory (e.g., src/mineflayer/playerState.ts).
In src/ code, you may use the global variable appViewer from src/appViewer.ts directly. Do not import appViewer or use window.appViewer; use the global appViewer variable as-is.

Files:

  • src/customChannels.ts
renderer/**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/vars-usage.mdc)

renderer/**/*.ts: Do not use the global variable bot directly in any file under the renderer/ directory or its subfolders (e.g., renderer/viewer/three/worldrendererThree.ts).
In renderer code, all bot/player state and events must be accessed via explicit interfaces, state managers, or passed-in objects, never by referencing bot directly.
In renderer code (such as in WorldRendererThree), use the playerState property (e.g., worldRenderer.playerState.gameMode) to access player state. The implementation for playerState lives in src/mineflayer/playerState.ts.

Files:

  • renderer/viewer/three/waypoints.ts
  • renderer/viewer/three/waypointSprite.ts
🧬 Code graph analysis (2)
src/customChannels.ts (1)
renderer/viewer/three/threeJsMethods.ts (1)
  • getThreeJsRendererMethods (4-15)
renderer/viewer/three/waypoints.ts (1)
renderer/viewer/three/waypointSprite.ts (1)
  • createWaypointSprite (46-323)
🪛 GitHub Check: build-and-deploy
renderer/viewer/three/waypointSprite.ts

[failure] 150-150:
Trailing spaces not allowed


[failure] 142-142:
Trailing spaces not allowed


[failure] 135-135:
Trailing spaces not allowed

🪛 GitHub Actions: CI
renderer/viewer/three/waypointSprite.ts

[error] 135-135: Trailing spaces not allowed. (stylistic/no-trailing-spaces)

🔇 Additional comments (4)
renderer/viewer/three/waypoints.ts (1)

75-76: LGTM: options destructuring and propagation.

Metadata is forwarded correctly to the sprite factory.

src/customChannels.ts (1)

85-89: LGTM: channel schema extended with metadataJson.

Optional JSON payload is added without breaking existing fields.

renderer/viewer/three/waypointSprite.ts (2)

19-21: LGTM: larger, padded arrows improve visibility.

Increased pixelSize and padding are reasonable defaults.


138-149: LGTM: arrow shape and colorization.

Arrow uses waypoint color with black stroke; renderOrder set higher than label sprite.

Comment on lines 135 to 151

// Draw arrow shape
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(size * 0.15, size * 0.5)
ctx.lineTo(size * 0.85, size * 0.5)
ctx.lineTo(size * 0.5, size * 0.15)
ctx.closePath()
ctx.lineWidth = 4

// Use waypoint color for arrow
const colorHex = `#${color.toString(16).padStart(6, '0')}`
ctx.lineWidth = 6
ctx.strokeStyle = 'black'
ctx.stroke()
ctx.fillStyle = 'white'
ctx.fillStyle = colorHex
ctx.fill()

const texture = new THREE.CanvasTexture(canvas)
Copy link

@coderabbitai coderabbitai bot Sep 19, 2025

Choose a reason for hiding this comment

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

⚠️ Potential issue

Keep arrow color in sync with setColor().

Arrow texture is baked once with the initial color and won’t update after setWaypointColor. Update the arrow texture on color change.

Apply this diff within ensureArrow to allow reuse of the texture generator:

 function ensureArrow () {
   if (arrowSprite) return
-  const size = 128
-  const canvas = document.createElement('canvas')
-  canvas.width = size
-  canvas.height = size
-  const ctx = canvas.getContext('2d')!
-  ctx.clearRect(0, 0, size, size)
- 
-  // Draw arrow shape
-  ctx.beginPath()
-  ctx.moveTo(size * 0.15, size * 0.5)
-  ctx.lineTo(size * 0.85, size * 0.5)
-  ctx.lineTo(size * 0.5, size * 0.15)
-  ctx.closePath()
- 
-  // Use waypoint color for arrow
-  const colorHex = `#${color.toString(16).padStart(6, '0')}`
-  ctx.lineWidth = 6
-  ctx.strokeStyle = 'black'
-  ctx.stroke()
-  ctx.fillStyle = colorHex
-  ctx.fill()
- 
-  const texture = new THREE.CanvasTexture(canvas)
+  const texture = makeArrowTexture(color)
   const material = new THREE.SpriteMaterial({ map: texture, transparent: true, depthTest: false, depthWrite: false })
   arrowSprite = new THREE.Sprite(material)
   arrowSprite.renderOrder = 12
   arrowSprite.visible = false
   if (arrowParent) arrowParent.add(arrowSprite)
 }
+
+function makeArrowTexture (c: number): THREE.CanvasTexture {
+  const size = 128
+  const canvas = document.createElement('canvas')
+  canvas.width = size
+  canvas.height = size
+  const ctx = canvas.getContext('2d')!
+  ctx.clearRect(0, 0, size, size)
+  ctx.beginPath()
+  ctx.moveTo(size * 0.15, size * 0.5)
+  ctx.lineTo(size * 0.85, size * 0.5)
+  ctx.lineTo(size * 0.5, size * 0.15)
+  ctx.closePath()
+  const colorHex = `#${c.toString(16).padStart(6, '0')}`
+  ctx.lineWidth = 6
+  ctx.strokeStyle = 'black'
+  ctx.stroke()
+  ctx.fillStyle = colorHex
+  ctx.fill()
+  return new THREE.CanvasTexture(canvas)
+}

Then, add this in setColor (outside the changed hunk):

// after updating the main sprite texture:
if (arrowSprite) {
  const mat = arrowSprite.material as THREE.SpriteMaterial
  mat.map?.dispose()
  mat.map = makeArrowTexture(newColor)
  mat.needsUpdate = true
}
🧰 Tools
🪛 GitHub Check: build-and-deploy

[failure] 150-150:
Trailing spaces not allowed


[failure] 142-142:
Trailing spaces not allowed


[failure] 135-135:
Trailing spaces not allowed

🪛 GitHub Actions: CI

[error] 135-135: Trailing spaces not allowed. (stylistic/no-trailing-spaces)

🤖 Prompt for AI Agents
In renderer/viewer/three/waypointSprite.ts around lines 135-151, the arrow
canvas texture is baked once with the initial color and never updated when
setColor/setWaypointColor is called; move the arrow texture creation into a
reusable function (e.g., makeArrowTexture(color)) inside ensureArrow so it can
be called whenever you need a fresh texture, and in setColor after updating the
main sprite texture check for arrowSprite, dispose its current material.map,
assign mat.map = makeArrowTexture(newColor) and set mat.needsUpdate = true to
update the arrow color at runtime.

Copy link
Owner Author

Choose a reason for hiding this comment

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

actually very good suggestion 👍

Copy link

Choose a reason for hiding this comment

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

@zardoy Thank you! I'm glad the suggestion was helpful. The arrow color synchronization issue could definitely cause confusion for users when they change waypoint colors at runtime, so extracting the texture creation into a reusable function should make the behavior much more consistent.


If you found this review helpful, would you consider giving us a shout-out on X?

Thank you for using CodeRabbit!

@zardoy zardoy changed the title Update waypoint offscreen arrows based on metadata feat: make arrows colorful and metadata Sep 19, 2025
@zardoy zardoy merged commit 3b94889 into next Sep 19, 2025
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants