mirror of
https://github.com/OpenCut-app/OpenCut.git
synced 2026-07-13 21:52:53 +02:00
chore: normalize line endings
This commit is contained in:
@@ -1,2 +1,2 @@
|
||||
export const TIME_EPSILON_SECONDS = 1 / 1000;
|
||||
export const MIN_TRANSFORM_SCALE = 0.01;
|
||||
export const TIME_EPSILON_SECONDS = 1 / 1000;
|
||||
export const MIN_TRANSFORM_SCALE = 0.01;
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import type { ExportOptions } from "@/lib/export";
|
||||
|
||||
export const DEFAULT_EXPORT_OPTIONS = {
|
||||
format: "mp4",
|
||||
quality: "high",
|
||||
includeAudio: true,
|
||||
} satisfies ExportOptions;
|
||||
|
||||
export const EXPORT_MIME_TYPES = {
|
||||
webm: "video/webm",
|
||||
mp4: "video/mp4",
|
||||
} as const;
|
||||
import type { ExportOptions } from "@/lib/export";
|
||||
|
||||
export const DEFAULT_EXPORT_OPTIONS = {
|
||||
format: "mp4",
|
||||
quality: "high",
|
||||
includeAudio: true,
|
||||
} satisfies ExportOptions;
|
||||
|
||||
export const EXPORT_MIME_TYPES = {
|
||||
webm: "video/webm",
|
||||
mp4: "video/mp4",
|
||||
} as const;
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
export const SYSTEM_FONTS = new Set([
|
||||
"Arial",
|
||||
"Helvetica",
|
||||
"Times New Roman",
|
||||
"Courier New",
|
||||
"Verdana",
|
||||
"Georgia",
|
||||
"monospace",
|
||||
"sans-serif",
|
||||
"serif",
|
||||
]);
|
||||
export const SYSTEM_FONTS = new Set([
|
||||
"Arial",
|
||||
"Helvetica",
|
||||
"Times New Roman",
|
||||
"Courier New",
|
||||
"Verdana",
|
||||
"Georgia",
|
||||
"monospace",
|
||||
"sans-serif",
|
||||
"serif",
|
||||
]);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export const GRID_MIN = 1;
|
||||
export const GRID_MAX = 24;
|
||||
|
||||
export const DEFAULT_GRID_CONFIG = { rows: 3, cols: 3 } as const;
|
||||
export const GRID_MIN = 1;
|
||||
export const GRID_MAX = 24;
|
||||
|
||||
export const DEFAULT_GRID_CONFIG = { rows: 3, cols: 3 } as const;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export const MAX_FEATHER = 1000;
|
||||
export const FEATHER_HANDLE_SCALE = 0.11;
|
||||
export const DEFAULT_SHAPE_MASK_SHORT_SIDE_RATIO = 0.6;
|
||||
export const MIN_MASK_DIMENSION = 0.01;
|
||||
export const MAX_FEATHER = 1000;
|
||||
export const FEATHER_HANDLE_SCALE = 0.11;
|
||||
export const DEFAULT_SHAPE_MASK_SHORT_SIDE_RATIO = 0.6;
|
||||
export const MIN_MASK_DIMENSION = 0.01;
|
||||
|
||||
@@ -1,30 +1,30 @@
|
||||
export const DEFAULT_RETIME_RATE = 1;
|
||||
export const MIN_RETIME_RATE = 0.01;
|
||||
export const MAX_RETIME_RATE = 5;
|
||||
export const MAX_PITCH_PRESERVE_RATE = 10;
|
||||
|
||||
export function clampRetimeRate({ rate }: { rate: number }): number {
|
||||
if (!Number.isFinite(rate) || rate <= 0) {
|
||||
return DEFAULT_RETIME_RATE;
|
||||
}
|
||||
|
||||
return Math.min(Math.max(rate, MIN_RETIME_RATE), MAX_RETIME_RATE);
|
||||
}
|
||||
|
||||
export function canMaintainPitch({ rate }: { rate: number }): boolean {
|
||||
if (!Number.isFinite(rate) || rate <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return clampRetimeRate({ rate }) <= MAX_PITCH_PRESERVE_RATE;
|
||||
}
|
||||
|
||||
export function shouldMaintainPitch({
|
||||
rate,
|
||||
maintainPitch,
|
||||
}: {
|
||||
rate: number;
|
||||
maintainPitch?: boolean;
|
||||
}): boolean {
|
||||
return maintainPitch === true && canMaintainPitch({ rate });
|
||||
}
|
||||
export const DEFAULT_RETIME_RATE = 1;
|
||||
export const MIN_RETIME_RATE = 0.01;
|
||||
export const MAX_RETIME_RATE = 5;
|
||||
export const MAX_PITCH_PRESERVE_RATE = 10;
|
||||
|
||||
export function clampRetimeRate({ rate }: { rate: number }): number {
|
||||
if (!Number.isFinite(rate) || rate <= 0) {
|
||||
return DEFAULT_RETIME_RATE;
|
||||
}
|
||||
|
||||
return Math.min(Math.max(rate, MIN_RETIME_RATE), MAX_RETIME_RATE);
|
||||
}
|
||||
|
||||
export function canMaintainPitch({ rate }: { rate: number }): boolean {
|
||||
if (!Number.isFinite(rate) || rate <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return clampRetimeRate({ rate }) <= MAX_PITCH_PRESERVE_RATE;
|
||||
}
|
||||
|
||||
export function shouldMaintainPitch({
|
||||
rate,
|
||||
maintainPitch,
|
||||
}: {
|
||||
rate: number;
|
||||
maintainPitch?: boolean;
|
||||
}): boolean {
|
||||
return maintainPitch === true && canMaintainPitch({ rate });
|
||||
}
|
||||
|
||||
@@ -1,69 +1,69 @@
|
||||
import { OcDataBuddyIcon, OcMarbleIcon } from "@opencut/ui/icons";
|
||||
|
||||
export const SITE_URL = "https://opencut.app";
|
||||
|
||||
export const SITE_INFO = {
|
||||
title: "OpenCut",
|
||||
description:
|
||||
"A simple but powerful video editor that gets the job done. In your browser.",
|
||||
url: SITE_URL,
|
||||
openGraphImage: "/open-graph/default.jpg",
|
||||
twitterImage: "/open-graph/default.jpg",
|
||||
favicon: "/favicon.ico",
|
||||
};
|
||||
|
||||
export type ExternalTool = {
|
||||
name: string;
|
||||
description: string;
|
||||
url: string;
|
||||
icon: React.ElementType;
|
||||
};
|
||||
|
||||
export const EXTERNAL_TOOLS: ExternalTool[] = [
|
||||
{
|
||||
name: "Marble",
|
||||
description:
|
||||
"Modern headless CMS for content management and the blog for OpenCut",
|
||||
url: "https://marblecms.com?utm_source=opencut",
|
||||
icon: OcMarbleIcon,
|
||||
},
|
||||
{
|
||||
name: "Databuddy",
|
||||
description: "GDPR compliant analytics and user insights for OpenCut",
|
||||
url: "https://databuddy.cc?utm_source=opencut",
|
||||
icon: OcDataBuddyIcon,
|
||||
},
|
||||
];
|
||||
|
||||
export const DEFAULT_LOGO_URL = "/logos/opencut/svg/logo.svg";
|
||||
|
||||
export const SOCIAL_LINKS = {
|
||||
x: "https://x.com/opencutapp",
|
||||
github: "https://github.com/OpenCut-app/OpenCut",
|
||||
discord: "https://discord.com/invite/Mu3acKZvCp",
|
||||
};
|
||||
|
||||
export type Sponsor = {
|
||||
name: string;
|
||||
url: string;
|
||||
logo: string;
|
||||
description: string;
|
||||
invertOnDark?: boolean;
|
||||
};
|
||||
|
||||
export const SPONSORS: Sponsor[] = [
|
||||
{
|
||||
name: "Fal.ai",
|
||||
url: "https://fal.ai?utm_source=opencut",
|
||||
logo: "/logos/others/fal.svg",
|
||||
description: "Generative image, video, and audio models all in one place.",
|
||||
invertOnDark: true,
|
||||
},
|
||||
{
|
||||
name: "Vercel",
|
||||
url: "https://vercel.com?utm_source=opencut",
|
||||
logo: "/logos/others/vercel.svg",
|
||||
description: "Platform where we deploy and host OpenCut.",
|
||||
invertOnDark: true,
|
||||
},
|
||||
];
|
||||
import { OcDataBuddyIcon, OcMarbleIcon } from "@opencut/ui/icons";
|
||||
|
||||
export const SITE_URL = "https://opencut.app";
|
||||
|
||||
export const SITE_INFO = {
|
||||
title: "OpenCut",
|
||||
description:
|
||||
"A simple but powerful video editor that gets the job done. In your browser.",
|
||||
url: SITE_URL,
|
||||
openGraphImage: "/open-graph/default.jpg",
|
||||
twitterImage: "/open-graph/default.jpg",
|
||||
favicon: "/favicon.ico",
|
||||
};
|
||||
|
||||
export type ExternalTool = {
|
||||
name: string;
|
||||
description: string;
|
||||
url: string;
|
||||
icon: React.ElementType;
|
||||
};
|
||||
|
||||
export const EXTERNAL_TOOLS: ExternalTool[] = [
|
||||
{
|
||||
name: "Marble",
|
||||
description:
|
||||
"Modern headless CMS for content management and the blog for OpenCut",
|
||||
url: "https://marblecms.com?utm_source=opencut",
|
||||
icon: OcMarbleIcon,
|
||||
},
|
||||
{
|
||||
name: "Databuddy",
|
||||
description: "GDPR compliant analytics and user insights for OpenCut",
|
||||
url: "https://databuddy.cc?utm_source=opencut",
|
||||
icon: OcDataBuddyIcon,
|
||||
},
|
||||
];
|
||||
|
||||
export const DEFAULT_LOGO_URL = "/logos/opencut/svg/logo.svg";
|
||||
|
||||
export const SOCIAL_LINKS = {
|
||||
x: "https://x.com/opencutapp",
|
||||
github: "https://github.com/OpenCut-app/OpenCut",
|
||||
discord: "https://discord.com/invite/Mu3acKZvCp",
|
||||
};
|
||||
|
||||
export type Sponsor = {
|
||||
name: string;
|
||||
url: string;
|
||||
logo: string;
|
||||
description: string;
|
||||
invertOnDark?: boolean;
|
||||
};
|
||||
|
||||
export const SPONSORS: Sponsor[] = [
|
||||
{
|
||||
name: "Fal.ai",
|
||||
url: "https://fal.ai?utm_source=opencut",
|
||||
logo: "/logos/others/fal.svg",
|
||||
description: "Generative image, video, and audio models all in one place.",
|
||||
invertOnDark: true,
|
||||
},
|
||||
{
|
||||
name: "Vercel",
|
||||
url: "https://vercel.com?utm_source=opencut",
|
||||
logo: "/logos/others/vercel.svg",
|
||||
description: "Platform where we deploy and host OpenCut.",
|
||||
invertOnDark: true,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
export const STICKER_INTRINSIC_SIZE_FALLBACK = 200;
|
||||
|
||||
export const STICKER_CATEGORIES = {
|
||||
all: "All",
|
||||
logos: "Logos",
|
||||
flags: "Flags",
|
||||
shapes: "Shapes",
|
||||
};
|
||||
export const STICKER_INTRINSIC_SIZE_FALLBACK = 200;
|
||||
|
||||
export const STICKER_CATEGORIES = {
|
||||
all: "All",
|
||||
logos: "Logos",
|
||||
flags: "Flags",
|
||||
shapes: "Shapes",
|
||||
};
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
export const MIN_FONT_SIZE = 5;
|
||||
export const MAX_FONT_SIZE = 300;
|
||||
|
||||
/**
|
||||
* higher value: smaller font size
|
||||
* lower value: larger font size
|
||||
*/
|
||||
export const FONT_SIZE_SCALE_REFERENCE = 90;
|
||||
|
||||
export const CORNER_RADIUS_MIN = 0;
|
||||
export const CORNER_RADIUS_MAX = 100;
|
||||
export const MIN_FONT_SIZE = 5;
|
||||
export const MAX_FONT_SIZE = 300;
|
||||
|
||||
/**
|
||||
* higher value: smaller font size
|
||||
* lower value: larger font size
|
||||
*/
|
||||
export const FONT_SIZE_SCALE_REFERENCE = 90;
|
||||
|
||||
export const CORNER_RADIUS_MIN = 0;
|
||||
export const CORNER_RADIUS_MAX = 100;
|
||||
|
||||
@@ -1,85 +1,85 @@
|
||||
import type { ElementType, TrackType } from "@/lib/timeline";
|
||||
|
||||
export const TRACK_CONFIG: Record<
|
||||
TrackType,
|
||||
{
|
||||
height: number;
|
||||
defaultName: string;
|
||||
}
|
||||
> = {
|
||||
video: {
|
||||
height: 65,
|
||||
defaultName: "Video track",
|
||||
},
|
||||
text: {
|
||||
height: 25,
|
||||
defaultName: "Text track",
|
||||
},
|
||||
audio: {
|
||||
height: 50,
|
||||
defaultName: "Audio track",
|
||||
},
|
||||
graphic: {
|
||||
height: 25,
|
||||
defaultName: "Graphic track",
|
||||
},
|
||||
effect: {
|
||||
height: 25,
|
||||
defaultName: "Effect track",
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const ELEMENT_TYPE_CONFIG: Record<
|
||||
TrackType,
|
||||
{
|
||||
background: string;
|
||||
waveformColor?: string;
|
||||
}
|
||||
> = {
|
||||
video: { background: "transparent" },
|
||||
text: { background: "bg-[#5DBAA0]" },
|
||||
audio: {
|
||||
background: "bg-[#8F5DBA]",
|
||||
waveformColor: "rgba(255, 255, 255, 0.5)",
|
||||
},
|
||||
graphic: { background: "bg-[#BA5D7A]" },
|
||||
effect: { background: "bg-[#5d93ba]" },
|
||||
} as const;
|
||||
|
||||
export const ELEMENT_TRACK_MAP: Record<ElementType, TrackType> = {
|
||||
audio: "audio",
|
||||
text: "text",
|
||||
sticker: "graphic",
|
||||
graphic: "graphic",
|
||||
effect: "effect",
|
||||
video: "video",
|
||||
image: "video",
|
||||
};
|
||||
|
||||
export const TRACK_GAP = 6;
|
||||
export const TRACK_LABELS_WIDTH_PX = 112;
|
||||
|
||||
export const TIMELINE_RULER_HEIGHT = 22;
|
||||
export const TIMELINE_BOOKMARK_ROW_HEIGHT = 16;
|
||||
|
||||
export const DEFAULT_BOOKMARK_COLOR = "#009dff";
|
||||
export const DRAG_THRESHOLD_PX = 5;
|
||||
export const TIMELINE_SCROLLBAR_SIZE_PX = 12;
|
||||
export const TIMELINE_LAYERS = {
|
||||
trackContent: 10,
|
||||
dragLine: 20,
|
||||
playhead: 30,
|
||||
snapIndicator: 40,
|
||||
} as const;
|
||||
|
||||
export const TIMELINE_CONSTANTS = {
|
||||
PIXELS_PER_SECOND: 50,
|
||||
DEFAULT_ELEMENT_DURATION: 5,
|
||||
PADDING_TOP_PX: 2,
|
||||
HORIZONTAL_WHEEL_STEP_PX: 40,
|
||||
ZOOM_MIN: 0.1,
|
||||
ZOOM_MAX: 100,
|
||||
ZOOM_BUTTON_FACTOR: 1.7,
|
||||
ZOOM_ANCHOR_PLAYHEAD_THRESHOLD: 0.15,
|
||||
TRACK_SELECTED_BG: "bg-accent/50",
|
||||
} as const;
|
||||
import type { ElementType, TrackType } from "@/lib/timeline";
|
||||
|
||||
export const TRACK_CONFIG: Record<
|
||||
TrackType,
|
||||
{
|
||||
height: number;
|
||||
defaultName: string;
|
||||
}
|
||||
> = {
|
||||
video: {
|
||||
height: 65,
|
||||
defaultName: "Video track",
|
||||
},
|
||||
text: {
|
||||
height: 25,
|
||||
defaultName: "Text track",
|
||||
},
|
||||
audio: {
|
||||
height: 50,
|
||||
defaultName: "Audio track",
|
||||
},
|
||||
graphic: {
|
||||
height: 25,
|
||||
defaultName: "Graphic track",
|
||||
},
|
||||
effect: {
|
||||
height: 25,
|
||||
defaultName: "Effect track",
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const ELEMENT_TYPE_CONFIG: Record<
|
||||
TrackType,
|
||||
{
|
||||
background: string;
|
||||
waveformColor?: string;
|
||||
}
|
||||
> = {
|
||||
video: { background: "transparent" },
|
||||
text: { background: "bg-[#5DBAA0]" },
|
||||
audio: {
|
||||
background: "bg-[#8F5DBA]",
|
||||
waveformColor: "rgba(255, 255, 255, 0.5)",
|
||||
},
|
||||
graphic: { background: "bg-[#BA5D7A]" },
|
||||
effect: { background: "bg-[#5d93ba]" },
|
||||
} as const;
|
||||
|
||||
export const ELEMENT_TRACK_MAP: Record<ElementType, TrackType> = {
|
||||
audio: "audio",
|
||||
text: "text",
|
||||
sticker: "graphic",
|
||||
graphic: "graphic",
|
||||
effect: "effect",
|
||||
video: "video",
|
||||
image: "video",
|
||||
};
|
||||
|
||||
export const TRACK_GAP = 6;
|
||||
export const TRACK_LABELS_WIDTH_PX = 112;
|
||||
|
||||
export const TIMELINE_RULER_HEIGHT = 22;
|
||||
export const TIMELINE_BOOKMARK_ROW_HEIGHT = 16;
|
||||
|
||||
export const DEFAULT_BOOKMARK_COLOR = "#009dff";
|
||||
export const DRAG_THRESHOLD_PX = 5;
|
||||
export const TIMELINE_SCROLLBAR_SIZE_PX = 12;
|
||||
export const TIMELINE_LAYERS = {
|
||||
trackContent: 10,
|
||||
dragLine: 20,
|
||||
playhead: 30,
|
||||
snapIndicator: 40,
|
||||
} as const;
|
||||
|
||||
export const TIMELINE_CONSTANTS = {
|
||||
PIXELS_PER_SECOND: 50,
|
||||
DEFAULT_ELEMENT_DURATION: 5,
|
||||
PADDING_TOP_PX: 2,
|
||||
HORIZONTAL_WHEEL_STEP_PX: 40,
|
||||
ZOOM_MIN: 0.1,
|
||||
ZOOM_MAX: 100,
|
||||
ZOOM_BUTTON_FACTOR: 1.7,
|
||||
ZOOM_ANCHOR_PLAYHEAD_THRESHOLD: 0.15,
|
||||
TRACK_SELECTED_BG: "bg-accent/50",
|
||||
} as const;
|
||||
|
||||
@@ -1,60 +1,60 @@
|
||||
import { LANGUAGES } from "@/constants/language-constants";
|
||||
import type {
|
||||
TranscriptionModel,
|
||||
TranscriptionModelId,
|
||||
} from "@/lib/transcription/types";
|
||||
import type { LanguageCode } from "@/constants/language-constants";
|
||||
|
||||
const SUPPORTED_TRANSCRIPTION_LANGS: ReadonlyArray<LanguageCode> = [
|
||||
"en",
|
||||
"es",
|
||||
"it",
|
||||
"fr",
|
||||
"de",
|
||||
"pt",
|
||||
"ru",
|
||||
"ja",
|
||||
"zh",
|
||||
];
|
||||
|
||||
export const TRANSCRIPTION_LANGUAGES = LANGUAGES.filter((language) =>
|
||||
SUPPORTED_TRANSCRIPTION_LANGS.includes(language.code),
|
||||
);
|
||||
|
||||
export const TRANSCRIPTION_MODELS: TranscriptionModel[] = [
|
||||
{
|
||||
id: "whisper-tiny",
|
||||
name: "Tiny",
|
||||
huggingFaceId: "onnx-community/whisper-tiny",
|
||||
description: "Fastest, lower accuracy",
|
||||
},
|
||||
{
|
||||
id: "whisper-small",
|
||||
name: "Small",
|
||||
huggingFaceId: "onnx-community/whisper-small",
|
||||
description: "Good balance of speed and accuracy",
|
||||
},
|
||||
{
|
||||
id: "whisper-medium",
|
||||
name: "Medium",
|
||||
huggingFaceId: "onnx-community/whisper-medium",
|
||||
description: "Higher accuracy, slower",
|
||||
},
|
||||
{
|
||||
id: "whisper-large-v3-turbo",
|
||||
name: "Large v3 Turbo",
|
||||
huggingFaceId: "onnx-community/whisper-large-v3-turbo",
|
||||
description: "Best accuracy, requires WebGPU for good performance",
|
||||
},
|
||||
];
|
||||
|
||||
export const DEFAULT_TRANSCRIPTION_MODEL: TranscriptionModelId =
|
||||
"whisper-small";
|
||||
|
||||
export const DEFAULT_TRANSCRIPTION_SAMPLE_RATE = 16000;
|
||||
|
||||
export const DEFAULT_CHUNK_LENGTH_SECONDS = 30;
|
||||
export const DEFAULT_STRIDE_SECONDS = 5;
|
||||
|
||||
export const DEFAULT_WORDS_PER_CAPTION = 3;
|
||||
export const MIN_CAPTION_DURATION_SECONDS = 0.8;
|
||||
import { LANGUAGES } from "@/constants/language-constants";
|
||||
import type {
|
||||
TranscriptionModel,
|
||||
TranscriptionModelId,
|
||||
} from "@/lib/transcription/types";
|
||||
import type { LanguageCode } from "@/constants/language-constants";
|
||||
|
||||
const SUPPORTED_TRANSCRIPTION_LANGS: ReadonlyArray<LanguageCode> = [
|
||||
"en",
|
||||
"es",
|
||||
"it",
|
||||
"fr",
|
||||
"de",
|
||||
"pt",
|
||||
"ru",
|
||||
"ja",
|
||||
"zh",
|
||||
];
|
||||
|
||||
export const TRANSCRIPTION_LANGUAGES = LANGUAGES.filter((language) =>
|
||||
SUPPORTED_TRANSCRIPTION_LANGS.includes(language.code),
|
||||
);
|
||||
|
||||
export const TRANSCRIPTION_MODELS: TranscriptionModel[] = [
|
||||
{
|
||||
id: "whisper-tiny",
|
||||
name: "Tiny",
|
||||
huggingFaceId: "onnx-community/whisper-tiny",
|
||||
description: "Fastest, lower accuracy",
|
||||
},
|
||||
{
|
||||
id: "whisper-small",
|
||||
name: "Small",
|
||||
huggingFaceId: "onnx-community/whisper-small",
|
||||
description: "Good balance of speed and accuracy",
|
||||
},
|
||||
{
|
||||
id: "whisper-medium",
|
||||
name: "Medium",
|
||||
huggingFaceId: "onnx-community/whisper-medium",
|
||||
description: "Higher accuracy, slower",
|
||||
},
|
||||
{
|
||||
id: "whisper-large-v3-turbo",
|
||||
name: "Large v3 Turbo",
|
||||
huggingFaceId: "onnx-community/whisper-large-v3-turbo",
|
||||
description: "Best accuracy, requires WebGPU for good performance",
|
||||
},
|
||||
];
|
||||
|
||||
export const DEFAULT_TRANSCRIPTION_MODEL: TranscriptionModelId =
|
||||
"whisper-small";
|
||||
|
||||
export const DEFAULT_TRANSCRIPTION_SAMPLE_RATE = 16000;
|
||||
|
||||
export const DEFAULT_CHUNK_LENGTH_SECONDS = 30;
|
||||
export const DEFAULT_STRIDE_SECONDS = 5;
|
||||
|
||||
export const DEFAULT_WORDS_PER_CAPTION = 3;
|
||||
export const MIN_CAPTION_DURATION_SECONDS = 0.8;
|
||||
|
||||
Reference in New Issue
Block a user