не меняй дизайн  оптемезируй код  и исправь логические ошибки
<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <title>Расширенный Эмулятор GPU RTX</title>
    <!-- Подключение CodeMirror CSS -->
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/codemirror.min.css">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/theme/monokai.min.css">
    <!-- Стилизация интерфейса -->
    <style>
        body {
            font-family: Arial, sans-serif;
            background-color: #1e1e1e;
            color: #fff;
            display: flex;
            flex-direction: column;
            align-items: center;
            padding: 20px;
            min-height: 100vh;
            box-sizing: border-box;
        }
        #gpuInterface {
            margin-bottom: 20px;
            padding: 20px;
            background-color: #2e2e2e;
            border-radius: 8px;
            width: 90%;
            max-width: 1000px;
            display: flex;
            flex-direction: column;
            gap: 15px;
            box-shadow: 0 4px 10px rgba(0,0,0,0.5);
        }
        #gpuInterface h2 {
            margin-top: 0;
            text-align: center;
            font-size: 24px;
            color: #00ffea;
        }
        /* CodeMirror Контейнер */
        .CodeMirror {
            height: auto;
            min-height: 300px;
            background-color: #1e1e1e;
            color: #fff;
            border: 1px solid #555;
            border-radius: 4px;
            font-family: monospace;
            font-size: 14px;
        }
        #gpuControls {
            display: flex;
            gap: 10px;
            flex-wrap: wrap;
            justify-content: center;
        }
        #gpuControls button {
            padding: 10px 20px;
            background-color: #007acc;
            border: none;
            border-radius: 4px;
            color: #fff;
            cursor: pointer;
            flex: 1;
            min-width: 140px;
            transition: background-color 0.3s;
        }
        #gpuControls button:hover {
            background-color: #005fa3;
        }
        #outputCanvas, #outputWebGL {
            border: 2px solid #555;
            background-color: #000;
            margin-bottom: 10px;
            border-radius: 4px;
            max-width: 100%;
        }
        #outputWebGL {
            display: none;
        }
        #vramStatus {
            font-size: 14px;
            text-align: center;
        }
        #log {
            background-color: #2e2e2e;
            padding: 10px;
            border-radius: 4px;
            max-height: 200px;
            overflow-y: auto;
            font-family: monospace;
            font-size: 12px;
            box-shadow: inset 0 0 5px rgba(0,0,0,0.5);
        }
        #log h3 {
            margin-top: 0;
            color: #ff6347;
        }
        #vramViewer {
            width: 100%;
            max-width: 400px;
            height: auto;
            border: 1px solid #555;
            overflow: hidden;
            background-color: #1e1e1e;
            border-radius: 4px;
            margin: 0 auto;
        }
        #vramCanvas {
            display: block;
            width: 100%;
            height: auto;
        }
        /* Модальное окно помощи */
        #helpModal {
            display: none;
            position: fixed;
            top: 5%;
            left: 10%;
            width: 80%;
            height: 90%;
            background-color: #333;
            color: #fff;
            padding: 20px;
            overflow-y: auto;
            border-radius: 8px;
            z-index: 1000;
            box-shadow: 0 4px 20px rgba(0,0,0,0.7);
        }
        #helpModal h2 {
            text-align: center;
            color: #00ffea;
        }
        #helpModal ul {
            list-style: none;
            padding: 0;
        }
        #helpModal li {
            margin-bottom: 10px;
            line-height: 1.5;
        }
        #helpModal button {
            margin-top: 20px;
            padding: 10px 20px;
            background-color: #007acc;
            border: none;
            border-radius: 4px;
            color: #fff;
            cursor: pointer;
            display: block;
            margin-left: auto;
            margin-right: auto;
            transition: background-color 0.3s;
        }
        #helpModal button:hover {
            background-color: #005fa3;
        }
        /* Responsive дизайн */
        @media (max-width: 600px) {
            #gpuControls button {
                min-width: 100px;
                padding: 8px 16px;
            }
            #gpuInterface {
                padding: 15px;
            }
            #gpuInterface h2 {
                font-size: 20px;
            }
        }
    </style>
</head>
<body>
    <div id="gpuInterface">
        <h2>Эмулятор GPU RTX</h2>
        <!-- Текстовый редактор CodeMirror -->
        <textarea id="gpuProgram" placeholder="Введите программу GPU (пример ниже)"></textarea>
        <div id="gpuControls">
            <button id="runProgram">Выполнить</button>
            <button id="clearCanvas">Очистить Canvas</button>
            <button id="saveProgram">Сохранить программу</button>
            <button id="loadProgram">Загрузить программу</button>
            <button id="toggleRenderMode">Включить WebGL</button>
            <button id="showHelp">Помощь</button>
        </div>
        <div id="vramStatus">VRAM: 0 / 480000</div>
        <div id="log">
            <h3>Лог GPU:</h3>
            <div id="logContent"></div>
        </div>
        <h3>Просмотр VRAM:</h3>
        <div id="vramViewer">
            <canvas id="vramCanvas" width="200" height="150"></canvas>
        </div>
    </div>
    <!-- Два Canvas: для обычного рендеринга и WebGL -->
    <canvas id="outputCanvas" width="800" height="600"></canvas>
    <canvas id="outputWebGL" width="800" height="600"></canvas>
    
    <!-- Модальное окно помощи -->
    <div id="helpModal">
        <h2>Помощь по Инструкциям GPU</h2>
        <ul>
            <li><strong>DRAW x y r g b</strong>: Рисует пиксель в (x, y) с цветом (r, g, b).</li>
            <li><strong>DRAW_LINE x1 y1 x2 y2 r g b</strong>: Рисует линию от (x1, y1) до (x2, y2) цветом (r, g, b).</li>
            <li><strong>FILL_RECT x y width height r g b</strong>: Заполняет прямоугольник с верхним левым углом в (x, y), заданными размерами и цветом.</li>
            <li><strong>DRAW_CIRCLE x y radius r g b</strong>: Рисует окружность с центром в (x, y), заданным радиусом и цветом.</li>
            <li><strong>DRAW_ELLIPSE x y radiusX radiusY r g b</strong>: Рисует эллипс с центром в (x, y), заданными радиусами и цветом.</li>
            <li><strong>DRAW_SPLINE x1 y1 x2 y2 x3 y3 r g b</strong>: Рисует квадратичный сплайн через точки (x1, y1), (x2, y2), (x3, y3) с цветом (r, g, b).</li>
            <li><strong>DRAW_TRIANGLE x1 y1 x2 y2 x3 y3 r g b</strong>: Рисует треугольник через точки (x1, y1), (x2, y2), (x3, y3) с цветом (r, g, b).</li>
            <li><strong>CLEAR r g b</strong>: Очищает экран заливкой цветом (r, g, b).</li>
            <li><strong>SET_VARIABLE varName value</strong>: Устанавливает значение переменной. Поддерживаются простые арифметические выражения, например: SET_VARIABLE x {x} + 5</li>
            <li><strong>GET_VARIABLE varName</strong>: Получает значение переменной.</li>
            <li><strong>VERTEX_SHADER code</strong>: Определяет вершинный шейдер.</li>
            <li><strong>FRAGMENT_SHADER code</strong>: Определяет фрагментный шейдер.</li>
            <li><strong>USE_SHADERS true/false</strong>: Включает или отключает применение шейдеров.</li>
            <li><strong>FUNCTION functionName</strong> / <strong>END_FUNCTION</strong>: Определяет функцию.</li>
            <li><strong>CALL functionName</strong>: Вызывает определённую функцию.</li>
            <li><strong>LOAD_SPRITE url x y</strong>: Загружает изображение из URL и отображает его на (x, y).</li>
            <!-- Добавьте другие инструкции по мере необходимости -->
        </ul>
        <button id="closeHelp">Закрыть</button>
    </div>

    <!-- Подключение CodeMirror JS -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/codemirror.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/mode/javascript/javascript.min.js"></script>
    <!-- Основной скрипт эмулятора GPU -->
    <script>
        class GPUEmulator {
            constructor(width, height, ctx, logElement, vramCanvas, vramCtx, vramStatusElement) {
                this.width = width;
                this.height = height;
                this.ctx = ctx;
                this.logElement = logElement;
                this.vramCanvas = vramCanvas;
                this.vramCtx = vramCtx;
                this.vramSize = width * height; // Каждый пиксель - 1 ячейка VRAM
                this.vram = new Uint32Array(this.vramSize); // 32-битная VRAM
                this.programMemory = [];
                this.variables = {};
                this.functions = {};
                this.vertexShader = null;
                this.fragmentShader = null;
                this.useShaders = false;
                this.shaderCache = {};
                this.gl = null; // WebGL контекст
                this.program = null;
                this.positionBuffer = null;
                this.texCoordBuffer = null;
                this.texture = null;
                this.positionLocation = null;
                this.texCoordLocation = null;
                this.textureLocation = null;
                this.vramStatusElement = vramStatusElement;
            }

            log(message) {
                const logEntry = document.createElement('div');
                logEntry.textContent = message;
                this.logElement.appendChild(logEntry);
                this.logElement.parentElement.scrollTop = this.logElement.parentElement.scrollHeight;
                console.log(message);
            }

            loadProgram(program) {
                this.programMemory = program.split('\n')
                    .map(line => line.trim())
                    .filter(line => line && !line.startsWith('//'));
                this.log(`Программа загружена: ${this.programMemory.length} команд.`);
            }

            replaceVariables(parts) {
                return parts.map(part => {
                    if (part.startsWith('{') && part.endsWith('}')) {
                        const varName = part.slice(1, -1);
                        if (this.variables.hasOwnProperty(varName)) {
                            return this.variables[varName];
                        } else {
                            this.log(`Предупреждение: Переменная "${varName}" не определена.`);
                            return 0;
                        }
                    }
                    return part;
                });
            }

            setShader(type, code) {
                if (type === 'VERTEX_SHADER') {
                    try {
                        this.vertexShaderCode = code;
                        this.log('Вершинный шейдер установлен.');
                    } catch (error) {
                        this.log(`Ошибка в вершине шейдера: ${error}`);
                    }
                } else if (type === 'FRAGMENT_SHADER') {
                    try {
                        this.fragmentShaderCode = code;
                        this.log('Фрагментный шейдер установлен.');
                    } catch (error) {
                        this.log(`Ошибка в фрагментном шейдере: ${error}`);
                    }
                }
            }

            applyShaders(color, x, y) {
                if (this.useShaders && this.vertexShaderCode && this.fragmentShaderCode) {
                    try {
                        // Применяем вершинный шейдер
                        const transformed = this.vertexShader(x, y, this.height);
                        // Применяем фрагментный шейдер
                        return this.fragmentShader({...color}, transformed.x, transformed.y);
                    } catch (error) {
                        this.log(`Ошибка при применении шейдеров: ${error}`);
                        return color;
                    }
                }
                return color;
            }

            drawPixel(x, y, color) {
                if (x < 0 || x >= this.width || y < 0 || y >= this.height) return;
                let finalColor = color;
                if (this.useShaders) {
                    finalColor = this.applyShaders(color, x, y);
                }
                const index = y * this.width + x;
                this.vram[index] = (finalColor.b << 24) | (finalColor.g << 16) | (finalColor.r << 8) | finalColor.a;
            }

            drawLine(x1, y1, x2, y2, color) {
                // Алгоритм Брезенхэма
                const dx = Math.abs(x2 - x1);
                const dy = Math.abs(y2 - y1);
                const sx = x1 < x2 ? 1 : -1;
                const sy = y1 < y2 ? 1 : -1;
                let err = dx - dy;

                while (true) {
                    this.drawPixel(x1, y1, color);
                    if (x1 === x2 && y1 === y2) break;
                    const e2 = 2 * err;
                    if (e2 > -dy) { err -= dy; x1 += sx; }
                    if (e2 < dx) { err += dx; y1 += sy; }
                }
            }

            fillRect(x, y, width, height, color) {
                for (let i = x; i < x + width; i++) {
                    for (let j = y; j < y + height; j++) {
                        this.drawPixel(i, j, color);
                    }
                }
            }

            drawCircle(x, y, radius, color) {
                // Алгоритм Брезенхэма для окружности
                let dx = radius;
                let dy = 0;
                let err = 0;

                while (dx >= dy) {
                    this.drawPixel(x + dx, y + dy, color);
                    this.drawPixel(x + dy, y + dx, color);
                    this.drawPixel(x - dy, y + dx, color);
                    this.drawPixel(x - dx, y + dy, color);
                    this.drawPixel(x - dx, y - dy, color);
                    this.drawPixel(x - dy, y - dx, color);
                    this.drawPixel(x + dy, y - dx, color);
                    this.drawPixel(x + dx, y - dy, color);

                    dy += 1;
                    if (err <= 0) {
                        err += 2 * dy + 1;
                    } else {
                        dx -= 1;
                        err -= 2 * dx + 1;
                    }
                }
            }

            drawEllipse(x, y, radiusX, radiusY, color) {
                // Параметрическое уравнение эллипса
                for (let angle = 0; angle < 360; angle++) {
                    const rad = angle * (Math.PI / 180);
                    const px = Math.round(x + radiusX * Math.cos(rad));
                    const py = Math.round(y + radiusY * Math.sin(rad));
                    this.drawPixel(px, py, color);
                }
            }

            drawQuadraticSpline(x1, y1, x2, y2, x3, y3, color) {
                // Квадратичный сплайн
                for (let t = 0; t <= 1; t += 0.01) {
                    const xt = (1 - t) * (1 - t) * x1 + 2 * (1 - t) * t * x2 + t * t * x3;
                    const yt = (1 - t) * (1 - t) * y1 + 2 * (1 - t) * t * y2 + t * t * y3;
                    this.drawPixel(Math.round(xt), Math.round(yt), color);
                }
            }

            drawTriangle(x1, y1, x2, y2, x3, y3, color) {
                // Рисование треугольника через линию
                this.drawLine(x1, y1, x2, y2, color);
                this.drawLine(x2, y2, x3, y3, color);
                this.drawLine(x3, y3, x1, y1, color);
            }

            clearScreen(color) {
                for (let i = 0; i < this.vramSize; i++) {
                    this.vram[i] = (color.b << 24) | (color.g << 16) | (color.r << 8) | color.a;
                }
            }

            loadSprite(url, x, y) {
                const img = new Image();
                img.crossOrigin = "Anonymous"; // Для избежания CORS проблем
                img.src = url;
                img.onload = () => {
                    const spriteWidth = img.width;
                    const spriteHeight = img.height;
                    const tempCanvas = document.createElement('canvas');
                    tempCanvas.width = spriteWidth;
                    tempCanvas.height = spriteHeight;
                    const tempCtx = tempCanvas.getContext('2d');
                    tempCtx.drawImage(img, 0, 0);
                    const imgData = tempCtx.getImageData(0, 0, spriteWidth, spriteHeight);
                    for (let j = 0; j < spriteHeight; j++) {
                        for (let i = 0; i < spriteWidth; i++) {
                            const index = (j * spriteWidth + i) * 4;
                            const r = imgData.data[index];
                            const g = imgData.data[index + 1];
                            const b = imgData.data[index + 2];
                            const a = imgData.data[index + 3];
                            if (a > 0) { // Прозрачные пиксели не отрисовываются
                                this.drawPixel(x + i, y + j, { r, g, b, a: 255 });
                            }
                        }
                    }
                    this.log(`LOAD_SPRITE: "${url}" загружен и отрисован.`);
                    this.updateViewer();
                    this.updateVRAMStatus();
                };
                img.onerror = () => {
                    this.log(`Ошибка: Не удалось загрузить спрайт с URL "${url}".`);
                };
            }

            logFunction(funcName) {
                // Логирование вызовов функций (если требуется)
            }

            setVariable(varName, expression) {
                try {
                    const value = eval(expression);
                    this.variables[varName] = value;
                    this.log(`SET_VARIABLE: ${varName} = ${value}`);
                } catch (error) {
                    this.log(`Ошибка при установке переменной "${varName}": ${error}`);
                }
            }

            getVariable(varName) {
                if (this.variables.hasOwnProperty(varName)) {
                    this.log(`GET_VARIABLE: ${varName} = ${this.variables[varName]}`);
                    return this.variables[varName];
                } else {
                    this.log(`Предупреждение: Переменная "${varName}" не определена.`);
                    return 0;
                }
            }

            defineFunction(funcName, commands) {
                this.functions[funcName] = commands;
                this.log(`FUNCTION: "${funcName}" определена с ${commands.length} командами.`);
            }

            async executeProgram() {
                let i = 0;
                while (i < this.programMemory.length) {
                    let cmd = this.programMemory[i];
                    let parts = cmd.split(' ').filter(part => part);
                    const instruction = parts[0].toUpperCase();

                    // Замена переменных
                    parts = this.replaceVariables(parts);

                    try {
                        switch (instruction) {
                            case 'DRAW':
                                // DRAW x y r g b
                                if (parts.length !== 6) throw `Недостаточно параметров для DRAW на строке ${i + 1}`;
                                const [dx, dy, dr, dg, db] = parts.slice(1).map(Number);
                                this.drawPixel(dx, dy, { r: dr, g: dg, b: db, a: 255 });
                                this.log(`DRAW: (${dx}, ${dy}) цвет (${dr}, ${dg}, ${db})`);
                                break;
                            case 'DRAW_LINE':
                                // DRAW_LINE x1 y1 x2 y2 r g b
                                if (parts.length !== 8) throw `Недостаточно параметров для DRAW_LINE на строке ${i + 1}`;
                                const [lx1, ly1, lx2, ly2, lr, lg, lb] = parts.slice(1).map(Number);
                                this.drawLine(lx1, ly1, lx2, ly2, { r: lr, g: lg, b: lb, a: 255 });
                                this.log(`DRAW_LINE: От (${lx1}, ${ly1}) до (${lx2}, ${ly2}) цвет (${lr}, ${lg}, ${lb})`);
                                break;
                            case 'FILL_RECT':
                                // FILL_RECT x y width height r g b
                                if (parts.length !== 8) throw `Недостаточно параметров для FILL_RECT на строке ${i + 1}`;
                                const [frx, fry, frw, frh, fr, fg, fb] = parts.slice(1).map(Number);
                                this.fillRect(frx, fry, frw, frh, { r: fr, g: fg, b: fb, a: 255 });
                                this.log(`FILL_RECT: (${frx}, ${fry}), Ширина: ${frw}, Высота: ${frh}, цвет (${fr}, ${fg}, ${fb})`);
                                break;
                            case 'DRAW_CIRCLE':
                                // DRAW_CIRCLE x y radius r g b
                                if (parts.length !== 7) throw `Недостаточно параметров для DRAW_CIRCLE на строке ${i + 1}`;
                                const [cx, cy, cradius, cr, cg, cb] = parts.slice(1).map(Number);
                                this.drawCircle(cx, cy, cradius, { r: cr, g: cg, b: cb, a: 255 });
                                this.log(`DRAW_CIRCLE: Центр (${cx}, ${cy}), Радиус: ${cradius}, цвет (${cr}, ${cg}, ${cb})`);
                                break;
                            case 'DRAW_ELLIPSE':
                                // DRAW_ELLIPSE x y radiusX radiusY r g b
                                if (parts.length !== 8) throw `Недостаточно параметров для DRAW_ELLIPSE на строке ${i + 1}`;
                                const [ex, ey, erX, erY, er, eg, eb] = parts.slice(1).map(Number);
                                this.drawEllipse(ex, ey, erX, erY, { r: er, g: eg, b: eb, a: 255 });
                                this.log(`DRAW_ELLIPSE: Центр (${ex}, ${ey}), Радиусы (${erX}, ${erY}), цвет (${er}, ${eg}, ${eb})`);
                                break;
                            case 'DRAW_SPLINE':
                                // DRAW_SPLINE x1 y1 x2 y2 x3 y3 r g b
                                if (parts.length !== 10) throw `Недостаточно параметров для DRAW_SPLINE на строке ${i + 1}`;
                                const [sx1, sy1, sx2, sy2, sx3, sy3, sr, sg, sb] = parts.slice(1).map(Number);
                                this.drawQuadraticSpline(sx1, sy1, sx2, sy2, sx3, sy3, { r: sr, g: sg, b: sb, a: 255 });
                                this.log(`DRAW_SPLINE: Точки (${sx1}, ${sy1}), (${sx2}, ${sy2}), (${sx3}, ${sy3}) цвет (${sr}, ${sg}, ${sb})`);
                                break;
                            case 'DRAW_TRIANGLE':
                                // DRAW_TRIANGLE x1 y1 x2 y2 x3 y3 r g b
                                if (parts.length !== 10) throw `Недостаточно параметров для DRAW_TRIANGLE на строке ${i + 1}`;
                                const [tx1, ty1, tx2, ty2, tx3, ty3, tr, tg, tb] = parts.slice(1).map(Number);
                                this.drawTriangle(tx1, ty1, tx2, ty2, tx3, ty3, { r: tr, g: tg, b: tb, a: 255 });
                                this.log(`DRAW_TRIANGLE: Точки (${tx1}, ${ty1}), (${tx2}, ${ty2}), (${tx3}, ${ty3}) цвет (${tr}, ${tg}, ${tb})`);
                                break;
                            case 'CLEAR':
                                // CLEAR r g b
                                if (parts.length !== 4) throw `Недостаточно параметров для CLEAR на строке ${i + 1}`;
                                const [clr, clg, clb] = parts.slice(1).map(Number);
                                this.clearScreen({ r: clr, g: clg, b: clb, a: 255 });
                                this.log(`CLEAR: цвет (${clr}, ${clg}, ${clb})`);
                                break;
                            case 'SET_VARIABLE':
                                // SET_VARIABLE varName value_expression
                                if (parts.length < 3) throw `Недостаточно параметров для SET_VARIABLE на строке ${i + 1}`;
                                const varName = parts[1];
                                const expression = parts.slice(2).join(' ');
                                this.setVariable(varName, expression);
                                break;
                            case 'GET_VARIABLE':
                                // GET_VARIABLE varName
                                if (parts.length !== 2) throw `Недостаточно параметров для GET_VARIABLE на строке ${i + 1}`;
                                const getVarName = parts[1];
                                const varValue = this.getVariable(getVarName);
                                break;
                            case 'VERTEX_SHADER':
                                // VERTEX_SHADER code
                                if (parts.length < 2) throw `Недостаточно параметров для VERTEX_SHADER на строке ${i + 1}`;
                                const vertexCode = parts.slice(1).join(' ');
                                this.setShader('VERTEX_SHADER', vertexCode);
                                break;
                            case 'FRAGMENT_SHADER':
                                // FRAGMENT_SHADER code
                                if (parts.length < 2) throw `Недостаточно параметров для FRAGMENT_SHADER на строке ${i + 1}`;
                                const fragmentCode = parts.slice(1).join(' ');
                                this.setShader('FRAGMENT_SHADER', fragmentCode);
                                break;
                            case 'USE_SHADERS':
                                // USE_SHADERS true/false
                                if (parts.length !== 2) throw `Недостаточно параметров для USE_SHADERS на строке ${i + 1}`;
                                this.useShaders = parts[1].toUpperCase() === 'TRUE';
                                this.log(`USE_SHADERS: ${this.useShaders}`);
                                break;
                            case 'FUNCTION':
                                // FUNCTION functionName
                                if (parts.length !== 2) throw `Недостаточно параметров для FUNCTION на строке ${i + 1}`;
                                const funcName = parts[1];
                                this.functions[funcName] = [];
                                i++;
                                while (i < this.programMemory.length && this.programMemory[i].toUpperCase() !== 'END_FUNCTION') {
                                    this.functions[funcName].push(this.programMemory[i]);
                                    i++;
                                }
                                if (i === this.programMemory.length) {
                                    throw `Не найдено END_FUNCTION для FUNCTION "${funcName}"`;
                                }
                                this.log(`FUNCTION: "${funcName}" определена с ${this.functions[funcName].length} командами.`);
                                break;
                            case 'CALL':
                                // CALL functionName
                                if (parts.length !== 2) throw `Недостаточно параметров для CALL на строке ${i + 1}`;
                                const callFuncName = parts[1];
                                await this.callFunction(callFuncName);
                                break;
                            case 'CALL_PROCEDURE':
                                // CALL_PROCEDURE procedureName
                                if (parts.length !== 2) throw `Недостаточно параметров для CALL_PROCEDURE на строке ${i + 1}`;
                                const callProcName = parts[1];
                                await this.callFunction(callProcName); // Используем функции как процедуры
                                break;
                            case 'PROCEDURE':
                                // PROCEDURE procedureName
                                if (parts.length !== 2) throw `Недостаточно параметров для PROCEDURE на строке ${i + 1}`;
                                const procName = parts[1];
                                this.functions[procName] = [];
                                i++;
                                while (i < this.programMemory.length && this.programMemory[i].toUpperCase() !== 'END_PROCEDURE') {
                                    this.functions[procName].push(this.programMemory[i]);
                                    i++;
                                }
                                if (i === this.programMemory.length) {
                                    throw `Не найдено END_PROCEDURE для PROCEDURE "${procName}"`;
                                }
                                this.log(`PROCEDURE: "${procName}" определена с ${this.functions[procName].length} командами.`);
                                break;
                            case 'LOOP':
                                // LOOP count
                                if (parts.length !== 2) throw `Недостаточно параметров для LOOP на строке ${i + 1}`;
                                const count = parseInt(parts[1], 10);
                                if (isNaN(count) || count <= 0) throw `Неверный параметр для LOOP на строке ${i + 1}`;
                                this.log(`LOOP: Начало цикла ${count} раз(а) на строке ${i + 1}`);
                                const loopCommands = [];
                                i++;
                                while (i < this.programMemory.length && this.programMemory[i].toUpperCase() !== 'END_LOOP') {
                                    loopCommands.push(this.programMemory[i]);
                                    i++;
                                }
                                if (i === this.programMemory.length) {
                                    throw `Не найдено END_LOOP для LOOP на строке ${i + 1}`;
                                }
                                for (let l = 0; l < count; l++) {
                                    this.log(`LOOP: Итерация ${l + 1} из ${count}`);
                                    await this.executeCommands(loopCommands);
                                }
                                break;
                            case 'WAIT':
                                // WAIT milliseconds
                                if (parts.length !== 2) throw `Недостаточно параметров для WAIT на строке ${i + 1}`;
                                const ms = parseInt(parts[1], 10);
                                if (isNaN(ms) || ms < 0) throw `Неверный параметр для WAIT на строке ${i + 1}`;
                                this.log(`WAIT: Пауза на ${ms} миллисекунд`);
                                await new Promise(resolve => setTimeout(resolve, ms));
                                break;
                            case 'LOAD_SPRITE':
                                // LOAD_SPRITE url x y
                                if (parts.length !== 4) throw `Недостаточно параметров для LOAD_SPRITE на строке ${i + 1}`;
                                const [url, sx, sy] = parts.slice(1);
                                this.loadSprite(url, parseInt(sx, 10), parseInt(sy, 10));
                                break;
                            default:
                                if (instruction === '') {
                                    // Пустая строка, пропускаем
                                } else {
                                    this.log(`Неизвестная инструкция "${instruction}" на строке ${i + 1}`);
                                }
                        }
                    } catch (error) {
                        this.log(`Ошибка: ${error}`);
                    }

                    i++;
                }

                // Обновление Canvas и VRAM Viewer
                this.updateCanvas();
                this.updateViewer();
                this.updateVRAMStatus();

                // Обновление WebGL (если используется и инициализирован)
                if (this.useShaders && this.gl) {
                    this.updateWebGL();
                }
            }

            async executeCommands(commands) {
                for (let cmd of commands) {
                    let parts = cmd.split(' ').filter(part => part);
                    const instruction = parts[0].toUpperCase();

                    // Замена переменных
                    parts = this.replaceVariables(parts);

                    try {
                        switch (instruction) {
                            case 'DRAW':
                                // DRAW x y r g b
                                if (parts.length !== 6) throw `Недостаточно параметров для DRAW на строке`;
                                const [dx, dy, dr, dg, db] = parts.slice(1).map(Number);
                                this.drawPixel(dx, dy, { r: dr, g: dg, b: db, a: 255 });
                                this.log(`DRAW: (${dx}, ${dy}) цвет (${dr}, ${dg}, ${db})`);
                                break;
                            case 'DRAW_LINE':
                                // DRAW_LINE x1 y1 x2 y2 r g b
                                if (parts.length !== 8) throw `Недостаточно параметров для DRAW_LINE на строке`;
                                const [lx1, ly1, lx2, ly2, lr, lg, lb] = parts.slice(1).map(Number);
                                this.drawLine(lx1, ly1, lx2, ly2, { r: lr, g: lg, b: lb, a: 255 });
                                this.log(`DRAW_LINE: От (${lx1}, ${ly1}) до (${lx2}, ${ly2}) цвет (${lr}, ${lg}, ${lb})`);
                                break;
                            case 'FILL_RECT':
                                // FILL_RECT x y width height r g b
                                if (parts.length !== 8) throw `Недостаточно параметров для FILL_RECT на строке`;
                                const [frx, fry, frw, frh, fr, fg, fb] = parts.slice(1).map(Number);
                                this.fillRect(frx, fry, frw, frh, { r: fr, g: fg, b: fb, a: 255 });
                                this.log(`FILL_RECT: (${frx}, ${fry}), Ширина: ${frw}, Высота: ${frh}, цвет (${fr}, ${fg}, ${fb})`);
                                break;
                            case 'DRAW_CIRCLE':
                                // DRAW_CIRCLE x y radius r g b
                                if (parts.length !== 7) throw `Недостаточно параметров для DRAW_CIRCLE на строке`;
                                const [cx, cy, cradius, cr, cg, cb] = parts.slice(1).map(Number);
                                this.drawCircle(cx, cy, cradius, { r: cr, g: cg, b: cb, a: 255 });
                                this.log(`DRAW_CIRCLE: Центр (${cx}, ${cy}), Радиус: ${cradius}, цвет (${cr}, ${cg}, ${cb})`);
                                break;
                            case 'DRAW_ELLIPSE':
                                // DRAW_ELLIPSE x y radiusX radiusY r g b
                                if (parts.length !== 8) throw `Недостаточно параметров для DRAW_ELLIPSE на строке`;
                                const [ex, ey, erX, erY, er, eg, eb] = parts.slice(1).map(Number);
                                this.drawEllipse(ex, ey, erX, erY, { r: er, g: eg, b: eb, a: 255 });
                                this.log(`DRAW_ELLIPSE: Центр (${ex}, ${ey}), Радиусы (${erX}, ${erY}), цвет (${er}, ${eg}, ${eb})`);
                                break;
                            case 'DRAW_SPLINE':
                                // DRAW_SPLINE x1 y1 x2 y2 x3 y3 r g b
                                if (parts.length !== 10) throw `Недостаточно параметров для DRAW_SPLINE на строке`;
                                const [sx1, sy1, sx2, sy2, sx3, sy3, sr, sg, sb] = parts.slice(1).map(Number);
                                this.drawQuadraticSpline(sx1, sy1, sx2, sy2, sx3, sy3, { r: sr, g: sg, b: sb, a: 255 });
                                this.log(`DRAW_SPLINE: Точки (${sx1}, ${sy1}), (${sx2}, ${sy2}), (${sx3}, ${sy3}) цвет (${sr}, ${sg}, ${sb})`);
                                break;
                            case 'DRAW_TRIANGLE':
                                // DRAW_TRIANGLE x1 y1 x2 y2 x3 y3 r g b
                                if (parts.length !== 10) throw `Недостаточно параметров для DRAW_TRIANGLE на строке`;
                                const [tx1, ty1, tx2, ty2, tx3, ty3, tr, tg, tb] = parts.slice(1).map(Number);
                                this.drawTriangle(tx1, ty1, tx2, ty2, tx3, ty3, { r: tr, g: tg, b: tb, a: 255 });
                                this.log(`DRAW_TRIANGLE: Точки (${tx1}, ${ty1}), (${tx2}, ${ty2}), (${tx3}, ${ty3}) цвет (${tr}, ${tg}, ${tb})`);
                                break;
                            case 'CLEAR':
                                // CLEAR r g b
                                if (parts.length !== 4) throw `Недостаточно параметров для CLEAR на строке`;
                                const [clr, clg, clb] = parts.slice(1).map(Number);
                                this.clearScreen({ r: clr, g: clg, b: clb, a: 255 });
                                this.log(`CLEAR: цвет (${clr}, ${clg}, ${clb})`);
                                break;
                            case 'SET_VARIABLE':
                                // SET_VARIABLE varName value_expression
                                if (parts.length < 3) throw `Недостаточно параметров для SET_VARIABLE на строке`;
                                const setVarName = parts[1];
                                const expression = parts.slice(2).join(' ');
                                this.setVariable(setVarName, expression);
                                break;
                            case 'GET_VARIABLE':
                                // GET_VARIABLE varName
                                if (parts.length !== 2) throw `Недостаточно параметров для GET_VARIABLE на строке`;
                                const getVarName = parts[1];
                                const varValue = this.getVariable(getVarName);
                                break;
                            case 'VERTEX_SHADER':
                                // VERTEX_SHADER code
                                if (parts.length < 2) throw `Недостаточно параметров для VERTEX_SHADER на строке`;
                                const vertexCode = parts.slice(1).join(' ');
                                this.setShader('VERTEX_SHADER', vertexCode);
                                break;
                            case 'FRAGMENT_SHADER':
                                // FRAGMENT_SHADER code
                                if (parts.length < 2) throw `Недостаточно параметров для FRAGMENT_SHADER на строке`;
                                const fragmentCode = parts.slice(1).join(' ');
                                this.setShader('FRAGMENT_SHADER', fragmentCode);
                                break;
                            case 'USE_SHADERS':
                                // USE_SHADERS true/false
                                if (parts.length !== 2) throw `Недостаточно параметров для USE_SHADERS на строке`;
                                this.useShaders = parts[1].toUpperCase() === 'TRUE';
                                this.log(`USE_SHADERS: ${this.useShaders}`);
                                break;
                            case 'FUNCTION':
                                // FUNCTION functionName
                                if (parts.length !== 2) throw `Недостаточно параметров для FUNCTION на строке`;
                                const funcName = parts[1];
                                this.functions[funcName] = [];
                                i++;
                                while (i < this.programMemory.length && this.programMemory[i].toUpperCase() !== 'END_FUNCTION') {
                                    this.functions[funcName].push(this.programMemory[i]);
                                    i++;
                                }
                                if (i === this.programMemory.length) {
                                    throw `Не найдено END_FUNCTION для FUNCTION "${funcName}"`;
                                }
                                this.log(`FUNCTION: "${funcName}" определена с ${this.functions[funcName].length} командами.`);
                                break;
                            case 'CALL':
                                // CALL functionName
                                if (parts.length !== 2) throw `Недостаточно параметров для CALL на строке`;
                                const callFuncName = parts[1];
                                await this.callFunction(callFuncName);
                                break;
                            case 'CALL_PROCEDURE':
                                // CALL_PROCEDURE procedureName
                                if (parts.length !== 2) throw `Недостаточно параметров для CALL_PROCEDURE на строке`;
                                const callProcName = parts[1];
                                await this.callFunction(callProcName); // Используем функции как процедуры
                                break;
                            case 'PROCEDURE':
                                // PROCEDURE procedureName
                                if (parts.length !== 2) throw `Недостаточно параметров для PROCEDURE на строке`;
                                const procName = parts[1];
                                this.functions[procName] = [];
                                i++;
                                while (i < this.programMemory.length && this.programMemory[i].toUpperCase() !== 'END_PROCEDURE') {
                                    this.functions[procName].push(this.programMemory[i]);
                                    i++;
                                }
                                if (i === this.programMemory.length) {
                                    throw `Не найдено END_PROCEDURE для PROCEDURE "${procName}"`;
                                }
                                this.log(`PROCEDURE: "${procName}" определена с ${this.functions[procName].length} командами.`);
                                break;
                            case 'LOOP':
                                // LOOP count
                                if (parts.length !== 2) throw `Недостаточно параметров для LOOP на строке`;
                                const count = parseInt(parts[1], 10);
                                if (isNaN(count) || count <= 0) throw `Неверный параметр для LOOP на строке`;
                                this.log(`LOOP: Начало цикла ${count} раз(а) на строке`);
                                const loopCommands = [];
                                i++;
                                while (i < this.programMemory.length && this.programMemory[i].toUpperCase() !== 'END_LOOP') {
                                    loopCommands.push(this.programMemory[i]);
                                    i++;
                                }
                                if (i === this.programMemory.length) {
                                    throw `Не найдено END_LOOP для LOOP на строке`;
                                }
                                for (let l = 0; l < count; l++) {
                                    this.log(`LOOP: Итерация ${l + 1} из ${count}`);
                                    await this.executeCommands(loopCommands);
                                }
                                break;
                            case 'WAIT':
                                // WAIT milliseconds
                                if (parts.length !== 2) throw `Недостаточно параметров для WAIT на строке`;
                                const ms = parseInt(parts[1], 10);
                                if (isNaN(ms) || ms < 0) throw `Неверный параметр для WAIT на строке`;
                                this.log(`WAIT: Пауза на ${ms} миллисекунд`);
                                await new Promise(resolve => setTimeout(resolve, ms));
                                break;
                            case 'LOAD_SPRITE':
                                // LOAD_SPRITE url x y
                                if (parts.length !== 4) throw `Недостаточно параметров для LOAD_SPRITE на строке`;
                                const [url, sx, sy] = parts.slice(1);
                                this.loadSprite(url, parseInt(sx, 10), parseInt(sy, 10));
                                break;
                            default:
                                if (instruction === '') {
                                    // Пустая строка, пропускаем
                                } else {
                                    this.log(`Неизвестная инструкция "${instruction}"`);
                                }
                        }
                    } catch (error) {
                        this.log(`Ошибка: ${error}`);
                    }
                }

                async executeCommands(commands) {
                    for (let cmd of commands) {
                        let parts = cmd.split(' ').filter(part => part);
                        const instruction = parts[0].toUpperCase();

                        // Замена переменных
                        parts = this.replaceVariables(parts);

                        try {
                            switch (instruction) {
                                case 'DRAW':
                                    // DRAW x y r g b
                                    if (parts.length !== 6) throw `Недостаточно параметров для DRAW на строке`;
                                    const [dx, dy, dr, dg, db] = parts.slice(1).map(Number);
                                    this.drawPixel(dx, dy, { r: dr, g: dg, b: db, a: 255 });
                                    this.log(`DRAW: (${dx}, ${dy}) цвет (${dr}, ${dg}, ${db})`);
                                    break;
                                case 'DRAW_LINE':
                                    // DRAW_LINE x1 y1 x2 y2 r g b
                                    if (parts.length !== 8) throw `Недостаточно параметров для DRAW_LINE на строке`;
                                    const [lx1, ly1, lx2, ly2, lr, lg, lb] = parts.slice(1).map(Number);
                                    this.drawLine(lx1, ly1, lx2, ly2, { r: lr, g: lg, b: lb, a: 255 });
                                    this.log(`DRAW_LINE: От (${lx1}, ${ly1}) до (${lx2}, ${ly2}) цвет (${lr}, ${lg}, ${lb})`);
                                    break;
                                case 'FILL_RECT':
                                    // FILL_RECT x y width height r g b
                                    if (parts.length !== 8) throw `Недостаточно параметров для FILL_RECT на строке`;
                                    const [frx, fry, frw, frh, fr, fg, fb] = parts.slice(1).map(Number);
                                    this.fillRect(frx, fry, frw, frh, { r: fr, g: fg, b: fb, a: 255 });
                                    this.log(`FILL_RECT: (${frx}, ${fry}), Ширина: ${frw}, Высота: ${frh}, цвет (${fr}, ${fg}, ${fb})`);
                                    break;
                                case 'DRAW_CIRCLE':
                                    // DRAW_CIRCLE x y radius r g b
                                    if (parts.length !== 7) throw `Недостаточно параметров для DRAW_CIRCLE на строке`;
                                    const [cx, cy, cradius, cr, cg, cb] = parts.slice(1).map(Number);
                                    this.drawCircle(cx, cy, cradius, { r: cr, g: cg, b: cb, a: 255 });
                                    this.log(`DRAW_CIRCLE: Центр (${cx}, ${cy}), Радиус: ${cradius}, цвет (${cr}, ${cg}, ${cb})`);
                                    break;
                                case 'DRAW_ELLIPSE':
                                    // DRAW_ELLIPSE x y radiusX radiusY r g b
                                    if (parts.length !== 8) throw `Недостаточно параметров для DRAW_ELLIPSE на строке`;
                                    const [ex, ey, erX, erY, er, eg, eb] = parts.slice(1).map(Number);
                                    this.drawEllipse(ex, ey, erX, erY, { r: er, g: eg, b: eb, a: 255 });
                                    this.log(`DRAW_ELLIPSE: Центр (${ex}, ${ey}), Радиусы (${erX}, ${erY}), цвет (${er}, ${eg}, ${eb})`);
                                    break;
                                case 'DRAW_SPLINE':
                                    // DRAW_SPLINE x1 y1 x2 y2 x3 y3 r g b
                                    if (parts.length !== 10) throw `Недостаточно параметров для DRAW_SPLINE на строке`;
                                    const [sx1, sy1, sx2, sy2, sx3, sy3, sr, sg, sb] = parts.slice(1).map(Number);
                                    this.drawQuadraticSpline(sx1, sy1, sx2, sy2, sx3, sy3, { r: sr, g: sg, b: sb, a: 255 });
                                    this.log(`DRAW_SPLINE: Точки (${sx1}, ${sy1}), (${sx2}, ${sy2}), (${sx3}, ${sy3}) цвет (${sr}, ${sg}, ${sb})`);
                                    break;
                                case 'DRAW_TRIANGLE':
                                    // DRAW_TRIANGLE x1 y1 x2 y2 x3 y3 r g b
                                    if (parts.length !== 10) throw `Недостаточно параметров для DRAW_TRIANGLE на строке`;
                                    const [tx1, ty1, tx2, ty2, tx3, ty3, tr, tg, tb] = parts.slice(1).map(Number);
                                    this.drawTriangle(tx1, ty1, tx2, ty2, tx3, ty3, { r: tr, g: tg, b: tb, a: 255 });
                                    this.log(`DRAW_TRIANGLE: Точки (${tx1}, ${ty1}), (${tx2}, ${ty2}), (${tx3}, ${ty3}) цвет (${tr}, ${tg}, ${tb})`);
                                    break;
                                case 'CLEAR':
                                    // CLEAR r g b
                                    if (parts.length !== 4) throw `Недостаточно параметров для CLEAR на строке`;
                                    const [clr, clg, clb] = parts.slice(1).map(Number);
                                    this.clearScreen({ r: clr, g: clg, b: clb, a: 255 });
                                    this.log(`CLEAR: цвет (${clr}, ${clg}, ${clb})`);
                                    break;
                                case 'SET_VARIABLE':
                                    // SET_VARIABLE varName value_expression
                                    if (parts.length < 3) throw `Недостаточно параметров для SET_VARIABLE на строке`;
                                    const setVarName = parts[1];
                                    const expression = parts.slice(2).join(' ');
                                    this.setVariable(setVarName, expression);
                                    break;
                                case 'GET_VARIABLE':
                                    // GET_VARIABLE varName
                                    if (parts.length !== 2) throw `Недостаточно параметров для GET_VARIABLE на строке`;
                                    const getVarName = parts[1];
                                    const varValue = this.getVariable(getVarName);
                                    break;
                                case 'VERTEX_SHADER':
                                    // VERTEX_SHADER code
                                    if (parts.length < 2) throw `Недостаточно параметров для VERTEX_SHADER на строке`;
                                    const vertexCode = parts.slice(1).join(' ');
                                    this.setShader('VERTEX_SHADER', vertexCode);
                                    break;
                                case 'FRAGMENT_SHADER':
                                    // FRAGMENT_SHADER code
                                    if (parts.length < 2) throw `Недостаточно параметров для FRAGMENT_SHADER на строке`;
                                    const fragmentCode = parts.slice(1).join(' ');
                                    this.setShader('FRAGMENT_SHADER', fragmentCode);
                                    break;
                                case 'USE_SHADERS':
                                    // USE_SHADERS true/false
                                    if (parts.length !== 2) throw `Недостаточно параметров для USE_SHADERS на строке`;
                                    this.useShaders = parts[1].toUpperCase() === 'TRUE';
                                    this.log(`USE_SHADERS: ${this.useShaders}`);
                                    break;
                                case 'FUNCTION':
                                    // FUNCTION functionName
                                    if (parts.length !== 2) throw `Недостаточно параметров для FUNCTION на строке`;
                                    const funcName = parts[1];
                                    this.functions[funcName] = [];
                                    i++;
                                    while (i < this.programMemory.length && this.programMemory[i].toUpperCase() !== 'END_FUNCTION') {
                                        this.functions[funcName].push(this.programMemory[i]);
                                        i++;
                                    }
                                    if (i === this.programMemory.length) {
                                        throw `Не найдено END_FUNCTION для FUNCTION "${funcName}"`;
                                    }
                                    this.log(`FUNCTION: "${funcName}" определена с ${this.functions[funcName].length} командами.`);
                                    break;
                                case 'CALL':
                                    // CALL functionName
                                    if (parts.length !== 2) throw `Недостаточно параметров для CALL на строке`;
                                    const callFuncName = parts[1];
                                    await this.callFunction(callFuncName);
                                    break;
                                case 'CALL_PROCEDURE':
                                    // CALL_PROCEDURE procedureName
                                    if (parts.length !== 2) throw `Недостаточно параметров для CALL_PROCEDURE на строке`;
                                    const callProcName = parts[1];
                                    await this.callFunction(callProcName); // Используем функции как процедуры
                                    break;
                                case 'PROCEDURE':
                                    // PROCEDURE procedureName
                                    if (parts.length !== 2) throw `Недостаточно параметров для PROCEDURE на строке`;
                                    const procName = parts[1];
                                    this.functions[procName] = [];
                                    i++;
                                    while (i < this.programMemory.length && this.programMemory[i].toUpperCase() !== 'END_PROCEDURE') {
                                        this.functions[procName].push(this.programMemory[i]);
                                        i++;
                                    }
                                    if (i === this.programMemory.length) {
                                        throw `Не найдено END_PROCEDURE для PROCEDURE "${procName}"`;
                                    }
                                    this.log(`PROCEDURE: "${procName}" определена с ${this.functions[procName].length} командами.`);
                                    break;
                                case 'LOOP':
                                    // LOOP count
                                    if (parts.length !== 2) throw `Недостаточно параметров для LOOP на строке`;
                                    const count = parseInt(parts[1], 10);
                                    if (isNaN(count) || count <= 0) throw `Неверный параметр для LOOP на строке`;
                                    this.log(`LOOP: Начало цикла ${count} раз(а)`);
                                    const loopCommands = [];
                                    i++;
                                    while (i < this.programMemory.length && this.programMemory[i].toUpperCase() !== 'END_LOOP') {
                                        loopCommands.push(this.programMemory[i]);
                                        i++;
                                    }
                                    if (i === this.programMemory.length) {
                                        throw `Не найдено END_LOOP для LOOP на строке`;
                                    }
                                    for (let l = 0; l < count; l++) {
                                        this.log(`LOOP: Итерация ${l + 1} из ${count}`);
                                        await this.executeCommands(loopCommands);
                                    }
                                    break;
                                case 'WAIT':
                                    // WAIT milliseconds
                                    if (parts.length !== 2) throw `Недостаточно параметров для WAIT на строке`;
                                    const ms = parseInt(parts[1], 10);
                                    if (isNaN(ms) || ms < 0) throw `Неверный параметр для WAIT на строке`;
                                    this.log(`WAIT: Пауза на ${ms} миллисекунд`);
                                    await new Promise(resolve => setTimeout(resolve, ms));
                                    break;
                                case 'LOAD_SPRITE':
                                    // LOAD_SPRITE url x y
                                    if (parts.length !== 4) throw `Недостаточно параметров для LOAD_SPRITE на строке`;
                                    const [url, sx, sy] = parts.slice(1);
                                    this.loadSprite(url, parseInt(sx, 10), parseInt(sy, 10));
                                    break;
                                default:
                                    if (instruction === '') {
                                        // Пустая строка, пропускаем
                                    } else {
                                        this.log(`Неизвестная инструкция "${instruction}"`);
                                    }
                            }
                        } catch (error) {
                            this.log(`Ошибка: ${error}`);
                        }
                    }

                    // Обновление Canvas и VRAM Viewer
                    this.updateCanvas();
                    this.updateViewer();
                    this.updateVRAMStatus();

                    // Обновление WebGL (если используется и инициализирован)
                    if (this.useShaders && this.gl) {
                        this.updateWebGL();
                    }
                }

                async callFunction(funcName) {
                    if (this.functions.hasOwnProperty(funcName)) {
                        this.log(`CALL: Вызов функции/процедуры "${funcName}"`);
                        await this.executeCommands(this.functions[funcName]);
                    } else {
                        this.log(`Ошибка: Функция/Процедура "${funcName}" не определена.`);
                    }
                }

                updateCanvas() {
                    const imageData = this.ctx.createImageData(this.width, this.height);
                    const data = imageData.data;

                    for (let i = 0; i < this.vramSize; i++) {
                        const pixel = this.vram[i];
                        data[i * 4] = (pixel >> 8) & 0xFF;    // R
                        data[i * 4 + 1] = (pixel >> 16) & 0xFF; // G
                        data[i * 4 + 2] = (pixel >> 24) & 0xFF; // B
                        data[i * 4 + 3] = (pixel & 0xFF);         // A
                    }

                    this.ctx.putImageData(imageData, 0, 0);
                }

                updateViewer() {
                    const scaleX = this.vramCanvas.width / this.width;
                    const scaleY = this.vramCanvas.height / this.height;
                    const imageData = this.vramCtx.createImageData(this.vramCanvas.width, this.vramCanvas.height);
                    const data = imageData.data;

                    for (let y = 0; y < this.vramCanvas.height; y++) {
                        for (let x = 0; x < this.vramCanvas.width; x++) {
                            const srcX = Math.floor(x / scaleX);
                            const srcY = Math.floor(y / scaleY);
                            const indexSrc = srcY * this.width + srcX;
                            const pixel = this.vram[indexSrc];
                            data[(y * this.vramCanvas.width + x) * 4] = (pixel >> 8) & 0xFF;    // R
                            data[(y * this.vramCanvas.width + x) * 4 + 1] = (pixel >> 16) & 0xFF; // G
                            data[(y * this.vramCanvas.width + x) * 4 + 2] = (pixel >> 24) & 0xFF; // B
                            data[(y * this.vramCanvas.width + x) * 4 + 3] = pixel & 0xFF;         // A
                        }
                    }

                    this.vramCtx.putImageData(imageData, 0, 0);
                }

                updateVRAMStatus() {
                    let used = 0;
                    for (let i = 0; i < this.vram.length; i++) {
                        if (this.vram[i] !== 0) used++;
                    }
                    this.vramStatusElement.innerText = `VRAM: ${used.toLocaleString()} / ${this.vramSize.toLocaleString()}`;
                }

                initWebGL() {
                    const canvas = document.getElementById('outputWebGL');
                    this.gl = canvas.getContext('webgl');
                    if (!this.gl) {
                        this.log('WebGL не поддерживается.');
                        this.useShaders = false;
                        return;
                    }

                    // Настройка шейдеров WebGL
                    const vertexShaderSource = `
                        attribute vec4 a_position;
                        attribute vec2 a_texCoord;
                        varying vec2 v_texCoord;

                        void main() {
                            gl_Position = a_position;
                            v_texCoord = a_texCoord;
                        }
                    `;
                    const fragmentShaderSource = `
                        precision mediump float;
                        varying vec2 v_texCoord;
                        uniform sampler2D u_texture;

                        void main() {
                            gl_FragColor = texture2D(u_texture, v_texCoord);
                        }
                    `;
                    this.vertexShaderWebGL = this.createShader(this.gl.VERTEX_SHADER, vertexShaderSource);
                    this.fragmentShaderWebGL = this.createShader(this.gl.FRAGMENT_SHADER, fragmentShaderSource);
                    this.programWebGL = this.createProgram(this.vertexShaderWebGL, this.fragmentShaderWebGL);

                    this.positionLocation = this.gl.getAttribLocation(this.programWebGL, 'a_position');
                    this.texCoordLocation = this.gl.getAttribLocation(this.programWebGL, 'a_texCoord');
                    this.textureLocation = this.gl.getUniformLocation(this.programWebGL, 'u_texture');

                    this.positionBufferWebGL = this.gl.createBuffer();
                    this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.positionBufferWebGL);
                    // Прямоугольник от -1 до 1 по обеим осям
                    this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array([
                        -1, -1,
                         1, -1,
                        -1,  1,
                        -1,  1,
                         1, -1,
                         1,  1,
                    ]), this.gl.STATIC_DRAW);

                    this.texCoordBufferWebGL = this.gl.createBuffer();
                    this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.texCoordBufferWebGL);
                    // Координаты текстуры от 0 до 1
                    this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array([
                        0, 0,
                        1, 0,
                        0, 1,
                        0, 1,
                        1, 0,
                        1, 1,
                    ]), this.gl.STATIC_DRAW);

                    // Создание текстуры
                    this.textureWebGL = this.gl.createTexture();
                    this.gl.bindTexture(this.gl.TEXTURE_2D, this.textureWebGL);
                    this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.NEAREST);
                    this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.NEAREST);
                    this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE);
                    this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE);
                }

                createShader(type, source) {
                    const shader = this.gl.createShader(type);
                    this.gl.shaderSource(shader, source);
                    this.gl.compileShader(shader);
                    const success = this.gl.getShaderParameter(shader, this.gl.COMPILE_STATUS);
                    if (success) {
                        return shader;
                    }
                    console.error(this.gl.getShaderInfoLog(shader));
                    this.gl.deleteShader(shader);
                }

                createProgram(vertexShader, fragmentShader) {
                    const program = this.gl.createProgram();
                    this.gl.attachShader(program, vertexShader);
                    this.gl.attachShader(program, fragmentShader);
                    this.gl.linkProgram(program);
                    const success = this.gl.getProgramParameter(program, this.gl.LINK_STATUS);
                    if (success) {
                        return program;
                    }
                    console.error(this.gl.getProgramInfoLog(program));
                    this.gl.deleteProgram(program);
                }

                updateWebGL() {
                    if (!this.gl) return;

                    // Обновление текстуры из VRAM
                    const imageDataArray = new Uint8Array(this.vram.buffer);
                    this.gl.bindTexture(this.gl.TEXTURE_2D, this.textureWebGL);
                    this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGBA, this.width, this.height, 0,
                                       this.gl.RGBA, this.gl.UNSIGNED_BYTE, imageDataArray);

                    // Рендеринг
                    this.gl.viewport(0, 0, this.gl.canvas.width, this.gl.canvas.height);
                    this.gl.clearColor(0, 0, 0, 0);
                    this.gl.clear(this.gl.COLOR_BUFFER_BIT);

                    this.gl.useProgram(this.programWebGL);

                    // Настройка позиционного буфера
                    this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.positionBufferWebGL);
                    this.gl.enableVertexAttribArray(this.positionLocation);
                    this.gl.vertexAttribPointer(this.positionLocation, 2, this.gl.FLOAT, false, 0, 0);

                    // Настройка буфера координат текстуры
                    this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.texCoordBufferWebGL);
                    this.gl.enableVertexAttribArray(this.texCoordLocation);
                    this.gl.vertexAttribPointer(this.texCoordLocation, 2, this.gl.FLOAT, false, 0, 0);

                    // Активируем текстуру
                    this.gl.activeTexture(this.gl.TEXTURE0);
                    this.gl.bindTexture(this.gl.TEXTURE_2D, this.textureWebGL);
                    this.gl.uniform1i(this.textureLocation, 0);

                    // Рисуем прямоугольник
                    this.gl.drawArrays(this.gl.TRIANGLES, 0, 6);
                }
            }

            window.addEventListener('DOMContentLoaded', () => {
                const canvas = document.getElementById('outputCanvas');
                const ctx = canvas.getContext('2d');
                const canvasWebGL = document.getElementById('outputWebGL');
                const gpuProgramTextarea = document.getElementById('gpuProgram');
                const runProgramButton = document.getElementById('runProgram');
                const clearCanvasButton = document.getElementById('clearCanvas');
                const saveProgramButton = document.getElementById('saveProgram');
                const loadProgramButton = document.getElementById('loadProgram');
                const toggleRenderModeButton = document.getElementById('toggleRenderMode');
                const showHelpButton = document.getElementById('showHelp');
                const closeHelpButton = document.getElementById('closeHelp');
                const logContent = document.getElementById('logContent');
                const vramCanvas = document.getElementById('vramCanvas');
                const vramCtx = vramCanvas.getContext('2d');
                const vramStatusElement = document.getElementById('vramStatus');
                const helpModal = document.getElementById('helpModal');

                // Инициализация CodeMirror
                const gpuProgramEditor = CodeMirror.fromTextArea(gpuProgramTextarea, {
                    mode: 'default',
                    lineNumbers: true,
                    theme: 'monokai',
                    autofocus: true,
                    indentUnit: 4,
                    tabSize: 4,
                    lineWrapping: true,
                    extraKeys: {"Ctrl-Space": "autocomplete"}
                });

                // Пример расширенной программы GPU
                const exampleProgram = `
// Пример расширенной программы GPU
CLEAR 10 10 10
FILL_RECT 150 100 300 200 0 128 255
DRAW_LINE 100 50 700 550 255 255 0
DRAW_CIRCLE 400 300 100 255 0 255

// Определение функции для рисования рамки
FUNCTION drawFrame
    FILL_RECT 0 0 800 10 255 255 255
    FILL_RECT 0 590 800 10 255 255 255
    FILL_RECT 0 0 10 600 255 255 255
    FILL_RECT 790 0 10 600 255 255 255
END_FUNCTION

// Вызов функции
CALL drawFrame

// Использование переменных
SET_VARIABLE x 100
SET_VARIABLE y 100

// Цикл для анимации
LOOP 50
    FILL_RECT {x} {y} 50 50 255 0 0
    WAIT 50
    CLEAR 10 10 10
    SET_VARIABLE x {x} + 5
END_LOOP

// Загрузка спрайта
LOAD_SPRITE https://i.imgur.com/4aiwY6A.png 300 200
                `;
                gpuProgramEditor.setValue(exampleProgram.trim());

                // Инициализация эмулятора GPU
                const gpu = new GPUEmulator(
                    canvas.width, 
                    canvas.height, 
                    ctx, 
                    logContent, 
                    vramCanvas, 
                    vramCtx, 
                    vramStatusElement
                );

                // Функция для очистки Canvas и лога
                function clearCanvasAndLog() {
                    gpu.clearScreen({ r: 0, g: 0, b: 0, a: 255 });
                    gpu.log('Canvas очищен.');
                    logContent.innerHTML = '';
                    gpu.updateCanvas();
                    gpu.updateViewer();
                    gpu.updateVRAMStatus();
                    if (gpu.useShaders && gpu.gl) {
                        gpu.updateWebGL();
                    }
                }

                // Обработчик выполнения программы
                runProgramButton.addEventListener('click', async () => {
                    const program = gpuProgramEditor.getValue();
                    gpu.loadProgram(program);
                    await gpu.executeProgram();
                });

                // Обработчик очистки Canvas
                clearCanvasButton.addEventListener('click', () => {
                    clearCanvasAndLog();
                    gpu.log('Canvas и лог очищены.');
                });

                // Обработчик сохранения программы
                saveProgramButton.addEventListener('click', () => {
                    const program = gpuProgramEditor.getValue();
                    const blob = new Blob([program], { type: 'text/plain' });
                    const url = URL.createObjectURL(blob);
                    const a = document.createElement('a');
                    a.href = url;
                    a.download = 'gpu_program.txt';
                    a.click();
                    URL.revokeObjectURL(url);
                    gpu.log('Программа сохранена как "gpu_program.txt"');
                });

                // Обработчик загрузки программы
                loadProgramButton.addEventListener('click', () => {
                    const input = document.createElement('input');
                    input.type = 'file';
                    input.accept = '.txt';
                    input.onchange = e => {
                        const file = e.target.files[0];
                        if (!file) return;
                        const reader = new FileReader();
                        reader.onload = function(event) {
                            gpuProgramEditor.setValue(event.target.result);
                            gpu.log(`Программа "${file.name}" загружена.`);
                        };
                        reader.readAsText(file);
                    };
                    input.click();
                });

                // Обработчик переключения режима рендеринга
                toggleRenderModeButton.addEventListener('click', () => {
                    gpu.useShaders = !gpu.useShaders;
                    if (gpu.useShaders) {
                        if (!gpu.gl) {
                            gpu.initWebGL();
                            if (!gpu.gl) {
                                // Если WebGL не инициализирован, отключаем режим шейдеров
                                gpu.useShaders = false;
                                toggleRenderModeButton.textContent = 'Включить WebGL';
                                return;
                            }
                        }
                        toggleRenderModeButton.textContent = 'Отключить WebGL';
                        canvas.style.display = 'none';
                        canvasWebGL.style.display = 'block';
                        gpu.log('Рендеринг переключён на WebGL.');
                        gpu.updateWebGL();
                    } else {
                        toggleRenderModeButton.textContent = 'Включить WebGL';
                        canvas.style.display = 'block';
                        canvasWebGL.style.display = 'none';
                        gpu.useShaders = false;
                        gpu.log('Рендеринг переключён на Canvas.');
                        gpu.updateCanvas();
                    }
                });

                // Обработчик отображения помощи
                showHelpButton.addEventListener('click', () => {
                    helpModal.style.display = 'block';
                });

                // Обработчик закрытия помощи
                closeHelpButton.addEventListener('click', () => {
                    helpModal.style.display = 'none';
                });

                // Закрытие модального окна при клике вне его
                window.addEventListener('click', (event) => {
                    if (event.target === helpModal) {
                        helpModal.style.display = 'none';
                    }
                });
            });
    </script>
</body>
</html>