Hi all,
I’m the author of AutoLayoutPRO, a Burst-compiled, NativeArray-based layout engine for Unity. The engine is fully headless - pure float math over blittable structs, with zero Unity dependencies in the core - and the layout model is based on Subform / Morphorm (the same family of constraint-based, parent-driven layout used by Vizia in Rust). In my experience it’s easier to reason about than flexbox for the kind of UI work I do: each element’s sizing is expressed as Hug / Fill / Pixels / Percent / Aspect, with the layout type (Row / Column / Grid / Absolute) on the parent - no flex-grow × flex-shrink × flex-basis interactions, no main/cross-axis indirection.
Quick context up front: my primary focus today is uGUI - that’s where AutoLayoutPRO started and where my inspiration came from. The asset isn’t on the Asset Store yet; I’m preparing for submission soon. I’ve also posted about it on Reddit. UITK is the long-term direction I want to think through carefully, not something I’m rushing to ship. I already have a working UITK demo built on top of public APIs only - Position.Absolute + style.translate per managed VisualElement - which is enough to show that the AutoLayout output is correct on UITK trees. No reflection, no internals. So this isn’t a blocked-product post; it’s “I’ve validated on the public surface that AutoLayout-on-UITK works, and I’m trying to find out whether Unity would consider opening up the cleaner integration seam I noticed in the source.”
What I’d like to do, eventually, is make AutoLayoutPRO a first-class UITK layout option - not as a forced global replacement of Yoga, but as an opt-in engine that users apply per subtree, with Yoga continuing to handle everything else in the same panel. In my view, different parts of the same UI often have different layout needs, and giving users the option to mix engines per subtree is a flexible way to support that.
Reading through the UI Toolkit source it looks like Unity already designed for exactly this. In Modules/UIElements/Core/Layout/LayoutProcessor.cs there’s a clean swappable extension point:
namespace UnityEngine.UIElements.Layout;
interface ILayoutProcessor
{
void CalculateLayout(LayoutNode node, float parentWidth,
float parentHeight, LayoutDirection parentDirection);
}
static class LayoutProcessor
{
static ILayoutProcessor s_Processor = new LayoutProcessorNative();
public static ILayoutProcessor Processor
{
get => s_Processor;
set => s_Processor = value ?? new LayoutProcessorNative();
}
}
UIRLayoutUpdater.Update() ultimately calls visualTree.layoutNode.CalculateLayout(), which forwards to LayoutProcessor.Processor.CalculateLayout(...). That single hook is the perfect seam: implement ILayoutProcessor, assign it once, and the entire UITK pipeline (styles → layout → repaint, GeometryChangedEvent, clipping, transforms) keeps working unchanged - just with a different engine producing the layout.
And - important - the single static processor doesn’t preclude mixed trees, it enables them. A custom ILayoutProcessor can wrap the existing LayoutProcessorNative, inspect the incoming LayoutNode (e.g. via a USS marker class on the owning VisualElement - which is what my demo already uses), and per-subtree decide whether to run its own engine or delegate to Yoga. From UITK’s perspective there’s still one processor; from the user’s perspective they can mark just the containers they want and leave the rest alone. The mixed-tree behaviour is already what my current style-override UITK demo gives users in practice - they tag containers with --al-layout-type, AutoLayout owns those subtrees, the rest of the tree stays Yoga-driven. The demo just gets there the awkward way: by writing inline styles back to UITK, which forces Yoga to run a redundant pass over results that are already correct. ILayoutProcessor would let me deliver the same user-visible behaviour without the dual-engine cost.
The problem: every type involved is internal (declared without an access modifier, which in C# defaults to internal at namespace scope):
ILayoutProcessor(internal interface)LayoutProcessor(internal static class with the publicProcessorproperty)LayoutNode,LayoutComputedData,LayoutStyleDataLayoutDirection,LayoutEdge,LayoutDimension
So a third-party package can’t legitimately implement the interface or write results back. The only options today are:
- Reflection - fragile across Unity versions and not something I want to depend on in a paid asset.
InternalsVisibleTo- would require Unity to add my assembly toUnityEngine.UIElementsModule, which obviously doesn’t scale.- Style override (what I do today) - calculate positions in my engine, write them back via
ve.style.translate/style.left/top/width/height. This works, but Yoga still runs every frame and discards or recomputes those values, plusCustomStyleResolvedEventcreates a feedback loop. Lots of wasted work for a result that’s already correct.
What I’d like to ask for (in increasing scope; even just #1 unlocks the use case):
- Make
ILayoutProcessorandLayoutProcessorpublic. This alone lets external engines opt into being the layout processor. (LayoutProcessor.Processor’s setter is already public - only the enclosing type’s accessibility blocks external use.) - Expose the minimum
LayoutNodesurface needed by anILayoutProcessor:GetOwner(),Style(read),Parent/children traversal, and a way to set the computedPosition/Dimensions. Either a public read-onlyLayoutNodeview + aSetComputedLayout(...)writer method, or simply makingLayoutNodeandLayoutComputedDatapublic, would work. - A way to compose with the existing Yoga processor. This is what makes the opt-in mixed-tree model work cleanly. A public
LayoutProcessorNative- or, less invasive, aLayoutProcessor.Defaultaccessor that returns the original processor - would let a customILayoutProcessordelegate non-opted-in subtrees to Yoga without having to capture and hold the original at install time (which is fragile: the field is mutable and other packages may try to install their own).
Why I think this is worth exposing:
- Opt-in mixed-engine trees, in my view, are a flexible model - and
ILayoutProcessoris already shaped to support it, since a custom processor can wrap Yoga and dispatch per subtree. Unity wouldn’t need to add per-element opt-in machinery; that logic lives entirely in the third-party processor. - Yoga is excellent. A Burst + NativeArray-based engine offers a different point on the cost/flexibility curve, and having the option available rather than mandated seems like a healthy place for the ecosystem to be.
- A different layout model has, for me, real ergonomic value. Subform/Morphorm-style sizing (Hug / Fill / Pixels / Percent / Aspect on each element, layout type on the parent) is, in my experience, easier to reason about than flexbox for the kind of UI work I do - I’d rather say “this column hugs, that one fills, the third is 30%” than juggle
flex-grow/flex-shrink/flex-basis. UITK currently mandates flexbox; exposingILayoutProcessorwould let users who feel the same opt in to a different model on their own subtrees. - Because my engine is headless (no
VisualElement/MonoBehaviourdependency in the core), it’s already the right shape for anILayoutProcessor- adapters just translateLayoutNode.Style→UINodeinputs and write results back. The Unity-facing surface is small and well-isolated. - The hook already exists and the design looks clean from the outside. This isn’t a request to add new API surface - it’s a request to drop the
internalmodifier on a small, already-shipping abstraction. - Unity’s own architecture treats
LayoutProcessor.Processoras a swappable slot (LayoutProcessorNativeis what’s installed today). Making that slot reachable from outside the assembly seems like a small change relative to what it would unlock.
Stability concern, addressed up front: I understand the worry that exposing this locks Unity into the current shape of LayoutNode. A reasonable middle ground would be marking it [Experimental] or [Obsolete("Subject to change in 7.0")] - even an “experimental, not covered by API guarantees” surface would be enormously useful, and is already the Unity precedent (UIElements.Experimental.*). I would much rather pin to an experimental API than ship reflection in a paid asset.
Has anyone from the UITK team weighed in on this previously? Is there a planned exposure path? If a public seam isn’t possible, is there a sanctioned hook I’m missing - for example a way to suppress Yoga on a subtree without setting position: absolute on every element?
Happy to share the working UITK demo, the integration code, profiles, or the full review I did against the UITK source if any of it would be useful for the discussion. To be clear about where I am: the uGUI adapter is the main product and that’s where my day-to-day focus is (preparing for Asset Store submission); the UITK demo runs on public API only (Position.Absolute + style.translate) and shows the layout output is correct, but it leaves Yoga running a redundant pass on every frame; this post is the long-term ask. I’d rather plan the UITK direction around a sanctioned ILayoutProcessor hook than ship anything that depends on reflection or internals.
Thanks for reading.