The .prisma ASCII format
The ASCII encoding
.prisma is the human-authorable encoding of a Document: a USDA-flavoured ASCII format that is diff-clean and stable, the form you write by hand and commit to git. It is one of Core's two native encodings, alongside the .prism binary. They carry the same Document and convert losslessly either way.
Every file begins with a version header, then nests Elements with braces:
#prisma 4.0
def group "world" {
def object "ball" {
float3 position = (0, 1, 0)
float radius = 1.5
float3 albedo = (1, 1, 1)
connect albedo = </world/mat.out>
}
}
The grammar, briefly
- Header:
#prisma <version>(the current format is4.0; older majors still parse). - Element:
def <type> "<name>" { … }. The type token is a plain string; quote it if it is not a bare identifier. The name is quoted, so it may contain digits and punctuation, which is what lets the JSON codec use indexed names like"0","1". - Property:
<dtype> <name> = <value>. Scalars are bare (1.5,true,"hi"); vectors are parenthesised ((0, 1, 0)); arrays are bracketed ([0.1, 0.2]); multi-dimensional shapes carry their dtype-and-shape so the text is self-describing. - Time samples: a brace block of
time: valuekeyframes in place of a single value. - Connection:
connect <target> = <source>. The consumer (target) on the left reads from the source on the right. The target is a bare slot name (relative to the enclosing element) or a<path.slot>(absolute, and may carry a*glob, so one source drives every match); the source is always an absolute<path.slot>. The directive works inside an element or at the document top level.
Stable and diff-clean
The serializer sorts deterministically, so two saves of the same Document produce byte-identical files and a real change produces a small, readable diff. That is a deliberate property: .prisma is meant to live in version control, be reviewed in a pull request, and merge sanely. Values are self-describing (the dtype and shape travel with the data), so a .prisma file carries everything a reader needs, with no external schema.
Parsing, with located errors
deserialize accepts an optional ParseError* that is filled with a file-absolute line:column and a message on failure, the same diagnosis the CLI's check surfaces:
ParseError err;
auto doc = deserialize(text, &err);
if (!doc) fprintf(stderr, "%zu:%zu: %s\n", err.line, err.column, err.message.c_str());
$ kinogaki check broken.prisma
broken.prisma:4:18: error: invalid value for its declared type
Encoding is detected by content, so the parser reads a file by its leading bytes whatever its suffix. When you want compactness or large numeric arrays in place of readability, reach for the binary format.