Rendering an In-World Text at a specific onscreen position Last updated November 18, 2020

For creating player HUDs, sometimes it can be advantageous to use In-World Texts instead of HUD Texts.


  • The text can be more easily positioned, especially on the bottom of the screen
  • More options for text sizes


  • The positions of In-World Texts may be inconsistent or even broken depending on an individual player's video settings
  • In certain situations, the extra readability of a HUD Text header may be more desirable
  • Custom Strings containing newlines typically interfere with the alignment of In-World Texts on the screen

What you need

To determine the onscreen position of an In-World Text, you will need an expression (in workshop script) for the following 4 pieces of information:

  1. {{eye}}: The eye position from which to view the text, which can be a player's eye position or the position of a Start Camera action
  2. {{zAxis}}: The facing direction of the eye position, which can again be a player's facing direction or the facing direction of a camera. Make sure that this is a unit vector (length 1). You can ensure this by using the Normalize value: Normalize({{zAxis}}).
  3. {{xPos}}: The x coordinate of the onscreen position
  4. {{yPos}}: The y coordinate of the onscreen position

In this implementation, the origin [(x,y) = (0,0)] is at the center of the screen (on the crosshair), positive x is toward the right, and positive y is towards the top of the screen. It is recommended to limit the x coordinate to ±2.5 and the y coordinate to ±1.25, since these are more or less the limits of the screen for a player on the lowest possible FoV and a 16:9 aspect ratio.

Determining the position

Once you have your four expressions, you can get the expression for the position of the text by substituting them into this:

Update Every Frame({{eye}} + 100 * (
    {{xPos}} * Cross Product({{zAxis}}, Direction From Angles(Horizontal Angle From Direction({{zAxis}}, Vertical Angle From Direction({{zAxis}})-90))) 
    + ({{yPos}} - 0.2) * Direction From Angles(Horizontal Angle From Direction({{zAxis}}, Vertical Angle From Direction({{zAxis}})-90))
    + 3 * {{zAxis}}))

After replacing the expressions, simply paste the final expression in the Position field of the relevant Create In-World Text action. Note that if you are developing on console, you'll have to manually input these values, so things may look a little different.


  • This solution is generalized for an eye position and facing direction that may not be bound to a player. If it is bound to a player, you can use the following version instead, which only requires {{xPos}} and {{yPos}}:
Update Every Frame(Eye Position(Event Player) + 100 * (
    {{xPos}} * World Vector Of(Right, Event Player, Rotation)
    + ({{yPos}} - 0.2) * Direction From Angles(Horizontal Angle From Direction(Facing Direction Of(Event Player), Vertical Angle From Direction(Facing Direction Of(Event Player))-90))
    + 3 * Facing Direction Of(Event Player))
  • Make sure that Clipping is set to Do Not Clip for the Create In-World Text action. This will ensure that the text is not obscured by map geometry or the player's first person viewmodel.
  • The values 100, 3, and 0.2 were determined by trial and error and are somewhat arbitrary. In some cases, if players are near the world boundary for Overwatch maps, the position expression may fail because the Workshop is trying to render texts outside the world boundary. In this case, you may need to change some of these values, which will also affect the scale of onscreen coordinates.
Elo Hell Logo_H-M-Dark
Join the Elo Hell Workshops Discord