Click in the world
Goal
Show a hover marker at the collider under the pointer, and click to select a target or walk a character to the hit point.
Files you will edit
src/game.ts— the existing game's pointer system.
Steps
Allocate hit and HUD records once, then add this system after your camera system. Keep the existing player and collider setup. The HUD receives the hover position and entity; use the existing HUD's mint marker to highlight it.
tsimport { hitUnderCursor, simpleMoveTo, type CursorHit, type GameContext } from 'gameable'; const hit: CursorHit = { point: { x: 0, y: 0, z: 0 }, normal: { x: 0, y: 1, z: 0 }, entity: 0, distance: 0, }; const model = { hover: { visible: false, entity: 0, x: 0, y: 0, z: 0 }, selected: 0, }; export function pointerSystem(ctx: GameContext): void { const found = hitUnderCursor(ctx, hit); model.hover.visible = found; model.hover.entity = found ? hit.entity : 0; if (found) { model.hover.x = hit.point.x; model.hover.y = hit.point.y; model.hover.z = hit.point.z; if (ctx.started && ctx.input.pressed('LMB')) { model.selected = hit.entity; if (ctx.player !== 0) simpleMoveTo(ctx, ctx.player, hit.point); } } ctx.hud.set(model); }Register
pointerSystemandstepMovesin yoursystemslist (mergemodelinto an existing HUD model). For target-only games, dropsimpleMoveTo.
The pointer and viewport() are in CSS pixels from the first tick (hosts send an initial resize), relative to the view's top-left. Pick in a system, after this frame's camera is set. hitUnderCursor reaches 500 m by default; query is physics.raycast's layer mask. Third-person picking assumes the full arm length. With no ground collider, use screenRay then rayToGround(ray, 0, destination).
Verify
Run npm run dev in your game. With pointer lock disabled, hover over a collider: the HUD hover data contains its entity and world position. Click once: selected changes to that entity and the player walks to the hit point. Hover empty space: visible becomes false and clicking leaves the selection unchanged.