Lay out and draw a UI with no HTML at all: build the element tree in C# with CSS property values, render it with LivePage, then change text and hover state and redraw only what changed.
using OneRender; using OneRender.Image; using OneRender.Interaction; using OneRender.Style; using OneRender.Tree; var tree = new StyledTree(); StyledNode root = tree.AddRoot("div", new StyleDeclaration() .Set("width", "480px").Set("height", "200px").Set("padding", "16px") .Set("display", "flex").Set("flex-direction", "column").Set("gap", "12px") .Set("background", "#16202c").Set("font", "16px sans-serif").Set("color", "#e8edf3")); StyledNode title = tree.AddElement(root, "h1", new StyleDeclaration().Set("font-size", "22px").Set("margin", "0")); tree.AddText(title, "Inventory"); StyledNode bar = tree.AddElement(root, "div", new StyleDeclaration().Set("display", "flex").Set("gap", "8px")); (StyledNode gold, StyledNode goldText) = AddButton("Gold 120"); (StyledNode gems, _) = AddButton("Gems 4"); var hover = new StyleDeclaration().Set("background", "#3b82f6"); tree.SetStateStyle(gems, ElementStates.Hover, hover); var page = new LivePage(tree, new LivePageOptions(FontProviders.CreateDefault()) { ViewportWidth = 512, ViewportHeight = 232 }); FlushResult first = page.Flush(); Console.WriteLine($"first flush: {first.Work}, {page.Display.Current.Count} display items"); File.WriteAllBytes("ui-1.png", DisplayListRasterizer.Render(page.Display.Current, 512, 232).ToPng()); page.Display.ClearDamage(); // A frame later: new text and a hover state. Only what changed is restyled, laid out and repainted. tree.SetText(goldText, "Gold 135"); tree.SetStates(gems, ElementStates.Hover); FlushResult next = page.Flush(); Console.WriteLine($"second flush: {next.Work}, reused {next.ReusedSubtrees} subtrees, {page.Display.Damage.Count} damaged areas"); for (int i = 0; i < page.Display.Damage.Count; i++) Console.WriteLine($" damage {page.Display.Damage[i]}"); File.WriteAllBytes("ui-2.png", DisplayListRasterizer.Render(page.Display.Current, 512, 232).ToPng()); (StyledNode Button, StyledNode Text) AddButton(string label) { StyledNode b = tree.AddElement(bar, "div", new StyleDeclaration() .Set("padding", "8px 14px").Set("border-radius", "6px").Set("background", "#2a3644")); return (b, tree.AddText(b, label)); }
first flush: None, 6 display items second flush: Restyled, BoxesPatched, Relaid, Repainted, reused 2 subtrees, 2 damaged areas damage RectF { X = 26, Y = 60, Width = 72.9375, Height = 24, Right = 98.9375, Bottom = 84, IsEmpty = False } damage RectF { X = 117, Y = 54, Width = 84, Height = 34, Right = 201, Bottom = 88, IsEmpty = False }
ui-1.png shows a dark panel with the “Inventory” heading and two buttons. In ui-2.png the first button reads “Gold 135” and the second is blue.
How it works
- Values are CSS text.
StyleDeclaration.Setgoes through the same parsers as a style sheet, so a builder tree and an HTML page compute alike, flexbox and grid included. A value the parser rejects is ignored;TrySetreturns false for it.var()isn’t available here. - No user-agent style sheet. Tag names are just names here: an
h1gets no bold or margin unless you give it some. - The constructor does the first layout and paint, so the first
Flushhas nothing to do (None). - Edits are logged, not applied.
SetText,SetDeclaration,SetProperty,SetStates,InsertElement,RemoveandMoverecord a change.Flushthen restyles, relays out and repaints only what changed, and the result equals a full rebuild. - State styles.
SetStateStyleattaches a declaration for:hover,:activeor:focus;SetStatesturns the state on or off. - Damage.
page.Display.Damagelists the rectangles that changed sinceClearDamage. Here, only the first button’s text and the second button need redrawing.
In a game loop
Each frame, apply the game state to the tree and call Flush. If Repainted is set, draw page.Display.Current (or just its damaged areas) and clear the damage. Steady frames, and the usual changes such as a hover, a text change or a transform or opacity animation, allocate nothing. A game engine with its own GPU renderer reads the display list directly: see Game hosts and The display list.
For HTML pages with input, events and focus instead, see Hit testing and events.