Glaze
Glaze builds desktop applications with a Racket backend and a Web frontend rendered inside a native OS window. Windows uses WebView2, macOS uses WKWebView, and Linux uses WebKitGTK.
1 Quick Start
$ raco pkg install --auto glaze |
$ raco glaze init myapp |
$ cd myapp |
$ racket main.rkt |
# or: raco glaze dev |
A Glaze application is native-GUI only. If its native WebView cannot start, application startup fails with platform-specific installation or repair guidance. Glaze never substitutes a system-browser tab for the desktop window.
2 Application Lifecycle
| (require glaze/app) | package: glaze |
When the native window closes, the local server is stopped and the procedure returns (values 'webview shutdown). If native WebView startup fails, Glaze first stops the local server and then propagates an actionable startup error. There is intentionally no browser-fallback option.
#:api-token may be a string or #t. With #t, Glaze generates a random capability token and uses a one-time bootstrap URL to set an HttpOnly cookie for the embedded frontend. #:on-error receives API handler failures. #:check-update wires an update manifest into the application lifecycle.
parameter
(current-api-token token) → void? token : string?
3 Local Server
| (require glaze/server) | package: glaze |
procedure
(start-server [ #:port port #:public-dir public-dir #:api api #:events events #:api-token api-token #:serve-api-client? serve-api-client?])
→
exact-nonnegative-integer? procedure? port : exact-nonnegative-integer? = 8080 public-dir : (or/c string? path?) = "public" api : (listof route?) = '() events : (or/c #f event-bus?) = #f api-token : (or/c #f string?) = #f serve-api-client? : boolean? = #t
| (require glaze/browser) | package: glaze |
4 JavaScript Bridge
| (require glaze/api) | package: glaze |
The embedded frontend calls Racket through ordinary same-origin HTTP requests. This keeps the bridge easy to inspect and test with normal developer tools.
A route handler receives the web-server request followed by any captured :param path values. Returning a jsexpr produces a JSON 200 response; a full response value may also be returned.
procedure
status : exact-nonnegative-integer? message : string?
| (require glaze/api-macros) | package: glaze |
(define-api-routes api [(POST "api/counter/bump") (bump [delta exact-nonnegative-integer? 1]) (hasheq 'count (add1 delta))])
The generated /glaze/api.js exposes route-specific functions plus glaze.call(...) and glaze.on(...).
5 Event Push
| (require glaze/events) | package: glaze |
Glaze uses same-origin Server-Sent Events for backend-to-frontend push.
procedure
bus : event-bus? name : (or/c symbol? string?) data : jsexpr?
6 Native WebView
| (require glaze/webview/main) | package: glaze |
The native WebView is an application prerequisite, not an optional rendering mode. The backends are WebView2 on Windows, WKWebView on macOS, and WebKitGTK on Linux.
procedure
(open-window url [ #:title title #:width width #:height height #:devtools? devtools? #:on-close on-close]) → webview? url : string? title : string? = "Glaze" width : exact-positive-integer? = 1024 height : exact-positive-integer? = 768 devtools? : boolean? = #f on-close : (-> any) = (lambda () (void))
There is no #:fallback-browser? keyword.
procedure
(open-webview url [ #:title title #:width width #:height height #:devtools? devtools? #:on-close on-close]) → webview? url : string? title : string? = "Glaze" width : exact-positive-integer? = 1024 height : exact-positive-integer? = 768 devtools? : boolean? = #f on-close : (-> any) = (lambda () (void))
procedure
wv : webview? dest : (or/c #f string? path?) = #f
procedure
wv : webview? width : exact-positive-integer? height : exact-positive-integer?
6.1 Startup Dependency Feedback
When native startup fails, Glaze reports the backend error and remediation. Typical guidance includes:
Windows: install or repair Microsoft Edge WebView2 Runtime (Evergreen), with a winget command and Microsoft’s official download page.
Debian/Ubuntu: sudo apt install libgtk-3-0 libwebkit2gtk-4.1-0.
Fedora: sudo dnf install gtk3 webkit2gtk4.1.
Arch: sudo pacman -S gtk3 webkit2gtk-4.1.
macOS: WKWebView is built in; use a logged-in graphical session and report the preserved backend error if initialization still fails.
Set environment variable GLAZE_NO_STARTUP_DIALOG to 1 to suppress the interactive error dialog while retaining the exception. Dialogs are also suppressed automatically under common CI environments.
7 System Integrations
| (require glaze/sys) | package: glaze |
procedure
title : string? body : string? = "" subtitle : string? = ""
These helpers are best-effort integrations. Their failure semantics are separate from the WebView startup contract: the WebView is required for the application itself, while an optional integration may report failure without changing the application’s rendering model.
8 System Tray
| (require glaze/tray) | package: glaze |
procedure
(make-tray #:icon icon #:tooltip tooltip #:menu menu [ #:on-event on-event]) → tray? icon : any/c tooltip : string? menu : list? on-event : procedure? = (lambda (e) (void))
The tray remains an optional capability. If its native backend is unavailable, Glaze may use an inert tray stub; this does not weaken the mandatory native WebView contract for the main window.
9 Security
The local server binds to loopback and validates Host headers against 127.0.0.1, localhost, and [::1] to reduce DNS rebinding risk.
With #:api-token, API routes and the SSE stream require a capability. run-app opens the native WebView at a one-time bootstrap URL; the server exchanges the token for an HttpOnly cookie and redirects to the clean path. Programmatic clients may use the X-Glaze-Token header.
This is defense in depth against casual local callers, not isolation from other processes running as the same OS user.
10 Update Checks
| (require glaze/update) | package: glaze |
procedure
(check-update manifest-url [ #:current-version current-version]) → (or/c #f hash?) manifest-url : string? current-version : string? = "0.0.0"
procedure
path : (or/c string? path?) expected-hex : string?
11 Licensing
| (require glaze/license) | package: glaze |
Glaze includes an offline RSA-2048/SHA-256 licensing helper backed by the system openssl command.
procedure
(issue-license #:private-key private-key #:product product #:subject subject [ #:expiry expiry #:machine-id machine-id #:out output]) → path? private-key : path-string? product : string? subject : string? expiry : (or/c #f string?) = #f machine-id : (or/c #f string?) = #f output : (or/c string? path?) = "app.license"
procedure
(validate-license license-file #:public-key public-key #:product product [ #:machine-id machine-id]) → hash? license-file : (or/c string? path?) public-key : path-string? product : string? machine-id : string? = (machine-id)
12 File Dialogs
| (require glaze/dialogs) | package: glaze |
procedure
(pick-file [ #:title title #:directory directory #:filters filters]) → (or/c #f path?) title : (or/c #f string?) = #f directory : (or/c #f path-string?) = #f filters : list? = '()
procedure
(pick-files [ #:title title #:directory directory #:filters filters]) → (listof path?) title : (or/c #f string?) = #f directory : (or/c #f path-string?) = #f filters : list? = '()
13 Deep Links and Launch at Login
| (require glaze/deeplink) | package: glaze |
procedure
(ensure-url-scheme! scheme [ #:app-name app-name]) → any/c scheme : string? app-name : string? = scheme
| (require glaze/autolaunch) | package: glaze |
14 Packaging
| (require glaze/build) | package: glaze |
procedure
(build-app [ #:entry entry #:name name #:version version #:icon icon #:out-dir out-dir #:embed-dlls? embed-dlls? #:installer? installer? #:sign sign #:entitlements entitlements #:no-hardened-runtime? no-hardened-runtime? #:timestamp-url timestamp-url #:notarize-profile notarize-profile #:url-schemes url-schemes]) → path? entry : (or/c string? path?) = "main.rkt" name : (or/c #f string?) = #f version : (or/c #f string?) = #f icon : any/c = #f out-dir : (or/c string? path?) = "dist" embed-dlls? : boolean? = #f installer? : boolean? = #f sign : (or/c #f string?) = #f entitlements : any/c = #f no-hardened-runtime? : boolean? = #f timestamp-url : (or/c #f string?) = #f notarize-profile : (or/c #f string?) = #f url-schemes : list? = '()
Installer-toolchain absence may degrade an installer request to an archive with a loud warning. That packaging fallback is unrelated to runtime startup: the built application still requires its native WebView.
15 CLI Commands
raco glaze init <name> Create a native desktop project |
raco glaze dev Run the project's native main.rkt |
raco glaze build Build a distributable / installer |
raco glaze keygen [--out <dir>] Create an RSA keypair for licenses |
raco glaze license sign|verify Sign or verify license files |
raco glaze help Show help |
There is intentionally no browser-mode dev or serve command. Development and production use the same native WebView startup path.