Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ export async function checkPieceContentStatusAndDependencies(
blacks: [],
scenes: [],

thumbnailUrl: undefined,
thumbnailUrl: '/dev/fakeThumbnail.png',
previewUrl: '/dev/fakePreview.mp4',

packageName: null,
Expand Down
136 changes: 135 additions & 1 deletion packages/blueprints-integration/src/previews.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,60 @@
import { SplitsContentBoxContent, SplitsContentBoxProperties } from './content.js'
/**
* This file defines the types for content previews that can be returned from blueprints.
*/
import { SourceLayerType, SplitsContentBoxContent, SplitsContentBoxProperties } from './content.js'
import { NoteSeverity } from './lib.js'
import { ITranslatableMessage } from './translations.js'

/**
* Optional container for preview content with optional warnings and additional content.
* If not added to a piece, the core will use the default preview handling.
*
* @example
* ```ts
* import { TablePreview, PreviewType } from 'blueprints-integration';
* const preview: TablePreview = {
* type: PreviewType.Table,
* entries: [ { key: 'Title', value: 'My Piece' } ],
* displayTiming: true,
* // the additionalPreviewContent can contain any number of content items of various types
* additionalPreviewContent: [
* {
* type: 'script',
* script: 'console.log("Hello World")',
* },
* { type: 'separationLine' },
* {
* type: 'layerInfo',
* layerType: SourceLayerType.Graphics,
* text: ['Breaking News: Something happened!'],
* inTime: 0,
* duration: 5000
* },
* {
* type: 'layerInfo',
* layerType: SourceLayerType.Graphics,
* text: ['Person Name - Title'],
* inTime: 1000,
* duration: 3000
* },
* { type: 'separationLine' },
* {
* type: 'iframe',
* href: 'https://example.com/preview', // Could be an external URL or a local server serving live preview content
* }
* ]
* };
* return { preview };
* ```
*/
export interface PopupPreview<P extends Previews = Previews> {
name?: string
preview?: P
warnings?: InvalidPreview[]
/**
* Add custom content preview content
*/
additionalPreviewContent?: Array<PreviewContent>
}
export type Previews = TablePreview | ScriptPreview | HTMLPreview | SplitPreview | VTPreview | BlueprintImagePreview

Expand All @@ -19,22 +68,99 @@ export enum PreviewType {
BlueprintImage = 'blueprintImage',
}

/**
* Additional preview content that can be added to a PopupPreview.
* Supports various content types: iframe, image, video, script, title, inOutWords, layerInfo, separationLine, and data.
* The purpose of this is to allow blueprints to provide extra preview content for pieces, e.g. showing script text,
* Lower3rd GFX information, images, an iFrame with a live preview or other relevant information.
* These preview content types are the same that are used in thedefault PreviewPopUp component in the web UI.
*/
export type PreviewContent =
| {
/** Embed an iframe with optional postMessage communication */
type: 'iframe'
href: string
postMessage?: any
dimensions?: { width: number; height: number }
}
| {
/** Display an image */
type: 'image'
src: string
}
| {
/** Display a video player */
type: 'video'
src: string
}
| {
/** Show script content with timing words and metadata */
type: 'script'
script?: string
firstWords?: string
lastWords?: string
comment?: string
lastModified?: number
}
| {
/** Display a title heading */
type: 'title'
content: string
}
| {
/** Show in/out timing words */
type: 'inOutWords'
in?: string
out: string
}
| {
/** Display layer information with timing
* Used for showing information about a specific source layer, such as graphics or lower thirds.
* The inTime, outTime, and duration is for information only and can be specified as
* numbers (milliseconds) or strings (e.g. "00:00:05:00" for 5 seconds).
* They are optional, and if not specified, the layer info is shown without timing.
*/
type: 'layerInfo'
Copy link
Contributor

@jstarpl jstarpl Sep 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a layerInfo or more of an "auxiliary Piece info" on a layer of given type?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do think that calling it layerInfo makes sense, based on what it's used for.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comments has been added to the code, to explain it's purpose

layerType: SourceLayerType
text: Array<string>
inTime?: number | string
outTime?: number | string
duration?: number | string
Comment on lines +126 to +128
Copy link
Contributor

@jstarpl jstarpl Sep 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do these properties mean? What's the difference between outTime vs inTime + duration? I'm also somewhat unsure about making this interface this loose & bound to a particular implementation of the hoverscrub preview component/any other component using this infromation - say Presenters' Screen. Any change there would effectively require a change to blueprints integration, which we expect to be at least reasonably stable.

I'm also not a big fan of introducing terms inTime and duration - I think they somewhat overlap with expectedStart and expectedDuration? Are they the same? If that's the case, I think it would make sense to use the same names.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are optional values for the "in", "out", "duration" labels, and used for the LayerInfo content, not necessary an expectedStart or expectedDuration calculation.
So either we should add a comment in here that explains what it is, or add it to some documentation, what do you prefer?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comments for it's use has been added to code.

}
| {
/** Add a visual separator line */
type: 'separationLine'
}
| {
/** Display key-value data pairs
* this is a basic data preview where the key is the Label and the value is the value
* the layerInfo should preferably be used for layer specific information and color
*/
type: 'data'
content: { key: string; value: string }[]
}

interface PreviewBase {
type: PreviewType
}

/** Indicates an invalid preview with a severity level and reason */
export interface InvalidPreview extends PreviewBase {
type: PreviewType.Invalid

severity: NoteSeverity
reason: ITranslatableMessage
}

/** Display a table of key-value pairs, optionally with timing information */
export interface TablePreview extends PreviewBase {
type: PreviewType.Table

entries: { key: string; value: string }[]
displayTiming: boolean
}

/** Show script text with last words, comments, and last modified time */
export interface ScriptPreview extends PreviewBase {
type: PreviewType.Script

Expand All @@ -43,6 +169,8 @@ export interface ScriptPreview extends PreviewBase {
comment?: string
lastModified?: number
}

/** Embed a custom HTML preview via URL, with optional steps and dimensions */
export interface HTMLPreview extends PreviewBase {
// todo - expose if and how steps can be controlled
type: PreviewType.HTML
Expand All @@ -56,12 +184,16 @@ export interface HTMLPreview extends PreviewBase {

steps?: { current: number; total: number }
}

/** Show a split screen with multiple content boxes (e.g. for multi-camera or multi-source content) */
export interface SplitPreview extends PreviewBase {
type: PreviewType.Split

background?: string // file asset upload?
boxes: (SplitsContentBoxContent & SplitsContentBoxProperties)[]
}

/** Video Tape preview with in/out words for timing */
export interface VTPreview extends PreviewBase {
type: PreviewType.VT

Expand All @@ -71,6 +203,8 @@ export interface VTPreview extends PreviewBase {
inWords?: string // note - only displayed if outWords are present
outWords?: string
}

/** Show an image asset as a preview */
export interface BlueprintImagePreview extends PreviewBase {
type: PreviewType.BlueprintImage

Expand Down
Binary file added packages/webui/public/dev/fakeThumbnail.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
}

.dashboard-panel__panel__button {
margin-top: 10px;
height: 110px;
max-width: 170px !important;
> .dashboard-panel__panel__button__content {
display: grid;
grid-template-columns: 1fr min-content;
Expand All @@ -31,7 +34,7 @@

> .dashboard-panel__panel__button__thumbnail {
position: relative;
height: auto;
height: 85px;
z-index: 1;
overflow: hidden;
grid-column: auto / span 2;
Expand Down
Loading
Loading