Grammar
The whole shape of a construct: sigils, the head, the three brackets, and when a line is prose.
#Prose and constructs
A Chalk document is plain text. Prose is prose — a line of writing compiles to a paragraph without ceremony — and everything that is not prose is a construct: a node, a micronode, or a directive. A node is recognised only by an opening bracket, so a line beginning Note: this is important stays prose forever, even though note is an element — nothing opens a bracket. Micronodes and directives carry their own sigil, so they stand bare: !value:#fit.slope and :overview.part.chalk are both constructs on their own.
scene{
# Falling objects
Galileo's insight was that mass does not matter.
}[
canvas.graph#drop{
curve#h(expression: 100 - 4.9x^2)
}(
x-axis-label: t
y-axis-label: height
)
]That is a whole valid document: one scene whose body holds the narrative, and whose detail declares a graph pane with a single curve. Every page of this manual is about some part of that shape.
#The head
Before its brackets, every construct is written the same way:
name[#id][:value]#id assigns an identifier — universal, available on every node, micronode and directive. :value supplies the construct's implicit attribute: a positional shorthand for whichever attribute the element declares first. Both are optional and independent, and the order is fixed: # before :.
curve#flight #flight names this curve
image:photo.jpg :photo.jpg fills source, the first attribute image declaresThat is the whole of it — an id and one attribute. Everything else is an ordinary attribute written in the group, and the shorthand form and the explicit form mean exactly the same thing:
image#hero:photo.jpg(width: 400)
image#hero(source: photo.jpg; width: 400)The : value is a simple token: it starts immediately after the colon and ends at the first bracket, whitespace, or end of line. Anything more complex — spaces, brackets, a list — is written as a named attribute instead. And because the name, id and value are read in that fixed order, a # inside the value is just a character, which is what lets !value:#logged.slope parse as a reference.
#The three brackets
{ }— the body[ ]— the detail, which for a scene is its canvas( )— the attribute group
What is legal inside the body and the detail is the element's containment policy — every reference page prints its policy under "Allowed content", and the reverse ("Allowed in") says where the element may be written. Body & detail covers the policies in full.
() is not a special form — it is an attribute group with nothing in it. A bare node head like image:photo.jpg is prose until a bracket follows; image:photo.jpg() is the node. Micronodes don't need the crutch — their sigil already marks them.#Attributes
Attributes live in a parenthesised group, separated by semicolons: point(x: 1; y: 2; colour: orange), or one per line when the group is written across several. The group comes last, after the body and detail. The control-flow directives are the exception — (audience: teacher){…} and (n: 0..4){…} put theirs first.
The implicit attribute is not a special mechanism — it is the first attribute in the element's schema, and both spellings are equivalent: image:photo.jpg is image(source: photo.jpg). Every value in Chalk is a string until an attribute's declared type parses it; the type reference lists what each type accepts.
#Sigils
.— namespace and member access:canvas.graph,#islands.area#— assigns or refers to an identifier:curve#flight,path: #flight:— supplies the implicit attribute:image:photo.jpg!— a micronode:!teal{…},!value:#f.slope@— a directive:(…),#islands*— the document header, at the top of the file{{ }}— compile-time substitution:{{z-expected}}
The cheatsheet puts all of it on one page.