Skip to content

Layout

Write a GameObject’s size with size and pivot, and arrange children with <Row> and <Grid>. size and pivot aren’t written to the prefab; they’re used only for arrangement calculations and inspect’s counts.

Assets/Example/Office.mochi.xml
<Office prefab="true">
<Object name="Desk" size="1.2 0.7 0.6" pivot="0.5 0 0.5"/>
<Object name="Chair" size="0.5 0.9 0.5" pivot="0.5 0 0.5" position="0 0 -0.6"/>
</Office>
sizeWidth, height, and depth (meters, 0 or more). A length in the GameObject’s own coordinates; its own and its ancestors’ scale are applied.
pivotWrites where the origin sits inside the size box, as a 0-1 fraction on each axis (the same idea as Unity’s RectTransform.pivot). 0.5 0 0.5 is the center of the bottom face.
Omitting pivotBecomes the center of the box.
pivot without sizeAn error. Excludes <Row>, <Grid>, and places where a part with a size is used.
SyntaxNumberExample
pivot on an <Object> without sizeMOCHI1008pivot-without-size

The spacing, align, and columns attributes are in <Row> and <Grid>.

Assets/Example/Shelf.mochi.xml
<Shelf prefab="true">
<Row name="Books" spacing="0.05" align="bottom">
<Object name="A" size="0.1 0.3 0.2"/>
<Object name="B" size="0.1 0.25 0.2"/>
</Row>
</Shelf>
Assets/Example/Tiles.mochi.xml
<Tiles prefab="true">
<Grid name="Board" columns="2" spacing="0.5 0.25" position="0 1.5 0">
<Object name="A" size="1 1 0.1"/>
<Object name="B" size="1 1 0.1"/>
<Object name="C" size="1 0.5 0.1"/>
</Grid>
</Tiles>
Arrangement direction<Row> arranges children left to right in the +X direction. <Grid> fills each row left to right, and rows proceed top to bottom (-Y direction).
Children that are arrangedIncludes direct host and part children, as well as what <For> and <If> expand to, and the contents of <Slot>.
Conditions on childrenEvery child needs size, except a <Prefab> without size and a part without size as below. Children can’t have position.
A <Prefab> without sizeArranged by the box around the meshes of the active objects with an enabled Renderer inside the prefab (or model) (built-in, .asset and model meshes, and SkinnedMeshRenderer bounds). A rotated <Prefab> rotates the box of each mesh first and then wraps them once (the same as Unity’s Renderer.bounds). Colliders, inactive objects, disabled Renderers, TextMeshPro and particles take no room. The active of the instance’s root itself is not looked at.
A <Prefab> that can’t be measuredOne with a mesh from a model Unity has not read yet is MOCHI2018 (save the file in Unity once, or write size). One with no visible mesh, one with a mesh whose bounds can’t be read, and one with a pivot need size (MOCHI1008). A prefab that shows only text (TextMeshPro) also needs size (the box of the letters is known only after Unity lays out the text).
A part without sizeIf the body of the part (apart from <Props>) is a single <Prefab> without size, the part is arranged by the box measured from that <Prefab>. The position, rotation and scale of the <Prefab> inside the part apply. A part whose body is one such part is followed down the same way. Any other part (two or more roots, an <Object> root, a mesh on the part itself, and so on) needs size (MOCHI1008).
Size of <Row> and <Grid>The size of the box that contains the arranged children. size can’t be written.
Columns and rows of <Grid>Column width is the maximum among that column’s children, and row height is the maximum among that row’s children. Children are centered within their column.
Rotated or scaled childrenTurns the box of size and scale, and lays it out by the axis-aligned box around it. A <Prefab> without rotation or scale takes the rotation and scale of the prefab’s root
Front-back positionPlaces every child’s origin at the same Z.
Origin of <Row> and <Grid>The position obtained by applying its own pivot (center by default) to the arranged box.
Assets/Gallery/Strip.mochi.xml
<Strip prefab="true">
<Row name="Frames" spacing="0.5" position="0 1.5 0">
<For each="art" in="folder('art/')">
<Object key="{art.key}" name="{art.title}" size="1 1 0.05"/>
</For>
<Object name="Caption" size="0.6 0.3 0.05"/>
</Row>
</Strip>
SyntaxNumberExample
A <Row> child with position writtenMOCHI1005row-child-position
A <Row> child that is an <Object> without sizeMOCHI1008row-child-without-size
A <Row> with size writtenMOCHI1005row-with-size
A <Grid> without columnsMOCHI1008grid-without-columns

If you don’t write size where a part is used, the size of the part’s root GameObject becomes the size at the usage site.

Assets/Example/Shelf.mochi.xml
<Shelf prefab="true">
<Row name="Books" spacing="0.02" align="bottom">
<Book name="A"/>
<Book name="B"/>
<Book name="C" size="0.08 0.25 0.2"/>
</Row>
</Shelf>
<!-- file: Assets/Example/Book.mochi.xml -->
<Book>
<Object name="Cover" size="0.05 0.3 0.2" pivot="0.5 0 0.5"/>
</Book>
ConditionThe part’s body (excluding <Props>) is a single host that either writes size, or is a <Row> or <Grid>.
size at the usage siteIf written, that value is used instead.
pivot at the usage siteShifts the part’s root by (the root’s pivot - the usage site’s pivot) × size.
A part whose root has position or scalePasses its size (the root’s size × scale) to the usage site only when pivot is written there. The root moves so that pivot places that box (the root’s position is ignored). Without pivot, the size is not passed
A part whose root has rotationThe size is not passed to where the part is used. Writing pivot there is an error, because it is not supported yet. A <Prefab> whose prefab root is rotated counts as a rotated root too
A part whose body is one <Prefab> without sizeHas no size. Only inside a <Row> or <Grid> is it arranged by the box measured from that <Prefab>.
SyntaxNumberExample
pivot written on the usage of a part whose root has rotationMOCHI9001part-pivot-moved-root

inspect counts overlaps between GameObjects whose size is known (those with a size written, <Row> and <Grid>, and placed parts whose root has a size), and overflows from the nearest ancestor that has a size (see inspect for how it’s counted). GameObjects whose size is not known aren’t counted, so even with zero overlaps, that’s not evidence of no collisions.