Builtin Library
README.md
entity_hierarchy
Hierarchy helpers built on top of the entity bounds API. Implements
issue #876 (entity hierarchy swap) on top of issue #874 (entity bounds
API). Pure Luau — uses entity(id).hierarchyBounds(), entity.spawn,
and the transform primitives. Used to replace blockout geometry with a
generated/imported asset, fitting the asset to the source's bounds and
inheriting transform + (optionally) name.
Exports
M.swap(entityId: string, assetPath: string, opts: SwapOpts?) -> (string?, string?)— replaceentityIdwithassetPath. On success returns(newEntityId, nil); on failure(nil, errmsg).
Types:
SwapOpts = { fit?: string, source_origin?: string, asset_origin?: string, keep?: { string }, timeout?: number }
Options:
fit—"bounds"(default, uniform scale to fit inside the source's AABB),"bounds_xy"(uniform XZ, identity Y),"none"(no scaling).source_origin/asset_origin—"bottom"(default),"center","top". XZ always anchors on centre; only Y is picked.keep— list of attributes to preserve onto the new entity. Currently only"name"is honoured.timeout— seconds to wait for the asset's bounds to become queryable (default 5).
Usage
local EntityHierarchy = require("@builtin::modules.entity_hierarchy")
local newId, err = EntityHierarchy.swap(
"blockout_tree",
"@builtin::meshes.cube",
{
fit = "bounds",
source_origin = "center",
asset_origin = "bottom",
keep = { "name" },
}
)
Notes
- The replacement is spawned far below the scene (Y = -1000000) before bounds become queryable, then moved to the final anchored position once the asset loader populates its bounds. Avoids a one-frame visual pop at the origin.
awaitBoundspollsentity(id).hierarchyBounds()at 20 Hz viaawait(delay(0.05))—task.wait(0)cooperative yields don't always give the asset-load systems enough slack to make progress.- When the source has no geometry,
fitis force-set to"none"(there's nothing to measure against) and the new entity is anchored on the source'slocalPosition. - The source entity is despawned at the end of
swap— caller must not referenceentityIdafterward. keeponly supports"name"today; preserving component instances would require re-attaching every script-component and is out of scope.