WebGPU без боли и с 25 КБ в бандле — разбираемся с vgpu от Vercel Labs

30 авг 2026
932
36
2
1 неделя

Давно я не встречал WebGPU-библиотеку, у которой есть бюджет на размер бандла, да ещё и проверяемый в CI. А тут именно так: полный экран с эффектом укладывается в 25 КБ gzipped, и если кто-то раздует этот лимит — сборка падает. Разбираемся, что за проект и зачем он рядовому фронтендеру.

Что это вообще такое

vgpu — TypeScript-библиотека для WebGPU от vercel-labs. Авторы описывают её как модульную и кросс-рантаймовую: один и тот же код работает в браузере, в headless-режиме под Node (через Dawn) и в тестах с мок-адаптером, где реальная видеокарта не нужна.

На момент написания у проекта 932 звезды и 36 форков, лицензия MIT. Развивается активно, судя по коммитам. WebGPU как API уже поддержан в Chrome и Edge, поэтому тема перестала быть экзотикой.

Кому это пригодится? Тому, кто рисует шейдеры, делает визуализации данных, генеративную графику или хочет запускать вычисления на GPU. И особенно тому, кто устал от того, что WebGPU-код в браузере и в тестах — это два разных мира.

Главные фишки

Шейдеры как TypeScript-модули

Моя любимая часть. .wgsl-файлы импортируются как обычные модули, причём с типами:

Реклама
import waveShader from "./wave.wgsl";

Импорты резолвятся на этапе сборки через типизированную рефлексию WGSL. Не нужен отдельный шаг кодогенерации, не надо вручную описывать binding'и и синхронизировать их с шейдером. Компилятор сам знает, какие имена, типы и раскладки буферов у вас в WGSL.

Есть и стандартная библиотека: пакет @vgpu/wgsl-std отдаёт готовые функции — шум, хеши, цвет, сэмплинг. Шейдер может экспортировать свои функции для других шейдеров, как в обычном коде:

import { hash2 } from "@vgpu/wgsl-std/hash";

export fn grain(uv: vec2f, time: f32) -> f32 {
  return hash2(uv * time).x;
}

Для тех, кто писал шейдеры методом копипасты кусков GLSL между проектами, это выглядит как разумная эволюция.

Один контекст вместо глобального состояния

init() возвращает единственный объект Gpu. Каждый вызов API — draw, effect, frame, surface — принимает его первым аргументом. Никакого скрытого глобального стейта.

Зачем это? Например, для тестов: хочется параллельно гонять несколько независимых GPU-контекстов, и с vgpu это просто ещё один вызов init(). А ещё такой стиль хорошо ложится на React strict mode и hot reload, где глобальные синглтоны регулярно ломают жизнь.

Быстрый пример из документации:

import { clock, init, effect, frameLoop, surface } from "vgpu";
import waveShader from "./wave.wgsl";

const gpu = await init();
const canvasSurface = surface(gpu, canvas, { dpr: [1, 2] });
const wave = effect(gpu, waveShader, { set: { speed: 2 } });

const time = clock(gpu);
frameLoop(gpu, (frame) => {
  wave.set({ time: time.time });
  frame.pass(canvasSurface, wave);
});

Обратите внимание на effect и set(): юниформы адресуются по именам из WGSL, а запись проходит сразу, без очередей. В цикле меняется только то, что реально изменилось.

Кросс-рантайм как базовая опция

Вот тут проект заметно отличается от конкурентов. Один публичный API, три рантайма:

  • браузер — то, что ожидаемо;
  • vgpu/node — headless-режим на бэкенде Dawn, для рендера на сервере или в CLI;
  • vgpu/mock — детерминированный мок-адаптер, с которым тесты не требуют GPU вообще.

Код в Node выглядит так:

import { draw, frame, init, target } from "vgpu/node";
import triangleShader from "./triangle.wgsl";

const gpu = await init();
const colorTarget = target(gpu, { size: [256, 256], format: "rgba8unorm" });
const triangle = draw(gpu, { shader: triangleShader });

frame(gpu, (f) => f.pass(colorTarget, triangle));
const pixels = await colorTarget.read();
gpu.dispose();

Смущает только одно: dispose() вызывается вручную. В браузере этого нет — там за вами убирает GC. Не критично, но помнить стоит.

Явные кадры вместо сцены-графа

frame(gpu, (f) => f.pass(target, effect)). Пассы, клиры и дроу-коллы — явные вызовы, никакого неявного состояния сцены. Кто имел дело с тяжеловесными 3D-фреймворками, оценит прозрачность: видно ровно то, что отправится на GPU.

Командная строка и агенты

Необычный поворот: проект явно рассчитан и на ИИ-агентов. Документация, галерея примеров и валидация шейдеров доступны прямо из CLI:

npx vgpu docs        # офлайн-документация
npx vgpu examples    # галерея примеров
npx vgpu check       # валидация шейдеров

Сайт vgpu.sh отдаёт agents.md и llms.txt для LLM, есть read-only API и даже MCP-эндпоинт. Можно подключить агента через npx vgpu mcp.

Зачем обычному разработчику MCP в графической библиотеке? Смею предположить: запрос «напиши мне шейдер с raymarching» сейчас падает не на человека, а на Claude Code или Cursor. И у vercel-labs есть все основания позаботиться о том, чтобы агент сделал всё правильно.

Из чего состоит монорепозиторий

Проект собран как монорепозиторий с чётким разделением пакетов:

  • vgpu — основной API: init, draw, compute, effect, frame, bundle, target, uniforms;
  • @vgpu/cli — команда vgpu с документами, check и doctor;
  • @vgpu/core — низкоуровневые обёртки над Device, Buffer, Texture, bind-группами;
  • @vgpu/wgsl — превращает .wgsl в JS-модули и резолвит импорты до бандлинга;
  • @vgpu/wgsl-std — стандартная библиотека для WGSL;
  • @vgpu/adapter-node и @vgpu/adapter-mock — адаптеры для Node и мока;
  • @vgpu/render — вспомогательные утилиты за пределами основного рендеринга.

Хочется отдельно похвалить подход к размеру: неиспользуемые декларации вырезаются до минификации, а бюджет в 25 КБ на полный fullscreen-эффект проверяется в CI. Для сравнения: many WebGL-библиотеки с похожим функционалом весят на порядок больше.

Где это пригодится

Судя по описанию и API, целевые сценарии такие:

  • Визуализация данных. Миллионы точек на GPU вместо долго рисующихся SVG-графиков.
  • Генеративная графика и шейдерные эксперименты. Быстрый цикл: написал WGSL, импортировал, увидел результат.
  • Рендер на сервере. vgpu/node позволяет генерить превьюшки и экспортировать кадры без браузера.
  • Тестирование графики. Мок-адаптер даёт детерминированный результат, CI не требует реальной видеокарты.
  • Нейросети и GPU-тензоры. GitHub-описание упоминает их, хотя в README подробностей маловато.

Минусы, куда без них

Честно скажу: проект молодой. 932 звезды — это интересно, но не массовое признание; API ещё может поменяться. Документация есть (vgpu.sh + офлайн через CLI), но полных руководств по продакшену, вероятно, пока нет. Если планируете что-то серьёзное, закладывайте время на чтение исходников — благо, они открыты.

Ещё нюанс: WebGPU по-прежнему недоступен в Safari до определённых версий и в старых браузерах, так что для широкого продакшена с fallback на WebGL vgpu сам по себе проблему не решает.

Стоит ли пробовать

Если вы пишете на TypeScript и хотите начать с WebGPU — да, попробуйте. Порог входа низкий:

pnpm add vgpu
pnpm add -D @webgpu/types

Дальше — Getting started, а для тех, кто хочет сразу правильно, — гайд по производительности, где разобраны инстансинг, ping-pong, MSAA и другие приёмы.

Кому особенно зайдёт:

  • фронтендерам, которым нужен GPU для визуализации или креативного кода;
  • авторам библиотек, которым важно тестировать рендер без железа;
  • тем, кто устал от магии тяжёлых 3D-фреймворков и хочет явного контроля;
  • разработчикам, работающим в паре с ИИ-агентами.

Проект бесплатный, под MIT. Начните с галереи примеров на vgpu.sh — глазами это обычно убедительнее, чем словами.

🍪 Мы используем файлы cookie и сервис аналитики Яндекс.Метрика, чтобы сайт работал лучше. Продолжая пользоваться devtrends.ru, вы соглашаетесь с обработкой данных согласно Политике конфиденциальности.