Skip to content

Proposal: @lazyCompute compiling-time decorator for GPU Kernels in TypeScript #391

@yorkie

Description

@yorkie

Motivation

The goal of this proposal is to allow developers to write GPU kernels directly in TypeScript using a @lazyCompute decorator. The decorated functions will be compiled at build-time into GPU shader code (WGSL or GLSL) and executed on the GPU via runtime APIs such as WebGPU. This enables parallel computation directly from TypeScript while keeping the syntax familiar.

Syntax

@lazyCompute(options?)
function funcName(param1: Type1, param2: Type2, ...): ReturnType {
  // GPU-executable code
}
  • @lazyCompute marks the function as a GPU kernel.
  • options is an optional object with:
    • workgroupSize: number — Threads per GPU workgroup (default 64)
    • sharedMemory?: number — Shared memory in bytes

Supported Parameter Types

TypeScript Type Description WGSL Type GLSL Type
f32 32-bit float f32 float
f64 64-bit float f64 double (optional)
i32 32-bit signed integer i32 int
u32 32-bit unsigned integer u32 uint
Vec2 2D float vector vec2 vec2
Vec3 3D float vector vec3 vec3
Vec4 4D float vector vec4 vec4
Float32Array GPU buffer array array float[] / buffer
Int32Array GPU buffer array array int[] / buffer
Uint32Array GPU buffer array array uint[] / buffer

Note: GLSL arrays often require a fixed length at compile time; WGSL supports dynamic arrays and structs.

Function Body Limitations

  • Control flow: for, while, if, else
  • GPU built-ins: global_id.x/y/z, local_id.x/y/z, workgroup_id.x/y/z
  • Not allowed: async functions, dynamic typing, DOM or JS-specific APIs, variable-length array operations in GLSL.

Built-in Variables

Name Description WGSL GLSL
global_id Global thread index @Builtin(global_invocation_id) gl_GlobalInvocationID
local_id Thread index in workgroup @Builtin(local_invocation_id) gl_LocalInvocationID
workgroup_id Workgroup index @Builtin(workgroup_id) gl_WorkGroupID

Compilation Behavior

  1. Compile-time validation
  • Check parameter types
  • Validate kernel body syntax
  • Throw errors for unsupported types or operations
  1. Code generation
  • AST of the TS compute function is transformed into corresponding computation graph, then compiled to WGSL or GLSL at execution time
  • Shader files or inline strings are produced
  1. JS wrapper
  • Original TS function is replaced by a GPU call wrapper
  • Automatically maps buffers, dispatches the shader, and returns results

Example

TypeScript functions

@lazyCompute({ workgroupSize: 128 })
function vecAdd(a: Float32Array, b: Float32Array, out: Float32Array, n: i32) {
  let i = global_id.x;
  if (i < n) {
    out[i] = a[i] + b[i];
  }
}

WGSL output

@group(0) @binding(0) var<storage, read> a: array<f32>;
@group(0) @binding(1) var<storage, read> b: array<f32>;
@group(0) @binding(2) var<storage, read_write> out: array<f32>;

@compute @workgroup_size(128)
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
  let i = gid.x;
  if (i < n) {
    out[i] = a[i] + b[i];
  }
}

GLSL output

#version 450
layout(local_size_x = 128) in;

layout(set = 0, binding = 0) buffer A { float a[]; };
layout(set = 0, binding = 1) buffer B { float b[]; };
layout(set = 0, binding = 2) buffer Out { float out[]; };

void main() {
    uint i = gl_GlobalInvocationID.x;
    if (i < n) {
        out[i] = a[i] + b[i];
    }
}

Future Extensions

  • Multi-dimensional indices: global_id.xy, global_id.xyz
  • Shared memory and atomic operations
  • Graph composition and chaining
  • Automatic optimization of workgroup sizes and memory layout

Summary

@lazyCompute is a TypeScript compile-time DSL enabling GPU programming directly from TypeScript.
It allows developers to write GPU-executable code using familiar TS syntax, with SWC or custom transforms converting kernels to WGSL or GLSL shaders, and JS wrappers for runtime execution.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions