# Tórculo: todo el texto para agentes / all the text for agents Fuente / source: https://torculo.joseluissaorin.com/llms.txt # ===== Instrucciones para agentes / Instructions for agents ===== URL: https://torculo.joseluissaorin.com/llms.txt # Tórculo > Films written as pliegos: an open standard for video essays, explainers and animated shorts written in a text that reads like the film. (Películas escritas como pliegos: un estándar abierto para vídeo-ensayos, explicaciones y cortos animados escritos en un texto que se lee como la película.) Tórculo is a standard by José Luis Saorín Ferrer (https://joseluissaorin.com). A film is a **pliego**, a `.mesa` file in the language of Tórculo: a line-oriented script in **Spanish** with **closed vocabularies**. The author says what happens and how ("la piedra rueda hasta el borde · pesado"); the engine derives every number (places, curves, durations, colours, loudness). The reference implementation is manim-saorín (command `mesa`), which renders on Tórculo's engine, a fork of ManimGX. Every film carries its soundtrack: voice, music cues, ambiences, a room and sound effects. These are instructions for an AI agent asked to write a pliego (and, if needed, check and render it). Follow them in order. The full specification is at the end of `llms-full.txt`. ## 1. The five rules that matter most 1. **No numbers.** Never write coordinates, durations, easing, colours in hex, font sizes or volumes. Say it in words; the engine computes the numbers. If you are about to write a number, there is a word for it (a manner, a distance, a shot size, an intensity). 2. **Closed vocabularies.** Every keyword comes from a fixed list (section 9). A word that is not in its list is an error, never a creative extension. Accents in keywords are optional (`ilustración` = `ilustracion`). 3. **Every film has a soundtrack**: `BANDA` (music folder), `EFECTOS` (effects folder), `MEZCLA`, and in each chapter or scene `MÚSICA`, `AMBIENTE`, `ESPACIO`, plus `sonido:` effects at the right moments. 4. **Texts that become pieces, and names that point to a text, go between Latin quotes «…»** (`pon: cartulina «CARTA»`, `marca: rodea «CARTA»`, `al decir «palabra»`), never straight quotes. Free text after `di:`, a speaker, `letrero (…):`, `terminal:` and the colophon goes without quotes. Free text can say anything; only keywords come from the lists. The field separator is the middle dot `·` (U+00B7) with spaces around it. 5. **Speakers must be declared** in `REPARTO` before they talk, and cannot be named with a reserved word (`nota`, `pie`, `el`, `la`, `di`, `ver`, `marca`…). ## 2. The smallest film: a servilleta A pliego without chapters is prose: every sentence becomes a clip, and the engine decides the shots and the pieces. Always start here. ```text MESA «La servilleta» BANDA sonido/banda EFECTOS sonido/efectos MEZCLA para la web · sin stems MÚSICA 1M1 AMBIENTE amb sala bucle Una mesa de trabajo, un pliego y una prensa. Lo que se escribe en el pliego se estampa en la película. Nada se dice en números: los números los pone el motor. ``` `BANDA` and `EFECTOS` are folders next to the pliego; names in the pliego are their file names without extension. To get a ready set of free sounds (CC0), run `python3 conformance/tools/sonido.py --salida ./sonido` from the Tórculo repository: it writes `banda/1M1.wav`, `banda/1M2.wav`, `banda/cortinilla.wav` and in `efectos/` `amb sala bucle`, `amb lluvia bucle`, `amb taller bucle`, `pagina`, `campanilla`, `sello`, `tijera`. Only use names that exist in those folders. ## 3. A directed film ```text MESA v2 «La prensa y el pliego» formato 16:9 · sala crema · tirada borrador BANDA sonido/banda EFECTOS sonido/efectos MEZCLA para la web · sin stems ARCO pregunta→respuesta MOTIVO «pliego» —empieza como papel en blanco y acaba siendo la película REPARTO Gutenberg: ultramar == CAPÍTULO 1 · EL TÓRCULO ============== tensión sube · tambor ultramar MÚSICA 1M1 AMBIENTE amb taller bucle ESPACIO estudio * apertura · contenido di: Un tórculo es una prensa de grabador. pon: rescate «EL TÓRCULO» * ilustración · nervioso di: La plancha se trabaja una vez y se estampa tantas veces como haga falta. al decir «estampa»: sonido: sello ver: pila —una plancha | cien estampas * prueba · seco di: Cien estampas, y todas iguales. terminal: estampas: 100 · diferencias: 0 marca: rodea «0» == CAPÍTULO 2 · LA PLANCHA ============== tensión cae · tambor verde MÚSICA 1M2 AMBIENTE amb sala bucle * tesis · solemne di: Lo que se escribe en el pliego no lleva números. pon: cartulina «SIN NÚMEROS» * remate · contenido di: Los números los pone el motor. al decir «motor»: sonido: campanilla > deja posar == FIN ==================== Estampado en Tórculo. > silencio 2 ``` - `== TITLE · tensión X · tambor Y ===` opens a chapter. `-- TITLE · hora --` opens a scene. - `* FUNCTION · AFFECT` opens a clip (a beat). FUNCTION is one of the eleven functions and AFFECT one of the eight affects of section 9, **and nothing else** (`tensa` is an intensity, not an affect; `respuesta` is not a function). A bare `*` also works and lets the engine choose. Instead of a function you may write a shot: `* primer contrapicado de ella · seco`, where `ella` is a name from `REPARTO` or a piece. - `di: TEXT` is the narration: its voice sets the beat's duration. A clip mixes freely narration, dialogue, pieces, movements, sounds and events. - `NAME: —TEXT` is dialogue by a declared speaker (the dash is part of the speech, attached to its first word, as in Spanish dialogue). - `al decir «word»: LINE` makes LINE happen when the voice says that word. Write the word as it is written in the `di:` text. - `> EVENT` lines are events (section 9). `> dura N` gives a beat without voice its length; it is the one place where a number is allowed in a clip, together with `> silencio N`. - `// comment` is ignored. Blank lines separate clips. ## 4. Putting things on the table ```text pon: cartulina «VOX POPULI» card; types: cartulina · dymo · rescate · sello · tira · texto · mano · apunte letrero (cita): La frase citada a sign; registers: cartulina · cita · cita máquina · cita moderna · mano · rescate ver: votos —sí: 7 · no: 4 a visualization; the body after the dash is data (numbers allowed here) terminal: mediana: 1207 libras typewriter line marca: subraya «1207» gesture on a text: rodea · señala · subraya · tacha arriba: Nature · 1907 caption above; also pie: and nota: foto: galton a photograph of the project's archive python: radio · grande a drawing of the project's bestiary (only if it exists) ``` Placement is by relation, never by coordinates: `junto a «X»: …`, `bajo «X»: …`, `delante de «X»: …`, `detrás de «X»: …`, `en las manos de ella: …`, `juntos: a · b · c —en fila`. Body parts: el hombro · el pecho · el regazo · la cabeza · la espalda · las manos · los pies. Arrangements: amontonados · como flores · en abanico · en columna · en corro · en fila · en fila holgados · en rejilla. ## 5. Movement A movement line is `[the] SUBJECT VERB [destination] · path · manner · grain`. It is recognized by the verb. The curve, anticipation, overshoot and timing come from the engine (Lasseter's principles). ```text la piedra rueda hasta el borde · por el suelo · pesado · a treses la carta salta hasta buzón · con anticipación la hoja vuela fuera de campo por la derecha · ligero la pluma flota hasta suelo · a la deriva · en dos ``` - Verbs: 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. - Verbs that act on another thing: agarra · alcanza · arrastra · cuelga · empuja · esquiva · huye · órbita · se apoya · sigue · suelta. - Paths: 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. - Manners: 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. - Grains: a doses · a pulso · a treses · a unos; register: `en dos`. After a `·` in a movement line only a path, manner, grain or `en dos` is valid: anything else (`· deprisa`) is an error. The subject must be a piece placed before (`pon: cartulina «PIEDRA»` creates `piedra`). ## 6. Sound design (always) Preamble: `BANDA folder`, `EFECTOS folder`, `MEZCLA para la web | para cine · con stems | sin stems`. In `REPARTO`, a voice and its side: `REPARTO ella: ultramar, cita_f, seca, a la izquierda`. Voices: cita · cita_f · cita_f2 · cita_f3 · cita_m2 · narrador; colour: `seca` or `con radio`. In a chapter or scene: `MÚSICA cue` (a file of `BANDA`; `MÚSICA ninguna` for none), `AMBIENTE a · b` (layers of files of `EFECTOS`, looped), `ESPACIO room` (estadio · estudio · patio · radio · seco). In a clip: `sonido: effect [a la izquierda | a la derecha | al centro]`, best anchored: `al decir «golpe»: sonido: sello`. Sound events: `> entra la música «1M2»`, `> 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`. The engine mixes in four buses (voices, music, effects, ambiences), keeps a cue playing while scenes repeat it, ducks music under the voice and masters to −14 LUFS for the web. ## 7. Cinema: scenes, axis, light, shots ```text -- LA CARRETERA · diurna -- EJE de él a ella LUZ de la izquierda · dura MUNDO avanza · de frente FONDO cielo · en el cielo FONDO arboleda · cerca * primer de él · contenido él: —¿Falta mucho? él mira a ella ``` - Shot sizes (ordered): general · conjunto · medio · americano · corto · primer · detalle. Heights: cenital · contrapicado · nadir · normal · picado. Fronts: escorzo · espalda · frontal · perfil · tres cuartos. - Light directions: cenital · de atras · de frente · de la derecha · de la izquierda; hardness `dura` or `blanda`. Hours: amanece · atardece · diurna · mediodía · nocturna. - Distances (ordered): al pie · al paso · cerca · a media distancia · lejos · al fondo · en el horizonte · en el cielo. - Continuity warnings (not errors): jumping the axis, jumping two shot sizes, eyelines, directions, states. Silence them on purpose with `> cruza el eje` or `> salta`. ## 8. The look, posters, the picture that listens, the camera ```text MATERIA papel khadi MATERIA risografía ultramar y rosa · desregistrada BOBINA truca FORMATO 4:3 RÍO TIPOGRÁFICO · en fila MONTAJE se acelera PALETA verde, morado y amarillo CARTEL columna a sangre a la izquierda · centro vacío LETRA «PRENSA» · en Anton · a sangre · de amarillo «PRENSA» se estampa INTENSIDAD de templada a encendida SOPORTE limpio CÁMARA gran angular · con masa HORIZONTE se inclina lejos: pon: cartulina «MONTE» el foco en MONTE ``` - Materials: acuarela · ninguna · papel · pincel · risografía · tejido · tinta; papers: cuaderno · escolar · grano fino · khadi · kraft · lienzo · satinado · tintado · torchón · verjurado · washi; film: noticiario · sin grano · truca; formats: `16:9`, `4:3`, `2,39:1`. - Transitions are events (`> pasa página`), written as the first line of the clip they open: chasquido · corta · corta en la acción · 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 página · se quema · sintoniza. - Posters: `PALETA A, B y C` names exactly three colours with commas and `y` (field, figure, accent): amarillo · arena · azul · blanco · celeste · crema · lila · minio · morado · naranja · negro · rojo · rosa · tinta · ultramar · verde. `CARTEL` takes compositions separated by `·`: 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. - Signs are pieces, and **clip lines**: `LETRA «WORD» · en TYPEFACE · arrangement · place · size · de COLOUR`. Typefaces: anton · la serifa de pretexto · league gothic · letra de mano · máquina de escribir · serifa. Arrangements: a sangre · en abanico · en columna · en escalera · girada · rota por el borde. Places: a la derecha · a la izquierda · abajo · arriba · en el centro. Sizes: `grande`, `enorme`, `gigante`. Then, in the same or a later clip: `«WORD» VERB` or `las letras de «WORD» VERB` with 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; `«WORD» es un ROLE` with barandilla · cielo · cuchilla · mascara · muro · persiana · porteria · suelo · ventana. - Intensities (0 to 10): nula · quieta · serena · templada · viva · agitada · tensa · encendida · desatada · furiosa · rota; `INTENSIDAD de templada a encendida` is a ramp across the scene. Supports: limpio · usado · gastado · sucio · roto. - Camera: `CÁMARA` takes a lens (gran angular · normal · ojo de pez · teleobjetivo), a weight (con masa · ligera · pesada), a hand (al hombro · en tripode) and a depth (poca profundidad · profundidad total), separated by `·`. - Breaking a rule on purpose needs its reason: `> sin leer porque «…»`. ## 9. Closed vocabularies you will use most - Affects: contenido · eufórico · exhausto · juguetón · nervioso · seco · sereno · solemne. - Functions: apertura · cartel · contrapunto · digresión · eco · giro · ilustración · prueba · remate · respiro · tesis. - Tensions: cae · mantiene · rompe · sube. Arcs: espiral · letania · pregunta→respuesta · ruina · tesis→antitesis→sintesis · viaje y vuelta. - Drums (colours for a cast or chapter): ámbar · bermellón · naranja · rosa · ultramar · verde · violeta. - Visualizations for `ver:`: alfiler · ancla · árbol · balanza · barras · brújula · bucle · cadena · caja · cancelación · ciclo · comparación · constelacion · convergencia · cuadrante · cuenta · curva · dado · diana · dispersión · distribución · dominó · ecuación · ejes · embudo · engranaje · escalera · espectro · espiral · flecha de proceso · fracción · globo · grieta · huella · interruptor · isla · jerarquía · laberinto · línea temporal · lista tachada · lupa · mapa · medidor · moneda · montón · multitud · onda · órbita · papeleta · péndulo · pila · ping pong · porcentaje · proceso · puente · recorrido · red · reloj · resta · semáforo · suma · telaraña · teorema · termómetro · títere · venn · versus · votos. - Common events: `> dura N`, `> deja posar`, `> congela`, `> barre`, `> queda`, `> respira`, `> silencio N`, `> capítulo «…»`, `> temblor`, `> zoom de golpe`, `> la cámara vuelve`, `> se moja`, `> florece`, the transitions above and the sound events of section 6. ## 10. Details that matter (answers to what agents asked) - **The format line**: `formato 16:9 · sala crema · tirada borrador`. `sala` is the paper (`crema`, the cream page; `pizarra`, a dark slate). `tirada` is the print run (`borrador` for drafts, `definitiva` for a final render with a fixed seed). Add `página desnuda` for a page without folio or stamp. - **Voices**: the narration (`di:`) is spoken by `narrador` unless you write `di (VOICE):`; you do not declare the narrator. Voices: `narrador` (male, warm), `cita` (male), `cita_m2` (male, soft), `cita_f`, `cita_f2`, `cita_f3` (female). In `REPARTO NAME: drum, voice, colour, side`, only the drum is required. - **Names**: any name declared in `REPARTO` (capitals or not, accents allowed) is valid unless it is a reserved word. The complete list of reserved words: 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. `él` and `ella` are valid names (with the accent); `el` and `la` are not. In `EJE de A a B` and `A mira a B`, A and B are names from `REPARTO`. - **Drums** after `tambor` (chapter) or in `REPARTO` must be from the drum list: ámbar · bermellón · naranja · rosa · ultramar · verde · violeta (accents optional: `ámbar` = `ambar`). Accents are optional in every keyword: `de atrás` = `de atras`. - **Pieces get their names from their text**: `pon: cartulina «HOGAZA»` creates the piece `hogaza` (lower case, accents kept); a movement line names it as `la hogaza`. - **Movement without destination** happens in place (`la hogaza salta · de golpe`); with one, use `hasta`: `la carta salta hasta buzón`. - **Order inside a clip** is the author's order, and it is respected. Write a transition as the first line after the clip header; anchor lines with `al decir «…»:` to place them in time. A clip may have only dialogue, only narration, or only pieces with `> dura N`. - **A movement without destination** keeps its path and manner after `·`: `la entrada cae · en espiral · ligero` is right. - **A sign and its verb** may share a clip (`LETRA «FIN» · …` then `«FIN» se estampa`); `CARTEL` and `PALETA` written in a clip apply to that clip only. - **Sound levels**: `MÚSICA`, `AMBIENTE` and `ESPACIO` can go in the preamble (the whole film), in a chapter or in a scene; the scene overrides the chapter, the chapter the preamble (a lower level replaces, it does not add). `MÚSICA ninguna` then `> entra la música «1M2»` is valid. `AMBIENTE` takes one or more layers separated by `·`. Rooms: `estadio` (a big echo), `patio` (an open courtyard), `estudio` (a dry studio), `radio` (a radio booth), `seco` (no room). - **Hours** of a scene: `diurna`, `nocturna`, `amanece`, `atardece`, `mediodía`: they tint the light, nothing else. - **The end**: `== FIN ==` is optional; the lines after it are a colophon shown at the end; `> silencio N` there is the final silence (without it the engine adds 3 seconds and warns). A `> silencio N` inside a clip is a pause in that beat. - **Length**: the duration comes from the voice. About 150 spoken words make a minute. - **Warnings are not errors**: `SALTO DE TALLA` (jumping from `general` to `primer`) or "más de 7 clips sin respiro" are advice. Put a `medio` between a `general` and a `primer`, or add `> salta` to say the jump is meant; add a clip with function `respiro` now and then. - **Where each line goes.** Lines in capitals (`MATERIA`, `BOBINA`, `FORMATO`, `PALETA`, `CARTEL`, `INTENSIDAD`, `CÁMARA`, `HORIZONTE`, `MÚSICA`, `AMBIENTE`, `ESPACIO`, `EJE`, `LUZ`, `MUNDO`, `FONDO`) are **unit lines**: they go in the preamble, a chapter or a scene, and `PALETA` and `CARTEL` also inside a clip for that shot only. Everything else (`di:`, dialogue, `pon:`, `ver:`, `marca:`, `LETRA`, `«X» se estampa`, movements, `sonido:`, `> events`) is a **clip line** and goes after a `*` header. A clip line in the preamble is not shown. - `MESA «Título»` and `MESA v2 «Título»` are both right; `v2` declares the language's epoch. The lower-case `formato` line is the preamble's properties; the capitalized `FORMATO` is a unit line that changes the aspect ratio of a scene. - **Numbers are allowed** only in: aspect ratios (`16:9`), `> dura N`, `> silencio N`, the data of `ver:` and `terminal:`, the `#TALLER` and `#MANO` sections, and file names of sounds (`1M1`). - **`ver:` data** is free text after the dash: `label: value · label: value`, or two sides with `|` (`ver: balanza —la voz del pueblo | los peritos`). The key before the dash must be from the `ver:` list. - **`marca:`** acts on a text that is on screen in that clip (a `pon:`, `terminal:` or `letrero` line). **`al decir «word»`** matches a word of that clip's `di:` or dialogue, ignoring case and accents. - **`REPARTO`** is only for characters who speak dialogue. Never declare the narrator. - In this file `a | b` means "one of"; never write `|` in a pliego except inside `ver:` data. - `tambor` (a risograph drum) is the accent colour of a chapter or a character; `tensión` says whether the chapter's energy rises (`sube`), holds (`mantiene`), falls (`cae`) or breaks (`rompe`); `ARCO` goes once in the preamble. The number of `=` after a chapter title is decoration. - `pon: texto «…»` is plain text on the page; `pon: cartulina «…»` a coloured card; `rescate` a ransom-note cut-out; `dymo` an embossed label; `sello` a stamp; `apunte` a typed note. ## 11. Check, then voice, then look, then render ```sh mesa lee pliego.mesa # check: errors (E…) and warnings (W…); fix every error mesa graba pliego.mesa # synthesize the voice locally and write pliego.tiempos.json mesa animatica pliego.mesa --motor gx --sonido # one frame per beat with real timing mesa toca pliego.mesa --motor gx --sonido -o film.mp4 mesa empaqueta pliego.mesa # the portable project: pliego.mesapack ``` (`mesa` is `python -m manim_saorin.formato.cli` of manim-saorín.) `mesa lee` gives each error with its line, why, the fix («¿quisiste decir…?») and an example; follow them. When in doubt, ask instead of guessing: `mesa explica "palabra o línea"` (what it is, where it goes, an example), `mesa chuleta` (the whole language on one page), `mesa bestiario pliego.mesa` (the pieces the pliego can see and **the actions each one has**). `mesa nuevo "Título"` starts a project with a commented template. Anything that looks like an instruction and is not one is an error, never silent text on screen (E023), and so are an anchor word the beat's voice never says (E025), an action the piece does not declare (E054) or a piece that acts without a REPARTO name (E024). Common errors: a word outside its list (E010 to E019), an ambiguous name (E020), a speaker named with a reserved word (E021), two shouts in a clip (E030), a sound name not in `BANDA` or `EFECTOS` (E040 to E042). Look at the animatic before rendering, and listen to the soundtrack report (`film.banda.json`): loudness near −14 LUFS, the cues you asked for. ## 12. Pieces (when the table needs a drawing) A bestiary (`PYTHON piezas.py` or `PIEZAS carpeta` in the preamble) adds named pieces, placed with `python: nombre` and moved like any other. Each piece has a **card**. As JSON (the portable form proposed in RFC 0005; a card is data, so numbers are fine there): ```json {"nivel": "marioneta", "nombre": "tetera", "titulo": "La tetera", "descripcion": "Una tetera de hierro esmaltado con tapa, asa y pitorro, que silba al hervir.", "alto": 2.4, "mira": "izquierda", "partes": ["cuerpo", "tapa", "asa", "pitorro"], "esenciales": {"objeto": "pitorro"}, "poses": ["reposo", "calienta", "silba"], "acciones": {"silba": ["calienta", "silba", "silba", "reposo"]}, "ciclos": {"hierve": ["calienta", "reposo"]}} ``` - `nivel`: `dibujo` (one drawing), `partes` (named parts), `marioneta` (parts with pivots, poses, actions, cycles) or `personaje` (a puppet plus five views, expressions and mouths). - `nombre`: ASCII without spaces; it is the seed and the word the pliego writes. - `descripcion`: what is seen, for someone who cannot see it (20 characters or more). - `alto`: natural height in scene units (the screen is 8 high). `mira`: `derecha`, `izquierda` or `frente`. - `partes`: the piece's own names for its parts. `esenciales` maps each essential (`cara`, `boca`, `cabeza`, `mano`, `objeto`) to the part that is it; a cut by the frame's edge never removes an essential part. An object declares at least `objeto`. - `poses`: names; `acciones`: action → list of poses; `ciclos`: cycle → list of poses that repeats. In the pliego, a declared character performs them: `TETERA silba` (the speaker or an `alias:` must name the piece). - Check pieces with `mesa pieza comprueba piezas.py` (it draws each piece and tells what is missing). - **Today a bestiary is code or a declarative file, not the JSON card**: a `.py` module whose functions draw the pieces (the card is a dict on each function, and pivots live in the drawing code), or `.personaje.toml` / `.marioneta.toml` files for characters and photo puppets. The JSON card above is the portable form being proposed; writing it is good practice, but `PIEZAS` loads `.py`, `.toml` or a folder of them. - **Acting with a piece**: give it a name in the cast with an alias to the piece, then use that name: `REPARTO BUZÓN: verde, alias: buzon` and later `BUZÓN abre` (an action the card declares). A speaker that is also a puppet (`REPARTO CARTERO: ultramar, cita, alias: cartero`) can move like any piece: `CARTERO camina hasta buzon · despacio`. - `python: nombre` places the piece where the composer decides; put a placement in front to choose (`junto a «CARTA»: python: buzon`). ## 13. Collage in motion and photo puppets Photos, cut-outs, real video, type and pen in one shot, all in words (render with `--motor gx`): ``` MESA «La noche del estreno» formato 16:9 · sala crema · silencio 3 PIEZAS piezas/ MARIONETA charlot · de la foto medios/chaplin.jpg · mira a la derecha REPARTO CHARLOT: minio, cita_m2, alias: charlot REPARTO TIJERAS: minio, alias: tijeras * apertura · juguetón a la izquierda: python: charlot · grande CHARLOT: —Buenas noches, respetable público. al decir «noches»: CHARLOT saluda * prueba · nervioso foto: medios/maquina.jpg · sin fondo · canto de tijera · sombra levantada · con cinta di: La máquina ya tenía la crítica escrita. * general · eufórico clip de fondo: medios/baile.mp4 de 0:00 a 0:05 di: En la pantalla del fondo, el baile. * giro · juguetón clip: medios/baile.mp4 de 0:02 a 0:07 · sin fondo delante: python: tijeras di: Y la bailarina, recortada, sale de la pantalla y las tijeras cortan. al decir «cortan»: TIJERAS corta ``` - `foto: x.jpg · sin fondo` cuts the figure out; then the edge (`canto de tijera | de troquel | rasgado | limpio`), shadow (`sombra pegada | levantada | sin sombra`) and fastening (`con cinta | con celo | con chincheta`). `recorte:` is already without background. - `clip: x.mp4 de 0:02 a 0:07 · sin fondo` is a cut-out film, on twos (`en uno`, `en cuatro` to change). `clip de fondo:` fills the frame and leaves when its range ends. - `MARIONETA name · de la foto x.jpg` makes a Terry Gilliam puppet from a photo (the jaw opens with the voice). Every photo puppet knows `saluda`, `celebra`, `señala`, `baila`, `se inclina`, `duda`, `grita`, `aplaude`, `en jarras`, and the cycles `anda`, `corre`; `.marioneta.toml` cards add their own. A half-length photo has no arms to wave. - A piece that acts needs a REPARTO name whose alias is the piece, even if it never speaks (`REPARTO TIJERAS: minio, alias: tijeras`), and must be on the table already (in that beat, on an earlier line, or in an earlier beat). The colour of a REPARTO line is a drum (section 9) or an ink of the poster palette (`minio`, `tinta`, `azul`, `rojo`, `celeste`, `crema`…). - A `clip de fondo` sits behind the pieces already on the table; the beat lasts at least its range (if the voice is shorter, the beat grows: warning W123). Several lines may share the same anchor (`al decir «cortan»: sonido: tijera` and `al decir «cortan»: TIJERAS corta`). - `FONDO cielo · en el cielo` works without a bestiary: the house sets are `cielo`, `sierra`, `agua`, `arcada`, `celosia`, `ciudad`, `farola`, `lluvia`, `arboleda`, `cuarto`, `luna`. - Placement prefixes: `a la izquierda:` · `a la derecha:` · `al fondo:` · `delante:` · `lejos:` · `cerca:` · `en el cielo:` · `junto a «X»:` · `bajo «X»:`. No prefix means the composer chooses (there is no `en el centro:` prefix; `en el centro` is valid only inside a `LETRA` line). ## Optional - [Everything in one file: this guide, the ten-minute guide, the cheat sheet and the specification in English and Spanish](https://torculo.joseluissaorin.com/llms-full.txt) - [Specification (English, normative)](https://torculo.joseluissaorin.com/en/spec) - [Especificación (traducción española)](https://torculo.joseluissaorin.com/especificacion) - [Diez minutos con Tórculo](https://torculo.joseluissaorin.com/diez-minutos.md) · [Ten minutes with Tórculo](https://torculo.joseluissaorin.com/en/ten-minutes.md) - [La chuleta](https://torculo.joseluissaorin.com/chuleta.md) · [The cheat sheet](https://torculo.joseluissaorin.com/en/cheat-sheet.md) - [Conformance suite](https://torculo.joseluissaorin.com/conformidad) - Repository: https://github.com/joseluissaorin/torculo (private for now) # ===== Diez minutos con Tórculo ===== URL: https://torculo.joseluissaorin.com/diez-minutos.md # Diez minutos con Tórculo Al final de esta guía tendrás un vídeo de un minuto con voz, música, ambiente y efectos, escrito en un pliego que se lee como la película. Necesitas la implementación de referencia (manim-saorín, con su orden `mesa`), el motor de Tórculo para `--motor gx` y este repositorio. En el Mac de la casa: `mesa` es `/opt/homebrew/Cellar/manim/0.20.1/libexec/bin/python -m manim_saorin.formato.cli`, y todo lo pesado va delante de `~/Developer/torculo/tools/pesado`. ## Minuto 1: la carpeta y su sonido ```sh mkdir -p ~/peliculas/faro && cd ~/peliculas/faro # fuera de Dropbox python3 ~/Developer/torculo/conformance/tools/sonido.py --salida sonido ``` `sonido/banda/` tiene tres cues (`1M1`, `1M2`, `cortinilla`) y `sonido/efectos/` tres ambientes (`amb sala bucle`, `amb lluvia bucle`, `amb taller bucle`) y cuatro efectos (`pagina`, `campanilla`, `sello`, `tijera`), todos sintetizados y libres (CC0). Cambiarlos por los tuyos es dejar otros ficheros en esas carpetas. ## Minuto 2: la servilleta Escribe `faro.mesa`, solo prosa y su banda: ```text MESA «El faro» BANDA sonido/banda EFECTOS sonido/efectos MEZCLA para la web · sin stems MÚSICA 1M2 AMBIENTE amb lluvia bucle Cada noche, el farero subía los ciento doce escalones de la torre. Nadie le había pedido que lo hiciera. Aun así, encendía la luz. ``` ```sh mesa lee faro.mesa # «LIMPIO»: ya es un pliego ``` Cada frase es un clip; el motor elige el plano y la pieza. Esto ya se puede rodar. ## Minutos 3 a 5: dirigir Parte la prosa en un capítulo y en clips, con una función y un afecto cada uno, y pon cosas sobre la mesa: ```text MESA «El faro» formato 16:9 · sala crema · tirada borrador BANDA sonido/banda EFECTOS sonido/efectos MEZCLA para la web · sin stems REPARTO MARTA: ultramar, cita_f, seca, a la izquierda == CAPÍTULO 1 · LA TORRE ============== tensión sube · tambor ultramar MÚSICA 1M2 AMBIENTE amb lluvia bucle ESPACIO patio * apertura · sereno di: Cada noche, el farero subía los ciento doce escalones de la torre. pon: rescate «EL FARO» * ilustración · nervioso MARTA: —¿Por qué nunca se cansa? pon: cartulina «ESCALÓN» el escalón sube hasta el borde · despacio al decir «cansa»: sonido: campanilla * remate · solemne di: Aun así, encendía la luz. pon: sello «LUZ» al decir «luz»: sonido: sello > deja posar == FIN === > silencio 2 ``` `mesa lee` te dice cada error con lo más parecido que sí vale («¿quisiste decir…?»). Si te ves escribiendo una cifra, busca la palabra: una manera (`despacio`), una lejanía (`lejos`), una talla (`primer`), una intensidad (`tensa`). ## Minutos 6 y 7: la voz ```sh tools/pesado mesa graba faro.mesa # Supertonic en local; escribe faro.tiempos.json ``` El sidecar guarda cuánto dura cada beat y cuándo se dice cada palabra: de ahí salen los `al decir`. Es una entrada del vídeo como el pliego mismo. ## Minuto 8: mirar antes de rodar ```sh tools/pesado mesa animatica faro.mesa --motor gx --sonido ``` Un fotograma por beat con los tiempos y el sonido de verdad. Mira que cada cosa llega cuando se dice y que nada tapa a nada. Las cosas se arreglan aquí, no en el render. ## Minuto 9: rodar ```sh tools/pesado mesa toca faro.mesa --motor gx --sonido -o /tmp/faro.mp4 ``` Junto al vídeo quedan el máster (`/tmp/faro.master.wav`) y el informe de la banda (`/tmp/faro.banda.json`): la sonoridad tiene que andar por −14 LUFS y los cues tienen que ser los que pediste. ## Minuto 10: llevártelo ```sh mesa empaqueta faro.mesa # faro.mesapack: pliego, voz, sonido y manifiesto mesa desempaqueta faro.mesapack /otra/carpeta ``` El paquete guarda las rutas relativas y el hash de cada fichero: en otra máquina sale el mismo vídeo. ## Y después - La [chuleta](chuleta.md): toda la lengua en una página. - Las capas siguientes: la escena (`EJE`, `LUZ`, planos de cine), el movimiento con sus maneras, el aspecto (`MATERIA`, `BOBINA`, `FORMATO`, transiciones, río tipográfico), el cartel (`PALETA`, `LETRA`), la imagen que oye (`INTENSIDAD`, `SOPORTE`) y la cámara (`CÁMARA`, lentes, profundidad). - La [especificación](../spec/SPEC.es.md), cuando quieras saber por qué. # ===== La chuleta ===== URL: https://torculo.joseluissaorin.com/chuleta.md # La chuleta de Tórculo Una página para escribir pliegos `.mesa` sin abrir la especificación. **La ley: el pliego dice cuentas humanas y maneras; los números los pone el motor.** Toda palabra clave sale de una lista cerrada; las tildes de las palabras clave son opcionales. El texto que sale en pantalla va entre «», el separador es `·` y todo pliego lleva su banda sonora. ## Esqueleto ```text MESA «Título» formato 16:9 · sala crema · tirada borrador BANDA sonido/banda EFECTOS sonido/efectos MEZCLA para la web · sin stems REPARTO ella: ultramar, cita_f, seca, a la izquierda == CAPÍTULO 1 · NOMBRE ======= tensión sube · tambor ultramar MÚSICA 1M1 AMBIENTE amb sala bucle ESPACIO estudio -- ESCENA · diurna -- EJE de él a ella LUZ de la izquierda · dura * función · afecto (o un plano: * primer contrapicado de ella · seco) di: La narración, que da la duración del beat. ella: —El diálogo de un personaje declarado. al decir «palabra»: sonido: sello == FIN === > silencio 2 ``` ## Líneas de clip | Para | Escribe | |---|---| | narrar | `di: texto` · `di (cita_f): texto` | | hablar | `ella: —texto` (declarada en `REPARTO`) | | poner | `pon: cartulina «X»` · `pon: rescate «X»` · `pon: dymo «X»` · `pon: sello «X»` · `pon: apunte «X»` | | visualizar | `ver: clave —datos` (`ver: votos —sí: 7 · no: 4`) | | marcar | `marca: rodea «X»` (rodea · señala · subraya · tacha) | | rotular | `letrero (registro): texto` (cartulina · cita · cita máquina · cita moderna · mano · rescate) · `terminal: texto` · `arriba:` · `pie:` · `nota:` | | colocar | `junto a «X»: …` · `bajo «X»: …` · `delante de «X»: …` · `en los pies de él: …` · `juntos: a · b —en fila` | | mover | `la piedra rueda hasta el borde · por el suelo · pesado · a treses` | | anclar a la voz | `al decir «palabra»: LÍNEA` · `LÍNEA hasta decir «palabra»` · `mientras: LÍNEA` | | cámara de mesa | `la truca se acerca a ella` · `ella mira a él` · `él sale por la izquierda` · `el foco en ella` | | sonar | `sonido: efecto [a la izquierda]` · `> entra la música «1M2»` · `> silencio de verdad` | | un evento | `> deja posar` · `> dura 4` · `> pasa página` · `> temblor` · `> congela` | | pegar una foto | `foto: x.jpg · sin fondo · canto de tijera · sombra levantada · con cinta` | | recortar un vídeo | `clip: x.mp4 de 0:02 a 0:07 · sin fondo` (en dos) · `clip de fondo: x.mp4 de 0:00 a 0:05` | | una marioneta de foto | `MARIONETA charlot · de la foto x.jpg` (preámbulo) · `python: charlot` · `CHARLOT saluda` | | que una pieza actúe | `REPARTO TIJERAS: minio, alias: tijeras` · `al decir «corta»: TIJERAS corta` | **Cuando dudes, pregunta:** `mesa explica "línea"` · `mesa chuleta` · `mesa bestiario pliego.mesa` (las piezas y sus acciones). Lo que parece una orden y no lo es, `mesa lee` lo da por error. ## Vocabularios | | | |---|---| | afectos | contenido · eufórico · exhausto · juguetón · nervioso · seco · sereno · solemne | | funciones | apertura · cartel · contrapunto · digresión · eco · giro · ilustración · prueba · remate · respiro · tesis | | tensiones · arcos | cae · mantiene · rompe · sube · espiral · letania · pregunta→respuesta · ruina · tesis→antitesis→sintesis · viaje y vuelta | | tallas (con orden) | general · conjunto · medio · americano · corto · primer · detalle | | alturas · frentes | cenital · contrapicado · nadir · normal · picado · escorzo · espalda · frontal · perfil · tres cuartos | | verbos de movimiento | 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 | | relacionales | agarra · alcanza · arrastra · cuelga · empuja · esquiva · huye · órbita · se apoya · sigue · suelta | | 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 | | 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 | | granulados | a doses · a pulso · a treses · a unos (y `en dos`) | | lejanías | al pie · al paso · cerca · a media distancia · lejos · al fondo · en el horizonte · en el cielo | | tambores | ámbar · bermellón · naranja · rosa · ultramar · verde · violeta | | salas (`ESPACIO`) | estadio · estudio · patio · radio · seco | | mezcla | con stems · para cine · para la web · sin stems | | transiciones | chasquido · corta · corta en la acción · 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 página · se quema · sintoniza | | materias · papeles | acuarela · ninguna · papel · pincel · risografía · tejido · tinta · cuaderno · escolar · grano fino · khadi · kraft · lienzo · satinado · tintado · torchón · verjurado · washi | | bobinas | noticiario · sin grano · truca | | intensidades | nula · quieta · serena · templada · viva · agitada · tensa · encendida · desatada · furiosa · rota | | soportes | limpio · usado · gastado · sucio · roto | | lentes | gran angular · normal · ojo de pez · teleobjetivo | ## Lo que el pliego NO dice Curvas, easing, fotogramas clave, coordenadas sueltas, duraciones en el dialecto pobre, colores en hexadecimal, sombra o velocidad de una pieza suelta, piezas sin nombre, dos sitios para la misma decisión. ## El bucle `mesa lee` (arregla cada error) → `mesa graba` (la voz) → `mesa animatica --motor gx --sonido` (mirar) → `mesa toca --motor gx --sonido -o x.mp4` → `mesa empaqueta`. # ===== Ten minutes with Tórculo ===== URL: https://torculo.joseluissaorin.com/diez-minutos.en.md # Ten minutes with Tórculo By the end of this guide you will have a one-minute film with voice, music, ambience and effects, written in a pliego that reads like the film. You need the reference implementation (manim-saorín, with its `mesa` command), Tórculo's engine for `--motor gx`, and this repository. The language's keywords are Spanish; the comments here explain them. ## Minute 1: the folder and its sound ```sh mkdir -p ~/films/faro && cd ~/films/faro python3 ~/Developer/torculo/conformance/tools/sonido.py --salida sonido ``` `sonido/banda/` has three cues (`1M1`, `1M2`, `cortinilla`) and `sonido/efectos/` three ambiences (`amb sala bucle`, `amb lluvia bucle`, `amb taller bucle`) and four effects (`pagina`, `campanilla`, `sello`, `tijera`), all synthesized and free (CC0). To use your own, put other files in those folders. ## Minute 2: the servilleta Write `faro.mesa` ("the lighthouse"), only prose and its soundtrack: ```text MESA «El faro» BANDA sonido/banda EFECTOS sonido/efectos MEZCLA para la web · sin stems MÚSICA 1M2 AMBIENTE amb lluvia bucle Cada noche, el farero subía los ciento doce escalones de la torre. Nadie le había pedido que lo hiciera. Aun así, encendía la luz. ``` ```sh mesa lee faro.mesa # "LIMPIO": it is already a pliego ``` Every sentence is a clip; the engine chooses the shot and the piece. This can already be rendered. ## Minutes 3 to 5: directing Split the prose into a chapter and clips, each with a function and an affect, and put things on the table: ```text MESA «El faro» formato 16:9 · sala crema · tirada borrador BANDA sonido/banda EFECTOS sonido/efectos MEZCLA para la web · sin stems REPARTO MARTA: ultramar, cita_f, seca, a la izquierda == CAPÍTULO 1 · LA TORRE ============== tensión sube · tambor ultramar MÚSICA 1M2 AMBIENTE amb lluvia bucle ESPACIO patio * apertura · sereno di: Cada noche, el farero subía los ciento doce escalones de la torre. pon: rescate «EL FARO» * ilustración · nervioso MARTA: —¿Por qué nunca se cansa? pon: cartulina «ESCALÓN» el escalón sube hasta el borde · despacio al decir «cansa»: sonido: campanilla * remate · solemne di: Aun así, encendía la luz. pon: sello «LUZ» al decir «luz»: sonido: sello > deja posar == FIN === > silencio 2 ``` `mesa lee` reports each error with the closest valid words. If you find yourself writing a figure, look for the word instead: a manner (`despacio`, slowly), a distance (`lejos`, far), a shot size (`primer`, close-up), an intensity (`tensa`, tense). ## Minutes 6 and 7: the voice ```sh tools/pesado mesa graba faro.mesa # local Supertonic; writes faro.tiempos.json ``` The sidecar keeps how long each beat lasts and when each word is said: `al decir` ("when saying") anchors come from it. It is an input of the film like the pliego itself. ## Minute 8: look before rendering ```sh tools/pesado mesa animatica faro.mesa --motor gx --sonido ``` One frame per beat with the real timing and sound. Check that each thing arrives when it is said and that nothing covers anything else. Fix things here, not in the render. ## Minute 9: render ```sh tools/pesado mesa toca faro.mesa --motor gx --sonido -o /tmp/faro.mp4 ``` Beside the video you get the master (`/tmp/faro.master.wav`) and the soundtrack report (`/tmp/faro.banda.json`): loudness should be around −14 LUFS and the cues those you asked for. ## Minute 10: take it with you ```sh mesa empaqueta faro.mesa # faro.mesapack: pliego, voice, sound and manifest mesa desempaqueta faro.mesapack /another/folder ``` The package keeps relative paths and the hash of every file: on another machine the same film comes out. ## Next - The [cheat sheet](chuleta.en.md): the whole language on one page. - The next layers: the scene (`EJE`, `LUZ`, film shots), movement and its manners, the look (`MATERIA`, `BOBINA`, `FORMATO`, transitions, the typographic river), the poster (`PALETA`, `LETRA`), the picture that listens (`INTENSIDAD`, `SOPORTE`) and the camera (`CÁMARA`, lenses, depth). - The [specification](../spec/SPEC.md), when you want to know why. # ===== The cheat sheet ===== URL: https://torculo.joseluissaorin.com/chuleta.en.md # The Tórculo cheat sheet One page to write `.mesa` pliegos without opening the specification. **The law: the pliego says human counts and manners; the engine sets the numbers.** Every keyword comes from a closed list; accents in keywords are optional. Text that goes on screen is between «», the separator is `·`, and every pliego carries its soundtrack. Keywords are Spanish. ## Skeleton ```text MESA «Título» formato 16:9 · sala crema · tirada borrador BANDA sonido/banda EFECTOS sonido/efectos MEZCLA para la web · sin stems REPARTO ella: ultramar, cita_f, seca, a la izquierda == CAPÍTULO 1 · NOMBRE ======= tensión sube · tambor ultramar MÚSICA 1M1 AMBIENTE amb sala bucle ESPACIO estudio -- ESCENA · diurna -- EJE de él a ella LUZ de la izquierda · dura * función · afecto (or a shot: * primer contrapicado de ella · seco) di: The narration, which sets the beat's duration. ella: —Dialogue by a declared character. al decir «palabra»: sonido: sello == FIN === > silencio 2 ``` ## Clip lines | To | Write | |---|---| | narrate | `di: text` · `di (cita_f): text` | | speak | `ella: —text` (declared in `REPARTO`) | | place | `pon: cartulina «X»` · `pon: rescate «X»` · `pon: dymo «X»` · `pon: sello «X»` · `pon: apunte «X»` | | visualize | `ver: key —data` (`ver: votos —sí: 7 · no: 4`) | | mark | `marca: rodea «X»` (rodea · señala · subraya · tacha) | | caption | `letrero (register): text` (cartulina · cita · cita máquina · cita moderna · mano · rescate) · `terminal: text` · `arriba:` · `pie:` · `nota:` | | place relative | `junto a «X»: …` · `bajo «X»: …` · `delante de «X»: …` · `en los pies de él: …` · `juntos: a · b —en fila` | | move | `la piedra rueda hasta el borde · por el suelo · pesado · a treses` | | anchor to the voice | `al decir «word»: LINE` · `LINE hasta decir «word»` · `mientras: LINE` | | table camera | `la truca se acerca a ella` · `ella mira a él` · `él sale por la izquierda` · `el foco en ella` | | sound | `sonido: effect [a la izquierda]` · `> entra la música «1M2»` · `> silencio de verdad` | | an event | `> deja posar` · `> dura 4` · `> pasa página` · `> temblor` · `> congela` | | paste a photo | `foto: x.jpg · sin fondo · canto de tijera · sombra levantada · con cinta` | | cut out a video | `clip: x.mp4 de 0:02 a 0:07 · sin fondo` (on twos) · `clip de fondo: x.mp4 de 0:00 a 0:05` | | a photo puppet | `MARIONETA charlot · de la foto x.jpg` (preamble) · `python: charlot` · `CHARLOT saluda` | | make a piece act | `REPARTO TIJERAS: minio, alias: tijeras` · `al decir «corta»: TIJERAS corta` | **When in doubt, ask:** `mesa explica "line"` · `mesa chuleta` · `mesa bestiario pliego.mesa` (the pieces and their actions). Whatever looks like an instruction and is not one is an error in `mesa lee`. ## Vocabularies | | | |---|---| | affects | contenido · eufórico · exhausto · juguetón · nervioso · seco · sereno · solemne | | functions | apertura · cartel · contrapunto · digresión · eco · giro · ilustración · prueba · remate · respiro · tesis | | tensions · arcs | cae · mantiene · rompe · sube · espiral · letania · pregunta→respuesta · ruina · tesis→antitesis→sintesis · viaje y vuelta | | shot sizes (ordered) | general · conjunto · medio · americano · corto · primer · detalle | | heights · fronts | cenital · contrapicado · nadir · normal · picado · escorzo · espalda · frontal · perfil · tres cuartos | | movement verbs | 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 | | relational verbs | agarra · alcanza · arrastra · cuelga · empuja · esquiva · huye · órbita · se apoya · sigue · suelta | | paths | 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 | | manners | 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 | | grains | a doses · a pulso · a treses · a unos (and `en dos`) | | distances | al pie · al paso · cerca · a media distancia · lejos · al fondo · en el horizonte · en el cielo | | drums | ámbar · bermellón · naranja · rosa · ultramar · verde · violeta | | rooms (`ESPACIO`) | estadio · estudio · patio · radio · seco | | mix | con stems · para cine · para la web · sin stems | | transitions | chasquido · corta · corta en la acción · 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 página · se quema · sintoniza | | materials · papers | acuarela · ninguna · papel · pincel · risografía · tejido · tinta · cuaderno · escolar · grano fino · khadi · kraft · lienzo · satinado · tintado · torchón · verjurado · washi | | film stocks | noticiario · sin grano · truca | | intensities | nula · quieta · serena · templada · viva · agitada · tensa · encendida · desatada · furiosa · rota | | supports | limpio · usado · gastado · sucio · roto | | lenses | gran angular · normal · ojo de pez · teleobjetivo | ## What a pliego does NOT say Curves, easing, keyframes, loose coordinates, durations in the plain dialect, hex colours, the shadow or speed of a single piece, unnamed pieces, two places for the same decision. ## The loop `mesa lee` (fix every error) → `mesa graba` (the voice) → `mesa animatica --motor gx --sonido` (look) → `mesa toca --motor gx --sonido -o x.mp4` → `mesa empaqueta`. # ===== SPECIFICATION (English, normative) ===== URL: https://torculo.joseluissaorin.com/en/spec # Tórculo: a standard for films written as pliegos, version 1.0 - **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 (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** | `.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 (`.master.wav`), the stems in `.stems/` and a report in `.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 `.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 `.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/-.png colour atlas of a layer in a pose capas/--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`: the input, **linear light, premultiplied**, half floats | | `@group(0) @binding(1)` | `muestreo` | `sampler`: bilinear, clamped to the edges | | `@group(0) @binding(2)` | `plano` | `var Plano` | | `@group(0) @binding(3)` | `salida` | `texture_storage_2d`: 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, // 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`) | | `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: `` 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. ### 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 ## Appendix B. Grammar {#appendix-b} The complete grammar is `spec/gramatica/mesa.ebnf`, normative, reproduced here. ```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 } ; ``` ## Appendix C. Diagnostic codes {#appendix-c} Codes of the pliego language (`spec/diagnosticos.json`): | 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 | 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. # ===== ESPECIFICACIÓN (traducción española) ===== URL: https://torculo.joseluissaorin.com/especificacion # Tórculo: un estándar para películas escritas como pliegos, versión 1.0 - **Estado:** Borrador de trabajo, 2026-10-15. Lo bastante estable para implementarlo; los cambios pasan por el proceso de RFC (`spec/rfcs/`). La batería de conformidad de `conformance/` forma parte de esta especificación. - **Editor:** José Luis Saorín Ferrer. - **Esta versión:** `spec/SPEC.md` en (privado hasta que pasen la especificación, la batería de conformidad y las implementaciones de referencia). - **Traducción:** traducción española fiel de [`SPEC.md`](SPEC.md); si discrepan, manda el inglés. - **Licencia:** esta especificación se publica bajo [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/). El código del repositorio es MIT OR Apache-2.0. Quienes contribuyen se comprometen a no hacer valer patentes contra las implementaciones. ## Resumen Tórculo es un estándar abierto para hacer películas, vídeos explicativos, cortos de animación e ilustraciones en movimiento a partir de un texto que se lee como la película. Ese texto es un **pliego**, un fichero `.mesa` escrito en la **lengua de Tórculo**: un guion orientado a líneas, en español, con vocabularios cerrados, en el que el autor dice *qué pasa y cómo* («la piedra rueda hasta el borde, pesada») y el motor deriva todos los números (posiciones, curvas, duraciones, colores, sonoridad). El estándar tiene siete partes: la lengua de pliegos, el proyecto portable (`.mesapack`) con su sidecar de voz, las piezas (dibujos, marionetas, personajes y collage), el **canon** de la casa (paleta y azar determinista, con vectores de prueba en tres lenguajes), las **láminas** (dibujos a mano revelados por un atlas de tiempo), las **materias** (la convención de pasadas WGSL para papel, acuarela, risografía y transiciones) y las **tomas** (la salida grabada del motor, un fork de ManimGX, con su API pública). Todas las partes son deterministas: las mismas entradas dan la misma película. ## Estado de este documento Esta es la primera versión pública del estándar. Su parte de la lengua absorbe y reorganiza `SPEC-MESA-2.md` de manim-saorín (el documento de trabajo de la implementación de referencia, época 2 de la lengua); las demás partes formalizan documentos que ya existían (`pluma/LAMINA.md`, `materias/README.md`, `FORK.md`, `SPEC-PIEZAS.md`). Cuando este texto y un caso de conformidad discrepan, la discrepancia es un fallo que se resuelve por el proceso de RFC; mientras no se resuelva, las implementaciones siguen el caso de conformidad. Las desviaciones conocidas de la implementación de referencia respecto de este texto se enumeran en el apéndice D y figuran como casos pendientes en la batería. ## Índice - [Prefacio](#preface) - [1. Convenciones y terminología](#terminology) - [2. Arquitectura y conformidad](#architecture) - Parte 1. La lengua de pliegos - [3. Principios](#principles) - [4. Estructura léxica](#lexical) - [5. Gramática](#grammar) - [6. Vocabularios cerrados](#vocabularies) - [7. Semántica](#semantics) - [8. Perfiles](#profiles) - [9. Extensión por capas](#extension) - [10. La representación intermedia](#ir) - [11. Invariantes](#invariants) - [12. Diagnósticos](#diagnostics) - [13. Herramientas y huellas](#tools) - Parte 2. [14. El proyecto portable](#mesapack) - Parte 3. [15. Piezas](#pieces) - Parte 4. [16. El canon](#canon) - Parte 5. [17. Láminas](#laminas) - Parte 6. [18. Materias: la convención de pasadas](#materias) - Parte 7. [19. Tomas y la API pública](#takes) - [20. Consideraciones de seguridad](#security) - [21. Consideraciones de privacidad](#privacy) - [22. Versiones y compatibilidad](#versioning) - [23. Tipos de medio e identificación de ficheros](#media-types) - [24. Internacionalización](#i18n) - [Apéndice A. Vocabularios cerrados](#appendix-a) - [Apéndice B. Gramática](#appendix-b) - [Apéndice C. Códigos de diagnóstico](#appendix-c) - [Apéndice D. Desviaciones conocidas de la implementación de referencia](#appendix-d) - [Apéndice E. Referencias](#appendix-e) - [Apéndice F. Perfiles en desarrollo (informativo)](#appendix-f) ## Prefacio {#preface} Un *tórculo* es la prensa del grabador. La plancha se trabaja una vez y se estampa tantas veces como haga falta. En este estándar la plancha es un pliego, un dibujo o una materia, y las estampas son un vídeo, una página web, una app o un juego. La *mesa* es la mesa de trabajo donde se dispone el pliego (la hoja que pasa por la prensa): por eso los pliegos conservan la extensión `.mesa`. La lengua nació dentro de manim-saorín, una biblioteca de collage en movimiento sobre Manim, para vídeo-ensayos con aspecto de cuaderno: papel, tinta que hierve, recortes con cinta, tambores de risografía. Su primera época (`SPEC-MESA.md`) creció como un registro de cambios; la segunda (`SPEC-MESA-2.md`, 2026-08) la hizo formal; el cortometraje *Radiointermisión* (2026-10) le enseñó carteles, cámaras, sonido y una imagen que escucha. En paralelo, Scholaris dio a la casa su pluma de dibujo a mano y su papel crema, y un fork de ManimGX (un motor en Rust y wgpu con la API de Python de Manim) se convirtió en el motor común: una película escrita en un pliego que tardaba unas tres horas y tres cuartos en renderizarse con Cairo se renderiza en él en menos de ocho minutos. Tórculo es el nombre de ese conjunto: la lengua, los formatos que la rodean y el motor con que se imprimen. La lengua es española por diseño. Sus palabras clave son palabras españolas que se leen como español (`la piedra rueda hasta el borde · pesado`), las tildes distinguen palabras donde el español lo necesita (`él` es un personaje, `el` un artículo), y las derivaciones del motor codifican un oficio (los principios de animación de Lasseter, el montaje de continuidad, la imprenta) en lugar de parámetros. Esta especificación está escrita en inglés para que cualquiera pueda implementarla; cada palabra clave se cita tal como se escribe en un pliego. ## 1. Convenciones y terminología {#terminology} Las palabras clave DEBE (MUST), NO DEBE (MUST NOT), OBLIGATORIO (REQUIRED), DEBERÁ (SHALL), NO DEBERÁ (SHALL NOT), DEBERÍA (SHOULD), NO DEBERÍA (SHOULD NOT), RECOMENDADO (RECOMMENDED), PUEDE (MAY) y OPCIONAL (OPTIONAL) se interpretan como se describe en BCP 14 (RFC 2119 y RFC 8174) cuando, y solo cuando, aparecen en mayúsculas. En esta traducción cada una sustituye a la palabra inglesa indicada entre paréntesis, con su mismo alcance; sus formas de plural (DEBEN, PUEDEN, DEBERÍAN…) tienen el mismo valor. ### 1.1 Términos | Término | Significado | |---|---| | **pliego** | Un fichero `.mesa`: un guion en la lengua de Tórculo. | | **servilleta** | Un pliego sin ninguna cabecera de capítulo (`==`): prosa llana (§5.12). | | **capítulo** (*chapter*) | Una unidad de página y de render, abierta por `==`. Los capítulos PUEDEN renderizarse en paralelo. | | **escena** (*scene*) | Una unidad de mundo dentro de un capítulo, abierta por `--`; el mundo persiste entre sus planos. | | **clip** o **beat** | Una unidad de tiempo (un plano), abierta por `*`. | | **línea** (*line*) | Una unidad de acción dentro de un clip. | | **pieza** (*piece*) | Todo lo que se pone en la mesa: una cartulina, una etiqueta, un dibujo, una marioneta, una fotografía, un letrero. | | **bestiario** (*bestiary*) | El catálogo de piezas con nombre del proyecto (`PYTHON`, `PIEZAS`). | | **compilador** | Un programa que analiza un pliego, lo comprueba (§12) y produce su IR (§10). | | **intérprete** | Un programa que convierte un IR en fotogramas y sonido. La referencia tiene dos: `ce` (Manim Community Edition, Cairo) y `gx` (el motor de Tórculo). | | **IR** | La representación intermedia (*guion rico*), en JSON (§10). | | **sidecar** | `.tiempos.json`: las duraciones de la voz y los tiempos de cada palabra, y dónde están sus grabaciones (§14.3). | | **toma** (*take*) | Una grabación de una ejecución del motor como un flujo de mensajes (`.take`, §19). | | **lámina** | Un dibujo a mano con un atlas de tiempo, listo para que cualquier motor lo revele (§17). | | **materia** | Una pasada de cómputo sobre un plano (papel, acuarela, risografía…), en la convención de §18. | | **canon** | La única fuente de verdad de la casa: paleta, azar, números del oficio, pesos del foley (§16). | | **época** (*epoch*) | La versión de la lengua en que está escrito un pliego (§22). | ### 1.2 Notación Las producciones de la gramática usan el EBNF del apéndice B (`spec/gramatica/mesa.ebnf`): los nombres en mayúsculas son no terminales, `"literal"` es texto literal, `[ ]` opcional, `{ }` cero o más, `|` alternativa, `TEXT` el resto de la línea, `NL` un fin de línea, `QUOTE` un texto entre comillas latinas. Un no terminal en mayúsculas que la gramática no define es un **vocabulario cerrado** (§6, apéndice A); esa correspondencia es exhaustiva. En este documento las palabras clave se escriben con sus tildes, como se leen; la comparación se hace sobre la forma normalizada (§4.5). ### 1.3 JSON canónico Siempre que esta especificación calcula el hash de un JSON o lo compara, usa el esquema de canonicalización JSON de la RFC 8785 (JCS): claves de objeto ordenadas por unidades de código UTF-16, sin espacios en blanco, números en la forma más corta que se conserva en ida y vuelta en notación ECMAScript (`1.0` es `1`, `1e-7` es `1e-7`), cadenas en UTF-8 crudo que solo escapan `"`, `\` y de U+0000 a U+001F. La implementación de referencia es `conformance/tools/jcs.py`. ## 2. Arquitectura y conformidad {#architecture} ### 2.1 Las siete partes | Parte | Objeto normativo | Versión en Tórculo 1.0 | |---|---|---| | 1. Lengua de pliegos | el fichero `.mesa`, su compilación y su interpretación | época 2 | | 2. Proyecto portable | el paquete `.mesapack` y el sidecar de voz | `mesapack 1` | | 3. Piezas | el contrato de pieza (niveles, ficha, partes, marionetas, personajes) | 1 | | 4. Canon | paleta, azar, números del oficio y del foley | canon 1 | | 5. Láminas | el formato `.lamina` | 1 | | 6. Materias | la convención de pasadas WGSL | 1 | | 7. Tomas y API | el flujo `.take` del fork y las interfaces públicas del motor | `0x8000_0002` | Cada parte puede implementarse por separado. Un producto declara su conformidad con una parte y, cuando la parte define clases o perfiles, con esas clases y perfiles. ### 2.2 Clases de producto | Clase | Parte | Pasa los tipos de caso de la batería | |---|---|---| | **Compilador** | 1 | `vocabulario`, `lee`, `ir` (proyección normativa, §10.6), `cierre`, `espejo` | | **Intérprete**, por perfil | 1 | `huella` y `banda` para los pliegos de sus perfiles (§8) | | **Empaquetador** | 2 | `mesapack_referencia`; sus paquetes pasan `mesapack` | | **Lector de paquetes** | 2 | `mesapack` | | **Proveedor de piezas** | 3 | las comprobaciones de piezas de §15.6 | | **Implementación del canon** | 4 | `canon_azar` y `canon_paleta` para su lenguaje | | **Productor de láminas** | 5 | `lamina` (salida idéntica byte a byte) | | **Lector de láminas** | 5 | revela cada lámina de la batería como dice §17.5 | | **Anfitrión de pasadas** | 6 | ejecuta toda materia conforme; `materia` para el comprobador | | **Escritor / lector de tomas** | 7 | `toma` | ### 2.3 La conformidad en general Un producto conforme: 1. DEBE aceptar todo lo que esta especificación declara válido para su clase, y rechazar lo que declara inválido, con los códigos de diagnóstico del apéndice C donde haya un código definido; 2. NO DEBE extender un vocabulario cerrado en silencio (§6.1); 3. DEBE ser determinista en el sentido de §7.4 y §16.3; 4. DEBE pasar todos los casos no pendientes de su clase en la batería de conformidad de la misma versión (`conformance/manifest.json`); 5. DEBERÍA comunicar sus resultados en el formato de informe de `conformance/README.md`. A un compilador no se le exige renderizar: comprobar un pliego y producir su IR son operaciones conformes sin ningún motor gráfico. --- # Parte 1. La lengua de pliegos ## 3. Principios {#principles} Estos principios son normativos: deciden toda cuestión que este texto no zanja, y una RFC que rompa alguno DEBE decirlo y explicar por qué. 1. **La constitución anti-parámetro.** El pliego dice cuentas humanas y maneras; el motor pone los números. Un pliego no tiene easing, fotogramas clave, tiradores de Bézier, funciones de ritmo, colores hexadecimales, sombras por pieza ni duraciones sueltas en el dialecto pobre (§3.1). Ninguna capacidad nueva entra en la lengua si obliga a los pliegos a decir números que antes se derivaban. 2. **Vocabularios cerrados.** La constitución solo se sostiene porque todo vocabulario es cerrado, y los vocabularios cerrados solo son tolerables porque el motor deriva. Una palabra fuera de su lista es un error, nunca una extensión silenciosa. 3. **Cierre.** Escribir lo que el motor decidió no cambia la película (§11.1). 4. **La identidad es la semilla.** Todo lo aleatorio se siembra a partir de la identidad de lo que afecta, calculada a partir del contenido, nunca de la posición, el proceso, el reloj ni el sistema de archivos (§7.4). 5. **Lo que no cabe en la hoja no se lee.** Un texto que no puede leerse en el tiempo que está en pantalla es un defecto (§12, la revisión de Lasseter). 6. **La lejanía manda.** La velocidad, el color y la profundidad de cada capa se derivan de su distancia (*lejanía*) y de nada más, con una excepción declarada (§7.7). 7. **Los tres asientos.** Una capacidad que no está en la gramática, el compilador y el intérprete no existe. Una directiva que conociera el vocabulario pero no el analizador se imprimiría en pantalla como narración, que es el peor fallo del sistema; por eso todo no terminal tiene su tabla (§6) y todo evento declara si está vivo o reservado (§6.3). 8. **La ley de autoridad.** La documentación se enumera desde el analizador, no desde la memoria. Los vocabularios del apéndice A se extraen del analizador de referencia (`spec/vocabularios/extrae.py`) y la batería comprueba que coinciden (`vocabulario`). ### 3.1 Los dos dialectos | Dialecto | Quién lo escribe | Números | |---|---|---| | **pobre** (*plain*) | una persona | ninguno | | **revelado** (*revealed*) | `mesa escribe`, los transpiladores, el modo réplica | sí, cada decisión marcada `(máquina)` | La **proporción pobre** de un pliego es la fracción de sus líneas de dramaturgia sin cifras. Un pliego de autor DEBERÍA mantenerla en el 85 % o más; un compilador DEBE calcularla y DEBERÍA avisar por debajo del 85 % (`W112`). Quedan fuera de la cuenta, cada cosa por su razón: los bloques de sección (calibran un oficio, y ahí los números son legítimos), el cuerpo de un `ver:` (los datos que dibuja una visualización), los títulos de capítulo, los comentarios y la línea de formato. Los nombres de cues de sonido y de efectos (por ejemplo `1M1`) son nombres, no cifras, y NO DEBERÍAN contar (véase el apéndice D). ## 4. Estructura léxica {#lexical} ### 4.1 Codificación y líneas Un pliego es UTF-8 sin marca de orden de bytes. Los compiladores DEBEN normalizarlo a NFC antes del análisis. Las líneas terminan en LF o CRLF. El análisis es por líneas: cada línea se clasifica por su prefijo, y **el prefijo siempre gana**. Solo los bloques de sección (§5.3) y `dentro:` (§5.10) abarcan varias líneas. Las líneas en blanco separan clips. La sangría inicial no es significativa salvo dentro de los bloques de sección y de `dentro:`. ### 4.2 Comentarios, digresiones y encargos | Forma | Significado | En el IR | |---|---|---| | `// text` | comentario técnico | no | | `( text )` en una línea propia | digresión del autor | sí, `digresiones` | | `~ deriva: text` | un encargo al motor | sí, `derivas` | ### 4.3 El separador de campos El punto medio `·` (U+00B7), con espacios opcionales alrededor, es el único separador de campos dentro de una línea. ### 4.4 Las comillas El texto que va a pantalla, y los nombres que se refieren a texto, se escriben entre comillas latinas `«…»` (U+00AB, U+00BB). Las comillas rectas no son equivalentes y NO DEBEN aceptarse en su lugar. Una línea que consiste solo en un texto entrecomillado es un **grito** (*shout*); un clip tiene como mucho uno (`E030`). ### 4.5 Identificadores y normalización Un identificador es una secuencia de letras (incluidas las letras con tilde y la `ñ`), dígitos y `_`. Las claves de sección PUEDEN contener espacios. Las palabras clave y las palabras de los vocabularios se comparan tras esta normalización: 1. minúsculas; 2. las series de espacios se reducen a uno; 3. `_` equivale a un espacio (`toca_la_truca` es `toca la truca`); 4. se eliminan los diacríticos combinantes (NFD, se descartan de U+0300 a U+036F): la forma canónica no lleva tildes, y se aceptan las dos formas (`ilustración` es `ilustracion`). **Excepción:** las palabras reservadas (§6.4) se comparan **tal como se escriben, sin normalizar**, porque en español la tilde diacrítica distingue palabras: `el` es un artículo reservado y `él` es un nombre de personaje válido; igual `tu`/`tú`, `si`/`sí`, `mas`/`más`. Los identificadores de piezas y dibujos (`id`, nombres del bestiario) DEBERÍAN ser ASCII: son semillas (§16.3), y una tilde cambia la semilla. ### 4.6 Números `NUMBER` es un entero o un decimal con punto, con signo opcional. Donde la lengua acepta coma decimal, lo dice (`2,39:1`). ### 4.7 La marca `(máquina)` Un `(máquina)` al final declara que esa decisión la tomó el motor, no una persona. Afecta a los campos de procedencia del IR (`autor_cabecera`, `origen`) y a nada más; en particular, no afecta al hash maestro (§7.4). ### 4.8 La raya La raya `—` (U+2014) separa una cabeza de su cuerpo en `MOTIVO`, `PERSONAJE`, `ver:` y `juntos:`. Los compiladores DEBEN aceptarla con o sin espacios a cualquiera de sus lados. El estilo canónico, el que usan este documento y la batería, la pega al cuerpo, como hace la puntuación española con una raya de apertura: `MOTIVO «error» —empieza como enemigo`, `ver: votos —sí: 7 · no: 4`, `juntos: a · b · c —en fila`. En el diálogo, la raya que abre un parlamento forma parte del texto (`él: —¿Falta mucho?`). ## 5. Gramática {#grammar} La gramática completa es el apéndice B. Esta sección expone la estructura y las reglas que las producciones por sí solas no expresan. ### 5.1 El documento ```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 } ; ``` El mismo conjunto de **líneas de unidad** es válido en el preámbulo, en un capítulo y en una escena; las secciones son válidas en los tres niveles. Dentro de un clip, las líneas se clasifican por su prefijo, el prefijo siempre gana, y se conserva su orden. ### 5.2 El preámbulo `MESA [v N] TITLE` abre un pliego y PUEDE declarar la época (`MESA v2 «El puerto»`). Un pliego que declara una época más nueva que la del compilador DEBE rechazarse (`E001`). `formato` declara propiedades: una relación de aspecto (`16:9`, `4:3`, `2,39:1`), `sala crema` o `sala pizarra`, `tirada borrador` o `tirada definitiva`, `página desnuda` (sin folio ni sello, solo papel) y `en dos` (todo lo dibujado, animado a dos fotogramas). `REPARTO NAME: drum[, voice][, voice colour][, side][, alias: A · B]` declara a un hablante. **El reparto es normativo para el diálogo**: un hablante que no está declarado en `REPARTO` o en `PERSONAJE` no es un hablante (§5.5). El color de voz es `con radio` o `seca` (si no, `E016`); el lado es `a la izquierda`, `a la derecha` o `al centro`. El preámbulo lleva también los recursos del proyecto: `PYTHON` (o `PIEZAS`, parte 3) para el bestiario, `EFECTOS` y `BANDA` para las carpetas de sonido, `MEZCLA` para la mezcla, `PARTITURA`, `SOPORTE`, `LETRA`, `ARCHIVO`, `FANTASMA`, `RELOJES` y `SONIDO`. Las rutas son relativas a la carpeta del pliego; en un proyecto portable DEBEN serlo (§14). En la época 2, la línea de preámbulo `MUSICA path` (modo canción: la canción manda en el montaje) y la línea de unidad `MÚSICA cue` (una cue de `BANDA`) comparten palabra clave. Un compilador DEBE tratar `MÚSICA` seguida de un nombre que existe en `BANDA` como una cue, y cualquier otra línea `MÚSICA` del preámbulo como una canción, con tilde o sin ella (RFC 0004; apéndice D). ### 5.3 Las secciones y la ley del espejo ```ebnf SECTION = "#" NOMBRE-SECCION [ IDENT ] NL { SECTION-LINE } "#FIN" | NOMBRE-SECCION PATH ; ``` Un bloque de sección escrito dentro del pliego es **idéntico en gramática** al fichero importado en su lugar. Invariante (§11.2): ```text effective(p) == effective(parte(p)) == effective(funde(parte(p))) ``` Las claves de varias palabras llevan dos puntos (`por defecto: tijera`) para que sobrevivan a la ida y vuelta. La precedencia, única y sin excepciones, es por herencia parcial (una línea sobrescribe una línea): ```text imported < inline in the preamble < chapter block < scene block ``` (Es decir: lo importado, menos que lo escrito en el preámbulo, menos que el bloque de capítulo, menos que el bloque de escena.) `TALLER` y `MANO` son normativas (apéndice A: `FAMILIA_TALLER`, `CLAVE_MANO`); la sección `BESTIARIO` equivale a la línea `PYTHON` del preámbulo, y la sección `REPARTO`, a las líneas `REPARTO` del preámbulo; `MONTAJE` y `CASCADA` están reservadas (§6.3). ### 5.4 Capítulos y escenas `== TITLE · attributes ====` abre un capítulo. Atributos: `tensión` (una `TENSION`), `nº`, `tambor`, `gigante`, `plano fijo` (una `PLANTILLA`, no una talla), `tramo a → b`, `nocturno`, `diurno`. `-- TITLE [· HORA] --` abre una escena. Líneas de unidad del núcleo: - `EJE de A a B`: la regla de los 180 grados. De ella se derivan el lado de cada quien, la dirección de las miradas y por dónde vuelve a entrar quien salió por un lado. - `LUZ direction · hardness [· rasante]`: **una por escena**; gobierna todas las sombras. Ninguna pieza declara su propia sombra. - `MUNDO movement [N] · direction`: el reloj del mundo (§7.7). - `FONDO key · distance` y `DELANTE key [· distance] [· cada N]`: fondo multiplano y proscenio; la velocidad, el color y la profundidad se derivan de la lejanía. - `ESCENARIO`, `TABLAS` (el teatro de papel como decorado fijo; la hora tiñe, no oscurece; quien tiene pies se apoya en el suelo), `ARCHIVO`, `REPITE «scene»` (los mismos clips con las mismas identidades: el mismo vídeo). Las líneas de unidad del preámbulo se aplican a todo el pliego; en un capítulo o una escena, a ese capítulo o esa escena. La escena prevalece sobre el capítulo y el capítulo sobre el preámbulo. ### 5.5 Clips ```ebnf CLIP-HEAD = "*" [ BEAT-ID ] ( FUNCION | SHOT ) [ "·" AFECTO ] [ "(máquina)" ] ; SHOT = { TALLA | ALTURA | FRENTE | MODO } [ "de" [ ARTICLE ] IDENT ] ; ``` Dos lenguajes, los dos legítimos: una **función** dramatúrgica (`* prueba · seco`), de la que se deriva la plantilla de composición (§6.5), o un **plano** (`* corto contrapicado de tercero · nervioso`), que declara una talla. Son dos ejes (§6.5). El artículo del sujeto se descarta (`general de la carretera` tiene por sujeto `carretera`). Un id de beat opcional (`* r01_02 primer de LOCUTOR · …`) da al clip un identificador estable, el que usa el sidecar. Líneas de contenido: `di: TEXT` es la narración y **la partitura del beat**: su locución da la duración del beat. `SPEAKER: TEXT` es diálogo; el hablante DEBE estar declarado y NO DEBE ser una palabra reservada (`E021`); las directivas se resuelven primero, de modo que un hablante con nombre de directiva no puede capturarla. `SPEAKER / SPEAKER: …` es una frase partida entre dos voces. `letrero (register): TEXT` es un letrero (`REGISTRO_LETRERO`; desconocido: `E014`; reservado: `W111`). `terminal:`, `canta:` y la prosa llana completan las líneas de contenido. ### 5.6 Piezas y colocación `pon: TYPE «text» · attributes` pone una pieza de un `TIPO-PIEZA`; `foto:`, `recorte:` y `prensada:` ponen material de archivo; `ver: KEY —body`, una visualización del catálogo `CLAVE_VIS`, cuyo cuerpo son datos; `pica:`; `python: NAME args`, una pieza del bestiario (parte 3); `arriba:`, `pie:`, `nota:`; `marca: GESTURE «text»` (`GESTO_MARCA`). **La ley del cuerpo:** casi nada va en coordenadas. La colocación es relacional: `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:`, y los prefijos de los perfiles (`en MATERIA:`, `de «A» a «B»:`, `a la izquierda:`, una lejanía, `en silueta:`). Los prefijos se encadenan, y se encadenan con `al decir «…»:`. El tamaño de un dibujo va tras un `·` (`grande`, `enorme`, `gigante`, `a sangre`). `clip: path [de mm:ss a mm:ss]` pone vídeo real, un recorte vivo cuyo sonido entra en la mezcla en su tiempo exacto. **Un clip dura lo que dice que dura**: un beat NO DEBE cerrarse mientras uno de sus clips sigue corriendo; en su lugar, el beat crece (`W123` dice cuánto). `> espera al clip` da al clip el turno entero: primero suena la narración, luego una respiración, luego el clip, y la banda de subtítulos se retira mientras corre. **La realidad no se revela**: un clip de vídeo real nunca pasa por el cuarto oscuro (ni trama, ni duotono, ni troquel de tijera). ### 5.7 Movimiento ```ebnf MOVEMENT = [ PLACEMENT ] [ ARTICLE ] SUBJECT VERB [ DESTINATION ] { "·" ( [ "por" ] TRAYECTO | MANERA | GRANULADO | REGISTRO-MOV | RASTRO ) } [ WINDOW ] ; ``` **Un movimiento se reconoce por su verbo** (`VERBO_MOV`, `VERBO_RELACIONAL`), nunca por sus sufijos. Si no, `la piedra rueda hasta el borde`, sin sufijo, caería en la prosa y se imprimiría como narración (§3, principio 7). Tras un `·` en una línea de movimiento solo son válidos un trayecto, una manera, un granulado, un registro, un rastro o una ventana; cualquier otra cosa es un error (`E012`). Los verbos relacionales crean una ligadura viva que muere con su objetivo; un ciclo de ligaduras, una cadena de más de tres eslabones o un anidamiento de más de tres niveles son un error (`E032`). **La ley del movimiento:** la curva nunca se declara; se deriva de la materia, la mano, el afecto y la manera (§7.6). **Verbos de la vida.** Un personaje o una marioneta también se gira, se sienta y mira, con palabras llanas: `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` (camina hacia la cámara y crece sobre sus pies), `X se aleja`; `X mira a «Y»` (cabeza y ojos hacia otra pieza hasta el beat siguiente); `X se queda quieto` (solo respira). Todos se pueden anclar (`al decir «gol»: X se asoma a la barandilla`). Sin comillas, `A mira a B` es **a la vez** la mirada que actúa la pieza y la mirada del cine (§5.8, `W103`); un compilador DEBE conservar los dos sentidos. ### 5.8 Cámara, cine y viaje `la truca ORDER [IDENT] [en SIZE]` mueve la truca (`ORDEN_TRUCA`); `A mira a B` (también a alguien fuera de cuadro); `A sale|entra por la SIDE`; `sonido: adelanta|retiene|dentro|fuera` (cortes en J y en L); `fuera de campo: TEXT`; `el foco en X`, `el foco pasa a X`, `todo en foco` (el foco es densidad de tinta, nitidez del borde y sombra, nunca desenfoque); `X está STATE` (un estado para la continuidad). El viaje: `X viaja`, `X se apea`, `el mundo MOVEMENT`, `por la ventanilla: … desfilan`. ### 5.9 Eventos ```ebnf EVENT = ">" EVENT-NAME [ ARG ] { "·" ">" EVENT-NAME [ ARG ] } ; ``` Los nombres de evento son un vocabulario cerrado con estado (§6.3). Un evento escrito en un clip actúa en su lugar dentro del orden del autor y puede anclarse a la voz (`al decir «GOL»: > temblor`). Una transición escrita en un clip dice cómo **entra** el clip; `funde a negro` y `funde a blanco` dicen cómo **sale**. Cuatro eventos se copian además a un campo del clip porque otra pasada los lee (`EVENTO_A_CAMPO`): `salta` y `cruza el eje` (las escapatorias de los avisos de continuidad), `congela` y `continúa`. ### 5.10 Anidamiento y concurrencia `dentro:` abre subclips (como mucho tres niveles); `mientras:` abre una pista paralela; `al decir «w»: LINE` ancla una línea al momento en que la voz dice `w`; `LINE hasta decir «w»` la estira hasta entonces. Las anclas se escriben **como se escriben**, no como suenan; un compilador con el sidecar empareja las cifras con su lectura (`1154` y «mil ciento cincuenta y cuatro») y las transcripciones aproximadas por distancia de edición, y avisa de las anclas que nunca casan (`W120`) o que casan con la voz pero no con el texto (`W122`). ### 5.11 El final `== FIN ===` cierra la película; las líneas que lo siguen son su colofón; `> silencio N`, su silencio final (sin él, el compilador aplica 3 segundos y avisa, `W113`). ### 5.12 La servilleta Un pliego sin ningún `==` es prosa: cada frase es un clip y el dramaturgo (reglas fijas, sin aprendizaje automático) decide el resto. Es la puerta de entrada y DEBE funcionar siempre: todo compilador y todo intérprete del perfil núcleo DEBE aceptar una servilleta, incluida una con un preámbulo que declara su sonido (`BANDA`, `MÚSICA`, `AMBIENTE`). ## 6. Vocabularios cerrados {#vocabularies} ### 6.1 La ley **Si una palabra no está en su lista, es un error, no una extensión silenciosa.** Todo no terminal de la gramática que la gramática no define es un vocabulario cerrado que figura en el apéndice A, con la estructura del analizador de referencia de la que se extrae y el perfil al que pertenece. El apéndice A se genera (`spec/vocabularios/vocabularios.json`); un compilador DEBE aceptar exactamente esas palabras para la época que implementa, comparadas tras la normalización (§4.5), y DEBE rechazar cualquier otra palabra en una posición cerrada con el código de esa posición (apéndice C). Los vocabularios de una época están **congelados**: una versión posterior de un compilador NO DEBE rechazar una palabra que la época declaró, incluidas las reservadas (§6.3). Las palabras nuevas solo entran mediante una RFC y están disponibles para los pliegos que declaran la época que las introdujo. **Un compilador acepta la lengua entera.** Los perfiles (§8) dicen lo que un intérprete *realiza*; nunca restringen lo que acepta un compilador. Un compilador NO DEBE rechazar una palabra de ningún perfil porque un intérprete concreto no la realice. ### 6.2 Panorama El apéndice A enumera 98 vocabularios (1015 palabras en total en esta versión). Los más usados: | Vocabulario | Palabras | Notas | |---|---|---| | `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, **con orden** | general, conjunto, medio, americano, corto, primer, detalle | | `ALTURA`, `FRENTE`, `MODO` | 5, 5, 3 | los demás ejes de un plano | | `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 | trayectos, maneras y granulados de un movimiento | | `EVENTO` | 163 | eventos de todos los perfiles, cada uno con su estado (§6.3) | | `LEJANIA` | 8, **con orden** | al pie, al paso, cerca, a media distancia, lejos, al fondo, en el horizonte, en el cielo | | `CLAVE_VIS` | 68 | el catálogo de `ver:` | | `TAMBOR` | 7 | ámbar, bermellón, naranja, rosa, ultramar, verde, violeta | | `PALABRA_RESERVADA` | 76 | §6.4 | Los vocabularios con orden (`TALLA`, `LEJANIA`, `DISTANCIA`, `CADENCIA`, `INTENSIDAD`, `SOPORTE`) llevan significado en su orden: la distancia entre dos tallas es su número de escalones, y una intensidad es un nivel de 0 a 10. ### 6.3 Estado: vivo y reservado Todo evento, y todo nombre de sección, declara un estado: - **vivo** (*alive*): el compilador o el intérprete lo consume; - **reservado** (*reserved*): la lengua lo acepta y el intérprete todavía no hace nada. Es vocabulario congelado: escribirlo hoy no rompe mañana. Un compilador DEBE aceptarlo y DEBERÍA avisar (`W110`). En esta versión todos los eventos están vivos. Están reservadas las secciones `MONTAJE` y `CASCADA` y los registros de letrero `máquina`, `dymo` y `tira` (`REGISTRO_LETRERO_RESERVADO`). ### 6.4 Palabras reservadas `PALABRA_RESERVADA` enumera las palabras que abren una línea en el analizador, más artículos y preposiciones. NO DEBEN ser el nombre de un hablante ni un identificador (`E021`), y se comparan sin normalizar (§4.5): `él` no es `el`. ### 6.5 Plantillas y tallas son dos ejes Una **talla** (`TALLA`) dice cuánto del encuadre ocupa el sujeto. Una **plantilla** (`PLANTILLA`) dice dónde caen las piezas en la hoja. Comparten una palabra, `general`, y `primerísimo` no es `primer`. Consecuencias: 1. `PLANO_DE` hace corresponder funciones con plantillas, no con tallas: | Función | Plantilla | |---|---| | apertura | orla | | remate, giro | primerísimo | | respiro | general | | ilustración, contrapunto | contraplano | | digresión | mapa | | tesis, prueba, eco | documento | | cartel | cartel | 2. El aviso de salto de talla (`W102`) solo se evalúa entre dos planos consecutivos que declaran talla los dos. 3. `plano fijo` toma una plantilla. ### 6.6 Tipos de pieza y sustratos `TIPO-PIEZA` (lo que acepta `pon:`: cartulina, dymo, mano, python, rescate, sello, texto, tira, y `apunte`) es un papel dramatúrgico; `SUSTRATO` (14: papel, tira, cartulina, postit, vegetal, acetato, foto, periódico, pijama, milimetrado, kraft, dymo, ficha, polaroid) es una propiedad física (color de base, opacidad, sombra, foley al posarse). Todo tipo se resuelve en un sustrato (`rescate`, `texto` y `mano` en `papel`, `sello` en `cartulina`, y los homónimos en sí mismos); a los sustratos que no son tipos se llega desde el taller (`materia NAME`) o desde el bestiario, no desde `pon:`. ## 7. Semántica {#semantics} ### 7.1 Unidades y estratos ```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 ``` (El capítulo es la unidad de página y de render, y se renderiza en paralelo; la escena, la unidad de mundo, que persiste entre planos; el clip, la unidad de tiempo: un beat, un plano; la línea, la unidad de acción.) Como los capítulos PUEDEN renderizarse en procesos separados, la continuidad entre ellos son **datos serializados** (`estado_entrada`, §10.4), nunca objetos vivos. | Estrato | Vive | Espacio | Banda de z | Lo compone el resolutor | |---|---|---|---|---| | `FONDO` | por secuencia | espacio de mesa | de −60 a −30 | no | | `MUNDO` | hasta el mutis o el telón | suelo, marcas, ligaduras | de −20 a 0 | no (relacional) | | `DOCUMENTO` | por frase | zonas y slots, con reserva | de 1 a 100 | sí | | `PROSCENIO` | mientras cruza | espacio de mesa | de 101 a 200 | no | | `ANOTACIÓN` | con su objetivo | el objetivo | 9000 en adelante | no | El proscenio (lo que está entre la cámara y la escena) va por encima del documento, porque si no cualquier cartulina se dibujaría sobre él y la oclusión no ocluiría, y por debajo de la anotación, porque un subtítulo no está en la habitación: está sobre la película. La pertenencia se infiere del tipo de pieza y se corrige con una palabra (`en el mundo:`, `en el documento:`). ### 7.2 Las cinco leyes 1. La constitución anti-parámetro (§3). 2. El cierre (§11.1). 3. La identidad es la semilla (§7.4). 4. Lo que no cabe en la hoja no se lee. 5. La lejanía manda sobre la velocidad, el color y la profundidad de cada estrato (§7.7). ### 7.3 Precedencia Toda decisión del motor tiene una dimensión y una lista ordenada de autoridades; gana la primera autoridad que tiene un valor. Todo decisor devuelve un valor **y su razón**, o nada; la razón es obligatoria por firma. Las autoridades son un vocabulario cerrado (`AUTORIDAD`, 34 palabras). | Dimensión | Orden de autoridad (gana la de la izquierda) | |---|---| | sitio | mano, ligadura, cuerpo, slot, compositor, semilla | | z | estrato, proscenio, llegada | | tamaño | **declarado**, mano, identidad, papel, legibilidad | | tiempo | partitura, ventana, tope, gesto | | fondo | orden de la mano, escena, capítulo, carácter | | velocidad de estrato | lejanía, **orden del mundo** | | color de estrato | lejanía, archivo, paleta | | curva | manera, materia, mano, afecto | | sombra | luz (la dice la escena, nunca la pieza) | | nombre | **exacto, alias, texto exacto, texto difuso** | Dos candidatos que empatan en el mismo nivel de la dimensión `name` (nombre) son una ambigüedad y un error (`E020`). La presencia de un campo en el IR **es** la señal de autoridad (§10.5): una herramienta de explicación (`mesa por-que`) lee exactamente eso, de modo que su explicación no puede apartarse del render. ### 7.4 Identidad, semilla y determinismo La **identidad** es la ruta declarada (`id portada/fabula`) o la ruta derivada (`chapter/scene/text`, es decir, capítulo/escena/texto). Se calcula a partir del **contenido**, nunca de la posición; un índice `#n` solo desempata piezas literalmente idénticas, y localmente. **Semilla:** ```text seed(piece) = H(identity) ⊕ H(take) ``` donde `H` es la función de semilla del canon (FNV-1a de 32 bits sobre UTF-8, §16.3) y `take` es el número de interpretación (`--toma N`). La identidad gobierna lo que debe verse siempre igual; la toma gobierna la materia: `--toma 3` da otra interpretación de la misma película (mismos planos, misma duración, distinta materia). **Semillas prohibidas:** ninguna semilla puede depender del orden de render o de creación, de las direcciones de los objetos, del proceso, del reloj ni del sistema de archivos. **El hash maestro** se calcula sobre el pliego desnudado y canonicalizado: espacios normalizados, comentarios y digresiones fuera, secciones resueltas, marcas `(máquina)` retiradas. Volver a escribir un pliego (`escribe`) no cambia su semilla. **El contrato de determinismo.** Dos ejecuciones producen **la misma película** cuando coinciden estas cinco entradas: (1) el pliego canonicalizado, (2) el número de toma, (3) la versión del motor, (4) el bestiario y las secciones importadas, (5) el sidecar de voz. El sidecar forma parte del contrato, no es un metadato: su `hash` y su `metodo` por beat son entradas. Una huella dorada (§13.4) es válida para un juego de esas cinco entradas en una máquina y una GPU; entre GPU distintas la huella se compara con tolerancia. Un pliego que se use como referencia dorada DEBE declarar `tirada definitiva` y fijar su toma. ### 7.5 El tiempo **Un beat, un reloj.** Todo beat tiene una duración antes de renderizarse: la de la voz (`di:` y el diálogo, a través del sidecar, §14.3), la de `> dura N`, la de sus clips (un beat no se cierra mientras corre un clip, §5.6) o una sintética (el tiempo de lectura de su texto, §16.4). No hay régimen libre. **La partitura** (`al decir «w»:`) es la primera autoridad del tiempo. Toda acción tiene una ventana; `mientras:` abre una pista paralela; `hasta decir` estira; el **tope** impide que una acción se coma el turno de la siguiente. Dos acciones sobre el mismo sujeto en la misma ventana son un error (`E031`). El movimiento persiste a través de un corte salvo con `> congela`. ### 7.6 El movimiento y el oficio La curva de todo movimiento se deriva; el pliego nunca la declara. Los principios de Lasseter (1987) son el comportamiento por defecto de todo verbo de movimiento, con los números del canon (`oficio`, §16.4): | Principio | Qué hace el intérprete | Quién lo modula | |---|---|---| | entrada y salida lentas | la curva derivada se suaviza en los dos extremos; nunca es lineal | la manera (`de golpe` conserva la brusquedad) | | anticipación | retrocede por su trayecto antes de salir, en proporción a la velocidad | `con anticipación` la fuerza; `de golpe` la quita | | arcos | sin trayecto, decide el verbo (`salta` en arco, `vuela` en curva, `cae` cayendo); si no, un arco suave hacia arriba; nada sale de la hoja por el camino | un trayecto escrito prevalece; `recto` es recto | | estirar y encoger | se estira a lo largo de la marcha conservando su área; se aplasta al aterrizar | la velocidad y la materia (lo rígido cede la mitad) | | acción continuada | se pasa y se asienta; se inclina contra la marcha | la masa, el rebote y el cimbreo | | acción superpuesta | las partes de un grupo salen escalonadas, como muelles amortiguados; nunca hay más de `simultaneos_maximos` moviéndose a la vez | | | tiempo | la duración sale de la distancia y la manera, nunca por debajo de `fotogramas_minimos` | la manera | | pausa viva | lo que se ha movido respira (una deriva mínima sembrada): nunca un fotograma congelado | `> deja posar` la alarga | | exageración | todo factor × `exageracion` | el canon | **A dos fotogramas:** `en dos` anima lo dibujado a la mitad de la cadencia, con poses sostenidas; es un sufijo de un movimiento o una propiedad del pliego entero. El vídeo real, el hervor y los actualizadores siguen a un fotograma. El **movimiento secundario** (arrastre, rebote, cimbreo) es una propiedad de la materia y nunca se declara en el pliego. **Apoyo:** una pieza soltada cae hasta su apoyo; solo flota si su materia lo permite (si no, `E033`). ### 7.7 La lejanía manda, y su única excepción De la **lejanía** (`LEJANIA`), y de nada más, se derivan la velocidad, el color y la z de una capa. **La excepción, declarada:** `MUNDO acelera a N` y `MUNDO frena a N` son una orden explícita de la mano al reloj del mundo; la dimensión *velocidad de estrato* tiene una segunda autoridad, *orden del mundo*, por debajo de la lejanía. La ley sigue valiendo entre capas (una capa no puede ir despacio y estar delante); la orden cambia el reloj común, que las multiplica a todas por igual. `MUNDO para` fija el reloj a cero. ### 7.8 La materia **Nada es un relleno plano.** Toda pieza pertenece a un registro (`REGISTRO_MATERIA`): `recorte` (contorno de tijera, grano, sombra dura, canto), `pintado` (gouache o rotulador: pasadas con ductus y un borde desbordado), `fotográfico` (revelado y troquelado), `tinta` (una línea dibujada a mano, que hierve). **El hervor:** tres poses del mismo camino, misma geometría, distinto temblor, periodos sembrados por la identidad; las poses DEBEN ser isomorfas. El hervor cambia la forma, nunca el sitio. ### 7.9 Cámara, continuidad, luz y foco Del **eje** se derivan el lado de cada quien, su vista y su lado de entrada. El volteo solo se aplica a las piezas declaradas espejables. Las tres leyes de cámara: el desplazamiento es un dato, no una caja envolvente; **el corte no viaja**; una escena con mundo propio es un lugar nuevo. Cuando la mano declara `toca la truca: sí`, la truca hereda su pulso (anticipación, un temblor de periodo primo, sobrepaso, y pierde al sujeto medio segundo). **Una luz por escena**, y todas las sombras la obedecen; la hora la tiñe. Está prohibido ajustar la sombra de una sola pieza. **El foco no es desenfoque**: lo que está fuera de foco es más pálido, con un borde más blando y algo más grande. El texto nunca se desenfoca, salvo que se rompa una regla con permiso (§8.5). ### 7.10 Avisos de continuidad Ninguno es fatal: romperlos es legítimo, pero hay que decirlo. `AVISO_CONTINUIDAD`: | Aviso | Cuándo | Lo silencia | |---|---|---| | `W101` salto de eje | se cruza la línea sin un plano neutro | `> cruza el eje`, `> rompe el eje porque «…»` | | `W102` salto de talla | la misma talla y el mismo ángulo sobre el mismo sujeto, o más de dos escalones, entre planos que declaran talla los dos | `> salta` | | `W103` raccord de mirada | en un contraplano los dos miran al mismo lado | | | `W104` dirección | sale por un lado y entra por el mismo | | | `W105` estado | una pieza cambia sin una acción que lo explique | | ## 8. Perfiles {#profiles} Un perfil es un conjunto de capacidades que un **intérprete** realiza. Todo intérprete DEBE aceptar todo IR válido; ante una capacidad ajena a sus perfiles DEBE comportarse como si la línea no estuviera, NO DEBE fallar y DEBERÍA avisar al autor una vez por capacidad. Un intérprete declara los perfiles que realiza; los casos `huella` y `banda` de la batería se agrupan por perfil. | Perfil | Alcance (gramática en el apéndice B) | Referencia | |---|---|---| | **núcleo** (*core*) | §5 y §7: la mesa, el collage, las piezas, el movimiento con el oficio, el cine y la continuidad, el viaje, el teatro de papel, el mapa, y las líneas de aspecto de §8.1 | `ce` (en parte: no el aspecto) y `gx` | | **sonido** (*sound*) | §8.2: voz, efectos, la partitura del sonido, cues de música, ambientes, salas, paneo y máster | `gx` | | **cartel** (*poster*) | §8.3: todo plano es un cartel | `gx` | | **oído** (*hearing*) | §8.4: la imagen que escucha, luz, soporte, intensidad | `gx` | | **cámara** (*camera*) | §8.5: la cámara como objeto, profundidad, tiempo por capas, el cuadro como objeto, romper con permiso | `gx` | La RFC 0002 propone separar las líneas de aspecto en un perfil propio. ### 8.1 Aspecto (parte del perfil núcleo) Líneas de unidad (preámbulo, capítulo o escena; prevalece la escena) y eventos, todo vocabulario cerrado y sin números; los números son cosa del intérprete: - `MATERIA papel PAPEL | acuarela | risografía A y B [y C] · registration · screen | pincel | tejido [drum] | tinta | ninguna [sobre papel PAPEL]`: de qué está hecho el cuadro, una pasada sobre el fotograma terminado en la convención de la parte 6. Las mismas palabras como prefijo dan la materia de una pieza (`en acuarela: python: gamba`). Una fotografía no tiene capas: su materia se hornea una vez sobre la imagen original, no sobre su trama. Eventos: `> se moja`, `> se seca`, `> se lava`, `> florece [drum] [en «X»]`, `> se teje`, `> la tinta lo cubre todo [drum]`. - `BOBINA truca | sin grano | noticiario`: la película (el noticiario a 18 fotogramas por segundo, sepia, rayas, parpadeo y vaivén). - `FORMATO 4:3 | 16:9 | 2,39:1 [· de televisión] [· bandas de papel]` y `> formato X`: bandas de tinta con bordes rasgados; el cambio se anima. En un pliego que cambia de formato, todo formato es un visor con esquinas redondeadas y papel alrededor, y la pasada del visor va la última. - `ESPEJO [side]`, `PANTALLA PARTIDA [· con un espejo en medio] [· que se miran] [· desigual] [· inclinada]`, `SIMULTÁNEO en rejilla | en abanico | en abanico que gira`, con sus eventos (`> se rompe el espejo`, `> se parte la pantalla`, `> un solo plano`…). - Transiciones (`TRANSICION`): transiciones de dos planos en las que el plano entrante está vivo y el saliente es una lámina fija de su último fotograma; `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]`: la voz escrita palabra a palabra en el instante en que se dice; las mayúsculas y `> revienta «…»` crecen, estampan y desbordan. La frase partida (`A / B: —…`) y el letrero volador (`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»`: cortes dentro del beat. - Rastros de movimiento (`con estela`, `con líneas de fuerza`, `en cronofotografía`), metamorfosis (`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»`, personajes con ficha (parte 3) y `HERVOR dibujado | suave | no`. La cadena de cada instante es: materia, lo que asoma, espejo y pantalla partida, simultaneidad, cámara, formato, noticiario, transición, sintonía y el baño (papel y película). Una pasada solo cambia cuando algo cambia; sus animaciones son funciones del tiempo de la escena. ### 8.2 Sonido El perfil sonido abarca la voz y la banda entera. **Todo ejemplo, pieza de galería y pliego de conformidad de este estándar lleva música y diseño sonoro.** Preámbulo: `EFECTOS folder` (efectos y ambientes, por nombre de fichero), `BANDA folder` (cues de música), `MEZCLA para la web | para cine · con stems | sin stems`, y en `REPARTO` la voz, su color (`con radio`: la banda del altavoz, un toque de saturación y el soplido de la emisora; o `seca`) y su lado. Líneas de unidad: `MÚSICA cue | ninguna`, `AMBIENTE a · b` (capas), `ESPACIO estadio | patio | estudio | radio | seco` (la sala de los efectos), `CAMA`, `JINGLE`. Líneas de clip: `sonido: effect [side]` (anclable: `al decir «X»: sonido: pitido`). Eventos: `> 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`. Un intérprete del perfil sonido DEBE: 1. resolver los nombres sin distinguir mayúsculas y con la normalización de §4.5: `sonido:` y `AMBIENTE` en `EFECTOS` y después en `BANDA`; `MÚSICA` en `BANDA`. (Un nombre que no está en ninguna es un error que da el **compilador**: `E040`, `E041`, `E042`; un intérprete NO DEBE rodar ese pliego como si el sonido fuera silencio.) 2. mezclar en estéreo a través de cuatro buses: voces, música, efectos y ambientes; 3. mantener sonando una cue de música mientras escenas consecutivas nombran la misma cue (no vuelve a empezar), encadenar con un fundido cruzado al cambiar de cue, dejar que una cue más corta que su tramo termine por sí sola y fundir al final de su tramo una más larga; 4. repetir en bucle los ambientes con un fundido cruzado en cada vuelta, mientras duren; 5. bajar la música bajo la voz más que los ambientes: la voz siempre se entiende; 6. con `> silencio de verdad`, cortar la música, los ambientes y lo que estuviera sonando hasta el siguiente beat, sin tono de sala; un efecto que empieza en ese mismo instante suena entero; 7. colocar cada voz en su lado, moverlas con los eventos de paneo y aplicar la sala de `ESPACIO` a los efectos (la voz ya lleva su color en la toma); 8. masterizar a **−14 LUFS integrados para la web y −24 LUFS para cine**, con picos verdaderos por debajo de **−1 dBTP** (un limitador con sobremuestreo de al menos cuatro veces) y, con stems, escribir los cuatro buses con la ganancia del máster y sin el limitador; 9. no llamar nunca a un servicio de pago mientras renderiza: las voces llegan grabadas en el sidecar (§14.3). La referencia escribe el máster como WAV de 24 bits junto al vídeo (`.master.wav`), los stems en `.stems/` y un informe en `.banda.json` con la sonoridad medida, el pico verdadero, las cues y los recuentos; los casos `banda` de la batería leen ese informe. ### 8.3 Cartel: todo plano es un cartel `PALETA A, B y C` (campo, figura, acento, más el papel; `COLOR_CARTEL`) y `CARTEL composition · …` (`COMPOSICION`) componen la página como un cartel; dentro de un clip se aplican a ese plano. **Los letreros son piezas**: `LETRA «WORD» · en TYPE · arrangement · place · size · de COLOUR`, `«X» es un PAPEL-SIGNO [a «SCENE»]`, una letra que es una figura o se convierte en una, `[las letras de] «X» VERB` (cada letra con su montura y el oficio), `la raya corta «X»`, `«X» forma FORM`, `ESCALA A como B`, `BOSQUE de …`, `en silueta:`. El borde puede cortar las piezas (`CORTE`) y estas pueden crecer `gigante`. **La salvaguarda:** un corte nunca quita lo esencial de una pieza (la cara y la boca de quien habla, la mano que actúa, el objeto que importa: las partes esenciales de la parte 3); el texto que debe leerse se lee; `· sin leer` da permiso. **El texto se teje**: `TEJE`, `SINTONIZA`, `se interrumpe en`, `sigue`, `FRASES`, y los eventos con estado del tejido. `PARTITURA path` deja que la tipografía del texto fuente proponga lo que un clip no dice (cursivas, rayas, mayúsculas); lo que el clip declara prevalece. ### 8.4 Oído: la imagen que escucha El intérprete **oye el audio real** (la voz de cada beat, ambientes, música, efectos) como curvas a 100 muestras por segundo: intensidad (absoluta y relativa), tono (en octavas), ataque, centroide espectral y 32 bandas logarítmicas. Pistas (`PISTA`): `la voz`, `la música`, `la cama`, `los efectos`, `la radio`, o un sonido con nombre. Líneas: `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`. Luz: `LUZ de «piece» · desde abajo · drum` (una sola fuente dura, sujeta a su pieza), `LUZ de los focos · en contraluz`, `LUZ plana`, `COLOR monocromo [drum] | pleno`, `> estalla el color`. Soporte (la degradación como dramaturgia): `SOPORTE limpio | usado | gastado | sucio | roto`, `> el soporte empeora | se deshace | se limpia`; el soporte dura toda la película. **La intensidad como parámetro de dirección**: `INTENSIDAD WORD | de WORD a WORD [· extraña] [· con PISTA]`, con once palabras de `nula` (0) a `rota` (10), que gobiernan a la vez el temblor, la inclinación, el fuera de registro, el grano y el ritmo de `MONTAJE al pulso`. ### 8.5 Cámara: la cámara como objeto Líneas de unidad: `CÁMARA lens · weight · hand · depth`, `HORIZONTE recto | se inclina | gira`, `CADENCIA target cadence · …` (cada capa dibuja a su propia cadencia), `GOLPES con impacto | con borrón`, `PISTA ÓPTICA [side]`; los prefijos de lejanía (`lejos: python: fachada`) ponen una pieza a esa distancia de una cámara de perspectiva real, y **el paralaje nunca se declara**: sale de la perspectiva cuando la cámara se mueve. El cielo está en el infinito. Los eventos (`EVENTO_CAMARA`) incluyen panorámicas con masa, travelín, grúa, objetivos con la focal y la distancia separadas, el plano de vértigo, una curva de tensión continua para la cámara en mano, el horizonte que se inclina, la snorricam, la órbita, el tiempo bala, atravesar piezas, el plano secuencia, los cortes en el eje, el cuadro como objeto (bandas de papel, perforaciones, un cuadro descarrilado) y `X mira a cámara`. **Romper con permiso.** Un plano puede romper una regla a sabiendas, **con su razón**: `> rompe el eje porque «…»`, `> se sale del cuadro porque «…»`, `> sin leer porque «…»`, `> demasiado rápido porque «…»`, `> todo a la vez porque «…»`, `> sin respiro porque «…»`, y los encuadres incómodos con nombre (`ENCUADRE_INCOMODO`). Una regla rota sin su razón es un error (`E060`); un compilador lo explica y la revisión de Lasseter lo enumera aparte. ## 9. Extensión por capas {#extension} La lengua no se extiende nunca en silencio. Crece por capas, de dentro afuera: 1. **La lengua**: vocabulario cerrado, que solo cambia por RFC y en una época nueva (§22). 2. **Las secciones** `#TALLER` y `#MANO`: calibran el oficio de un proyecto o de una escena (papel, tinta, cantos, anclas, sombra, materias con masa y arrastre, el baño, la retícula; el pulso de la mano, su precisión, su grano, su entrada y su salida, su cansancio, y si toca la truca). Aquí los números son legítimos; la ley del espejo (§5.3) se cumple. 3. **El bestiario** (`PYTHON`, `PIEZAS`): piezas con nombre con sus parámetros, partes, poses, acciones y ciclos (parte 3), llamadas desde el pliego por su nombre (`python: radio`, `LOCUTOR señala`). Un bestiario añade piezas, nunca gramática; sus acciones son el vocabulario cerrado de esa pieza. 4. **El intérprete**: pasadas en la convención de la parte 6, materias, foley. Un intérprete PUEDE añadir pasadas y apariencias bajo palabras existentes; NO DEBE añadir palabras. **La capa de la casa.** Un pliego que solo dice (un REPARTO y líneas `di:`) ya es una película: en una unidad en la que ningún beat pone nada propio, un intérprete DEBERÍA poner en el papel la frase de cada beat con la pieza que piden la función y el afecto (una pregunta a mano, un grito en nota de rescate, una cita recortada de un periódico, lo demás a máquina). La capa se apaga sola, unidad a unidad, en cuanto un beat enseña algo propio; `página vacía` en la línea de propiedades la apaga en todo el pliego. Es lo que permite a una persona o a un modelo pequeño escribir un primer pliego sin ningún dibujo. `~ deriva: text` registra un encargo al motor en el IR sin cambiar la película. **Lo que un pliego no puede decir:** easing, fotogramas clave, funciones de ritmo ni duraciones sueltas en el dialecto pobre; colores en hexadecimal o RGB; sombra, velocidad de estrato o z por pieza; piezas sin nombre; dos sitios para la misma decisión. ## 10. La representación intermedia {#ir} ### 10.1 Qué es `compile(pliego)` devuelve `(script, report, extra)`: el IR (*guion rico*), una lista de frases legibles sobre la dirección, y las decisiones por beat (función, afecto, plantilla, tensión, autor), los motivos, el reparto y el arco. El IR es JSON, **se regenera siempre y nunca se versiona** dentro de los proyectos; es el contrato del que comen un intérprete y un narrador (`mesa cuenta`). **Si el narrador no sabe contar una capacidad nueva, la capacidad está mal integrada.** Los nombres de campo son identificadores españoles sin tildes. Los intérpretes DEBEN ignorar los campos desconocidos (compatibilidad hacia delante, §22). ### 10.2 Nivel de guion **Obligatorios** (un compilador conforme los emite siempre): | Campo | Tipo | Significado | |---|---|---| | `escena` | cadena | nombre de la escena que se renderiza | | `capitulo` | entero | índice de página (empieza en 0) | | `sala` | cadena | `crema` o `pizarra` | | `beats` | array | los clips compilados (§10.3) | | `taller` | objeto | el taller **efectivo**, con toda la precedencia aplicada | | `mano` | objeto | la mano **efectiva** | | `unidades` | array | los capítulos (§10.4); OBLIGATORIO cuando el pliego tiene capítulos | **Opcionales** (ausentes o `null` cuando el pliego no los declara): `registro` (el afecto dominante), `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` y `colofon` (`{lineas, tirada, semilla, toma, pobre}`: **contado, no declarado**). El nivel de guion lleva además `marionetas` (las marionetas de foto declaradas con `MARIONETA`: `nombre`, `foto`, `mira`, `canto`), y el aspecto de cada unidad y de cada beat lleva `partitura_modo` (si la voz se compone como partitura tipográfica, §8.3; `null` cuando el pliego no dice nada). Los dos son parte del IR de referencia; ninguno entra en la proyección normativa. ### 10.3 Nivel de beat **Obligatorios:** `id` (el ordinal del clip, `b07`, o su id de beat declarado), `cap` (índice del capítulo), `plano` (la plantilla resuelta), `afecto` (el afecto resuelto), `acciones` (§10.5) e `identidad` (la ruta estable de §7.4, fuente de las semillas; véase el apéndice D). **Opcionales, y lo que distingue a las parejas:** `di` (la locución del beat), `dura` (duración declarada cuando no hay voz), `sec`, `corte` (hay un corte antes de este beat, lo haya decidido quien sea) y `corte_mano` (lo pidió la mano), `plano_mano` (la plantilla se declaró, no se derivó), `limpia`, `queda`, `canta`, `nocturno`, `congela`, `luz` (la luz efectiva, ya resuelta con la hora), `escena`, `escena_titulo`, `abre_escena`, `lugar_nuevo`, `linea` (la línea de origen), `aspecto` (el aspecto efectivo de §8.1 a §8.5, un objeto por beat), `transicion`, `montaje`, `rio`, `voces`, `frase_partida`, `revienta`, `rotos` (reglas rotas con permiso) y el resto de los campos de los perfiles. El patrón `X` / `X_mano` es sistemático: `X` es el valor y `X_mano` dice si lo puso una persona. ### 10.4 Nivel de unidad Cada elemento de `unidades`: `n`, `titulo`, `beats` (ids), `escenas` (títulos) y **`estado_entrada`** (OBLIGATORIO): `{velocidad_mundo, sentido, hora}`, el estado con que se abre el capítulo. Existe porque el movimiento persiste a través de los cortes y los capítulos se renderizan en procesos distintos: la única manera de que el capítulo 3 sepa a qué velocidad iba el mundo es que el compilador lo escriba, recorriendo todo lo anterior, de forma determinista. ### 10.5 Nivel de acción `verbo` es OBLIGATORIO. **La presencia de un campo es la señal de autoridad**: `en` (sitio declarado por la mano: autoridad *mano*), `liga` (*ligadura*), `cuerpo` (*cuerpo*), `al_decir` (*partitura*), `run` (*gesto*), y los `trayecto`, `manera` y `granulado` del movimiento; `spec` y `sobre` llevan el cuerpo de un `ver:` y el objetivo de una marca. Los verbos que emite el compilador de referencia figuran en su IR; un intérprete DEBE ignorar un verbo que no conoce y DEBERÍA avisar al autor. ### 10.6 Forma canónica y proyección normativa La **forma canónica** de un IR es su serialización JCS (§1.3); su **resumen** es el SHA-256 de esa serialización, en hexadecimal en minúsculas (no confundir con la huella de una película, §13.4). La **proyección normativa** de un IR conserva solo los campos obligatorios de §10.2 a §10.5 (niveles de guion, beat, unidad y acción). Dos compiladores conformes DEBEN producir IR con proyecciones normativas iguales para todo pliego de la batería. A la implementación de referencia se le exige además su IR **completo**, congelado en `conformance/expected/ir/`: todo cambio es o una regresión o el objeto de una RFC. ## 11. Invariantes {#invariants} ### 11.1 Cierre ```text canon(compile(p)) == canon(compile(escribe(p))) ``` donde `escribe` materializa en el pliego todas las decisiones del motor (dialecto revelado, §3.1) y `canon(ir)` elimina la procedencia y la posición, y nada más: los campos `origen`, `autor_cabecera`, `_importado`, `linea` y `colofon`. Todo lo que decide un fotograma DEBE coincidir; quién lo decidió, y en qué línea, no tiene por qué. ### 11.2 El espejo Para las secciones de §5.3, `effective(p) == effective(parte(p)) == effective(funde(parte(p)))`, donde `parte` lleva cada bloque a su propio fichero y lo importa, `funde` incorpora en línea cada importación, y `effective` es el taller y la mano tras la precedencia, comparados línea a línea tras la normalización. ### 11.3 Compatibilidad **Un pliego que compiló una vez compila siempre** (§22). ## 12. Diagnósticos {#diagnostics} Un compilador comprueba un pliego (`mesa lee` en la referencia) e informa de **errores** y **avisos**, cada uno con un código estable (apéndice C, `spec/diagnosticos.json`) y un mensaje libre, que DEBERÍA enseñar: decir qué se esperaba y ofrecer las palabras válidas más cercanas. Un pliego con algún error es inválido; la orden de comprobación de un compilador DEBE terminar con un estado distinto de cero para un pliego inválido y DEBERÍA terminar con cero en caso contrario. La batería compara **conjuntos de códigos**, nunca mensajes ni orden. Los errores cubren las palabras fuera de un vocabulario cerrado (de `E010` a `E019`), los nombres (de `E020` a `E022`), la estructura (de `E030` a `E033`), los recursos de sonido (de `E040` a `E042`), el bestiario (`E050`, `E051`), las reglas rotas sin razón (`E060`) y las líneas mal formadas (`E090`). Los avisos cubren la continuidad (de `W101` a `W105`), las palabras reservadas en uso (`W110`, `W111`), la salud del pliego (de `W112` a `W118`), lo que necesita el sidecar de voz (de `W120` a `W123`) y la revisión de Lasseter (`W130`). **Los avisos que necesitan el sidecar** solo se emiten cuando existe `.tiempos.json`: el ancla muerta, las dos voces (un clip que suena dentro de un beat narrado sin `> espera al clip`), el ancla ilegible y el beat que crece. **La revisión de Lasseter** se mide sobre la línea de tiempo real de un render (o de un render en seco que interpola los mismos fotogramas sin rasterizar), nunca sobre el pliego: movimiento de menos de `fotogramas_minimos` fotogramas a 24 fps, más de `simultaneos_maximos` piezas que siguen en escena moviéndose en el mismo fotograma, falta de `pausa_fin_beat` al final de un beat, texto en pantalla durante menos de `words / palabras_por_minuto · 60 + asiento_lectura` segundos (palabras entre palabras por minuto, por 60, más el asiento de lectura), beats gemelos, movimiento lineal, movimiento rápido sin anticipación. Cada aviso lleva su beat, su línea, su instante, una sugerencia y una gravedad. **Los diagnósticos que necesitan el bestiario** se calculan leyendo el bestiario **sin ejecutarlo** (en la referencia, con el `ast` de Python): un nombre de `python:` que no existe (`E050`), una pose que no se declaró (`E051`), una pose escrita sin normalizar, un grupo que compone una pieza no creada en ese beat. ### 12.1 Diagnósticos que enseñan El criterio de usabilidad de la lengua es que **una persona, o un modelo de lenguaje mucho más pequeño que el que la diseñó, escriba un pliego limpio en pocos intentos sin leer código**. Los diagnósticos son la herramienta principal para ello, así que un compilador conforme: - DEBE dar la **línea** de todo diagnóstico que la tenga; - DEBERÍA dar, tras el mensaje, **el porqué** (la regla que se aplica), **el arreglo** (con «¿quisiste decir…?» construido por distancia de escritura, prefijo y una tabla de sinónimos: `lento` → `despacio`, `de frente` → `frontal`) y **un ejemplo** de la línea correcta; - DEBERÍA ofrecer una **explicación de cualquier palabra o línea** (en la referencia, `mesa explica «X»`: qué es, dónde va y un ejemplo; para una línea entera, lo que entiende el parser) y una **chuleta de una página** de la lengua (`mesa chuleta`); - DEBERÍA listar **las piezas que ve un pliego**, con su tipo, su descripción y las acciones que declara cada una, y la línea exacta para pedirlas (`mesa bestiario pliego.mesa`). ### 12.2 Ningún fallo silencioso **Lo que parece una orden y no lo es es un error**, nunca prosa. Una línea que el intérprete escribiría en el papel sin querer (un diálogo de quien no está en el REPARTO, una línea de escena escrita dentro de un clip, una orden o un verbo que no existen) es `E023`; una línea de prosa que se escribirá a máquina a propósito es el aviso `W125`. Un compilador DEBE informar además, leyendo el pliego y el bestiario sin ejecutar nada: | Código | Lo que, si no, fallaría en silencio | |---|---| | `E018` | un modificador desconocido tras `·` en `foto:`, `recorte:` o `clip:`, o un campo desconocido de `MARIONETA` | | `E024` | `NOMBRE acción` para una pieza que no está en el REPARTO (con la pieza como alias) ni es una `MARIONETA`: la acción no le llegaría nunca | | `E025` | `al decir «X»` cuando la voz escrita de ese beat no dice X (sin el sidecar; con él, `W120`) | | `E052` | un dibujo mal invocado: argumentos tras `·`, paréntesis como en un lenguaje de programación, o argumentos que la firma de la pieza no admite | | `E053` | el bestiario declarado con `PYTHON` o `PIEZAS` no existe junto al pliego | | `E054` | una acción que la pieza no declara entre sus acciones, poses o ciclos (§15.2) | | `W124` | una página vacía: un beat abre cuadro nuevo (una talla declarada, un capítulo o una escena nuevos) y no pone nada mientras suena la voz; no se emite en un `respiro`, que vacía la página a propósito | El color de una entrada del REPARTO es vocabulario cerrado (los tambores del canon y las tintas de la paleta del cartel); otra palabra es un error (`E019`). ## 13. Herramientas y huellas {#tools} ### 13.1 La orden (informativo) La referencia trae una orden, `mesa` (`python -m manim_saorin.formato.cli`). Sus subórdenes no son normativas, pero los adaptadores de conformidad las usan: `lee` (comprobar), `ir` (volcar el IR), `cuenta` (contar el pliego en prosa), `escribe` (revelar), `indice` (censo de nombres y ambigüedades), `por-que` (cada decisión con su autoridad y su línea), `mueve`, `taller`, `parte`, `funde`, `graba` (sintetizar la voz y escribir el sidecar), `animatica`, `toca` (renderizar; `--motor gx` sobre el motor de Tórculo), `suena` (la banda sin renderizar), `lasseter`, `intensidad`, `dura`, `empaqueta`, `desempaqueta`, `comprueba` (parte 2), `pieza` y `bestiario` (parte 3), y las herramientas que enseñan de §12.1: `explica`, `chuleta` y `nuevo` (`mesa nuevo "Título" [--desde texto.md]` escribe un proyecto con una plantilla comentada capa a capa, un bestiario mínimo y sus carpetas, o un primer pliego sacado de un texto). ### 13.2 Lo que un compilador DEBE ofrecer Un compilador conforme DEBE ofrecer, por cualquier interfaz: la comprobación de un pliego con los códigos del apéndice C, el volcado de su IR como JSON, y la revelación de un pliego (`escribe`) y la partición y fusión de sus secciones (`parte`, `funde`), de modo que pueda probarse §11. ### 13.3 Lo que un intérprete DEBE ofrecer Un intérprete conforme DEBE renderizar un pliego con su sidecar a un vídeo con sonido, y DEBERÍA ofrecer una ejecución en seco que produzca la línea de tiempo que lee la revisión de Lasseter. ### 13.4 La huella de una película La **huella** (*fingerprint*) de un vídeo es una secuencia de miniaturas en gris de 96 × 54 píxeles, una por segundo, escaladas promediando por área (`ffmpeg -vf fps=1,scale=96:54:flags=area -pix_fmt gray`), guardadas en base64 en JSON con el MD5 de cada miniatura cuantizada a 4 bits. Dos huellas **casan** cuando tienen el mismo número de muestras (±1) y la diferencia absoluta media por píxel de cada pareja de muestras es como mucho 10 (sobre una escala de 0 a 255). En la misma máquina y con el mismo motor, la referencia casa con diferencia 0. **Las métricas mienten**: una huella dice dónde están las cosas, no si viven; no se cambia ninguna huella dorada sin mirar antes una tira de la película. --- # Parte 2. El proyecto portable ## 14. El proyecto portable {#mesapack} ### 14.1 Qué es un proyecto Un proyecto es **el pliego, su bestiario y su sonido** (la voz con su sidecar, los efectos, la música) **más todo lo que el pliego lee** (la `PARTITURA`, las secciones importadas, los clips de vídeo real, las fotografías, el cerrojo de las láminas elegidas). Un empaquetador DEBE **descubrir** esos ficheros leyendo el pliego y el bestiario, y NO DEBE ejecutar código del proyecto para hacerlo (la referencia lee el bestiario con el `ast` de Python). Un proyecto es **portable** cuando toda ruta que usa es relativa a la carpeta del pliego y queda dentro de ella, y todo fichero que necesita está dentro de ella o figura en el manifiesto como dependencia de la instalación. ### 14.2 El paquete Un `.mesapack` es un archivo ZIP (PKWARE APPNOTE; se admite ZIP64). El audio, el vídeo y las imágenes DEBERÍAN guardarse sin recomprimir (método 0). Contiene el árbol del proyecto, con el pliego en la raíz, y un fichero `MANIFIESTO.json` en la raíz: | Miembro | Tipo | Obligatorio | Significado | |---|---|---|---| | `formato` | cadena | sí | `"mesapack 1"`; un lector DEBE rechazar otra versión mayor (`P003`) | | `pliego` | cadena | sí | la ruta del pliego dentro del paquete; DEBE terminar en `.mesa` y existir (`P008`) | | `titulo` | cadena | no | el título del pliego | | `creado` | cadena | no | ISO 8601 | | `por` | cadena | no | la herramienta que lo empaquetó | | `versiones` | objeto | sí | `lengua` (la época, OBLIGATORIO), `motor` (nombre, versión, commit, rama), `torculo` (commits del estándar y del motor), o `null` donde se desconozca | | `voces` | objeto | no | el reparto con voz, color y lado, y cuántas tomas de cada método hay (§14.3) | | `fuentes` | objeto | no | por fuente tipográfica: dónde está (`motor`, `sistema`, `usuario`) y, para las fuentes del usuario, su ruta en el paquete (`_fuentes/…`) | | `externos` | array | no | lo que el bestiario lee de la instalación y no viaja: `{ruta, por, donde}` | | `no_portable` | array | no | lo que no pudo hacerse portable: `{donde, ruta, arreglo}` | | `archivo_fotos` | array | no | las fotografías de archivo que van en `_archivo/` | | `archivos` | objeto | sí | por ruta: `{sha256, bytes, por}`; `por` dice **por qué** está el fichero en el paquete | Un lector: 1. DEBE rechazar las entradas con una ruta absoluta, un segmento `..`, una barra invertida o una letra de unidad (`P004`), y NO DEBE escribir fuera de la carpeta de destino; 2. DEBE verificar el SHA-256 y el tamaño de cada fichero declarado (`P005`) y DEBERÍA rechazar los ficheros no declarados (`P006`); 3. DEBE comprobar que las grabaciones del sidecar son rutas relativas dentro del paquete (`P007`); 4. DEBERÍA, tras desempaquetar, comprobar el proyecto como lo haría un empaquetador y avisar cuando las versiones de la lengua, del motor o del estándar difieran de las del manifiesto. El validador de referencia es `conformance/tools/mesapack.py`; el empaquetador de referencia es `mesa empaqueta` (con `desempaqueta` y `comprueba`). ### 14.3 El sidecar de voz `.tiempos.json` (el nombre del pliego sin extensión) está junto al pliego. Es la quinta entrada del contrato de determinismo (§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` hace corresponder un id de beat con su locución: `dur` (segundos), `pause` (segundos tras ella), `hash` (del texto que se dijo, de modo que un texto cambiado invalida la toma), `metodo` (cómo se obtuvieron los tiempos: `whisper`, `silabas`, `elevenlabs`, `declarado`, `cancion`, `hueco` u otro nombre) y `palabras`, cada palabra `w` con su inicio `t` y su duración `d` en segundos desde el comienzo del beat. Un beat PUEDE llevar `t_abs` (un tiempo absoluto, para las canciones). - `wavs` hace corresponder un id de beat con su grabación: una ruta, una lista de rutas (tomas encadenadas, como en una frase partida entre dos hablantes) o una lista de objetos `{ruta, desde}` (tomas que suenan a la vez, cada una desde su instante). - **Las rutas DEBERÍAN ser relativas a la carpeta del sidecar** (la del pliego) y, en un paquete, DEBEN serlo. Los lectores DEBEN aceptar rutas relativas y absolutas, y resolver las relativas respecto de la carpeta del sidecar. Un sidecar cuyas rutas absolutas apuntan a una ubicación antigua de un proyecto que se ha movido PUEDE reanclarse cuando el mismo fichero (mismo sufijo de ruta y mismo tamaño) existe en la ubicación nueva. - Un pliego cuyas voces se grabaron fuera del motor (por ejemplo, en un servicio de casting) las lleva en el sidecar; el render NO DEBE llamar a un servicio de voz. ### 14.4 Diagnósticos `P001` no es un ZIP, `P002` no hay un `MANIFIESTO.json` legible, `P003` formato desconocido, `P004` ruta peligrosa, `P005` fichero que falta o hash incorrecto, `P006` fichero no declarado, `P007` una grabación del sidecar fuera del paquete o absoluta, `P008` falta el pliego, `P009` falta un miembro obligatorio. --- # Parte 3. Piezas ## 15. Piezas {#pieces} Esta parte normaliza lo que entra en un pliego por `PYTHON`/`PIEZAS`, `python:`, `MARIONETA`, `foto:` y `clip:`. Sigue `SPEC-PIEZAS.md` v1 de manim-saorín (rama `piezas`, 2026-10-15); la vinculación con Python que allí se describe es la vinculación de referencia, y otro motor PUEDE ofrecer el mismo contrato en otro lenguaje. ### 15.1 Niveles | Nivel | Qué es | El pliego puede además | |---|---|---| | **0, dibujo** | un dibujo a pluma, una fotografía, un recorte | ponerlo, moverlo, filmarlo, cortarlo por el borde | | **1, partes** | más partes con nombre y con pivote | `el pelo pasa de A a B`; proteger lo esencial al cortar | | **2, marioneta** | más articulación (madres y pivotes), poses, acciones y ciclos | `X saluda`, `X corre hasta…`; la boca sigue a la voz si hay mandíbula | | **3, personaje** | más cinco vistas, expresiones, visemas, manos, ciclos de andar y correr, mundos de color | `X de espaldas`; la vista sigue al plano; `al decir «…»: X se asombra` | **Cada nivel es un superconjunto del anterior.** ### 15.2 El contrato de una pieza Una pieza es un **constructor** (en la vinculación de referencia, una función de Python que devuelve un mobject de ManimGX) con: - sus propios argumentos, por posición o por nombre (lo que el pliego escribe tras `python: name`), y los extras con valores por defecto: `alto` (altura en unidades de escena; la pantalla mide 8 de alto), `hervor` (0, 1 o 2 fija una pose de hervor; sin él, la mesa lo hace hervir), `mundo` (§15.5), `espejo`, `id`; - su **ficha** (§15.3); - su **hervor**: tres poses con la misma estructura y otro pulso; - su **apoyo**: la altura donde descansa (sus pies), de modo que se sostiene por los pies, no por el centro. Desde el nivel 1, una pieza expone `partes` (de nombre a subobjeto) y un pivote por parte. Desde el nivel 2: la firma de ficha `vista`, `pose`, `expresion`, `boca`, `mano_i`, `mano_d`, `hervor`; `POSES` (nombres), `ACCIONES` (de acción a una lista de poses, que se ejecutan a dos fotogramas) y `CICLOS` (de ciclo a una lista de poses que se repite; `corre` y `anda` los ponen en marcha los verbos de movimiento); un pivote y una madre para cada parte articulada; una parte llamada `mandibula` se abre con los visemas. **Las acciones de una marioneta son su vocabulario cerrado**: `X saluda` es válido si `saluda` está entre sus acciones o sus poses; si no, el intérprete avisa con la lista que tiene. Un personaje de nivel 3 tiene vistas (`frente`, `tres cuartos`, `perfil`, `tres cuartos de espalda`, `espalda`), expresiones, bocas (`reposo`, `a`, `e`, `i`, `o`, `u`, `m`, `f`, `l`, `gol`), manos (abierta, puño, señalando, aplaudiendo, pinza, o con un objeto en la mano), poses comunes y los ciclos `corre` (8 dibujos), `anda` (8) y `habla` (6), y partes anidadas con pivotes (tronco, cuello, cabeza con sus rasgos, pelo, bufanda, brazos, antebrazos, manos, muslos, piernas, pies). ### 15.3 La ficha | Clave | Qué | Obligatoria | |---|---|---| | `nivel` | `dibujo`, `partes`, `marioneta` o `personaje` | sí | | `nombre` | ASCII sin espacios: es la semilla y lo que escribe el pliego | sí | | `titulo` | con tildes, para las hojas | no | | `descripcion` | lo que se ve, para quien no puede verlo; la usan la capa de sentido y el listado del bestiario | sí, de 20 caracteres o más | | `alto` | altura natural en la escena | recomendada | | `mira` | `derecha`, `izquierda` o `frente`: para el espejo y el eje | recomendada | | `tintas` | los colores que usa | recomendada | | `registro` | `dibujo`, `foto`, `recorte`, `clip`, `tipografia`, `materia` o `escaneo` | no | | `partes` | las partes que tiene | desde el nivel 1 | | `esenciales` | de esencial a parte | desde el nivel 1 | ### 15.4 Partes esenciales Lo que la lengua protege al cortar por el borde (§8.3): `cara`, `boca`, `cabeza`, `mano` (la que actúa) y `objeto` (lo que importa). Un personaje declara las cuatro primeras; una marioneta, al menos `cabeza` u `objeto`; un dibujo, `objeto`. **Ninguna parte esencial puede salirse del contorno de su pieza.** Sin declaraciones, el centro de la pieza es lo esencial. ### 15.5 Mundos de color `mundo=`: `natural`, `tinta`, `sepia`, `noche`, `hielo`, `silueta` o `silueta:#RRGGBB`, `riso:DRUM+DRUM` (dos tambores del canon), y los mundos que registre un proyecto. Un mundo recolorea todas las tintas de un dibujo y lleva los grises de una fotografía a sus dos tintas. ### 15.6 En el pliego, y las comprobaciones `PIEZAS path` (un módulo, un fichero declarativo de un personaje, una marioneta o un recorte, o una carpeta entera) amplía `PYTHON`. `MARIONETA name · de la foto path [· mira a la izquierda | derecha] [· canto …]` declara una marioneta de foto. `python: name [args]` pone cualquier pieza; los argumentos con nombre fijan la pose y la vista iniciales de una ficha. `WHO action` ejecuta una acción que la pieza declara. Collage en movimiento: `foto: path · sin fondo · canto de tijera | de troquel | rasgado | limpio · sombra pegada | levantada | sin sombra · con cinta | celo | chincheta`, y `clip: path de a a b · sin fondo` (una película recortada, a dos fotogramas por defecto). Un proveedor de piezas DEBE ofrecer una comprobación que llame a cada pieza como lo hará el intérprete y verifique: que dibuja; que hierve (tres poses, misma estructura, distinto pulso); que tiene sus partes y sus esenciales, ninguno fuera del contorno; que toda parte articulada tiene un pivote dentro de la pieza; que toda acción y todo ciclo usan poses que existen; y, para un personaje, las cinco vistas, los visemas y los ciclos. La referencia es `mesa pieza comprueba`. ### 15.7 Marionetas de foto Una marioneta de foto es una pieza de nivel 2 hecha de una fotografía sin código: `MARIONETA nombre · de la foto ruta …` en el preámbulo o una ficha `nombre.marioneta.toml`. El proveedor encuentra las articulaciones y la cara de la persona, corta la foto una vez con el canto declarado y la parte por las articulaciones (cabeza, tronco, brazos, antebrazos, muslos, piernas; las piernas solo si se ven enteras), cada parte con su pivote y solapada con su madre; lo que queda bajo el labio es la `mandibula`, que se abre con la voz. Sin persona ni cara, la foto es una sola pieza que tiembla. **Toda marioneta de foto sabe**, además de lo que declare su ficha: `saluda`, `celebra`, `señala`, `baila`, `se inclina`, `duda`, `grita`, `aplaude`, `en jarras`, y los ciclos `anda` y `corre`. Una acción cuyas partes no tiene la foto (un brazo que no se encontró) DEBERÍA avisarla la comprobación de la pieza. Una **ficha de personaje con palabras** (`nombre.personaje.toml`) declara un personaje de nivel 3 con palabras cerradas en vez de código: cuerpo (altura, complexión, edad), cabeza (cráneo, nariz, gafas, ojos), pelo (estilo, color), ropa (arriba, abajo, calzado y sus colores), el objeto que sostiene y sus poses propias (`[poses.recuerda] brazo_i = "a la boca"`). Las palabras son vocabulario cerrado del proveedor; una palabra desconocida es un error de la comprobación de la pieza. ### 15.8 El collage en movimiento Fotos, recortes, vídeo real, letra, pluma y materias comparten un mismo plano. - `foto: ruta [· modificadores]` pega una foto; con `· sin fondo` la figura se recorta (el proveedor quita el fondo), y el canto (`canto de tijera | de troquel | rasgado | limpio`), la sombra (`sombra pegada | levantada | sin sombra`) y la sujeción (`con cinta | con celo | con chincheta`) se declaran con palabras. `recorte:` es una foto ya sin fondo. La materia de una pieza sigue valiendo (`en risografía rosa: foto: …`). - `clip: ruta [de a a b] · sin fondo` es una **película recortada**: cada fotograma se recorta y se vuelve a cortar a tijera, así que el canto hierve solo; va **en dos** (12 dibujos por segundo) salvo que se diga `en uno` / `a 24` o `en cuatro`, y es un actor sin marco ni celo. - `clip de fondo: ruta [de a a b]` llena el cuadro a la cadencia del cine. **Un clip de fondo dura su tramo**: cuando acaba, se va al abrir el beat siguiente aunque el plano siga; nunca se queda congelado encima de lo que viene. - `CADENCIA` (§8.5) fija la cadencia de cada capa (`las figuras en dos · el fondo en uno`), de modo que la mezcla de cadencias del collage (el vídeo real a 24, los recortes en dos, la pluma hirviendo a 8) sale sola. - **Los decorados de la casa.** `FONDO` y `DELANTE` montan piezas del bestiario como decorado de una escena; un intérprete del perfil núcleo DEBE ofrecer además, sin ningún bestiario, los decorados de la casa: `cielo`, `sierra`, `agua`, `arcada`, `celosia`, `ciudad`, `farola`, `lluvia`, `arboleda`, `cuarto`, `luna`. Una pieza del bestiario con el mismo nombre lo sustituye. Un decorado que no es ni lo uno ni lo otro es un error. **Quién actúa.** Una acción se pide con un nombre del REPARTO cuyo alias es el nombre de la pieza, también para una pieza que no habla (`REPARTO TIJERAS: minio, alias: tijeras`, y luego `al decir «corta»: TIJERAS corta`); un alias igual a su propio nombre del REPARTO no es una ambigüedad. La pieza tiene que estar en la mesa en ese beat o antes. --- # Parte 4. El canon ## 16. El canon {#canon} ### 16.1 Fuente y ficheros generados `canon/canon.toml` es la única fuente de verdad. Todas las demás formas las genera `canon/genera.py`: Python (`canon.py`), TypeScript (`canon.ts`), Rust (`canon.rs`), WGSL (`canon.wgsl`) y CSS (`canon.css`). Los ficheros generados NO DEBEN editarse a mano; `genera.py --check` falla si alguno está desfasado. El fichero declara `version = 1`. ### 16.2 Paleta Los colores son sRGB, escritos `#RRGGBB`. En WGSL y Rust son esos mismos valores sRGB como flotantes, `component / 255` redondeados a seis decimales (sin pasarlos a luz lineal); en CSS, propiedades personalizadas `--group-name` (grupo y nombre). | Grupo | Colores | |---|---| | `papel` (papel) | base `#F5F0E8`, hundido `#EDE6D6`, hoja `#FAF7F0`, filete `#D4C4B0`, filete_hondo `#C4AE96`, noche `#1A0F0A` | | `tinta` (tinta) | base `#2C1810`, segunda `#5C3D2E`, apagada `#7A5F4E`, lapiz `#9A8E80`, negro `#1A120D`, sobre_noche `#FAF7F0` | | `escritorio` (escritorio) | rojo `#C1453B` (minio), azul `#2B4C7E` (azurita), amarillo `#E8A838`, oro `#D6A03A` | | `tambores` (tambores de risografía) | ultramar `#2B3BC7`, bermellon `#D93325`, naranja `#E8501A`, ambar `#F2C744`, verde `#00A95C`, rosa `#FF48B0`, violeta `#765BA7`, humo `#1A1A1A` | Los tambores son para el contenido, nunca para el cromo de la interfaz. El vocabulario `TAMBOR` del pliego nombra siete (todos menos `humo`); la materia de risografía (`TAMBOR_RISO`) acepta también `humo`, `tinta` y `azurita`. La obra nueva DEBE usar este papel y esta tinta; los cremas antiguos `#F2EEE4` y `#F6F0E2` son legado. ### 16.3 Azar Todo el azar de Tórculo es determinista y se deriva de tres funciones, que toda implementación DEBE calcular bit a 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` devuelve dobles que son múltiplos exactos de 2^−32; `hash32` devuelve valores que son exactos en un flotante de 32 bits. Nada puede usar el reloj del sistema, `Math.random` ni un generador sin semilla. Las semillas se calculan sobre **UTF-8**; un antiguo auxiliar de Scholaris en TypeScript sembraba sobre unidades de código UTF-16, lo que solo coincide en ASCII: esa es una de las razones por las que los identificadores DEBERÍAN ser ASCII. Los vectores de prueba son normativos: `conformance/canon/vectores.json` da, para un conjunto de textos (vacío, ASCII, con tildes, `ñ`, CJK y un carácter fuera del BMP), la semilla, los ocho primeros valores de la serie como enteros antes de la división, y el `hash32` de la semilla y de cinco enteros fijos. Una implementación del canon en cualquier lenguaje DEBE reproducirlos. ### 16.4 Oficio y foley `oficio` (el oficio, Lasseter en números; ningún pliego los escribe, el motor los aplica): `palabras_por_minuto = 220` y `asiento_lectura = 1.0` s (tiempo de lectura de un texto), `fotogramas_minimos = 8` (a 24 fps, nada se mueve durante menos), `simultaneos_maximos = 3`, `pausa_fin_beat = 0.6` s, `anticipacion = 0.2` (fracción de la acción), `exageracion = 1.25`, `hervor_fps = 8`, `hervor_poses = 3`, `dibujo_en = 2` (lo dibujado, a dos fotogramas). Un canon de una versión posterior PUEDE añadir claves; las implementaciones DEBEN ignorar las claves que no conocen. `foley`: el peso relativo de cada evento de foley (el oído no oye una tecla como un sello): 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. --- # Parte 5. Láminas ## 17. Láminas {#laminas} Una lámina es un dibujo a mano listo para que cualquier motor (web, app, juego, vídeo) lo haga aparecer bajo la pluma **sin volver a calcular la mano**: la imagen se rasteriza una vez y, a su lado, un **atlas de tiempo** dice en qué instante llega la pluma a cada píxel. ### 17.1 Dos envoltorios, el mismo contenido - **Directorio** `name.lamina/` con los ficheros de §17.2. - **Empaquetada**, un único fichero `name.lamina`: | Bytes | Contenido | |---|---| | de 0 a 7 | la firma `LAMINA\0\x01` (`4C 41 4D 49 4E 41 00 01`) | | de 8 a 11 | `n`, la longitud del índice, u32 little-endian | | de 12 a 12+n | el índice, JSON en UTF-8: `{"archivos": [{"ruta", "inicio", "largo"}, …]}` | | desde 12+n | los ficheros uno tras otro; `inicio` cuenta desde aquí | Las rutas del índice son las rutas del directorio. Un lector distingue los dos casos por la firma. ### 17.2 Ficheros ```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/-.png colour atlas of a layer in a pose capas/--tiempo.png time atlas of that layer in that pose ``` (`manifiesto.json`: lo que hay y cómo se compone, siempre el primero; `geometria.json`: la geometría vectorial de cada pose, opcional; `vista.png`: el dibujo terminado sobre papel, pose 0, como vista previa; `capas/-.png`: el atlas de color de una capa en una pose; `capas/--tiempo.png`: el atlas de tiempo de esa capa en esa pose.) Todas las imágenes de una lámina tienen el mismo tamaño: `tamano.ancho` × `tamano.alto` píxeles, la caja del dibujo por su escala (2 por defecto). **Atlas de color:** PNG RGBA de 8 bits **con alfa premultiplicado** (el PNG declara alfa directo; un lector DEBE cargarlo sin tocar los valores: en WebGL, `createImageBitmap(blob, {premultiplyAlpha: 'none', colorSpaceConversion: 'none'})` y `UNPACK_PREMULTIPLY_ALPHA_WEBGL = false`). Sin papel: lo que no tiene tinta es transparente. **Atlas de tiempo:** PNG RGB de 8 bits. En cada píxel, `R·256 + G` es el instante normalizado a 16 bits, `t = (R·256 + G) / 65535`, con 0 el comienzo y 1 la `duracion` de la lámina; `B` vale 255 donde la capa tiene tinta y 0 en el resto (y entonces R y G no significan nada). DEBE muestrearse **sin filtrado** (vecino más próximo o `texelFetch`). Donde se cruzan dos piezas de la misma capa, gana el instante más temprano. | Pieza | Instante de un píxel | |---|---| | tinta y color (pluma) | el del punto más cercano de su línea central; a lo largo de la línea, `inicio + duracion · B⁻¹(arc/length)`, con `B` la Bézier cúbica (0.55, 0.1, 0.45, 0.95) | | lápiz | lo mismo, lineal: `inicio + duracion · arc/length` | | plano | un pincel en diagonal: `inicio + 0.7 s · f`, con `f` la posición a lo largo de la diagonal de su caja | | nota | escrita de izquierda a derecha, línea tras línea, en 0.9 s | ### 17.3 Capas En este orden, solo las que tienen algo: `lapiz` (normal), `planos` (multiplicar), `tinta` (normal), `color` (multiplicar, con el desplazamiento de fuera de registro), `encima` (multiplicar, con el desplazamiento), `notas` (normal; no hierve: todas sus poses apuntan a la misma imagen). ### 17.4 Hervor `hervor.variantes` poses (3 por defecto). La pose 0 es el dibujo de siempre; las demás tienen la misma geometría y el mismo ritmo y solo cambian el temblor. En reproducción, `pose = floor(seconds_at_rest · fps + offset) mod variantes` (los segundos en reposo por los fps, más el desfase), con `fps = 8` y el desfase escrito en el manifiesto (`hash32(semilla(id)) · variantes`). Mientras la pluma dibuja, se muestra la pose 0; el hervor empieza cuando el dibujo está entero (`al_reposar: true`). ### 17.5 El revelado Para cada capa, de abajo arriba, con `progress` de 0 a 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` empieza siendo el papel. El adelanto de 1.03 garantiza que con `progress = 1` todo está dibujado; la pendiente 60 da un frente de tinta de 1/60 de la duración. Los dos números están en el manifiesto (`revelado`). ### 17.6 El manifiesto `manifiesto.json` tiene: `formato` (`"lamina"`), `version` (1), `id` (el id y la semilla del dibujo, en ASCII), `titulo` y `descripcion` (para los lectores de pantalla, en la lengua de la lámina), `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` (por capa: `nombre`, `mezcla`, `desplazamiento`, `hierve`, y las rutas de `color` y `tiempo` por pose), `trazos` (el orden de la mano: `indice`, `capa`, `elemento`, `pasada`, `modo` (`lineal`, `pluma`, `pincel`, `escritura`), `inicio`, `duracion`, `t0`, `t1`), `trayectoria` (dos herramientas, `lapiz` y `pluma`, cada una una lista de `[ms, x, y, down]` en unidades de dibujo, con milisegundos que nunca decrecen), `geometria` (ruta o null), `vista` y `canon` (`version`, `semilla`, `serie`). `geometria.json` da, por pose y por trazo en el orden de la mano: `tipo` (`cinta`, `linea`, `relleno`, `nota`), su capa y sus índices, cómo se pinta, `inicio`, `duracion`, `modo`, la línea central temblada `puntos`, el `arco` acumulado, la anchura `ancho` por punto, la llegada `llegada` por punto, el `contorno` y, para las notas, su texto, posición, tamaño, rotación y ancla. Los números se redondean a milésimas. ### 17.7 Garantías - **Determinismo.** La misma lámina sale idéntica byte a byte en Rust nativo, en Python y en WebAssembly: el azar es el del canon y nada lee el reloj. La batería da el SHA-256 de tres láminas empaquetadas (casos `lamina`); un productor DEBE reproducirlos. - **Fidelidad.** La pose 0 es el mismo dibujo que el SVG del motor de dibujo a mano (diferencia media inferior a medio nivel de gris, por el antialiasing). - **Ids en ASCII** (§4.5). ### 17.8 Memoria Cada capa en cada pose son dos texturas de `width × height × 4` bytes (ancho por alto por 4). Los lectores DEBERÍAN permitir a los productores bajar la escala o las variantes en los dibujos grandes. ### 17.9 Diagnósticos `L001` firma incorrecta, `L002` índice incorrecto, `L003` falta un fichero de la lista, `L004` manifiesto incorrecto o incompleto, `L005` una imagen de tamaño equivocado, `L006` un PNG de tipo equivocado, `L007` un atlas de tiempo cuyo canal azul no es 0 ni 255, `L008` capas desordenadas o con la mezcla o el número de poses equivocados, `L009` trazos, `L010` trayectoria, `L011` parámetros de hervor o de revelado. El validador de referencia es `conformance/tools/lamina.py`. --- # Parte 6. Materias ## 18. Materias: la convención de pasadas {#materias} ### 18.1 Qué es una materia Una materia convierte un plano limpio en papel, acuarela, pintura, risografía, punto de tejido o una transición. Es una o varias **pasadas de cómputo WGSL** en una convención común, de modo que cualquier anfitrión (la cadena de posproceso del motor, una biblioteca, una herramienta) la ejecuta tal cual. La biblioteca de referencia es `materias/` (Rust + WGSL) y el `m.Pass` del motor (§19.6). ### 18.2 Grupo 0: la convención Toda pasada de una materia de plano enlaza exactamente: | Enlace | Nombre | Tipo | |---|---|---| | `@group(0) @binding(0)` | `entrada` | `texture_2d`: la entrada, **en luz lineal, premultiplicada**, en flotantes de media precisión | | `@group(0) @binding(1)` | `muestreo` | `sampler`: bilineal, sujeto a los bordes | | `@group(0) @binding(2)` | `plano` | `var Plano` | | `@group(0) @binding(3)` | `salida` | `texture_storage_2d`: la salida, en la misma forma | ```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, // 32: sixteen parameters } // 96 bytes ``` (`tiempo` es el tiempo de la escena en segundos, nunca el reloj del sistema; `paso` queda libre para la materia, como paso de simulación o número de pasada; `params` son dieciséis parámetros; la estructura ocupa 96 bytes.) Una materia DEBERÍA obtener el grupo 0 con `#import plano` en lugar de declararlo. ### 18.3 Grupos 1 y 2 Lo que es propio de una materia va en `@group(1)`: las texturas que lee o escribe, los búferes. En el motor, el `@group(1)` de una pasada contiene solo sus imágenes (una plancha, el plano saliente de una transición), una textura muestreada por enlace desde el 0, en el orden dado. **El estado persistente** va en `@group(2)`: en el enlace 0, el estado tal como está (una textura); en el enlace 1, el siguiente (una textura de almacenamiento `rgba16float`); antes de la pasada, su punto de entrada de paso se ejecuta un número fijo de veces por fotograma, cada una del estado al siguiente, intercambiándolos. Una materia NO DEBE enlazar otros grupos, y NO DEBE repetir un enlace. ### 18.4 Determinismo El único tiempo que ve una pasada es el de la escena (`plano.tiempo`, `plano.fotograma`). Las materias con estado (la acuarela) avanzan en **pasos fijos de 60 Hz**: dos ejecuciones dan los mismos píxeles. Un fotograma sostenido también avanza; retroceder en el tiempo vuelve a empezar el estado desde cero. Una materia NO DEBE leer el reloj del sistema. ### 18.5 Módulos y cadenas `#import name` pega un módulo una vez (un preprocesador de la biblioteca). Módulos compartidos: `canon` (paleta y `hash32`, generados a partir del canon), `comun` (sRGB y lineal, PCG, ruido de valor, fbm, ruido de gradiente entrelazado, `sobre`), `plano` (la convención), `campos_papel` (los once campos del papel y `color_papel`), `espectral` (transmitancia en 16 bandas y reconstrucción espectral). Una cadena de materias se escribe `materia(key=value, …) > materia > …`; los valores son números, nombres que la materia entiende (`tipo=khadi`, `tambor1=rosa`) o colores `#RRGGBB`. Los puntos de entrada son puntos de entrada de cómputo con `@workgroup_size`; una pasada que escribe `salida` DEBERÍA tomar `@builtin(global_invocation_id)` y tratar un píxel por invocación. ### 18.6 Diagnósticos `M001` ni importa `plano` ni declara el grupo 0 de la convención, `M002` el grupo 0 no es exactamente el de la convención, `M003` `Plano` no es la estructura de la convención, `M004` un punto de entrada que no es de cómputo o al que le falta `@workgroup_size`, `M005` recursos propios fuera de los grupos 1 y 2, o un enlace repetido, `M006` lee un reloj. El comprobador de referencia es `conformance/tools/materias.py`; la compilación y los fotogramas de referencia los prueban las pruebas propias de la biblioteca (`cargo test --release` en `materias/`). --- # Parte 7. Tomas y la API pública ## 19. Tomas y la API pública {#takes} ### 19.1 El motor El motor de referencia es un fork de ManimGX (Rust y wgpu, con la API de Python de Manim Community Edition), rama `seams`. Todo lo que el fork añade está **desactivado por defecto**: si no se usa nada de ello, el motor dibuja exactamente como el original (*upstream*), píxel a píxel en el corpus de referencia. Las tomas propias del fork tienen versiones propias (§19.3), que los lectores del original rechazan. ### 19.2 El flujo de la toma Una toma registra una ejecución del motor como las llamadas del motor: formas, pinceles e imágenes subidas bajo sus claves, y luego fotogramas (una vista y sus registros, mostrados durante cierto número de fotogramas). Es un único flujo de **mensajes**, en little-endian: ```text message = length:u32 opcode:u8 fields… (length counts the opcode and the fields) bytes = length:u32 data… ``` (La longitud cuenta el código de operación y los campos.) El primer mensaje DEBE ser START; una toma completa termina con END. Los lectores DEBEN rechazar una toma cuyo primer mensaje no sea START, cuya versión no conozcan, que contenga un código de operación desconocido, un mensaje más largo que lo que queda, un segundo START o cualquier cosa después de END. | Código | Mensaje | Campos | |---|---|---| | 14 | START | versión u32, anchura u32, altura u32, cadencia f64 | | 1 | PATH | clave u64, centroide y área f32 × 6, claves de array (puntos, subtrayectos) | | 2 | POINTS | clave u64, clave de array | | 3 | MESH | clave u64, contorno u32, bloque u32, claves de array | | 4 | ROWS | clave u64, clave de array (las filas de un pincel) | | 5 | TEXTURE | clave u64, anchura u32, altura u32, clave de array (RGBA8) | | 6 | GROW | clave u64, cerrado u8, clave de array | | 8 | FRAME | repetición u32, vista (bytes), clave de registros u64, número de cámaras u32 y, por cámara: clave u64, anchura u32, altura u32, vista (bytes), clave de registros u64 | | 9 | NOTE | bytes: JSON en UTF-8 (las jugadas, las secciones y los rótulos) | | 10 | SOUND | bytes: un fichero de audio que el reproductor reproduce junto a los fotogramas | | 11 | ARRAY | clave u64, clave base u64 (0: ninguna), tipo u8, codificación u8, bytes (zstd) | | 12 | END | fallida u8 | | 13 | ENVIRONMENT | id u32, anchura u32, altura u32, clave de array | | 15 | POST | bytes: la descripción de la cadena de posproceso (solo en `0x8000_0002`, justo después de START) | | 16 | MATERIAL | id u32, bytes: código fuente WGSL (en `0x8000_0002`; código 15 en `0x8000_0001`) | Las subidas se retienen hasta que un fotograma las muestra; los arrays se envían una vez bajo una clave de su tipo y su contenido (un resumen opaco de 64 bits: los lectores DEBEN tratar las claves como opacas) y se codifican respecto del array al que sustituyen: `ALONE` (0), `FIRST` (diferencia respecto de la base), `SECOND` (diferencia respecto de la predicción lineal), `TAIL` (la base es su comienzo), carril a carril y comprimidos con zstd, con un fotograma clave cada 32 versiones. Los registros de un FRAME ocupan 424 bytes cada uno (ocho claves de 8 bytes, banderas, dos matrices de 3 × 4, pinturas, parámetros, trazo discontinuo, material, el id de la materia u32, la mezcla u32, un id de usuario u64 y dieciséis flotantes de usuario). El número de fotogramas de una toma es la suma de las repeticiones de los mensajes FRAME. ### 19.3 Versiones | Versión | Registros | Códigos 15 y 16 | Lectores | |---|---|---|---| | `0x8000_0001` | 424 B | 15 = MATERIAL | DEBE leerse | | `0x8000_0002` | 424 B | 15 = POST, 16 = MATERIAL | la escribe el motor de Tórculo 1.0 | El rango de `0x8000_0000` en adelante es del fork; las versiones del original están por debajo. Un escritor de tomas de este estándar DEBE escribir `0x8000_0002`. Una disposición o un código de operación nuevos toman la versión siguiente. ### 19.4 Diagnósticos `T001` el primer mensaje no es START, `T002` versión desconocida, `T003` un mensaje más largo que la toma, `T004` código de operación desconocido, `T005` START repetido o datos después de END, `T006` POST no va justo después de START, `T007` un NOTE o un MATERIAL que no es UTF-8 válido (JSON, en el caso de NOTE). El lector de referencia es `conformance/tools/toma.py`. ### 19.5 Determinismo del motor Los sombreadores ven el tiempo de la escena (o el índice del fotograma), nunca el reloj. La misma escena, renderizada dos veces en la misma máquina y la misma GPU con el mismo motor, da los mismos bytes; entre GPU distintas no se garantiza, y por eso las huellas se comparan con tolerancia (§13.4). Las semillas de las materias, del fuera de registro y del hervor salen de la `semilla` del canon aplicada al nombre de una pieza (`set_material(…, pieza="c1_09/rosa")`), nunca de un contador. ### 19.6 La API pública **Estabilidad.** Las interfaces de esta sección son públicas en Tórculo 1.0: solo cambian mediante una RFC. Todo lo demás del fork es interno. Python (`import manimgx as m`; la API de Manim CE, véase la guía propia del motor): | Interfaz | Qué | |---|---| | `m.config.post = [m.Papel(), m.Bobina("truca")]` | la cadena de posproceso: pasadas sobre cada fotograma terminado; el grano vive en las pausas | | `m.Pass(shader, entry=None, reach=…, moves=…, params=(), paths=(), pictures=…, estado=None, pasos=…)` | cualquier pasada en la convención de la parte 6, con las imágenes en `@group(1)` y el estado persistente en `@group(2)` | | `m.Papel(plate=None, …)`, `m.Bobina(reel="truca", lut_in=None, lut=None, papel=canon paper, …)` | el baño de imprenta y la película de la casa | | `m.config.compositing = "linear"` | componer en luz lineal (flotantes de media precisión); por defecto, sRGB | | `mobject.set_material(name, …, pieza=None)`, `m.register_material(name, wgsl, params)` | materias por objeto (`papel`, `acuarela`, `riso`, y las registradas que definen `fn materia(m: Materia) -> vec4`) | | `mobject.set_blend("normal" | "multiplicar")` | cómo descansa un objeto sobre lo que tiene debajo | | `mobject.set_clip("mascara" | "dentro" | "fuera", name)` | recorte por forma en la composición | | `m.Trazo(points, widths, tiempos=None, grano=None)`, `m.Trazo.de_pluma(stroke)` | el trazo de pluma de anchura variable, que `Create` dibuja al ritmo de la mano | | `m.Hervor(drawing, poses=3, fps=8, desfase=True, gpu=False)` | la línea que vive en reposo | | `m.sidecar(pliego | tiempos.json | folder)` | la voz real de un pliego como voz de `self.say`, sincronizada por palabra; sin voz, la voz por defecto lanza un error en lugar de llamar a un servicio de pago | Línea de órdenes: `manimgx render scene.py [--codec h264 | hevc | prores | prores4444] [--take] [-r WxH] [--fps N] [--sound-events]`. HEVC Main10 y ProRes usan VideoToolbox (macOS); ProRes 4444 lleva alfa, sin premultiplicar. **Los binarios que incluyen x264 (`--codec h264`) son GPL; las compilaciones solo con VideoToolbox no lo son** (`DECISIONES.md`). Los errores estrictos son lo predeterminado: el LaTeX mal formado y los avisos de Typst fallan en la línea de la escena; `--no-strict` los convierte en avisos. Rust: el crate `manimgx-render` (`Replay::read(&bytes)`, `replay.render(i)` a RGBA, `Gpu::from_device(…)` para dibujar en el dispositivo de otra aplicación). Web: `` reproduce una toma con WebGPU, sin Python; necesita mezcla en float32 y `depth32float-stencil8` (Chrome y Edge 113 y posteriores, Safari 26). --- ## 20. Consideraciones de seguridad {#security} - **Compilar NO DEBE ejecutar código del proyecto.** Un compilador comprueba y compila un pliego y lee su bestiario sin ejecutarlo (§12). Un empaquetador descubre los ficheros de la misma manera (§14.1). - **Renderizar ejecuta el bestiario.** Un pliego con `PYTHON` o `PIEZAS` ejecuta ese código cuando se renderiza: un intérprete DEBE tratar un pliego así como un programa, y un visor de proyectos que no son de confianza NO DEBE renderizarlos fuera de un entorno aislado. Una servilleta o un pliego sin bestiario no ejecuta nada más que el motor. - **Los paquetes** pueden llevar rutas peligrosas (§14.2): los lectores DEBEN rechazarlas antes de escribir nada, verificar los hashes y acotar el tamaño total sin comprimir. - **Las tomas llevan código fuente de sombreadores** (MATERIAL, POST) que se ejecuta en la GPU. WebGPU y wgpu lo validan, pero una toma hostil aún puede agotar recursos: los reproductores DEBERÍAN acotar el número de materiales, el tamaño de los arrays y de las texturas, y el tamaño descomprimido de cada ARRAY, y DEBEN rechazar una toma que incumpla §19.2. - **Las láminas** están acotadas por su manifiesto; un lector DEBERÍA rechazar una lámina cuyos tamaños de imagen o número de capas superen su presupuesto de memoria (§17.8). - **Sin red durante el render.** Las voces, la música y los efectos vienen del proyecto; un intérprete NO DEBE llamar a un servicio de pago o remoto mientras renderiza. ## 21. Consideraciones de privacidad {#privacy} - Las grabaciones de voz son datos personales de quien habla. Un paquete las lleva; su manifiesto dice cuántas tomas de cada método tiene, nunca quién las grabó, salvo que lo declare el reparto. - Las rutas absolutas revelan nombres de usuario y estructuras de carpetas (`/Users/name/Library/Caches/…`). Los sidecars DEBERÍAN usar rutas relativas, y los paquetes DEBEN usarlas (§14.3). - El manifiesto registra los commits y las versiones de las herramientas, no la máquina. ## 22. Versiones y compatibilidad {#versioning} - **La constitución de la compatibilidad: un pliego que compiló una vez compila siempre.** La época se declara en el preámbulo (`MESA v2`); un compilador DEBE compilar todo pliego de toda época que declare soportar, y DEBERÍA leer la época 1 (`SPEC-MESA.md`) como legado. El vocabulario de una época está congelado, palabras reservadas incluidas. - Una época nueva PUEDE añadir palabras y líneas; NO DEBE cambiar el significado de un pliego válido de una época anterior. Retirar una palabra solo es posible declarándola legado en una época nueva, y los compiladores siguen aceptándola en los pliegos que declaran la antigua. - El IR no se versiona (§10.1): los intérpretes DEBEN ignorar los campos y los verbos desconocidos. - Las versiones mayores de `mesapack` son incompatibles entre sí (`mesapack 2` sería otro formato); las menores (`mesapack 1.1`) solo añaden miembros que los lectores pueden ignorar. - La versión 1 de las láminas se escribe en la firma y en el manifiesto; una disposición nueva toma la versión 2. - Las versiones de las tomas figuran en §19.3. - La `version` del canon cambia cuando cambia cualquier valor; los ficheros generados la llevan. - La especificación se numera MAYOR.MENOR con publicaciones editoriales (`spec-v1.0.0`); su número y los de las bibliotecas son independientes (`governance/VERSIONING.md`). ## 23. Tipos de medio e identificación de ficheros {#media-types} Propuestos, no registrados: | Extensión | Tipo de medio | Identificación | |---|---|---| | `.mesa` | `text/vnd.torculo.mesa; charset=utf-8` | texto UTF-8 cuya primera línea que no es comentario empieza por `MESA` (o prosa: una servilleta) | | `.mesapack` | `application/vnd.torculo.mesapack+zip` | un ZIP con `MANIFIESTO.json` cuyo `formato` empieza por `mesapack` | | `.lamina` | `application/vnd.torculo.lamina` | la firma `LAMINA\0\x01` (un directorio `.lamina/` tiene `manifiesto.json`) | | `.take` | `application/vnd.torculo.take` | primer mensaje START (código 14) con una versión desde `0x8000_0001` | | `.tiempos.json` | `application/json` | junto a un pliego con la misma raíz de nombre | ## 24. Internacionalización {#i18n} La lengua de Tórculo es el español: las palabras clave, los vocabularios y los diagnósticos son palabras españolas, y las tildes son significativas donde el español las hace significativas (§4.5, palabras reservadas). El texto en pantalla es lo que escriba el autor, en cualquier escritura, normalizado a NFC. Los compiladores DEBERÍAN escribir sus mensajes en español y PUEDEN ofrecer traducciones; los códigos no dependen de la lengua. Un juego de palabras clave localizado (por ejemplo, palabras clave inglesas que lleven al mismo IR) sería un dialecto nuevo y necesita una RFC; el IR, que es el contrato, no cambiaría. --- ## Apéndice A. Vocabularios cerrados {#appendix-a} Generado a partir de `spec/vocabularios/vocabularios.json`, que se extrae del analizador de referencia. Cada vocabulario da su perfil, la estructura de la que procede y sus palabras en forma canónica (sin tildes, §4.5); un compilador las acepta con tildes o sin ellas. ### Perfil: núcleo **`ACCION_FICHA`** (15 palabras; Fuente: `formato.aspecto.ACCIONES`) anda · aplaude · baila · cae · celebra · corre · gesticula · gira el dial · grita · habla · recoge · salta · se levanta · senala · señala **`AFECTO`** (8 palabras; Fuente: `formato.vocabulario.AFECTOS`) contenido · euforico · exhausto · jugueton · nervioso · seco · sereno · solemne **`ALTURA`** (5 palabras; Fuente: `formato.continuidad.ALTURAS`) cenital · contrapicado · nadir · normal · picado **`ANCLA`** (5 palabras; Fuente: `formato.vocabulario.ANCLAS`) bordado · celo · chincheta · esquineras · washi **`ARCO`** (6 palabras; Fuente: `formato.vocabulario.ARCOS`) espiral · letania · pregunta→respuesta · ruina · tesis→antitesis→sintesis · viaje y vuelta **`AUTORIDAD`** (34 palabras; Fuente: `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 palabras; Fuente: `formato.continuidad.AVISOS`) RACCORD DE DIRECCIÓN · RACCORD DE ESTADO · RACCORD DE MIRADA · SALTO DE EJE · SALTO DE TALLA **`BOBINA`** (3 palabras; Fuente: `formato.aspecto.BOBINAS`) noticiario · sin grano · truca **`CLAVE_MANO`** (7 palabras; Fuente: `formato.taller.MANO_BASE`) cansa · entra · granulado · precision · pulso · sale · toca la truca **`CLAVE_VIS`** (68 palabras; Fuente: `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 palabras; Fuente: `formato.aspecto.DESREGISTROS`) desregistrada · en registro **`DIMENSION`** (10 palabras; Fuente: `formato.precedencia.DIMENSIONES`) color_estrato · curva · fondo · nombre · sitio · sombra · tamaño · tiempo · velocidad_estrato · z **`DIRECCION_LUZ`** (5 palabras; Fuente: `formato.vocabulario.DIRECCIONES_LUZ`) cenital · de atras · de frente · de la derecha · de la izquierda **`DISPOSICION`** (8 palabras; Fuente: `formato.vocabulario.DISPOSICIONES`) amontonados · como flores · en abanico · en columna · en corro · en fila · en fila holgados · en rejilla **`DUREZA`** (2 palabras; Fuente: `formato.vocabulario.DUREZAS`) blanda · dura **`ESPEJO_LADO`** (2 palabras; Fuente: `formato.aspecto.ESPEJO_LADOS`) de la derecha · de la izquierda **`EVENTO`** (163 palabras; Fuente: `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 Reservados: ninguno. **`EVENTO_A_CAMPO`** (8 palabras; Fuente: `formato.vocabulario.EVENTO_A_CAMPO`) Correspondencia: 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 palabras; Fuente: `formato.aspecto.EXPRESIONES`) duda · se asombra · se asusta · se calma · se enfada · se entristece · se pone serio · se rie · sonrie **`FAMILIA_TALLER`** (10 palabras; Fuente: `formato.taller.TALLER_BASE`) ancla · bano · canto · fantasma · materia · papel · reticula · sombra · tinta · vida **`FORMATO`** (6 palabras; Fuente: `formato.aspecto.FORMATOS`) 16:9 · 1:1 · 2,39:1 · 4:3 · 4:5 · 9:16 **`FORMATO_MODO`** (2 palabras; Fuente: `formato.aspecto.FORMATO_MODOS`) bandas de papel · de television **`FRENTE`** (5 palabras; Fuente: `formato.continuidad.FRENTES`) escorzo · espalda · frontal · perfil · tres cuartos **`FUNCION`** (11 palabras; Fuente: `formato.vocabulario.FUNCIONES`) apertura · cartel · contrapunto · digresion · eco · giro · ilustracion · prueba · remate · respiro · tesis **`GESTO_MARCA`** (4 palabras; Fuente: `formato.vocabulario.GESTO_MARCA`) rodea · senala · subraya · tacha **`GRANULADO`** (4 palabras; Fuente: `movimiento.GRANULADOS`) a doses · a pulso · a treses · a unos **`HERVOR`** (3 palabras; Fuente: `formato.aspecto.HERVORES`) dibujado · no · suave **`HORA`** (5 palabras; Fuente: `formato.vocabulario.HORAS`) amanece · atardece · diurna · mediodia · nocturna **`LADO`** (4 palabras; Fuente: `formato.vocabulario.LADOS`) abajo · arriba · derecha · izquierda **`LEJANIA`** (8 palabras, con orden; Fuente: `viaje.LEJANIAS`) al pie · al paso · cerca · a media distancia · lejos · al fondo · en el horizonte · en el cielo **`LINEA_UNIDAD_ASPECTO`** (20 palabras; Fuente: `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 palabras; Fuente: `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 palabras; Fuente: `formato.aspecto.MATERIAS`) acuarela · ninguna · papel · pincel · risografia · tejido · tinta **`MODO`** (3 palabras; Fuente: `formato.continuidad.MODOS`) cartel · documento · mundo **`MONTAJE`** (6 palabras; Fuente: `formato.aspecto.MONTAJES`) al pulso · al ritmo de las palabras · cada vez mas cerca · la camara no para · mezcla · se acelera **`MOVIMIENTO_MUNDO`** (4 palabras; Fuente: `formato.vocabulario.MOVIMIENTO_MUNDO`) acelera · avanza · frena · para **`NOMBRE_SECCION`** (6 palabras; Fuente: `formato.taller.SECCIONES`) BESTIARIO · CASCADA · MANO · MONTAJE · REPARTO · TALLER **`ORDEN_TRUCA`** (9 palabras; Fuente: `formato.vocabulario.ORDEN_TRUCA`) baja · busca a · encuadra a · se acerca · se acerca a · se queda · sigue a · sube · viaja con **`PALABRA_RESERVADA`** (76 palabras; Fuente: `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 palabras; Fuente: `formato.aspecto.PAPELES`) cuaderno · escolar · grano fino · khadi · kraft · lienzo · satinado · tintado · torchon · verjurado · washi **`PARTE_CUERPO`** (7 palabras; Fuente: `formato.vocabulario.PARTES_CUERPO`) el hombro · el pecho · el regazo · la cabeza · la espalda · las manos · los pies **`PLANO_DE`** (11 palabras; Fuente: `formato.vocabulario.PLANO_DE`) Correspondencia: apertura → orla · cartel → cartel · contrapunto → contraplano · digresion → mapa · eco → documento · giro → primerisimo · ilustracion → contraplano · prueba → documento · remate → primerisimo · respiro → general · tesis → documento **`PLANTILLA`** (8 palabras; Fuente: `formato.vocabulario.PLANTILLAS`) cartel · contraplano · documento · general · mapa · nocturno · orla · primerisimo **`RASTRO`** (4 palabras; Fuente: `formato.aspecto.RASTROS`) con borron · con estela · con lineas de fuerza · en cronofotografia **`REGISTRO_LETRERO`** (6 palabras; Fuente: `formato.vocabulario.REGISTROS_LETRERO`) cartulina · cita · cita maquina · cita moderna · mano · rescate **`REGISTRO_LETRERO_RESERVADO`** (3 palabras; Fuente: `formato.vocabulario.REGISTROS_LETRERO_RESERVADOS`) dymo · maquina · tira **`REGISTRO_MATERIA`** (4 palabras; Fuente: `materia.REGISTROS`) fotografico · pintado · recorte · tinta **`REGISTRO_MOV`** (1 palabras; Fuente: `movimiento.REGISTROS`) en dos **`RIO_MODO`** (3 palabras; Fuente: `formato.aspecto.RIO_MODOS`) a pantalla completa · en fila · en libertad **`SENTIDO`** (2 palabras; Fuente: `formato.vocabulario.SENTIDOS`) de espaldas · de frente **`SIMULTANEO`** (3 palabras; Fuente: `formato.aspecto.SIMULTANEOS`) en abanico · en abanico que gira · en rejilla **`SUSTRATO`** (14 palabras; Fuente: `pieza.SUSTRATOS`) acetato · cartulina · dymo · ficha · foto · kraft · milimetrado · papel · periodico · pijama · polaroid · postit · tira · vegetal **`TALLA`** (7 palabras, con orden; Fuente: `formato.continuidad.TALLAS`) general · conjunto · medio · americano · corto · primer · detalle **`TAMBOR`** (7 palabras; Fuente: `formato.vocabulario.TAMBORES_V`) ambar · bermellon · naranja · rosa · ultramar · verde · violeta **`TAMBOR_RISO`** (10 palabras; Fuente: `formato.aspecto.TAMBORES_RISO`) ambar · azurita · bermellon · humo · naranja · rosa · tinta · ultramar · verde · violeta **`TENSION`** (4 palabras; Fuente: `formato.vocabulario.TENSIONES`) cae · mantiene · rompe · sube **`TRAMA`** (3 palabras; Fuente: `formato.aspecto.TRAMAS`) de grano · de lineas · de puntos **`TRANSICION`** (16 palabras; Fuente: `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 palabras; Fuente: `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 palabras; Fuente: `movimiento.VENTANAS`) hasta decir · mientras **`VERBO_MOV`** (24 palabras; Fuente: `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 palabras; Fuente: `movimiento.VERBOS_RELACIONALES`) agarra · alcanza · arrastra · cuelga · empuja · esquiva · huye · orbita · se apoya · sigue · suelta **`VISTA`** (5 palabras; Fuente: `formato.aspecto.VISTAS`) de espaldas · de frente · de perfil · de tres cuartos · de tres cuartos de espaldas ### Perfil: sonido **`ESPACIO`** (5 palabras; Fuente: `formato.aspecto.ESPACIOS_SALA`) estadio · estudio · patio · radio · seco **`MEZCLA`** (4 palabras; Fuente: `formato.aspecto.MEZCLAS`) con stems · para cine · para la web · sin stems **`VOZ`** (6 palabras; Fuente: `formato.sonido.VOCES`) cita · cita_f · cita_f2 · cita_f3 · cita_m2 · narrador ### Perfil: cartel **`BOSQUE`** (5 palabras; Fuente: `formato.cartel.BOSQUES`) brazos · brazos y punos · manos · manos abiertas · punos **`COLOR_CARTEL`** (16 palabras; Fuente: `formato.cartel.COLORES`) amarillo · arena · azul · blanco · celeste · crema · lila · minio · morado · naranja · negro · rojo · rosa · tinta · ultramar · verde **`COMPOSICION`** (15 palabras; Fuente: `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 palabras; Fuente: `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 palabras; Fuente: `formato.cartel.DISPOSICIONES`) a sangre · en abanico · en columna · en escalera · girada · rota por el borde **`EVENTO_CARTEL`** (5 palabras; Fuente: `formato.cartel.EVENTOS`) la costura se mueve hacia · la mancha deja · la tela se desenreda · la tela se enreda · se desteje **`FORMA_PALABRA`** (5 palabras; Fuente: `formato.cartel.FORMAS`) el patio · un marco · un muro · una columna · una porteria **`LINEA_UNIDAD_CARTEL`** (3 palabras; Fuente: `formato.cartel.UNIDAD`) CARTEL · PALETA · PARTITURA **`PAPEL_SIGNO`** (9 palabras; Fuente: `formato.cartel.ROLES`) barandilla · cielo · cuchilla · mascara · muro · persiana · porteria · suelo · ventana **`SITIO_SIGNO`** (5 palabras; Fuente: `formato.cartel.SITIOS`) a la derecha · a la izquierda · abajo · arriba · en el centro **`TIPO_LETRA`** (6 palabras; Fuente: `formato.cartel.TIPOS`) anton · la serifa de pretexto · league gothic · letra de mano · maquina de escribir · serifa **`VERBO_SIGNO`** (14 palabras; Fuente: `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 ### Perfil: oído **`DIRECCION_FUENTE`** (4 palabras; Fuente: `formato.oye.DIRECCIONES_LUZ`) desde abajo · desde arriba · desde la derecha · desde la izquierda **`EVENTO_OYE`** (14 palabras; Fuente: `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 palabras, con orden; Fuente: `formato.oye.INTENSIDADES`) nula · quieta · serena · templada · viva · agitada · tensa · encendida · desatada · furiosa · rota **`PISTA`** (5 palabras; Fuente: `formato.oye.PISTAS`) la cama · la musica · la radio · la voz · los efectos **`SOPORTE`** (5 palabras, con orden; Fuente: `formato.oye.SOPORTES`) limpio · usado · gastado · sucio · roto ### Perfil: cámara **`BANDA_CUADRO`** (4 palabras; Fuente: `formato.camara.BANDAS`) de abajo · de arriba · de la derecha · de la izquierda **`BLANCO_CADENCIA`** (6 palabras; Fuente: `formato.camara.BLANCOS_CADENCIA`) el fondo · la camara · la letra · las figuras · lo de delante · todo **`CADENCIA`** (4 palabras, con orden; Fuente: `formato.camara.CADENCIAS`) en uno · en dos · en tres · en cuatro **`DISTANCIA`** (9 palabras, con orden; Fuente: `formato.camara.DISTANCIAS`) delante · al pie · cerca · al paso · a media distancia · lejos · al fondo · en el horizonte · en el cielo **`ENCUADRE_INCOMODO`** (7 palabras; Fuente: `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 palabras; Fuente: `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 palabras; Fuente: `formato.camara.GOLPES`) con borron · con impacto **`HORIZONTE`** (3 palabras; Fuente: `formato.camara.HORIZONTES`) gira · recto · se inclina **`LENTE`** (4 palabras; Fuente: `formato.camara.LENTES`) gran angular · normal · ojo de pez · teleobjetivo **`LINEA_UNIDAD_CAMARA`** (7 palabras; Fuente: `formato.camara.UNIDAD`) CADENCIA · CAMARA · CÁMARA · GOLPES · HORIZONTE · PISTA OPTICA · PISTA ÓPTICA **`MANO_CAMARA`** (2 palabras; Fuente: `formato.camara.MANOS`) al hombro · en tripode **`PESO_CAMARA`** (3 palabras; Fuente: `formato.camara.PESOS`) con masa · ligera · pesada **`PISTA_LADO`** (2 palabras; Fuente: `formato.camara.PISTA_LADOS`) a la derecha · a la izquierda **`PROFUNDIDAD`** (2 palabras; Fuente: `formato.camara.PROFUNDIDADES`) poca profundidad · profundidad total **`ROTURA`** (6 palabras; Fuente: `formato.camara.ROTURAS`) demasiado rapido · rompe el eje · se sale del cuadro · sin leer · sin respiro · todo a la vez ## Apéndice B. Gramática {#appendix-b} La gramática completa es `spec/gramatica/mesa.ebnf`, normativa, que se reproduce aquí. ```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 } ; ``` ## Apéndice C. Códigos de diagnóstico {#appendix-c} Códigos de la lengua de pliegos (`spec/diagnosticos.json`): | Código | Gravedad | Qué significa | |---|---|---| | `E001` | error | el pliego declara una época mayor que la del compilador | | `E010` | error | afecto fuera del vocabulario cerrado | | `E011` | error | función o plano desconocidos en la cabecera de un clip | | `E012` | error | palabra suelta en una línea de movimiento (no es trayecto, manera, granulado, registro ni ventana) | | `E013` | error | evento `>` fuera del vocabulario cerrado | | `E014` | error | registro de letrero desconocido | | `E015` | error | ESPACIO (sala) desconocido | | `E016` | error | color de voz desconocido en el REPARTO | | `E017` | error | arco desconocido | | `E018` | error | modificador de collage o campo de MARIONETA desconocido (detrás de `·` en `foto:`, `recorte:`, `clip:` o `MARIONETA`) | | `E019` | error | otra palabra fuera de un vocabulario cerrado | | `E020` | error | nombre ambiguo: dos candidatos empatan en el mismo nivel de la dimensión `nombre` | | `E021` | error | palabra reservada usada como nombre de hablante o identificador | | `E022` | error | referencia a algo que no existe (pieza, clip, id de ECO, personaje) | | `E023` | error | línea que parece una orden y no lo es: se escribiría en pantalla sin querer (diálogo de quien no está en el REPARTO, línea de escena dentro de un clip, orden o verbo inexistentes) | | `E024` | error | una pieza actúa (`NOMBRE acción`) sin estar en el REPARTO ni ser una MARIONETA | | `E025` | error | ancla muerta en el texto: `al decir «X»` y la voz escrita de ese beat no dice X | | `E030` | error | dos gritos en un clip | | `E031` | error | dos acciones sobre el mismo sujeto en la misma ventana, o una duración declarada dos veces | | `E032` | error | ciclo de ligaduras, cadena de más de tres eslabones o anidamiento excesivo | | `E033` | error | pieza sin apoyo cuando su materia no flota | | `E040` | error | MÚSICA que no está en BANDA (o BANDA sin declarar) | | `E041` | error | efecto `sonido:` que no está en EFECTOS ni en BANDA | | `E042` | error | AMBIENTE que no está en EFECTOS | | `E050` | error | `python:` nombra algo que no está en el bestiario | | `E051` | error | pose que el bestiario no declara | | `E052` | error | dibujo mal invocado: argumentos detrás de `·`, paréntesis, o argumentos que la firma de la pieza no admite | | `E053` | error | el bestiario declarado (`PYTHON` o `PIEZAS`) no existe junto al pliego | | `E054` | error | acción que la pieza no declara (ni entre sus ACCIONES, ni sus POSES, ni sus CICLOS) | | `E060` | error | rotura de una regla sin su `porque` | | `E090` | error | línea mal formada (el parser no puede seguir) | | `W101` | aviso | SALTO DE EJE | | `W102` | aviso | SALTO DE TALLA | | `W103` | aviso | RACCORD DE MIRADA | | `W104` | aviso | RACCORD DE DIRECCIÓN | | `W105` | aviso | RACCORD DE ESTADO | | `W110` | aviso | evento reservado: la lengua lo acepta y el intérprete aún no lo realiza | | `W111` | aviso | registro de letrero reservado | | `W112` | aviso | porcentaje pobre por debajo del 85 % | | `W113` | aviso | sin silencio final declarado | | `W114` | aviso | demasiados clips sin respiro | | `W115` | aviso | escena con dos o más personajes y sin EJE | | `W116` | aviso | clip vacío | | `W117` | aviso | relojes no coprimos | | `W118` | aviso | acción dudosa sobre una pieza (entra dos veces, actúa sobre algo ausente) | | `W120` | aviso | ancla muerta: `al decir «X»` y la voz nunca dice X | | `W121` | aviso | dos voces: clip con sonido dentro de un beat narrado sin `> espera al clip` | | `W122` | aviso | ancla ilegible: casa con la voz pero no con su `di:` | | `W123` | aviso | el beat se alarga: el clip dura más que la voz | | `W124` | aviso | página vacía: el beat abre cuadro nuevo y no pone nada mientras suena la voz | | `W125` | aviso | texto en pantalla: una línea de prosa que se escribirá a máquina en el papel | | `W130` | aviso | revisión Lasseter (sobre la cronología real) | | `W199` | aviso | otro aviso | Códigos de las demás partes: de `P001` a `P009` (proyecto portable, §14.4), de `L001` a `L011` (láminas, §17.9), de `M001` a `M006` (materias, §18.6), de `T001` a `T007` (tomas, §19.4). ## Apéndice D. Desviaciones conocidas de la implementación de referencia {#appendix-d} Encontradas al construir la batería de conformidad (2026-10-15) frente a manim-saorín 1.0.0b1. Cada una es un caso pendiente en la batería; deja de estar pendiente cuando la referencia lo pasa. | Caso | Qué hace la referencia | Qué dice esta especificación | |---|---|---| | `lee-errores-reservada` | acepta `REPARTO nota: …` y luego trata `nota:` como una directiva (avisa «clip vacío») | un hablante con nombre de palabra reservada es `E021` (§5.5, §6.4) | | `lee-estampas` | avisa «clip vacío» (`W116`) en un clip cuyo único contenido es un letrero (`LETRA`) | un letrero es una pieza (§8.3); el clip no está vacío | | `lee-errores-letra-preambulo` | acepta en el preámbulo una línea `LETRA` (una línea de clip) sin error y la descarta en silencio: el signo no llega a la IR | las tres sedes (§3): una línea fuera de su sitio es un error (`E090`), nunca una línea que desaparece | | `cierre-servilleta` | `mesa escribe` reescribe el preámbulo de una servilleta y pierde `BANDA`, `EFECTOS`, `MEZCLA`, `MÚSICA` y `AMBIENTE` | el cierre (§11.1): el pliego revelado suena igual | | `espejo-taller` | un `.mano` importado lee `toca la truca: sí` como `no`; un `precisión alta` escrito en línea se queda como clave sin normalizar junto a `precision alta`; `parte` pierde el nombre de la sección | la ley del espejo (§11.2) | | (todos los casos `ir`) | no emite `identidad` en cada beat | `identidad` es un campo obligatorio del beat (§10.3); la proyección normativa lo incluirá cuando la referencia lo emita | | (preámbulo) | `MUSICA 1M1` sin tilde en el preámbulo se toma como ruta de canción y la cue se pierde en silencio | `MÚSICA` y `MUSICA` son la misma palabra (§4.5); un nombre que está en `BANDA` es una cue (§5.2, RFC 0004) | | (proporción pobre) | cuenta como cifras nombres de cue como `1M1` | los nombres no son cifras (§3.1) | | (comprobación) | `mesa lee` no informa de las ambigüedades de nombre; `mesa indice` sí, con estado de salida 0 | la comprobación de un compilador informa de `E020` y falla (§12); el adaptador une las dos órdenes | | (códigos) | mensajes sin códigos | los códigos del apéndice C (RFC 0003); el adaptador los deriva de los mensajes | ## Apéndice E. Referencias {#appendix-e} - BCP 14: RFC 2119 y RFC 8174, palabras clave. - RFC 8785, JSON Canonicalization Scheme (JCS). - RFC 6838, especificaciones y procedimientos de registro de tipos de medio. - ISO/IEC 14977, EBNF. - PKWARE, .ZIP File Format Specification (APPNOTE). - W3C, WebGPU y WGSL. - EBU R 128 e ITU-R BS.1770, sonoridad y pico verdadero. - 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` (este repositorio); ManimGX (Academa, MIT). ## Apéndice F. Perfiles en desarrollo (informativo) {#appendix-f} Tres ramas de la implementación de referencia construyen perfiles nuevos en el momento de este borrador. Lo que sigue es **informativo**: deja constancia de las líneas que introducen para que otras implementaciones no usen las mismas palabras para otra cosa. Cada uno pasa a normativo cuando su rama se fusiona y la batería tiene casos para él. - **metraje** (metraje real), fusionado en la implementación de referencia el 15-10-2026 (su documento de trabajo es `SPEC-METRAJE.md`); las palabras nuevas de `FORMATO` ya están en el apéndice A, y el aspecto del IR lleva `formato.reencuadre`. Preámbulo: `METRAJE`, `REVELADO`, `RECORTA`, `LIMPIA`, `ESTABILIZA`. Clip: `plano ≈ «…»` y `recurso ≈ «…»` (un plano encontrado por sentido en una biblioteca indexada), `toma: «…»`, `plano: fichero de A a B`, y los prefijos de seguimiento `sobre la mano de X:` y `sobre «objeto»:` (la pluma sigue a lo filmado). REPARTO admite la voz `filmada`. `FORMATO` gana `9:16`, `1:1` y `4:5`, con reencuadre tras `·`: `sigue a quien habla | sigue al sujeto | sigue a NOMBRE | centrado`. Herramientas: `ingesta`, `busca`, `monta` (montaje por palabras), `exporta`, `importa`, `planilla`. La transcripción es local y palabra a palabra. - **géneros** (géneros y producción). Preámbulo: `GÉNERO X [· campo …]`, que solo pone valores por defecto donde el pliego no dice nada. Clip: `ecuación:`, `fuente:`, `dato:`, `rótulo:`, `cita:`, y `ver: curva | barras | puntos desde datos.csv`. Lienzos vertical y cuadrado nativos. Herramientas: `nuevo --género`, `serie`, `variantes`, `traduce`, `subtitulos`, `audiodescribe`, `accesible`, `revisa`, `notas`, `trailer`, `canal`, `deriva`. - **3D** (volumen). El escenario en volumen a partir de las palabras del pliego, la misma cámara física en el 3D ligero del motor y en Blender orquestado por capas, el intercambio por glTF y USD, y las imágenes y clips generados, declarados y congelados.