summaryrefslogtreecommitdiff
path: root/.cursor/rules/codebase-index.mdc
diff options
context:
space:
mode:
authorMaze <167211895+mazeincoding@users.noreply.github.com>2026-01-31 00:20:04 +0100
committerGitHub <noreply@github.com>2026-01-31 00:20:04 +0100
commit7bf0984698e43b9aa2dd879f65951318ed410390 (patch)
treeccf2cd590a47d550152afc07129cb55c71a9ec35 /.cursor/rules/codebase-index.mdc
parent0173db99448d1c4c6415dcf15272e17551b48b04 (diff)
downloadopencut-7bf0984698e43b9aa2dd879f65951318ed410390.tar.gz
codebase overhaul (#697)
Diffstat (limited to '.cursor/rules/codebase-index.mdc')
-rw-r--r--.cursor/rules/codebase-index.mdc1837
1 files changed, 1837 insertions, 0 deletions
diff --git a/.cursor/rules/codebase-index.mdc b/.cursor/rules/codebase-index.mdc
new file mode 100644
index 00000000..be1509dc
--- /dev/null
+++ b/.cursor/rules/codebase-index.mdc
@@ -0,0 +1,1837 @@
+---
+alwaysApply: true
+---
+
+# video-editor-oss Codebase Index
+
+**This file provides an index of exported functions, types, interfaces, classes, and constants in your codebase.**
+
+Updated in real-time by Twiggy. Use this to discover existing utilities and avoid duplicating code.
+
+## How to Use
+
+When implementing new features:
+1. Check if similar functionality already exists
+2. Reuse existing types and utilities
+3. Understand the API surface of your codebase
+
+```typescript
+## apps/web/src/constants
+
+editor-constants.ts
+ export const PLATFORM_LAYOUTS: Record<TPlatformLayout, string>
+ export const PANEL_CONFIG
+
+export-constants.ts
+ export const DEFAULT_EXPORT_OPTIONS
+ export const EXPORT_MIME_TYPES
+
+font-constants.ts
+ export interface FontOption {
+ value: string
+ label: string
+ category: "system" | "google" | "custom"
+ weights?: number[]
+ hasClassName?: boolean
+ }
+ export const FONT_OPTIONS: FontOption[]
+ export const DEFAULT_FONT
+ export type FontFamily = (typeof FONT_OPTIONS)[number]["value"]
+ export const getFontByValue = (value: string): FontOption | undefined => ...
+ export const getGoogleFonts = (): FontOption[] => ...
+ export const getSystemFonts = (): FontOption[] => ...
+
+language-constants.ts
+ export const LANGUAGES
+
+project-constants.ts
+ export const DEFAULT_CANVAS_PRESETS: TCanvasSize[]
+ export const FPS_PRESETS
+ export const BLUR_INTENSITY_PRESETS: { label: string; value: number }[]
+ export const DEFAULT_CANVAS_SIZE: TCanvasSize
+ export const DEFAULT_FPS
+ export const DEFAULT_BLUR_INTENSITY
+ export const DEFAULT_COLOR
+
+site-constants.ts
+ export const SITE_URL
+ export const SITE_INFO
+ export type ExternalTool = {
+ name: string;
+ description: string;
+ url: string;
+ icon: React.ElementType;
+ }
+ export const EXTERNAL_TOOLS: ExternalTool[]
+ export const DEFAULT_LOGO_URL
+ export const SOCIAL_LINKS
+ export type Sponsor = {
+ name: string;
+ url: string;
+ logo: string;
+ description: string;
+ }
+ export const SPONSORS: Sponsor[]
+
+stickers-constants.ts
+ export const STICKER_CATEGORIES
+ export const STICKER_CATEGORY_CONFIG: Record<
+ (typeof STICKER_CATEGORIES)[number],
+ string | undefined
+ >
+
+text-constants.ts
+ export const DEFAULT_TEXT_ELEMENT: Omit<TextElement, "id">
+
+timeline-constants.tsx
+ export const TRACK_COLORS: Record<TrackType, { background: string }>
+ export const TRACK_HEIGHTS: Record<TrackType, number>
+ export const TRACK_GAP
+ export const TIMELINE_CONSTANTS
+ export const DEFAULT_TIMELINE_VIEW_STATE: TTimelineViewState
+ export const TRACK_ICONS: Record<TrackType, React.ReactNode>
+
+transcription-constants.ts
+ export const TRANSCRIPTION_LANGUAGES
+ export const TRANSCRIPTION_MODELS: TranscriptionModel[]
+ export const DEFAULT_TRANSCRIPTION_MODEL: TranscriptionModelId
+ export const DEFAULT_CHUNK_LENGTH_SECONDS
+ export const DEFAULT_STRIDE_SECONDS
+ export const DEFAULT_WORDS_PER_CAPTION
+ export const MIN_CAPTION_DURATION_SECONDS
+
+## apps/web/src/core
+
+index.ts
+ export class EditorCore {
+ instance: EditorCore | null
+ command: CommandManager
+ playback: PlaybackManager
+ timeline: TimelineManager
+ scenes: ScenesManager
+ project: ProjectManager
+ media: MediaManager
+ renderer: RendererManager
+ save: SaveManager
+ audio: AudioManager
+ selection: SelectionManager
+ static getInstance(): EditorCore
+ static reset(): void
+ }
+
+## apps/web/src/hooks
+
+use-editor.ts
+ export function useEditor(): EditorCore
+
+use-file-upload.ts
+ export function useFileUpload({
+ accept,
+ multiple,
+ onFilesSelected,
+ }: UseFileUploadOptions = {})
+
+use-infinite-scroll.ts
+ export function useInfiniteScroll({
+ onLoadMore,
+ hasMore,
+ isLoading,
+ threshold = 200,
+ enabled = true,
+ }: UseInfiniteScrollOptions)
+
+use-keybindings.ts
+ export function useKeybindingsListener()
+ export function useKeybindingDisabler()
+
+use-keyboard-shortcuts-help.ts
+ export interface KeyboardShortcut {
+ id: string
+ keys: string[]
+ description: string
+ category: string
+ action: TAction
+ icon?: React.ReactNode
+ }
+ export function useKeyboardShortcutsHelp()
+
+use-mobile.ts
+ export function useIsMobile()
+
+use-raf-loop.ts
+ export function useRafLoop(callback: ({ time }: { time: number }) => void)
+
+use-reveal-item.ts
+ export function useRevealItem(
+ highlightId: string | null,
+ onClearHighlight: () => void,
+ highlightDuration = 1000,
+ )
+
+use-sound-search.ts
+ export function useSoundSearch({
+ query,
+ commercialOnly,
+ }: {
+ query: string;
+ commercialOnly: boolean;
+ })
+
+## apps/web/src/hooks/actions
+
+use-action-handler.ts
+ export function useActionHandler(
+ action: A,
+ handler: TActionFunc<A>,
+ isActive: TActionHandlerOptions,
+ )
+
+use-editor-actions.ts
+ export function useEditorActions()
+
+## apps/web/src/hooks/storage
+
+use-local-storage.ts
+ export function useLocalStorage({
+ key,
+ defaultValue,
+ }: {
+ key: string;
+ defaultValue: T;
+ }): [
+ T,
+ ({ value }: { value: T | ((previousValue: T) => T) }) => void,
+ boolean,
+ ]
+
+## apps/web/src/hooks/timeline
+
+use-edge-auto-scroll.ts
+ export function useEdgeAutoScroll({
+ isActive,
+ getMouseClientX,
+ rulerScrollRef,
+ tracksScrollRef,
+ contentWidth,
+ edgeThreshold = 100,
+ maxScrollSpeed = 15,
+ }: UseEdgeAutoScrollParams): void
+
+use-scroll-sync.ts
+ export function useScrollSync({
+ tracksScrollRef,
+ rulerScrollRef,
+ trackLabelsScrollRef,
+ bookmarksScrollRef,
+ }: UseScrollSyncProps)
+
+use-selection-box.ts
+ export function useSelectionBox({
+ containerRef,
+ onSelectionComplete,
+ isEnabled = true,
+ tracksScrollRef,
+ zoomLevel,
+ }: UseSelectionBoxProps)
+
+use-snap-indicator-position.ts
+ export function useSnapIndicatorPosition({
+ snapPoint,
+ zoomLevel,
+ tracks,
+ timelineRef,
+ trackLabelsRef,
+ tracksScrollRef,
+ }: UseSnapIndicatorPositionParams): SnapIndicatorPosition
+
+use-timeline-drag-drop.ts
+ export function useTimelineDragDrop({
+ containerRef,
+ headerRef,
+ zoomLevel,
+ }: UseTimelineDragDropProps)
+
+use-timeline-playhead.ts
+ export function useTimelinePlayhead({
+ zoomLevel,
+ rulerRef,
+ rulerScrollRef,
+ tracksScrollRef,
+ playheadRef,
+ }: UseTimelinePlayheadProps)
+
+use-timeline-seek.ts
+ export function useTimelineSeek({
+ playheadRef,
+ trackLabelsRef,
+ rulerScrollRef,
+ tracksScrollRef,
+ zoomLevel,
+ duration,
+ isSelecting,
+ clearSelectedElements,
+ seek,
+ }: UseTimelineSeekProps)
+
+use-timeline-snapping.ts
+ export interface SnapPoint {
+ time: number
+ type: "element-start" | "element-end" | "playhead"
+ elementId?: string
+ trackId?: string
+ }
+ export interface SnapResult {
+ snappedTime: number
+ snapPoint: SnapPoint | null
+ snapDistance: number
+ }
+ export interface UseTimelineSnappingOptions {
+ snapThreshold?: number
+ enableElementSnapping?: boolean
+ enablePlayheadSnapping?: boolean
+ }
+ export function useTimelineSnapping({
+ snapThreshold = 10,
+ enableElementSnapping = true,
+ enablePlayheadSnapping = true,
+ }: UseTimelineSnappingOptions = {})
+
+use-timeline-zoom.ts
+ export function useTimelineZoom({
+ containerRef,
+ minZoom = TIMELINE_CONSTANTS.ZOOM_MIN,
+ initialZoom,
+ initialScrollLeft,
+ initialPlayheadTime,
+ tracksScrollRef,
+ rulerScrollRef,
+ }: UseTimelineZoomProps): UseTimelineZoomReturn
+
+## apps/web/src/hooks/timeline/element
+
+use-element-interaction.ts
+ export function useElementInteraction({
+ zoomLevel,
+ timelineRef,
+ tracksContainerRef,
+ tracksScrollRef,
+ headerRef,
+ snappingEnabled,
+ onSnapPointChange,
+ }: UseElementInteractionProps)
+
+use-element-resize.ts
+ export interface ResizeState {
+ elementId: string
+ side: "left" | "right"
+ startX: number
+ initialTrimStart: number
+ initialTrimEnd: number
+ initialStartTime: number
+ initialDuration: number
+ }
+ export function useTimelineElementResize({
+ element,
+ track,
+ zoomLevel,
+ onSnapPointChange,
+ onResizeStateChange,
+ }: UseTimelineElementResizeProps)
+
+use-element-selection.ts
+ export function useElementSelection()
+
+## apps/web/src/lib
+
+drag-data.ts
+ export function setDragData({
+ dataTransfer,
+ dragData,
+ }: {
+ dataTransfer: DataTransfer;
+ dragData: TimelineDragData;
+ }): void
+ export function getDragData({
+ dataTransfer,
+ }: {
+ dataTransfer: DataTransfer;
+ }): TimelineDragData | null
+ export function hasDragData({
+ dataTransfer,
+ }: {
+ dataTransfer: DataTransfer;
+ }): boolean
+ export function clearDragData(): void
+
+export.ts
+ export function getExportMimeType({
+ format,
+ }: {
+ format: ExportFormat;
+ }): string
+ export function getExportFileExtension({
+ format,
+ }: {
+ format: ExportFormat;
+ }): string
+
+iconify-api.ts
+ export const ICONIFY_HOSTS
+ export interface IconSet {
+ prefix: string
+ name: string
+ total: number
+ author?: {
+ name: string;
+ url?: string;
+ }
+ license?: {
+ title: string;
+ spdx?: string;
+ url?: string;
+ }
+ samples?: string[]
+ category?: string
+ palette?: boolean
+ }
+ export interface IconSearchResult {
+ icons: string[]
+ total: number
+ limit: number
+ start: number
+ collections: Record<string, IconSet>
+ }
+ export interface CollectionInfo {
+ prefix: string
+ total: number
+ title?: string
+ uncategorized?: string[]
+ categories?: Record<string, string[]>
+ hidden?: string[]
+ aliases?: Record<string, string>
+ }
+ export function getCollections(
+ category?: string,
+ ): Promise<Record<string, IconSet>>
+ export function getCollection(
+ prefix: string,
+ ): Promise<CollectionInfo | null>
+ export function searchIcons(
+ query: string,
+ limit: number = 64,
+ prefixes?: string[],
+ category?: string,
+ ): Promise<IconSearchResult>
+ export function buildIconSvgUrl(
+ host: string,
+ iconName: string,
+ params?: {
+ color?: string;
+ width?: number;
+ height?: number;
+ flip?: "horizontal" | "vertical" | "horizontal,vertical";
+ rotate?: number | string;
+ },
+ ): string
+ export function getIconSvgUrl(
+ iconName: string,
+ params?: Parameters<typeof buildIconSvgUrl>[2],
+ ): string
+ export function downloadSvgAsText(
+ iconName: string,
+ params?: Parameters<typeof getIconSvgUrl>[1],
+ ): Promise<string>
+ export function svgToFile(svgText: string, fileName: string): File
+ export const POPULAR_COLLECTIONS
+ export function getCategoriesFromCollections(
+ collections: Record<string, IconSet>,
+ ): string[]
+
+rate-limit.ts
+ export const baseRateLimit
+ export function checkRateLimit({ request }: { request: Request })
+
+scenes.ts
+ export function getMainScene({ scenes }: { scenes: TScene[] }): TScene | null
+ export function ensureMainScene({ scenes }: { scenes: TScene[] }): TScene[]
+ export function buildDefaultScene({
+ name,
+ isMain,
+ }: {
+ name: string;
+ isMain: boolean;
+ }): TScene
+ export function canDeleteScene({ scene }: { scene: TScene }): {
+ canDelete: boolean;
+ reason?: string;
+ }
+ export function getFallbackSceneAfterDelete({
+ scenes,
+ deletedSceneId,
+ currentSceneId,
+ }: {
+ scenes: TScene[];
+ deletedSceneId: string;
+ currentSceneId: string | null;
+ }): TScene | null
+ export function findCurrentScene({
+ scenes,
+ currentSceneId,
+ }: {
+ scenes: TScene[];
+ currentSceneId: string;
+ }): TScene | null
+ export function getProjectDurationFromScenes({
+ scenes,
+ }: {
+ scenes: TScene[];
+ }): number
+ export function updateSceneInArray({
+ scenes,
+ sceneId,
+ updates,
+ }: {
+ scenes: TScene[];
+ sceneId: string;
+ updates: Partial<TScene>;
+ }): TScene[]
+
+time.ts
+ export function roundToFrame({
+ time,
+ fps,
+ }: {
+ time: number;
+ fps: number;
+ }): number
+ export function formatTimeCode({
+ timeInSeconds,
+ format = "HH:MM:SS:CS",
+ fps,
+ }: {
+ timeInSeconds: number;
+ format?: TTimeCode;
+ fps?: number;
+ }): string
+ export function parseTimeCode({
+ timeCode,
+ format = "HH:MM:SS:CS",
+ fps,
+ }: {
+ timeCode: string;
+ format?: TTimeCode;
+ fps: number;
+ }): number | null
+ export function guessTimeCodeFormat({
+ timeCode,
+ }: {
+ timeCode: string;
+ }): TTimeCode | null
+ export function timeToFrame({
+ time,
+ fps,
+ }: {
+ time: number;
+ fps: number;
+ }): number
+ export function frameToTime({
+ frame,
+ fps,
+ }: {
+ frame: number;
+ fps: number;
+ }): number
+ export function snapTimeToFrame({
+ time,
+ fps,
+ }: {
+ time: number;
+ fps: number;
+ }): number
+ export function getSnappedSeekTime({
+ rawTime,
+ duration,
+ fps,
+ }: {
+ rawTime: number;
+ duration: number;
+ fps: number;
+ }): number
+ export function getLastFrameTime({
+ duration,
+ fps,
+ }: {
+ duration: number;
+ fps: number;
+ }): number
+
+## apps/web/src/lib/actions
+
+definitions.ts
+ export type TActionCategory = | "playback"
+ | "navigation"
+ | "editing"
+ | "selection"
+ | "history"
+ | "timeline"
+ | "controls"
+ export interface TActionDefinition {
+ description: string
+ category: TActionCategory
+ defaultShortcuts?: ShortcutKey[]
+ args?: Record<string, unknown>
+ }
+ export const ACTIONS
+ export type TAction = keyof typeof ACTIONS
+ export function getActionDefinition(action: TAction): TActionDefinition
+ export function getDefaultShortcuts(): Record<ShortcutKey, TAction>
+
+registry.ts
+ export function bindAction(
+ action: A,
+ handler: TActionFunc<A>,
+ )
+ export function unbindAction(
+ action: A,
+ handler: TActionFunc<A>,
+ )
+ export const invokeAction = (
+ action: A,
+ args?: TArgOfAction<A>,
+ trigger?: TInvocationTrigger,
+ ) => ...
+
+types.ts
+ export type TActionArgsMap = {
+ "seek-forward": { seconds: number } | undefined;
+ "seek-backward": { seconds: number } | undef...
+ export type TActionWithArgs = keyof TActionArgsMap
+ export type TActionWithOptionalArgs = | TActionWithNoArgs
+ | TKeysWithValueUndefined<TActionArgsMap>
+ export type TActionWithNoArgs = Exclude<TAction, TActionWithArgs>
+ export type TArgOfAction<A extends TAction> = A extends TActionWithArgs
+ ? TActionArgsMap[A]
+ : undefined
+ export type TActionFunc<A extends TAction> = A extends TActionWithArgs
+ ? (arg: TArgOfAction<A>, trigger?: TInvocationTrigger) => void
+ : (_?:...
+ export type TInvocationTrigger = "keypress" | "mouseclick"
+ export type TBoundActionList = {
+ [A in TAction]?: Array<TActionFunc<A>>;
+ }
+ export type TActionHandlerOptions = | MutableRefObject<boolean>
+ | boolean
+ | undefined
+
+## apps/web/src/lib/auth
+
+server.ts
+ export const auth
+ export type Auth = typeof auth
+
+## apps/web/src/lib/blog
+
+query.ts
+ export function getPosts()
+ export function getTags()
+ export function getSinglePost({ slug }: { slug: string })
+ export function getCategories()
+ export function getAuthors()
+ export function processHtmlContent({
+ html,
+ }: {
+ html: string;
+ }): Promise<string>
+
+## apps/web/src/lib/db
+
+index.ts
+ export const db
+
+schema.ts
+ export const users
+ export const sessions
+ export const accounts
+ export const verifications
+
+## apps/web/src/lib/gradients
+
+canvas.ts
+ export function drawCssBackground({
+ ctx,
+ width,
+ height,
+ css,
+ }: {
+ ctx: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D;
+ width: number;
+ height: number;
+ css: string;
+ }): void
+
+parser.ts
+ export type GradientOrientation = LinearOrientation | Array<RadialOrientation>
+ export type Color = | { type: "hex"; value: string }
+ | { type: "literal"; value: string }
+ | { type: "rgb"; value: A...
+ export type ColorStop = Color & { length?: Distance }
+ export type GradientAst = {
+ type: GradientType;
+ orientation: GradientOrientation | undefined;
+ colorStops: Array<ColorSto...
+ export const parseGradient = ({
+ code,
+ }: {
+ code: string;
+ }): Array<GradientAst> => ...
+ export const GradientParser
+
+## apps/web/src/lib/media
+
+audio.ts
+ export type CollectedAudioElement = Omit<
+ AudioElement,
+ "type" | "mediaId" | "volume" | "id" | "name" | "sourceType" | "sourceUrl"
+ ...
+ export function createAudioContext(): AudioContext
+ export interface DecodedAudio {
+ samples: Float32Array
+ sampleRate: number
+ }
+ export function decodeAudioToFloat32({
+ audioBlob,
+ }: {
+ audioBlob: Blob;
+ }): Promise<DecodedAudio>
+ export function collectAudioElements({
+ tracks,
+ mediaAssets,
+ audioContext,
+ }: {
+ tracks: TimelineTrack[];
+ mediaAssets: MediaAsset[];
+ audioContext: AudioContext;
+ }): Promise<CollectedAudioElement[]>
+ export interface AudioClipSource {
+ id: string
+ sourceKey: string
+ file: File
+ startTime: number
+ duration: number
+ trimStart: number
+ trimEnd: number
+ muted: boolean
+ }
+ export function collectAudioMixSources({
+ tracks,
+ mediaAssets,
+ }: {
+ tracks: TimelineTrack[];
+ mediaAssets: MediaAsset[];
+ }): Promise<AudioMixSource[]>
+ export function collectAudioClips({
+ tracks,
+ mediaAssets,
+ }: {
+ tracks: TimelineTrack[];
+ mediaAssets: MediaAsset[];
+ }): Promise<AudioClipSource[]>
+ export function createTimelineAudioBuffer({
+ tracks,
+ mediaAssets,
+ duration,
+ sampleRate = 44100,
+ audioContext,
+ }: {
+ tracks: TimelineTrack[];
+ mediaAssets: MediaAsset[];
+ duration: number;
+ sampleRate?: number;
+ audioContext?: AudioContext;
+ }): Promise<AudioBuffer | null>
+
+media-utils.ts
+ export const SUPPORTS_AUDIO: readonly MediaType[]
+ export function mediaSupportsAudio({
+ media,
+ }: {
+ media: MediaAsset | null | undefined;
+ }): boolean
+ export const getMediaTypeFromFile = ({
+ file,
+ }: {
+ file: File;
+ }): MediaType | null => ...
+
+mediabunny.ts
+ export function getVideoInfo({
+ videoFile,
+ }: {
+ videoFile: File;
+ }): Promise<{
+ duration: number;
+ width: number;
+ height: number;
+ fps: number;
+ }>
+ export const extractTimelineAudio = ({
+ tracks,
+ mediaAssets,
+ totalDuration,
+ onProgress,
+ }: {
+ tracks: TimelineTrack[];
+ mediaAssets: MediaAsset[];
+ totalDuration: number;
+ onProgress?: (progress: number) => void;
+ }): Promise<Blob> => ...
+
+processing.ts
+ export interface ProcessedMediaAsset extends Omit<MediaAsset, "id">
+ export function generateThumbnail({
+ videoFile,
+ timeInSeconds,
+ }: {
+ videoFile: File;
+ timeInSeconds: number;
+ }): Promise<string>
+ export function generateImageThumbnail({
+ imageFile,
+ }: {
+ imageFile: File;
+ }): Promise<string>
+ export function processMediaAssets({
+ files,
+ onProgress,
+ }: {
+ files: FileList | File[];
+ onProgress?: ({ progress }: { progress: number }) => void;
+ }): Promise<ProcessedMediaAsset[]>
+
+## apps/web/src/lib/timeline
+
+bookmarks.ts
+ export function findBookmarkIndex({
+ bookmarks,
+ frameTime,
+ }: {
+ bookmarks: number[];
+ frameTime: number;
+ }): number
+ export function isBookmarkAtTime({
+ bookmarks,
+ frameTime,
+ }: {
+ bookmarks: number[];
+ frameTime: number;
+ }): boolean
+ export function toggleBookmarkInArray({
+ bookmarks,
+ frameTime,
+ }: {
+ bookmarks: number[];
+ frameTime: number;
+ }): number[]
+ export function removeBookmarkFromArray({
+ bookmarks,
+ frameTime,
+ }: {
+ bookmarks: number[];
+ frameTime: number;
+ }): number[]
+ export function getFrameTime({
+ time,
+ fps,
+ }: {
+ time: number;
+ fps: number;
+ }): number
+
+drop-utils.ts
+ export function computeDropTarget({
+ elementType,
+ mouseX,
+ mouseY,
+ tracks,
+ playheadTime,
+ isExternalDrop,
+ elementDuration,
+ pixelsPerSecond,
+ zoomLevel,
+ verticalDragDirection,
+ startTimeOverride,
+ excludeElementId,
+ }: ComputeDropTargetParams): DropTarget
+ export function getDropLineY({
+ dropTarget,
+ tracks,
+ }: {
+ dropTarget: DropTarget;
+ tracks: TimelineTrack[];
+ }): number
+
+element-utils.ts
+ export function canElementHaveAudio(
+ element: TimelineElement,
+ )
+ export function canElementBeHidden(
+ element: TimelineElement,
+ )
+ export function hasMediaId(
+ element: TimelineElement,
+ )
+ export function requiresMediaId({
+ element,
+ }: {
+ element: CreateTimelineElement;
+ }): boolean
+ export function checkElementOverlaps({
+ elements,
+ }: {
+ elements: TimelineElement[];
+ }): boolean
+ export function resolveElementOverlaps({
+ elements,
+ }: {
+ elements: TimelineElement[];
+ }): TimelineElement[]
+ export function wouldElementOverlap({
+ elements,
+ startTime,
+ endTime,
+ excludeElementId,
+ }: {
+ elements: TimelineElement[];
+ startTime: number;
+ endTime: number;
+ excludeElementId?: string;
+ }): boolean
+ export function buildTextElement({
+ raw,
+ startTime,
+ }: {
+ raw: Partial<Omit<TextElement, "type" | "id">>;
+ startTime: number;
+ }): CreateTimelineElement
+ export function buildStickerElement({
+ iconName,
+ startTime,
+ }: {
+ iconName: string;
+ startTime: number;
+ }): CreateStickerElement
+ export function buildVideoElement({
+ mediaId,
+ name,
+ duration,
+ startTime,
+ }: {
+ mediaId: string;
+ name: string;
+ duration: number;
+ startTime: number;
+ }): CreateVideoElement
+ export function buildImageElement({
+ mediaId,
+ name,
+ duration,
+ startTime,
+ }: {
+ mediaId: string;
+ name: string;
+ duration: number;
+ startTime: number;
+ }): CreateImageElement
+ export function buildUploadAudioElement({
+ mediaId,
+ name,
+ duration,
+ startTime,
+ buffer,
+ }: {
+ mediaId: string;
+ name: string;
+ duration: number;
+ startTime: number;
+ buffer?: AudioBuffer;
+ }): CreateUploadAudioElement
+ export function buildLibraryAudioElement({
+ sourceUrl,
+ name,
+ duration,
+ startTime,
+ buffer,
+ }: {
+ sourceUrl: string;
+ name: string;
+ duration: number;
+ startTime: number;
+ buffer?: AudioBuffer;
+ }): CreateLibraryAudioElement
+ export function getElementsAtTime({
+ tracks,
+ time,
+ }: {
+ tracks: TimelineTrack[];
+ time: number;
+ }): { trackId: string; elementId: string }[]
+
+index.ts
+ export function calculateTotalDuration({
+ tracks,
+ }: {
+ tracks: TimelineTrack[];
+ }): number
+
+ruler-utils.ts
+ export interface RulerConfig {
+ labelIntervalSeconds: number
+ tickIntervalSeconds: number
+ }
+ export function getRulerConfig({
+ zoomLevel,
+ fps,
+ }: {
+ zoomLevel: number;
+ fps: number;
+ }): RulerConfig
+ export function shouldShowLabel({
+ time,
+ labelIntervalSeconds,
+ }: {
+ time: number;
+ labelIntervalSeconds: number;
+ }): boolean
+ export function formatRulerLabel({
+ timeInSeconds,
+ fps,
+ }: {
+ timeInSeconds: number;
+ fps: number;
+ }): string
+
+track-utils.ts
+ export function canTracktHaveAudio(
+ track: TimelineTrack,
+ )
+ export function canTrackBeHidden(
+ track: TimelineTrack,
+ )
+ export function getTrackColor({ type }: { type: TrackType })
+ export function getTrackClasses({ type }: { type: TrackType })
+ export function getTrackHeight({ type }: { type: TrackType }): number
+ export function getCumulativeHeightBefore({
+ tracks,
+ trackIndex,
+ }: {
+ tracks: Array<{ type: TrackType }>;
+ trackIndex: number;
+ }): number
+ export function getTotalTracksHeight({
+ tracks,
+ }: {
+ tracks: Array<{ type: TrackType }>;
+ }): number
+ export function buildEmptyTrack({
+ id,
+ type,
+ name,
+ }: {
+ id: string;
+ type: TrackType;
+ name?: string;
+ }): TimelineTrack
+ export function getDefaultInsertIndexForTrack({
+ tracks,
+ trackType,
+ }: {
+ tracks: TimelineTrack[];
+ trackType: TrackType;
+ }): number
+ export function getHighestInsertIndexForTrack({
+ tracks,
+ trackType,
+ }: {
+ tracks: TimelineTrack[];
+ trackType: TrackType;
+ }): number
+ export function isMainTrack(track: TimelineTrack)
+ export function getMainTrack({
+ tracks,
+ }: {
+ tracks: TimelineTrack[];
+ }): TimelineTrack | null
+ export function ensureMainTrack({
+ tracks,
+ }: {
+ tracks: TimelineTrack[];
+ }): TimelineTrack[]
+ export function canElementGoOnTrack({
+ elementType,
+ trackType,
+ }: {
+ elementType: ElementType;
+ trackType: TrackType;
+ }): boolean
+ export function validateElementTrackCompatibility({
+ element,
+ track,
+ }: {
+ element: { type: ElementType };
+ track: { type: TrackType };
+ }): { isValid: boolean; errorMessage?: string }
+
+zoom-utils.ts
+ export function getTimelineZoomMin({
+ duration,
+ containerWidth,
+ }: {
+ duration: number;
+ containerWidth: number | null | undefined;
+ }): number
+ export function getTimelinePaddingPx({
+ containerWidth,
+ zoomLevel,
+ minZoom,
+ }: {
+ containerWidth: number;
+ zoomLevel: number;
+ minZoom: number;
+ }): number
+ export function getZoomPercent({
+ zoomLevel,
+ minZoom,
+ }: {
+ zoomLevel: number;
+ minZoom: number;
+ }): number
+
+## apps/web/src/lib/transcription
+
+caption.ts
+ export function buildCaptionChunks({
+ segments,
+ wordsPerChunk = DEFAULT_WORDS_PER_CAPTION,
+ minDuration = MIN_CAPTION_DURATION_SECONDS,
+ }: {
+ segments: TranscriptionSegment[];
+ wordsPerChunk?: number;
+ minDuration?: number;
+ }): CaptionChunk[]
+
+## apps/web/src/services/media
+
+video-cache.ts
+ export class VideoCache {
+ sinks
+ initPromises
+ async getFrameAt({
+ mediaId,
+ file,
+ time,
+ }: {
+ mediaId: string;
+ file: File;
+ time: number;
+ }): Promise<WrappedCanvas | null>
+ clearVideo({ mediaId }: { mediaId: string }): void
+ clearAll(): void
+ getStats()
+ }
+ export const videoCache
+
+## apps/web/src/services/renderer
+
+canvas-renderer.ts
+ export type CanvasRendererParams = {
+ width: number;
+ height: number;
+ fps: number;
+ }
+ export class CanvasRenderer {
+ canvas: OffscreenCanvas | HTMLCanvasElement
+ context: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D
+ width: number
+ height: number
+ fps: number
+ constructor({ width, height, fps }: CanvasRendererParams)
+ setSize({ width, height }: { width: number; height: number })
+ async render({ node, time }: { node: BaseNode; time: number })
+ async renderToCanvas({
+ node,
+ time,
+ targetCanvas,
+ }: {
+ node: BaseNode;
+ time: number;
+ targetCanvas: HTMLCanvasElement;
+ })
+ }
+
+scene-builder.ts
+ export type BuildSceneParams = {
+ canvasSize: TCanvasSize;
+ tracks: TimelineTrack[];
+ mediaAssets: MediaAsset[];
+ duration: numb...
+ export function buildScene(params: BuildSceneParams)
+
+scene-exporter.ts
+ export type ExportFormat = "mp4" | "webm"
+ export type ExportQuality = "low" | "medium" | "high" | "very_high"
+ export type SceneExporterEvents = {
+ progress: [progress: number];
+ complete: [buffer: ArrayBuffer];
+ error: [error: Error];
+ cance...
+ export class SceneExporter extends EventEmitter<SceneExporterEvents> {
+ renderer: CanvasRenderer
+ format: ExportFormat
+ quality: ExportQuality
+ shouldIncludeAudio: boolean
+ audioBuffer: AudioBuffer
+ isCancelled
+ constructor({
+ width,
+ height,
+ fps,
+ format,
+ quality,
+ shouldIncludeAudio,
+ audioBuffer,
+ }: ExportParams)
+ cancel(): void
+ async export({
+ rootNode,
+ }: {
+ rootNode: RootNode;
+ }): Promise<ArrayBuffer | null>
+ }
+
+## apps/web/src/services/storage
+
+indexeddb-adapter.ts
+ export class IndexedDBAdapter implements StorageAdapter<T> {
+ dbName: string
+ storeName: string
+ version: number
+ constructor(dbName: string, storeName: string, version = 1)
+ async get(key: string): Promise<T | null>
+ async set(key: string, value: T): Promise<void>
+ async remove(key: string): Promise<void>
+ async list(): Promise<string[]>
+ async getAll(): Promise<T[]>
+ async clear(): Promise<void>
+ }
+
+opfs-adapter.ts
+ export class OPFSAdapter implements StorageAdapter<File> {
+ directoryName: string
+ constructor(directoryName = "media")
+ async get(key: string): Promise<File | null>
+ async set(key: string, file: File): Promise<void>
+ async remove(key: string): Promise<void>
+ async list(): Promise<string[]>
+ async clear(): Promise<void>
+ static isSupported(): boolean
+ }
+
+storage-service.ts
+ export const storageService
+
+types.ts
+ export interface StorageAdapter<T> {
+ get(key: string): Promise<T | null>
+ set(key: string, value: T): Promise<void>
+ remove(key: string): Promise<void>
+ list(): Promise<string[]>
+ clear(): Promise<void>
+ }
+ export interface MediaAssetData {
+ id: string
+ name: string
+ type: MediaType
+ size: number
+ lastModified: number
+ width?: number
+ height?: number
+ duration?: number
+ fps?: number
+ ephemeral?: boolean
+ thumbnailUrl?: string
+ sourceStickerIconName?: string
+ }
+ export type SerializedScene = Omit<TScene, "createdAt" | "updatedAt"> & {
+ createdAt: string;
+ updatedAt: string;
+ }
+ export type SerializedProjectMetadata = Omit<
+ TProjectMetadata,
+ "createdAt" | "updatedAt"
+ > & {
+ createdAt: string;
+ updatedAt: string;
+ }
+ export type SerializedProject = Omit<TProject, "metadata" | "scenes"> & {
+ metadata: SerializedProjectMetadata;
+ scenes: Serializ...
+ export interface StorageConfig {
+ projectsDb: string
+ mediaDb: string
+ savedSoundsDb: string
+ version: number
+ }
+
+## apps/web/src/services/transcription
+
+index.ts
+ export const transcriptionService
+
+worker.ts
+ export type WorkerMessage = | { type: "init"; modelId: string }
+ | { type: "transcribe"; audio: Float32Array; language: strin...
+ export type WorkerResponse = | { type: "init-progress"; progress: number }
+ | { type: "init-complete" }
+ | { type: "init-error...
+
+## apps/web/src/stores
+
+assets-panel-store.tsx
+ export const TAB_KEYS
+ export type Tab = (typeof TAB_KEYS)[number]
+ export const tabs
+ export const useAssetsPanelStore
+
+editor-store.ts
+ export const useEditorStore
+
+keybindings-store.ts
+ export const defaultKeybindings: KeybindingConfig
+ export interface KeybindingConflict {
+ key: ShortcutKey
+ existingAction: TActionWithOptionalArgs
+ newAction: TActionWithOptionalArgs
+ }
+ export const useKeybindingsStore
+
+panel-store.ts
+ export interface PanelSizes {
+ tools: number
+ preview: number
+ properties: number
+ mainContent: number
+ timeline: number
+ }
+ export type PanelId = keyof PanelSizes
+ export const usePanelStore
+
+sounds-store.ts
+ export const useSoundsStore
+
+stickers-store.ts
+ export const useStickersStore
+
+text-properties-store.ts
+ export type TextPropertiesTab = "text" | "transform"
+ export interface TextPropertiesTabMeta {
+ value: TextPropertiesTab
+ label: string
+ }
+ export const TEXT_PROPERTIES_TABS: ReadonlyArray<TextPropertiesTabMeta>
+ export function isTextPropertiesTab(value: string)
+ export const useTextPropertiesStore
+
+timeline-store.ts
+ export const useTimelineStore
+
+## apps/web/src/types
+
+assets.ts
+ export type MediaType = "image" | "video" | "audio"
+ export interface MediaAsset extends Omit<MediaAssetData, "size" | "lastModified"> {
+ file: File
+ url?: string
+ }
+
+blog.ts
+ export type Post = {
+ id: string;
+ slug: string;
+ title: string;
+ content: string;
+ description: string;
+ coverImage...
+ export type Pagination = {
+ limit: number;
+ currpage: number;
+ nextPage: number | null;
+ prevPage: number | null;
+ totalIt...
+ export type MarblePostList = {
+ posts: Post[];
+ pagination: Pagination;
+ }
+ export type MarblePost = {
+ post: Post;
+ }
+ export type Tag = {
+ id: string;
+ name: string;
+ slug: string;
+ }
+ export type MarbleTag = {
+ tag: Tag;
+ }
+ export type MarbleTagList = {
+ tags: Tag[];
+ pagination: Pagination;
+ }
+ export type Category = {
+ id: string;
+ name: string;
+ slug: string;
+ }
+ export type MarbleCategory = {
+ category: Category;
+ }
+ export type MarbleCategoryList = {
+ categories: Category[];
+ pagination: Pagination;
+ }
+ export type Author = {
+ id: string;
+ name: string;
+ image: string;
+ }
+ export type MarbleAuthor = {
+ author: Author;
+ }
+ export type MarbleAuthorList = {
+ authors: Author[];
+ pagination: Pagination;
+ }
+
+drag.ts
+ export interface MediaDragData extends BaseDragData {
+ type: "media"
+ mediaType: "image" | "video" | "audio"
+ }
+ export interface TextDragData extends BaseDragData {
+ type: "text"
+ content: string
+ }
+ export interface StickerDragData extends BaseDragData {
+ type: "sticker"
+ iconName: string
+ }
+ export type TimelineDragData = MediaDragData | TextDragData | StickerDragData
+
+editor.ts
+ export type TPlatformLayout = "tiktok"
+
+export.ts
+ export const EXPORT_QUALITY_VALUES
+ export const EXPORT_FORMAT_VALUES
+ export type ExportFormat = (typeof EXPORT_FORMAT_VALUES)[number]
+ export type ExportQuality = (typeof EXPORT_QUALITY_VALUES)[number]
+ export interface ExportOptions {
+ format: ExportFormat
+ quality: ExportQuality
+ fps?: number
+ includeAudio?: boolean
+ onProgress?: ({ progress }: { progress: number }) => void
+ onCancel?: () => boolean
+ }
+ export interface ExportResult {
+ success: boolean
+ buffer?: ArrayBuffer
+ error?: string
+ cancelled?: boolean
+ }
+
+keybinding.ts
+ export type ModifierKeys = | "ctrl"
+ | "alt"
+ | "shift"
+ | "ctrl+shift"
+ | "alt+shift"
+ | "ctrl+alt"
+ | "ctrl+alt+shift"
+ export type Key = | "a"
+ | "b"
+ | "c"
+ | "d"
+ | "e"
+ | "f"
+ | "g"
+ | "h"
+ | "i"
+ | "j"
+ | "k"
+ | "l"
+ | "m"
+ | "n"
+ ...
+ export type ModifierBasedShortcutKey = `${ModifierKeys}+${Key}`
+ export type SingleCharacterShortcutKey = `${Key}`
+ export type ShortcutKey = ModifierBasedShortcutKey | SingleCharacterShortcutKey
+ export type KeybindingConfig = {
+ [key in ShortcutKey]?: TActionWithOptionalArgs;
+ }
+
+language.ts
+ export type Language = (typeof LANGUAGES)[number]
+ export type LanguageCode = Language["code"]
+
+project.ts
+ export type TBackground = | {
+ type: "color";
+ color: string;
+ }
+ | {
+ type: "blur";
+ blurIntensity: number;
+ }
+ export interface TCanvasSize {
+ width: number
+ height: number
+ }
+ export interface TProjectMetadata {
+ id: string
+ name: string
+ thumbnail?: string
+ duration: number
+ createdAt: Date
+ updatedAt: Date
+ }
+ export interface TProjectSettings {
+ fps: number
+ canvasSize: TCanvasSize
+ originalCanvasSize?: TCanvasSize | null
+ background: TBackground
+ }
+ export interface TTimelineViewState {
+ zoomLevel: number
+ scrollLeft: number
+ playheadTime: number
+ }
+ export interface TProject {
+ metadata: TProjectMetadata
+ scenes: TScene[]
+ currentSceneId: string
+ settings: TProjectSettings
+ version: number
+ timelineViewState?: TTimelineViewState
+ }
+ export type TProjectSortKey = "createdAt" | "updatedAt" | "name" | "duration"
+ export type TSortOrder = "asc" | "desc"
+ export type TProjectSortOption = `${TProjectSortKey}-${TSortOrder}`
+
+sounds.ts
+ export interface SoundEffect {
+ id: number
+ name: string
+ description: string
+ url: string
+ previewUrl?: string
+ downloadUrl?: string
+ duration: number
+ filesize: number
+ type: string
+ channels: number
+ bitrate: number
+ bitdepth: number
+ samplerate: number
+ username: string
+ tags: string[]
+ license: string
+ created: string
+ downloads: number
+ rating: number
+ ratingCount: number
+ }
+ export interface SavedSound {
+ id: number
+ name: string
+ username: string
+ previewUrl?: string
+ downloadUrl?: string
+ duration: number
+ tags: string[]
+ license: string
+ savedAt: string
+ }
+ export interface SavedSoundsData {
+ sounds: SavedSound[]
+ lastModified: string
+ }
+
+stickers.ts
+ export type StickerCategory = (typeof STICKER_CATEGORIES)[number]
+
+time.ts
+ export type TTimeCode = "MM:SS" | "HH:MM:SS" | "HH:MM:SS:CS" | "HH:MM:SS:FF"
+
+timeline.ts
+ export interface TScene {
+ id: string
+ name: string
+ isMain: boolean
+ tracks: TimelineTrack[]
+ bookmarks: number[]
+ createdAt: Date
+ updatedAt: Date
+ }
+ export type TrackType = "video" | "text" | "audio" | "sticker"
+ export interface VideoTrack extends BaseTrack {
+ type: "video"
+ elements: (VideoElement | ImageElement)[]
+ isMain: boolean
+ muted: boolean
+ hidden: boolean
+ }
+ export interface TextTrack extends BaseTrack {
+ type: "text"
+ elements: TextElement[]
+ hidden: boolean
+ }
+ export interface AudioTrack extends BaseTrack {
+ type: "audio"
+ elements: AudioElement[]
+ muted: boolean
+ }
+ export interface StickerTrack extends BaseTrack {
+ type: "sticker"
+ elements: StickerElement[]
+ hidden: boolean
+ }
+ export type TimelineTrack = VideoTrack | TextTrack | AudioTrack | StickerTrack
+ export interface Transform {
+ scale: number
+ position: {
+ x: number;
+ y: number;
+ }
+ rotate: number
+ }
+ export interface UploadAudioElement extends BaseAudioElement {
+ sourceType: "upload"
+ mediaId: string
+ }
+ export interface LibraryAudioElement extends BaseAudioElement {
+ sourceType: "library"
+ sourceUrl: string
+ }
+ export type AudioElement = UploadAudioElement | LibraryAudioElement
+ export interface VideoElement extends BaseTimelineElement {
+ type: "video"
+ mediaId: string
+ muted?: boolean
+ hidden?: boolean
+ transform: Transform
+ opacity: number
+ }
+ export interface ImageElement extends BaseTimelineElement {
+ type: "image"
+ mediaId: string
+ hidden?: boolean
+ transform: Transform
+ opacity: number
+ }
+ export interface TextElement extends BaseTimelineElement {
+ type: "text"
+ content: string
+ fontSize: number
+ fontFamily: string
+ color: string
+ backgroundColor: string
+ textAlign: "left" | "center" | "right"
+ fontWeight: "normal" | "bold"
+ fontStyle: "normal" | "italic"
+ textDecoration: "none" | "underline" | "line-through"
+ hidden?: boolean
+ transform: Transform
+ opacity: number
+ }
+ export interface StickerElement extends BaseTimelineElement {
+ type: "sticker"
+ iconName: string
+ hidden?: boolean
+ transform: Transform
+ opacity: number
+ color?: string
+ }
+ export type TimelineElement = | AudioElement
+ | VideoElement
+ | ImageElement
+ | TextElement
+ | StickerElement
+ export type ElementType = TimelineElement["type"]
+ export type CreateUploadAudioElement = Omit<UploadAudioElement, "id">
+ export type CreateLibraryAudioElement = Omit<LibraryAudioElement, "id">
+ export type CreateAudioElement = | CreateUploadAudioElement
+ | CreateLibraryAudioElement
+ export type CreateVideoElement = Omit<VideoElement, "id">
+ export type CreateImageElement = Omit<ImageElement, "id">
+ export type CreateTextElement = Omit<TextElement, "id">
+ export type CreateStickerElement = Omit<StickerElement, "id">
+ export type CreateTimelineElement = | CreateAudioElement
+ | CreateVideoElement
+ | CreateImageElement
+ | CreateTextElement
+ | CreateSt...
+ export interface ElementDragState {
+ isDragging: boolean
+ elementId: string | null
+ trackId: string | null
+ startMouseX: number
+ startMouseY: number
+ startElementTime: number
+ clickOffsetTime: number
+ currentTime: number
+ currentMouseY: number
+ }
+ export interface DropTarget {
+ trackIndex: number
+ isNewTrack: boolean
+ insertPosition: "above" | "below" | null
+ xPosition: number
+ }
+ export interface ComputeDropTargetParams {
+ elementType: ElementType
+ mouseX: number
+ mouseY: number
+ tracks: TimelineTrack[]
+ playheadTime: number
+ isExternalDrop: boolean
+ elementDuration: number
+ pixelsPerSecond: number
+ zoomLevel: number
+ verticalDragDirection?: "up" | "down" | null
+ startTimeOverride?: number
+ excludeElementId?: string
+ }
+ export interface ClipboardItem {
+ trackId: string
+ trackType: TrackType
+ element: CreateTimelineElement
+ }
+
+transcription.ts
+ export type TranscriptionLanguage = LanguageCode | "auto"
+ export interface TranscriptionSegment {
+ text: string
+ start: number
+ end: number
+ }
+ export interface TranscriptionResult {
+ text: string
+ segments: TranscriptionSegment[]
+ language: string
+ }
+ export type TranscriptionStatus = | "idle"
+ | "loading-model"
+ | "transcribing"
+ | "complete"
+ | "error"
+ export interface TranscriptionProgress {
+ status: TranscriptionStatus
+ progress: number
+ message?: string
+ }
+ export type TranscriptionModelId = | "whisper-tiny"
+ | "whisper-small"
+ | "whisper-medium"
+ | "whisper-large-v3-turbo"
+ export interface TranscriptionModel {
+ id: TranscriptionModelId
+ name: string
+ huggingFaceId: string
+ description: string
+ }
+ export interface CaptionChunk {
+ text: string
+ startTime: number
+ duration: number
+ }
+
+## apps/web/src/utils
+
+browser.ts
+ export function isTypableDOMElement({
+ element,
+ }: {
+ element: HTMLElement;
+ }): boolean
+
+date.ts
+ export function formatDate({ date }: { date: Date }): string
+
+geometry.ts
+ export function dimensionToAspectRatio({
+ width,
+ height,
+ }: {
+ width: number;
+ height: number;
+ }): string
+
+id.ts
+ export function generateUUID(): string
+
+math.ts
+ export function clamp({
+ value,
+ min,
+ max,
+ }: {
+ value: number;
+ min: number;
+ max: number;
+ }): number
+
+platform.ts
+ export function getPlatformSpecialKey(): string
+ export function getPlatformAlternateKey(): string
+ export function isAppleDevice(): boolean
+
+string.ts
+ export function capitalizeFirstLetter({ string }: { string: string })
+ export function uppercase({ string }: { string: string })
+
+ui.ts
+ export function cn(...inputs: ClassValue[]): string
+
+## packages/ui/src/icons
+
+brand.tsx
+ export function OcVercelIcon({ className }: { className?: string })
+ export function OcMarbleIcon({
+ className = "",
+ size = 32,
+ }: {
+ className?: string;
+ size?: number;
+ })
+ export function OcDataBuddyIcon({
+ className = "",
+ size = 32,
+ }: {
+ className?: string;
+ size?: number;
+ })
+
+ui.tsx
+ export function OcVideoIcon({
+ className = "",
+ size = 32,
+ }: {
+ className?: string;
+ size?: number;
+ })
+
+```
+
+---
+
+*Generated and maintained by [Twiggy](https://github.com/twiggy-tools/Twiggy)*