Skip to content

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:

text
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.

text
# 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.

text
# This is a Lattice comment.
entity item it_key (name: "Signal key"); # trailing comment
ConstructClosing syntax
use, story, entity, predicate, state, state group, pool;
scene or module with a bodyclosing } 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.

FormExampleUse
Identifieropening, ch_mara, resolutionDeclaration 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
Number3, 1.5Event or extension literal where accepted
Booleantrue, falseEvent 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:

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:

text
# 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.

text
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:

text
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_:

text
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.

text
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]
);
FieldRequiredAccepted valueMeaning
titleyesstring or proseReader-facing story title
languageyesquoted BCP 47 stringLanguage of authored story content
formatyesnovel or screenplayPresentation/export format
entryyesBlock IDMain-story Block where reading begins
logline, audience, content_ratingnotextDescriptive metadata
genres, themes, tagsnotext or listClassification metadata
prose_unitwith goalcounting-unit identifierword_like or non_whitespace_graphemes
prose_scopewith goalauthored_bodyReader-visible authored body content
prose_targetwith goalpositive integerIntended total prose length
prose_minimum, prose_maximumnopositive integerOptional delivery bounds
beat_ordernolist of identifiersExpected global order for Scene beats
initial_stateCYOA onlylist of State IDsActive 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> (...).

text
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.

KindOptional fields
characterrole identifier; description text; aliases, traits, tags as text or lists
locationdescription text; tags as text or a list
itemdescription 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.

text
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 (...) { ... }
}
FieldRequiredAccepted value
titleyestext
summary, timenotext
beat, pov, locationnoidentifier/reference
tone, tagsnotext or list
prose_targetnopositive 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

text
project/
├── main.la
└── story/
    ├── entities.la
    ├── opening.la
    └── ending.la
text
# 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.