How to make boids be a bit more stable?

You can write your topic however you want, but you need to answer these questions:

  1. What do you want to achieve? Keep it simple and clear!
    I want to make boids that look like this video.

  2. What is the issue? Include screenshots / videos if possible!
    Although the code works, the boids change direction a lot, and quite abruptly, resulting in stuff like this:

  3. What solutions have you tried so far? Did you look for solutions on the Developer Hub?
    I’ve tried lerping to see if that would stabilise it, but it’s not working.

Here is the code for the boids that matters:

function  Boid.__index:CalculateDirection(): Vector3?
    local AverageHeading = ZERO_VECTOR
    local AveragePosition = ZERO_VECTOR
    local SeperationHeading = ZERO_VECTOR
    local NumBoids = 0
    local AvoidBoids = 0
    for Id, OtherBoid in ipairs(BoidArray) do
        if OtherBoid.Id == self.Id then
        local Offset = OtherBoid.Position - self.Position
        local Distance = Offset.Magnitude

        if Distance > self.Range then
        if GetAngleBetweenVectors(self.Position, OtherBoid.Position) > self.ViewAngle then
        AverageHeading += OtherBoid.Direction
        AveragePosition += OtherBoid.Position
        if Distance < AVOID_RADIUS then
            SeperationHeading -= Offset / Distance
            AvoidBoids += 1
        NumBoids += 1
    if NumBoids < 1 then
    AverageHeading /= NumBoids
    AverageHeading *= ALIGN_WEIGHT
    AveragePosition = AveragePosition / NumBoids - self.Position
    AveragePosition *= COHESIVE_WEIGHT
    -- Dividing by 0 results in nan values, which caused me way too much headache :/ 
    if AvoidBoids > 0 then
        SeperationHeading /= AvoidBoids
        SeperationHeading *= SEPERATION_WEIGHT
        return ClampVector(AverageHeading + AveragePosition, MAX_VELOCITY)
    return ClampVector(AverageHeading + AveragePosition + SeperationHeading, MAX_VELOCITY)
function Boid.__index:Update(dt: NumberValue)
    local NewHeading = self:CalculateDirection()
    if NewHeading then
        self.Direction += NewHeading * dt
        self.Direction = self.Direction.Unit
    self.Position += self.Direction * dt
    --VectorVisualizer.UpdateVector(self.VectorVisualizer, self.Direction, self.Position)

I feel as if that behavior is supposed to happen because in the video you only ever see the Boids moving. Have you tried making them follow a part?

If it’s still an issue, then I recommend implementing a creates a variable of the boid’s starting position and tries to keep it in that general position if it hasn’t been programmed to follow a part.