GUI WASM (forja-wasm-gui)
Crate: crates/forja-wasm-gui/ — la GUI de Forja compilada a WebAssembly
¿Por qué existe?
Renderiza interfaces Forja dentro de un <canvas> HTML5 usando la Canvas 2D API. Es una implementación liviana y autónoma del runtime GUI: no depende de winit, Xilem, Masonry ni Vello, por lo que puede ejecutarse en el navegador como un módulo WASM. Es la pieza que habilita el playground web de la documentación para mostrar GUIs Forja sin servidor nativo.
Arquitectura del pipeline:
Código Forja (.fa)
→ forja::compilar_con_ast() → AST
→ extraer_layout() → Layout simplificado
→ renderizar_layout() → Canvas 2D
→ eventos (click) → hit-testing sobre rectángulos
→ ejecutar_funcion() (evaluador tree-walking) Estructuras clave
| Componente | Descripción |
|---|---|
ValorGUI | Valor dinámico del evaluador: Texto, Entero, Decimal, Booleano, Nulo; con es_verdadero(), to_display(), to_json_value()/from_serde() y to_f64() |
Layout | Representación intermedia de UI: Column, Row, ZStack, Label, VariableLabel, Button, TextInput, Title, Spacer y Unimplemented (placeholder para widgets no soportados en Canvas) |
VariableStore | Variables globales como Rc<RefCell<HashMap<String, serde_json::Value>>> (single-threaded para WASM); los widgets que leen variables se actualizan desde aquí |
Ambito | Ámbito de variables del evaluador por llamada de función |
WidgetHitArea | Rectángulo (x, y, ancho, alto) + referencia al Layout para el hit-testing de eventos |
AppState | Estado global en thread_local!: store, declaraciones AST, hit_areas, último layout y tamaño del canvas |
Tema Material You simplificado
El renderizador usa una paleta fija basada en Material Design 3: COLOR_PRIMARY #6750A4, COLOR_ON_PRIMARY, COLOR_PRIMARY_CONTAINER, COLOR_SECONDARY, COLOR_SURFACE #F5F0F7, COLOR_ON_SURFACE, COLOR_OUTLINE, COLOR_BACKGROUND #FEF7FF, COLOR_ERROR #B3261E, etc.
Renderizado y eventos
| Función | Descripción |
|---|---|
renderizar_layout() | Recorre el layout dibujando en el canvas y registrando las WidgetHitArea; devuelve el tamaño usado por cada sub-layout |
renderizar_boton() | Botón Material (sombra + fondo primario + texto centrado) con radio redondeado; registra su hit area |
renderizar_text_input() | Campo estilo filled con borde inferior, muestra el valor actual o el placeholder |
redondear_rect() | Path 2D de rectángulo redondeado |
extraer_layout() / expr_a_layout() | Busca la función main en el AST y convierte las llamadas de UI (columna, fila, pila, etiqueta, titulo, etiqueta_dinamica, boton, entrada_texto, espacio… y alias en inglés) al enum Layout |
procesar_click() | Hit-testing de atrás hacia adelante (Z-order); si el widget es un botón, ejecuta su callback con el evaluador; los TextInput solo logean a consola por ahora |
configurar_eventos_canvas() | Adjunta un listener click al canvas vía add_event_listener_with_callback |
Evaluador tree-walking
ejecutar_funcion(), evaluar_bloque(), evaluar_declaracion() y evaluar_expresion() implementan un intérprete simplificado del AST: soporta variables, asignaciones, si/sino, mientras, para, cuando, retornos, aritmética, comparaciones, lógica, arreglos/mapas como JSON, ternarios e indexación. Operaciones sin soporte en WASM (Closure, Hilo, CanalNuevo, Seleccionar, Instanciacion, Match) retornan error explícito. inicializar_estado() evalúa main() para precargar las variables iniciales en el store.
Exports wasm-bindgen
| Función | Firma JS | Descripción |
|---|---|---|
version() | () → String | Retorna "forja-wasm-gui v0.1.0" |
renderizar(canvas_id, codigo) | (String, String) → String | Compila el código, inicializa estado, extrae layout, lo dibuja en el canvas y configura eventos; retorna "ok" o un mensaje de error |
ejecutar_gui(canvas_id, codigo) | (String, String) → String | Atajo: renderizar + eventos |
rerenderizar(canvas_id) | (String) → String | Re-renderiza el último layout (útil después de un evento que cambió variables) |
Compilación con wasm-bindgen
El crate es crate-type = ["cdylib"] y depende de wasm-bindgen 0.2, js-sys 0.3, web-sys (features de canvas/DOM/eventos), el crate raíz forja (path = "../..") y serde_json. En CI (rust.yml) se compila con:
WASM_OPT=false wasm-pack build crates/forja-wasm-gui --target web \
--out-dir ../../wasm-output-gui --out-name forja_wasm_gui --no-opt
wasm-opt --enable-bulk-memory --enable-nontrapping-float-to-int \
--enable-sign-ext -O3 wasm-output-gui/forja_wasm_gui_bg.wasm -o … Los artefactos (forja_wasm_gui.js + forja_wasm_gui_bg.wasm) se publican en GitHub Releases; el workflow de deploy de docs los descarga a docs/src/wasm/ y docs/public/wasm/.
Relación con forja-gui-rt y el playground
| Componente | Relación |
|---|---|
forja-gui-rt | Runtime GUI nativo (Xilem/Masonry/Vello) para apps de escritorio y el Native Activity Android. forja-wasm-gui es una reimplementación independiente en Canvas 2D que no comparte código de rendering, pero imita su semántica de widgets y su sistema de variables reactivas |
| Playground web | docs/src/pages/playground.astro carga forja_wasm_gui.js (con un stub en docs/src/wasm/ cuando el WASM no está disponible) y llama forjaWasmGui.ejecutar_gui('forja-canvas', source) para renderizar la GUI del código del usuario |
Crate raíz forja | Aporta el compilador completo: forja::compilar_con_ast() produce el AST que luego se convierte en Layout |
forja-lang/forja-wasm-gui) y su GUI es un subconjunto funcional del runtime nativo: columnas, filas, z-stacks, labels, botones, inputs de texto, títulos y spacers. Los widgets avanzados se muestran como Unimplemented.