From fcfe612cd66c6c38c4ea27513dbcb9a70bd89c92 Mon Sep 17 00:00:00 2001 From: Maze Winther Date: Wed, 16 Jul 2025 17:36:47 +0200 Subject: [PATCH 01/15] fix: handlers component on mobile --- .../web/src/components/landing/handlebars.tsx | 48 +++++++++++++++++-- 1 file changed, 44 insertions(+), 4 deletions(-) diff --git a/apps/web/src/components/landing/handlebars.tsx b/apps/web/src/components/landing/handlebars.tsx index 36705e90..e2eb2573 100644 --- a/apps/web/src/components/landing/handlebars.tsx +++ b/apps/web/src/components/landing/handlebars.tsx @@ -19,6 +19,7 @@ export function Handlebars({ const [leftHandle, setLeftHandle] = useState(0); const [rightHandle, setRightHandle] = useState(maxWidth); const [contentWidth, setContentWidth] = useState(maxWidth); + const [isDragging, setIsDragging] = useState(false); const leftHandleX = useMotionValue(0); const rightHandleX = useMotionValue(maxWidth); @@ -33,6 +34,27 @@ export function Handlebars({ const containerRef = useRef(null); const measureRef = useRef(null); + // Prevent scroll when dragging on mobile + useEffect(() => { + const preventDefault = (e: TouchEvent) => { + if (isDragging) { + e.preventDefault(); + } + }; + + if (isDragging) { + document.addEventListener("touchmove", preventDefault, { + passive: false, + }); + document.body.style.overflow = "hidden"; + } + + return () => { + document.removeEventListener("touchmove", preventDefault); + document.body.style.overflow = ""; + }; + }, [isDragging]); + useEffect(() => { if (!measureRef.current) return; @@ -80,6 +102,14 @@ export function Handlebars({ setRightHandle(newRight); }; + const handleDragStart = () => { + setIsDragging(true); + }; + + const handleDragEnd = () => { + setIsDragging(false); + }; + return (
+ {/* Left Handle */}
+ {/* Right Handle */}
@@ -161,4 +201,4 @@ export function Handlebars({
); -}; +} From c1c4b114eb583489afdf1e49cf96197fbb10bca2 Mon Sep 17 00:00:00 2001 From: Maze Winther Date: Wed, 16 Jul 2025 17:38:29 +0200 Subject: [PATCH 02/15] fix: snapping for both directions (left/right) --- .../src/components/editor/timeline-track.tsx | 47 +++++++++++++++++-- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/apps/web/src/components/editor/timeline-track.tsx b/apps/web/src/components/editor/timeline-track.tsx index 2be143eb..9b94ee6d 100644 --- a/apps/web/src/components/editor/timeline-track.tsx +++ b/apps/web/src/components/editor/timeline-track.tsx @@ -54,7 +54,7 @@ export function TimelineTrackContent({ const { currentTime } = usePlaybackStore(); // Initialize snapping hook - const { snapElementPosition } = useTimelineSnapping({ + const { snapElementPosition, snapElementEdge } = useTimelineSnapping({ snapThreshold: 10, enableElementSnapping: snappingEnabled, enablePlayheadSnapping: snappingEnabled, @@ -103,15 +103,52 @@ export function TimelineTrackContent({ let finalTime = adjustedTime; let snapPoint = null; if (snappingEnabled) { - const snapResult = snapElementPosition( + // Find the element being dragged to get its duration + let elementDuration = 5; // fallback duration + if (dragState.elementId && dragState.trackId) { + const sourceTrack = tracks.find((t) => t.id === dragState.trackId); + const element = sourceTrack?.elements.find( + (e) => e.id === dragState.elementId + ); + if (element) { + elementDuration = + element.duration - element.trimStart - element.trimEnd; + } + } + + // Try snapping both start and end edges + const startSnapResult = snapElementEdge( adjustedTime, + elementDuration, tracks, currentTime, zoomLevel, - dragState.elementId || undefined + dragState.elementId || undefined, + true // snap to start edge ); - finalTime = snapResult.snappedTime; - snapPoint = snapResult.snapPoint; + + const endSnapResult = snapElementEdge( + adjustedTime, + elementDuration, + tracks, + currentTime, + zoomLevel, + dragState.elementId || undefined, + false // snap to end edge + ); + + // Choose the snap result with the smaller distance (closer snap) + let bestSnapResult = startSnapResult; + if ( + endSnapResult.snapPoint && + (!startSnapResult.snapPoint || + endSnapResult.snapDistance < startSnapResult.snapDistance) + ) { + bestSnapResult = endSnapResult; + } + + finalTime = bestSnapResult.snappedTime; + snapPoint = bestSnapResult.snapPoint; // Notify parent component about snap point change onSnapPointChange?.(snapPoint); From 218625b61a344e371688bbffc152ec3632615e46 Mon Sep 17 00:00:00 2001 From: Maze Winther Date: Wed, 16 Jul 2025 17:44:44 +0200 Subject: [PATCH 03/15] feat: advance snapping --- .../src/components/editor/timeline-track.tsx | 119 +++++++++++++----- 1 file changed, 91 insertions(+), 28 deletions(-) diff --git a/apps/web/src/components/editor/timeline-track.tsx b/apps/web/src/components/editor/timeline-track.tsx index 9b94ee6d..91b3ffa3 100644 --- a/apps/web/src/components/editor/timeline-track.tsx +++ b/apps/web/src/components/editor/timeline-track.tsx @@ -60,6 +60,53 @@ export function TimelineTrackContent({ enablePlayheadSnapping: snappingEnabled, }); + // Helper function for drop snapping that tries both edges + const getDropSnappedTime = ( + dropTime: number, + elementDuration: number, + excludeElementId?: string + ) => { + if (!snappingEnabled) { + // Use frame snapping if project has FPS, otherwise use decimal snapping + const projectStore = useProjectStore.getState(); + const projectFps = projectStore.activeProject?.fps || 30; + return snapTimeToFrame(dropTime, projectFps); + } + + // Try snapping both start and end edges for drops + const startSnapResult = snapElementEdge( + dropTime, + elementDuration, + tracks, + currentTime, + zoomLevel, + excludeElementId, + true // snap to start edge + ); + + const endSnapResult = snapElementEdge( + dropTime, + elementDuration, + tracks, + currentTime, + zoomLevel, + excludeElementId, + false // snap to end edge + ); + + // Choose the snap result with the smaller distance (closer snap) + let bestSnapResult = startSnapResult; + if ( + endSnapResult.snapPoint && + (!startSnapResult.snapPoint || + endSnapResult.snapDistance < startSnapResult.snapDistance) + ) { + bestSnapResult = endSnapResult; + } + + return bestSnapResult.snappedTime; + }; + const timelineRef = useRef(null); const [isDropping, setIsDropping] = useState(false); const [dropPosition, setDropPosition] = useState(null); @@ -427,9 +474,10 @@ export function TimelineTrackContent({ if (dragData.type === "text") { // Text elements have default duration of 5 seconds const newElementDuration = 5; - const projectStore = useProjectStore.getState(); - const projectFps = projectStore.activeProject?.fps || 30; - const snappedTime = snapTimeToFrame(dropTime, projectFps); + const snappedTime = getDropSnappedTime( + dropTime, + newElementDuration + ); const newElementEnd = snappedTime + newElementDuration; wouldOverlap = track.elements.some((existingElement) => { @@ -448,9 +496,10 @@ export function TimelineTrackContent({ ); if (mediaItem) { const newElementDuration = mediaItem.duration || 5; - const projectStore = useProjectStore.getState(); - const projectFps = projectStore.activeProject?.fps || 30; - const snappedTime = snapTimeToFrame(dropTime, projectFps); + const snappedTime = getDropSnappedTime( + dropTime, + newElementDuration + ); const newElementEnd = snappedTime + newElementDuration; wouldOverlap = track.elements.some((existingElement) => { @@ -490,9 +539,11 @@ export function TimelineTrackContent({ movingElement.duration - movingElement.trimStart - movingElement.trimEnd; - const projectStore = useProjectStore.getState(); - const projectFps = projectStore.activeProject?.fps || 30; - const snappedTime = snapTimeToFrame(dropTime, projectFps); + const snappedTime = getDropSnappedTime( + dropTime, + movingElementDuration, + elementId + ); const movingElementEnd = snappedTime + movingElementDuration; wouldOverlap = track.elements.some((existingElement) => { @@ -519,17 +570,15 @@ export function TimelineTrackContent({ if (wouldOverlap) { e.dataTransfer.dropEffect = "none"; setWouldOverlap(true); - const projectStore = useProjectStore.getState(); - const projectFps = projectStore.activeProject?.fps || 30; - setDropPosition(snapTimeToFrame(dropTime, projectFps)); + // Use default duration for position indicator + setDropPosition(getDropSnappedTime(dropTime, 5)); return; } e.dataTransfer.dropEffect = hasTimelineElement ? "move" : "copy"; setWouldOverlap(false); - const projectStore = useProjectStore.getState(); - const projectFps = projectStore.activeProject?.fps || 30; - setDropPosition(snapTimeToFrame(dropTime, projectFps)); + // Use default duration for position indicator + setDropPosition(getDropSnappedTime(dropTime, 5)); }; const handleTrackDragEnter = (e: React.DragEvent) => { @@ -651,18 +700,20 @@ export function TimelineTrackContent({ return; } - // Adjust position based on where user clicked on the element - const adjustedStartTime = snappedTime - clickOffsetTime; - const finalStartTime = Math.max( - 0, - snapTimeToFrame(adjustedStartTime, projectFps) - ); - // Check for overlaps with existing elements (excluding the moving element itself) const movingElementDuration = movingElement.duration - movingElement.trimStart - movingElement.trimEnd; + + // Adjust position based on where user clicked on the element + const adjustedStartTime = newStartTime - clickOffsetTime; + const snappedStartTime = getDropSnappedTime( + adjustedStartTime, + movingElementDuration, + elementId + ); + const finalStartTime = Math.max(0, snappedStartTime); const movingElementEnd = finalStartTime + movingElementDuration; const hasOverlap = track.elements.some((existingElement) => { @@ -748,7 +799,11 @@ export function TimelineTrackContent({ // Check for overlaps with existing elements in target track const newElementDuration = 5; // Default text duration - const newElementEnd = snappedTime + newElementDuration; + const textSnappedTime = getDropSnappedTime( + newStartTime, + newElementDuration + ); + const newElementEnd = textSnappedTime + newElementDuration; const hasOverlap = targetTrack.elements.some((existingElement) => { const existingStart = existingElement.startTime; @@ -759,7 +814,9 @@ export function TimelineTrackContent({ existingElement.trimEnd); // Check if elements overlap - return snappedTime < existingEnd && newElementEnd > existingStart; + return ( + textSnappedTime < existingEnd && newElementEnd > existingStart + ); }); if (hasOverlap) { @@ -774,7 +831,7 @@ export function TimelineTrackContent({ name: dragData.name || "Text", content: dragData.content || "Default Text", duration: TIMELINE_CONSTANTS.DEFAULT_TEXT_DURATION, - startTime: snappedTime, + startTime: textSnappedTime, trimStart: 0, trimEnd: 0, fontSize: 48, @@ -894,7 +951,11 @@ export function TimelineTrackContent({ // Check for overlaps with existing elements in target track const newElementDuration = mediaItem.duration || 5; - const newElementEnd = snappedTime + newElementDuration; + const mediaSnappedTime = getDropSnappedTime( + newStartTime, + newElementDuration + ); + const newElementEnd = mediaSnappedTime + newElementDuration; const hasOverlap = targetTrack.elements.some((existingElement) => { const existingStart = existingElement.startTime; @@ -905,7 +966,9 @@ export function TimelineTrackContent({ existingElement.trimEnd); // Check if elements overlap - return snappedTime < existingEnd && newElementEnd > existingStart; + return ( + mediaSnappedTime < existingEnd && newElementEnd > existingStart + ); }); if (hasOverlap) { @@ -920,7 +983,7 @@ export function TimelineTrackContent({ mediaId: mediaItem.id, name: mediaItem.name, duration: mediaItem.duration || 5, - startTime: snappedTime, + startTime: mediaSnappedTime, trimStart: 0, trimEnd: 0, }); From e419eba29bb2c6092a8c3d3866fbe46ee2937b23 Mon Sep 17 00:00:00 2001 From: Zaid-maker <53424436+Zaid-maker@users.noreply.github.com> Date: Wed, 16 Jul 2025 21:34:03 +0500 Subject: [PATCH 04/15] fix build by passing correct env --- .github/workflows/bun-ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/bun-ci.yml b/.github/workflows/bun-ci.yml index dbcf6f9c..1bd00ca5 100644 --- a/.github/workflows/bun-ci.yml +++ b/.github/workflows/bun-ci.yml @@ -23,6 +23,8 @@ jobs: env: DATABASE_URL: "postgresql://opencut:opencutthegoat@localhost:5432/opencut" + BETTER_AUTH_SECRET: "supersecret" + BETTER_AUTH_URL: "http://localhost:3000" steps: - name: Checkout repository From caf6fef3adb0425e3a89ca318136adc3e5f5d17c Mon Sep 17 00:00:00 2001 From: Sahil Sobhani Date: Wed, 16 Jul 2025 23:34:20 +0530 Subject: [PATCH 05/15] Redesigned the footer for mobile devices: UI Changes --- apps/web/.env.example | 15 --------------- apps/web/src/components/footer.tsx | 8 ++++---- 2 files changed, 4 insertions(+), 19 deletions(-) delete mode 100644 apps/web/.env.example diff --git a/apps/web/.env.example b/apps/web/.env.example deleted file mode 100644 index d63df851..00000000 --- a/apps/web/.env.example +++ /dev/null @@ -1,15 +0,0 @@ -# Environment Variables Example -# Copy this file to .env.local and update the values as needed - -DATABASE_URL="postgresql://opencut:opencutthegoat@localhost:5432/opencut" - -# Better Auth -NEXT_PUBLIC_BETTER_AUTH_URL=http://localhost:3000 -BETTER_AUTH_SECRET=your-secret-key-here - -# Development Environment -NODE_ENV=development - -# Redis -UPSTASH_REDIS_REST_URL=http://localhost:8079 -UPSTASH_REDIS_REST_TOKEN=example_token diff --git a/apps/web/src/components/footer.tsx b/apps/web/src/components/footer.tsx index 81505d4a..731aa2f7 100644 --- a/apps/web/src/components/footer.tsx +++ b/apps/web/src/components/footer.tsx @@ -34,15 +34,15 @@ export function Footer() {
{/* Brand Section */}
-
+
OpenCut OpenCut
-

+

The open source video editor that gets the job done. Simple, powerful, and works on any platform.

-
+
-
+

Resources

    From 04a10367701a804a4421051b1ff39ef5e09479c2 Mon Sep 17 00:00:00 2001 From: Sahil Sobhani Date: Wed, 16 Jul 2025 23:35:25 +0530 Subject: [PATCH 06/15] added .env.example --- apps/web/.env.example | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 apps/web/.env.example diff --git a/apps/web/.env.example b/apps/web/.env.example new file mode 100644 index 00000000..d63df851 --- /dev/null +++ b/apps/web/.env.example @@ -0,0 +1,15 @@ +# Environment Variables Example +# Copy this file to .env.local and update the values as needed + +DATABASE_URL="postgresql://opencut:opencutthegoat@localhost:5432/opencut" + +# Better Auth +NEXT_PUBLIC_BETTER_AUTH_URL=http://localhost:3000 +BETTER_AUTH_SECRET=your-secret-key-here + +# Development Environment +NODE_ENV=development + +# Redis +UPSTASH_REDIS_REST_URL=http://localhost:8079 +UPSTASH_REDIS_REST_TOKEN=example_token From 87dd275e573958af32412147378b73dcf988ed18 Mon Sep 17 00:00:00 2001 From: Maze Winther Date: Wed, 16 Jul 2025 21:05:28 +0200 Subject: [PATCH 07/15] fix: no more rounded corners in preview --- apps/web/src/components/editor/preview-panel.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/src/components/editor/preview-panel.tsx b/apps/web/src/components/editor/preview-panel.tsx index 894b6257..2ecee391 100644 --- a/apps/web/src/components/editor/preview-panel.tsx +++ b/apps/web/src/components/editor/preview-panel.tsx @@ -347,7 +347,7 @@ export function PreviewPanel() { {hasAnyElements ? (
    Date: Thu, 17 Jul 2025 00:28:35 +0500 Subject: [PATCH 08/15] fix typo --- .github/workflows/bun-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/bun-ci.yml b/.github/workflows/bun-ci.yml index 1bd00ca5..29a202b8 100644 --- a/.github/workflows/bun-ci.yml +++ b/.github/workflows/bun-ci.yml @@ -24,7 +24,7 @@ jobs: env: DATABASE_URL: "postgresql://opencut:opencutthegoat@localhost:5432/opencut" BETTER_AUTH_SECRET: "supersecret" - BETTER_AUTH_URL: "http://localhost:3000" + NEXT_PUBLIC_BETTER_AUTH_URL: "http://localhost:3000" steps: - name: Checkout repository From 2b618b189cca5830f314d9a773648e1c59c3c20e Mon Sep 17 00:00:00 2001 From: Zaid-maker <53424436+Zaid-maker@users.noreply.github.com> Date: Thu, 17 Jul 2025 01:10:49 +0500 Subject: [PATCH 09/15] more --- .github/workflows/bun-ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/bun-ci.yml b/.github/workflows/bun-ci.yml index 29a202b8..f01b9878 100644 --- a/.github/workflows/bun-ci.yml +++ b/.github/workflows/bun-ci.yml @@ -25,6 +25,8 @@ jobs: DATABASE_URL: "postgresql://opencut:opencutthegoat@localhost:5432/opencut" BETTER_AUTH_SECRET: "supersecret" NEXT_PUBLIC_BETTER_AUTH_URL: "http://localhost:3000" + UPSTASH_REDIS_REST_URL: "https://your-upstash-redis-url" + UPSTASH_REDIS_REST_TOKEN: "your-upstash-redis-token" steps: - name: Checkout repository From 4851c38e74ac93839a116c53687c48ef7ef52b54 Mon Sep 17 00:00:00 2001 From: Maze Winther Date: Wed, 16 Jul 2025 22:39:33 +0200 Subject: [PATCH 10/15] style(footer): align everything to left --- apps/web/src/components/footer.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/web/src/components/footer.tsx b/apps/web/src/components/footer.tsx index 731aa2f7..5b7f2303 100644 --- a/apps/web/src/components/footer.tsx +++ b/apps/web/src/components/footer.tsx @@ -34,15 +34,15 @@ export function Footer() {
    {/* Brand Section */}
    -
    +
    OpenCut OpenCut
    -

    +

    The open source video editor that gets the job done. Simple, powerful, and works on any platform.

    -
    +
    -
    +

    Resources

      @@ -129,7 +129,7 @@ export function Footer() {
    {/* Bottom Section */} -
    +
    © 2025 OpenCut, All Rights Reserved
    From 7d1f99c20ca60933984fe08ef83601248c6e0765 Mon Sep 17 00:00:00 2001 From: Maze Winther Date: Wed, 16 Jul 2025 22:49:10 +0200 Subject: [PATCH 11/15] fix --- apps/web/src/app/projects/page.tsx | 12 ++---------- apps/web/src/stores/project-store.ts | 11 ----------- 2 files changed, 2 insertions(+), 21 deletions(-) diff --git a/apps/web/src/app/projects/page.tsx b/apps/web/src/app/projects/page.tsx index 9fcb025b..499b999a 100644 --- a/apps/web/src/app/projects/page.tsx +++ b/apps/web/src/app/projects/page.tsx @@ -1,8 +1,7 @@ -"use client" -import { redirect } from "next/navigation"; +"use client"; import Link from "next/link"; -import React, { useState } from "react"; +import { useState } from "react"; import { Button } from "@/components/ui/button"; import { Card, CardContent } from "@/components/ui/card"; import { Checkbox } from "@/components/ui/checkbox"; @@ -29,15 +28,8 @@ import { useProjectStore } from "@/stores/project-store"; import { useRouter } from "next/navigation"; import { DeleteProjectDialog } from "@/components/delete-project-dialog"; import { RenameProjectDialog } from "@/components/rename-project-dialog"; -import { toast } from "sonner"; export default function ProjectsPage() { - - if (process.env.NODE_ENV !== "development") { - toast.error("You are not allowed to access this page"); - redirect("/"); - } - const { createNewProject, savedProjects, diff --git a/apps/web/src/stores/project-store.ts b/apps/web/src/stores/project-store.ts index 5017be2d..efb9cc71 100644 --- a/apps/web/src/stores/project-store.ts +++ b/apps/web/src/stores/project-store.ts @@ -5,7 +5,6 @@ import { toast } from "sonner"; import { useMediaStore } from "./media-store"; import { useTimelineStore } from "./timeline-store"; import { generateUUID } from "@/lib/utils"; -import { env } from "@/env"; interface ProjectStore { activeProject: TProject | null; @@ -37,16 +36,6 @@ export const useProjectStore = create((set, get) => ({ isInitialized: false, createNewProject: async (name: string) => { - try { - if (process.env.NODE_ENV !== "development") { - toast.error("Project creation is disabled outside development environment"); - throw new Error("Not allowed in production"); - } - } catch (error) { - toast.error("Failed to create new project"); - throw error; - } - const newProject: TProject = { id: generateUUID(), name, From 36516b874f86daee8dea5b559de4fda2a4c602fa Mon Sep 17 00:00:00 2001 From: Maze Winther Date: Wed, 16 Jul 2025 22:50:40 +0200 Subject: [PATCH 12/15] remove onboarding --- apps/web/src/app/editor/[project_id]/page.tsx | 6 ------ 1 file changed, 6 deletions(-) diff --git a/apps/web/src/app/editor/[project_id]/page.tsx b/apps/web/src/app/editor/[project_id]/page.tsx index 41bef8bd..aa5b7315 100644 --- a/apps/web/src/app/editor/[project_id]/page.tsx +++ b/apps/web/src/app/editor/[project_id]/page.tsx @@ -140,12 +140,6 @@ export default function Editor() {
    - { - setIsOnboardingOpen(false); - }} - /> ); } From a3c84e4a199add132340fb4f0a5e74e9062d5d5f Mon Sep 17 00:00:00 2001 From: Maze Winther Date: Wed, 16 Jul 2025 23:28:26 +0200 Subject: [PATCH 13/15] fix handlebars --- .../web/src/components/landing/handlebars.tsx | 48 ++----------------- 1 file changed, 4 insertions(+), 44 deletions(-) diff --git a/apps/web/src/components/landing/handlebars.tsx b/apps/web/src/components/landing/handlebars.tsx index e2eb2573..36705e90 100644 --- a/apps/web/src/components/landing/handlebars.tsx +++ b/apps/web/src/components/landing/handlebars.tsx @@ -19,7 +19,6 @@ export function Handlebars({ const [leftHandle, setLeftHandle] = useState(0); const [rightHandle, setRightHandle] = useState(maxWidth); const [contentWidth, setContentWidth] = useState(maxWidth); - const [isDragging, setIsDragging] = useState(false); const leftHandleX = useMotionValue(0); const rightHandleX = useMotionValue(maxWidth); @@ -34,27 +33,6 @@ export function Handlebars({ const containerRef = useRef(null); const measureRef = useRef(null); - // Prevent scroll when dragging on mobile - useEffect(() => { - const preventDefault = (e: TouchEvent) => { - if (isDragging) { - e.preventDefault(); - } - }; - - if (isDragging) { - document.addEventListener("touchmove", preventDefault, { - passive: false, - }); - document.body.style.overflow = "hidden"; - } - - return () => { - document.removeEventListener("touchmove", preventDefault); - document.body.style.overflow = ""; - }; - }, [isDragging]); - useEffect(() => { if (!measureRef.current) return; @@ -102,14 +80,6 @@ export function Handlebars({ setRightHandle(newRight); }; - const handleDragStart = () => { - setIsDragging(true); - }; - - const handleDragEnd = () => { - setIsDragging(false); - }; - return (
    - {/* Left Handle */}
    - {/* Right Handle */}
    @@ -201,4 +161,4 @@ export function Handlebars({
    ); -} +}; From 51857f1709e9aaf16efe7e9a12c1d2cf0bcc82c0 Mon Sep 17 00:00:00 2001 From: Maze Winther Date: Thu, 17 Jul 2025 11:50:28 +0200 Subject: [PATCH 14/15] docs: what to focus on section --- .github/CONTRIBUTING.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 995dbf19..77d7a6b6 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -15,6 +15,27 @@ Thank you for your interest in contributing to OpenCut! This document provides g > 1. Upgrade to a recent npm version (v9 or later), which has full workspace protocol support. > 2. Use an alternative package manager such as **bun** or **pnpm**. +## What to Focus On + +**🎯 Good Areas to Contribute:** +- Timeline functionality and UI improvements +- Project management features +- Performance optimizations +- Bug fixes in existing functionality +- UI/UX improvements +- Documentation and testing + +**⚠️ Areas to Avoid:** +- Preview panel enhancements (text fonts, stickers, effects) +- Export functionality improvements +- Preview rendering optimizations + +**Why?** We're currently planning a major refactor of the preview system. The current preview renders DOM elements (HTML), but we're moving to a binary rendering approach similar to CapCut. This new system will ensure consistency between preview and export, and provide much better performance and quality. + +The current HTML-based preview is essentially a prototype - the binary approach will be the "real deal." To avoid wasted effort, please focus on other areas of the application until this refactor is complete. + +If you're unsure whether your idea falls into the preview category, feel free to ask us [directly in discord](https://discord.gg/zmR9N35cjK) or create a GitHub issue! + ## Development Setup ### Prerequisites From 7d4cbca1190edc12ff9ae17029613b77b08436e0 Mon Sep 17 00:00:00 2001 From: Maze Winther Date: Thu, 17 Jul 2025 11:51:20 +0200 Subject: [PATCH 15/15] docs: README --- README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 9ce027f9..ad9a6d38 100644 --- a/README.md +++ b/README.md @@ -129,11 +129,13 @@ The application will be available at [http://localhost:3000](http://localhost:30 ## Contributing -**Note**: We're currently moving at an extremely fast pace with rapid development and breaking changes. While we appreciate the interest, it's recommended to wait until the project stabilizes before contributing to avoid conflicts and wasted effort. +We welcome contributions! While we're actively developing and refactoring certain areas, there are plenty of opportunities to contribute effectively. -## Visit [CONTRIBUTING.md](.github/CONTRIBUTING.md) +**🎯 Focus areas:** Timeline functionality, project management, performance, bug fixes, and UI improvements outside the preview panel. -We welcome contributions! Please see our [Contributing Guide](.github/CONTRIBUTING.md) for detailed setup instructions and development guidelines. +**⚠️ Avoid for now:** Preview panel enhancements (fonts, stickers, effects) and export functionality - we're refactoring these with a new binary rendering approach. + +See our [Contributing Guide](.github/CONTRIBUTING.md) for detailed setup instructions, development guidelines, and complete focus area guidance. **Quick start for contributors:**