Boost basics

The smallest end-to-end dasImgui v2 program. One window, one slider, one button. The slider drives a float (VOLUME.value) and the button accumulates a click counter (BUMP_BTN.click_count). Both pieces of state are auto-generated daslang globals; nothing is stored inside Dear ImGui.

Source: examples/tutorial/boost_basics.das.

Walkthrough

boost_basics recording
 1options gen2
 2
 3require imgui
 4require imgui_app
 5require glfw/glfw_boost
 6require opengl/opengl_boost
 7require live/glfw_live
 8require live/live_api
 9require live/live_commands
10require live/live_vars
11require live/opengl_live
12require live_host
13require imgui/imgui_live
14require imgui/imgui_boost_runtime
15require imgui/imgui_boost_v2
16require imgui/imgui_widgets_builtin
17require imgui/imgui_containers_builtin
18require imgui/imgui_visual_aids
19
20// =============================================================================
21// TUTORIAL: boost_basics — the smallest dasImgui v2 program.
22//
23// One window. One slider drives a float. One button increments a counter.
24// State lives in daslang globals (@live by default, so values survive reload).
25//
26// STANDALONE: daslang.exe modules/dasImgui/examples/tutorial/boost_basics.das
27// LIVE:       daslang-live modules/dasImgui/examples/tutorial/boost_basics.das
28//
29// DRIVE (when running live):
30//   curl -X POST -d '{"name":"imgui_snapshot"}' localhost:9090/command
31//   curl -X POST -d '{"name":"imgui_set","args":{"target":"BASICS_WIN/VOLUME","value":0.75}}' \
32//        localhost:9090/command
33//   curl -X POST -d '{"name":"imgui_click","args":{"target":"BASICS_WIN/BUMP_BTN"}}' \
34//        localhost:9090/command
35// =============================================================================
36
37[export]
38def init() {
39    live_create_window("dasImgui boost basics", 640, 320)
40    live_imgui_init(live_window)
41    var io & = unsafe(GetIO())
42    io.FontGlobalScale = 1.5
43}
44
45[export]
46def update() {
47    if (!live_begin_frame()) return
48    begin_frame()
49
50    ImGui_ImplOpenGL3_NewFrame()
51    ImGui_ImplGlfw_NewFrame()
52    apply_synth_io_override()
53    NewFrame()
54
55    SetNextWindowSize(ImVec2(560.0, 240.0), ImGuiCond.Always)
56    window(BASICS_WIN, (text = "Boost basics", closable = false,
57                        flags = ImGuiWindowFlags.None)) {
58        // Slider — VOLUME state lives in a generated daslang global.
59        VOLUME.bounds = (0.0f, 1.0f)
60        slider_float(VOLUME, (text = "Volume"))
61        text("volume = {VOLUME.value}")
62
63        spacing(BB_SP_1)
64
65        // Button — BUMP_BTN.click_count is updated on every click.
66        if (button(BUMP_BTN, (text = "Bump"))) {
67            print("bump clicked\n")
68        }
69        text("bumps = {BUMP_BTN.click_count}")
70    }
71
72    end_of_frame()
73    Render()
74    var w, h : int
75    live_get_framebuffer_size(w, h)
76    glViewport(0, 0, w, h)
77    glClearColor(0.10f, 0.10f, 0.12f, 1.0f)
78    glClear(GL_COLOR_BUFFER_BIT)
79    ImGui_ImplOpenGL3_RenderDrawData(GetDrawData())
80
81    live_end_frame()
82}
83
84[export]
85def shutdown() {
86    live_imgui_shutdown()
87    live_destroy_window()
88}
89
90[export]
91def main() {
92    init()
93    while (!exit_requested()) {
94        update()
95    }
96    shutdown()
97}

Requires

The require block pulls in:

  • The C++-bound Dear ImGui surface (imgui, imgui_app).

  • The GLFW backend + OpenGL renderer + live-reload host glue (glfw/..., opengl/..., live/...).

  • The dasImgui v2 boost layer: imgui_live (lifecycle), imgui_boost_runtime (state structs), imgui_boost_v2 (macros), imgui_widgets_builtin (the actual widget implementations), imgui_containers_builtin (the window(...) block-arg container and its siblings), imgui_visual_aids (the synth-IO override hook used by the recording driver — see Recording APNGs).

Init and shutdown

init() opens a 640x320 GLFW window via live_create_window and hands its handle to live_imgui_init so the ImGui context, fonts, and GL backend get wired up. shutdown() reverses the pair in shutdown order.

The frame loop

update() is what runs every frame. The pattern, line by line:

  1. live_begin_frame() — return early if the window is closing.

  2. begin_frame() — boost-side per-frame setup (registry, command dispatch).

  3. ImGui_ImplOpenGL3_NewFrame / ImGui_ImplGlfw_NewFrame / apply_synth_io_override / NewFrame — the ImGui backend prologue. apply_synth_io_override lets synthetic mouse/keyboard events from live-commands win against the GLFW backend’s per-frame poll (needed for tutorial recordings).

  4. The widget block (see below).

  5. end_of_frame() / Render() — boost-side bookkeeping, then ImGui composes the draw list.

  6. glViewport / glClear / ImGui_ImplOpenGL3_RenderDrawData — paint.

  7. live_end_frame() — swap buffers, advance live-reload housekeeping.

The window container

The window(NAME, ...) { ... } macro is the boost-layer wrapper around ImGui’s Begin/End pair:

SetNextWindowSize(ImVec2(560.0, 240.0), ImGuiCond.Always)
window(BASICS_WIN, (text = "Boost basics", closable = false,
                    flags = ImGuiWindowFlags.None)) {
    // ... widgets ...
}

Three things to notice:

  • The block runs the body once per frame between Begin and End — no manual End() to forget.

  • BASICS_WIN is a daslang identifier — the macro auto-emits a WindowState global named that, and pushes BASICS_WIN onto the boost registry path. Every leaf widget registers under BASICS_WIN/<ident>.

  • Per-call config goes in the named-tuple — text is the title, closable controls whether the X-button shows, flags are the raw ImGuiWindowFlags bits.

SetNextWindowSize / SetNextWindowPos are the same raw ImGui calls you’d use without the boost layer — they affect the next Begin (the one the macro emits) just like before.

Widgets

Two boost macros do the actual work:

VOLUME.bounds = (0.0f, 1.0f)
slider_float(VOLUME, (text = "Volume"))
Text("volume = {VOLUME.value}")

The macro form slider_float(VOLUME, ...) declares a module global VOLUME : SliderStateFloat the first time it expands. Telemetry registers it under the path-prefixed name BASICS_WIN/VOLUME (every widget inside window(BASICS_WIN, ...) inherits the prefix); the bounds line is plain assignment to the struct field.

if (button(BUMP_BTN, (text = "Bump"))) {
    print("bump clicked\n")
}
Text("bumps = {BUMP_BTN.click_count}")

button(BUMP_BTN, ...) returns true on the frame the click registers; the underlying ButtonState keeps click_count updated for later assertions (e.g. from imgui_playwright).

Standalone vs live

main() runs the loop directly when invoked as daslang.exe boost_basics.das. Under daslang-live the host calls init / update / shutdown itself; main is ignored. The slider and button states preserve across live reloads because every boost-generated global carries @live by default.

Driving from outside

When run live, the boost layer exposes the standard live-command surface at localhost:9090. Mutate the slider:

curl -X POST -d '{"name":"imgui_set","args":{"target":"BASICS_WIN/VOLUME","value":0.75}}' \
     localhost:9090/command

…and VOLUME.value jumps to 0.75 on the next frame. Note the BASICS_WIN/ prefix — the window container pushes its identifier onto the registry path, so external drivers target the path-qualified name.

Next steps

The next tutorial walks the full common-widget surface — text input, slider, checkbox, combo, color, button — on a single panel.

See also

Full source: examples/tutorial/boost_basics.das

Richer reference: examples/tutorial/visual_aids_tour.das — keeper reference exercising highlights, mouse trail, narration, and recording.

Next tutorial: Widgets tour

Boost macros — the macro layer.

Builtin widgets — widget reference.