ralph-gpu

작성자: vercel

최소한의 WebGPU 셰이더 라이브러리로, 크리에이티브 코딩 및 실시간 그래픽을 위한 도구입니다. 전체 화면 패스, 파티클, 컴퓨트 셰이더, 렌더 타겟, 핑퐁 등을 제공합니다.

npx skills add https://github.com/vercel-labs/ralph-gpu --skill ralph-gpu

ralph-gpu

A minimal WebGPU shader library for creative coding and real-time graphics.

When to Use

Use this skill when:

  • Building WebGPU shader effects, creative coding projects, or real-time graphics
  • Working with fullscreen shader passes, particle systems, or compute shaders
  • Need guidance on ralph-gpu API, render targets, or WGSL shader patterns
  • Implementing GPU-accelerated simulations or visual effects

Installation

npm install ralph-gpu
# For TypeScript support:
npm install -D @webgpu/types

Core Concepts

ConceptDescription
gpuModule entry point for initialization
ctxGPU context — manages state and rendering
passFullscreen shader (fragment only, uses internal quad)
materialShader with custom vertex code (particles, geometry)
targetRender target (offscreen texture)
pingPongPair of render targets for iterative effects
computeCompute shader for GPU-parallel computation
storageStorage buffer for large data (particles, simulations)
samplerCustom texture sampler with explicit filtering/wrapping
textureLoad images, canvases, video, or raw data as GPU textures

Auto-Injected Globals

Every shader automatically has access to these uniforms:

struct Globals {
  resolution: vec2f,  // Current render target size in pixels
  time: f32,          // Seconds since init
  deltaTime: f32,     // Seconds since last frame
  frame: u32,         // Frame count since init
  aspect: f32,        // resolution.x / resolution.y
}
@group(0) @binding(0) var<uniform> globals: Globals;

Quick Start

import { gpu } from "ralph-gpu";

// Check support
if (!gpu.isSupported()) {
  console.error("WebGPU not supported");
  return;
}

// Initialize
const ctx = await gpu.init(canvas, { autoResize: true });

// Create fullscreen shader pass
const pass = ctx.pass(\`
  @fragment
  fn main(@builtin(position) pos: vec4f) -> @location(0) vec4f {
    let uv = pos.xy / globals.resolution;
    return vec4f(uv, sin(globals.time) * 0.5 + 0.5, 1.0);
  }
\`);

// Render loop
function frame() {
  pass.draw();
  requestAnimationFrame(frame);
}
frame();

API Overview

Context Creation

const ctx = await gpu.init(canvas, {
  autoResize?: boolean,  // Auto-handle canvas sizing (default: false)
  dpr?: number,          // Device pixel ratio
  debug?: boolean,       // Enable debug mode
  events?: {             // Event tracking
    enabled: boolean,
    types?: string[],
    historySize?: number
  }
});

Fullscreen Passes

// Simple mode (auto-generated bindings)
const pass = ctx.pass(wgslCode, {
  uTexture: someTarget,
  color: [1, 0, 0],
  intensity: 0.5
});
pass.set("intensity", 0.8);  // Update uniforms

// Manual mode (explicit bindings)
const pass = ctx.pass(wgslCode, {
  uniforms: {
    myValue: { value: 1.0 }
  }
});
pass.uniforms.myValue.value = 2.0;

Render Targets

const target = ctx.target(512, 512, {
  format?: "rgba8unorm" | "rgba16float" | "r16float" | "rg16float",
  filter?: "linear" | "nearest",
  wrap?: "clamp" | "repeat" | "mirror",
  usage?: "render" | "storage" | "both"
});

ctx.setTarget(target);  // Render to target
ctx.setTarget(null);    // Render to screen

Ping-Pong Buffers

const simulation = ctx.pingPong(128, 128, {
  format: "rgba16float"
});

// In render loop:
uniforms.inputTex.value = simulation.read;
ctx.setTarget(simulation.write);
processPass.draw();
simulation.swap();

Particles (Instanced Quads)

const particles = ctx.particles(1000, {
  shader: wgslCode,      // Full vertex + fragment shader
  bufferSize: 1000 * 16, // Buffer size in bytes
  blend: "additive"
});

particles.write(particleData);  // Float32Array
particles.draw();

Compute Shaders

const compute = ctx.compute(\`
  @compute @workgroup_size(64)
  fn main(@builtin(global_invocation_id) id: vec3<u32>) {
    // GPU computation
  }
\`);

compute.storage("buffer", storageBuffer);
compute.dispatch(Math.ceil(count / 64));

Storage Buffers

const buffer = ctx.storage(byteSize);
buffer.write(new Float32Array([...]));

// Bind to shader
pass.storage("dataBuffer", buffer);

Texture Loading

// From URL (async)
const tex = await ctx.texture("image.png");

// From canvas / video / ImageBitmap (sync)
const tex = ctx.texture(canvas);

// From raw pixel data (sync)
const tex = ctx.texture(new Uint8Array(data), { width: 256, height: 256 });

// Options
const tex = await ctx.texture("photo.jpg", {
  filter: "linear",     // "linear" | "nearest"
  wrap: "repeat",       // "clamp" | "repeat" | "mirror"
  format: "rgba8unorm", // GPU texture format
  flipY: true,          // Flip vertically on load
});

// Bind to shader (manual mode)
const pass = ctx.pass(shader, {
  uniforms: {
    uTex: { value: tex },  // .texture and .sampler auto-bound
  }
});

// Update from live source (canvas, video)
tex.update(videoElement);

// Clean up
tex.dispose();

Important Notes

WGSL Alignment: array<vec3f> has 16-byte stride, not 12. Always pad to 16 bytes:

// Correct: [x, y, z, 0.0] per element
const buffer = ctx.storage(count * 16);

Particle Rendering: Use instanced quads, not point-list (WebGPU points are always 1px)

Texture References: Target references stay valid after resize — no need to update uniforms

Screen Readback: Cannot read pixels from screen, only from render targets

Examples

Full working examples extracted from the docs app:

  • Simple Gradient — The simplest possible shader — map UV coordinates to colors. This creates a gradient from black (bottom-left) to cyan (top-right).
  • Animated Wave — A glowing sine wave with custom uniforms. The wave animates over time using globals.time.
  • Time-Based Color Cycling — A hypnotic pattern that cycles through colors over time. Combines time, distance, and angle for a mesmerizing effect.
  • Raymarching Sphere — A basic 3D sphere rendered using raymarching. This demonstrates how to create 3D shapes and lighting entirely within a fragment shader.
  • Perlin-style Noise — Layered fractional Brownian motion (fBm) noise. This technique is fundamental for generating procedural textures, terrain, and natural-looking patterns.
  • Metaballs — Organic-looking "blobs" that merge together based on an implicit surface. This effect uses a distance-based field and a threshold to create smooth blending.
  • Mandelbrot Set — The classic complex number fractal. This shader computes the set by iterating z = z² + c and mapping the escape time to vibrant colors.
  • Alien Planet — A procedurally generated alien world with atmospheric scattering and an orbiting moon. Uses raymarching with fBm noise for terrain detail.
  • Fluid Simulation — Real-time Navier-Stokes fluid simulation using ping-pong buffers, vorticity confinement, and pressure projection.
  • Triangle Particles — GPU-driven particle system with SDF-based physics. 30,000 particles spawn on triangle edges and flow along a signed distance field with chromatic aberration postprocessing.

Resources

vercel의 다른 스킬

benchmark-sandbox
vercel
Vercel Sandbox에서 vercel-plugin eval 시나리오를 로컬 WezTerm 패널 대신 실행합니다. Claude Code와 플러그인이 사전 설치된 임시 마이크로VM을 프로비저닝합니다.
official
emil-design-eng
vercel
이 스킬은 Emil Kowalski의 UI 폴리시, 컴포넌트 디자인, 애니메이션 결정, 그리고 소프트웨어를 훌륭하게 만드는 보이지 않는 세부 사항에 대한 철학을 인코딩합니다.
official
vercel-react-best-practices
vercel
Vercel Engineering의 React 및 Next.js 성능 최적화 가이드라인입니다. 이 스킬은 React/Next.js 코드를 작성, 검토 또는 리팩토링할 때 사용해야 합니다.
official
vercel-react-best-practices
vercel
Vercel Engineering의 React 및 Next.js 성능 최적화 가이드라인입니다. 이 스킬은 React/Next.js 코드를 작성, 검토 또는 리팩토링할 때 사용해야 합니다.
official
write-guide
vercel
점진적인 예제를 통해 실제 사용 사례를 가르치는 기술 가이드를 제작합니다. 개념은 독자가 필요로 할 때만 소개됩니다.
official
release
vercel
Vercel-plugin 릴리스 — 게이트 실행, 버전 업, 아티팩트 생성, 커밋 및 푸시. "릴리스", "배포", "버전 업 및 푸시", "릴리스 생성" 요청 시 사용.
official
deepsec
vercel
dev3000에서 체크아웃한 Vercel 프로젝트에 대해 DeepSec을 실행합니다. 원클릭 DeepSec 설정, 프로젝트 컨텍스트 부트스트래핑, 제한된 1차 처리 등에 사용합니다.
official
backport-pr
vercel
병합된 Next.js 풀 리퀘스트를 canary에서 next-16-2와 같은 이전 릴리스 브랜치로 백포트합니다. 사용자가 백포트, 체리픽 또는 열기를 요청할 때 사용합니다…
official