Saltar al contenido
Tórculo1.0 · borrador de trabajo

Parte 7 · tomas y API

Tomas en el navegador

Una toma es el trabajo del motor grabado una vez; el elemento <manimgx-film> la estampa en la página con el propio motor de ManimGX compilado a WebAssembly y WebGPU, sin Python.

Motor con un parche

El motor del fork en 9647ce7 no pinta en Chrome: su WGSL de materias (materia.wgsl y materia_vector.wgsl) mezcla * y ^ sin paréntesis, cosa que naga acepta y Tint rechaza. El de esta hoja se ha compilado desde una copia con esos paréntesis puestos (6 líneas); el arreglo está propuesto para el fork. Otra diferencia con lo que dice FORK.md: este reproductor web no lee las tomas 0x8000_0001.

Pliego.take · 189 KB · 960 × 540 · 24 fps · 0x8000_0002 · el mismo rodaje en MP4
Prensa.take · 172 KB · 960 × 540 · 24 fps · 0x8000_0002 · el mismo rodaje en MP4

Qué es una toma

Una escena de ManimGX se rueda una vez con manimgx render escena.py --take: en vez de un vídeo, se guarda el trabajo del motor (los objetos de cada fotograma, sus formas, sus pasadas). Esa toma la vuelve a estampar cualquier reproductor de ManimGX: la biblioteca de Rust, la app o, aquí, el navegador. Las del fork de Tórculo llevan su propio rango de versión, 0x8000_0002 (registros de 424 bytes, con los mensajes POST y MATERIAL), y los lectores leen también las 0x8000_0001.

Cómo se pone en una página

<script type="module" src="/medios/motor/manimgx-film.js"></script>
<manimgx-film src="Prensa.take" autoplay></manimgx-film>

El elemento carga el motor (engine.js y engine_bg.wasm, 1,8 MB) y la letra de sus mandos desde su misma carpeta. Necesita WebGPU: Chrome y Edge de escritorio, Safari 26 o Firefox reciente. Sin WebGPU, esta página enseña el mismo rodaje en MP4. Motor compilado desde el fork en 9647ce7.

Las escenas

Escritas con import manimgx as m en la paleta del canon, y grabadas con site/scripts/tomas.sh:

site/tomas/pliego.py
"""El pliego y la película: lo escrito sin números, lo rodado con ellos.

Toma pequeña para la web (parte 7: tomas). Se graba con
    tools/pesado manimgx/.venv/bin/manimgx render site/tomas/pliego.py --take -r 960x540 --fps 24
"""
import manimgx as m

PAPEL, TINTA, APAGADA, MINIO, AZURITA, AMARILLO = "#F5F0E8", "#2C1810", "#7A5F4E", "#C1453B", "#2B4C7E", "#E8A838"
m.config.background_color = PAPEL


class Pliego(m.Scene):
    def construct(self):
        hoja = m.Rectangle(width=4.6, height=5.2, color=APAGADA, stroke_width=2, fill_color="#FAF7F0", fill_opacity=1).shift(m.LEFT * 3.4)
        lineas = m.VGroup(
            m.Text("== CAPÍTULO 1 ==", font="monospace", color=MINIO, font_size=22),
            m.Text("* apertura · sereno", font="monospace", color=AZURITA, font_size=22),
            m.Text("di: Una prensa.", font="monospace", color=TINTA, font_size=22),
            m.Text("pon: cartulina «PLIEGO»", font="monospace", color=TINTA, font_size=22),
            m.Text("> deja posar", font="monospace", color=APAGADA, font_size=22),
        ).arrange(m.DOWN, aligned_edge=m.LEFT, buff=0.32).move_to(hoja)
        self.play(m.FadeIn(hoja), run_time=0.5)
        self.play(m.LaggedStart(*[m.Write(l) for l in lineas], lag_ratio=0.35), run_time=2.4)
        flecha = m.Arrow(m.LEFT * 0.8, m.RIGHT * 0.8, color=TINTA, stroke_width=5)
        pantalla = m.Rectangle(width=4.8, height=2.7, color=TINTA, stroke_width=3).shift(m.RIGHT * 3.6)
        carta = m.Rectangle(width=2.6, height=1.0, color=AMARILLO, fill_color=AMARILLO, fill_opacity=1, stroke_width=0).move_to(pantalla)
        rotulo = m.Text("PLIEGO", font="serif", color=TINTA, font_size=34).move_to(carta)
        self.play(m.GrowArrow(flecha), m.Create(pantalla), run_time=0.9)
        self.play(m.FadeIn(carta, shift=m.UP * 0.3), m.Write(rotulo), run_time=0.9)
        self.play(m.Indicate(lineas[3], color=MINIO), run_time=0.8)
        self.wait(1.0)
site/tomas/prensa.py
"""La prensa: una plancha se trabaja una vez y se estampa muchas.

Toma pequeña para la web (parte 7: tomas). Se graba con
    tools/pesado manimgx/.venv/bin/manimgx render site/tomas/prensa.py --take -r 960x540 --fps 24
"""
import manimgx as m

PAPEL, TINTA, MINIO, AZURITA, AMARILLO, ORO = "#F5F0E8", "#2C1810", "#C1453B", "#2B4C7E", "#E8A838", "#D6A03A"
m.config.background_color = PAPEL


def plancha() -> m.VGroup:
    marco = m.RoundedRectangle(corner_radius=0.12, width=2.4, height=3.0, color=TINTA, stroke_width=4)
    sol = m.Circle(radius=0.55, color=MINIO, fill_color=MINIO, fill_opacity=1, stroke_width=0).shift(m.UP * 0.45)
    tierra = m.Rectangle(width=1.8, height=0.5, color=AZURITA, fill_color=AZURITA, fill_opacity=1, stroke_width=0).shift(m.DOWN * 0.85)
    raya = m.Line(m.LEFT * 0.9, m.RIGHT * 0.9, color=ORO, stroke_width=6).shift(m.DOWN * 0.35)
    return m.VGroup(marco, sol, tierra, raya)


class Prensa(m.Scene):
    def construct(self):
        p = plancha()
        titulo = m.Text("una plancha", font="serif", color=TINTA, font_size=36).to_edge(m.UP, buff=0.5)
        self.play(m.Create(p[0]), m.Write(titulo), run_time=1.2)
        self.play(m.FadeIn(p[1], scale=0.6), m.GrowFromCenter(p[2]), m.Create(p[3]), run_time=1.0)
        self.wait(0.4)
        copias = m.VGroup(*[plancha().scale(0.42) for _ in range(8)]).arrange_in_grid(2, 4, buff=0.35).shift(m.DOWN * 0.35)
        otro = m.Text("muchas estampas", font="serif", color=TINTA, font_size=36).to_edge(m.UP, buff=0.5)
        self.play(p.animate.scale(0.42).move_to(copias[0]), m.Transform(titulo, otro), run_time=0.9)
        self.play(m.LaggedStart(*[m.FadeIn(c, scale=1.25) for c in copias[1:]], lag_ratio=0.18), run_time=1.6)
        self.wait(1.0)