Getting the character controller to stick to the ground?

I got this to work but really simply by using a Raycast and checking for the angle then pushing the player down with verticalVelocity. But then it prevents the player from jumping when moving up or down stairs, and even though I added a clause for that with if (!Input("Jump)") and a groundedTimer of 0.3f seconds, there’s still really inconsistent movement.

Like at the very start of the scene, debugging shows that the player is NOT grounded, and my animation reflects that because the falling animation plays. Adding isGrounded = true; to Start() works but that doesn’t seem like a good solution. I’m just trying to get the player to stick to every surface it’s moving on but still be able to jump normally. Running down stairs makes my player run into the air, then fall down.

I also don’t know how a Raycast or SphereCast will work on different surfaces like rough terrain, rounded objects, etc, or at the bottom of stairs/slopes, etc, where the Raycast will no longer work. But replacing it with a SphereCast makes it work on the edges of objects which shouldn’t happen. Using layers has been inconsistent so far, unless I add invisible colliders to every single object with a certain layer to prevent those edge cases, but I don’t know if that’s smart either.

if (Physics.Raycast(transform.position, -transform.up, out RaycastHit hit, 1.3f))
{
    float angle = Vector3.Angle(Vector3.up, hit.normal);

    if (angle > 0.1f)
    {
        hitNormal = hit.normal;
        velocity.y = -15f; // Make the player snap to/stay on the ground
    }
    else
    {
        hitNormal = Vector3.up;
    }
}
else
{
    hitNormal = Vector3.up;
}

if (!isGrounded)
{
    Debug.Log(isGrounded);
}

Edit: I seemed to have fixed the bouncing, but at the bottom of any angled surface, the ray stops hitting so there’s bouncing which looks and feels terrible gameplay wise. A sphereCast makes it a bit worse on edges. I also think I fixed the jumping portion, but it’s still not great so not sure what to do next.

using UnityEngine;
public class BasicController : MonoBehaviour
{
    CharacterController cc;
    Vector3 velocity;

    void Start()
    {
        cc = GetComponent<CharacterController>();
    }

    void Update()
    {
        if (cc.isGrounded)
        {
            if (Input.GetButtonDown("Jump"))
                velocity.y=cc.velocity.y + 5;
            else if (velocity.y < 0) // are we probably going down a slope?
                velocity.y = -6;
        }
        
        Vector3 force=((transform.right*Input.GetAxis("Horizontal")) + (transform.forward*Input.GetAxis("Vertical")))*10;
        if (Input.GetKey(KeyCode.LeftShift)) force*=2; // run?
        velocity=new Vector3(force.x, velocity.y + Physics.gravity.y * Time.deltaTime, force.z);
        cc.Move(velocity * Time.deltaTime);
    }
}