1# llimphi-widget-rive-button
2
3A **reactive** button driven by a Rive-style state machine
4(`llimphi_anim::StateMachine`).
5
6It is the first *real* consumer of the state machine outside `llimphi-anim-studio`
7(which authors it) and the `llimphi-lottie` examples. It encapsulates the
8canonical composition of the `pointer_listeners_demo` as a reusable widget: three
9states — `idle` / `hover` / `press` — each with its own Lottie clip, threaded by
10inputs the engine derives from the raw pointer:
11
12- **hover** (`bool`): the `Enter`/`Exit` listeners over the whole surface turn the
13 `hovered` input on and off; `idle ⇄ hover` with a crossfade.
14- **press** (`trigger`): the host calls `RiveButton::press` from its `on_click`;
15 that fires the `pressed` trigger, the machine enters the `press` state (a
16 **non-looping** clip) and, when the clip finishes (`ClipDone`), returns to
17 `hover` or `idle` depending on whether the pointer is still over it.
18
19The widget is **stateful** (like `text-editor`/`nodegraph`): the host keeps it in
20its `Model`, advances it with `advance` from a periodic tick, forwards the
21pointer with `pointer` and the click with `press`, and paints it with `view`.
22Hit-testing lives in the engine, not in the app.
23
24```ignore
25// In the host's Model:
26button: RiveButton::builtin(),
27// update:
28Msg::Tick => m.button.advance(DT),
29Msg::Pointer(p) => m.button.pointer(p),
30Msg::Click => { m.button.press(); /* the host's action */ }
31// view:
32m.button.view(Msg::Pointer, Msg::Click)
33```
34
35---
36
37Part of **llimphi** — see [llimphi](../../README.md).
README.md
llimphi-widget-rive-button
A reactive button driven by a Rive-style state machine
(llimphi_anim::StateMachine).
It is the first real consumer of the state machine outside llimphi-anim-studio
(which authors it) and the llimphi-lottie examples. It encapsulates the
canonical composition of the pointer_listeners_demo as a reusable widget: three
states — idle / hover / press — each with its own Lottie clip, threaded by
inputs the engine derives from the raw pointer:
- hover (
bool): the Enter/Exit listeners over the whole surface turn the
hovered input on and off; idle ⇄ hover with a crossfade.
- press (
trigger): the host calls RiveButton::press from its on_click;
that fires the pressed trigger, the machine enters the press state (a
non-looping clip) and, when the clip finishes (ClipDone), returns to
hover or idle depending on whether the pointer is still over it.
The widget is stateful (like text-editor/nodegraph): the host keeps it in
its Model, advances it with advance from a periodic tick, forwards the
pointer with pointer and the click with press, and paints it with view.
Hit-testing lives in the engine, not in the app.
// In the host's Model:
button: RiveButton::builtin(),
// update:
Msg::Tick => m.button.advance(DT),
Msg::Pointer(p) => m.button.pointer(p),
Msg::Click => { m.button.press(); /* the host's action */ }
// view:
m.button.view(Msg::Pointer, Msg::Click)
Part of llimphi — see llimphi.