First frame
A one-cube scene reaches its first frame in about 420 ms (median of 3 cold loads).
three.js gives you a renderer. Everything after that is your job: loaders, environment lighting, shadows, post-processing, controls, the game loop, the HUD, audio, asset handling, licensing and the deploy checks. Aura3D ships all of that as one engine and one toolchain, with its own renderer, a typed declarative scene and an asset pipeline that will not let an unverified model reach production. It is built from the start to be written by AI coding agents.
Line counts include imports and skip blank lines. Aura3D benchmark, five scenes; the method and sources are under “How we measured” below.
Both scenes load the same GLB with HDR studio lighting, a shadow-casting key light, tone mapping and a framed camera. The Aura3D version also adds orbit controls in its 10 lines.
import * as THREE from "three";
import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
import { HDRLoader } from "three/addons/loaders/HDRLoader.js";
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(Math.min(devicePixelRatio, 2));
renderer.setSize(innerWidth, innerHeight);
renderer.toneMapping = THREE.NeutralToneMapping;
renderer.shadowMap.enabled = true;
document.querySelector("#app")!.appendChild(renderer.domElement);
const scene = new THREE.Scene();
scene.background = new THREE.Color("#2b2f36");
const camera = new THREE.PerspectiveCamera(35, innerWidth / innerHeight, 0.1, 100);
const pmrem = new THREE.PMREMGenerator(renderer);
new HDRLoader().load("/hdri/studio_small_08_1k.hdr", (hdr) => {
scene.environment = pmrem.fromEquirectangular(hdr).texture;
scene.environmentIntensity = 1.1;
hdr.dispose();
});
const key = new THREE.DirectionalLight("#ffffff", 2.4);
key.position.set(6.52, 18.39, 13.98);
key.castShadow = true;
key.shadow.mapSize.set(2048, 2048);
scene.add(key);
new GLTFLoader().load("/aura-assets/product-fixture.glb", (gltf) => {
gltf.scene.traverse((o) => { if ((o as THREE.Mesh).isMesh) o.castShadow = o.receiveShadow = true; });
scene.add(gltf.scene);
const box = new THREE.Box3().setFromObject(gltf.scene);
const center = box.getCenter(new THREE.Vector3());
const dist = box.getSize(new THREE.Vector3()).length() / (2 * Math.tan((camera.fov * Math.PI) / 360));
camera.position.copy(center).add(new THREE.Vector3(0.5, 0.35, 1).normalize().multiplyScalar(dist));
camera.lookAt(center);
});
addEventListener("resize", () => {
camera.aspect = innerWidth / innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(innerWidth, innerHeight);
});
renderer.setAnimationLoop(() => renderer.render(scene, camera));
import { camera, createAuraApp, interactions, looks, model, scene } from "@aura3d/engine";
import { assets } from "./aura-assets";
createAuraApp("#app", {
scene: scene()
.add(looks.preset("product-studio"))
.add(model(assets.product, { name: "product", targetHeight: 1.6, castShadow: true }))
.add(interactions.orbit({ target: "product" }))
.camera(camera.frameAsset(assets.product, { targetHeight: 1.6 })),
...looks.appOptions("product-studio")
});
Both files are in the Aura3D repository: tools/bench-vs-threejs/tagline/three-minimal/main.ts and tools/bench-vs-threejs/tagline/aura-variants/hero.ts. Both build with a stock vite build.
Each row names the file or result it comes from, so you can check it.
looks.preset(id) supplies HDRI lighting, a shadow-casting key light, background, grade and post effects in one call. 15 genre looks.packages/engine/src/agent-api/looks/lookPresets.ts, RESULTS.md §11RESULTS.md §1RESULTS.md §3effects.bloom(), shadow: true, effects.shaderPass().EffectComposer plus 3 or 4 addon passes; shadow flags on every mesh.RESULTS.md §11instances.*({ transforms, colors }).InstancedMesh matrix code.RESULTS.md §11handle.play("Run", { crossFade })) and fit the character to a height with one targetHeight option.AnimationMixer, clipAction and manual fitting with Box3.RESULTS.md §11model(assets.robot): a generated typed key, so a missing asset is a compile error.templates/product-viewer/src/aura-assets.ts, tests/unit/agent-api/public-example-boundary.test.tsdocs/agents/claims-and-boundaries.md §5 and §6, docs/api/model-loader.mdaura3d assets search and resolve pull licence-tagged open models (CC0, CC-BY) and type them. Meshy generation, optimization, inspection and thumbnails come from the same CLI.packages/aura3d-cli/src/cli-help.tsaura3d check-deploy --dist dist fails the build on a missing hashed asset, stray files and asset-validation errors. --release adds licence and quality gates.packages/aura3d-cli/src/index.ts (check-deploy)@aura3d/engine/game), plus genre kits for racket sports, karting, car soccer, fighting and platformer motion.docs/api/root-exports.md (game-kit exports), docs/api/game-kit.mdcreateFixedStepLoop, seeded createCountedRng and installQaHooks for scripted, repeatable test runs.packages/engine/src/qa/, docs/api/qa-kit.mdcreateRenderInterpolator and createFixedStepPresenter: a 60 Hz simulation no longer freezes on every second frame at 120 Hz (50% stalled frames before, 0% after).docs/api/motion-presenter.mdinstallSafetyNet detects black frames and recovers. createFrameErrorBoundary keeps rendering after a throwing frame callback. A ?diag=1 diagnostics panel is built in.packages/debug/src/safety, docs/api/safety-net.mdpackages/audio/src/synth, docs/api/audio-synth.mdmaterial.custom GLSL with a chunk library (a3d_math, a3d_noise, a3d_sky, a3d_fog, a3d_toon) and loud compile errors.ShaderMaterial with uniforms and varyings declared by hand.docs/api/glsl-chunks.md, RESULTS.md §11llms.txt, 14 agent skills, compiled recipes and a type-traps table, written into every new project by create-aura3d.packages/aura3d-cli/skills/, create-aura3d --helpaura3d migrate three maps 245 three.js constructs and writes an annotated port worklist.packages/aura3d-cli/src/migrate-three/create-aura3d templates (product viewer, mini-game, racing, falling blocks, fighting, arena shooter, character controller, animation studio and more), each with route-health and screenshot tests.packages/create-aura3d/templates/docs/workflows/game-inventory.json, showcaseComparison target: three.js 0.185.1. RESULTS.md is evidence/vs-threejs/RESULTS.md. Benchmark rows are Aura3D benchmark, five scenes.
Facts about Aura3D alone, each from a benchmark target that passes. Software WebGL2 on a remote CPU runner, 640x360, one run. These are not GPU numbers.
A one-cube scene reaches its first frame in about 420 ms (median of 3 cold loads).
A one-cube scene draws in 1 call. A PBR viewer scene with a shadow and bloom draws in 25 (33 in the previous release).
The five benchmark scenes log no console warnings or errors.
Every option covered by the option-coverage test either takes effect or raises OPTION_IGNORED: 16 of 16 tests pass.
Targets that did not pass carry no claim; each is listed with its cause in evidence/vs-threejs/RESULTS-4.5.0.md.
These four parts only work because the engine, the CLI and the docs are built together.
Assets are typed, hashed and licensed end to end, and the renderer enforces it at run time. The CLI admits each model with its source and a hash, generates the typed key, and check-deploy fails the build when a hashed file is missing. In production the renderer refuses to draw an unverified model. If you ship AI-generated or third-party art, this is your licensing and supply-chain answer.
The API, docs, recipes and skills ship together and are tuned by a repeatable cold-start trial (tools/agent-eval). As we improved the docs, fresh agents working from the Aura3D docs alone went from 8 to 14 working scenes out of 15 and from 40 to 10 median turns, and every first build compiled (15 of 15). One model, 15 runs per arm.
Fixed-step loop, seeded replay, QA hooks, safety net, high-refresh interpolation, HUD, touch, audio and genre kits come in one install, and 25 shipped games exercise them.
The public-example boundary test, route-health specs in all 20 templates, assets validate --release and check-deploy come with the code. You get the release process along with the engine.
aura3d migrate three maps 245 three.js constructs to Aura3D and writes an annotated port worklist for the rest, so you start from a list of changes instead of a blank file. The porting guide covers the 40 most common APIs and what the codemod leaves to you: docs/migration/from-threejs.md.
The benchmark builds five scenes (PBR viewer, forest, skinned character, game loop and water) as standalone Vite apps in both libraries and counts non-blank source lines, imports and API symbols, imports included. The product-shot comparison above is a separate check: the 10-line hero builds on a stock create-aura3d product-viewer project and renders, and the matched three.js app is 38 lines. Numbers are labelled “Aura3D benchmark, five scenes” wherever they appear; render checks ran on software WebGL2 on a CPU runner. The scenes, scripts, results and frames are in evidence/vs-threejs, so you can rerun them.
Scaffold a template, add a typed asset and ship a route you can check. Your agent writes the code; Aura3D supplies the stack.