Uses the oxframe skill (workflow, full API cheat sheet); install both with npx skills add oxygenframe/oxframe-sdk.
#[oxframe::scene]
async fn intro(view: View) {
let square = view.add(Rect::new().size(200.0).fill(Accent).opacity(0.0));
let line = voice("First we draw a square, then we turn it").start();
line.at_word("square").await;
square.fade_in().await;
line.at_word("turn").await;
square.rotation().to(90.0, 1.0).await;
line.await; // the scene must not end before the line
}
voice(text).start()speaks now;.at_word("word")waits for that word; awaiting the line waits for its end.checkreportsvoice_cutandvoice_overlap.- oxframe does not call a speech service. Implement
TtsProvider(id,synthesize→Synthesis { rate, samples, words }) and pass it withProject::tts(..); read the API key from the environment. Without a provider or key, timing is estimated and there is no audio. - The first render caches audio in
tts/; commit that folder so CI renders the real voice without a key. - Music:
Project::audio(Audio::track("assets/music.mp3").duck_under_voice()). - Subtitles:
oxframe render --subtitles out.srt(.vttby extension).