ExampleComponents/SpinComponent.cs
public sealed class SpinComponent : Component
{
	[Property] public Angles SpinAngles { get; set; }

	protected override void OnFixedUpdate()
	{
		if ( IsProxy ) return;

		LocalRotation *= (SpinAngles * Time.Delta).ToRotation();
	}
}


public sealed class MoveComponent : Component
{
	[Property] public Vector3 Distance { get; set; }
	[Property] public float Speed { get; set; } = 10.0f;

	Transform startPos;

	protected override void OnEnabled()
	{
		base.OnEnabled();

		startPos = LocalTransform;
	}

	protected override void OnFixedUpdate()
	{
		if ( IsProxy ) return;

		LocalPosition = startPos.Position + (Distance * (MathF.Sin( Time.Now * Speed ).Remap( -1, 1 )));
	}
}


public sealed class MoveSinComponent : Component
{
	[Property] public Vector3 Scale { get; set; } = 100;
	[Property] public float Speed { get; set; } = 1.0f;
	[Property] public float Offset { get; set; } = 0.0f;
	[Property] public float Height { get; set; } = 32.0f;

	Transform startPos;

	protected override void OnEnabled()
	{
		base.OnEnabled();

		startPos = LocalTransform;
	}

	protected override void DrawGizmos()
	{
		base.DrawGizmos();


		Gizmo.Transform = Gizmo.Transform.WithScale( 1 );

		int steps = 100;

		Vector3 pos = default;

		for ( int i = 0; i <= steps; i++ )
		{
			var p = GetPositionAt( i / (float)steps );

			if ( i > 0 )
			{
				Gizmo.Draw.Line( pos, p );
			}

			pos = p;
		}
	}

	Vector3 GetPositionAt( float t )
	{
		var p = startPos.Position;

		p += MathF.Sin( t * MathF.PI * 2.0f + (Offset * MathF.PI * 2.0f) ) * Scale.x * Vector3.Left;
		p += MathF.Cos( t * MathF.PI * 2.0f + (Offset * MathF.PI * 2.0f) ) * Scale.y * Vector3.Forward;

		p += MathF.Sin( t * MathF.PI * 4.0f + (Offset * MathF.PI * 2.0f) ).Remap( -1, 1 ) * Height * Vector3.Up;

		return p;
	}

	protected override void OnFixedUpdate()
	{
		if ( IsProxy ) return;

		var prev = GetPositionAt( (Time.Now * Speed) - 0.01f );

		LocalPosition = GetPositionAt( Time.Now * Speed );
		LocalRotation = Rotation.LookAt( prev - LocalPosition );
	}
}


public sealed class MoveBrownianComponent : Component
{
	[Property] public float Speed { get; set; } = 1.0f;
	[Property] public float Noise { get; set; } = 0.0f;

	Transform startPos;

	protected override void OnEnabled()
	{
		base.OnEnabled();

		startPos = LocalTransform;
	}

	protected override void DrawGizmos()
	{
		base.DrawGizmos();

		Gizmo.Transform = Gizmo.Transform.WithScale( 1 );
		int steps = 100;

		Vector3 pos = default;

		for ( int i = 0; i <= steps; i++ )
		{
			var p = GetPositionAt( i / (float)steps );

			if ( i > 0 )
			{
				Gizmo.Draw.Line( pos, p );
			}

			pos = p;
		}
	}

	Vector3 GetPositionAt( float t )
	{
		var p = startPos.Position;

		var noise = Sandbox.Utility.Noise.FbmVector( 1, 0, t * 512 );

		p += noise.x * Vector3.Left * Noise;
		p += noise.y * Vector3.Forward * Noise;
		p += noise.z * Vector3.Up * Noise * 0.1f;

		return p;
	}

	protected override void OnFixedUpdate()
	{
		if ( IsProxy ) return;

		var prev = GetPositionAt( (Time.Now * Speed) - 0.03f );

		LocalPosition = GetPositionAt( Time.Now * Speed );
		//	LocalRotation = Rotation.LookAt( prev - LocalPosition );
	}
}

public sealed class MoveAlongSplineComponent : Component
{
	[Property] public SplineComponent Spline { get; set; }

	[Property] public float Speed { get; set; } = 20.0f;

	[Property] public bool UpdateRotation { get; set; } = false;

	private float _currentDistance = 0;

	protected override void OnEnabled()
	{
		base.OnEnabled();

		if (!Spline.IsValid())
		{
			return;
		}
		WorldPosition = Spline.Spline.SampleAtDistance( 0 ).Position + Spline.GameObject.WorldPosition;
	}

	protected override void OnFixedUpdate()
	{
		if ( IsProxy ) return;

		if ( !Spline.IsValid() )
		{
			return;
		}

		_currentDistance += Time.Delta * Speed;

		if (  _currentDistance > Spline.Spline.Length )
		{
			_currentDistance = _currentDistance - Spline.Spline.Length;
		}

		WorldPosition = Spline.Spline.SampleAtDistance( _currentDistance ).Position + Spline.GameObject.WorldPosition;

		if ( UpdateRotation )
		{
			// quick and dirty tangent frame
			var tanget = Spline.Spline.SampleAtDistance( _currentDistance ).Tangent;
			Vector3 up = Vector3.Up;

			// Choose an initial up vector if tangent is parallel to Up
			if ( MathF.Abs( Vector3.Dot( tanget, up ) ) > 0.999f )
			{
				up = Vector3.Right;
			}

			LocalRotation = Rotation.LookAt( tanget, up );
		}
	}
}