Chapter 2

The graph: entities, edges, tags

Underneath everything, a TropeLang story is a graph: a set of nodes (the things in the story), edges (how they relate), and tags (what each thing is like). It is a temporal graph — facts are stamped into beats and scenes, and the store is append-mostly, so the engine can always look back at what was true earlier. The point of the model is that once a story is a graph, "find the tropes" becomes "find the shapes," which a machine can do.

Entities are nodes

A node is declared with a keyword and a name. There are five kinds: char (a character or actor), set (a place or time), obj (an object), evt (an event — something that happens), and arc (a thread or the story itself, which is both a container and a node you can tag). That's the whole vocabulary of kinds; everything more specific is expressed with tags.

char vale [+Protagonist] [+Grifter]
char renn [+Antagonist] [+Collector]
char dossey [+Ally]
obj ledger
vale -- renn : "the appraisal"
vale > ledger
dossey -- vale : "old partners"

Composition over inheritance

In vale [+Grifter], the tag is a component the node carries, alongside [+Protagonist] — there is no Grifter class that vale is an instance of. Tags stack freely: a character can be a grifter, a mentor, and grieving at once, with no class hierarchy to manage. Specialization comes from adding tags, never from subclassing. (Tags do form an ontology among themselves — one tag can imply others — but that is a relationship between tags, covered in Chapter 3.)

Edges are relationships

An edge connects two nodes, optionally annotated with a quoted phrase. The operator says what kind of tie it is:

Most are directed. Prefixing with ! severs a tie — vale !-- renn breaks the association, the moment a friendship ends or trust dies. Because the store never truly deletes, that severance is itself a recorded fact: the engine knows there was a bond, and that it broke.

Time is built in

Facts live inside nested temporal containers — beat (a single action), scene (a run of beats), act, and arc. Order matters: a setup in beat 1 and its payoff in beat 2 are different moments, and recognition can reason about that gap — "the hero never did disarm the bomb."

This is why a .trl file has two distinct phases: the declarations up top (the cast and props you just met) and the temporal event log below (the scenes and beats, in reading order). Everything the timeline names already exists above it — a convention worth its own page in the style guide.

scene the_appraisal {
  beat 1 {
    char vale [+Grifter]
    char renn [+Mark]
    vale -- renn : "introductions"
  }
  beat 2 {
    evt the_switch [&Deceives(agent=vale, target=renn)]
  }
}

Every name here — Protagonist, Grifter, Collector, Deceives — comes from a shared vocabulary the engine understands. How that vocabulary works, and how one tag can pull in a dozen others, is next.