Model schemas
Zod schemas and constants for the project document and its elements.
Schemas
assetIdSchema
const assetIdSchema = z
.custom<AssetId>(
(v) => typeof v === 'string' && /^a-[\w-]+$/.test(v),
'invalid asset id (expected "a-..." prefix)',
)
.meta({ type: 'string', pattern: '^a-[\\w-]+$' })Zod schema for an AssetId, a string with the a- prefix.
assetRefSchema
const assetRefSchema = z.object({
id: assetIdSchema,
kind: z.enum(['video', 'audio', 'image']),
src: z.string(),
hash: z.string().optional(),
name: z.string().optional(),
mimeType: z.string().optional(),
nativePreview: z.boolean().optional(),
durationMs: z.number().int().positive().optional(),
width: z.number().int().positive().optional(),
height: z.number().int().positive().optional(),
})Zod schema for a project asset, its id, kind, source URL, and optional hash, name, MIME type, native preview flag, duration, and size.
audioElementSchema
const audioElementSchema = composeFull('audio', audioShape)Zod schema for an audio element, the shared id and timing fields plus asset, trim, time map, reversal, volume, mute, fades, and an optional voice mix.
captionElementSchema
const captionElementSchema = composeFull('caption', captionShape)Zod schema for a caption element, the shared id and timing fields plus text, optional word timings, and caption style.
captionStyleSchema
const captionStyleSchema = z
.object({
fontFamily: z.string().default('sans-serif'),
fontSize: z.number().positive().default(48),
fontWeight: z.number().int().min(100).max(1000).default(700),
color: z.string().default('#ffffff'),
activeWordColor: z.string().optional(),
backgroundColor: z.string().default('rgba(0, 0, 0, 0.55)'),
position: z.enum(['top', 'middle', 'bottom']).default('bottom'),
})
.prefault({})Zod schema for caption styling, font, size, weight, colors, background, and vertical position, with defaults for every field.
captionWordSchema
const captionWordSchema = z.object({
text: z.string(),
startMs: z.number().int().nonnegative(),
endMs: z.number().int().nonnegative(),
}).refine((word) => word.endMs >= word.startMs, 'caption word endMs must be >= startMs')Zod schema for one caption word with timing relative to the caption's startMs, rejecting a word whose endMs is before its startMs.
elementIdSchema
const elementIdSchema = z
.custom<ElementId>(
(v) => typeof v === 'string' && /^e-[\w-]+$/.test(v),
'invalid element id (expected "e-..." prefix)',
)
.meta({ type: 'string', pattern: '^e-[\\w-]+$' })Zod schema for an ElementId, a string with the e- prefix.
elementInputSchema
const elementInputSchema: z.ZodType<TimelineElementDraft, TimelineElementInput>Zod discriminated union over the six element kinds with id optional, used when inserting elements.
elementSchema
const elementSchema: z.ZodType<TimelineElement>Zod discriminated union on type over the six element schemas, from videoElementSchema to multicamElementSchema.
groupIdSchema
const groupIdSchema = z
.custom<GroupId>(
(v) => typeof v === 'string' && /^g-[\w-]+$/.test(v),
'invalid group id (expected "g-..." prefix)',
)
.meta({ type: 'string', pattern: '^g-[\\w-]+$' })Zod schema for a GroupId, a string with the g- prefix.
imageElementSchema
const imageElementSchema = composeFull('image', imageShape)Zod schema for an image element, the shared id and timing fields plus asset, transform, opacity, visual effects, and frame styling.
markerIdSchema
const markerIdSchema = z
.custom<MarkerId>(
(v) => typeof v === 'string' && /^m-[\w-]+$/.test(v),
'invalid marker id (expected "m-..." prefix)',
)
.meta({ type: 'string', pattern: '^m-[\\w-]+$' })Zod schema for a MarkerId, a string with the m- prefix.
markerSchema
const markerSchema = z.object({
id: markerIdSchema,
timeMs: z.number().int().nonnegative(),
label: z.string().optional(),
color: z.string().optional(),
})Zod schema for a project marker, a named point on the time ruler with an optional label and color.
multicamElementSchema
const multicamElementSchema = composeFull('multicam', multicamShape)Zod schema for a multicam element, the shared id and timing fields plus synced sources, angle cuts on the source clock, angle transition, audio source, trim, time map, reversal, transform, opacity, audio fields, an optional voice mix, visual effects, and frame styling. It is a media clip like a video element, and its trim, time map, and reversal read the source clock that every source shares.
projectSchema
const projectSchema = z.object({
version: z.literal(PROJECT_VERSION).default(PROJECT_VERSION),
id: z.string(),
name: z.string(),
width: z.number().int().positive(),
height: z.number().int().positive(),
fps: z.number().positive(),
tracks: z.array(trackSchema).default([]),
assets: z.record(z.string(), assetRefSchema).default({}),
layouts: z.array(layoutSchema).default([]),
presets: z.array(propertyPresetSchema).default([]),
markers: z.array(markerSchema).default([]),
vocabulary: z.array(z.string().trim().min(1).max(100)).max(1000).optional(),
})Zod schema for a project, its version, id, name, size, fps, tracks, assets, layouts, presets, markers, and the vocabulary of names and terms transcription gets as hints.
textElementSchema
const textElementSchema = composeFull('text', textShape)Zod schema for a text element, the shared id and timing fields plus text, style, rich text runs, box, transform, opacity, and visual effects.
textBoxSchema
const textBoxSchema = z.object({
width: z.number().positive(),
height: z.number().positive().optional(),
overflow: z.enum(['visible', 'clip']).default('clip'),
})Zod schema for a text box with a width, optional height, and overflow mode.
textShadowSchema
const textShadowSchema = shadowSchemaZod schema for a text shadow, the same shape as shadowSchema.
textStrokeSchema
const textStrokeSchema = strokeSchemaZod schema for a text outline, the same shape as strokeSchema.
textStyleSchema
const textStyleSchema = z
.object({
fontFamily: z.string().default('sans-serif'),
fontSize: z.number().positive().default(64),
fontWeight: z.number().int().min(100).max(1000).default(600),
fontStyle: z.enum(['normal', 'italic']).default('normal'),
color: z.string().default('#ffffff'),
align: z.enum(['left', 'center', 'right']).default('center'),
backgroundColor: z.string().optional(),
letterSpacing: z.number().default(0),
lineHeight: z.number().positive().default(1.25),
textTransform: z.enum(['none', 'uppercase', 'lowercase']).default('none'),
stroke: textStrokeSchema.optional(),
shadow: textShadowSchema.optional(),
})
.prefault({})Zod schema for text styling, font, weight, style, color, alignment, background, spacing, line height, case transform, stroke, and shadow.
trackIdSchema
const trackIdSchema = z
.custom<TrackId>(
(v) => typeof v === 'string' && /^t-[\w-]+$/.test(v),
'invalid track id (expected "t-..." prefix)',
)
.meta({ type: 'string', pattern: '^t-[\\w-]+$' })Zod schema for a TrackId, a string with the t- prefix.
trackSchema
const trackSchema = z.object({
id: trackIdSchema,
name: z.string(),
muted: z.boolean().default(false),
hidden: z.boolean().default(false),
locked: z.boolean().default(false),
magnetic: z.boolean().default(false),
elements: z.array(elementSchema).default([]),
})Zod schema for a track, its id, name, muted, hidden, locked, and magnetic flags, and its elements.
transformSchema
const transformSchema = z
.object({
x: z.number().default(0),
y: z.number().default(0),
scaleX: scaleSchema.default(1),
scaleY: scaleSchema.default(1),
rotation: z.number().default(0),
})
.prefault({})Zod schema for position, scale, and rotation, where coordinates are center-origin and scale may be negative but not zero.
videoElementSchema
const videoElementSchema = composeFull('video', videoShape)Zod schema for a video element, the shared id and timing fields plus asset, trim, time map, reversal, transform, opacity, audio fields, an optional voice mix, visual effects, and frame styling.
voiceSchema
const voiceSchema = z.object({ enabled: z.boolean(), amount: z.number().min(0).max(1) })
Zod schema for the optional voice cleanup mix on video, audio, and multicam clips. enabled turns the cleaned stem on, and amount is the wet level from 0 to 1.
Constants
MIN_ELEMENT_DURATION_MS
const MIN_ELEMENT_DURATION_MS = 10The shortest element duration the schema accepts, 10 ms.