Guided Scripted Practice
Presenter mode with predetermined avatar lines and host-controlled learner turns.
When to use this pattern
Use guided scripted practice when avatar lines are predetermined (lessons, drills, rehearsal) and
the host app owns turn flow and feedback. The avatar speaks scripted lines via speak(); learner speech is captured between explicit Start and Stop controls; scoring
or hints stay in your UI — not in the avatar conversation output.
Session setup
In Svelte, use the lifecycle-owning <Experience> component with presenter mode and manual speech input. Bind its typed handle for
scripted speech and explicit Start/Stop controls. The player-owned start button unlocks audio and
requests the microphone once.
<script lang="ts">
import {
Experience,
type ExperienceHandle
} from '@liforma/client/svelte';
let experience: ExperienceHandle | undefined = $state();
let feedback = $state('');
let audioUnlocked = $state(false);
async function playTutorLine() {
audioUnlocked = true;
await experience?.speech.speak({ text: 'Read this sentence aloud.' });
}
async function startAnswer() {
if (!experience) return;
await experience.startListening();
}
async function finishAnswer() {
if (!experience) return;
const utterance = await experience.stopListening();
feedback = `You said: ${utterance.text}`;
}
<\/script>
<Experience
bind:this={experience}
experienceId="exp_T0I7ACMQLBMPG6K"
mode="presenter"
speechInputMode="manual"
onStarted={playTutorLine}
/>
<button disabled={!audioUnlocked || !experience} onclick={startAnswer}>Start</button>
<button disabled={!audioUnlocked || !experience} onclick={finishAnswer}>Stop</button>
<p>{feedback}</p> onStarted is the safe point to speak because audio is unlocked. The earlier onReady callback only means the Session Launch is resolved and the player is attached.
Calls to speak(), startListening(), stopListening(), and listenOnce() preserve the root API's state checks and do not queue until startup.
Turn loop
Typical sequence for each scripted line:
await experience.speech.speak({ text: line })— character delivers the tutor lineawait experience.startListening()— learner taps Startawait experience.stopListening()— learner taps Stop; pauses do not finalize- Run host-side feedback (pronunciation, rubric, etc.) on
utterance.text - Wait for your Next control, then repeat with the next line
The component owns session creation, attachment, callback subscriptions, restart, and cleanup. Keep lesson turn state, transcript display, and feedback in the page.
Vanilla JavaScript
For framework-neutral integrations, use the imperative class and subscribe to its events directly.
const experience = await Experience.startSession({
experienceId: 'exp_T0I7ACMQLBMPG6K',
mode: 'presenter',
speechInputMode: 'manual'
});
experience.on('started', async () => {
await experience.speech.speak({ text: 'Welcome to the lesson.' });
});
await experience.attach({ container: '#avatar' }); async function runPracticeTurn(line) {
await experience.speech.speak({ text: line });
await experience.startListening();
}
async function finishPracticeTurn(line) {
const utterance = await experience.stopListening();
const feedback = await getReadingFeedback({
expectedText: line,
spokenText: utterance.text
});
showFeedback(feedback);
// Host Next button calls runPracticeTurn(nextLine).
} History and events
Scripted assistant lines and finalized user utterances appear in getConversation(). Feedback objects are application state unless you store them
separately. In Svelte, use callback props such as onCharacterSpeechStarted, onCharacterSpeechEnded, onUserTranscript, onUserSpeechStarted, onUserSpeechEnded, and onListeningState. See Events.
For automatic capture without Start/Stop buttons, see Listen Once Capture. For browser-owned replies after each utterance, see Custom Conversation Processor.
Runnable examples
Clone and run the guided-practice examples from examples.liforma.ai:
- Vanilla JavaScript — port
4003with./start - SvelteKit —
./start sveltekit(basic embed on4001, Spanish Tutor on4002, guided practice on4003)
Full API detail: Experience API speech section.