прив, у меня есть код змейки для garry'smod написанный на GLua: local WINDOW_WIDTH = 600
local WINDOW_HEIGHT = 450
local GRID_SIZE = 20
local SNAKE_SPEED = 0.1

local snake = {{x = 15, y = 11}}
local direction = {x = 1, y = 0}
local food = {}
local score = 0
local health = 100
local gameOver = false
local window = nil
local musicChannel = nil
local gameStarted = false

-- Укажите здесь прямую ссылку на вашу музыку
local MUSIC_URL = "https://dl.dropboxusercontent.com/scl/fi/txvkpbkb3m3plendr9jje/bullish-older-1-mp3cut.net.mp3?rlkey=j0lxay08w2g7yveyguxmwgrxl&st=mrayoa7s&dl=0"

-- Функции для работы с музыкой
local function startMusic()
    if IsValid(musicChannel) then
        musicChannel:Stop()
    end
    
    sound.PlayURL(MUSIC_URL, "noblock", function(channel, errCode, errStr)
        if IsValid(channel) then
            musicChannel = channel
            musicChannel:SetVolume(0.5)  -- Установите желаемую громкость (от 0 до 1)
            musicChannel:EnableLooping(true)
            musicChannel:Play()
        else
            print("Error playing sound:", errStr)
        end
    end)
end

local function stopMusic()
    if IsValid(musicChannel) then
        musicChannel:Stop()
        musicChannel = nil
    end
end

local function spawnFood()
    food = {
        x = math.random(0, (WINDOW_WIDTH / GRID_SIZE) - 1),
        y = math.random(0, (WINDOW_HEIGHT / GRID_SIZE) - 1)
    }
end

local function createStylishButton(parent, text, x, y, w, h)
    local button = vgui.Create("DButton", parent)
    button:SetText("")
    button:SetPos(x, y)
    button:SetSize(w, h)
    
    button.Paint = function(self, w, h)
        local time = CurTime() * 2
        local r = math.sin(time) * 127 + 128
        local g = math.sin(time + 2) * 127 + 128
        local b = math.sin(time + 4) * 127 + 128
        
        -- Фон кнопки
        draw.RoundedBox(8, 0, 0, w, h, Color(r, g, b, 200))
        
        -- Обводка кнопки
        surface.SetDrawColor(255, 255, 255, 200)
        surface.DrawOutlinedRect(0, 0, w, h, 2)
        
        -- Текст кнопки
        draw.SimpleText(text, "DermaLarge", w/2, h/2, Color(255, 255, 255), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
    end
    
    return button
end

local function moveSnake()
    if gameOver then return end

    local head = snake[1]
    local newHead = {x = head.x + direction.x, y = head.y + direction.y}
    
    if newHead.x < 0 or newHead.x >= WINDOW_WIDTH / GRID_SIZE or
       newHead.y < 0 or newHead.y >= WINDOW_HEIGHT / GRID_SIZE then
        gameOver = true
        return
    end
    
    for i = 2, #snake do
        if newHead.x == snake[i].x and newHead.y == snake[i].y then
            gameOver = true
            return
        end
    end
    
    table.insert(snake, 1, newHead)
    
    if newHead.x == food.x and newHead.y == food.y then
        score = score + 10
        health = math.min(health + 5, 100)
        spawnFood()
    else
        table.remove(snake)
    end
end

local function drawGame(w, h)
    -- Фон
    draw.RoundedBox(0, 0, 0, w, h, Color(0, 0, 0))
    
    -- RGB рамка
    local time = CurTime() * 0.5
    local r = math.sin(time) * 127 + 128
    local g = math.sin(time + 2) * 127 + 128
    local b = math.sin(time + 4) * 127 + 128
    local borderColor = Color(r, g, b)
    
    local borderWidth = 2
    draw.RoundedBox(0, 0, 0, w, borderWidth, borderColor)  -- Верхняя граница
    draw.RoundedBox(0, 0, h - borderWidth, w, borderWidth, borderColor)  -- Нижняя граница
    draw.RoundedBox(0, 0, 0, borderWidth, h, borderColor)  -- Левая граница
    draw.RoundedBox(0, w - borderWidth, 0, borderWidth, h, borderColor)  -- Правая граница
    
    if gameStarted then
        -- Змейка
        for _, segment in ipairs(snake) do
            if segment and segment.x and segment.y then
                draw.RoundedBox(0, segment.x * GRID_SIZE, segment.y * GRID_SIZE, GRID_SIZE - 1, GRID_SIZE - 1, Color(0, 255, 0, 255))
            end
        end
        
        -- Еда
        if food and food.x and food.y then
            draw.RoundedBox(0, food.x * GRID_SIZE, food.y * GRID_SIZE, GRID_SIZE - 1, GRID_SIZE - 1, Color(255, 0, 0, 255))
        end
        
        -- Счет и здоровье
        draw.SimpleText("Score: " .. score, "DermaDefault", w - 10, 30, Color(255, 255, 255), TEXT_ALIGN_RIGHT)
        draw.SimpleText("Health: " .. health, "DermaDefault", w - 10, 50, Color(255, 255, 255), TEXT_ALIGN_RIGHT)
        
        if gameOver then
            draw.SimpleText("Game Over", "DermaLarge", w / 2, h / 2 - 30, Color(255, 255, 255), TEXT_ALIGN_CENTER)
        end
    else
        -- Заголовок для начального меню
        draw.SimpleText("Snake Game", "DermaLarge", w / 2, h / 4, Color(255, 255, 255), TEXT_ALIGN_CENTER)
    end
end

local function startGame()
    gameStarted = true
    snake = {{x = 15, y = 11}}
    direction = {x = 1, y = 0}
    score = 0
    health = 100
    gameOver = false
    spawnFood()
    startMusic()
end

local function createMainMenu()
    local startButton = createStylishButton(window, "Start Game", WINDOW_WIDTH/2 - 100, WINDOW_HEIGHT/2 - 40, 200, 60)
    local exitButton = createStylishButton(window, "Exit", WINDOW_WIDTH/2 - 100, WINDOW_HEIGHT/2 + 40, 200, 60)
    
    startButton.DoClick = function()
        startButton:Remove()
        exitButton:Remove()
        startGame()
    end
    
    exitButton.DoClick = function()
        window:Close()
    end
end

local function createWindow()
    if IsValid(window) then window:Remove() end
    
    window = vgui.Create("DFrame")
    window:SetSize(WINDOW_WIDTH, WINDOW_HEIGHT)
    window:SetTitle("Snake Game")
    window:SetDraggable(true)
    window:SetSizable(false)
    window:Center()
    window:MakePopup()
    
    window.Paint = function(self, w, h)
        drawGame(w, h)
    end
    
    local retryButton = createStylishButton(window, "Retry", WINDOW_WIDTH/2 - 110, WINDOW_HEIGHT/2 + 20, 100, 40)
    retryButton.DoClick = startGame
    retryButton:SetVisible(false)
    
    local exitButton = createStylishButton(window, "Exit", WINDOW_WIDTH/2 + 10, WINDOW_HEIGHT/2 + 20, 100, 40)
    exitButton.DoClick = function()
        stopMusic()
        window:Close()
    end
    exitButton:SetVisible(false)
    
    window.Think = function()
        if gameStarted then
            if gameOver then
                retryButton:SetVisible(true)
                exitButton:SetVisible(true)
            else
                retryButton:SetVisible(false)
                exitButton:SetVisible(false)
                
                if input.IsKeyDown(KEY_UP) and direction.y == 0 then
                    direction = {x = 0, y = -1}
                elseif input.IsKeyDown(KEY_DOWN) and direction.y == 0 then
                    direction = {x = 0, y = 1}
                elseif input.IsKeyDown(KEY_LEFT) and direction.x == 0 then
                    direction = {x = -1, y = 0}
                elseif input.IsKeyDown(KEY_RIGHT) and direction.x == 0 then
                    direction = {x = 1, y = 0}
                end
                
                if CurTime() - (window.LastMove or 0) > SNAKE_SPEED then
                    moveSnake()
                    window.LastMove = CurTime()
                end
            end
        end
    end
    
    window.OnRemove = function()
        stopMusic()
    end
    
    createMainMenu()
end

createWindow()


я хочу добавить снизу поля audio visualizer, чтобы он синхронизировался с музыкой и двигался в такт мелодии, можешь добавить в код?