acdream/docs/plans/animation-system-audit.md

557 lines
22 KiB
Markdown

# Animation System Audit
Phase A audit for `feature/animation-system-complete`.
Date: 2026-04-28.
## Summary
The animation core is much stronger than the feature surface around it.
`AnimationSequencer` already handles cyclic state changes, transition links,
negative-speed retail remaps, mid-cycle speed changes, frame hooks, and
PosFrame root-motion accumulation. `GameWindow.OnLiveMotionUpdated` already
routes `InterpretedMotionState.Commands[]` through `PlayAction`, which means
server-broadcast NPC/monster/emote/action overlays are likely to animate when
the server emits motion commands.
The remaining gap is mostly orchestration:
- local combat/spell/item-use commands build wire packets but do not yet drive
the local visible action immediately;
- several combat/spell/emote packet surfaces need conformance fixes before
animation triggers can be trusted: combat mode enum values, split
melee/missile attack builders, `CombatCommenceAttack`, `AttackDone`,
damage/death notification parsers, `MagicSchool` enum order, and outbound
emote/soul-emote builders;
- combat/spell/item-use game events populate state/chat but do not yet map to
animation overlays for attacker/defender/caster;
- style changes are handled as simple `SetCycle(style, motion)` swaps, not the
full ACE `MotionTable.GetObjectSequence` multi-link style transition chain;
- held posture/emote commands need a small command resolver and tests around
one-shot-vs-persistent routing;
- death needs explicit `Sanctuary` action -> `Dead/Fallen` persistence rather
than relying on chat/health side effects.
## Evidence Sources
Named retail decomp:
- `CMotionTable::is_allowed` at `0x005226C0`
- `CMotionTable::get_link` at `0x00522710`
- `CSequence::update_internal` at `0x005255D0`
- `CMotionInterp::adjust_motion` at `0x00528010`
- `CMotionInterp::charge_jump` at `0x005281C0`
- `CMotionInterp::get_jump_v_z` at `0x00527AA0`
- `CMotionInterp::jump` at `0x00528780`
- `CMotionInterp::apply_current_movement` at `0x00528870`
- `CMotionInterp::HitGround` at `0x00528AC0`
- `CMotionInterp::LeaveGround` at `0x00528B00`
- `CMotionInterp::DoMotion` at `0x00528D20`
- `CMotionInterp::DoInterpretedMotion` at `0x00528360`
- `ClientCombatSystem::HandleCommenceAttackEvent` at `0x0056AD20`
- `ClientCombatSystem::SetCombatMode` at `0x0056BE30`
- `ClientCombatSystem::StartAttackRequest` at `0x0056C040`
- `ClientCombatSystem::EndAttackRequest` at `0x0056C0E0`
- `ClientCombatSystem::StartPowerBarBuild` at `0x0056ADB0`
- `ClientCombatSystem::GetPowerBarLevel` at `0x0056ADE0`
- `ClientCombatSystem::ExecuteAttack` at `0x0056BB70`
- `ClientCombatSystem::HandleDefenderNotificationEvent` at `0x0056C920`
- `ClientCombatSystem::HandleEvasionDefenderNotificationEvent` at `0x0056C620`
- `ClientCombatSystem::HandlePlayerDeathEvent` at `0x0056C320`
- `ClientCombatSystem::HandleAttackerNotificationEvent` at `0x0056B420`
- `ClientCombatSystem::HandleAttackDoneEvent` at `0x0056C500`
- `CM_Combat::Event_ChangeCombatMode` at `0x006A9A70`
- `CM_Combat::Event_TargetedMeleeAttack` at `0x006A9C10`
- `CM_Combat::Event_TargetedMissileAttack` at `0x006A9D60`
- `AttackHook::Execute` at `0x00526B70`
- `gmSpellcastingUI::Cast` at `0x004C6050`
- `ClientMagicSystem::CastSpell` at `0x00568040`
- `ClientMagicSystem::FreeHandsAndCastSpell` at `0x00566EF0`
- `ClientMagicSystem::GetAppropriateSpellFormula` at `0x00567D50`
- `CM_Magic::Event_CastUntargetedSpell` at `0x006A3150`
- `CM_Magic::Event_CastTargetedSpell` at `0x006A3040`
- `ItemHolder::UseObject` at `0x00588A80`
- `CM_Inventory::Event_UseEvent` at `0x006AC3B0`
- `CM_Inventory::Event_UseWithTargetEvent` at `0x006AC480`
- `CM_Item::DispatchUI_UseDone` at `0x006A8510`
- `CommandInterpreter::PlayerIsDead` at `0x006B3D70`
- `SmartBox::HandlePlayScriptID` at `0x00452020`
- `CM_Physics::DispatchSB_PlayScriptID` at `0x006ACC40`
- `CM_Physics::DispatchSB_PlayScriptType` at `0x006AC6E0`
- `ClientCommunicationSystem::DoEmote` at `0x00578AD0`
- `ClientCommunicationSystem::Pose` at `0x00580480`
- `ClientCommunicationSystem::Handle_Communication__HearEmote` at
`0x0057CBE0`
- `ClientCommunicationSystem::Handle_Communication__HearSoulEmote` at
`0x0057D020`
- `ChatPoseTable::InqChatPoseCommand` at `0x00570AD0`
- `ChatEmoteData::Pack` at `0x004FCE80`
Cross-reference material:
- `docs/research/deepdives/r03-motion-animation.md`
- `C:\Users\erikn\source\repos\acdream\references\ACE\Source\ACE.Server\Physics\Animation\MotionTable.cs`
- `C:\Users\erikn\source\repos\acdream\references\ACE\Source\ACE.Server\Physics\Animation\MotionInterp.cs`
- `C:\Users\erikn\source\repos\acdream\references\ACE\Source\ACE.Entity\Enum\MotionCommand.cs`
- `C:\Users\erikn\source\repos\acdream\references\holtburger\apps\holtburger-cli\src\pages\game\combat.rs`
- `C:\Users\erikn\source\repos\acdream\references\holtburger\crates\holtburger-core\src\client\messages.rs`
- `C:\Users\erikn\source\repos\acdream\references\holtburger\crates\holtburger-protocol\src\messages\movement\types.rs`
The clean worktree intentionally does not contain `references/`; it was read
read-only from the original checkout path above.
## Current Code Surface
Core animation:
- `src/AcDream.Core/Physics/AnimationSequencer.cs`
- `SetCycle(style, motion, speedMod, skipTransitionLink)` handles cyclic
state changes and transition links.
- `PlayAction(motionCommand, speedMod)` handles Action, Modifier, and
ChatEmote one-shots through Links/Modifiers lookup.
- `Advance(dt)` emits pending hooks and accumulates PosFrame deltas.
- Missing: full style-transition chain, durable modifier list, action queue
accounting, and a public command-resolution facade that callers can test
without `GameWindow`.
- `src/AcDream.Core/Physics/MotionInterpreter.cs`
- Handles locomotion, jump, leave-ground/hit-ground, and basic contact
guards.
- Missing: full retail `MotionState`, action list, modifier list, hold-key
run application, combat-state guards, and `move_to_interpreted_state`.
- `src/AcDream.Core/Physics/MotionCommandResolver.cs`
- Reconstructs full 32-bit commands from 16-bit wire values.
App integration:
- `src/AcDream.App/Input/PlayerMovementController.cs`
- Local walk/run/strafe/turn/jump driver. It does not own combat/spell/item
action animation.
- `src/AcDream.App/Rendering/GameWindow.cs`
- `OnLiveMotionUpdated` is the main inbound motion/action router.
- `OnLiveVectorUpdated` seeds airborne jump arcs and Falling cycles.
- `OnLivePositionUpdated` snaps positions and lands airborne remotes.
- `TickAnimations` advances sequencers and drains hooks.
- `UpdatePlayerAnimation` drives the local movement cycle.
- Missing: typed animation coordinator for combat/spell/use/death/emote
events; too much command mapping still lives inline.
Wire/state:
- `src/AcDream.Core.Net/Messages/AttackTargetRequest.cs`: outbound attack
request exists, but currently combines melee and missile into one layout;
retail/ACE/holtburger use distinct `0x0008` melee and `0x000A` missile
payloads.
- `src/AcDream.Core.Net/Messages/CastSpellRequest.cs`: outbound spell request
exists.
- `src/AcDream.Core.Net/Messages/CharacterActions.cs`: combat mode request
exists, but the combat-mode enum must be corrected to retail values
`NonCombat=1`, `Melee=2`, `Missile=4`, `Magic=8`.
- `src/AcDream.Core.Net/Messages/InteractRequests.cs`: use/use-with-target
request exists.
- `src/AcDream.Core.Net/GameEventWiring.cs`: combat, spell, item, chat events
route into state classes.
- Missing: public `WorldSession.SendAttack/SendCast/SendUse/ChangeCombatMode`
wrappers and animation-side subscriptions.
## Retail Command Catalogue To Use
From ACE `MotionCommand.cs` + `r03-motion-animation.md`:
- Locomotion substates: Ready `0x41000003`, WalkForward `0x45000005`,
WalkBackward `0x45000006`, RunForward `0x44000007`, TurnRight
`0x6500000D`, TurnLeft `0x6500000E`, SideStepRight `0x6500000F`,
SideStepLeft `0x65000010`, Falling `0x40000015`.
- Held/posture substates: Crouch `0x41000012`, Sitting `0x41000013`,
Sleeping `0x41000014`, Dead `0x40000011`, Fallen `0x40000008`.
- Item/use substates: Reload `0x40000016`, Unload `0x40000017`, Pickup
`0x40000018`, StoreInBackpack `0x40000019`, Eat `0x4000001A`, Drink
`0x4000001B`, Reading `0x4000001C`.
- Spell substates/actions: CastSpell `0x400000D3`, MagicBlast
`0x4000002B`, MagicSelfHead `0x4000002C`, MagicSelfHeart `0x4000002D`,
MagicBonus..MagicPenalty `0x4000002E..0x40000034`, MagicTransfer
`0x40000035`, MagicEnchantItem `0x40000037`, MagicPortal `0x40000038`,
MagicPray `0x40000039`, MagicPowerUp01..10 `0x1000006F..0x10000078`,
MagicPowerUp01Purple..10Purple `0x1000012B..0x10000134`.
- Combat actions: Sanctuary `0x10000057`, ThrustMed/Low/High
`0x10000058..0x1000005A`, SlashHigh/Med/Low `0x1000005B..0x1000005D`,
BackhandHigh/Med/Low `0x1000005E..0x10000060`, Shoot `0x10000061`,
AttackHigh/Med/Low1..6 `0x10000062..0x1000006A` and
`0x10000186..0x1000018E`, MissileAttack1..3 `0x100000D0..0x100000D2`,
SpecialAttack1..3 `0x100000CD..0x100000CF`, dual-wield/offhand ranges
`0x10000173..0x1000019A`.
- ChatEmote actions: Wave `0x13000087`, BowDeep `0x1300007D`, Laugh
`0x13000080`, Point `0x13000084`, Salute `0x1300008A`, Kneel
`0x13000092`, HaveASeat `0x13000152`, DrudgeDance `0x13000151`, plus
the full `0x1200/0x1300` ranges in `r03`.
- Persistent emote states: `0x430000EA..0x430000FD`, SnowAngelState
`0x43000118`, CurtseyState `0x4300011A`, AFKState `0x4300011B`,
MeditateState `0x4300011C`, SitState `0x4300013A`,
SitCrossleggedState `0x4300013B`, SitBackState `0x4300013C`,
PossumState `0x43000142`, HaveASeatState `0x43000145`. ACE's enum is a
useful alias catalog but has a shifted range for some late chat-emote states;
named-retail values win when hard-coding constants.
## Category Audit
### 1. Own Player Movement
Status: mostly working.
Evidence: retail `CMotionInterp` jump/grounding symbols listed above; ACE
`MotionInterp.cs` for `adjust_motion`, `apply_current_movement`, `HitGround`,
and `LeaveGround`.
acdream locations: `PlayerMovementController`, `MotionInterpreter`,
`UpdatePlayerAnimation`, `OnLiveVectorUpdated`, `OnLivePositionUpdated`.
Gaps:
- held postures exist as retail commands but are not driven by a general
posture/action API;
- `MotionInterpreter` does not yet own full `MotionState`, so non-locomotion
commands cannot be uniformly tested there;
- mounted/swimming need dat/retail verification before any implementation.
Tests to add:
- posture state `SetCycle` tests for Crouch/Sitting/Sleeping;
- `motion_allows_jump` conformance for item/spell/aim/posture ranges;
- local action does not stomp Falling while airborne.
### 2. Other Players' Movement
Status: partially working after the K-fix series.
Evidence: `UpdateMotion` handling in `OnLiveMotionUpdated`; retail
`CMotionInterp::DoInterpretedMotion` and `apply_current_movement`; ACE
`MotionInterp.apply_current_movement`.
acdream locations: `RemoteMotion`, `OnLiveMotionUpdated`,
`OnLiveVectorUpdated`, `OnLivePositionUpdated`, `TickAnimations`.
Gaps:
- remote action overlays only happen when the server includes
`InterpretedMotionState.Commands[]`; combat/spell game events do not yet
synthesize overlays when the wire omits motion commands;
- no test fixture exercises `OnLiveMotionUpdated` command-list routing outside
`GameWindow`;
- root-motion deltas are accumulated but not applied to remote body transforms.
Tests to add:
- command-list `Wave` -> `PlayAction` routing through a new coordinator;
- airborne remote ignores mid-arc locomotion cycle swaps but still updates
interpreted movement;
- landing swaps Falling back to current interpreted command.
### 3. NPC Movement
Status: likely works for UpdateMotion-driven locomotion and simple gestures;
not verified.
Evidence: retail MotionTable/InterpretedMotionState path; ACE
`MotionTable.GetObjectSequence` and `MotionInterp.move_to_interpreted_state`.
acdream locations: `CreateObject.ParseServerMotionState`,
`OnLiveMotionUpdated`, `TickAnimations`.
Gaps:
- no NPC-specific live test checklist;
- no retained action/modifier list, so repeated scripted gestures are
fire-and-forget overlays only;
- no head-look/threat-pose state beyond whatever arrives as motion commands.
Tests to add:
- synthetic NPC `UpdateMotion` with `Commands=[Wave, Ready]` plays one-shot
then returns to Ready;
- style-default fallback for creature motion tables.
### 4. Monster Movement
Status: locomotion probably works when `MotionTableId` and UpdateMotion are
present; special attacks are unknown.
Evidence: ACE MotionTable supports monster actions such as HeadThrow,
FistSlam, BreatheFlame, SpinAttack, Bite, SpecialAttack1..3.
acdream locations: same as NPC movement; `AnimationHookRouter` for VFX/audio
side effects.
Gaps:
- attack action overlays for monsters depend on server motion command lists;
- no mapping from combat events to visible monster attack/hit reactions;
- no exotic creature spot-checks.
Tests to add:
- `PlayAction(BreatheFlame)` resolves from Links/Modifiers when synthetic data
provides it;
- Attack hooks fire exactly once for a synthetic monster action.
### 5. Combat Actions
Status: wire codecs and combat state exist; visual action orchestration is
missing for local and event-driven paths.
Evidence:
- retail `ClientCombatSystem::StartPowerBarBuild`,
`ClientCombatSystem::GetPowerBarLevel`, `ClientCombatSystem::ExecuteAttack`,
`HandleCommenceAttackEvent`, `HandleAttackerNotificationEvent`,
`HandleAttackDoneEvent`;
- ACE `MotionTable.GetAttackFrames` scans Attack hooks and is the canonical
hit-frame source;
- holtburger combat UI tracks `AttackCommenced`, `AttackDone`, victim,
attacker, defender, evasion, and killed feedback as runtime state.
acdream locations:
- `AttackTargetRequest` exists but no `WorldSession.SendAttack` wrapper was
found;
- `CombatState` emits `DamageTaken`, `DamageDealtAccepted`, evasion,
`AttackDone`, and `KillLanded`;
- `GameEventWiring` registers combat event parsers;
- `AnimationSequencer.PlayAction` can play the swing once the command is known.
Gaps:
- combat-mode enum values are currently non-retail for missile/magic;
- melee/missile attack request builders need to be split to retail layouts:
`0x0008 targetGuid, attackHeight, power` and
`0x000A targetGuid, attackHeight, accuracy`;
- `CombatCommenceAttack (0x01B8)` is enumerated but not parsed/wired;
- `AttackDone (0x01A7)` and attacker/defender/death notification parsers need
ACE/holtburger fixtures before downstream animation can trust them;
- `CombatState` has no `CurrentMode`, no attack sequence active flag, no
selected target, and no power-bar state;
- no local predictive swing on attack request;
- hit reactions (Twitch/Stagger/Tipped/FallDown) are not mapped from defender
notifications;
- style changes for draw/sheath do not run the full style-transition chain.
Tests to add:
- parse/wire `CombatCommenceAttack`;
- `CombatAnimationCoordinator` maps height/power/style to attack command;
- defender hit quadrant maps to a stable flinch command;
- `AttackHook` dispatch is one-shot.
### 6. Spell Casting
Status: outbound cast packets and spellbook/enchantment state exist; visible
cast-stage animation is missing.
Evidence:
- retail `ClientMagicSystem::CastSpell` and `FreeHandsAndCastSpell`;
- `gmSpellcastingUI::Cast` calls `ClientMagicSystem::CastSpell`;
- outbound cast actions are `0x0048` untargeted (`spellId`) and `0x004A`
targeted (`targetGuid`, `spellId`);
- retail/ACE school order is `War=1`, `Life=2`, `Item=3`, `Creature=4`,
`Void=5`;
- MotionCommand spell catalogue above;
- `GameEventWiring` wires spellbook/enchantment updates but not casting
animation.
acdream locations:
- `CastSpellRequest` targeted/untargeted builders;
- `Spellbook`, `SpellTable`, `GameEventWiring` spell handlers;
- `AnimationHookRouter` already routes hooks to audio/VFX sinks.
Gaps:
- no cast coordinator reading server `UpdateMotion`, spellcasting chat,
`PlayScript.Fizzle`, `UseDone`, and errors into one local cast timeline;
- no fizzle/interruption animation mapping from `PlayScript.Fizzle = 0x51`
(ACE sends speed `0.5`) and `WeenieError`;
- no recoil/release state;
- no local immediate cast animation on request.
- `MagicSchool` enum currently needs conformance against the retail/ACE order.
Tests to add:
- spell school/effect classifier maps to MagicBlast/MagicSelf/MagicPortal;
- fizzle error maps to a one-shot action or recovery state once retail
command is confirmed;
- cast request triggers local action overlay without waiting for enchantment.
### 7. Emotes
Status: inbound text parsers and chat display exist; motion command-list
emotes likely animate if server emits them. Slash-command-to-emote wire and
text-event-to-animation are missing.
Evidence:
- retail `ClientCommunicationSystem::DoEmote`, `HelpEmote`,
`DoEmoteList`, `InitializeEmoteInputActionHash`;
- retail `ClientCommunicationSystem::Pose` looks up a token in
`ChatPoseTable`, issues the motion command locally, then sends SoulEmote;
- `ChatEmoteData::Pack`;
- ACE MotionCommand ChatEmote range.
acdream locations:
- `EmoteText` and `SoulEmote` top-level parsers;
- `ChatLog.OnEmote` / `OnSoulEmote`;
- `GameWindow.OnLiveMotionUpdated` command-list `PlayAction` route.
Gaps:
- no outbound `Communication_Emote (0x01DF)` or
`Communication_SoulEmote (0x01E1)` GameAction builder found;
- `MoveToState` currently writes zero command-list entries, so the client
cannot yet send pose/emote commands in the retail motion-state path;
- `ChatInputParser` has no `/em`, `/emote`, `/me`, `/sit`, `/kneel`,
`/sleep`, or `/lie` parsing;
- `EmoteText`/`SoulEmote` text events do not carry an emote id, so they
should not be used as the primary animation source unless retail proves a
deterministic text -> command mapping;
- held postures need `SetCycle`, not `PlayAction`.
Tests to add:
- `MotionCommandResolver` reconstructs representative ChatEmotes;
- command-list Wave routes to `PlayAction`;
- persistent Sit/Meditate routes to `SetCycle`.
### 8. Death Animations
Status: death chat and killer notifications exist; pose transition is missing.
Evidence:
- retail `CommandInterpreter::PlayerIsDead` checks forward command
`0x40000011`;
- MotionCommand `Sanctuary = 0x10000057` is an action and must not be used as
the persistent death state;
- MotionCommand `Dead = 0x40000011` and `Fallen = 0x40000008` are persistent
states;
- `PlayerKilled` top-level message and `KillerNotification (0x01AD)` are
parsed/wired.
acdream locations:
- `PlayerKilled`, `ChatLog.OnPlayerKilled`;
- `CombatState.OnKillerNotification`;
- `MotionCommand.Dead` currently incorrectly comments `0x10000057` in
`MotionInterpreter`; this should be split into `Sanctuary` action and
`Dead` substate before death work.
Gaps:
- no explicit death animation coordinator;
- no hit-direction-aware fall;
- no dead-pose persistence or respawn reset.
Tests to add:
- death event plays Sanctuary then persists Dead/Fallen;
- movement is blocked while Dead/Fallen;
- respawn/reset returns to Ready.
### 9. Item-Use Animations
Status: outbound use builders exist; local visible use animations are missing.
Evidence:
- retail `ItemHolder::UseObject`;
- MotionCommand item/use states: Pickup, StoreInBackpack, Eat, Drink,
Reading, HouseRecall, LifestoneRecall.
acdream locations:
- `InteractRequests.BuildUse` / `BuildUseWithTarget`;
- `ItemRepository`, appraise/use-done event enum.
Gaps:
- no `WorldSession.SendUse` wrapper found;
- `UseDone (0x01C7)` is enumerated but not parsed/wired;
- `0xF754 PlayScriptId` is wired, but target anchoring and speed handling need
audit; `0xF755 PlayScriptType` is not wired;
- no item-class-to-motion mapping.
Tests to add:
- potion use maps to Drink;
- food maps to Eat;
- scroll/book maps to Reading;
- recall spell/item maps to recall command once retail source is confirmed.
### 10. Mounting / Dismounting
Status: not implemented; likely not relevant to retail AC character movement.
Evidence: `r03` lists `Graze` as a monster-only/mount-like stance, but no
player mount feature has been verified in retail references in this audit.
Action: defer until a server/content feature requires it. Do not invent
mounting behavior.
### 11. Floating-Point / Polish
Status: partially implemented.
Evidence:
- `AnimationSequencer.MultiplyCyclicFramerate` exists and is tested;
- `LocalAnimationSpeed` exists in `MovementResult`;
- PosFrame deltas are accumulated in `AnimationSequencer`.
Gaps:
- root-motion deltas are not composed into entity/body transforms;
- remote animation speed scaling is tied to ForwardSpeed/SidestepSpeed/TurnSpeed
only when UpdateMotion carries them;
- style-transition and modifier physics combination are incomplete.
Tests to add:
- same-motion/different-speed rescale remains green;
- root-motion delta is consumed by an integration coordinator;
- modifiers combine velocity/omega instead of replacing base cycle physics.
## Implementation Order
1. Extract an `AnimationCommandRouter` in Core/App-adjacent code that owns
`SetCycle` vs `PlayAction` routing for full 32-bit commands. Move the
command-list logic out of `GameWindow.OnLiveMotionUpdated` into tests.
2. Add missing MotionCommand constants and fix the `Dead`/`Sanctuary`
distinction.
3. Fix combat wire conformance first: combat-mode enum, split attack builders,
`CombatCommenceAttack`, `AttackDone`, damage/evasion/death notification
parsers, and fixtures from ACE/holtburger.
4. Wire `CombatState.CurrentMode` and `WorldSession.SendAttack/ChangeCombatMode`;
trigger local and remote swing overlays through the router.
5. Add spell-cast event/state wiring: `WorldSession.SendCast`, school enum
conformance, `UpdateMotion` cast actions, spellcasting chat,
`PlayScript.Fizzle`, `UseDone`, and errors.
6. Add outbound emote/soul-emote builders, MoveToState command-list emission,
chat parser aliases, and posture routing.
7. Add item-use wrappers, `UseDone`, script target anchoring, and
item-class-to-motion mapping.
8. Add death coordinator and respawn reset.
9. Port full ACE style-transition/modifier/action queue semantics into a
`MotionTableWalker` or equivalent, replacing `SetCycle` special cases only
after the category tests cover current behavior.
10. Apply/consume root motion where retail expects it; leave purely decorative
PosFrames un-applied when decomp/ACE proves they should not move the body.
## Visual Sign-Off Points
The agent can build, test, and live-launch autonomously, but these require
user visual confirmation before claiming complete:
- local attack swing + defender flinch;
- local spell windup -> release/fizzle;
- local `/wave` and persistent sit/lie/kneel/sleep;
- local death pose and respawn recovery;
- potion drink/eat/read animations;
- remote observer view for all of the above.