Out of Time
Core-to-Unreal automation pipeline and large-scale mob rendering for a multiplayer rogue-lite
Manticore Games
2026
Product Developer / Senior Technical Artist
Context
A multiplayer rogue-lite where artists iterate quickly in the Core editor while an offline pipeline I built converts static environments into native Unreal levels, and VAT rendering supports 200+ on-screen mobs to hit the Steam Deck performance target.
My Contribution
Led the design and implementation of the Core-to-UE conversion pipeline, the World Partition and Data Layer map structure, Jenkins build automation, and the VAT system for distant mobs.
Impact / Outcome
Artists kept Core's fast iteration while the runtime gained native UE performance. The pipeline became the performance foundation of Out of Time: ~50% fewer actors, ~90% fewer mob draw calls, and 200+ on-screen mobs at 30 FPS on Steam Deck.
Outcome Summary
Out of Time: Core-to-UE Pipeline and Large-Scale Mob Rendering
TL;DR: The Core editor is fast to iterate in, but large scenes carry a heavy runtime cost. I led the development of an offline Core-to-UE conversion pipeline that turns static environments into native Unreal open-world levels and became the performance foundation of Out of Time. I also designed and implemented a VAT system for distant mobs. The game now runs 200+ animated mobs on screen at 30 FPS on Steam Deck.
Table of Contents
- At a Glance
- The Problem
- Constraints
- Optimization 1: Map Structure
- Optimization 2: Core-to-UE Conversion Pipeline
- Optimization 3: VAT for Distant Mobs
- My Contribution
- Retrospective: What I Would Do Differently
At a Glance
| Project period | 2023 - 2026 |
| My role | Owner of the Core-to-UE pipeline; designed and implemented the open-world map structure and the VAT system |
| Platforms | PC, Steam Deck |
| Key numbers | Actors −~50% · Mob draw calls −~90% · 30 FPS with 200+ on-screen mobs on Steam Deck · 140+ mob types converted to VAT · 500+ automated builds · −80+ material instructions |
The Problem
Out of Time is a multiplayer rogue-lite built on Core, centered on large era-themed wilderness maps, repeatable combat encounters, and high enemy counts.
The Core editor is designed for live editing: every mesh needs a Core-level wrapper actor, and materials and VFX stay fully editable at runtime. That makes iteration very fast, but it comes with a runtime cost. At 2k×2k map sizes with hundreds of enemies on screen, this dynamic representation could not keep up. Large maps stuttered noticeably in Core, especially in areas with heavy use of dynamic assets such as spline meshes.
This created a conflict:
- Artists needed to keep iterating quickly in Core and see their changes immediately.
- The runtime needed native, static, optimized UE assets.
Constraints
- Don't change how artists work: environment artists keep building maps in the Core editor, and the pipeline stays invisible to them.
- Maps are constantly iterated: the conversion must be repeatable and automated, not a one-time manual migration.
- Not everything can be converted: gameplay systems rely on Core's built-in features, so only non-interactive environment assets are candidates for static conversion.
- Steam Deck is a target platform.
- Two source control systems: Git on the Core side, Perforce on the UE side.
Optimization 1: Map Structure
Each wilderness map is 2k×2k, with one map per era and four zones per map.
Why one large map per era: all four zones share the same era, so keeping them in one map makes visual consistency easier. Shared assets only need to exist once, each zone simply hides content that should not be visible, and the artist workflow stays simpler.
Alternative considered: one map per zone. Shared assets would have to be duplicated across zones, vistas could not be shared, and every environment change would have to be repeated across multiple maps. That would make consistency harder, add work, and make any change to player routes expensive.
The structure:
- World Partition is the base loading strategy. Zone content is distributed across separate Data Layers, so each zone loads only what it needs.
- A shared "always-on" Data Layer holds vista objects visible from all four zones.
- Recognizable structures such as buildings, castles, and bridges are packed as Packed Level Actors or Level Instances.
- Sparse props are split into separate Level Instances by the World Partition cell grid.
- Layered HLODs handle distant objects beyond the player's immediate view.
Optimization 2: Core-to-UE Conversion Pipeline
How It Works
In a Core map, each group of assets to be converted sits under a custom node called a CUE node. The pipeline processes everything under each CUE node and converts it into native UE level assets, including static meshes, spline meshes, decals, VFX, sound effects, and lights. Each asset type has its own conversion rules. The core mechanism: capture the state of every asset during a UE Play-In-Editor (PIE) session, then write it out to a native level.
Why capture in PIE instead of parsing Core map data directly: the final state of a Core object is only fully determined at runtime (script-generated content, parameterized materials, and so on), so offline parsing struggles to produce consistent results. In PIE, all of an asset's current data is directly available, and it can be saved straight into new native UE assets, which makes rebuilding straightforward.
Iteration Workflow
In Core, environment changes are visible immediately after republishing. In UE, every change requires a full build cycle. So whenever an environment artist updates a zone, the conversion has to be re-run for that era. To reduce run time, I added change detection so the pipeline only processes what changed, which greatly shortened iteration time.
The whole process runs automatically as a Jenkins job. Each map has its own job that can be queued independently. The pipeline pulls updates from Git, identifies the changed CUE nodes, runs an incremental conversion, and submits the updated UE assets to Perforce automatically. It can also run HLOD builds automatically.
- Run time: from about 20 minutes for an incremental run to about 4 hours for a full run, plus HLOD build time
- Successful runs: 500+
- Failure handling: Slack notification with a log link and the name of the failing CUE node. I documented common errors so they can be diagnosed quickly, and I investigate the rare edge cases directly.
Automated Optimization Passes
Every rebuild applies the following passes:
| Optimization | Approach | Result |
|---|---|---|
| Remove wrapper actors from all environment assets | Capture a data table of the native UE assets each wrapper references, then rebuild using the original assets | ~50% fewer actors |
| Mesh instancing | Automatically instance static meshes that share the same asset, across Packed Level Actors | Large draw-call reduction |
| Actor merging | Merge actors made of many small parts into a single mesh, then instance it | Large draw-call reduction |
| Spline mesh merging | Merge Core's editable spline meshes into static meshes | Affected areas went from noticeable stutter to 40+ FPS |
| Material simplification | Save dynamic materials as deduplicated static material instances, reduce instruction counts, use more static switches, and strip logic branches only needed in the Core editor | 80+ fewer instructions on average for eligible materials |
| Blueprint data baking (selective) | Bake runtime data into blueprints to remove dynamic logic where possible | Lower CPU cost |
Optimization 3: VAT for Distant Mobs
Rendering many animated skeletal meshes at once is expensive. Beyond a certain threshold, we switch mobs to Vertex Animated Textures (VATs): each mob's attack and run cycles are baked into a texture, and a vertex shader on a static mesh reproduces the skeletal animation.
Key Design Decisions
- When to switch: driven by UE's Significance Manager, which scores each mob by distance and screen size and switches it to VAT below a threshold. On Steam Deck, where the CPU is the bottleneck and the loss of close-range animation fidelity is barely noticeable to players, all mobs use VAT.
- Avoiding popping: the switch happens within a single frame, with animation phase aligned.
- Baked animations: attack and run.
- Animation textures: 8K, storing bone position, rotation, and weight. All instances of the same mob type share one texture.
- Baking workflow: UE's built-in Animation to Texture plugin, run either as a batch over all mobs or on a single mob. Each bake takes about 10 seconds.
In total, 140+ mob types were processed. Every non-boss mob went through the VAT pipeline.
Results
- Replacing skeletal meshes with VAT meshes reduced draw calls by ~90%. Because of the high mob counts, we also applied instancing, collision adjustments, and lighting setup to the VAT meshes, reaching the Steam Deck target of 30 FPS.
- 200+ animated mobs can stay on screen at once.
My Contribution
Owned end to end:
- Open-world map setup and comparison, plus HLOD setup and testing
- Overall design and implementation of the Core-to-UE pipeline
- Design and implementation of the conversion logic for every asset type in the pipeline
- Primary maintenance of the pipeline and its tools
- Implementation of the VAT system and processing of all mob assets
Led, in collaboration with others:
- Defined the CUE node specification with engineers and artists
- Worked with engineers on Jenkins integration, including editor launch and map loading in the automated flow
- Defined mesh-merging rules and scope with artists
- Ran A/B tests on selected features with engineers
Supported work led by others:
- Engineers implemented automatic static mesh instancing across Packed Level Actors; I provided test validation and pipeline integration
Retrospective: What I Would Do Differently
- Define per-zone performance budgets earlier (draw calls, triangles, memory), instead of hunting for problems during the optimization phase.
- Build a reproducible benchmark for every optimization: we tested the most uncertain optimizations on target hardware using fixed camera paths, but not all of them, which is why a few rows in the table above can only say "large reduction." Next time, I would measure frame time and draw calls for each optimization individually, both to quantify its benefit and to see which ones give the best return on effort.
- Push for upstream improvements: the conversion pipeline essentially works around Core's runtime overhead downstream. Having built it, I would push for native "mark as static and bake" support in Core, so this kind of optimization becomes a platform capability that other Core games can benefit from too.
- Catch errors on the Core side: today, a failed conversion only surfaces as a Slack notification after the Jenkins job finishes. A pre-flight check in the Core editor, flagging unsupported asset types and non-convertible materials under CUE nodes, would let artists catch problems before submitting and save a wait that can run to several hours.
Related Projects

Core Platform / Core Games
Manticore Games · 2020
Multiverse game engine and platform for user-generated games
Impact
Improved internal content creation workflows, supported shipped live experiences and marketplace content, and created tools that remained useful to production teams over multiple years.

UE Art Pipeline Tools
Manticore Games · 2020
Asset import, validation, and automation tooling on the Unreal side
Impact
Gave 20+ artists a UE-side tool layer they use daily, with import and setup collapsed into one click. 98 data-driven validation rules catch asset problems before they reach a build, bringing daily build errors from asset issues down to near zero.

DCC Tools / Pipeline
Manticore Games · 2020
Digital content creation tools and pipeline integrations
Impact
Standardized artist-facing DCC workflows, reduced manual export/setup work, and made pipeline tools easier for technical artists to maintain and extend.





