gioser

tawasuyu/llimphi

Sovereign retained-mode GPU UI framework in Rust (wgpu+vello+taffy+parley), Elm loop, 40+ widgets.

Rust 229TOML 101Markdown 82Shell 24052 Definitions

⎇ main shared/foreign-lottie/README.md Markdown · 66 lines · 3.7 KB History raw

chore: refresco desde el monorepo (pin tawasuyu.git v0.3.0) b575c63f1 · Sergio ·

1# foreign-lottie
2
3Fork vendorizado de **[velato](https://github.com/linebender/velato) 0.9.0**
4(reproductor de Lottie de Linebender, `Apache-2.0 OR MIT`) — el motor que parsea
5un `.json` de Lottie y lo emite a una `vello::Scene`. Entra al repo como puente
6de formato ajeno (Regla 4 de `CLAUDE.md`: los formatos ajenos viven en
7`shared/foreign-*`, nunca en el núcleo de las apps).
8
9Lo consume `02_ruway/llimphi/llimphi-lottie` (el puente fino a Llimphi).
10
11## Por qué un fork y no la dependencia de crates.io
12
13velato 0.9 es la única versión que clava `vello 0.7` (la del workspace), así que
14arrancó como dependencia directa. Pero su **importador paniquea**
15(`todo!()`/`unimplemented!()`) ante features perfectamente válidas de Lottie —
16y eso corre en el hilo de UI. Forkeamos para que **degrade con gracia** en vez
17de tumbar la app.
18
19## Cambios respecto de velato 0.9.0 upstream
20
21Todos marcados con `// FORK tawasuyu:` en el código. Concentrados en
22`src/import/converters.rs`:
23
24| Caso upstream (panic) | Fork (degradación graciosa) |
25|---|---|
26| transform sin campo de rotación → `todo!("split rotation")` | rotación 0 |
27| `SplitRotation` (rot. x/y/z separadas) → `todo!()` | usa la componente z (la 2D visible) |
28| `SplitPosition` en shape-transform → `todo!("split position")` | arma la posición desde x/y |
29| asset desconocido (imagen embebida…) → `unimplemented!()` | se omite el asset |
30| blend `Add` → `unimplemented!()` | compositing aditivo (`Compose::Plus`) |
31| blend `HardMix` → `unimplemented!()` | `HardLight` (el mix más cercano) |
32| capa de un `ty` no modelado (texto=5, cámara, luz…) → `Err("unknown layer type")` **que rechaza el documento entero** | la capa se saltea (`AnyLayer::Unsupported`), el resto se importa |
33| transform sin campo `s` → escala **1 %** (el default era `[1,1,1]` y la escala de Lottie va en porcentaje) | escala 100 % |
34
35El camino de render (`runtime/`) quedó intacto — es panic-free. Los `panic!` que
36restan en `src/schema/*` son test-only o del lado serializador (que no usamos);
37`llimphi-lottie` igual envuelve el parse en `catch_unwind` como red secundaria.
38
39## Pendiente (gaps del propio velato, no introducidos por el fork)
40
41velato no implementa todavía, y aquí tampoco (degradan a omisión, no a panic):
42**capas de texto**, **effects** (blur/drop-shadow) y **expresiones**. Declarado
43en `src/schema/mod.rs`. Son lo grande; se completan cuando un `.json` concreto
44los pida.
45
46> Esta línea decía «degradan a omisión» **desde antes de que fuera cierto**. Lo
47> era del lado del importador, que efectivamente omite lo que no entiende, pero
48> no del **deserializador**: un `ty` fuera de 0–4 devolvía `Err`, y serde aborta
49> el documento al primer error, así que un solo layer de texto —o una cámara, o
50> una luz, que en un export de After Effects vienen de fábrica— tumbaba el
51> `.json` entero. No se perdía el rótulo: se perdía la animación. Lo encontró
52> `02_ruway/llimphi/llimphi-test/tests/lottie_degrada_pero_pinta.rs` (2026-09-03)
53> al preguntar por primera vez si lo que importa con `Ok` además **se ve**.
54
55## Tests
56
57`tests/no_panic_fork.rs` certifica que cada caso que antes paniqueaba ahora
58importa con `Ok`, y que el camino feliz sigue intacto.
59
60Eso es **la mitad** de la pregunta, y hay que leerlo sabiéndolo: un `Ok` que
61devuelve una composición vacía, o una capa descartada entera por un campo que
62no se entendió, da exactamente el mismo `is_ok()`. La otra mitad —que lo
63importado **dibuje**— vive en
64`02_ruway/llimphi/llimphi-test/tests/lottie_degrada_pero_pinta.rs`, que rasteriza
65cada caso y cuenta píxeles. Las dos últimas filas de la tabla de arriba
66salieron de ahí; con `is_ok()` solo, las dos estaban verdes.

README.md

foreign-lottie

Fork vendorizado de velato 0.9.0 (reproductor de Lottie de Linebender, Apache-2.0 OR MIT) — el motor que parsea un .json de Lottie y lo emite a una vello::Scene. Entra al repo como puente de formato ajeno (Regla 4 de CLAUDE.md: los formatos ajenos viven en shared/foreign-*, nunca en el núcleo de las apps).

Lo consume 02_ruway/llimphi/llimphi-lottie (el puente fino a Llimphi).

Por qué un fork y no la dependencia de crates.io

velato 0.9 es la única versión que clava vello 0.7 (la del workspace), así que arrancó como dependencia directa. Pero su importador paniquea (todo!()/unimplemented!()) ante features perfectamente válidas de Lottie — y eso corre en el hilo de UI. Forkeamos para que degrade con gracia en vez de tumbar la app.

Cambios respecto de velato 0.9.0 upstream

Todos marcados con // FORK tawasuyu: en el código. Concentrados en src/import/converters.rs:

Caso upstream (panic)Fork (degradación graciosa)
transform sin campo de rotación → todo!("split rotation")rotación 0
SplitRotation (rot. x/y/z separadas) → todo!()usa la componente z (la 2D visible)
SplitPosition en shape-transform → todo!("split position")arma la posición desde x/y
asset desconocido (imagen embebida…) → unimplemented!()se omite el asset
blend Add → unimplemented!()compositing aditivo (Compose::Plus)
blend HardMix → unimplemented!()HardLight (el mix más cercano)
capa de un ty no modelado (texto=5, cámara, luz…) → Err("unknown layer type") que rechaza el documento enterola capa se saltea (AnyLayer::Unsupported), el resto se importa
transform sin campo s → escala 1 % (el default era [1,1,1] y la escala de Lottie va en porcentaje)escala 100 %

El camino de render (runtime/) quedó intacto — es panic-free. Los panic! que restan en src/schema/* son test-only o del lado serializador (que no usamos); llimphi-lottie igual envuelve el parse en catch_unwind como red secundaria.

Pendiente (gaps del propio velato, no introducidos por el fork)

velato no implementa todavía, y aquí tampoco (degradan a omisión, no a panic): capas de texto, effects (blur/drop-shadow) y expresiones. Declarado en src/schema/mod.rs. Son lo grande; se completan cuando un .json concreto los pida.

Esta línea decía «degradan a omisión» desde antes de que fuera cierto. Lo era del lado del importador, que efectivamente omite lo que no entiende, pero no del deserializador: un ty fuera de 0–4 devolvía Err, y serde aborta el documento al primer error, así que un solo layer de texto —o una cámara, o una luz, que en un export de After Effects vienen de fábrica— tumbaba el .json entero. No se perdía el rótulo: se perdía la animación. Lo encontró 02_ruway/llimphi/llimphi-test/tests/lottie_degrada_pero_pinta.rs (2026-09-03) al preguntar por primera vez si lo que importa con Ok además se ve.

Tests

tests/no_panic_fork.rs certifica que cada caso que antes paniqueaba ahora importa con Ok, y que el camino feliz sigue intacto.

Eso es la mitad de la pregunta, y hay que leerlo sabiéndolo: un Ok que devuelve una composición vacía, o una capa descartada entera por un campo que no se entendió, da exactamente el mismo is_ok(). La otra mitad —que lo importado dibuje— vive en 02_ruway/llimphi/llimphi-test/tests/lottie_degrada_pero_pinta.rs, que rasteriza cada caso y cuenta píxeles. Las dos últimas filas de la tabla de arriba salieron de ahí; con is_ok() solo, las dos estaban verdes.