{durationLabel ?? "—"}
From 6bad0d42cadb183c83f615f4787d1b96ba4114f7 Mon Sep 17 00:00:00 2001
From: Abelino Chavez
Date: Fri, 30 Jan 2026 20:40:54 -0600
Subject: [PATCH 03/10] feat: add file size validation for media uploads (#653)
Validates file sizes before processing media uploads:
- Image limit: 50MB
- Video limit: 500MB
- Audio limit: 100MB
Shows clear error messages with actual file size when exceeded.
Valid files still process even when some files are rejected.
Co-Authored-By: Claude Opus 4.5
---
.../editor/panels/assets/views/assets.tsx | 71 ++++++++++++++++++-
1 file changed, 70 insertions(+), 1 deletion(-)
diff --git a/apps/web/src/components/editor/panels/assets/views/assets.tsx b/apps/web/src/components/editor/panels/assets/views/assets.tsx
index 808961f1..55fabd8c 100644
--- a/apps/web/src/components/editor/panels/assets/views/assets.tsx
+++ b/apps/web/src/components/editor/panels/assets/views/assets.tsx
@@ -45,6 +45,45 @@ import {
} from "@hugeicons/core-free-icons";
import { HugeiconsIcon, type IconSvgElement } from "@hugeicons/react";
+// File size limits in bytes
+const FILE_SIZE_LIMITS = {
+ image: 50 * 1024 * 1024, // 50MB
+ video: 500 * 1024 * 1024, // 500MB
+ audio: 100 * 1024 * 1024, // 100MB
+} as const;
+
+function formatFileSize(bytes: number): string {
+ if (bytes < 1024) return `${bytes} B`;
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
+ if (bytes < 1024 * 1024 * 1024)
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
+ return `${(bytes / (1024 * 1024 * 1024)).toFixed(1)} GB`;
+}
+
+function getMediaTypeFromFile(file: File): "image" | "video" | "audio" | null {
+ if (file.type.startsWith("image/")) return "image";
+ if (file.type.startsWith("video/")) return "video";
+ if (file.type.startsWith("audio/")) return "audio";
+ return null;
+}
+
+function validateFileSize(file: File): { valid: boolean; error?: string } {
+ const mediaType = getMediaTypeFromFile(file);
+ if (!mediaType) {
+ return { valid: false, error: `Unsupported file type: ${file.type}` };
+ }
+
+ const limit = FILE_SIZE_LIMITS[mediaType];
+ if (file.size > limit) {
+ return {
+ valid: false,
+ error: `${file.name} (${formatFileSize(file.size)}) exceeds the ${formatFileSize(limit)} limit for ${mediaType} files`,
+ };
+ }
+
+ return { valid: true };
+}
+
export function MediaView() {
const editor = useEditor();
const mediaFiles = editor.media.getAssets();
@@ -71,11 +110,41 @@ export function MediaView() {
return;
}
+ // Validate file sizes before processing
+ const validFiles: File[] = [];
+ const errors: string[] = [];
+
+ for (const file of Array.from(files)) {
+ const validation = validateFileSize(file);
+ if (validation.valid) {
+ validFiles.push(file);
+ } else if (validation.error) {
+ errors.push(validation.error);
+ }
+ }
+
+ // Show errors for rejected files
+ for (const error of errors) {
+ toast.error(error);
+ }
+
+ // If no valid files, stop here
+ if (validFiles.length === 0) {
+ return;
+ }
+
+ // Create a new FileList-like object from valid files
+ const dataTransfer = new DataTransfer();
+ for (const file of validFiles) {
+ dataTransfer.items.add(file);
+ }
+ const validFileList = dataTransfer.files;
+
setIsProcessing(true);
setProgress(0);
try {
const processedAssets = await processMediaAssets({
- files,
+ files: validFileList,
onProgress: (progress: { progress: number }) =>
setProgress(progress.progress),
});
From 147f473fd3cb32fcc4057cec6f6b0d835173062f Mon Sep 17 00:00:00 2001
From: Abelino Chavez
Date: Fri, 30 Jan 2026 20:42:51 -0600
Subject: [PATCH 04/10] feat: add Ctrl+X cut shortcut for timeline elements
(#672)
Adds a "cut-selected" action that copies selected elements to
clipboard and then deletes them, enabling standard cut behavior.
Note: Drag/drop elements to other tracks was already implemented.
Co-Authored-By: Claude Opus 4.5
---
.../src/hooks/actions/use-editor-actions.ts | 27 +++++++++++++++++++
apps/web/src/lib/actions/definitions.ts | 5 ++++
2 files changed, 32 insertions(+)
diff --git a/apps/web/src/hooks/actions/use-editor-actions.ts b/apps/web/src/hooks/actions/use-editor-actions.ts
index 1ce890cb..abf54dd8 100644
--- a/apps/web/src/hooks/actions/use-editor-actions.ts
+++ b/apps/web/src/hooks/actions/use-editor-actions.ts
@@ -274,6 +274,33 @@ export function useEditorActions() {
undefined,
);
+ useActionHandler(
+ "cut-selected",
+ () => {
+ if (selectedElements.length === 0) return;
+
+ // Copy elements to clipboard
+ const results = editor.timeline.getElementsWithTracks({
+ elements: selectedElements,
+ });
+ const items = results.map(({ track, element }) => {
+ const { ...elementWithoutId } = element;
+ return {
+ trackId: track.id,
+ trackType: track.type,
+ element: elementWithoutId,
+ };
+ });
+ setClipboard({ items });
+
+ // Delete the selected elements
+ editor.timeline.deleteElements({
+ elements: selectedElements,
+ });
+ },
+ undefined,
+ );
+
useActionHandler(
"paste-copied",
() => {
diff --git a/apps/web/src/lib/actions/definitions.ts b/apps/web/src/lib/actions/definitions.ts
index 83144a25..bdcb685d 100644
--- a/apps/web/src/lib/actions/definitions.ts
+++ b/apps/web/src/lib/actions/definitions.ts
@@ -95,6 +95,11 @@ export const ACTIONS = {
category: "editing",
defaultShortcuts: ["ctrl+c"],
},
+ "cut-selected": {
+ description: "Cut selected elements",
+ category: "editing",
+ defaultShortcuts: ["ctrl+x"],
+ },
"paste-copied": {
description: "Paste elements at playhead",
category: "editing",
From de5293b02454c411f3a7513ce9f02b56aba425b0 Mon Sep 17 00:00:00 2001
From: Abelino Chavez
Date: Fri, 30 Jan 2026 20:44:26 -0600
Subject: [PATCH 05/10] feat: add dedicated About page (#624)
Creates a new /about page with:
- Project mission and vision
- Key features overview
- Open source information
- Community links
- Call to action
Updates footer to link to /about instead of GitHub README.
Co-Authored-By: Claude Opus 4.5
---
apps/web/src/app/about/page.tsx | 133 +++++++++++++++++++++++++++++
apps/web/src/components/footer.tsx | 2 +-
2 files changed, 134 insertions(+), 1 deletion(-)
create mode 100644 apps/web/src/app/about/page.tsx
diff --git a/apps/web/src/app/about/page.tsx b/apps/web/src/app/about/page.tsx
new file mode 100644
index 00000000..48ec4860
--- /dev/null
+++ b/apps/web/src/app/about/page.tsx
@@ -0,0 +1,133 @@
+import type { Metadata } from "next";
+import Link from "next/link";
+import { BasePage } from "@/app/base-page";
+import { Button } from "@/components/ui/button";
+import { SOCIAL_LINKS } from "@/constants/site-constants";
+import { ArrowRight } from "lucide-react";
+
+export const metadata: Metadata = {
+ title: "About - OpenCut",
+ description:
+ "OpenCut is a free, open-source video editor built for privacy and simplicity. Edit videos directly in your browser without uploading to servers.",
+ openGraph: {
+ title: "About - OpenCut",
+ description:
+ "OpenCut is a free, open-source video editor built for privacy and simplicity. Edit videos directly in your browser without uploading to servers.",
+ type: "website",
+ },
+};
+
+export default function AboutPage() {
+ return (
+
+
+
Our Mission
+
+ OpenCut was created to provide a powerful video editing experience
+ that doesn't compromise on privacy. We believe that editing your
+ videos should be simple, fast, and free from data collection.
+
+
+ Your videos stay on your device. No uploads to external servers for
+ basic editing. No tracking of your content. Just a clean, efficient
+ editor that works anywhere.
+
+
+
+
+
Key Features
+
+
+ Privacy-first: Basic editing happens entirely in
+ your browser - your files never leave your device
+
+
+ Multi-track timeline: Arrange video, audio, and
+ images across multiple tracks with precision
+
+
+ Real-time preview: See your edits instantly without
+ waiting for renders
+
+
+ Cross-platform: Works on any device with a modern
+ web browser
+
+
+ Open source: Fully transparent code you can audit,
+ modify, or self-host
+
+
+ Free forever: No subscriptions, no paywalls, no
+ hidden costs
+
+
+
+
+
+
Open Source
+
+ OpenCut is completely open source under the MIT license. This means
+ you can view, modify, and distribute the code freely. We believe in
+ transparency and community-driven development.
+
+
+ Our source code is available on GitHub, where you can report issues,
+ suggest features, or contribute code. Every contribution helps make
+ OpenCut better for everyone.
+
+
+
+
+ View on GitHub
+
+
+
+
+
+
+
+
Community
+
+ Join our growing community of creators, developers, and video editing
+ enthusiasts. Whether you need help, want to share your creations, or
+ are interested in contributing, we'd love to have you.
+