1# llimphi-wawa
2
3> The [llimphi](../README.md) shell over the kernel framebuffer.
4
5Closes the `View<Msg> → mount → layout → paint → blit` cycle **without winit,
6without a GPU and without `std`**. It is the `llimphi-ui` twin for wawa: same
7compositor, same composition, different skin. W3.c of
8[`PLAN-LLIMPHI.md`](../../../03_ukupacha/wawa/PLAN-LLIMPHI.md).
9
10Deliberately thin: it does not reimplement a single line of the compositor. The
11tree, taffy layout, paint and hit-test are the **same code** that runs on Linux,
12compiled with different features.
13
14## Usage
15
16```rust
17let mut cascara = Cascara::new(width, height);
18
19// Per frame:
20let montado = cascara.fotograma(my_view);
21cascara.volcar(framebuffer, stride_bytes, Formato::Bgra8);
22
23// When a click arrives from the kernel:
24if let Some(msg) = cascara.click(&montado, x, y) {
25 model = App::update(model, msg);
26}
27```
28
29## What it does NOT do, on purpose
30
31- **No loop of its own.** The kernel's cooperative reactor is in charge; the
32 shell offers `fotograma()` and `click()` for it to call when appropriate. A
33 loop here would fight the one outside.
34- **It does not know the time.** The frame instant arrives as an argument (the
35 kernel reads it off its PIT) — the same discipline `llimphi_compositor::Instant`
36 imposes by having no `now()`.
37- **It does not touch hardware.** It takes a `&mut [u8]` and its stride. Who
38 mapped that memory — firmware GOP, virtio-gpu scanout — is the kernel's
39 business.
40
41## The other path: scenes arriving over the wire (W4)
42
43`fotograma()` takes a `View<Msg>` and mounts it here. But a `.wasm` app composes
44**on the far side of the boundary** and ships the finished result as a
45[`llimphi-wire-escena`](../llimphi-wire-escena/README.md). That's what the twin
46is for:
47
48```rust
49let recibida: EscenaWire = postcard::from_bytes(&bytes)?;
50let st = cascara.fotograma_wire(&recibida);
51// st.textos = how many strings were shaped on THIS side — the point of W4.1
52```
53
54From `pintar` down it is the same code: the kernel needs no second rasterizer
55because there are no two kinds of drawing.
56
57Three things worth knowing about this path:
58
59- **The `Typesetter` is the shell's**, not a fresh one. Text arrives unshaped and
60 is resolved here, so the cache must survive between frames — a new one per
61 frame would make every frame "cold" (3.4 fps instead of 53, per W4.1).
62- **It does not trust the wire.** The scene comes from a sandboxed app:
63 out-of-range style indices and images without a blob are counted in
64 `EstadisticasReproduccion` and skipped. An `unwrap` there would be a Ring 0
65 panic triggerable from userspace.
66- **There is no hit-testing, and that is correct.** The node tree stayed on the
67 far side of the boundary; the app is who knows what sits under the pointer.
68 Input travels back as a coordinate.
69
70## Deps
71
72- `llimphi-compositor` (feature `cpu`) · `llimphi-cpu` · `llimphi-text` ·
73 `llimphi-layout` · `llimphi-wire-escena`
74
75Feature `std`: run the shell on the host, for tests. The default is `libm` — the
76bare-metal profile this crate exists for.
README.md
llimphi-wawa
The llimphi shell over the kernel framebuffer.
Closes the View<Msg> → mount → layout → paint → blit cycle without winit,
without a GPU and without std. It is the llimphi-ui twin for wawa: same
compositor, same composition, different skin. W3.c of
PLAN-LLIMPHI.md.
Deliberately thin: it does not reimplement a single line of the compositor. The
tree, taffy layout, paint and hit-test are the same code that runs on Linux,
compiled with different features.
Usage
let mut cascara = Cascara::new(width, height);
// Per frame:
let montado = cascara.fotograma(my_view);
cascara.volcar(framebuffer, stride_bytes, Formato::Bgra8);
// When a click arrives from the kernel:
if let Some(msg) = cascara.click(&montado, x, y) {
model = App::update(model, msg);
}
What it does NOT do, on purpose
- No loop of its own. The kernel's cooperative reactor is in charge; the
shell offers
fotograma() and click() for it to call when appropriate. A
loop here would fight the one outside.
- It does not know the time. The frame instant arrives as an argument (the
kernel reads it off its PIT) — the same discipline
llimphi_compositor::Instant
imposes by having no now().
- It does not touch hardware. It takes a
&mut [u8] and its stride. Who
mapped that memory — firmware GOP, virtio-gpu scanout — is the kernel's
business.
The other path: scenes arriving over the wire (W4)
fotograma() takes a View<Msg> and mounts it here. But a .wasm app composes
on the far side of the boundary and ships the finished result as a
llimphi-wire-escena. That's what the twin
is for:
let recibida: EscenaWire = postcard::from_bytes(&bytes)?;
let st = cascara.fotograma_wire(&recibida);
// st.textos = how many strings were shaped on THIS side — the point of W4.1
From pintar down it is the same code: the kernel needs no second rasterizer
because there are no two kinds of drawing.
Three things worth knowing about this path:
- The
Typesetter is the shell's, not a fresh one. Text arrives unshaped and
is resolved here, so the cache must survive between frames — a new one per
frame would make every frame "cold" (3.4 fps instead of 53, per W4.1).
- It does not trust the wire. The scene comes from a sandboxed app:
out-of-range style indices and images without a blob are counted in
EstadisticasReproduccion and skipped. An unwrap there would be a Ring 0
panic triggerable from userspace.
- There is no hit-testing, and that is correct. The node tree stayed on the
far side of the boundary; the app is who knows what sits under the pointer.
Input travels back as a coordinate.
Deps
llimphi-compositor (feature cpu) · llimphi-cpu · llimphi-text ·
llimphi-layout · llimphi-wire-escena
Feature std: run the shell on the host, for tests. The default is libm — the
bare-metal profile this crate exists for.