Gio UI: GUI multiplataforma para Go
(gioui.org)- Es una biblioteca que permite a los desarrolladores de Go crear GUI de modo inmediato para varios sistemas operativos y WebAssembly
- Admite una amplia cobertura de plataformas, incluyendo Linux, macOS, Windows, Android, iOS, FreeBSD, OpenBSD y WebAssembly
- Está diseñada para reducir dependencias y aprovechar las bibliotecas de cada plataforma para la gestión de ventanas, entrada y dibujo con GPU
- El renderizado incluye el renderizador vectorial Pathfinder, basado en OpenGL ES y Direct3D 11, y está migrando hacia un renderizador con shaders de cómputo basado en piet-gpu
- Renderiza texto y formas como contornos, sin convertirlos en texturas, lo que permite animaciones, dibujo con transformaciones e independencia respecto de la resolución de píxeles
Objetivo y alcance de soporte de Gio
- Gio es una biblioteca para crear GUI eficientes, fluidas y portables en Go
- Las plataformas compatibles son Linux, macOS, Windows, Android, iOS, FreeBSD, OpenBSD y WebAssembly
- Hay una demo en WebAssembly para una prueba rápida; para ejecutarla se necesita un navegador compatible con WebAssembly
- El código fuente del ejemplo se puede consultar en Kitchen project
Instalación y ruta de aprendizaje
- Gio está diseñado con el objetivo de tener pocas dependencias
- Se pueden consultar las dependencias necesarias en la documentación de instalación de cada plataforma
- Después de instalar, se puede empezar con la documentación de Learn y Hello World
- El showcase incluye godcr, Tailscale, gotraceui, Sointu, Protonet, entre otros
Tecnología de renderizado
- Gio combina la flexibilidad del paradigma de gráficos de modo inmediato con tecnologías modernas de gráficos 2D
- El renderizador vectorial se basa en el Pathfinder project y está implementado sobre OpenGL ES y Direct3D 11
- El renderizador está migrando hacia un renderizador más eficiente basado en shaders de cómputo, construido sobre piet-gpu
- El texto y las formas no se preprocesan como imágenes de textura, sino que se renderizan usando solo contornos
- Permite animaciones eficientes
- Es adecuado para dibujo con transformaciones
- Permite mantener independencia respecto de la resolución de píxeles
Modelo de financiamiento
- El desarrollo de Gio se financia mediante patrocinios
- Si el proyecto te resulta útil, puedes considerar apoyar el proyecto Gio en OpenCollective o patrocinar directamente a sus desarrolladores
1 comentarios
Opiniones de Hacker News
Tras usarlo en la práctica, me resultó imposible crear con esto una app compleja en serio
No tiene componentes como video, mapas o texto enriquecido, que otras plataformas incluyen de base, y tampoco hay un camino claro y sencillo para agregarlos uno mismo
La API se rompe cada pocos meses y tampoco hay forma de aplicar temas
Los gráficos en modo inmediato están bien hasta que hay que manejar estados complejos; a partir de ahí, terminas teniendo que implementar tus propios gráficos en modo retenido, trayendo de vuelta problemas que se resolvieron hace mucho
El vistoso renderizador basado en
piet-gputambién funciona recibiendo solo puntos de control de curvas Bézier como entrada y teselándolo todo, así que el concepto es genial, pero para dibujar un círculo real terminas dependiendo de una aproximación con 4 curvas BézierWasm se parece más a una prueba de concepto que necesitaría varios años de refinamiento de ingeniería por parte del equipo del compilador para llegar a nivel de producto, y en general parece estar bien para desarrolladores Go que quieran crear una UI simple con listas y campos de entrada
También tiene temas de Material Design y modo claro/oscuro
Un excelente ejemplo de app gioui con modo claro/oscuro y temas personalizados es https://github.com/chapar-rest/chapar
En Mac o Windows basta con
go run .El kerning de texto, texto que fluye siguiendo un arco y RTL/LTR también son posibles gracias a
github.com/go-text/typesettingTambién hay widgets complejos como selectores de calendario o diagramas en GitHub, pero falta esfuerzo para reunirlos en un solo lugar
Si esas cosas se agruparan, creo que habría incentivos suficientemente grandes para que más desarrolladores se sumen
No parece haber una cultura que valore que el código de los usuarios no se rompa
Ambos son estables hoy y cuentan con un conjunto relativamente rico de controles y bibliotecas
En la web parece renderizar todo en un canvas, como Flutter, y se sabe que este enfoque tiene problemas de accesibilidad y de sensación nativa
No se puede pasar con Tab entre botones de opción, en macOS
CMD+Ano selecciona todo el campo de texto, mientras queCTRL+AsíParece posible, pero también requeriría bastante trabajo
Se sale un poco del tema, pero últimamente me pregunto cuál es la mejor forma de crear apps móviles y web multiplataforma
Ya sea compartiendo tanto la lógica de negocio como la UI, o solo la lógica de negocio
Estuve evaluando opciones como gomobile, Rust y TypeScript
Durante un tiempo TypeScript me pareció la tecnología más portable y quería usarla para toda la lógica de negocio, pero descubrí que en iOS no hay una buena forma de ejecutar JavaScript con un rendimiento decente
Si te parece bien escribir la UI en nativo y compartir solo la lógica de negocio, Kotlin también es una opción: https://kotlinlang.org/docs/multiplatform.html#kotlin-multip...
Con Compose también se puede crear la UI en Kotlin: https://www.jetbrains.com/lp/compose-multiplatform/
Pero el soporte para iOS todavía está en alfa y web es “experimental”, así que si no quieres asumir que tendrás que cambiar código a medida que el framework evolucione, Flutter, que ya es bastante estable en todas las plataformas, es lo indicado
Si ya conoces TypeScript y React, también podrías considerar React Native, pero es difícil garantizar su rendimiento en iOS u otros entornos: https://reactnative.dev/
Ya vi demasiados frameworks que prometían resolverlo todo y no cumplieron
Al principio empiezas más rápido, pero pronto terminas parcheando bibliotecas clave para que, después de una actualización del OS, los FPS se acerquen a lo nativo o las animaciones del sistema se parezcan más
Solo ahorras tiempo cuando no vas a pulir la UI
La lógica central sí se puede compartir
Uso gomobile y en general me gusta, pero su overhead de runtime es de 3 MB, así que no sirve para la web
Kotlin Multiplatform se veía bien, pero le faltaban bibliotecas básicas y, quizá porque ya existen en Kotlin Android, no había mucha gente haciendo equivalentes multiplataforma
Rust y la capa de bindings de lenguaje de Mozilla también se ven bien, pero todavía no los he probado
Flutter tampoco está mal, pero en web renderiza en un canvas, así que se siente flojo en cuanto a sensación y accesibilidad
En iOS también sigue teniendo problemas de latencia incluso después de introducir el motor de renderizado Impeller
Si miras el cliente de Bluesky, tiene buen rendimiento en todas las plataformas compatibles y usa una sola base de código
https://github.com/bluesky-social/social-app
Es open source y apunta a Android, iOS, Windows, Mac y Linux: https://platform.uno/platforms/
Usa C# e implementa automáticamente vistas y controles con el framework de UI nativo de cada plataforma
También tiene buen soporte de IDE como Visual Studio, VS Code y Rider, y no te limita a esas herramientas
Además tiene un plugin de Figma para colaboración en diseño
No sé si también sea una buena herramienta para productos de consumo
Para nuestro caso encaja bastante bien, porque son principalmente herramientas para técnicos de plantas solares, y usar TypeScript multiplataforma en condiciones de internet deficientes se volvió demasiado pesado para un equipo pequeño
Estoy haciendo una app de streaming con gioui, y es muy fácil; además, las actualizaciones siempre son sencillas
Porque es Go y los desarrolladores principales se toman los cambios bastante en serio
Cuando necesito una GUI web, uso este sistema de plugins de gioui: https://github.com/gioui-plugins/gio-plugins
Sorprende que WebView funcione en web, escritorio y móvil
También hay deep links, así que si envías un enlace por email o de una notificación de Monike, la app del usuario se abre exactamente en la ubicación correcta de la GUI
También tiene notificaciones y extensiones para compartir para todos los OS, así que realmente lo veo como algo cercano a un sistema completo
Estoy de acuerdo en que dar soporte a todos los OS es difícil, pero en el mundo actual la diversidad es lo normal
Me gusta poder hacer todo esto solo con Go, sin estar saltando entre varias tecnologías
El backend en Go siempre lo escribo para que funcione tanto con gio como con HTML
Si necesito SEO o reproducción de video, lo manejo en WebView, y también puedo satisfacer el SEO de Google del lado web de gio
Pongo Markdown en Hugo para que Google SEO lo vea
Como principiante en Go, me da curiosidad esta parte de la documentación.
Dice que la razón para usar
op.ColorOp{Color: red}.Add(ops)en lugar deops.Add(ColorOp{Color: red})es evitar asignaciones al llamar, haciendo que el métodoAddno reciba un argumento de tipo interfaz, y que eso es clave en el diseño de “zero allocation” de Gio.Quiero entender por qué se produce una asignación, qué se asigna y cómo se ahorra.
Cuando una función recibe un argumento de tipo interfaz y se le pasa una estructura pura, Go crea un wrapper alrededor; esa es la asignación mencionada en la cita.
Ese wrapper es un par de punteros: un puntero de tipo/vtable y un puntero a los datos de la estructura.
Esto permite la inferencia de tipos en tiempo de ejecución y la extensión implícita de interfaces.
Es decir, para implementar una interfaz basta con implementar sus métodos, y no hace falta declarar explícitamente el tipo como en
ByteReader extends Reader.Este costo solo se paga cuando se usa, así que mucho código de rutas rápidas usa solo estructuras siempre que puede.
v := interfaceType(concreteTypeValue), a bajo nivel ocurre algo más o menos así:dataPtr := &concreteTypeValue,typePtr := typeData[concreteType](), y luego se crea un valor de interfaz con el puntero a datos y el puntero de tipo.La primera línea es la asignación; según la regla que recuerdo, en Go los punteros no apuntan a valores en la pila, así que
concreteTypeValuedebe asignarse en el heap.La regla de que los punteros no apunten a la pila existe para que las pilas de las goroutines puedan crecer dinámicamente con facilidad.
Consulta https://go.dev/doc/faq#stack_or_heap
ColorOp{Color: red}debe ser boxeado y asignado en el heap.Esto se debe a que
ops.Addnormalmente recibe un puntero “grueso” a un valor que implementa cierta interfaz, no un valor de tipo concreto.op.ColorOp{Color: red}.Add(ops)se lee raro.Para mí se lee como “agregar
opsal resultado deop.ColorOp{Color: red}”.Por eso me gustaría llamar a la función
AddTo:op.ColorOp{Color: red}.AddTo(ops).Sigue sin ser muy idiomático, pero al menos indica que el argumento de la función se modifica.
Es interesante que en una PC bastante común con Windows 10 y Chrome, la demo de WASM de la primera página renderiza solo rectángulos negros donde debería haber texto.
En Chrome en un teléfono Android se renderizó correctamente.
Además, se ejecutó lentísimo.
Hice una app pequeña en Go usando Fyne y no pienso volver a usarlo.
Tanto Gio como Fyne están muy lejos del nivel de pulido y funcionalidades que ofrece Flutter.
Terminé haciendo la lógica central en Golang y envolviéndola en una app Android, pero la GUI parecía salida de 2003 y había pocas formas de arreglarla.
Puedes escribir toda la lógica en Go y la UI en HTML, usando o no un framework web.
Es parecido a Electron, pero más liviano porque no distribuye Chrome junto con la app, sino que usa el visor web del sistema.
[1] https://github.com/wailsapp/wails
Me gustaría que pudieras explicar cómo la envolviste como app Android.
¿Por qué todas estas GUI multiplataforma parecen haber sido diseñadas hace 50 años?
La demo no me funciona.
En Chromium sobre Win 11 veo algunos botones, pero la mayor parte está completamente en negro.
A diferencia de Fyne, esta biblioteca pasó mi primera prueba: renderizado de texto CJK, lo cual es una buena señal.
Fyne no puede hacer eso a menos que le des una fuente personalizada única para renderizar todo.
Encontrar una sola fuente que incluya satisfactoriamente no solo todos los sistemas de escritura de uso común en el mundo, sino también emojis, es cuestión de tener mucha suerte.
Por eso, para mí Fyne queda descartado de inmediato si voy a crear algo con contenido generado por usuarios, contenido web o la más mínima posibilidad de localización.