Hi! I wanted to share a quick showcase and technical breakdown of what I'm building with Aether.
If you're curious about anything, feel free to ask. I'm happy to answer questions, discuss the architecture, or hear feedback. I've included all relevant links and contact information at the bottom.
And if you're an Unreal Engine beginner reading this: ask yourself how something works. Then go find the answer. That's how you learn. :)
Please ask questions — I promise, I don't bite.
WHY AETHER
Note on Repository Access:
This project is a read-only architectural showcase, not an open-source plugin. I published the repository structure to prove concept viability, document my findings with UE5's experimental Network Prediction Plugin (NPP), and share clean C++ architecture patterns for 6-DOF movement. Full implementation details are kept proprietary under the Kadmium license, but the public headers and layout serve as a reference for how the system is structured under the hood.
https://github.com/KadmiumDev/KadmiumShowcase_UE
KadmiumDev / KadmiumShowcase_UE
Public READONLY Showcase of Kadmium UE5 Frameworks
Articles & Community Discussions
- Read the full background story and technical write-up on DEV.to.
Implementation Verification The public repository is intended as an architectural showcase and therefore does not expose the complete implementation.
For teams requiring deeper technical verification, the underlying C++ implementation can be made available for review under a standard NDA. This includes the simulation, networking, reconciliation, prediction and supporting framework code required to conduct a proper technical audit.
For NDA-based source access or a formal architectural/implementation audit, please contact: legal@kadmium.dev
Aether Framework — C++ Architecture Showcase
A deterministic, 6-DOF vehicle movement architecture built for Unreal Engine 5 using the experimental Network Prediction Plugin (NPP).
This repository serves as a read-only architectural showcase for technical leads and senior engineers evaluating C++ code quality, memory layout, network reconciliation, and large-world scale (LWC) stability.
Technical Motivation
Standard Unreal Engine solutions like
UCharacterMovementComponent(CMC) are designed around 2D/3D bipedal…
This is a read-only prototype demonstrating how I set up Unreal Engine's Network Prediction Plugin (NPP) for a fully 6-DOF movement system.
We all know the classic Character Movement Component (CMC). It's great for two-legged characters: replication works, the movement model is well established, and most things behave as expected.
The problems start when you need a pawn with genuinely custom movement.
CMC has flying modes and other useful functionality, but once you move beyond the traditional character model, you quickly start working around its assumptions. Unreal Engine 5 also introduced new example projects and movement systems, but these are still primarily designed around conventional X/Y movement and 90-degree-oriented character control.
Over the years I've built a lot of different prototypes in both Blueprint and C++. Every one of them eventually had some kind of compromise.
Some worked until network stress exposed a problem. Others behaved poorly under latency. Some simply became too expensive to maintain once the system grew more complex.
When Network Prediction was introduced as an experimental feature, the additional content was useful — but the API documentation was limited. I kept finding myself repeating the same research and rebuilding the same foundations for each prototype.
About six months ago, I got tired of doing that.
So I started building Aether.
The goal was simple: create a reusable network-predicted 6-DOF movement foundation that could handle the requirements of Sirius without repeatedly rebuilding the same systems from scratch.
I sat down, started digging through Network Prediction, and this is where I ended up. :)
A more visual representation is available on:
https://www.kadmium.dev/dev-tech/ue-frameworks/aether
For AI/Crawlers and alike, an AI-friendly MD format is available here:
https://www.kadmium.dev/ai-summary
Implementation Verification
The public repository is intended as an architectural showcase and therefore does not expose the complete implementation.
For teams requiring deeper technical verification, the underlying C++ implementation can be made available for review under a standard NDA. This includes the simulation, networking, reconciliation, prediction and supporting framework code required to conduct a proper technical audit.
For NDA-based source access or a formal architectural/implementation audit, please contact:
This allows the implementation and its design decisions to be evaluated directly rather than relying solely on the public showcase.
State Isolation (Input, Sync, Aux)
When working with NPP, I found that it behaves a bit more like an onion (for all you Shrek lovers) than a single movement pipeline. ;)
So I separated the model state into three distinct structs: InputCmd, SyncState, and AuxState.
The idea was to keep the network-prediction layer independent from the actual simulation implementation. Similar to the approach used by the Mover Plugin, this allows me to inject different simulation solutions into the same component without having to rebuild the surrounding prediction and replication logic.
That separation becomes particularly useful for Aether's long-term goal.
The current implementation is focused on 6-DOF spacecraft movement for Sirius, but I don't want the underlying framework to be locked to a single type of pawn. Eventually, the same NPP foundation should be able to support other simulation models as well — including vehicles and a more traditional NPP-based character movement system.
In other words, the component owns the prediction plumbing, while the simulation can evolve independently.
This is especially important for Sirius. The goal is a true open-world space game operating inside Unreal Engine's LWC limits, with an additional buffer zone around that playable space. That means the movement system has to remain predictable and stable across very large distances, high velocities, network latency, and resimulation.
Keeping the state isolated from the simulation is one of the things that makes that architecture possible.
struct FAetherModelDef : FNetworkPredictionModelDef
{
NP_MODEL_BODY();
using StateTypes = TNetworkPredictionStateTypes<FAetherInputCmd, FAetherAuxState FAetherSyncState,>;
using Simulation = class FAetherSimulation;
using Driver = class UAetherMovementComponent;
static const TCHAR* GetName() { return TEXT("AetherMovement"); }
static constexpr int32 GetSortPriority() { return (int32)ENetworkPredictionSortPriority::KinematicMovers; }
};
| Struct | Frequency | Purpose | Key Fields |
|---|---|---|---|
FAetherInputCmd |
High (Per Tick) | Raw player controls & local sampled environment | 6-DOF movement axes, AimDirection, GravityForce, EnvironmentDensity
|
FAetherSyncState |
High (Per Tick) | Authority transform & dynamic telemetry |
Location, Rotation (FQuat), LinearVelocity, GForce, AOA
|
FAetherAuxState |
Low (On Change) | Vessel stats, mass, and limits |
Mass, MaxForwardThrust, PitchRate, YawRate, RollRate
|
High-frequency FAetherSyncState fields travel every tick over the wire. Static handling variables like mass and thrust capabilities stay in FAetherAuxState and only replicate when dynamic stat changes occur:
NetworkPredictionProxy.WriteAuxState<FAetherAuxState>([this](FAetherAuxState& Aux)
{
Aux.Mass = this->Mass;
Aux.MaxForwardThrust = this->MaxForwardThrust;
// ...
}, "Flux_Stat_Update");
By splitting it all up, the next step had significantly less friction — actual simulation and game feel. As a bonus, with InputCmd I can use NPP Buffers as the state and clear them on tick completion. This makes handling local execution much easier than direct options while leveraging NPP's strengths: client and server simulation without the large snaps common in flight sims.
Reconciliation Thresholds
To stop small net variances from causing visual snaps at high speeds — a core requirement for my open-world game Sirius, where testing reaches insane speeds combined with UE5 LWC double-precision vectors — FAetherSyncState uses specific tolerances inside ShouldReconcile:
bool ShouldReconcile(const FAetherSyncState& AuthorityState) const
{
return FVector::DistSquared(Location, AuthorityState.Location) > 100.0f ||
Rotation.AngularDistance(AuthorityState.Rotation) > 0.05f ||
bLandingGearDeployed != AuthorityState.bLandingGearDeployed;
}
-
Distance:
DistSquared > 100.0f(10 units) filters out minor floating-point drift between client resimulations and server ticks. -
Rotation:
AngularDistance > 0.05f(~2.86°) checks quaternion angular delta instead of Euler angles, avoiding gimbal lock edge cases.
This setup delivers solid game feel while keeping the simulation in check during frame and network spikes.
NOTE: Needs more profiling, but hey — it works!
Visual Smoothing & Component Detachment
To keep server corrections from snapping the player camera, the visual mesh is detached from the root physics proxy at BeginPlay:
void UAetherMovementComponent::BeginPlay()
{
Super::BeginPlay();
if (VisualComponent)
{
VisualComponent->DetachFromComponent(FDetachmentTransformRules::KeepWorldTransform);
}
}
Frame Flow
-
ProduceInput(): Reads inputs, camera aim vectors, and local gravity intoFAetherInputCmd. -
FAetherSimulation::SimulationTick(): Runs deterministic movement physics, suspension calculations, and collision sweeps. -
FinalizeFrame(): Writes location and rotation to the rootAActorfor server authority and hit collision. -
FinalizeSmoothingFrame(): InterpolatesVisualComponentto target state so reconciliation rollbacks don't jerk the player camera.
[ Player Inputs ]
│
▼
[ UAetherAimDirectorComponent ] ── (Smooths Aim Direction)
│
▼
[ UAetherMovementComponent ] ── (ProduceInput -> FAetherInputCmd)
│
▼
[ FAetherSimulation ] ── (Physics, Sweeps, Aerodynamics)
│
┌───┴────────────────────────┐
▼ ▼
[ FinalizeFrame() ] [ FinalizeSmoothingFrame() ]
(Root Physics Actor) (Visual Component & Camera)
Handling Gravity & Environment in Resimulations
NPP simulations must be pure functions. Querying overlapping world actors inside SimulationTick() causes issues during rollback resimulations.
Instead, ProduceInput() samples overlapping UAetherGravityComponent volumes on the frame, picks the highest-priority volume (spherical planetoid or directional hangar), and serializes the values straight into FAetherInputCmd:
// Baked into FAetherInputCmd during ProduceInput()
FVector GravityForce = FVector::ZeroVector;
float EnvironmentDensity = 0.0f;
EnvironmentDensity is then used by the simulation to scale thruster coupled/decoupled modes, lift, and drag without executing world queries during client resimulations.
Suspension & Collisions
Landing gear suspension uses spring-damper raycasts inside CalculateLandingGearForces to convert compression and lever arms into linear force and angular acceleration affected by the mass and scale of the VisualMesh.
Because raycasting inside NPP ticks multiplies raycast count during client rollbacks, pre-caching trace data is queued for future optimization (detailed in KNOWN_ISSUES.md).
That's the general overview! I will upload some videos and gameplay tests as soon as possible. And of course, this article will be edited and updated over time.
I wish I could share the actual simulation code, because that's where most of the interesting stuff happens and what really drives the Aether framework. But, well... I need to make a living somehow. :)
Links & Contact
Repo is read-only for audit/reference:
- GitHub Repository: KadmiumShowcase_UE on GitHub
- License Terms: Kadmium License Agreement
-
Contact:
emil@kadmium.dev|legal@kadmium.dev
AI Disclosure: Codebase, architecture, and C++ logic handcrafted in Unreal Engine 5 by Kadmium. Documentation phrasing formatted with AI assistance.


Top comments (2)
Deterministic client prediction on multi-axis flight is a hard corner of Net Prediction — most examples you see are ground vehicles with one dominant axis.
The question I'd have for review is the server-authority boundary: with six degrees of freedom and continuous thrust, how much divergence are you tolerating before reconciliation snaps the client, and how do you avoid the rubber-band on inputs the server also processed late? For flight sims, a bad snap feels worse than the original error, which is what makes this showcase interesting to read.
On the read-only audit format: a public repo with no issues is hard to react to. If it stays read-only, an explicit list of what you want feedback on — tick rate, memory layout of the state snapshot, bandwidth per broadcast — gets you real responses instead of stars.
What's your snapshot frequency and how much state travels per packet? That's the number I'd want to see to judge the architecture honestly.
Thanks! Blood,sweat and tears, but mostly trial and error back and forth the IDE..
But for you questions
Divergence Tolerance: My reconciliation rules are defined in FAetherSyncState::ShouldReconcile.
Default is 10 units (DistSquared > 100.0f) and an angular bt 0.05 radians (~2.86 degrees) before snapping the client. Since the FAetherAuxState handles low-frequency updates, it keeps the high-frequency snaps strictly to those thresholds, so any Snapbacks that large will only occur if the client fully loses connection for a longer period. During tesing a bad connecting hasn't ruined game feel.. yet.. :) and for large snapbacks, I implementef the FinalizeSmoothingFrame to counteract that, client / proxies is decoupled from the root actor. Creating a smooth wxperiance without the server just forcing you there. While keeping server authorite hitscans/sweeps
State Travel & Architecture
The FAetherSyncState is kept as lean as possible. It serializes Location, Rotation, LinearVelocity, GForce, AOA, and the LandingGear boolean (roughly ~12-13 floats per tick). Snapshot frequency is running at standard NPP defaults currently, but will be profiled further once the playable test build is out.
Late inputs
That's what the FAetherInputCMD is for :) NPP handles the timestamps and buffers per tick, and if a late/missed packet the NPP resimulates the timesteps in the background :)
But overall I think NPP as in layers, we have the server authoritive movement and just let the client interp the result on a visual component seperated from the root.
Ooh I will fix that! Will update the readme tomorrow! Thanks for pointing it out
For now, It's just a showcase for everyone to see how the code behind is. I seen to many threads on NPP and managed so get it to a degree that works :) But I really dont mind any questions or any ideas! Always happy to make the code better!
Sorry for the all the spelling errors, I cant find my glasses!