Repository navigation
Aura3D 4.5.0
Pre-releaseSuperseded. This version is deprecated. Upgrade to Aura3D 5.5.1; see the 4.x to 5.0 migration guide.
A release with two visual changes: the default render path and the exposure calibration. Read both before upgrading. All timings below are software WebGL2 on a remote runner; no real-GPU run has been made.
-
Visual change:
createAuraApptakesqualityand picks a cheaper render path for plain scenes (engine, rendering).quality: "auto" | "production" | "safe-basic" | "cinematic"(defaultauto). A scene with no post-processing, output options, transmission or custom shader draws in one pass to the canvas; every other scene, andquality: "production", uses the HDR chain exactly as before (the production call sequence is unchanged and covered byrender-path-selection.test.ts).app.diagnostics().renderPathand its reason say which one ran.setOutputon a direct-path app now warns instead of silently doing nothing. Measured on the cube scene: steady frame 42.9 ms to about 6 ms, first frame 954 ms to about 450 ms, 2 draw calls to 1. -
preserveDrawingBuffercan be requested and is on for capture pages (engine). In 4.3.7 the renderer profiles listedpreserveDrawingBuffer: truebut the value never reached the WebGL context, which was always created without it. 4.5.0 adds apreserveDrawingBufferoption tocreateAuraAppand turns it on for?capture=1and?qa=1pages; every other page keeps the 4.3.7 behaviour.app.screenshot()now re-renders before reading, so screenshots and the stockcheck-deploy --browserblack-frame check work on any page. If you read the canvas yourself outside a render call, passpreserveDrawingBuffer: trueor useapp.capture()/app.screenshot(). -
Bloom fuses draws without adding fill on the
autoandcinematicpaths;renderer.bloomFusionselects the mode (engine, rendering).bloomFusion: "separable"(default) folds the bright extract into the level-0 downsample, sums the mips in one pass and folds the last upsample into the composite, and blurs mips 3 and 4 in 2-D only within a tap budget: the PBR viewer drops from 33 to 25 draw calls with frames within 0.001/255 mean and 1/255 max ofproductionin three remote runs, and frame time at parity withproductionwithin runner noise (strictly lower is not established).bloomFusion: "fused-2d"(opt-in, also?aura3d-bloom-fusion=) blurs mips 1 to 4 in 2-D as well (23 draws) and costs 45% to 52% more frame time on software WebGL2, so it is off until a real-GPU run exists. An invalid value throws.app.diagnostics().renderPath.bloomFusionreports the mode that ran and saysoffwhen no fused pass can run (production,safe-basic, or no bloom).quality: "production"keeps the separable chain unchanged. -
Per-frame cost (engine, rendering). The GL error check runs on the first frames, after resource changes and every 60th frame (every frame in
strictand?diag=1), the default lighting probe builds faster with bit-identical output, and per-frame report objects are built on read. See the next entries for the second round of cuts. -
Per-frame JS memoisation and allocation cut on the direct path (engine, rendering). Program keys, the registry's active list, the derived core-output-off flags, the page-URL flag and shadow lookups, and the WebGL2 state-cache bookkeeping no longer rebuild or re-serialise what has not changed. On the cube scene this cut allocation from 385 KB to 235 KB per frame and CPU in
frame()from 0.17 to 0.12 ms in the deterministic budget test (frame-submission-budget). The remote A/B on software WebGL2 did not reach the 0.5 ms target for the cube frame (1.5 to 1.1 ms gate figure, 1.0 to 0.8 ms settled);evidence/vs-threejs/wp5-frame-submission.mdhas the profile and the floor. -
Shadow cascades no visible item can sample are skipped, and the program warm stops compiling variants nothing draws (rendering). On
autoandcinematiconly (productionstill draws every cascade), the game-loop scene goes from 38 to 20 draws and from 6 to 4 programs, and the skinned character from 8 to 4 programs, withproductionpixels byte-identical on both frames. Frame time did not improve on software WebGL2 (both scenes are fill-bound there). Seeevidence/vs-threejs/wp7/README.md. -
Dense instanced shadow casters draw depth in one call per node per cascade (rendering). Nodes with 1,024 or more instances that use the engine's instanced shadow proxy go from batches of 64 to one instanced depth draw per cascade: the 10,000-instance forest goes from 569 to 11 draws, pixel-identical on the remote runner. A leak in the vertex-array eviction index (one empty set per disposed instance buffer) is fixed. Opt out with
__A3D_DENSE_DEPTH_DRAWS__ = "off". -
Shadow PCF tap tiers are opt-in (rendering).
?shadowtaps=32|16|8caps the kernel length of the forward shadow filter;?qualitytaps=onmaps the quality tier (low 8, medium 16) and?densetaps=onsends scenes with 8,192 or more shadow-casting instances to 8 taps. Nothing changes unless one is set. Measured on the 18,000-instance forest the 8-tap tier changes the frame by 0 to 2% on software WebGL2 (the kernel is already 9 taps) and differs by up to 9/255 at penumbrae, so no tier is applied by default. -
Time to first frame of the cube (rendering). The analytic floor probe is built and turned into its equirect without per-texel work, and the baked default probe decodes after the first frame has been submitted (a 3 s timeout, and no wait where no renderer exists). Settled frames are bit-identical (SHA-256 equal on all 15 loads). On software WebGL2 through the unbundled dev server,
createAuraAppto first frame went from 407-491 ms to 209-252 ms and navigation to first frame from 755-873 ms to 596-649 ms. The 500 ms target holds for the first and not for the second: about 390 ms of navigation is the dev server loading the module graph. The deferral of the baked probe showed no measurable difference in that harness. Seeevidence/vs-threejs/wp8-first-frame.md. -
Exposure gaps against three.js are attributed, not calibrated (docs, tests). Remote ablations of the cube, PBR viewer and forest scenes trace each difference to the benchmark sources or documented defaults; no engine change was made. See
evidence/exposure-parity. -
Options that were accepted and ignored now say so (engine).
primitives.*,instances.*andinteractions.*raise anOPTION_IGNOREDdiagnostic, naming the valid keys, for an option they do not read (inapp.diagnostics(); strict mode throws).primitive()now forwardsrenderOrder,frustumCulled,layers,userData,rotationOrderandquaternion, which it used to drop.interactions.orbitaccepts a node name or a world point pluspositionandautoRotate. -
Instancing at scale (engine, rendering).
setInstanceTransforms(typedArray)is the per-frame path (about 0.3 ms of CPU for 18,000 instances), unchanged instance buffers skip the upload, and large instanced draws send only the instances inside the camera frustum. Dense shadow-casting instanced nodes (1,024 or more instances of a builtin primitive) use a coarser shadow stand-in, so their shadows are more faceted; opt out withshadowproxy=off. The 10,000-instance forest now completes on software GL in about 4 minutes (it did not finish before); it is still 3.3x to 3.9x the frame time of the same scene in three.js there. -
Animation layers, root motion, retargeting and two-bone IK work from the root with receipts (engine, animation). Fixes found on the way:
playLayerno longer activates its clip as a base action (masks leaked onto the whole body),mask: { humanoid, exclude }is honoured,addClipsFromaccepts a model node handle or id, and the retarget worker falls back to an in-process bake when it cannot start. Seedocs/api/animation-root.md. -
Root physics collision for box, sphere and capsule bodies has a receipt (engine). A bare capsule or cylinder physics spec now gets a collider that spans the visible size;
physics: { bindNodes: true }makes steppingapp.physicsmove the visible nodes. -
Scene kits and effects have pixel receipts (engine). Nine scene kits and the ambient-occlusion, colour-grade, vignette and depth-of-field effects have software-WebGL2 receipts.
effects.contactShadowsproduced identical frames in 4.3.7; it is now a real screen-space contact-shadow mask (next entry). Three kits reported problems against their own defaults (particle readiness gate, the solar-system sun check, neon-tunnel ring count) and are fixed; the built-in humanoid GLB is no longer rejected as an unsafe URL. Seedocs/agents/effects-and-scene-kits.md. -
effects.contactShadows()builds a screen-space contact-shadow mask that forward lighting samples (rendering). It replaces the interim lowering to the ambient-occlusion pass. The mask is built from scene depth before the forward pass, marched along the sun direction, and multiplied into the visibility of the shadow-casting directional light only (an absent mask is exactly 1.0). It needs a directional light withshadow: trueand a shadow caster: with a spot or point light only, or none, the effect renders nothing,diagnostics().shadows.contactShadows.unavailablesays why and one warning is logged. Orthographic cameras are supported. The glTF extension variants (clearcoat, transmission and similar) do not sample the mask, and a blocker deeper than twice the march length is ignored by design. Receiptevidence/receipts/effects-contact-shadows/4.5.0.json(software WebGL2, 600x400): the near-base floor darkens where the mask acts, the far floor and the spot and no-caster pairs are unchanged, and no ambient-occlusion pass is requested. Where the shadow map already shadows the receiver the mask adds little; the large effect is in the scene where the subject is outside the shadow map. -
@aura3d/react:AuraCanvasrenders its children and keeps its app across parent re-renders (react). Before,useAuraFrame,useAuraAppand<Model suspendOnLoad>inside it never ran and the app was recreated on every parent render. The package stays experimental; mount, cleanup and StrictMode have not run in a browser. -
aura3d migrate three: fidelity is tested and reported (cli). Everyexactrow names a fixture that runs against real three.js; 48 rows are exact (21 before), 150 approximate, 47 none and 0 pending (3 before). 14 math rows (Vector2/3/4,Matrix3/4,Quaternion,Euler,Color,Box3,Sphere,Plane,Ray,Frustum,Triangle) became exact by pointing at the new mutable subpath below; at option sites the codemod still emits the hex string or tuple. -
New
@aura3d/math/threesubpath: mutable, three.js-shaped math (math).Vector2/3/4,Matrix3/4,Quaternion,Euler,Color,Box3,Sphere,Plane,Ray,FrustumandTrianglemutate in place, returnthis, take target out-parameters and returnnullon a miss, withfromImmutable/toImmutableto cross to the immutable@aura3d/mathclasses, which are unchanged. 453 method-level goldens taken from three@0.185.1 backtests/unit/math/three-compat-parity.test.ts. Seeevidence/vs-threejs/wp2-math-compat.md. Fixed on the way:Clock.start()resets elapsed time, step tracks return the key's own value at its keyframe time,ShapeGeometrydrops the repeated closing vertex, andSphericalHarmonics3.getBasisAt(normal, target)fills its target. -
Capability audit and gates (docs, tools). The audit's
Proofcolumn names the receipt or test behind eachshippedrow, andnode tools/receipts/check.mjsfails a missing proof and lists receipts to regenerate when the minor version moves.tools/docs-codeblockstypechecks the effect, scene-kit and genre-kit examples and now resolves@aura3d/engine/physics. The benchmark gate istools/bench-vs-threejs/gate.mjs. -
Look presets with no HDRI keep their brightness (engine).
night-city,polar-night,neon-arcade,spaceandunderwaterused to be lit by the implicit neutral-room fill; they now carry an explicitenvironments.neutralfill (AuraLookV0Expansion.fill,preset: "neutral", intensity 0.85 for the three night looks, 1.0 forspace, 0.65 forunderwater, calibrated on steady-state captures), so their mean luma stays within about 5% of 4.3.7 in the standard look scene and inside the games. The first cut used the bakednight/studioprobes, whose diffuse irradiance is about 30x (night) and 0.8x (studio) of the neutral room: they read right on the first frame, while the analytic neutral floor was still bound, and dropped to near black once the baked probe loaded (Aura Diamond 3D Skyline 71 to 2.6, Hoops Shanghai 53.5 to 5.7). Like the implicit fill it replaces, the fill is dropped when the scene authors alights.ambient. The other ten presets bring an HDRI and are unchanged. -
Visual change: a scene that authors its own lights and no environment is now lit by those lights only (engine). A directional light of intensity I on a Lambert surface of albedo A gives
A * I / PI, ambient givesA * I / PI, and a hemisphere light givesA * mean(ground, sky) * I / PI(three.js r185's value on a horizontal normal; up- and down-facing surfaces differ by half the sky/ground gap). Before this, the scene category's implicit studio/daylight environment was stacked on top of the authored lights, which made the same nominal lights 2x to 13x brighter in linear light (measured on software WebGL2: one grey plane, directional intensity 1 gave linear 0.434 against three.js 0.069; the skinned-character bench scene read mean luma 192.5 against three.js 144.0). Scenes with anenvironments.*node, scenes with no lights at all, and scenes with a light probe are unchanged. To get the old fill back, addenvironments.studio()(or anyenvironments.*); to brighten or darken the whole frame, setoutput: { exposure }oncreateAuraApp. Hemisphere lights now contribute in this mode (they were dropped before). -
Ambient occlusion and depth of field read real depth (rendering).
createRenderTargetgave RGBA32F colour targets linear filters, which makes them texture-incomplete untilOES_texture_float_linearis enabled, so the v2 post chain's view-space depth read as zero: ambient occlusion darkened the frame by a constant factor with no crease structure and depth of field read the same zeros.renderTargetSampleFilterenables the extension and falls back to NEAREST for RGBA32F without it; RGBA8 and RGBA16F are unchanged, and scenes that never create an RGBA32F target are unchanged. This is an intended change toquality: "production"output, for scenes with ambient occlusion, god rays, depth of field, TAA, motion blur or auto-exposure. -
WEIGHTS_0rescaling of rounding noise no longer logs a console warning (assets). Skin weights whose sum is within 5% of 1 (export rounding on unmodified assets; the three.js Soldier has 52 vertices up to 2% off) are renormalized silently with oneconsole.debugline per primitive; real defects (degenerate or badly scaled weights) still warn.
Upgrade notes for the 25 live showcase games: docs/upgrade-4.5.0.