# Product Promise & Surfaces

```mermaid
mindmap
  root((V2 product promise))
    Game
      Per-ruleset combat feel
      Modes training replay and events
      Roster stages story and progression
      Racing and open-world crossover
    Web
      Competitive and esports presence
      Creator operator and support surfaces
      Public results and community
    Companion
      Read-only progress events and replays
      Notifications accessibility and recovery
    Shared spine
      Identity entitlement and content versions
      Online authority integrity and persistence
      Store telemetry audit and operations
```

The surfaces expose different jobs and authority. The companion and public web
may project match truth; only the governed game/service path can create or
settle it.

V2 is one fighting game built on Unreal Engine 5.5 that has to feel like seven
different fighting games — Mortal Kombat, Street Fighter, Tekken, Soul Calibur,
UFC, WWE, and Def Jam — without becoming a compromise blend of all of them. That
is the product promise, and it is the thing every other V2 feature is in service
of. But a fighting game in 2026 is not only the match: it is a launcher and a
front-end, a competitive web presence, an out-of-game companion, a store, a
developer portal, and a cloud backbone that ties them together. This page is the
**orientation door** to the V2 feature catalogue. It states what V2 commits to
shipping _as a fighter_, then walks the **product surfaces** that commitment
reaches across — the game client, the web surfaces, and the companion — naming
the real code behind each and labelling honestly what is built, what is wired as
a contract, and what is still spec. It is the features-side companion to the
architecture's product-promise page, and it hands the deep mechanics off to its
siblings rather than re-deriving them. The feature map this page belongs to is
[../V2_features.md](../V2_features.md).

## What ships, honestly

The **game client is the substantive surface and it is real**. `V2/ue/` is a
UE5.5 project with **27 Source modules on disk** (`ls V2/ue/Source/*/` returns
exactly 27 directories), and the modules carry genuine weight rather than stubs:
`V2Gameplay` is ~218 C++ files of Gameplay Ability System code, `V2Combat` ~36,
and the player-facing `V2UI` module ships **87 headers** of CommonUI screens,
HUD widgets, and accessibility surfaces. The promise's "persistent main menu"
and "in-match HUD that auto-switches per ruleset" are not aspirational copy —
they have named C++ classes behind them (catalogued under the game-client
section below).

The **web surfaces are real and plural**, not one marketing page. `apps/v2/web/`
holds a Vite + React application (`apps/v2/web/src/App.tsx`, data-driven from
`apps/v2/web/src/data/marketingData.ts` and `buildReportData.ts`) plus a set of
schema-backed static surfaces — `hub/`, `community/`, `esports/results/`,
`balance/`, `calendar/`, `support/`, `live-service/`, `legal/`, and a real
`dev-portal/` documentation tree. A second, shell-native web surface lives in
the sister monorepo at `apps/oshun/web/src/app/v2/` as a Next.js `/v2` route.
The **services backbone is large**: `apps/v2/` holds **91 service directories**,
most of them thin bridges to shared Oshun substrates.

Three honest qualifications keep this page from over-claiming:

- **The esports "toolkit" is real TypeScript, but it is not a standalone bracket
  builder.** `apps/v2/esports-tools/` is the package `@v2/esports-tools`, and
  its shipped source (`esports-broadcast-pipeline`,
  `arena-led-projection-integration`, `veritas-esports-fact-checking`) wires
  broadcast production (`@uzume/broadcast`), in-arena LED/projection
  (`@uzume/lumina`, `@uzume/prism`), and post-match fact-checking
  (`@veritas/fact-checking`). The bracket builder, scheduler, and result
  reporter that the feature monolith lists are surfaced as a **public REST API**
  (documented in `apps/v2/web/dev-portal/tournament-tool-api.md`) and a results
  web surface — not as a binary under `tools/esports/src/`.
- **The companion is an honest seam.** A real OpenAPI contract exists at
  `libs/openapi/v2/companion.yaml` and the public API is documented in
  `apps/v2/web/dev-portal/api-reference.md`, but **there is no iOS/Android app
  codebase in the repo** — the mobile client is planned. By deliberate design
  the companion is read-only and out-of-game, which is an integrity decision as
  much as a product one (detailed below).
- **AI-produced broadcast and generation are provider-gated.** The `iris-*`,
  `isis-*`, `psyche-*`, and `euterpe-*` packages under `apps/v2/` are real
  orchestration bridges; the live commentary, synthesized voice, and animated
  caster face they produce are capabilities of the shared AI substrates those
  bridges call, and they fail loud when a provider is unconfigured rather than
  fabricating a caster.

The deeper enforcement story — how a promise becomes a contract becomes a CI
gate — is the architecture companion
[../architecture/v2-product-promise.md](../architecture/v2-product-promise.md),
and the determinism that the netcode promise rests on is
[../architecture/combat-system-gas-frame-data-and-determinism.md](../architecture/combat-system-gas-frame-data-and-determinism.md).

## The product promise — what V2 commits to as a fighter

V2's promise, authored in `V2/V2_features.md` under features§"V2 Product
Promise", is a small set of non-negotiable commitments. The unifying idea is
**per-ruleset feel, one shared spine**: a match in Mortal Kombat ruleset must
feel like MK; in Tekken ruleset, like Tekken; in WWE ruleset, like WWE — "no
compromise blends" — yet all rulesets share one roster, one creator suite, one
online backbone, and one story. The commitments that matter for orientation:

- **One product, not seven.** Per-ruleset feel with no blends. Mode and ruleset
  identity live in the `V2Modes` registry today; per-ruleset combat feel is the
  subject of
  [./combat-systems-defense-and-game-feel.md](./combat-systems-defense-and-game-feel.md).
- **Rollback netcode is the default for the small-roster competitive core.** The
  promise targets rollback for 1v1 and 2v2 tag at 60 Hz with a bounded rollback
  window under typical latency; 3v3 tag, Royal Rumble, and large in-ring modes
  fall to client-server with input prediction; battle-royale, World Tour, Battle
  Hub, Convoy, Heist, and World Boss run on dedicated servers. These are
  **stated targets**, not measured ship metrics on this page — the rollback
  engine's real state is the combat sibling and the architecture's netcode
  pages.
- **Complete launch content** across every advertised mode — no "coming soon"
  panels — and **first-class single-player** content where each career-style
  mode stands alone as a long-form experience.
- **Honor the audience.** Gore is opt-in/opt-out and locale-aware; the UFC sim
  is faithful; WWE booking depth is respected; Soul Calibur weapon depth is
  honored; Tekken juggle culture is preserved; Street Fighter motion inputs are
  left unsmoothed; Def Jam soundtrack feel is preserved.
- **Treat the creator suite as a first-class surface** — CAF / CAW / CAS / CAA /
  CAE / CAM — not a checkbox.
- **Cross-play and cross-progression** across PC, PS5, XSX, Switch 2, and Steam
  Deck (provider-gated via the online-services plugins).
- **Degrade safely** under offline, partial-net, low-bandwidth, controller-loss,
  mid-match-disconnect, and provider-outage conditions, and **launch only with**
  automated verification, observability, runbooks, release gates, and rollback
  plans in place.

The hard floor under the rollback promise is determinism — rollback re-simulates
past frames, so the same inputs must produce bit-identical state on both peers —
which is why the build itself, not just the gameplay code, carries the
determinism policy. That chain is owned by
[../architecture/v2-product-promise.md](../architecture/v2-product-promise.md).
For the notation that lets these promises stay machine-checked across five large
documents — bare section references, target-artifact discipline, the package-
and link-honesty gates — see
[./foundations-glossary-and-conventions.md](./foundations-glossary-and-conventions.md).

## The surfaces the promise spans

V2 is one game, but the product reaches well beyond `V2/ue/`. Three player- and
developer-facing surface families carry it.

### The game client (`V2/ue/`)

The game client is where the promise is actually played, and it is the most
heavily-built surface. The **persistent front-end** is real CommonUI C++:
`V2UI/Public/V2MainMenuScreen.h` is the menu spine, with `V2MatchSetupScreen.h`
driving the Play funnel, `V2CommerceScreen.h` the store,
`V2FrontendPolishScreen.h` the front-of-house polish layer, and a full modding
front-end (`V2ModBrowserScreen.h`, `V2ModAuthorDashboardScreen.h`,
`V2ModLoadOrderScreen.h`, `V2ModDependencyResolutionScreen.h`). The **Modes Hub
funnel** the promise describes is backed by the `V2Modes` module
(`V2ModeRegistrySubsystem.h`, `V2ModeCatalog.h`, `V2ModesConfigAsset.h`) — mode
identity lives in a registry so a ruleset can be selected and swapped rather
than hard-compiled into the menu.

The **per-ruleset in-match HUD** is the part of the promise that `V2UI` proves
most concretely. Rather than one fixed overlay, the module ships
ruleset-specific widgets: `V2HealthResourceBarWidget.h`, `V2HypeMeterOverlay.h`,
`V2HitMarkerWidget.h`, `V2AmmoResourceCounterWidget.h`, and a dedicated MMA HUD
family (`V2MMABodyDamageIndicatorOverlay.h`,
`V2MMAFacialDamageVignetteOverlay.h`, `V2MMAPointDeductionOverlay.h`) so an
octagon round reads like UFC while a fighting-game round reads like SF. The
promise's "HUD-scale + reduced-motion variant" is not a stub either:
`V2HUDAccessibilitySettingsWidget.h`, `V2HUDThemePickerWidget.h`,
`V2CameraShakeIntensitySlider.h`, `V2ColorblindSafePalette.h`,
`V2ColorblindSimulation.h`, `V2HighContrastMode.h`, and
`V2FontAccessibilityOptions.h` all exist as authored surfaces — the same
reduced-motion ceilings the combat game-feel catalog reads. There is also a
training-and-coaching HUD layer (`V2HitConfirmTrainerOverlay.h`,
`V2InputBufferTutorialOverlay.h`, `V2InHUDCombatTelemetryOverlay.h`).

Two promise items are real-but-bridged rather than self-contained in the client.
Photo-mode tournament tie-ins route through the
`photo-mode-tournament-voting-bridge` service, and the in-game changelog /
"what's new" feed and parental controls (gore tier, profanity, chat,
community-content visibility) are gated by the locale and compliance data under
`V2/legal/` and the live-ops services. The moment-to-moment combat the HUD sits
on top of is
[./combat-systems-defense-and-game-feel.md](./combat-systems-defense-and-game-feel.md).

### The web surfaces (`apps/v2/web/` and the shell tile)

V2 ships **two distinct web surfaces** that should not be conflated.

The **shell-native tile** is `apps/oshun/web/src/app/v2/` in the sister monorepo
— a Next.js `/v2` route whose `page.tsx` renders a `V2ShellSurface` component
and consumes the shared shell clients (`@oshun/shell-core`,
`@oshun/auth-client`, `@oshun/developer-portal`, `@oshun/persistence`). It
carries `glossary/`, `roadmap/`, and `wiki/` subroutes, so the in-game knowledge
surfaces (frame data, per-ruleset mechanic explanations, strategy terms) have a
real web home rather than a standalone CMS.

The **standalone `apps/v2/web/` surface** is a Vite + React app plus a family of
schema-versioned static surfaces, each backed by a JSON data file with an
explicit schema string:

- `hub/` (`v2.webHub.v1`) — the account hub: handle, rank, Crown points,
  Battle-Pass tier, faction, a region-aware `commerce` block carrying a refund
  policy, friends presence, and a wishlist.
- `community/` (`v2.web.community.v1`) — featured player / crew / replay of the
  week, plus a creator gallery where every entry carries `moderation` and
  `consent` flags (the moderation pipeline is a real `apps/v2/` concern).
- `esports/results/` (`v2.esports.resultsArchive.v1`) — a searchable results
  archive with tiered `rankingWeights` (championship / major / regional / local
  plus win and replay bonuses) and per-event match records.
- `balance/` — public frame data as both `balance.json` and a `frame-data.csv`,
  `calendar/` (live-service calendar), `support/`, `live-service/`
  (`config-dashboard`, `content-calendar`, `economy-balance-tuning`, `roadmap`),
  and `legal/sub-processors`.

The **developer portal** (`apps/v2/web/dev-portal/`) is real documentation, not
a placeholder: `api-reference.md`, `tournament-tool-api.md` (bracket creation,
result reporting, leaderboard ingest, HMAC-signed webhooks), `broadcast-sdk.md`,
a `caster-api/` (with `schema.json` and reference overlays), a
`discord-bot-template/`, `modding-policy-pc.md`, plus the code of conduct,
privacy policy, and terms of service. The operator-side esports tooling
(`@v2/esports-tools`) sits behind it, treating `@uzume/broadcast` as the primary
broadcast pipeline and explicitly marking itself `mayInfluenceRollback: false`
so broadcast operations can never feed deterministic match state. End-to-end
coverage for these surfaces lives under `apps/v2/web/e2e/` as Playwright specs.

### The companion (planned mobile client, live API contract)

The **companion is V2's clearest honest seam**, and it is intentional. The
public-facing contract is real: `libs/openapi/v2/companion.yaml` is the OpenAPI
spec, and `apps/v2/web/dev-portal/api-reference.md` documents the surface —
`GET /player/{playerId}/stats` (rank, league, win-rate, per-fighter and
per-stage stats, faction, Crown points), `GET /player/{playerId}/history`, and
`GET /replay/{replayId}`, each gated by a per-account public-flag, authenticated
with OAuth 2.1 PKCE, and rate-limited (100 req/min unauthenticated, 1000 for a
registered app, 30 per account on personal data) so a scraper cannot exhaust the
service. Push handoff (match-end, party-invite, tournament-round,
daily-challenge, Battle-Pass-tier) routes to APNS / FCM with per-category
opt-out.

What is **not** in the repo is the iOS/Android app binary — the mobile client is
planned, served read-only from these contracts. That scoping is a competitive
integrity decision: a phone is not a deterministic match client, so the
companion is kept entirely outside the rollback path. Second-screen mode (a
low-bandwidth view of the opponent's move list and frame data) and coach mode
(annotations on a submitted replay) are **cosmetic-only with no gameplay
effect**, and the app is excluded from cross-play. The architecture treatment is
the esports/companion page under `V2/architecture/`.

## How the surfaces share one spine

The reason these surfaces are part of _one_ product and not bolted-on satellites
is that they read the same backbone the game client does — auth, friends and
parties, presence, leaderboards, the replay cloud, the cosmetic store,
telemetry, and the moderation pipeline all live as `apps/v2/` packages — but
they read it **read-side only** for the web and companion surfaces. The
authoritative, deterministic match stays inside `V2/ue/`; everything outside it
consumes produced results (stats, replays, broadcast feeds) rather than
perturbing the simulation. That is the same fail-loud-when-unconfigured
discipline the AI broadcast bridges use, and the same target-artifact discipline
that lets a feature claim on this page be traced to a module on disk. The
promise is kept honest because the surfaces are kept layered.

## Related

- [../V2_features.md](../V2_features.md) — the V2 feature map this page orients
- [./foundations-glossary-and-conventions.md](./foundations-glossary-and-conventions.md)
  — the glossary, module topology, and the machine-checked cross-reference
  conventions behind every claim here
- [./combat-systems-defense-and-game-feel.md](./combat-systems-defense-and-game-feel.md)
  — per-ruleset feel, defensive vocabulary, and game-feel tuning the in-match
  HUD sits on
- [../architecture/v2-product-promise.md](../architecture/v2-product-promise.md)
  — the architecture companion: how the promise becomes a contract becomes a CI
  gate
- [../architecture/combat-system-gas-frame-data-and-determinism.md](../architecture/combat-system-gas-frame-data-and-determinism.md)
  — the determinism the netcode promise rests on
