2.9.16
Coherent GT
A modern user interface library for games
Layers and how to use them

The purpose of this section is to discuss where and why to use layers.

Firstly, let's define what Render Tree is. The tree consists of visual elements of the document or in other words - their visual representation in it. An "element" in this case is defined as render object. Each render object in the Render tree has defined style properties, including its geometry and position. Every time an element changes its geometry or position, it affects other elements too.

For example - if a scene has one wrapper at the top with dropdown menus, opening a menu will touch on other elements which are visually under it, causing those other elements to repaint too. This can be avoided by promoting the wrapper to layer. By doing this when a menu is opened, only the wrapper and its children will be repainted. Making an element a layer creates new texture especially for the content of this element.

Which elements should you promote to layers?

  • Big elements which hold other dynamic elements e.g. wrapper with buttons which have some hover effect.
  • Elements which position themselves over other elements in the UI, either by some hover effect or with an animation.
  • List elements which are relative and close to one another and have some hover effect or animation.

How to use layers appropriately

  • A layer should remain a layer at all times.

    Preserve the transformation:

    .element {
        transform: translate3d(0vh, 0vh, 0vh);
    }
    
    .element:hover {
        transform: translate3d(0vh, -0.6vh, 0vh);
    }
    

    If you are using 2D transformations, keep the element as a layer at all times by applying rotateX(0deg):

    .element {
        transform: rotateX(0deg);
    }
    
    .element:hover {
        transform: rotateX(0deg) scale(1.1);
    }
    
  • Do not make every element a layer. Using too many layers can take up a lot of memory. It can also make the UI less responsive. Promoting elements to layers should always go hand in hand with profiling with the Debugger through the Timeline and using the "Show paint rectangles" feature to see if painting is contained only to the desired element. These are the only ways to see if the decision is beneficial and as expected.
  • It is enough to promote a parent element to layer even if some of its children also have an animation. Layers don't allow the Paint to spread "outside" of it. An exception case is when the element has too many nested elements in which case another layer can be considered to be added inside the parent element. Make sure to profile.

List of properties that trigger layer creation in GT:

  1. All Filters -webkit-filter.
  2. backface-visibility
  3. Transformations:
    • translate3d
    • scale3d
    • rotateX
    • rotateY
    • rotate3d
    • perspective (transform property only)
    • matrix3d
    • translateZ
Note
Transform: translateZ(0) don't create layers.

Tip: Use pagination instead of making long one page scrollable list with items. This will lighten the page load by making the non-active pages hidden with display: none along with their children. If the design doesn't allow it, make sure only the elements in the visible area of the screen are displayed. Consider using virtual lists and lazy-loading approaches for large lists.

Internal options for layer creation management

Starting with Coherent GT version 2.8.2 there's an internal option available that allows fine-grained control over layer creation. As the description suggests, its purpose is for internal testing and should only be used for experimenting.

The option can be used by passing the appropriate structure to the DeveloperOptions member of the SystemSettings struct. The following example shows how to disable creation of layers caused by CSS animations or canvas elements.

struct DevOptions
{
enum CompositingTriggers
{
// Filtered list of the most widely used triggers
CanvasTrigger = 1 << 3,
AnimationTrigger = 1 << 4,
AnimatedOpacityTrigger = 1 << 7,
};
const char* Ignored = "";
unsigned Triggers = 0xFFFFFFFF & ~(CanvasTrigger | AnimationTrigger);
} devOpts;
settings.DeveloperOptions = &devOpts;