Demos/AnimationShowcase/Sections/StaggerSection.cs
using Goo;
using Goo.Animation;
using Sandbox.UI;
using static Sandbox.DemoTokens;

namespace Sandbox.AnimationShowcase;

// N independent things doing the same action staggered in time; three rows fade in one-by-one via Timeline.At with absolute start times, HOLD-LAST keeps faded-in rows visible. stateless: each row's opacity comes straight from Sample at Build time, no cached fields, no manual reset.
public class StaggerSection
{
    static readonly Timeline Stagger = Timeline.At(
        ( 0.0f, new Tween( Easing.EaseOut, duration: 0.4f ) ),   // row 0: [0.0, 0.4]
        ( 0.7f, new Tween( Easing.EaseOut, duration: 0.4f ) ),   // row 1: [0.7, 1.1]  gap [0.4, 0.7]
        ( 1.4f, new Tween( Easing.EaseOut, duration: 0.4f ) ) ); // row 2: [1.4, 1.8]  gap [1.1, 1.4]

    TimelineAnimator _anim = new( Stagger ) { Elapsed = 999f };   // start past-end (settled)

    public void Update( float dt ) => _anim.Update( dt );

    public Container Build()
    {
        var s = _anim.Sample;
        return Section.Build(
            "Stagger - Three rows fade in one by one, last item holds",
            new Container
            {
                FlexDirection = FlexDirection.Column,
                Gap           = Space3,
                AlignItems    = Align.FlexStart,
                Children =
                {
                    Row( "first item",  RowOpacity( s, 0 ), Info ),
                    Row( "second item", RowOpacity( s, 1 ), Positive ),
                    Row( "third item",  RowOpacity( s, 2 ), Warning ),
                    CtrlButton.Build( "replay", _ => _anim.Restart() ),
                },
            } );
    }

    // Row N is invisible until segment N starts, animates with sample.Value while
    // segment N is active, and stays fully visible once any later segment runs.
    static float RowOpacity( TimelineSample s, int row )
    {
        if ( s.SegmentIndex < row ) return 0f;
        if ( s.SegmentIndex == row ) return s.Value;
        return 1f;
    }

    static Container Row( string label, float opacity, Color color ) => new Container
    {
        FlexDirection = FlexDirection.Row,
        Gap           = Space3,
        AlignItems    = Align.Center,
        Opacity       = opacity,
        Children =
        {
            new Container
            {
                Width           = 14f,
                Height          = 14f,
                BorderRadius    = 7f,
                BackgroundColor = color,
            },
            new Text( label ) { FontSize = FontBody, FontColor = FgPrimary },
        },
    };
}