EnglishFrançais

01 — Getting started

Prerequisites

Install

From the project where you'll write the app:

amc package add ui-web

This fetches amalgame-ui-web into ~/.amalgame/packages/, pins the version in amalgame.lock, and lets amc wire the import Amalgame.UI.Web statement.

If you prefer scaffolding, amc new --template ui-web-form lays out a complete project (amalgame.toml, src/main.am, build.sh, .gitignore) — see the main README for the flags.

A minimal window

src/hello.am:

import Amalgame.UI.Web

class Program {
    public static void Main() {
        let win: Window = new Window("Hello", 480, 320, false)
        if (!win.IsValid()) {
            Console.WriteError("ui-web: failed to create webview slot")
            return
        }

        Page.New()
            .SetTitle("Hello, Amalgame!")
            .SetBody(
                Element.Stack()
                    .AddChild(Element.Heading("Hello, Amalgame"))
                    .AddChild(Element.Label("Welcome to ui-web v0.0.5."))
                    .AddChild(Element.Button("Click me")
                        .OnClick((req: string) => "\"clicked\"")
                        .OnResult("out"))
                    .AddChild(Element.Pre("").Id("out"))
            )
            .ApplyTo(win)

        win.Run()
        win.Destroy()
    }
}

The Window constructor takes (title, width, height, debug). debug=true exposes DevTools (Ctrl+Shift+I); leave it false in shipped builds.

Shorter entry point — Form + Application.Run (v0.0.7)

For apps that read more naturally as WinForms boilerplate, use the value-style Form wrapper and let Application.Run handle the Window + Page + ApplyTo + Run + Destroy plumbing:

import Amalgame.UI.Web

class Program {
    public static void Main() {
        let f: Form = new Form("Hello", 480, 320)
        f.SetBody(
            Element.Stack()
                .AddChild(Element.Heading("Hello, Amalgame"))
                .AddChild(Element.Button("Click me")
                    .OnClick((req: string) => "\"clicked\"")
                    .OnResult("out"))
                .AddChild(Element.Pre("").Id("out"))
        )
        Application.Run(f)
    }
}

Form is a flat class (not a base to subclass — AM's static dispatch makes parent-virtual overrides unreliable). It carries the title, size, body, theme, debug flag, plus an optional OnLoad(handler) Closure that fires once the window is up so you can do late win.Bind registrations:

let f: Form = new Form("Editor", 1024, 768)
f.SetTheme("auto")
f.SetDebug(false)
f.OnLoad((req: string) => {
    // wire late bindings here once the webview is live
    return ""
})
f.SetBody( … )
Application.Run(f)

Both styles produce identical binaries — Application.Run is sugar over the explicit new Window(...) → Page.ApplyTo → win.Run() sequence.

Build script

A typical build.sh on Linux (mirrors what amc new generates):

#!/bin/sh
set -eu

AMC="${AMC:-amc}"
APP_NAME="hello"
PKG_DIR="${AMALGAME_PACKAGES_DIR:-$HOME/.amalgame/packages}"
UIWEB="$PKG_DIR/amalgame-ui-web"

# 1. Compile the webview C++ implementation once.
test -f "$UIWEB/runtime/vendor/webview/webview.o" || \
    g++ -c -O2 -DWEBVIEW_GTK \
        "$UIWEB/runtime/vendor/webview/webview.cc" \
        -o "$UIWEB/runtime/vendor/webview/webview.o"

# 2. Compile the C glue layer.
test -f "$UIWEB/runtime/Amalgame_UI_Web.o" || \
    gcc -c -O2 -I"$UIWEB/runtime" \
        "$UIWEB/runtime/Amalgame_UI_Web.c" \
        -o "$UIWEB/runtime/Amalgame_UI_Web.o"

# 3. Compile facade.am into a static lib once per ui-web version.
(cd "$UIWEB" && test -f facade.o || ("$AMC" --lib facade.am --quiet && \
    gcc -c -O2 -Iruntime a.out.c -o facade.o))

# 4. Compile our app + link.
"$AMC" -o "$APP_NAME" "src/main.am" --external "$UIWEB/facade.am" --quiet
gcc -O2 \
    -I"$UIWEB/runtime" -I"$UIWEB/runtime/vendor/webview" \
    "${APP_NAME}.c" \
    "$UIWEB/facade.o" \
    "$UIWEB/runtime/Amalgame_UI_Web.o" \
    "$UIWEB/runtime/vendor/webview/webview.o" \
    $(pkg-config --libs webkit2gtk-4.1) \
    -lstdc++ -lgc -lm -lcurl -lz \
    -o "$APP_NAME"

amc new --template ui-web-form produces a turnkey version of this with macOS / Windows paths. Existing apps can copy it verbatim — only the package path lookup changes between OSes.

Run:

./build.sh && ./hello

You should see a 480×320 window with the heading, a button, and an empty <pre> panel. Clicking the button prints "clicked" (with quotes — that's the JSON encoding) into the panel.

What's happening

You write Amalgame for the entire app. No hand-written HTML. No JS unless you reach for it deliberately (see 05-extending.md).

Where to look next

Common pitfalls