# Tórculo specification

> The normative text of the Tórculo standard: the pliego language, the portable project, pieces, canon, plates, materials and takes.

URL: https://torculo.joseluissaorin.com/en/spec · Reviewed: 2026-10-15 · Español: https://torculo.joseluissaorin.com/especificacion.md

- **Status:** Working Draft, 2026-10-15. Stable enough to implement; changes go through the
  RFC process (`spec/rfcs/`). The conformance suite in `conformance/` is part of this
  specification.
- **Editor:** José Luis Saorín Ferrer.
- **This version:** `spec/SPEC.md` in <https://github.com/joseluissaorin/torculo> (private
  until the specification, the conformance suite and the reference implementations pass).
- **Spanish translation:** [`SPEC.es.md`](SPEC.es.md) (faithful; in case of conflict the
  English text prevails).
- **License:** this specification is published under
  [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/). Code in the repository is
  MIT OR Apache-2.0. Contributors commit not to assert patents against implementations.

## Abstract

Tórculo is an open standard for making films, explainers, animated shorts and moving
illustrations from a text that reads like the film. That text is a **pliego**, a `.mesa`
file written in the **language of Tórculo**: a line-oriented, Spanish-language script with
closed vocabularies, in which the author says *what happens and how* ("the stone rolls to
the edge, heavy") and the engine derives every number (positions, curves, durations,
colours, loudness). The standard has seven parts: the pliego language, the portable
project (`.mesapack`) with its voice sidecar, pieces (drawings, puppets, characters and
collage), the house **canon** (palette and deterministic randomness, with test vectors in
three languages), **láminas** (hand drawings revealed by a time atlas), **materias** (the
WGSL pass convention for paper, watercolour, risograph and transitions) and **takes** (the
recorded output of the engine, a fork of ManimGX, with its public API). Every part is
deterministic: the same inputs give the same film.

## Status of this document

This is the first public version of the standard. Its language part absorbs and
reorganizes `SPEC-MESA-2.md` of manim-saorín (the working document of the reference
implementation, epoch 2 of the language); the other parts formalize documents that already
existed (`pluma/LAMINA.md`, `materias/README.md`, `FORK.md`, `SPEC-PIEZAS.md`). Where this
text and a conformance case disagree, the disagreement is a bug to be resolved through the
RFC process; until it is, implementations follow the conformance case. Known deviations of
the reference implementation from this text are listed in Appendix D and marked as pending
cases in the suite.

## Contents

- [Preface](#preface)
- [1. Conventions and terminology](#terminology)
- [2. Architecture and conformance](#architecture)
- Part 1. The pliego language
  - [3. Principles](#principles)
  - [4. Lexical structure](#lexical)
  - [5. Grammar](#grammar)
  - [6. Closed vocabularies](#vocabularies)
  - [7. Semantics](#semantics)
  - [8. Profiles](#profiles)
  - [9. Extension by layers](#extension)
  - [10. The intermediate representation](#ir)
  - [11. Invariants](#invariants)
  - [12. Diagnostics](#diagnostics)
  - [13. Tools and fingerprints](#tools)
- Part 2. [14. The portable project](#mesapack)
- Part 3. [15. Pieces](#pieces)
- Part 4. [16. The canon](#canon)
- Part 5. [17. Láminas](#laminas)
- Part 6. [18. Materias: the pass convention](#materias)
- Part 7. [19. Takes and the public API](#takes)
- [20. Security considerations](#security)
- [21. Privacy considerations](#privacy)
- [22. Versioning and compatibility](#versioning)
- [23. Media types and file identification](#media-types)
- [24. Internationalization](#i18n)
- [Appendix A. Closed vocabularies](#appendix-a)
- [Appendix B. Grammar](#appendix-b)
- [Appendix C. Diagnostic codes](#appendix-c)
- [Appendix D. Known deviations of the reference implementation](#appendix-d)
- [Appendix E. References](#appendix-e)
- [Appendix F. Profiles in development (informative)](#appendix-f)

## Preface {#preface}

A *tórculo* is the engraver's press. The plate is worked once and printed as many times as
needed. In this standard the plate is a pliego, a drawing or a materia, and the prints are
a video, a web page, an app or a game. The *mesa* is the work table where the pliego (the
sheet that goes through the press) is laid out: that is why pliegos keep the extension
`.mesa`.

The language was born inside manim-saorín, a collage-in-motion library on top of Manim,
for video essays with the look of a notebook: paper, ink that boils, cut-outs with tape,
risograph drums. Its first epoch (`SPEC-MESA.md`) grew as a changelog; the second
(`SPEC-MESA-2.md`, 2026-08) made it formal; the short film *Radiointermisión* (2026-10)
taught it posters, cameras, sound and a picture that listens. In parallel, Scholaris gave
the house its hand-drawing pen and its cream paper, and a fork of ManimGX (a Rust and wgpu
engine with the Python API of Manim) became the common engine: a film written in a pliego
that took about three and three quarter hours to render with Cairo renders in under eight
minutes on it. Tórculo is the name of that whole: the language, the formats around it, and
the engine they print with.

The language is Spanish by design. Its keywords are Spanish words read as Spanish
(`la piedra rueda hasta el borde · pesado`), diacritics distinguish words where Spanish
needs them (`él` is a character, `el` an article), and the engine's derivations encode a
craft (Lasseter's principles of animation, continuity editing, the print shop) rather
than parameters. This specification is written in English so that anyone can implement
it; every keyword is quoted as written in a pliego.

## 1. Conventions and terminology {#terminology}

The key words MUST, MUST NOT, REQUIRED, SHALL, SHALL NOT, SHOULD, SHOULD NOT, RECOMMENDED,
MAY and OPTIONAL are to be interpreted as described in BCP 14 (RFC 2119 and RFC 8174) when,
and only when, they appear in capitals.

### 1.1 Terms

| Term | Meaning |
|---|---|
| **pliego** | A `.mesa` file: a script in the language of Tórculo. |
| **servilleta** | A pliego without any chapter head (`==`): plain prose (§5.12). |
| **chapter** (*capítulo*) | A unit of page and of rendering, opened by `==`. Chapters MAY be rendered in parallel. |
| **scene** (*escena*) | A unit of world inside a chapter, opened by `--`; the world persists between its shots. |
| **clip** or **beat** | A unit of time (a shot), opened by `*`. |
| **line** | A unit of action inside a clip. |
| **piece** (*pieza*) | Anything placed on the table: a card, a label, a drawing, a puppet, a photograph, a sign. |
| **bestiary** (*bestiario*) | The project's catalogue of named pieces (`PYTHON`, `PIEZAS`). |
| **compiler** | A program that parses a pliego, checks it (§12) and produces its IR (§10). |
| **interpreter** | A program that turns an IR into frames and sound. The reference has two: `ce` (Manim Community Edition, Cairo) and `gx` (Tórculo's engine). |
| **IR** | The intermediate representation (*guion rico*), JSON (§10). |
| **sidecar** | `<pliego>.tiempos.json`: the voice's durations and word timings, and where its recordings are (§14.3). |
| **take** (*toma*) | A recording of an engine run as a stream of messages (`.take`, §19). |
| **lámina** | A hand drawing with a time atlas, ready to be revealed by any engine (§17). |
| **materia** | A compute pass over a plane (paper, watercolour, risograph…), in the convention of §18. |
| **canon** | The house's single source of truth: palette, randomness, craft numbers, foley weights (§16). |
| **epoch** (*época*) | The version of the language a pliego is written in (§22). |

### 1.2 Notation

Grammar productions use the EBNF of Appendix B (`spec/gramatica/mesa.ebnf`): names in
capitals are nonterminals, `"literal"` is literal text, `[ ]` optional, `{ }` zero or more,
`|` alternative, `TEXT` the rest of the line, `NL` a line end, `QUOTE` a text between Latin
quotation marks. A nonterminal in capitals that the grammar does not define is a **closed
vocabulary** (§6, Appendix A); that correspondence is exhaustive.

In this document keywords are written with their accents, as they are read; comparison is
by normalized form (§4.5).

### 1.3 Canonical JSON

Wherever this specification hashes or compares JSON, it uses the JSON Canonicalization
Scheme of RFC 8785 (JCS): object keys sorted by UTF-16 code units, no whitespace, numbers in
the shortest form that round-trips in ECMAScript notation (`1.0` is `1`, `1e-7` is
`1e-7`), strings in raw UTF-8 escaping only `"`, `\` and U+0000 to U+001F. The reference
implementation is `conformance/tools/jcs.py`.

## 2. Architecture and conformance {#architecture}

### 2.1 The seven parts

| Part | Normative object | Version in Tórculo 1.0 |
|---|---|---|
| 1. Pliego language | the `.mesa` file, its compilation and its interpretation | epoch 2 |
| 2. Portable project | the `.mesapack` package and the voice sidecar | `mesapack 1` |
| 3. Pieces | the piece contract (levels, card, parts, puppets, characters) | 1 |
| 4. Canon | palette, randomness, craft and foley numbers | canon 1 |
| 5. Láminas | the `.lamina` format | 1 |
| 6. Materias | the WGSL pass convention | 1 |
| 7. Takes and API | the `.take` stream of the fork and the engine's public interfaces | `0x8000_0002` |

Each part can be implemented on its own. A product claims conformance to a part and, where
the part defines classes or profiles, to those classes and profiles.

### 2.2 Product classes

| Class | Part | Passes the suite's kinds |
|---|---|---|
| **Compiler** | 1 | `vocabulario`, `lee`, `ir` (normative projection, §10.6), `cierre`, `espejo` |
| **Interpreter**, per profile | 1 | `huella` and `banda` for the pliegos of its profiles (§8) |
| **Packager** | 2 | `mesapack_referencia`; its packages pass `mesapack` |
| **Package reader** | 2 | `mesapack` |
| **Piece provider** | 3 | the piece checks of §15.6 |
| **Canon implementation** | 4 | `canon_azar` and `canon_paleta` for its language |
| **Lámina producer** | 5 | `lamina` (byte-identical output) |
| **Lámina reader** | 5 | reveals every lámina of the suite as §17.5 says |
| **Pass host** | 6 | runs every conforming materia; `materia` for the checker |
| **Take writer / reader** | 7 | `toma` |

### 2.3 Conformance in general

A conforming product:

1. MUST accept everything this specification declares valid for its class, and reject what
   it declares invalid, with the diagnostic codes of Appendix C where a code is defined;
2. MUST NOT extend a closed vocabulary silently (§6.1);
3. MUST be deterministic in the sense of §7.4 and §16.3;
4. MUST pass every non-pending case of its class in the conformance suite of the same
   version (`conformance/manifest.json`);
5. SHOULD report its results in the report format of `conformance/README.md`.

A compiler is not required to render: checking a pliego and producing its IR are
conforming without any graphics engine.

---

# Part 1. The pliego language

## 3. Principles {#principles}

These principles are normative: they decide every question this text does not settle,
and an RFC that breaks one of them MUST say so and why.

1. **The anti-parameter constitution.** The pliego says human counts and manners; the
   engine sets the numbers. A pliego has no easing, keyframes, Bézier handles, rate
   functions, hexadecimal colours, per-piece shadows or loose durations in the plain
   dialect (§3.1). No new capability enters the language if it forces pliegos to say
   numbers that were previously derived.
2. **Closed vocabularies.** The constitution only holds because every vocabulary is closed,
   and closed vocabularies are only bearable because the engine derives. A word outside
   its list is an error, never a silent extension.
3. **Closure.** Writing out what the engine decided does not change the film (§11.1).
4. **Identity is the seed.** Everything random is seeded from the identity of what it
   affects, computed from content, never from position, process, clock or file system
   (§7.4).
5. **What does not fit on the sheet is not read.** Text that cannot be read in the time it
   is on screen is a defect (§12, the Lasseter review).
6. **Distance rules.** The speed, colour and depth of every layer derive from its distance
   (*lejanía*) and from nothing else, with one declared exception (§7.7).
7. **The three seats.** A capability that is not in the grammar, the compiler and the
   interpreter does not exist. A directive known to the vocabulary but not to the parser
   would be printed on screen as narration, which is the worst failure of the system; hence
   every nonterminal has its table (§6) and every event declares whether it is alive or
   reserved (§6.3).
8. **The law of authority.** Documentation is enumerated from the parser, not from memory.
   The vocabularies of Appendix A are extracted from the reference parser
   (`spec/vocabularios/extrae.py`) and the suite checks that they match (`vocabulario`).

### 3.1 The two dialects

| Dialect | Who writes it | Numbers |
|---|---|---|
| **plain** (*pobre*) | a person | none |
| **revealed** (*revelado*) | `mesa escribe`, transpilers, replica mode | yes, each decision marked `(máquina)` |

The **plain share** of a pliego is the fraction of its dramaturgy lines without figures. An
author's pliego SHOULD keep it at 85 % or more; a compiler MUST compute it and SHOULD warn
below 85 % (`W112`). Exempt from the count, each for its reason: section blocks (they
calibrate a craft, where numbers are legitimate), the body of a `ver:` (the data a
visualization draws), chapter titles, comments and the format line. Names of sound cues
and effects (for example `1M1`) are names, not figures, and SHOULD NOT count (see
Appendix D).

## 4. Lexical structure {#lexical}

### 4.1 Encoding and lines

A pliego is UTF-8 without a byte order mark. Compilers MUST normalize it to NFC before
analysis. Lines end in LF or CRLF. Analysis is line oriented: each line is classified by
its prefix, and **the prefix always wins**. Only section blocks (§5.3) and `dentro:`
(§5.10) span several lines. Blank lines separate clips. Leading indentation is not
significant except inside section blocks and `dentro:`.

### 4.2 Comments, digressions and commissions

| Form | Meaning | In the IR |
|---|---|---|
| `// text` | technical comment | no |
| `( text )` on its own line | author's digression | yes, `digresiones` |
| `~ deriva: text` | a commission to the engine | yes, `derivas` |

### 4.3 The field separator

The middle dot `·` (U+00B7), with optional spaces around it, is the only field separator
inside a line.

### 4.4 Quotation

Text that goes on screen, and names that refer to text, are written between Latin
quotation marks `«…»` (U+00AB, U+00BB). Straight quotation marks are not equivalent and
MUST NOT be accepted in their place. A line that consists only of a quotation is a
**shout** (*grito*); a clip has at most one (`E030`).

### 4.5 Identifiers and normalization

An identifier is a sequence of letters (including accented letters and `ñ`), digits and
`_`. Section keys MAY contain spaces.

Keywords and vocabulary words are compared after this normalization:

1. lower case;
2. runs of spaces collapsed to one;
3. `_` is equivalent to a space (`toca_la_truca` is `toca la truca`);
4. combining diacritics removed (NFD, drop U+0300 to U+036F): the canonical form has no
   accents, and both forms are accepted (`ilustración` is `ilustracion`).

**Exception:** reserved words (§6.4) are compared **as written, without normalization**,
because in Spanish the diacritic distinguishes words: `el` is a reserved article and `él`
is a valid character name; likewise `tu`/`tú`, `si`/`sí`, `mas`/`más`.

Piece and drawing identifiers (`id`, bestiary names) SHOULD be ASCII: they are seeds
(§16.3), and an accent changes the seed.

### 4.6 Numbers

`NUMBER` is an integer or a decimal with a point, with an optional sign. Where the
language accepts a decimal comma it says so (`2,39:1`).

### 4.7 The `(máquina)` mark

A trailing `(máquina)` declares that the engine, not a person, took that decision. It
affects provenance fields of the IR (`autor_cabecera`, `origen`) and nothing else; in
particular it does not affect the master hash (§7.4).

### 4.8 The dash

The em dash `—` (U+2014) separates a head from its body in `MOTIVO`, `PERSONAJE`, `ver:`
and `juntos:`. Compilers MUST accept it with or without spaces on either side. The
canonical style, the one used in this document and in the suite, attaches it to the body,
as Spanish punctuation does with an opening dash: `MOTIVO «error» —empieza como enemigo`,
`ver: votos —sí: 7 · no: 4`, `juntos: a · b · c —en fila`. In dialogue, the dash that opens
a speech is part of the text (`él: —¿Falta mucho?`).

## 5. Grammar {#grammar}

The complete grammar is Appendix B. This section states the structure and the rules that
the productions alone do not express.

### 5.1 The document

```ebnf
PLIEGO   = PREAMBLE { CHAPTER } [ END ] ;
CHAPTER  = CHAPTER-HEAD { UNIT-LINE | SECTION | COMMENT } { SCENE | CLIP } ;
SCENE    = SCENE-HEAD { UNIT-LINE | SECTION | COMMENT } { CLIP } ;
CLIP     = CLIP-HEAD { CLIP-LINE } ;
```

The same set of **unit lines** is valid in the preamble, a chapter and a scene; sections
are valid at the three levels. Inside a clip, lines are classified by prefix, the prefix
always wins, and their order is kept.

### 5.2 The preamble

`MESA [v N] TITLE` opens a pliego and MAY declare the epoch (`MESA v2 «El puerto»`). A
pliego that declares an epoch newer than the compiler's MUST be rejected (`E001`).

`formato` declares properties: an aspect ratio (`16:9`, `4:3`, `2,39:1`), `sala crema` or
`sala pizarra`, `tirada borrador` or `tirada definitiva`, `página desnuda` (no folio, no
stamp, only paper) and `en dos` (everything drawn animated on twos).

`REPARTO NAME: drum[, voice][, voice colour][, side][, alias: A · B]` declares a speaker.
**The cast is normative for dialogue**: a speaker that is not declared in `REPARTO` or
`PERSONAJE` is not a speaker (§5.5). The voice colour is `con radio` or `seca` (`E016`
otherwise); the side is `a la izquierda`, `a la derecha` or `al centro`.

The preamble also carries the project's resources: `PYTHON` (or `PIEZAS`, Part 3) for the
bestiary, `EFECTOS` and `BANDA` for sound folders, `MEZCLA` for the mix, `PARTITURA`,
`SOPORTE`, `LETRA`, `ARCHIVO`, `FANTASMA`, `RELOJES` and `SONIDO`. Paths are relative to
the pliego's folder; in a portable project they MUST be (§14).

In epoch 2 the preamble line `MUSICA path` (song mode: the song leads the edit) and the
unit line `MÚSICA cue` (a cue of `BANDA`) share a keyword. A compiler MUST treat `MÚSICA`
followed by a name that exists in `BANDA` as a cue and any other `MÚSICA` line of the
preamble as a song, regardless of accents (RFC 0004; Appendix D).

### 5.3 Sections and the mirror law

```ebnf
SECTION = "#" NOMBRE-SECCION [ IDENT ] NL { SECTION-LINE } "#FIN" | NOMBRE-SECCION PATH ;
```

A section block written inside the pliego is **identical in grammar** to the file imported
in its place. Invariant (§11.2):

```text
effective(p) == effective(parte(p)) == effective(funde(parte(p)))
```

Keys of several words take a colon (`por defecto: tijera`) so that they survive the round
trip. Precedence, single and without exceptions, by partial inheritance (one line
overrides one line):

```text
imported  <  inline in the preamble  <  chapter block  <  scene block
```

`TALLER` and `MANO` are normative (Appendix A: `FAMILIA_TALLER`, `CLAVE_MANO`); the
section `BESTIARIO` is equivalent to the preamble line `PYTHON`, and the section `REPARTO`
to the preamble lines `REPARTO`;
`MONTAJE` and `CASCADA` are reserved (§6.3).

### 5.4 Chapters and scenes

`== TITLE · attributes ====` opens a chapter. Attributes: `tensión` (a `TENSION`), `nº`,
`tambor`, `gigante`, `plano fijo` (a `PLANTILLA`, not a shot size), `tramo a → b`,
`nocturno`, `diurno`.

`-- TITLE [· HORA] --` opens a scene. Core unit lines:

- `EJE de A a B`: the 180-degree rule. From it derive each one's side, the direction of
  looks and where someone who left by one side enters again.
- `LUZ direction · hardness [· rasante]`: **one per scene**; it governs all shadows. No
  piece declares its own shadow.
- `MUNDO movement [N] · direction`: the world clock (§7.7).
- `FONDO key · distance` and `DELANTE key [· distance] [· cada N]`: multi-plane
  background and the proscenium; speed, colour and depth derive from the distance.
- `ESCENARIO`, `TABLAS` (the paper theatre as a still set; the hour tints, it does not
  dim; whoever has feet stands on the floor), `ARCHIVO`, `REPITE «scene»` (the same clips
  with the same identities: the same video).

Unit lines in the preamble apply to the whole pliego; in a chapter or a scene, to it. The
scene prevails over the chapter and the chapter over the preamble.

### 5.5 Clips

```ebnf
CLIP-HEAD = "*" [ BEAT-ID ] ( FUNCION | SHOT ) [ "·" AFECTO ] [ "(máquina)" ] ;
SHOT      = { TALLA | ALTURA | FRENTE | MODO } [ "de" [ ARTICLE ] IDENT ] ;
```

Two languages, both legitimate: a dramaturgical **function** (`* prueba · seco`), from
which the composition template derives (§6.5), or a **shot** (`* corto contrapicado de
tercero · nervioso`), which declares a shot size. They are two axes (§6.5). The article of
the subject is dropped (`general de la carretera` has subject `carretera`). An optional
beat id (`* r01_02 primer de LOCUTOR · …`) gives the clip a stable identifier, the one the
sidecar uses.

Content lines: `di: TEXT` is the narration and **the score of the beat**: its delivery
gives the beat's duration. `SPEAKER: TEXT` is dialogue; the speaker MUST be declared and
MUST NOT be a reserved word (`E021`); directives are resolved first, so a speaker named
like a directive cannot capture it. `SPEAKER / SPEAKER: …` is a sentence split between two
voices. `letrero (register): TEXT` is a sign (`REGISTRO_LETRERO`; unknown: `E014`;
reserved: `W111`). `terminal:`, `canta:` and plain prose complete the content lines.

### 5.6 Pieces and placement

`pon: TYPE «text» · attributes` places a piece of a `TIPO-PIEZA`; `foto:`, `recorte:`,
`prensada:` place archive material; `ver: KEY —body` a visualization of the `CLAVE_VIS`
catalogue, whose body is data; `pica:`; `python: NAME args` a bestiary piece (Part 3);
`arriba:`, `pie:`, `nota:`; `marca: GESTURE «text»` (`GESTO_MARCA`).

**The law of the body:** almost nothing goes in coordinates. Placement is relational:
`en los pies de primero:`, `bajo «X» a 0.42:`, `junto a`, `delante de`, `detrás de`,
`juntos: a · b · c —disposition`, `en el mundo:`, `en el documento:`, and the prefixes of
the profiles (`en MATERIA:`, `de «A» a «B»:`, `a la izquierda:`, a distance, `en
silueta:`). Prefixes chain, and chain with `al decir «…»:`. The size of a drawing follows a
`·` (`grande`, `enorme`, `gigante`, `a sangre`).

`clip: path [de mm:ss a mm:ss]` places real video, a live cut-out whose sound joins the mix
at its exact time. **A clip lasts what it says it lasts**: a beat MUST NOT close while one
of its clips is still running; the beat grows instead (`W123` says by how much). `> espera
al clip` gives the clip the whole turn: the narration sounds first, then a breath, then
the clip, and the subtitle band withdraws while it runs. **Reality is not developed**: a
real-video clip never goes through the darkroom (no halftone, duotone or scissor die).

### 5.7 Movement

```ebnf
MOVEMENT = [ PLACEMENT ] [ ARTICLE ] SUBJECT VERB [ DESTINATION ]
           { "·" ( [ "por" ] TRAYECTO | MANERA | GRANULADO | REGISTRO-MOV | RASTRO ) } [ WINDOW ] ;
```

**A movement is recognized by its verb** (`VERBO_MOV`, `VERBO_RELACIONAL`), never by its
suffixes. Otherwise `la piedra rueda hasta el borde`, with no suffix, would fall to prose
and be printed as narration (§3, principle 7). After a `·` in a movement line only a path,
manner, grain, register, trail or window is valid; anything else is an error (`E012`).
Relational verbs create a live binding that dies with its target; a cycle of bindings,
a chain of more than three links, or nesting deeper than three levels is an error
(`E032`).

**The law of movement:** the curve is never declared; it is derived from the material,
the hand, the affect and the manner (§7.6).

**Life verbs.** A character or a puppet also turns, sits and looks, in plain words:
`X se gira`, `X se da la vuelta`, `X se vuelve hacia la cámara`, `X se pone de frente |
de perfil`, `X se vuelve de espaldas`; `X se sienta | se levanta | se inclina | se yergue |
se asoma a la barandilla | se apoya en la barandilla`; `X asiente | niega | se encoge de
hombros | se rasca la cabeza`; `X se acerca` (walks towards the camera and grows on its
feet), `X se aleja`; `X mira a «Y»` (head and eyes towards another piece until the next
beat); `X se queda quieto` (only breathes). All of them can be anchored (`al decir «gol»:
X se asoma a la barandilla`). Without quotes, `A mira a B` is **both** the look acted by
the piece and the eyeline of cinema (§5.8, `W103`); a compiler MUST keep both meanings.

### 5.8 Camera, cinema and journey

`la truca ORDER [IDENT] [en SIZE]` moves the rostrum (`ORDEN_TRUCA`); `A mira a B` (also
to someone off frame); `A sale|entra por la SIDE`; `sonido: adelanta|retiene|dentro|fuera`
(J and L cuts); `fuera de campo: TEXT`; `el foco en X`, `el foco pasa a X`, `todo en foco`
(focus is ink density, edge sharpness and shadow, never blur); `X está STATE` (a state for
continuity). The journey: `X viaja`, `X se apea`, `el mundo MOVEMENT`, `por la
ventanilla: … desfilan`.

### 5.9 Events

```ebnf
EVENT = ">" EVENT-NAME [ ARG ] { "·" ">" EVENT-NAME [ ARG ] } ;
```

Event names are a closed vocabulary with state (§6.3). An event written in a clip acts at
its place in the author's order and can be anchored to the voice (`al decir «GOL»: >
temblor`). A transition written in a clip says how the clip **enters**; `funde a negro`
and `funde a blanco` say how it **leaves**. Four events are also copied to a field of the
clip because another pass reads them (`EVENTO_A_CAMPO`): `salta` and `cruza el eje` (the
escapes of the continuity warnings), `congela` and `continúa`.

### 5.10 Nesting and concurrency

`dentro:` opens sub-clips (at most three levels); `mientras:` opens a parallel track;
`al decir «w»: LINE` anchors a line to the moment the voice says `w`; `LINE hasta decir
«w»` stretches it until then. Anchors are written **as written**, not as they sound; a
compiler with the sidecar matches figures with their reading (`1154` and «mil ciento
cincuenta y cuatro») and approximate transcriptions by edit distance, and warns of anchors
that never match (`W120`) or that match the voice but not the text (`W122`).

### 5.11 The end

`== FIN ===` closes the film; the lines after it are its colophon; `> silencio N` its final
silence (without it the compiler applies 3 seconds and warns, `W113`).

### 5.12 The servilleta

A pliego without any `==` is prose: every sentence is a clip and the dramaturge (fixed
rules, no machine learning) decides the rest. It is the entry point and MUST always work:
every compiler and every interpreter of the core profile MUST accept a servilleta,
including one with a preamble that declares its sound (`BANDA`, `MÚSICA`, `AMBIENTE`).

## 6. Closed vocabularies {#vocabularies}

### 6.1 The law

**If a word is not in its list, it is an error, not a silent extension.** Every
nonterminal of the grammar that the grammar does not define is a closed vocabulary listed
in Appendix A, with the structure of the reference parser it is extracted from and the
profile it belongs to. Appendix A is generated (`spec/vocabularios/vocabularios.json`); a
compiler MUST accept exactly those words for the epoch it implements, compared after
normalization (§4.5), and MUST reject any other word in a closed position with the code
of that position (Appendix C).

The vocabularies of an epoch are **frozen**: a later version of a compiler MUST NOT reject
a word the epoch declared, including reserved words (§6.3). New words enter only through
an RFC and are available to pliegos that declare the epoch that introduced them.

**A compiler accepts the whole language.** Profiles (§8) say what an interpreter
*realizes*; they never restrict what a compiler accepts. A compiler MUST NOT reject a word
of any profile because a particular interpreter does not realize it.

### 6.2 Overview

Appendix A lists 98 vocabularies (1015 words in total in this version). The most used:

| Vocabulary | Words | Notes |
|---|---|---|
| `AFECTO` | 8 | contenido, eufórico, exhausto, juguetón, nervioso, seco, sereno, solemne |
| `FUNCION` | 11 | apertura, cartel, contrapunto, digresión, eco, giro, ilustración, prueba, remate, respiro, tesis |
| `TENSION` | 4 | sube, mantiene, cae, rompe |
| `ARCO` | 6 | espiral, letanía, pregunta→respuesta, ruina, tesis→antítesis→síntesis, viaje y vuelta |
| `TALLA` | 7, **ordered** | general, conjunto, medio, americano, corto, primer, detalle |
| `ALTURA`, `FRENTE`, `MODO` | 5, 5, 3 | the other axes of a shot |
| `PLANTILLA` | 8 | documento, primerísimo, general, mapa, contraplano, orla, nocturno, cartel |
| `VERBO_MOV` | 24 | baja, cae, camina, corre, cruza, entra, esquiva, flota, gira… |
| `VERBO_RELACIONAL` | 11 | agarra, alcanza, arrastra, cuelga, empuja, esquiva, huye, orbita, se apoya, sigue, suelta |
| `TRAYECTO`, `MANERA`, `GRANULADO` | 16, 15, 4 | paths, manners and grains of a movement |
| `EVENTO` | 163 | events of every profile, each with its state (§6.3) |
| `LEJANIA` | 8, **ordered** | al pie, al paso, cerca, a media distancia, lejos, al fondo, en el horizonte, en el cielo |
| `CLAVE_VIS` | 68 | the catalogue of `ver:` |
| `TAMBOR` | 7 | ámbar, bermellón, naranja, rosa, ultramar, verde, violeta |
| `PALABRA_RESERVADA` | 76 | §6.4 |

Ordered vocabularies (`TALLA`, `LEJANIA`, `DISTANCIA`, `CADENCIA`, `INTENSIDAD`,
`SOPORTE`) carry meaning in their order: the distance between two shot sizes is their
number of steps, an intensity is a level from 0 to 10.

### 6.3 State: alive and reserved

Every event, and every section name, declares a state:

- **alive** (*vivo*): the compiler or the interpreter consumes it;
- **reserved** (*reservado*): the language accepts it and the interpreter does nothing yet.
  It is frozen vocabulary: writing it today does not break tomorrow. A compiler MUST accept
  it and SHOULD warn (`W110`).

In this version every event is alive. The sections `MONTAJE` and `CASCADA` and the sign
registers `máquina`, `dymo` and `tira` (`REGISTRO_LETRERO_RESERVADO`) are reserved.

### 6.4 Reserved words

`PALABRA_RESERVADA` lists the words that open a line in the parser plus articles and
prepositions. They MUST NOT be the name of a speaker or an identifier (`E021`), and they
are compared without normalization (§4.5): `él` is not `el`.

### 6.5 Templates and shot sizes are two axes

A **shot size** (`TALLA`) says how much of the frame the subject occupies. A **template**
(`PLANTILLA`) says where the pieces fall on the sheet. They share one word, `general`, and
`primerísimo` is not `primer`. Consequences:

1. `PLANO_DE` maps functions to templates, not to sizes:

   | Function | Template |
   |---|---|
   | apertura | orla |
   | remate, giro | primerísimo |
   | respiro | general |
   | ilustración, contrapunto | contraplano |
   | digresión | mapa |
   | tesis, prueba, eco | documento |
   | cartel | cartel |

2. The size-jump warning (`W102`) is only evaluated between two consecutive shots that
   both declare a size.
3. `plano fijo` takes a template.

### 6.6 Piece types and substrates

`TIPO-PIEZA` (what `pon:` accepts: cartulina, dymo, mano, python, rescate, sello, texto,
tira, and `apunte`) is a dramaturgical role; `SUSTRATO` (14: papel, tira, cartulina,
postit, vegetal, acetato, foto, periódico, pijama, milimetrado, kraft, dymo, ficha,
polaroid) is a physical property (base colour, opacity, shadow, foley when it lands).
Every type resolves to a substrate (`rescate`, `texto` and `mano` to `papel`, `sello` to
`cartulina`, and the homonyms to themselves); the substrates that are not types are
reached from the workshop (`materia NAME`) or from the bestiary, not from `pon:`.

## 7. Semantics {#semantics}

### 7.1 Units and strata

```text
PLIEGO
 └─ CHAPTER      unit of page and of rendering (rendered in parallel)
     └─ SCENE    unit of world (the world persists between shots)
         └─ CLIP unit of time: a beat, a shot
             └─ LINE  unit of action
```

Because chapters MAY be rendered in separate processes, continuity between them is
**serialized data** (`estado_entrada`, §10.4), never live objects.

| Stratum | Lives | Space | z band | Composed by the resolver |
|---|---|---|---|---|
| `FONDO` | per sequence | table space | −60 to −30 | no |
| `MUNDO` | until exit or curtain | floor, marks, bindings | −20 to 0 | no (relational) |
| `DOCUMENTO` | per sentence | zones and slots, with reservation | 1 to 100 | yes |
| `PROSCENIO` | while it crosses | table space | 101 to 200 | no |
| `ANOTACIÓN` | with its target | the target | 9000 and above | no |

The proscenium (what is between the camera and the scene) goes above the document,
otherwise any card would be drawn over it and occlusion would not occlude, and below the
annotation, because a subtitle is not in the room: it is on the film. Membership is
inferred from the kind of piece and corrected with a word (`en el mundo:`, `en el
documento:`).

### 7.2 The five laws

1. The anti-parameter constitution (§3).
2. Closure (§11.1).
3. Identity is the seed (§7.4).
4. What does not fit on the sheet is not read.
5. Distance rules over speed, colour and depth of every stratum (§7.7).

### 7.3 Precedence

Every decision of the engine has a dimension and an ordered list of authorities; the first
authority that has a value wins. Every decider returns a value **and its reason**, or
nothing; the reason is mandatory by signature. Authorities are a closed vocabulary
(`AUTORIDAD`, 34 words).

| Dimension | Order of authority (left wins) |
|---|---|
| place | hand, binding, body, slot, composer, seed |
| z | stratum, proscenium, arrival |
| size | **declared**, hand, identity, paper, legibility |
| time | score, window, cap, gesture |
| background | order of the hand, scene, chapter, character |
| stratum speed | distance, **order of the world** |
| stratum colour | distance, archive, palette |
| curve | manner, material, hand, affect |
| shadow | light (the scene says it, never the piece) |
| name | **exact, alias, exact text, fuzzy text** |

Two candidates that tie at the same level of the `name` dimension are an ambiguity and an
error (`E020`). The presence of a field in the IR **is** the signal of authority (§10.5):
an explanation tool (`mesa por-que`) reads exactly that, so its explanation cannot diverge
from the render.

### 7.4 Identity, seed and determinism

**Identity** is the declared path (`id portada/fabula`) or the derived path
(`chapter/scene/text`). It is computed from **content**, never from position; an index
`#n` only breaks ties between literally identical pieces, locally.

**Seed:**

```text
seed(piece) = H(identity) ⊕ H(take)
```

where `H` is the canon's seed function (FNV-1a 32 over UTF-8, §16.3) and `take` is the
interpretation number (`--toma N`). Identity governs what must always look the same; the
take governs the material: `--toma 3` gives another interpretation of the same film (same
shots, same duration, different material).

**Forbidden seeds:** no seed may depend on rendering or creation order, object addresses,
the process, the clock or the file system.

**The master hash** is computed over the stripped, canonicalized pliego: spaces
normalized, comments and digressions removed, sections resolved, `(máquina)` marks
removed. Writing a pliego back (`escribe`) does not change its seed.

**The determinism contract.** Two runs produce **the same film** when these five inputs
coincide: (1) the canonicalized pliego, (2) the take number, (3) the engine version,
(4) the bestiary and the imported sections, (5) the voice sidecar. The sidecar is part of
the contract, not metadata: its `hash` and `metodo` per beat are inputs. A golden
fingerprint (§13.4) is valid for one set of the five inputs on one machine and GPU; across GPUs the fingerprint is compared with tolerance. A pliego used as a golden
reference MUST declare `tirada definitiva` and fix its take.

### 7.5 Time

**One beat, one clock.** Every beat has a duration before rendering: from the voice
(`di:` and dialogue, through the sidecar, §14.3), from `> dura N`, from its clips
(a beat does not close while a clip runs, §5.6) or synthetic (reading time of its text,
§16.4). There is no free regime.

**The score** (`al decir «w»:`) is the first authority of time. Every action has a window;
`mientras:` opens a parallel track; `hasta decir` stretches; the **cap** prevents an action
from eating the turn of the next. Two actions on the same subject in the same window are
an error (`E031`). Movement persists across a cut unless `> congela`.

### 7.6 Movement and the craft

The curve of every movement is derived; the pliego never declares it. The principles of
Lasseter (1987) are the default behaviour of every movement verb, with the numbers of the
canon (`oficio`, §16.4):

| Principle | What the interpreter does | Modulated by |
|---|---|---|
| slow in, slow out | the derived curve is eased at both ends; it is never linear | the manner (`de golpe` keeps the abruptness) |
| anticipation | moves back along its path before leaving, in proportion to speed | `con anticipación` forces it; `de golpe` removes it |
| arcs | without a path the verb decides (`salta` in an arc, `vuela` in a curve, `cae` falling); otherwise a gentle upward arc; nothing leaves the sheet on the way | a written path prevails; `recto` is straight |
| squash and stretch | stretches along the motion keeping its area; squashes on landing | speed and material (rigid gives half) |
| follow-through | overshoots and settles; leans against the motion | mass, bounce and sway |
| overlapping action | the parts of a group leave staggered, as damped springs; never more than `simultaneos_maximos` moving at once | |
| timing | duration from distance and manner, never under `fotogramas_minimos` | the manner |
| moving hold | what has moved breathes (a seeded minimal drift): never a frozen frame | `> deja posar` lengthens it |
| exaggeration | every factor × `exageracion` | the canon |

**On twos:** `en dos` animates drawn things at half the frame rate with held poses; it is
a suffix of a movement or a property of the whole pliego. Real video, boil and updaters
stay on ones.

**Secondary motion** (drag, bounce, sway) is a property of the material and is never
declared in the pliego. **Support:** a released piece falls to its support; it floats only
if its material allows it (`E033` otherwise).

### 7.7 Distance rules, and its one exception

From the **distance** (`LEJANIA`), and from nothing else, derive the speed, colour and z of
a layer. **The exception, declared:** `MUNDO acelera a N` and `MUNDO frena a N` are an
explicit order of the hand to the world clock; the dimension *stratum speed* has a second
authority, *order of the world*, below distance. The law still holds between layers (a
layer cannot be slow and in front); the order changes the common clock, which multiplies
all of them alike. `MUNDO para` sets the clock to zero.

### 7.8 Material

**Nothing is a flat fill.** Every piece belongs to a register (`REGISTRO_MATERIA`):
`recorte` (scissor outline, grain, hard shadow, edge), `pintado` (gouache or marker: passes
with ductus and an overflowing edge), `fotográfico` (developed and die-cut), `tinta` (a
hand-drawn line, which boils). **The boil:** three poses of the same path, same geometry,
different tremor, periods seeded by identity; the poses MUST be isomorphic. The boil
changes the shape, never the place.

### 7.9 Camera, continuity, light and focus

From the **axis** derive each one's side, view and entry side. Flipping applies only to
pieces declared mirrorable. The three laws of camera: displacement is data, not a bounding
box; **the cut does not travel**; a scene with a world of its own is a new place. When the
hand declares `toca la truca: sí`, the rostrum inherits its pulse (anticipation, a tremor
of prime period, overshoot, and it loses the subject for half a second).

**One light per scene**, and every shadow obeys it; the hour tints it. Adjusting the
shadow of a single piece is forbidden. **Focus is not blur**: what is out of focus is
paler, with a softer edge and slightly larger. Text is never defocused, unless a rule is
broken with permission (§8.5).

### 7.10 Continuity warnings

None is fatal: breaking them is legitimate, but it must be said. `AVISO_CONTINUIDAD`:

| Warning | When | Silenced by |
|---|---|---|
| `W101` axis jump | crossing the line without a neutral shot | `> cruza el eje`, `> rompe el eje porque «…»` |
| `W102` size jump | the same size and angle on the same subject, or more than two steps, between shots that both declare a size | `> salta` |
| `W103` eyeline | in a reverse shot both look to the same side | |
| `W104` direction | leaves by one side and enters by the same | |
| `W105` state | a piece changes without an action that explains it | |

## 8. Profiles {#profiles}

A profile is a set of capabilities an **interpreter** realizes. Every interpreter MUST
accept every valid IR; for a capability outside its profiles it MUST behave as if the
line were absent, MUST NOT fail, and SHOULD tell the author once per capability. An
interpreter declares the profiles it realizes; the suite's `huella` and `banda` cases are
grouped by profile.

| Profile | Scope (grammar in Appendix B) | Reference |
|---|---|---|
| **núcleo** (core) | §5 and §7: the table, collage, pieces, movement with the craft, cinema and continuity, the journey, the paper theatre, the map, and the aspect lines of §8.1 | `ce` (partially: not the aspect) and `gx` |
| **sonido** (sound) | §8.2: voice, effects, the score of sound, music cues, ambiences, rooms, panning and master | `gx` |
| **cartel** (poster) | §8.3: every shot is a poster | `gx` |
| **oído** (hearing) | §8.4: the picture that listens, light, support, intensity | `gx` |
| **cámara** (camera) | §8.5: the camera as an object, depth, layered time, the frame as an object, breaking with permission | `gx` |

RFC 0002 proposes separating the aspect lines into a profile of their own.

### 8.1 Aspect (part of the core profile)

Unit lines (preamble, chapter or scene; the scene prevails) and events, all closed
vocabulary and without numbers; the numbers belong to the interpreter:

- `MATERIA papel PAPEL | acuarela | risografía A y B [y C] · registration · screen | pincel
  | tejido [drum] | tinta | ninguna [sobre papel PAPEL]`: what the frame is made of, a pass
  over the finished frame in the convention of Part 6. The same words as a prefix give the
  material of one piece (`en acuarela: python: gamba`). A photograph has no layers: its
  material is baked once on the original image, not on its halftone. Events: `> se moja`,
  `> se seca`, `> se lava`, `> florece [drum] [en «X»]`, `> se teje`, `> la tinta lo cubre
  todo [drum]`.
- `BOBINA truca | sin grano | noticiario`: the film stock (the newsreel at 18 frames per
  second, sepia, scratches, flicker and weave).
- `FORMATO 4:3 | 16:9 | 2,39:1 [· de televisión] [· bandas de papel]` and `> formato X`:
  bands of ink with torn edges; the change is animated. In a pliego that changes format,
  every format is a viewer with round corners and paper around it, and the viewer pass goes
  last.
- `ESPEJO [side]`, `PANTALLA PARTIDA [· con un espejo en medio] [· que se miran] [·
  desigual] [· inclinada]`, `SIMULTÁNEO en rejilla | en abanico | en abanico que gira`, with
  their events (`> se rompe el espejo`, `> se parte la pantalla`, `> un solo plano`…).
- Transitions (`TRANSICION`): two-plane transitions where the incoming plane is alive and
  the outgoing one is a still lámina of its last frame; `corta`, `corta en la acción`,
  `sintoniza`, `a la vez`, `se sostiene`, `retención larga`.
- `RÍO TIPOGRÁFICO [· en fila | en libertad | a pantalla completa | no]`: the voice written
  word by word at the instant it is said; capitals and `> revienta «…»` grow, stamp and
  overflow. The split sentence (`A / B: —…`) and the flying sign (`de «A» a «B»: pon: …`).
- `MONTAJE se acelera · al ritmo de las palabras · al pulso · cada vez más cerca · la
  cámara no para · mezcla «A» · «B»`: cuts inside the beat.
- Movement trails (`con estela`, `con líneas de fuerza`, `en cronofotografía`),
  metamorphosis (`X se funde en Y`, `X hierve con Y`, `el pelo pasa de X a Y`), `> se rasga
  el papel y asoma «SCENE»`, `> asoma «SCENE» en el hueco`, `REPITE «SCENE»`, characters
  with a card (Part 3) and `HERVOR dibujado | suave | no`.

The chain of every instant is: material, what peeks through, mirror and split screen,
simultaneity, camera, format, newsreel, transition, tuning, and the bath (paper and film).
A pass changes only when something changes; its animations are functions of scene time.

### 8.2 Sound

The sound profile covers the voice and the whole soundtrack. **Every example, gallery item
and conformance pliego of this standard carries music and sound design.**

Preamble: `EFECTOS folder` (effects and ambiences, by file name), `BANDA folder` (music
cues), `MEZCLA para la web | para cine · con stems | sin stems`, and in `REPARTO` the voice,
its colour (`con radio`: the loudspeaker band, a touch of saturation and the station's
hiss; or `seca`) and its side. Unit lines: `MÚSICA cue | ninguna`, `AMBIENTE a · b`
(layers), `ESPACIO estadio | patio | estudio | radio | seco` (the room of the effects),
`CAMA`, `JINGLE`. Clip lines: `sonido: effect [side]` (anchorable: `al decir «X»: sonido:
pitido`). Events: `> entra la música «cue»`, `> la música se corta`, `> la música se
apaga`, `> silencio de verdad`, `> las voces se juntan en el centro`, `> cada voz a su
lado`, `> la voz se vuelve radio`.

An interpreter of the sound profile MUST:

1. resolve names case-insensitively and with the normalization of §4.5: `sonido:` and
   `AMBIENTE` in `EFECTOS` and then in `BANDA`; `MÚSICA` in `BANDA`. (A name that is found
   in neither is an error the **compiler** reports: `E040`, `E041`, `E042`; an interpreter
   MUST NOT render such a pliego as if the sound were silence.)
2. mix in stereo through four buses: voices, music, effects and ambiences;
3. keep a music cue running while consecutive scenes name the same cue (it does not
   restart), crossfade on a change of cue, end a cue shorter than its stretch on its own and
   fade one longer at the end of its stretch;
4. loop ambiences with a crossfade at each turn, for as long as they last;
5. duck music under the voice more than ambiences: the voice is always intelligible;
6. on `> silencio de verdad`, cut music, ambiences and what was sounding until the next beat,
   without room tone; an effect that starts at that very instant sounds whole;
7. place each voice at its side, move them on the panning events, and apply the room of
   `ESPACIO` to the effects (the voice already carries its colour in the take);
8. master to **−14 LUFS integrated for the web and −24 LUFS for cinema**, with true peaks
   below **−1 dBTP** (a limiter oversampled at least four times), and, with stems, write the
   four buses with the master's gain and without the limiter;
9. never call a paid service while rendering: voices come recorded in the sidecar (§14.3).

The reference writes the master as 24-bit WAV beside the video (`<out>.master.wav`), the
stems in `<out>.stems/` and a report in `<out>.banda.json` with the measured loudness,
true peak, cues and counts; the suite's `banda` cases read that report.

### 8.3 Cartel: every shot is a poster

`PALETA A, B y C` (field, figure, accent, plus the paper; `COLOR_CARTEL`) and `CARTEL
composition · …` (`COMPOSICION`) compose the page as a poster; inside a clip they apply to
that shot. **Signs are pieces**: `LETRA «WORD» · en TYPE · arrangement · place · size · de
COLOUR`, `«X» es un PAPEL-SIGNO [a «SCENE»]`, a letter that is a figure or becomes one,
`[las letras de] «X» VERB` (each letter with its rig and the craft), `la raya corta «X»`,
`«X» forma FORM`, `ESCALA A como B`, `BOSQUE de …`, `en silueta:`. Pieces can be cut by the
edge (`CORTE`) and grow `gigante`. **The safeguard:** a cut never takes away what is
essential in a piece (face and mouth of who speaks, the acting hand, the object that
matters: the essential parts of Part 3); text that must be read is read; `· sin leer` gives
permission. **Text is woven**: `TEJE`, `SINTONIZA`, `se interrumpe en`, `sigue`, `FRASES`,
and the stateful events of the cloth. `PARTITURA path` lets the typography of the source
text propose what a clip does not say (italics, dashes, capitals); what the clip declares
prevails.

### 8.4 Oído: the picture that listens

The interpreter **hears the real audio** (the voice of each beat, ambiences, music,
effects) as curves at 100 samples per second: intensity (absolute and relative), pitch (in
octaves), attack, spectral centroid and 32 log bands. Tracks (`PISTA`): `la voz`, `la
música`, `la cama`, `los efectos`, `la radio`, or a named sound. Lines: `la cámara respira
con PISTA`, `el río mide la voz`, `la luz sube con PISTA`, `el dial es la línea de tiempo`,
`X es el espectrograma de PISTA`. Light: `LUZ de «piece» · desde abajo · drum` (one hard
source, attached to its piece), `LUZ de los focos · en contraluz`, `LUZ plana`, `COLOR
monocromo [drum] | pleno`, `> estalla el color`. Support (degradation as dramaturgy):
`SOPORTE limpio | usado | gastado | sucio | roto`, `> el soporte empeora | se deshace | se
limpia`; the support lasts the whole film. **Intensity as a direction parameter**:
`INTENSIDAD WORD | de WORD a WORD [· extraña] [· con PISTA]`, with eleven words from `nula`
(0) to `rota` (10), governing at once tremor, tilt, misregistration, grain and the pace of
`MONTAJE al pulso`.

### 8.5 Cámara: the camera as an object

Unit lines: `CÁMARA lens · weight · hand · depth`, `HORIZONTE recto | se inclina | gira`,
`CADENCIA target cadence · …` (each layer draws at its own rate), `GOLPES con impacto |
con borrón`, `PISTA ÓPTICA [side]`; distance prefixes (`lejos: python: fachada`) put a
piece at that distance from a real perspective camera, and **parallax is never declared**:
it comes from the perspective when the camera moves. The sky is at infinity. Events
(`EVENTO_CAMARA`) include pans with mass, dolly, crane, lenses with focal length and
distance separated, the vertigo shot, a continuous tension curve for the handheld camera,
the tilting horizon, snorricam, orbit, bullet time, going through pieces, the long take,
axial cuts, the frame as an object (paper bands, perforations, a derailed frame), and
`X mira a cámara`.

**Breaking with permission.** A shot may break a rule knowingly, **with its reason**:
`> rompe el eje porque «…»`, `> se sale del cuadro porque «…»`, `> sin leer porque «…»`,
`> demasiado rápido porque «…»`, `> todo a la vez porque «…»`, `> sin respiro porque
«…»`, and the named awkward framings (`ENCUADRE_INCOMODO`). A rule broken without its
reason is an error (`E060`); a compiler explains it and the Lasseter review lists it apart.

## 9. Extension by layers {#extension}

The language is never extended in silence. It grows by layers, from the inside out:

1. **The language**: closed vocabulary, changed only by RFC and in a new epoch (§22).
2. **The sections** `#TALLER` and `#MANO`: they calibrate the craft of a project or a scene
   (paper, ink, edges, anchors, shadow, materials with mass and drag, the bath, the grid;
   the hand's pulse, precision, grain, entry and exit, fatigue, and whether it touches the
   rostrum). Numbers are legitimate here; the mirror law (§5.3) holds.
3. **The bestiary** (`PYTHON`, `PIEZAS`): named pieces with their parameters, parts,
   poses, actions and cycles (Part 3), called from the pliego by name (`python: radio`,
   `LOCUTOR señala`). A bestiary adds pieces, never grammar; its actions are the closed
   vocabulary of that piece.
4. **The interpreter**: passes in the convention of Part 6, materials, foley. An
   interpreter MAY add passes and looks under existing words; it MUST NOT add words.

**The house layer.** A pliego that only says (a REPARTO and `di:` lines) is already a
film: in a unit where no beat places anything of its own, an interpreter SHOULD put the
sentence of each beat on the paper with the piece the function and the affect call for (a
question by hand, a shout as a ransom note, a quotation as a newspaper cutting, the rest
typed). The layer switches itself off, unit by unit, as soon as a beat teaches something
of its own; `página vacía` in the property line switches it off for the whole pliego. It
is what lets a person or a small model write a first pliego with no drawings at all.

`~ deriva: text` records a commission to the engine in the IR without changing the film.
**What a pliego cannot say:** easing, keyframes, rate functions or loose durations in the
plain dialect; colours by hex or RGB; shadow, stratum speed or z per piece; unnamed pieces;
two places for the same decision.

## 10. The intermediate representation {#ir}

### 10.1 What it is

`compile(pliego)` returns `(script, report, extra)`: the IR (*guion rico*), a list of
readable sentences about the direction, and per-beat decisions (function, affect,
template, tension, author), motifs, cast and arc. The IR is JSON, is **regenerated always
and never versioned** inside projects; it is the contract an interpreter and a narrator
(`mesa cuenta`) eat. **If the narrator cannot tell a new capability, the capability is
badly integrated.**

Field names are Spanish identifiers without accents. Unknown fields MUST be ignored by
interpreters (forward compatibility, §22).

### 10.2 Script level

**Required** (a conforming compiler always emits them):

| Field | Type | Meaning |
|---|---|---|
| `escena` | string | name of the scene to render |
| `capitulo` | integer | page index (0-based) |
| `sala` | string | `crema` or `pizarra` |
| `beats` | array | the compiled clips (§10.3) |
| `taller` | object | the **effective** workshop, with all precedence applied |
| `mano` | object | the **effective** hand |
| `unidades` | array | the chapters (§10.4); REQUIRED when the pliego has chapters |

**Optional** (absent or `null` when the pliego does not declare them): `registro` (the
dominant affect), `subtitulos`, `gigantes`, `personajes`, `reparto`, `claves_cap`,
`tambor_cap`, `tramos_cap`, `archivo`, `archivo_cap`, `archivo_tintas`, `fantasma`,
`python_ruta`, `python_rutas`, `replica`, `efectos`, `banda`, `mezcla`, `bano`, `en_dos`,
`pagina`, `aspectos`, and `colofon` (`{lineas, tirada, semilla, toma, pobre}`: **counted,
not declared**).

The script level also carries `marionetas` (the photo puppets declared
with `MARIONETA`: `nombre`, `foto`, `mira`, `canto`), and the aspect of every unit and
beat carries `partitura_modo` (whether the voice is set as a typographic score, §8.3; `null`
when the pliego says nothing). Both are part of the reference IR; neither enters the
normative projection.

### 10.3 Beat level

**Required:** `id` (the clip's ordinal, `b07`, or its declared beat id), `cap` (chapter
index), `plano` (the resolved template), `afecto` (the resolved affect), `acciones`
(§10.5), and `identidad` (the stable path of §7.4, source of the seeds; see Appendix D).

**Optional, and what distinguishes the pairs:** `di` (the beat's delivery), `dura`
(declared duration when there is no voice), `sec`, `corte` (there is a cut before this beat,
whoever decided it) and `corte_mano` (the hand asked for it), `plano_mano` (the template
was declared, not derived), `limpia`, `queda`, `canta`, `nocturno`, `congela`, `luz` (the
effective light, already resolved with the hour), `escena`, `escena_titulo`,
`abre_escena`, `lugar_nuevo`, `linea` (the source line), `aspecto` (the effective aspect of
§8.1 to §8.5, one object per beat), `transicion`, `montaje`, `rio`, `voces`,
`frase_partida`, `revienta`, `rotos` (rules broken with permission) and the rest of the
fields of the profiles. The pattern `X` / `X_mano` is systematic: `X` is the value and
`X_mano` says whether a person set it.

### 10.4 Unit level

Each element of `unidades`: `n`, `titulo`, `beats` (ids), `escenas` (titles) and
**`estado_entrada`** (REQUIRED): `{velocidad_mundo, sentido, hora}`, the state the chapter
opens with. It exists because movement persists across cuts and chapters are rendered in
different processes: the only way for chapter 3 to know how fast the world was going is
that the compiler writes it, walking everything before, deterministically.

### 10.5 Action level

`verbo` is REQUIRED. **The presence of a field is the signal of authority**: `en` (place
declared by the hand: authority *hand*), `liga` (*binding*), `cuerpo` (*body*), `al_decir`
(*score*), `run` (*gesture*), and the movement's `trayecto`, `manera`, `granulado`; `spec`
and `sobre` carry the body of a `ver:` and the target of a mark. The verbs the reference
compiler emits are listed in its IR; an interpreter MUST ignore a verb it does not know
and SHOULD tell the author.

### 10.6 Canonical form and normative projection

The **canonical form** of an IR is its JCS serialization (§1.3); its **digest** is the
SHA-256 of that serialization, in lowercase hex (not to be confused with the fingerprint of
a film, §13.4).

The **normative projection** of an IR keeps only the required fields of §10.2 to §10.5
(script, beat, unit and action levels). Two conforming compilers MUST produce IRs with
equal normative projections for every pliego of the suite. The reference implementation is
additionally held to its **full** IR, frozen in `conformance/expected/ir/`: any change is
either a regression or the subject of an RFC.

## 11. Invariants {#invariants}

### 11.1 Closure

```text
canon(compile(p)) == canon(compile(escribe(p)))
```

where `escribe` materializes every decision of the engine into the pliego (revealed
dialect, §3.1) and `canon(ir)` removes provenance and position, and nothing else: the
fields `origen`, `autor_cabecera`, `_importado`, `linea` and `colofon`. Everything that
decides a frame MUST coincide; who decided it, and on which line, need not.

### 11.2 The mirror

For the sections of §5.3, `effective(p) == effective(parte(p)) ==
effective(funde(parte(p)))`, where `parte` moves every block to its own file and imports
it, `funde` inlines every import, and `effective` is the workshop and the hand after
precedence, compared line by line after normalization.

### 11.3 Compatibility

**A pliego that compiled once compiles always** (§22).

## 12. Diagnostics {#diagnostics}

A compiler checks a pliego (`mesa lee` in the reference) and reports **errors** and
**warnings**, each with a stable code (Appendix C, `spec/diagnosticos.json`) and a free
message, which SHOULD teach: say what was expected and offer the closest valid words. A
pliego with any error is invalid; a compiler's checking command MUST exit with a non-zero
status for an invalid pliego and SHOULD exit with zero otherwise. The suite compares
**sets of codes**, never messages or order.

Errors cover words outside a closed vocabulary (`E010` to `E019`), names (`E020` to
`E022`), structure (`E030` to `E033`), sound resources (`E040` to `E042`), the bestiary
(`E050`, `E051`), rules broken without reason (`E060`), and malformed lines (`E090`).
Warnings cover continuity (`W101` to `W105`), reserved words in use (`W110`, `W111`), the
health of the pliego (`W112` to `W118`), what needs the voice sidecar (`W120` to `W123`)
and the Lasseter review (`W130`).

**Warnings that need the sidecar** are emitted only when `<pliego>.tiempos.json` exists:
the dead anchor, two voices (a sounding clip inside a narrated beat without `> espera al
clip`), the illegible anchor, and the beat that grows.

**The Lasseter review** is measured on the real timeline of a render (or a dry render
that interpolates the same frames without rasterizing), never on the pliego: movement
shorter than `fotogramas_minimos` frames at 24 fps, more than `simultaneos_maximos` pieces
that stay on stage moving in the same frame, no `pausa_fin_beat` at the end of a beat, text
on screen for less than `words / palabras_por_minuto · 60 + asiento_lectura` seconds, twin
beats, linear movement, fast movement without anticipation. Each warning carries its beat,
its line, its instant, a suggestion and a severity.

**Diagnostics that need the bestiary** are computed by reading the bestiary **without
executing it** (in the reference, with Python's `ast`): a `python:` name that does not
exist (`E050`), a pose that was not declared (`E051`), a pose written without
normalization, a group that composes a piece not created in that beat.

### 12.1 Diagnostics that teach

The criterion of usability of the language is that **a person, or a language model much
smaller than the one that designed it, writes a clean pliego in a few attempts without
reading any code**. Diagnostics are the main tool for that, so a conforming compiler:

- MUST give the **line** of every diagnostic that has one;
- SHOULD give, after the message, **why** (the rule that applies), **the fix** (with «did
  you mean …?» built from spelling distance, prefix and a table of synonyms: `lento` →
  `despacio`, `de frente` → `frontal`) and **an example** of the correct line;
- SHOULD offer an **explanation of any word or line** (in the reference, `mesa explica
  «X»`: what it is, where it goes and an example; for a whole line, what the parser
  understands) and a **one-page cheat sheet** of the language (`mesa chuleta`);
- SHOULD list the **pieces a pliego can see**, with their kind, description and the
  actions each one declares, and the exact line to ask for them (`mesa bestiario
  pliego.mesa`).

### 12.2 No silent failures

**Whatever looks like an instruction and is not one is an error**, never prose. A line the
interpreter would print on the paper by accident (dialogue by a speaker who is not in
REPARTO, a scene line written inside a clip, an instruction or verb that does not exist) is
`E023`; a line of prose that will be typed on purpose is the warning `W125`. A compiler
MUST also report, reading the pliego and the bestiary without executing anything:

| Code | What would otherwise fail in silence |
|---|---|
| `E018` | an unknown modifier after `·` in `foto:`, `recorte:` or `clip:`, or an unknown field of `MARIONETA` |
| `E024` | `NAME action` for a piece that is neither in REPARTO (with the piece as alias) nor a `MARIONETA`: the action would never reach it |
| `E025` | `al decir «X»` where the written voice of that beat never says X (without the sidecar; with it, `W120`) |
| `E052` | a drawing invoked wrongly: arguments after `·`, parentheses as in a programming language, or arguments the signature of the piece does not accept |
| `E053` | the bestiary declared with `PYTHON` or `PIEZAS` does not exist next to the pliego |
| `E054` | an action the piece does not declare among its actions, poses or cycles (§15.2) |
| `W124` | an empty page: a beat opens a new frame (a declared shot size, a new chapter or scene) and places nothing while the voice sounds; not emitted for `respiro`, which empties the page on purpose |

The colour of a REPARTO entry is a closed vocabulary (the drums of the canon and the inks
of the poster palette); another word is an error (`E019`).

## 13. Tools and fingerprints {#tools}

### 13.1 The command (informative)

The reference ships one command, `mesa` (`python -m manim_saorin.formato.cli`). Its
subcommands are not normative, but conformance adapters use them: `lee` (check), `ir`
(dump the IR), `cuenta` (tell the pliego in prose), `escribe` (reveal), `indice` (census
of names and ambiguities), `por-que` (each decision with its authority and line), `mueve`,
`taller`, `parte`, `funde`, `graba` (synthesize the voice and write the sidecar),
`animatica`, `toca` (render; `--motor gx` on Tórculo's engine), `suena` (the soundtrack
without rendering), `lasseter`, `intensidad`, `dura`, `empaqueta`, `desempaqueta`,
`comprueba` (Part 2), `pieza` and `bestiario` (Part 3), and the teaching tools of §12.1:
`explica`, `chuleta` and `nuevo` (`mesa nuevo "Title" [--desde text.md]` writes a project
with a commented template layer by layer, a minimal bestiary and its folders, or a first
pliego drafted from a text).

### 13.2 What a compiler MUST offer

A conforming compiler MUST offer, by any interface: checking a pliego with the codes of
Appendix C, dumping its IR as JSON, and revealing a pliego (`escribe`) and splitting and
merging its sections (`parte`, `funde`) so that §11 can be tested.

### 13.3 What an interpreter MUST offer

A conforming interpreter MUST render a pliego with its sidecar to a video with sound, and
SHOULD offer a dry run that produces the timeline the Lasseter review reads.

### 13.4 The fingerprint of a film

The **fingerprint** (*huella*) of a video is a sequence of grey thumbnails of 96 × 54
pixels, one per second, scaled with area averaging (`ffmpeg -vf fps=1,scale=96:54:flags=area
-pix_fmt gray`), stored base64 in JSON with the MD5 of each thumbnail quantized to 4 bits.
Two fingerprints **match** when they have the same number of samples (±1) and the mean
absolute difference per pixel of every pair of samples is at most 10 (on 0 to 255). On the
same machine and engine the reference matches with difference 0. **Metrics lie**: a
fingerprint says where things are, not whether they live; no golden fingerprint is changed
without looking at a strip of the film first.

---

# Part 2. The portable project

## 14. The portable project {#mesapack}

### 14.1 What a project is

A project is **the pliego, its bestiary and its sound** (the voice with its sidecar, the
effects, the music) **plus everything the pliego reads** (the `PARTITURA`, imported
sections, real-video clips, photographs, the lock of chosen láminas). A packager MUST
**discover** these files by reading the pliego and the bestiary, and MUST NOT execute
project code to do so (the reference reads the bestiary with Python's `ast`).

A project is **portable** when every path it uses is relative to the pliego's folder and
stays inside it, and every file it needs is inside it or is declared as an installation
dependency in the manifest.

### 14.2 The package

A `.mesapack` is a ZIP archive (PKWARE APPNOTE; ZIP64 allowed). Audio, video and images
SHOULD be stored without recompression (method 0). It contains the project tree, with the
pliego at the root, and a file `MANIFIESTO.json` at the root:

| Member | Type | Required | Meaning |
|---|---|---|---|
| `formato` | string | yes | `"mesapack 1"`; a reader MUST reject another major (`P003`) |
| `pliego` | string | yes | the pliego's path inside the package; MUST end in `.mesa` and exist (`P008`) |
| `titulo` | string | no | the pliego's title |
| `creado` | string | no | ISO 8601 |
| `por` | string | no | the tool that packed it |
| `versiones` | object | yes | `lengua` (the epoch, REQUIRED), `motor` (name, version, commit, branch), `torculo` (commits of the standard and of the engine), or `null` where unknown |
| `voces` | object | no | the cast with voice, colour and side, and how many takes of each method (§14.3) |
| `fuentes` | object | no | per font: where it is (`motor`, `sistema`, `usuario`) and, for user fonts, its path in the package (`_fuentes/…`) |
| `externos` | array | no | what the bestiary reads from the installation and does not travel: `{ruta, por, donde}` |
| `no_portable` | array | no | what could not be made portable: `{donde, ruta, arreglo}` |
| `archivo_fotos` | array | no | archive photographs carried in `_archivo/` |
| `archivos` | object | yes | per path: `{sha256, bytes, por}`; `por` says **why** the file is in the package |

A reader:

1. MUST reject entries with an absolute path, a `..` segment, a backslash or a drive letter
   (`P004`), and MUST NOT write outside the destination folder;
2. MUST verify the SHA-256 and size of every declared file (`P005`) and SHOULD reject
   undeclared files (`P006`);
3. MUST check that the sidecar's recordings are relative paths inside the package
   (`P007`);
4. SHOULD, after unpacking, check the project as a packager would and warn when the
   language, engine or standard versions differ from the manifest's.

The reference validator is `conformance/tools/mesapack.py`; the reference packager is
`mesa empaqueta` (with `desempaqueta` and `comprueba`).

### 14.3 The voice sidecar

`<pliego without extension>.tiempos.json` sits beside the pliego. It is the fifth input of
the determinism contract (§7.4).

```json
{
  "beats": {
    "b01": {"dur": 2.57, "pause": 0.4, "hash": "cf79cc76fda2", "metodo": "silabas",
            "palabras": [{"w": "Un", "t": 0.05, "d": 0.214}, {"w": "tórculo", "t": 0.264, "d": 0.482}]}
  },
  "wavs": {"b01": "audio/voz/b01.wav"}
}
```

- `beats` maps a beat id to its delivery: `dur` (seconds), `pause` (seconds after it),
  `hash` (of the text that was spoken, so a changed text invalidates the take), `metodo`
  (how the timings were obtained: `whisper`, `silabas`, `elevenlabs`, `declarado`,
  `cancion`, `hueco`, or another name), and `palabras`, each word `w` with its start `t`
  and duration `d` in seconds from the start of the beat. A beat MAY carry `t_abs` (an
  absolute time, for songs).
- `wavs` maps a beat id to its recording: a path, a list of paths (takes chained, as in a
  sentence split between two speakers), or a list of `{ruta, desde}` objects (takes that
  sound at once, each from its instant).
- **Paths SHOULD be relative to the sidecar's folder** (the pliego's) and, in a package,
  MUST be. Readers MUST accept relative and absolute paths, resolving relative ones
  against the sidecar's folder. A sidecar whose absolute paths point to an old location of
  a moved project MAY be re-anchored when the same file (same path suffix and size) exists
  in the new location.
- A pliego whose voices were recorded outside the engine (for example by a casting
  service) carries them in the sidecar; rendering MUST NOT call a voice service.

### 14.4 Diagnostics

`P001` not a ZIP, `P002` no readable `MANIFIESTO.json`, `P003` unknown format, `P004`
dangerous path, `P005` missing file or wrong hash, `P006` undeclared file, `P007` a sidecar
recording outside the package or absolute, `P008` the pliego is missing, `P009` a required
member is missing.

---

# Part 3. Pieces

## 15. Pieces {#pieces}

This part normalizes what enters a pliego through `PYTHON`/`PIEZAS`, `python:`,
`MARIONETA`, `foto:` and `clip:`. It follows `SPEC-PIEZAS.md` v1 of manim-saorín (branch
`piezas`, 2026-10-15); the binding to Python described there is the reference binding, and
another engine MAY offer the same contract in another language.

### 15.1 Levels

| Level | What it is | The pliego may also |
|---|---|---|
| **0, drawing** | a pen drawing, a photograph, a cut-out | place it, move it, film it, cut it by the edge |
| **1, parts** | plus named parts with a pivot | `el pelo pasa de A a B`; protect what is essential when cutting |
| **2, puppet** | plus articulation (mothers and pivots), poses, actions and cycles | `X saluda`, `X corre hasta…`; the mouth follows the voice if there is a jaw |
| **3, character** | plus five views, expressions, visemes, hands, walk and run cycles, colour worlds | `X de espaldas`; the view follows the shot; `al decir «…»: X se asombra` |

**Each level is a superset of the one below.**

### 15.2 The contract of a piece

A piece is a **constructor** (in the reference binding, a Python function returning a
ManimGX mobject) with:

- its own arguments, by position or by name (what the pliego writes after `python: name`),
  and the extras with defaults: `alto` (height in scene units; the screen is 8 high),
  `hervor` (0, 1 or 2 fixes a boil pose; none lets the table boil it), `mundo` (§15.5),
  `espejo`, `id`;
- its **card** (§15.3);
- its **boil**: three poses with the same structure and another pulse;
- its **support**: the height where it rests (its feet), so it stands by its feet, not by
  its centre.

From level 1, a piece exposes `partes` (name to sub-object) and a pivot per part. From
level 2: the card signature `vista`, `pose`, `expresion`, `boca`, `mano_i`, `mano_d`,
`hervor`; `POSES` (names), `ACCIONES` (action to a list of poses, performed on twos) and
`CICLOS` (cycle to a repeating list of poses; `corre` and `anda` are started by the
movement verbs); a pivot and a mother for every articulated part; a part named `mandibula`
opens with the visemes. **The actions of a puppet are its closed vocabulary**: `X saluda`
is valid if `saluda` is among its actions or poses; otherwise the interpreter warns with
the list it has.

A level 3 character has views (`frente`, `tres cuartos`, `perfil`, `tres cuartos de
espalda`, `espalda`), expressions, mouths (`reposo`, `a`, `e`, `i`, `o`, `u`, `m`, `f`,
`l`, `gol`), hands (open, fist, pointing, clapping, pinch, or an object held), common poses
and the cycles `corre` (8 drawings), `anda` (8) and `habla` (6), and nested parts with
pivots (trunk, neck, head with its features, hair, scarf, arms, forearms, hands, thighs,
legs, feet).

### 15.3 The card

| Key | What | Required |
|---|---|---|
| `nivel` | `dibujo`, `partes`, `marioneta` or `personaje` | yes |
| `nombre` | ASCII without spaces: it is the seed and what the pliego writes | yes |
| `titulo` | with accents, for the sheets | no |
| `descripcion` | what is seen, for whoever cannot see it; used by the meaning layer and the bestiary listing | yes, 20 characters or more |
| `alto` | natural height in the scene | recommended |
| `mira` | `derecha`, `izquierda` or `frente`: for mirroring and the axis | recommended |
| `tintas` | the colours it uses | recommended |
| `registro` | `dibujo`, `foto`, `recorte`, `clip`, `tipografia`, `materia` or `escaneo` | no |
| `partes` | the parts it has | from level 1 |
| `esenciales` | essential to part | from level 1 |

### 15.4 Essential parts

What the language protects when cutting by the edge (§8.3): `cara`, `boca`, `cabeza`,
`mano` (the acting one) and `objeto` (what matters). A character declares the first four;
a puppet at least `cabeza` or `objeto`; a drawing `objeto`. **No essential part may leave
the outline of its piece.** Without declarations, the centre of the piece is essential.

### 15.5 Colour worlds

`mundo=`: `natural`, `tinta`, `sepia`, `noche`, `hielo`, `silueta` or `silueta:#RRGGBB`,
`riso:DRUM+DRUM` (two drums of the canon), and the worlds a project registers. A world
recolours every ink of a drawing and maps the greys of a photograph to its two inks.

### 15.6 In the pliego, and the checks

`PIEZAS path` (a module, a declarative file of a character, puppet or cut-out, or a whole
folder) extends `PYTHON`. `MARIONETA name · de la foto path [· mira a la izquierda |
derecha] [· canto …]` declares a photo puppet. `python: name [args]` places any piece;
named arguments fix the starting pose and view of a card. `WHO action` performs an action
the piece declares. Collage in motion: `foto: path · sin fondo · canto de tijera | de
troquel | rasgado | limpio · sombra pegada | levantada | sin sombra · con cinta | celo |
chincheta`, and `clip: path de a a b · sin fondo` (a cut-out film, on twos by default).

A piece provider MUST offer a check that calls each piece as the interpreter will and
verifies: it draws; it boils (three poses, same structure, different pulse); it has its
parts and essentials, none outside the outline; every articulated part has a pivot inside
the piece; every action and cycle uses poses that exist; for a character, the five views,
the visemes and the cycles. The reference is `mesa pieza comprueba`.

### 15.7 Photo puppets

A photo puppet is a level 2 piece made from a photograph without code: `MARIONETA name ·
de la foto path …` in the preamble or a `name.marioneta.toml` card. The provider finds the
joints and the face of the person, cuts the photograph once with the declared edge and
splits it at the joints (head, trunk, arms, forearms, thighs, legs; legs only when they
are seen whole), each part with a pivot and overlapping its mother; the part below the lip
becomes the `mandibula`, which opens with the voice. Without a person or a face the
photograph is one piece that trembles. **Every photo puppet knows**, besides what its card
declares: `saluda`, `celebra`, `señala`, `baila`, `se inclina`, `duda`, `grita`,
`aplaude`, `en jarras`, and the cycles `anda` and `corre`. An action whose parts the
photograph does not have (an arm that was not found) SHOULD be warned by the piece check.

A **character card in words** (`name.personaje.toml`) declares a level 3 character with
closed words instead of code: body (height, build, age), head (skull, nose, glasses,
eyes), hair (style, colour), clothes (top, bottom, shoes and their colours), the object it
holds, and its own poses (`[poses.recuerda] brazo_i = "a la boca"`). The words are a closed
vocabulary of the provider; an unknown word is an error of the piece check.

### 15.8 Collage in motion

Photographs, cut-outs, real video, type, pen and materials share one shot.

- `foto: path [· modifiers]` pastes a photograph; with `· sin fondo` the figure is cut out
  (the provider removes the background), and the edge (`canto de tijera | de troquel |
  rasgado | limpio`), the shadow (`sombra pegada | levantada | sin sombra`) and the
  fastening (`con cinta | con celo | con chincheta`) are declared in words. `recorte:` is a
  photograph already without background. The material of a piece still applies (`en
  risografía rosa: foto: …`).
- `clip: path [de a a b] · sin fondo` is a **cut-out film**: every frame is cut out and cut
  again with scissors, so the edge boils by itself; it plays **on twos** (12 drawings per
  second) unless `en uno` / `a 24` or `en cuatro` is said, and it is an actor without frame
  or tape.
- `clip de fondo: path [de a a b]` fills the frame at the cadence of cinema. **A background
  clip lasts its range**: when it ends it leaves at the opening of the next beat, even if
  the shot continues; it never stays frozen over what comes next.
- `CADENCIA` (§8.5) sets each layer's cadence (`las figuras en dos · el fondo en uno`), so
  the mixture of cadences of collage (real video at 24, cut-outs on twos, the pen boiling
  at 8) comes out by itself.
- **The house sets.** `FONDO` and `DELANTE` mount pieces of the bestiary as a scene's set;
  an interpreter of the core profile MUST also offer, without any bestiary, the sets of the
  house: `cielo`, `sierra`, `agua`, `arcada`, `celosia`, `ciudad`, `farola`, `lluvia`,
  `arboleda`, `cuarto`, `luna`. A bestiary piece with the same name replaces it. A set that
  is neither is an error.

**Who acts.** An action is asked with a REPARTO name whose alias is the piece's name, even
for a piece that does not speak (`REPARTO TIJERAS: minio, alias: tijeras`, then `al decir
«corta»: TIJERAS corta`); an alias equal to its own REPARTO name is not an ambiguity. The
piece must be on the table in that beat or before.

---

# Part 4. The canon

## 16. The canon {#canon}

### 16.1 Source and generated files

`canon/canon.toml` is the single source of truth. Every other form is generated by
`canon/genera.py`: Python (`canon.py`), TypeScript (`canon.ts`), Rust (`canon.rs`), WGSL
(`canon.wgsl`) and CSS (`canon.css`). Generated files MUST NOT be edited by hand;
`genera.py --check` fails if any is stale. The file declares `version = 1`.

### 16.2 Palette

Colours are sRGB, written `#RRGGBB`. In WGSL and Rust they are the same sRGB values as
floats, `component / 255` rounded to six decimals (not converted to linear light); in CSS,
custom properties `--group-name`.

| Group | Colours |
|---|---|
| `papel` (paper) | base `#F5F0E8`, hundido `#EDE6D6`, hoja `#FAF7F0`, filete `#D4C4B0`, filete_hondo `#C4AE96`, noche `#1A0F0A` |
| `tinta` (ink) | base `#2C1810`, segunda `#5C3D2E`, apagada `#7A5F4E`, lapiz `#9A8E80`, negro `#1A120D`, sobre_noche `#FAF7F0` |
| `escritorio` (desk) | rojo `#C1453B` (minium), azul `#2B4C7E` (azurite), amarillo `#E8A838`, oro `#D6A03A` |
| `tambores` (risograph drums) | ultramar `#2B3BC7`, bermellon `#D93325`, naranja `#E8501A`, ambar `#F2C744`, verde `#00A95C`, rosa `#FF48B0`, violeta `#765BA7`, humo `#1A1A1A` |

Drums are for content, never for chrome. The pliego's `TAMBOR` vocabulary names seven of
them (all but `humo`); the risograph materia (`TAMBOR_RISO`) accepts `humo`, `tinta` and
`azurita` too. New work MUST use this paper and ink; the older
creams `#F2EEE4` and `#F6F0E2` are legacy.

### 16.3 Randomness

All randomness in Tórculo is deterministic and derives from three functions, which every
implementation MUST compute bit for bit:

```text
semilla(text):   FNV-1a, 32 bits, over the UTF-8 bytes of text
                 h = 0x811C9DC5; for each byte b: h = (h XOR b) * 0x01000193 mod 2^32
serie(s):        Mulberry32 seeded with s; each call:
                 a = (a + 0x6D2B79F5) mod 2^32; t = a
                 t = (t XOR (t >> 15)) * (t OR 1)               mod 2^32
                 t = t XOR ((t + ((t XOR (t >> 7)) * (t OR 61))) mod 2^32)
                 return (t XOR (t >> 14)) / 2^32                  in [0, 1)
hash32(n):       x = (n * 0x9E3779B9 mod 2^32) XOR 0x85EBCA6B
                 x = x XOR (x >> 13); x = x * 0xC2B2AE35 mod 2^32; x = x XOR (x >> 16)
                 return (x AND 0xFFFFFF) / 2^24                   in [0, 1)
```

`serie` returns doubles that are exact multiples of 2^−32; `hash32` returns values that are
exact in a 32-bit float. Nothing may use the system clock, `Math.random` or an unseeded
generator. Seeds are computed over **UTF-8**; an older TypeScript helper of Scholaris
seeded over UTF-16 code units, which agrees only for ASCII: that is one reason identifiers
SHOULD be ASCII.

The test vectors are normative: `conformance/canon/vectores.json` gives, for a set of
texts (empty, ASCII, accented, `ñ`, CJK and a non-BMP character), the seed, the first eight
values of the series as integers before division, and `hash32` of the seed and of five
fixed integers. A canon implementation in any language MUST reproduce them.

### 16.4 Craft and foley

`oficio` (the craft, Lasseter in numbers; no pliego writes them, the engine applies them):
`palabras_por_minuto = 220` and `asiento_lectura = 1.0` s (reading time of a text),
`fotogramas_minimos = 8` (at 24 fps, nothing moves for less), `simultaneos_maximos = 3`,
`pausa_fin_beat = 0.6` s, `anticipacion = 0.2` (fraction of the action), `exageracion =
1.25`, `hervor_fps = 8`, `hervor_poses = 3`, `dibujo_en = 2` (drawn things on twos). A
canon of a later version MAY add keys; implementations MUST ignore keys they do not know.

`foley`: the relative weight of each foley event (the ear does not hear a key like a
stamp): rotulador 0.55, tecla 0.75, hilo 0.8, papel-deslizar 1.0, papel-posar 1.0,
carton-posar 1.1, celo 1.15, despegar 1.15, tijera 1.3, chincheta 1.25, sello 1.35,
punzon 1.2, papel-rasgar 1.3, pagina 1.4, campanilla 1.1, pincel 0.6, lavado 0.7.

---

# Part 5. Láminas

## 17. Láminas {#laminas}

A lámina is a hand drawing ready for any engine (web, app, game, video) to make it appear
under the pen **without computing the hand again**: the image is rasterized once and,
beside it, a **time atlas** says at what instant the pen reaches each pixel.

### 17.1 Two envelopes, the same content

- **Directory** `name.lamina/` with the files of §17.2.
- **Packed**, a single file `name.lamina`:

  | Bytes | Content |
  |---|---|
  | 0 to 7 | the signature `LAMINA\0\x01` (`4C 41 4D 49 4E 41 00 01`) |
  | 8 to 11 | `n`, the length of the index, u32 little-endian |
  | 12 to 12+n | the index, UTF-8 JSON: `{"archivos": [{"ruta", "inicio", "largo"}, …]}` |
  | from 12+n | the files one after another; `inicio` counts from here |

Index paths are the directory's paths. A reader tells the two cases apart by the signature.

### 17.2 Files

```text
manifiesto.json                 what there is and how it is composed (always first)
geometria.json                  the vector geometry of every pose (optional)
vista.png                       the finished drawing on paper, pose 0 (preview)
capas/<layer>-<pose>.png        colour atlas of a layer in a pose
capas/<layer>-<pose>-tiempo.png time atlas of that layer in that pose
```

All images of a lámina have the same size: `tamano.ancho` × `tamano.alto` pixels, the
drawing's box times its scale (2 by default).

**Colour atlas:** 8-bit RGBA PNG **with premultiplied alpha** (the PNG declares straight
alpha; a reader MUST load it without touching the values: in WebGL,
`createImageBitmap(blob, {premultiplyAlpha: 'none', colorSpaceConversion: 'none'})` and
`UNPACK_PREMULTIPLY_ALPHA_WEBGL = false`). No paper: what has no ink is transparent.

**Time atlas:** 8-bit RGB PNG. Per pixel, `R·256 + G` is the instant normalized to 16 bits,
`t = (R·256 + G) / 65535`, 0 the start and 1 the lámina's `duracion`; `B` is 255 where the
layer has ink and 0 elsewhere (then R and G mean nothing). It MUST be sampled **without
filtering** (nearest or `texelFetch`). Where two pieces of the same layer cross, the
earliest instant wins.

| Piece | Instant of a pixel |
|---|---|
| ink and colour (pen) | that of the nearest point of its centre line; along the line, `inicio + duracion · B⁻¹(arc/length)`, with `B` the cubic Bézier (0.55, 0.1, 0.45, 0.95) |
| pencil | the same, linear: `inicio + duracion · arc/length` |
| plane | a diagonal brush: `inicio + 0.7 s · f`, `f` the position along the diagonal of its box |
| note | written left to right, line after line, in 0.9 s |

### 17.3 Layers

In this order, only those that have something: `lapiz` (normal), `planos` (multiply),
`tinta` (normal), `color` (multiply, with the misregistration offset), `encima` (multiply,
with the offset), `notas` (normal; does not boil: all its poses point to the same image).

### 17.4 Boil

`hervor.variantes` poses (3 by default). Pose 0 is the drawing as always; the others have
the same geometry and rhythm and only change the tremor. In playback,
`pose = floor(seconds_at_rest · fps + offset) mod variantes`, with `fps = 8` and the offset
written in the manifest (`hash32(semilla(id)) · variantes`). While the pen draws, pose 0 is
shown; the boil starts when the drawing is whole (`al_reposar: true`).

### 17.5 Revealing

For each layer, bottom to top, with `progress` from 0 to 1:

```glsl
float t = (R * 255.0 * 256.0 + G * 255.0) / 65535.0;
float reveal = B > 0.5 ? clamp((progress * 1.03 - t) * 60.0, 0.0, 1.0) : 1.0;
vec4 c = color * reveal;                        // premultiplied
dst = blend == "multiplicar" ? dst * (1.0 - c.a) + dst * c.rgb
                             : c.rgb + dst * (1.0 - c.a);
```

`dst` starts as the paper. The lead of 1.03 guarantees that at `progress = 1` everything is
drawn; the slope 60 gives an ink front of 1/60 of the duration. Both numbers are in the
manifest (`revelado`).

### 17.6 The manifest

`manifiesto.json` has: `formato` (`"lamina"`), `version` (1), `id` (the drawing's id and
seed, ASCII), `titulo` and `descripcion` (for screen readers, in the lámina's language),
`lengua`, `tamano` (`ancho`, `alto`, `escala`, `caja`), `duracion`, `papel`, `alfa`
(`"premultiplicada"`), `revelado` (`formula`, `adelanto` 1.03, `pendiente` 60), `hervor`
(`variantes`, `fps`, `desfase`, `semilla`, `al_reposar`), `capas` (per layer: `nombre`,
`mezcla`, `desplazamiento`, `hierve`, and the `color` and `tiempo` paths per pose), `trazos`
(the order of the hand: `indice`, `capa`, `elemento`, `pasada`, `modo` (`lineal`, `pluma`,
`pincel`, `escritura`), `inicio`, `duracion`, `t0`, `t1`), `trayectoria` (two tools,
`lapiz` and `pluma`, each a list of `[ms, x, y, down]` in drawing units, milliseconds never
decreasing), `geometria` (path or null), `vista` and `canon` (`version`, `semilla`,
`serie`).

`geometria.json` gives, per pose and per stroke in the order of the hand: `tipo` (`cinta`,
`linea`, `relleno`, `nota`), its layer and indices, how it is painted, `inicio`,
`duracion`, `modo`, the trembled centre line `puntos`, the accumulated `arco`, the width
`ancho` per point, the arrival `llegada` per point, the `contorno`, and for notes their
text, position, size, rotation and anchor. Numbers are rounded to thousandths.

### 17.7 Guarantees

- **Determinism.** The same lámina comes out byte for byte the same in native Rust, in
  Python and in WebAssembly: randomness is the canon's and nothing reads the clock. The
  suite gives the SHA-256 of three packed láminas (`lamina` cases); a producer MUST
  reproduce them.
- **Fidelity.** Pose 0 is the same drawing as the SVG of the hand-drawing engine (mean
  difference under half a grey level, from antialiasing).
- **Ids in ASCII** (§4.5).

### 17.8 Memory

Each layer in each pose is two textures of `width × height × 4` bytes. Readers SHOULD let
producers lower the scale or the variants for large drawings.

### 17.9 Diagnostics

`L001` bad signature, `L002` bad index, `L003` a listed file is missing, `L004` bad or
incomplete manifest, `L005` an image of the wrong size, `L006` a PNG of the wrong type,
`L007` a time atlas whose blue channel is not 0 or 255, `L008` layers out of order or with
the wrong blend or pose count, `L009` strokes, `L010` trajectory, `L011` boil or reveal
parameters. The reference validator is `conformance/tools/lamina.py`.

---

# Part 6. Materias

## 18. Materias: the pass convention {#materias}

### 18.1 What a materia is

A materia turns a clean plane into paper, watercolour, paint, risograph, knitting or a
transition. It is one or more **WGSL compute passes** in a common convention, so that any
host (the engine's post chain, a library, a tool) runs it as it is. The reference library
is `materias/` (Rust + WGSL) and the engine's `m.Pass` (§19.6).

### 18.2 Group 0: the convention

Every pass of a plane materia binds exactly:

| Binding | Name | Type |
|---|---|---|
| `@group(0) @binding(0)` | `entrada` | `texture_2d<f32>`: the input, **linear light, premultiplied**, half floats |
| `@group(0) @binding(1)` | `muestreo` | `sampler`: bilinear, clamped to the edges |
| `@group(0) @binding(2)` | `plano` | `var<uniform> Plano` |
| `@group(0) @binding(3)` | `salida` | `texture_storage_2d<rgba16float, write>`: the output, in the same form |

```wgsl
struct Plano {
    resolucion: vec2f,     // offset 0
    fotograma: u32,        // 8
    tiempo: f32,           // 12: scene time in seconds, never the system clock
    semilla: u32,          // 16
    paso: u32,             // 20: free for the materia (simulation step, pass number)
    _hueco0: u32,          // 24
    _hueco1: u32,          // 28
    params: array<vec4f, 4>, // 32: sixteen parameters
}                          // 96 bytes
```

A materia SHOULD obtain group 0 with `#import plano` rather than declaring it.

### 18.3 Groups 1 and 2

What is a materia's own goes in `@group(1)`: textures it reads or writes, buffers. In the
engine, a pass's `@group(1)` holds only its pictures (a plate, the outgoing plane of a
transition), one sampled texture per binding from 0, in the order given. **Persistent
state** goes in `@group(2)`: binding 0 the state as it is (a texture), binding 1 the next
(an `rgba16float` storage texture); before the pass, its step entry runs a fixed number of
times per frame, each from the state to the next and swapping them. A materia MUST NOT bind
other groups, and MUST NOT repeat a binding.

### 18.4 Determinism

The only time a pass sees is the scene's (`plano.tiempo`, `plano.fotograma`). Stateful
materias (watercolour) advance in **fixed steps of 60 Hz**: two runs give the same pixels.
A held frame steps too; going back in time starts the state again from zero. A materia
MUST NOT read the system clock.

### 18.5 Modules and chains

`#import name` pastes a module once (a preprocessor of the library). Shared modules:
`canon` (palette and `hash32`, generated from the canon), `comun` (sRGB and linear, PCG,
value noise, fbm, interleaved gradient noise, `sobre`), `plano` (the convention),
`campos_papel` (the eleven paper fields and `color_papel`), `espectral` (16-band
transmittance and spectral upsampling).

A chain of materias is written `materia(key=value, …) > materia > …`; values are numbers,
names the materia understands (`tipo=khadi`, `tambor1=rosa`) or `#RRGGBB` colours. Entry
points are compute entry points with `@workgroup_size`; a pass that writes `salida`
SHOULD take `@builtin(global_invocation_id)` and handle one pixel per invocation.

### 18.6 Diagnostics

`M001` neither imports `plano` nor declares the convention's group 0, `M002` group 0 is
not exactly the convention's, `M003` `Plano` is not the convention's struct, `M004` an
entry point that is not compute or lacks `@workgroup_size`, `M005` own resources outside
groups 1 and 2, or a repeated binding, `M006` reads a clock. The reference checker is
`conformance/tools/materias.py`; compilation and reference frames are tested by the
library's own tests (`cargo test --release` in `materias/`).

---

# Part 7. Takes and the public API

## 19. Takes and the public API {#takes}

### 19.1 The engine

The reference engine is a fork of ManimGX (Rust and wgpu, with the Python API of Manim
Community Edition), branch `seams`. Everything the fork adds is **off by default**: with
none of it in use, the engine draws exactly as upstream, pixel for pixel on the reference
corpus. The fork's own takes have versions of their own (§19.3), which upstream readers
refuse.

### 19.2 The take stream

A take records an engine run as the engine's calls: shapes, brushes and images uploaded
under their keys, then frames (a view and its records, shown for some frames). It is one
stream of **messages**, little-endian:

```text
message  = length:u32  opcode:u8  fields…        (length counts the opcode and the fields)
bytes    = length:u32  data…
```

The first message MUST be START; a complete take ends with END. Readers MUST reject a take
whose first message is not START, whose version they do not know, that contains an unknown
opcode, a message longer than what remains, a second START or anything after END.

| Opcode | Message | Fields |
|---|---|---|
| 14 | START | version u32, width u32, height u32, frame rate f64 |
| 1 | PATH | key u64, centroid and area f32 × 6, array keys (points, subpaths) |
| 2 | POINTS | key u64, array key |
| 3 | MESH | key u64, outline u32, block u32, array keys |
| 4 | ROWS | key u64, array key (a brush's rows) |
| 5 | TEXTURE | key u64, width u32, height u32, array key (RGBA8) |
| 6 | GROW | key u64, closed u8, array key |
| 8 | FRAME | repeat u32, view (bytes), records key u64, camera count u32, and per camera: key u64, width u32, height u32, view (bytes), records key u64 |
| 9 | NOTE | bytes: UTF-8 JSON (the plays, sections and captions) |
| 10 | SOUND | bytes: an audio file the player plays beside the frames |
| 11 | ARRAY | key u64, base key u64 (0: none), kind u8, coding u8, bytes (zstd) |
| 12 | END | failed u8 |
| 13 | ENVIRONMENT | id u32, width u32, height u32, array key |
| 15 | POST | bytes: the post chain's description (only in `0x8000_0002`, right after START) |
| 16 | MATERIAL | id u32, bytes: WGSL source (in `0x8000_0002`; opcode 15 in `0x8000_0001`) |

Uploads are held until a frame shows them; arrays are sent once under a key of their kind
and content (an opaque 64-bit digest: readers MUST treat keys as opaque) and coded against
the array they replace: `ALONE` (0), `FIRST` (difference from the base), `SECOND`
(difference from the linear prediction), `TAIL` (the base is its start), lane by lane and
compressed with zstd, with a keyframe every 32 versions. A FRAME's records are 424 bytes
each (eight keys of 8 bytes, flags, two 3 × 4 matrices, paints, parameters, dash, material,
the materia id u32, the blend u32, a user id u64 and sixteen user floats). The number of
frames of a take is the sum of the FRAME messages' repeats.

### 19.3 Versions

| Version | Records | Opcodes 15 and 16 | Readers |
|---|---|---|---|
| `0x8000_0001` | 424 B | 15 = MATERIAL | MUST be read |
| `0x8000_0002` | 424 B | 15 = POST, 16 = MATERIAL | written by the engine of Tórculo 1.0 |

The range `0x8000_0000` and above is the fork's; upstream's versions are below it. A take
writer of this standard MUST write `0x8000_0002`. A new layout or opcode takes the next
version.

### 19.4 Diagnostics

`T001` the first message is not START, `T002` unknown version, `T003` a message longer than
the take, `T004` unknown opcode, `T005` repeated START or data after END, `T006` POST not
right after START, `T007` a NOTE or MATERIAL that is not valid UTF-8 (JSON for NOTE). The
reference reader is `conformance/tools/toma.py`.

### 19.5 Determinism of the engine

Shaders see the scene's time (or the frame index), never the clock. The same scene,
rendered twice on the same machine and GPU with the same engine, gives the same bytes;
across GPUs this is not guaranteed, which is why fingerprints are compared with tolerance
(§13.4). Seeds of materials, misregistration and boil come from the canon's `semilla` of a
piece's name (`set_material(…, pieza="c1_09/rosa")`), never from a counter.

### 19.6 The public API

**Stability.** The interfaces in this section are public in Tórculo 1.0: they change only
through an RFC. Everything else in the fork is internal.

Python (`import manimgx as m`; the API of Manim CE, see the engine's own guide):

| Interface | What |
|---|---|
| `m.config.post = [m.Papel(), m.Bobina("truca")]` | the post chain: passes over every finished frame; the grain lives in the pauses |
| `m.Pass(shader, entry=None, reach=…, moves=…, params=(), paths=(), pictures=…, estado=None, pasos=…)` | any pass in the convention of Part 6, with pictures in `@group(1)` and persistent state in `@group(2)` |
| `m.Papel(plate=None, …)`, `m.Bobina(reel="truca", lut_in=None, lut=None, papel=canon paper, …)` | the house's print bath and film |
| `m.config.compositing = "linear"` | compose in linear light (half floats); default sRGB |
| `mobject.set_material(name, …, pieza=None)`, `m.register_material(name, wgsl, params)` | per-object materials (`papel`, `acuarela`, `riso`, and registered ones defining `fn materia(m: Materia) -> vec4<f32>`) |
| `mobject.set_blend("normal" | "multiplicar")` | how an object lies over what is below |
| `mobject.set_clip("mascara" | "dentro" | "fuera", name)` | clipping by shape in the composition |
| `m.Trazo(points, widths, tiempos=None, grano=None)`, `m.Trazo.de_pluma(stroke)` | the variable-width pen stroke, drawn by `Create` at the pace of the hand |
| `m.Hervor(drawing, poses=3, fps=8, desfase=True, gpu=False)` | the line that lives at rest |
| `m.sidecar(pliego | tiempos.json | folder)` | a pliego's real voice as the voice of `self.say`, synchronized per word; without a voice the default voice raises instead of calling a paid service |

Command line: `manimgx render scene.py [--codec h264 | hevc | prores | prores4444]
[--take] [-r WxH] [--fps N] [--sound-events]`. HEVC Main10 and ProRes use VideoToolbox
(macOS); ProRes 4444 carries alpha, unpremultiplied. **Binaries that include x264
(`--codec h264`) are GPL; builds with VideoToolbox only are not** (`DECISIONES.md`).
Strict errors are the default: malformed LaTeX and Typst warnings fail at the line of the
scene; `--no-strict` turns them into warnings.

Rust: the crate `manimgx-render` (`Replay::read(&bytes)`, `replay.render(i)` to RGBA,
`Gpu::from_device(…)` to draw on another application's device).

Web: `<manimgx-film src="Scene.take" autoplay>` plays a take with WebGPU, without Python;
it needs float32 blending and `depth32float-stencil8` (Chrome and Edge 113 and later,
Safari 26).

---

## 20. Security considerations {#security}

- **Compiling MUST NOT execute project code.** A compiler checks and compiles a pliego and
  reads its bestiary without running it (§12). A packager discovers files the same way
  (§14.1).
- **Rendering executes the bestiary.** A pliego with `PYTHON` or `PIEZAS` runs that code
  when it is rendered: an interpreter MUST treat such a pliego as a program, and a viewer
  of untrusted projects MUST NOT render them outside a sandbox. A servilleta or a pliego
  without a bestiary executes nothing but the engine.
- **Packages** can carry dangerous paths (§14.2): readers MUST reject them before writing
  anything, verify hashes, and bound the total uncompressed size.
- **Takes carry shader source** (MATERIAL, POST) that runs on the GPU. WebGPU and wgpu
  validate it, but a hostile take can still exhaust resources: players SHOULD bound the
  number of materials, the size of arrays and textures, and the decompressed size of each
  ARRAY, and MUST reject a take that breaks §19.2.
- **Láminas** are bounded by their manifest; a reader SHOULD refuse a lámina whose image
  sizes or layer counts would exceed its memory budget (§17.8).
- **No network while rendering.** Voices, music and effects come from the project; an
  interpreter MUST NOT call a paid or remote service while rendering.

## 21. Privacy considerations {#privacy}

- Voice recordings are personal data of whoever speaks. A package carries them; its
  manifest says how many takes of each method it has, never who recorded them unless the
  cast declares it.
- Absolute paths reveal user names and folder structures (`/Users/name/Library/Caches/…`).
  Sidecars SHOULD use relative paths, and packages MUST (§14.3).
- The manifest records commits and versions of the tools, not the machine.

## 22. Versioning and compatibility {#versioning}

- **The constitution of compatibility: a pliego that compiled once compiles always.** The
  epoch is declared in the preamble (`MESA v2`); a compiler MUST compile every pliego of
  every epoch it claims, and SHOULD read epoch 1 (`SPEC-MESA.md`) as legacy. The
  vocabulary of an epoch is frozen, reserved words included.
- A new epoch MAY add words and lines; it MUST NOT change the meaning of a valid pliego of
  an earlier epoch. Removing a word is only possible by declaring it legacy in a new epoch,
  and compilers keep accepting it for pliegos that declare the old one.
- The IR is not versioned (§10.1): interpreters MUST ignore unknown fields and verbs.
- `mesapack` majors are incompatible (`mesapack 2` would be another format); minors
  (`mesapack 1.1`) only add members readers can ignore.
- Lámina version 1 is written in the signature and the manifest; a new layout takes
  version 2.
- Take versions are listed in §19.3.
- The canon's `version` changes when any value changes; generated files carry it.
- The specification is numbered MAJOR.MINOR with editorial releases (`spec-v1.0.0`); its
  number and the libraries' numbers are independent (`governance/VERSIONING.md`).

## 23. Media types and file identification {#media-types}

Proposed, not registered:

| Extension | Media type | Identification |
|---|---|---|
| `.mesa` | `text/vnd.torculo.mesa; charset=utf-8` | UTF-8 text whose first non-comment line starts with `MESA` (or prose: a servilleta) |
| `.mesapack` | `application/vnd.torculo.mesapack+zip` | a ZIP with `MANIFIESTO.json` whose `formato` starts with `mesapack` |
| `.lamina` | `application/vnd.torculo.lamina` | the signature `LAMINA\0\x01` (a directory `.lamina/` has `manifiesto.json`) |
| `.take` | `application/vnd.torculo.take` | first message START (opcode 14) with a version from `0x8000_0001` |
| `.tiempos.json` | `application/json` | beside a pliego with the same stem |

## 24. Internationalization {#i18n}

The language of Tórculo is Spanish: keywords, vocabularies and diagnostics are Spanish
words, and diacritics are significant where Spanish makes them so (§4.5, reserved words).
Text on screen is whatever the author writes, in any script, normalized to NFC. Compilers
SHOULD write their messages in Spanish and MAY offer translations; codes are
language-independent. A localized keyword set (for example, English keywords mapped to the
same IR) would be a new dialect and needs an RFC; the IR, being the contract, would not
change.

---

## Appendix A. Closed vocabularies {#appendix-a}

Generated from `spec/vocabularios/vocabularios.json`, which is extracted from the reference
parser. Each vocabulary gives its profile, the structure it comes from and its words in
canonical form (without accents, §4.5); a compiler accepts them with or without accents.

<!-- vocabularios:inicio -->

### Profile: core

**`ACCION_FICHA`** (15 words; Source: `formato.aspecto.ACCIONES`)

anda · aplaude · baila · cae · celebra · corre · gesticula · gira el dial · grita · habla · recoge · salta · se levanta · senala · señala

**`AFECTO`** (8 words; Source: `formato.vocabulario.AFECTOS`)

contenido · euforico · exhausto · jugueton · nervioso · seco · sereno · solemne

**`ALTURA`** (5 words; Source: `formato.continuidad.ALTURAS`)

cenital · contrapicado · nadir · normal · picado

**`ANCLA`** (5 words; Source: `formato.vocabulario.ANCLAS`)

bordado · celo · chincheta · esquineras · washi

**`ARCO`** (6 words; Source: `formato.vocabulario.ARCOS`)

espiral · letania · pregunta→respuesta · ruina · tesis→antitesis→sintesis · viaje y vuelta

**`AUTORIDAD`** (34 words; Source: `formato.precedencia.AUTORIDADES`)

afecto · alias · archivo · capitulo · caracter · compositor · cuerpo · declarado · escena · estrato · exacto · gesto · identidad · legibilidad · lejania · ligadura · llegada · luz · manera · mano · mano_taller · materia · orden_mano · orden_mundo · paleta · papel · partitura · proscenio · semilla · slot · texto_difuso · texto_exacto · tope · ventana

**`AVISO_CONTINUIDAD`** (5 words; Source: `formato.continuidad.AVISOS`)

RACCORD DE DIRECCIÓN · RACCORD DE ESTADO · RACCORD DE MIRADA · SALTO DE EJE · SALTO DE TALLA

**`BOBINA`** (3 words; Source: `formato.aspecto.BOBINAS`)

noticiario · sin grano · truca

**`CLAVE_MANO`** (7 words; Source: `formato.taller.MANO_BASE`)

cansa · entra · granulado · precision · pulso · sale · toca la truca

**`CLAVE_VIS`** (68 words; Source: `visualizaciones.CATALOGO`)

alfiler · ancla · arbol · balanza · barras · brujula · bucle · cadena · caja · cancelacion · ciclo · comparacion · constelacion · convergencia · cuadrante · cuenta · curva · dado · diana · dispersion · distribucion · domino · ecuacion · ejes · embudo · engranaje · escalera · espectro · espiral · flecha de proceso · fraccion · globo · grieta · huella · interruptor · isla · jerarquia · laberinto · linea temporal · lista tachada · lupa · mapa · medidor · moneda · monton · multitud · onda · orbita · papeleta · pendulo · pila · ping pong · porcentaje · proceso · puente · recorrido · red · reloj · resta · semaforo · suma · telarana · teorema · termometro · titere · venn · versus · votos

**`DESREGISTRO`** (2 words; Source: `formato.aspecto.DESREGISTROS`)

desregistrada · en registro

**`DIMENSION`** (10 words; Source: `formato.precedencia.DIMENSIONES`)

color_estrato · curva · fondo · nombre · sitio · sombra · tamaño · tiempo · velocidad_estrato · z

**`DIRECCION_LUZ`** (5 words; Source: `formato.vocabulario.DIRECCIONES_LUZ`)

cenital · de atras · de frente · de la derecha · de la izquierda

**`DISPOSICION`** (8 words; Source: `formato.vocabulario.DISPOSICIONES`)

amontonados · como flores · en abanico · en columna · en corro · en fila · en fila holgados · en rejilla

**`DUREZA`** (2 words; Source: `formato.vocabulario.DUREZAS`)

blanda · dura

**`ESPEJO_LADO`** (2 words; Source: `formato.aspecto.ESPEJO_LADOS`)

de la derecha · de la izquierda

**`EVENTO`** (163 words; Source: `formato.vocabulario.EVENTOS`)

a la vez · aire al reves · amanece · anochece · arranca de golpe · asoma · barre · barrido · barrido a la derecha · barrido a la izquierda · barrido hacia abajo · barrido hacia arriba · barrido temporal · cada voz a su lado · camara lenta · camara lenta a saltos · capitulo · chasquido · congela · congela la imagen · continua · corta · corta en la accion · cortado por la barbilla · cortado por la frente · cortinilla de tijera · cruza el eje · cuadro vacio · deja posar · demasiado cerca de · demasiado rapido · desenfoque de pasada · destellan los focos · dura · el clip se agranda y se va · el color se apaga · el cuadro gira · el cuadro se endereza · el fotograma se descarrila · el horizonte se endereza · el horizonte se inclina · el montaje se acelera · el que habla fuera de campo · el rio mide · el soporte empeora · el soporte se deshace · el soporte se limpia · empapela · encadena · entra de golpe · entra la musica · espectrograma de · espera al clip · estalla el color · florece · formato · fotograma de impacto · fotograma en blanco · funde a blanco · funde a negro · funde desde blanco · funde desde negro · gigante · gran angular · iris · la camara atraviesa · la camara baja · la camara deja de respirar · la camara entra en · la camara gira alrededor de · la camara mira desde dentro de · la camara no para · la camara respira con · la camara sale de · la camara se acerca a · la camara se aleja · la camara sube · la camara va a · la camara va montada en · la camara va pegada a · la camara vuelve · la costura se mueve hacia · la intensidad cae a · la intensidad salta a · la intensidad sube a · la linea se endereza · la linea se inclina · la linea se mueve · la linea se rompe · la luz sube con · la mancha deja · la mano tapa · la musica se apaga · la musica se corta · la pista se desborda · la pista vuelve · la tela se desenreda · la tela se enreda · la tension cae · la tension rompe · la tension se mantiene · la tension sube · la tinta lo cubre todo · la voz se vuelve radio · las bandas bajan · las bandas suben · las voces se juntan en el centro · lente normal · mezcla los registros · mirando fuera de campo · montaje al pulso · montaje al ritmo de las palabras · ojo de pez · pasa pagina · pasa por delante · plano holandes · plano secuencia por · queda · rampa de velocidad · respira · retencion larga · revienta · rio tipografico · rompe el eje · salta · salto axial a · se desteje · se junta la pantalla · se lava · se moja · se para en seco · se parte la pantalla · se quema · se rasga el papel · se rasga la banda · se rompe el espejo · se sale del cuadro · se seca · se sostiene · se teje · se van las perforaciones · se ven las perforaciones · seco · silencio · silencio de verdad · simultaneo en abanico · simultaneo en abanico que gira · simultaneo en rejilla · sin leer · sin respiro · sintoniza · teleobjetivo · temblor · tiempo bala sobre · todo a la vez · todo se para menos · triple salto axial a · un solo plano · velocidad normal · vertigo · vertigo al reves · vuelve el espejo · zoom de golpe

Reserved: none.

**`EVENTO_A_CAMPO`** (8 words; Source: `formato.vocabulario.EVENTO_A_CAMPO`)

Mapping: congela → congela_mano · continua → continua · cortado por la barbilla → salta · cortado por la frente → salta · cruza el eje → cruza_eje · demasiado cerca de → salta · rompe el eje → cruza_eje · salta → salta

**`EXPRESION`** (9 words; Source: `formato.aspecto.EXPRESIONES`)

duda · se asombra · se asusta · se calma · se enfada · se entristece · se pone serio · se rie · sonrie

**`FAMILIA_TALLER`** (10 words; Source: `formato.taller.TALLER_BASE`)

ancla · bano · canto · fantasma · materia · papel · reticula · sombra · tinta · vida

**`FORMATO`** (6 words; Source: `formato.aspecto.FORMATOS`)

16:9 · 1:1 · 2,39:1 · 4:3 · 4:5 · 9:16

**`FORMATO_MODO`** (2 words; Source: `formato.aspecto.FORMATO_MODOS`)

bandas de papel · de television

**`FRENTE`** (5 words; Source: `formato.continuidad.FRENTES`)

escorzo · espalda · frontal · perfil · tres cuartos

**`FUNCION`** (11 words; Source: `formato.vocabulario.FUNCIONES`)

apertura · cartel · contrapunto · digresion · eco · giro · ilustracion · prueba · remate · respiro · tesis

**`GESTO_MARCA`** (4 words; Source: `formato.vocabulario.GESTO_MARCA`)

rodea · senala · subraya · tacha

**`GRANULADO`** (4 words; Source: `movimiento.GRANULADOS`)

a doses · a pulso · a treses · a unos

**`HERVOR`** (3 words; Source: `formato.aspecto.HERVORES`)

dibujado · no · suave

**`HORA`** (5 words; Source: `formato.vocabulario.HORAS`)

amanece · atardece · diurna · mediodia · nocturna

**`LADO`** (4 words; Source: `formato.vocabulario.LADOS`)

abajo · arriba · derecha · izquierda

**`LEJANIA`** (8 words, ordered; Source: `viaje.LEJANIAS`)

al pie · al paso · cerca · a media distancia · lejos · al fondo · en el horizonte · en el cielo

**`LINEA_UNIDAD_ASPECTO`** (20 words; Source: `formato.aspecto.UNIDAD`)

AMBIENTE · BANDA · BOBINA · CAMA · EFECTOS · ESPACIO · ESPEJO · FORMATO · HERVOR · JINGLE · MATERIA · MEZCLA · MONTAJE · MÚSICA · PANTALLA PARTIDA · REPITE · RIO TIPOGRAFICO · RÍO TIPOGRÁFICO · SIMULTANEO · SIMULTÁNEO

**`MANERA`** (15 words; Source: `movimiento.MANERAS`)

a la deriva · a regañadientes · a tirones · con anticipación · con cuidado · de golpe · de un tirón · despacio · en volandas · ligero · pesado · resuelto · rozando · sin ganas · titubeante

**`MATERIA`** (7 words; Source: `formato.aspecto.MATERIAS`)

acuarela · ninguna · papel · pincel · risografia · tejido · tinta

**`MODO`** (3 words; Source: `formato.continuidad.MODOS`)

cartel · documento · mundo

**`MONTAJE`** (6 words; Source: `formato.aspecto.MONTAJES`)

al pulso · al ritmo de las palabras · cada vez mas cerca · la camara no para · mezcla · se acelera

**`MOVIMIENTO_MUNDO`** (4 words; Source: `formato.vocabulario.MOVIMIENTO_MUNDO`)

acelera · avanza · frena · para

**`NOMBRE_SECCION`** (6 words; Source: `formato.taller.SECCIONES`)

BESTIARIO · CASCADA · MANO · MONTAJE · REPARTO · TALLER

**`ORDEN_TRUCA`** (9 words; Source: `formato.vocabulario.ORDEN_TRUCA`)

baja · busca a · encuadra a · se acerca · se acerca a · se queda · sigue a · sube · viaja con

**`PALABRA_RESERVADA`** (76 words; Source: `formato.vocabulario.PALABRAS_RESERVADAS`)

a · al · alias · ancla · archivo · arco · arriba · bajo · bestiario · camino · canta · cascada · clip · con · contenido · de · del · delante · dentro · deriva · detras · di · eco · eje · el · en · escenario · fantasma · foco · fondo · formato · foto · fuera · hilo · junto · juntos · la · las · letra · letrero · los · luz · mano · marca · mesa · mientras · montaje · motivo · mundo · musica · nota · o · para · personaje · pica · pie · pon · por · prensada · python · que · recorte · relojes · reparto · revelado · se · sobre · sonido · su · sus · taller · terminal · un · una · ver · y

**`PAPEL`** (11 words; Source: `formato.aspecto.PAPELES`)

cuaderno · escolar · grano fino · khadi · kraft · lienzo · satinado · tintado · torchon · verjurado · washi

**`PARTE_CUERPO`** (7 words; Source: `formato.vocabulario.PARTES_CUERPO`)

el hombro · el pecho · el regazo · la cabeza · la espalda · las manos · los pies

**`PLANO_DE`** (11 words; Source: `formato.vocabulario.PLANO_DE`)

Mapping: apertura → orla · cartel → cartel · contrapunto → contraplano · digresion → mapa · eco → documento · giro → primerisimo · ilustracion → contraplano · prueba → documento · remate → primerisimo · respiro → general · tesis → documento

**`PLANTILLA`** (8 words; Source: `formato.vocabulario.PLANTILLAS`)

cartel · contraplano · documento · general · mapa · nocturno · orla · primerisimo

**`RASTRO`** (4 words; Source: `formato.aspecto.RASTROS`)

con borron · con estela · con lineas de fuerza · en cronofotografia

**`REGISTRO_LETRERO`** (6 words; Source: `formato.vocabulario.REGISTROS_LETRERO`)

cartulina · cita · cita maquina · cita moderna · mano · rescate

**`REGISTRO_LETRERO_RESERVADO`** (3 words; Source: `formato.vocabulario.REGISTROS_LETRERO_RESERVADOS`)

dymo · maquina · tira

**`REGISTRO_MATERIA`** (4 words; Source: `materia.REGISTROS`)

fotografico · pintado · recorte · tinta

**`REGISTRO_MOV`** (1 words; Source: `movimiento.REGISTROS`)

en dos

**`RIO_MODO`** (3 words; Source: `formato.aspecto.RIO_MODOS`)

a pantalla completa · en fila · en libertad

**`SENTIDO`** (2 words; Source: `formato.vocabulario.SENTIDOS`)

de espaldas · de frente

**`SIMULTANEO`** (3 words; Source: `formato.aspecto.SIMULTANEOS`)

en abanico · en abanico que gira · en rejilla

**`SUSTRATO`** (14 words; Source: `pieza.SUSTRATOS`)

acetato · cartulina · dymo · ficha · foto · kraft · milimetrado · papel · periodico · pijama · polaroid · postit · tira · vegetal

**`TALLA`** (7 words, ordered; Source: `formato.continuidad.TALLAS`)

general · conjunto · medio · americano · corto · primer · detalle

**`TAMBOR`** (7 words; Source: `formato.vocabulario.TAMBORES_V`)

ambar · bermellon · naranja · rosa · ultramar · verde · violeta

**`TAMBOR_RISO`** (10 words; Source: `formato.aspecto.TAMBORES_RISO`)

ambar · azurita · bermellon · humo · naranja · rosa · tinta · ultramar · verde · violeta

**`TENSION`** (4 words; Source: `formato.vocabulario.TENSIONES`)

cae · mantiene · rompe · sube

**`TRAMA`** (3 words; Source: `formato.aspecto.TRAMAS`)

de grano · de lineas · de puntos

**`TRANSICION`** (16 words; Source: `formato.vocabulario.TRANSICIONES`)

chasquido · corta · corta en la accion · cortinilla de tijera · desenfoque de pasada · encadena · entra de golpe · funde a blanco · funde a negro · funde desde blanco · funde desde negro · iris · la mano tapa · pasa pagina · se quema · sintoniza

**`TRAYECTO`** (16 words; Source: `movimiento.TRAYECTOS`)

a saltos · cayendo · en arco · en curva · en espiral · en zigzag · flotando · fuera de campo · girando · por el borde · por el camino · por el suelo · rebotando · recto · resbalando · rodando

**`VENTANA`** (2 words; Source: `movimiento.VENTANAS`)

hasta decir · mientras

**`VERBO_MOV`** (24 words; Source: `movimiento.VERBOS`)

baja · cae · camina · corre · cruza · entra · esquiva · flota · gira · rebota · resbala · rueda · sale · salta · se apea · se encaja · se levanta · se sienta · sube · tiembla · tropieza · va · viaja · vuela

**`VERBO_RELACIONAL`** (11 words; Source: `movimiento.VERBOS_RELACIONALES`)

agarra · alcanza · arrastra · cuelga · empuja · esquiva · huye · orbita · se apoya · sigue · suelta

**`VISTA`** (5 words; Source: `formato.aspecto.VISTAS`)

de espaldas · de frente · de perfil · de tres cuartos · de tres cuartos de espaldas

### Profile: sound

**`ESPACIO`** (5 words; Source: `formato.aspecto.ESPACIOS_SALA`)

estadio · estudio · patio · radio · seco

**`MEZCLA`** (4 words; Source: `formato.aspecto.MEZCLAS`)

con stems · para cine · para la web · sin stems

**`VOZ`** (6 words; Source: `formato.sonido.VOCES`)

cita · cita_f · cita_f2 · cita_f3 · cita_m2 · narrador

### Profile: cartel

**`BOSQUE`** (5 words; Source: `formato.cartel.BOSQUES`)

brazos · brazos y punos · manos · manos abiertas · punos

**`COLOR_CARTEL`** (16 words; Source: `formato.cartel.COLORES`)

amarillo · arena · azul · blanco · celeste · crema · lila · minio · morado · naranja · negro · rojo · rosa · tinta · ultramar · verde

**`COMPOSICION`** (15 words; Source: `formato.cartel.COMPOSICIONES`)

campo a sangre · campo en bandas · campo partido en diagonal · centro vacio · columna a sangre a la derecha · columna a sangre a la izquierda · diagonal de abajo a la izquierda arriba a la derecha · diagonal de arriba a la izquierda abajo a la derecha · disco detras · en silueta · enorme · figura delante de la letra · la letra corta a la figura · la letra delante de la figura · tercios

**`CORTE`** (12 words; Source: `formato.cartel.CORTES`)

cortada por abajo · cortada por arriba · cortada por el borde · cortada por la derecha · cortada por la frente · cortada por la izquierda · cortado por abajo · cortado por arriba · cortado por el borde · cortado por la derecha · cortado por la frente · cortado por la izquierda

**`DISPOSICION_SIGNO`** (6 words; Source: `formato.cartel.DISPOSICIONES`)

a sangre · en abanico · en columna · en escalera · girada · rota por el borde

**`EVENTO_CARTEL`** (5 words; Source: `formato.cartel.EVENTOS`)

la costura se mueve hacia · la mancha deja · la tela se desenreda · la tela se enreda · se desteje

**`FORMA_PALABRA`** (5 words; Source: `formato.cartel.FORMAS`)

el patio · un marco · un muro · una columna · una porteria

**`LINEA_UNIDAD_CARTEL`** (3 words; Source: `formato.cartel.UNIDAD`)

CARTEL · PALETA · PARTITURA

**`PAPEL_SIGNO`** (9 words; Source: `formato.cartel.ROLES`)

barandilla · cielo · cuchilla · mascara · muro · persiana · porteria · suelo · ventana

**`SITIO_SIGNO`** (5 words; Source: `formato.cartel.SITIOS`)

a la derecha · a la izquierda · abajo · arriba · en el centro

**`TIPO_LETRA`** (6 words; Source: `formato.cartel.TIPOS`)

anton · la serifa de pretexto · league gothic · letra de mano · maquina de escribir · serifa

**`VERBO_SIGNO`** (14 words; Source: `formato.cartel.VERBOS_SIGNO`)

cae · caen · se abre · se abren · se apila · se apilan · se estampa · se estampan · se rompe · se rompen · se separa · se separan · se va · se van

### Profile: oído

**`DIRECCION_FUENTE`** (4 words; Source: `formato.oye.DIRECCIONES_LUZ`)

desde abajo · desde arriba · desde la derecha · desde la izquierda

**`EVENTO_OYE`** (14 words; Source: `formato.oye.EVENTOS_OYE`)

destellan los focos · el color se apaga · el rio mide · el soporte empeora · el soporte se deshace · el soporte se limpia · espectrograma de · estalla el color · la camara deja de respirar · la camara respira con · la intensidad cae a · la intensidad salta a · la intensidad sube a · la luz sube con

**`INTENSIDAD`** (11 words, ordered; Source: `formato.oye.INTENSIDADES`)

nula · quieta · serena · templada · viva · agitada · tensa · encendida · desatada · furiosa · rota

**`PISTA`** (5 words; Source: `formato.oye.PISTAS`)

la cama · la musica · la radio · la voz · los efectos

**`SOPORTE`** (5 words, ordered; Source: `formato.oye.SOPORTES`)

limpio · usado · gastado · sucio · roto

### Profile: cámara

**`BANDA_CUADRO`** (4 words; Source: `formato.camara.BANDAS`)

de abajo · de arriba · de la derecha · de la izquierda

**`BLANCO_CADENCIA`** (6 words; Source: `formato.camara.BLANCOS_CADENCIA`)

el fondo · la camara · la letra · las figuras · lo de delante · todo

**`CADENCIA`** (4 words, ordered; Source: `formato.camara.CADENCIAS`)

en uno · en dos · en tres · en cuatro

**`DISTANCIA`** (9 words, ordered; Source: `formato.camara.DISTANCIAS`)

delante · al pie · cerca · al paso · a media distancia · lejos · al fondo · en el horizonte · en el cielo

**`ENCUADRE_INCOMODO`** (7 words; Source: `formato.camara.INCOMODOS`)

aire al reves · cortado por la barbilla · cortado por la frente · cuadro vacio · demasiado cerca de · el que habla fuera de campo · mirando fuera de campo

**`EVENTO_CAMARA`** (47 words; Source: `formato.camara.EVENTOS_CAMARA`)

barrido temporal · camara lenta a saltos · el cuadro gira · el cuadro se endereza · el fotograma se descarrila · el horizonte se endereza · el horizonte se inclina · fotograma de impacto · gran angular · la camara atraviesa · la camara baja · la camara entra en · la camara gira alrededor de · la camara mira desde dentro de · la camara sale de · la camara se acerca a · la camara se aleja · la camara sube · la camara va a · la camara va montada en · la linea se endereza · la linea se inclina · la linea se mueve · la linea se rompe · la pista se desborda · la pista vuelve · la tension cae · la tension rompe · la tension se mantiene · la tension sube · las bandas bajan · las bandas suben · lente normal · ojo de pez · pasa por delante · plano secuencia por · rampa de velocidad · salto axial a · se rasga la banda · se van las perforaciones · se ven las perforaciones · teleobjetivo · tiempo bala sobre · todo se para menos · triple salto axial a · vertigo · vertigo al reves

**`GOLPE`** (2 words; Source: `formato.camara.GOLPES`)

con borron · con impacto

**`HORIZONTE`** (3 words; Source: `formato.camara.HORIZONTES`)

gira · recto · se inclina

**`LENTE`** (4 words; Source: `formato.camara.LENTES`)

gran angular · normal · ojo de pez · teleobjetivo

**`LINEA_UNIDAD_CAMARA`** (7 words; Source: `formato.camara.UNIDAD`)

CADENCIA · CAMARA · CÁMARA · GOLPES · HORIZONTE · PISTA OPTICA · PISTA ÓPTICA

**`MANO_CAMARA`** (2 words; Source: `formato.camara.MANOS`)

al hombro · en tripode

**`PESO_CAMARA`** (3 words; Source: `formato.camara.PESOS`)

con masa · ligera · pesada

**`PISTA_LADO`** (2 words; Source: `formato.camara.PISTA_LADOS`)

a la derecha · a la izquierda

**`PROFUNDIDAD`** (2 words; Source: `formato.camara.PROFUNDIDADES`)

poca profundidad · profundidad total

**`ROTURA`** (6 words; Source: `formato.camara.ROTURAS`)

demasiado rapido · rompe el eje · se sale del cuadro · sin leer · sin respiro · todo a la vez

<!-- vocabularios:fin -->

## Appendix B. Grammar {#appendix-b}

The complete grammar is `spec/gramatica/mesa.ebnf`, normative, reproduced here.

<!-- gramatica:inicio -->

```ebnf
(* Tórculo 1.0, part 1: the grammar of the pliego language (.mesa), epoch 2.

   Normative. Notation (SPEC §1.4):
     NAME            nonterminal; every nonterminal in capitals that is not defined
                     here is a closed vocabulary of Appendix A (spec/vocabularios/
                     vocabularios.json), and that correspondence is exhaustive.
     "literal"       literal text, compared after normalization (SPEC §4.5),
                     except reserved words, which are compared as written.
     A | B           alternative          [ A ]   optional       { A }  zero or more
     TEXT            any characters up to the end of the line
     NL              end of line
     IDENT           identifier (SPEC §4.5)
     NUMBER          integer or decimal with a point, optional sign
     QUOTE           "«" TEXT-WITHOUT-» "»"      (U+00AB … U+00BB; straight quotes are not equivalent)
     ·               the field separator, U+00B7 MIDDLE DOT, with optional spaces around it

   Analysis is line oriented: each line is classified by its prefix and the
   prefix always wins (SPEC §5.1). Only section blocks and "dentro:" span lines.
   Blank lines separate clips. *)

PLIEGO          = PREAMBLE { CHAPTER } [ END ] ;
PREAMBLE        = { PREAMBLE-LINE | UNIT-LINE | SECTION | COMMENT } ;

(* ---------- preamble ---------- *)
PREAMBLE-LINE   = "MESA" [ "v" NUMBER ] TITLE
                | "formato" PROPERTY { "·" PROPERTY }
                | "ARCO" ARCO
                | "MOTIVO" QUOTE [ "—" TEXT ]
                | "ECO" IDENT ( "→" | "->" ) IDENT
                | "REPARTO" SPEAKER ":" TAMBOR [ "," VOZ ] [ "," VOICE-COLOUR ] [ "," SIDE ] [ "," "alias:" ALIAS { "·" ALIAS } ]
                | "PERSONAJE" IDENT "—" TEXT
                | "LETRA" PATH
                | "PYTHON" PATH
                | "ARCHIVO" KEY { "·" KEY }
                | "FANTASMA" ( "foto" | "texto" | "numeral" ) NUMBER
                | "RELOJES" IDENT NUMBER { IDENT NUMBER }
                | "SONIDO" TEXT
                | "EFECTOS" PATH                       (* sound profile: folder of effects and ambiences *)
                | "BANDA" PATH                         (* sound profile: folder of music cues *)
                | "MEZCLA" MEZCLA { "·" MEZCLA }       (* sound profile: "para la web" | "para cine"; "con stems" | "sin stems" *)
                | "PARTITURA" PATH                     (* cartel profile *)
                | "SOPORTE" SOPORTE                    (* oído profile *)
                | "el dial es la línea de tiempo"      (* oído profile *)
                | "baño" BOBINA ;
PROPERTY        = ASPECT-RATIO | "sala" ( "crema" | "pizarra" ) | "tirada" ( "borrador" | "definitiva" )
                | "página desnuda" | "en dos" ;
ASPECT-RATIO    = FORMATO ;
VOICE-COLOUR    = "con radio" | "seca" ;
SIDE            = "a la izquierda" | "a la derecha" | "al centro" ;

(* ---------- sections: the mirror law (SPEC §5.3) ---------- *)
SECTION         = BLOCK | IMPORT ;
BLOCK           = "#" NOMBRE-SECCION [ IDENT ] NL { SECTION-LINE } "#FIN" ;
IMPORT          = NOMBRE-SECCION PATH ;
SECTION-LINE    = FAMILY [ VALUE ] { "·" FIELD } ;
FIELD           = KEY ( " " | ": " ) VALUE ;       (* keys of several words take a colon *)
FAMILY          = FAMILIA-TALLER | CLAVE-MANO ;

(* ---------- chapter and scene ---------- *)
CHAPTER         = CHAPTER-HEAD { UNIT-LINE | SECTION | COMMENT } { SCENE | CLIP } ;
CHAPTER-HEAD    = "==" TITLE { "·" CHAPTER-ATTR } { "=" } ;
CHAPTER-ATTR    = "tensión" TENSION | "nº" NUMBER | "tambor" TAMBOR | "gigante" WORD
                | "plano fijo" PLANTILLA | "tramo" NUMBER ( "→" | "->" | "a" ) NUMBER
                | "nocturno" | "diurno" ;
SCENE           = SCENE-HEAD { UNIT-LINE | SECTION | COMMENT } { CLIP } ;
SCENE-HEAD      = "--" TITLE [ "·" HORA ] "--" ;

(* Unit lines are valid in the preamble (whole pliego), a chapter or a scene;
   the scene prevails over the chapter, the chapter over the preamble. Several
   are also valid inside a clip, for that shot only (SPEC §5.6). *)
UNIT-LINE       = CORE-UNIT-LINE | ASPECT-UNIT-LINE | SOUND-UNIT-LINE
                | CARTEL-UNIT-LINE | OIDO-UNIT-LINE | CAMERA-UNIT-LINE ;
CORE-UNIT-LINE  = "EJE" "de" IDENT "a" IDENT
                | "LUZ" DIRECCION-LUZ { "·" ( DUREZA | "rasante" ) }
                | "MUNDO" MOVIMIENTO-MUNDO [ NUMBER ] [ "·" SENTIDO ]
                | "FONDO" KEY { ARG } "·" LEJANIA [ "·" NUMBER ]
                | "DELANTE" KEY { ARG } [ "·" LEJANIA ] [ "·" "cada" NUMBER ]
                | "ESCENARIO" TEXT
                | "TABLAS" { "·" ( HORA | "suelo" NUMBER | "a sangre" | "ancho" NUMBER | "alto" NUMBER ) }
                | "ARCHIVO" KEY { "·" KEY }
                | "REPITE" QUOTE ;
ASPECT-UNIT-LINE= "MATERIA" MATERIA-SPEC
                | "BOBINA" BOBINA
                | "FORMATO" FORMATO { "·" FORMATO-MODO }
                | "ESPEJO" [ ESPEJO-LADO ]
                | "PANTALLA PARTIDA" { "·" ( "con un espejo en medio" | "que se miran" | "desigual" | "inclinada" ) }
                | "RÍO TIPOGRÁFICO" [ "·" ( RIO-MODO | "no" ) ]
                | "SIMULTÁNEO" SIMULTANEO
                | "MONTAJE" MONTAJE-SPEC { "·" MONTAJE-SPEC }
                | "HERVOR" HERVOR ;
MATERIA-SPEC    = "papel" PAPEL
                | "acuarela" [ ON-PAPER ]
                | "risografía" TAMBOR-RISO "y" TAMBOR-RISO [ "y" TAMBOR-RISO ]
                     { "·" ( DESREGISTRO | "trama" TRAMA ) } [ ON-PAPER ]
                | "pincel" [ ON-PAPER ] | "tejido" [ TAMBOR-RISO ] | "tinta" [ ON-PAPER ] | "ninguna" ;
ON-PAPER        = "sobre papel" PAPEL ;
MONTAJE-SPEC    = MONTAJE | "mezcla" QUOTE { "·" QUOTE } ;
SOUND-UNIT-LINE = "MÚSICA" ( CUE | "ninguna" )
                | "AMBIENTE" EFFECT-NAME { "·" EFFECT-NAME }
                | "ESPACIO" ESPACIO
                | "CAMA" EFFECT-NAME | "JINGLE" EFFECT-NAME ;
CARTEL-UNIT-LINE= "PALETA" COLOR-CARTEL "," COLOR-CARTEL "y" COLOR-CARTEL
                | "CARTEL" COMPOSICION { "·" COMPOSICION } ;
OIDO-UNIT-LINE  = "INTENSIDAD" ( INTENSIDAD | "de" INTENSIDAD "a" INTENSIDAD ) { "·" ( "extraña" | "con" PISTA ) }
                | "SOPORTE" SOPORTE
                | "COLOR" ( "monocromo" [ TAMBOR-RISO ] | "pleno" )
                | "LUZ" ( "de" ( QUOTE | "los focos" ) { "·" ( DIRECCION-FUENTE | TAMBOR-RISO | "en contraluz" ) }
                        | "plana" [ "·" "de estudio" ] )
                | "la cámara respira con" PISTA | "el río mide la voz" | "la luz sube con" PISTA ;
CAMERA-UNIT-LINE= ( "CÁMARA" | "CAMARA" ) CAMERA-SPEC { "·" CAMERA-SPEC }
                | "HORIZONTE" HORIZONTE
                | "CADENCIA" BLANCO-CADENCIA CADENCIA { "·" BLANCO-CADENCIA CADENCIA }
                | "GOLPES" GOLPE { "·" GOLPE }
                | "PISTA ÓPTICA" [ PISTA-LADO ] ;
CAMERA-SPEC     = LENTE | PESO-CAMARA | MANO-CAMARA | PROFUNDIDAD ;

(* ---------- clip ---------- *)
CLIP            = CLIP-HEAD { CLIP-LINE } ;
CLIP-HEAD       = "*" [ BEAT-ID ] ( FUNCION | SHOT ) [ "·" AFECTO ] [ "(máquina)" ] ;
BEAT-ID         = IDENT ;                         (* optional, stable id for the sidecar (e.g. r01_02) *)
SHOT            = { TALLA | ALTURA | FRENTE | MODO } [ "de" [ ARTICLE ] IDENT ] ;

CLIP-LINE       = CONTENT | PIECE | REAL-VIDEO | PLACEMENT | SCENE-VERB | MAP | MOVEMENT | CAMERA
                | JOURNEY | SOUND | EVENT | NESTING | UNIT-LINE | SIGN | WEAVE | CHARACTER | COMMENT ;

CONTENT         = "di" [ "(" VOZ ")" ] ":" TEXT
                | SPEAKER-LIST ":" TEXT                (* the speaker MUST be declared (REPARTO, PERSONAJE) *)
                | "letrero" [ "(" REGISTRO-LETRERO ")" ] ":" TEXT { "/" TEXT }
                | "terminal:" TEXT | "canta:" TEXT | "contenido (máquina):" TEXT
                | QUOTE                              (* a shout: at most one per clip *)
                | TEXT ;                             (* prose: the beat's content *)
SPEAKER-LIST    = SPEAKER { "/" SPEAKER } ;        (* "VECINO / LOCUTOR": the split sentence *)

PIECE           = "pon:" TIPO-PIEZA QUOTE { "·" PIECE-ATTR }
                | ( "foto" | "recorte" | "prensada" ) ":" KEY
                | "ver:" CLAVE-VIS [ "—" BODY ]
                | "pica:" KEY [ "en" NUMBER ]
                | "python:" NAME { ARG | NAME "=" VALUE } { "·" PIECE-SIZE | "·" CORTE | "·" "sin leer" }
                | ( "arriba" | "pie" | "nota" ) ":" TEXT
                | "marca:" GESTO-MARCA QUOTE ;
PIECE-ATTR      = NUMBER | "id" PATH | TAMBOR ;
PIECE-SIZE      = "grande" | "enorme" | "gigante" | "a sangre" ;

REAL-VIDEO      = "clip" [ " de fondo" | " mudo" ] ":" PATH [ "de" TIME "a" TIME ] ;
TIME            = [ DIGITS ":" ] DIGITS [ "." DIGITS ] ;

PLACEMENT       = "en" NUMBER NUMBER ":" CLIP-LINE
                | "en" PARTE-CUERPO "de" IDENT [ NUMBER NUMBER ] ":" CLIP-LINE
                | RELATION OBJECT [ "a" NUMBER ] ":" CLIP-LINE
                | RELATION "cada uno:" IDENT TEXT
                | "juntos:" LIST "—" DISPOSICION
                | ( "en el mundo" | "en el documento" ) ":" CLIP-LINE
                | "en" MATERIA-SPEC ":" CLIP-LINE          (* the material of one piece *)
                | "de" QUOTE "a" QUOTE ":" CLIP-LINE       (* the sign that flies *)
                | ( "a la izquierda" | "a la derecha" ) ":" CLIP-LINE
                | DISTANCIA ":" CLIP-LINE                  (* camera profile: depth *)
                | "en silueta:" CLIP-LINE ;                (* cartel profile *)
RELATION        = "bajo" | "sobre" | "junto a" | "delante de" | "detrás de" ;

SCENE-VERB      = IDENT "con vista" VISTA
                | IDENT "se encaja en" HOLE | "en sus huecos:" LIST
                | "recoge" IDENT | "clava" IDENT "en" IDENT
                | ( "recorta" | "dobla" | "tapa" | "traslada" ) QUOTE TEXT
                | "retira:" ( "el escenario" | "las tablas" | "el teatro" )
                | "la truca" ( "se acerca a" IDENT | "vuelve" | "se aleja" ) ;

MAP             = "mapa:" MAP-ORDER ;
MAP-ORDER       = "territorio" QUOTE { "·" ( "con" LIST | "grande" | "en" PLACE ) }
                | "línea desde" QUOTE [ "hacia" QUOTE ]
                | "la línea de" QUOTE ( "llega a otro igual" | "se hunde" | "vuelve" )
                | "conecta" QUOTE { "·" QUOTE } | "el círculo se abre" | "mira a" QUOTE
                | "en fila abajo" | "en columna izquierda" | "se va" ;

(* Movement is recognized BY THE VERB (VERBO-MOV, VERBO-RELACIONAL), never by its suffixes. *)
MOVEMENT        = [ PLACEMENT-PREFIX ] [ ARTICLE ] SUBJECT ( VERBO-MOV | VERBO-RELACIONAL ) [ DESTINATION ]
                     { "·" ( [ "por" ] TRAYECTO | MANERA | GRANULADO | REGISTRO-MOV | RASTRO ) } [ VENTANA-SPEC ]
                | SUBJECT "se funde en" SUBJECT | SUBJECT "hierve con" SUBJECT
                | "el pelo pasa de" SUBJECT "a" SUBJECT
                | SUBJECT "se sale del cuadro" [ "por la" LADO ] ;
DESTINATION     = ( "hasta" | "a" | "hacia" ) OBJECT | "fuera de campo" [ "por la" LADO ] ;
VENTANA-SPEC    = "hasta decir" QUOTE | "mientras" ;

CAMERA          = "la truca" ORDEN-TRUCA [ IDENT ] [ "en" TALLA ]
                | IDENT "mira a" IDENT | IDENT "mira a cámara"
                | [ ARTICLE ] IDENT ( "sale" | "entra" ) "por la" LADO
                | "sonido:" CRUCE-SONIDO [ NUMBER ]
                | "fuera de campo" [ "por la" LADO ] ":" TEXT
                | [ "el" ] "foco" ( "en" | "pasa a" ) IDENT [ "y en" IDENT ] | "todo en foco"
                | IDENT "está" TEXT ;                   (* a state, for continuity *)

JOURNEY         = IDENT "viaja" | IDENT "se apea"
                | "el mundo" MOVIMIENTO-MUNDO [ NUMBER ]
                | "por la ventanilla:" LIST "desfilan"
                | "por" WINDOW-OF "de" IDENT "se ve el mundo" ;

SOUND           = "sonido:" EFFECT-NAME [ SIDE ] ;      (* an effect, at its place; anchorable with "al decir" *)

CHARACTER       = SUBJECT ( ACCION-FICHA | EXPRESION | "de espaldas" | "de perfil" | "de frente"
                          | "de tres cuartos" | "de tres cuartos de espaldas" ) ;

SIGN            = "LETRA" QUOTE { "·" ( "en" TIPO-LETRA | DISPOSICION-SIGNO | SITIO-SIGNO | PIECE-SIZE
                                      | "de" COLOR-CARTEL | "sin leer" ) }
                | QUOTE "es" ( "un" | "una" ) PAPEL-SIGNO [ ( "a" | "de" ) QUOTE ]
                | [ "la" | "el" ] LETTER "de" QUOTE ( "es" | "se convierte en" ) IDENT
                | IDENT "se convierte en" [ "la" | "el" ] LETTER "de" QUOTE
                | [ "las letras de" ] QUOTE VERBO-SIGNO
                | "la raya corta" QUOTE
                | QUOTE "forma" FORMA-PALABRA
                | QUOTE "tapa a" IDENT | IDENT "tapa" QUOTE
                | "el ojo completa" QUOTE
                | "ESCALA" IDENT "como" IDENT
                | "BOSQUE de" BOSQUE ;
WEAVE           = ( "TEJE" | "SINTONIZA" ) QUOTE { "·" ( "en" TIPO-LETRA | "con la aguja del dial" | PIECE-SIZE | DISPOSICION-SIGNO ) }
                | QUOTE "se interrumpe en" QUOTE | QUOTE "sigue"
                | "los hilos de" IDENT "y" IDENT "se entretejen"
                | "FRASES" QUOTE { "·" QUOTE } ;

(* Events: a closed vocabulary with state (alive | reserved). The union of
   EVENTO, EVENTO-CARTEL, EVENTO-OYE and EVENTO-CAMARA, some with an argument. *)
EVENT           = ">" EVENT-NAME [ ARG ] { "·" ">" EVENT-NAME [ ARG ] } ;
EVENT-NAME      = EVENTO | EVENTO-CARTEL | EVENTO-OYE | EVENTO-CAMARA | ROTURA-WITH-REASON | ENCUADRE-INCOMODO ;
ROTURA-WITH-REASON = ROTURA "porque" QUOTE ;      (* breaking a rule with permission: the reason is required *)

NESTING         = "dentro:" NL { CLIP-LINE }          (* sub-clips; at most three levels *)
                | "mientras:" CLIP-LINE
                | "al decir" QUOTE ":" CLIP-LINE
                | CLIP-LINE "hasta decir" QUOTE ;

(* ---------- end ---------- *)
END             = "==" "FIN" { "=" } { TEXT } [ NL ">" "silencio" NUMBER ] ;

(* ---------- comments ---------- *)
COMMENT         = "//" TEXT                  (* technical comment: not in the IR *)
                | "(" TEXT ")"               (* author's digression: in the IR, `digresiones` *)
                | "~" "deriva:" TEXT ;       (* a commission to the engine: in the IR, `derivas` *)

(* ---------- terminals ---------- *)
ARTICLE         = "el" | "la" | "los" | "las" ;
TITLE           = QUOTE | TEXT ;
SPEAKER         = IDENT ;          (* not a reserved word; compared as written *)
CUE             = WORD ;           (* a file of BANDA, by name, case-insensitive *)
EFFECT-NAME     = WORD { WORD } ;  (* a file of EFECTOS (or BANDA), by name *)
PATH            = TEXT ;           (* relative to the pliego's folder in a portable project *)
LIST            = IDENT { "·" IDENT } ;
```

<!-- gramatica:fin -->

## Appendix C. Diagnostic codes {#appendix-c}

Codes of the pliego language (`spec/diagnosticos.json`):

<!-- diagnosticos:inicio -->

| Code | Severity | Meaning |
|---|---|---|
| `E001` | error | the pliego declares a newer epoch than the compiler supports |
| `E010` | error | affect outside the closed vocabulary |
| `E011` | error | unknown function or shot in a clip header |
| `E012` | error | stray word in a movement line (not a path, manner, grain, register or window) |
| `E013` | error | `>` event outside the closed vocabulary |
| `E014` | error | unknown sign register |
| `E015` | error | unknown ESPACIO (room) |
| `E016` | error | unknown voice colour in REPARTO |
| `E017` | error | unknown arc |
| `E018` | error | unknown collage modifier or MARIONETA field (after `·` in `foto:`, `recorte:`, `clip:` or `MARIONETA`) |
| `E019` | error | another word outside a closed vocabulary |
| `E020` | error | ambiguous name: two candidates tie at the same level of the `name` dimension |
| `E021` | error | reserved word used as a speaker name or identifier |
| `E022` | error | reference to something that does not exist (piece, clip, ECO id, character) |
| `E023` | error | a line that looks like an instruction and is not one: it would be printed on screen by accident (dialogue by someone not in REPARTO, a scene line inside a clip, an instruction or verb that does not exist) |
| `E024` | error | a piece acts (`NAME action`) without being in REPARTO or being a MARIONETA |
| `E025` | error | dead anchor in the text: `al decir «X»` and the written voice of that beat never says X |
| `E030` | error | two shouts in one clip |
| `E031` | error | two actions on the same subject in the same window, or a duration declared twice |
| `E032` | error | cycle of bindings, chain of more than three links, or nesting too deep |
| `E033` | error | unsupported piece whose material does not float |
| `E040` | error | MÚSICA cue not found in BANDA (or no BANDA declared) |
| `E041` | error | `sonido:` effect found in neither EFECTOS nor BANDA |
| `E042` | error | AMBIENTE not found in EFECTOS |
| `E050` | error | `python:` names something that is not in the bestiary |
| `E051` | error | pose not declared by the bestiary |
| `E052` | error | drawing invoked wrongly: arguments after `·`, parentheses, or arguments the piece's signature does not accept |
| `E053` | error | the declared bestiary (`PYTHON` or `PIEZAS`) does not exist next to the pliego |
| `E054` | error | action the piece does not declare (neither among its ACCIONES, its POSES nor its CICLOS) |
| `E060` | error | a rule broken without its `porque` |
| `E090` | error | malformed line (the parser cannot continue) |
| `W101` | warning | axis jump (180-degree rule) |
| `W102` | warning | shot-size jump |
| `W103` | warning | eyeline mismatch |
| `W104` | warning | screen-direction mismatch |
| `W105` | warning | continuity-of-state mismatch |
| `W110` | warning | reserved event: accepted by the language, not yet realized |
| `W111` | warning | reserved sign register |
| `W112` | warning | plain-dialect share below 85 % |
| `W113` | warning | no final silence declared |
| `W114` | warning | too many clips without a breather |
| `W115` | warning | scene with two or more characters and no EJE |
| `W116` | warning | empty clip |
| `W117` | warning | clocks that are not coprime |
| `W118` | warning | dubious action on a piece (enters twice, acts on something absent) |
| `W120` | warning | dead anchor: `al decir «X»` and the voice never says X |
| `W121` | warning | two voices: a sounding clip inside a narrated beat without `> espera al clip` |
| `W122` | warning | illegible anchor: matches the voice but not its `di:` |
| `W123` | warning | the beat grows: the clip is longer than the voice |
| `W124` | warning | empty page: the beat opens a new frame and places nothing while the voice sounds |
| `W125` | warning | text on screen: a prose line that will be typed on the paper |
| `W130` | warning | Lasseter review (on the real timeline) |
| `W199` | warning | other warning |

<!-- diagnosticos:fin -->

Codes of the other parts: `P001` to `P009` (portable project, §14.4), `L001` to `L011`
(láminas, §17.9), `M001` to `M006` (materias, §18.6), `T001` to `T007` (takes, §19.4).

## Appendix D. Known deviations of the reference implementation {#appendix-d}

Found while building the conformance suite (2026-10-15) against manim-saorín 1.0.0b1. Each
is a pending case in the suite; it stops being pending when the reference passes it.

| Case | What the reference does | What this specification says |
|---|---|---|
| `lee-errores-reservada` | accepts `REPARTO nota: …` and then treats `nota:` as a directive (warns «clip vacío») | a speaker named with a reserved word is `E021` (§5.5, §6.4) |
| `lee-estampas` | warns «clip vacío» (`W116`) for a clip whose only content is a sign (`LETRA`) | a sign is a piece (§8.3); the clip is not empty |
| `lee-errores-letra-preambulo` | accepts a `LETRA` line (a clip line) in the preamble without error and drops it silently: the sign never reaches the IR | the three seats (§3): a line out of its place is an error (`E090`), never a line that disappears |
| `cierre-servilleta` | `mesa escribe` rewrites a servilleta's preamble and drops `BANDA`, `EFECTOS`, `MEZCLA`, `MÚSICA` and `AMBIENTE` | closure (§11.1): the revealed pliego sounds the same |
| `espejo-taller` | an imported `.mano` reads `toca la truca: sí` as `no`; an inline `precisión alta` stays as an unnormalized key beside `precision alta`; `parte` drops the section name | the mirror law (§11.2) |
| (all `ir` cases) | does not emit `identidad` in each beat | `identidad` is a required beat field (§10.3); the normative projection will include it when the reference emits it |
| (preamble) | `MUSICA 1M1` without the accent in the preamble is taken as a song path and the cue is silently lost | `MÚSICA` and `MUSICA` are the same word (§4.5); a name in `BANDA` is a cue (§5.2, RFC 0004) |
| (plain share) | counts cue names such as `1M1` as figures | names are not figures (§3.1) |
| (checking) | `mesa lee` does not report name ambiguities; `mesa indice` does, with exit status 0 | a compiler's check reports `E020` and fails (§12); the adapter merges both commands |
| (codes) | messages without codes | codes of Appendix C (RFC 0003); the adapter derives them from messages |

## Appendix E. References {#appendix-e}

- BCP 14: RFC 2119 and RFC 8174, key words.
- RFC 8785, JSON Canonicalization Scheme (JCS).
- RFC 6838, media type specifications and registration procedures.
- ISO/IEC 14977, EBNF.
- PKWARE, .ZIP File Format Specification (APPNOTE).
- W3C, WebGPU and WGSL.
- EBU R 128 and ITU-R BS.1770, loudness and true peak.
- J. Lasseter, *Principles of Traditional Animation Applied to 3D Computer Animation*,
  SIGGRAPH 1987.
- Real Academia Española, *Diccionario panhispánico de dudas*, «raya».
- `SPEC-MESA-2.md`, `SPEC-PIEZAS.md` (manim-saorín); `pluma/LAMINA.md`, `materias/README.md`,
  `FORK.md` (this repository); ManimGX (Academa, MIT).

## Appendix F. Profiles in development (informative) {#appendix-f}

Three branches of the reference implementation are building new profiles at the time of
this draft. What follows is **informative**: it records the lines they introduce so that
other implementations do not take the same words for something else. Each becomes
normative when its branch is merged and the suite has cases for it.

- **metraje** (real footage), merged into the reference implementation on 2026-10-15
  (its working document is `SPEC-METRAJE.md`); the new `FORMATO` words are already in
  Appendix A, and the aspect of the IR carries `formato.reencuadre`. Preamble: `METRAJE`, `REVELADO`, `RECORTA`, `LIMPIA`,
  `ESTABILIZA`. Clip: `plano ≈ «…»` and `recurso ≈ «…»` (a shot found by meaning in an
  indexed library), `toma: «…»`, `plano: file de A a B`, and the tracking prefixes `sobre
  la mano de X:` and `sobre «objeto»:` (the pen follows what was filmed). REPARTO accepts
  the voice `filmada`. `FORMATO` gains `9:16`, `1:1` and `4:5`, with reframing after `·`:
  `sigue a quien habla | sigue al sujeto | sigue a NAME | centrado`. Tools: `ingesta`,
  `busca`, `monta` (editing by words), `exporta`, `importa`, `planilla`. Transcription is
  local and word by word.
- **géneros** (genres and production). Preamble: `GÉNERO X [· field …]`, which only fills
  defaults where the pliego says nothing. Clip: `ecuación:`, `fuente:`, `dato:`, `rótulo:`,
  `cita:`, and `ver: curva | barras | puntos desde datos.csv`. Native vertical and square
  canvases. Tools: `nuevo --género`, `serie`, `variantes`, `traduce`, `subtitulos`,
  `audiodescribe`, `accesible`, `revisa`, `notas`, `trailer`, `canal`, `deriva`.
- **3D** (volume). The set in volume from the words of the pliego, the same physical camera
  in the light 3D of the engine and in Blender orchestrated by layers, exchange through
  glTF and USD, and generated images and clips that are declared and frozen.
