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. 1. Open your project in Unreal Editor
  2. 2. Window > FabReady to open the tab
  3. 3. Select policy (fab/v0), configure options
  4. 4. Click Run Preflight
  5. 5. Review findings — click Open Folder for HTML/JSON reports

Options

OptionDescription
Pack NameScopes validation to /Game/{PackName}/. Leave empty to scan all of /Game/.
Auto-FixAutomatically fix redirectors (unattended-safe, no dialogs).
Zip EvidenceCreate evidence_bundle.zip alongside the directory.
Build Staging ZipCreate fab_staging_project.zip for Fab upload.
Run Render QARun screenshot-based automation tests (requires GPU).

Rules

18 validation rules across 7 categories. All rules are free — always.

Rule IDDescription
fab.structure.pack_structureValidates project directory structure (Config/, Content/ exist)
fab.structure.plugin_zipValidates staging zip matches expected structure
fab.structure.single_rootContent must live under a single root folder
fab.structure.showcase_mapA demo/showcase level must exist in the project
fab.assets.redirectorsDetects leftover asset redirectors. Supports auto-fix.
fab.assets.unusedAssets not referenced by any other asset in the project
fab.assets.broken_referencesAssets referencing deleted or missing assets
fab.assets.duplicate_namesSame asset name in multiple folders
fab.meshes.collisionStaticMesh has no simple or complex-as-simple collision
fab.meshes.lod_presenceHigh-poly meshes (>10K tris) with only LOD 0
fab.meshes.lightmap_uvMissing lightmap UV channel at the expected index
fab.meshes.scale_validationMesh bounds outside reasonable range (wrong m/cm scale)
fab.meshes.material_slotsEmpty material slots with no material assigned
fab.textures.validationNon-power-of-2 dimensions or exceeds 4096 max resolution
fab.textures.srgb_correctnessNormal maps with sRGB enabled, mask textures in wrong color space
fab.naming.conventionsMissing expected prefix (BP_, M_, T_, SM_, etc.)
fab.blueprints.compile_statusBlueprint has compile errors
fab.audio.format_validationNon-standard sample rate (not 22050, 44100, or 48000 Hz)

Naming Prefix Rules

The fab.naming.conventions rule validates asset prefixes based on class:

BP_Blueprint
M_Material
MI_MaterialInstanceConstant
T_Texture2D
SM_StaticMesh
SK_SkeletalMesh
A_AnimSequence
ABP_AnimBlueprint
WBP_WidgetBlueprint
PS_ParticleSystem
NS_NiagaraSystem
SC_SoundCue
SW_SoundWave

CLI / Commandlet

Run FabReady headless for CI/CD pipelines. Same validation engine, same reports.

PowerShell (Windows)

run_commandlet.ps1
# 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)

run_commandlet.sh
# 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

CodeMeaningCI Action
0No error findingsPass
1Error findings presentFail build
2Fatal execution failureFail build

Output Artifacts

FileDescription
report.jsonMachine-readable findings report
report.htmlHuman-readable HTML report
fabready_run.logText summary of the run
compat_manifest.jsonCompatibility manifest with SHA-1 hashes
evidence_bundle/Self-contained archive of all artifacts
evidence_bundle.zipCompressed evidence (if ZipEvidence enabled)
fab_staging_project.zipFab 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.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

rules/030_texture_validation.json
{
  "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.

custom/strict/policy.json
{
  "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)

report.json
{
  "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

LevelCI ImpactMeaning
errorFails build (exit 1)Shipping blocker — must fix
warningPasses build (exit 0)Should fix, not blocking
infoPasses 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.

Custom Rule Example (C++)
#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.

Report Augmenter (C++)
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.