Skip to main content
@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.
Importing the module also puts the WebGPU classes (GPUBufferUsage, GPUTextureUsage, GPUShaderStage, …) on the global object, so ported WebGPU code runs as is.
Most effects don’t need any of this. Scene draws shapes, players with your own shaders and particles on top of it, with no pipelines to build.

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: pass language: "hlsl".
HLSL keeps WebGPU’s binding model. Write every resource with an explicit register, the group as the space and the binding as the number:
  • cbuffer for uniforms (not ConstantBuffer<T>), ByteAddressBuffer / RWByteAddressBuffer for storage buffers. StructuredBuffer isn’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_InstanceID start at 0 every draw (that’s D3D). WGSL’s vertex_index / instance_index are fixed up for you; in HLSL use GPU_VERTEX_INDEX(id) / GPU_INSTANCE_INDEX(id).
Compiler messages come back through 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:
What you submit is a recording. The render thread replays your latest one every frame until the next 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


Draws a player’s skinned pose with the current pipeline. 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

Model vertices are 80 bytes in game space (inches, Z up), bind pose. See GpuModelVertex.

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 the timestamp-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.