# Slide Preview Integration Guide

This guide is for integrating an authoritative slide preview into another React + Vite UI, using the real `GlitchPlayer` runtime rather than a custom thumbnail or placeholder renderer.

## Goal

When the editor user selects a slide, the preview should be:

- the real `GlitchPlayer`
- moved to the selected slide
- paused on that slide
- rendered with the same layout, video, timing, and slide runtime as the final presentation

This is the correct preview surface when fidelity matters more than efficiency.

## Use This, Not A Custom Thumbnail

For the main preview panel:

- use `GlitchPlayer`
- with `mode="slide-preview"`
- and `targetSlideId`

Do not use:

- `GlitchSlideThumbnail`
- `GlitchSlideRenderer`
- a hand-built editor preview

Those are useful for slide lists and lightweight surfaces, but not for the authoritative preview.

## Built Files To Consume

If the integration agent is only allowed to fetch built artifacts from this repo, use:

- [dist/vendor/gnommoplayer.js](/Users/jenstandstad/Projects/gnommoplayer/dist/vendor/gnommoplayer.js)
- [dist/vendor/gnommoplayer.css](/Users/jenstandstad/Projects/gnommoplayer/dist/vendor/gnommoplayer.css)

Build them with:

```bash
npm run build
```

That command now produces both the demo app build and the vendor bundle.

## What To Import

From `gnommoplayer.js`, the preview integration should import:

- `GlitchPlayer`
- `defaultSlideRegistry`

From `gnommoplayer.css`, import the player stylesheet once near the app root.

Example:

```tsx
import "../vendor/gnommoplayer/gnommoplayer.css";
import {
  GlitchPlayer,
  defaultSlideRegistry,
} from "../vendor/gnommoplayer/gnommoplayer.js";
```

## Required Data

The preview must receive a full presentation object, not just one slide.

That presentation should include:

- `id`
- `title`
- `version`
- `durationSec`
- `segments`
- `slides`

Why:

- the player needs the full timeline
- the player needs the talking-head video segments
- the player derives the active slide from presentation timing
- the player must match the final runtime, not a simplified editor view

## Preview Contract

The preview panel should render the player like this:

```tsx
<GlitchPlayer
  presentation={presentation}
  slideRegistry={defaultSlideRegistry}
  mode="slide-preview"
  targetSlideId={selectedSlideId}
  initialSessionId={`editor-preview-${presentation.id}`}
/>
```

Behavior of this mode:

- the player jumps to the targeted slide’s `startTimeSec`
- playback starts paused
- the real player UI and layout are used
- the talking-head video is still part of the runtime surface

## Recommended Host Component

The host app should wrap this in a dedicated preview component.

Example:

```tsx
import { useEffect, useState } from "react";
import "../vendor/gnommoplayer/gnommoplayer.css";
import {
  GlitchPlayer,
  defaultSlideRegistry,
} from "../vendor/gnommoplayer/gnommoplayer.js";

export function SlidePreviewPanel({
  presentationId,
  selectedSlideId,
}: {
  presentationId: string;
  selectedSlideId: string | null;
}) {
  const [presentation, setPresentation] = useState(null);
  const [error, setError] = useState(null);

  useEffect(() => {
    let cancelled = false;

    fetch(`/api/videos/${presentationId}/export`)
      .then((response) => {
        if (!response.ok) {
          throw new Error(`Preview fetch failed: ${response.status}`);
        }

        return response.json();
      })
      .then((data) => {
        if (!cancelled) {
          setPresentation(data);
          setError(null);
        }
      })
      .catch((caughtError) => {
        if (!cancelled) {
          setError(String(caughtError));
        }
      });

    return () => {
      cancelled = true;
    };
  }, [presentationId]);

  if (error) {
    return <div>Preview error: {error}</div>;
  }

  if (!presentation || !selectedSlideId) {
    return <div>Select a slide to preview.</div>;
  }

  return (
    <div style={{ width: "100%", height: "100%" }}>
      <GlitchPlayer
        presentation={presentation}
        slideRegistry={defaultSlideRegistry}
        mode="slide-preview"
        targetSlideId={selectedSlideId}
        initialSessionId={`editor-preview-${presentation.id}`}
      />
    </div>
  );
}
```

## How The Editor Should Drive It

The editor should keep one piece of selection state:

- `selectedSlideId`

When the user clicks a slide in the editor:

1. update `selectedSlideId`
2. keep the same `presentation`
3. re-render `GlitchPlayer` with the new `targetSlideId`

That is enough for the player to move to the correct slide.

## Important Implementation Notes

### 1. Use The Full Presentation

Do not try to construct a fake one-slide presentation for preview.

That creates drift in:

- timing
- fullscreen transitions
- video positioning
- segment masking
- variant behavior

The preview should be the real timeline.

### 2. It Is Fine If The Video Loads Again

That is an acceptable tradeoff for now.

The goal of the editor preview is correctness:

- same player
- same slide runtime
- same layout

Not maximum efficiency.

### 3. Keep Thumbnails Separate

This preview guide is only for the main preview panel.

For slide list cards:

- `GlitchSlideThumbnail` is still appropriate

For the large “truth” preview:

- use `GlitchPlayer`

### 4. Prefer Stable Slide Ids

The editor should pass a stable `selectedSlideId`, ideally the same id used in the exported presentation payload.

The preview mechanism depends on exact id matching:

```tsx
targetSlideId={selectedSlideId}
```

### 5. Do Not Replace The Player’s Internal Registry Logic

Use:

```tsx
slideRegistry={defaultSlideRegistry}
```

unless the host intentionally provides a superset registry.

The preview should not invent its own runtime component resolution.

## When To Use `GlitchSlideThumbnail` Instead

Use `GlitchSlideThumbnail` only for:

- slide list rows
- compact cards
- mini previews in inspector sidebars

Do not use it as a substitute for the main preview panel.

## Recommended Replacement Strategy

If the current editor preview is “kind of not working,” replace it with this sequence:

1. Keep the slide list as-is for now
2. Remove the custom preview widget
3. Add a dedicated preview panel component
4. Fetch the full exported presentation JSON
5. Render:

```tsx
<GlitchPlayer
  presentation={presentation}
  slideRegistry={defaultSlideRegistry}
  mode="slide-preview"
  targetSlideId={selectedSlideId}
/>
```

That gives you a preview surface that is as close to final runtime as possible.

## Short Handoff Note

If you need the shortest possible instruction for the other agent, use this:

Use the real player for slide preview, not the thumbnail renderer. Import `GlitchPlayer` and `defaultSlideRegistry` from `dist/vendor/gnommoplayer.js`, import `dist/vendor/gnommoplayer.css`, fetch the full presentation JSON, and render `GlitchPlayer` with `mode="slide-preview"` and `targetSlideId={selectedSlideId}`.
