export type MediaType = 'image' | 'video' | 'gif' | 'audio'; /** Attribution for stock media (Unsplash/Pexels). Carried alongside the media * item so a host can append a credit line at publish/render time. */ export type StockAttribution = { name: string; source: 'unsplash' | 'pexels'; kind: 'photo' | 'video'; authorUrl?: string; mediaPageUrl?: string; }; export type TimelineAspectRatio = '16:9' | '9:16' | '1:1'; export declare const FPS_OPTIONS: readonly [24, 25, 30, 50, 60]; export type TimelineFps = (typeof FPS_OPTIONS)[number]; export declare const FPS_DEFAULT: TimelineFps; export type TimelineTrack = { id: string; name: string; muted: boolean; solo: boolean; hidden: boolean; locked: boolean; height: number; }; export declare const TRACK_HEIGHT_MIN = 32; export declare const TRACK_HEIGHT_MAX = 120; export declare const TRACK_HEIGHT_DEFAULT = 56; export declare const ZOOM_MIN = 5; export declare const ZOOM_MAX = 400; export declare const ZOOM_DEFAULT = 50; /** Minimum clip length, in frames. */ export declare const CLIP_MIN_FRAMES = 1; export type AnimPreset = 'fade' | 'slide-left' | 'slide-right' | 'slide-up' | 'slide-down' | 'scale' | 'zoom' | 'bounce' | 'pop' | 'spin' | 'blur' | 'wipe' | 'flip'; export type Easing = 'linear' | 'ease-in' | 'ease-out' | 'ease-in-out'; export declare const ANIM_PRESETS: readonly AnimPreset[]; export declare const EASINGS: readonly Easing[]; /** One side of a clip transition. */ export type ClipTransition = { preset: AnimPreset; /** Animation length in frames; clamped to the clip's duration. */ durationF: number; easing: Easing; }; /** Optional enter/exit transitions on a clip. Either side may be absent. */ export type ClipAnimation = { in?: ClipTransition; out?: ClipTransition; }; /** Sensible default when a transition side is first enabled (~0.5s @30fps). */ export declare function defaultTransition(): ClipTransition; export type ClipBase = { id: string; trackId: string; startF: number; durationF: number; groupId: string | null; locked: boolean; name: string; /** Optional enter/exit transitions, applied in the preview/compositor. */ animation?: ClipAnimation; }; export type MediaClipKind = 'video' | 'image' | 'audio'; export type MediaClip = ClipBase & { kind: MediaClipKind; url: string; assetId?: string; trimInF: number; sourceDurationF: number | null; volume: number; /** Linear gain ramps, in frames from the clip edges. */ fadeInF: number; fadeOutF: number; linkId: string | null; audioDetached?: boolean; attribution?: StockAttribution; }; export type TextClipStyle = { fontFamily: string; fontSizePct: number; fontWeight: 400 | 600 | 700; color: string; backgroundColor: string | null; backgroundOpacity: number; borderColor: string | null; borderWidthPct: number; align: 'left' | 'center' | 'right'; xPct: number; yPct: number; paddingPct: number; borderRadiusPct: number; shadow: boolean; shadowColor: string; shadowBlurPct: number; shadowOffsetPct: number; }; export type TextClip = ClipBase & { kind: 'text'; text: string; style: TextClipStyle; }; export type TimelineClip = MediaClip | TextClip; export declare const MARKER_COLORS: readonly ["#ef4444", "#f59e0b", "#22c55e", "#06b6d4", "#8b5cf6", "#ec4899"]; export type TimelineMarker = { id: string; frame: number; color: string; label: string; }; /** Project-level preview/composition background. `null` (on the project) means * transparent — no background. The default for new/migrated projects is solid * black, not null, so the historical look is preserved. */ export type ProjectBackground = { type: 'solid'; color: string; } | { type: 'gradient'; from: string; to: string; angle: number; }; /** Solid background presets (20). */ export declare const BACKGROUND_SOLID_PRESETS: readonly ["#000000", "#ffffff", "#18181b", "#27272a", "#3f3f46", "#1e293b", "#0f172a", "#0c4a6e", "#1e3a8a", "#312e81", "#4c1d95", "#831843", "#7f1d1d", "#7c2d12", "#713f12", "#14532d", "#064e3b", "#134e4a", "#164e63", "#52525b"]; /** Linear-gradient background presets (20). */ export declare const BACKGROUND_GRADIENT_PRESETS: { from: string; to: string; angle: number; }[]; /** Default project background — explicit solid black (not transparent). */ export declare function defaultProjectBackground(): ProjectBackground; export type TimelineRange = { inFrame: number; outFrame: number; }; export type BinItem = { id: string; url: string; mediaType: MediaType; name: string; duration: number | null; assetId?: string; attribution?: StockAttribution; }; export type TimelineProject = { schemaVersion: 2; id: string; /** Optional host-owned grouping key (workspace/user/etc.); the editor * never reads it. Kept for hosts that want to scope stored projects. */ workspaceId: string; name: string; aspectRatio: TimelineAspectRatio; fps: TimelineFps; tracks: TimelineTrack[]; clips: TimelineClip[]; markers: TimelineMarker[]; range: TimelineRange | null; bin: BinItem[]; zoom: number; background: ProjectBackground | null; createdAt: number; updatedAt: number; }; export declare function isMediaClip(clip: TimelineClip): clip is MediaClip; export declare function isTextClip(clip: TimelineClip): clip is TextClip; export declare function clipEndF(clip: TimelineClip): number; export declare function frameToSec(frame: number, fps: number): number; export declare function secToFrame(seconds: number, fps: number): number; /** Whether a clip produces audio in the preview/render. */ export declare function clipHasAudio(clip: TimelineClip): clip is MediaClip; export declare function clipKindForMediaType(mediaType: MediaType): MediaClipKind; export declare function defaultTextClipStyle(): TextClipStyle; export declare function createTrack(name: string): TimelineTrack; export declare function createEmptyProject(name: string, options?: { fps?: TimelineFps; workspaceId?: string; }): TimelineProject;