gioser

tawasuyu/llimphi

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

Rust 660Markdown 302TOML 157RON 312382 Definiciones

⎇ main llimphi-jaula/README.md Markdown · 106 líneas · 4.0 KB Historia crudo

chore: refresco desde el monorepo — vello 0.9 / wgpu 29, 120 miembros d251eb32b · Sergio ·

1# llimphi-jaula
2
3The **app-side** shell: runs the Llimphi loop inside a WASM sandbox and emits an
4[`EscenaWire`](../llimphi-wire-escena/README.md) instead of rasterizing.
5
6It is the twin of [`llimphi-wawa`](../llimphi-wawa/README.md), on the other side
7of the boundary: that one receives and executes, this one composes and ships.
8
9Phase W4 of [`03_ukupacha/wawa/PLAN-LLIMPHI.md`](../../../03_ukupacha/wawa/PLAN-LLIMPHI.md).
10
11```
12View<Msg> → mount → layout → paint → EscenaWire → postcard → …
13…………………………… WASM boundary ……………………………
14                                   … → native shaping → rasterize
15```
16
17## The thing to understand
18
19Both shells run the **same `llimphi-compositor`** — same mount, same taffy
20layout, same 4,000-line `render.rs`. The only difference is the `Lienzo` alias
21and, with it, the `Typesetter`.
22
23That is the W4 result worth saying out loud: **there is no app compositor and
24kernel compositor.** A widget written once works on Linux, inside the kernel, and
25inside a sandbox.
26
27## Two things this one does that the kernel shell doesn't
28
29### It asks for measurements
30
31taffy cannot size a label without knowing how big it is, and measuring means
32shaping — precisely what must not happen inside the sandbox: the interpreter's
3330.3x would eat 72% of the frame (W4.1). So the measurer is an **argument**:
34
35```rust
36let mut jaula = Jaula::new(320.0, 72.0, |p: &Peticion| {
37    // On wawa: a `sys_medir_texto` crossing to parley on the native side.
38    // In a test: a real parley `Typesetter`.
39    medir_del_otro_lado(p)
40});
41let montado = jaula.fotograma(vista());
42let bytes = postcard::to_allocvec(jaula.escena())?;
43```
44
45With no measurer it does not return zero — a silent zero would collapse the whole
46layout and the screen would come out blank while "working". It estimates coarsely
47**and counts**: a non-zero `jaula.medidas_estimadas()` means that layout is
48approximate.
49
50On wawa that measurer already exists — it is [`medidor::wawa`](src/medidor.rs),
51wrapping the `sys_medir_texto` syscall:
52
53```rust
54let mut jaula = Jaula::new(ancho, alto, llimphi_jaula::medidor::wawa);
55```
56
57`sys_medir_texto` is **not permission-gated**: measuring text is not a privilege,
58it is arithmetic over a font, and every app that draws needs it. What it does
59carry is a quota, because the kernel pays for the shaping outside the app's
60`fuel`. Off wasm the measurer returns `None` rather than an invented number.
61
62### It keeps the tree
63
64The `Mounted` never crosses the boundary, so hit-testing resolves here: the
65kernel sends a coordinate and the app answers what was hit.
66
67```rust
68if let Some(msg) = jaula.click(&montado, x, y) {
69    modelo = App::update(modelo, msg);
70}
71```
72
73The opposite of the kernel shell, which **cannot** hit-test precisely because the
74tree stayed here.
75
76## Why it lives outside the workspace
77
78It enables `llimphi-text/wire`, a backend mutually exclusive with `vello` (what
79the rest of the repo uses by default). Cargo's feature unification would turn on
80both and trip the `compile_error!` `llimphi-text` carries to catch exactly that —
81the same trap `llimphi-wawa` already hit.
82
83Both being outside isn't friction: it's the design. They are two processes on two
84sides of a boundary.
85
86```bash
87cargo test  --manifest-path 02_ruway/llimphi/llimphi-jaula/Cargo.toml \
88  --no-default-features --features std
89cargo check --manifest-path 02_ruway/llimphi/llimphi-jaula/Cargo.toml \
90  --target wasm32-unknown-unknown --no-default-features --features libm
91```
92
93## The fixture
94
95Since encoder and replayer cannot be compiled together, the test seam is the same
96as the production one: **bytes**.
97
98```bash
99cargo run --example emitir_fixture --no-default-features --features std
100```
101
102It composes a view with the real compositor and drops the bytes in
103`../llimphi-wawa/pruebas/fixture_jaula.postcard`, where the
104`la_escena_que_emitio_el_compositor_llega_a_pixeles` test **and the kernel's boot
105path** pick them up. If anyone changes the wire format on one side only, those
106two will say so.

README.md

llimphi-jaula

The app-side shell: runs the Llimphi loop inside a WASM sandbox and emits an EscenaWire instead of rasterizing.

It is the twin of llimphi-wawa, on the other side of the boundary: that one receives and executes, this one composes and ships.

Phase W4 of 03_ukupacha/wawa/PLAN-LLIMPHI.md.

View<Msg> → mount → layout → paint → EscenaWire → postcard → …
…………………………… WASM boundary ……………………………
                                   … → native shaping → rasterize

The thing to understand

Both shells run the same llimphi-compositor — same mount, same taffy layout, same 4,000-line render.rs. The only difference is the Lienzo alias and, with it, the Typesetter.

That is the W4 result worth saying out loud: there is no app compositor and kernel compositor. A widget written once works on Linux, inside the kernel, and inside a sandbox.

Two things this one does that the kernel shell doesn't

It asks for measurements

taffy cannot size a label without knowing how big it is, and measuring means shaping — precisely what must not happen inside the sandbox: the interpreter's 30.3x would eat 72% of the frame (W4.1). So the measurer is an argument:

let mut jaula = Jaula::new(320.0, 72.0, |p: &Peticion| {
    // On wawa: a `sys_medir_texto` crossing to parley on the native side.
    // In a test: a real parley `Typesetter`.
    medir_del_otro_lado(p)
});
let montado = jaula.fotograma(vista());
let bytes = postcard::to_allocvec(jaula.escena())?;

With no measurer it does not return zero — a silent zero would collapse the whole layout and the screen would come out blank while "working". It estimates coarsely and counts: a non-zero jaula.medidas_estimadas() means that layout is approximate.

On wawa that measurer already exists — it is medidor::wawa, wrapping the sys_medir_texto syscall:

let mut jaula = Jaula::new(ancho, alto, llimphi_jaula::medidor::wawa);

sys_medir_texto is not permission-gated: measuring text is not a privilege, it is arithmetic over a font, and every app that draws needs it. What it does carry is a quota, because the kernel pays for the shaping outside the app's fuel. Off wasm the measurer returns None rather than an invented number.

It keeps the tree

The Mounted never crosses the boundary, so hit-testing resolves here: the kernel sends a coordinate and the app answers what was hit.

if let Some(msg) = jaula.click(&montado, x, y) {
    modelo = App::update(modelo, msg);
}

The opposite of the kernel shell, which cannot hit-test precisely because the tree stayed here.

Why it lives outside the workspace

It enables llimphi-text/wire, a backend mutually exclusive with vello (what the rest of the repo uses by default). Cargo's feature unification would turn on both and trip the compile_error! llimphi-text carries to catch exactly that — the same trap llimphi-wawa already hit.

Both being outside isn't friction: it's the design. They are two processes on two sides of a boundary.

cargo test  --manifest-path 02_ruway/llimphi/llimphi-jaula/Cargo.toml \
  --no-default-features --features std
cargo check --manifest-path 02_ruway/llimphi/llimphi-jaula/Cargo.toml \
  --target wasm32-unknown-unknown --no-default-features --features libm

The fixture

Since encoder and replayer cannot be compiled together, the test seam is the same as the production one: bytes.

cargo run --example emitir_fixture --no-default-features --features std

It composes a view with the real compositor and drops the bytes in ../llimphi-wawa/pruebas/fixture_jaula.postcard, where the la_escena_que_emitio_el_compositor_llega_a_pixeles test and the kernel's boot path pick them up. If anyone changes the wire format on one side only, those two will say so.