Svelte Component

Experience and ExperienceThumbnail — embed avatars and gallery previews in Svelte.

Install

npm install @liforma/client

Experience

Pass experienceId for a self-contained embed. The component handles session mint, attachment, and cleanup.

App.svelte
<script>
  import { Experience } from '@liforma/client/svelte';
<\/script>

<Experience experienceId="exp_T0I7ACMQLBMPG6K" />

If you know the visitor is already registered, pass alreadyConverted with the registration key so conversion rate excludes them. Prefer setting this on sessionEndpoint mint when you have a backend.

Host-controlled speech and listening

When your app must call speak(), startListening(), or stopListening() from its own buttons or lesson logic, bind the component with bind:this and type the variable as ExperienceHandle | undefined.

The example uses onStarted to speak after the player unlocks audio, then wires host Start/Stop buttons to manual listening. See Experience (Svelte) for the full walkthrough.

Lesson.svelte
<script lang="ts">
  import {
    Experience,
    type ExperienceHandle
  } from '@liforma/client/svelte';

  // Controller from bind:this — undefined until the component mounts.
  let experience: ExperienceHandle | undefined = $state();
  let audioUnlocked = $state(false);

  // Safe point to speak: player start button has unlocked audio.
  async function handleStarted() {
    audioUnlocked = true;
    await experience?.speech.speak({ text: 'Welcome to the lesson.' });
  }

  // Host-owned Start/Stop — manual speech capture for the learner.
  async function startAnswer() {
    if (!experience) return;
    await experience.startListening();
  }

  async function finishAnswer() {
    if (!experience) return;
    const utterance = await experience.stopListening();
    console.log(utterance.text);
  }
<\/script>

<Experience
  bind:this={experience}
  experienceId="exp_T0I7ACMQLBMPG6K"
  mode="presenter"
  speechInputMode="manual"
  onStarted={handleStarted}
/>

<button disabled={!audioUnlocked || !experience} onclick={startAnswer}>Start answer</button>
<button disabled={!audioUnlocked || !experience} onclick={finishAnswer}>Stop answer</button>

ready() means the Session Launch is resolved and the player is attached. started() means the player-owned user gesture has unlocked audio. Speech and listening methods do not silently wait for that gesture: they preserve the root API's state validation and reject if called before started. Use onStarted or await experience.started() before calling them.

Callbacks

Use Svelte 5 callback props for session events. Core callbacks include onReady, onStarted, onUserTranscript, onPlayerStatusChange, onClose, and onError.

App.svelte
<script lang="ts">
  import { Experience } from '@liforma/client/svelte';

  function reportError(error: Error) {
    console.error(error);
  }
<\/script>

<Experience
  experienceId="exp_T0I7ACMQLBMPG6K"
  onReady={({ session }) => console.log('Attached', session.id)}
  onStarted={({ mode }) => console.log('Audio unlocked', mode)}
  onUserTranscript={(update) => console.log('Transcript', update.text)}
  onPlayerStatusChange={(status) => console.log('Player status', status)}
  onClose={(event) => console.log('Player closed', event)}
  onError={reportError}
/>

SvelteKit

For browser embeds, pass experienceId only — let the client mint the session. Do not load credential-bearing Session Launch payloads in +page.server.ts.

<!-- +page.svelte -->
<Experience experienceId="exp_T0I7ACMQLBMPG6K" />

Props

The component accepts the relevant session launch options and owns restart and cleanup. Changes to launch-defining props restart the session; callback-only changes do not. Structurally equivalent startButton objects do not restart it.

Full ExperienceProps, ExperienceHandle, callback, restart, and close behavior reference: Experience (Svelte).

Close and compatibility

Default close handling navigates to the configured return URL. Supplying onClose overrides automatic navigation. The deprecated LiformaExperience export remains as a temporary alias; use Experience in new code.

ExperienceThumbnail

<ExperienceThumbnail> renders layered CDN gallery previews (no session mint). Import from @liforma/client/svelte/thumbnail on gallery / landing pages so the session SDK stays out of the bundle. Full props and recipes: ExperienceThumbnail.

Card.svelte
<script>
  import { ExperienceThumbnail } from '@liforma/client/svelte/thumbnail';
<\/script>

<ExperienceThumbnail
  experienceId={experience.experienceId}
  galleryThumb={experience.galleryThumb}
  alt={experience.title}
/>