Open-World Narrative · Architecture

The Creator Suite & the Mind Palace

A focused page within the Open-World Narrative Architecture documentation. The full map and every sibling page live in the Architecture hub.

5sections13 minread1diagram

On this page

V5 is one open world worn five ways — Urban Crime, Period Drama, Frontier, Monster Hunter, Sci-Fi — and two of its subsystems exist precisely to bind those cells back together rather than let them drift into five disconnected games. The creator suite is the in-editor tooling that lets a designer (or, through Workshop, a player) author a playable detective case — clues placed in a world, an interrogation tree, a publish package — without writing engine code, and have that case validated by the same rules the runtime will judge it under. The Mind Palace is the cross-cell deduction layer: a graph of evidence orbs and authored deduction threads, a volumetric "memory room" to manipulate them, and an accusation system that resolves a case into a branching outcome. It is V5's signature, the one screen where a clue picked up in the 1940s Period cell can be dragged against a clue from the Sci-Fi cell and — if the player has earned the Bureau XP to unlock it — snap into a cross-era deduction. The two systems are a matched pair: the creator suite authors the cases, the Mind Palace is where they are solved. This page is the deep companion to ../V5_ARCHITECTURE.md; the monolith's "Creator Suite Architecture" and "Mind Palace Deduction Architecture" sections carry the data-contract tables this expands on.

What ships, honestly#

The C++ logic, the JSON content catalogs, and the automation tests are real, committed, and compiled; 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. V5CaseAuthor, V5MindPalace, and V5DetectiveMindPalace are genuine UE5 C++ modules that compile to committed Linux editor binaries (V5/ue/Binaries/Linux/libUnrealEditor-V5CaseAuthor.so, …-V5MindPalace.so, …-V5DetectiveMindPalace.so, built as the ueagent user). Each ships IMPLEMENT_SIMPLE_AUTOMATION_TEST suites that assert specific authored counts and computed verdicts — not truthiness. The Mind Palace deduction graph, the weak-edge derivation, the breadth-first hypothesis walk, the evidence-chain accusation gate, the Bureau-XP cross-era gate, the daily-puzzle rotation math, and the leaderboard scoring are all real domain-specific algorithms.
  • Authored content is JSON, validated on load. The 110 authored deduction pairs and 15 accusation outcomes are committed data (V5/ue/Content/V5MindPalace/Data/), parsed and schema-checked at load, not hard-coded. The case-author templates and Mind-Palace mode counts are likewise committed manifests with a schemaVersion gate.
  • Honest fail-loud seams. Workshop publish and Mind-Palace cloud-sync build real requests (a real FHttpModule POST for cloud-sync) but their backends are the seam: an unhealthy service returns 503 and queues offline, a missing JWT returns 401, and the live round-trip test is gated on V5_ONLINE_LIVE=1. These refuse to fabricate a success they didn't get.
  • Art referenced, not committed. Preview worlds (/Game/V5/Editor/CaseAuthor/L_HomicideCasePreview), the 100 examinable 3-D evidence assets the Mind Palace mode validates the count of, and the MetaHuman interrogation faces 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 inside the editor#

The monolith lists nine creator tools (Mission Editor, Heist Author, Case Author, Contract Author, Ship Loadout, Bestiary, Cinematic Director, Replay Editor, Workshop Publisher), each emitting "a typed data file (USTRUCT-based) that the runtime loads." The committed, deeply-implemented one — and the one that ties the suite to the Mind Palace — is Case Author, the V5CaseAuthor module. Its 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.

A typed authoring model, not a blob#

V5CaseAuthorTypes.h defines the whole authoring surface as USTRUCTs. 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: a CaseId, an array of FV5CaseAuthorCluePlacement (each wrapping a real FV5InvestigationClueDefinition plus a world transform and interaction radius), the FV5InterrogationSceneDefinitions, and an array of FV5CaseAuthorInterrogationBranch mapping a source question to an EV5InterrogationChoice, a required-evidence id, and success/failure next-question ids. The FV5CaseAuthorCatalog ships three launch templates — case.vice.homicide.001, case.vice.narcotics.001, case.vice.corruption.001 (V5CaseAuthorSystems.cpp:254) — the "Vice-Squad-style case authoring" the monolith names.

Build-from-template wires real interrogation primitives#

BuildDraftFromTemplate (V5CaseAuthorSystems.cpp:309) is where the tool 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 if none is authored yet. It then synthesizes clue placements from the scene's required-evidence ids and a rotating set of extra clues (scene_photo, timeline_note, witness_pin, lab_report) until the template's RequiredClueCount is met, each clue stamped with four FV5InvestigationDetailSpots (powder residue, maker mark, transfer stain, hidden note). Finally BuildBranches walks the scene's questions and, for each one, derives the correct authored choice from the 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 that set 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 answerable 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. A lie the player can't catch with a planted clue fails authoring.
  • Branches — every branch maps to a source question that exists, and that branch's (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. That is the difference between authoring tooling and a CRUD form: the validator is the game's own logic, run at edit time.

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. PublishToWorkshop (:477) hands the request to UV5_Online_ServiceCatalog::ExecuteRequest, whose automation test (V5CaseAuthorTests.cpp:141) pins the honest seam: 202 on a healthy service, 503 + bQueuedOffline on an outage, 401 when the JWT is empty. The Workshop service is elsewhere; the editor's job is a correct, gated request and it does exactly that.

The visible tool is SV5CaseAuthorPanel (SV5CaseAuthorPanel.cpp), a real Slate widget: an SBorder over a four-column SHorizontalBox (Clues / Interrogation / Branches / Validation+Workshop) inside SScrollBoxes, with Validate, Preview, and Publish SButtons whose IsEnabled is wired to bSupportsCluePlacement && bSupportsInterrogationTree and WorkshopPlan.bReadyToPublish. The committed case_author_manifest.json mirrors the module's content counts and system flags under schemaVersion: 1.

The Mind Palace: a cross-cell deduction graph#

The Mind Palace is "a graph database + a UI shell," and conceptually a side-car to all five cells: each cell's investigation gameplay pushes evidence into it through one interface. IV5_Investigation_MindPalacePush (V5InvestigationMindPalacePush.h) declares a single EmitEvidenceNodeEvent(FV5InvestigationEvidenceNodeEvent); the graph implements it (V5MindPalaceGraph.cpp:21), translating an in-cell evidence event into an FV5MindPalaceEvidenceNode tagged to the MindPalace cell. That is how a clue examined in any cell becomes an orb in the shared room.

The data model#

V5MindPalaceTypes.h defines the graph. An FV5MindPalaceEvidenceNode is the monolith's V5_Evidence_NodeNodeId, CaseId, source cell, location, TimestampInFiction, Tags, Description, an Image soft path, examined details, and a bFalseLead flag. An FV5MindPalaceDeductionEdge is the V5_Deduction_Edge — a from/to node pair with their cells, DeductionText, a Confidence float, a Kind (Authored or Weak), bCrossEra, a RequiredBureauTier, and an UnlockFlag. An FV5MindPalaceAccusationOutcome (V5_Accusation_Outcome) carries the EvidenceChain, the RequiredEdgeIds it demands, a Rating (Brilliant/Good/Doubtful/Wrong) and an OutcomeBranch (TruthRevealed/PlausibleConviction/PoliticalCoverup/ Unproven). The FV5MindPalaceState is the V5_MindPalace_State: nodes, edges, accusations, and unlock flags.

The deduction mechanic is authored-first with a weak fallback#

AttemptDeduction(NodeA, NodeB, BureauLedger) (V5MindPalaceGraph.cpp:78) is the "drag two orbs onto the pedestal" action, and its logic is specific. After rejecting same-node or non-existent pairs, it looks up an authored edge for the unordered pair via FindAuthoredEdge. If none exists it calls BuildWeakEdge (:271), which only succeeds when the two nodes share a tag: it mints a weak.<a>.<b> edge at Confidence 0.35, Kind = Weak, marked bCrossEra when the cells differ and given RequiredBureauTier 5 + UnlockFlag MindPalace.CrossEraPairs in that case. So a pairing is either a known authored insight or an honest "weak thematic connection… needs stronger corroboration" — never a fabricated certainty. The candidate then passes through the cross-era gate before being committed to State.Edges; the result reports bSuccess, bGateBlocked, a FailureReason, and the resolved Edge.

The gate itself is UV5_MindPalace_CrossEraGate::CanUnlockDeduction (V5MindPalaceCrossEraGate.cpp): a non-cross-era edge is always allowed; a cross-era edge requires BureauLedger.CurrentTier >= max(1, RequiredBureauTier) or that the ledger's Unlocks already contains the edge's UnlockFlag. This is the spine connecting the Mind Palace to progression — the cross-cell "aha" moments are earned through Bureau XP, the same ledger detailed in the Hunter, Period & Bureau spine.

flowchart TD subgraph cells["Five cells push evidence"] INV["V5Investigation (per cell)<br/>player examines a clue"] end INV -->|"EmitEvidenceNodeEvent<br/>(IV5_Investigation_MindPalacePush)"| ADD[AddEvidenceNode<br/>upsert into State.Nodes] CAT[(deduction_pairs.json<br/>110 authored edges)] -->|ApplyAuthoredDeductionCatalog| GRAPH ADD --> GRAPH{{UV5_MindPalace_Graph}} GRAPH -->|AttemptDeduction A,B| FIND{authored edge<br/>for pair?} FIND -- yes --> GATE{cross-era gate<br/>CanUnlockDeduction} FIND -- no, shared tag --> WEAK[BuildWeakEdge<br/>Confidence 0.35] WEAK --> GATE GATE -- Tier &lt; required --> BLOCK[bGateBlocked<br/>fail loud] GATE -- unlocked --> EDGE[add edge to State.Edges] EDGE --> CHAIN[BuildHypothesisChain<br/>breadth-first walk] EDGE --> ACC[MakeAccusation<br/>requires full RequiredEdgeIds chain] ACC --> OUT["authored Rating + OutcomeBranch<br/>or Wrong/Unproven"] EDGE -.->|BuildGraphDiffPayload| SYNC[(mindpalace-cloud-sync :4220)]

Hypothesis chains and the accusation gate#

BuildHypothesisChain(start, maxDepth) (V5MindPalaceGraph.cpp:112) is a real breadth-first traversal over the committed edges: a frontier expands outward (depth clamped to 1–12), collecting reachable node and edge ids and accumulating an AverageConfidence. It is the "UI helper for visualizing" a line of reasoning, and the test asserts an authored chain carries AverageConfidence >= 0.80 (V5MindPalaceTests.cpp:99).

MakeAccusation(case, accused, chain) (:165) defaults to the worst outcome — Wrong / Unproven — then searches the authored catalog for a matching (case, accused) outcome. The match only "sticks" with its authored Rating and OutcomeBranch if the player's EvidenceChain contains every RequiredEdgeId; a chain missing a required link collapses back to Wrong/Unproven with "lacked the required evidence chain." This is a real proof-of-work gate, not a coin flip: the end-to-end test (V5MindPalaceTests.cpp:161) completes each of the 15 authored outcomes' required deductions and asserts the accusation resolves the expected branch, covering three distinct branches across the arc.

The volumetric memory room#

UV5_MindPalace_View_Volumetric::BuildViewState (V5MindPalaceViewVolumetric.cpp:33) renders the monolith's "circular memory room with evidence orbs in concentric rings by cell of origin." It first filters the node set through the filter rail, then places each surviving node on a ring whose radius is a function of its cell (RingForCell = 220 + cell·70), at an angle evenly distributed around the circle, lifted in z by index. The selected orb scales up (1.35) and glows; each orb takes a per-cell accent color (ColorForCell). Deduction threads are drawn only between two visible orbs; an authored thread's intensity tracks its confidence while cross-era threads are gold. UV5_MindPalace_FilterRail::FilterNodes (V5MindPalaceFilterRail.cpp:19) is the left rail: filter by cell, by case, by an in-fiction timestamp range, and by required tags (all must be present). The test drives this end-to-end — filtering to one node by cell+tag, then building a view with "two evidence orbs" and "one thread."

Authored content is data, validated on load#

The 110 deduction pairs and 15 accusation outcomes are not hard-coded. UV5_MindPalace_Catalog::LoadDeductionPairs (V5MindPalaceCatalog.cpp:121) reads V5/ue/Content/V5MindPalace/Data/deduction_pairs.json and validates it: a schemaVersion of 1, required string/number fields, no duplicate edge ids, no self-loops, positive confidence. The JSON is a compact generator spec — pairGroups whose counts sum to exactly 110 (one cross-era group of 30 spanning all five cells at requiredBureauTier 5, plus five per-cell groups of 16 = 80) — matching the test's Deductions.Num() == 110, CrossEraCount == 30, PerCellCount == 80 (V5MindPalaceTests.cpp:57). accusation_outcomes.json holds 15 outcomes — five anchor cases × three authored branches, an even PlausibleConviction / PoliticalCoverup / TruthRevealed split.

Cloud sync and the companion app#

V5MindPalaceCloudSyncHttp::BuildHttpRequest (exercised at V5MindPalaceTests.cpp:248) is a genuine FHttpModule POST to @v5/service-mindpalace-cloud-sync at /v5/mindpalace-cloud-sync/graph-diff on port :4220, a Bearer JWT header, application/json, and a body carrying a CRDT-style version-vector graph diff; ParseResult maps 2xx→success, 503→failure. A second, latent test (V5_ONLINE_LIVE=1) does a real round-trip against the running service and asserts the response acknowledges the merged diff. The companion-app path (V5MindPalaceCompanionAppRead) builds a read-only snapshot for the AR overlay and an editable snapshot exposing add-clue / annotate-clue, queuing append-only edit drafts for cloud-sync — the Year-1 Companion-App Mind Palace Editor.

The Detective Mind Palace mode: dailies, crossovers, scoring#

V5DetectiveMindPalace is the runtime mode plugin built on the graph. Its ValidateCatalog (V5DetectiveMindPalaceSystems.cpp:589) enforces the shape of the main arc — ten one-hour beats totalling ten hours, covering all 30 cross-era deductions, 80 per-cell deductions, and 100 examinable 3-D evidence assets (count validated; the assets themselves are the referenced art surface). On top sit two live-service systems:

  • Daily puzzles. BuildDailyPuzzleForDate (:541) is deterministic: it takes the floor of days since the rotation start (2027-06-07Z), wraps it modulo 365 (with a correct negative-safe ((d % n) + n) % n), and indexes the 365 authored puzzles — so day 0 → puzzle 001, day 1 → 002, day 365 wraps back to 001, exactly as the test pins (V5DetectiveMindPalaceTests.cpp:115). EvaluateDailyPuzzleSolve (:550) computes a leaderboard score — 50000 + tier·1500 + timeBonus − hintPenalty, floored at 1 — but only when the solve is clean: bSolved && bAntiCheatClean && positive time. A dirty solve scores zero and is leaderboard-ineligible. Scores submit through the shared leaderboards service.
  • Crossover pack. A Year-1 "Black Archive" six-hour, six-beat arc adding 12 new cross-era deductions, each validated as authored, cross-era, Bureau-gated, and referenced by exactly the beats that need it.

ScoreConnection (:705) grades a single thread: Confidence·100 clamped to 0–100, Strong only when the edge is authored and ≥70 and the cross-era gate is unlocked, and bCanSupportAccusation follows from Strong + unlocked. The five automation tests (Catalog, DailyPuzzleRotation, Year1CrossoverPackExpansion, ConnectionScoring, CrossEraUnlockMultiAccusation) assert these computed values directly.

Edge cases & connections#

  • A pairing with no authored edge and no shared tag yields "No meaningful connection found" (V5MindPalaceGraph.cpp:91) — the system refuses to invent a deduction. Shared-tag pairings produce only a low-confidence weak edge, never a confident one.
  • A cross-era deduction below the Bureau tier returns bGateBlocked with the candidate edge attached but not committed to state — the gate fails loud and leaves the graph unchanged until the player earns the unlock.
  • An accusation with an incomplete chain can never reach an authored conviction branch; the missing-link path is the explicit Wrong/Unproven collapse, so the outcome is always backed by the evidence the player actually assembled.
  • Authoring a lie with no catchable evidence fails ValidateDraft via the runtime's evidence-backed-lie resolver — the creator suite will not let a designer ship an unsolvable interrogation.
  • Offline / unhealthy backends surface as 503 + queued-offline (Workshop publish, cloud-sync) or 401 (missing JWT); the live cloud-sync round-trip is opt-in behind V5_ONLINE_LIVE, so the default test run never depends on a service being up.
  • Where the cases get played and judged. The interrogation rig the Case Author validates against — MotionScan tells, the Truth/Doubt/Lie call, scoring — and the Heist Author that shares the Mission Editor are detailed in Interrogation, Dialogue & Heist.
  • Platform substrate. The shared online services these systems target (Workshop, leaderboards, the Mind-Palace cloud-sync domain) and the Bureau-XP ledger they gate against are catalogued in Oshun Domain Libraries.

Together the creator suite and the Mind Palace are V5's answer to the open-world anthology problem: a tool that authors a detective case under the runtime's own rules, and a deduction layer that lets evidence cross cell boundaries — real in logic, honest about the art they reach for.