Was dissapointed there was no lava lamp models in the asset cloud, let alone a functioning one. So here ya go. just make a component with the follow code, slap it on a blob, and assign colors. thanks for trying!

using Sandbox;
using System;

public sealed class LavaBlob : Component
{
    [Header( "Vertical Movement" )]
    [Property] public float MinHeight { get; set; } = 0f;
    [Property] public float MaxHeight { get; set; } = 20f;
    [Property] public float Speed { get; set; } = 2.0f;

    [Header( "Horizontal Drift" )]
    [Property] public float HorizontalLimit { get; set; } = 1.0f; // How far sideways it can go
    [Property] public float HorizontalSpeed { get; set; } = 0.2f; // Keep this low for lazy drifting

    [Header( "The Squish" )]
    [Property, Range( 0f, 0.9f )] public float SquishAmount { get; set; } = 0.4f; 
    [Property] public float SquishRate { get; set; } = 8.0f; 
    [Property] public float SquishZone { get; set; } = 4.0f; 

    private Vector3 _homeBase; 
    private Vector3 _startScale;
    private float _currentHeight; 
    private bool _movingUp = true;
    private float _timeOffset;

    protected override void OnStart()
    {
        _homeBase = LocalPosition; 
        _startScale = LocalScale;
        _currentHeight = MinHeight;
        _movingUp = true;
        _timeOffset = Game.Random.Float( 0f, 100f );
    }

    protected override void OnUpdate()
    {
        float t = Time.Now + _timeOffset;

        // --- 1. VERTICAL MOVEMENT ---
        if ( _movingUp )
        {
            _currentHeight += Speed * Time.Delta;
            if ( _currentHeight >= MaxHeight )
            {
                _currentHeight = MaxHeight;
                _movingUp = false;
            }
        }
        else
        {
            _currentHeight -= Speed * Time.Delta;
            if ( _currentHeight <= MinHeight )
            {
                _currentHeight = MinHeight;
                _movingUp = true;
            }
        }

        // --- 2. GENTLE HORIZONTAL DRIFT ---
        // We use Cosine and Sine at slightly different speeds to create a natural, non-repeating oval wander
        float driftX = MathF.Sin( t * HorizontalSpeed ) * HorizontalLimit;
        float driftY = MathF.Cos( t * HorizontalSpeed * 0.8f ) * HorizontalLimit;


        // --- 3. SQUISH MATH ---
        float distToTop = MathF.Abs( MaxHeight - _currentHeight );
        float distToBot = MathF.Abs( _currentHeight - MinHeight );
        float closestDist = MathF.Min( distToTop, distToBot );

        float proximityMultiplier = 0f;
        if ( closestDist < SquishZone )
        {
            proximityMultiplier = 1f - (closestDist / SquishZone);
        }

        float pulse = MathF.Abs( MathF.Sin( t * SquishRate ) );
        float squishFactor = pulse * SquishAmount * proximityMultiplier;
        squishFactor = squishFactor.Clamp( 0f, 0.9f );

        // Apply scale
        LocalScale = new Vector3(
            _startScale.x * (1f + (squishFactor * 0.5f)),
            _startScale.y * (1f + (squishFactor * 0.5f)),
            _startScale.z * (1f - squishFactor)
        );

        // Apply position (Home Base + Horizontal Drift + Vertical Height)
        LocalPosition = new Vector3( 
            _homeBase.x + driftX, 
            _homeBase.y + driftY, 
            _homeBase.z + _currentHeight 
        );
    }
}