Generate Map/Biome Using Perlin Noise

I generated a blocky map using Perline Noise. It worked completely perfectly, but I want to add biomes to the map, and I don’t know how I can add biomes. I tried some ways to create a biome, but it didn’t work. Could you help me on how I can do it?

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService")
local Players = game:GetService("Players")
  
local Blocks = ReplicatedStorage:WaitForChild("Blocks")
local GrassBlock = Blocks:WaitForChild("Grass")
  
local ChunksFolder = Instance.new("Folder")
ChunksFolder.Name = "Chunks"
ChunksFolder.Parent = workspace
  
local renderDistance = 4 -- 1 = 3*3 2 = 5*5 3 = 7*7 4 = 9*9 ...
local chunkSize = 10 -- 10*10
  
local MountainScale = 0.04
local PlainScale = 0.015
  
local MountainWeight = 0.4
local PlainWeight = 0.6
  
local BlockSize = 4
  
local loadedChunks = {}
  
local function generateChunk(chunkX, chunkZ)
    local chunk = Instance.new("Model")
    chunk.Name = "Chunk_" .. chunkX .. "_" .. chunkZ
    chunk.Parent = ChunksFolder
  
    for x = 0, chunkSize - 1 do
        for z = 0, chunkSize - 1 do
            local globalX = (chunkX * chunkSize) + x
            local globalZ = (chunkZ * chunkSize) + z
  
            local height1 = math.noise(globalX * MountainScale, globalZ * MountainScale) * 10 * MountainWeight 
            local height2 = math.noise(globalX * PlainScale , globalZ * PlainScale ) * 10 * PlainWeight 
            local height = height1 + height2
            height = math.floor(height)
  
            local block = GrassBlock:Clone()
            block.Position = Vector3.new(globalX * BlockSize, height * BlockSize, globalZ * BlockSize)
            block.Parent = chunk
        end
    end
  
    loadedChunks[chunkX .. "_" .. chunkZ] = chunk
end
  
local function loadChunksAroundPlayer(player)
    local character = player.Character
    if not character or not character:FindFirstChild("HumanoidRootPart") then return end
  
    local playerPos = character.HumanoidRootPart.Position
    local currentChunkX = math.floor(playerPos.X / (chunkSize * BlockSize))
    local currentChunkZ = math.floor(playerPos.Z / (chunkSize * BlockSize))
  
    local newLoadedChunks = {}
  
    for i = -renderDistance, renderDistance do
        for j = -renderDistance, renderDistance do
            local chunkX = currentChunkX + i
            local chunkZ = currentChunkZ + j
            local chunkKey = chunkX .. "_" .. chunkZ
  
            if not loadedChunks[chunkKey] then
                generateChunk(chunkX, chunkZ)
            end
 
            newLoadedChunks[chunkKey] = true
        end
    end
  
    for chunkKey, chunk in pairs(loadedChunks) do
        if not newLoadedChunks[chunkKey] then
            chunk:Destroy()
            loadedChunks[chunkKey] = nil
        end
    end
end
  
local function onPlayerAdded(player)
    player.CharacterAdded:Connect(function(character)
        character:WaitForChild("Humanoid")

        while task.wait(0.1) do
            loadChunksAroundPlayer(player)
        end

    end)
end
  
Players.PlayerAdded:Connect(onPlayerAdded)

If you want to try it yourself, just change the Grass Block code to:

local GrassBlock = Instance.new("Part")
GrassBlock.Anchored = true
GrassBlock.Size = Vector3.new(4,4,4)
GrassBlock.Color = Color3.new(0, 0.4, 0)