293 lines
6.8 KiB
Markdown
293 lines
6.8 KiB
Markdown
# 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}`.
|