Fighting Game · Architecture

Audio, VFX, Cinematic & Signature Content Pipelines

A focused page within the Fighting Game Architecture documentation. The full map and every sibling page live in the Architecture hub.

9sections15 minread1diagram

On this page

This page covers the four presentation modules that turn a deterministic match into something an audience can feel: V2Audio (foley, voice, barks, dynamic music, spatialization, commentary), V2VFX (hit-sparks, blood, X-Ray, dismemberment, auras, stage destruction, weather), V2Cinematics (camera rigs, slow-mo, finishers, entrances, the replay viewer, MP4 export), and the cross-cutting per-fighter signature library and Character Presentation layer that bind those three together into a fighter's identity. Where the combat core has to be provably correct (see Combat System: GAS, Frame Data & Determinism), this layer has the opposite job: it is allowed to be as expensive and as hand-authored as the platform budget permits, provided it never desyncs a match. That single constraint shapes everything here. Every effect these modules emit is cosmetic, and the game-feel data they read is explicitly tagged rollback_budget_excluded and resim_cosmetic_suppressed in V2/balance/feel/hitstop_curves.csv — presentation is computed on the live frame and deliberately suppressed during rollback re-simulation, so a hit-spark or a slow-mo curve can never change the integer state the netcode hashes.

Architecturally, all three modules are built the same way and for the same reason. Each is a UGameInstanceSubsystem (UV2AudioSubsystem, UV2VFXSubsystem, UV2CinematicsSubsystem) that holds registered catalogs and exposes paired Resolve…/Queue… entry points, while the actual decision logic lives in a sibling …BlueprintLibrary of pure, static functions the subsystem delegates to. That split is not ceremony: it lets every resolution rule be unit-tested without a live world, and it keeps the math deterministic and side-effect-free so the same call produces the same answer on every machine. The source of truth is the Unreal C++ under V2/ue/Source/V2Audio, V2/ue/Source/V2VFX, and V2/ue/Source/V2Cinematics, the balance data under V2/balance/{dialogue,feel,cinema,audio,fighters}, and the compiled V2/ue/Plugins/V2AICommentary plugin. This page is part of the "Modes, Presentation & Interface" set; the section hub is ../V2_ARCHITECTURE.md.

What ships, honestly#

Real and tested (deterministic C++ that runs). The resolution logic in all three subsystems is genuine and heavily exercised: there are 26 audio, 9 VFX, and 37 cinematics dedicated *.spec.cpp suites under V2/ue/Source/V2Tests/Private/{Audio,VFX,Cinematics}/, plus module-level Audio.Module.spec.cpp, VFX.Module.spec.cpp, and Cinematics.Module.spec.cpp in V2/ue/Source/V2Tests/Automation/. These are not shape-only tests — they assert specific computed values. KOLastHitSlowMo.spec.cpp asserts that the Mortal Kombat Fatal-Blow curve reaches EvaluateDilationAt(0.08f) == 0.10f while the Tekken curve stays at 0.68f (readable), and that KO last-hit slow-mo is selectable by exactly four launch rulesets. The implementations behind those assertions are real algorithms (a piecewise-linear keyframe lerp for slow-mo, a gore-tier min-clamp for damage VFX, a fail-loud command router for middleware), not lookups of hardcoded results. The V2AICommentary plugin is compiledV2/ue/Plugins/V2AICommentary/Binaries/Linux/libUnrealEditor-V2AICommentary.so exists.

A real seam, not a real integration (audio middleware). The Wwise/FMOD "SDK integration" surface is honest about being a seam. InitializeWwiseSoundEngine and friends build a request struct and call Plan.ResolveCommand(...) (V2/ue/Source/V2Audio/Private/V2AudioBlueprintLibrary.cpp:4105), which validates a plan and either routes the command or rejects it with a tag like Audio.WwiseSDK.Rejected.NativeFallbackRequired (V2/ue/Source/V2Audio/Private/V2AudioTypes.cpp:1055). No actual Wwise or FMOD runtime is linked: V2Audio.Build.cs depends only on Core, CoreUObject, Engine, and GameplayTags. The native runtime is MetaSounds + Audio Modulation (EV2AudioRuntime::MetaSoundsAudioModulation is the default), and the middleware layer is a deterministic plan that records what would be issued and falls back loudly when the SDK is absent — exactly the fail-loud pattern, not a faked success.

Specified and validated, but art-pending. None of these modules ship the authored binaries the monolith's Content/<…>.uasset paths imply. The only authored gameplay .uasset in V2/ue/Content/ are the eight DA_RegionVariant_* data assets (plus an editor-only V2FrameDataInspector.uasset); there are zero camera-rig, Sequencer-preset, KO-curve, or Photo-Mode assets. Camera rigs, slow-mo curves, and Sequencer presets are modeled as USTRUCT catalogs registered at runtime, not as Content/Cameras/… or Content/Curves/… binaries. Voice-over is text + path placeholders: every locale_x_text column in V2/balance/dialogue/<fighter>.csv reads TODO, and the vo_file_path entries point at /Game/V2/Audio/Voice/… assets that do not exist yet. The per-fighter signature checklists say so explicitly — see the bolded note in V2/balance/fighters/Bishop/signature-checklist.md: a checked item "attests that the launch-roster signature catalog … defines and validates the requirement — it does not attest that any game asset has been authored." Treat this whole page as logic shipped, content pending.

Provider-gated. MP4 export's NIL/likeness check (@themis/likeness, forthcoming) and C2PA provenance stamping, licensed-streaming soundtrack rights, and the quarterly ADR recording pipeline are external dependencies; the code carries the gates and manifests, but the rights themselves are out-of-repo.

The shared pattern: register, resolve, queue, snapshot#

Every subsystem in this set follows one lifecycle, and understanding it once explains all three:

  1. Register — a RegisterXCatalog(const FX& Catalog, FString& OutFailureReason) call validates a catalog struct and stores it. Registration is fail-loud: an invalid catalog returns false with a human-readable reason and is not stored.
  2. Resolve — a BlueprintPure ResolveX(Request) const runs the deterministic decision (which template, which curve, which mix) against the registered catalog and returns a resolved struct carrying a bAccepted flag and, on rejection, a ReasonTag.
  3. Queue — a BlueprintCallable QueueX(Request) calls ResolveX, checks IsValidResult(...), and only then appends to a pending list; a rejected result is dropped with its reason rather than silently spawned. For example UV2VFXSubsystem::QueueAuraEffectVFX queues only when Result.IsValidResult(&FailureReason) && Result.bAccepted (V2/ue/Source/V2VFX/Private/V2VFXSubsystem.cpp).
  4. SnapshotCaptureRuntimeSnapshot() returns a flat struct of counts and "last resolved" fields (FV2AudioRuntimeSnapshot, FV2VFXRuntimeSnapshot, FV2CinematicsRuntimeSnapshot). This is the testable, introspectable surface the automation specs read back to confirm a registration or resolution actually happened.
flowchart LR Evt[Live match / replay event] --> Audio[UV2AudioSubsystem] Evt --> VFX[UV2VFXSubsystem] Evt --> Cine[UV2CinematicsSubsystem] Audio -- Resolve --> ABL[V2AudioBlueprintLibrary · pure] VFX -- Resolve --> VBL[V2VFXBlueprintLibrary · pure] Cine -- Resolve --> CBL[V2CinematicsBlueprintLibrary · pure] ABL -- accepted --> AQ[Queue + Snapshot] VBL -- accepted, gore-clamped --> VQ[Queue + Snapshot] CBL -- accepted --> CQ[Queue + Snapshot] GorePolicy[(Gore policy ceiling)] -. clamps .-> VFX NIL[(NIL / likeness gate)] -. blocks export .-> Cine Native[(Native-fallback seam)] -. routes .-> Audio AQ -- cosmetic, rollback-inert --> Frame[Presented frame] VQ --> Frame CQ --> Frame CQ --> Export[Replay viewer / MP4 export]

Audio pipeline (V2Audio)#

V2Audio is by far the largest of the three (V2AudioTypes.cpp alone is ~15.4k lines; V2AudioBlueprintLibrary.cpp ~7.5k), because it carries the full adaptive-music brain plus the middleware abstraction. The runtime baseline is MetaSounds + Audio Modulation (EV2AudioRuntime), and the FV2AudioRuntimeSnapshot in V2/ue/Source/V2Audio/Public/V2AudioSubsystem.h exposes hundreds of introspection fields covering each subsystem below.

  • Foley, voice, and barks. RegisterFighterFoleyCatalog + ResolveFighterFoleyLayer drive per-fighter footstep/cloth/weapon layers (EV2FoleyLayerKind); RegisterVoiceBank / QueueVoiceLine handle the per-fighter voice bank; and RegisterVoiceBarkCatalog / ResolveVoiceBarkEvent implement the priority + cooldown bark router on gameplay events (finisher and KO barks win all races).
  • Dynamic music. This is the richest part. Music intensity is a five-stage vertical stack — EV2MusicIntensity is Silence → Ambient → Tension → Climax → KOSting — driven by a real adaptive-music state machine (EV2AdaptiveMusicState: Exploration, Tension, Combat, Victory, Defeat, Menu). On top of that sit horizontal resequencing (verse/chorus/bridge via EV2HorizontalMusicSectionRole), vertical layering across seven instrument layers (EV2VerticalMusicInstrumentLayer: AmbientPad, Bass, Drums, Strings, Brass, Melody, Choir), intensity curves, one-shot stingers, sidechain-compression ducking under dialogue/SFX, beat-synchronized transitions snapped to beat/bar/phrase boundaries (EV2MusicSyncBoundary), tempo/BPM detection, and a Def Jam DJ-remix mixer. EvaluateMusicIntensityCurve updates the subsystem's CurrentMusicIntensity, CurrentAdaptiveMusicState, and active layer set only when the resolved result is accepted (V2/ue/Source/V2Audio/Private/V2AudioSubsystem.cpp).
  • Middleware abstraction (the seam). A unified provider layer (EV2AudioMiddlewareProvider) can route spatial sources, listeners, environment/reverb zones, occlusion raycasts, soundbank streaming, profiling, gameplay-event triggers, project generation, hot reload, fallback, and per-platform cook — for Wwise, FMOD, or a custom backend. As covered above, this resolves and validates commands but does not bind a real SDK; it routes to the native MetaSounds fallback when the middleware is absent.
  • Custom soundtrack, streamer-safe, and licensing. RegisterCustomSoundtrackPolicy / EvaluateCustomSoundtrackSource (EV2CustomSoundtrackSource, EV2MusicLicenseClass) gate user-imported tracks per platform TRC, and a streamer-safe catalog can auto-swap DMCA-risky tracks. Per-track license flags decide what may be uploaded to community galleries — the same per-import gate the entrance music slot enforces (below).
  • Spatial audio, commentary, crowd. Atmos / Tempest3D runtimes with a binaural HRTF fallback; a three-voice commentary stack with barge-in policy (EV2CommentaryBargeInPolicy) and ducking; per-fighter crowd chants, per-stage crowd noise, stamina-driven vocal modulation, a tournament "hush" mix, and announcer combo-callout tiers with language fallback. DualSense speaker routing and a microphone-consent gate (passive detection only; recording requires explicit consent) round it out.

VFX pipeline (V2VFX)#

UV2VFXSubsystem (V2/ue/Source/V2VFX/Public/V2VFXSubsystem.h) registers nine catalogs and exposes the same paired Resolve…/Queue… surface. The taxonomy is concrete and matches the design intent exactly:

  • Hit-sparks. EV2VFXStyle is the eight-spark library from the spec — Clean, Dust, Metal, Electric, Fire, Ice, Spirit, Blood — resolved by ResolveHitSpark to a FV2NiagaraTemplateSpec.
  • Gore, with a policy ceiling. EV2GoreTier is Off, Mild, Standard, Extreme. The important edge case is that the active gore policy clamps every request: ResolveCharacterDamageStateVFX min-clamps the requested tier to ActiveGorePolicy.GoreTier (V2/ue/Source/V2VFX/Private/V2VFXSubsystem.cpp:434), so a region or rating-board cap can never be exceeded by a caller asking for more. Blood is a full sub-pipeline: QueueBloodDecals, QueueGroundAndPoundBloodSplatter (EV2GroundAndPoundBloodPattern), and QueueBloodPool (EV2BloodPoolSpawnPolicy), with octagon-canvas absorption layers (EV2OctagonGroundTextureLayer) for the UFC ruleset.
  • X-Ray render pass. QueueXRaySkeletonPacket (and a cinematic variant, QueueXRayCinematicRenderPacket) builds packets across the X-Ray layers EV2XRayRenderLayer (TranslucentSkin, BoneStencil, BoneBreakFlash, OrganSilhouette, PierceThroughMask) with per-bone break types and animation states (EV2XRayBoneBreakType, EV2XRayBoneBreakAnimationState).
  • Dismemberment, hazards, trails, auras. ResolveDismembermentVFX is ruleset- and bone-gated (EV2CoreVFXRulesetScope restricts it to Mortal Kombat); stage hazards (EV2StageHazardVFX), weapon ribbon trails (EV2WeaponTrailProfileKind), and auras (EV2AuraEffectKind: DevilForm, SoulCharge, Heat, Burnout, the latter resolved against a normalized intensity) each have a resolve + queue pair.
  • Persistent damage and stages. Character damage layers (Sweat, Dirt, Bruise, Blood), a multi-tier damage-progression model with persistence rules, per-fighter signature damage VFX, stage destruction with reset policy (EV2StageDestructionResetRule), weather transitions (EV2StageWeatherKind), and atmospheric particles/god-rays. Every catalog has a b…CatalogValid snapshot flag so a cook can assert coverage before shipping.

Cinematic pipeline (V2Cinematics)#

UV2CinematicsSubsystem (V2/ue/Source/V2Cinematics/Public/V2CinematicsSubsystem.h) is the broadest by feature count, spanning camera, slow-mo, finishers, entrances, accessibility text, and the entire replay/export toolchain.

  • Per-ruleset camera rigs and slow-mo. Rigs key off EV2CinematicRuleset, which has nine members — the seven fighting rulesets (MortalKombat, StreetFighter, Tekken, WWE, UFC, SoulCalibur, DefJam) plus Racing and OpenWorld. Slow-mo is a real curve: EvaluateSlowMo looks up a FV2SlowMoCurveSpec by id and calls EvaluateDilationAt, a piecewise-linear interpolation over time-dilation keyframes (V2/ue/Source/V2Cinematics/Private/V2CinematicsTypes.cpp:356). ResolveKOLastHitSlowMo picks a per-ruleset KO style (EV2KOLastHitSlowMoStyle: Fatal-Blow strong, subtle, zoom-punch, broadcast-replay), which is what the balance file V2/balance/feel/slowmo_freeze_curves.csv encodes per ruleset (each row carries an accessibility_opt_out flag).
  • Finisher data assets. UV2FinisherData (V2/ue/Source/V2Cinematics/Public/V2FinisherData.h) is a UPrimaryDataAsset with a trigger condition (EV2CinematicTrigger, input motion/sequence, range window, required state tags), a soft cinematic sequence reference, a gore tier, a mode-eligibility bitflag (EV2FinisherModeEligibility: Fatality, Brutality, Friendship, Mercy, StageFatality, CriticalFinish, EnvironmentalFinisher), and eligible-ruleset tags. Its IsValidFinisherData validator is strict and domain-specific (V2/ue/Source/V2Cinematics/Private/V2FinisherData.cpp:78): a finisher must carry an id, a valid FinisherWindow trigger, a non-null cinematic ref, at least one mode bit, and an allowed ruleset tag (MK / Soul Calibur / Def Jam). Notably, finisher gore is restricted to Off, Mild, or Extreme — the intermediate Standard tier is deliberately excluded for finishers (IsSupportedFinisherGoreTier).
  • Entrance data assets. UV2EntranceData is the WWE/wrestling-grade entrance authoring model: ramp/curtain/aisle stage zones (EV2EntranceStageZoneKind), a pyro pattern with a safety radius and heat budget and a reduced-motion fallback (EV2EntrancePyroPatternKind), DMX-addressed lighting cues (EV2EntranceLightingCueKind), replay-safe camera cuts, pose-sequence montages, mic moments with captions and crowd response, a per-entrance music import slot (personal-use-only, with community-gallery upload blocked), and assignment scopes (Fighter, WWEUniverseShow, MyGMShow). A companion UV2EntranceEditorLibrary provides the editor-time validators (ValidateCameraCutSequence, ValidateAssignments, CanUseMusicImportSlotForEntrance).
  • Playback control: skip, resume, director cut, POV, commentary. Cinematics resolve skip granularity (EvaluateCinematicSkip), resume checkpoints (ResolveCinematicResumePoint), director-cut chapters, alternate POV, and an in-scene commentary track — each with a dedicated spec (CinematicSkipGranularity.spec.cpp, CinematicResumePoint.spec.cpp, DirectorCut.spec.cpp, AlternatePOV.spec.cpp).
  • Subtitles and captions. Speaker-tag styling, timing overrides, and cue captions (ResolveSubtitleSpeakerTag, ResolveSubtitleTimingOverride, ResolveCinematicCueCaption) make cinematic dialogue accessible.
  • Replay viewer and export. This is a full non-destructive editing surface layered over the deterministic input replay (the same stream V2Netcode produces — see Game Modes, Training & Replay): OpenReplayViewerSession, timeline edits, a free camera with orbit/entity tracking, a kill-cam (Start/Advance/CancelReplayKillCam), highlight detection (DetectReplayHighlights over EV2ReplayHighlightEventKind), and two export jobs — full QueueReplayExport and QueueReplayClipExport. Camera edits are keyframes (QueueReplayCameraKeyframe) layered on top of the original input, not edits to it. The MP4 export path is where the NIL/likeness gate and C2PA provenance stamping apply.

Character presentation & the per-fighter signature library#

The thing that makes a fighter feel theirs is not one module but a contract spanning all of them, expressed in two places.

The Character Presentation catalog (RegisterCharacterPresentationCatalog on the cinematics subsystem) carries the per-fighter presentation surface: bark triggers (EV2CharacterPresentationBarkTrigger: CounterHitLanded, ThrowLanded, ParryLanded, LowHP, ComboN, FinisherArmed, FinisherMissed, KO — the same gameplay events the audio bark router consumes), entrance styles (EV2CharacterPresentationEntranceStyle: WWEWalkout, TekkenStageArrival, MKPitSummon, SFHubArrival, DefJamClubStrut), nine ending-art styles (OilPainting, ComicBookPanel, AnimeCelShade, GothicWoodcut, HipHopGraffiti, PhotorealPortrait, UkiyoE, ArtNouveau, MangaInkWash), post-fight cutscene kinds (victory pose, UFC presser/mic interview, WWE mic moment), and unlock sources. The snapshot exposes bCharacterPresentationRosterReady, …MatchupsReady, …LoreReady, and …EntrancesReady so a cert pass can check roster coverage.

The Dialogue DB is real, per-fighter CSV. V2/balance/dialogue/<fighter>.csv (eight authored files: asha_storm, bishop_crowe, kai_voltage, lian_noor, mina_kade, nyx_river, rook_vale, sol_vega) carries the columns situation, opponent, ruleset, line_id, english_text, locale_x_text, vo_file_path, emotion, length_cap. Mirror matches use a dedicated mirror situation bank (e.g. Asha's Line.AshaStorm.Mirror.001, never the cross-matchup pool), and per-opponent lines override generic ones. The honest caveat: the locale_x_text column is uniformly TODO and the vo_file_path entries point at unrecorded assets — the text and routing ship; the localized VO does not.

The signature library is a per-fighter checklist at V2/balance/fighters/<Fighter>/signature-checklist.md (60 of them). Each tracks Section-72 requirements across animation, audio, VFX, stage, and HUD — eight unique impact stings, a signature crowd chant, stamina-driven breath layers, three dynamic theme variants, and so on. Crucially, the checklists are explicit that a checked box attests the catalog requirement is defined and validated (via UV2LaunchRosterLibrary::BuildDefaultFighterSignatureLibraryCatalog), not that any asset is authored; the "Asset authoring" section stays unchecked "until real assets land and pass the QA cert signature-library audit." This is the single clearest statement of where this whole layer sits: the contracts and resolution logic are real and tested; the art, audio, and VO they describe are the work that remains.

Director commentary, story theater & narrative expansion#

The "behind-the-scenes" layer has a real anchor and several spec-only extensions, and it is worth being precise about which is which.

Real and compiled: the V2AICommentary plugin (V2/ue/Plugins/V2AICommentary/). It defines validated catalogs — an Iris commentary cue contract, a post-match commentary spec, an auto-edited highlight reel spec (EV2AIHighlightShareFormat), a per-match analysis spec, an auto-clip library, a compliance spec, chat translation, and procedural dialogue — each built and validated through the BuildDefault… → Validate… → …Signature pattern (V2AICommentaryBlueprintLibrary). The cinematics narrative data is real too: V2/balance/cinema/cinematic-narrative-expansion.json carries four commentary track families (director, mocapBehindTheScenes, writer, internalMonologue), an ADR pipeline with quarterly session ids and per-event voice-line banks, and locale directors; BehindTheScenesCommentary.spec.cpp and DirectorCommentary.spec.cpp exercise the cinematics-side resolution.

Spec-only (referenced, not present): the monolith's V2/ue/Plugins/V2Mode_SideStory/, V2Mode_StoryTheater/, and V2Mode_CinematographyEditor plugins do not exist in the repo — the actual plugin set is V2AICommentary, V2AdaptiveAI, V2AssetLinter, V2Editor, and BellonaUnrealEditor. The Side-Story cinematic-plus-scripted-fights flow, the Story Theater browse/replay index with alt-language/subtitle/commentary toggles, the branch-tree visualizer, and the Ending Gallery are described in the architecture but are not yet code. The narrative-expansion data they would consume (commentary tracks, comics, ADR) is staged in V2/balance/cinema/ and the cinematics subsystem's FV2CinematicNarrativeExpansionCatalog, so the data contract exists ahead of the mode plugins.

Game feel, determinism, and failure modes#

The thread tying this page back to the combat core is the feel data under V2/balance/feel/. hitstop_curves.csv carries per-ruleset, per-reaction hitstop with attacker/defender/hitlag frame counts and — decisively — the columns rollback_budget_excluded and resim_cosmetic_suppressed set true on every row, so the feel layer is computed live and skipped on re-simulation. slowmo_freeze_curves.csv, camera_shake_curves.csv, and photo_mode_tone_curves.csv complete the set, each with an accessibility_opt_out lane. Accessibility is structural here, not bolted on: pyro and camera-cut definitions carry bReducedMotionFallback / bReducedMotionSafe, slow-mo rows carry accessibility_opt_out, and the microphone surface is consent-gated by construction.

Failure modes are uniformly fail-loud. A bad catalog fails registration with a reason string; a resolution that cannot be satisfied returns bAccepted = false and a ReasonTag (e.g. VFX.Aura.Rejected.InvalidResult, Audio.WwiseSDK.Rejected.NativeFallbackRequired) rather than spawning a degenerate effect; and the gore policy silently-but-safely clamps rather than honoring an over-budget request. Because every output is cosmetic and rollback-inert, the worst case for any bug in this layer is a missing or wrong effect on one client's screen — never a desync. That is the whole point of keeping presentation on the live frame and out of the hashed state.

For how these effects are triggered by combat, see Combat System: GAS, Frame Data & Determinism; for the montage notifies that fire foley and VFX, see Animation & Input Pipeline; for the replay stream the cinematics viewer edits, see Rollback Netcode & Tag-Team and Game Modes, Training & Replay.