In reviewMedium

Document Seminole UE 5.8 architecture (ARCHITECTURE.md + 8 ADRs) and scaffold C++ project, Git LFS and .gitignore

Proposed by Jonathan Miller 2 hours agoFunding opened 2 hours agoFunded 2 hours ago
Specification

Motivation

Establish Seminole's technical foundation so later community-funded features have a consistent place to land. The stack is fixed:

  • Unreal Engine 5.8, desktop first, distributed on Steam.
  • C++ for core systems; Blueprint and data assets for content.
  • StateTree, AI Perception and NavMesh for the infected.
  • Noise as a single shared gameplay event.
  • World Partition and PCG for the world.
  • Listen server for 1–4 player co-op.
  • Host-owned save game for persistence.
  • UMG/CommonUI for UI; MetaSounds for audio.
  • Git with Git LFS for source control.

This build records those decisions and creates the repository skeleton. It does not implement gameplay.

Scope

1. docs/ARCHITECTURE.md

A concise document with one section per topic:

  • Engine and programming model.
  • AI, including the state flow Idle -> Wander -> Hear Noise -> Investigate -> Detect Player -> Chase -> Attack -> Lose Player -> Search -> Wander.
  • Noise event system.
  • Large-population roadmap.
  • World.
  • Multiplayer/Steam.
  • Persistence.
  • Gameplay components.
  • UI.
  • Audio.
  • Art pipeline.
  • Source control.
  • Browser strategy.
  • Vertical slice contents and target loop.
  • Deferred / Out of scope.

The doc must also include an "Intended plugins" list: StateTree, CommonUI, PCG, MetaSounds, OnlineSubsystemSteam. State that each plugin is enabled in the later ticket that needs it.

Assumptions:

  • The original proposal text is not in the repo. Derive content from this spec's stack list and the game description.
  • The large-population roadmap is: StateTree actors first, with MassEntity as an optional later step.
  • The vertical slice is: one swamp map, canoe travel, a day scavenge phase and a night defense phase, and co-op.
  • Keep each section short; do not invent detailed numbers.

2. docs/adr/

Create one ADR per decision, using Context / Decision / Consequences headings and numbered filenames (e.g. 0001-unreal-engine-5.md):

  1. UE5.
  2. C++ + Blueprint hybrid.
  3. StateTree AI without MassEntity at first.
  4. Noise event system.
  5. Listen server + Steam.
  6. Host-owned save game.
  7. No Gameplay Ability System by default.
  8. Git LFS before Perforce.

Also add docs/adr/README.md as an index.

3. UE project skeleton

Treat the repository as greenfield. If any existing files are found, preserve them and integrate around them. Never overwrite or delete existing work; for README, .gitignore and .gitattributes, append or merge.

  • Seminole.uproject:
    • FileVersion 3.
    • EngineAssociation "5.8".
    • One module Seminole with Type Runtime and LoadingPhase Default.
    • No Plugins entries enabled.
  • Source/Seminole.Target.cs (Game) and Source/SeminoleEditor.Target.cs (Editor).
    • Use BuildSettingsVersion.Latest and EngineIncludeOrderVersion.Latest (assumption: this avoids version-specific enums).
  • Source/Seminole/Seminole.Build.cs:
    • PCHUsage set to UseExplicitOrSharedPCHs.
    • Dependencies: Core, CoreUObject, Engine, InputCore, EnhancedInput (assumption: EnhancedInput is built in and does not require a plugin entry).
  • Source/Seminole/Seminole.h and Seminole.cpp, using IMPLEMENT_PRIMARY_GAME_MODULE(FDefaultGameModuleImpl, Seminole, "Seminole").
  • Source/Seminole/ subfolders, each containing a README.md stub that states the folder's purpose: AI, Characters, Combat, Community, Inventory, Interaction, Multiplayer, Persistence, Survival, Vehicles, World.
  • Content/ subfolders, each with a .gitkeep: AI, Characters, Environments, Items, Maps, Missions, Weapons, UI, Audio.
  • Minimal valid Config/ files:
    • DefaultEngine.ini: no map references to non-existent assets.
    • DefaultGame.ini: ProjectName set to Seminole.
    • DefaultInput.ini: Enhanced Input default classes.
  • Plugins/.gitkeep.

4. .gitattributes

Route these extensions through LFS with filter=lfs diff=lfs merge=lfs -text: *.uasset, *.umap, *.fbx, *.wav, *.png, *.tga, *.psd, *.blend, *.spp, *.sbs, *.sbsar.

5. .gitignore

Standard Unreal ignores: Binaries/, Intermediate/, Saved/, DerivedDataCache/, .vs/, .idea/, *.sln, *.suo, *.VC.db, and similar. Do not ignore Content/ or Config/.

6. README

Add a section that:

  • links to docs/ARCHITECTURE.md and docs/adr/;
  • states UE 5.8;
  • gives the Git LFS setup step (git lfs install before cloning or pulling).

Acceptance criteria

  • docs/ARCHITECTURE.md has a heading for every topic in Scope 1, including the full AI state flow string, an Intended plugins list and a Deferred / Out of scope list.
  • docs/adr/ contains at least 8 ADR files, each with Context, Decision and Consequences headings, covering the 8 listed decisions.
  • Seminole.uproject parses as JSON (python -m json.tool) and has FileVersion 3 and EngineAssociation "5.8".
  • Seminole.uproject lists exactly one module Seminole with Type Runtime and enables no plugins.
  • The Target.cs, Build.cs, Seminole.h and Seminole.cpp files exist and follow standard UE5 game-module boilerplate. Compilation is not verified because Unreal Engine is unavailable in the sandbox.
  • Every listed Source and Content subfolder exists and contains a tracked file.
  • .gitattributes contains an LFS rule for each listed extension.
  • .gitignore excludes Binaries/, Intermediate/, Saved/ and DerivedDataCache/.
  • No C++ classes exist beyond the module stub.
  • No .uasset or .umap files are added.
  • No pre-existing file is deleted.

Out of scope

  • Any gameplay system: AI, noise, health, inventory, weapons, canoe, persistence, networking.
  • .uasset or .umap content.
  • Enabling or configuring plugins.
  • Steam AppID or Steamworks config.
  • CI pipelines.
  • Dedicated servers, MMO-style worlds, backend orchestration.
  • Browser-first or mobile builds, console ports.
  • Mandatory MassEntity, full GAS adoption.
  • Final art direction or content.
Build #20
SUCCEEDED

Model claude-fable-5-1 · ceiling $10.50 · started 2 hours ago · finished 2 hours ago

38agent turns
1.1Mtokens
$1.96spent at list price

Builder summary
## Feature #21: UE 5.8 architecture docs + Unreal project scaffold, Git LFS and .gitignore Branch `nabled/feature-21-job-20`, one commit (`a3d7cc7`), 43 files added/changed, 0 deleted. ### Important context The repo was **not** greenfield: it holds a working Babylon.js browser prototype (`src/`, `index.html`, `package.json`, Vitest tests, GitHub Pages workflow). Per the spec, everything was preserved and the UE skeleton was integrated around it. The README, `.gitignore` were appended/merged; `.gitattributes` did not exist and was created. `docs/ARCHITECTURE.md` → "Browser strategy" explicitly describes the prototype as a preview/design sandbox, with the UE 5.8 project as the shipping target. ### What changed **Docs** - `docs/ARCHITECTURE.md` — one section per required topic (Engine and programming model, AI with the full state-flow string, Noise event system, Large-population roadmap [StateTree actors → distance tiers → optional MassEntity], World, Multiplayer/Steam, Persistence, Gameplay components, UI, Audio, Art pipeline, Source control, Browser strategy, Vertical slice contents and target loop, Deferred / Out of scope) plus an "Intended plugins" table (StateTree, CommonUI, PCG, MetaSounds, OnlineSubsystemSteam) stating each is enabled by the later ticket that needs it. No invented numbers. - `docs/adr/0001`–`0008` — one ADR per decision, each with Context / Decision / Consequences; `docs/adr/README.md` index. **UE project skeleton** - `Seminole.uproject` — FileVersion 3, EngineAssociation "5.8", single `Seminole` module (Runtime / Default), `"Plugins": []`. - `Source/Seminole.Target.cs`, `Source/SeminoleEditor.Target.cs` — `BuildSettingsVersion.Latest`, `EngineIncludeOrderVersion.Latest`. - `Source/Seminole/Seminole.Build.cs` — `UseExplicitOrSharedPCHs`; deps Core, CoreUObject, Engine, InputCore, EnhancedInput. - `Source/Seminole/Seminole.h/.cpp` — `IMPLEMENT_PRIMARY_GAME_MODULE(FDefaultGameModuleImpl, Seminole, "Seminole")`. No other C++ classes. - 11 `Source/Seminole/<System>/README.md` stubs; 9 `Content/<Folder>/.gitkeep`; `Plugins/.gitkeep`. - `Config/DefaultEngine.ini` (no map references; desktop hardware target, a few UE5 renderer defaults), `DefaultGame.ini` (`ProjectName=Seminole`), `DefaultInput.ini` (EnhancedPlayerInput / EnhancedInputComponent). **Source control** - `.gitattributes` — LFS rule for each of the 11 listed extensions. - `.gitignore` — existing 4 lines kept; appended Binaries/, Intermediate/, Saved/, DerivedDataCache/, .vs/, .vscode/, .idea/, *.sln, *.suo, *.VC.db and similar. Content/ and Config/ are not ignored (verified with `git check-ignore`). - `README.md` — new "Unreal Engine project" section linking ARCHITECTURE.md and docs/adr/, stating UE 5.8, giving the `git lfs install` step; "Project layout" block extended with the new top-level folders. ### Verification - `python3 -m json.tool Seminole.uproject` passes; scripted checks confirm FileVersion/EngineAssociation/module/plugins, every required ARCHITECTURE heading and the exact AI state-flow string, Context/Decision/Consequences in all 8 ADRs, all 11 LFS rules, required ignores, and a tracked file in every Source/Content subfolder. - `git diff main --diff-filter=D` → 0 deletions; no `.uasset`/`.umap` added. - Existing browser prototype unaffected: `npm ci && npm test` → 7 files, 133 tests pass. - **Not verified:** UE compilation (Unreal Engine is unavailable in the sandbox). The Target.cs/Build.cs/module files follow standard UE5 boilerplate; a maintainer with UE 5.8 should generate project files and build `SeminoleEditor` once. ### Things to look at - `git lfs` is not installed in the sandbox, so the LFS filter was never exercised. Existing `docs/screenshots/*.png` remain ordinary Git objects (noted in ADR 0008); only new `*.png` etc. will go through LFS. Decide whether to migrate them (`git lfs migrate`) — intentionally not done here since it rewrites history. - `Config/DefaultEngine.ini` includes a handful of UE5 desktop renderer def
View pull request ↗Download patchnabled/feature-21-job-20

Agent log
**Docs**
- `docs/ARCHITECTURE.md` — one section per required topic (Engine and programming model, AI with the full state-flow string, Noise event system, Large-population roadmap [StateTree actors → distance tiers → optional MassEntity], World, Multiplayer/Steam, Persistence, Gameplay components, UI, Audio, Art pipeline, Source control, Browser strategy, Vertical slice contents and target loop, Deferred / Out of scope) plus an "Intended plugins" table (StateTree, CommonUI, PCG, MetaSounds, OnlineSubsystemSteam) stating each is enabled by the later ticket that needs it. No invented numbers.
- `docs/adr/0001`–`0008` — one ADR per decision, each with Context / Decision / Consequences; `docs/adr/README.md` index.

**UE project skeleton**
- `Seminole.uproject` — FileVersion 3, EngineAssociation "5.8", single `Seminole` module (Runtime / Default), `"Plugins": []`.
- `Source/Seminole.Target.cs`, `Source/SeminoleEditor.Target.cs` — `BuildSettingsVersion.Latest`, `EngineIncludeOrderVersion.Latest`.
- `Source/Seminole/Seminole.Build.cs` — `UseExplicitOrSharedPCHs`; deps Core, CoreUObject, Engine, InputCore, EnhancedInput.
- `Source/Seminole/Seminole.h/.cpp` — `IMPLEMENT_PRIMARY_GAME_MODULE(FDefaultGameModuleImpl, Seminole, "Seminole")`. No other C++ classes.
- 11 `Source/Seminole/<System>/README.md` stubs; 9 `Content/<Folder>/.gitkeep`; `Plugins/.gitkeep`.
- `Config/DefaultEngine.ini` (no map references; desktop hardware target, a few UE5 renderer defaults), `DefaultGame.ini` (`ProjectName=Seminole`), `DefaultInput.ini` (EnhancedPlayerInput / EnhancedInputComponent).

**Source control**
- `.gitattributes` — LFS rule for each of the 11 listed extensions.
- `.gitignore` — existing 4 lines kept; appended Binaries/, Intermediate/, Saved/, DerivedDataCache/, .vs/, .vscode/, .idea/, *.sln, *.suo, *.VC.db and similar. Content/ and Config/ are not ignored (verified with `git check-ignore`).
- `README.md` — new "Unreal Engine project" section linking ARCHITECTURE.md and docs/adr/, stating UE 5.8, giving the `git lfs install` step; "Project layout" block extended with the new top-level folders.

### Verification
- `python3 -m json.tool Seminole.uproject` passes; scripted checks confirm FileVersion/EngineAssociation/module/plugins, every required ARCHITECTURE heading and the exact AI state-flow string, Context/Decision/Consequences in all 8 ADRs, all 11 LFS rules, required ignores, and a tracked file in every Source/Content subfolder.
- `git diff main --diff-filter=D` → 0 deletions; no `.uasset`/`.umap` added.
- Existing browser prototype unaffected: `npm ci && npm test` → 7 files, 133 tests pass.
- **Not verified:** UE compilation (Unreal Engine is unavailable in the sandbox). The Target.cs/Build.cs/module files follow standard UE5 boilerplate; a maintainer with UE 5.8 should generate project files and build `SeminoleEditor` once.

### Things to look at
- `git lfs` is not installed in the sandbox, so the LFS filter was never exercised. Existing `docs/screenshots/*.png` remain ordinary Git objects (noted in ADR 0008); only new `*.png` etc. will go through LFS. Decide whether to migrate them (`git lfs migrate`) — intentionally not done here since it rewrites history.
- `Config/DefaultEngine.ini` includes a handful of UE5 desktop renderer defaults (Lumen GI/reflections, VSM, mesh distance fields). They are standard for a new 5.x desktop project but can be trimmed if you prefer a bare file.
- `DefaultGame.ini` has a placeholder `ProjectID` GUID; UE will accept it or you can regenerate from Project Settings.
- The `.gitignore` does not ignore `Build/` (UE uses it for platform resources), only `Build/Receipts/`.
2026-10-05T02:19:37Z  [claude] The work is complete and pushed to `nabled/feature-21-job-20`.

**Summary:** The repository already contained a Babylon.js browser prototype, so I integrated the Unreal Engine 5.8 skeleton around it without deleting or overwriting anything. The branch adds `docs/ARCHITECTURE.md` (all 15 required sections plus the Intended plugins table and the exact AI state-flow string), 8 ADRs with an index, the `Seminole.uproject` / Target.cs / Build.cs / module stub, README-stubbed Source folders, `.gitkeep`'d Content and Plugins folders, minimal Config INIs, Git LFS rules for all 11 extensions, standard Unreal ignores appended to `.gitignore`, and a README section covering the doc links, UE 5.8 and `git lfs install`.

Verified via JSON parsing and scripted checks against every acceptance criterion; the existing 133 Vitest tests still pass. UE compilation could not be verified since Unreal isn't available in the sandbox — that's the one thing a maintainer should do once.
2026-10-05T02:19:38Z  Changed files:
added  .gitattributes  +13 -0
modified  .gitignore  +20 -0
added  Config/DefaultEngine.ini  +21 -0
added  Config/DefaultGame.ini  +7 -0
added  Config/DefaultInput.ini  +4 -0
added  Content/AI/.gitkeep  +0 -0
added  Content/Audio/.gitkeep  +0 -0
added  Content/Characters/.gitkeep  +0 -0
added  Content/Environments/.gitkeep  +0 -0
added  Content/Items/.gitkeep  +0 -0
added  Content/Maps/.gitkeep  +0 -0
added  Content/Missions/.gitkeep  +0 -0
added  Content/UI/.gitkeep  +0 -0
added  Content/Weapons/.gitkeep  +0 -0
added  Plugins/.gitkeep  +0 -0
modified  README.md  +36 -0
added  Seminole.uproject  +17 -0
added  Source/Seminole.Target.cs  +16 -0
added  Source/Seminole/AI/README.md  +6 -0
added  Source/Seminole/Characters/README.md  +6 -0
added  Source/Seminole/Combat/README.md  +6 -0
added  Source/Seminole/Community/README.md  +6 -0
added  Source/Seminole/Interaction/README.md  +6 -0
added  Source/Seminole/Inventory/README.md  +6 -0
added  Source/Seminole/Multiplayer/README.md  +6 -0
added  Source/Seminole/Persistence/README.md  +6 -0
added  Source/Seminole/Seminole.Build.cs  +22 -0
added  Source/Seminole/Seminole.cpp  +6 -0
added  Source/Seminole/Seminole.h  +5 -0
added  Source/Seminole/Survival/README.md  +6 -0
added  Source/Seminole/Vehicles/README.md  +6 -0
added  Source/Seminole/World/README.md  +6 -0
added  Source/SeminoleEditor.Target.cs  +16 -0
added  docs/ARCHITECTURE.md  +243 -0
added  docs/adr/0001-unreal-engine-5.md  +27 -0
added  docs/adr/0002-cpp-blueprint-hybrid.md  +31 -0
added  docs/adr/0003-statetree-ai-without-massentity-at-first.md  +35 -0
added  docs/adr/0004-noise-event-system.md  +32 -0
added  docs/adr/0005-listen-server-and-steam.md  +32 -0
added  docs/adr/0006-host-owned-save-game.md  +29 -0
added  docs/adr/0007-no-gameplay-ability-system-by-default.md  +28 -0
added  docs/adr/0008-git-lfs-before-perforce.md  +36 -0
added  docs/adr/README.md  +20 -0
2026-10-05T02:19:40Z  Opened pull request https://github.com/nabledhq/seminole/pull/8
2026-10-05T02:19:40Z  Finished: success=true turns=38 tokens(in/out)=1111112/22572 list cost=$1.96

Show patch
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..a6ff67c
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,13 @@
+# Git LFS: large binary assets for the Unreal Engine project.
+# Run `git lfs install` once before cloning or pulling (see README).
+*.uasset filter=lfs diff=lfs merge=lfs -text
+*.umap filter=lfs diff=lfs merge=lfs -text
+*.fbx filter=lfs diff=lfs merge=lfs -text
+*.wav filter=lfs diff=lfs merge=lfs -text
+*.png filter=lfs diff=lfs merge=lfs -text
+*.tga filter=lfs diff=lfs merge=lfs -text
+*.psd filter=lfs diff=lfs merge=lfs -text
+*.blend filter=lfs diff=lfs merge=lfs -text
+*.spp filter=lfs diff=lfs merge=lfs -text
+*.sbs filter=lfs diff=lfs merge=lfs -text
+*.sbsar filter=lfs diff=lfs merge=lfs -text
diff --git a/.gitignore b/.gitignore
index dd6e803..ecab79a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,3 +2,23 @@ node_modules/
 dist/
 *.log
 .DS_Store
+
+# Unreal Engine: generated, cached and IDE files only (project assets and settings stay tracked)
+Binaries/
+Intermediate/
+Saved/
+DerivedDataCache/
+Build/Receipts/
+.vs/
+.vscode/
+.idea/
+*.sln
+*.suo
+*.VC.db
+*.VC.opendb
+*.sdf
+*.opensdf
+*.xcodeproj
+*.xcworkspace
+*.code-workspace
+*.generated.h
diff --git a/Config/DefaultEngine.ini b/Config/DefaultEngine.ini
new file mode 100644
index 0000000..03aa992
--- /dev/null
+++ b/Config/DefaultEngine.ini
@@ -0,0 +1,21 @@
+[/Script/EngineSettings.GameMapsSettings]
+; No startup, default or server maps are set: Content/Maps is empty until the first map ticket lands.
+; GlobalDefaultGameMode is left at the engine default for the same reason.
+
+[/Script/HardwareTargeting.HardwareTargetingSettings]
+TargetedHardwareClass=Desktop
+AppliedTargetedHardwareClass=Desktop
+DefaultGraphicsPerformance=Maximum
+AppliedDefaultGraphicsPerformance=Maximum
+
+[/Script/Engine.RendererSettings]
+r.GenerateMeshDistanceFields=True
+r.DynamicGlobalIlluminationMethod=1
+r.ReflectionMethod=1
+r.Shadow.Virtual.Enable=1
+r.DefaultFeature.AutoExposure.ExtendDefaultLuminanceRange=True
+
+[/Script/Engine.UserInterfaceSettings]
+bAuthorizeAutomaticWidgetVariableCreation=False
+FontDPIPreset=Standard
+FontDPI=72
diff --git a/Config/DefaultGame.ini b/Config/DefaultGame.ini
new file mode 100644
index 0000000..73d3654
--- /dev/null
+++ b/Config/DefaultGame.ini
@@ -0,0 +1,7 @@
+[/Script/EngineSettings.GeneralProjectSettings]
+ProjectName=Seminole
+ProjectID=4C1B9E2A4F3D4B7E8A6C2D1F0E9B8A7C
+CompanyName=Seminole contributors
+Description=A co-op survival game set in the Florida Everglades around 1900.
+ProjectVersion=0.1.0
+CopyrightNotice=Copyright Seminole contributors. MIT licence.
diff --git a/Config/DefaultInput.ini b/Config/DefaultInput.ini
new file mode 100644
index 0000000..66c1186
--- /dev/null
+++ b/Config/DefaultInput.ini
@@ -0,0 +1,4 @@
+[/Script/Engine.InputSettings]
+DefaultPlayerInputClass=/Script/EnhancedInput.EnhancedPlayerInput
+DefaultInputComponentClass=/Script/EnhancedInput.EnhancedInputComponent
+; Input Actions and Input Mapping Contexts are data assets and land under Content/ with the first character ticket.
diff --git a/Content/AI/.gitkeep b/Content/AI/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/Content/Audio/.gitkeep b/Content/Audio/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/Content/Characters/.gitkeep b/Content/Characters/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/Content/Environments/.gitkeep b/Content/Environments/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/Content/Items/.gitkeep b/Content/Items/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/Content/Maps/.gitkeep b/Content/Maps/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/Content/Missions/.gitkeep b/Content/Missions/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/Content/UI/.gitkeep b/Content/UI/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/Content/Weapons/.gitkeep b/Content/Weapons/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/Plugins/.gitkeep b/Plugins/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/README.md b/README.md
index f97df80..5dd1a83 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,32 @@
 # seminole
 Seminole is a 3d game where the user is part of a Seminole tribe in the 1900s
 
+## Unreal Engine project
+
+The shipping game is built with **Unreal Engine 5.8** (`Seminole.uproject`,
+C++ module `Seminole` under `Source/`, content under `Content/`). The
+technical foundation is documented in [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md)
+and the decisions behind it in [docs/adr/](docs/adr/README.md). The UE project
+is currently a skeleton: no gameplay, maps or plugins yet.
+
+Binary assets go through **Git LFS**. Install it once, *before* cloning or
+pulling, so LFS files are fetched instead of pointer stubs:
+
+```sh
+git lfs install
+git clone https://github.com/nabledhq/seminole.git
+```
+
+If you cloned before installing LFS, run `git lfs install` and then
+`git lfs pull` inside the repository.
+
+To open the project, install Unreal Engine 5.8 with a C++ toolchain,
+right-click `Seminole.uproject` and generate project files, then build the
+`SeminoleEditor` target and open the `.uproject`.
+
+The browser prototype below is a preview and design sandbox and keeps working
+independently of the Unreal project.
+
 ## Playing
 
 The game runs in the browser using [Babylon.js](https://www.babylonjs.com/)
@@ -93,6 +119,16 @@ See [ASSETS_LICENSES.md](ASSETS_LICENSES.md).
 ## Project layout
 
 ```
+Seminole.uproject       Unreal Engine 5.8 project (module Seminole; no plugins enabled yet)
+Source/                 UE C++: Seminole.Target.cs, SeminoleEditor.Target.cs and the Seminole module
+  Seminole/             Module stub plus one README-only folder per planned system
+Content/                UE assets (AI, Characters, Environments, Items, Maps, Missions, Weapons, UI, Audio); empty for now
+Config/                 UE DefaultEngine.ini, DefaultGame.ini, DefaultInput.ini
+Plugins/                Project plugins (none yet)
+docs/ARCHITECTURE.md    Technical foundation of the Unreal project
+docs/adr/               Architecture decision records
+.gitattributes          Git LFS rules for binary assets
+
 index.html              Page shell, HUD, hover prompt and the How to Play panel container
 src/main.js             Entry point: checks for WebGL and starts the game
 src/engine/             Babylon.js runtime
diff --git a/Seminole.uproject b/Seminole.uproject
new file mode 100644
index 0000000..2222045
--- /dev/null
+++ b/Seminole.uproject
@@ -0,0 +1,17 @@
+{
+	"FileVersion": 3,
+	"EngineAssociation": "5.8",
+	"Category": "",
+	"Description": "Seminole: a co-op survival game set in the Florida Everglades around 1900.",
+	"Modules": [
+		{
+			"Name": "Seminole",
+			"Type": "Runtime",
+			"LoadingPhase": "Default",
+			"AdditionalDependencies": [
+				"Engine"
+			]
+		}
+	],
+	"Plugins": []
+}
diff --git a/Source/Seminole.Target.cs b/Source/Seminole.Target.cs
new file mode 100644
index 0000000..8588ac1
--- /dev/null
+++ b/Source/Seminole.Target.cs
@@ -0,0 +1,16 @@
+// Copyright Seminole contributors. MIT licence; see LICENSE.
+
+using UnrealBuildTool;
+using System.Collections.Generic;
+
+public class SeminoleTarget : TargetRules
+{
+	public SeminoleTarget(TargetInfo Target) : base(Target)
+	{
+		Type = TargetType.Game;
+		DefaultBuildSettings = BuildSettingsVersion.Latest;
+		IncludeOrderVersion = EngineIncludeOrderVersion.Latest;
+
+		ExtraModuleNames.Add("Seminole");
+	}
+}
diff --git a/Source/Seminole/AI/README.md b/Source/Seminole/AI/README.md
new file mode 100644
index 0000000..b781bb7
--- /dev/null
+++ b/Source/Seminole/AI/README.md
@@ -0,0 +1,6 @@
+# AI
+
+Infected AI: StateTree assets' C++ tasks, conditions and evaluators, AI Perception setup (sight and hearing) and NavMesh movement. The state flow is Idle -> Wander -> Hear Noise -> Investigate -> Detect Player -> Chase -> Attack -> Lose Player -> Search -> Wander.
+
+No code lives here yet; this folder fixes where the system lands when its ticket is funded.
+See [docs/ARCHITECTURE.md](../../../docs/ARCHITECTURE.md).
diff --git a/Source/Seminole/Characters/README.md b/Source/Seminole/Characters/README.md
new file mode 100644
index 0000000..356cc0e
--- /dev/null
+++ b/Source/Seminole/Characters/README.md
@@ -0,0 +1,6 @@
+# Characters
+
+Player and NPC characters: the base character class, Enhanced Input bindings, movement and animation hooks.
+
+No code lives here yet; this folder fixes where the system lands when its ticket is funded.
+See [docs/ARCHITECTURE.md](../../../docs/ARCHITECTURE.md).
diff --git a/Source/Seminole/Combat/README.md b/Source/Seminole/Combat/README.md
new file mode 100644
index 0000000..65c28b0
--- /dev/null
+++ b/Source/Seminole/Combat/README.md
@@ -0,0 +1,6 @@
+# Combat
+
+Weapons, melee and ranged attacks, damage application and hit reactions. Attacks emit noise events.
+
+No code lives here yet; this folder fixes where the system lands when its ticket is funded.
+See [docs/ARCHITECTURE.md](../../../docs/ARCHITECTURE.md).
diff --git a/Source/Seminole/Community/README.md b/Source/Seminole/Community/README.md
new file mode 100644
index 0000000..a976504
--- /dev/null
+++ b/Source/Seminole/Community/README.md
@@ -0,0 +1,6 @@
+# Community
+
+The player camp as a community: villagers, their roles and needs, and camp upgrades between day and night phases.
+
+No code lives here yet; this folder fixes where the system lands when its ticket is funded.
+See [docs/ARCHITECTURE.md](../../../docs/ARCHITECTURE.md).
diff --git a/Source/Seminole/Interaction/README.md b/Source/Seminole/Interaction/README.md
new file mode 100644
index 0000000..5d4fe7e
--- /dev/null
+++ b/Source/Seminole/Interaction/README.md
@@ -0,0 +1,6 @@
+# Interaction
+
+Interactable actors and the interaction component: pick up, use, open, board a canoe.
+
+No code lives here yet; this folder fixes where the system lands when its ticket is funded.
+See [docs/ARCHITECTURE.md](../../../docs/ARCHITECTURE.md).
diff --git a/Source/Seminole/Inventory/README.md b/Source/Seminole/Inventory/README.md
new file mode 100644
index 0000000..60e8b9e
--- /dev/null
+++ b/Source/Seminole/Inventory/README.md
@@ -0,0 +1,6 @@
+# Inventory
+
+Items, containers, equipment slots and the data assets that describe them.
+
+No code lives here yet; this folder fixes where the system lands when its ticket is funded.
+See [docs/ARCHITECTURE.md](../../../docs/ARCHITECTURE.md).
diff --git a/Source/Seminole/Multiplayer/README.md b/Source/Seminole/Multiplayer/README.md
new file mode 100644
index 0000000..59590c1
--- /dev/null
+++ b/Source/Seminole/Multiplayer/README.md
@@ -0,0 +1,6 @@
+# Multiplayer
+
+Listen-server co-op plumbing: sessions, join flow, replication helpers and the Steam online subsystem integration (enabled in a later ticket).
+
+No code lives here yet; this folder fixes where the system lands when its ticket is funded.
+See [docs/ARCHITECTURE.md](../../../docs/ARCHITECTURE.md).
diff --git a/Source/Seminole/Persistence/README.md b/Source/Seminole/Persistence/README.md
new file mode 100644
index 0000000..2985c7d
--- /dev/null
+++ b/Source/Seminole/Persistence/README.md
@@ -0,0 +1,6 @@
+# Persistence
+
+Host-owned save game: what is saved, when, and how clients receive world state on join.
+
+No code lives here yet; this folder fixes where the system lands when its ticket is funded.
+See [docs/ARCHITECTURE.md](../../../docs/ARCHITECTURE.md).
diff --git a/Source/Seminole/Seminole.Build.cs b/Source/Seminole/Seminole.Build.cs
new file mode 100644
index 0000000..2d1f7d1
--- /dev/null
+++ b/Source/Seminole/Seminole.Build.cs
@@ -0,0 +1,22 @@
+// Copyright Seminole contributors. MIT licence; see LICENSE.
+
+using UnrealBuildTool;
+
+public class Seminole : ModuleRules
+{
+	public Seminole(ReadOnlyTargetRules Target) : base(Target)
+	{
+		PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
+
+		PublicDependencyModuleNames.AddRange(new string[]
+		{
+			"Core",
+			"CoreUObject",
+			"Engine",
+			"InputCore",
+			"EnhancedInput"
+		});
+
+		PrivateDependencyModuleNames.AddRange(new string[] { });
+	}
+}
diff --git a/Source/Seminole/Seminole.cpp b/Source/Seminole/Seminole.cpp
new file mode 100644
index 0000000..62adeec
--- /dev/null
+++ b/Source/Seminole/Seminole.cpp
@@ -0,0 +1,6 @@
+// Copyright Seminole contributors. MIT licence; see LICENSE.
+
+#include "Seminole.h"
+#include "Modules/ModuleManager.h"
+
+IMPLEMENT_PRIMARY_GAME_MODULE(FDefaultGameModuleImpl, Seminole, "Seminole");
diff --git a/Source/Seminole/Seminole.h b/Source/Seminole/Seminole.h
new file mode 100644
index 0000000..ac66745
--- /dev/null
+++ b/Source/Seminole/Seminole.h
@@ -0,0 +1,5 @@
+// Copyright Seminole contributors. MIT licence; see LICENSE.
+
+#pragma once
+
+#include "CoreMinimal.h"
diff --git a/Source/Seminole/Survival/README.md b/Source/Seminole/Survival/README.md
new file mode 100644
index 0000000..e1f5da7
--- /dev/null
+++ b/Source/Seminole/Survival/README.md
@@ -0,0 +1,6 @@
+# Survival
+
+Health, hunger, stamina and the day/night cycle that drives the scavenge and defense phases.
+
+No code lives here yet; this folder fixes where the system lands when its ticket is funded.
+See [docs/ARCHITECTURE.md](../../../docs/ARCHITECTURE.md).
diff --git a/Source/Seminole/Vehicles/README.md b/Source/Seminole/Vehicles/README.md
new file mode 100644
index 0000000..885fe49
--- /dev/null
+++ b/Source/Seminole/Vehicles/README.md
@@ -0,0 +1,6 @@
+# Vehicles
+
+Canoe travel: a paddled watercraft with passengers, used to move between islands in the swamp.
+
+No code lives here yet; this folder fixes where the system lands when its ticket is funded.
+See [docs/ARCHITECTURE.md](../../../docs/ARCHITECTURE.md).
diff --git a/Source/Seminole/World/README.md b/Source/Seminole/World/README.md
new file mode 100644
index 0000000..e25e7d6
--- /dev/null
+++ b/Source/Seminole/World/README.md
@@ -0,0 +1,6 @@
+# World
+
+World Partition and PCG integration: the swamp map, biome rules, loot and spawn placement, and the shared noise event subsystem.
+
+No code lives here yet; this folder fixes where the system lands when its ticket is funded.
+See [docs/ARCHITECTURE.md](../../../docs/ARCHITECTURE.md).
diff --git a/Source/SeminoleEditor.Target.cs b/Source/SeminoleEditor.Target.cs
new file mode 100644
index 0000000..3dd4173
--- /dev/null
+++ b/Source/SeminoleEditor.Target.cs
@@ -0,0 +1,16 @@
+// Copyright Seminole contributors. MIT licence; see LICENSE.
+
+using UnrealBuildTool;
+using System.Collections.Generic;
+
+public class SeminoleEditorTarget : TargetRules
+{
+	public SeminoleEditorTarget(TargetInfo Target) : base(Target)
+	{
+		Type = TargetType.Editor;
+		DefaultBuildSettings = BuildSettingsVersion.Latest;
+		IncludeOrderVersion = EngineIncludeOrderVersion.Latest;
+
+		ExtraModuleNames.Add("Seminole");
+	}
+}
diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md
new file mode 100644
index 0000000..0ec1b4d
--- /dev/null
+++ b/docs/ARCHITECTURE.md
@@ -0,0 +1,243 @@
+# Seminole architecture
+
+Seminole is a 1–4 player co-op survival game set in the Florida Everglades
+around 1900. Players are members of a Seminole camp: by day they travel the
+swamp by canoe and scavenge; by night they defend the camp against the
+infected. This document records the technical foundation every later
+community-funded feature builds on. Each major choice has an architecture
+decision record in [`adr/`](adr/README.md).
+
+This document describes intent. Nothing below is implemented yet; the ticket
+that implements a system owns the details and updates this file.
+
+## Engine and programming model
+
+* Unreal Engine **5.8**, desktop first (Windows, then Linux and macOS as
+  effort allows), distributed on Steam. See [ADR 0001](adr/0001-unreal-engine-5.md).
+* One game module, `Seminole`, under `Source/Seminole/`, with one subfolder
+  per system (AI, Characters, Combat, Community, Inventory, Interaction,
+  Multiplayer, Persistence, Survival, Vehicles, World). Each subfolder's
+  `README.md` states its purpose.
+* C++ for core systems: base classes, components, subsystems, replication,
+  save/load and anything performance-sensitive. Blueprint and data assets for
+  content: concrete characters, items, weapons, missions and tuning. Blueprint
+  classes derive from C++ bases and are not expected to contain system logic.
+  See [ADR 0002](adr/0002-cpp-blueprint-hybrid.md).
+* Enhanced Input for all player input; Input Actions and Mapping Contexts are
+  data assets under `Content/`.
+* No Gameplay Ability System by default. Health, stamina, damage and status
+  effects are plain components and data assets until a concrete need appears.
+  See [ADR 0007](adr/0007-no-gameplay-ability-system-by-default.md).
+
+### Intended plugins
+
+The project enables **no** plugins today (`Seminole.uproject` has an empty
+`Plugins` list). Each of the following is enabled in the later ticket that
+first needs it, never speculatively:
+
+| Plugin | Needed by |
+| --- | --- |
+| StateTree | Infected AI |
+| CommonUI | UI |
+| PCG | World generation |
+| MetaSounds | Audio |
+| OnlineSubsystemSteam | Multiplayer/Steam |
+
+## AI
+
+The infected are `ACharacter`-based actors driven by **StateTree**, perceiving
+through **AI Perception** (sight and hearing) and moving on **NavMesh**.
+See [ADR 0003](adr/0003-statetree-ai-without-massentity-at-first.md).
+
+State flow:
+
+```
+Idle -> Wander -> Hear Noise -> Investigate -> Detect Player -> Chase -> Attack -> Lose Player -> Search -> Wander
+```
+
+* `Idle` / `Wander`: low-cost ambient behaviour; wander picks reachable
+  NavMesh points near a home location.
+* `Hear Noise` / `Investigate`: a noise event (below) or a hearing stimulus
+  sets a point of interest; the infected walks there and looks around.
+* `Detect Player` / `Chase` / `Attack`: sight confirms a target; chase uses
+  NavMesh pathing; attack is a melee range check and a hit on the target.
+* `Lose Player` / `Search`: on losing sight, search around the last known
+  position for a while, then fall back to `Wander`.
+
+StateTree tasks, conditions and evaluators are C++ in `Source/Seminole/AI/`;
+the trees themselves and per-type tuning are assets under `Content/AI/`.
+AI runs on the host only (see Multiplayer); clients receive replicated
+movement and animation.
+
+## Noise event system
+
+Noise is **one shared gameplay event**, not a per-system mechanic. See
+[ADR 0004](adr/0004-noise-event-system.md).
+
+* A world subsystem (`Source/Seminole/World/`) exposes
+  `ReportNoise(Location, Loudness, Instigator, Tag)`.
+* Everything that makes noise calls it: footsteps, gunshots, melee impacts,
+  canoe paddling, doors, dropped items, campfire work.
+* The subsystem forwards each event to AI Perception's hearing sense and
+  broadcasts a delegate so other systems (audio cues, UI, missions) can react
+  to the same event.
+* Loudness is a radius in world units; falloff and material attenuation are
+  tuning details for the implementing ticket.
+
+## Large-population roadmap
+
+1. **StateTree actors first.** The vertical slice uses individual
+   `ACharacter` infected driven by StateTree. This is the simplest thing that
+   works, debuggable in the editor, and sufficient for the camp-defense scale
+   of the slice.
+2. **Cheap distance tiers.** Reduce tick rate, perception frequency and
+   animation quality for infected far from any player before touching the
+   architecture.
+3. **MassEntity as an optional later step.** If a later feature needs hordes
+   beyond what tiered actors can handle, MassEntity can represent distant
+   infected as entities and hand off to StateTree actors near players. This
+   is not planned for the vertical slice and is not a dependency of any
+   current system.
+
+## World
+
+* One persistent swamp level using **World Partition** for streaming; islands,
+  hammocks and camp sites are placed as data layers and streamed by distance.
+* **PCG** scatters vegetation, debris and loot spawn points from biome rules
+  so the swamp can grow without hand-placing every palmetto.
+* Water is traversable by canoe (see Gameplay components) and slow to wade.
+* A day/night cycle is the clock for the scavenge and defense phases
+  (Survival).
+* World code lives in `Source/Seminole/World/`; maps and PCG graphs under
+  `Content/Maps/` and `Content/Environments/`.
+
+## Multiplayer/Steam
+
+* **Listen server** for 1–4 players: one player hosts, others join. Single
+  player is a listen server with no clients. See
+  [ADR 0005](adr/0005-listen-server-and-steam.md).
+* Authority lives on the host: AI, noise, damage, inventory mutations, loot
+  and the day/night clock. Clients predict only their own movement.
+* Steam provides sessions, invites and friends-join through
+  `OnlineSubsystemSteam`; the Steam AppID and Steamworks configuration are
+  added when the Steam ticket is funded.
+* Code in `Source/Seminole/Multiplayer/`. No dedicated servers.
+
+## Persistence
+
+* A **host-owned save game**: the host's machine stores the camp, world state,
+  mission progress and every participating player's character. See
+  [ADR 0006](adr/0006-host-owned-save-game.md).
+* Saving happens at phase boundaries (end of day, end of night) and on
+  graceful exit, using `USaveGame` subclasses serialised with the engine's
+  save system.
+* Clients joining a saved session receive state through normal replication;
+  their own character is restored from the host's save when they reconnect.
+* Code in `Source/Seminole/Persistence/`.
+
+## Gameplay components
+
+Systems are `UActorComponent`s on C++ base actors, configured by data assets.
+Planned components and their folders:
+
+| Folder | Components |
+| --- | --- |
+| `Characters/` | Player and villager base characters, Enhanced Input, animation hooks |
+| `Survival/` | Health, stamina, hunger, day/night phase |
+| `Combat/` | Weapons, melee and ranged attacks, damage |
+| `Inventory/` | Items, containers, equipment |
+| `Interaction/` | Interactable actors and the interaction component |
+| `Vehicles/` | Canoe: a paddled pawn carrying passengers |
+| `Community/` | Villagers, roles, camp upgrades |
+
+Every component that can make noise reports it through the noise subsystem.
+
+## UI
+
+* **UMG** widgets built on **CommonUI** for consistent input handling across
+  keyboard/mouse and gamepad, and for a single activatable-widget stack.
+* HUD (health, stamina, time of day, noise indicator), inventory, pause and
+  session menus. Widget assets under `Content/UI/`.
+
+## Audio
+
+* **MetaSounds** for procedural, parameter-driven sound: swamp ambience that
+  follows the time of day, infected vocalisations, weapons.
+* Audio reacts to the same noise events the AI hears, so what players hear and
+  what the infected hear stay consistent.
+* Sound assets under `Content/Audio/`.
+
+## Art pipeline
+
+* Source files (`.blend`, `.spp`, `.sbs`, `.sbsar`, `.psd`) are kept in the
+  repository through Git LFS alongside the exported `.fbx`, `.png`, `.tga`
+  and `.wav` they produce.
+* Characters, environments, items and weapons each have a `Content/`
+  folder; naming and texel-density conventions are set by the first art
+  ticket.
+* The period setting (Seminole camp life around 1900) should be reviewed by
+  cultural advisors before final art is accepted.
+
+## Source control
+
+* **Git with Git LFS**. `.gitattributes` routes `.uasset`, `.umap`, `.fbx`,
+  `.wav`, `.png`, `.tga`, `.psd`, `.blend`, `.spp`, `.sbs` and `.sbsar`
+  through LFS. See [ADR 0008](adr/0008-git-lfs-before-perforce.md).
+* Binary assets cannot be merged. Until file locking is needed, coordinate
+  through tickets: one open ticket owns a given map or asset at a time. Keep
+  maps small and split content with World Partition data layers and One File
+  Per Actor to reduce conflicts.
+* `.gitignore` excludes `Binaries/`, `Intermediate/`, `Saved/`,
+  `DerivedDataCache/` and IDE files. `Content/` and `Config/` are tracked.
+* Perforce is a possible later move if LFS becomes a bottleneck; nothing in
+  the layout prevents it.
+
+## Browser strategy
+
+* The repository also contains a **Babylon.js browser prototype** (`src/`,
+  `index.html`, `package.json`, deployed to GitHub Pages by
+  `.github/workflows/nabled-play.yml`). It exists so backers can try builds
+  in a browser and it predates this document.
+* The shipping game is the Unreal Engine 5.8 project. The browser prototype
+  is a preview and design sandbox, not a second target: gameplay systems
+  are built once, in Unreal.
+* The prototype stays in the repository and keeps working; it is not deleted
+  by the UE scaffold, and the two trees do not share code. Its future
+  (keep as showcase, or retire once the UE build has playable releases) is
+  a later decision.
+* Browser-first builds of the Unreal project (Pixel Streaming or otherwise)
+  are out of scope.
+
+## Vertical slice contents and target loop
+
+Contents:
+
+* One swamp map (World Partition, PCG-scattered vegetation).
+* Canoe travel between the camp and scavenge sites.
+* A **day scavenge phase**: paddle out, explore, gather items, make noise
+  carefully, return.
+* A **night defense phase**: infected drawn by noise and light approach the
+  camp; players defend it.
+* Co-op for 1–4 players over a listen server.
+
+Target loop: wake at camp -> canoe out -> scavenge -> return before dark ->
+prepare -> survive the night -> repeat. Each loop should make the camp a
+little stronger and the night a little harder.
+
+## Deferred / Out of scope
+
+Deferred (possible later, not planned now):
+
+* MassEntity for large infected populations.
+* Gameplay Ability System.
+* Perforce.
+* Linux and macOS builds; gamepad polish beyond CommonUI defaults.
+* Retiring or re-scoping the browser prototype.
+
+Out of scope for this project:
+
+* Dedicated servers, MMO-style worlds, backend orchestration.
+* Browser-first or mobile builds, console ports.
+* Final art direction or content.
+* Any gameplay system in this ticket: AI, noise, health, inventory, weapons,
+  canoe, persistence, networking are documented here and implemented later.
diff --git a/docs/adr/0001-unreal-engine-5.md b/docs/adr/0001-unreal-engine-5.md
new file mode 100644
index 0000000..08351b8
--- /dev/null
+++ b/docs/adr/0001-unreal-engine-5.md
@@ -0,0 +1,27 @@
+# 0001. Unreal Engine 5
+
+Status: Accepted
+
+## Context
+
+Seminole needs a 3D engine for a desktop co-op survival game with a large
+streamed outdoor world, a population of AI characters, networking and a Steam
+release. The repository already holds a Babylon.js browser prototype that is
+useful for previews but is not a production game engine for this scope.
+
+## Decision
+
+Build the game on Unreal Engine **5.8**. Desktop first, distributed on Steam.
+The project is a C++ project (`Seminole.uproject`, module `Seminole`), not a
+Blueprint-only project.
+
+## Consequences
+
+* World Partition, PCG, StateTree, AI Perception, NavMesh, the replication
+  system, Enhanced Input, UMG/CommonUI and MetaSounds come with the engine;
+  the other ADRs build on them.
+* Binary assets (`.uasset`, `.umap`) require Git LFS and careful
+  coordination (see ADR 0008).
+* Contributors need an Unreal 5.8 installation and a C++ toolchain. Engine
+  version is pinned by `EngineAssociation`; upgrades are explicit tickets.
+* The browser prototype remains a preview, not a second target.
diff --git a/docs/adr/0002-cpp-blueprint-hybrid.md b/docs/adr/0002-cpp-blueprint-hybrid.md
new file mode 100644
index 0000000..a692aa3
--- /dev/null
+++ b/docs/adr/0002-cpp-blueprint-hybrid.md
@@ -0,0 +1,31 @@
+# 0002. C++ and Blueprint hybrid
+
+Status: Accepted
+
+## Context
+
+Unreal supports pure Blueprint, pure C++ and mixed projects. Seminole's
+systems (AI, noise, replication, persistence) need performance, diffable
+source and unit-testable logic. Its content (characters, items, weapons,
+missions, tuning) benefits from fast iteration by non-programmers.
+
+## Decision
+
+* **C++ for core systems**: base actor and component classes, subsystems,
+  replication, save/load, StateTree tasks and anything performance-sensitive.
+  Code lives in `Source/Seminole/<System>/`.
+* **Blueprint and data assets for content**: concrete characters, items,
+  weapons, missions, StateTree assets and tuning values. Blueprint classes
+  derive from C++ bases and contain presentation and configuration, not
+  system logic.
+* Exposed C++ API is marked `BlueprintCallable` / `BlueprintReadOnly` where
+  content needs it; everything else stays private.
+
+## Consequences
+
+* Core logic is reviewable in pull requests and merges cleanly; Blueprint
+  assets are binary and conflict-prone, so they stay thin.
+* Every system ticket delivers a C++ base plus one or more Blueprint or data
+  asset examples under `Content/`.
+* Contributors who only touch content do not need to compile C++ once a
+  build is available, but the repository remains a C++ project.
diff --git a/docs/adr/0003-statetree-ai-without-massentity-at-first.md b/docs/adr/0003-statetree-ai-without-massentity-at-first.md
new file mode 100644
index 0000000..345eafb
--- /dev/null
+++ b/docs/adr/0003-statetree-ai-without-massentity-at-first.md
@@ -0,0 +1,35 @@
+# 0003. StateTree AI without MassEntity at first
+
+Status: Accepted
+
+## Context
+
+The infected need to idle, wander, react to noise, investigate, detect,
+chase, attack, lose and search for players. Unreal offers Behavior Trees,
+StateTree, and the MassEntity framework (with StateTree-driven Mass
+processors) for very large populations. The vertical slice is one camp
+defended at night, not a city-scale horde.
+
+## Decision
+
+* Drive each infected with **StateTree** on an `ACharacter`-based actor,
+  using **AI Perception** (sight, hearing) and **NavMesh** movement.
+* The state flow is
+  `Idle -> Wander -> Hear Noise -> Investigate -> Detect Player -> Chase -> Attack -> Lose Player -> Search -> Wander`.
+* StateTree tasks, conditions and evaluators are C++ in
+  `Source/Seminole/AI/`; tree assets and tuning are under `Content/AI/`.
+* **MassEntity is not used initially.** It remains an optional later step
+  for distant or very large populations, with a hand-off to StateTree actors
+  near players.
+* Before any move to Mass, apply cheap distance tiers (tick rate, perception
+  frequency, animation quality) to far-away infected.
+
+## Consequences
+
+* The AI is debuggable with the standard editor tools and simple to reason
+  about on a listen server (host authority).
+* Population size is bounded by actor cost; this is acceptable for the slice
+  and is the explicit trade-off.
+* The `StateTree` plugin is enabled by the AI ticket, not before.
+* If Mass is adopted later, the state flow and noise interface stay the same;
+  only the representation of distant infected changes.
diff --git a/docs/adr/0004-noise-event-system.md b/docs/adr/0004-noise-event-system.md
new file mode 100644
index 0000000..7662a3f
--- /dev/null
+++ b/docs/adr/0004-noise-event-system.md
@@ -0,0 +1,32 @@
+# 0004. Noise event system
+
+Status: Accepted
+
+## Context
+
+Noise is the central tension of Seminole: scavenging quietly by day and
+holding the camp at night both depend on what the infected hear. Footsteps,
+gunshots, melee, paddling, doors, dropped items and camp work all make
+noise. If each system reported noise its own way, the AI, audio and UI would
+drift apart and tuning would be scattered.
+
+## Decision
+
+* Noise is **one shared gameplay event** handled by a single world subsystem
+  (`Source/Seminole/World/`), with an API of the form
+  `ReportNoise(Location, Loudness, Instigator, Tag)`.
+* Every noise source calls this one entry point; nothing talks to AI
+  Perception's hearing sense directly.
+* The subsystem forwards the event to AI Perception hearing and broadcasts a
+  delegate so audio, UI (noise indicator) and missions react to the same
+  event.
+* Loudness is a world-space radius; attenuation rules belong to the
+  implementing ticket.
+* Noise is authoritative on the host (see ADR 0005).
+
+## Consequences
+
+* One place to tune, log and visualise noise; one place to replicate it.
+* AI, audio and UI agree on what happened, by construction.
+* Every gameplay ticket that adds a noisy action depends on this subsystem
+  and must call it; the stub README in `Source/Seminole/World/` records this.
diff --git a/docs/adr/0005-listen-server-and-steam.md b/docs/adr/0005-listen-server-and-steam.md
new file mode 100644
index 0000000..16e5a5b
--- /dev/null
+++ b/docs/adr/0005-listen-server-and-steam.md
@@ -0,0 +1,32 @@
+# 0005. Listen server and Steam
+
+Status: Accepted
+
+## Context
+
+Seminole is co-op for 1–4 players, sold on Steam. Options are a listen
+server (one player's game hosts), dedicated servers (hosted by us or by
+players) or peer-to-peer. Dedicated servers need infrastructure and
+operations the project does not want; the player count is small and sessions
+are friend groups.
+
+## Decision
+
+* **Listen server**: the hosting player's game is the authority. Single
+  player is a listen server with no clients.
+* **Steam** (`OnlineSubsystemSteam`) provides sessions, invites and
+  friends-join. The Steam AppID and Steamworks configuration are added by
+  the Steam ticket, not now.
+* Authority on the host for AI, noise, damage, inventory mutations, loot and
+  the day/night clock. Clients predict only their own movement.
+* Code in `Source/Seminole/Multiplayer/`.
+
+## Consequences
+
+* No server infrastructure to run or pay for; sessions live and die with the
+  host.
+* Host advantage (zero latency) is accepted for a co-op game.
+* Replication is designed from the start: every gameplay system ticket
+  states what replicates and what is host-only.
+* Dedicated servers, MMO-style worlds and backend orchestration are out of
+  scope.
diff --git a/docs/adr/0006-host-owned-save-game.md b/docs/adr/0006-host-owned-save-game.md
new file mode 100644
index 0000000..c4e78a6
--- /dev/null
+++ b/docs/adr/0006-host-owned-save-game.md
@@ -0,0 +1,29 @@
+# 0006. Host-owned save game
+
+Status: Accepted
+
+## Context
+
+Progress (camp, world state, missions, characters) must survive between
+sessions. With a listen server (ADR 0005) the host already owns the
+authoritative state. Alternatives are per-player saves that must be merged,
+or a cloud/backend store.
+
+## Decision
+
+* The save game is **owned by the host**: the hosting player's machine
+  stores the camp, world state, mission progress and every participating
+  player's character, keyed by their online identity.
+* Save at phase boundaries (end of day, end of night) and on graceful exit,
+  using `USaveGame` subclasses and the engine's save system.
+* Clients receive state through replication on join; a returning client's
+  character is restored from the host's save.
+* Code in `Source/Seminole/Persistence/`.
+
+## Consequences
+
+* One consistent world per host; no merge of divergent saves.
+* A player's progress in a given camp lives with that camp's host. Players
+  who host their own camp have their own save. This is the accepted
+  trade-off; portable per-player characters are a possible later feature.
+* Steam Cloud sync of the host's save is a later, optional addition.
diff --git a/docs/adr/0007-no-gameplay-ability-system-by-default.md b/docs/adr/0007-no-gameplay-ability-system-by-default.md
new file mode 100644
index 0000000..93fd8fb
--- /dev/null
+++ b/docs/adr/0007-no-gameplay-ability-system-by-default.md
@@ -0,0 +1,28 @@
+# 0007. No Gameplay Ability System by default
+
+Status: Accepted
+
+## Context
+
+The Gameplay Ability System (GAS) is Unreal's framework for abilities,
+attributes and effects with built-in replication and prediction. It is
+powerful, but it has a steep learning curve, pervasive boilerplate and
+shapes every gameplay class around it. Seminole's needs are health, stamina,
+hunger, a few weapons, melee and some status effects, in a small co-op game.
+
+## Decision
+
+* Do **not** adopt GAS by default.
+* Model health, stamina, hunger, damage and status effects as plain
+  `UActorComponent`s and data assets in `Source/Seminole/Survival/` and
+  `Combat/`, replicated with standard property replication and RPCs.
+* Revisit if a concrete feature needs predicted abilities, stacking effects
+  with complex lifetimes, or a large ability catalogue. Adoption would be
+  its own ADR and ticket.
+
+## Consequences
+
+* Lower barrier for contributors; smaller, readable systems.
+* Some things GAS gives for free (effect stacking, attribute aggregation,
+  cue routing) are written by hand if and when needed; keep them small.
+* Full GAS adoption is explicitly out of scope for the vertical slice.
diff --git a/docs/adr/0008-git-lfs-before-perforce.md b/docs/adr/0008-git-lfs-before-perforce.md
new file mode 100644
index 0000000..2d8c800
--- /dev/null
+++ b/docs/adr/0008-git-lfs-before-perforce.md
@@ -0,0 +1,36 @@
+# 0008. Git LFS before Perforce
+
+Status: Accepted
+
+## Context
+
+Unreal projects hold many large binary assets (`.uasset`, `.umap`, textures,
+meshes, audio) that Git handles poorly without help. Perforce is the
+industry default for Unreal teams, with file locking and good editor
+integration, but it needs a server and is a poor fit for a community-funded
+open project whose contributions arrive as GitHub pull requests.
+
+## Decision
+
+* Keep **Git**, hosted on GitHub, and route binary assets through **Git
+  LFS**. `.gitattributes` tracks `*.uasset`, `*.umap`, `*.fbx`, `*.wav`,
+  `*.png`, `*.tga`, `*.psd`, `*.blend`, `*.spp`, `*.sbs` and `*.sbsar`.
+* Contributors run `git lfs install` once before cloning or pulling.
+* Avoid binary merge conflicts by process: one open ticket owns a given map
+  or asset at a time; keep maps small; use World Partition data layers and
+  One File Per Actor.
+* `.gitignore` excludes generated directories (`Binaries/`,
+  `Intermediate/`, `Saved/`, `DerivedDataCache/`) and IDE files; `Content/`
+  and `Config/` are tracked.
+
+## Consequences
+
+* The existing pull-request workflow and GitHub Pages preview keep working.
+* LFS bandwidth and storage quotas apply; large asset drops should be
+  reviewed for size (see `ASSETS_LICENSES.md` for the current limits).
+* LFS has no locking by default; coordination is social, not enforced. If
+  this becomes a bottleneck, moving to Perforce (or enabling LFS file
+  locking) is a later ticket. Nothing in the layout prevents it.
+* Files already committed before this rule (for example the screenshots in
+  `docs/screenshots/`) remain ordinary Git objects; only new matching files
+  go through LFS unless a migration is done deliberately.
diff --git a/docs/adr/README.md b/docs/adr/README.md
new file mode 100644
index 0000000..e57bf3a
--- /dev/null
+++ b/docs/adr/README.md
@@ -0,0 +1,20 @@
+# Architecture decision records
+
+Each record captures one decision behind [ARCHITECTURE.md](../ARCHITECTURE.md)
+with **Context**, **Decision** and **Consequences** headings. Records are
+numbered in order and never edited to change their meaning; a reversed
+decision gets a new record that supersedes the old one.
+
+| # | Decision |
+| --- | --- |
+| [0001](0001-unreal-engine-5.md) | Unreal Engine 5 (5.8, desktop first, Steam) |
+| [0002](0002-cpp-blueprint-hybrid.md) | C++ for core systems, Blueprint and data assets for content |
+| [0003](0003-statetree-ai-without-massentity-at-first.md) | StateTree AI without MassEntity at first |
+| [0004](0004-noise-event-system.md) | Noise as one shared gameplay event |
+| [0005](0005-listen-server-and-steam.md) | Listen server for 1–4 player co-op, Steam for sessions |
+| [0006](0006-host-owned-save-game.md) | Host-owned save game |
+| [0007](0007-no-gameplay-ability-system-by-default.md) | No Gameplay Ability System by default |
+| [0008](0008-git-lfs-before-perforce.md) | Git with Git LFS before Perforce |
+
+To add a record, copy the structure of an existing file, use the next number
+and add a row here.
Acceptance · round 1
Voting open
CIPassed
Automated reviewPass

The diff delivers every scoped item: a thorough ARCHITECTURE.md covering all 15 topics, 8 well-structured ADRs with an index, a standard UE 5.8 C++ project skeleton, LFS rules, Unreal ignores and a README section. The existing Babylon.js prototype was correctly preserved and integrated around. Every acceptance criterion is met on inspection. Remaining items are minor: the PNG-through-LFS interaction with the existing prototype and Pages deploy, a possibly dangling ASSETS_LICENSES.md reference, slightly more than minimal engine config, and unverified UE compilation, which the spec allows.

Acceptance criteria · 11 of 11 met
  • YESdocs/ARCHITECTURE.md has a heading for every Scope 1 topic, the full AI state flow string, an Intended plugins list and a Deferred / Out of scope listdocs/ARCHITECTURE.md has ## headings for all 15 topics, the exact state flow string in a code block, a '### Intended plugins' table of the 5 plugins stating each is enabled by the later ticket, and a '## Deferred / Out of scope' section.
  • YESdocs/adr/ contains at least 8 ADR files with Context, Decision and Consequences headings covering the 8 decisionsdocs/adr/0001–0008 each have ## Context / ## Decision / ## Consequences and map one-to-one to the listed decisions, and docs/adr/README.md indexes them.
  • YESSeminole.uproject parses as JSON with FileVersion 3 and EngineAssociation "5.8"Seminole.uproject is well-formed JSON with "FileVersion": 3 and "EngineAssociation": "5.8".
  • YESSeminole.uproject lists exactly one module Seminole (Runtime) and enables no pluginsThere is a single Modules entry with Name Seminole, Type Runtime and LoadingPhase Default, and "Plugins": [] is empty.
  • YESTarget.cs, Build.cs, Seminole.h and Seminole.cpp exist and follow standard UE5 game-module boilerplateThe Game and Editor targets use BuildSettingsVersion.Latest and EngineIncludeOrderVersion.Latest, Build.cs uses UseExplicitOrSharedPCHs with the 5 listed deps, and Seminole.cpp calls IMPLEMENT_PRIMARY_GAME_MODULE(FDefaultGameModuleImpl, Seminole, "Seminole").
  • YESEvery listed Source and Content subfolder exists and contains a tracked fileThere are 11 Source/Seminole/<System>/README.md stubs, each stating its purpose, and 9 Content/<Folder>/.gitkeep files, plus Plugins/.gitkeep.
  • YES.gitattributes contains an LFS rule for each listed extensionThe new .gitattributes has `filter=lfs diff=lfs merge=lfs -text` lines for all 11 extensions.
  • YES.gitignore excludes Binaries/, Intermediate/, Saved/ and DerivedDataCache/These entries are appended to the existing .gitignore along with IDE ignores, without ignoring Content/ or Config/.
  • YESNo C++ classes exist beyond the module stubThe only C++ files are Seminole.h, which includes CoreMinimal, and Seminole.cpp, which contains the module macro.
  • YESNo .uasset or .umap files are addedThe diff file list contains no .uasset or .umap files, and DefaultEngine.ini sets no maps.
  • YESNo pre-existing file is deletedThe diff shows only new files plus appends to README.md and .gitignore, with existing lines retained.
Concerns
  • The `*.png` LFS rule (required by the spec) also covers the existing browser prototype. If prototype PNGs are added later, the GitHub Pages workflow will deploy LFS pointer files unless its checkout enables `lfs: true`. Already-committed `docs/screenshots/*.png` may also show as modified for contributors who run `git lfs install`. The builder flagged this; a maintainer should decide on migration and workflow changes.
  • ADR 0008 says to see `ASSETS_LICENSES.md` "for the current limits" on LFS size and quota. The diff cannot confirm that file actually documents such limits; if it does not, this is a dangling reference.
  • `Config/DefaultEngine.ini` adds renderer and hardware-targeting defaults (Lumen GI and reflections, virtual shadows, mesh distance fields) beyond the "minimal valid" config the spec asked for. This is harmless but is an unrequested project-level choice.
  • The ARCHITECTURE large-population roadmap inserts a "cheap distance tiers" step between StateTree actors and MassEntity, slightly elaborating the spec's two-step assumption. It is reasonable, but it is an addition.
  • UE compilation is unverified, as the spec allows, and CI build and deploy were skipped. The C++ and C# boilerplate looks standard, but a maintainer should build `SeminoleEditor` once with UE 5.8.

BackersWaiting for votes
0 accept · 0 rebuild · 1 not voted · quorum 1 of 1
MaintainerNot decided yet

Both keys are needed: a majority of backers to accept and the maintainer to merge. The window closes in 6 days. Below quorum, the automated verdict decides for the backers. Rebuilds used: 0 of 2.

Automated review cost $0.15, counted as builder cost.

Discussion · 0

No comments yet.