Bevy
bevy_lingara is a Bevy plugin over Lingara’s player core. Add it to your app, tell it how to reach your server for tokens, and read what Lingara sends as ordinary Bevy Messages.
Add the plugin
Add the crate to your game, then add LingaraPlugin to your app with a LingaraConfig.
Get tokens from your server
The plugin never holds a secret. When it needs a token, it asks your own server, which mints one with a server kit and answers with the token and its expiry.
There are two ways to answer. In the common case, give the config your server’s token route and any header your session needs, and the plugin calls it for you. Or leave the route unset and answer each LingaraTokenNeeded Message yourself with a ProvideToken, using whatever sign-in your game already has.
Read events once per frame
The core runs its network I/O on its own thread and never calls into your code. The plugin drains its queue once per frame and turns what arrived into Messages your systems read like any other:
LingaraEventReceivedfor an event about the player, such as a lesson plan becoming ready;NpcTranscript, a component on each character that grows as a reply streams in (see NPC dialogue);PracticeFinishedwhen a practice session ends (see practice results).
Nothing blocks a frame: a slow network shows up as a Message arriving a little later.
Bevy
cargo add bevy_lingara@0.1.0-alpha.6Bevy
/// The common case: the plugin POSTs to your own server's token route, with
/// your game's session as a header, and reads `{token, expires_at}`.
fn lingara_config(session_header: bevy_lingara::lingara_embed::Header) -> LingaraConfig {
LingaraConfig::new()
.token_endpoint("https://game.example.com/lingara-token", vec![session_header])
.source_lang("en")
}
/// Or keep the session in ECS: leave the token endpoint unset, answer each
/// `LingaraTokenNeeded` with what your server returned.
fn answer_token_requests(mut needed: MessageReader<LingaraTokenNeeded>, mut provide: MessageWriter<ProvideToken>) {
for _request in needed.read() {
let (token, expires_at) = fetch_from_your_server();
provide.write(ProvideToken::new(token, expires_at));
}
}Bevy
App::new()
.add_plugins(DefaultPlugins)
.add_plugins(LingaraPlugin::new(lingara_config(header)))
.add_systems(Update, on_lingara_event)
/// The plugin drains Lingara's events once per frame: read them as Messages.
fn on_lingara_event(mut events: MessageReader<LingaraEventReceived>) {
for LingaraEventReceived(event) in events.read() {
info!("{}: {}", event.event_type, event.data_json);
}
}