This page defines the grammar of attribute values in EBNF, using the same notation as the XML 1.0 specification. Which attribute is read with which rule is in Rules per attribute at the end.
The diagnostic number reported when the rule isn’t met. For props written on a part tag and for <Prop default>, any value that doesn’t fit the type gives MOCHI3006
By the XML rules, line breaks and tabs in an attribute value are replaced with spaces (#x20) before the value is read. Write a line break as (text="First line Second line")
Character references
", &, and so on are read after XML turns them back into characters
Escaped ::= ( "{{" Char* ) - ( "{{" Char* "}}" Char* ) /* becomes the text with the first "{" removed */ [MOCHI5002]
Binding ::= "{" S* Reference S* "}" [MOCHI5002]
Plain ::= [^{]* /* contains no "{" */ [MOCHI5002]
Char ::= /* any one character */
S ::= /* whitespace */
Plain
Read as a value of the attribute’s type (a number, a Vector3, a path, and so on)
Binding
Reads the value of a prop or a <For> row and converts it to the attribute’s type (Binding)
Escaped
The form for text that starts with {. Only the first { is removed and nothing else is changed. "{{draft}" is the text {draft}, and "{{score} pts}" is {score} pts}
A value that starts with {{ and has }} after it
"{{score}}" and "{{score}} pts" are MOCHI5002 (that }} would stay as it is and give {score}} pts). Write "{{score}" for {score} and "{{score} pts" for {score} pts. A text that starts with { and contains }} cannot be written this way
/* "!": the opposite of a bool value (also a value that changes at runtime) */
Reference ::= Name ( "." Name )? [MOCHI5002]
/* one Name: a prop (in a part with a T# script, also a C# member) */
/* Name "." Name: a <For> row and one of its columns */
/* Name "(" arguments ")": a function call (only in a part with a T# script) */
Where it can appear
The entire value. It can’t appear partway through text, as in name="Room {n}" or position="0 {y} 0"
Names that can be read
Only the props of the same file and the <For> rows of the same file (Name scope). In a part with a T# script, other names are read as C# members of that part (Value that changes at runtime)
Whitespace inside { and }
Skipped. { title } is the same as {title}
Just a row name
Writing just a row name, as in {art}, is an error. Write the column too ({art.title})
A name or column that isn’t found
MOCHI5001.
Inside a default
A binding can’t be written
Function calls
{IsCurrent(art.index)} calls a C# method of a part with a T# script (Value that changes at runtime). In a part without a T# script it is MOCHI5002, and MOCHI8001 where T# is not available
Negation
{!featured} is the opposite of a bool value. A value that isn’t a bool gives MOCHI5002; a value that changes at runtime and isn’t a bool gives MOCHI3006
Int ::= Number /* a number whose fractional part is 0; "2.0" is 2 */ [MOCHI1009]
Decimal numbers
1.5, -2, +1, .5, and 2. can be written
Unsupported forms
Exponent notation (1e3), digit separators (1,000), leading or trailing whitespace, NaN, and Infinity. Only a component’s float attributes take Infinity and -Infinity
int values
A number whose fractional part is 0. 2.0 is read as 2
Digits written to the prefab
Rounded. position and the RectTransform values are written to 4 decimal places, and scale, rotation and component values to 6
Path ::= PathChar+ /* can't start with "/" */ [MOCHI2001]
PathChar ::= [^\:] /* anything but "\" and ":" */ [MOCHI2001]
A path starting with Assets/ or Packages/
A path from the project root. It’s case-sensitive, so assets/ is treated as a relative path
Any other path
A path relative to the folder of the file it is written in. A path written in a column of a table (the file column, and any other column used as a path) is relative to the table file
A path passed to a part
Resolved from the caller’s file
A path in a prop’s default
Resolved from the part’s file
., .., and empty segments
. and // are skipped, and .. is the parent folder
Outside the project
A path that points outside Assets/ and Packages/ can’t be written (MOCHI2001)
Names starting with builtin:
Not paths. They contain :, so writing one where a path goes gives MOCHI2001
Checking what it points to
A missing file gives MOCHI2002, a missing .meta gives MOCHI2009, and the wrong kind of asset gives MOCHI2008
In this example, the part Picture is in Assets/Parts/; the passed image path resolves from Assets/Gallery/Wall.mochi.xml, and the default image path resolves from Assets/Parts/Picture.mochi.xml.
.csv or .json (the extension is case-insensitive). Any other extension gives MOCHI2007
CSV
The first line is the header. Wrapping in " lets a cell contain , and line breaks, and "" is a single ". Whitespace around a cell stays in the value. All values are string
JSON
A flat array of objects. Values are text, numbers, or true/false. Numbers may also use exponent notation (1e3)
A row’s key
If there’s an id column, its value; otherwise, the text in the file column. A table with an id column must fill in id on every row. In JSON, if any row has an id, every row needs one
The file column
Resolved from the table’s file, and its existence is checked. Read through a binding, it’s a path from the project root
Reserved column names
key and index can’t be column names. Give a row’s key with an id column
There are 5 words, and each maps to one Unity static flag. The flags are set only on the GameObject they are written on, not on the GameObjects under it (write them on each one to set them there too).
ObjectName ::= [^/]+ /* the name of a GameObject inside the prefab */
FillPattern ::= ( [^{/*] | "*" )+ /* "*" matches any sequence of characters, including none */ [MOCHI1009]
PrefabPath
Written in <At path> and <Slot path>. Names from the prefab’s root, separated by /; an empty string is the root. At each step, the name must match exactly one GameObject. The inside of a prefab nested in the prefab can’t be addressed
FillPattern
Written in <Prefab fill>. Compared with the whole GameObject name
String. A number or bool read through a binding becomes its text
Vector3
Vector3
Color
Color
Texture
Path. An image, a Texture2D saved as an .asset, or a .renderTexture
Material
Path。.mat
GameObject
Path. A prefab or a model
Object
A path to a GameObject in the same prefab (table below)
Asset checks
For Texture, Material, and GameObject, the file and its .meta must exist (a missing .meta gives MOCHI2009). The kind of asset Unity imported is also checked (a mismatch gives MOCHI2008)
A value that doesn’t fit the type
MOCHI3006.
Object values
The path written where the part is used is counted from there: a relative path from the GameObject of the element that uses the part, a path starting with / from the root of that file
Where an Object can be written
Inside the part, as the whole value of an attribute that points to an object in the same prefab or of a public variable of an attached <UdonBehaviour> that holds an object, and as the path of a UnityEvent item (onClick="{target}:Open"). It can also be passed as is to another part’s Object prop. Anywhere else it is MOCHI3006
Object errors
No object at the path (MOCHI2015) or no component of the attribute’s type (MOCHI2016) is reported where the path is written