Limits the number of frames whose GPU work may be unfinished when the next frame starts.
OrbitControlsOptionsorbitControls · 6 fields
sensitivity?
number= 0.008, as cameras.turn
Sets rotation per dragged pixel, in radians.
zoomSpeed?
number= 0.001
Sets wheel zoom speed.
button?
'primary' | 'secondary'= 'primary'
Orbits with this mouse button.
pan?
boolean= false
Enables panning with the secondary button, or the middle one when it orbits, and with two fingers moving together.
page?
boolean= false, so the element handles every drag and wheel input
Allows page scrolling around an embedded view.
onChange?
() => void= none
Runs after each input that changes the goal, for views that draw on demand.
PointerOptionspointer · 7 fields
move?
PointerHandler= none
Runs as the pointer moves over the element, or anywhere while it holds a button down.
down?
PointerHandler= none
Runs as a button goes down on the element.
up?
PointerHandler= none
Runs as a button comes up, or as the browser cancels the pointer.
leave?
() => void= none
Runs as the pointer leaves the element with no button down.
zoom?
(by: number) => void= none
Runs as the wheel turns or two fingers pinch on the element, with the factor to scale a distance by, above 1 farther: e^(deltaY × 0.001) for the wheel, and the ratio of the fingers' last spread to the new one for a pinch.
page?
boolean= false, so the element takes every touch drag and wheel turn
Allows page scrolling around an embedded element: touch drags scroll the page instead of reaching move, and only the wheel with Ctrl or Command held zooms.
menu?
boolean= true
Shows the context menu on a secondary click.
HostOptionshost · 15 fields
canvas
HTMLCanvasElement
Supplies the canvas for the scene.
optionalFeatures?
Iterable<GPUFeatureName>= none
Requests these features when the adapter supports them, such as timestamp-query.
device?
GPUDevice= a device that the web host requests and destroys with the scene
Supplies a device that the host keeps alive.
root?
TgpuRoot= a root that the host creates on device and destroys with the scene
Supplies a root that the host keeps alive, so scenes can share it.
schedule?
Schedule | false= requestAnimationFrame, or display vsync on a React Native worker
FixedSize= the layout size multiplied by the capped pixel ratio, following layout changes
Fixes the drawing-buffer size before surface returns.
maxPixelRatio?
number= 2
Caps drawing-buffer pixels per CSS pixel unless size is set.
VideoOptionsvideo · 1 field
mirrored?
boolean= false
Flips every frame left to right, as a mirror shows a front camera.
owns
the canvas's configuration and a resize observer; a hosted scene also owns the surface ·its root and the device unless it was given them ·the scene's stage and what its `attach` returned
allocates
each frame
A view of the canvas's texture, which is new every frame; under paced, a promise of the frame's work; for video, an imported texture per read of a frame.
Raise the phone pixel-ratio cap to align drawing-buffer checks with the screen-pixel grid at 3×. The magnified view spans six CSS pixels; the full-canvas counts show 2.25 times as many pixels as at 2×.
A page lays out a canvas in CSS pixels, while its drawing buffer measures canvas.width by canvas.height device pixels. Layout, screen and zoom changes can make those sizes disagree, blurring or stretching the picture. A surface configures the canvas for your root and keeps the drawing buffer matched to its layout.
Records a frame into one encoder and submits once, with a clock. Borrows the root. The
synchronous recorder borrows each frame's encoder.
@submits ― always once a frame after your recorder returns, and again at each frame.submit()
@param ― record your frame, recorded into each frame's encoder
@returns ― a loop you run with each frame's time and destroy
create(
constroot:TgpuRoot
root,(
frame:frames.Frame
frame)=>{
const
constpass:TgpuRenderPass
pass=
frame:frames.Frame
frame.
Frame.encoder: TgpuCommandEncoder
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);// runs the loop at every animation frame
// react-native-webgpu requests implicit-device-synchronization for every device
Creates a react-native-webgpu canvas surface for presentation on the JS thread. Throws if the
canvas has no WebGPU context or the fixed size is invalid.
@param ― canvas the CanvasRef from a <Canvas ref>; its context's canvas holds the size
@param ― options.pixelRatio PixelRatio.get()
@returns ― a surface you resize, pause, resume and destroy
surface(
constroot:TgpuRoot
root,
constcanvas:native.Canvas
canvas,{
SurfaceOptions.pixelRatio: number
Sets the display pixel ratio from PixelRatio.get().
Resumes the surface and reconfigures its context with the same options. This recovers
drawables that can remain unavailable after a long stay in the background.
resume():
constsurface:native.Surface
surface.
Surface.pause(): void
Pauses frames while the app is in the background, where it must not submit GPU work.
Records a frame into one encoder and submits once, with a clock. Borrows the root. The
synchronous recorder borrows each frame's encoder.
@submits ― always once a frame after your recorder returns, and again at each frame.submit()
@param ― record your frame, recorded into each frame's encoder
@returns ― a loop you run with each frame's time and destroy
create(
constroot:TgpuRoot
root,(
frame:frames.Frame
frame)=>{
const
constpass:TgpuRenderPass
pass=
frame:frames.Frame
frame.
Frame.encoder: TgpuCommandEncoder
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,{
AnimateOptions.surface?:{
readonly paused: boolean;
}|undefined
Stops frames and elapsed time while paused is true. The first frame after resume() has a
dt of 0. On React Native, pass the canvas surface and pause it from AppState. On the web,
pause it from an IntersectionObserver or a pause menu. Without a surface, frames run until
the animation is destroyed. Default none.
surface});// runs no frames while the surface is paused
The drawing buffer uses the layout size multiplied by the screen’s pixel ratio, capped at maxPixelRatio, 2 by default. On a 3× phone, this shades 44% of the full-resolution pixels and uses less than half the memory for full-size targets.
pixelRatio is the capped number of drawing-buffer pixels per CSS pixel or point. Multiply point sizes by it for dots, hairlines and margins. A separately read screen ratio can exceed the cap.
maxPixelRatio caps the ratio but never raises it above the screen’s ratio. To render more pixels, draw into a target sized with targets.scaled(surface, 2) and filter it down. To use the same size on every screen, fix the size.
The size is clamped to the device’s maxTextureDimension2D.
For fewer pixels, or a resolution that changes while the game runs, render at a resolution below the surface.
flow-field65 536 particles, each steered by the Perlin noise under it.
This canvas hosts the flow field scene. The loupe shows drawing-buffer pixels one for one with screen pixels, up to a pixel ratio of 2. Point size is measured in drawing-buffer pixels.
A benchmark, GPU capture or offline render needs a fixed pixel size, such as 2560 × 1440. Pass size in pixels to set the drawing buffer before surface returns. Layout and pixel ratio changes leave it unchanged. The canvas’s CSS size still scales the image on screen. This benchmark steps frames by hand:
Configures a canvas for the root. Matches its drawing buffer to the layout size or the fixed
options.size. Throws if the fixed size is invalid.
@param ― canvas the canvas it configures and sizes
@returns ― a surface you draw into and destroy
surface(
constroot:TgpuRoot
root,
constcanvas:HTMLCanvasElement
canvas,{
SurfaceOptions.size?:web.FixedSize|undefined
Fixes the drawing-buffer size before surface returns. The canvas CSS size still scales it on screen. Default the layout size multiplied by
the capped pixel ratio, following layout changes.
Records a frame into one encoder and submits once, with a clock. Borrows the root. The
synchronous recorder borrows each frame's encoder.
@submits ― always once a frame after your recorder returns, and again at each frame.submit()
@param ― record your frame, recorded into each frame's encoder
@returns ― a loop you run with each frame's time and destroy
create(
constroot:TgpuRoot
root,(
frame:frames.Frame
frame)=>
constscene:{
frame(frame:Frame):void;
}
scene.
functionframe(frame:Frame):void
frame(
frame:frames.Frame
frame));
for(let
let i:number
i=0;
let i:number
i<600;
let i:number
i++)
constloop:frames.Frames
loop.
Frames.run(seconds: number): boolean
Records and submits one frame with a fresh Frame and encoder. Requires finite, nondecreasing
seconds. Throws for an invalid time, a nested frame or an asynchronous recorder. Returns
false if the loop is destroyed before or during recording. Runs all after-submit callbacks. If
any throw, the frame still counts and run rethrows their errors.
run(
let i:number
i/60);
await
constroot:TgpuRoot
root.
TgpuRoot.device: GPUDevice
The GPU device associated with this root.
device.
GPUDevice.queue: GPUQueue
The queue read-only property of the GPUDevice interface returns the primary GPUQueue for the device.
Returns a Promise that resolves once this queue finishes processing all the work submitted
up to this moment.
Resolution of this Promise implies the completion of
GPUBuffer#mapAsync
calls made prior to that call,
on
GPUBuffer
s last used exclusively on that queue.
onSubmittedWorkDone();
pixelRatio is the size’s pixelRatio, 1 unless you pass it, so what is measured in points comes out the same on every screen. maxPixelRatio doesn’t apply.
setSize(size) fixes a new size from the next view(), for a run at several resolutions; setSize(undefined) follows the layout again. web.host takes size too, and its page reaches setSize through send(({ surface }) => …).
A size that isn’t whole pixels from 1 to maxTextureDimension2D throws.
On React Native, native.surface and scenes.host take size too. resize then changes nothing until setSize(undefined), and setSize applies at once.
On the web, a ResizeObserver watches the canvas’s device-pixel box, the screen pixels it covers, so the drawing buffer matches the screen pixel for pixel. Without that box, the size is the CSS size times the ratio, rounded.
width and height report a size change immediately. The next view() applies it to the canvas in the frame where render targets rebuild through fit(). Deferring the canvas resize avoids clearing a frame already drawn.
view(frame) applies any pending size change and returns a view cached for the current canvas texture. Using surface.context directly as an attachment doesn’t apply pending sizes.
Use the Surface type from @typegpu/kit for code shared by both platforms and its tests. Pass the frame to view so React Native can present after submit.
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){
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){
const
constpass:TgpuRenderPass
pass=
frame: Frame
frame.
Frame.encoder: TgpuCommandEncoder
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.
With --disable-gpu-vsync --disable-frame-rate-limit, Chrome can schedule frames faster than the GPU finishes them. Use web.paced(queue) as schedule to bound queued work. It waits until at most inFlight frames remain, 2 by default, before scheduling another frame. Normal vsync needs no extra pacing.
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
Supplies animation frames. Use runtimes.vsync(worker) on a React Native worker runtime, or a
schedule you step by hand in a test. Default requestAnimationFrame.
Supplies animation frames that wait while inFlight frames remain unfinished on the GPU. Use as
animate's schedule when frame callbacks can outpace GPU work. Throws unless inFlight is an
integer above 0.
@param ― queue the device's queue, root.device.queue
@returns ― a schedule to give animate
paced(
constroot:TgpuRoot
root.
TgpuRoot.device: GPUDevice
The GPU device associated with this root.
device.
GPUDevice.queue: GPUQueue
The queue read-only property of the GPUDevice interface returns the primary GPUQueue for the device.
Follows the mouse, touch or pen on an element in the coordinates rayAt takes, 0 to 1 across
the element with +y down. Read the position each frame or take each move, press, release and
zoom. A button pressed on the element keeps the pointer until it comes up, so a drag continues
outside and its positions run past 0 and 1.
@param ― element what the pointer moves over, usually the canvas
@returns ― the pointer, which you destroy to remove the listeners
pointer(
constcanvas:HTMLCanvasElement
canvas,{
PointerOptions.down?:web.PointerHandler|undefined
Runs as a button goes down on the element. Read the button from event.button. Default none.
down(
x: number
x,
y: number
y,
event: PointerEvent
event){
if(
event: PointerEvent
event.
MouseEvent.button: number
The MouseEvent.button read-only property indicates which button was pressed or released on the mouse to trigger the event.
Writes the ray through a point of the surface into out, as ray does. x and y range from
0 to 1 across the surface with +y down, as pointer handlers receive them.
Finds where a ray, such as one from view.rayAt, meets the ground at height, such as the
ground under a pointer. A height function, such as a terrain's, is searched in growing steps
up to reach, then refined by halving the last step. Writes the point into out when given.
Allocates nothing.
@param ― ray an origin and a unit direction
@param ― height the y of a level plane, or of the ground at each x and z
@param ― out where the point goes
@returns ― the distance along the ray, or undefined for a ray that misses
hitHeight(
constray:{
origin:number[];
direction:number[];
}
ray,0,
constground:number[]
ground)!==
var undefined
undefined)
functionselect(point:number[]):void
select(
constground:number[]
ground);
},
});
// Each frame, the ground under the pointer
if(
constmouse:web.Pointer
mouse.
Pointer.over: boolean
Tells whether the pointer is over the element or holds a button down that began on it.
over){
constview:cameras.OrbitCamera
view.
CpuView.rayAt(x: number, y: number, out: {
readonly origin:cameras.Out3;
readonly direction: cameras.Out3;
}): void
Writes the ray through a point of the surface into out, as ray does. x and y range from
0 to 1 across the surface with +y down, as pointer handlers receive them.
rayAt(
constmouse:web.Pointer
mouse.
Pointer.x: number
Holds the last position from 0 to 1 across the element, +y down. Starts at 0.5.
x,
constmouse:web.Pointer
mouse.
Pointer.y: number
Holds the last position from 0 to 1 down the element, as x does.
Finds where a ray, such as one from view.rayAt, meets the ground at height, such as the
ground under a pointer. A height function, such as a terrain's, is searched in growing steps
up to reach, then refined by halving the last step. Writes the point into out when given.
Allocates nothing.
@param ― ray an origin and a unit direction
@param ― height the y of a level plane, or of the ground at each x and z
@param ― out where the point goes
@returns ― the distance along the ray, or undefined for a ray that misses
hitHeight(
constray:{
origin:number[];
direction:number[];
}
ray,0,
constground:number[]
ground);
}
x and y run from 0 to 1 across the element with +y down, as rayAt takes them and projectAt writes them. Read them each frame, or take them in move, down and up.
zoom(by) runs as the wheel turns, with edeltaY·0.001, and as two fingers pinch, with the ratio of their last spread to the new one. Multiply a distance by by, which is above 1 farther.
A press keeps the pointer until its button comes up, so a drag continues outside the element, with positions past 0 and 1. up also runs when the browser cancels a pointer.
over is true while the pointer is over the element or holds a button pressed on it. A finger is over only while it touches. buttons holds the buttons down, as PointerEvent.buttons does.
It sets the element’s touch-action to none, or pan-y with page: true so touch drags scroll the page and only the wheel with Ctrl or ⌘ held zooms. menu: false keeps the context menu shut for drags with the secondary button.
destroy(), or [Symbol.dispose], removes the listeners and restores touch-action. Create it in attach on a hosted page to dispose it with the scene.
On React Native, divide a gesture’s position by the canvas’s layout size for the same coordinates.
A view of the canvas's texture, which is new every frame.
lifecycle
✓destroy()✓[Symbol.dispose]
requires
implicit-device-synchronizationrequired
React-native-webgpu requests it for every device; checkDevice warns without it. Devices used from two threads require it to avoid crashes.
platform
nativeonly
@typegpu/kit/native has no React Native imports. Pass it the canvas, pixel ratio and layout.
native.surface takes the CanvasRef that <Canvas ref> holds, the web’s canvas options and the pixelRatio. The drawing buffer’s size is on its context’s canvas.
resize(width, height) takes the layout in points, as onLayout reports it.
view(frame) schedules context.present() after submit. React Native requires an explicit present. Dawn rejects presenting without first acquiring the canvas texture.
A backgrounded app must not submit GPU work. pause() sets paused, which frames.animate checks before every frame, and view() throws while paused, so a loop of your own fails at once rather than submitting in the background.
resume() reconfigures the context with every canvas option. After a long background pause, the first getCurrentTexture can block the JS thread.
device.lost and uncapturederror reach only the main JS runtime.
tgpu.init({ device: { optionalFeatures } }) keeps each feature the adapter has; device.features says which it got.
Above the cap, the device-pixel size is scaled by maxPixelRatio / ratio, so the drawing buffer matches the screen pixel for pixel only at or below the cap.
On React Native, a frame that takes the view and is never submitted drops its present; the next frame that takes the view presents.
The web surface’s view() doesn’t throw while paused, since a submit from a paused page does no harm.
implicit-device-synchronization costs one uncontended mutex per API call.