V6 — Egbe — is a universe of LLM-driven autonomous beings, the Ori, and
the product promise is that you can stand next to one. An Ori is, by design,
split across three authorities: its decisions live in the Moirai cognition
cluster, its biography lives in the Ori service, and neither of them is a
body. The body is the UE5 client's job. The canonical Egbe client is a single
UE5.5 LTS project at V6/ue/, carved into eighteen *.Build.cs modules, and
its hardest problem is one V3's metaverse never faced at this scale: a single
Orun ground routinely renders far more simultaneous embodied agents than a V3
venue ever did, and each of those agents is a mind that costs money to think. So
embodiment in V6 is not just "spawn a skeletal mesh" — it is a coupled
render-and-perception LOD pipeline that decides, per agent per frame, how much
body it gets and how much cognition it is owed, so that fidelity and cost both
scale with what the player can actually see.
This page is the client side of that wire. It walks the UE5 module split, then the embodiment stack proper — the near pawn, the avatar runtime (VRM and MetaHuman through the vendored VRM4U plugin and the reused V3 avatar pipeline), emotion-driven animation, the Mass Entity density LOD ladder, and the StateTree-driven autonomous behavior that runs at the body when no model call is affordable. V6 reuses V3's avatar/animation/audio substrate wholesale and adds the agent-density and Ori-binding layer on top; the orientation map for the whole system is ../V6_ARCHITECTURE.md.
What ships, honestly#
The embodiment logic is real C++ and is tested. The avatar runtime, the
emotion→animation resolver, the agent density/perception LOD planner, the
Ori-backed LOD-transition continuity check, the StateTree behavior selector, and
the Sequencer cinematics director are all implemented under V6/ue/Source/ and
covered by V6Tests automation specs that the V6 completion run built and ran
on the on-box UnrealEngine-5.5.4 (the full V6 UE suite reported 30/30 green).
The load-bearing specs for this page are real and named:
V6.Avatar.Runtime.AppearanceSeedCostumeAndAging,
V6.Animation.EmotionDrivenGaitPostureIdleAndFace,
V6.Agent.NearPawnBindsFullEmbodiment / ...RejectsIncompleteEmbodiment,
V6.Agent.DensityLOD.Holds150AgentDrawBudget,
V6.Agent.PerceptionLOD.BoundsCognitionByVisibleAgents,
V6.Agent.LODBoundary.PreservesOriStateAcrossRenderLODs, and
V6.Agent.Behavior.SelectsPerCognitionTier / ...FailsLoudWithoutTree.
V6 ships zero binary UE content — by deliberate decision, not omission.
There are no .uasset/.umap files in the project; V6/ue/Content/ is
.gitkeep placeholders. The six Orun districts are authored as procedural C++
grounds (V6World/V6OrunDistricts.cpp), not authored levels, and the
embodiment modules here are the runtime binding and resolution logic plus the
data contracts that a skeletal mesh, an AnimBP, a MetaHuman master, or a VRM
body would be driven through — not the art itself. This is the same honest line
V3 draws between its real retarget tables and the avatars they gate
(v3arch§"Avatar Pipeline"): the pipeline is code; the bodies are content the
pipeline binds and validates.
VRM4U is vendored, not hard-linked. The avatar plugin is the third-party
VRM4U importer/runtime loader, dropped in at
V6/ue/Plugins/VRM4U/ as an untracked submodule with
"EnabledByDefault": false. Notably, V6Avatar.Build.cs does not list
VRM4U as a module dependency — it depends only on Core, CoreUObject,
Engine, GameplayTags, and V6Core. V6 reaches VRM bodies through soft
references (an FSoftObjectPath VrmAssetPath) and the named V3 retarget profile
V3Avatar.Oshun60, so the V6 C++ stays buildable and testable headless without
the plugin loaded. (On Linux the editor additionally needs VRM4U's
Shaders/Private case-shim symlink before it will boot — a build-time shim,
never committed.)
Four modules are honestly thin. The integration-boundary modules V6Net (32
lines), V6Gameplay (21), V6OnlineServices (31), and V6Telemetry (31) are
currently module-registration contracts; their heavy lifting lives in the Rust
services and the libs/v6/* packages (the wire protocol, for instance, is the
373-line proto3 schema in libs/v6/egbe-protocol, documented in the
gateway page). The
embodiment-critical modules — V6Avatar, V6Animation, V6Agent, V6Voice
(1,585 lines), V6Audio (527), V6Cinematics, V6UI, V6World — carry real
domain types.
The UE5 client module split#
C++ is the primary gameplay language; Blueprint is reserved for designers, data assets, and cinematic glue. The client is a high-fidelity client of authoritative Rust world-server state — it owns no frame-deterministic combat (that belongs to the destination Aye realm on incarnation), and all client-side prediction reconciles against the world server. The eighteen modules group into four bands:
- Foundation —
V6Core(theAV6EgbeGameMode/AV6EgbePawn, engine subsystems, save-game and V1-account bridge, theUV6GameFeatureDataregistration that lets districts and shard modes hot-load as Game Feature Plugins) andV6World(the client-side replicated shard modelUV6ClientWorldModeland the procedural district grounds). - Embodiment —
V6Avatar,V6Animation, andV6Agent, the subject of the rest of this page. - Interaction & presence —
V6Input(Enhanced Input plus an OpenXR backend matrix and VR stewardship interaction),V6Voice(the Vac mic / intent / squad client),V6Audio(MetaSound and conversation-audio types),V6UI(token-themed CommonUI roster / dossier / Chronicle / HUD widgets with first-classFV6AccessibilityDescriptormetadata),V6VFX, andV6Cinematics. - Integration & tooling — the four thin boundary modules above, plus
V6Persistence,V6Editor(the Egbe Studio authoring / verification commandlets), andV6Tests(the automation harness and Gauntlet drivers).
Agent embodiment: the near pawn#
The richest form an Ori can take is a near pawn: AV6AgentPawn, an
ACharacter that composes a UV6AgentComponent, a UAudioComponent for agent
TTS, and a USphereComponent for the interaction radius. These are the Clotho
candidates — co-present, on-screen, addressable, full collision and movement.
Binding one is a fail-loud contract, not a best-effort spawn.
UV6AgentComponent::BindNearAgent() takes a FV6AgentNearEmbodimentSpec and
the live skeletal-mesh, voice, interaction, movement, and collision components,
and BuildNearReadinessReport() returns a FV6AgentNearReadinessReport whose
EV6AgentNearBindingState is exactly one of Unbound, BoundIncomplete, or
RenderReady. RenderReady requires all capabilities present — an Ori id,
the V3 avatar pipeline binding (V3AvatarPipelineRef defaults to
V3Avatar.VRMOrMetaHuman), a full skeletal mesh, individual animation, voice,
expression channels, a renderable appearance seed, emotion animation, collision,
movement, and interaction. Anything missing is listed by name in
MissingCapabilities; the spec carries an EV6AgentBodySource of Vrm,
MetaHuman, or Procedural. This is what
V6.Agent.NearPawnBindsFullEmbodiment and its rejection twin guard — a
half-bound agent reports BoundIncomplete rather than rendering a broken body.
Avatars: appearance seed, costume, and visible aging (V6Avatar)#
V6Avatar is the runtime that turns an Ori's FV6AvatarAppearanceSeed into a
dressed, age-marked body. The seed names its EV6AvatarRuntimeSource (VRM or
MetaHuman), carries the soft VrmAssetPath / MetaHumanBlueprintPath, the
V3Avatar.Oshun60 retarget profile, a list of FV6AvatarCostumeSlotBinding,
and a list of FV6AvatarAgingMark. The default wardrobe is three slots —
body, outer (the steward-wrap), and accent (the "ori-thread") — each
mapped to a named material vector+scalar parameter pair.
The component does real engine work, not bookkeeping.
ApplyCostumeSlotsToMesh() calls
USkeletalMeshComponent::SetVectorParameterValueOnMaterials() and
SetScalarParameterValueOnMaterials() to tint each slot, and
ApplyAgingMarksToMesh() calls SetMorphTarget() plus a material scalar to
weight each aging mark. Visible aging — V6's signature addition over V3 — is
driven from arc state: ResolveLifeStageFromArc(ArcProgress, bTranscendent)
maps a normalized arc into NewlyKnown (<0.18), Young (<0.42), Adult
(<0.78), Elder, or Ancestor (on transcendence), and the three default marks
— adult-story-lines (weight 0.42), elder-silvering (0.72), and
ancestor-lumens (1.0) — fade in by stage via
FV6AvatarAgingMark::AppliesToStage(). BuildRuntimeBindingReport() is again
fail-loud: it enumerates every missing capability and only an avatar with an Ori
id, a runtime asset, the V3 retarget profile, required costume slots, and
stage-appropriate aging marks reports IsRenderable().
(V6.Avatar.Runtime.AppearanceSeedCostumeAndAging.)
Emotion-driven animation (V6Animation)#
The second V6 addition is that mood is legible at a distance, before any
dialogue. V6Animation maps eight EV6OriEmotionState values — Calm,
Joy, Focus, Concern, Grief, Anger, Awe, Tired — to gait, posture,
idle, and facial-curve profiles. BuildDefaultEmotionPoseMap() authors a full
FV6EmotionAnimationPose per emotion (grief, for instance, is
gait.grief.weighted + posture.closed.lowered, an 11° forward lean, and the
V6Face_Grief / V6Face_LowerLids curves), and
ResolveEmotionDrivenAnimation() takes the live FV6EmotionAnimationInput
(valence, arousal, confidence from the Ori) and blends it: arousal nudges the
gait-speed multiplier (clamped 0.25–1.75) and idle intensity, low confidence
lengthens the blend time, and the resolver computes a
MoodLegibilityDistanceMeters from posture lean, idle intensity, arousal, and
facial richness. ValidateMoodLegibilityAtDistance() enforces a real floor —
the blend must read at ≥ 12 m — so an agent's emotional state is
silhouette-legible across a plaza. An unrecognized emotion falls back to the
Calm pose rather than producing nothing.
(V6.Animation.EmotionDrivenGaitPostureIdleAndFace.)
The density LOD pipeline (Mass Entity)#
This is the part of embodiment that is genuinely new at the V6 scale, and it is
where V6Agent depends on the full UE Mass framework (MassEntity, MassLOD,
MassRepresentation, MassActors, MassSpawner, …). Agents stream across four
render tiers, and — the load-bearing idea — perception and cognition LOD are
slaved to render LOD, so the world server only spends rich perception, and
Moirai only spends a full model call, on agents the player can actually see.
UV6AgentDensityLODLibrary::PlanDensityLOD() sorts agents by visibility, then
importance, then distance (with a lexical Ori-id tiebreak for determinism) and
greedily assigns NearPawn within NearRadiusCm (default 2,500 cm) up to
MaxNearPawns, MidMassInstanced within MidRadiusCm (9,000 cm) up to
MaxMidMassAgents, FarSilhouette within FarRadiusCm (25,000 cm), and
Culled beyond. Caps and the draw budget are per platform, read from the
[V6.MassEntity] config section with code defaults: desktop allows 64 near
pawns / 64 mid / a 340-draw-unit budget; mobile drops to 24 / 48 / 160; a Pixel
Streaming worker to 48 near / 280; the Tier-2 fallback floor to 16 / 32 / 100. A
near pawn costs 4 draw units, a Mass-instanced mid agent 1, and the entire far
silhouette batch 1 — so the FV6AgentDensityLODSummary can prove
bWithinDrawBudget (V6.Agent.DensityLOD.Holds150AgentDrawBudget,
V6.Agent.DensityLOD.HoldsFestivalTierGatheringBudget).
PlanPerceptionLOD() then walks the render assignments and derives, per agent,
the EV6AgentPerceptionLOD (Rich / Coarse / Summary / Dormant) and the
EV6AgentCognitionTier (Clotho / Lachesis / Atropos / Dormant) directly
from the render LOD — NearPawn→Rich→Clotho, Mid→Coarse→Lachesis,
Far→Summary→Atropos. Because every cognition tier is anchored to a render tier,
the summary can assert bWithinCognitionBudget and
bRenderAndPerceptionLODsTrack: total cognition is bounded by the visible-agent
count, which is the client-side half of V6's cost story
(V6.Agent.PerceptionLOD.BoundsCognitionByVisibleAgents,
V6.Agent.PerceptionLOD.TracksRenderLOD). PlanAppearanceAssetStreaming()
closes the loop on memory: FullBody ≈ 48 MB resident, the shared mid proxy ≈ 12
MB, a silhouette ≈ 2 MB, dormant 0, each checked against the residency budget
and flagged bCanShedDetailWithoutPop.
The Mass side is concrete: UV6AgentMassVisualizationTrait (a
UMassMovableVisualizationTrait) carries the mid instanced mesh, the far
silhouette billboard mesh, and the silhouette material, and
RepresentationForRenderLOD() maps mid/far to
EMassRepresentationType::StaticMeshInstance. Agent identity, Ori durable
state, render LOD, and perception LOD all ride as FMassFragments
(FV6AgentMassIdentityFragment, FV6AgentOriDurableStateFragment, …) so they
survive the ECS.
Crossing a LOD boundary without popping#
The reason a player never feels an agent drop from a full pawn to a Mass
instance is that durable agent state lives in the Ori, not the pawn.
FV6AgentOriDurableState carries the Ori id, the current activity (id / tag /
phase / progress), the relationship LOD set, and the authoritative transform,
with explicit PreservesIdentityWith() / PreservesActivityWith() /
PreservesRelationshipsWith() / PreservesTransformWith() comparators (the
last with a 1 cm tolerance). ValidateLODTransitionContinuity() takes a from/to
transition and returns a FV6AgentLODTransitionContinuityReport that is
bSeamless only when the LOD actually changed and both sides are Ori-backed
and identity, activity, relationships, and transform are all preserved;
otherwise it lists the ContinuityBreaks by name. That guarantee is exactly
what V6.Agent.LODBoundary.PreservesOriStateAcrossRenderLODs asserts.
Autonomous behavior at the body (V6Agent StateTree)#
A budget without a behavior is useless, so V6Agent carries a real AI path.
Each frame the system has a cognition tier for an agent;
UV6AgentBehaviorComponent::EvaluateBehavior(tier) writes that tier into an
FV6AgentBehaviorBlackboard and runs an authored UStateTree through a real
FStateTreeExecutionContext. The tree's states are gated by
FV6AgentTierCondition (an enter-condition that passes when the blackboard tier
matches the state's MatchTier), and the matching state's
FV6AgentSetBehaviorTask writes the selected EV6AgentBehavior —
FullDeliberation for Clotho, CoarsePlanning for Lachesis, AmbientRoutine
for Atropos, Idle for Dormant. Crucially it fails loud: with no usable
StateTree assigned, EvaluateBehavior returns EV6AgentBehavior::None rather
than fabricating a behavior, which is what
V6.Agent.Behavior.FailsLoudWithoutTree pins (and
V6.Agent.Behavior.SelectsPerCognitionTier proves the real selection path, the
spec compiling a StateTree in-process). This is the believability floor the
cognition stack drops to when a model
call is unavailable or over budget.
Presence, cinematics, and the client edge#
Two more client subsystems carry embodiment beyond the live pawn.
V6Cinematics is the runtime Sequencer hook:
UV6CinematicsDirector::PlayAuthoredSequence() instantiates a real
ULevelSequencePlayer for an authored ULevelSequence, tracks it by tag, and
tears it down on StopPlaybacksByTag() / StopAllPlaybacks() — this is the
playback half of Clio Chronicle replays, incarnation ceremonies, and Yemaya
memorial reels. It is honestly scoped: the header states that offline
MovieRenderQueue render-to-file is not driven here, because it needs a live
GPU render unavailable in a headless -nullrhi context; the director owns
real-time playback and never fakes a render
(V6.Cinematics.Director.PlaysAndManagesAuthoredSequences). VR presence is
V6Input's VR stewardship interaction plus V6UI's VR comfort options,
validated by V6.XR.OpenXRBackendMatrix and
V6.XR.VRComfort.OptionsPersistenceReview, so a steward can be embodied
alongside their company in VR with comfort options that persist.
Underneath all of it, the client is a peer on one wire. The near pawn, the Mass
crowd, and the silhouette field are all rendered from interest-managed
egbe-protocol agent state delivered through the Realtime Gateway; the density
LOD planner's near/mid/far bands are the client-side consumer of the protocol's
interest windows and visible-agent caps. Fidelity is the only thing that moves —
identity, presence, and the authoritative world do not.
How it composes#
The client is the visible end of the mind/body/memory split. The body it renders
is owned by the
world server and shard continuum —
agent transforms, perception, and the 20 Hz tick that feeds the density
planner's distance / visibility inputs. The frames and the wire that carry that
state to a native UE client, a Pixel Streaming worker, or the Tier-2 three.js
fallback are
the gateway, Pixel Streaming, and the web fallback,
whose interest windows and per-surface agent caps the density LOD ladder mirrors
one-for-one. And the player's voice into an agent's ear — mic capture in
V6Voice, intent parsing, agent TTS played back on the pawn's
UAudioComponent, and squad comms — is
the Vac communication pipeline. Across all
three, the rule holds: the UE5 client makes the Ori legible — its dress, its
age, its mood, its attention — but it is never authoritative over who the Ori
is.