NullG's engine is built from scratch in C++20 with Vulkan rendering and AI-assisted development. SDL3 provides platform support and input, Jolt handles collision, Slang compiles shaders, Vulkan Memory Allocator manages GPU memory, and EnTT provides the scene registry.
The simulation runs at a fixed 60 Hz whether the engine is drawing one view, four views or none. It supplies race state to graphics, audio, HUDs, networking, replays and inspection tools. Rendering can interpolate between ticks without changing the simulation timestep.
The race simulation
GameSession handles the racers, race progression, rescue, random streams, weapons and projectiles. Each tick produces a snapshot and ordered events. Rendering interpolates between those snapshots, while audio and networking take the information they need. The simulation can also run without graphics, which is how the headless checks and reinforcement-learning workers use it.
WipEout and XL use separate physics paths to preserve their movement behaviour. NullG's original handling uses Jolt and SI units, with mass, thrust, drag, hover support and airbrakes determining how a craft drives. Collision and combat forces use the same physical units.
The shared coordinate system is right-handed, with +Y up, -Z forward and one unit per metre. Imported coordinates are converted during loading, so the rest of the engine has a consistent frame to work in.
Motion and sound
A planned motion cockpit would translate acceleration, braking, corners, elevation changes and impacts into physical movement and tactile feedback. Race telemetry provides the source data; hardware output is not yet implemented.
Audio is currently event-driven stereo, covering engines, weapons, impacts, warnings, menus and music. Split-screen balances the mix across player views. Positional audio is planned.
Rendering more than one view
Split-screen needs more than another camera pointed at the track. Each view has its own render targets, lighting selection, post-processing history and HUD. The scene is extracted once and shared, while the resources that depend on a particular camera stay with that view.
Separate view resources also provide a basis for a future cockpit with forward, peripheral and instrument displays. Local split-screen is implemented; the multi-display cockpit arrangement is not.
Gameplay scenes keep their presentation objects in an ECS registry. A render bridge passes triple-buffered snapshots to Vulkan so it can draw from stable data. The renderer uses dynamic rendering, bindless sampled images, GPU-driven draws and a depth pre-pass, followed by lighting, shadows, particles, HDR and post-processing.
Rendering budgets
Rendering presets control scene resolution, lighting, shadows, ambient occlusion, bloom, mesh detail and particles. Disabled effects skip their passes and release optional allocations. Particle capacity and geometry pools scale down as well, while texture resolution stays the same.
At 1080p output, Low draws the race at 960 × 540 and overlays a native-resolution HUD. Split-screen divides the scene pixel budget between active views. Scene extraction, particle preparation and immutable uploads are shared across cameras.
Auto starts conservatively based on available GPU memory. On hardware with GPU timestamps it can then adjust scene resolution to the measured load. Manual settings stay fixed. These changes affect the picture, not the physics, collision or AI.
Profiling on the second-generation Apple TV 4K's A12 exposed several bottlenecks. Redundant fragment-depth output prevented early depth rejection, while a per-pixel lighting path was expensive on devices with a unified graphics/compute queue. Fixes to those paths and scene scaling reduced GPU work. Audio refill polling was also made nonblocking after a mutex caused 45–48 ms stalls.
A subsequent one-minute Talon's Reach capture averaged approximately 60 fps on that device, using Low and FXAA with native XL physics, AI and source combat. The scene rendered at 960 × 540 with a 1080p HUD. This is a single-track measurement, not a result for every track, split-screen layout or GPU.
GPU-driven indirect draws reduce CPU submission work in the shared renderer. Hardware-specific paths stay within that renderer so fixes can apply across platforms.
Menus
Race setup uses a summary with separate pickers for the circuit, ship, pilot and speed class where supported. Each game keeps its own draft. Browsing a ship doesn't select it; confirming a choice returns to the summary, and Start Race launches the event.
Advanced Rules edits a copy with Apply Changes and Cancel. Race Again retains the last successfully started setup, so browsing or changing a draft doesn't overwrite it.
The multiplayer lobby follows the same idea. Each player chooses their craft and locks it with Ready. The host edits the event settings separately, then applies the complete change for everyone.
Loading content
NullG's core content includes the menus, icons, controller previews, fallback music and import interface. User-imported tracks, ships, textures and sounds live in a separate library, with their source identity and provenance retained.
Resource identities include the source game, which keeps similarly named assets from getting mixed up and lets multiplayer compare gameplay-critical content. The rebuilt XL fleet is bundled separately as replacement visuals. It doesn't include the original tracks, audio or gameplay data.
Model and track preparation can run on IO workers, with staged uploads moving the prepared data to the GPU. A disk cache avoids repeating CPU model preparation on later loads. The current background stays visible while the next one is prepared, and track sections use shared geometry pools and streaming.
Scene activation, static shadows and some legacy loading paths can still block, and streaming coverage varies between sources. Preparation, upload completion and activation remain separate stages, allowing the current scene to stay visible while its replacement is prepared.
Making the models
The original menu props and controller previews start with visual references and finish in Blender. Model generation is used where it helps, with Meshy and Blender MCP assisting the work. The export scripts keep the process repeatable and retain where the assets came from. Editable models stay separate from the game exports, so individual parts and materials can still be changed.
The five modern XL ships use the same authoring process. FEISAR, Qirex, Auricom, AG Systems and Piranha are reconstructions of the original designs, separate from original NullG content. AI-assisted construction is finished in Blender. Editable .blend files and 4K texture masters are retained; the runtime assets are self-contained GLBs with 2K textures.
Worn satin paint, exposed metal and glass use normal maps for surface detail and packed occlusion, roughness and metallic maps for material response. Checks cover scale, orientation, bounds, geometry and texture costs, including rear and underside views. Exports are reviewed in the native viewer, menus and races to check both close-up detail and readability at racing distance.
The model data is shared when several racers use the same ship. Each racer has its own cosmetic aileron movement driven by steering and airbrakes. The original collision geometry, handling and participant identities remain unchanged. Modern Ship Models is on by default for supported XL ships; switching it off restores the original visuals.
Importing the games
Players supply their own game media. The importer identifies the edition, presents it for review, extracts the content and records hashes and manifests before activating it in the user's library.
For original WipEout PSX media, that means reading mixed-mode BIN/CUE data and converting CD audio ranges to WAV masters. The source adapters then load the models, textures, tracks, sound banks and race metadata.
XL has its own prepared asset path for track geometry, texture metadata, ships, music and presentation. Once decoded, both games use the shared engine systems.