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:

  1. GooPanel<Container> is a Sandbox.PanelComponent. drop it on a GameObject like any other component.
  2. Build() returns a Container. that's your root blob.
  3. children sit inside Children = { ... } in the same initializer.

blobs

a blob is one of three types today:

all three 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.

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.

structural diff

the reconciler matches blobs by type and optionally Key.

if you didn't understand any of this, that's ok you can learn by doing