ExperienceThumbnail
Layered CDN gallery previews with optional parallax and hosted-player launch — available in Svelte, React, Next.js, and vanilla.
Overview
<ExperienceThumbnail> renders the same layered Meet-style preview used on
www.liforma.ai: avatar plate plus optional location background and foreground, with lazy load
and pointer/scroll parallax. It is a catalog preview, not a live player.
Painting the thumb needs no API key and no origin allowlist — pass CDN URLs
from your server-side catalog fetch. Keys and allowlists apply only when a session starts
(hosted launch click, or a page that mounts <Experience>).
Install
npm install @liforma/client | Surface | Import / tag |
|---|---|
| Svelte | @liforma/client/svelte |
| React | @liforma/client/react |
| Next.js | @liforma/client/next (client component) |
| Vanilla | <liforma-experience-thumbnail> via the CDN v2 script |
Zero-config hosted launch
Pass experienceId and galleryThumb with no href / onclick. Click opens player.liforma.ai/{experienceId}?returnUrl=… and returns to the embedding
page on close. Add your site origin to the project allowlist first (launch path only).
<script>
import { ExperienceThumbnail } from '@liforma/client/svelte';
<\/script>
<ExperienceThumbnail
experienceId={experience.experienceId}
galleryThumb={experience.galleryThumb}
alt={experience.title}
/> import { ExperienceThumbnail } from '@liforma/client/react';
// Next.js App Router client files can also use:
// import { ExperienceThumbnail } from '@liforma/client/next';
export function GalleryCard({ experience }) {
return (
<ExperienceThumbnail
experienceId={experience.experienceId}
galleryThumb={experience.galleryThumb}
alt={experience.title}
/>
);
} <script type="module" src="https://cdn.liforma.ai/sdk/v2/client.js"><\/script>
<liforma-experience-thumbnail
experience-id="exp_01EXAMPLES_COFFEE_BARISTA"
alt="Spanish Cafe"
gallery-thumb='{"avatarImage":"https://cdn.liforma.ai/avatars/05a87620/256/05a87620_neutral.webp"}'
></liforma-experience-thumbnail> App-owned routing
When your app owns the session page (Meet-style), pass href to your slug route.
That page should mount <Experience> with experienceId (and
usually sessionEndpoint for authenticated mint).
<script>
import { ExperienceThumbnail } from '@liforma/client/svelte';
<\/script>
<ExperienceThumbnail
galleryThumb={experience.galleryThumb}
alt={experience.title}
href={`/experiences/${experience.slug}`}
/> Presentational (parent owns the link)
Omit experienceId, href, and onclick. Wrap the thumb
yourself and use alt="" when the parent already provides the accessible name.
<a href="/experiences/{experience.slug}" aria-label={experience.title}>
<ExperienceThumbnail galleryThumb={experience.galleryThumb} alt="" />
</a> Click behaviour
| Provide | Click does |
|---|---|
experienceId (no href/onclick) | Open hosted player; return to this page |
href | Navigate to that URL |
onclick / onClick | Run your handler (modal, analytics, SPA goto) |
| None of the above | Non-interactive preview |
Priority: href > click-only > hosted default > presentational.
Hosted launch is for public experiences. Authenticated gallery cards should use href / onclick plus your BFF session route — not the hosted player
default.
Props
| Prop | Type | Notes |
|---|---|---|
galleryThumb | GalleryThumb | Catalog shape: avatarImage, optional backgroundImage / foregroundImage |
avatarImage | string | Flattened alternative to galleryThumb |
alt | string | Accessible name (use "" when a parent link names the card) |
experienceId | string | Required for hosted-player default |
href | string | App-owned destination; disables hosted default |
onclick / onClick | (event) => void | Custom handler; may preventDefault with href |
returnUrl | string | Hosted close destination; default = current page URL |
parallax | boolean | Default true; respects prefers-reduced-motion |
lazy | boolean | Default true; IntersectionObserver load |
fallbackImage | string | Flat image if the layered avatar fails |
Layout and image size
The component fills its container. Set width / aspect-ratio on the parent — there is no size prop. CDN assets are thumb-tier only:
- Avatars:
/256/(larger tiers are rewritten automatically) - Locations:
256x256
Prefer catalog galleryThumb over flat thumbnailPath (which may still
point at larger plates).
Gallery walkthrough
For a full SvelteKit catalog → cards → slug → <Experience> flow, see Dynamic Experience Gallery.