the model¶
your UI is a tree¶
every goo UI is a tree of blobs. a blob is a small C# value that describes a node. nesting blobs gives you structure. the root is whatever you return from Build().
public class MyHud : GooPanel<Container>
{
protected override Container Build() => new Container
{
FlexDirection = FlexDirection.Column,
Padding = 16,
Children = { new Text("Hello World") },
};
}
three things to notice:
GooPanel<Container>is aSandbox.PanelComponent. drop it on a GameObject like any other component.Build()returns aContainer. that's your root blob.- children sit inside
Children = { ... }in the same initializer.
blobs¶
there are ten blob types:
Container. wraps an enginePanel. a container holds children.Text. wraps an engineLabel. holds a string.Image. wraps an engine image panel. takes aTexturereference or an assetPath.Sector. a filled annular wedge shape. useful for pie charts and radial meters.Arc. a stroked arc segment. useful for progress rings and outlines.Polygon. a filled arbitrary-vertex shape baked into an alpha mask.ScenePanel. embeds a 3D scene render inside a panel.SvgPanel. renders an SVG asset at panel size.WebPanel. embeds a Chromium webview.TextEntry. a single-line or multiline text input field.
all ten are readonly record struct types. cheap to allocate, cheap to compare. you don't keep references to them. you describe the tree you want, goo mutates the engine Panel tree to match.
the Shapes class (Goo.Shapes) is a separate named surface: a static factory that returns composite subtrees for common shapes like rings and discs. it is not a blob type itself, but it produces blobs you use like any other. see shapes for the full rundown.
why not razor?¶
razor in s&box pairs a .razor template with a .razor.scss stylesheet. the template is markup, the code-behind is C#, the styling is a sibling file. three languages, three syntaxes, three file mouths to feed for one component.
goo drops the template and the stylesheet. the tree is C#. the styles are C# init-only properties on the same record. you read top-to-bottom in one language.
other things you get:
composition by extraction¶
want a reusable card? write a function that returns a Container. see composition for the pattern in depth.
structural diff¶
the reconciler matches blobs by type and optionally Key. see build method for what that comparison covers per blob.
if you didn't understand any of this, that's ok. work through the hands-on articles in order and circle back to this page later.
see also¶
- your first panel - build your first goo panel from a blank file.
- build method - how
Build()runs, when it re-runs, and how the structural diff andKeywork. - styles - init-only style properties, kept dry across many blobs.
- composition - one stateful root, stateless presenters below it.
- shapes -
Sector,Arc, andPolygon, plus theGoo.Shapeshelpers.