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 ViewportorAdd to Player Screenhas a viewport-managed root slot. These nodes update that slot. Set Position in Viewportchanges the slot's 2D placement. ItsRemove DPI Scaleinput decides whether the position still needs conversion from viewport pixels into Unreal Motion Graphics (UMG) layout units.Set Desired Size in Viewportsupplies an explicit root-slot size. It does not inspect the widget's content and discover its natural desired size for you.Set Alignment in Viewportchooses 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 Slotor the slot returned byAdd Child to Canvasinstead.
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:
- The User Widget object must be valid. A
Nonetarget is an invalid Blueprint object call, not a pending layout request. - The widget must eventually be registered to show anything. Stored slot data alone does not paint a widget.
- 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:
- Target is
None. Blueprint can reportAccessed None; no intended slot changes. - 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.
- The widget was never added. Slot data exists, but nothing is registered for painting.
- The widget still fills the screen. No explicit desired size was set, or another path rewrote the slot.
- The position changes with resolution. Pixel and UMG units were mixed, or inverse DPI was applied twice.
- The pivot is offset by half the widget. Alignment and manual half-size subtraction both centered it.
- The measured size is zero or stale. Desired size was read before the Slate widget and a layout prepass existed, or content changed afterward.
- The marker crosses a split-screen boundary. Full-viewport projection or bounds were mixed with a player-screen slot.
- The popup leaves the screen after resize. A fixed coordinate owned a responsive relationship that should have used anchors or recalculation.
- 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¶
- Canvas Panel Slots: Anchors / Offsets / Alignment / Size to Content - the separate parent-owned slot used by internal Canvas children.
- Project World Location to Widget Position and off-screen markers - player-local UMG coordinates, DPI, pivots, clamping, and safe areas.
- Create Widget + Add to Viewport - owning
player,
Add to Player Screen, Z order, and stored references. - Set Visibility: Hidden, Collapsed, and hit testing - why placement does not decide painting or interaction.
- Official docs: UUserWidget, UGameViewportSubsystem, FGameViewportWidgetSlot, Get Desired Size, and Force Layout Prepass.
- Engine source (requires engine access - we do not reproduce it here):
UUserWidget::SetPositionInViewport,SetDesiredSizeInViewport, andSetAlignmentInViewportinEngine/Source/Runtime/UMG/Private/UserWidget.cpp;UGameViewportSubsystem::GetWidgetSlot,SetWidgetSlot,SetWidgetSlotPosition, andSetWidgetSlotDesiredSizeinEngine/Source/Runtime/UMG/Private/Blueprint/GameViewportSubsystem.cpp; andFGameViewportWidgetSlotinEngine/Source/Runtime/UMG/Public/Blueprint/GameViewportSubsystem.h.