Install the kit, draw a first frame and host it as a scene, in a project of your own.
TypeGPU Kit is a set of GPU modules on TypeGPU. Each borrows your root and records into your passes. You create the device, run the loop and submit the commands. This page sets up a web project, draws a frame and hands it to a host.
In a Vite project, install the kit, TypeGPU and its noise and colour packages, then Vite, the TypeGPU bundler plugin, tsover in place of TypeScript, and WebGPU’s types:
The script asks TypeGPU for a root, its handle on the GPU. A surface configures the canvas for the root and keeps its drawing buffer the size of its layout. A fragment function colours every pixel of a triangle that covers the canvas, and a frame loop gives each frame an encoder and submits it when your function returns:
The frame this section draws. Turn on Glow to add a bloom.
TgpuRoot.createUniform<d.F32>(typeSchema: d.F32, initial?: number |((buffer:TgpuBuffer<NoInfer<d.F32>>)=>void)|undefined): TgpuUniform<d.F32>(+1 overload)
Allocates memory on the GPU, allows passing data between host and shader.
Read-only on the GPU, optimized for small data. For a general-purpose buffer,
use
TgpuRoot.createBuffer
.
@param ― typeSchema The type of data that this buffer will hold.
@param ― initial Either initial value of the buffer, or an initializer to execute on the mapped buffer. (optional)
createUniform(
import d
d.
constf32:d.F32
export f32
A schema that represents a 32-bit float value. (equivalent to f32 in WGSL)
Records commands for submission after the recorder returns. submit() replaces this encoder.
Read it at each call instead of keeping it, and let the frame submit it.
Runs the loop on each scheduled frame. Time advances by at most maxDt per frame, never steps
back, and stops while the surface is paused. Destroying the animation keeps the loop alive.
Another animation on the same loop continues from its recorded time. A frame error stops the
animation.
@param ― loop the loop to run on each unpaused frame. Continues from its seconds if it ran before
@returns ― an animation you destroy to stop the frames
animate(
constloop:frames.Frames
loop);
Start Vite, then open the page in a WebGPU browser:
Move what you draw into a scene: a file that exports createScene(root, surface) and returns its frame and destroy. A scene holds no loop or page code, so it runs unchanged on the web, on React Native and in a test.
src/scene.ts
importtype{
(alias)interfaceFrame
importFrame
Represents one frame being recorded. Each run creates a separate object, so modules can
compare frames by identity.
Frame,
(alias)interfaceSurface
importSurface
Provides a destination for frames, such as a canvas from web.surface or native.surface, or a
texture from offscreenSurface in a test. Pass the frame to view for code that works with
every destination.
Provides a destination for frames, such as a canvas from web.surface or native.surface, or a
texture from offscreenSurface in a test. Pass the frame to view for code that works with
every destination.
Surface){
// The uniform, fragment function and pipeline from index.ts
return{
functionframe(frame:Frame):void
frame(
frame: Frame
frame:
(alias)interfaceFrame
importFrame
Represents one frame being recorded. Each run creates a separate object, so modules can
compare frames by identity.
Frame){
// The body of the frame loop from index.ts
},
functiondestroy():void
destroy(){},
};
}
web.host creates the root, surface and loop, runs the scene and reports its first error. Its handle’s destroy() tears them down in order:
Runs a scene on a canvas with a root, surface, frame loop and animation. destroy tears them
down in order. Use send to control the scene or onFrame to read it. If scene options are
optional, call host(createScene, { canvas }). Throws if both device and root are supplied.
@param ― createScene the scene file's createScene
@param ― options the scene's third argument
@param ― hosting the canvas, the device or root, and what the page runs beside the scene
@returns ― a hosted scene you send closures to and destroy
The packages ship built JavaScript with their 'use gpu' functions already transformed, and declarations. The plugin transforms your own 'use gpu' functions. Vector operators in them, a * b, type-check only under tsover, TypeGPU’s fork of TypeScript. It replaces typescript, so a project on another TypeScript version moves to tsover’s.
A few entries need optional peers:
Import
Needs
text’s font baker, @typegpu/kit/bake and typegpu-kit-bake-font
@pmndrs/glyph and Node 24.2 or later, at build time. On React Native, add rgba to Metro’s assetExts for the atlas.
@typegpu/kit/native, /runtimes, /scenes and /scenes/react
React, React Native, react-native-webgpu 0.20.0 or later and react-native-worklets 0.13.0 or later.
The packages ship built JavaScript, so leave them to Vite’s dependency prebundling, and add no resolve.dedupe. Excluding them from optimizeDeps while TypeGPU stays prebundled loads two copies of TypeGPU: the page warns “Found duplicate TypeGPU version”, then fails on its first schema.
A hosted scene runs on a worklet runtime, which needs react-native-worklets’ Bundle Mode: a worklet’s named imports load again on the runtime it runs on. This setup targets Expo 58 with React Native 0.88.1, react-native-worklets 0.13.1 and react-native-webgpu 0.21.1.
babel.config.js
constworklets={
bundleMode:true,
strictGlobal:true,
importForwarding:{
// Packages a worklet imports from, with their subpaths, loaded again on the runtime it runs on.
Bundle Mode needs two Metro patches. The kit ships them in node_modules/@typegpu/kit/patches/. With pnpm, copy them into the project and list them in pnpm-workspace.yaml, then install again:
With npm or Yarn, use the patch-package or Yarn versions of the same patches from react-native-worklets’ Bundle Mode patches, which also cover other Metro versions.
moduleNames lists every package your worklets import from; each entry covers the package’s subpaths too. relativePaths lists the kit and the file of your scene worklets, the one-line wrappers a hosted scene takes off the JS thread. Entries match folder names inside packages too, so a bare src forwards Reanimated’s own imports and crashes its animations on the UI runtime.
relativePaths entries match the path after the last node_modules. '@typegpu/kit' matches the kit installed from npm.
Import 'react-native-webgpu' first in index.ts. Bundle Mode turns on inline requires, so an import further down installs navigator.gpu only when first used.
Import kit subpaths on React Native, such as @typegpu/kit/frames: Metro keeps every file it reaches.
The patches are for Expo 58’s versions; metro is the one inside @expo/metro. Both are worklets’ own workarounds for Bundle Mode. Without the metro patch the bundle fails with “Failed to get the SHA-1” for a file in react-native-worklets/.worklets; the metro-runtime patch carries Fast Refresh to the worklet runtimes, in development.
The surface page draws the same first frame on a React Native canvas, and Platforms lists each platform’s requirements.
The kit ships a guide for coding agents, the skill skills/typegpu-kit/SKILL.md. It lists the kit’s rules, such as one encoder per frame, uniforms split by when they change, fixed steps and @typegpu/noise, and links to these pages as Markdown in the package’s docs/, with every module’s contract and the examples’ source. The site serves each page as Markdown too, at its address with .md for the trailing slash, and lists them in llms.txt at the site’s root. These name the kit version they describe and send agents in a project with the kit installed to its docs/.
TanStack Intent points the project’s agent config at the skills its packages ship. Run it once: