Lattice reference · 1 of 4
Source files and declarations
This chapter defines the common syntax available to both Linear story and CYOA projects. It covers the project expansion model and every declaration that establishes story identity and narrative context.
The shape of a document
A .la file contains zero or more top-level items. The complete top-level vocabulary is:
use "./relative-file.la";
story main (...);
entity character ch_mara (...);
predicate knows (...);
state group location (...);
state st_knows_signal (...): event { ... };
pool investigation (...);
module md_decode (...) { ... }
scene garden (...) { ... }predicate, state, pool, and module belong to CYOA. A Linear project may only use imports, one Story, entities, top-level Scenes, and the Blocks and content nested inside those Scenes.
Files and imports
The project configuration names one entry file, normally main.la. TypeApe starts there and expands every use recursively.
# main.la
use "./story/entities.la";
use "./story/opening.la";
story main (
title: "Signal Garden",
language: "en",
format: novel,
entry: opening
);An import path:
- is a quoted path relative to the file containing
use; - must resolve to a file inside the open project;
- cannot escape with
..or an outward-pointing symbolic link; - cannot form an import cycle;
- cannot load the same file twice, even through different relative paths.
Imported declarations appear before declarations in their importer. This does not create Block flow, but it does make declaration order deterministic and controls the presentation order of eligible CYOA Modules.
After expansion, the whole project must contain exactly one story declaration. Imported files should contribute entities, Scenes, State, or Modules rather than declaring another Story.
Comments, commas, and semicolons
Only # starts a line comment. // is ordinary invalid syntax.
# This is a Lattice comment.
entity item it_key (name: "Signal key"); # trailing comment| Construct | Closing syntax |
|---|---|
use, story, entity, predicate, state, state group, pool | ; |
scene or module with a body | closing } without ; |
text, dialogue, foreshadowing, reveals | ; |
next, end, enter, complete, each option | ; |
the enclosing choice { ... } | closing } without ; |
Metadata properties and event fields are comma-separated. A trailing comma is not part of the documented syntax, so omit it after the last property.
Identifiers, strings, and prose
Lattice deliberately distinguishes identity, exact text, and narrative prose.
| Form | Example | Use |
|---|---|---|
| Identifier | opening, ch_mara, resolution | Declaration IDs, references, enum-like values |
| String | "en", "before dawn" | Exact text where a quoted string is required |
| Prose | { A light wakes. } | Narrative content or text metadata |
| Number | 3, 1.5 | Event or extension literal where accepted |
| Boolean | true, false | Event or extension literal where accepted |
| List | [opening, resolution] | Ordered metadata values, including an empty [] |
Identity is not a title
In this declaration, ch_mara is the stable identity and "Mara" is display text:
entity character ch_mara (name: "Mara");Change name when the reader-facing name changes. Change ch_mara only when the entity's identity changes, then update every reference and validate globally. Never quote an ID reference:
# Correct
pov: ch_mara
# Wrong: this is a string, not a character reference
pov: "ch_mara"Prose braces are syntax
Prose begins with { and ends with }. Newlines and ordinary punctuation inside are retained.
logline: {
A patient signal hunter discovers that tomorrow
has been answering from beneath her garden.
}Use prose for narrative paragraphs and text metadata. Use a quoted string for fields such as language whose type requires one.
Metadata
Metadata follows a declaration ID in parentheses:
scene opening_scene (
title: "Opening",
beat: opening,
pov: ch_mara
) {
# Blocks
}Each key may appear at most once on one declaration. Fields are owner-specific and type-checked: a valid Scene field may still be invalid on a Story or Block.
An unknown key is an error unless it starts with x_:
scene opening_scene (
title: "Opening",
x_editor_color: "blue"
) { ... }x_ metadata is preserved but semantically inert. It cannot create flow, change Preview, mutate State, bypass a diagnostic, or affect export unless a named product capability explicitly defines that extension.
Story declaration
Exactly one Story exists after imports are expanded.
story main (
title: "Signal Garden",
language: "en",
format: novel,
entry: opening,
logline: { A buried signal calls its hunter home. },
audience: "Young adult",
content_rating: "Teen",
genres: [mystery, science_fiction],
themes: [memory, belonging],
tags: [draft],
prose_unit: word_like,
prose_scope: authored_body,
prose_minimum: 4500,
prose_target: 5000,
prose_maximum: 5500,
beat_order: [opening, midpoint, resolution]
);| Field | Required | Accepted value | Meaning |
|---|---|---|---|
title | yes | string or prose | Reader-facing story title |
language | yes | quoted BCP 47 string | Language of authored story content |
format | yes | novel or screenplay | Presentation/export format |
entry | yes | Block ID | Main-story Block where reading begins |
logline, audience, content_rating | no | text | Descriptive metadata |
genres, themes, tags | no | text or list | Classification metadata |
prose_unit | with goal | counting-unit identifier | word_like or non_whitespace_graphemes |
prose_scope | with goal | authored_body | Reader-visible authored body content |
prose_target | with goal | positive integer | Intended total prose length |
prose_minimum, prose_maximum | no | positive integer | Optional delivery bounds |
beat_order | no | list of identifiers | Expected global order for Scene beats |
initial_state | CYOA only | list of State IDs | Active State at runtime start |
The entry must exist in the main story. A Block owned by a Module cannot be the Story entry. Linear story must not declare initial_state, including an empty list.
prose_unit, prose_scope, and prose_target form one optional goal and must be declared together. If present, the bounds must satisfy minimum <= target <= maximum. word_like counts word-like tokens; use non_whitespace_graphemes for requests expressed as Chinese 字数. Only TypeApe-owned fields affect the authoring contract; x_* metadata remains inert.
Entity declarations
The declaration shape is entity <kind> <id> (...).
entity character ch_mara (
name: "Mara",
role: protagonist,
description: { A patient signal hunter. },
aliases: ["Mara Venn", "The Listener"],
traits: [observant, stubborn],
tags: [cast, point_of_view]
);
entity location loc_garden (
name: "Signal Garden",
description: { A buried antenna field beneath wet soil. },
tags: [exterior]
);
entity item it_key (
name: "Signal key",
description: { A warm shard that pulses at midnight. }
);Supported kinds are character, location, and item. Every entity requires name text.
| Kind | Optional fields |
|---|---|
character | role identifier; description text; aliases, traits, tags as text or lists |
location | description text; tags as text or a list |
item | description text; tags as text or a list |
References are kind-checked. A Dialogue speaker and Scene pov must be characters; Scene location must be a location. CYOA Predicate tuples also verify that each entity matches the declared field kind.
Scene declarations
A Scene groups Blocks under shared narrative context.
scene garden (
title: "The garden",
summary: { Mara hears the buried signal. },
beat: opening,
pov: ch_mara,
location: loc_garden,
time: "before dawn",
tone: [quiet, uneasy],
prose_target: 1200,
tags: [chapter_one]
) {
block opening (...) { ... }
}| Field | Required | Accepted value |
|---|---|---|
title | yes | text |
summary, time | no | text |
beat, pov, location | no | identifier/reference |
tone, tags | no | text or list |
prose_target | no | positive integer |
A top-level Scene belongs to the main story. A Scene nested inside a Module belongs exclusively to that Module. Every Block inherits its Scene's owner, and flow targets cannot cross from main story into a Module, between Modules, or from a Module back to main story.
A Scene prose_target is a reallocatable drafting budget, not a standalone validity threshold. It requires a complete Story prose goal.
A safe multi-file layout
project/
├── main.la
└── story/
├── entities.la
├── opening.la
└── ending.la# main.la
use "./story/entities.la";
use "./story/opening.la";
use "./story/ending.la";
story main (
title: "Signal Garden",
language: "en",
format: novel,
entry: opening
);Imports organize declarations; they never imply narrative order. The next chapter defines Blocks, content, annotations, and Linear flow.
