@native/gpu is WebGPU running on the overlay’s D3D11 / D3D12 device.
Buffers, textures, pipelines, compute, render passes: the same API a browser has, so the
spec and MDN are the reference for everything on this page that isn’t
marked as an extension.
The extension is the game frame. device.frame hands you the scene’s color and depth, the camera, every
player’s skinned pose, the map geometry and the smokes as GPU objects, and lets your command buffers run
at fixed points inside the frame.
GPUBufferUsage, GPUTextureUsage, GPUShaderStage,
…) on the global object, so ported WebGPU code runs as is.
Overview
Shaders
WGSL by default, HLSL with
language: "hlsl".The frame
device.frame: targets, camera, poses, map, smokes, hooks.Players
pass.drawPose, replacing the cheat’s chams.Game assets
importTexture, importModel, exportImage.Canvas
OffscreenCanvas that shows up over the game.Limits
Memory budgets, device loss, GPU resets.
Shaders
WGSL is the default, exactly as in a browser. HLSL is an extension: passlanguage: "hlsl".
cbufferfor uniforms (notConstantBuffer<T>),ByteAddressBuffer/RWByteAddressBufferfor storage buffers.StructuredBufferisn’t supported.- Vertex inputs use
LOCATION(n), the same slot a WGSL@location(n)takes. #include <gpu.hlsli>gives you the camera, space conversions and the engine data layouts: see gpu.hlsli.SV_VertexID/SV_InstanceIDstart at 0 every draw (that’s D3D). WGSL’svertex_index/instance_indexare fixed up for you; in HLSL useGPU_VERTEX_INDEX(id)/GPU_INSTANCE_INDEX(id).
getCompilationInfo() with your own line numbers. Compiling is
async: createRenderPipelineAsync doesn’t block your script, and results are cached across reloads.
The frame
device.frame is the game frame as GPU objects. The resources are virtual: they always point at the
current frame, and resize with the game.
Plus a few numbers:
width / height, time, deltaTime, index, targetFormat, worldVertexCount,
worldIndexCount, worldGeneration (changes with the map), smokeCount, smokeVoxelCount.
Engine data costs nothing until you use it. Poses, smokes, worldDepth and solidDepth are only made
while some recording reads them; smokeCount stays 0 until then.
Hooks
Your command buffers run inside the frame at five points:
Submit to a hook from inside an
on("render") listener:
render dispatch replaces it, so the game never waits on your script. queue.submit is different: it
runs once, at the start of the next frame.
Camera space
The game uses inches with Z up, the engine scene uses meters with Y up.camera.viewProj takes game
positions (what entities gives you), camera.sceneViewProj takes scene positions (poses, map). The
matrices are stored as DirectX row-vector matrices; in HLSL mul(camera.viewProj, float4(p, 1)) is
the right product. Don’t declare them row_major.
Players
player is a slot 0..63, a controller or a
pawn. The pose vertices are bound to vertexSlot (stride 64, per vertex) and the pose record to
instanceSlot (stride 64, per instance); bind everything else yourself.
replaceNative turns off the visible pass, the x-ray pass and the glow outline of the cheat’s chams for
that player. When your script stops, reloads or loses its device, they come back on their own.
Game assets
Canvas
OffscreenCanvas works, with one extension: present: "overlay" composites it over the game every
frame. It’s there for code that expects a canvas to draw into, like WebGPU libraries.
context.exportImage() gives you the canvas as a Texture instead.
Queries
Occlusion and timestamp query sets work, with thetimestamp-query feature. On D3D12 they resolve on
the GPU; on D3D11 resolveQuerySet waits for the results on the CPU, so don’t resolve every frame there.
Limits and device loss
Textures and buffers you drop without
destroy() are freed by the garbage collector, which knows how
much GPU memory they hold. Still, destroy() what you’re done with.
The device is lost when the overlay rebuilds its own (switching D3D11 / D3D12, a driver reset). Listen
to device.lost and request a new one.
If a shader hangs the GPU, Windows resets it. The overlay recovers, and the script whose work was
running gets device.lost with a message saying so. It can’t open a new device until it’s reloaded.
On the CPU, your
@native/gpu calls cost about as much as a browser’s. The GPU work itself is the
same as native code. A frame of a few hundred draws is cheap; for thousands, use instancing or
indirect draws, like you would on the web.