Cursor

Usage guide of ui.cursor: the game cursor and its modes, the ground marker left by a click order, rings under characters, settings and defaults, service methods, variables, the pointer.command and fx.ground_marker events.

Source: module-kits:kits/ui_cursor/usage/en.mdView Markdown source

Also read offline — CLI: grip-forge docs ui-cursorMCP tool: gripforge_docs { "topic": "ui-cursor" }

Game cursor, order markers and rings (ui.cursor) #

What it is for #

ui.cursor is for mouse-driven games (MOBA, RTS, action RPG, top-down). It replaces the system pointer with a game cursor, leaves a marker on the ground where the player gives an order (arrows closing on the spot for a move, red for an attack) and, when asked, draws coloured rings on the ground under characters (the hero, a downed ally). The kit decides nothing about the order itself: the kit that turns a click into an order emits pointer.command, and ui.cursor answers. It draws nothing on its own; the display module of the kit draws the markers and the rings, and the page draws the cursor from the variables. For the other screens of the interface, see the interface guide.

Turn it on #

gripforge_gamekit_install   { project_id: "gkp_…", id: "ui.cursor" }
gripforge_gamekit_configure { project_id: "gkp_…", id: "ui.cursor",
                              config: { "cursor": "crosshair", "marker": "ring", "markerSeconds": 0.8 } }

It requires game.engine only. The cursor turns to its attack mode over an enemy when combat.damage is installed.

First example #

<!-- test: kits/ui_cursor/present/src/lib.rs::tests::an_order_leaves_a_marker_that_closes_and_goes --> A click-to-move kit emits the order; ui.cursor turns it into a marker event, and the display module draws it:

{ "topic": "pointer.command", "payload": { "point": [2, 0, 3], "kind": "move" } }

becomes fx.ground_marker { position: [2, 0, 3], color: "#3ee06a", seconds: 0.55, size: 1.8, style: "arrows" }. For kind: "attack" the colour is attackColor and the size is 85 % of markerSize. The marker closes on the spot, then fades; a new marker at the same spot replaces it, and the oldest goes when there are too many.

Settings and defaults #

SettingTypeDefaultMeaning
cursorstringgauntletgauntlet, arrow, crosshair or system (the browser pointer).
cursorColorstring#d8dde6Cursor body colour.
cursorSizeinteger32Cursor size in pixels (16 to 64).
markerstringarrowsGround marker of a click: arrows, ring or none.
moveColorstring#3ee06aMarker colour of a move order.
attackColorstring#ff4d4dMarker and cursor colour of an attack order.
markerSecondsnumber0.55How long the marker stays (0.15 to 3).
markerSizenumber1.8Marker radius in metres (0.3 to 6).
ringslist[]Ring rules, up to 16 (see below). Empty: no ring.

Colours are #rrggbb; anything else falls back to the default.

Rings #

Each entity takes the first rule of rings that matches it. A rule has:

FieldDefaultMeaning
tag(required)The tag an entity carries to get this ring (player, enemy, downed, ally...).
whoanyany, local (only the character the camera follows) or others (every one but it).
unless[]No ring for an entity that also carries one of these tags (up to 8).
color#2eb8d4Ring colour.
radius0.6Radius to the middle of the band, metres (0.1 to 5).
width0.04Thickness of the band, metres (0.005 to 1).
opacity10 to 1.
pulse0Pulses per second (0 to 10); 0: steady.
lift0.03Height above the feet, metres (0 to 1).
littrueLit by the scene like the ground, or drawn flat (false: readable in the dark).
{ "rings": [
  { "tag": "downed", "who": "others", "color": "#ac302b", "pulse": 1.2, "lit": false },
  { "tag": "player", "who": "local", "color": "#2eb8d4" }
] }

Service, variables, events #

Service ui.cursor:

  • mark(position, kind?): leave a ground marker at [x, y, z]; kind is "attack" or anything else for a move.
  • setMode(mode): force the cursor mode (default, attack, ally, blocked). An empty value gives control back to the automatic mode.

Variables the page and the engines read: ui.cursor.style, ui.cursor.mode, ui.cursor.color, ui.cursor.attack_color, ui.cursor.size and ui.cursor.rings (the rules, cleaned).

Events: the kit listens to pointer.command { point, kind, target? } and emits fx.ground_marker { position, color, seconds, size, style }. A point that is not three finite numbers, and the style none, produce no marker.

Hooks and modding #

No hook: every setting is a look, and all of them are moddable. A mod can restyle the cursor and the marker or add ring rules.

The asset cursor_image (a small square image, hotspot at the top-left tip) replaces the drawn cursor.

Engines #

The marker events and the variables are the same everywhere; the web page draws the cursor, and the web and Bevy renderers draw the markers and the rings.

When it does not do what you expect #

  • No marker after a click: marker is none, or the kit that handles clicks does not emit pointer.command with a point of three numbers.
  • The cursor never turns to attack: it needs combat.damage, a player with a team in combat.health, and aim.point (or aim.target) published by an aiming kit; the test runs every six ticks.
  • A forced mode stays: call setMode("").
  • No ring: rings is empty, no rule's tag matches, or an unless tag is present.

Limits #

It does not handle the click, pathfinding or the order itself, and it draws nothing in the scene by itself.

Versions #

Kit version 1.2.0 (rings under characters); the cursor, the markers and the modes came with 1.0.0.