Example projects #
Regulus needs real examples that prove the compiler can handle useful Gleam projects, browser-oriented Wasm, and JS-hosted server Wasm. The first examples should be small enough to maintain, but large enough to expose missing compiler capabilities before they become design debt.
Goals #
- Build a local-first Lustre single-page app that shows simple National Weather Service forecasts for US cities.
- Build a Wisp-style Wasm API deployable to a JS-hosted server environment that serves a small developer reference API.
- Use the examples as compiler acceptance fixtures, not as separate product projects.
- Keep host boundaries explicit and target-specific.
- Prefer general language, dependency, runtime, and ABI support over example-specific compiler behavior.
Current compiler gaps #
The current CLI builds supported gleam.toml projects into one linked Wasm
artifact. It also keeps single-file compilation available for small tests and
fixtures.
The compiler can load selected Hex and path dependency source modules, but it does not compile arbitrary dependency code without subset limits.
General external functions lower to Wasm imports when the selected target and
ABI shape are supported. Bodyless @external declarations from project and
dependency source use the same selected target ABI when metadata is available.
The low-level host ABI supports scalar values and borrowed managed pointers. The generated JavaScript adapter is the checked host path for browser, bundler, and Node.js targets. It supports strings, selected structured export results, import/export metadata, standard browser and Node.js import helpers, and adapter-owned opaque handle tables.
Structured JavaScript values passed into Gleam imports or exported function parameters are still deferred. Broader dependency source compilation, full dynamic decoding, and arena reset reclamation remain the main gaps for larger examples.
gleam/dynamic, gleam/dynamic/decode, gleam/uri, gleam/pair,
gleam/set, gleam/string_tree, and gleam/bytes_tree are still unsupported
or interface-only. The examples should avoid unnecessary breadth, but JSON and
HTTP work should be handled by compiling library code where possible plus a
small dynamic-value or host bridge where necessary.
Lustre weather SPA #
The weather app should be a local-first browser example. It should compile a Lustre app to Wasm, load it from a small JS host, and use the NWS Weather API for forecasts based on selected US cities.
The first version should avoid geocoding. It can ship a static city table with city names and known NWS grid points. The app stores the selected city and the last successful forecast locally, then refreshes from the network when the browser host is online.
The compiler should not need to implement browser networking directly in
Gleam. A small target-specific host import can provide fetch_text, local
storage reads and writes, and time or online state as needed. The Gleam side
should keep those imports behind an example module with explicit types. The
compiler should only provide general external-function lowering, target
validation, ABI checks, and runtime adapters.
The example is useful when it proves:
- The existing project build path can host a real browser app shape.
- Lustre dependency interfaces can be loaded or modeled.
- Browser-specific host APIs are adapted through the JS host ABI.
- String and simple structured values cross the host boundary predictably.
- Unsupported dependency or ABI shapes fail with source-spanned diagnostics.
Wisp developer reference API #
The Wisp example should compile to a Wasm module that a JS-hosted server can call for route handling or route data. The first version should serve a small static developer reference catalog.
The initial route surface should stay intentionally small:
GET /gitignoreGET /gitignore/:nameGET /gitattributesGET /gitattributes/:nameGET /licensesGET /licenses/:idGET /spdxGET /spdx/:idGET /mime/:extensionGET /http/status/:codeGET /languagesGET /languages/:nameGET /cronGET /cron/:name
The datasets should cover gitignore templates, gitattributes templates, common licenses, SPDX metadata, MIME type lookup, HTTP status metadata, language metadata, and common cron presets.
Static content can be embedded in Gleam source or generated into Gleam modules at build time. Generated sources must be deterministic and small enough for review.
The JS host can own the real request and response objects. The Wasm API should start with simple string inputs and structured return data, then graduate to opaque request and response handles only when needed. Routing, static data lookup, and response shaping should live in compiled Gleam code, not in compiler-owned special cases.
The example is useful when it proves:
- The existing project build path can host a JS-server Wasm API shape.
- Wisp dependency interfaces can be loaded or modeled.
- Bundler-profile externals lower to Wasm imports.
- Static data can be embedded without brittle manual memory handling.
- The emitted Wasm and bundler adapter are usable without manual pointer handling in application code.
Acceptance #
Both examples must be built from normal project directories with gleam.toml.
The compiler should emit deterministic Wasm and optional WAT/debug artifacts.
Each example must have:
- A checked fixture or integration test that compiles it.
- A small host adapter checked into
examples/. - Documentation for the host imports and exported functions it uses.
- Clear diagnostics for the next unsupported feature encountered.
Active tasks #
See Lustre weather example tasks and Wisp static data API tasks.