Infinite Ocean using Mesh Deformation HELP

I’ve used this guy wave system - Realistic Oceans Using Mesh Deformation!

And I’m trying to make it infinite, i want it to make so the waves “stay in place” when i move but the ocean goes with me to make the illusion that is infinite.

What i got

If you got another method to make a ocean like that or if my method is wrong pls tell

here is the script :

(local)

local Wave = require(script.WaveModule)

local Sea = workspace:FindFirstChild("Sea") or workspace:WaitForChild("Sea")

local Plane = Sea:FindFirstChild("Plane") or Sea:WaitForChild("Plane")
local Ground = Sea:FindFirstChild("Ground") or Sea:WaitForChild("Ground")

local Settings = {
WaveLength = 50,
	Direction = Vector2.new(0,0), -- It is 0, 0, so it will use the perlin noise algorithm to make random waves for me
	--PushPoint = Plane, -- Alternative to Direction, the wave's direction will always push away from the part.
	Steepness = 0.6,
	TimeModifier = 8,
	MaxDistance = 1500,
}

local Wave1 = Wave.new(Plane,Settings)
Wave1:ConnectRenderStepped()


local PLR = game:GetService("Players").LocalPlayer

while true do
	wait()
	local CHar = PLR.Character or PLR.CharacterAdded:Wait()
	local HRP = CHar:FindFirstChild("HumanoidRootPart") or CHar:WaitForChild("HumanoidRootPart")
	
	Plane.Position = Vector3.new(HRP.Position.X,Plane.Position.Y,HRP.Position.Z)
	Ground.Position = Vector3.new(HRP.Position.X,Ground.Position.Y,HRP.Position.Z)
	
end

module bellow the local script witch is the same as the other guy i mentioned:


local Wave = {}
Wave.__index = Wave

local newCFrame = CFrame.new
local IdentityCFrame = newCFrame()
local EmptyVector2 = Vector2.new()
local math_noise = math.noise
local random = math.random
local setseed = math.randomseed

local Stepped = game:GetService("RunService").RenderStepped
local Player = game:GetService("Players").LocalPlayer

local Module2 = script.Parent.WaveModule2

local default = {
	WaveLength = 85,
	Gravity = 1.5,
	Direction = Vector2.new(1,0), -- Must be a Vector2
	FollowPoint = nil, -- Alternative to Direction, the wave's direction will always push away from the part or Vector3.
	Steepness = 1,
	TimeModifier = 4,
	MaxDistance = 1500,
}

local function Gerstner(Position: Vector3,Wavelength: number,Direction: Vector2,Steepness: number,Gravity: number,Time: number)
	local k = (2 * math.pi) / Wavelength
	local a = Steepness/k
	local d = Direction.Unit
	local c = math.sqrt(Gravity / k)
	local f = k * d:Dot(Vector2.new(Position.X,Position.Z)) - c * Time
	local cosF = math.cos(f)

	--Displacement Vectors
	local dX = (d.X * (a * cosF))
	local dY = a * math.sin(f)
	local dZ = ( d.Y * (a * cosF))
	return Vector3.new(dX,dY,dZ)
end

local function CreateSettings(s: table,o: table)
	o = o or {}
	s = s or default
	local new = {
		WaveLength = s.WaveLength or o.WaveLength or default.WaveLength,
		Gravity = s.Gravity or o.Gravity or default.Gravity,
		Direction = s.Direction or o.Direction or default.Direction,
		PushPoint = s.PushPoint or o.PushPoint or default.PushPoint,
		Steepness = s.Steepness or o.Steepness or default.Steepness,
		TimeModifier = s.TimeModifier or o.TimeModifier or default.TimeModifier,
		MaxDistance = s.MaxDistance or o.MaxDistance or default.MaxDistance,
	}
	return new
end

local function GetDirection(Settings,WorldPos)
	local Direction = Settings.Direction
	local PushPoint = Settings.PushPoint

	if PushPoint then
		local PartPos = nil

		if PushPoint:IsA("Attachment") then
			PartPos = PushPoint.WorldPosition
		elseif PushPoint:IsA("BasePart") then
			PartPos = PushPoint.Position
		else
			warn("Invalid class for FollowPart, must be BasePart or Attachment")
			return
		end

		Direction = (PartPos-WorldPos).Unit
		Direction = Vector2.new(Direction.X,Direction.Z)
	end
	
	return Direction
end

function Wave.new(instance: instance, waveSettings: table | nil, bones: table | nil)
	-- Get bones on our own
	if bones == nil then
		bones = {}
		for _,v in pairs(instance:GetDescendants()) do
			if v:IsA("Bone") then
				table.insert(bones,v)
			end
		end
	end
	
	local Time = os.time()
	
	return setmetatable({
		_instance = instance,
		_bones = bones,
		_time = 0,
		_connections = {},
		_noise = {},
		_settings = CreateSettings(waveSettings)
	},Wave)
end

function Wave:Update()
	for _,v in pairs(self._bones) do
		local WorldPos = v.WorldPosition
		local Settings = self._settings
		local Direction = Settings.Direction
		
		
		if Direction == EmptyVector2 then
			-- Use Perlin Noise
			local Noise = self._noise[v]
			local NoiseX = Noise and self._noise[v].X
			local NoiseZ = Noise and self._noise[v].Z
			local NoiseModifier = 1 -- If you want more of a consistent direction, change this number to something bigger
			
			if not Noise then
				self._noise[v] = {}
				-- Uses perlin noise to generate smooth transitions between random directions in the waves
				NoiseX = math_noise(WorldPos.X/NoiseModifier,WorldPos.Z/NoiseModifier,1)
				NoiseZ = math_noise(WorldPos.X/NoiseModifier,WorldPos.Z/NoiseModifier,0)
				
				self._noise[v].X = NoiseX
				self._noise[v].Z = NoiseZ
			end
			
			Direction = Vector2.new(NoiseX,NoiseZ)
		else
			Direction = GetDirection(Settings,WorldPos)
		end
		
		v.Transform = newCFrame(Gerstner(WorldPos,Settings.WaveLength,Direction,Settings.Steepness,Settings.Gravity,self._time))
	end
end

function Wave:Refresh()
	for _,v in pairs(self._bones) do
		v.Transform = IdentityCFrame
	end
end

function Wave:UpdateSettings(waveSettings)
	self._settings = CreateSettings(waveSettings,self._settings)
end

function Wave:ConnectRenderStepped()
	local Connection = Stepped:Connect(function()
		if not game:IsLoaded() then return end
		local Character = Player.Character
		local Settings = self._settings
		if not Character or (Character.PrimaryPart.Position-self._instance.Position).Magnitude < Settings.MaxDistance then
			local Time = (DateTime.now().UnixTimestampMillis/1000)/Settings.TimeModifier
			self._time = Time
			self:Update()
		else
			self:Refresh()
		end
	end)
	table.insert(self._connections,Connection)
	return Connection
end

function Wave:Destroy()
	self._instance = nil
	for _,v in pairs(self._connections) do
		pcall(function()
			v:Disconnect()
		end)
	end
	self._bones = {}
	self._settings = {}
	self = nil
	-- Basically makes the wave impossible to use
end



return Wave

Try creating a table of the bones and their initial locations once the game starts.

Instead of using this code: (2nd line in the Wave:Update() function)

Use the positions from the table.

The height of the wave is determined by WorldPos. When the bones move, their world position changes, which affects the height. By storing their initial locations in a table, you can keep the reference point static.

i tried to do that and it didnt work, i dont know if i did it right or wrong, can u show an example on how to do it ( im rlly terrible with tables and mesh def sry )

also thanks for the quick answer

Try something like this:

function Wave.new(instance: instance, waveSettings: table | nil, bones: table | nil)
	local initialPositions = {} -- Table to store the positions
	
	if bones == nil then
		bones = {}
		for _,v in pairs(instance:GetDescendants()) do
			if v:IsA("Bone") then
				table.insert(bones,v)
				initialPositions[v] = v.WorldPosition -- Add bone's position to table
			end
		end
	end

	local Time = os.time()

	return setmetatable({
		_instance = instance,
		_initialPositions = initialPositions, -- Create variable
		_bones = bones,
		_time = 0,
		_connections = {},
		_noise = {},
		_settings = CreateSettings(waveSettings)
	},Wave)
end

function Wave:Update()
	for _,v in pairs(self._bones) do
		local WorldPos = self._initialPositions[v] -- Get position from table
		
		...

it did not work, is it what i use to move the waves? if u have another method for infinite ocean without using special mesh tell me, idk if im asking too much sry

You could snap the player’s position to a large grid, then move the ocean when the player moves to another space in that grid. Because the height of each wave is determined by the bone’s position, it should look seamless. However, you would need some kind of fog or LOD to mask the space that isn’t covered by the ocean.