Skip to main content

app_entry

Macro app_entry 

Source
macro_rules! app_entry {
    ($A:ty) => { ... };
}
Expand description

Emits the wasm-bindgen FFI surface driving $A: App<TerminalWasm> + Default from a browser terminal emulator (e.g. xterm.js), on wasm32 only.

examples/src/wasm_entry.rs’s __wasm_terminal_entry! does the same job for the examples crate’s private Example trait, but that crate is publish = false, so nothing outside this repo can reach it (retroglyph#684). This macro is the generally-usable version: generic over App (public, stable, and already the update contract every other driver in retroglyph-core shares), not Example.

Call it once, at the top level of a wasm32 binary crate that depends on this crate and retroglyph-core:

#[derive(Default)]
struct MyGame { /* ... */ }

impl retroglyph_core::app::App<retroglyph_terminal_wasm::TerminalWasm> for MyGame {
    fn update(
        &mut self,
        term: &mut retroglyph_core::terminal::Terminal<retroglyph_terminal_wasm::TerminalWasm>,
        frame: &retroglyph_core::app::Frame,
    ) -> retroglyph_core::app::Flow {
        // ...
        retroglyph_core::app::Flow::Continue
    }
}

retroglyph_terminal_wasm::app_entry!(MyGame);

fn main() {}

Expands to nothing at all off wasm32 (a native build of the same crate just doesn’t get this FFI surface, since nothing would call it).

Exports, all thread-local and single-instance (one $A per page; construct a fresh handle-based session per instance instead via this crate’s wasm module, only compiled for target_arch = "wasm32", if a page needs more than one):

  • wasm_app_init(width, height): builds the Terminal<TerminalWasm> at the given size (in cells) and $A::default(). Call once, before the first tick, after sizing the host terminal emulator (e.g. xterm.js’s fitAddon.fit()).
  • wasm_app_resize(width, height): reports a new size (in cells) via resize_terminal, so the driven $A sees the matching Event::Resize on its next update, not just a backend that silently changed size under it.
  • wasm_app_push_key(code, mods) / wasm_app_push_mouse(x, y, action, button, mods): decode and queue input via decode_key_event/ decode_mouse_event.
  • wasm_app_push_paste(text): queues text as a single Event::Paste.
  • wasm_app_push_focus(focused): queues Event::FocusGained/Event::FocusLost.
  • wasm_app_tick() -> String: runs one App::update, presents unless it returned Flow::Idle (or already presented itself), and returns the ANSI bytes rendered since the last call, the same contract TerminalWasm::take_output documents. Frame::delta is wall-clock time since the previous tick, clamped to MAX_TICK_DELTA (250ms): a backgrounded tab can starve requestAnimationFrame for seconds or minutes, and an uncapped delta handed straight to an animation/physics step would try to simulate that entire gap in one frame (the same “spiral of death” concern FrameClock caps steps-per-frame to avoid), just on the raw delta feeding into Frame instead. All FFI functions are no-ops (returning an empty string for wasm_app_tick) if called before wasm_app_init.
  • wasm_app_exited() -> bool: true once $A::update has returned Flow::Exit at least once. A browser tab has no native “exit the process” the way a windowed backend’s event loop does, so this crate can’t stop JS’s requestAnimationFrame loop for it; check this after wasm_app_tick and stop calling it once it flips true, e.g. to show a fixed “Game Over” frame’s own draw already put on screen. wasm_app_tick keeps calling $A::update (and, correctly, doing nothing useful) if the caller ignores this rather than panicking or hanging.