import type { TrackType } from "@/types/timeline"; // Track color definitions export const TRACK_COLORS: Record< TrackType, { solid: string; background: string; border: string } > = { media: { solid: "bg-blue-500", background: "bg-blue-500/20", border: "border-white/80", }, text: { solid: "bg-[#9C4937]", background: "bg-[#9C4937]", border: "border-white/80", }, audio: { solid: "bg-green-500", background: "bg-green-500/20", border: "border-white/80", }, } as const; // Utility functions export function getTrackColors(type: TrackType) { return TRACK_COLORS[type]; } export function getTrackElementClasses(type: TrackType) { const colors = getTrackColors(type); return `${colors.background} ${colors.border}`; } // Track height definitions export const TRACK_HEIGHTS: Record = { media: 65, text: 25, audio: 50, } as const; // Utility function for track heights export function getTrackHeight(type: TrackType): number { return TRACK_HEIGHTS[type]; } // Calculate cumulative height up to (but not including) a track index export function getCumulativeHeightBefore( tracks: Array<{ type: TrackType }>, trackIndex: number ): number { const GAP = 4; // 4px gap between tracks (equivalent to Tailwind's gap-1) return tracks .slice(0, trackIndex) .reduce((sum, track) => sum + getTrackHeight(track.type) + GAP, 0); } // Calculate total height of all tracks export function getTotalTracksHeight( tracks: Array<{ type: TrackType }> ): number { const GAP = 4; // 4px gap between tracks (equivalent to Tailwind's gap-1) const tracksHeight = tracks.reduce( (sum, track) => sum + getTrackHeight(track.type), 0 ); const gapsHeight = Math.max(0, tracks.length - 1) * GAP; // n-1 gaps for n tracks return tracksHeight + gapsHeight; } // Other timeline constants export const TIMELINE_CONSTANTS = { ELEMENT_MIN_WIDTH: 80, PIXELS_PER_SECOND: 50, TRACK_HEIGHT: 60, // Default fallback DEFAULT_TEXT_DURATION: 5, ZOOM_LEVELS: [0.25, 0.5, 1, 1.5, 2, 3, 4], } as const; // FPS presets for project settings export const FPS_PRESETS = [ { value: "24", label: "24 fps (Film)" }, { value: "25", label: "25 fps (PAL)" }, { value: "30", label: "30 fps (NTSC)" }, { value: "60", label: "60 fps (High)" }, { value: "120", label: "120 fps (Slow-mo)" }, ] as const; // Frame snapping utilities export function timeToFrame(time: number, fps: number): number { return Math.round(time * fps); } export function frameToTime(frame: number, fps: number): number { return frame / fps; } export function snapTimeToFrame(time: number, fps: number): number { if (fps <= 0) return time; // Fallback for invalid FPS const frame = timeToFrame(time, fps); return frameToTime(frame, fps); } export function getFrameDuration(fps: number): number { return 1 / fps; } // Media thumbnail tiling constants export const MEDIA_THUMBNAIL_CONSTANTS = { DEFAULT_ASPECT_RATIO: 16 / 9, IMAGE_PADDING: 8, VIDEO_PADDING: 16, PARTIAL_TILE_THRESHOLD_IMAGE: 0.2, // Show partial tile if >20% visible for images PARTIAL_TILE_THRESHOLD_VIDEO: 0.3, // Show partial tile if >30% visible for videos MIN_OVERLAY_WIDTH_RATIO: 1.5, // Minimum width ratio to show name overlay } as const; // Utility function to calculate media thumbnail tiling export function calculateMediaTiling( elementWidth: number, trackType: TrackType, mediaType: "image" | "video" ) { const trackHeight = getTrackHeight(trackType); const aspectRatio = MEDIA_THUMBNAIL_CONSTANTS.DEFAULT_ASPECT_RATIO; const padding = mediaType === "image" ? MEDIA_THUMBNAIL_CONSTANTS.IMAGE_PADDING : MEDIA_THUMBNAIL_CONSTANTS.VIDEO_PADDING; const tileHeight = trackHeight - padding; const tileWidth = tileHeight * aspectRatio; // Calculate how many complete tiles we can fit const numCompleteTiles = Math.floor(elementWidth / tileWidth); const remainingWidth = elementWidth - numCompleteTiles * tileWidth; const threshold = mediaType === "image" ? MEDIA_THUMBNAIL_CONSTANTS.PARTIAL_TILE_THRESHOLD_IMAGE : MEDIA_THUMBNAIL_CONSTANTS.PARTIAL_TILE_THRESHOLD_VIDEO; const showPartialTile = remainingWidth > tileWidth * threshold; const totalTiles = numCompleteTiles + (showPartialTile ? 1 : 0); return { tileWidth, tileHeight, numCompleteTiles, remainingWidth, showPartialTile, totalTiles: Math.max(1, totalTiles), // Always show at least one tile canShowOverlay: elementWidth > tileWidth * MEDIA_THUMBNAIL_CONSTANTS.MIN_OVERLAY_WIDTH_RATIO, }; }