Docs
FabReady v0.3-dev — Automated preflight QA for Fab marketplace submissions.
Getting Started
Prerequisites
- * Unreal Engine 5.4, 5.5, 5.6, or 5.7
- * Visual Studio 2022 with C++ workload (Windows) or Xcode (macOS)
Installation
Clone or download the FabReady plugin into your project's Plugins/ directory. On first launch, UE will prompt to compile the plugin. Requires Visual Studio 2022 with C++ workload (Windows) or Xcode (macOS).
Prebuilt binaries for UE 5.4–5.7 will be available on the Fab marketplace when v1.0 ships.
Running in Editor
- 1. Open your project in Unreal Editor
- 2. Window > FabReady to open the tab
- 3. Select policy (
fab/v0), configure options - 4. Click Run Preflight
- 5. Review findings — click Open Folder for HTML/JSON reports
Options
| Option | Description |
|---|---|
| Pack Name | Scopes validation to /Game/{PackName}/. Leave empty to scan all of /Game/. |
| Auto-Fix | Automatically fix redirectors (unattended-safe, no dialogs). |
| Zip Evidence | Create evidence_bundle.zip alongside the directory. |
| Build Staging Zip | Create fab_staging_project.zip for Fab upload. |
| Run Render QA | Run screenshot-based automation tests (requires GPU). |
Rules
18 validation rules across 7 categories. All rules are free — always.
| Rule ID | Severity | Description |
|---|---|---|
| fab.structure.pack_structure | error | Validates project directory structure (Config/, Content/ exist) |
| fab.structure.plugin_zip | warning | Validates staging zip matches expected structure |
| fab.structure.single_root | error | Content must live under a single root folder |
| fab.structure.showcase_map | warning | A demo/showcase level must exist in the project |
| fab.assets.redirectors | warning | Detects leftover asset redirectors. Supports auto-fix. |
| fab.assets.unused | warning | Assets not referenced by any other asset in the project |
| fab.assets.broken_references | error | Assets referencing deleted or missing assets |
| fab.assets.duplicate_names | warning | Same asset name in multiple folders |
| fab.meshes.collision | warning | StaticMesh has no simple or complex-as-simple collision |
| fab.meshes.lod_presence | warning | High-poly meshes (>10K tris) with only LOD 0 |
| fab.meshes.lightmap_uv | warning | Missing lightmap UV channel at the expected index |
| fab.meshes.scale_validation | warning | Mesh bounds outside reasonable range (wrong m/cm scale) |
| fab.meshes.material_slots | warning | Empty material slots with no material assigned |
| fab.textures.validation | warning | Non-power-of-2 dimensions or exceeds 4096 max resolution |
| fab.textures.srgb_correctness | error | Normal maps with sRGB enabled, mask textures in wrong color space |
| fab.naming.conventions | warning | Missing expected prefix (BP_, M_, T_, SM_, etc.) |
| fab.blueprints.compile_status | error | Blueprint has compile errors |
| fab.audio.format_validation | warning | Non-standard sample rate (not 22050, 44100, or 48000 Hz) |
Naming Prefix Rules
The fab.naming.conventions rule validates asset prefixes based on class:
CLI / Commandlet
Run FabReady headless for CI/CD pipelines. Same validation engine, same reports.
PowerShell (Windows)
# Basic run — scans all of /Game/ .\Scripts\run_commandlet.ps1 -Policy "fab/v0" # Scoped to a pack .\Scripts\run_commandlet.ps1 -Policy "fab/v0" -PackName "MyGame" # With auto-fix and evidence .\Scripts\run_commandlet.ps1 -Policy "fab/v0" -AutoFix -ZipEvidence
Bash (Linux / macOS)
# Basic run ./Scripts/run_commandlet.sh --policy "fab/v0" # Scoped to a pack ./Scripts/run_commandlet.sh --policy "fab/v0" --pack-name "MyGame"
Direct invocation
UnrealEditor-Cmd.exe MyProject.uproject \ -run=FabReady \ -OutputDir="Output" \ -Policy=fab/v0 \ -AutoFix=1 \ -ZipEvidence=1 \ -BuildStagingZip=1 \ -unattended -nopause
Exit Codes
| Code | Meaning | CI Action |
|---|---|---|
| 0 | No error findings | Pass |
| 1 | Error findings present | Fail build |
| 2 | Fatal execution failure | Fail build |
Output Artifacts
| File | Description |
|---|---|
| report.json | Machine-readable findings report |
| report.html | Human-readable HTML report |
| fabready_run.log | Text summary of the run |
| compat_manifest.json | Compatibility manifest with SHA-1 hashes |
| evidence_bundle/ | Self-contained archive of all artifacts |
| evidence_bundle.zip | Compressed evidence (if ZipEvidence enabled) |
| fab_staging_project.zip | Fab upload package (if BuildStagingZip enabled) |
Policy Packs
Rules are defined in JSON policy files. Swap policies for different submission targets, override severity levels, or create custom rule sets.
Directory Structure
Policies/
└── fab/v0/
├── policy.json # Main policy definition
└── rules/
├── 000_pack_structure.json
├── 001_redirectors.json
├── 010_naming.json
└── ...policy.json
{
"policy_id": "fab/v0",
"version": "0.1.0",
"name": "FabReady Base Policy Pack",
"description": "Core shipping QA rules for Fab submissions",
"rules": [
{
"rule_id": "fab.structure.pack_structure",
"path": "rules/000_pack_structure.json",
"enabled": true,
"severity": "error"
}
]
}Rule Definition
{
"rule_id": "fab.textures.validation",
"title": "Texture Dimension Validation",
"description": "Validates power-of-2 and max resolution",
"severity_default": "warning",
"params_schema": {
"type": "object",
"properties": {
"max_resolution": {
"type": "integer",
"default": 4096
}
}
},
"implementation": "builtin"
}Custom Policy Example
Create Policies/custom/strict/policy.json and run with -Policy=custom/strict.
{
"policy_id": "custom/strict",
"version": "1.0.0",
"name": "Strict Shipping Rules",
"description": "All warnings promoted to errors",
"rules": [
{
"rule_id": "fab.assets.redirectors",
"path": "../../fab/v0/rules/001_redirectors.json",
"enabled": true,
"severity": "error"
}
]
}Reports
Every run produces deterministic reports — same project, same output, every time. SHA-1 fingerprinted for auditability.
JSON Schema (v0)
{
"schema_version": "fabready.report.v0",
"policy_pack_version": "0.1.0",
"run_fingerprint": "a3f8c1d2e4b67890...",
"context": {
"project_path": "/path/to/project",
"pack_name": "MyGame",
"policy_id": "fab/v0",
"engine_version": "5.7.0-...",
"timestamp_utc": "2026-03-20T22:23:00Z",
"auto_fix_enabled": false
},
"summary": {
"total": 30, "errors": 3,
"warnings": 27, "info": 0
},
"findings": [
{
"rule_id": "fab.textures.validation",
"severity": "error",
"message": "Texture exceeds maximum resolution",
"asset_or_path": "/Game/T_Oversized",
"remediation": "Resize to 4096 or smaller",
"can_auto_fix": false
}
]
}Severity Levels
| Level | CI Impact | Meaning |
|---|---|---|
| error | Fails build (exit 1) | Shipping blocker — must fix |
| warning | Passes build (exit 0) | Should fix, not blocking |
| info | Passes build (exit 0) | Informational only |
Fingerprint
The run_fingerprint is a SHA-1 hash of: PolicyId, PolicyPackVersion, EngineVersion, PackName, ProjectPath, and all triggered RuleIds. Two runs with identical fingerprints produce identical findings.
Extensions
Third-party plugins register custom rules via the extension API. Community rules, studio checks, and commercial packs all use the same interface.
IFabReadyRuleProvider
Implement this interface to add custom validation rules without modifying core code.
#include "FabReadyRuleInterface.h"
class FMyCustomRule : public IFabReadyRule
{
public:
virtual FString GetRuleId() const override
{
return TEXT("custom.my_rule");
}
virtual void Evaluate(
const FFabReadyRunContext& Context,
const FFabReadyRuleDefinition& RuleDef,
TArray<FFabReadyFinding>& OutFindings) override
{
// Your validation logic here
FFabReadyFinding Finding;
Finding.RuleId = GetRuleId();
Finding.Severity = RuleDef.SeverityDefault;
Finding.Message = TEXT("Something to report");
OutFindings.Add(Finding);
}
};
FABREADY_REGISTER_RULE(FMyCustomRule)IFabReadyReportAugmenter
Add custom sections or artifacts to reports.
class FMyAugmenter : public IFabReadyReportAugmenter
{
virtual FString GetAugmenterId() const override
{
return TEXT("my-augmenter");
}
virtual void AugmentReport(
FFabReadyReport& Report) override
{
// Add fields to the report extensions
}
virtual TArray<FString> GetAdditionalArtifactPaths(
const FFabReadyRunContext& Context) const override
{
return { TEXT("my_data.json") };
}
};Data Format Licensing
Policy pack, rule definition, and report JSON schemas are MIT licensed. Parse FabReady reports in your CI. Create compatible policy packs. Build integrations. No restrictions on the data formats.