{"id":48764221,"url":"https://github.com/crgimenes/glaze","last_synced_at":"2026-04-13T07:46:14.069Z","repository":{"id":337403155,"uuid":"1153451710","full_name":"crgimenes/glaze","owner":"crgimenes","description":"Glaze: a CGO-free desktop WebView toolkit for Go, with practical helpers for building native app windows from web UIs.","archived":false,"fork":false,"pushed_at":"2026-03-31T14:18:47.000Z","size":84968,"stargazers_count":10,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-03-31T16:25:00.501Z","etag":null,"topics":["cgo-free","cross-platform","desktop","go","golang","purego","webview"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/crgimenes.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-02-09T10:11:38.000Z","updated_at":"2026-03-31T14:19:58.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/crgimenes/glaze","commit_stats":null,"previous_names":["crgimenes/go-webview","crgimenes/glaze"],"tags_count":14,"template":false,"template_full_name":null,"purl":"pkg:github/crgimenes/glaze","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/crgimenes%2Fglaze","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/crgimenes%2Fglaze/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/crgimenes%2Fglaze/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/crgimenes%2Fglaze/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/crgimenes","download_url":"https://codeload.github.com/crgimenes/glaze/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/crgimenes%2Fglaze/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31744404,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-13T06:26:45.479Z","status":"ssl_error","status_checked_at":"2026-04-13T06:26:44.645Z","response_time":93,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cgo-free","cross-platform","desktop","go","golang","purego","webview"],"created_at":"2026-04-13T07:46:13.378Z","updated_at":"2026-04-13T07:46:14.048Z","avatar_url":"https://github.com/crgimenes.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Glaze\n\nGlaze is a pure Go desktop WebView binding built on top of [webview/webview](https://github.com/webview/webview) and [purego](https://github.com/ebitengine/purego).\n\nThis repository started from the original `go-webview` project, but it has diverged significantly and is maintained as a separate codebase with its own goals and APIs.\n\n## Goals\n\n- Keep a CGo-free desktop integration layer for Go applications.\n- Provide pragmatic helpers for desktop app workflows.\n- Keep behavior explicit and testable.\n- Stay friendly to multi-module `go.work` development.\n\n## Key Features\n\n- No CGo\n- Windows, macOS, and Linux support\n- Native library loading with embedded runtime assets\n- JavaScript to Go binding support\n- Utility helpers for desktop app patterns: `BindMethods`, `RenderHTML`, `AppWindow`\n\n## Examples\n\n| Desktop | Game of Life | Starfield |\n| --- | --- | --- |\n| [![Desktop example preview](imgs/desktop.gif)](examples/desktop/) | [![Game of Life example preview](imgs/gameoflife.gif)](examples/gameoflife/) | [![Starfield example preview](imgs/starfield.gif)](examples/starfield/) |\n\n| Doom Fire | Mandelbrot | Falling Sand |\n| --- | --- | --- |\n| [![Doom Fire example preview](imgs/doomfire.gif)](examples/doomfire/) | [![Mandelbrot example preview](imgs/mandelbrot.gif)](examples/mandelbrot/) | [![Falling Sand example preview](imgs/fallingsand.gif)](examples/fallingsand/) |\n\n| Raycasting | Filo REPL | |\n| --- | --- | --- |\n| [![Raycasting example preview](imgs/raycasting.gif)](examples/raycasting/) | [![Filo REPL example preview](imgs/filorepl.gif)](examples/filorepl/) | |\n\n## Install\n\n```bash\ngo get github.com/crgimenes/glaze@latest\n```\n\nTo use embedded native libraries:\n\n```go\nimport _ \"github.com/crgimenes/glaze/embedded\"\n```\n\n## Quick Start\n\n```go\npackage main\n\nimport (\n \"log\"\n\n \"github.com/crgimenes/glaze\"\n _ \"github.com/crgimenes/glaze/embedded\"\n)\n\nfunc main() {\n w, err := glaze.New(true)\n if err != nil {\n  log.Fatal(err)\n }\n defer w.Destroy()\n\n w.SetTitle(\"Glaze\")\n w.SetSize(800, 600, glaze.HintNone)\n w.SetHtml(\"\u003ch1\u003eHello from Glaze\u003c/h1\u003e\")\n w.Run()\n}\n```\n\nGlaze pins the goroutine that creates the first window to its current OS thread.\nKeep direct window calls on that goroutine, and use `Dispatch` to re-enter the UI\nthread from background work.\n\n## Desktop Helpers\n\n### BindMethods\n\n`BindMethods` is a convenience layer over `Bind` that exposes all exported\nmethods of a Go value as JavaScript-callable functions.\n\nWhat it does:\n\n- Reflects over exported methods on a struct or pointer receiver.\n- Builds JavaScript names using a prefix and snake_case conversion.\n  - Example: `GetUserByID` with prefix `api` becomes `api_get_user_by_id`.\n- Applies the same function signature rules as `Bind`:\n  - no return\n  - value\n  - error\n  - value and error\n- Returns the list of bound names so you can log or verify registration.\n\nThis is useful when you have a service object and want to expose a consistent\nJavaScript API without writing one `Bind` call per method.\n\n```go\ntype Store struct{}\n\nfunc (s *Store) GetItems() []string { return []string{\"a\", \"b\"} }\n\nbound, err := glaze.BindMethods(w, \"store\", \u0026Store{})\n```\n\n### RenderHTML\n\n`RenderHTML` renders a named Go `html/template` into a string for `SetHtml`.\n\nWhat it does:\n\n- Executes a specific template by name (including nested template calls).\n- Returns the final HTML string.\n- Wraps template execution errors with template context.\n\nThis is useful when you want server-style template rendering in a local desktop\napp without running an HTTP server for that page.\n\n```go\nhtml, err := glaze.RenderHTML(tpl, \"page\", data)\nif err != nil {\n return err\n}\nw.SetHtml(html)\n```\n\n### AppWindow\n\n`AppWindow` wraps an `http.Handler` inside a native desktop window backed by a\nlocal loopback HTTP server.\n\nWhat it does:\n\n- Supports selectable transport with platform-aware default:\n  - `auto` (default): `unix` on macOS/Linux, `tcp` on Windows\n  - `tcp`: direct loopback HTTP (`127.0.0.1`)\n  - `unix`: handler served on Unix socket with a lightweight loopback HTTP\n    gateway for browser navigation\n- Starts listeners using random free ports/paths by default (or custom\n  `Addr`/`UnixSocketPath`).\n- Creates a native window and navigates it to that local URL.\n- Runs the UI loop and closes the HTTP server when the window exits.\n- Supports window sizing, title, debug mode, and optional readiness callback.\n  - `OnReady`: receives browser URL (always `http://127.0.0.1:...`).\n  - `OnReadyInfo`: receives resolved backend details (`Transport`, `Backend`,\n    `Gateway`) so you can verify unix vs tcp in logs.\n\nThis is the simplest way to reuse an existing `net/http` application as a\ndesktop app with minimal changes to your routing, templates, and assets.\n\n```go\nerr := glaze.AppWindow(glaze.AppOptions{\n Title:     \"My App\",\n Width:     1280,\n Height:    800,\n Transport: glaze.AppTransportAuto,\n Handler:   mux,\n OnReadyInfo: func(info glaze.AppReadyInfo) {\n  log.Printf(\"transport=%s backend=%s gateway=%s\", info.Transport, info.Backend, info.Gateway)\n },\n})\n```\n\n## Running Examples\n\nFrom the repository root:\n\n```bash\ngo run ./examples/simple\ngo run ./examples/bind\ngo run ./examples/zero_tcp\n```\n\nFrom each example directory:\n\n```bash\ncd examples/appwindow \u0026\u0026 go run .\ncd examples/desktop \u0026\u0026 go run .\ncd examples/filorepl \u0026\u0026 go run .\n```\n\n`examples/zero_tcp` demonstrates a local-first UI with `SetHtml + BindMethods`\nonly. It does not start an HTTP server, so there is no loopback TCP gateway.\n\n## Testing\n\nDefault tests (headless safe):\n\n```bash\ngo test ./...\n```\n\nGUI integration test:\n\n```bash\ngo test -tags=integration -run TestWebview ./...\n```\n\n## Building on Windows\n\nUse `windowsgui` to hide the console window:\n\n```bash\ngo build -ldflags=\"-H windowsgui\" .\n```\n\n## Project Layout\n\n- `webview.go` - core API and binding internals\n- `appwindow.go` - desktop window plus local HTTP server helper\n- `helpers.go` - utility helpers (`BindMethods`, `RenderHTML`)\n- `embedded/` - embedded native library assets per platform\n- `examples/` - runnable sample applications\n\n## Security: Library Integrity Verification\n\nGlaze embeds native libraries and extracts them to disk before loading. By\ndefault, the extraction target is a temporary directory that may be writable by\nother processes, which could allow an attacker to replace the library file.\n\nTo mitigate this, Glaze computes a BLAKE2b-256 hash of the embedded library\nbytes at runtime and verifies every extracted (or pre-existing) file against\nthat hash before loading. If the hash does not match, extraction fails with an\nintegrity error and the library is **not** loaded.\n\nAdditionally, extracted files are created with restricted permissions (`0500`\nowner read+execute) inside a directory with `0700` permissions.\n\n### Custom Library Directory\n\nFor production deployments, use `ExtractTo` to place the library in a secure,\napplication-controlled directory instead of the system temp directory:\n\n```go\npackage main\n\nimport (\n \"log\"\n\n \"github.com/crgimenes/glaze\"\n \"github.com/crgimenes/glaze/embedded\"\n)\n\nfunc main() {\n // Extract to a directory with restricted access.\n if err := embedded.ExtractTo(\"/opt/myapp/lib\"); err != nil {\n  log.Fatal(err)\n }\n\n w, err := glaze.New(true)\n if err != nil {\n  log.Fatal(err)\n }\n defer w.Destroy()\n\n w.SetTitle(\"Secure App\")\n w.SetSize(800, 600, glaze.HintNone)\n w.SetHtml(\"\u003ch1\u003eHello\u003c/h1\u003e\")\n w.Run()\n}\n```\n\nWhen using `ExtractTo`, do **not** use `import _ \"github.com/crgimenes/glaze/embedded\"` — that\nblank import triggers `init()` which extracts to the default temp directory.\nCall `ExtractTo` explicitly instead.\n\n## Acknowledgments\n\n- [abemedia/go-webview](https://github.com/abemedia/go-webview) for the original Go binding base\n- [webview/webview](https://github.com/webview/webview) for the native WebView implementation\n- [purego](https://github.com/ebitengine/purego) for dynamic linking without CGo\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcrgimenes%2Fglaze","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcrgimenes%2Fglaze","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcrgimenes%2Fglaze/lists"}