tawasuyu

tawasuyu/llimphi

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

Rust 229TOML 101Markdown 82Shell 24052 Definitions

⎇ 168cd187519c0ad575d3ce63baee2f164c38d9d1 llimphi-ui/Cargo.toml TOML · 181 lines · 8.5 KB History raw

chore: refresco desde el monorepo — 128 miembros, los 76 widgets y los 11 módulos b3f12e136 · Sergio ·

1[package]
2name = "llimphi-ui"
3version.workspace = true
4edition.workspace = true
5license.workspace = true
6authors.workspace = true
7publish.workspace = true
8
9description = "Native Rust UI framework: retained-mode View<Msg> Elm loop over vello + wgpu + taffy + parley."
10repository.workspace = true
11[dependencies]
12# El trait de despacho. `Handle` lo implementa para que animar —y cualquier otra
13# cosa que sólo quiera mandar un `Msg`— deje de arrastrar el bucle de escritorio
14# entero. Ver `llimphi-despacho`.
15llimphi-despacho = { path = "../llimphi-despacho", version = "0.1.0" }
16llimphi-hal = { path = "../llimphi-hal", version = "0.1.0" }
17llimphi-layout = { path = "../llimphi-layout", version = "0.1.0" }
18llimphi-raster = { path = "../llimphi-raster", version = "0.1.0" }
19# `default-features = false` en los dos que conmutan de backend: sus defaults
20# encienden el perfil `vello`, que es EXCLUYENTE del `cpu` que pide la feature
21# `hybrid`. Las features del perfil normal se listan explícitas abajo.
22llimphi-text = { path = "../llimphi-text", version = "0.1.0", default-features = false }
23# El compositor declarativo (winit-free): View, mount, paint, hit-test.
24llimphi-compositor = { path = "../llimphi-compositor", version = "0.1.0", default-features = false }
25pollster = { workspace = true }
26# Árbol de accesibilidad por frame (NVDA/VoiceOver/Orca/TalkBack). Lo
27# alimentamos desde `View::semantics` + el árbol Mounted. `accesskit_winit`
28# es el adapter que conecta el árbol a la API nativa del SO vía winit.
29accesskit = { workspace = true }
30accesskit_winit = { workspace = true }
31# `accesskit::TreeId` envuelve un `uuid::Uuid` — generamos uno por proceso
32# para identificar el árbol entre actualizaciones (el lector lo necesita
33# para distinguir nuestra app de otras ventanas AccessKit del SO).
34uuid = { version = "1", features = ["v4"] }
35# Reloj monotónico portable. En cualquier target NATIVO `web_time::Instant` es
36# literalmente un re-export de `std::time::Instant` — coste cero, mismo tipo,
37# mismo comportamiento. En wasm32 se apoya en `performance.now()`, donde
38# `std::time::Instant::now()` PANICA («time not implemented on this platform»).
39# Es además el tipo con el que winit tipa `ControlFlow::WaitUntil` en web, así
40# que unificarlo acá arregla el reloj y el borde con winit de una vez.
41# Reexportado como `llimphi_ui::Instant`; dentro del crate se usa `crate::Instant`.
42web-time = "1"
43# Portapapeles del sistema para copiar texto seleccionado fuera del editor
44# (Ctrl/Cmd+C). Best-effort: si no hay backend (headless) degrada a no-op sin
45# panicar. Feature `clipboard` (default) para que builds sin display puedan
46# apagarlo con --no-default-features. En Android y en wasm arboard no existe:
47# la dep va target-gated y `copy_to_clipboard` es no-op aunque la feature esté
48# activa (en el navegador el portapapeles es `navigator.clipboard`, asíncrono y
49# detrás de un gesto del usuario — otro camino, no arboard).
50[target.'cfg(all(not(target_os = "android"), not(target_arch = "wasm32")))'.dependencies]
51arboard = { workspace = true, optional = true }
52
53# Pista `wp_content_type_v1` (ver `src/content_type.rs`): winit no habla ese
54# protocolo, así que se monta una conexión wayland-client sobre el MISMO
55# `wl_display` que ya abrió winit (`Backend::from_foreign_display`) y se envuelve
56# su `wl_surface` por `ObjectId::from_ptr`. Es el cruce winit↔wayland-client
57# ajeno que validó el spike `llimphi-video-plane`. Sólo Linux: en macOS/Windows
58# no hay Wayland y el módulo cae a un no-op.
59[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
60# Sólo con la feature `config-wawa` (ver [features]). Fuera de wasm: en el
61# navegador no hay bus de config del SO que leer.
62
63
64[target.'cfg(target_os = "linux")'.dependencies]
65wayland-client = "0.31"
66wayland-backend = { version = "0.3", features = ["client_system"] }
67# `staging`: content-type-v1 todavía vive en staging/ del repo de protocolos.
68wayland-protocols = { version = "0.32", features = ["client", "staging"] }
69
70[target.'cfg(target_os = "android")'.dependencies]
71# Logging a logcat: en Android eprintln! va a /dev/null; los errores del
72# runtime (event loop, GPU) salen por `log` (la app instala android_logger).
73log = "0.4"
74
75[target.'cfg(target_arch = "wasm32")'.dependencies]
76# `uuid` v4 necesita una fuente de aleatoriedad EXPLÍCITA en
77# wasm32-unknown-unknown: el target no tiene syscall de entropía y el crate
78# emite un `compile_error!` en vez de inventar una. `js` la toma de
79# `crypto.getRandomValues` del navegador. El uuid es el `accesskit::TreeId`
80# del árbol de accesibilidad — uno por proceso.
81#
82# Este era el ÚNICO error de todo el árbol de `llimphi-ui` al compilar para
83# wasm32 (verificado 2026-07-26 con --keep-going): winit, wgpu, vello, parley
84# y taffy ya traen su propio soporte web.
85uuid = { version = "1", features = ["v4", "js"] }
86# El runtime web (`run_web`). `spawn_local` lanza el arranque asíncrono del
87# `Hal`; `web-sys` da el `<canvas>` del documento y la consola (en wasm
88# `eprintln!` no va a ningún lado); `wasm-bindgen` da el `JsCast` para bajar de
89# `Element` a `HtmlCanvasElement`.
90wasm-bindgen = "0.2"
91wasm-bindgen-futures = "0.4"
92web-sys = { version = "0.3", features = [
93    "console",
94    "Document",
95    "Element",
96    "HtmlCanvasElement",
97    "Window",
98] }
99
100[features]
101default = ["clipboard", "vello"]
102clipboard = ["dep:arboard"]
103# El perfil normal: rasterizado con vello y todo lo que cuelga de él (fuentes
104# del sistema, GPU directa). Es el default; `hybrid` es su alternativa.
105vello = ["llimphi-text/vello", "llimphi-text/system", "llimphi-compositor/vello", "llimphi-compositor/system", "llimphi-compositor/gpu"]
106# Rasteriza con vello_hybrid (CPU+GPU, SIN compute shaders) en vez de vello.
107#
108# **No es una preferencia de rendimiento: es el único camino a píxeles en GPUs
109# cuyo compilador de shaders no digiere el compute de vello.** El Mali-G57 del
110# Redmi de pruebas pierde el device en el primer cuadro por Vulkan y aborta por
111# GLES; con este perfil y `Backends::GL` pinta a 119 fps. La matriz completa
112# está en `02_ruway/llimphi/android/DIAGNOSTICO.md`.
113#
114# Enciende el perfil `cpu` de text y compositor —los que pintan en una `Escena`
115# grabada en vez de en una `vello::Scene`— y el backend hybrid del rasterizador.
116# Los tres tienen que ir juntos: son el mismo tipo de escena visto desde tres
117# crates, y `llimphi-text` lleva un `compile_error!` que delata la mezcla.
118#
119# Cuesta el hook de GPU directa (`View::gpu_paint_with`): vive en la feature
120# `gpu` del compositor, que implica el backend vello porque encima una pasada
121# de wgpu sobre la `vello::Scene`. Una app que lo use no puede ir por acá.
122hybrid = [
123    "llimphi-raster/hybrid",
124    "llimphi-text/cpu",
125    "llimphi-text/std",
126    "llimphi-text/system",
127    "llimphi-compositor/cpu",
128    "llimphi-compositor/std",
129    "llimphi-compositor/system",
130]
131# Instala `alloc::ContadorAlloc` como `#[global_allocator]` del binario para
132# que `LLIMPHI_PERF` reporte asignaciones/bytes por frame (Bloque 21). OFF por
133# defecto: cuenta con dos `fetch_add` relajados por asignación, y un runtime no
134# le impone el allocator a nadie sin que lo pidan.
135perf-alloc = []
136# Lee el **sentido de la rueda** (ratón / touchpad, por separado) del bus de
137# config del SO wawa y lo fija al arrancar, con watcher para el cambio en
138# caliente. OFF por defecto porque `llimphi-ui` es toolkit y `wawa-config` es el
139# bus de un sistema operativo concreto: el toolkit publicable no puede depender
140# de él. En tawasuyu la enciende el `[workspace.dependencies]` de la raíz, así
141# que TODAS las apps del monorepo obedecen la misma config sin tocar una línea.
142config-wawa = []
143
144[[example]]
145name = "content_type"
146path = "examples/content_type.rs"
147
148[[example]]
149name = "counter"
150path = "examples/counter.rs"
151
152# El mismo counter, en el navegador. `cdylib` porque es lo que wasm-bindgen
153# necesita; en targets nativos el archivo entero está bajo
154# `#![cfg(target_arch = "wasm32")]`, así que queda una biblioteca vacía y
155# `cargo check --workspace --examples` lo cubre sin ruido.
156[[example]]
157name = "counter_web"
158path = "examples/counter_web.rs"
159crate-type = ["cdylib"]
160
161[[example]]
162name = "editor"
163path = "examples/editor.rs"
164
165[[example]]
166name = "gpu_paint_demo"
167path = "examples/gpu_paint_demo.rs"
168
169[[example]]
170name = "gestos"
171path = "examples/gestos.rs"
172
173# Instrumento del auto-repeat: `view()` duerme a propósito para que un toque de
174# tecla caiga entero dentro de un cuadro. Ver el encabezado del archivo.
175[[example]]
176name = "melaza_teclas"
177path = "examples/melaza_teclas.rs"
178
179[[example]]
180name = "selectable_text"
181path = "examples/selectable_text.rs"