OpenScreen Project File Format: JSON Structure and Electron Persistence

OpenScreen persists projects as human-readable JSON documents using the .openscreen file extension, managed through Electron IPC handlers that serialize EditorProjectData objects via JSON.stringify and deserialize them with fs.readFile.

The OpenScreen project file format defines how the siddharthvaddem/openscreen video editor stores and retrieves editing sessions. Unlike binary formats, OpenScreen uses a schema-backed JSON structure that captures media references, timeline edits, and export settings in a portable text file.

OpenScreen Project File Structure

Every .openscreen file adheres to the EditorProjectData interface defined in src/components/video-editor/projectPersistence.ts (lines 55-60). The document contains three primary properties that preserve the complete editing context.

EditorProjectData Schema

The JSON structure follows this TypeScript shape:

  • version (number): The project format version, currently set to 2 via the PROJECT_VERSION constant (line 31 in projectPersistence.ts). This enables backward compatibility handling for legacy projects.
  • media (ProjectMedia, optional): References to source recordings including screenVideoPath (required) and optional webcamVideoPath for picture-in-picture layouts.
  • editor (ProjectEditorState): Comprehensive editor configuration including wallpaper paths, crop regions, zoom/trim/speed regions, annotation data, aspect ratio presets, and export quality settings.
  • videoPath (string, optional): Legacy field retained for migrating projects from earlier OpenScreen versions.

The human-readable structure means you can inspect project contents with any text editor, debug serialization issues, or generate projects programmatically.

How OpenScreen Persists Project Data

Persistence operates through Electron's main-renderer IPC layer, delegating file system operations to the main process while the renderer handles UI state.

Saving Projects via IPC

When triggering a save operation, the renderer invokes window.electronAPI.saveProjectFile(), which channels through the save-project-file handler in electron/ipc/handlers.ts (lines 71-84 and 93-108).

The handler performs three operations:

  1. Opens a native Save dialog restricted to the .openscreen extension
  2. Generates a safe filename if none provided
  3. Writes the payload using JSON.stringify(data, null, 2) to produce formatted, two-space indented JSON

This pretty-printing ensures the file remains human-readable and version-control friendly.

Loading Projects from Disk

Loading reverses the process through the load-project-file handler (lines 118-132 in electron/ipc/handlers.ts):

  1. Displays a native Open dialog filtering for .openscreen files
  2. Reads the selected file using Node.js fs.readFile
  3. Parses the JSON buffer and validates the resulting object against the expected EditorProjectData shape
  4. Returns the deserialized project to the renderer for state restoration

The electron/preload.ts file (lines 82-88) exposes these capabilities to the renderer via context-bridge isolation, ensuring secure communication between UI and file system.

Working with the .openscreen Format in Code

Creating Project Data

Generate compliant project objects using the factory function from projectPersistence.ts:

import { createProjectData, PROJECT_VERSION } from "@/components/video-editor/projectPersistence";
import type { ProjectMedia } from "@/lib/recordingSession";

const media: ProjectMedia = { 
  screenVideoPath: "/recordings/screen.webm",
  webcamVideoPath: "/recordings/webcam.webm" 
};

const editorState = {
  wallpaper: "/wallpapers/abstract.jpg",
  shadowIntensity: 0.5,
  showBlur: true,
  motionBlurAmount: 2,
  borderRadius: 12,
  padding: 40,
  cropRegion: { x: 0.1, y: 0.1, width: 0.8, height: 0.8 },
  zoomRegions: [{ startTime: 5, endTime: 10, scale: 1.5 }],
  trimRegions: [],
  speedRegions: [],
  annotationRegions: [],
  aspectRatio: "16:9",
  webcamLayoutPreset: "picture-in-picture",
  webcamPosition: { x: 0.8, y: 0.8 },
  exportQuality: "high",
  exportFormat: "mp4",
  gifFrameRate: 30,
  gifLoop: true,
  gifSizePreset: "large"
};

const project = createProjectData(media, editorState);

Source: createProjectData implementation in projectPersistence.ts (lines 87-95).

Saving from the Renderer

Trigger the native save dialog from React components:

const handleSave = async () => {
  const result = await window.electronAPI.saveProjectFile(project, "tutorial-project");
  if (result.success) {
    console.log("Saved to:", result.path);
  } else {
    console.error("Save failed:", result.message);
  }
};

Source: save-project-file handler in ipc/handlers.ts (lines 71-84).

Loading a Project

Restore editing sessions asynchronously:

const loadProject = async () => {
  const result = await window.electronAPI.loadProjectFile();
  if (result.success) {
    const loaded: EditorProjectData = result.project;
    // Restore media and editor state from loaded.version, loaded.media, loaded.editor
  } else {
    console.error("Load failed:", result.message);
  }
};

Source: load-project-file handler in ipc/handlers.ts (lines 118-132).

Example File Contents

A saved project.openscreen file contains formatted JSON:

{
  "version": 2,
  "media": {
    "screenVideoPath": "/recordings/screen.webm",
    "webcamVideoPath": "/recordings/webcam.webm"
  },
  "editor": {
    "wallpaper": "/wallpapers/abstract.jpg",
    "shadowIntensity": 0.5,
    "showBlur": true,
    "motionBlurAmount": 2,
    "borderRadius": 12,
    "padding": 40,
    "cropRegion": { "x": 0.1, "y": 0.1, "width": 0.8, "height": 0.8 },
    "zoomRegions": [{ "startTime": 5, "endTime": 10, "scale": 1.5 }],
    "trimRegions": [],
    "speedRegions": [],
    "annotationRegions": [],
    "aspectRatio": "16:9",
    "webcamLayoutPreset": "picture-in-picture",
    "webcamPosition": { "x": 0.8, "y": 0.8 },
    "exportQuality": "high",
    "exportFormat": "mp4",
    "gifFrameRate": 30,
    "gifLoop": true,
    "gifSizePreset": "large"
  }
}

Summary

  • OpenScreen project file format uses standard JSON with the .openscreen extension, defined by the EditorProjectData interface in projectPersistence.ts.
  • The current schema version is 2, tracked by the PROJECT_VERSION constant (line 31).
  • Persistence flows through Electron IPC: save-project-file writes via JSON.stringify(..., null, 2) while load-project-file reads using fs.readFile and JSON.parse.
  • The format stores media references separately from editor state, enabling non-destructive editing workflows.
  • Legacy projects containing the single videoPath field remain compatible through the optional schema property.

Frequently Asked Questions

What file extension does OpenScreen use?

OpenScreen uses the .openscreen extension to identify project files. The Electron save dialog automatically appends this extension, and the open dialog filters the file picker to show only .openscreen files, preventing accidental loading of unrelated JSON documents.

Is the OpenScreen project file format human-readable?

Yes. The format uses pretty-printed JSON with two-space indentation generated by JSON.stringify(data, null, 2). This allows developers and users to inspect project contents, debug media path issues, or manually edit configuration values using standard text editors.

What happens if I open an older project version?

The version property (currently 2) enables forward compatibility. When loading, the load-project-file handler in electron/ipc/handlers.ts (lines 118-132) parses the JSON and passes the object to the renderer, which can detect legacy versions (such as those using the single videoPath field instead of the media object) and migrate data accordingly.

Where is the project schema defined?

The TypeScript interfaces defining the OpenScreen project file format reside in src/components/video-editor/projectPersistence.ts. Key definitions include EditorProjectData (lines 55-60), ProjectMedia, and ProjectEditorState, while the actual file I/O logic implementing the persistence mechanism lives in electron/ipc/handlers.ts (lines 71-132).

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →