Native desktop GUIs from Elixir, powered by iced.
Quick start
{:ok, pid} = Plushie.start_link(MyApp)Dev mode (live code reloading)
# In config/dev.exs:
config :plushie, code_reloader: true
# Or as a start_link option:
{:ok, pid} = Plushie.start_link(MyApp, code_reloader: true)Under a supervisor
children = [
{Plushie, app: MyApp}
]Options
:app: (required) the app module implementingPlushie.App:app_opts: opts forwarded toapp.init/1(default:[]):binary: path to the plushie binary (default: auto-resolved):name: supervisor registration name (default:Plushie):daemon: iftrue, keep running after the last window closes(default: `false`). In daemon mode, `all_windows_closed` is delivered to `update/2` instead of triggering shutdown.:code_reloader: enable dev-mode live reloading.false(default),`true`, or a keyword list of reloader options (`:debounce_ms`, `:rebuild_artifacts`). Can also be set via `config :plushie, code_reloader: true`.:transport::spawn(default, spawns the renderer as a childprocess), `:stdio` (reads/writes the BEAM's own stdin/stdout, for use with `plushie --exec`), or `{:iostream, pid}` (custom transport via iostream adapter, see `Plushie.Bridge` for the protocol):format: wire format,:msgpack(default) or:json:log_level: plushie binary log level (:off,:error,:warning,:info,:debug).Default: `:error`.:renderer_args: extra CLI args passed to the renderer process:heartbeat_interval: maximum time (ms) between renderer messagesbefore the bridge considers it unresponsive and restarts the renderer. `nil` disables the watchdog. Default: `30_000`.
When :transport is :stdio or {:iostream, pid}, the :binary
option is ignored (no renderer subprocess is spawned).
Telemetry
Plushie emits :telemetry events for observability. Spans include
both start and stop (or exception) suffixes automatically.
Spans
Spans are emitted via :telemetry.span/3. Each produces
[:plushie, <name>, :start] and [:plushie, <name>, :stop]
events (or :exception on failure).
[:plushie, :view]- callsapp.view(model). Metadata:%{app: module()}.[:plushie, :normalize]- normalizes the raw view tree into canonical wire format, including widget rendering and memo caching. Metadata:%{app: module()}.[:plushie, :diff]- diffs old and new trees to produce patch operations. Metadata:%{app: module()}.[:plushie, :update]- callsapp.update(model, event). Metadata:%{app: module(), event: Plushie.Event.t()}.[:plushie, :commands]- executes commands returned byupdate/2orinit/1. Metadata:%{count: non_neg_integer()}.[:plushie, :subscriptions, :sync]- diffs and synchronizes active subscriptions. Metadata:%{}.
Single events
Single events are emitted via :telemetry.execute/3.
Runtime
[:plushie, :runtime, :view_error]-view/1raised or threw. Measurements:%{count: 1}. Metadata:%{app: module()}.[:plushie, :runtime, :update_error]-update/2raised or threw. Measurements:%{count: 1}. Metadata:%{app: module(), event: term()}.[:plushie, :runtime, :effect_timeout]- a pending effect request timed out. Measurements:%{count: 1}. Metadata:%{id: term()}.[:plushie, :runtime, :ticks_drained]- coalesced multiple pending ticks into one cycle. Measurements:%{count: integer()}. Metadata:%{tag: atom()}.
Tree
[:plushie, :memo, :hit]- memo cache hit during normalization. Measurements:%{count: 1}. Metadata:%{id: String.t()}.[:plushie, :memo, :miss]- memo cache miss during normalization. Measurements:%{count: 1}. Metadata:%{id: String.t()}.[:plushie, :widget_cache, :hit]- widget view cache hit. Measurements:%{count: 1}. Metadata:%{id: String.t(), module: module()}.[:plushie, :widget_cache, :miss]- widget view cache miss. Measurements:%{count: 1}. Metadata:%{id: String.t(), module: module()}.
Bridge
[:plushie, :bridge, :send]- frame sent to the renderer. Measurements:%{byte_size: non_neg_integer()}.[:plushie, :bridge, :receive]- frame received from the renderer. Measurements:%{byte_size: non_neg_integer()}.[:plushie, :bridge, :restart]- renderer process restarted. Measurements:%{count: pos_integer()}(cumulative restart count).[:plushie, :bridge, :protocol_error]- failed to decode a renderer frame. Metadata:%{reason: term(), format: atom()}.[:plushie, :bridge, :max_restarts_reached]- renderer exceeded the maximum restart limit. Metadata:%{reason: term(), max_restarts: integer()}.
Summary
Functions
Returns the registered name of the bridge for the given instance.
Child spec for embedding Plushie under an existing supervisor.
Returns the registered name of the runtime for the given instance.
Starts a Plushie application under a supervisor linked to the calling process.
Stops a running Plushie supervisor.
Types
@type transport() :: :spawn | :stdio | {:iostream, pid()}
Functions
Returns the registered name of the bridge for the given instance.
@spec child_spec(keyword()) :: Supervisor.child_spec()
Child spec for embedding Plushie under an existing supervisor.
Example
children = [
{Plushie, app: MyApp, name: :my_app_gui}
]
Returns the registered name of the runtime for the given instance.
@spec start_link( module(), keyword() ) :: Supervisor.on_start()
Starts a Plushie application under a supervisor linked to the calling process.
Returns {:ok, pid} on success.
Stops a running Plushie supervisor.
Accepts a pid or the instance name passed as :name to start_link/2
(defaults to Plushie, matching the default registration).