Skip to content

Set Position / Desired Size / Alignment in Viewport

At a glance

Lives on: a root User Widget registered with the game viewport or a local player's screen - Changes: that root widget's viewport slot position, explicit size, and layout pivot - Returns: no success value - Can fail by: targeting None, moving a nested widget whose viewport slot is not being used, mixing pixel and UMG coordinates, or measuring desired size before layout - Official docs: Set Position in Viewport, Set Desired Size in Viewport, and Set Alignment in Viewport

These nodes arrange one UserWidget as a root screen layer. They do not reach inside that Widget Blueprint and move an arbitrary Button, Image, or Canvas child.

The one-minute version

  • A widget added with Add to Viewport or Add to Player Screen has a viewport-managed root slot. These nodes update that slot.
  • Set Position in Viewport changes the slot's 2D placement. Its Remove DPI Scale input decides whether the position still needs conversion from viewport pixels into Unreal Motion Graphics (UMG) layout units.
  • Set Desired Size in Viewport supplies an explicit root-slot size. It does not inspect the widget's content and discover its natural desired size for you.
  • Set Alignment in Viewport chooses which point in that sized rectangle sits at the position: (0,0) top-left, (0.5,0.5) center, (1,1) bottom-right.
  • In current UE5, viewport slot information can be stored before the widget is added and applied later. The widget is not visible until it is actually added, and geometry-based measurement still needs construction and a layout prepass.
  • For split-screen, create the widget for the correct local Player Controller, use Add to Player Screen, and keep projection, position, and bounds in that same player's coordinate space.
  • For an internal Canvas child, use Slot as Canvas Slot or the slot returned by Add Child to Canvas instead.

Which slot these nodes actually change

Current UE5 tracks root screen layout in an FGameViewportWidgetSlot managed by UGameViewportSubsystem. That record includes anchors, offsets, alignment, and Z order. Add to Viewport registers a root widget for the game viewport; Add to Player Screen registers one in the owning local player's section.

That relationship is separate from the UPanelSlot relationships inside a Widget Blueprint:

game viewport / local player screen
`-- WBP_ObjectiveMarker (viewport slot)
    `-- RootCanvas
        `-- MarkerImage (Canvas Panel Slot)

Calling Set Position in Viewport on WBP_ObjectiveMarker moves the root screen layer. Calling Canvas Panel Slot Set Position on MarkerImage moves that child inside RootCanvas. Neither setter crosses into the other relationship.

A nested User Widget can still expose the viewport functions because its class is UUserWidget, but changing a stored viewport slot record does not rearrange the panel slot currently displaying it. The target must be the User Widget that was, or will be, registered as the screen root for the change to affect that screen relationship.

What the three nodes actually do

At beginner altitude, the slot calculation is:

pseudocode of the layout relationship - not engine source

slotPosition = position interpreted relative to the slot's anchors
slotSize     = explicit desired size, or the slot's full-screen/default rule
topLeft      = slotPosition - (slotSize * alignment)

The real slot also owns anchors and offsets, and its parent supplies the available player-screen or viewport rectangle. The model explains the most important interaction: alignment needs a meaningful size to know how far to move the rectangle around the position.

Set Position in Viewport

This writes the 2D position used by the root viewport slot. The node has an execution output but no Boolean result. A valid call means "store this position," not "prove the final rectangle is visible and unclipped."

The position is not automatically responsive. A fixed coordinate can become wrong after:

  • a window resize or aspect-ratio change;
  • split-screen adding or removing a local player;
  • a project DPI scale change;
  • safe-zone padding changing for a platform; or
  • the widget's own size changing.

Use viewport anchors, player-local geometry, or a deliberate resize/update path when the root must stay attached to an edge or center. For a normal HUD, it is often simpler to leave one root widget full-screen and make its internal panels responsive than to reposition the root HUD itself.

Set Desired Size in Viewport

Despite its name, this setter does not ask the widget "what size do you desire?" It takes the Vector2D you provide and makes that the explicit root slot size. Epic's Add to Viewport contract otherwise defaults to filling the screen.

These are different operations:

Operation What it answers
Get Desired Size What size does the widget hierarchy currently request from layout?
Set Desired Size in Viewport What explicit size should this root viewport slot use?
Size Box overrides What constraints should content report during layout?
Canvas Slot Set Size What size should this direct Canvas child use?

If you want the root slot to match natural content, first obtain a current desired size, then pass that value into the viewport setter. Get Desired Size is useful only after the underlying Slate widget exists and at least one layout prepass has measured the hierarchy. Text, wrapping, localization, images, padding, visibility, and child changes can all change that measurement.

One prepass normally happens before widgets Tick. Use Force Layout Prepass only when content was added or changed this frame and immediate measurement is actually required. An arbitrary Delay can appear to fix stale size, but its cost is timing-dependent UI that breaks again when content or frame timing changes; prefer a known layout boundary or an intentional prepass.

Set Alignment in Viewport

Alignment is the root slot's layout pivot:

Alignment Point placed at the slot position
(0,0) top-left
(0.5,0.5) center
(1,1) bottom-right
(0.5,1) bottom-center

For a (200,80) widget positioned at (600,300):

Alignment (0,0)       -> top-left is (600,300)
Alignment (0.5,0.5)   -> top-left is (500,260)
Alignment (0.5,1.0)   -> top-left is (500,220)

Alignment is not a Render Transform Pivot. Viewport alignment participates in layout and changes the arranged rectangle. Render Transform Pivot controls a later visual scale/rotation around a point inside the already arranged widget.

Do not use centered alignment and also subtract half the widget's width and height from the position. That applies the pivot twice.

Remove DPI Scale: the pin that causes drifting UI

UMG lays out widgets in logical Slate units, then project DPI scaling turns those units into display pixels. Remove DPI Scale means "apply the inverse of the current DPI scale before storing this position."

  • true (the default): use when the input is still in viewport/screen pixels and has not already been converted into widget units.
  • false: use when the input is already in UMG/Slate layout units or you already applied the inverse DPI conversion.

For example, Project World Location to Widget Position already produces a widget-ready position. Feeding that output into Set Position in Viewport with Remove DPI Scale = true converts it a second time and makes the marker drift as the viewport scale changes. Use false for that path.

By contrast, a pixel coordinate from a screen-pixel API normally still needs the inverse-DPI step. Do not choose the flag from the node name alone; name the coordinate space carried by the value at the connection.

Project World Location to Widget Position
-> Branch Return Value
   true:
       Set Position in Viewport(
           Position = ScreenPosition,
           Remove DPI Scale = false)

If a marker is an internal Canvas child, send that same widget-ready position to its Canvas slot instead of using this root-slot node.

Anchors, resizing, and safe zones still matter

The root viewport slot also has anchors. Set Anchors in Viewport changes which point or span of the owning screen region the offsets are relative to. The three nodes on this page do not automatically choose responsive anchors.

A useful fixed popup pattern is:

Set Anchors in Viewport = fixed top-center (0.5, 0.0)
Set Desired Size in Viewport = (480, 160)
Set Alignment in Viewport = (0.5, 0.0)
Set Position in Viewport = (0, 24) in UMG units

The center anchor handles width changes; the alignment centers the popup on that anchor; the position is only the designed top gap. A raw top-left pixel position would need recalculation whenever the owning region changes.

Safe zones are another layer. An anchor at (1,1) means the edge of the viewport or player region, not the last platform-safe point. Put content under a Safe Zone or apply the platform padding once in the same coordinate space. These setters do not inspect notches, overscan, subtitles, or your art direction margins.

Owning player and split-screen

Owning Player establishes which local player the User Widget belongs to; Add to Player Screen uses that context to put it in that player's screen section. Keep the whole chain coherent:

Local Player Controller
-> Create Widget(Owning Player = that controller)
-> Add to Player Screen
-> calculate position from that player's projection/geometry
-> Set viewport position/size/alignment on that widget instance

In a two-player local game, do not create both widgets with Player Controller 0 and then try to repair the positions with offsets. Each local player should own a separate widget instance and separate slot. Derive bounds from Get Player Screen Widget Geometry for that player rather than from desktop resolution or the full game viewport.

For network multiplayer, this is local presentation. Replicate the gameplay fact - an objective Actor, health, target state - and let each owning client arrange its own root or Canvas marker. A server does not replicate viewport slots, DPI settings, or safe-zone choices to clients.

Does the widget have to be added first?

In current UE5, UGameViewportSubsystem::SetWidgetSlot can update an already registered widget or retain slot information for a widget that will be added later. Therefore these setter calls can establish root-slot data before Add to Viewport / Add to Player Screen.

Three boundaries still matter:

  1. The User Widget object must be valid. A None target is an invalid Blueprint object call, not a pending layout request.
  2. The widget must eventually be registered to show anything. Stored slot data alone does not paint a widget.
  3. Measurement and cached geometry need layout. Natural desired size, player-screen geometry, and exact arranged bounds are not useful just because an object was constructed.

For readability, most gameplay graphs use this order:

Create Widget
-> validate/store reference
-> Add to Player Screen or Add to Viewport
-> set anchors / size / alignment / position

Preconfiguring the slot is valid when values are already known. Adding first does not make an early Get Desired Size current in the same instant; that is a layout-prepass question, not merely an attachment question.

When placement fails (and what failure looks like)

The setters return no success value, throw no gameplay exception, and do not retry. Common failures are:

  1. Target is None. Blueprint can report Accessed None; no intended slot changes.
  2. The target is a nested User Widget. Its active parent panel slot still owns its layout, so the stored viewport slot has no visible effect.
  3. The widget was never added. Slot data exists, but nothing is registered for painting.
  4. The widget still fills the screen. No explicit desired size was set, or another path rewrote the slot.
  5. The position changes with resolution. Pixel and UMG units were mixed, or inverse DPI was applied twice.
  6. The pivot is offset by half the widget. Alignment and manual half-size subtraction both centered it.
  7. The measured size is zero or stale. Desired size was read before the Slate widget and a layout prepass existed, or content changed afterward.
  8. The marker crosses a split-screen boundary. Full-viewport projection or bounds were mixed with a player-screen slot.
  9. The popup leaves the screen after resize. A fixed coordinate owned a responsive relationship that should have used anchors or recalculation.
  10. The widget overlaps an unsafe edge. Safe-zone policy was never applied.

Print the exact widget instance, owning player, Is In Viewport, viewport scale, supplied coordinate space, alignment, and explicit size. Then inspect the live hierarchy with Widget Reflector. Debugging only the final Vector2D misses most root-slot mistakes.

The patterns everyone actually uses

Place a fixed-size player-local popup

Create Widget WBP_Notification (Owning Player = LocalPC)
-> Add to Player Screen(ZOrder = 20)
-> Set Anchors in Viewport(fixed top-center)
-> Set Desired Size in Viewport(480, 160)
-> Set Alignment in Viewport(0.5, 0.0)
-> Set Position in Viewport((0, 24), Remove DPI Scale = false)

Place one independently added world marker

Project World Location to Widget Position(
    Player Controller = MarkerWidget.GetOwningPlayer,
    Player Viewport Relative = true)
-> if success:
    MarkerWidget.SetDesiredSizeInViewport((64,64))
    MarkerWidget.SetAlignmentInViewport((0.5,0.5))
    MarkerWidget.SetPositionInViewport(ProjectedPosition, false)

For many markers, one full-player-screen HUD with pooled Canvas children is usually easier to clamp, layer, and update than many independent viewport roots.

Match a root popup to measured content

Add popup to player screen
-> update localized text/content
-> wait for the normal layout prepass
-> Get Desired Size
-> Set Desired Size in Viewport(Return Value)
-> place with the intended alignment

Use Force Layout Prepass before Get Desired Size only when this must happen in the same frame.

The C++ twin, for the curious (our own example code):

void UMarkerPresenter::PlaceRootMarker(
    UUserWidget* Marker,
    const FVector2D& WidgetPosition)
{
    if (!IsValid(Marker))
    {
        return;
    }

    Marker->SetDesiredSizeInViewport(FVector2D(64.0, 64.0));
    Marker->SetAlignmentInViewport(FVector2D(0.5, 0.5));
    // WidgetPosition is already in UMG units, so do not remove DPI again.
    Marker->SetPositionInViewport(WidgetPosition, false);
}

What these nodes do not do

They do not:

  • create, add, remove, show, hide, or destroy a widget;
  • move an arbitrary Canvas/Overlay/Box child inside a Widget Blueprint;
  • discover natural content size for Set Desired Size in Viewport;
  • guarantee the final rectangle is on-screen, unclipped, or inside a safe zone;
  • automatically respond to window, aspect-ratio, split-screen, or DPI changes;
  • convert a widget-ready projection a second time correctly;
  • change Z order, visibility, enabled state, focus, input mode, or cursor state;
  • update internal Canvas anchors or slots;
  • replicate layout to another machine; or
  • prevent an animation, binding, or another setter from overwriting the slot.

Lookalikes - which one do I want?

Node / tool Use when Watch out
Set Position / Desired Size / Alignment in Viewport An independently added root User Widget needs explicit screen-slot layout. The three setters return no success value and coordinate space still matters.
Set Anchors in Viewport The root slot should follow an edge, center, or stretched region. Safe zones and alignment remain separate.
Canvas Panel Slot setters A direct Canvas child inside an existing widget needs free placement. Slot as Canvas Slot returns None under another parent type.
Panel slot setters A Box/Grid/Overlay child needs that parent's layout controls. There is no universal widget position independent of its parent.
Render Transform / Translation You need a visual offset, scale, or rotation after layout. Layout still reserves the original rectangle.
Project World Location to Widget Position A world point must become player-local UMG coordinates. Branch on success; use Remove DPI Scale = false afterward.
Get Desired Size You need the hierarchy's measured natural request. It needs a constructed Slate widget and a completed prepass.
Size Box Content should report min/max/override constraints during layout. It does not place the root screen slot.
Safe Zone Platform unsafe regions should pad a subtree. Viewport anchors alone do not know the safe region.

Rule of thumb: move the slot that actually owns the relationship, keep one named coordinate space from source to setter, and let alignment own the pivot exactly once.

Going deeper