test/SplatBall.cs
public sealed class SplatBall : Component, Component.ICollisionListener
{
	[Property] GameObject Ball { get; set; }

	protected override void OnStart()
	{
		base.OnStart();
		Ball.LocalRotation = Rotation.Random;
	}

	void ICollisionListener.OnCollisionStart( Collision collision )
	{
		if ( collision.Other.Collider.Tags.Has( "world" ) )
		{
			using ( Scene.Push() )
			{
				var go = new GameObject( "Splat" );
				go.WorldPosition = collision.Contact.Point;
				var comp = go.AddComponent<GaussianSplatVolume>();
				comp.Mode = SplatVolumeMode.Add;
				comp.Shape = SplatVolumeShape.Sphere;
				comp.Radius = 20f;
				comp.Intensity = 1f;
				comp.Falloff = 0f;
				comp.ExcludeTags = new TagSet( ["splatball"] );
				var grow = go.AddComponent<GrowToSize>();
				grow.Volume = comp;
			}
			GameObject.Destroy();
		}
	}
}

public class GrowToSize : Component
{
	[Property] public GaussianSplatVolume Volume { get; set; }
	[Property] public float TargetSize { get; set; } = 200f;

	[Property] public float GrowthRate { get; set; } = 2f;
	[Property] public float ShrinkSpeed { get; set; } = 1f;

	TimeSince timeSinceStart = 0f;

	protected override void OnUpdate()
	{
		if ( timeSinceStart < 5f )
		{
			Volume.Radius = Volume.Radius.LerpTo( TargetSize, GrowthRate * Time.Delta );
		}
		else
		{
			Volume.Radius -= Time.Delta * ShrinkSpeed;
			if ( Volume.Radius <= 0f )
			{
				GameObject.Destroy();
			}
		}
	}
}