Skip to main content
Version: 1.0.0

Counter

Pine 1.0.0 provides native uGUI declarations. Import using Pine; and use P directly. View is a declaration; UnityEngine.Component is the native object built from it. App.Mount() runs once. Sources update retained native components through tracked getters.

using Pine;
using UnityEngine;

public static class App
{
public static View Mount()
{
var count = P.Source(0);
return P.Vertical(
spacing: 12,
childControlWidth: true,
childControlHeight: true,
childForceExpandHeight: false,
sizeDelta: new Vector2(240, 160)
)
.With(
P.Text(() => $"Count: {count.Value}", fontSize: 24)
.With(P.LayoutElement(preferredHeight: 40)),
P.Button("Increment", onClick: () => count.Value++)
.With(P.LayoutElement(preferredHeight: 40)),
P.Button(
"Reset",
onClick: () => count.Value = 0,
interactable: new Value<bool>(() => count.Value > 0)
)
.With(P.LayoutElement(preferredHeight: 40))
);
}
}

P.Button creates a real UnityEngine.UI.Button and wires its background Image. Supplying text adds a TMP caption. Layout sizing uses native LayoutElement settings. Omitted props retain native component defaults, so this example explicitly enables layout child sizing.

Run the example​

Download App.cs. Keep one App.cs entry in a project.

After installing Pine, save the script in your project and enter Play mode. The label starts at Count: 0; Reset starts disabled. Click Increment twice to see Count: 2, then Reset to return to zero and disable Reset again.

How the counter updates​

count is writable state. The text getter reads count.Value, so Pine tracks that dependency and updates the existing TMP component when a button changes the source. The Reset binding reads the same source to update the native button's interactable property. The event handlers write the source; they do not rebuild the view tree or search the scene for labels.

Keep the getter in P.Text(() => $"Count: {count.Value}"). Passing a completed string such as P.Text($"Count: {count.Value}") supplies a literal snapshot, which will not follow later changes. The reactive props tutorial explains literals, getters and editable source write-back.

The mounted root owns the text and button bindings. Destroying that root ends its scope and removes the owned bindings and handlers. See state and ownership before moving calculations into a service or a custom component.