This demo shows the onPlayerInit callback, which provides a reactive PlayerRef for accessing player state from outside the Root subtree.
The "External Dashboard" panel on the right is a sibling of the
player, not a child — it cannot use getPlayerContext(). Instead, onPlayerInit bridges the gap by providing a PlayerRef that stays reactive because it's backed by Svelte 5's $state and $derived internally.
<script>
import { IIIFPlayer, type PlayerRef } from '@umd-mith/iiif-timed-transcript';
let player = $state<PlayerRef | null>(null);
</script>
<!-- onPlayerInit fires once after manifest loads -->
<IIIFPlayer.Root {manifestUrl} onPlayerInit={(ref) => player = ref}>
<IIIFPlayer.Viewer />
<IIIFPlayer.Controls>...</IIIFPlayer.Controls>
</IIIFPlayer.Root>
<!-- Sibling component reads PlayerRef reactively -->
{#if player}
<p>Time: {player.state.currentTime}</p>
<button onclick={() => player.actions.seekTo(0)}>Restart</button>
{/if}
The player on the left is wrapped in IIIFPlayer.Root. The dashboard on the right is a sibling that reads state and
fires actions via the PlayerRef received from onPlayerInit.
Reading PlayerRef outside Root
Waiting for player...