# Content, Creator Tools & Workshop

V5 ships as one UE5 open world worn six ways, and a game that wide only stays
alive if the people who play it can also build for it. This page covers the half
of that promise that faces the maker rather than the player: the **creator
suite** — the in-editor tools that let a designer (or, through Workshop, a
player) author a playable detective case, a multi-protagonist heist, a mission,
or a cinematic without writing engine code — and the **Workshop**, the in-game
distribution layer that takes that authored output, pre-screens it, moderates
it, curates it, lets others discover and subscribe to it, and (post-Year-1)
sells it with a creator revenue share. The throughline is a single discipline: a
creator authors **data, not code**, and that data is validated by the _same_
runtime rules the live game will judge it under, so a case that passes the
editor is guaranteed solvable in play. The strongest, most deeply-implemented
piece is **Case Author** (the `V5CaseAuthor` module), which authors the
Vice-Squad detective cases the [Mind Palace](./mind-palace.md) later solves; the
broadest is **`V5WorkshopEditor`**, which carries discovery, subscription,
curation, ML moderation, and the paid-mod marketplace. Both are real, compiled
UE5 C++. This page tours them on the maker's side of the menu and is honest
about where the runtime stops and the art begins. For the full feature scope
this slots into, start at the hub: [../V5_features.md](../V5_features.md).

## What ships, honestly

The **C++ logic, the JSON manifests, and the automation tests are real,
committed, and compiled to on-box Linux editor binaries** (built as the
`ueagent` user, since the editor refuses root); the _3-D art_ those systems
point at is the manifest-referenced surface that, per the V5 posture, is not
checked in as binary `.uasset`. Four honest layers:

- **Real, built, and tested.** Five creator-suite modules compile to committed
  `.so` binaries under `V5/ue/Binaries/Linux/`:
  `libUnrealEditor-V5CaseAuthor.so`, `…-V5HeistAuthor.so`,
  `…-V5MissionEditor.so`, `…-V5Cinematics.so`, and `…-V5WorkshopEditor.so`. Each
  ships `IMPLEMENT_SIMPLE_AUTOMATION_TEST` suites that assert specific authored
  counts and computed verdicts — not truthiness. Case Author's draft validation,
  the Workshop's discovery filter/sort, the ML pre-screen risk scoring, the
  revenue-share basis-point math, and the auto-update planner are all genuine
  domain logic.
- **Authored content is data, validated on load or on build.** The case-author
  templates, the workshop catalog, the curated showcase, the moderator
  dashboard, and the paid-mod marketplace are committed manifests under each
  plugin's `Content/Data/` with a `schemaVersion` gate, mirrored by the runtime
  modules and cross-checked by Python validators in `V5/tools/`.
- **Honest fail-loud seams.** Every Workshop action — publish, subscribe,
  auto-update, marketplace purchase, pre-screen — builds a **real**
  `FV5OnlineServiceRequest` and dispatches it through
  `UV5_Online_ServiceCatalog::ExecuteRequest`, which returns `202`/`200` on a
  healthy service, `503` + queued-offline on an outage, and `401` when the JWT
  is empty. These refuse to fabricate a success they didn't get; the real
  `FHttpModule` transport lives in `V5OnlineServices` (proven by a gated live
  round-trip, see [Modes & Multiplayer](./modes-and-multiplayer.md)).
- **Art referenced, not committed.** Preview worlds
  (`/Game/V5/Editor/CaseAuthor/L_HomicideCasePreview`), marketplace preview
  images (`/Game/V5/UI/Workshop/Marketplace/…`), and spotlight portraits are
  asset **paths** named by manifest. They are the UE-art surface V5 keeps out of
  git; the logic that consumes them is here, the binary art is not.

## The creator suite: authoring under the runtime's rules

The monolith (features§"Creator Suite") lists nine tools — Mission Editor, Heist
Author, Case Author, Contract Author, Ship Loadout, Bestiary, Cinematic
Director, Cross-Cell Replay Editor, Workshop Publisher — each "built on the UE
Editor with custom Slate panels … emitting a typed USTRUCT data file the runtime
loads." The committed, separately-compiled modules are **Mission Editor, Heist
Author, Case Author, Cinematic Director, and the Workshop browser** (plus the
`V5Mode_Replay` plugin carrying the Cross-Cell Replay Editor manifest); Contract
Author, Ship Loadout, and Bestiary are named in the tool table as Mission-Editor
templates rather than standalone modules. The exemplar — and the one that binds
the suite to the Mind Palace — is **Case Author**.

### Case Author: a typed model, not a blob

`V5CaseAuthor`'s `Build.cs` is the tell: it depends on `V5Investigation`,
`V5Interrogation`, and `V5OnlineServices` alongside `Slate`/`SlateCore`, so the
editor tool is built on the very runtime types a _played_ case uses, not a
parallel authoring model. `V5CaseAuthorTypes.h` defines the whole authoring
surface as `USTRUCT`s: an `FV5CaseAuthorTemplate` carries a `CaseId`, a
`BaseInterrogationSceneId`, an `EV5Cell`, a `PreviewWorldPath`, a
`WorkshopCategoryTag`, and floor requirements (`RequiredClueCount = 4`,
`RequiredInterrogationQuestionCount = 3`). An `FV5CaseAuthorDraft` is the
editable document: an array of `FV5CaseAuthorCluePlacement` (each wrapping a
real `FV5InvestigationClueDefinition` plus a world transform and interaction
radius), the `FV5InterrogationSceneDefinition`s, and an array of
`FV5CaseAuthorInterrogationBranch` mapping a source question to an
`EV5InterrogationChoice`, a required-evidence id, and success/failure
next-question ids. The `BuildTemplates` catalog ships three launch templates —
`case.vice.homicide.001`, `case.vice.narcotics.001`, `case.vice.corruption.001`
(`V5CaseAuthorSystems.cpp:254`), the Period-cell "Vice-Squad-style case
authoring" the monolith names.

`BuildDraftFromTemplate` (`:309`) earns trust. It loads the template's
interrogation scene through the runtime's own
`UV5_Interrogation_TellLibrary::FindScene` (falling back to a fully-formed
`FallbackScene`), synthesizes clue placements from the scene's required-evidence
ids _plus_ rotating extras (`scene_photo`, `timeline_note`, `witness_pin`,
`lab_report`) until `RequiredClueCount` is met, each clue stamped with four
`FV5InvestigationDetailSpot`s, then walks the questions deriving the **correct**
authored choice from each question's truth-state — `CorrectChoiceForQuestion`
maps `Truthful→Truth`, `Withholding→Doubt`, `Lying→Lie` (`:63`). The draft a
designer starts from is therefore already a self-consistent, runtime-shaped
case.

### Validation is the contract, and it's domain-specific

`ValidateDraft` (`V5CaseAuthorSystems.cpp:324`) is the heart of the tool, and it
is not a shape check. It runs three graded sub-passes setting
`bCluePlacementValid` / `bInterrogationValid` / `bBranchValid` independently:

- **Clues** — at least four placements, ids unique, each clue belonging to the
  active case, each carrying a scene id, **at least three detail spots**, and a
  positive interaction radius.
- **Interrogation** — every scene belongs to the case, at least three questions,
  and the load-bearing rule: a **`Lying` question must be catchable with placed
  evidence**, checked by calling the runtime's
  `UV5_Interrogation_EvidenceBackedLie::CanChallengeWithLie(Question, EvidenceInventory)`
  (`:357-360`) against an inventory built from the draft's own clue placements.
- **Branches** — every branch maps to a question that exists, and the
  `(question, expected-choice, has-evidence)` triple must `ResolveInput` to
  `bCorrect` through `UV5_Interrogation_TruthDoubtLie::ResolveInput` (`:376`);
  every question needs a branch and every branch needs a success path.

Because both checks call the **same** `V5Interrogation` resolvers the runtime
uses, a case that passes the editor is guaranteed solvable under the live rules
— the difference between authoring tooling and a CRUD form. The three automation
tests (`V5.CaseAuthor.Catalog`, `.PanelAuthoring`, `.WorkshopPublish`,
`V5CaseAuthorTests.cpp`) drive the full edit loop — placing a clue, re-prompting
a question, re-pathing a branch — and re-assert validity after each mutation.

### Publish: a real request with a fail-loud seam

`BuildWorkshopPublishPlan` (`V5CaseAuthorSystems.cpp:454`) assembles an
`FV5OnlineServiceRequest` via `UV5_Online_WorkshopClient::BuildPublishRequest`,
targets `/v5/workshop/case-author/publish`, and serializes a payload carrying
the clue/scene/branch counts, the `valid` flag, and
`moderationState: "pending"`. `bReadyToPublish` is true only when the draft is
valid **and** an account id and JWT are present (`:473`). `PublishToWorkshop`
hands the request to `ExecuteRequest`, and the automation test pins the seam:
`202` on a healthy service (`V5CaseAuthorTests.cpp:141`), `503` +
`bQueuedOffline` on an outage, `401` when the JWT is empty. The visible tool is
`SV5CaseAuthorPanel` — a real Slate widget, a four-column `SHorizontalBox`
(Clues / Interrogation / Branches / Validation+Workshop) with `Validate`,
`Preview`, and `Publish` `SButton`s whose `IsEnabled` is wired to
`bSupportsCluePlacement && bSupportsInterrogationTree` and
`WorkshopPlan.bReadyToPublish` — and the committed `case_author_manifest.json`
mirrors the module's counts under `schemaVersion: 1`. The Heist Author and
Cinematic Director follow the same shape (typed draft → graded validation →
gated `FV5OnlineServiceRequest`) over their own runtime types.

## The Workshop: discovery, curation, moderation, marketplace

`V5WorkshopEditor` (plugin `V5Mode_Editor_Workshop`, cell `MindPalace`) is the
in-game distribution surface for everything the suite emits, and it is the
broadest single module on this page — a 1,400-line systems file and a 900-line
type header. Its `Build.cs` depends only on `V5Core` and `V5OnlineServices`,
because Workshop never re-implements an online call: it composes the shared
service seam.

### The catalog, discovery, and subscriptions

`BuildCatalog` assembles eight launch browse items across every content kind —
`Mission`, `Heist`, `CaseFile`, `ColdCasePack`, `HordeMap`, plus the
`VehicleBlueprint` and `PaidModPack` kinds — and then appends the 50 curated
community heists, so the catalog ships **58** items
(`V5WorkshopEditorTests.cpp:72`). `ApplyDiscoveryFilter`
(`V5WorkshopEditorSystems.cpp:1249`) is a real query: it filters by free-text
(matching title, id, or category, case-insensitively), category tag, cell,
featured-only, and subscribed-only, then **sorts curator- featured first, then
by descending rating**. `BuildSubscriptions` derives a subscription list from
the items a player follows, and `BuildAutoUpdatePlan` (`:1329`) emits one
`/v5/workshop/subscriptions/update` request per subscription whose available
version exceeds its installed version — semantic-version auto-update, with a
`bNeedsRestart` flag only for horde-map content. The
`V5.WorkshopEditor.BrowseSubscribe` test exercises the full loop and pins the
seam at `202`/`503`/`401`.

### Curation: featured slots, the Top 50, the main-menu showcase

Three curation surfaces sit on top of the catalog. **Five curator slots** pin
hand-picked items in order. The **Community Heist Hub**
(`BuildCuratedCommunityHeists`, `:516`) carries the Year-1 **Top 50
player-created heists** — 50 named entries under the
`workshop.heist.player_created` category, each with a curator rank, a rating
that decays with rank, and a source heist-author template — and a
`workshop.heist.player_created` discovery filter returns exactly those 50
(`V5WorkshopEditorTests.cpp:214`). The **main-menu curated showcase**
(`BuildMainMenuCuratedShowcase`, `:623`) feeds **six** auto-advancing carousel
slides (8-second dwell) plus **twelve** monthly community spotlights keyed
`2026-05` through `2027-04`, each spotlight gated on `bPrivacyConsent` and
`bTrustSafetyApproved` before it can surface. A separate **vehicle-blueprint
share** path publishes data-only Tier-2 vehicle blueprints (seven parts) through
`/v5/workshop/vehicle-blueprints/share`.

### Moderation: the ML pre-screen and the community dashboard

Moderation is a three-layer pipeline, and the first layer is real code.
`EvaluateContentPreScreen` (`V5WorkshopEditorSystems.cpp:1355`) computes a risk
score from `ReportCount × 8`, `+5` for high subscriber reach (≥10,000), `−10`
for a trusted creator, plus a per-signal weight for each risk tag — **Spoiler
25, Profanity 35, CopyrightRisk 45, PersonalData 55, StabilityRisk 40** —
clamped to 0–100. The score then routes deterministically: **≥85 auto-rejects,
≥70 escalates, ≥35 needs human review, below that auto-approves** (model version
`ml.workshop.prescreen.v1`). `BuildYear1ModeratorDashboard` runs that classifier
across twelve queue items, and the `V5.WorkshopEditor.ModeratorTools` test pins
the aggregate — **7 pending, 3 escalated, 3 auto-approved, 2 auto-rejected** —
and asserts the clean item auto-approves while the high-risk item auto-rejects.
Above the ML layer sit community report queues and paid human moderators with a
DSA-compliant appeal path; the dashboard exposes
`/v5/workshop/moderation/dashboard` and `/v5/workshop/moderation/pre-screen`.

### The paid-mod marketplace

The post-Year-1 paid-mod marketplace (`BuildPaidModMarketplace`, `:659`) lists
**six** data-only `PaidModPack`s, one per browsing cell, each with USD pricing
(≥$0.99), a SKU, KYC/tax/refund eligibility gates, and a preview image path.
`ValidatePaidModMarketplace` (`:1148`) enforces the economics exactly: the
revenue-share policy must sum to **10,000 basis points** across creator **7000**
(70%), platform **2000**, creator-fund **500**, chargeback-reserve **300**, and
tax-reserve **200**, with a 30-day payout cadence and a $25 minimum. It demands
one payout row per listing (each with positive gross/net/fee/reserve and a
`/v5/workshop/marketplace/payouts` endpoint), a sample purchase that grants an
entitlement and books revenue share, and the full data-only /
ranked-PvP-disabled / KYC / tax / refund posture. The
`V5.WorkshopEditor.PaidModMarketplace` test asserts the 70/20/5 split and the
10,000-bps total directly.

```mermaid
flowchart TD
  subgraph author["Creator suite (in-editor)"]
    CA["V5CaseAuthor<br/>ValidateDraft + publish plan"]
    HA["V5HeistAuthor / MissionEditor /<br/>Cinematics"]
  end
  CA -->|"FV5OnlineServiceRequest<br/>/v5/workshop/case-author/publish"| EXEC{{ExecuteRequest<br/>fail-loud seam}}
  HA --> EXEC
  EXEC -- "healthy" --> PRESCREEN["EvaluateContentPreScreen<br/>ml.workshop.prescreen.v1"]
  EXEC -- "outage" --> Q503["503 + queued offline"]
  EXEC -- "no JWT" --> Q401["401 auth.jwt.required"]
  PRESCREEN --> RISK{risk score 0–100}
  RISK -- "&lt;35" --> APPROVE[AutoApproved]
  RISK -- "35–69" --> HUMAN[NeedsHumanReview]
  RISK -- "70–84" --> ESC[Escalated]
  RISK -- "&ge;85" --> REJECT[AutoRejected]
  APPROVE --> CAT[(Workshop catalog<br/>58 items)]
  HUMAN --> DASH[Moderator dashboard<br/>community + appeals]
  DASH --> CAT
  CAT --> DISC["ApplyDiscoveryFilter<br/>featured-first, rating-sorted"]
  DISC --> SUB["subscribe + auto-update<br/>semantic versions"]
  CAT --> CUR["curator slots · Top 50 ·<br/>main-menu showcase"]
  CAT --> MKT["paid-mod marketplace<br/>70/20/5/3/2 bps = 10000"]
  MKT --> ENT["purchase → entitlement<br/>+ revenue share booked"]
```

## The integrity gates: Python validators

Around the C++ sit a wall of Python validators in `V5/tools/` — one per Year-1
Workshop feature (`workshop-curated-showcase`, `workshop-moderator-tools`,
`modder-marketplace`, `heist-author-top50`, plus `cross-cell-replay-editor`,
`cinematic-director-mode`, and the per-cell content validators). These are
**not** shape stubs. `validate-modder-marketplace.py`, for example, loads
`year1_modder_marketplace_manifest.json`, asserts every `sourceSystems` path
exists, checks six listings across six unique cells, verifies the revenue-share
basis points total 10,000 with a 70% creator floor, confirms the runtime types
(`FV5WorkshopPaidModListing`, `FV5WorkshopRevenueSharePolicy`, …) and system
functions (`BuildPaidModMarketplace`, `ValidatePaidModMarketplace`, …) are
present in the C++ source, that the five marketplace endpoints appear in the
service contract, controller, contract test, and shared runtime, that the
features and architecture docs name the feature, and that the corresponding TODO
is checked. Each is wrapped by a `pytest` shim (`test_validate_*.py`), so the
manifest, the C++, the service contract, and the prose cannot drift apart
without a red test. This is the cross-reference spine that keeps "the doc says
X" honest against "the code does X."

## Community surfaces around the Workshop

The Workshop does not stand alone;
`V5/community/customer-support-community-manifest.json` wires it into the live
community program. Community **ambassadors** carry a `workshop-curator` role
(and a `gallery-curator` role) with `canCurate: true` but `canModerate: false`
and `canViewPrivatePlayerData: false` — they seed and spotlight, they do not
adjudicate — under a conduct agreement and a 30-day review cadence, with at
least 48 active ambassadors across NA/EU/LATAM/APAC. A **Hall of Fame** public
API surfaces a `workshop-contributors` category (ranked by a curated
install/rating composite, privacy-opt-out respected) alongside
`mind-palace-solves`, and a weekly **Player of the Week** draws nominations
partly from workshop curators. Tier-1 chat (60-second SLA) and tier-2 ticketing
route moderation appeals and DSAR requests, closing the loop between a creator's
upload, its moderation, and its recognition. These surfaces are detailed in
[Live Service & Community](./live-service-and-community.md).

## Edge cases & connections

- **An unsolvable case cannot publish.** A `Lying` interrogation question with
  no catchable planted evidence fails `ValidateDraft` via the runtime's
  evidence-backed-lie resolver, `bReadyToPublish` stays false, and the Publish
  button is disabled — the suite will not let a designer ship an unwinnable
  interrogation.
- **High-risk uploads never auto-publish.** A pre-screen score ≥85 auto-rejects
  and ≥70 escalates before any human sees it; the score is computed from real
  report/reach/trust/signal inputs, not a coin flip.
- **Offline / unhealthy backends fail loud.** Publish, subscribe, auto-update,
  and purchase all surface `503 + queued-offline` (where the endpoint supports
  it) or `401` on a missing JWT; the editor's job is a correct, gated request
  and it does exactly that, deferring the live HTTP transport to
  `V5OnlineServices`.
- **Paid mods are fenced.** Data-only, disabled in ranked PvP, KYC- and
  tax-gated, with a refund window — and the 70/20/5/3/2 basis-point split is
  asserted by both the C++ validator and the automation test, so the economics
  cannot drift.
- **Where the cases get played.** The interrogation rig the Case Author
  validates against and the cross-cell deduction layer that solves the published
  cases are the [Mind Palace](./mind-palace.md); its architecture companion
  carries the data-contract tables.
- **Where this sits in the menu.** The modes that host workshop content (and
  disable it in ranked/esports) are in
  [Modes & Multiplayer](./modes-and-multiplayer.md); the seasonal calendar,
  creator programs, and community recognition that schedule and surface this
  output are in [Live Service & Community](./live-service-and-community.md).
- **The deep engine treatment.** The Slate-panel architecture, the GameFeature
  plugin packaging, and the validation-as-runtime-rules design are expanded in
  the architecture companion,
  [../architecture/creator-suite-and-mind-palace.md](../architecture/creator-suite-and-mind-palace.md).

Together the creator suite and the Workshop are V5's answer to "a world this
wide needs its players to extend it": tools that author content under the
runtime's own rules, and a distribution layer that pre-screens, moderates,
curates, and (eventually) pays for it — real in logic, honest about the art it
reaches for.
