Code/Demos/BeatPad/OscilloscopeBlob.cs
using System;
using Goo;
using Sandbox.UI;
using static Sandbox.BeatPadTokens;

namespace Sandbox;

// pure presenter for the retro-LCD oscilloscope: scrolling synthetic trace on an Ink LCD. trace state (sample ring) lives in BeatPadUI; zero per-frame allocation.
internal static class OscilloscopeBlob
{
    public readonly record struct Props(
        float[] Samples,   // -1..1, newest at the end (scrolls right -> left)
        float Glow);       // 0..1 overall brightness hint (the decaying hit envelope)

    public static Container Build(Props p)
    {
        int n = p.Samples.Length;
        float colPct = 100f / n;
        float traceAlpha = 0.55f + 0.45f * Math.Clamp(p.Glow, 0f, 1f);

        var lcd = new Container
        {
            Key = "lcd",
            Width = Length.Percent(100),
            Height = Length.Percent(100),
            Position = PositionMode.Relative,
            BackgroundColor = Ink,
            BorderColor = Ink,
            BorderWidth = OutlineWidth,
            BorderRadius = ScopeRadius,
            Children =
            {
                // dimmed center axis
                new Container
                {
                    Key = "axis",
                    Position = PositionMode.Absolute,
                    Left = 0, Top = Length.Percent(50),
                    Width = Length.Percent(100), Height = 1f,
                    BackgroundColor = Hot.WithAlpha(0.22f),
                    PointerEvents = PointerEvents.None,
                },
            },
        };

        // Each sample -> a thin vertical bar from the midline to the sample's amplitude.
        const float halfSpan = 0.46f; // fraction of height available each side of center
        for (int i = 0; i < n; i++)
        {
            float s = Math.Clamp(p.Samples[i], -1f, 1f);
            float h = MathF.Abs(s) * halfSpan;           // fraction of full height
            float top = s >= 0f ? (0.5f - h) : 0.5f;     // grow up for +, down for -

            lcd.Children.Add(new Container
            {
                Key = $"c{i}",
                Position = PositionMode.Absolute,
                Left = Length.Percent(i * colPct),
                Top = Length.Percent(top * 100f),
                Width = Length.Percent(colPct * 0.7f),
                Height = Length.Percent(MathF.Max(h * 100f, 0.6f)),
                BackgroundColor = Hot.WithAlpha(traceAlpha),
                PointerEvents = PointerEvents.None,
            });
        }

        return lcd;
    }
}