Introduction
What a Chalk document is made of: nodes, micronodes, heads, attributes, bodies and sigils.
#How a document is put together
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: an element, a directive, or an inline micronode. 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 are constructs on their own: !value:#fit.slope and :overview.part.chalk both stand bare.
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
)
]The example above 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.
#Nodes and micronodes
Constructs come in three kinds. Block elements (nodes) occupy lines of their own — scenes, headings, tables, graph panes, marks. Inline elements (micronodes) live inside prose and are written with the ! sigil — !teal{like this}, !value:#fit.slope(). Directives are written with the @ sigil and speak to the compiler rather than the reader — (...) declares constants, #islands:file.csv a dataset, :3{...} a repetition.
#The head
Every construct head follows one grammar:
name[#id][:implicit]#id assigns an identifier — universal, available on every node, micronode and directive. :value supplies the construct's implicit attribute — a positional shorthand for its first declared attribute. Both are optional and independent, and the order is fixed: # before :.
curve#flight id: flight
image:photo.jpg source: photo.jpg
@preset#apple:text(size: 24) id: apple, node: text, size: 24An implicit value is a simple token: it starts immediately after the : and ends at the first bracket, whitespace, or end of line. Anything more complex — spaces, brackets, a list — is written as an ordinary named attribute instead. And because heads read name#id:implicit in that order, a # inside an implicit value is just a character — which is what lets !value:#logged.slope() parse as a reference.
#Attributes
Attributes live in a parenthesised group, separated by semicolons: point(x: 1; y: 2; colour: orange). 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.
() 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.#Body and detail
A construct may carry a { } body and a [ ] detail. What is legal inside each is the element's containment policy — every reference page lists its element's policy under "Allowed content", and the reverse ("Allowed in") tells you where an element may be written. For a scene the split is the document's central seam: the body is the narrative column, the detail is the board.
#Sigils, complete
.— namespace and member access:canvas.graph,#islands.area,#fit.slope.#— assigns or refers to an identifier:curve#flight,path: #flight. One namespace, document-wide, forwards and backwards.:— supplies the implicit attribute::card,image:photo.jpg.{{ }}— compile-time substitution:{{z-expected}},{{#survey.area}}.!name— a micronode in prose:!teal{...},!value:#ref().@name— a directive:(...),:overview.part.chalk.
. deliberately covers both namespace access (reach into the canvas family for the graph type) and member access (reach into the islands dataset for the area column) — the same operation over different containers.