mcut
@mcut/timeline

Layouts, presets, and thumbnails

Layout and slot schemas, property presets, and thumbnail templates.

Types

Layout

type Layout = z.infer<typeof layoutSchema>

A layout as inferred from layoutSchema.

LayoutSlot

type LayoutSlot = z.infer<typeof layoutSlotSchema>

A layout slot as inferred from layoutSlotSchema.

PropertyPreset

type PropertyPreset = z.infer<typeof propertyPresetSchema>

A property preset as inferred from propertyPresetSchema.

ThumbnailItem

type ThumbnailItem = z.infer<typeof thumbnailItemSchema>

A template item as inferred from thumbnailItemSchema.

ThumbnailTemplate

type ThumbnailTemplate = z.infer<typeof thumbnailTemplateSchema>

A thumbnail template as inferred from thumbnailTemplateSchema.

Schemas

layoutSchema

const layoutSchema = z.object({
  id: z.string().min(1),
  name: z.string().min(1),
  slots: z.array(layoutSlotSchema).min(1),
})

Zod schema for a layout, an id, a name, and at least one slot.

layoutSlotSchema

const layoutSlotSchema = z.object({
  source: z.string().min(1),
  rect: z.object({
    x: z.number().min(-1).max(2),
    y: z.number().min(-1).max(2),
    w: z.number().positive().max(3),
    h: z.number().positive().max(3),
  }),
  fit: z.enum(['cover', 'contain']).default('cover'),
  ...frameStyleSchema.shape,
})

Zod schema for one layout slot, the source key it shows, a rect in normalized canvas coordinates, a fit mode, and the same frame style a video clip takes. The slot's crop picks the source region that is fitted into the rect, so panning a cover slot moves its crop.

The saveLayout command merges each slot it is given into the saved slot with the same source. An omitted field keeps its value, null clears a frame style field, and only a source new to the layout needs a rect. A saved slot whose source is left out is removed.

propertyPresetSchema

const propertyPresetSchema = z.object({
  id: z.string().min(1),
  name: z.string().min(1),
  kind: z.string().min(1),
  values: z.record(z.string(), z.unknown()),
})

Zod schema for a property preset, an id, a name, the kind of surface that captured it, and a record of captured values.

thumbnailItemSchema

const thumbnailItemSchema = z.discriminatedUnion('kind', [
  z.object({
    kind: z.literal('text'),
    rect: rectSchema,
    text: z.string(),
    role: z.string().default('Text'),
    style: textStyleSchema,
  }),
  z.object({
    kind: z.literal('slot'),
    rect: rectSchema,
    fit: z.enum(['cover', 'contain']).default('cover'),
    label: z.string().default('Media'),
  }),
])

Zod schema for one template item, either a text item with a normalized rect, text, role, and style or a slot with a rect, fit mode, and label.

thumbnailTemplateSchema

const thumbnailTemplateSchema = z.object({
  name: z.string().min(1),
  items: z.array(thumbnailItemSchema).min(1),
})

Zod schema for a thumbnail template, a name and at least one item.

Constants

THUMBNAIL_FRAME_COUNT

const THUMBNAIL_FRAME_COUNT = 5

The number of frames the cover spans, 5.

THUMBNAIL_TEMPLATES

const THUMBNAIL_TEMPLATES: ThumbnailTemplate[]

The three starter covers, big title, lower third, and center punch.

THUMBNAIL_TRACK_NAME

const THUMBNAIL_TRACK_NAME = 'Thumbnail'

The name that marks a track as the thumbnail track, Thumbnail.

Functions

createDefaultLayouts

function createDefaultLayouts(canvas: Pick<Project, 'width' | 'height'>): Layout[]

Returns five starter layouts for a screen and camera pair with fresh ids, full screen with camera picture in picture, camera only, screen only, two 3 by 4 panels, and side by side. The picture in picture shadow is sized from the canvas so it scales with the slot. saveLayout gives the same corner radius and shadow to an overlay slot new to a layout that sets none of cornerRadius, stroke, and shadow.

getLayout

function getLayout(layouts: readonly Layout[], layoutId: string): Layout | null

Returns the layout with the given id, or null.

listPresets

function listPresets(project: Project, kind: string): PropertyPreset[]

Returns the project's presets whose kind matches, in saved order.

captureThumbnailTemplate

function captureThumbnailTemplate(
  project: Project,
  name: string,
): ThumbnailTemplate | null

Returns a template built from the thumbnail track, turning text elements into text items and image elements into slots, or null when the track is missing or empty.

expandThumbnailTemplate

function expandThumbnailTemplate(
  project: Pick<Project, 'width' | 'height' | 'fps'>,
  template: ThumbnailTemplate,
): TimelineElement[]

Returns text elements for the template's text items, scaled from 1080p template space to the project size and positioned from their normalized rects, and skips slot items.

findThumbnailTracks

function findThumbnailTracks(project: Project): Track[]

Returns every track named Thumbnail in track order, one per text layer of the applied template.

thumbnailDurationMs

function thumbnailDurationMs(fps: number): number

Returns the length of the cover span, five frames at the given fps or the minimum element duration if that is longer.

On this page