Skip to content

Media Panel

The Media panel holds everything your project uses: imported files, compositions, folders and generated media. Import with the Import Media button in its header or by dropping files onto it, then drag items onto the Timeline; proxies for heavy video: Proxy System.

It has three views (Classic list, Icons and Board), folders, and a + Add menu for compositions, folders, live inputs and Gaussian splats. Text, solids, blank clips, 3D and motion layers are made on the timeline: right-click empty space on a video track → Add Layer.


The Source Monitor fits the complete still image into its viewport, preserving its original aspect ratio even when the composition is 16:9. Fit view resets source zoom and pan; the separate placement Fit command targets the timeline.

Canon .CR2 photos import through the normal file picker or drag and drop. The browser develops the full-resolution sensor image in a dedicated LibRaw WASM worker, applies the as-shot camera white balance, and creates an 8-bit sRGB PNG for thumbnails, source preview, timeline rendering, and export. Originals remain unchanged and are retained for project save/relink; reopening develops the RAW again. Decoding is serialized and its runtime PNG cache is limited to 128 MiB. This is a fixed RAW development, without interactive RAW exposure/white-balance controls or a 16-bit RAW grading pipeline. Other camera RAW extensions are not yet advertised. See Lens Correction for the Canon EF 24–105 mm profile dropdown and manual optical corrections.

Type Formats
Video MP4, WebM, MOV, AVI, MKV, WMV, M4V, FLV
Audio WAV, MP3, OGG, FLAC, AAC, M4A, WMA, AIFF, OPUS
Image PNG, JPG/JPEG, GIF, WebP, BMP, SVG
Vector Animation .lottie, .riv, Lottie JSON (.json, content-sniffed)
Premiere Pro project .prproj (gzip or plain Premiere XML)
Signal Assets CSV as table signals; any other unknown file as a binary signal

The panel also accepts a few specialized asset types that flow into the timeline as 3D clips:

  • model files: OBJ, glTF/GLB
  • gaussian-splat files: PLY, compressed PLY, SPLAT, KSPLAT, SPZ, SOG, LCC, and SOG-style ZIP payloads

Lottie and Rive imports are treated as first-class media items. .json files are accepted when their contents match Lottie structure.

Other files are routed through the universal Signal IR importer. Signal assets can be organized, renamed, labeled, deleted, saved, loaded, and dragged to video tracks. The timeline renderer dispatcher uses real 3D clip paths for renderable model and point-cloud artifacts, while data/document/binary signals use text-summary clips. Source signal metadata is preserved on every materialized clip.

Click the Import button in the panel header. Uses the File System Access API when available (Chrome/Edge) for native file picker with persistent handles, or falls back to a standard file input.

On touch-first devices, including Android and iPadOS/iOS, the visible Import control is bound directly to the native file input so the browser keeps the required user activation and opens it with one tap. Its media-only filter offers the system photo/video library instead of forcing the Files browser. MasterSelects receives only the photos or videos the user explicitly selects; the browser never gets unrestricted device-file access.

The + Add button in the header and the Add submenu of the right-click menu hold the same entries:

  • Composition: a new composition (the Composition Settings dialog opens first)
  • Folder: a new folder
  • Import files…: the same picker as the Import button
  • Live Input…: a camera, display or composition-feedback input
  • Import Gaussian Splat…: a splat file as a 3D item

Text, Solid and Blank Clip layers, and the 3D and Motion layers, are added on the timeline: right-click empty space on a video track → Add Layer. See Timeline and Text Clips.

Right-click a video, audio file, image, 3D model or Gaussian splat and choose Create Comp. The source starts at time zero in a new composition. Audio uses an audio track; visual media uses a video track. Source dimensions and duration are used when available, with the default composition size and a five-second duration otherwise. Existing compositions and live inputs also support Create Comp.

  • Drag files or folders from the OS anywhere over the open editor: a large blue overlay covers the workspace.
  • Drop outside the Timeline to import into Media and reveal the Media Panel. Drops inside the Media Panel preserve folder and Board placement.
  • Drop on the Timeline to place clips there using its existing track/position preview. MP3 and other audio files dragged from the desktop are recognized while hovering over an audio track. Internal clip and media drags keep their usual behavior.
  • Paste clipboard images or files with Ctrl+V while the Media Panel is hovered
  • Paste a copied video link (YouTube and other yt-dlp sites) with Ctrl+V to open the in-panel download dialog with thumbnail and resolution choices (Media Downloads)
  • Drag folders directly into the panel; nested folders are recreated inside the project
  • Multiple files supported
  • Attempts to acquire file handles via getAsFileSystemHandle for persistence
  • Uses directory-entry walking where needed
  • Falls back to standard File objects when handles are unavailable

Dropping or selecting a .prproj parses the project incrementally in a worker, then opens a sequence chooser before timeline data is created. The selected Premiere sequences become MasterSelects compositions inside one import folder. The importer preserves video/audio track layout, cuts, trims, clip speed, nested composition references, and static Motion/Opacity values. Video tracks are reversed into MasterSelects’ top-to-bottom compositing order.

Media already present in the current MasterSelects project is reused by normalized path and filename. Sources that cannot be identified uniquely are added as missing media with their Premiere path and flow through the normal Relink dialog.

Premiere-attached media remains a single Media Panel item with durable alternate source descriptions. If an original such as BRAW is offline but its attached ProRes .mov proxy is available, Auto can activate that linked proxy without pretending the original has been relinked. The timeline keeps the original composition-space dimensions while decoding the lower-resolution proxy, so Premiere’s proxy scaling is reproduced automatically.

Use Media Source in a video’s context menu to choose Auto, Original, or a specific Linked Proxy. Linked file handles are restored with the project, and the normal Relink scan can satisfy original and linked filenames independently. While an external linked proxy is active, MasterSelects does not generate another JPEG/WAV proxy from it. ProRes proxy thumbnails use the TurboRes decoder and the persistent thumbnail cache is reused across refreshes.

Media imports use a two-phase approach:

  1. Phase 1 (instant): A placeholder entry appears immediately in the panel with isImporting: true, showing file name and size
  2. Phase 2 (background): Full processing runs in the background:
    • Media info extraction (dimensions, duration, FPS, codec, bitrate, audio detection)
    • Gaussian-splat stats extraction (container, file size, per-file splat count, and sequence totals)
    • Thumbnail generation (for video and image files)
    • File hash calculation (for deduplication and proxy matching)
    • Copy to project RAW folder when copyMediaToProject is enabled, or when the import is forced; the setting is disabled by default
    • Existing proxy detection (by file hash)

The import placeholder reports staged progress instead of presenting an apparently frozen panel. Gaussian scene parsing is deferred until the native scene runtime needs it, then runs in a module worker with parser progress when workers are available. The native timeline path owns that one parse/upload lifecycle and does not also start the legacy renderer’s prewarm pass.

Deduplication: Files with matching name + size are automatically skipped.

Batch processing: When importing multiple files, up to 3 files are processed in parallel.

If a project-local Raw/ copy is created, that copy becomes the canonical source for the imported asset. The store promotes the copied handle, and reloads and exports use the project copy.

Besides the Copy media to project folder setting, a file is copied when its link would not survive a reload: it has no reopenable location (<input> picks), or the browser cannot store file handles (WebKit: Safari on iPhone, iPad and Mac). A notice shows the copied size and remaining browser storage, reports failed copies instead of dropping them silently, and offers to keep future imports linked (see Project Persistence).

How the copy is stored. In a project kept in browser storage or a folder (the repository), the picked File itself is handed to the project storage worker; the main thread never reads its bytes. The worker hashes it once (native SHA-256 up to 128 MB, a streaming hash above, so a multi-GB recording never needs a whole-file buffer), then reads, checks and writes it in 4 MB slices and confirms the write by the stored length on the same file. This length-only confirmation and the session trust apply to media copies into Raw/ only: a copy the worker wrote in the session is not re-read by later checks (saving its manifest, opening the copy, switching the media to it); they only confirm it is still there with its length, and the next session’s full verification catches byte damage. Every other artifact (proxies, thumbnails, transcripts, also in desktop folder projects) is still read back and re-hashed after its write and on every check. At most two whole-file hash or store jobs run in the worker at once; further ones wait for a slot, so several background copies never hold more than two file buffers. Before, the main thread hashed the file in JavaScript, sent it as 256 KB acknowledged messages and the copy was read back and re-hashed four times: a 30 MB phone recording took 8.2 s, now about 1.3 s (window.__MS_MEDIA_IMPORT__, copy_* phases).

Background copies. importFile(file, parent, { copyInBackground: true }) (all phone imports) resolves once metadata and thumbnail are ready; the media start on the original File with projectCopy: 'copying' (runtime only, never saved). The copy is announced in the copy notice while it runs and the page asks before it is left; a notice that ends with only successful background copies is cleared at once instead of showing Copied into project (isQuietProjectMediaCopyNotice), because that toast covered the Library rows and source-sheet controls tapped next. Durability copies, linked files and failures still show. The notice passes taps on its text through; only its buttons take them. When the copy is durable the media switch to the project copy: file, projectPath and the promoted handle, then the primary URL (created only after the switch is recorded; the old one is retired with its grace period, so playing elements rebuild from the new one). projectPath is a resolver field saved as the workspace view codec/resolvers/<media key>, not in a content revision; whatever content the switch changes is a background revision, never an Undo step, and Undo/Redo activation reads projectPath from the views, so a recorded switch survives them.

  • Waiting for the project. The switch waits instead of failing while the project refuses writes only for now: a multi-file phone import keeps one “Add media” batch open until every file is imported and placed, and that batch owns the media until it commits (ProjectTransactionCoordinator.isEntityOpen), and Undo/Redo activation or a handover refuses writes while it runs (isSwitching). Both notify the coordinator’s listeners when they end. Every other ownership refusal (a read-only tab, a failed storage worker, an editor out of sync with its project) lasts as long as the project is open: the switch fails, sets projectCopy: 'failed' and is reported in the notice instead of waiting forever.
  • Saved before it counts. The copy stays pending in the notice (status and unload guard on) until the project path is saved: the switch awaits flushEditorRepositoryViews, and a failed view write (for example a full browser storage right after a large copy) is reported as a failed copy.
  • Undo, Redo, delete, cancel. Media removed by Undo or a delete when the copy finishes leave the copy unused in the notice; if Undo/Redo brings them back without a project path, the switch is recorded then and their timeline clips, restored without a runtime file, are rebound to the copy (restoreLinkedTimelineMedia), so they play without a reload. A copy whose “Add media” batch was cancelled (its media never reached a committed revision) is unused and the wait ends.
  • Project switches. openEditorRepository and closeEditorRepository, which every open, create, duplicate, archive import and close goes through, first wait for all pending copies (projectSwitchCopyWait.ts) and show Finishing the copy into the current project with the files and bytes left on the blocking load screen. The bytes left come from the storage worker, which reports how far its hash and write passes read (request-progress messages, at most four a second; a file counts half when hashed and whole when written). The switch to the copy is therefore recorded in the project that imported the media, not dropped by the project change. The wait always has a way out: the caller’s Cancel (an archive import passes its AbortSignal) ends it with an AbortError and the copy keeps running in the open project; after 8 s the load screen offers Continue without it (desktop load toast and phone loading view, with the line “Media not copied yet must be picked again in this project”). Continuing reports each unfinished copy as Copy into project interrupted and goes on with the switch; the project’s media-copy/pending note stays, so reopening that project names the files again. A copy that never settles (storage that does not answer, a transaction that never ends) therefore cannot hold the editor on the load screen until a reload.
  • Killed tabs. Android never fires beforeunload for a discarded or swiped-away tab, and the media were saved before their copy was durable. A running copy is therefore noted in the project as the workspace view media-copy/pending (pendingProjectCopyMarker.ts) and removed once it settles. On the next open, media still noted that have no project path are reported as Copy into project interrupted (pick them again; re-picking the same file repairs them through the missing-source re-import), and the note is cleared. Only the tab that writes the project keeps, reads and clears the note. The workspace is shared by every tab of the browser, so a read-only tab of the same project sees the writer’s note while that copy is still running, and it neither reports nor clears it; the writer lock is released only after the writer’s copies finished, so a note the writer finds on open belongs to a page that closed.
  • Same names. Copies with the same requested Raw name run one after another (copyRepositoryRaw), so two different phone files both named video.mp4 land as video.mp4 and its hashed name, and identical bytes share one stored file. A compare-and-set lost to a writer outside that queue is checked once more before the copy fails.
  • Unused copies. A copy whose media were replaced meanwhile, whose import failed after the copy started (also on importFile’s replaced-placeholder path), or whose project closed changes nothing and is settled as unused (logged, not counted as copied); the file stays in Raw/ because identical bytes may be shared with other media.

Code: src/stores/mediaStore/slices/fileImport/backgroundProjectCopy.ts, tests backgroundProjectCopy, backgroundProjectCopyHistory, backgroundProjectCopyImportFile, projectSwitchPendingMediaCopies, projectSwitchContinueAction, projectMediaCopyStorage, repositoryRawNameRace. Desktop imports keep waiting for the copy as before.

Signal imports use the universal import orchestrator. CSV files emit table, metadata, and binary refs; unknown files emit binary and metadata refs. When a project is open, their binary artifacts are persisted content-addressed under Cache/artifacts/ and referenced from project.json. Without an open File System Access project, the same artifact store persists bytes in IndexedDB so SignalAssets are not metadata-only session objects.

When supported (Chrome/Edge):

  • Native file picker via showOpenFilePicker
  • Persistent file handles stored in IndexedDB
  • Path information preserved
  • Handles from drag-and-drop also captured when available
  • If the same media is also copied into the project Raw/ folder, that project copy is preferred on reload
Size Behavior
< 500MB Full thumbnails generated
> 500MB Thumbnail generation skipped

Solid and text items that older projects keep in their Solids and Text folders still work: drag them onto the timeline to make clips. New solids and texts are added on the timeline (right-click empty space on a video track → Add Layer); a solid item’s color opens in the Solid Settings dialog. See Text Clips.


The panel supports three view modes through the header mode control. The selected mode is persisted in localStorage. When Wooden media panel theme is enabled in Appearance settings, the Classic, Icons, Board, and Media generator tray chrome use the same wood/leather/brass skin family as the Audio Mixer; the setting defaults off and turning it off keeps the standard dark panel styling. Image and video-capable media items show a cursor-following preview tooltip only after the pointer rests on the item for 400ms; images use the existing thumbnail/image URL, while videos loop muted at 2x speed from their proxy or source URL. The tooltip fades in/out over 100ms.

  • Table layout with sortable, reorderable columns
  • Nested folder tree with expand/collapse arrows
  • Column headers for sorting and drag-to-reorder
  • Resizable name column (120px - 500px range, saved to localStorage)
  • Metadata columns keep a stable header set but show type-specific values. Audio files reuse the visual columns for waveform state, stem label, audio codec, and audio proxy state; still images show still/raster/image labels; Signal assets show signal kinds, provider, artifact count, file type, and diagnostics count.
  • Images the browser cannot decode (damaged, truncated, HEIC on an unsupported browser, revoked file access) are never silent: import, clip placement and the main preview image loader report through src/services/mediaRuntime/imageDecodeFailure.ts, which logs one explained ImageDecode warning per file (reusing describeImageLoadFailure), shows Cannot decode in the Resolution column, and marks timeline clips of that media with a red BROKEN badge. The flag is transient (not saved) and clears on the next successful decode, for example after relinking.
  • Thumbnail grid with file names below each item
  • Folder navigation via breadcrumb bar
  • Double-click folders to navigate into them
  • Breadcrumb shows full path from root, each segment is clickable
  • Hover tooltip shows detailed metadata (resolution, duration, codec, bitrate, file size)
  • Duration badge overlay on video and composition thumbnails
  • Item count badge on folder thumbnails
  • Board canvas grouped by Media Panel folders; every folder appears as a group, including empty folders
  • The root area contains top-level folders instead of rendering them beside root as separate peers
  • Mouse wheel zooms around the cursor; left-dragging the board, a node, or a folder group pans the board, with the background grid moving at a subtle parallax offset
  • Folder groups grow and shrink dynamically with their contents
  • Growing folder groups push sibling groups out of the way so board groups do not overlap
  • Double-clicking a folder group name starts inline rename for that folder
  • Items inside each folder wrap into dynamic rows sized from the media aspect ratio instead of fixed slots
  • Right-dragging nodes reorders the selected items in the target folder; nearby items make space during drag hover to preview the exact insertion point
  • Right-dragging a folder group moves the group and its contents as a spatial unit; nested folder groups move along with their parent folder
  • Folder groups accept dropped items and folders from the other Media Panel views, while drops outside the root area are ignored
  • Ctrl/right-drag starts a marquee selection; right-clicking opens the normal Media Panel context menu
  • Media, compositions, text, solids, meshes, cameras, lights, 3D effectors, math scenes, and motion shapes appear as board nodes with hover-only name and metadata overlays
  • Board annotations can be added from the Board context menu, then edited, resized, and stored locally
  • Video board nodes request missing thumbnails lazily like images, use a middle-frame thumbnail as the poster frame, and skim while hovered: horizontal mouse position maps to video time with a full-height white scrub indicator line like editor thumbnail scrubbing instead of always starting playback at 0:00; the board also loads a capped set of visible video nodes as poster fallbacks, including in the zoomed-out overview canvas mode, so missing or black cached thumbnails do not leave the board blank
  • Board zoom supports deep inspection up to 6400%; from 250% zoom upward, board UI text, badges, and metadata overlays counter-scale so they stop growing while media content keeps magnifying
  • At 400% zoom and higher, the image node closest to the viewport center is promoted from its thumbnail to the original source URL; other nodes stay on thumbnails so high-resolution files are lazy-loaded one at a time
  • During deep board zoom, the focused node’s existing name, metadata, and duration overlays stay visible and slide inward when their normal positions would run beyond the Media Panel edges; the collapsed Chat/Generate/Studio/Downloads launcher is hidden so it does not cover the inspected media
  • Board order, folder group offsets, and viewport are saved into the project UI state, with localStorage as the live-session fallback
  • Drag files or folders from the OS onto a group to import directly into that folder
  • OS file drops on the Board canvas place the imported top-level files at the drop point instead of waiting for auto-pack placement
  • Drag existing Media Panel items onto groups to move them between folders
  • Context-menu Add actions in Board view place new compositions, folders, live inputs and splats at the clicked canvas point
  • Cropped image results are placed beside their original Board node when the Board is open
  • Switching to or from Board view morphs folder groups from/to their Classic rows or Icons thumbnails using the same 500ms view transition as media items
  • The board uses the same + Add menu and context menu as Classic view; new folders appear immediately in Classic, Icons, and Board view
  • The Generate board action expands the Media Panel’s bottom-right AI generator tray; generated results still import through the normal Media Store path
  • A compact four-action launcher is available at the bottom right of the Media Panel without changing the current Classic, Icons, or Board view: Chat, Generate, Studio, and Downloads
  • Expanding the pill opens only the compact FlashBoard prompt composer: prompt field, model controls, ordered reference media cards, multi-shot controls, and the generate button
  • Studio opens the additional docked AI Studio; it does not replace or change the compact Generate flow
  • Chat mode has exactly two prompt paths, Auto and Story. Auto defaults to resumable Codex Direct in development and production, with Fast (the same Direct workflow on DeepSeek V4.1 Flash) as the other visible model choice; Story uses the same Chat button to start or reopen the docked preproduction workflow
  • The Story run is not duplicated inside Media: Media retains the single prompt input and chat history, while direction, treatment, sources, master looks, keyframes, progress, and review stay in Story
  • Image, video, and audio files can be referenced from Classic, Icons, or Board view by right-clicking and choosing Reference in AI Prompt; the same menu changes to Unreference from AI Prompt when all selected media are already linked
  • Dragging a media-panel image, video, or audio item onto the expanded prompt composer appends it to the ordered reference strip without moving it between folders
  • Queued and running generations appear above the prompt as compact preview cards with output type, status, elapsed timer, prompt, provider metadata, progress when available, and dismiss controls for failed/canceled jobs
  • Generation starts from Media, and results land back in the Media Pool under the normal AI Gen folders

Board pan and reorder previews use imperative CSS transforms and commit final order only on mouse-up/drop. This avoids re-rendering the Media Panel and writing localStorage on every pointer move, which keeps board interaction responsive while heavy preview scenes or splat renders are active.


Video thumbnails are generated per source media file, not per clip instance.

  • Generation runs at roughly 1 thumbnail per second of source media
  • Split and trimmed clips reuse the same source thumbnail set instead of regenerating thumbnails
  • Thumbnails are cached in IndexedDB and promoted into an in-memory URL cache on load
  • The cache can also be reused by file hash when the same source is imported again
  • Large files above the thumbnail threshold skip this generation path entirely

  1. + Add → Folder
  2. Or right-click → Add → Folder
  3. Folders are created expanded by default
  • Nested folders supported
  • Drag-and-drop items into folders (single or multi-select)
  • Expand/collapse tree view (list mode) or navigate into (grid mode)
  • Cycle detection prevents dropping a folder into itself or its descendants
  • Label colors assignable to folders
createFolder(name, parentId?) // Create folder (returns MediaFolder)
removeFolder(id) // Delete (reparents files, compositions, and Signal assets)
renameFolder(id, name) // Rename
toggleFolderExpanded(id) // Toggle expand/collapse
moveToFolder(itemIds[], folderId) // Move items (null = root)

Moving a folder into itself or one of its own subfolders would detach the whole branch from the tree, so moveToFolder refuses those folders with a logged warning and still moves the other items.


Deleting imported media files from the Media Panel performs a project-wide cleanup:

  • If the media is used by clips in any composition, a confirmation dialog reports that those clips will be removed from all compositions.
  • Project-local source files in Raw/ are deleted when no remaining media item references the same project path.
  • Derived project files are deleted: Proxy/ folders, Analysis/*.json, Transcripts/*.json, Cache/waveforms/*.waveform, Cache/thumbnails/*.jpg, gaussian-splat runtime caches, and referenced audio-analysis artifacts.
  • IndexedDB mirrors are cleaned up as well: media records, proxy frames, analysis cache, source thumbnails, thumbnails, file handles, and audio artifacts.
  • Hash-based artifacts such as proxies and thumbnails are preserved when another remaining media item still shares the same file hash.

  1. + Add → Composition
  2. The Composition Settings dialog opens before an empty composition is created.
  3. Width, height, frame rate, and duration can be confirmed or customized.
  4. Starts with two Video tracks and one Audio track.

Creating a composition from a media file is the exception: it uses the exact source dimensions and timing immediately, so no redundant settings dialog is shown.

Edit via right-click -> Composition Settings:

  • Width and height are free numeric values with a link toggle for changing both dimensions proportionally.
  • The shared landscape/portrait control swaps the dimensions without replacing the chosen resolution preset.
  • Resolution presets cover 720p, 1080p, 1440p, and 4K; custom dimensions remain editable directly.
  • Frame rate uses common presets plus a Custom numeric option.
  • Duration is freely editable in seconds.
  • The dialog uses the same soft liquid-glass IOR treatment as the mobile layer controls, including subtle background refraction.
  • Editing the active composition updates the preview crop live. Existing layers keep their visual size while normalized positions and position keyframes are adjusted to preserve their pixel offsets. Cancel restores the original composition settings and transforms.

The active composition’s frameRate is the playback/timeline source of truth: timeline ruler labels, dynamic preview target FPS diagnostics, and the Media Panel FPS column read this value. Export-panel FPS overrides are export-only.

createComposition(name, settings?) // Create with optional overrides
duplicateComposition(id, { name? }) // Deep copy, default name "Name Copy"
removeComposition(id) // Delete
updateComposition(id, updates) // Update settings
openCompositionTab(id, options?) // Edit in timeline (with animation)
closeCompositionTab(id) // Close tab
reorderCompositionTabs(from, to) // Drag to reorder tabs
setActiveComposition(id) // Switch active composition
getActiveComposition() // Get current composition
getOpenCompositions() // List open tabs

Duplicate (context menu or Ctrl+D), copy/paste, and the AI tool duplicateComposition share one store action:

  • Duplicating the active composition copies its live timeline. The stored timelineData of the active composition is only a mirror that the composition switch and the 30-second timeline autosave refresh, so the action serializes the live timeline (the same getSerializableState the switch and project save use) and refreshes the original’s mirror in the same write. While a timeline restore or project sync holds the store-sync guard it falls back to the stored timeline and logs a warning; the AI tool waits for the guard first.
  • The copy is a deep clone: editing it never changes the original. Clip, track, keyframe, effect, mask, and transition ids are kept because they are scoped per composition (the repository keys clips as clip:<compositionId>:<clipId>, and nested rendering derives runtime ids from the parent clip), so motion parents (parentClipId), linked clips, keyframes, text, motion-shape appearance stacks, composition graphs, and track visibility stay valid as is.
  • The compositions the source privately owns (transition compositions, their legacy backups, legacy caption compositions) are cloned for the copy and retargeted to it, so editing a transition in the copy leaves the original’s transition untouched. Nested user-visible compositions stay shared references.
  • Transition and caption compositions cannot be duplicated on their own; the action logs the reason and the AI tool returns it as an error.
  • Compositions open as tabs in the timeline
  • Creating a composition from the Media Panel opens it immediately in the timeline
  • Tab switching saves current timeline state and loads the new composition’s state
  • Animated transitions (exit/enter) when switching between compositions
  • Synced playhead when navigating into/out of nested compositions
  • Drag composition to timeline to create a nested comp clip
  • Double-click composition clip to navigate into it
  • Double-clicking a composition item outside its name opens that composition in the Timeline, even when no composition is currently open. Double-clicking the name itself remains the explicit rename gesture and does not open a preview or context menu.
  • Hovering a composition item can show a correctly aspect-fitted frame preview without changing the active Timeline composition.
  • Playhead position syncs between parent and nested compositions
  • Changes in nested comp reflect in parent timeline
  • H.265/HEVC MP4/MOV files use the shared adaptive decoder for import thumbnails, hover playback and the source monitor. See HEVC decoding.
  • Double-click a video or image file to open it in the source monitor
  • Double-clicking a completed AI Studio generation tile opens its imported media through the same Source Monitor path.
  • Image source monitor sessions include a CROP button. Applying a crop imports a new image beside the source, prefixed as CROP <original name>; in Board view the new node is placed beside the original node.
  • Locked-aspect image crop resizing keeps the opposite corner anchored while dragging a corner handle.
  • Sets sourceMonitorFileId in the store

Proxies require an open project (via projectFileService). For large video files:

  1. Right-click video -> Generate Proxy
  2. Proxy frames are generated and stored in the project folder
  • Video is decoded frame-by-frame using proxyGenerator
  • Frames are saved individually to the project’s proxy storage via projectFileService
  • Audio is extracted separately in the background (non-blocking)
  • Generation can be cancelled; partial proxies are preserved
  • Resumed automatically if a partial proxy exists on disk
FPS: min(30, source FPS) // 30 FPS fallback when source FPS is unavailable

A proxy is considered complete when >= 98% of expected frames are available:

frameCount >= Math.ceil(duration * PROXY_FPS) * 0.98
interface MediaFile {
proxyStatus: 'none' | 'generating' | 'ready' | 'error';
proxyProgress: number; // 0-100
proxyFrameCount?: number; // Total frames generated
proxyFps?: number; // At most 30; may match a lower source FPS
hasProxyAudio?: boolean; // Audio proxy extracted
}

Toggle proxy playback mode via proxyEnabled / toggleProxyEnabled():

  • When enabled, mutes all video elements in the timeline
  • Uses proxy frames instead of original video for playback
Badge Meaning
P (blue) Proxy ready
P (filling animation) + X% Generating, with progress

  • Click - Select single item
  • Ctrl/Cmd + Click - Toggle item in selection
  • Shift + Click - Add to selection
  • Click and drag on empty space in the item list to draw a selection rectangle
  • 4px movement threshold before marquee activates
  • Hold Ctrl/Cmd while marquee selecting to add to existing selection
  • Works in Classic and Icons view modes

16 AE-style label colors assignable to any item (files, folders, compositions, text, solids):

none, red, yellow, blue, green, purple, orange, pink, cyan, brown, lavender, peach, seafoam, fuchsia, tan, aqua

Click the label dot in the list view to open the color picker. When multiple items are selected, the color is applied to all selected items.


Right-click on items or empty space for context options. On touch devices, either long-press or double-tap opens the menu above the finger when viewport space permits. The first tap on a menu action is accepted immediately, and a press anywhere outside the menu closes it. Safari keeps these gestures active after project hydration and a page refresh without requiring a layout switch first.

  • Import Media…
  • New Composition
  • New Folder
  • New Text
  • New Solid
  • 3D submenu: Mesh (Cube, Sphere, Plane, Cylinder, Torus, Cone), 3D Text, Camera, Light, 3D Effector, Gaussian Splat
  • Live Input…, Motion Null, Adjustment Layer, Math Scene, Motion Shape
  • Reference in AI Prompt / Unreference from AI Prompt for selected image, video, and audio files
  • Rename (single selection only)
  • Download (single file selection, saves through the browser from the retained file/blob URL). If a stored source was moved or deleted, the download tries the retained URL and reports unavailable media when no fallback remains. Failed project/handle reads are caught and logged instead of escaping as an unhandled rejection.
  • Crop (single image selection, opens the source monitor directly in crop mode)
  • Create Comp (single video, audio, image, 3D model, splat, composition or supported live input; opens a new composition and places the source at time 0 on the matching track)
  • Extract First Frame / Extract Last Frame (single video selection, imports the extracted PNG beside the source media)
  • Move to Folder submenu (shows available folders + “Root”)
  • Delete (shows count for multi-selection)
  • Extract First Frame / Extract Last Frame imports a PNG still from the selected source video into the same Media Panel folder and selects it after import
  • Regenerate submenu: Proxy / Stop Proxy Generation (X%), Scene Cuts, Thumbnails, and (when audio is available) WAV Audio Proxy, Waveform, and Spectral
  • Media Source submenu: Auto / Original / attached Linked Source or Linked Proxy, plus the global Use MS Proxies toggle
  • Show in Explorer submenu:
    • Raw (downloads file if no native path)
    • Proxy (disabled if no proxy)
  • Set Proxy Folder…
  • Composition Settings… (opens settings dialog)
  • Solid Settings… (opens color/dimension editor)

The media list displays items in a table with the following columns:

Column Description Example
Name File name with AE-style file type icon Video.mp4
Label Colored dot indicator (clickable) colored circle
Duration Clip length (m:ss) 4:02
Resolution Width x Height, or splat count / sequence total for gaussian splats 1920x1080, 3f / 12.4M splats
FPS Frame rate (video) or composition frame rate 25
Container File container format MP4, MKV, WebM, PLY Seq
Codec Video codec or splat runtime family H.264, VP9, Splat Seq
Audio Has audio track? Yes / No
Bitrate Data rate 12.5 Mbps
Size File size 125.4 MB

Sortable Columns:

  • Click column header to sort ascending
  • Click again for descending
  • Click a third time to remove sort
  • Folders always sort separately (stay at top)

Reorderable Columns:

  • Drag column headers to rearrange order
  • Order is saved in localStorage (media-panel-column-order)

Resize Name Column:

  • Drag the vertical resize handle on the right edge of the Name column
  • Width range: 120px - 500px
  • Width saved in localStorage (media-panel-name-width)
Badge Meaning
P (blue) Proxy ready
P (filling) + % Proxy generating
T (green) Fully transcribed - click to open transcript
T (filling) Partially transcribed - shows coverage %
A (orange) Fully analyzed - click to open analysis
A (filling) Partially analyzed - shows coverage %

Clicking transcript or analysis badges selects the corresponding clip in the timeline and opens the clip properties panel.

interface MediaFile {
id: string;
name: string;
type: 'video' | 'audio' | 'image' | 'model' | 'gaussian-avatar' | 'gaussian-splat' | 'lottie' | 'rive';
file?: File; // Undefined when needs reload
url: string;
parentId: string | null;
createdAt: number;
duration?: number;
width?: number;
height?: number;
fps?: number; // Frame rate (video)
codec?: string; // H.264, VP9, AV1, ProRes, etc.
audioCodec?: string; // AAC, AC-3, Opus, etc.
container?: string; // MP4, MKV, WebM, etc.
fileSize?: number; // File size in bytes
bitrate?: number; // Bits per second
hasAudio?: boolean; // Whether video has audio tracks
splatCount?: number; // First/only gaussian-splat frame count
totalSplatCount?: number; // Sequence total, abbreviated in UI as K/M/B
splatFrameCount?: number; // Gaussian-splat sequence frame count
thumbnailUrl?: string;
fileHash?: string; // For dedup and proxy matching
labelColor?: LabelColor; // 16-color label system
isImporting?: boolean; // True during background import
// Proxy
proxyStatus?: ProxyStatus;
proxyProgress?: number;
proxyVideoUrl?: string; // URL to proxy video
proxyFrameCount?: number;
proxyFps?: number;
proxyFormat?: 'jpeg-sequence' | 'mp4-all-intra';
hasProxyAudio?: boolean;
audioProxyStatus?: ProxyStatus;
audioProxyProgress?: number;
waveformStatus?: 'idle' | 'generating' | 'ready' | 'skipped' | 'error';
sceneCutStatus?: SceneCutAnalysisStatus;
// Transcript
transcriptStatus?: TranscriptStatus;
transcript?: TranscriptWord[];
transcriptCoverage?: number;
transcribedRanges?: [number, number][]; // Time ranges that have been transcribed
// Analysis
analysisStatus?: AnalysisStatus;
analysisCoverage?: number;
vectorAnimation?: VectorAnimationMetadata;
// File System Access API
hasFileHandle?: boolean;
filePath?: string;
absolutePath?: string;
projectPath?: string; // Path within project RAW folder
}

  1. Select media in panel
  2. Drag to timeline with a mouse, or briefly hold and drag with touch
  3. Drop on appropriate track

Touch drags use the same internal external-drop bridge as desktop and guided drags. Track validation, non-overlap placement, linked video/audio creation, new-track zones, and the timeline drop preview therefore stay on the existing deterministic placement path instead of maintaining a separate mobile clip-creation path. The drag starts only after a deliberate 14 px movement, so small finger jitter remains available to the long-press context menu. A normal vertical panel scroll that starts before the short hold threshold cancels the touch drag, and list rows keep native vertical scrolling without exposing metadata columns during the hold. Classic-list touches are also excluded from dock panel-tab swiping, so a diagonal or edge-started list scroll is not cancelled by panel navigation.

Holding Shift while dragging a compatible Media Panel source over an existing clip switches the hover preview to source replacement. Dropping replaces only the clip source and keeps its timing, transforms, effects, masks, and keyframes. The media file’s shared object URL stays alive (the media panel, other clips and the undo of the replacement still use it); only URLs private to the clip are revoked. A lazily loaded video element that still streams the old media is rebuilt for the new one. The same replacement path is available from the Source section in the Transform tab by dropping a compatible source there.

Item Type Drag Payload Kind Data Transfer Key
Media file (video/image/lottie/rive) media-file application/x-media-file-id
Media file (audio) media-file (marked as audio) application/x-media-file-id
Composition composition application/x-composition-id
Text item text application/x-text-item-id
Solid item solid application/x-solid-item-id
Mesh item mesh application/x-mesh-item-id
Folder Internal move only (no timeline drop) —
  • Creates clip from media source
  • Uses actual media duration
  • Audio-only files restricted to audio tracks
  • Files still importing or missing cannot be dragged to timeline
  • Compositions cannot be dragged into themselves (active comp check)
  • Mesh items create 3D clips with is3D: true and meshType (rendered via the shared 3D scene)
  • Signal assets create timeline clips through renderer adapters: OBJ/glTF/GLB mesh or geometry artifacts become model clips, PLY/SPLAT-family point-cloud or geometry artifacts become gaussian-splat clips, and other Signal refs become text-summary clips.
Media Type Allowed Tracks
Video/Image/Lottie/Rive/Composition/Text/Solid/Mesh Video tracks only
Audio Audio tracks only

Media references are saved with the project file, while IndexedDB keeps the handle cache and other reload helpers:

  • File metadata (name, type, dimensions, duration, codec, etc.)
  • File handles (for reload on next session)
  • Folder structure
  • Media Panel view mode, Board viewport, Board folder group offsets, and Board slot order
  • Composition state with timeline data
  • Text, solid, mesh, camera, light, 3D-effector, math-scene, and motion-shape items saved in project data
  • When present, projectPath points at the copied Raw/<name> file and is used for automatic relinking

On project load:

  • Project-local Raw/ copies are tried first and become the canonical source when available
  • Media metadata restored from IndexedDB and project JSON
  • File handles used to restore file access when no Raw/ copy is available
  • Thumbnails restored from Cache/thumbnails by file hash
  • Existing proxies detected automatically
  • Existing transcripts and analysis data loaded from the project folder
  • Dead blob/object URLs are regenerated for available files
  • If a retained File object is still present, image/video thumbnails are rebuilt when needed after refresh
  • Project load is marked ready after relink and UI hydration; thumbnail, metadata, proxy, transcript, and analysis cache checks continue in an idle window so preview playback after refresh is not blocked by media-panel cache work.
  • Folder structure, expansion state, dock layout, and per-composition view state restored
  • Each media has a unique timestamp-based ID
  • Clips reference media by mediaFileId
  • Survives project reload
  • File hash used for proxy and thumbnail deduplication across reimports

When media files lose access (e.g., after browser restart):

  1. Automatic detection - Panel shows “Relink (N)” button when files need reload
  2. Relink dialog - Click the button to open the relink interface
  3. Files dimmed in list with no-file styling when unavailable

Files are reloaded in priority order:

  1. Project RAW folder - If the asset was copied into the project and the project is open
  2. Project folder scan - Recursively scans the opened project folder and all subfolders, keeping Raw/ matches first when duplicate names exist
  3. Stored file handle - Re-access the original file location, including permission re-checks

On project load and in the Relink dialog, missing files are matched case-insensitively by expected filenames. Recursive scans preserve relative subfolder paths and all duplicate basenames; path suffixes disambiguate matches such as Folder A/1.mp4 versus Folder B/1.mp4. A basename-only collision stays unresolved for manual selection instead of silently linking the wrong file. Sequence assets match their frame filenames (.glb, .ply, .splat) instead of the media-panel display name.

Premiere-linked sources participate in the same scan. Relinking an attached proxy stores it separately from the unavailable original, and source selection can switch between them without changing timeline clip identity or creating duplicate media items.

Importing a file (file input, drop, picker, or handle import) whose name matches a disconnected media item reconnects that item, and every disconnected duplicate of the same source, instead of adding another media entry. The normal relink validation (size and fingerprint) runs first; a file with different bytes is imported as new media. Items no clip currently uses count as disconnected here too. This covers files imported without a persistent browser handle, which go offline after a reload in projects without a project folder.

Double-clicking a file that has lost access triggers a single-file reload attempt with permission request.

State Appearance
File missing/needs reload Row dimmed, no-file class
File importing importing class with loading state
Proxy available Blue “P” badge

Dragging a board item into the timeline restores the board’s starting pan and zoom after edge auto-pan, keeping its layout and viewing position stable.

New compositions are selected and revealed automatically: Classic view scrolls to the item, Icons view opens its parent folder, and Board view centers it. This also applies to compositions created from an existing media item.

When a Board drop overlaps another item, both its placement preview and committed position use the nearest free grid position while respecting item size and folder bounds.

Dragging an existing Text, Camera, or Mesh media item onto the timeline preserves its saved text/font/color, camera optics/resolution, or mesh primitive/color respectively. Timeline copy/paste also preserves clip effects, keyframes, and node graphs. Editing a timeline instance does not save a reusable Media preset or write its changes back to the source media item.

The media store is split into modular slices:

Slice File Responsibility
fileImportSlice slices/fileImportSlice.ts Import via picker, drag-drop, handles
fileManageSlice slices/fileManageSlice.ts Remove, rename, reload files
compositionSlice slices/compositionSlice.ts CRUD, tabs, active composition switching
slotSlice slices/slotSlice.ts Resolume-style slot grid assignments
multiLayerSlice slices/multiLayerSlice.ts Multi-layer playback activation
folderSlice slices/folderSlice.ts Folder CRUD and expand/collapse
selectionSlice slices/selectionSlice.ts Selection, move-to-folder, label colors
duplicateSlice slices/duplicateSlice.ts Copy, paste, and duplicate Media Panel items
proxySlice slices/proxySlice.ts Proxy generation, cancellation, progress
projectSlice slices/projectSlice.ts Save, load, init from DB

Inline actions (in index.ts): item creation/removal and folder helpers for text, solids, meshes, cameras, lights, 3D effectors, math scenes, motion shapes, and live inputs; plus getItemsByFolder, getItemById, and getFileByName.

Boot Sequence: init.ts handles IndexedDB initialization, timeline restore from saved state, status synchronization, auto-save interval setup, beforeunload handler, and audio cleanup via disposeAllAudio().

Helper modules in helpers/:

Module Purpose
importPipeline.ts Unified import processing – orchestrates the two-phase import (placeholder then background processing)
mediaInfoHelpers.ts Codec detection, metadata extraction (uses mp4box for MP4 container parsing)
thumbnailHelpers.ts Thumbnail generation, deduplication by file hash, skip logic for large files
fileHashHelpers.ts File hash calculation for deduplication and proxy matching

Test File Tests Coverage
fileManageSlice.test.ts 121 Files, folders, solids, text items, selection, labels
compositionSlice.test.ts 113 Compositions

Run tests: npx vitest run



Source: src/components/panels/MediaPanel.tsx, src/components/panels/media/, src/stores/mediaStore/index.ts, src/stores/mediaStore/slices/

An import whose media item is removed or replaced while it runs (or that is cancelled) ends with an AbortError; it is logged as Import stopped: <file> at info level and not counted as an import failure. Only real failures log Import failed: <file> as an error.

Repeated import requests while the native file picker is open are ignored. Only the original request receives the selected files; cancellation and errors release the picker guard for the next request.