Skip to content
SiteEmail

Beyond standard CSS performance practices, Gameface provides two proprietary properties that skip expensive rendering operations entirely. display: simple bypasses the Yoga layout solver for containers where all children are absolutely positioned, eliminating the layout calculation cost on every frame. coh-simple-opacity eliminates the intermediate GPU texture that standard CSS opacity forces the engine to allocate before compositing. Both are narrow-purpose tools with clear performance wins and specific trade-offs that make them the wrong choice in the wrong context.

The previous article covered how to minimize the cost of a Full Layout Solve. For certain UI views, a different approach is possible: eliminate the layout solve entirely.

Every flex container runs through Yoga, which distributes space, resolves wrapping, calculates flex basis, and handles cross-axis alignment. For many screens, this computation is necessary. But a subset of game UIs - HUDs, floating nameplates, minimap overlays, tooltip hosts - have one thing in common: every element sits at a declared, absolute position. Nothing in those views flows. Nothing wraps. Yoga’s calculations produce the same result as not running them at all.

display: simple is a Gameface-proprietary display value for exactly this situation. A container set to display: simple has Yoga’s layout solve disabled entirely. The engine skips main-axis distribution, cross-axis alignment, and flex-line calculations. Direct children are expected to declare their own position using position: absolute, and the engine places them at those coordinates without involving the layout tree.

The following shows a dedicated HUD view where every element is anchored to a corner or edge of the screen:

<!-- A HUD view: every element is anchored at a fixed screen position -->
<body>
<div class="health-bar"></div>
<div class="ammo-counter"></div>
<div class="minimap"></div>
<div class="objective-tracker"></div>
</body>
hud.css
/* display: simple bypasses Yoga for the body entirely */
body {
display: simple;
width: 100vw;
height: 100vh;
}
/* Each direct child must declare its own absolute position */
.health-bar {
position: absolute;
bottom: 2rem;
left: 2rem;
width: 20rem;
height: 1.5rem;
}
.minimap {
position: absolute;
top: 2rem;
right: 2rem;
width: 18rem;
height: 18rem;
}

The constraint applies only to direct children of the display: simple container. Elements at any depth below it can use display: flex freely. A health bar that is absolutely positioned on screen can still lay out its internal fill bar and label using flexbox:

hud.css
/* flex is valid inside a display: simple subtree */
.health-bar {
position: absolute;
bottom: 2rem;
left: 2rem;
display: flex; /* Internal flex layout of the bar is fine */
align-items: center;
gap: 0.5rem;
width: 20rem;
height: 1.5rem;
}
.health-bar__fill {
flex-basis: 60%; /* flex rules apply normally inside this subtree */
height: 100%;
background-color: #e84040;
}

display: simple fits well on views that are entirely overlay-based: HUD screens, floating nameplate containers, tooltip layers, and notification overlays. These views share the property that positions are declared in CSS, elements do not respond to each other’s dimensions, and the visual structure is driven by absolute coordinates rather than flex distribution.

It is the wrong choice for any screen where content flows: inventory grids, settings panels, menu screens, character creation screens, or any view where elements stack, wrap, or react to their siblings’ sizes. On those screens, using display: simple breaks the layout.


Standard CSS opacity creates a compositing layer . The engine renders the element and all of its children to a temporary off-screen GPU texture at full opacity, then composites that texture onto the scene at the declared opacity value. This guarantees that children blend correctly relative to each other before the group’s combined opacity is applied to the background.

That temporary texture carries a real cost. The engine allocates GPU memory for the intermediate surface, renders to it, and then performs an additional compositing pass. A pause menu, a damage flash overlay, and a notification panel each fading in and out on every relevant event each trigger this allocation on every frame they are visible.

coh-simple-opacity is a Gameface-proprietary property that changes this rendering path. A container with coh-simple-opacity: on skips the intermediate texture. The engine applies the opacity value directly to each child’s color during the primary render pass, blending them individually into the scene without a separate compositing layer.

The property and the standard opacity value work together - coh-simple-opacity: on changes how the opacity is applied at the GPU level, while the opacity property still controls the actual value and drives any transitions:

<!-- A notification panel that fades in when an objective updates -->
<div class="notification-panel">
<div class="notification-panel__icon"></div>
<div class="notification-panel__text">New Objective Added</div>
</div>
hud.css
.notification-panel {
coh-simple-opacity: on; /* Skip the intermediate GPU texture */
opacity: 0; /* Still use opacity to control the visible value */
transition: opacity 0.3s ease-in-out;
position: absolute;
top: 4rem;
right: 2rem;
}
.notification-panel.is-visible {
opacity: 1;
}

The GPU memory saving is the win. The cost is a change in how overlapping children composite.

With standard opacity, children render into a group first. Their overlapping regions look correct because the children share the same compositing surface before the group opacity is applied to the scene. With coh-simple-opacity, each child blends directly into the scene independently. If two children overlap and the parent has opacity: 0.5, the overlapping region appears brighter than the surrounding area because both children contribute their color to the same background pixel without being grouped first.