mola-sitegen-wren logo
mola-sitegen-wren

Wren, Zig, HTML IR, WASM

Live Demo

Static HTML, live WASM demos.

Demo 1

Hacker News panel

This panel is rendered at build time with placeholders, then hydrated by Zig/WASM in the browser. Mode changes, fetch sequencing, and fragment rendering all live in app.wasm.

loading

Fetching stories...

The client will replace this placeholder after app.wasm starts.

Code example

Live feed example

The WASM runtime constructs the API URLs and drives the fetch lifecycle itself.

fn requestIds(panel_index: u32, request_id: u32, mode: []const u8) !void {
    const url = try std.fmt.allocPrint(allocator, "https://hacker-news.firebaseio.com/v0/{s}stories.json", .{mode});
    defer allocator.free(url);

    jsFetch(panel_index, request_id, @intFromEnum(FetchPhase.ids), slicePtr(url), @intCast(url.len));
}

Demo 2

WASM form

Submitting this form sends the current config into Zig/WASM. The runtime updates a preview card and uses the same settings to influence the live feed behavior.

Feed mode

Preview

WASM preview

Preview will hydrate

The first form submission will replace this placeholder.

Code example

Form to WASM example

JS is only the host bridge. It forwards browser events and form state into WASM.

control.element.addEventListener("click", () => {
  invokeWithStrings(exportsRef, [control.mode], (modeArgv) => {
    exportsRef.selectMode(panelIndex, modeArgv.ptr, modeArgv.len);
  });
});

form.addEventListener("submit", (event) => {
  event.preventDefault();
  runtime.updateDemo(readDemoConfig(form));
});

Code example

Preview rendering example

The preview card is not handwritten HTML in JavaScript. Zig renders it like every other fragment.

pub fn renderDemoPreviewAlloc(allocator: std.mem.Allocator, title: []const u8, mode: []const u8, item_count: u32, show_comments: bool, hostname_only: bool) ![]u8 {
    // Build a preview card with the same mola-sitegen1 HTML IR used elsewhere.
}

Demo 3

Image gallery

This demo fetches image metadata from a public API, then renders the gallery through Zig-owned HTML fragments instead of handwritten DOM code.

loading

Code example

Image gallery example

The URL and gallery state live in WASM. JavaScript only performs the browser fetch and DOM patch.

fn requestImages(request_id: u32, page: u32) !void {
    const url = try std.fmt.allocPrint(allocator, "https://picsum.photos/v2/list?page={d}&limit=6", .{page});
    defer allocator.free(url);
    jsFetchImage(request_id, @intFromEnum(ImageFetchPhase.gallery), slicePtr(url), @intCast(url.len));
}

Demo 4

WASM SVG

This form sends SVG parameters into Zig/WASM. The preview markup is generated there and mounted into the page as a browser-side artifact.

Preview

SVG preview

SVG preview will hydrate

The initial SVG comes from app.wasm, then updates on form submission.

Code example

SVG generation example

The SVG is not stored as a static asset. It is generated in the WASM runtime from the submitted form state.

pub fn renderSvgPreviewAlloc(allocator: std.mem.Allocator, title: []const u8, accent_hex: []const u8, ring_count: u32) ![]u8 {
    // Build the SVG markup in Zig and return an HTML fragment for mounting.
}

Code example

Host bridge example

The browser host only forwards form state and mounts the HTML returned from Zig.

jsSetSvgPreviewHtml(htmlPtr, htmlLen) {
  svgDemo.preview.innerHTML = readWasmString(exportsRef.memory, htmlPtr, htmlLen);
}

const config = JSON.stringify(readSvgConfig(svgDemo.form));
exportsRef.updateSvg(configArgv.ptr, configArgv.len);