Notched Screen Support [Studio Beta]

Update: Beta Reopened!


Hi Developers!

We want to share how Roblox will be rendered on notched mobile devices going forward and allow you to try this out as a Studio Beta feature.

Notched screen support allows your experiences to use every pixel of mobile displays, regardless of their shape. We believe this will make your experiences feel even more immersive.

  • Current: if a phone has a notch that pushes into the screen, Roblox displays a black bar in the area around the notch

  • Future: We will remove the black bar and render Roblox across the entire screen for all experiences

    • The 3D viewport will fill the entire visible screen area, including the notch area
    • UI in ScreenGuis will automatically adapt to notched screens

We aim to preserve existing UI layouts as much as possible, but there are some important differences that you should be aware of:

  • ScreenGui content will be inset on both sides into the screen’s safe area, ensuring that UI does not sit underneath the hardware notch.

  • GuiObjects that cover the entire safe area and were previously full screen, will be expanded by default to cover the notch area (i.e. full screen backgrounds are still full screen).

  • New ScreenGui properties will allow you to further customize how this works.

Here’s an example of what notch screen support looks like in Livetopia:

How can I try out Notched Screen Support?

You can preview this change as a Studio Beta feature with notched emulation devices that have been added to the emulator to test your experiences. The emulated devices allow you to see what your UI will look like on mobile devices with different notch types.

Here’s how to enable the Studio Beta for Notched Screen Support and test the feature:

  1. Go to File → Beta Features and click the checkbox next to “Notched Screen Support”:

  2. Open the Studio Device Emulator by clicking on the “Test” tab, then click the “Device” button:

  3. Click on the device selector in the toolbar and change the emulation device to one with a notch:

  4. Try the new emulation devices that have notches or screen cutouts:

    • iPhone X
    • iPhone XR
    • Samsung Galaxy A51
    • Xiaomi Redmi Note 9
    • iPhone 14 Pro

      Remember - you can test both landscape and portrait display modes by clicking the button to the right of the device model to rotate the emulated screen.


Details

What are “notched” screens?

Recently, mobile devices have come out with new screen shapes that aren’t simple rectangles. Modern mobile displays can include notches, hole punch cutouts, and rounded corners. Here are some examples:

How will Roblox be rendered on notched displays?

We are making 3 core changes to how Roblox is rendered on notched displays:

  1. The 3D viewport now fills the entire display area, including the area around the notch:

  2. By default, UI in ScreenGuis is automatically adapted to support notched displays. This allows existing and new UI that is authored for rectangular displays, to work on non-rectangular displays:

  3. For backwards compatibility on notched screens, Lua APIs which refer to the 3D viewport (such as Camera.ViewportSize) now refer to the device safe area viewport. This change won’t break existing games using the 3D viewport APIs. Additional details on behavior changes can be found below.

What is a safe area?

Safe areas are screen regions that help us simplify UI design across different devices. Portrait and Landscape safe areas are shown in the diagram below.

  • The Device Safe Area (shown in green) is a rectangular screen region that is not occluded by any hardware screen cutouts from notches or camera hole punches.

  • The Core UI Safe Area (shown in blue) is a rectangular screen region within the Device Safe Area that does not include the Roblox top bar.

Do I have to update my experiences to support notched screens?

For the 3D viewport portion of your experience, no action is needed to use the full-screen area! The 3D viewport will automatically fill the entire available screen area, including the notch area.

For the 2D UI portion of your experience, we anticipate that most experiences won’t need major changes. We’ve added several automatic UI adaptation features to make many existing UIs automatically compatible with notched screens (see the next section). However, we still encourage you to test your experience on notched devices in the Studio Device Emulator.

The following types of UI may need adjustments to provide optimal notch support:

  • Separate UI objects that don’t individually cover the screen are not automatically extended. If you have multiple Frames that cover different parts of the screen, but each one doesn’t individually cover the entire screen, these Frames won’t be automatically extended to the fullscreen area. For example, if you have a Frame covering the top bar, and another covering the rest of the screen, neither Frame will be extended!

  • “Edge-anchored” UI that is designed to be at the edge of the screen and do not work as well as floating elements

  • Animated UI that transitions from onscreen → offscreen or vice versa.

See below for more details on the automatic UI adaption features as well as some additional tips on how to author UI that works on all screen types.

Extended Functionality

We are investigating a new UI component to extend specific GuiObjects within a ScreenGui, to the edges of the fullscreen area (beyond the safe area). We’d like to understand whether the existing functionality in the Beta is adequate or whether additional control is required. Let us know!

How is UI in ScreenGuis automatically adapted for notched displays?

We can use the safe areas defined above to automatically adapt the most common types of UI to notched displays. Here are the 3 adaptation techniques that we are using:

  1. Adding safe area insets
  2. Automatic background expansion
  3. Clipping to Device Safe Area

   1. Adding safe area insets

Click to show...

To ensure UI isn’t cut-off in existing experiences when running on displays with notches and screen cutouts, we modify the boundaries of each ScreenGui as follows:

  • ScreenGuis with IgnoreGuiInset=false use the Core UI Safe Area bounds.
  • ScreenGuis with IgnoreGuiInset=true use the Device Safe Area bounds.

This effectively adds safe area insets to each ScreenGui:

How can I customize safe area insets?

You can customize the safe area insets applied to a ScreenGui using the new ScreenGui.ScreenInsets property.

The ScreenInsets property controls whether the ScreenGui’s content are laid out in the fullscreen area, or in one of the 2 safe areas defined above.

New Property Type Default Value Description
ScreenGui. ScreenInsets Enum. ScreenInsets CoreUISafeInsets The insets that are applied to all children of this ScreenGui. This can be None, DeviceSafeInsets, or CoreUISafeInsets. This corresponds to the safe areas described above.

Example

You can put UI that is meant to be part of the “background” (i.e. OK to sit underneath a notch) in a ScreenGui with ScreenInsets=None. On the other hand, any UI that needs to be entirely visible (like text or buttons) should be placed in a ScreenGui with ScreenInsets=CoreUISafeInsets or DeviceSafeInsets.

Example, where the left menu is placed in a ScreenGui with ScreenInsets=CoreUISafeInsets, while the background ScreenGui has ScreenInsets=None:

   2. Automatic background expansion

Click to show...

Some types of UI elements will look better if they are not inset into the safe area. For example, fullscreen backgrounds such as loading screens, feel more immersive if they cover the entire visible area.

To support this use case, we automatically detect “fullscreen” GuiObjects and expand their backgrounds to cover the fullscreen area. Here’s what this looks like in action:

How does GuiObject background extension work?

We define the “background” of a GuiObject to be the color specified by GuiObject.BackgroundColor3. For ImageLabel/ImageButton, the Image is part of the background. For VideoFrame, the video is part of the background.

We define the “content” of a GuiObject to be the area containing any text content (for TextLabel, TextButton, TextBox Instances), and the area containing the GuiObject’s children. We show the background and content areas for each type of GuiObject below:

If a GuiObject is in a ScreenGui with SafeAreaCompaibility = FullscreenExtension and the GuiObject’s bounds cover the Device Safe Area, then only the background of the GuiObject is extended to cover the Fullscreen Area.

How can I customize fullscreen background expansion?

You can enable/disable automatic fullscreen background expansion using the new ScreenGui.SafeAreaCompatibility property:

New Property Type Default Value Description
ScreenGui. SafeAreaCompatibility Enum. SafeAreaCompatibility FullscreenExtension What transformations, if any, are applied to this ScreenGui’s descendants to improve safe area compatibility. The current options are None and FullscreenExtension.

   3. Clipping to Device Safe Area

Click to show...

On a notched screen, GuiObjects that are located just outside the screen boundaries might now be visible due to safe area insets pushing in the ScreenGui boundaries.

To ensure GuiObjects that are positioned off screen on rectangular screens, are still not visible to notch phone users, we automatically clip ScreenGui contents outside the Device Safe Area. This clips the “unsafe area” outside the Device Safe Area, because this area is normally off screen on rectangular screens. Here’s what this looks like:

How can I customize safe area clipping?

We’ve added the ScreenGui.ClipToDeviceSafeArea property to control the ScreenGui’s clipping behavior:

New Property Type Default Value Description
ScreenGui. ClipToDeviceSafeArea boolean true If true, all descendants are clipped to the device safe area.

Design Tips: How to update your UI for notched devices

Click to show...
  1. Edge Anchored UI
    If your experience contains UI elements that are anchored to one or more screen edges, check how these look on a notched device with the Studio Device Emulator. Consider a “floating” UI design that will work on all types of mobile devices.

  1. UI animation on and off screen
    If your experience animates UI elements from offscreen to onscreen, or vice versa, consider setting ScreenGui.ClipToDeviceSafeArea=false on the ancestor ScreenGui. This will prevent GuiObjects from being clipped as they travel on/off the screen. You may need to add offsets to the offscreen position of GuiObjects to ensure they move completely off screen, due to the visible area outside of the safe area.

  2. Off screen placeholder for UI animation
    A method to handle offscreen animations with safe area insets is to create a hidden “placeholder” GuiObject in a ScreenGui with ScreenInsets=None. Make sure this placeholder is outside of the ScreenGui’s visible area. This ensures the placeholder GuiObject is always offscreen for any value of the safe area insets. When tweening a GuiObject offscreen, set its final position to be the placeholder GuiObject’s AbsolutePosition.

Behavior changes to existing 3D viewport APIs to ensure backwards compatibility

Click to show...

We’ve changed how several existing viewport-related APIs work on notched screens to achieve maximum backwards compatibility. Some experiences have positioned 2D GuiObjects in ScreenGuis that are meant to sync up with 3D objects in the 3D viewport. Insetting ScreenGui’s will also require insetting 3D viewport APIs.

Every API that references the “viewport” on a device without hardware safe area insets now uses the device safe area viewport. Each API that utilized the “inset” viewport (aka “Screen space”) uses the Core UI safe area viewport.

Example: Camera:ViewportPointToRay()

Here is an example of how Camera:ViewportPointToRay() works on a notched device:
On a rectangular device, Camera:ViewportPointToRay(0, 0) returns the ray corresponding to the top left of the screen. On a notched device, Camera:ViewportPointToRay(0, 0) returns the ray corresponding to the top left of the device safe area viewport (below, right):

Example: Camera.ViewportSize

On a rectangular display, Camera.ViewportSize returns a Vector2 corresponding to the fullscreen width and height (below, left). On a notched display, Camera.ViewportSize returns the size of the device safe area viewport (below, right).

Note that Camera.ViewportSize may be smaller than what might be considered the “full-screen size” on a notched mobile phone, as it is the size of the safe area, not the full screen.

Example: AbsolutePosition Coordinates

The GuiBase2d.AbsolutePosition property as well as InputObject.Position both use Core UI Safe Inset coordinates, where the origin is at the top left of the Core UI Safe Area. On devices with safe area insets, note that this coordinate system becomes inset by the hardware safe area insets:

List of APIs that are inset by hardware safe area insets

Instance Type Property/method using device safe inset viewport Property/method using Core UI safe inset viewport
Camera ViewportSize
ViewportPointToRay
WorldToViewportPoint
ScreenPointToRay
WorldToScreenPoint
InputObject Position
UserInputService Supported in v559:
TouchTapInWorld
GetMouseLocation
Supported in v559:
TouchTap
TouchPan
TouchPinch
TouchRotate
TouchLongPress
Mouse Not currently supported:
ViewSizeX
ViewSizeY
X, Y
GuiBase2d AbsolutePosition
GuiObject MouseMoved
MouseLeave
MouseEnter
MouseWheelBackward
MouseWheelForward

Supported in v559:
TouchTap
TouchPan
TouchPinch
TouchRotate
TouchSwipe
TouchLongPress
InputBegan
InputChanged
InputEnded

Advanced: How can I get the device’s safe area inset sizes?

Click to show...

For more complex UI with safe-area-aware animations, it may be necessary to get the safe area sizes. Here’s a helper function to do this. If you think this would be useful to include as a built-in function, please let us know!

type inset4 = {left: number, top: number, right: number, bottom: number}

local function getHardwareSafeAreaInsets()
	local playerGui = game.Players.LocalPlayer.PlayerGui
	assert(playerGui)
	
	local fullscreenGui = playerGui:FindFirstChild("_FullscreenTestGui")
	if not fullscreenGui then
		fullscreenGui = Instance.new("ScreenGui")
		fullscreenGui.Name = "_FullscreenTestGui"
		fullscreenGui.Parent = playerGui
		fullscreenGui.ScreenInsets = Enum.ScreenInsets.None
	end
	
	local deviceGui = playerGui:FindFirstChild("_DeviceTestGui")
	if not deviceGui then
		deviceGui = Instance.new("ScreenGui")
		deviceGui.Name = "_DeviceTestGui"
		deviceGui.Parent = playerGui
		deviceGui.ScreenInsets = Enum.ScreenInsets.DeviceSafeInsets
	end
	
	local tlInset = deviceGui.AbsolutePosition - fullscreenGui.AbsolutePosition
	local brInset = fullscreenGui.AbsolutePosition + fullscreenGui.AbsoluteSize
                    - (deviceGui.AbsolutePosition + deviceGui.AbsoluteSize)
	local result: inset4 = {left = tlInset.X, top = tlInset.Y, right = brInset.X, bottom = brInset.Y}
	
	return result
end

Why are we making the above changes?

Click to show...

We’d like to explain the considerations and reasons behind this update.

A changing landscape of mobile displays

Traditionally, screen displays have been simple rectangles. However, improvements to display technology have allowed for an increasingly large variety of screen configurations. New mobile devices are likely to have notches or cutouts, and screen displays will continue to vary in size and shape going forward.

The current Roblox approach of placing the viewport in the largest unobstructed rectangle looks increasingly poor on these creative screen shapes and requires non-rectangular areas of the screen to be blacked out. Roblox will continue to expand our device support going forward, new devices and unique screen shapes will be released, and your experiences need to look amazing on every screen shape or size we support!

The core fullscreen change

The core solution is to extend the 3D viewport so that it fills the display regardless of shape. This is the standard approach today that 3D games take to ensure that there is immersive and engaging content that fills the entire display.

This change works well for 3D content. However, the GUI system and related API’s such as Camera:WorldToScreenPoint work in screen space. If the GUI system remains coupled to the 3D viewport, we run the risk of cutting off or covering up important UI!

The challenge of ScreenGui.IgnoreGuiInset

Most developers who have worked with GUIs will be familiar with the IgnoreGuiInset property on ScreenGui’s. This property controls whether the Roblox Core UI inset (currently a top-edge inset of 36 pixels) should be applied to the ScreenGui. This property caused us particular difficulty because when IgnoreGuiInset is true, the developer might intend either of the following:

  • The ScreenGui viewport should exactly match the 3D viewport, to align a GUI with something in 3D space. That is, the developer intends zero insets for all 4 edges of the screen.
  • Ignore the top bar so that additional items may be placed alongside the Roblox menu button within the top bar area. The developer only intends there to be zero inset for the screen’s top edge, but there should be insets on the other 3 screen edges.

Previously these two meant the same thing because the Roblox menu and top bar was always positioned at the top left corner of the viewport. With notch screen support, the ambiguity of which inset(s) IgnoreGuiInset refers to means that we can’t just make ScreenGuis with IgnoreGuiInset=true take up the full 3D viewport anymore because UI in these ScreenGuis could sit under a hardware notch.

Other solutions would break the legacy use cases and negatively impact some experiences. Solving with the smaller viewport (safe area) ensures the UI doesn’t appear under a notch and still allows legacy experiences to take advantage of the extended screen space, so that’s what we went for.

Known Issues

Reminder: Automatic fullscreen extension won’t extend groups of GuiObjects that each cover only part of the screen. See here for more info.

  • ScreenGui.ClipToDeviceSafeArea does not clip rotated GuiObjects
  • Some screen-position-related APIs don’t currently support safe area insets, see the table in “Behavior changes to existing 3D viewport APIs to ensure backwards compatibility”.
  • CanvasGroup, ViewportFrame, and VideoFrame don’t currently extend their backgrounds as part of the GuiObject fullscreen extension. However, they should do this in the future
  • Mac Only: resizing GuiObjects in the UI Editor doesn’t work for notched devices

Fixed in v559:

  • Reading Camera.ViewportSize in a callback to Camera:GetPropertyChangedSignal("ViewportSize") returns a stale value until the next frame is rendered.
  • GuiObject BorderSizePixel and UIStroke aren’t included in the size used for detecting fullscreen background expansion
  • UIStroke is not affected by background expansion

Feedback

We want to hear your feedback on the notch screen support after you test the changes. Is this a welcome change? We’d also like to hear about any issues you run into or any suggestions you may have.

231 Likes

This topic was automatically opened after 10 minutes.

Finally, this is something I’ve been waiting for quite a while. How would this work, though? Say, Pixel phones with a hole punch notch. Would more devices be added to replace the older ones?

20 Likes

Whoa, impressive feature. now phone users wont struggle to click a button or read!

8 Likes

I really appreciate the detail that’s gone into making sure that this update works well. I would hope that many of the automatic options are superseded by manual workflows for new work going forward, because depending on automatic ‘magic’ adaptation behaviour for new games is a recipe for confusion, but it’s a good compatibility option to have at the very least. I just hope they’re treated as such and don’t become technical debt that has to be dramatically dealt with in the future.

I made a video talking about my concerns:

Thanks for the detailed work! I look forward to seeing what people do with this :slightly_smiling_face:

54 Likes

This is great! I’d love to finally see mobile Roblox screenshots without giant black bars on the side.

Will there be a way for experiences to detect what type of notch the device has? I want to take advantage of the entire screen for UIs without clipping through notches and punch-holes, and taking advantage with as much space as possible.

10 Likes

Safe areas are a great addition from the standpoint of a player as well. They improve looks and ergonomics dramatically. Finally, I won’t have to break my thumb in order to press the jump button!

7 Likes

I disagree with the changes to the 3D api, if I am checking the camera’s ViewportSize its because I want to know the resolution of what the Camera is rendering, not the resolution of the mobilescreen excluding notches. Personally I feel that if the notches interfere with the usecase of the game developer the game developer should make a active to take that into consideration and it should not be the other way around, changing the behavior of ViewportSize and other 3D API’s seems like such a strange choice which just adds more annoyance to the 3D API’s.

Personally adding these API’s would make more sense since it would allow game developers to program in support for notches for when they are using 3D API’s while preserving the original behavior of the 3D API’s
GUIService.NotchSize: Vector2 The size of the notch in pixels.
GUIService.NotchPosition: Enum.NotchPostion The position of the notch TopLeft TopRight BottomMiddle etc.
GUIService.CornerNotches: integer The size of the unsafe area around the device corners.

3 Likes

Will this come to high-end Android phones?

2 Likes

All the effort invested in this is very appreciated.

Wanted to mention that I have a case where background extension doesn’t work. The CanvasGroup appears to prevent the background frame from filling out the screen.
image

6 Likes

This is something that got overlooked, but the swipe-up-homescreen-bar on the iPhone X is still missing from the emulator. We actively design our UI around the existence of this bar, and seeing a refresh to emulator to support notches without the inclusion of this is slightly disappointing.

In the first screen shot you can make out the horizontal grey bar:
image

In the actual emulator window it is not present.
image

28 Likes

This looks like an amazing change. Although I don’t play Roblox on mobile, it will make games look much better on mobile!

Well done Roblox!

2 Likes

Is it a bug or intended behavior that ScreenGuis reset to IgnoreGuiInset = false when reopening a place? I have tried tweaking the new screen support settings instead, but it still resets. I may have to opt out for now because this is interfering with several of my UI.

2 Likes

This feature sure is top “notch”

16 Likes

Now that this has come to phones, when will this come to tablets like the Samsung Galaxy Tab S8 Ultra?

3 Likes

Thank you so much! I’ve been waiting for this change for a long time!

I’m very confused by how few devices have been added to the emulator. Could we please get support for a wider range of modern phones? This would allow developers to be able to insure their game works right on more devices.

4 Likes

It’s kind of weird how they didn’t include new high-end android phones. Like for Samsung, they made it a budget phone. For Xiaomi, they made it a old phone.

4 Likes

Hi @dragonfrosting, that sounds like a bug! If you save a ScreenGui with IgnoreGuiInset=true, it should still be true when you open the place.
Would you be able to provide a placefile example where this is happening?

5 Likes

It happens in any place file, I have tried saving the place after fixing the ScreenGuis but reopening it resets the Guis again.

I’ve disabled the Beta and the issue has stopped. I can try uploading a sample file if you are unable to reproduce the bug.

4 Likes

Did you guys consider simply rendering the graphics in what was formerly the black bar, but keeping all UI behavior the same as prior? So this would mean that old UI layouts would work completely fine, minus the fullscreen problem.

Also not a huge fan of losing the space on the un-notched side of the screen, but now we can’t make use of the space easily because of ergonomics or symmetry or whatever. If you guys could do the equivalent of IgnoreGuiInset but for the un-notched side of the screen, that would be excellent, because while I do not want my content to be hidden behind a notch, I don’t mind it being on the un-notched edge where the screen may curve but there is no notch. With this update, anchoring elements to the un-notched side of the screen is a lot harder

1 Like