From 8e737d87e0accbf1d433f4c8b1e8e0f125849799 Mon Sep 17 00:00:00 2001 From: Kha Nguyen Date: Thu, 24 Jul 2025 17:04:27 -0500 Subject: Revert "merge main" This reverts commit 1ccacf6bb5db579cf6f343d9de57bce92d296f5f. --- apps/web/src/app/api/auth/[...all]/route.ts | 8 +- apps/web/src/app/api/waitlist/route.ts | 188 ++++---- apps/web/src/app/api/waitlist/token/route.ts | 23 +- apps/web/src/app/contributors/page.tsx | 554 +++++++++++------------ apps/web/src/app/metadata.ts | 21 +- apps/web/src/app/page.tsx | 8 - apps/web/src/app/privacy/page.tsx | 506 ++++++++++----------- apps/web/src/app/roadmap/page.tsx | 494 ++++++++++----------- apps/web/src/app/rss.xml/route.ts | 42 +- apps/web/src/app/terms/page.tsx | 634 +++++++++++++-------------- apps/web/src/app/why-not-capcut/page.tsx | 382 ++++++++-------- 11 files changed, 1412 insertions(+), 1448 deletions(-) (limited to 'apps/web/src/app') diff --git a/apps/web/src/app/api/auth/[...all]/route.ts b/apps/web/src/app/api/auth/[...all]/route.ts index 5deef204..55510dcb 100644 --- a/apps/web/src/app/api/auth/[...all]/route.ts +++ b/apps/web/src/app/api/auth/[...all]/route.ts @@ -1,4 +1,4 @@ -import { auth } from "@opencut/auth"; -import { toNextJsHandler } from "better-auth/next-js"; - -export const { POST, GET } = toNextJsHandler(auth); +import { auth } from "@opencut/auth"; +import { toNextJsHandler } from "better-auth/next-js"; + +export const { POST, GET } = toNextJsHandler(auth); \ No newline at end of file diff --git a/apps/web/src/app/api/waitlist/route.ts b/apps/web/src/app/api/waitlist/route.ts index 9f00f221..e5c9fd94 100644 --- a/apps/web/src/app/api/waitlist/route.ts +++ b/apps/web/src/app/api/waitlist/route.ts @@ -1,105 +1,83 @@ -import { NextRequest, NextResponse } from "next/server"; -import { db, eq, waitlist } from "@opencut/db"; -import { checkBotId } from "botid/server"; -import { nanoid } from "nanoid"; -import { waitlistRateLimit } from "@/lib/rate-limit"; -import { z } from "zod"; -import { env } from "@/env"; -import { cookies } from "next/headers"; -import crypto from "crypto"; - -const waitlistSchema = z.object({ - email: z.string().email("Invalid email format").min(1, "Email is required"), -}); - -const CSRF_TOKEN_NAME = "waitlist-csrf"; -const TOKEN_EXPIRY = 60 * 60 * 1000; - -async function validateCSRFToken(request: NextRequest): Promise { - const clientToken = request.headers.get("x-csrf-token"); - if (!clientToken) return false; - - const cookieStore = await cookies(); - const cookieValue = cookieStore.get(CSRF_TOKEN_NAME)?.value; - if (!cookieValue) return false; - - const [token, timestamp, signature] = cookieValue.split(":"); - if (!token || !timestamp || !signature) return false; - - if (clientToken !== token) return false; - - const now = Date.now(); - const tokenTime = parseInt(timestamp); - if (now - tokenTime > TOKEN_EXPIRY) return false; - - const expectedSignature = crypto - .createHmac("sha256", env.BETTER_AUTH_SECRET) - .update(`${token}:${timestamp}`) - .digest("hex"); - - return signature === expectedSignature; -} - -export async function POST(request: NextRequest) { - const verification = await checkBotId(); - - if (verification.isBot) { - return NextResponse.json({ error: "Access denied" }, { status: 403 }); - } - - const identifier = request.headers.get("x-forwarded-for") ?? "127.0.0.1"; - const { success } = await waitlistRateLimit.limit(identifier); - - if (!success) { - return NextResponse.json( - { error: "Too many requests. Please try again later." }, - { status: 429 } - ); - } - const isValidToken = await validateCSRFToken(request); - if (!isValidToken) { - return NextResponse.json( - { error: "Invalid security token" }, - { status: 403 } - ); - } - - try { - const body = await request.json(); - const { email } = waitlistSchema.parse(body); - - const existingEmail = await db - .select() - .from(waitlist) - .where(eq(waitlist.email, email.toLowerCase())) - .limit(1); - - if (existingEmail.length > 0) { - return NextResponse.json( - { error: "Email already registered" }, - { status: 409 } - ); - } - - await db.insert(waitlist).values({ - id: nanoid(), - email: email.toLowerCase(), - }); - - return NextResponse.json( - { message: "Successfully joined waitlist!" }, - { status: 201 } - ); - } catch (error) { - if (error instanceof z.ZodError) { - const firstError = error.errors[0]; - return NextResponse.json({ error: firstError.message }, { status: 400 }); - } - - console.error("Waitlist signup error:", error); - return NextResponse.json( - { error: "Internal server error" }, - { status: 500 } - ); - } -} +import { NextRequest, NextResponse } from "next/server"; +import { db, eq, waitlist } from "@opencut/db"; +import { checkBotId } from "botid/server"; +import { nanoid } from "nanoid"; +import { waitlistRateLimit } from "@/lib/rate-limit"; +import { z } from "zod"; +import { env } from "@/env"; +import { cookies } from "next/headers"; +import crypto from "crypto"; + +const waitlistSchema = z.object({ + email: z.string().email("Invalid email format").min(1, "Email is required"), +}); + +const CSRF_TOKEN_NAME = "waitlist-csrf"; +const TOKEN_EXPIRY = 60 * 60 * 1000; + +async function validateCSRFToken(request: NextRequest): Promise { + const clientToken = request.headers.get("x-csrf-token"); + if (!clientToken) return false; + + const cookieStore = await cookies(); + const cookieValue = cookieStore.get(CSRF_TOKEN_NAME)?.value; + if (!cookieValue) return false; + + const [token, timestamp, signature] = cookieValue.split(":"); + if (!token || !timestamp || !signature) return false; + + if (clientToken !== token) return false; + + const now = Date.now(); + const tokenTime = parseInt(timestamp); + if (now - tokenTime > TOKEN_EXPIRY) return false; + + const expectedSignature = crypto.createHmac("sha256", env.BETTER_AUTH_SECRET).update(`${token}:${timestamp}`).digest("hex"); + + return signature === expectedSignature; +} + +export async function POST(request: NextRequest) { + const verification = await checkBotId(); + + if (verification.isBot) { + return NextResponse.json({ error: "Access denied" }, { status: 403 }); + } + + const identifier = request.headers.get("x-forwarded-for") ?? "127.0.0.1"; + const { success } = await waitlistRateLimit.limit(identifier); + + if (!success) { + return NextResponse.json({ error: "Too many requests. Please try again later." }, { status: 429 }); + } + const isValidToken = await validateCSRFToken(request); + if (!isValidToken) { + return NextResponse.json({ error: "Invalid security token" }, { status: 403 }); + } + + try { + const body = await request.json(); + const { email } = waitlistSchema.parse(body); + + const existingEmail = await db.select().from(waitlist).where(eq(waitlist.email, email.toLowerCase())).limit(1); + + if (existingEmail.length > 0) { + return NextResponse.json({ error: "Email already registered" }, { status: 409 }); + } + + await db.insert(waitlist).values({ + id: nanoid(), + email: email.toLowerCase(), + }); + + return NextResponse.json({ message: "Successfully joined waitlist!" }, { status: 201 }); + } catch (error) { + if (error instanceof z.ZodError) { + const firstError = error.errors[0]; + return NextResponse.json({ error: firstError.message }, { status: 400 }); + } + + console.error("Waitlist signup error:", error); + return NextResponse.json({ error: "Internal server error" }, { status: 500 }); + } +} diff --git a/apps/web/src/app/api/waitlist/token/route.ts b/apps/web/src/app/api/waitlist/token/route.ts index fc2ff32c..4c7695fa 100644 --- a/apps/web/src/app/api/waitlist/token/route.ts +++ b/apps/web/src/app/api/waitlist/token/route.ts @@ -5,10 +5,7 @@ import { env } from "@/env"; const CSRF_TOKEN_NAME = "waitlist-csrf"; const TOKEN_EXPIRY = 60 * 60 * 1000; -const allowedHosts = - env.NODE_ENV === "development" - ? ["localhost:3000", "127.0.0.1:3000"] - : ["opencut.app", "www.opencut.app"]; +const allowedHosts = env.NODE_ENV === "development" ? ["localhost:3000", "127.0.0.1:3000"] : ["opencut.app", "www.opencut.app"]; export async function GET(request: NextRequest) { const referer = request.headers.get("referer"); @@ -17,20 +14,11 @@ export async function GET(request: NextRequest) { if (referer) { const refererUrl = new URL(referer); - if ( - !allowedHosts.some( - (allowed) => - refererUrl.host === allowed || refererUrl.host.endsWith(allowed) - ) - ) { + if (!allowedHosts.some((allowed) => refererUrl.host === allowed || refererUrl.host.endsWith(allowed))) { return NextResponse.json({ error: "Forbidden" }, { status: 403 }); } } else if (host) { - if ( - !allowedHosts.some( - (allowed) => host === allowed || host.endsWith(allowed) - ) - ) { + if (!allowedHosts.some((allowed) => host === allowed || host.endsWith(allowed))) { return NextResponse.json({ error: "Forbidden" }, { status: 403 }); } } else { @@ -43,10 +31,7 @@ export async function GET(request: NextRequest) { const token = crypto.randomBytes(32).toString("hex"); const timestamp = Date.now(); - const signature = crypto - .createHmac("sha256", env.BETTER_AUTH_SECRET) - .update(`${token}:${timestamp}`) - .digest("hex"); + const signature = crypto.createHmac("sha256", env.BETTER_AUTH_SECRET).update(`${token}:${timestamp}`).digest("hex"); const cookieStore = await cookies(); cookieStore.set(CSRF_TOKEN_NAME, `${token}:${timestamp}:${signature}`, { diff --git a/apps/web/src/app/contributors/page.tsx b/apps/web/src/app/contributors/page.tsx index 6a524866..5613f1f9 100644 --- a/apps/web/src/app/contributors/page.tsx +++ b/apps/web/src/app/contributors/page.tsx @@ -1,277 +1,277 @@ -import { Metadata } from "next"; -import { Header } from "@/components/header"; -import { Card, CardContent } from "@/components/ui/card"; -import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; -import { Button } from "@/components/ui/button"; -import { ExternalLink } from "lucide-react"; -import Link from "next/link"; -import { GithubIcon } from "@/components/icons"; -import { Badge } from "@/components/ui/badge"; - -export const metadata: Metadata = { - title: "Contributors - OpenCut", - description: - "Meet the amazing people who contribute to OpenCut, the free and open-source video editor.", - openGraph: { - title: "Contributors - OpenCut", - description: - "Meet the amazing people who contribute to OpenCut, the free and open-source video editor.", - type: "website", - }, -}; - -interface Contributor { - id: number; - login: string; - avatar_url: string; - html_url: string; - contributions: number; - type: string; -} - -async function getContributors(): Promise { - try { - const response = await fetch( - "https://api.github.com/repos/OpenCut-app/OpenCut/contributors?per_page=100", - { - headers: { - Accept: "application/vnd.github.v3+json", - "User-Agent": "OpenCut-Web-App", - }, - next: { revalidate: 600 }, // 10 minutes - } - ); - - if (!response.ok) { - console.error("Failed to fetch contributors"); - return []; - } - - const contributors = (await response.json()) as Contributor[]; - - const filteredContributors = contributors.filter( - (contributor: Contributor) => contributor.type === "User" - ); - - return filteredContributors; - } catch (error) { - console.error("Error fetching contributors:", error); - return []; - } -} - -export default async function ContributorsPage() { - const contributors = await getContributors(); - const topContributors = contributors.slice(0, 2); - const otherContributors = contributors.slice(2); - - return ( -
-
- -
-
-
-
-
- -
-
-
- - - - Open Source - - -

- Contributors -

-

- Meet the amazing developers who are building the future of video - editing -

- -
-
-
- {contributors.length} - contributors -
-
-
- - {contributors.reduce((sum, c) => sum + c.contributions, 0)} - - contributions -
-
-
- - {topContributors.length > 0 && ( -
-
-

- Top Contributors -

-

- Leading the way in contributions -

-
- -
- {topContributors.map((contributor, index) => ( - -
-
- - -
- - - - {contributor.login.charAt(0).toUpperCase()} - - -
-

- {contributor.login} -

-
- - {contributor.contributions} - - contributions -
-
-
-
- - ))} -
-
- )} - - {otherContributors.length > 0 && ( -
-
-

- All Contributors -

-

- Everyone who makes OpenCut better -

-
- -
- {otherContributors.map((contributor, index) => ( - -
- - - - {contributor.login.charAt(0).toUpperCase()} - - -

- {contributor.login} -

-

- {contributor.contributions} -

-
- - ))} -
-
- )} - - {contributors.length === 0 && ( -
-
- -
-

- No contributors found -

-

- Unable to load contributors at the moment. Check back later or - view on GitHub. -

- - - -
- )} - -
-
-

Join the community

-

- OpenCut is built by developers like you. Every contribution, - no matter how small, helps make video editing more accessible - for everyone. -

- -
- - - - - - -
-
-
-
-
-
-
- ); -} +import { Metadata } from "next"; +import { Header } from "@/components/header"; +import { Card, CardContent } from "@/components/ui/card"; +import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; +import { Button } from "@/components/ui/button"; +import { ExternalLink } from "lucide-react"; +import Link from "next/link"; +import { GithubIcon } from "@/components/icons"; +import { Badge } from "@/components/ui/badge"; + +export const metadata: Metadata = { + title: "Contributors - OpenCut", + description: + "Meet the amazing people who contribute to OpenCut, the free and open-source video editor.", + openGraph: { + title: "Contributors - OpenCut", + description: + "Meet the amazing people who contribute to OpenCut, the free and open-source video editor.", + type: "website", + }, +}; + +interface Contributor { + id: number; + login: string; + avatar_url: string; + html_url: string; + contributions: number; + type: string; +} + +async function getContributors(): Promise { + try { + const response = await fetch( + "https://api.github.com/repos/OpenCut-app/OpenCut/contributors?per_page=100", + { + headers: { + Accept: "application/vnd.github.v3+json", + "User-Agent": "OpenCut-Web-App", + }, + next: { revalidate: 600 }, // 10 minutes + } + ); + + if (!response.ok) { + console.error("Failed to fetch contributors"); + return []; + } + + const contributors = (await response.json()) as Contributor[]; + + const filteredContributors = contributors.filter( + (contributor: Contributor) => contributor.type === "User" + ); + + return filteredContributors; + } catch (error) { + console.error("Error fetching contributors:", error); + return []; + } +} + +export default async function ContributorsPage() { + const contributors = await getContributors(); + const topContributors = contributors.slice(0, 2); + const otherContributors = contributors.slice(2); + + return ( +
+
+ +
+
+
+
+
+ +
+
+
+ + + + Open Source + + +

+ Contributors +

+

+ Meet the amazing developers who are building the future of video + editing +

+ +
+
+
+ {contributors.length} + contributors +
+
+
+ + {contributors.reduce((sum, c) => sum + c.contributions, 0)} + + contributions +
+
+
+ + {topContributors.length > 0 && ( +
+
+

+ Top Contributors +

+

+ Leading the way in contributions +

+
+ +
+ {topContributors.map((contributor, index) => ( + +
+
+ + +
+ + + + {contributor.login.charAt(0).toUpperCase()} + + +
+

+ {contributor.login} +

+
+ + {contributor.contributions} + + contributions +
+
+
+
+ + ))} +
+
+ )} + + {otherContributors.length > 0 && ( +
+
+

+ All Contributors +

+

+ Everyone who makes OpenCut better +

+
+ +
+ {otherContributors.map((contributor, index) => ( + +
+ + + + {contributor.login.charAt(0).toUpperCase()} + + +

+ {contributor.login} +

+

+ {contributor.contributions} +

+
+ + ))} +
+
+ )} + + {contributors.length === 0 && ( +
+
+ +
+

+ No contributors found +

+

+ Unable to load contributors at the moment. Check back later or + view on GitHub. +

+ + + +
+ )} + +
+
+

Join the community

+

+ OpenCut is built by developers like you. Every contribution, + no matter how small, helps make video editing more accessible + for everyone. +

+ +
+ + + + + + +
+
+
+
+
+
+
+ ); +} diff --git a/apps/web/src/app/metadata.ts b/apps/web/src/app/metadata.ts index 0608974d..de8cf6f0 100644 --- a/apps/web/src/app/metadata.ts +++ b/apps/web/src/app/metadata.ts @@ -1,15 +1,24 @@ -import type { Metadata } from "next"; -import { SITE_INFO, SITE_URL } from "@/constants/site"; +import { Metadata } from "next"; + +export const SITE_INFO = { + title: "OpenCut", + description: + "A simple but powerful video editor that gets the job done. In your browser.", + url: "https://opencut.app", + openGraphImage: "https://opencut.app/open-graph/default.jpg", + twitterImage: "/open-graph/default.jpg", + favicon: "/favicon.ico", +}; export const baseMetaData: Metadata = { - metadataBase: new URL(SITE_URL), + metadataBase: new URL("https://opencut.app"), title: SITE_INFO.title, description: SITE_INFO.description, openGraph: { title: SITE_INFO.title, description: SITE_INFO.description, - url: SITE_URL, - siteName: SITE_INFO.title, + url: "https://opencut.app", + siteName: "OpenCut", locale: "en_US", type: "website", images: [ @@ -17,7 +26,7 @@ export const baseMetaData: Metadata = { url: SITE_INFO.openGraphImage, width: 1200, height: 630, - alt: "OpenCut Wordmark", + alt: "OpenCut", }, ], }, diff --git a/apps/web/src/app/page.tsx b/apps/web/src/app/page.tsx index 818884ed..74961549 100644 --- a/apps/web/src/app/page.tsx +++ b/apps/web/src/app/page.tsx @@ -1,14 +1,6 @@ import { Hero } from "@/components/landing/hero"; import { Header } from "@/components/header"; import { Footer } from "@/components/footer"; -import type { Metadata } from "next"; -import { SITE_URL } from "@/constants/site"; - -export const metadata: Metadata = { - alternates: { - canonical: SITE_URL, - }, -}; export default async function Home() { return ( diff --git a/apps/web/src/app/privacy/page.tsx b/apps/web/src/app/privacy/page.tsx index b7d700b5..42dd0f9a 100644 --- a/apps/web/src/app/privacy/page.tsx +++ b/apps/web/src/app/privacy/page.tsx @@ -1,253 +1,253 @@ -import { Metadata } from "next"; -import { Card, CardContent } from "@/components/ui/card"; -import { Badge } from "@/components/ui/badge"; -import { GithubIcon } from "@/components/icons"; -import Link from "next/link"; -import { Footer } from "@/components/footer"; -import { Header } from "@/components/header"; - -export const metadata: Metadata = { - title: "Privacy Policy - OpenCut", - description: - "Learn how OpenCut handles your data and privacy. Our commitment to protecting your information while you edit videos.", - openGraph: { - title: "Privacy Policy - OpenCut", - description: - "Learn how OpenCut handles your data and privacy. Our commitment to protecting your information while you edit videos.", - type: "website", - }, -}; - -export default function PrivacyPage() { - return ( -
-
-
-
-
-
-
-
-
-
- - - - Open Source - - -

- Privacy Policy -

-

- Learn how we handle your data and privacy. Contact us if you - have any questions. -

-
- - -
-

- Your Videos Stay Private -

-

- - OpenCut processes all videos locally on your device. - {" "} - We never upload, store, or have access to your video files. - Your content remains completely private and under your - control at all times. -

-

- All video editing, rendering, and processing happens in your - browser using WebAssembly and local storage. No video data - is transmitted to our servers. -

-
- -
-

- Account Information -

-

- When you create an account, we only collect: -

-
    -
  • Email address (for account access)
  • -
  • - Profile information from Google OAuth (if you choose to - sign in with Google) -
  • -
-

- - We do NOT store your projects on our servers. - {" "} - All project data, including names, thumbnails, and creation - dates, is stored locally in your browser using IndexedDB. -

-

- We use{" "} - - Better Auth - {" "} - for secure authentication and follow industry-standard - security practices. -

-
- -
-

Analytics

-

- We use{" "} - - Databuddy - {" "} - for completely anonymized and non-invasive analytics to - understand how people use OpenCut. -

-

- This helps us improve the editor, but we never collect - personal information, track individual users, or store any - data that could identify you. -

-
- -
-

- Local Storage & Cookies -

-

- We use browser local storage and IndexedDB to: -

-
    -
  • Save your projects locally on your device
  • -
  • Remember your editor preferences and settings
  • -
  • Keep you logged in across browser sessions
  • -
-

- All data stays on your device and can be cleared at any time - through your browser settings. -

-
- -
-

- Third-Party Services -

-

- OpenCut integrates with these services: -

-
    -
  • - Google OAuth: For optional Google sign-in - (governed by Google's privacy policy) -
  • -
  • - Vercel: For hosting and content delivery -
  • -
  • - Databuddy: For anonymized analytics -
  • -
-
- -
-

Your Rights

-

- You have complete control over your data: -

-
    -
  • - Delete your account and all associated data at any time -
  • -
  • Export your project data
  • -
  • Clear local storage to remove all saved projects
  • -
  • Contact us with any privacy concerns
  • -
-
- -
-

- Open Source Transparency -

-

- OpenCut is completely open source. You can review our code, - see exactly how we handle data, and even self-host the - application if you prefer. -

-

- View our source code on{" "} - - GitHub - - . -

-
- -
-

Contact Us

-

- Questions about this privacy policy or how we handle your - data? -

-

- Open an issue on our{" "} - - GitHub repository - - , email us at{" "} - - oss@opencut.app - - , or reach out on{" "} - - X (Twitter) - - . -

-
- -

- Last updated: July 14, 2025 -

-
-
-
-
-
-
-
- ); -} +import { Metadata } from "next"; +import { Card, CardContent } from "@/components/ui/card"; +import { Badge } from "@/components/ui/badge"; +import { GithubIcon } from "@/components/icons"; +import Link from "next/link"; +import { Footer } from "@/components/footer"; +import { Header } from "@/components/header"; + +export const metadata: Metadata = { + title: "Privacy Policy - OpenCut", + description: + "Learn how OpenCut handles your data and privacy. Our commitment to protecting your information while you edit videos.", + openGraph: { + title: "Privacy Policy - OpenCut", + description: + "Learn how OpenCut handles your data and privacy. Our commitment to protecting your information while you edit videos.", + type: "website", + }, +}; + +export default function PrivacyPage() { + return ( +
+
+
+
+
+
+
+
+
+
+ + + + Open Source + + +

+ Privacy Policy +

+

+ Learn how we handle your data and privacy. Contact us if you + have any questions. +

+
+ + +
+

+ Your Videos Stay Private +

+

+ + OpenCut processes all videos locally on your device. + {" "} + We never upload, store, or have access to your video files. + Your content remains completely private and under your + control at all times. +

+

+ All video editing, rendering, and processing happens in your + browser using WebAssembly and local storage. No video data + is transmitted to our servers. +

+
+ +
+

+ Account Information +

+

+ When you create an account, we only collect: +

+
    +
  • Email address (for account access)
  • +
  • + Profile information from Google OAuth (if you choose to + sign in with Google) +
  • +
+

+ + We do NOT store your projects on our servers. + {" "} + All project data, including names, thumbnails, and creation + dates, is stored locally in your browser using IndexedDB. +

+

+ We use{" "} + + Better Auth + {" "} + for secure authentication and follow industry-standard + security practices. +

+
+ +
+

Analytics

+

+ We use{" "} + + Databuddy + {" "} + for completely anonymized and non-invasive analytics to + understand how people use OpenCut. +

+

+ This helps us improve the editor, but we never collect + personal information, track individual users, or store any + data that could identify you. +

+
+ +
+

+ Local Storage & Cookies +

+

+ We use browser local storage and IndexedDB to: +

+
    +
  • Save your projects locally on your device
  • +
  • Remember your editor preferences and settings
  • +
  • Keep you logged in across browser sessions
  • +
+

+ All data stays on your device and can be cleared at any time + through your browser settings. +

+
+ +
+

+ Third-Party Services +

+

+ OpenCut integrates with these services: +

+
    +
  • + Google OAuth: For optional Google sign-in + (governed by Google's privacy policy) +
  • +
  • + Vercel: For hosting and content delivery +
  • +
  • + Databuddy: For anonymized analytics +
  • +
+
+ +
+

Your Rights

+

+ You have complete control over your data: +

+
    +
  • + Delete your account and all associated data at any time +
  • +
  • Export your project data
  • +
  • Clear local storage to remove all saved projects
  • +
  • Contact us with any privacy concerns
  • +
+
+ +
+

+ Open Source Transparency +

+

+ OpenCut is completely open source. You can review our code, + see exactly how we handle data, and even self-host the + application if you prefer. +

+

+ View our source code on{" "} + + GitHub + + . +

+
+ +
+

Contact Us

+

+ Questions about this privacy policy or how we handle your + data? +

+

+ Open an issue on our{" "} + + GitHub repository + + , email us at{" "} + + oss@opencut.app + + , or reach out on{" "} + + X (Twitter) + + . +

+
+ +

+ Last updated: July 14, 2025 +

+
+
+
+
+
+
+
+ ); +} diff --git a/apps/web/src/app/roadmap/page.tsx b/apps/web/src/app/roadmap/page.tsx index 5c003cf0..c62dce3a 100644 --- a/apps/web/src/app/roadmap/page.tsx +++ b/apps/web/src/app/roadmap/page.tsx @@ -1,247 +1,247 @@ -import { Metadata } from "next"; -import { Badge } from "@/components/ui/badge"; -import { GithubIcon } from "@/components/icons"; -import Link from "next/link"; -import { Footer } from "@/components/footer"; -import { Header } from "@/components/header"; -import ReactMarkdown from "react-markdown"; -import { cn } from "@/lib/utils"; - -const roadmapItems: { - title: string; - description: string; - status: { - text: string; - type: "complete" | "pending" | "default" | "info"; - }; -}[] = [ - { - title: "Start", - description: - "This is where it all started. Repository created, initial project structure, and the vision for a free, open-source video editor. [Check out the first tweet](https://x.com/mazeincoding/status/1936706642512388188) to see where it started.", - status: { - text: "Completed", - type: "complete", - }, - }, - { - title: "Core UI", - description: - "Built the foundation - main layout, header, sidebar, timeline container, and basic component structure. Not all functionality yet, but the UI framework that everything else builds on.", - status: { - text: "Completed", - type: "complete", - }, - }, - { - title: "Basic Functionality", - description: - "The heart of any video editor. Timeline zoom in/out, making clips longer/shorter, dragging elements around, selection, playhead scrubbing. **This part has to be fucking perfect** because it's what users interact with 99% of the time.", - status: { - text: "In Progress", - type: "pending", - }, - }, - { - title: "Export/Preview Logic", - description: - "The foundation that enables everything else. Real-time preview, video rendering, export functionality. Once this works, we can add effects, filters, transitions - basically everything that makes a video editor powerful.", - status: { - text: "In Progress", - type: "pending", - }, - }, - { - title: "Text", - description: - "After media, text is the next most important thing. Font selection with custom font imports, text stroke, colors. All the text essential text properties.", - status: { - text: "Not Started", - type: "default", - }, - }, - { - title: "Effects", - description: - "Adding visual effects to both text and media. Blur, brightness, contrast, saturation, filters, and all the creative tools that make videos pop. This is where the magic happens.", - status: { - text: "Not Started", - type: "default", - }, - }, - { - title: "Transitions", - description: - "Smooth transitions between clips. Fade in/out, slide, zoom, dissolve, and custom transition effects.", - status: { - text: "Not Started", - type: "default", - }, - }, - { - title: "Refine from Here", - description: - "Once we nail the above, we have a **solid foundation** to build anything. Advanced features, performance optimizations, mobile support, desktop app.", - status: { - text: "Future", - type: "info", - }, - }, -]; - -export const metadata: Metadata = { - title: "Roadmap - OpenCut", - description: - "See what's coming next for OpenCut - the free, open-source video editor that respects your privacy.", - openGraph: { - title: "OpenCut Roadmap - What's Coming Next", - description: - "See what's coming next for OpenCut - the free, open-source video editor that respects your privacy.", - type: "website", - images: [ - { - url: "/open-graph/roadmap.jpg", - width: 1200, - height: 630, - alt: "OpenCut Roadmap", - }, - ], - }, - twitter: { - card: "summary_large_image", - title: "OpenCut Roadmap - What's Coming Next", - description: - "See what's coming next for OpenCut - the free, open-source video editor that respects your privacy.", - images: ["/open-graph/roadmap.jpg"], - }, -}; - -export default function RoadmapPage() { - return ( -
-
-
-
-
-
-
-
-
-
- - - - Open Source - - -

- Roadmap -

-

- What's coming next for OpenCut (last updated: July 14, 2025) -

-
-
- {roadmapItems.map((item, index) => ( -
-
- - {index + 1}. - -
-
-

{item.title}

- - {item.status.text} - -
-
- ( - - {children} - - ), - strong: ({ children }) => ( - - {children} - - ), - }} - > - {item.description} - -
-
-
-
- ))} -
- -
-
-

Want to Help?

-

- OpenCut is open source and built by the community. Every - contribution, no matter how small, helps us build the best - free video editor possible. -

-
- - - - Start Contributing - - - - - Report Issues - - -
-
-
-
-
-
-
-
- ); -} +import { Metadata } from "next"; +import { Badge } from "@/components/ui/badge"; +import { GithubIcon } from "@/components/icons"; +import Link from "next/link"; +import { Footer } from "@/components/footer"; +import { Header } from "@/components/header"; +import ReactMarkdown from "react-markdown"; +import { cn } from "@/lib/utils"; + +const roadmapItems: { + title: string; + description: string; + status: { + text: string; + type: "complete" | "pending" | "default" | "info"; + }; +}[] = [ + { + title: "Start", + description: + "This is where it all started. Repository created, initial project structure, and the vision for a free, open-source video editor. [Check out the first tweet](https://x.com/mazeincoding/status/1936706642512388188) to see where it started.", + status: { + text: "Completed", + type: "complete", + }, + }, + { + title: "Core UI", + description: + "Built the foundation - main layout, header, sidebar, timeline container, and basic component structure. Not all functionality yet, but the UI framework that everything else builds on.", + status: { + text: "Completed", + type: "complete", + }, + }, + { + title: "Basic Functionality", + description: + "The heart of any video editor. Timeline zoom in/out, making clips longer/shorter, dragging elements around, selection, playhead scrubbing. **This part has to be fucking perfect** because it's what users interact with 99% of the time.", + status: { + text: "In Progress", + type: "pending", + }, + }, + { + title: "Export/Preview Logic", + description: + "The foundation that enables everything else. Real-time preview, video rendering, export functionality. Once this works, we can add effects, filters, transitions - basically everything that makes a video editor powerful.", + status: { + text: "In Progress", + type: "pending", + }, + }, + { + title: "Text", + description: + "After media, text is the next most important thing. Font selection with custom font imports, text stroke, colors. All the text essential text properties.", + status: { + text: "Not Started", + type: "default", + }, + }, + { + title: "Effects", + description: + "Adding visual effects to both text and media. Blur, brightness, contrast, saturation, filters, and all the creative tools that make videos pop. This is where the magic happens.", + status: { + text: "Not Started", + type: "default", + }, + }, + { + title: "Transitions", + description: + "Smooth transitions between clips. Fade in/out, slide, zoom, dissolve, and custom transition effects.", + status: { + text: "Not Started", + type: "default", + }, + }, + { + title: "Refine from Here", + description: + "Once we nail the above, we have a **solid foundation** to build anything. Advanced features, performance optimizations, mobile support, desktop app.", + status: { + text: "Future", + type: "info", + }, + }, +]; + +export const metadata: Metadata = { + title: "Roadmap - OpenCut", + description: + "See what's coming next for OpenCut - the free, open-source video editor that respects your privacy.", + openGraph: { + title: "OpenCut Roadmap - What's Coming Next", + description: + "See what's coming next for OpenCut - the free, open-source video editor that respects your privacy.", + type: "website", + images: [ + { + url: "/open-graph/roadmap.jpg", + width: 1200, + height: 630, + alt: "OpenCut Roadmap", + }, + ], + }, + twitter: { + card: "summary_large_image", + title: "OpenCut Roadmap - What's Coming Next", + description: + "See what's coming next for OpenCut - the free, open-source video editor that respects your privacy.", + images: ["/open-graph/roadmap.jpg"], + }, +}; + +export default function RoadmapPage() { + return ( +
+
+
+
+
+
+
+
+
+
+ + + + Open Source + + +

+ Roadmap +

+

+ What's coming next for OpenCut (last updated: July 14, 2025) +

+
+
+ {roadmapItems.map((item, index) => ( +
+
+ + {index + 1}. + +
+
+

{item.title}

+ + {item.status.text} + +
+
+ ( + + {children} + + ), + strong: ({ children }) => ( + + {children} + + ), + }} + > + {item.description} + +
+
+
+
+ ))} +
+ +
+
+

Want to Help?

+

+ OpenCut is open source and built by the community. Every + contribution, no matter how small, helps us build the best + free video editor possible. +

+
+ + + + Start Contributing + + + + + Report Issues + + +
+
+
+
+
+
+
+
+ ); +} diff --git a/apps/web/src/app/rss.xml/route.ts b/apps/web/src/app/rss.xml/route.ts index ab645655..b16bd856 100644 --- a/apps/web/src/app/rss.xml/route.ts +++ b/apps/web/src/app/rss.xml/route.ts @@ -1,33 +1,33 @@ -import { Feed } from "feed"; -import { getPosts } from "@/lib/blog-query"; -import { SITE_INFO, SITE_URL } from "@/constants/site"; +import { Feed } from 'feed'; +import { getPosts } from '@/lib/blog-query'; +import { SITE_INFO } from '../metadata'; export async function GET() { try { const { posts } = await getPosts(); - + const feed = new Feed({ - title: `${SITE_INFO.title} Blog`, + title: 'OpenCut Blog', description: SITE_INFO.description, - id: `${SITE_URL}`, - link: `${SITE_URL}/blog/`, - language: "en", + id: `${SITE_INFO.url}`, + link: `${SITE_INFO.url}/blog/`, + language: 'en', image: `${SITE_INFO.openGraphImage}`, favicon: `${SITE_INFO.favicon}`, copyright: `All rights reserved ${new Date().getFullYear()}, ${ SITE_INFO.title }`, }); - + for (const post of posts) { feed.addItem({ - title: post.title, - id: `${SITE_URL}/blog/${post.slug}`, - link: `${SITE_URL}/blog/${post.slug}`, - description: post.description, - author: post.authors.map((author) => ({ - name: author.name, - })), + title: post.title, + id: `${SITE_INFO.url}/blog/${post.slug}`, + link: `${SITE_INFO.url}/blog/${post.slug}`, + description: post.description, + author: post.authors.map((author) => ({ + name: author.name, + })), date: new Date(post.publishedAt), image: post.coverImage || SITE_INFO.openGraphImage, }); @@ -35,12 +35,12 @@ export async function GET() { return new Response(feed.rss2(), { headers: { - "Content-Type": "text/xml", - "Cache-Control": "public, max-age=86400, stale-while-revalidate", + 'Content-Type': 'text/xml', + 'Cache-Control': 'public, max-age=86400, stale-while-revalidate', }, }); } catch (error) { - console.error("Error generating RSS feed", error); - return new Response("Internal Server Error", { status: 500 }); + console.error('Error generating RSS feed', error); + return new Response('Internal Server Error', { status: 500 }); } -} +} \ No newline at end of file diff --git a/apps/web/src/app/terms/page.tsx b/apps/web/src/app/terms/page.tsx index 7d1fda7f..c56e8fc1 100644 --- a/apps/web/src/app/terms/page.tsx +++ b/apps/web/src/app/terms/page.tsx @@ -1,317 +1,317 @@ -import { Metadata } from "next"; -import { Card, CardContent } from "@/components/ui/card"; -import { Badge } from "@/components/ui/badge"; -import { GithubIcon } from "@/components/icons"; -import Link from "next/link"; -import { Footer } from "@/components/footer"; -import { Header } from "@/components/header"; - -export const metadata: Metadata = { - title: "Terms of Service - OpenCut", - description: - "OpenCut's Terms of Service. Fair, transparent terms for our free and open-source video editor.", - openGraph: { - title: "Terms of Service - OpenCut", - description: - "OpenCut's Terms of Service. Fair, transparent terms for our free and open-source video editor.", - type: "website", - }, -}; - -export default function TermsPage() { - return ( -
-
-
-
-
-
-
-
-
-
- - - - Open Source - - -

- Terms of Service -

-

- Fair and transparent terms for our free, open-source video - editor. -

-
- - -
-

- Welcome to OpenCut -

-

- OpenCut is a free, open-source video editor that runs in - your browser. By using our service, you agree to these - terms. We've designed these terms to be fair and protect - both you and our project. -

-

- Key principle: Your content stays on your - device. We never claim ownership of your videos or projects. -

-
- -
-

- Your Content, Your Rights -

-

- You own everything you create. OpenCut - processes your videos locally on your device, so we never - have access to your content. We make no claims to ownership, - licensing, or rights over your videos, projects, or any - content you create using OpenCut. -

-
    -
  • - Your videos remain completely private and under your - control -
  • -
  • - You retain all intellectual property rights to your - content -
  • -
  • - You can export and use your content however you choose -
  • -
  • - No watermarks, no licensing restrictions from OpenCut -
  • -
-
- -
-

- How You Can Use OpenCut -

-

- OpenCut is free for personal and commercial use. You can: -

-
    -
  • - Create videos for personal, educational, or commercial - purposes -
  • -
  • Use OpenCut for client work and paid projects
  • -
  • Share and distribute videos created with OpenCut
  • -
  • - Modify and distribute the OpenCut software (under MIT - license) -
  • -
-

- What we ask: Don't use OpenCut for illegal - activities, harassment, or creating harmful content. Be - respectful of others and follow applicable laws. -

-
- -
-

- Account and Service -

-

- To use certain features, you may create an account: -

-
    -
  • Provide accurate information when signing up
  • -
  • - Keep your account secure and don't share credentials -
  • -
  • You're responsible for activity under your account
  • -
  • You can delete your account at any time
  • -
-

- OpenCut is provided "as is" without warranties. While we - strive for reliability, we can't guarantee uninterrupted - service. -

-
- -
-

- Open Source Benefits -

-

- Because OpenCut is open source, you have additional rights: -

-
    -
  • - Review our code to see exactly how we handle your data -
  • -
  • Self-host OpenCut on your own servers
  • -
  • Modify the software to suit your needs
  • -
  • Contribute improvements back to the community
  • -
-

- View our source code and license on{" "} - - GitHub - - . -

-
- -
-

- Third-Party Content -

-

- When using OpenCut, make sure you have the right to use any - content you import: -

-
    -
  • - Only upload content you own or have permission to use -
  • -
  • - Respect copyright, trademarks, and other intellectual - property -
  • -
  • - Don't use copyrighted music, images, or videos without - permission -
  • -
  • - You're responsible for any claims related to your content -
  • -
-
- -
-

- Limitations and Liability -

-

- OpenCut is provided free of charge. To the extent permitted - by law: -

-
    -
  • We're not liable for any loss of data or content
  • -
  • - Projects are stored in your browser and may be lost if you - clear browser data -
  • -
  • We're not responsible for how you use the service
  • -
  • - Our liability is limited to the maximum extent allowed by - law -
  • -
-

- Since your content stays on your device, we have no way to - recover lost projects. Consider exporting important videos - when finished editing. -

-
- -
-

- Service Changes -

-

We may update OpenCut and these terms:

-
    -
  • - We'll notify you of significant changes to these terms -
  • -
  • Continued use means you accept any updates
  • -
  • - You can always self-host an older version if you prefer -
  • -
  • - Major changes will be discussed with the community on - GitHub -
  • -
-
- -
-

Termination

-

- You can stop using OpenCut at any time: -

-
    -
  • Delete your account through your profile settings
  • -
  • Clear your browser data to remove local projects
  • -
  • - Your content remains yours even if you stop using OpenCut -
  • -
  • - We may suspend accounts for violations of these terms -
  • -
-
- -
-

- Contact and Disputes -

-

- Questions about these terms or need to report an issue? -

-

- Contact us through our{" "} - - GitHub repository - - , email us at{" "} - - oss@opencut.app - - , or reach out on{" "} - - X (Twitter) - - . -

-

- These terms are governed by applicable law in your - jurisdiction. We prefer to resolve disputes through friendly - discussion in our open-source community. -

-
- -

- Last updated: July 14, 2025 -

-
-
-
-
-
-
-
- ); -} +import { Metadata } from "next"; +import { Card, CardContent } from "@/components/ui/card"; +import { Badge } from "@/components/ui/badge"; +import { GithubIcon } from "@/components/icons"; +import Link from "next/link"; +import { Footer } from "@/components/footer"; +import { Header } from "@/components/header"; + +export const metadata: Metadata = { + title: "Terms of Service - OpenCut", + description: + "OpenCut's Terms of Service. Fair, transparent terms for our free and open-source video editor.", + openGraph: { + title: "Terms of Service - OpenCut", + description: + "OpenCut's Terms of Service. Fair, transparent terms for our free and open-source video editor.", + type: "website", + }, +}; + +export default function TermsPage() { + return ( +
+
+
+
+
+
+
+
+
+
+ + + + Open Source + + +

+ Terms of Service +

+

+ Fair and transparent terms for our free, open-source video + editor. +

+
+ + +
+

+ Welcome to OpenCut +

+

+ OpenCut is a free, open-source video editor that runs in + your browser. By using our service, you agree to these + terms. We've designed these terms to be fair and protect + both you and our project. +

+

+ Key principle: Your content stays on your + device. We never claim ownership of your videos or projects. +

+
+ +
+

+ Your Content, Your Rights +

+

+ You own everything you create. OpenCut + processes your videos locally on your device, so we never + have access to your content. We make no claims to ownership, + licensing, or rights over your videos, projects, or any + content you create using OpenCut. +

+
    +
  • + Your videos remain completely private and under your + control +
  • +
  • + You retain all intellectual property rights to your + content +
  • +
  • + You can export and use your content however you choose +
  • +
  • + No watermarks, no licensing restrictions from OpenCut +
  • +
+
+ +
+

+ How You Can Use OpenCut +

+

+ OpenCut is free for personal and commercial use. You can: +

+
    +
  • + Create videos for personal, educational, or commercial + purposes +
  • +
  • Use OpenCut for client work and paid projects
  • +
  • Share and distribute videos created with OpenCut
  • +
  • + Modify and distribute the OpenCut software (under MIT + license) +
  • +
+

+ What we ask: Don't use OpenCut for illegal + activities, harassment, or creating harmful content. Be + respectful of others and follow applicable laws. +

+
+ +
+

+ Account and Service +

+

+ To use certain features, you may create an account: +

+
    +
  • Provide accurate information when signing up
  • +
  • + Keep your account secure and don't share credentials +
  • +
  • You're responsible for activity under your account
  • +
  • You can delete your account at any time
  • +
+

+ OpenCut is provided "as is" without warranties. While we + strive for reliability, we can't guarantee uninterrupted + service. +

+
+ +
+

+ Open Source Benefits +

+

+ Because OpenCut is open source, you have additional rights: +

+
    +
  • + Review our code to see exactly how we handle your data +
  • +
  • Self-host OpenCut on your own servers
  • +
  • Modify the software to suit your needs
  • +
  • Contribute improvements back to the community
  • +
+

+ View our source code and license on{" "} + + GitHub + + . +

+
+ +
+

+ Third-Party Content +

+

+ When using OpenCut, make sure you have the right to use any + content you import: +

+
    +
  • + Only upload content you own or have permission to use +
  • +
  • + Respect copyright, trademarks, and other intellectual + property +
  • +
  • + Don't use copyrighted music, images, or videos without + permission +
  • +
  • + You're responsible for any claims related to your content +
  • +
+
+ +
+

+ Limitations and Liability +

+

+ OpenCut is provided free of charge. To the extent permitted + by law: +

+
    +
  • We're not liable for any loss of data or content
  • +
  • + Projects are stored in your browser and may be lost if you + clear browser data +
  • +
  • We're not responsible for how you use the service
  • +
  • + Our liability is limited to the maximum extent allowed by + law +
  • +
+

+ Since your content stays on your device, we have no way to + recover lost projects. Consider exporting important videos + when finished editing. +

+
+ +
+

+ Service Changes +

+

We may update OpenCut and these terms:

+
    +
  • + We'll notify you of significant changes to these terms +
  • +
  • Continued use means you accept any updates
  • +
  • + You can always self-host an older version if you prefer +
  • +
  • + Major changes will be discussed with the community on + GitHub +
  • +
+
+ +
+

Termination

+

+ You can stop using OpenCut at any time: +

+
    +
  • Delete your account through your profile settings
  • +
  • Clear your browser data to remove local projects
  • +
  • + Your content remains yours even if you stop using OpenCut +
  • +
  • + We may suspend accounts for violations of these terms +
  • +
+
+ +
+

+ Contact and Disputes +

+

+ Questions about these terms or need to report an issue? +

+

+ Contact us through our{" "} + + GitHub repository + + , email us at{" "} + + oss@opencut.app + + , or reach out on{" "} + + X (Twitter) + + . +

+

+ These terms are governed by applicable law in your + jurisdiction. We prefer to resolve disputes through friendly + discussion in our open-source community. +

+
+ +

+ Last updated: July 14, 2025 +

+
+
+
+
+
+
+
+ ); +} diff --git a/apps/web/src/app/why-not-capcut/page.tsx b/apps/web/src/app/why-not-capcut/page.tsx index 7fe6df66..56b3d27a 100644 --- a/apps/web/src/app/why-not-capcut/page.tsx +++ b/apps/web/src/app/why-not-capcut/page.tsx @@ -1,191 +1,191 @@ -import { Header } from "@/components/header"; - -export default function WhyNotCapcut() { - return ( -
-
- -
-
-
-
-
- -
-
-
-

- Fuck CapCut -

-

- Roasting time, so get ready motherfucker. -

-
- -
-
-

- Seriously, what the fuck else do you want? -

-

- You probably use CapCut and think your video editing is - special. You think your fucking TikTok with 47 transitions and - 12 different fonts is going to get you some viral fame. You - think loading up every goddamn effect in their library makes - your content better. Wrong, motherfucker. Let me describe what - CapCut actually gives you: -

-
    -
  • A paywall every time you breathe
  • -
  • Terms of service that steal your shit
  • -
  • - More "Get Pro" dialogs than a Windows 95 error message -
  • -
  • - Features that disappear behind paywalls while you're fucking - using them -
  • -
  • Bugs disguised as "premium features"
  • -
-

- Well guess what, motherfucker: -

-

- You. Are. Getting. Scammed. Look at this shit. It's a fucking - video editor. Why the fuck do you need to pay $20/month just - to remove a goddamn watermark? You spent hours editing your - video and they slap their logo on it like they fucking made - it. -

-
- -
-

- The "Get Pro" dialog is everywhere -

-

- This motherfucking dialog pops up more than ads on a pirated - movie site. Want to add a transition? Get Pro. Want to export - without their watermark? Get Pro. Want to use more than 2 - fonts? Get fucking Pro, peasant. -

-

- Did you seriously think you could edit a video without seeing - this dialog 47 times? You click one button and BAM - there it - is again, asking for your credit card like a desperate ex - asking for money. -

-
- -
-

- Everything costs money now -

-

- You dumbass. You thought CapCut was free, but no. Free means - they let you open the app. Everything else costs money. Basic - shake effect? That'll be $20/month. A decent transition that - isn't "fade"? Pay up, motherfucker. -

-

- Here's my favorite piece of bullshit: You import an MP3 file - - you know, AUDIO - and try to export. "Sorry, can't export - because you're using our premium extract audio feature!" -

-

- - My MP3 was already fucking audio, you absolute morons. - -

-

- But wait, there's more! If you drag that same MP3 to their - media panel first, then to the timeline, it magically works. - This isn't a bug, it's a fucking scam disguised as software - engineering. -

-
- -
-

- Their Terms of Service are insane -

-

- Look at this shit. You upload your content and they basically - say "thanks for the free content, we own it now, but if Disney - sues anyone, that's your problem." -

-

- CapCut's Terms of Service: We get full rights - to use, modify, distribute, and monetize everything you upload - - permanently and without paying you shit. But you're still - responsible if anything goes wrong. -

-

- Translation: "We'll make money off your viral video, you - handle the lawsuits." Brilliant legal strategy, you fucks. -

-
- -
-

- The editor is actually good -

-

- Here's the thing that makes me want to punch my monitor: the - actual video editor is fucking good. It's intuitive, powerful, - and anyone can figure it out. When it's not begging for money - every 30 seconds, it actually works well. -

-

- Which makes everything else so much worse. They built - something people want to use, then turned it into a digital - slot machine. Every click might trigger a payment request. -

-
- -
-

- This is a video editor. Look at it. You've never seen one - before. -

-

- Like the person who's never used software that doesn't - constantly beg for money, you have no fucking idea what a - video editor should be. All you've ever seen are predatory - apps disguised as creative tools. -

-

- A real video editor lets you edit videos. It doesn't steal - your content. It doesn't pop up payment dialogs every 5 - seconds. It doesn't charge you separately for basic features - that should be free. -

-
- -
-

- Yes, this is fucking satire, you fuck -

-

- I'm not actually saying all video editors should be basic as - shit. What I'm saying is that all the problems we have with - video editing apps are{" "} - ones they create themselves. Video editors - aren't broken by default - they edit videos, export them, and - let you use basic features without constantly begging for - money. CapCut breaks them. They turn them into payment - processors with video editing as a side feature. -

-

- "Good software gets out of your way." -
- Some smart motherfucker who definitely wasn't working - at CapCut -

-
-
-
-
-
-
- ); -} +import { Header } from "@/components/header"; + +export default function WhyNotCapcut() { + return ( +
+
+ +
+
+
+
+
+ +
+
+
+

+ Fuck CapCut +

+

+ Roasting time, so get ready motherfucker. +

+
+ +
+
+

+ Seriously, what the fuck else do you want? +

+

+ You probably use CapCut and think your video editing is + special. You think your fucking TikTok with 47 transitions and + 12 different fonts is going to get you some viral fame. You + think loading up every goddamn effect in their library makes + your content better. Wrong, motherfucker. Let me describe what + CapCut actually gives you: +

+
    +
  • A paywall every time you breathe
  • +
  • Terms of service that steal your shit
  • +
  • + More "Get Pro" dialogs than a Windows 95 error message +
  • +
  • + Features that disappear behind paywalls while you're fucking + using them +
  • +
  • Bugs disguised as "premium features"
  • +
+

+ Well guess what, motherfucker: +

+

+ You. Are. Getting. Scammed. Look at this shit. It's a fucking + video editor. Why the fuck do you need to pay $20/month just + to remove a goddamn watermark? You spent hours editing your + video and they slap their logo on it like they fucking made + it. +

+
+ +
+

+ The "Get Pro" dialog is everywhere +

+

+ This motherfucking dialog pops up more than ads on a pirated + movie site. Want to add a transition? Get Pro. Want to export + without their watermark? Get Pro. Want to use more than 2 + fonts? Get fucking Pro, peasant. +

+

+ Did you seriously think you could edit a video without seeing + this dialog 47 times? You click one button and BAM - there it + is again, asking for your credit card like a desperate ex + asking for money. +

+
+ +
+

+ Everything costs money now +

+

+ You dumbass. You thought CapCut was free, but no. Free means + they let you open the app. Everything else costs money. Basic + shake effect? That'll be $20/month. A decent transition that isn't + "fade"? Pay up, motherfucker. +

+

+ Here's my favorite piece of bullshit: You import an MP3 file - + you know, AUDIO - and try to export. "Sorry, can't export + because you're using our premium extract audio feature!" +

+

+ + My MP3 was already fucking audio, you absolute morons. + +

+

+ But wait, there's more! If you drag that same MP3 to their + media panel first, then to the timeline, it magically works. + This isn't a bug, it's a fucking scam disguised as software + engineering. +

+
+ +
+

+ Their Terms of Service are insane +

+

+ Look at this shit. You upload your content and they basically + say "thanks for the free content, we own it now, but if Disney + sues anyone, that's your problem." +

+

+ CapCut's Terms of Service: We get full rights + to use, modify, distribute, and monetize everything you upload + - permanently and without paying you shit. But you're still + responsible if anything goes wrong. +

+

+ Translation: "We'll make money off your viral video, you + handle the lawsuits." Brilliant legal strategy, you fucks. +

+
+ +
+

+ The editor is actually good +

+

+ Here's the thing that makes me want to punch my monitor: the + actual video editor is fucking good. It's intuitive, powerful, + and anyone can figure it out. When it's not begging for money + every 30 seconds, it actually works well. +

+

+ Which makes everything else so much worse. They built + something people want to use, then turned it into a digital + slot machine. Every click might trigger a payment request. +

+
+ +
+

+ This is a video editor. Look at it. You've never seen one + before. +

+

+ Like the person who's never used software that doesn't + constantly beg for money, you have no fucking idea what a + video editor should be. All you've ever seen are predatory + apps disguised as creative tools. +

+

+ A real video editor lets you edit videos. It doesn't steal + your content. It doesn't pop up payment dialogs every 5 + seconds. It doesn't charge you separately for basic features + that should be free. +

+
+ +
+

+ Yes, this is fucking satire, you fuck +

+

+ I'm not actually saying all video editors should be basic as + shit. What I'm saying is that all the problems we have with + video editing apps are{" "} + ones they create themselves. Video editors + aren't broken by default - they edit videos, export them, and + let you use basic features without constantly begging for + money. CapCut breaks them. They turn them into payment + processors with video editing as a side feature. +

+

+ "Good software gets out of your way." +
- Some smart motherfucker who definitely wasn't working + at CapCut +

+
+
+
+
+
+
+ ); +} -- cgit v1.3.1