Article · · Drift Technologies
Six 3D engines measured: the method and results
How the DriftEngine comparison was measured on a desktop and a phone, the figures it produced, and the feature matrix with a note and a source for every cell.
We publish the method, aggregate measurements and sourced feature notes behind our engine comparison here. The benchmark code and raw reports remain private.
What was measured
| Engine | Version | Backends | Sponza from |
|---|---|---|---|
| DriftEngine | 4.13.0 | WebGPU, WebGL2 | a container from its own baker |
| Three.js | r186 | WebGPU, WebGL2 | the glTF, through GLTFLoader |
| Babylon.js | 9.30.0 | WebGPU, WebGL2 | the glTF, through its glTF loader |
| PlayCanvas | 2.23.2 | WebGPU, WebGL2 | the glTF, through its container loader |
| Godot | 4.7.2 | WebGL2 | the glTF, imported into the project |
| Bevy | 0.20.0 | WebGPU, WebGL2, one build each | the glTF, through its asset server |
We wrote each engine's scenes from its documentation and examples. A shared layout sets object positions and light colours, with equivalent code in GDScript and Rust. The engines use their own rendering paths and asset pipelines. Bevy automatically batches the separate cubes; in the instancing scene, it creates an entity per cube and uses automatic instancing. Neither scene isolates the cost of a GPU draw call.
The machine and the browser
We measured the desktop on 2026-10-11 using an AMD Radeon RX 9070 XT, reported
by the browser as amd rdna-4, in
Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/151.0.0.0 Safari/537.36. The GPU runs through ANGLE on Vulkan. We disabled vsync and
the browser's frame-rate cap, and checked for hardware rendering before each session.
We measured the phone on 2026-10-11 using a Samsung Galaxy S23 Ultra with an
Adreno 740, in Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/154.0.0.0 Mobile Safari/537.36. The runner controlled it over USB and opened
each page in the foreground. Every page used the desktop's 1280 by
720 canvas at a pixel ratio of one. We checked the reported canvas
size and corrected Bevy's pixel ratio before taking the published measurements.
Phone vsync remained on, so cube timings mostly reflect the display's refresh interval. Temperature affects the accepted counts; we measured the lights column in one sitting with the phone on its charger.
How a frame time is taken
The probe waits for each engine's readiness signal before warming up. Where available, we use
its preparation calls, including DriftEngine's prepare and ready, Three.js's compileAsync
and Babylon.js's whenReadyAsync. Fixed-count runs discard
120 warm-up frames, then record up to
600 frames within 15 seconds.
Slow runs therefore have fewer readings.
We record intervals from both the page's CPU loop and GPU completion, using onSubmittedWorkDone
on WebGPU and fences on WebGL2. The probe holds back the next frame when
2 frames are still unfinished on the GPU. We use the GPU readings
when their mean exceeds 1.05 times the CPU mean; otherwise we use the CPU
readings. These are frame intervals under that scheduling rule, rather than isolated GPU execution
times. We wait for outstanding GPU work to finish before the next run.
Each reading averages 4 frames. This smooths out the browser reporting adjacent completions together, but also spreads an individual slow frame across the window. The median and 95th percentile are readings at those ranks, without interpolation. Desktop fixed-count measurements have 3 interleaved runs, and we print the median of each metric. Desktop count searches and all phone measurements have one run.
First-frame time starts at navigation and ends when the GPU completes the first frame after the
engine reports ready. Pages are served locally on desktop and through USB port forwarding on the
phone, so these figures do not estimate loading over the internet. Memory comes from the browser's
measureUserAgentSpecificMemory() after the scene settles; it does not measure GPU memory.
Download totals cover fetched application resources, including the engine and assets but excluding the benchmark probe. We count the bytes at the server, using the highest Brotli and gzip settings. Images served without HTTP compression keep their stored size. Sponza's download column uses Brotli. KB and MB here mean 1,024 and 1,048,576 bytes.
How a ceiling is found
For separate objects, instances and lights, we search for the largest count held at sixty frames a second. A count meets the timing criterion when the 95th percentile of the four-frame readings is at or under the 18 ms hold. This allows some room around the target frame interval; it does not guarantee every frame meets it.
Each search step discards 60 warm-up frames and measures up to 180 frames within 6 seconds. We double the count until a step exceeds the timing limit or is excluded, then bisect the interval between the last accepted count and the first rejected one. We stop when the gap is at most the greater of 16 objects and 5% of the accepted count, or after 20 steps. The table reports the largest accepted count tested.
An accepted count must pass the image check. We photograph each step that meets the timing criterion and reject a flat canvas. This checks that something was drawn; it cannot verify every requested object or light. A GPU error or lost device also excludes the step. After a GPU loss, we restart the browser before continuing the search.
What is not a number
If a run uses another backend, uses a software rasteriser, reports a GPU error or has GPU work the probe cannot observe, we print the outcome in place of a number. Desktop fixed-count runs are also photographed; a flat-colour image excludes the run.
We repeated DriftEngine and Three.js desktop measurements for the cube and separate-object scenes in two sessions. The differences were 2.0% at the median and 4.9% at worst. These repeats cover only those engines and desktop scenes.
Bold marks the best value, plus frame intervals within 2.0% and counts within 5% of it. We use these bands to group nearby results; bold does not establish a tie. Download, first-frame and memory columns bold only the best value. A column with every value inside the band has nothing in bold. A plus sign means the search cap was reached, so the engine's maximum remains unknown. A figure an engine reached by shading fewer lights than it was given is never bold.
The picture sheets show separate desktop captures at fixed counts, including those timed in the tables. They do not show the search ceilings or phone runs. The lights section records the settings changed between the timed runs and these captures.
Desktop
Download, first frame and memory
| Engine | Backend | Brotli | gzip | First frame | Memory |
|---|---|---|---|---|---|
| DriftEngine | WebGPU | 544.5 KB | 928.1 KB | 456 ms | 26.6 MB |
| DriftEngine | WebGL2 | 304.1 KB | 378.6 KB | 148 ms | 13.7 MB |
| Three.js | WebGPU | 241.7 KB | 300.3 KB | 156 ms | 13.1 MB |
| Three.js | WebGL2 | 163.6 KB | 198.9 KB | 81 ms | 10.6 MB |
| Babylon.js | WebGPU | 317.5 KB | 368.6 KB | 258 ms | 10.4 MB |
| Babylon.js | WebGL2 | 318.7 KB | 370.2 KB | 237 ms | 13.5 MB |
| PlayCanvas | WebGPU | 485.3 KB | 624.8 KB | 169 ms | 20.5 MB |
| PlayCanvas | WebGL2 | 485.3 KB | 624.8 KB | 149 ms | 19.5 MB |
| Godot | WebGL2 | 6.8 MB | 9.8 MB | 1430 ms | 63.0 MB |
| Bevy | WebGPU | 4.3 MB | 6.2 MB | 813 ms | 65.1 MB |
| Bevy | WebGL2 | 4.3 MB | 6.2 MB | 736 ms | 48.0 MB |

Separate objects
| Engine | Backend | 1,000: median | 1,000: p95 | 10,000: median | 10,000: p95 | Most at 60 fps |
|---|---|---|---|---|---|---|
| DriftEngine | WebGPU | 2.67 ms | 3.24 ms | 22.39 ms | 25.34 ms | 7,168 |
| DriftEngine | WebGL2 | 2.67 ms | 3.21 ms | 21.68 ms | 24.49 ms | 7,424 |
| Three.js | WebGPU | 4.71 ms | 6.45 ms | 55.29 ms | 62.17 ms | 2,688 |
| Three.js | WebGL2 | 1.47 ms | 1.93 ms | 12.51 ms | 14.11 ms | 9,472 |
| Babylon.js | WebGPU | 7.67 ms | 8.93 ms | 87.99 ms | 93.07 ms | 1,792 |
| Babylon.js | WebGL2 | 4.10 ms | 6.21 ms | 61.86 ms | 64.71 ms | 2,688 |
| PlayCanvas | WebGPU | 1.35 ms | 1.77 ms | 16.60 ms | 21.43 ms | 8,192 |
| PlayCanvas | WebGL2 | 1.48 ms | 2.03 ms | 18.37 ms | 21.83 ms | 7,424 |
| Godot | WebGL2 | 3.04 ms | 3.46 ms | 29.14 ms | 31.48 ms | 5,376 |
| Bevy | WebGPU | 3.12 ms | 4.02 ms | 10.58 ms | 11.75 ms | 16,896 |
| Bevy | WebGL2 | 2.41 ms | 3.29 ms | 10.77 ms | 12.04 ms | 15,360 |



One object, many times
| Engine | Backend | 100,000: median | 100,000: p95 | 1,000,000: median | 1,000,000: p95 | Most at 60 fps |
|---|---|---|---|---|---|---|
| DriftEngine | WebGPU | 0.45 ms | 0.55 ms | 1.08 ms | 1.64 ms | 4,194,304+ |
| DriftEngine | WebGL2 | 0.47 ms | 0.65 ms | 3.15 ms | 4.04 ms | 3,801,088 |
| Three.js | WebGPU | 0.37 ms | 0.55 ms | 1.49 ms | 2.20 ms | 4,063,232 |
| Three.js | WebGL2 | 0.33 ms | 0.56 ms | 1.12 ms | 1.43 ms | 4,194,304+ |
| Babylon.js | WebGPU | 0.31 ms | 0.46 ms | 1.13 ms | 1.70 ms | 4,194,304+ |
| Babylon.js | WebGL2 | 0.30 ms | 0.47 ms | 1.14 ms | 1.40 ms | 4,194,304+ |
| PlayCanvas | WebGPU | 0.37 ms | 0.59 ms | 1.13 ms | 1.71 ms | 4,194,304+ |
| PlayCanvas | WebGL2 | 0.33 ms | 0.53 ms | 1.32 ms | 2.02 ms | 4,194,304+ |
| Godot | WebGL2 | 0.51 ms | 0.65 ms | 2.05 ms | 3.03 ms | 4,194,304+ |
| Bevy | WebGPU | 24.12 ms | 25.65 ms | 211.10 ms | 218.15 ms | 71,680 |
| Bevy | WebGL2 | 94.71 ms | 97.27 ms | 895.04 ms | 908.40 ms | 15,872 |



Point lights
DriftEngine's desktop figures include point-light shadows, which none of the other engines draws in this scene. They are off in the phone measurements and in these separate picture captures.
| Engine | Backend | 64 lights | 256 lights | Most lights at 60 fps | Limits |
|---|---|---|---|---|---|
| DriftEngine | WebGPU | 0.48 ms | 0.70 ms | 4,096+ | shades the nearest 320 of 4096 lights |
| DriftEngine | WebGL2 | 0.57 ms | 0.92 ms | 4,096+ | shades the nearest 320 of 4096 lights |
| Three.js | WebGPU | 0.51 ms | 0.57 ms | 4,096+ | |
| Three.js | WebGL2 | 0.45 ms | 1.21 ms | 992 | forward: every light is evaluated for every fragment |
| Babylon.js | WebGPU | 0.72 ms | 0.78 ms | 4,096+ | |
| Babylon.js | WebGL2 | 0.59 ms | 0.64 ms | 4,096+ | |
| PlayCanvas | WebGPU | 0.52 ms | 0.77 ms | 4,096+ | |
| PlayCanvas | WebGL2 | 0.48 ms | 0.72 ms | 4,096+ | |
| Godot | WebGL2 | 0.62 ms | 0.69 ms | 4,096+ | Compatibility renderer: at most 32 lights per object |
| Bevy | WebGPU | 2.52 ms | 2.46 ms | 4,096+ | |
| Bevy | WebGL2 | 2.01 ms | 2.39 ms | 4,096+ | WebGL2: at most 256 clusterable lights |



We measured Godot's floor and pillars with an orange material. The pictures use grey to match the other engines and show the blue lights more clearly. A separate interleaved check found frame times within the observed spread after the colour change.
Godot's Compatibility renderer shades at most 32 lights per object, leaving the floor lit around its middle beyond that count. Bevy on WebGL2 leaves the far end dark at 256 lights. Babylon.js's standard material fades each light linearly to its range, so the overlapping lights make the floor white. The floor is still drawn.
Sponza
| Engine | Backend | Download | Load to first frame | Frame |
|---|---|---|---|---|
| DriftEngine (baked) | WebGPU | 44.2 MB | 2445 ms | 1.09 ms |
| DriftEngine (baked) | WebGL2 | 44.0 MB | 1974 ms | 1.25 ms |
| Three.js | WebGPU | 73.7 MB | 1778 ms | 2.71 ms |
| Three.js | WebGL2 | 73.6 MB | 1638 ms | 1.85 ms |
| Babylon.js | WebGPU | 74.0 MB | 2108 ms | 4.27 ms |
| Babylon.js | WebGL2 | 74.0 MB | 2722 ms | 2.47 ms |
| PlayCanvas | WebGPU | 73.9 MB | 1753 ms | 1.00 ms |
| PlayCanvas | WebGL2 | 73.9 MB | 1678 ms | 1.44 ms |
| Godot (imported) | WebGL2 | 230.1 MB | 6386 ms | 2.71 ms |
| Bevy | WebGPU | 77.8 MB | 5680 ms | 4.17 ms |
| Bevy | WebGL2 | 77.7 MB | 5515 ms | 9.45 ms |

We set each engine's sun and sky separately. The pictures show those settings and do not rank rendering quality.
Phone
| Engine | Backend | Most draws at 60 fps | Most instances at 60 fps | Most lights at 60 fps | Sponza frame | Sponza first frame |
|---|---|---|---|---|---|---|
| DriftEngine | WebGPU | 1,728 | 63,488 | 160 | 37.5 ms | 6386 ms |
| DriftEngine | WebGL2 | 2,688 | 262,144 | 192 | 33.3 ms | 3001 ms |
| Three.js | WebGPU | 1,024 | 688,128 | 4,096+ | 16.7 ms | 3226 ms |
| Three.js | WebGL2 | 8,704 | 753,664 | 48 | 16.7 ms | 2561 ms |
| Babylon.js | WebGPU | 1,280 | 753,664 | 1,792 | 16.7 ms | 3309 ms |
| Babylon.js | WebGL2 | 4,096 | 786,432 | 4,096+ | 16.7 ms | 3326 ms |
| PlayCanvas | WebGPU | 7,168 | 540,672 | 4,096+ | 16.7 ms | 3034 ms |
| PlayCanvas | WebGL2 | 7,936 | 819,200 | 4,096+ | 16.7 ms | 2933 ms |
| Godot | WebGL2 | 3,712 | 360,448 | 4,096+ | 16.7 ms | 38643 ms |
| Bevy | WebGPU | 12,288 | 53,248 | 624 | 25.0 ms | 6850 ms |
| Bevy | WebGL2 | 12,288 | 13,824 | 4,096+ | 20.8 ms | 7659 ms |
The feature matrix
Four states: built in; an official add-on, published by the engine's own organisation; a community plugin, published by someone else; and none, where neither exists. Each state links to the page that shows it, read against the versions above.
The notes on each cell
Rigid-body physics
- DriftEngine, built in: In @driftengine/physics, which core depends on and re-exports, so installing core installs it. Source
- Three.js, official add-on: RapierPhysics, AmmoPhysics and JoltPhysics in three/addons wrap third-party engines. RapierPhysics loads Rapier from a CDN. Source
- Babylon.js, official add-on: Physics V2 is in @babylonjs/core, but the Havok engine it drives is the separate, official @babylonjs/havok package. Source
- PlayCanvas, official add-on: Rigid body and collision components are in the engine; the physics itself is ammo.js, loaded as a separate WebAssembly module. Source
- Godot, built in: Rigid bodies, areas and joints in the engine. Source
- Bevy, community plugin: Rapier via bevy_rapier3d, whose 0.37 release targets Bevy 0.20. avian3d is the other option and targets Bevy 0.19 as of this reading. Source
Character controller
- DriftEngine, built in: CharacterController with acceleration, air control and a jump buffer, in @driftengine/physics. Source
- Three.js, community plugin: Rapier's kinematic character controller via @dimforge/rapier3d. The official physics_rapier_character_controller example calls it directly; the RapierPhysics add-on does not wrap it. Source
- Babylon.js, official add-on: PhysicsCharacterController in Physics V2, which runs on the separate @babylonjs/havok package. Source
- PlayCanvas, official add-on: First-person and third-person controller scripts in the engine repository's scripts/esm. No controller component. Source
- Godot, built in: CharacterBody3D. Source
- Bevy, community plugin: bevy_rapier3d's kinematic character controller. bevy-tnua is an alternative and targets Bevy 0.19 so far. Source
Vehicle physics
- DriftEngine, built in: A raycast Vehicle with tyre curves, in @driftengine/physics. Source
- Three.js, community plugin: Rapier's raycast vehicle controller via @dimforge/rapier3d, used directly by the official physics_rapier_vehicle_controller example. Source
- Babylon.js, none found: No vehicle controller in core or the official add-ons. Forum projects build cars from rigid bodies, joints and shape casts, and no maintained package was found. Source
- PlayCanvas, official add-on: An official tutorial and a script in the engine repository drive ammo.js's RaycastVehicle. No vehicle component. Source
- Godot, built in: VehicleBody3D with VehicleWheel3D. Source
- Bevy, community plugin: bevy_rapier3d's raycast vehicle controller. Source
Ragdolls
- DriftEngine, built in: A ragdoll built from a skeleton, and cloth, in @driftengine/physics. Source
- Three.js, none found: No ragdoll add-on or maintained package found. Joints in Rapier or Ammo can be assembled into one by hand. Source
- Babylon.js, official add-on: A Ragdoll class in Physics V2 builds one from a skeleton and a list of shapes, on the separate @babylonjs/havok package. Source
- PlayCanvas, none found: No ragdoll helper. The official ragdoll example assembles one by hand from the joint component, which is marked alpha. Source
- Godot, built in: Physical bones driven from a Skeleton3D. Source
- Bevy, none found: No ragdoll plugin found. Joints in bevy_rapier3d or avian3d can be assembled into one by hand. Source
Deterministic simulation and replays
- DriftEngine, built in: A fixed-step loop, a seeded generator whose sequence is frozen, and world fingerprints, so a replay or a test reruns exactly. Source
- Three.js, none found: three.js is a renderer rather than a simulation runtime: it has a seeded random function (MathUtils.seededRandom) but no fixed-step loop or replay, and its Timer reports variable frame deltas. Rapier's deterministic builds cover physics only. Source
- Babylon.js, none found: Partial. A deterministicLockstep engine option steps physics and animation at a fixed rate, which the docs suggest for replays, but there is no seeded random generator and no cross-machine guarantee. Source
- PlayCanvas, none found: Partial. Physics steps at a fixed 1/60 s, but the engine random helpers use Math.random with no seed and nothing promises reproducible runs. Source
- Godot, none found: The physics docs state that physics is not deterministic. RandomNumberGenerator takes a seed, but its reference calls the algorithm an implementation detail. Source
- Bevy, community plugin: Bevy has a built-in FixedUpdate schedule. Seeded, portable random numbers come from bevy_rand and cross-platform physics from bevy_rapier3d's enhanced-determinism feature with Bevy's libm feature. Source
Rollback netcode
- DriftEngine, official add-on: @driftengine/network: lockstep and rollback over a lossy link, checked by fingerprints. Source
- Three.js, none found: Nothing three.js-specific. NetplayJS, an engine-agnostic rollback library, has had no npm release since April 2023. Source
- Babylon.js, none found: The networking guide uses Colyseus for server-authoritative state sync. No rollback layer found. Source
- PlayCanvas, none found: Nothing PlayCanvas-specific. NetplayJS, an engine-agnostic rollback library, has had no npm release since April 2023. Source
- Godot, community plugin: netfox (foxssake/netfox), addons for Godot 4.x with rollback, client-side prediction and server reconciliation. Source
- Bevy, community plugin: bevy_ggrs, GGRS rollback for Bevy. Its latest release targets Bevy 0.19. Source
WebGPU with an automatic WebGL2 fallback
- DriftEngine, built in: createRenderer tries WebGPU and accepts a device only after drawing a probe frame on it, else WebGL2. Source
- Three.js, built in: WebGPURenderer uses WebGPU when the browser has it and falls back to a WebGL 2 backend. Source
- Babylon.js, built in: EngineFactory.CreateAsync creates a WebGPU engine when supported, otherwise a WebGL one. The plain Engine class is WebGL only. Source
- PlayCanvas, built in: createGraphicsDevice tries WebGPU when it is listed in deviceTypes and falls back to WebGL 2. WebGL 2 is the default. Source
- Godot, none found: The web export renders with WebGL 2 through the Compatibility renderer. The docs state that Godot does not support WebGPU. Source
- Bevy, none found: webgl2 and webgpu are build-time features. A build with webgpu enabled overrides webgl2 and will not run in browsers without WebGPU. Source
Native desktop builds
- DriftEngine, official add-on: @driftengine/package builds Linux, Windows and macOS apps; the native host runs a game on Dawn and SDL. Source
- Three.js, community plugin: No packaging of its own. A web shell such as Electron or Tauri wraps the page. Source
- Babylon.js, official add-on: Babylon Native runs Babylon.js in native apps on Windows, macOS and Linux. It is a public preview in source form. The docs also suggest Electron. Source
- PlayCanvas, community plugin: The docs recommend NW.js, a third-party web shell, for Windows, macOS and Linux executables. Source
- Godot, built in: Export to Windows, Linux and macOS from the same project. Source
- Bevy, built in: Windows, macOS and Linux. Source
Android builds
- DriftEngine, official add-on: @driftengine/package builds an Android app. Source
- Three.js, community plugin: No packaging of its own. A WebView shell such as Capacitor or Cordova wraps the page. Source
- Babylon.js, official add-on: Babylon Native and Babylon React Native target Android. The docs also suggest Ionic. Source
- PlayCanvas, community plugin: Apache Cordova wraps the app in a WebView. PlayCanvas publishes a tool that prepares Editor projects for it. Source
- Godot, built in: Android export from the editor. Source
- Bevy, built in: Built with cargo-ndk and Gradle, as the examples README describes. Source
Navigation meshes
- DriftEngine, official add-on: @driftengine/nav Source
- Three.js, community plugin: recast-navigation-js with its @recast-navigation/three helpers. Source
- Babylon.js, built in: RecastJSPlugin in core, which needs the recast-detour library. Its successor, built on recast-navigation-js, is in the official @babylonjs/addons package. Source
- PlayCanvas, community plugin: recast-navigation-js with its @recast-navigation/playcanvas helpers. Source
- Godot, built in: NavigationMesh baking and the navigation server. Source
- Bevy, community plugin: bevy_rerecast, a Rust port of Recast, with bevy_landmass or vleue_navigator for agents. All target Bevy 0.19 so far. Source
Terrain
- DriftEngine, official add-on: @driftengine/terrain Source
- Three.js, community plugin: THREE.Terrain (three.terrain.js), procedural height-map terrain. The official examples build terrain from noise but ship no terrain add-on. Source
- Babylon.js, built in: Ground from a height map in core. The Dynamic Terrain extension, a community project, adds a terrain that follows the camera. Source
- PlayCanvas, none found: No terrain system. An official tutorial builds a mesh from a height map with the mesh API, and no maintained terrain package was found. Source
- Godot, community plugin: Terrain3D (TokisanGames). Its docs call web exports very experimental. HTerrain, written in GDScript, is an alternative. Source
- Bevy, community plugin: bevy_heightmap builds meshes from height maps and targets Bevy 0.19. It is a small project, and no larger maintained terrain plugin was found. Source
Spatial audio
- DriftEngine, official add-on: @driftengine/audio Source
- Three.js, built in: PositionalAudio and AudioListener over the Web Audio API. Source
- Babylon.js, built in: Spatial sounds and a listener in the audio engine (AudioEngineV2). Source
- PlayCanvas, built in: The sound component's positional mode, heard through an audio listener component. Source
- Godot, built in: AudioStreamPlayer3D. On the web the default sample playback may not handle positional audio correctly, and the Stream playback type restores it at higher latency. Source
- Bevy, built in: SpatialListener with spatial audio sinks, panned by ear position. Source
Gaussian splats
- DriftEngine, official add-on: @driftengine/splats Source
- Three.js, official add-on: GaussianSplat add-on with SPLAT and SPZ loaders, for WebGPURenderer only. The community Spark library (@sparkjsdev/spark) is a larger alternative. Source
- Babylon.js, built in: GaussianSplattingMesh loads PLY, SPLAT, SPZ and SOG. Source
- PlayCanvas, built in: The gsplat component and asset type, with streamed levels of detail. Source
- Godot, none found: For the web export. GDGS (community) renders splats on desktop but needs the Forward+ renderer and compute shaders, which the web export does not have. Source
- Bevy, community plugin: bevy_gaussian_splatting. Its latest release targets Bevy 0.19. Source
A scripting language of its own
- DriftEngine, official add-on: DriftScript, through @driftengine/script Source
- Three.js, none found: Code is written in JavaScript or TypeScript. No scripting language of its own. Source
- Babylon.js, built in: Flow Graph, a node-based visual scripting system in core with an official editor. Visual only: there is no text scripting language. Source
- PlayCanvas, none found: Scripts are JavaScript or TypeScript classes. No scripting language of its own. Source
- Godot, built in: GDScript. C# projects cannot be exported to the web in Godot 4. Source
- Bevy, community plugin: bevy_mod_scripting adds Lua and Rhai. Its latest release targets Bevy 0.19. Source
Coding-agent tooling
- DriftEngine, official add-on: npm create @driftengine starts a project with instructions for an agent, the driftengine skill and a check that opens the game on both backends; llms.txt and a skills index on driftengine.dev. Source
- Three.js, official add-on: llms.txt and llms-full.txt published on threejs.org. Source
- Babylon.js, official add-on: llms.txt on doc.babylonjs.com. The @babylonjs/mcp-servers package also lets agents drive the node and GUI editors. Source
- PlayCanvas, official add-on: npm create playcanvas includes PlayCanvas Skills for coding agents. An llms.txt and an Editor MCP server are also published. Source
- Godot, community plugin: GodotPrompter, agent skills for Godot 4.x. The project publishes no llms.txt or agent skill of its own. Source
- Bevy, community plugin: bevy_brp_mcp, an MCP server that lets coding agents inspect and drive a running app over the Bevy Remote Protocol, with Bevy 0.20 support. It is not a skill or an llms.txt, and the project publishes neither. Source
Visual editor
- DriftEngine, official add-on: @driftengine/editor holds a scene tree, an inspector and play-in-editor, and an editor app lives in the engine repository. A full visual editor is the next step on the roadmap. Source
- Three.js, official add-on: A browser scene editor kept in the editor folder of the three.js repository. Source
- Babylon.js, official add-on: The Babylon.js Editor lives in the BabylonJS GitHub organisation, though its docs call it a community project. The official Inspector edits a running scene. Source
- PlayCanvas, official add-on: The browser-based Editor is a hosted service separate from the MIT engine. Its front end is published on GitHub under MIT. Source
- Godot, built in: The Godot editor. Source
- Bevy, community plugin: Skein uses Blender as the scene editor. Bevy has no editor yet, and its 0.20 notes describe editor building blocks. Source
Sponza
We used Intel Sponza (2022), commissioned by Frank Meinl and sponsored by Anton Kaplanyan, from the Intel Sample Library under Creative Commons Attribution. Reference photographs are by Katica Putica and Princino.photo, Dubrovnik. We resized the base scene's textures to at most 1,024 pixels on a side and removed its lights and cameras before applying the benchmark's settings. The model and texture files are not distributed here. Intel does not endorse this benchmark or any engine in it.