| name | pcg |
| display_name | Procedural Content Generation (PCG) |
| description | Create, inspect, and edit PCG Graph assets — add nodes, configure settings, connect pins, and wire procedural generation graphs (native PCG Python API). Use when the user asks to build a PCG graph, add PCG nodes (Surface Sampler, Static Mesh Spawner, filters), wire PCG pins, place a PCGVolume and generate, or set up procedural scattering. |
| unreal_classes | ["PCGGraph","PCGNode","PCGEdge","PCGPin","PCGPinProperties","PCGSettings","PCGGraphFactory","PCGSurfaceSamplerSettings","PCGStaticMeshSpawnerSettings","PCGMeshSamplerSettings"] |
| keywords | ["pcg","procedural","procedural content generation","pcg graph","pcg node","pcg pin","pcg edge","surface sampler","mesh spawner","static mesh spawner","point filter","density filter","transform","attribute","subgraph","pcg component","connect nodes","add node","wire","graph editor"] |
PCG Skill
PCG (Procedural Content Generation) in UE 5.7 is production-ready and fully scriptable via
the PCGPythonInterop plugin. No VibeUE service wrapper is needed — the Python API is complete.
⚠️ Read this before writing any code
These are the mistakes that cause infinite retry loops. Check each one before executing:
Do not call discover_python_class or discover_python_function on any PCG class — this skill contains everything you need. Calling discover bloats context and causes content filter failures.
- Volume Sampler input pin is
"Volume", not "In" — add_edge(input_node, 'In', sampler_node, 'Volume'). Using 'In' silently no-ops and produces 0 points.
voxel_size is a Vector, not a float — set_editor_property('voxel_size', unreal.Vector(200, 200, 200)). Passing a float raises a TypeError.
graph property on PCGComponent is protected — use pcg_comp.set_graph(graph), never set_editor_property('graph', ...).
- After modifying a graph, always: save → reload → reassign → generate — skipping reload means the component runs the old cached version.
- Check for existing nodes before adding — always inspect
[type(n.get_settings()).__name__ for n in graph.nodes] first. Adding a node type that already exists creates duplicates that break wiring.
- Always save AND reload after every change — call
save_asset then reload_packages every time. Without the reload the PCG graph editor window won't update and users will think nothing happened.
- Use Volume Sampler for empty levels, not Surface Sampler — Surface Sampler requires geometry to sample from. An empty level has no geometry, so Surface Sampler always produces 0 points. Use
PCGVolumeSamplerSettings with unbounded=True for empty or sparse levels.
- Never spawn test actors to verify meshes or materials — do not use
spawn_actor_from_class to place test cubes. Verify by checking ISM instance counts on the PCGVolume instead: sum(c.get_instance_count() for c in volume.get_components_by_class(unreal.InstancedStaticMeshComponent)).
⚠️ Prerequisites
Both plugins must be enabled in the project's .uproject:
{ "Name": "PCG", "Enabled": true },
{ "Name": "PCGPythonInterop", "Enabled": true }
Verify they're loaded before executing:
import unreal
assert hasattr(unreal, 'PCGGraph'), "PCG plugins not enabled — check .uproject"
Creating a PCG Graph Asset
import unreal
factory = unreal.PCGGraphFactory()
asset_tools = unreal.AssetToolsHelpers.get_asset_tools()
graph = asset_tools.create_asset('MyPCGGraph', '/Game/PCG', unreal.PCGGraph, factory)
unreal.EditorAssetLibrary.save_asset('/Game/PCG/MyPCGGraph')
Loading an Existing PCG Graph
import unreal
graph = unreal.EditorAssetLibrary.load_asset('/Game/PCG/MyPCGGraph')
Or search first with the Asset Registry (or Epic's AssetTools toolset):
ar = unreal.AssetRegistryHelpers.get_asset_registry()
hits = ar.get_assets_by_class(unreal.TopLevelAssetPath("/Script/PCG", "PCGGraph"))
⚠️ PCGGraph.is_standalone_graph is deprecated (issue #465) — it logs a deprecation
warning in 5.8. Use the graph's GraphUsageContext / usage flags instead of is_standalone_graph
to tell a top-level graph from a subgraph.
Adding Nodes
Use add_node_of_type(SettingsClass) — returns a (PCGNode, PCGSettings) tuple.
All Settings classes are direct attributes of the unreal module — no find_class needed:
import unreal
node, settings = graph.add_node_of_type(unreal.PCGSurfaceSamplerSettings)
settings.set_editor_property('points_per_squared_meter', 5.0)
settings.set_editor_property('point_extents', unreal.Vector(50, 50, 50))
node.set_node_position(200, 0)
spawner_node, spawner_settings = graph.add_node_of_type(unreal.PCGStaticMeshSpawnerSettings)
spawner_node.set_node_position(500, 0)
Settings can also be read/written after creation via node.get_settings():
settings = node.get_settings()
settings.set_editor_property('unbounded', True)
print(settings.get_editor_property('points_per_squared_meter'))
Identifying Nodes
node.get_editor_property('node_title') is None by default. Identify nodes by their settings class:
for node in graph.nodes:
print(type(node.get_settings()).__name__)
Note: the nodes array does not include the graph's Input and Output nodes.
Access those via graph.get_input_node() and graph.get_output_node().
Discovering Available Node Types
import unreal
node_types = sorted([x for x in dir(unreal) if x.endswith('Settings') and 'PCG' in x])
print(node_types)
Task Index
| Task | Sub-doc | Sample script |
|---|
| Create / load a PCG graph | (above) | scripts/build_pcg_graph.txt |
| Add / identify / discover nodes | (above) | scripts/build_pcg_graph.txt |
| Connect pins / position / remove | workflows.md | scripts/build_pcg_graph.txt |
| Place a PCGVolume and generate | workflows.md → Placing a PCGVolume | — |
| Surface Sampler → Mesh Spawner | workflows.md → Full Example | — |
| Settings property names / SMS config | reference.md | — |
Sub-docs
workflows.md — pin inspection/connection, node positioning/removal, editor notify, save/delete,
placing a PCGVolume + generating, the full surface-sampler→mesh-spawner example, subgraphs.
reference.md — settings property names, lowercase struct properties, Static Mesh Spawner config,
common node settings classes.
Sample scripts (run via execute_python_code)
scripts/build_pcg_graph.txt — create a PCG graph and add Surface Sampler + Static Mesh Spawner nodes (native PCG API).