From d2359d3f3a3703ab80d6953d9a675fcfb8604e18 Mon Sep 17 00:00:00 2001 From: bilalgursen Date: Sun, 4 Oct 2026 14:00:33 +0300 Subject: [PATCH] Lansman videosu (Remotion) projesi eklendi MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit video/ ayrı bir Remotion projesi; Docker imajı, ESLint ve tsc kapsamı dışında. Co-Authored-By: Claude Fable 5.1 --- .dockerignore | 2 + eslint.config.mjs | 2 + tsconfig.json | 2 +- video/.gitignore | 2 + video/REMOCN-NOTU.md | 30 + video/components.json | 17 + video/package.json | 32 + video/pnpm-lock.yaml | 2811 +++++++++++++++++ video/public/fonts/ClarityCity-Bold.woff2 | Bin 0 -> 17168 bytes .../public/fonts/ClarityCity-ExtraBold.woff2 | Bin 0 -> 17200 bytes video/public/fonts/ClarityCity-Medium.woff2 | Bin 0 -> 17092 bytes video/public/fonts/ClarityCity-Regular.woff2 | Bin 0 -> 16856 bytes video/public/fonts/ClarityCity-SemiBold.woff2 | Bin 0 -> 17252 bytes video/remotion.config.ts | 19 + video/src/Lansman.tsx | 100 + video/src/Root.tsx | 15 + video/src/bilesenler/Gren.tsx | 60 + video/src/bilesenler/Imlec.tsx | 84 + video/src/bilesenler/Kinetik.tsx | 48 + video/src/bilesenler/Logo.tsx | 94 + video/src/bilesenler/PikselZemin.tsx | 55 + video/src/bilesenler/UI.tsx | 200 ++ video/src/components/remocn/caret.tsx | 69 + video/src/components/remocn/cursor.tsx | 115 + .../components/remocn/focus-blur-resolve.tsx | 115 + .../remocn/kinetic-center-build.tsx | 243 ++ .../components/remocn/per-character-rise.tsx | 86 + video/src/components/remocn/push-through.tsx | 72 + .../components/remocn/slot-machine-roll.tsx | 112 + video/src/components/remocn/tracking-in.tsx | 77 + video/src/components/remocn/typewriter.tsx | 72 + .../src/components/remocn/use-cursor-path.ts | 133 + video/src/fontlar-hazir.ts | 22 + video/src/fontlar.ts | 38 + video/src/gecisler/piksel-dalga.tsx | 137 + video/src/index.ts | 4 + video/src/lib/remocn-ui/color.ts | 87 + video/src/lib/remocn-ui/index.ts | 27 + video/src/lib/remocn-ui/motion.ts | 17 + video/src/lib/remocn-ui/theme.ts | 108 + video/src/lib/remocn-ui/timeline.ts | 96 + video/src/lib/remocn-ui/types.ts | 5 + video/src/marka.ts | 67 + video/src/sahneler/S1Gurultu.tsx | 183 ++ video/src/sahneler/S2Harita.tsx | 355 +++ video/src/sahneler/S3Siralama.tsx | 155 + video/src/sahneler/S4Havuz.tsx | 707 +++++ video/src/sahneler/S5Danisman.tsx | 242 ++ video/src/sahneler/S6Deger.tsx | 120 + video/src/sahneler/S7Kapanis.tsx | 205 ++ video/src/turkiye.ts | 51 + video/src/veri.ts | 88 + video/src/yardimci.ts | 53 + video/src/zaman.ts | 41 + video/tsconfig.json | 18 + 55 files changed, 7492 insertions(+), 1 deletion(-) create mode 100644 video/.gitignore create mode 100644 video/REMOCN-NOTU.md create mode 100644 video/components.json create mode 100644 video/package.json create mode 100644 video/pnpm-lock.yaml create mode 100644 video/public/fonts/ClarityCity-Bold.woff2 create mode 100644 video/public/fonts/ClarityCity-ExtraBold.woff2 create mode 100644 video/public/fonts/ClarityCity-Medium.woff2 create mode 100644 video/public/fonts/ClarityCity-Regular.woff2 create mode 100644 video/public/fonts/ClarityCity-SemiBold.woff2 create mode 100644 video/remotion.config.ts create mode 100644 video/src/Lansman.tsx create mode 100644 video/src/Root.tsx create mode 100644 video/src/bilesenler/Gren.tsx create mode 100644 video/src/bilesenler/Imlec.tsx create mode 100644 video/src/bilesenler/Kinetik.tsx create mode 100644 video/src/bilesenler/Logo.tsx create mode 100644 video/src/bilesenler/PikselZemin.tsx create mode 100644 video/src/bilesenler/UI.tsx create mode 100644 video/src/components/remocn/caret.tsx create mode 100644 video/src/components/remocn/cursor.tsx create mode 100644 video/src/components/remocn/focus-blur-resolve.tsx create mode 100644 video/src/components/remocn/kinetic-center-build.tsx create mode 100644 video/src/components/remocn/per-character-rise.tsx create mode 100644 video/src/components/remocn/push-through.tsx create mode 100644 video/src/components/remocn/slot-machine-roll.tsx create mode 100644 video/src/components/remocn/tracking-in.tsx create mode 100644 video/src/components/remocn/typewriter.tsx create mode 100644 video/src/components/remocn/use-cursor-path.ts create mode 100644 video/src/fontlar-hazir.ts create mode 100644 video/src/fontlar.ts create mode 100644 video/src/gecisler/piksel-dalga.tsx create mode 100644 video/src/index.ts create mode 100644 video/src/lib/remocn-ui/color.ts create mode 100644 video/src/lib/remocn-ui/index.ts create mode 100644 video/src/lib/remocn-ui/motion.ts create mode 100644 video/src/lib/remocn-ui/theme.ts create mode 100644 video/src/lib/remocn-ui/timeline.ts create mode 100644 video/src/lib/remocn-ui/types.ts create mode 100644 video/src/marka.ts create mode 100644 video/src/sahneler/S1Gurultu.tsx create mode 100644 video/src/sahneler/S2Harita.tsx create mode 100644 video/src/sahneler/S3Siralama.tsx create mode 100644 video/src/sahneler/S4Havuz.tsx create mode 100644 video/src/sahneler/S5Danisman.tsx create mode 100644 video/src/sahneler/S6Deger.tsx create mode 100644 video/src/sahneler/S7Kapanis.tsx create mode 100644 video/src/turkiye.ts create mode 100644 video/src/veri.ts create mode 100644 video/src/yardimci.ts create mode 100644 video/src/zaman.ts create mode 100644 video/tsconfig.json diff --git a/.dockerignore b/.dockerignore index 8db092c..09e1c96 100644 --- a/.dockerignore +++ b/.dockerignore @@ -27,3 +27,5 @@ data/ !data/yokatlas.db !data/yokatlas.db-wal !data/yokatlas.db-shm +# Lansman videosu (Remotion) imaja girmez +video/ diff --git a/eslint.config.mjs b/eslint.config.mjs index 05e726d..1637080 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -12,6 +12,8 @@ const eslintConfig = defineConfig([ "out/**", "build/**", "next-env.d.ts", + // Lansman videosu ayrı bir Remotion projesi (kendi package.json'ı var) + "video/**", ]), ]); diff --git a/tsconfig.json b/tsconfig.json index cf9c65d..9dbaa4f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -30,5 +30,5 @@ ".next/dev/types/**/*.ts", "**/*.mts" ], - "exclude": ["node_modules"] + "exclude": ["node_modules", "video"] } diff --git a/video/.gitignore b/video/.gitignore new file mode 100644 index 0000000..9209ef5 --- /dev/null +++ b/video/.gitignore @@ -0,0 +1,2 @@ +node_modules +out diff --git a/video/REMOCN-NOTU.md b/video/REMOCN-NOTU.md new file mode 100644 index 0000000..fda2a46 --- /dev/null +++ b/video/REMOCN-NOTU.md @@ -0,0 +1,30 @@ +# remocn kurulum notu + +remocn bileşenleri shadcn registry'sinden kurulur: + +```sh +pnpm dlx shadcn@latest add @remocn/ +``` + +**Dikkat:** shadcn CLI kurulumda string literal'leri Tailwind sınıf listesi gibi +işleyip tekrar eden "sınıfları" siliyor. Bu, boşlukla ayrılmış ve içinde +yinelenen değer olan her string'i bozar: SVG path'leri, `viewBox="0 0 24 24"`, +`transformOrigin: "0 0"`, `oklch(1 0 0 / 10%)`. İlk kurulumda `cursor.tsx` +(el ve ok imleci path'leri, viewBox) ve `lib/remocn-ui/theme.ts` (iki oklch +değeri) böyle bozuldu ve registry JSON'undan (`https://remocn.dev/r/.json`) +geri yüklendi. + +Yeni bir bileşen kurduktan sonra, içindeki boşluklu string'leri registry +JSON'uyla karşılaştır. + +## Bu projede yerel olarak değiştirilen bileşenler + +shadcn mantığı: kod bizim. Marka yazı tiplerini ve sahne ihtiyaçlarını +karşılamak için şu dosyalar değiştirildi (yeniden `add --overwrite` yapılırsa +değişiklikler gider): + +- `tracking-in.tsx`: `fontFamily`, `background` (şeffaf), `endTracking`, ReactNode metin +- `kinetic-center-build.tsx`: gerçek yazı tipiyle ölçüm, `birim` (harf/kelime), `vurgu`, `gap` +- `focus-blur-resolve.tsx`: `fontFamily` +- `slot-machine-roll.tsx`: `inline`, `fontFamily`, `stagger`, karaktere göre sütun genişliği +- `push-through.tsx`: `origin` (itmenin tıklanan noktadan yapılması) diff --git a/video/components.json b/video/components.json new file mode 100644 index 0000000..bbebf20 --- /dev/null +++ b/video/components.json @@ -0,0 +1,17 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "new-york", + "rsc": false, + "tsx": true, + "tailwind": { "config": "", "css": "", "baseColor": "slate", "cssVariables": false }, + "aliases": { + "components": "@/components", + "utils": "@/lib/utils", + "ui": "@/components/ui", + "lib": "@/lib", + "hooks": "@/hooks" + }, + "registries": { + "@remocn": "https://remocn.dev/r/{name}.json" + } +} diff --git a/video/package.json b/video/package.json new file mode 100644 index 0000000..7fffa20 --- /dev/null +++ b/video/package.json @@ -0,0 +1,32 @@ +{ + "name": "kolaytercih-video", + "version": "0.1.0", + "private": true, + "description": "KolayTercih lansman videosu (Remotion + remocn)", + "scripts": { + "studio": "remotion studio src/index.ts", + "render": "remotion render src/index.ts Lansman out/kolaytercih-lansman.mp4", + "render:dikey": "remotion render src/index.ts LansmanDikey out/kolaytercih-lansman-dikey.mp4", + "kare": "remotion still src/index.ts Lansman", + "tip": "tsc --noEmit" + }, + "dependencies": { + "@remotion/cli": "4.0.531", + "@remotion/fonts": "4.0.531", + "@remotion/google-fonts": "4.0.531", + "@remotion/transitions": "4.0.531", + "culori": "^4.0.2", + "lucide-react": "^1.49.0", + "react": "19.2.4", + "react-dom": "19.2.4", + "remotion": "4.0.531", + "zod": "4.5.4" + }, + "devDependencies": { + "@types/culori": "^4.0.1", + "@types/node": "22", + "@types/react": "19", + "@types/react-dom": "19", + "typescript": "^5.9.3" + } +} diff --git a/video/pnpm-lock.yaml b/video/pnpm-lock.yaml new file mode 100644 index 0000000..9910d4b --- /dev/null +++ b/video/pnpm-lock.yaml @@ -0,0 +1,2811 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@remotion/cli': + specifier: 4.0.531 + version: 4.0.531(postcss@8.5.28)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) + '@remotion/fonts': + specifier: 4.0.531 + version: 4.0.531(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@remotion/google-fonts': + specifier: 4.0.531 + version: 4.0.531(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@remotion/transitions': + specifier: 4.0.531 + version: 4.0.531(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + culori: + specifier: ^4.0.2 + version: 4.0.2 + lucide-react: + specifier: ^1.49.0 + version: 1.49.0(@types/react@19.3.0)(react@19.2.4) + react: + specifier: 19.2.4 + version: 19.2.4 + react-dom: + specifier: 19.2.4 + version: 19.2.4(react@19.2.4) + remotion: + specifier: 4.0.531 + version: 4.0.531(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + zod: + specifier: 4.5.4 + version: 4.5.4 + devDependencies: + '@types/culori': + specifier: ^4.0.1 + version: 4.0.1 + '@types/node': + specifier: '22' + version: 22.20.4 + '@types/react': + specifier: '19' + version: 19.3.0 + '@types/react-dom': + specifier: '19' + version: 19.3.0(@types/react@19.3.0) + typescript: + specifier: ^5.9.3 + version: 5.9.3 + +packages: + + '@babel/code-frame@7.29.7': + resolution: {integrity: sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==} + engines: {node: '>=6.9.0'} + + '@babel/compat-data@7.29.7': + resolution: {integrity: sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.29.7': + resolution: {integrity: sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.29.8': + resolution: {integrity: sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-compilation-targets@7.29.7': + resolution: {integrity: sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==} + engines: {node: '>=6.9.0'} + + '@babel/helper-globals@7.29.7': + resolution: {integrity: sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.29.7': + resolution: {integrity: sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-transforms@7.29.7': + resolution: {integrity: sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-string-parser@7.29.7': + resolution: {integrity: sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.29.7': + resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-option@7.29.7': + resolution: {integrity: sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.29.7': + resolution: {integrity: sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.24.1': + resolution: {integrity: sha512-Zo9c7N3xdOIQrNip7Lc9wvRPzlRtovHVE4lkz8WEDr7uYh/GMQhSiIgFxGIArRHYdJE5kxtZjAf8rT0xhdLCzg==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/parser@7.29.9': + resolution: {integrity: sha512-CjXrNHTnvqBVqHgdBysY3vk2T8tpJHb5/RMeHJBTyVa9xgugCB0CJTx/3oO8RV2QRQP391RWpB7D6hLjm8V9uA==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/template@7.29.7': + resolution: {integrity: sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.29.8': + resolution: {integrity: sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.24.0': + resolution: {integrity: sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.29.8': + resolution: {integrity: sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==} + engines: {node: '>=6.9.0'} + + '@emnapi/core@1.11.3': + resolution: {integrity: sha512-zLpS5asjEb7lq8jYLq37N6XKaE41DIexlY1rF/z4/tIl3wo13Sqm28fRyfIsKZD+NZ8mM5RoKkpW/rBcuoSZSg==} + + '@emnapi/runtime@1.11.3': + resolution: {integrity: sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==} + + '@emnapi/wasi-threads@1.2.3': + resolution: {integrity: sha512-ELEBe8PsLvvJ6QMr0zLt8ffvOHW/dc1m3CEzNMg7aJUv3bMaoDtw2TXyDAwkYBuroxxuHEwhRTLJSe5sya547g==} + + '@esbuild/aix-ppc64@0.28.1': + resolution: {integrity: sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.28.1': + resolution: {integrity: sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.28.1': + resolution: {integrity: sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.28.1': + resolution: {integrity: sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.28.1': + resolution: {integrity: sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.28.1': + resolution: {integrity: sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.28.1': + resolution: {integrity: sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.28.1': + resolution: {integrity: sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.28.1': + resolution: {integrity: sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.28.1': + resolution: {integrity: sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.28.1': + resolution: {integrity: sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.28.1': + resolution: {integrity: sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.28.1': + resolution: {integrity: sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.28.1': + resolution: {integrity: sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.28.1': + resolution: {integrity: sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.28.1': + resolution: {integrity: sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.28.1': + resolution: {integrity: sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.28.1': + resolution: {integrity: sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.28.1': + resolution: {integrity: sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.28.1': + resolution: {integrity: sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.28.1': + resolution: {integrity: sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.28.1': + resolution: {integrity: sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.28.1': + resolution: {integrity: sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.28.1': + resolution: {integrity: sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.28.1': + resolution: {integrity: sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.28.1': + resolution: {integrity: sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/source-map@0.3.11': + resolution: {integrity: sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==} + + '@jridgewell/sourcemap-codec@1.6.0': + resolution: {integrity: sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==} + + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + + '@mediabunny/aac-encoder@1.56.1': + resolution: {integrity: sha512-a+OY/BctP7zC4G/prHikooOVaoWXMD4+bUyEwHg2dtQiQdIwC6TDJdVYJu5dfrdSNOiAFkv1HKcYEeROdwMezg==} + peerDependencies: + mediabunny: ^1.0.0 + + '@mediabunny/flac-encoder@1.56.1': + resolution: {integrity: sha512-zbmorMVlF1izwtlz5mWnu7A1rJLM+V26I0pEFr9Td1EDTwE5uAGRSW+/UZlnjwj1t00Woe3Zonfh9kb7lRRBqg==} + peerDependencies: + mediabunny: ^1.0.0 + + '@mediabunny/mp3-encoder@1.56.1': + resolution: {integrity: sha512-p66ovEq6mZt3ejje45NOju84hIJI4v8rHfsmc1D2J34ziV0USE8AdJBzmiwqxl6nZkIAQLNB19HzbVRcQfc51g==} + peerDependencies: + mediabunny: ^1.0.0 + + '@module-federation/error-codes@0.22.0': + resolution: {integrity: sha512-xF9SjnEy7vTdx+xekjPCV5cIHOGCkdn3pIxo9vU7gEZMIw0SvAEdsy6Uh17xaCpm8V0FWvR0SZoK9Ik6jGOaug==} + + '@module-federation/runtime-core@0.22.0': + resolution: {integrity: sha512-GR1TcD6/s7zqItfhC87zAp30PqzvceoeDGYTgF3Vx2TXvsfDrhP6Qw9T4vudDQL3uJRne6t7CzdT29YyVxlgIA==} + + '@module-federation/runtime-tools@0.22.0': + resolution: {integrity: sha512-4ScUJ/aUfEernb+4PbLdhM/c60VHl698Gn1gY21m9vyC1Ucn69fPCA1y2EwcCB7IItseRMoNhdcWQnzt/OPCNA==} + + '@module-federation/runtime@0.22.0': + resolution: {integrity: sha512-38g5iPju2tPC3KHMPxRKmy4k4onNp6ypFPS1eKGsNLUkXgHsPMBFqAjDw96iEcjri91BrahG4XcdyKi97xZzlA==} + + '@module-federation/sdk@0.22.0': + resolution: {integrity: sha512-x4aFNBKn2KVQRuNVC5A7SnrSCSqyfIWmm1DvubjbO9iKFe7ith5niw8dqSFBekYBg2Fwy+eMg4sEFNVvCAdo6g==} + + '@module-federation/webpack-bundler-runtime@0.22.0': + resolution: {integrity: sha512-aM8gCqXu+/4wBmJtVeMeeMN5guw3chf+2i6HajKtQv7SJfxV/f4IyNQJUeUQu9HfiAZHjqtMV5Lvq/Lvh8LdyA==} + + '@napi-rs/wasm-runtime@1.0.7': + resolution: {integrity: sha512-SeDnOO0Tk7Okiq6DbXmmBODgOAb9dp9gjlphokTUxmt8U3liIP1ZsozBahH69j/RJv+Rfs6IwUKHTgQYJ/HBAw==} + + '@remotion/bundler@4.0.531': + resolution: {integrity: sha512-Dv7LjGA/Uhy9H1D7vrrrwZJyL8hT70o8jxW8LsZbBYsrtn+N2Ntzt1mukdj1NM4xFLBjz8qY5flyJyNEdficSA==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + '@remotion/canvas@4.0.531': + resolution: {integrity: sha512-VINlJX8nLozdf55lkgFj/hoILPuyBaXIzkwpaoBLh3C+heLDKf4LvfXh8JXorgCNDiwv7uKlkw6gsbkAIgcCGw==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + '@remotion/captions@4.0.531': + resolution: {integrity: sha512-/T1VsjEhAM0ShTuRIx2M0cnAkADGeqxqK+A0MyEZefU4p/ddD25qul6Sk73MdSovKy8tx/jD+e6xnkogOLHIOA==} + + '@remotion/cli@4.0.531': + resolution: {integrity: sha512-p99o3iG4NOMTneeqIDVCDEHU61GR6x5VdDSkjpfjHn7oKhp5sPu02mQEWG3lzdYa0r40xkdankQ1Blztqo8zJg==} + hasBin: true + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + '@remotion/codemods@4.0.531': + resolution: {integrity: sha512-rkzC3nda0dsYwElqKxgtzTL6sCqo5K9i0lLEah8CeC0naYOA85w9ySaY+/OdQZfsOWX9LNCZBrR9nwo4hoQ49Q==} + + '@remotion/compositor-darwin-arm64@4.0.531': + resolution: {integrity: sha512-4EUrY22YfNrlXAe2PVg3wJWGLwFnVlHTwmptPJ6ZlYnN8sGYfYZkACTVTLOTO/YmLkRb9I+md1cH2mBX0ugAuQ==} + cpu: [arm64] + os: [darwin] + + '@remotion/compositor-darwin-x64@4.0.531': + resolution: {integrity: sha512-Uhr8cHwYhvYVYS+/Sl+RHyc0QGey+h9lsr1dEVeVKeGVQOESI5L0Xz0enyuj5vO6lgSxhBnXrFRmyOJ/JhtkiQ==} + cpu: [x64] + os: [darwin] + + '@remotion/compositor-linux-arm64-gnu@4.0.531': + resolution: {integrity: sha512-tOzrR5AqWVaQ25uPoYBRmOul1NEtb3CAElMriIfGDJqOEqXJZ+PzcULnjyfyj+B0Q38c27a6sF6UcXVAfyHBTw==} + cpu: [arm64] + os: [linux] + + '@remotion/compositor-linux-arm64-musl@4.0.531': + resolution: {integrity: sha512-Q2Pt6p9M9WRXaKmd1jYngSMDac42Kj3Cha4n2coTSxiqvMtAtKq7+I+LerGratYw8HsqGJx2SrUwfRH1UMf54g==} + cpu: [arm64] + os: [linux] + + '@remotion/compositor-linux-x64-gnu@4.0.531': + resolution: {integrity: sha512-o9L1kBAiDVK5SGUpsgXKAeUj1uj2JUR8NoUYSo1nIWFd2Dgt/zRvyMtusp9ojofmiFQhvZszpOSbEB58muMc8Q==} + cpu: [x64] + os: [linux] + + '@remotion/compositor-linux-x64-musl@4.0.531': + resolution: {integrity: sha512-gn9OPNe4VTKwt91EtZWoGdlLjc+FTDwsQxeynfBA6favxkzYZl5DMyi24xwh0blHVrzMuzXY/neywMqKlc9Lig==} + cpu: [x64] + os: [linux] + + '@remotion/compositor-win32-x64-msvc@4.0.531': + resolution: {integrity: sha512-q2/xGTcN+ZLTrPzTXORf+z6GretJEF2Vi2OTgLxV1S3tDOcBx4K16XAUM2KuieKv2E9hYO9VsU1AyQanJOyT5g==} + cpu: [x64] + os: [win32] + + '@remotion/elevenlabs@4.0.531': + resolution: {integrity: sha512-h6rN4dEjaaVqev3Z3vMaqjeKmB9PneiRQRqsuoVrL7TG6YzG4tWub27kri/y6NMGLbDWF49suK0ucfx0aPzJxA==} + + '@remotion/fonts@4.0.531': + resolution: {integrity: sha512-0eemQzfyBPNQYZZ3AumHaMbdFRwnoP+eHX96QeVwk16XXaTxAJ0jkUI8e86BW7/ABvYlFj0iIjtqbgvE9C3cJg==} + + '@remotion/google-fonts@4.0.531': + resolution: {integrity: sha512-Jy1qVNsse6yH9CdFLzZTxHUYfZsx7/igZsW4IQd6hHhjncqpd6krrt7u9O2eFZ3XRsKKVCPGElF02iuNMrsbLw==} + + '@remotion/licensing@4.0.531': + resolution: {integrity: sha512-h17IbJSbD8GmkwJrayVJFUGCjIPTR4uj1AVOWQQYfBfv7/mgPNtCZPXDths9yQOphFXfwPq4IRRIZFPXYJFJZw==} + + '@remotion/media-parser@4.0.531': + resolution: {integrity: sha512-R8z0K2vPACQ5wsxOHnykIN2vbDpfyobGuuScJxtCEfH5IycuS1TL+JGnd1cFJGMg3+XPePeenJjEJPsrrni/TA==} + + '@remotion/media-utils@4.0.531': + resolution: {integrity: sha512-z3Zi8nqAfYrMG3Kkqji5KeAavNmF/af2jNffSsSKLfNoIcg+tgmsKeLy5srtLVrDdfgku8E8Jootnq2IE8emwA==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + '@remotion/media@4.0.531': + resolution: {integrity: sha512-MQhJqvn0WC51hBUyqHsR368gYrN+kyZe0HWX652UqxQ601iOHGIJyIHUAx/YNDxOE9qoBt85M+5r0wKULKnrvw==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + '@remotion/openai-whisper@4.0.531': + resolution: {integrity: sha512-RUfZ/1EjvvyY6fGpAbYrLaUWmiqys6UCwd5+ozcD/0NkDLsg9vcmyED5MnZnsLRO8eDaLRzjGbL+QuA/o8ePGg==} + + '@remotion/paths@4.0.531': + resolution: {integrity: sha512-fpSoVjz5mSa5whVOy4TvCWwDPHaVDIhf9x1nusxa2faNi/Y6IPzNUq2WHtxoZ5gxd9iExgDu4VGjf1arVnPLOQ==} + + '@remotion/player@4.0.531': + resolution: {integrity: sha512-a2iq13CQvUJMXq2Lf9aJD1TOyQ0Z44n4dEtHjOV1i4P8z6fjnvVDH19n+5ya/NLmakBdLyYmTghF3t0962b92g==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + '@remotion/renderer@4.0.531': + resolution: {integrity: sha512-xsPrN0gmweNjEhpt9bOLUDV9odfPlVrUJkn4tOv4TA621X33U/gejfGdvMbOM/kPkZ62Bx6P3rY3eBCgFGQnkw==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + '@remotion/shapes@4.0.531': + resolution: {integrity: sha512-0g2TdbC67PibqUv4GgTc6abQzuTBu2Si4R2mDQKxlBHwHIvwLRx4D3UgX6Ccux7kzkVkBnxlHdl4nZv0SxwQJw==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + '@remotion/streaming@4.0.531': + resolution: {integrity: sha512-cCXg6HBvgTPCvMGxnpb+2hmwfaBmD+0VuRVX9yjDWzxoDoAG+abYq/JQHsSbJHQRnRkfwHaow73u1H1DOW27qQ==} + + '@remotion/studio-protocol@4.0.531': + resolution: {integrity: sha512-8UewGkNOSRVNwgzKiAYZpHJo6QOdzuHpaP7pR503fIlPn5ZpDb771T8ZqJ91oWzoih6B4V6aHu6/Ny+jUkJoEw==} + + '@remotion/studio-server@4.0.531': + resolution: {integrity: sha512-HqyvUnFNb78j+ht/jEqykxzNVqyrFwr6suDOidOvSrwUhfb+dgorrolSjz7vLZmMGDvlSeo2333UcJ+WJnfGxQ==} + + '@remotion/studio-shared@4.0.531': + resolution: {integrity: sha512-no/I+Tt6df/guYRpBFGEj/JOS532pmyGCQfor6wfLDjW4zWDmhsehny1JZrYHWgg25DVrnl731JlkfVaoZIF8A==} + + '@remotion/studio@4.0.531': + resolution: {integrity: sha512-mFdI2tzKX8MiXDBpqIImV4LqPA3BNEg1jzn++h/vISltJQ6FuwMxXYSWa8QPlTW5zMaFEVODuPLhooGuMU8aWQ==} + peerDependencies: + '@remotion/video-matting': 4.0.531 + '@remotion/whisper-webgpu': 4.0.531 + react: '>=16.8.0' + react-dom: '>=16.8.0' + peerDependenciesMeta: + '@remotion/video-matting': + optional: true + '@remotion/whisper-webgpu': + optional: true + + '@remotion/timeline-utils@4.0.531': + resolution: {integrity: sha512-XE2ikcvYYgxZW57TUE3UEaJVR4zpujOsHq7rmxucqnaDqyu0N6+tGXpJK+MKzW0RVsYik1nQ8Gv0NSp4DjaL6w==} + + '@remotion/transitions@4.0.531': + resolution: {integrity: sha512-WQJCitaF0guxYxZuCujasL6WeFnpOaObmM8nzwduEJizE0HNGq8e8ragRznpt2op7osfri8/eHjKzVRKBsngjw==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + '@remotion/web-renderer@4.0.531': + resolution: {integrity: sha512-fIS7v0ZB97xGEKKKMvFQ/7/puV4ZqJRfoQQwczcGRp9WppJLO65IQYPYnWp206j0KBDo8Qff6CtICRIrd5C2Qw==} + peerDependencies: + react: '>=18.0.0' + react-dom: '>=18.0.0' + + '@remotion/zod-types@4.0.531': + resolution: {integrity: sha512-EWaHyq1i2ATtVRbpNiQlS2DCub6Rc5L0eU5OgYBFfY4TWQ3yihXgt3X3XIOFwLLA63ZAEzBEpZXUk4KBC3inOw==} + + '@rspack/binding-darwin-arm64@1.7.11': + resolution: {integrity: sha512-oduECiZVqbO5zlVw+q7Vy65sJFth99fWPTyucwvLJJtJkPL5n17Uiql2cYP6Ijn0pkqtf1SXgK8WjiKLG5bIig==} + cpu: [arm64] + os: [darwin] + + '@rspack/binding-darwin-x64@1.7.11': + resolution: {integrity: sha512-a1+TtTE9ap6RalgFi7FGIgkJP6O4Vy6ctv+9WGJy53E4kuqHR0RygzaiVxCI/GMc/vBT9vY23hyrpWb3d1vtXA==} + cpu: [x64] + os: [darwin] + + '@rspack/binding-linux-arm64-gnu@1.7.11': + resolution: {integrity: sha512-P0QrGRPbTWu6RKWfN0bDtbnEps3rXH0MWIMreZABoUrVmNQKtXR6e73J3ub6a+di5s2+K0M2LJ9Bh2/H4UsDUA==} + cpu: [arm64] + os: [linux] + + '@rspack/binding-linux-arm64-musl@1.7.11': + resolution: {integrity: sha512-6ky7R43VMjWwmx3Yx7Jl7faLBBMAgMDt+/bN35RgwjiPgsIByz65EwytUVuW9rikB43BGHvA/eqlnjLrUzNBqw==} + cpu: [arm64] + os: [linux] + + '@rspack/binding-linux-x64-gnu@1.7.11': + resolution: {integrity: sha512-cuOJMfCOvb2Wgsry5enXJ3iT1FGUjdPqtGUBVupQlEG4ntSYsQ2PtF4wIDVasR3wdxC5nQbipOrDiN/u6fYsdQ==} + cpu: [x64] + os: [linux] + + '@rspack/binding-linux-x64-musl@1.7.11': + resolution: {integrity: sha512-CoK37hva4AmHGh3VCsQXmGr40L36m1/AdnN5LEjUX6kx5rEH7/1nEBN6Ii72pejqDVvk9anEROmPDiPw10tpFg==} + cpu: [x64] + os: [linux] + + '@rspack/binding-wasm32-wasi@1.7.11': + resolution: {integrity: sha512-OtrmnPUVJMxjNa3eDMfHyPdtlLRmmp/aIm0fQHlAOATbZvlGm12q7rhPW5BXTu1yh+1rQ1/uqvz+SzKEZXuJaQ==} + cpu: [wasm32] + + '@rspack/binding-win32-arm64-msvc@1.7.11': + resolution: {integrity: sha512-lObFW6e5lCWNgTBNwT//yiEDbsxm9QG4BYUojqeXxothuzJ/L6ibXz6+gLMvbOvLGV3nKgkXmx8GvT9WDKR0mA==} + cpu: [arm64] + os: [win32] + + '@rspack/binding-win32-ia32-msvc@1.7.11': + resolution: {integrity: sha512-0pYGnZd8PPqNR68zQ8skamqNAXEA1sUfXuAdYcknIIRq2wsbiwFzIc0Pov1cIfHYab37G7sSIPBiOUdOWF5Ivw==} + cpu: [ia32] + os: [win32] + + '@rspack/binding-win32-x64-msvc@1.7.11': + resolution: {integrity: sha512-EeQXayoQk/uBkI3pdoXfQBXNIUrADq56L3s/DFyM2pJeUDrWmhfIw2UFIGkYPTMSCo8F2JcdcGM32FGJrSnU0Q==} + cpu: [x64] + os: [win32] + + '@rspack/binding@1.7.11': + resolution: {integrity: sha512-2MGdy2s2HimsDT444Bp5XnALzNRxuBNc7y0JzyuqKbHBywd4x2NeXyhWXXoxufaCFu5PBc9Qq9jyfjW2Aeh06Q==} + + '@rspack/core@1.7.11': + resolution: {integrity: sha512-rsD9b+Khmot5DwCMiB3cqTQo53ioPG3M/A7BySu8+0+RS7GCxKm+Z+mtsjtG/vsu4Tn2tcqCdZtA3pgLoJB+ew==} + engines: {node: '>=18.12.0'} + peerDependencies: + '@swc/helpers': '>=0.5.1' + peerDependenciesMeta: + '@swc/helpers': + optional: true + + '@rspack/lite-tapable@1.1.0': + resolution: {integrity: sha512-E2B0JhYFmVAwdDiG14+DW0Di4Ze4Jg10Pc4/lILUrd5DRCaklduz2OvJ5HYQ6G+hd+WTzqQb3QnDNfK4yvAFYw==} + + '@rspack/plugin-react-refresh@1.6.1': + resolution: {integrity: sha512-eqqW5645VG3CzGzFgNg5HqNdHVXY+567PGjtDhhrM8t67caxmsSzRmT5qfoEIfBcGgFkH9vEg7kzXwmCYQdQDw==} + peerDependencies: + react-refresh: '>=0.10.0 <1.0.0' + webpack-hot-middleware: 2.x + peerDependenciesMeta: + webpack-hot-middleware: + optional: true + + '@svgr/babel-plugin-add-jsx-attribute@8.0.0': + resolution: {integrity: sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g==} + engines: {node: '>=14'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@svgr/babel-plugin-remove-jsx-attribute@8.0.0': + resolution: {integrity: sha512-BcCkm/STipKvbCl6b7QFrMh/vx00vIP63k2eM66MfHJzPr6O2U0jYEViXkHJWqXqQYjdeA9cuCl5KWmlwjDvbA==} + engines: {node: '>=14'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@svgr/babel-plugin-remove-jsx-empty-expression@8.0.0': + resolution: {integrity: sha512-5BcGCBfBxB5+XSDSWnhTThfI9jcO5f0Ai2V24gZpG+wXF14BzwxxdDb4g6trdOux0rhibGs385BeFMSmxtS3uA==} + engines: {node: '>=14'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@svgr/babel-plugin-replace-jsx-attribute-value@8.0.0': + resolution: {integrity: sha512-KVQ+PtIjb1BuYT3ht8M5KbzWBhdAjjUPdlMtpuw/VjT8coTrItWX6Qafl9+ji831JaJcu6PJNKCV0bp01lBNzQ==} + engines: {node: '>=14'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@svgr/babel-plugin-svg-dynamic-title@8.0.0': + resolution: {integrity: sha512-omNiKqwjNmOQJ2v6ge4SErBbkooV2aAWwaPFs2vUY7p7GhVkzRkJ00kILXQvRhA6miHnNpXv7MRnnSjdRjK8og==} + engines: {node: '>=14'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@svgr/babel-plugin-svg-em-dimensions@8.0.0': + resolution: {integrity: sha512-mURHYnu6Iw3UBTbhGwE/vsngtCIbHE43xCRK7kCw4t01xyGqb2Pd+WXekRRoFOBIY29ZoOhUCTEweDMdrjfi9g==} + engines: {node: '>=14'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@svgr/babel-plugin-transform-react-native-svg@8.1.0': + resolution: {integrity: sha512-Tx8T58CHo+7nwJ+EhUwx3LfdNSG9R2OKfaIXXs5soiy5HtgoAEkDay9LIimLOcG8dJQH1wPZp/cnAv6S9CrR1Q==} + engines: {node: '>=14'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@svgr/babel-plugin-transform-svg-component@8.0.0': + resolution: {integrity: sha512-DFx8xa3cZXTdb/k3kfPeaixecQLgKh5NVBMwD0AQxOzcZawK4oo1Jh9LbrcACUivsCA7TLG8eeWgrDXjTMhRmw==} + engines: {node: '>=12'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@svgr/babel-preset@8.1.0': + resolution: {integrity: sha512-7EYDbHE7MxHpv4sxvnVPngw5fuR6pw79SkcrILHJ/iMpuKySNCl5W1qcwPEpU+LgyRXOaAFgH0KhwD18wwg6ug==} + engines: {node: '>=14'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@svgr/core@8.1.0': + resolution: {integrity: sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==} + engines: {node: '>=14'} + + '@svgr/hast-util-to-babel-ast@8.0.0': + resolution: {integrity: sha512-EbDKwO9GpfWP4jN9sGdYwPBU0kdomaPIL2Eu4YwmgP+sJeXT+L7bMwJUBnhzfH8Q2qMBqZ4fJwpCyYsAN3mt2Q==} + engines: {node: '>=14'} + + '@svgr/plugin-jsx@8.1.0': + resolution: {integrity: sha512-0xiIyBsLlr8quN+WyuxooNW9RJ0Dpr8uOnH/xrCVO8GLUcwHISwj1AG0k+LFzteTkAA0GbX0kj9q6Dk70PTiPA==} + engines: {node: '>=14'} + peerDependencies: + '@svgr/core': '*' + + '@tanstack/react-virtual@3.14.9': + resolution: {integrity: sha512-qZyr0FZDP8rDC4WBhsryIZmAd9bveJvFGUJJtskWaew6/0dTRS6wZxnR6VQ5bY2KwL3LjerrHqQLk3a0GKcPXQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + '@tanstack/virtual-core@3.17.7': + resolution: {integrity: sha512-bp+v10y65sp2H7WpWfIMyxTNfl8ZVfxFTLRjPIFRryi6FV/J33z4IS53WO4pTk36KlvJ4iLiQz+oaydDC1xbcA==} + + '@tybys/wasm-util@0.10.4': + resolution: {integrity: sha512-W3c4gRigFS0T/Ma4qIYF3GDAc5AQdHb1yL5znJT1Zv1YaD9Kitx656wBjvr19qbiosmZT8lWDM5BEMynUqX65A==} + + '@types/culori@4.0.1': + resolution: {integrity: sha512-43M51r/22CjhbOXyGT361GZ9vncSVQ39u62x5eJdBQFviI8zWp2X5jzqg7k4M6PVgDQAClpy2bUe2dtwEgEDVQ==} + + '@types/dom-mediacapture-transform@0.1.12': + resolution: {integrity: sha512-d7/QsLRwF864A5mgIM/YrfiglHoYn7zgCcAoJgW404r+2DwnNr7EBbLnCWpmOMgH8y0te73L1AV6H1bmauaWFw==} + + '@types/dom-webcodecs@0.1.13': + resolution: {integrity: sha512-O5hkiFIcjjszPIYyUSyvScyvrBoV3NOEEZx/pMlsu44TKzWNkLVBBxnxJz42in5n3QIolYOcBYFCPZZ0h8SkwQ==} + + '@types/eslint-scope@3.7.7': + resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==} + + '@types/eslint@9.6.1': + resolution: {integrity: sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==} + + '@types/estree@1.0.9': + resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} + + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + + '@types/node@22.20.4': + resolution: {integrity: sha512-zJRE40jpHtKqE/C4fgHrAKQLJuSpzEnP9ff9Y7YtoR3Wd2pwqzlekDeEuUQXjRd+QCYnVnNwuJYmhdk9XV8gvA==} + + '@types/react-dom@19.3.0': + resolution: {integrity: sha512-ZI7bU42mZXXKHn/qNLEw2IrbiINU7X5+vfgdixBHkCNpYWXjKgfQ/P+uyGb5CjOLB9UcnTeg3rylQtV2hym44Q==} + peerDependencies: + '@types/react': ^19.3.0 + + '@types/react@19.3.0': + resolution: {integrity: sha512-N0rFCuH9YoxG9/m61l9MfpJKfmLOVU0em7ipIz6TRgSSkvReLB9vL85GB+yr8Bs5leqpvg96JSwF4ZS1s4viQg==} + + '@webassemblyjs/ast@1.14.1': + resolution: {integrity: sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==} + + '@webassemblyjs/floating-point-hex-parser@1.13.2': + resolution: {integrity: sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==} + + '@webassemblyjs/helper-api-error@1.13.2': + resolution: {integrity: sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==} + + '@webassemblyjs/helper-buffer@1.14.1': + resolution: {integrity: sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==} + + '@webassemblyjs/helper-numbers@1.13.2': + resolution: {integrity: sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==} + + '@webassemblyjs/helper-wasm-bytecode@1.13.2': + resolution: {integrity: sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==} + + '@webassemblyjs/helper-wasm-section@1.14.1': + resolution: {integrity: sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==} + + '@webassemblyjs/ieee754@1.13.2': + resolution: {integrity: sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==} + + '@webassemblyjs/leb128@1.13.2': + resolution: {integrity: sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==} + + '@webassemblyjs/utf8@1.13.2': + resolution: {integrity: sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==} + + '@webassemblyjs/wasm-edit@1.14.1': + resolution: {integrity: sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==} + + '@webassemblyjs/wasm-gen@1.14.1': + resolution: {integrity: sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==} + + '@webassemblyjs/wasm-opt@1.14.1': + resolution: {integrity: sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==} + + '@webassemblyjs/wasm-parser@1.14.1': + resolution: {integrity: sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==} + + '@webassemblyjs/wast-printer@1.14.1': + resolution: {integrity: sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==} + + '@xtuc/ieee754@1.2.0': + resolution: {integrity: sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==} + + '@xtuc/long@4.2.2': + resolution: {integrity: sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==} + + acorn-import-phases@1.0.4: + resolution: {integrity: sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==} + engines: {node: '>=10.13.0'} + peerDependencies: + acorn: ^8.14.0 + + acorn@8.18.0: + resolution: {integrity: sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==} + engines: {node: '>=0.4.0'} + hasBin: true + + ajv-formats@3.0.1: + resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + + ajv-keywords@5.1.0: + resolution: {integrity: sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==} + peerDependencies: + ajv: ^8.8.2 + + ajv@8.20.0: + resolution: {integrity: sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + ast-types@0.16.1: + resolution: {integrity: sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==} + engines: {node: '>=4'} + + ast-types@0.16.3: + resolution: {integrity: sha512-FvWoWYfSCM6kRxCSH+MGLHIKKGRL6A6AW7Zek2O32REPQRdg131428uRTKMBYAeRd3XXAaHDS60Wpri7CdKDrA==} + engines: {node: '>=4'} + + baseline-browser-mapping@2.11.26: + resolution: {integrity: sha512-GLQdD3y6UF8iVuMJl5fHgE4jdn/ua7n+toKfLgNlg3BqQtOZjpy68T8Tup8/wGWZCDlm7KMg7tPb4MPn7oN0TQ==} + engines: {node: '>=6.0.0'} + hasBin: true + + browserslist@4.29.3: + resolution: {integrity: sha512-1R4kiYKXGViqEN0CnoDrXc1StD9niAwu+j2dukWzrD4bJgsD4lDmEp0CRbc6E/vYJIfTHwPmwyaKtVSudICdPA==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + camelcase@6.3.0: + resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} + engines: {node: '>=10'} + + caniuse-lite@1.0.30001814: + resolution: {integrity: sha512-/Uaf1lAzr59XcMpW0o96WoEfr+VXK2OX4U9AgFoiSHsVJ4HppnIFUjtYzsyDH2+tgANaQb2/oxYGwCPapN1FpA==} + + chrome-trace-event@1.0.4: + resolution: {integrity: sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==} + engines: {node: '>=6.0'} + + commander@2.20.3: + resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + + cosmiconfig@8.3.6: + resolution: {integrity: sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==} + engines: {node: '>=14'} + peerDependencies: + typescript: '>=4.9.5' + peerDependenciesMeta: + typescript: + optional: true + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + css-loader@7.1.4: + resolution: {integrity: sha512-vv3J9tlOl04WjiMvHQI/9tmIrCxVrj6PFbHemBB1iihpeRbi/I4h033eoFIhwxBBqLhI0KYFS7yvynBFhIZfTw==} + engines: {node: '>= 18.12.0'} + peerDependencies: + '@rspack/core': 0.x || ^1.0.0 || ^2.0.0-0 + webpack: ^5.27.0 + peerDependenciesMeta: + '@rspack/core': + optional: true + webpack: + optional: true + + cssesc@3.0.0: + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} + hasBin: true + + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + + culori@4.0.2: + resolution: {integrity: sha512-1+BhOB8ahCn4O0cep0Sh2l9KCOfOdY+BXJnKMHFFzDEouSr/el18QwXEMRlOj9UY5nCeA8UN3a/82rUWRBeyBw==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + define-lazy-prop@2.0.0: + resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==} + engines: {node: '>=8'} + + dot-case@3.0.4: + resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==} + + dotenv@17.3.1: + resolution: {integrity: sha512-IO8C/dzEb6O3F9/twg6ZLXz164a2fhTnEWb95H23Dm4OuN+92NmEAlTrupP9VW6Jm3sO26tQlqyvyi4CsnY9GA==} + engines: {node: '>=12'} + + electron-to-chromium@1.5.443: + resolution: {integrity: sha512-TDJG36L9A3CWWwZ97HKaE+Iz1sW80pNp6sAU0owzCIV3Zc9eVyRqZK8Vz6NKuMIU8WjP0pIkoqCa0VRf/yFD0Q==} + + enhanced-resolve@5.26.0: + resolution: {integrity: sha512-9vhedylFonb2YGogzUKX6+Ja72gOJbN1QHAqdrvqLwhdl/QWbKopzoUC9EbQNVsAns/bx/4uyqalrQAoy1IByw==} + engines: {node: '>=10.13.0'} + + entities@4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} + + error-ex@1.3.4: + resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==} + + error-stack-parser@2.1.4: + resolution: {integrity: sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==} + + es-module-lexer@2.3.2: + resolution: {integrity: sha512-poHGpORABojJJucnV9KbOavETW8lBVnphkW77ER5/BQ5Fz7oXSoCNek7IH3vR5nRjdsEz926ibFYX8KtLQmdyw==} + + esbuild@0.28.1: + resolution: {integrity: sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==} + engines: {node: '>=18'} + hasBin: true + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + eslint-scope@5.1.1: + resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} + engines: {node: '>=8.0.0'} + + esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + + esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + + estraverse@4.3.0: + resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} + engines: {node: '>=4.0'} + + estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + + events@3.3.0: + resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} + engines: {node: '>=0.8.x'} + + execa@5.1.1: + resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} + engines: {node: '>=10'} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-uri@3.1.8: + resolution: {integrity: sha512-GZMtZUTNRpOVIECoXwLNZS5xUGE+mVNbTB8h/7Rwh2TFWcBQiPzTgyZi05BF9UMZKkLJv8XBRJTlU7zg8+ZfMg==} + + fs-monkey@1.0.3: + resolution: {integrity: sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q==} + + gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + + get-stream@6.0.1: + resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} + engines: {node: '>=10'} + + glob-to-regexp@0.4.1: + resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + html-entities@2.6.0: + resolution: {integrity: sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==} + + human-signals@2.1.0: + resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} + engines: {node: '>=10.17.0'} + + icss-utils@5.1.0: + resolution: {integrity: sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==} + engines: {node: ^10 || ^12 || >= 14} + peerDependencies: + postcss: ^8.1.0 + + import-fresh@3.3.1: + resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} + engines: {node: '>=6'} + + is-arrayish@0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + + is-docker@2.2.1: + resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} + engines: {node: '>=8'} + hasBin: true + + is-stream@2.0.1: + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} + + is-wsl@2.2.0: + resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} + engines: {node: '>=8'} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + jest-worker@27.5.1: + resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==} + engines: {node: '>= 10.13.0'} + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + js-yaml@4.3.2: + resolution: {integrity: sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==} + hasBin: true + + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true + + json-parse-even-better-errors@2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + + json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + + kiwi-schema@0.5.0: + resolution: {integrity: sha512-X+FpfU0yTEtc6aTHS7VwbOpvQwRt70+pXXWRI5fd6CvWhe7pSVC854TVo4Zo0x5/wwcWj+/9KUlXpdcP0dY9AA==} + hasBin: true + + kleur@3.0.3: + resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} + engines: {node: '>=6'} + + lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + + loader-runner@4.3.2: + resolution: {integrity: sha512-DFEqQ3ihfS9blba08cLfYf1NRAIEm+dDjic073DRDc3/JspI/8wYmtDsHwd3+4hwvdxSK7PGaElfTmm0awWJ4w==} + engines: {node: '>=6.11.5'} + + lower-case@2.0.2: + resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==} + + lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + + lru-cache@6.0.0: + resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} + engines: {node: '>=10'} + + lucide-react@1.49.0: + resolution: {integrity: sha512-ApfaNM4/7jBrVopqLJ84Jz8TMQ1Q1JeZ1PmKh25aeS3E1FTVcMkSh1bEQB7dfzdIrwXRP8p3z4AJjTIHHb5IIA==} + peerDependencies: + '@types/react': '*' + react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + + mediabunny@1.56.1: + resolution: {integrity: sha512-DNOm0bRBmeOxJgCK/g3LxNWbxY5morTauNdlychujGmJ9L37ezVezkNoI1WtO2Xdb4WlWWJlYfIKnOEzd5phRw==} + + memfs@3.4.3: + resolution: {integrity: sha512-eivjfi7Ahr6eQTn44nvTnR60e4a1Fs1Via2kCR5lHo/kyNoiMWaXCNJ/GpSd0ilXas2JSOl9B5FTIhflXu0hlg==} + engines: {node: '>= 4.0.0'} + + merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + + mimic-fn@2.1.0: + resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} + engines: {node: '>=6'} + + minimist@1.2.6: + resolution: {integrity: sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + nanoid@3.3.19: + resolution: {integrity: sha512-Y2tUNy4ouw6tq5oDSKeQYGOyhkUBhNOcGV/02KC+6kd9eDGqdZd++mjMiIDilrBYvjEnCYvVtsuHCuP+okSfug==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + neo-async@2.6.2: + resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} + + no-case@3.0.4: + resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} + + node-releases@2.0.57: + resolution: {integrity: sha512-kQK9LGGFiHtrWiNhZtA7Qbw17AQz+dmsEKODRIVTXA9+e5MS/2gZEBhYJt13GrAz5/IOZKddH/0Z3TP/Zgo+yw==} + engines: {node: '>=18'} + + npm-run-path@4.0.1: + resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} + engines: {node: '>=8'} + + onetime@5.1.2: + resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} + engines: {node: '>=6'} + + open@8.4.2: + resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==} + engines: {node: '>=12'} + + parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + + parse-json@5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + postcss-modules-extract-imports@3.1.0: + resolution: {integrity: sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==} + engines: {node: ^10 || ^12 || >= 14} + peerDependencies: + postcss: ^8.1.0 + + postcss-modules-local-by-default@4.2.0: + resolution: {integrity: sha512-5kcJm/zk+GJDSfw+V/42fJ5fhjL5YbFDl8nVdXkJPLLW+Vf9mTD5Xe0wqIaDnLuL2U6cDNpTr+UQ+v2HWIBhzw==} + engines: {node: ^10 || ^12 || >= 14} + peerDependencies: + postcss: ^8.1.0 + + postcss-modules-scope@3.2.1: + resolution: {integrity: sha512-m9jZstCVaqGjTAuny8MdgE88scJnCiQSlSrOWcTQgM2t32UBe+MUmFSO5t7VMSfAf/FJKImAxBav8ooCHJXCJA==} + engines: {node: ^10 || ^12 || >= 14} + peerDependencies: + postcss: ^8.1.0 + + postcss-modules-values@4.0.0: + resolution: {integrity: sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==} + engines: {node: ^10 || ^12 || >= 14} + peerDependencies: + postcss: ^8.1.0 + + postcss-selector-parser@7.1.6: + resolution: {integrity: sha512-7qASPzhKF2l2KLboRZux8CCTRMdGiV08vWmyKzPz22qZ7ZjQBOeY7rNzNoCLSUiftJ7HUq0GERHmxw/t0dCdMw==} + engines: {node: '>=4'} + + postcss-value-parser@4.2.0: + resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} + + postcss@8.5.28: + resolution: {integrity: sha512-RRuzqDtt5Y9h3quz5hWhK+TPnsmVs6WwSU6LkJMeY4HstUEDuYTG8UJSdawMRzmzAtV+KEoG8N3Qg2qLy5vM/A==} + engines: {node: ^10 || ^12 || >=14} + + prismjs@1.30.0: + resolution: {integrity: sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==} + engines: {node: '>=6'} + + prompts@2.4.2: + resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} + engines: {node: '>= 6'} + + react-dom@19.2.4: + resolution: {integrity: sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==} + peerDependencies: + react: ^19.2.4 + + react-refresh@0.18.0: + resolution: {integrity: sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==} + engines: {node: '>=0.10.0'} + + react@19.2.4: + resolution: {integrity: sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==} + engines: {node: '>=0.10.0'} + + recast@0.23.21: + resolution: {integrity: sha512-mFAyJq9vUbSTARLZUvAEf1z3YxlvAwswbmxMx2mPA/MSm4KmpwvwvhsH/NIrZhyOuwD60Lzyw2qh83uCbgTPYw==} + engines: {node: '>= 4'} + + remotion@4.0.531: + resolution: {integrity: sha512-GchTilW0M1zk9NsYxK9pIMBeDQMiQ1TrIz3zhPpMiysf9P0rTUYwxkJ9bFANwykz4nlImpWRtUHSxZnhBYeDdw==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + + resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + scheduler@0.27.0: + resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} + + schema-utils@4.5.0: + resolution: {integrity: sha512-zJlMCZ0cAR5p/Y4oVpRoqioDMJcGxaXRrQ/4rP4WyR84vc5z/DolXdbvXeDpTwbtocDFr2rhPqHPErDCUtz2kA==} + engines: {node: '>= 10.13.0'} + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + semver@7.5.3: + resolution: {integrity: sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==} + engines: {node: '>=10'} + hasBin: true + + semver@7.8.5: + resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==} + engines: {node: '>=10'} + hasBin: true + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + signal-exit@3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + + sisteransi@1.0.5: + resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + + snake-case@3.0.4: + resolution: {integrity: sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==} + + source-map-js@1.2.2: + resolution: {integrity: sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==} + engines: {node: '>=0.10.0'} + + source-map-support@0.5.21: + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + + source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + + source-map@0.8.0: + resolution: {integrity: sha512-d8EqvL+k/SOXCreS/SUzg2ciyHqBBLcN/yuRjFsbvVhHTE2pgei7oAhmPM7kWFbkX6OSMQfUq4KbkF3au9lhYQ==} + engines: {node: '>= 12'} + + stackframe@1.3.4: + resolution: {integrity: sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==} + + strip-final-newline@2.0.0: + resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} + engines: {node: '>=6'} + + style-loader@4.0.0: + resolution: {integrity: sha512-1V4WqhhZZgjVAVJyt7TdDPZoPBPNHbekX4fWnCJL1yQukhCeZhJySUL+gL9y6sNdN95uEOS83Y55SqHcP7MzLA==} + engines: {node: '>= 18.12.0'} + peerDependencies: + webpack: ^5.27.0 + + supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + + svg-parser@2.1.0: + resolution: {integrity: sha512-bwLf38YmY+TDYHJw1Ex0Co8c4yeXuJAo8YnXGZrscxrvYoVVIvLeniEkV1Ks/54VteMnL4FtyN1+P+TZJdUPmQ==} + engines: {node: '>=8'} + + tapable@2.3.3: + resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==} + engines: {node: '>=6'} + + terser-webpack-plugin@5.6.1: + resolution: {integrity: sha512-201R5j+sJpK8nFWwKVyNfZot8FaJbLZDq5evriVzbV1wDtSXDjRUDRfJzHpAaxFDMEhsZL1QkeqM61wgsS3KaQ==} + engines: {node: '>= 10.13.0'} + peerDependencies: + '@minify-html/node': '*' + '@swc/core': '*' + '@swc/css': '*' + '@swc/html': '*' + clean-css: '*' + cssnano: '*' + csso: '*' + esbuild: '*' + html-minifier-terser: '*' + lightningcss: '*' + postcss: '*' + uglify-js: '*' + webpack: ^5.1.0 + peerDependenciesMeta: + '@minify-html/node': + optional: true + '@swc/core': + optional: true + '@swc/css': + optional: true + '@swc/html': + optional: true + clean-css: + optional: true + cssnano: + optional: true + csso: + optional: true + esbuild: + optional: true + html-minifier-terser: + optional: true + lightningcss: + optional: true + postcss: + optional: true + uglify-js: + optional: true + + terser@5.51.2: + resolution: {integrity: sha512-bWnjSNscmuI+GJze6ZupnHP8G/cTcsJF+bXCeQknk2SHQsgbNJnLrqiH9jZ2W4STPVXH2mDKKRX3iwPhc9Cn/Q==} + engines: {node: '>=10'} + hasBin: true + + tiny-invariant@1.3.3: + resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} + + to-fast-properties@2.0.0: + resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} + engines: {node: '>=4'} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true + + undici-types@6.21.0: + resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + + update-browserslist-db@1.3.3: + resolution: {integrity: sha512-pJ2sYawQS0R/WI928Gj5GlPhTGzbMelq0+4INtSYNDV9ErKJcX6xjGWkoG/VnB3dpUm00zALaqkrUD77pO5TDQ==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + watchpack@2.5.2: + resolution: {integrity: sha512-6i/00NBjP4yGPs+caKSyRfpTF/8Torsu0MOW3mMzIbhgISFder8i7xbqgHlLMwJrdiN8ndBV3UA1/AfzPSr+jg==} + engines: {node: '>=10.13.0'} + + webpack-sources@3.6.0: + resolution: {integrity: sha512-EIMmPVvNI0CYXyRPp34F2Qk7W37/BZVZIofS6LAUnrNjCVahS+hO4mxwFJDjQjODTGZDtVzLYoN2+1dYkhk9qA==} + engines: {node: '>=10.13.0'} + + webpack@5.105.0: + resolution: {integrity: sha512-gX/dMkRQc7QOMzgTe6KsYFM7DxeIONQSui1s0n/0xht36HvrgbxtM1xBlgx596NbpHuQU8P7QpKwrZYwUX48nw==} + engines: {node: '>=10.13.0'} + hasBin: true + peerDependencies: + webpack-cli: '*' + peerDependenciesMeta: + webpack-cli: + optional: true + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + ws@8.21.0: + resolution: {integrity: sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + + yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + + zod@4.5.4: + resolution: {integrity: sha512-sC95tT5iHHH9gtpj6A81kh+NEaRAUFN+qlUPDUbRfOMvNf5QCBqsb3WgvnpVtK5Y+4UfA6KqufotuTvMGiTlsA==} + +snapshots: + + '@babel/code-frame@7.29.7': + dependencies: + '@babel/helper-validator-identifier': 7.29.7 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/compat-data@7.29.7': {} + + '@babel/core@7.29.7': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/generator': 7.29.8 + '@babel/helper-compilation-targets': 7.29.7 + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7) + '@babel/helpers': 7.29.7 + '@babel/parser': 7.29.9 + '@babel/template': 7.29.7 + '@babel/traverse': 7.29.8 + '@babel/types': 7.29.8 + '@jridgewell/remapping': 2.3.5 + convert-source-map: 2.0.0 + debug: 4.4.3 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/generator@7.29.8': + dependencies: + '@babel/parser': 7.29.9 + '@babel/types': 7.29.8 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 + + '@babel/helper-compilation-targets@7.29.7': + dependencies: + '@babel/compat-data': 7.29.7 + '@babel/helper-validator-option': 7.29.7 + browserslist: 4.29.3 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-globals@7.29.7': {} + + '@babel/helper-module-imports@7.29.7': + dependencies: + '@babel/traverse': 7.29.8 + '@babel/types': 7.29.8 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-module-imports': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 + '@babel/traverse': 7.29.8 + transitivePeerDependencies: + - supports-color + + '@babel/helper-string-parser@7.29.7': {} + + '@babel/helper-validator-identifier@7.29.7': {} + + '@babel/helper-validator-option@7.29.7': {} + + '@babel/helpers@7.29.7': + dependencies: + '@babel/template': 7.29.7 + '@babel/types': 7.29.8 + + '@babel/parser@7.24.1': + dependencies: + '@babel/types': 7.29.8 + + '@babel/parser@7.29.9': + dependencies: + '@babel/types': 7.29.8 + + '@babel/template@7.29.7': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/parser': 7.29.9 + '@babel/types': 7.29.8 + + '@babel/traverse@7.29.8': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/generator': 7.29.8 + '@babel/helper-globals': 7.29.7 + '@babel/parser': 7.29.9 + '@babel/template': 7.29.7 + '@babel/types': 7.29.8 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + '@babel/types@7.24.0': + dependencies: + '@babel/helper-string-parser': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 + to-fast-properties: 2.0.0 + + '@babel/types@7.29.8': + dependencies: + '@babel/helper-string-parser': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 + + '@emnapi/core@1.11.3': + dependencies: + '@emnapi/wasi-threads': 1.2.3 + tslib: 2.8.1 + optional: true + + '@emnapi/runtime@1.11.3': + dependencies: + tslib: 2.8.1 + optional: true + + '@emnapi/wasi-threads@1.2.3': + dependencies: + tslib: 2.8.1 + optional: true + + '@esbuild/aix-ppc64@0.28.1': + optional: true + + '@esbuild/android-arm64@0.28.1': + optional: true + + '@esbuild/android-arm@0.28.1': + optional: true + + '@esbuild/android-x64@0.28.1': + optional: true + + '@esbuild/darwin-arm64@0.28.1': + optional: true + + '@esbuild/darwin-x64@0.28.1': + optional: true + + '@esbuild/freebsd-arm64@0.28.1': + optional: true + + '@esbuild/freebsd-x64@0.28.1': + optional: true + + '@esbuild/linux-arm64@0.28.1': + optional: true + + '@esbuild/linux-arm@0.28.1': + optional: true + + '@esbuild/linux-ia32@0.28.1': + optional: true + + '@esbuild/linux-loong64@0.28.1': + optional: true + + '@esbuild/linux-mips64el@0.28.1': + optional: true + + '@esbuild/linux-ppc64@0.28.1': + optional: true + + '@esbuild/linux-riscv64@0.28.1': + optional: true + + '@esbuild/linux-s390x@0.28.1': + optional: true + + '@esbuild/linux-x64@0.28.1': + optional: true + + '@esbuild/netbsd-arm64@0.28.1': + optional: true + + '@esbuild/netbsd-x64@0.28.1': + optional: true + + '@esbuild/openbsd-arm64@0.28.1': + optional: true + + '@esbuild/openbsd-x64@0.28.1': + optional: true + + '@esbuild/openharmony-arm64@0.28.1': + optional: true + + '@esbuild/sunos-x64@0.28.1': + optional: true + + '@esbuild/win32-arm64@0.28.1': + optional: true + + '@esbuild/win32-ia32@0.28.1': + optional: true + + '@esbuild/win32-x64@0.28.1': + optional: true + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.6.0 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/source-map@0.3.11': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/sourcemap-codec@1.6.0': {} + + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.6.0 + + '@mediabunny/aac-encoder@1.56.1(mediabunny@1.56.1)': + dependencies: + mediabunny: 1.56.1 + + '@mediabunny/flac-encoder@1.56.1(mediabunny@1.56.1)': + dependencies: + mediabunny: 1.56.1 + + '@mediabunny/mp3-encoder@1.56.1(mediabunny@1.56.1)': + dependencies: + mediabunny: 1.56.1 + + '@module-federation/error-codes@0.22.0': {} + + '@module-federation/runtime-core@0.22.0': + dependencies: + '@module-federation/error-codes': 0.22.0 + '@module-federation/sdk': 0.22.0 + + '@module-federation/runtime-tools@0.22.0': + dependencies: + '@module-federation/runtime': 0.22.0 + '@module-federation/webpack-bundler-runtime': 0.22.0 + + '@module-federation/runtime@0.22.0': + dependencies: + '@module-federation/error-codes': 0.22.0 + '@module-federation/runtime-core': 0.22.0 + '@module-federation/sdk': 0.22.0 + + '@module-federation/sdk@0.22.0': {} + + '@module-federation/webpack-bundler-runtime@0.22.0': + dependencies: + '@module-federation/runtime': 0.22.0 + '@module-federation/sdk': 0.22.0 + + '@napi-rs/wasm-runtime@1.0.7': + dependencies: + '@emnapi/core': 1.11.3 + '@emnapi/runtime': 1.11.3 + '@tybys/wasm-util': 0.10.4 + optional: true + + '@remotion/bundler@4.0.531(postcss@8.5.28)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@remotion/media-parser': 4.0.531 + '@remotion/studio': 4.0.531(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@remotion/studio-shared': 4.0.531(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@remotion/timeline-utils': 4.0.531(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@rspack/core': 1.7.11 + '@rspack/plugin-react-refresh': 1.6.1(react-refresh@0.18.0) + css-loader: 7.1.4(@rspack/core@1.7.11)(webpack@5.105.0(esbuild@0.28.1)(postcss@8.5.28)) + esbuild: 0.28.1 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + react-refresh: 0.18.0 + remotion: 4.0.531(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + style-loader: 4.0.0(webpack@5.105.0(esbuild@0.28.1)(postcss@8.5.28)) + webpack: 5.105.0(esbuild@0.28.1)(postcss@8.5.28) + transitivePeerDependencies: + - '@minify-html/node' + - '@remotion/video-matting' + - '@remotion/whisper-webgpu' + - '@swc/core' + - '@swc/css' + - '@swc/helpers' + - '@swc/html' + - bufferutil + - clean-css + - cssnano + - csso + - html-minifier-terser + - lightningcss + - postcss + - uglify-js + - utf-8-validate + - webpack-cli + - webpack-hot-middleware + + '@remotion/canvas@4.0.531(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@remotion/player': 4.0.531(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@remotion/studio-shared': 4.0.531(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + remotion: 4.0.531(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + + '@remotion/captions@4.0.531': {} + + '@remotion/cli@4.0.531(postcss@8.5.28)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)': + dependencies: + '@babel/parser': 7.24.1 + '@remotion/bundler': 4.0.531(postcss@8.5.28)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@remotion/media-utils': 4.0.531(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@remotion/player': 4.0.531(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@remotion/renderer': 4.0.531(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@remotion/studio': 4.0.531(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@remotion/studio-server': 4.0.531(postcss@8.5.28)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) + '@remotion/studio-shared': 4.0.531(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + dotenv: 17.3.1 + minimist: 1.2.6 + prompts: 2.4.2 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + remotion: 4.0.531(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + semver: 7.5.3 + transitivePeerDependencies: + - '@minify-html/node' + - '@remotion/video-matting' + - '@remotion/whisper-webgpu' + - '@swc/core' + - '@swc/css' + - '@swc/helpers' + - '@swc/html' + - bufferutil + - clean-css + - cssnano + - csso + - html-minifier-terser + - lightningcss + - postcss + - supports-color + - typescript + - uglify-js + - utf-8-validate + - webpack-cli + - webpack-hot-middleware + + '@remotion/codemods@4.0.531(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@babel/parser': 7.24.1 + '@babel/types': 7.24.0 + '@remotion/studio-protocol': 4.0.531 + '@remotion/studio-shared': 4.0.531(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + ast-types: 0.16.1 + recast: 0.23.21 + remotion: 4.0.531(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + transitivePeerDependencies: + - react + - react-dom + + '@remotion/compositor-darwin-arm64@4.0.531': + optional: true + + '@remotion/compositor-darwin-x64@4.0.531': + optional: true + + '@remotion/compositor-linux-arm64-gnu@4.0.531': + optional: true + + '@remotion/compositor-linux-arm64-musl@4.0.531': + optional: true + + '@remotion/compositor-linux-x64-gnu@4.0.531': + optional: true + + '@remotion/compositor-linux-x64-musl@4.0.531': + optional: true + + '@remotion/compositor-win32-x64-msvc@4.0.531': + optional: true + + '@remotion/elevenlabs@4.0.531': + dependencies: + '@remotion/captions': 4.0.531 + zod: 4.5.4 + + '@remotion/fonts@4.0.531(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + remotion: 4.0.531(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + transitivePeerDependencies: + - react + - react-dom + + '@remotion/google-fonts@4.0.531(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + remotion: 4.0.531(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + transitivePeerDependencies: + - react + - react-dom + + '@remotion/licensing@4.0.531': {} + + '@remotion/media-parser@4.0.531': {} + + '@remotion/media-utils@4.0.531(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + mediabunny: 1.56.1 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + remotion: 4.0.531(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + + '@remotion/media@4.0.531(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + mediabunny: 1.56.1 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + remotion: 4.0.531(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + zod: 4.5.4 + + '@remotion/openai-whisper@4.0.531': + dependencies: + '@remotion/captions': 4.0.531 + zod: 4.5.4 + + '@remotion/paths@4.0.531(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + remotion: 4.0.531(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + transitivePeerDependencies: + - react + - react-dom + + '@remotion/player@4.0.531(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + remotion: 4.0.531(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + + '@remotion/renderer@4.0.531(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@remotion/licensing': 4.0.531 + '@remotion/streaming': 4.0.531 + execa: 5.1.1 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + remotion: 4.0.531(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + source-map: 0.8.0 + ws: 8.21.0 + optionalDependencies: + '@remotion/compositor-darwin-arm64': 4.0.531 + '@remotion/compositor-darwin-x64': 4.0.531 + '@remotion/compositor-linux-arm64-gnu': 4.0.531 + '@remotion/compositor-linux-arm64-musl': 4.0.531 + '@remotion/compositor-linux-x64-gnu': 4.0.531 + '@remotion/compositor-linux-x64-musl': 4.0.531 + '@remotion/compositor-win32-x64-msvc': 4.0.531 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + '@remotion/shapes@4.0.531(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@remotion/paths': 4.0.531(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + remotion: 4.0.531(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + + '@remotion/streaming@4.0.531': {} + + '@remotion/studio-protocol@4.0.531': + dependencies: + zod: 4.5.4 + + '@remotion/studio-server@4.0.531(postcss@8.5.28)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)': + dependencies: + '@babel/parser': 7.24.1 + '@babel/types': 7.24.0 + '@remotion/bundler': 4.0.531(postcss@8.5.28)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@remotion/codemods': 4.0.531(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@remotion/renderer': 4.0.531(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@remotion/studio-protocol': 4.0.531 + '@remotion/studio-shared': 4.0.531(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@svgr/core': 8.1.0(typescript@5.9.3) + '@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@5.9.3)) + kiwi-schema: 0.5.0 + memfs: 3.4.3 + open: 8.4.2 + recast: 0.23.21 + remotion: 4.0.531(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + semver: 7.5.3 + zod: 4.5.4 + transitivePeerDependencies: + - '@minify-html/node' + - '@remotion/video-matting' + - '@remotion/whisper-webgpu' + - '@swc/core' + - '@swc/css' + - '@swc/helpers' + - '@swc/html' + - bufferutil + - clean-css + - cssnano + - csso + - html-minifier-terser + - lightningcss + - postcss + - react + - react-dom + - supports-color + - typescript + - uglify-js + - utf-8-validate + - webpack-cli + - webpack-hot-middleware + + '@remotion/studio-shared@4.0.531(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + remotion: 4.0.531(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + transitivePeerDependencies: + - react + - react-dom + + '@remotion/studio@4.0.531(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@jridgewell/trace-mapping': 0.3.31 + '@remotion/canvas': 4.0.531(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@remotion/captions': 4.0.531 + '@remotion/codemods': 4.0.531(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@remotion/elevenlabs': 4.0.531 + '@remotion/media': 4.0.531(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@remotion/media-utils': 4.0.531(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@remotion/openai-whisper': 4.0.531 + '@remotion/paths': 4.0.531(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@remotion/player': 4.0.531(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@remotion/renderer': 4.0.531(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@remotion/studio-protocol': 4.0.531 + '@remotion/studio-shared': 4.0.531(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@remotion/timeline-utils': 4.0.531(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@remotion/web-renderer': 4.0.531(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@remotion/zod-types': 4.0.531(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/react-virtual': 3.14.9(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + mediabunny: 1.56.1 + memfs: 3.4.3 + open: 8.4.2 + prismjs: 1.30.0 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + remotion: 4.0.531(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + semver: 7.5.3 + zod: 4.5.4 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + '@remotion/timeline-utils@4.0.531(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + mediabunny: 1.56.1 + remotion: 4.0.531(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + transitivePeerDependencies: + - react + - react-dom + + '@remotion/transitions@4.0.531(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@remotion/paths': 4.0.531(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@remotion/shapes': 4.0.531(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + remotion: 4.0.531(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + + '@remotion/web-renderer@4.0.531(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@mediabunny/aac-encoder': 1.56.1(mediabunny@1.56.1) + '@mediabunny/flac-encoder': 1.56.1(mediabunny@1.56.1) + '@mediabunny/mp3-encoder': 1.56.1(mediabunny@1.56.1) + '@remotion/licensing': 4.0.531 + mediabunny: 1.56.1 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + remotion: 4.0.531(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + + '@remotion/zod-types@4.0.531(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + remotion: 4.0.531(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + transitivePeerDependencies: + - react + - react-dom + + '@rspack/binding-darwin-arm64@1.7.11': + optional: true + + '@rspack/binding-darwin-x64@1.7.11': + optional: true + + '@rspack/binding-linux-arm64-gnu@1.7.11': + optional: true + + '@rspack/binding-linux-arm64-musl@1.7.11': + optional: true + + '@rspack/binding-linux-x64-gnu@1.7.11': + optional: true + + '@rspack/binding-linux-x64-musl@1.7.11': + optional: true + + '@rspack/binding-wasm32-wasi@1.7.11': + dependencies: + '@napi-rs/wasm-runtime': 1.0.7 + optional: true + + '@rspack/binding-win32-arm64-msvc@1.7.11': + optional: true + + '@rspack/binding-win32-ia32-msvc@1.7.11': + optional: true + + '@rspack/binding-win32-x64-msvc@1.7.11': + optional: true + + '@rspack/binding@1.7.11': + optionalDependencies: + '@rspack/binding-darwin-arm64': 1.7.11 + '@rspack/binding-darwin-x64': 1.7.11 + '@rspack/binding-linux-arm64-gnu': 1.7.11 + '@rspack/binding-linux-arm64-musl': 1.7.11 + '@rspack/binding-linux-x64-gnu': 1.7.11 + '@rspack/binding-linux-x64-musl': 1.7.11 + '@rspack/binding-wasm32-wasi': 1.7.11 + '@rspack/binding-win32-arm64-msvc': 1.7.11 + '@rspack/binding-win32-ia32-msvc': 1.7.11 + '@rspack/binding-win32-x64-msvc': 1.7.11 + + '@rspack/core@1.7.11': + dependencies: + '@module-federation/runtime-tools': 0.22.0 + '@rspack/binding': 1.7.11 + '@rspack/lite-tapable': 1.1.0 + + '@rspack/lite-tapable@1.1.0': {} + + '@rspack/plugin-react-refresh@1.6.1(react-refresh@0.18.0)': + dependencies: + error-stack-parser: 2.1.4 + html-entities: 2.6.0 + react-refresh: 0.18.0 + + '@svgr/babel-plugin-add-jsx-attribute@8.0.0(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + + '@svgr/babel-plugin-remove-jsx-attribute@8.0.0(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + + '@svgr/babel-plugin-remove-jsx-empty-expression@8.0.0(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + + '@svgr/babel-plugin-replace-jsx-attribute-value@8.0.0(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + + '@svgr/babel-plugin-svg-dynamic-title@8.0.0(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + + '@svgr/babel-plugin-svg-em-dimensions@8.0.0(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + + '@svgr/babel-plugin-transform-react-native-svg@8.1.0(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + + '@svgr/babel-plugin-transform-svg-component@8.0.0(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + + '@svgr/babel-preset@8.1.0(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@svgr/babel-plugin-add-jsx-attribute': 8.0.0(@babel/core@7.29.7) + '@svgr/babel-plugin-remove-jsx-attribute': 8.0.0(@babel/core@7.29.7) + '@svgr/babel-plugin-remove-jsx-empty-expression': 8.0.0(@babel/core@7.29.7) + '@svgr/babel-plugin-replace-jsx-attribute-value': 8.0.0(@babel/core@7.29.7) + '@svgr/babel-plugin-svg-dynamic-title': 8.0.0(@babel/core@7.29.7) + '@svgr/babel-plugin-svg-em-dimensions': 8.0.0(@babel/core@7.29.7) + '@svgr/babel-plugin-transform-react-native-svg': 8.1.0(@babel/core@7.29.7) + '@svgr/babel-plugin-transform-svg-component': 8.0.0(@babel/core@7.29.7) + + '@svgr/core@8.1.0(typescript@5.9.3)': + dependencies: + '@babel/core': 7.29.7 + '@svgr/babel-preset': 8.1.0(@babel/core@7.29.7) + camelcase: 6.3.0 + cosmiconfig: 8.3.6(typescript@5.9.3) + snake-case: 3.0.4 + transitivePeerDependencies: + - supports-color + - typescript + + '@svgr/hast-util-to-babel-ast@8.0.0': + dependencies: + '@babel/types': 7.24.0 + entities: 4.5.0 + + '@svgr/plugin-jsx@8.1.0(@svgr/core@8.1.0(typescript@5.9.3))': + dependencies: + '@babel/core': 7.29.7 + '@svgr/babel-preset': 8.1.0(@babel/core@7.29.7) + '@svgr/core': 8.1.0(typescript@5.9.3) + '@svgr/hast-util-to-babel-ast': 8.0.0 + svg-parser: 2.1.0 + transitivePeerDependencies: + - supports-color + + '@tanstack/react-virtual@3.14.9(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@tanstack/virtual-core': 3.17.7 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@tanstack/virtual-core@3.17.7': {} + + '@tybys/wasm-util@0.10.4': + dependencies: + tslib: 2.8.1 + optional: true + + '@types/culori@4.0.1': {} + + '@types/dom-mediacapture-transform@0.1.12': + dependencies: + '@types/dom-webcodecs': 0.1.13 + + '@types/dom-webcodecs@0.1.13': {} + + '@types/eslint-scope@3.7.7': + dependencies: + '@types/eslint': 9.6.1 + '@types/estree': 1.0.9 + + '@types/eslint@9.6.1': + dependencies: + '@types/estree': 1.0.9 + '@types/json-schema': 7.0.15 + + '@types/estree@1.0.9': {} + + '@types/json-schema@7.0.15': {} + + '@types/node@22.20.4': + dependencies: + undici-types: 6.21.0 + + '@types/react-dom@19.3.0(@types/react@19.3.0)': + dependencies: + '@types/react': 19.3.0 + + '@types/react@19.3.0': + dependencies: + csstype: 3.2.3 + + '@webassemblyjs/ast@1.14.1': + dependencies: + '@webassemblyjs/helper-numbers': 1.13.2 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + + '@webassemblyjs/floating-point-hex-parser@1.13.2': {} + + '@webassemblyjs/helper-api-error@1.13.2': {} + + '@webassemblyjs/helper-buffer@1.14.1': {} + + '@webassemblyjs/helper-numbers@1.13.2': + dependencies: + '@webassemblyjs/floating-point-hex-parser': 1.13.2 + '@webassemblyjs/helper-api-error': 1.13.2 + '@xtuc/long': 4.2.2 + + '@webassemblyjs/helper-wasm-bytecode@1.13.2': {} + + '@webassemblyjs/helper-wasm-section@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-buffer': 1.14.1 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/wasm-gen': 1.14.1 + + '@webassemblyjs/ieee754@1.13.2': + dependencies: + '@xtuc/ieee754': 1.2.0 + + '@webassemblyjs/leb128@1.13.2': + dependencies: + '@xtuc/long': 4.2.2 + + '@webassemblyjs/utf8@1.13.2': {} + + '@webassemblyjs/wasm-edit@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-buffer': 1.14.1 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/helper-wasm-section': 1.14.1 + '@webassemblyjs/wasm-gen': 1.14.1 + '@webassemblyjs/wasm-opt': 1.14.1 + '@webassemblyjs/wasm-parser': 1.14.1 + '@webassemblyjs/wast-printer': 1.14.1 + + '@webassemblyjs/wasm-gen@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/ieee754': 1.13.2 + '@webassemblyjs/leb128': 1.13.2 + '@webassemblyjs/utf8': 1.13.2 + + '@webassemblyjs/wasm-opt@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-buffer': 1.14.1 + '@webassemblyjs/wasm-gen': 1.14.1 + '@webassemblyjs/wasm-parser': 1.14.1 + + '@webassemblyjs/wasm-parser@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-api-error': 1.13.2 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/ieee754': 1.13.2 + '@webassemblyjs/leb128': 1.13.2 + '@webassemblyjs/utf8': 1.13.2 + + '@webassemblyjs/wast-printer@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@xtuc/long': 4.2.2 + + '@xtuc/ieee754@1.2.0': {} + + '@xtuc/long@4.2.2': {} + + acorn-import-phases@1.0.4(acorn@8.18.0): + dependencies: + acorn: 8.18.0 + + acorn@8.18.0: {} + + ajv-formats@3.0.1(ajv@8.20.0): + optionalDependencies: + ajv: 8.20.0 + + ajv-keywords@5.1.0(ajv@8.20.0): + dependencies: + ajv: 8.20.0 + fast-deep-equal: 3.1.3 + + ajv@8.20.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.1.8 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + + argparse@2.0.1: {} + + ast-types@0.16.1: + dependencies: + tslib: 2.8.1 + + ast-types@0.16.3: + dependencies: + tslib: 2.8.1 + + baseline-browser-mapping@2.11.26: {} + + browserslist@4.29.3: + dependencies: + baseline-browser-mapping: 2.11.26 + caniuse-lite: 1.0.30001814 + electron-to-chromium: 1.5.443 + node-releases: 2.0.57 + update-browserslist-db: 1.3.3(browserslist@4.29.3) + + buffer-from@1.1.2: {} + + callsites@3.1.0: {} + + camelcase@6.3.0: {} + + caniuse-lite@1.0.30001814: {} + + chrome-trace-event@1.0.4: {} + + commander@2.20.3: {} + + convert-source-map@2.0.0: {} + + cosmiconfig@8.3.6(typescript@5.9.3): + dependencies: + import-fresh: 3.3.1 + js-yaml: 4.3.2 + parse-json: 5.2.0 + path-type: 4.0.0 + optionalDependencies: + typescript: 5.9.3 + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + css-loader@7.1.4(@rspack/core@1.7.11)(webpack@5.105.0(esbuild@0.28.1)(postcss@8.5.28)): + dependencies: + icss-utils: 5.1.0(postcss@8.5.28) + postcss: 8.5.28 + postcss-modules-extract-imports: 3.1.0(postcss@8.5.28) + postcss-modules-local-by-default: 4.2.0(postcss@8.5.28) + postcss-modules-scope: 3.2.1(postcss@8.5.28) + postcss-modules-values: 4.0.0(postcss@8.5.28) + postcss-value-parser: 4.2.0 + semver: 7.8.5 + optionalDependencies: + '@rspack/core': 1.7.11 + webpack: 5.105.0(esbuild@0.28.1)(postcss@8.5.28) + + cssesc@3.0.0: {} + + csstype@3.2.3: {} + + culori@4.0.2: {} + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + define-lazy-prop@2.0.0: {} + + dot-case@3.0.4: + dependencies: + no-case: 3.0.4 + tslib: 2.8.1 + + dotenv@17.3.1: {} + + electron-to-chromium@1.5.443: {} + + enhanced-resolve@5.26.0: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.3.3 + + entities@4.5.0: {} + + error-ex@1.3.4: + dependencies: + is-arrayish: 0.2.1 + + error-stack-parser@2.1.4: + dependencies: + stackframe: 1.3.4 + + es-module-lexer@2.3.2: {} + + esbuild@0.28.1: + optionalDependencies: + '@esbuild/aix-ppc64': 0.28.1 + '@esbuild/android-arm': 0.28.1 + '@esbuild/android-arm64': 0.28.1 + '@esbuild/android-x64': 0.28.1 + '@esbuild/darwin-arm64': 0.28.1 + '@esbuild/darwin-x64': 0.28.1 + '@esbuild/freebsd-arm64': 0.28.1 + '@esbuild/freebsd-x64': 0.28.1 + '@esbuild/linux-arm': 0.28.1 + '@esbuild/linux-arm64': 0.28.1 + '@esbuild/linux-ia32': 0.28.1 + '@esbuild/linux-loong64': 0.28.1 + '@esbuild/linux-mips64el': 0.28.1 + '@esbuild/linux-ppc64': 0.28.1 + '@esbuild/linux-riscv64': 0.28.1 + '@esbuild/linux-s390x': 0.28.1 + '@esbuild/linux-x64': 0.28.1 + '@esbuild/netbsd-arm64': 0.28.1 + '@esbuild/netbsd-x64': 0.28.1 + '@esbuild/openbsd-arm64': 0.28.1 + '@esbuild/openbsd-x64': 0.28.1 + '@esbuild/openharmony-arm64': 0.28.1 + '@esbuild/sunos-x64': 0.28.1 + '@esbuild/win32-arm64': 0.28.1 + '@esbuild/win32-ia32': 0.28.1 + '@esbuild/win32-x64': 0.28.1 + + escalade@3.2.0: {} + + eslint-scope@5.1.1: + dependencies: + esrecurse: 4.3.0 + estraverse: 4.3.0 + + esprima@4.0.1: {} + + esrecurse@4.3.0: + dependencies: + estraverse: 5.3.0 + + estraverse@4.3.0: {} + + estraverse@5.3.0: {} + + events@3.3.0: {} + + execa@5.1.1: + dependencies: + cross-spawn: 7.0.6 + get-stream: 6.0.1 + human-signals: 2.1.0 + is-stream: 2.0.1 + merge-stream: 2.0.0 + npm-run-path: 4.0.1 + onetime: 5.1.2 + signal-exit: 3.0.7 + strip-final-newline: 2.0.0 + + fast-deep-equal@3.1.3: {} + + fast-uri@3.1.8: {} + + fs-monkey@1.0.3: {} + + gensync@1.0.0-beta.2: {} + + get-stream@6.0.1: {} + + glob-to-regexp@0.4.1: {} + + graceful-fs@4.2.11: {} + + has-flag@4.0.0: {} + + html-entities@2.6.0: {} + + human-signals@2.1.0: {} + + icss-utils@5.1.0(postcss@8.5.28): + dependencies: + postcss: 8.5.28 + + import-fresh@3.3.1: + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + + is-arrayish@0.2.1: {} + + is-docker@2.2.1: {} + + is-stream@2.0.1: {} + + is-wsl@2.2.0: + dependencies: + is-docker: 2.2.1 + + isexe@2.0.0: {} + + jest-worker@27.5.1: + dependencies: + '@types/node': 22.20.4 + merge-stream: 2.0.0 + supports-color: 8.1.1 + + js-tokens@4.0.0: {} + + js-yaml@4.3.2: + dependencies: + argparse: 2.0.1 + + jsesc@3.1.0: {} + + json-parse-even-better-errors@2.3.1: {} + + json-schema-traverse@1.0.0: {} + + json5@2.2.3: {} + + kiwi-schema@0.5.0: {} + + kleur@3.0.3: {} + + lines-and-columns@1.2.4: {} + + loader-runner@4.3.2: {} + + lower-case@2.0.2: + dependencies: + tslib: 2.8.1 + + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 + + lru-cache@6.0.0: + dependencies: + yallist: 4.0.0 + + lucide-react@1.49.0(@types/react@19.3.0)(react@19.2.4): + dependencies: + react: 19.2.4 + optionalDependencies: + '@types/react': 19.3.0 + + mediabunny@1.56.1: + dependencies: + '@types/dom-mediacapture-transform': 0.1.12 + '@types/dom-webcodecs': 0.1.13 + + memfs@3.4.3: + dependencies: + fs-monkey: 1.0.3 + + merge-stream@2.0.0: {} + + mime-db@1.52.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + + mimic-fn@2.1.0: {} + + minimist@1.2.6: {} + + ms@2.1.3: {} + + nanoid@3.3.19: {} + + neo-async@2.6.2: {} + + no-case@3.0.4: + dependencies: + lower-case: 2.0.2 + tslib: 2.8.1 + + node-releases@2.0.57: {} + + npm-run-path@4.0.1: + dependencies: + path-key: 3.1.1 + + onetime@5.1.2: + dependencies: + mimic-fn: 2.1.0 + + open@8.4.2: + dependencies: + define-lazy-prop: 2.0.0 + is-docker: 2.2.1 + is-wsl: 2.2.0 + + parent-module@1.0.1: + dependencies: + callsites: 3.1.0 + + parse-json@5.2.0: + dependencies: + '@babel/code-frame': 7.29.7 + error-ex: 1.3.4 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 + + path-key@3.1.1: {} + + path-type@4.0.0: {} + + picocolors@1.1.1: {} + + postcss-modules-extract-imports@3.1.0(postcss@8.5.28): + dependencies: + postcss: 8.5.28 + + postcss-modules-local-by-default@4.2.0(postcss@8.5.28): + dependencies: + icss-utils: 5.1.0(postcss@8.5.28) + postcss: 8.5.28 + postcss-selector-parser: 7.1.6 + postcss-value-parser: 4.2.0 + + postcss-modules-scope@3.2.1(postcss@8.5.28): + dependencies: + postcss: 8.5.28 + postcss-selector-parser: 7.1.6 + + postcss-modules-values@4.0.0(postcss@8.5.28): + dependencies: + icss-utils: 5.1.0(postcss@8.5.28) + postcss: 8.5.28 + + postcss-selector-parser@7.1.6: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + + postcss-value-parser@4.2.0: {} + + postcss@8.5.28: + dependencies: + nanoid: 3.3.19 + picocolors: 1.1.1 + source-map-js: 1.2.2 + + prismjs@1.30.0: {} + + prompts@2.4.2: + dependencies: + kleur: 3.0.3 + sisteransi: 1.0.5 + + react-dom@19.2.4(react@19.2.4): + dependencies: + react: 19.2.4 + scheduler: 0.27.0 + + react-refresh@0.18.0: {} + + react@19.2.4: {} + + recast@0.23.21: + dependencies: + ast-types: 0.16.3 + esprima: 4.0.1 + source-map: 0.6.1 + tiny-invariant: 1.3.3 + tslib: 2.8.1 + + remotion@4.0.531(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + dependencies: + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + require-from-string@2.0.2: {} + + resolve-from@4.0.0: {} + + scheduler@0.27.0: {} + + schema-utils@4.5.0: + dependencies: + '@types/json-schema': 7.0.15 + ajv: 8.20.0 + ajv-formats: 3.0.1(ajv@8.20.0) + ajv-keywords: 5.1.0(ajv@8.20.0) + + semver@6.3.1: {} + + semver@7.5.3: + dependencies: + lru-cache: 6.0.0 + + semver@7.8.5: {} + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + signal-exit@3.0.7: {} + + sisteransi@1.0.5: {} + + snake-case@3.0.4: + dependencies: + dot-case: 3.0.4 + tslib: 2.8.1 + + source-map-js@1.2.2: {} + + source-map-support@0.5.21: + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + + source-map@0.6.1: {} + + source-map@0.8.0: {} + + stackframe@1.3.4: {} + + strip-final-newline@2.0.0: {} + + style-loader@4.0.0(webpack@5.105.0(esbuild@0.28.1)(postcss@8.5.28)): + dependencies: + webpack: 5.105.0(esbuild@0.28.1)(postcss@8.5.28) + + supports-color@8.1.1: + dependencies: + has-flag: 4.0.0 + + svg-parser@2.1.0: {} + + tapable@2.3.3: {} + + terser-webpack-plugin@5.6.1(esbuild@0.28.1)(postcss@8.5.28)(webpack@5.105.0(postcss@8.5.28)): + dependencies: + '@jridgewell/trace-mapping': 0.3.31 + jest-worker: 27.5.1 + schema-utils: 4.5.0 + terser: 5.51.2 + webpack: 5.105.0(esbuild@0.28.1)(postcss@8.5.28) + optionalDependencies: + esbuild: 0.28.1 + postcss: 8.5.28 + + terser@5.51.2: + dependencies: + '@jridgewell/source-map': 0.3.11 + acorn: 8.18.0 + commander: 2.20.3 + source-map-support: 0.5.21 + + tiny-invariant@1.3.3: {} + + to-fast-properties@2.0.0: {} + + tslib@2.8.1: {} + + typescript@5.9.3: {} + + undici-types@6.21.0: {} + + update-browserslist-db@1.3.3(browserslist@4.29.3): + dependencies: + browserslist: 4.29.3 + escalade: 3.2.0 + picocolors: 1.1.1 + + util-deprecate@1.0.2: {} + + watchpack@2.5.2: + dependencies: + graceful-fs: 4.2.11 + + webpack-sources@3.6.0: {} + + webpack@5.105.0(esbuild@0.28.1)(postcss@8.5.28): + dependencies: + '@types/eslint-scope': 3.7.7 + '@types/estree': 1.0.9 + '@types/json-schema': 7.0.15 + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/wasm-edit': 1.14.1 + '@webassemblyjs/wasm-parser': 1.14.1 + acorn: 8.18.0 + acorn-import-phases: 1.0.4(acorn@8.18.0) + browserslist: 4.29.3 + chrome-trace-event: 1.0.4 + enhanced-resolve: 5.26.0 + es-module-lexer: 2.3.2 + eslint-scope: 5.1.1 + events: 3.3.0 + glob-to-regexp: 0.4.1 + graceful-fs: 4.2.11 + json-parse-even-better-errors: 2.3.1 + loader-runner: 4.3.2 + mime-types: 2.1.35 + neo-async: 2.6.2 + schema-utils: 4.5.0 + tapable: 2.3.3 + terser-webpack-plugin: 5.6.1(esbuild@0.28.1)(postcss@8.5.28)(webpack@5.105.0(postcss@8.5.28)) + watchpack: 2.5.2 + webpack-sources: 3.6.0 + transitivePeerDependencies: + - '@minify-html/node' + - '@swc/core' + - '@swc/css' + - '@swc/html' + - clean-css + - cssnano + - csso + - esbuild + - html-minifier-terser + - lightningcss + - postcss + - uglify-js + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + ws@8.21.0: {} + + yallist@3.1.1: {} + + yallist@4.0.0: {} + + zod@4.5.4: {} diff --git a/video/public/fonts/ClarityCity-Bold.woff2 b/video/public/fonts/ClarityCity-Bold.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..da8c2fa6b791ed70d04ab9b3a8a65b8a59e93c92 GIT binary patch literal 17168 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�ERTB@>%BxL!6&M@(i>%gP^{|Agx}4DT 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 XkM;@ZlMC432i<_?!|6N{Xl?)i*Ge~f literal 0 HcmV?d00001 diff --git a/video/public/fonts/ClarityCity-ExtraBold.woff2 b/video/public/fonts/ClarityCity-ExtraBold.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..1a3f07a760c9cad5a7832b6127381c7fc6f18205 GIT binary patch literal 17200 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 D6B1+@ literal 0 HcmV?d00001 diff --git a/video/public/fonts/ClarityCity-Medium.woff2 b/video/public/fonts/ClarityCity-Medium.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..b1786a898329bf47576bbb6b0d04cd53f22c706c GIT binary patch literal 17092 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 literal 0 HcmV?d00001 diff --git a/video/public/fonts/ClarityCity-Regular.woff2 b/video/public/fonts/ClarityCity-Regular.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..feedf7f5881d5ca3cb74153285fd849b7491ae43 GIT binary patch literal 16856 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 XH3rYU|JTIFBCz&NOCeZW0{{R3ACkm= literal 0 HcmV?d00001 diff --git a/video/public/fonts/ClarityCity-SemiBold.woff2 b/video/public/fonts/ClarityCity-SemiBold.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..a7dbc8c3a8271193136416fb6c4fcace0f89921a GIT binary patch literal 17252 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 DlDK)6 literal 0 HcmV?d00001 diff --git a/video/remotion.config.ts b/video/remotion.config.ts new file mode 100644 index 0000000..ffc9080 --- /dev/null +++ b/video/remotion.config.ts @@ -0,0 +1,19 @@ +import path from "node:path"; +import { Config } from "@remotion/cli/config"; + +Config.setVideoImageFormat("jpeg"); +Config.setJpegQuality(92); +Config.setOverwriteOutput(true); +Config.setConcurrency(4); + +// remocn bileşenleri "@/..." yollarıyla import eder (shadcn alias'ı) +Config.overrideWebpackConfig((config) => ({ + ...config, + resolve: { + ...config.resolve, + alias: { + ...(config.resolve?.alias ?? {}), + "@": path.join(process.cwd(), "src"), + }, + }, +})); diff --git a/video/src/Lansman.tsx b/video/src/Lansman.tsx new file mode 100644 index 0000000..d977b2c --- /dev/null +++ b/video/src/Lansman.tsx @@ -0,0 +1,100 @@ +import { linearTiming, TransitionSeries } from "@remotion/transitions"; +import { AbsoluteFill, useCurrentFrame } from "remotion"; +import { pushThrough } from "@/components/remocn/push-through"; +import { Gren } from "./bilesenler/Gren"; +import "./fontlar"; +import { useFontlarHazir } from "./fontlar-hazir"; +import { pikselDalga } from "./gecisler/piksel-dalga"; +import { R } from "./marka"; +import { S1Gurultu } from "./sahneler/S1Gurultu"; +import { haritaTiklama, S2Harita } from "./sahneler/S2Harita"; +import { S3Siralama, siralamaTiklama } from "./sahneler/S3Siralama"; +import { havuzTiklama, S4Havuz } from "./sahneler/S4Havuz"; +import { danismanDalgaNoktasi, S5Danisman } from "./sahneler/S5Danisman"; +import { degerDalgaNoktasi, S6Deger } from "./sahneler/S6Deger"; +import { S7Kapanis } from "./sahneler/S7Kapanis"; +import { GECIS, SAHNE } from "./zaman"; + +// Sahnelerin küresel başlangıç kareleri (geçişler üst üste biner) +const SIRA = [ + [SAHNE.gurultu, GECIS.g1], + [SAHNE.harita, GECIS.g2], + [SAHNE.siralama, GECIS.g3], + [SAHNE.havuz, GECIS.g4], + [SAHNE.danisman, GECIS.g5], + [SAHNE.deger, GECIS.g6], +] as const; +const BASLAR = SIRA.reduce((acc, [s, g]) => [...acc, acc[acc.length - 1] + s - g], [0]); +const KAPANIS_BASI = BASLAR[6]; + +export const Lansman: React.FC = () => { + useFontlarHazir(); + const f = useCurrentFrame(); + // Koyu sahnelerde gren daha belirgin ve açık zerreli + const koyu = f < SAHNE.gurultu - 14 || f > KAPANIS_BASI + 14; + + return ( + + + + + + {/* Tek piksel patlar: koyudan açığa, merkezden */} + + + + + {/* İmleç logonun turuncu karesine tıklar → dalga oradan */} + + + + + {/* CTA'ya basılır → sahne butonun içinden geçilerek terk edilir */} + + + + + {/* Listedeki satıra tıklanır → satırın içinden danışmana */} + + + + + {/* Trendin son (2026) pikselinden dalga */} + + + + + {/* Son gösterge karesinden koyu dalga: kapanışın CTA bandına */} + + + + + + + + ); +}; diff --git a/video/src/Root.tsx b/video/src/Root.tsx new file mode 100644 index 0000000..982206d --- /dev/null +++ b/video/src/Root.tsx @@ -0,0 +1,15 @@ +import { Composition } from "remotion"; +import { Lansman } from "./Lansman"; +import { FPS, H, W } from "./marka"; +import { TOPLAM } from "./zaman"; + +export const RemotionRoot: React.FC = () => ( + +); diff --git a/video/src/bilesenler/Gren.tsx b/video/src/bilesenler/Gren.tsx new file mode 100644 index 0000000..9866c78 --- /dev/null +++ b/video/src/bilesenler/Gren.tsx @@ -0,0 +1,60 @@ +import { AbsoluteFill, useCurrentFrame } from "remotion"; +import { H, W } from "../marka"; + +/** + * Film greni: her karede tohumu değişen fraktal gürültü (deterministik — + * aynı kare her render'da aynı greni verir). Tüm videonun üstünde durur; + * `guc` koyu sahnelerde artırılır. + */ +export const Gren: React.FC<{ guc: number; koyu?: boolean }> = ({ + guc, + koyu = false, +}) => { + const frame = useCurrentFrame(); + if (guc <= 0) return null; + const id = `gren-${frame}`; + return ( + + + + + {/* Tek kanallı gren: renkli gürültü değil */} + + {/* Açık sahnede yalnız koyu zerreler (multiply), koyuda yalnız açık + zerreler (screen) kalsın diye ortalama kaydırılıp kontrast verilir */} + + + + + + + + + + ); +}; + +/** Koyu sahnelerde kenar kararması */ +export const Vinyet: React.FC<{ guc?: number }> = ({ guc = 0.55 }) => ( + +); diff --git a/video/src/bilesenler/Imlec.tsx b/video/src/bilesenler/Imlec.tsx new file mode 100644 index 0000000..5c35a67 --- /dev/null +++ b/video/src/bilesenler/Imlec.tsx @@ -0,0 +1,84 @@ +import { useCurrentFrame } from "remotion"; +import { Cursor } from "@/components/remocn/cursor"; +import { + cursorPathAt, + type CursorWaypoint, +} from "@/components/remocn/use-cursor-path"; +import { R } from "../marka"; +import { aralik } from "../yardimci"; + +export type Yol = CursorWaypoint[]; + +/** + * remocn Cursor + useCursorPath, sitenin diline göre: koyu ok, beyaz kontur, + * tıklamada turuncu halka. Tıklanabilir bir şeyin üstündeyken el imlecine + * döner (sitede butonlar `cursor-pointer`). + */ +export const Imlec: React.FC<{ + yol: Yol; + /** [görünmeye başladığı kare, kaybolduğu kare] */ + gorunur?: [number, number]; + /** El imleci gösterilecek kare aralıkları */ + el?: [number, number][]; + boy?: number; +}> = ({ yol, gorunur = [0, 1e9], el = [], boy = 46 }) => { + const frame = useCurrentFrame(); + const st = cursorPathAt(yol, frame); + const op = + aralik(frame, gorunur[0], gorunur[0] + 8) * + (1 - aralik(frame, gorunur[1] - 8, gorunur[1])); + const elMi = el.some(([a, b]) => frame >= a && frame <= b); + if (op <= 0) return null; + // El imlecinin sıcak noktası parmak ucunda (viewBox 24'te x≈9.5): tıklama + // noktası ok ucuyla aynı kalsın diye kaydırılır. + const kaydir = elMi ? (9.5 / 24) * boy : (1 / 24) * boy; + return ( +
+ +
+ ); +}; + +export type IsiOrnek = { x: number; y: number; w: number }; + +/** + * Sitenin imleç ısı fırçası (use-pixel-heat.ts) video karşılığı: imleç + * yaklaşınca pikseller anında ısınır, uzaklaşınca yavaş soğur. İmleç yolu saf + * bir fonksiyon olduğu için geçmiş kareler yeniden hesaplanır — iz + * deterministiktir. + */ +export function isiIzi( + yol: Yol, + frame: number, + gorunur: [number, number] = [0, 1e9], + iz = 26, +): IsiOrnek[] { + const out: IsiOrnek[] = []; + for (let k = 0; k <= iz; k += 2) { + const f = frame - k; + if (f < gorunur[0] || f > gorunur[1]) continue; + const p = cursorPathAt(yol, f); + out.push({ x: p.x, y: p.y, w: k === 0 ? 1 : (1 - k / (iz + 2)) ** 1.7 }); + } + return out; +} + +export function isi(x: number, y: number, izler: IsiOrnek[], r: number) { + let h = 0; + const r2 = r * r; + for (const o of izler) { + const dx = x - o.x; + const dy = y - o.y; + const v = Math.exp(-(dx * dx + dy * dy) / r2) * o.w; + if (v > h) h = v; + } + return h; +} + +export { cursorPathAt }; diff --git a/video/src/bilesenler/Kinetik.tsx b/video/src/bilesenler/Kinetik.tsx new file mode 100644 index 0000000..41e8b71 --- /dev/null +++ b/video/src/bilesenler/Kinetik.tsx @@ -0,0 +1,48 @@ +import { useCurrentFrame } from "remotion"; +import { aralik, ease } from "../yardimci"; + +/** + * Metin çıkışı (remocn blur-out-up'ın sarmalayıcı hâli): içerik + * [bas, bas+sure] arasında yukarı kayar, bulanıklaşır ve söner. + * `giris` verilirse aynı yoldan tersine belirir. + */ +export const Cikis: React.FC<{ + bas: number; + sure?: number; + giris?: [number, number]; + yol?: number; + children: React.ReactNode; + style?: React.CSSProperties; +}> = ({ bas, sure = 10, giris, yol = 34, children, style }) => { + const f = useCurrentFrame(); + const c = aralik(f, bas, bas + sure, ease.in); + const g = giris ? aralik(f, giris[0], giris[1], ease.out) : 1; + return ( +
+ {children} +
+ ); +}; + +/** Mutlak konumlu kutu: kinetik bileşenler (inset:0 ortalar) bu kutuya göre ortalanır */ +export const Kutu: React.FC<{ + x?: number; + y: number; + w?: number; + h: number; + children: React.ReactNode; + style?: React.CSSProperties; +}> = ({ x = 0, y, w = 1920, h, children, style }) => ( +
+ {children} +
+); diff --git a/video/src/bilesenler/Logo.tsx b/video/src/bilesenler/Logo.tsx new file mode 100644 index 0000000..7506d7e --- /dev/null +++ b/video/src/bilesenler/Logo.tsx @@ -0,0 +1,94 @@ +import { LOGO_KARELER, R } from "../marka"; +import { FONT } from "../fontlar"; + +/** + * Logo işareti: üç kare (public/kolay-tercih-mark.svg). `kareStil` ile her + * kare ayrı ayrı oynatılabilir (animasyonlu-mark.tsx'teki "rota"/"nabız"). + */ +export const LogoIsaret: React.FC<{ + boy: number; + kareStil?: (i: number) => { dx?: number; dy?: number; olcek?: number; opaklik?: number }; + style?: React.CSSProperties; +}> = ({ boy, kareStil, style }) => ( + + {LOGO_KARELER.map((k, i) => { + const s = kareStil?.(i) ?? {}; + const cx = k.x + k.boy / 2 + (s.dx ?? 0); + const cy = k.y + k.boy / 2 + (s.dy ?? 0); + const o = s.olcek ?? 1; + return ( + + ); + })} + +); + +/** "Kolay" Bricolage 300 + "Tercih" 600, tracking -0.05em (logo svg'si) */ +export const Kelime: React.FC<{ boy: number; renk?: string }> = ({ + boy, + renk = "#0a0a0a", +}) => ( + + Kolay + Tercih + +); + +/** Rozet ikonu PixelMark (pixel-decor.tsx): 2×2 piksel, sağ üst turuncu */ +export const PikselIsaret: React.FC<{ boy: number }> = ({ boy }) => ( + + + + + + +); + +/** + * SectionEyebrow'un video karşılığı (2×): piksel imzalı rozet. + * `inline-flex items-center gap-2 rounded-full border border-slate-200 + * bg-white px-3.5 py-1.5 text-xs font-semibold text-primary` + */ +export const Rozet: React.FC<{ children: React.ReactNode; style?: React.CSSProperties }> = ({ + children, + style, +}) => ( + + + {children} + +); diff --git a/video/src/bilesenler/PikselZemin.tsx b/video/src/bilesenler/PikselZemin.tsx new file mode 100644 index 0000000..fe6d002 --- /dev/null +++ b/video/src/bilesenler/PikselZemin.tsx @@ -0,0 +1,55 @@ +import { useCurrentFrame } from "remotion"; +import { H, PIKSEL, R, W, opaklikFor } from "../marka"; +import { clamp01, hash, karis } from "../yardimci"; +import { isi, type IsiOrnek } from "./Imlec"; + +/** + * Sahne kenarlarında hero dokusu (PikselZemin'in video hâli): ortası boş, + * kenara yaklaştıkça sıklaşan noktalar. İmleç izi verilirse pikseller + * turuncuya ısınır. Yavaş kayma (parallax) derinlik verir. + */ +export const PikselZemin: React.FC<{ + hucre?: number; + tohum?: number; + renk?: string; + /** Kenar bandı: kısa kenarın oranı */ + kenar?: number; + izler?: IsiOrnek[]; + kayma?: number; + guc?: number; +}> = ({ hucre = 40, tohum = 7, renk = R.primary, kenar = 0.26, izler = [], kayma = 0.25, guc = 1 }) => { + const f = useCurrentFrame(); + const bant = Math.min(W, H) * kenar; + const dy = -f * kayma; + const sutun = Math.ceil(W / hucre); + const satir = Math.ceil(H / hucre) + 2; + const rects: React.ReactNode[] = []; + for (let j = 0; j < satir; j++) { + for (let i = 0; i < sutun; i++) { + const cx = i * hucre + hucre / 2; + const cy = j * hucre + hucre / 2 + (dy % hucre); + const kenarUz = Math.min(cx, W - cx, cy, H - cy); + const yogunluk = clamp01(1 - kenarUz / bant) ** 1.6; + if (hash(i, j, tohum) > yogunluk * 0.9) continue; + const h = izler.length ? isi(cx, cy, izler, 110) : 0; + const boy = hucre * PIKSEL.nokta; + rects.push( + , + ); + } + } + return ( + + {rects} + + ); +}; diff --git a/video/src/bilesenler/UI.tsx b/video/src/bilesenler/UI.tsx new file mode 100644 index 0000000..04eeca7 --- /dev/null +++ b/video/src/bilesenler/UI.tsx @@ -0,0 +1,200 @@ +import { ArrowRight } from "lucide-react"; +import { Caret } from "@/components/remocn/caret"; +import { FONT } from "../fontlar"; +import { R } from "../marka"; +import { DILIM_ETIKET, type Dilim } from "../veri"; +import { karis } from "../yardimci"; + +// Arayüz parçaları sitenin 2 katı ölçüde (DESIGN.md §4). Durumlar (hover, +// basma, seçim) 0–1 arası sayı alır ki kareler arasında yumuşak geçsin. + +/** Turuncu funnel CTA (§4.1): metin önce, ArrowRight sonda, yıldız yok */ +export const CtaButon: React.FC<{ + children: React.ReactNode; + hover?: number; + bas?: number; + yukseklik?: number; + style?: React.CSSProperties; +}> = ({ children, hover = 0, bas = 0, yukseklik = 104, style }) => ( +
+ {children} + +
+); + +/** Form alanı hap (§4.6): 48 px → 104 px, tam yuvarlak, slate-200 kenarlık */ +export const GirisHap: React.FC<{ + genislik: number; + deger: string; + placeholder: string; + odak?: number; + yaziyor?: boolean; + ikon?: React.ReactNode; + yukseklik?: number; +}> = ({ genislik, deger, placeholder, odak = 0, yaziyor = false, ikon, yukseklik = 104 }) => ( +
+ {ikon} + + {/* Boş alanda imleç placeholder'ın başında, doluyken metnin sonunda */} + {odak > 0.5 && !deger && ( + + )} + {deger || placeholder} + {odak > 0.5 && deger && ( + + )} + +
+); + +/** Etkileşimli çip (§4.17): pasif beyaz, seçili mavi dolu */ +export const Cip: React.FC<{ + children: React.ReactNode; + secili?: number; + hover?: number; + bas?: number; + ikon?: React.ReactNode; + boy?: number; + style?: React.CSSProperties; +}> = ({ children, secili = 0, hover = 0, bas = 0, ikon, boy = 80, style }) => { + const pasifKenar = karis(R.slate200, R.turuncu, hover); + const pasifYazi = karis(R.slate700, R.turuncu, hover); + return ( + + {ikon} + {children} + + ); +}; + +/** Dilim etiketi (§4.5 düzeni): nokta + metin; renk tek başına anlam taşımaz */ +export const DILIM_RENK: Record = { + hayal: { nokta: R.red500, yazi: R.red600 }, + dengeli: { nokta: R.amber500, yazi: R.amber600 }, + garanti: { nokta: R.emerald500, yazi: R.emerald600 }, +}; + +export const DilimEtiketi: React.FC<{ dilim: Dilim; boy?: number }> = ({ dilim, boy = 26 }) => ( + + + {DILIM_ETIKET[dilim]} + +); + +/** + * Piksel trend: 6 yılın taban sırası, her yıl bir piksel. Üstte = daha iyi + * (küçük) sıra. Son yıl turuncu yanar (PixelSira'nın dili). + */ +export const PikselTrend: React.FC<{ + sira: number[]; + hucre?: number; + yukseklik?: number; + ilerleme?: number; +}> = ({ sira, hucre = 18, yukseklik = 56, ilerleme = 1 }) => { + const min = Math.min(...sira); + const max = Math.max(...sira); + const boy = hucre * 0.74; + return ( + + {sira.map((s, i) => { + const t = max === min ? 0.5 : (s - min) / (max - min); + const gorunur = ilerleme * sira.length > i; + const son = i === sira.length - 1; + return ( + + ); + })} + + ); +}; diff --git a/video/src/components/remocn/caret.tsx b/video/src/components/remocn/caret.tsx new file mode 100644 index 0000000..6afadde --- /dev/null +++ b/video/src/components/remocn/caret.tsx @@ -0,0 +1,69 @@ +"use client"; + +import type { CSSProperties } from "react"; +import { useCurrentFrame, useVideoConfig } from "remotion"; + +export interface CaretProps { + color?: string; + width?: number; + height?: number; + radius?: number; + opacity?: number; + blink?: boolean; + blinkPerSecond?: number; + speed?: number; + marginLeft?: number; + className?: string; + style?: CSSProperties; +} + +export function caretBlinkOpacity( + frame: number, + opts: { fps: number; blinkPerSecond: number; speed: number }, +): number { + const cycles = opts.blinkPerSecond <= 0 ? 1 : opts.blinkPerSecond; + const halfPeriod = opts.fps / cycles / 2; + if (halfPeriod <= 0) return 1; + return Math.floor((frame * opts.speed) / halfPeriod) % 2 === 0 ? 1 : 0; +} + +export function Caret({ + color = "currentColor", + width = 2, + height = 18, + radius = 1, + opacity, + blink = false, + blinkPerSecond = 1, + speed = 1, + marginLeft = 0, + className, + style, +}: CaretProps) { + const frame = useCurrentFrame(); + const { fps } = useVideoConfig(); + + const resolvedOpacity = + opacity !== undefined + ? opacity + : blink + ? caretBlinkOpacity(frame, { fps, blinkPerSecond, speed }) + : 1; + + return ( + + ); +} diff --git a/video/src/components/remocn/cursor.tsx b/video/src/components/remocn/cursor.tsx new file mode 100644 index 0000000..dfcc13d --- /dev/null +++ b/video/src/components/remocn/cursor.tsx @@ -0,0 +1,115 @@ +"use client"; + +import { type RemocnTheme, useRemocnTheme } from "@/lib/remocn-ui"; + +export type CursorVariant = "arrow" | "pointer"; + +export interface CursorStyle { + x: number; + y: number; + scale: number; + rippleOpacity: number; + rippleScale: number; + pressScale?: number; +} + +export interface CursorProps { + style?: CursorStyle; + variant?: CursorVariant; + size?: number; + theme?: Partial; + rippleColor?: string; + className?: string; +} + +const REST: CursorStyle = { + x: 0, + y: 0, + scale: 1, + rippleOpacity: 0, + rippleScale: 0, +}; + +const ARROW_PATH = + "M1 1 L1 18.5 L5.6 14.4 L8.7 21.6 L11.6 20.4 L8.5 13.2 L14.5 13.2 Z"; +const POINTER_PATH = + "M8 2.2 C8 1.3 8.7 0.7 9.5 0.7 C10.3 0.7 11 1.3 11 2.2 L11 9 " + + "C11 9 11.3 8.4 12.2 8.4 C13 8.4 13.4 9 13.4 9.6 " + + "C13.4 9.6 13.9 9.1 14.7 9.1 C15.5 9.1 15.9 9.7 15.9 10.3 " + + "C15.9 10.3 16.4 9.9 17.1 9.9 C17.9 9.9 18.3 10.5 18.3 11.2 " + + "L18.3 16.8 C18.3 19.8 16.3 22.3 12.8 22.3 L11.4 22.3 " + + "C9 22.3 7.9 21.2 6.6 19.2 L4 15.2 C3.5 14.4 3.7 13.4 4.5 12.9 " + + "C5.1 12.5 5.9 12.6 6.4 13.2 L8 15 Z"; + +export function Cursor({ + style, + variant = "arrow", + size = 28, + theme: themeOverride, + rippleColor, + className, +}: CursorProps) { + const theme = useRemocnTheme(themeOverride, "light"); + const v = style ?? REST; + + const press = v.pressScale ?? 1; + const pressedScale = v.scale * (0.9 + 0.1 * press); + + const ring = rippleColor ?? theme.primary; + const fill = theme.foreground; + const stroke = theme.background; + const rippleSize = size * 1.8; + + return ( +
+ {} +
+ {} + + + +
+ ); +} diff --git a/video/src/components/remocn/focus-blur-resolve.tsx b/video/src/components/remocn/focus-blur-resolve.tsx new file mode 100644 index 0000000..c95722a --- /dev/null +++ b/video/src/components/remocn/focus-blur-resolve.tsx @@ -0,0 +1,115 @@ +"use client"; + +import { Easing, interpolate, useCurrentFrame, useVideoConfig } from "remotion"; + +export interface FocusBlurResolveProps { + text: string; + fontFamily?: string; + blur?: number; + fontSize?: number; + color?: string; + fontWeight?: number; + speed?: number; + className?: string; +} + +export function FocusBlurResolve({ + text, + blur = 14, + fontSize = 72, + color = "#171717", + fontWeight = 600, + speed = 1, + className, + fontFamily = "sans-serif", +}: FocusBlurResolveProps) { + const frame = useCurrentFrame() * speed; + const { durationInFrames } = useVideoConfig(); + + const enterDur = 23; + const exitDur = 16; + const exitStart = Math.max(enterDur, durationInFrames - exitDur); + + const enterEasing = Easing.bezier(0.22, 1, 0.36, 1); + const exitEasing = Easing.bezier(0.64, 0, 0.78, 0); + + const enterP = interpolate(frame, [0, enterDur], [0, 1], { + extrapolateLeft: "clamp", + extrapolateRight: "clamp", + easing: enterEasing, + }); + + const exitP = interpolate(frame, [exitStart, durationInFrames], [0, 1], { + extrapolateLeft: "clamp", + extrapolateRight: "clamp", + easing: exitEasing, + }); + + const opacity = enterP * (1 - exitP); + + const yEnter = interpolate(frame, [0, enterDur], [14, 0], { + extrapolateLeft: "clamp", + extrapolateRight: "clamp", + easing: enterEasing, + }); + + const yExit = interpolate(frame, [exitStart, durationInFrames], [0, -10], { + extrapolateLeft: "clamp", + extrapolateRight: "clamp", + easing: exitEasing, + }); + + const y = yEnter + yExit; + + const blurEnter = interpolate(frame, [0, enterDur], [blur, 0], { + extrapolateLeft: "clamp", + extrapolateRight: "clamp", + easing: enterEasing, + }); + + const blurExit = interpolate(frame, [exitStart, durationInFrames], [0, 10], { + extrapolateLeft: "clamp", + extrapolateRight: "clamp", + easing: exitEasing, + }); + + const blurVal = blurEnter + blurExit; + + const scale = interpolate(frame, [0, enterDur], [1.01, 1], { + extrapolateLeft: "clamp", + extrapolateRight: "clamp", + easing: enterEasing, + }); + + return ( +
+ + {text} + +
+ ); +} diff --git a/video/src/components/remocn/kinetic-center-build.tsx b/video/src/components/remocn/kinetic-center-build.tsx new file mode 100644 index 0000000..dedae6a --- /dev/null +++ b/video/src/components/remocn/kinetic-center-build.tsx @@ -0,0 +1,243 @@ +"use client"; + +import { type CSSProperties, useMemo } from "react"; +import { Easing, interpolate, useCurrentFrame } from "remotion"; + +export interface KineticCenterBuildProps { + text: string; + entryOffset?: number; + fontSize?: number; + color?: string; + fontWeight?: number; + speed?: number; + className?: string; + fontFamily?: string; + letterSpacing?: number; + gap?: number; + /** "harf": harfler sağdan girip satırı iter (upstream davranışı); + * "kelime": uzun cümlelerde kelime kelime */ + birim?: "harf" | "kelime"; + /** Vurgulanan kelimeler (kelime indeksi, iki modda da) ve yazı stili */ + vurgu?: { indices: number[]; style: KineticWordStyle }; +} + +export interface KineticWordStyle { + fontFamily?: string; + fontWeight?: number; + fontStyle?: "normal" | "italic"; + color?: string; + letterSpacing?: number; +} + + +// Ölçüm, kelimenin gerçekte basılacağı yazı tipiyle yapılır (Cal Sans, +// Bricolage…); aksi hâlde itme sırasında kelimeler üst üste biner. +function measureWidths( + words: string[], + fontSize: number, + styleFor: (i: number) => Required, +): number[] { + if (typeof document === "undefined") { + return words.map((w) => w.length * fontSize * 0.55); + } + const ctx = document.createElement("canvas").getContext("2d"); + if (!ctx) return words.map((w) => w.length * fontSize * 0.55); + return words.map((w, i) => { + const st = styleFor(i); + ctx.font = `${st.fontStyle} ${st.fontWeight} ${fontSize}px "${st.fontFamily}"`; + return ctx.measureText(w).width + st.letterSpacing * fontSize * Array.from(w).length; + }); +} + +export function KineticCenterBuild({ + text, + entryOffset = 88, + fontSize = 72, + color = "#171717", + fontWeight = 600, + speed = 1, + className, + fontFamily = "sans-serif", + letterSpacing = -0.03, + gap: gapProp, + vurgu, + birim = "harf", +}: KineticCenterBuildProps) { + const frame = useCurrentFrame() * speed; + + const words = useMemo( + () => (birim === "kelime" ? text.split(" ") : Array.from(text)), + [text, birim], + ); + // Her birimin ait olduğu kelime (vurgu kelime indeksiyle verilir) + const kelimeOf = useMemo(() => { + if (birim === "kelime") return words.map((_, i) => i); + let w = 0; + return words.map((ch) => { + const k = w; + if (ch === " ") w++; + return k; + }); + }, [words, birim]); + const styleFor = (i: number): Required => { + const base = { fontFamily, fontWeight, fontStyle: "normal" as const, color, letterSpacing }; + return vurgu?.indices.includes(kelimeOf[i]) ? { ...base, ...vurgu.style } : base; + }; + const widths = useMemo( + () => measureWidths(words, fontSize, styleFor), + // eslint-disable-next-line react-hooks/exhaustive-deps + [words, fontSize, fontWeight, fontFamily, letterSpacing, vurgu, kelimeOf], + ); + + const gap = gapProp ?? (birim === "kelime" ? fontSize * 0.26 : 0); + const firstDur = 10; + const pushDur = 13; + const travelDur = 7; + const entryScale = 0.992; + const entryBlur = 3.5; + const reflowBlur = 0.8; + const firstWordY = 6; + const easing = Easing.bezier(0.2, 0.8, 0.2, 1); + + const positionsAt = useMemo(() => { + const out: number[][] = []; + for (let k = 1; k <= words.length; k++) { + let total = gap * (k - 1); + for (let j = 0; j < k; j++) total += widths[j]; + let cursor = -total / 2; + const xs: number[] = []; + for (let j = 0; j < k; j++) { + xs.push(cursor + widths[j] / 2); + cursor += widths[j] + gap; + } + out.push(xs); + } + return out; + }, [words, widths]); + + const n = words.length; + + return ( +
+
+ {words.map((word, j) => { + const entryStart = j === 0 ? 0 : firstDur + (j - 1) * pushDur; + const entryEnd = entryStart + (j === 0 ? firstDur : pushDur); + const targetX = positionsAt[j][j]; + const xFrom = j === 0 ? 0 : targetX + entryOffset; + + let x = targetX; + let opacity = 1; + let scale = 1; + let blur = 0; + let y = 0; + + if (frame < entryStart) { + opacity = 0; + x = xFrom; + scale = entryScale; + blur = entryBlur; + y = j === 0 ? firstWordY : 0; + } else if (frame <= entryEnd) { + const range: [number, number] = [entryStart, entryEnd]; + const travelRange: [number, number] = [ + entryStart, + Math.min(entryStart + travelDur, entryEnd), + ]; + const opts = { + extrapolateLeft: "clamp" as const, + extrapolateRight: "clamp" as const, + easing, + }; + x = interpolate(frame, travelRange, [xFrom, targetX], opts); + opacity = interpolate(frame, range, [0, 1], opts); + scale = interpolate(frame, range, [entryScale, 1], opts); + blur = interpolate(frame, range, [entryBlur, 0], opts); + y = + j === 0 + ? interpolate(frame, travelRange, [firstWordY, 0], opts) + : 0; + } else { + for (let w = j + 1; w < n; w++) { + const pushStart = firstDur + (w - 1) * pushDur; + const pushEnd = pushStart + pushDur; + const fromX = positionsAt[w - 1][j]; + const toX = positionsAt[w][j]; + if (frame >= pushEnd) { + x = toX; + } else if (frame >= pushStart) { + x = interpolate( + frame, + [pushStart, Math.min(pushStart + travelDur, pushEnd)], + [fromX, toX], + { + extrapolateLeft: "clamp", + extrapolateRight: "clamp", + easing, + }, + ); + blur = interpolate( + frame, + [pushStart, (pushStart + pushEnd) / 2, pushEnd], + [0, reflowBlur, 0], + { extrapolateLeft: "clamp", extrapolateRight: "clamp" }, + ); + break; + } else { + x = fromX; + break; + } + } + } + + const st = styleFor(j); + const wordStyle: CSSProperties = { + fontFamily: st.fontFamily, + fontWeight: st.fontWeight, + fontStyle: st.fontStyle, + color: st.color, + letterSpacing: `${st.letterSpacing}em`, + }; + return ( + + {word} + + ); + })} +
+
+ ); +} diff --git a/video/src/components/remocn/per-character-rise.tsx b/video/src/components/remocn/per-character-rise.tsx new file mode 100644 index 0000000..e372854 --- /dev/null +++ b/video/src/components/remocn/per-character-rise.tsx @@ -0,0 +1,86 @@ +"use client"; + +import { Easing, interpolate, useCurrentFrame } from "remotion"; + +export interface PerCharacterRiseProps { + text: string; + distance?: number; + fontSize?: number; + color?: string; + fontWeight?: number; + speed?: number; + className?: string; +} + +export function PerCharacterRise({ + text, + distance = 32, + fontSize = 72, + color = "#171717", + fontWeight = 600, + speed = 1, + className, +}: PerCharacterRiseProps) { + const frame = useCurrentFrame() * speed; + + const chars = Array.from(text); + const charDurationFrames = 21; + const charTravelFrames = 10; + const staggerFrames = 1; + + return ( +
+ + {chars.map((char, i) => { + const local = frame - i * staggerFrames; + const easing = Easing.bezier(0.2, 0.8, 0.2, 1); + const travelEasing = Easing.bezier(0.2, 0.8, 0.6, 0.85); + const opacity = interpolate(local, [0, charDurationFrames], [0, 1], { + extrapolateLeft: "clamp", + extrapolateRight: "clamp", + easing, + }); + const y = interpolate(local, [0, charTravelFrames], [distance, 0], { + extrapolateLeft: "clamp", + extrapolateRight: "clamp", + easing: travelEasing, + }); + return ( + + {char} + + ); + })} + +
+ ); +} diff --git a/video/src/components/remocn/push-through.tsx b/video/src/components/remocn/push-through.tsx new file mode 100644 index 0000000..8738da9 --- /dev/null +++ b/video/src/components/remocn/push-through.tsx @@ -0,0 +1,72 @@ +"use client"; + +import type { + TransitionPresentation, + TransitionPresentationComponentProps, +} from "@remotion/transitions"; +import type React from "react"; +import { AbsoluteFill, Easing, interpolate } from "remotion"; + +const clampOpts = { + extrapolateLeft: "clamp" as const, + extrapolateRight: "clamp" as const, +}; + +export type PushThroughProps = { + zoom?: number; + blur?: number; + /** İtmenin merkezi (px). İmlecin tıkladığı nokta verilir: sahne o noktanın + * içinden geçilerek terk edilir, yenisi aynı noktadan açılır. */ + origin?: { x: number; y: number }; +}; + +const PushThroughPresentation: React.FC< + TransitionPresentationComponentProps +> = ({ + children, + presentationProgress, + presentationDirection, + passedProps, +}) => { + const { zoom = 2.4, blur = 14, origin } = passedProps; + const transformOrigin = origin ? `${origin.x}px ${origin.y}px` : "50% 50%"; + const entering = presentationDirection === "entering"; + const p = presentationProgress; + + if (!entering) { + const exitStyle: React.CSSProperties = { + transformOrigin, + opacity: interpolate(p, [0.4, 0.62], [1, 0], { + ...clampOpts, + easing: Easing.bezier(0.42, 0, 0.58, 1), + }), + scale: `${interpolate(p, [0, 0.65], [1, zoom], { + ...clampOpts, + easing: Easing.in(Easing.cubic), + })}`, + filter: `blur(${interpolate(p, [0.15, 0.6], [0, blur], clampOpts)}px)`, + }; + return {children}; + } + + const childStyle: React.CSSProperties = { + transformOrigin, + opacity: interpolate(p, [0.3, 0.5], [0, 1], clampOpts), + scale: `${interpolate(p, [0.3, 0.88, 1], [0.68, 1.02, 1], { + ...clampOpts, + easing: Easing.out(Easing.cubic), + })}`, + filter: `blur(${interpolate(p, [0.3, 0.75], [blur * 0.7, 0], clampOpts)}px)`, + }; + + return {children}; +}; + +export function pushThrough( + props: PushThroughProps = {}, +): TransitionPresentation { + return { + component: PushThroughPresentation, + props, + }; +} diff --git a/video/src/components/remocn/slot-machine-roll.tsx b/video/src/components/remocn/slot-machine-roll.tsx new file mode 100644 index 0000000..99bfa81 --- /dev/null +++ b/video/src/components/remocn/slot-machine-roll.tsx @@ -0,0 +1,112 @@ +"use client"; + +import { spring, useCurrentFrame, useVideoConfig } from "remotion"; + +export interface SlotMachineRollProps { + from?: string; + to?: string; + fontSize?: number; + color?: string; + fontWeight?: number; + speed?: number; + className?: string; + fontFamily?: string; + /** true: tam kare sarmalayıcı ve beyaz zemin olmadan satır içi basar */ + inline?: boolean; + /** Sütunlar arası kademe (kare) */ + stagger?: number; +} + +// Nokta, virgül ve boşluk rakam kadar yer kaplamasın +const charWidth = (ch: string) => + ch === "." || ch === "," ? "0.3em" : ch === " " ? "0.25em" : ch === "%" ? "0.8em" : "0.62em"; + +export function SlotMachineRoll({ + from = "$99", + to = "$199", + fontSize = 120, + color = "#171717", + fontWeight = 700, + speed = 1, + className, + fontFamily = "sans-serif", + inline = false, + stagger = 4, +}: SlotMachineRollProps) { + const frame = useCurrentFrame() * speed; + const { fps } = useVideoConfig(); + + const len = Math.max(from.length, to.length); + const paddedFrom = from.padStart(len, " "); + const paddedTo = to.padStart(len, " "); + + const columns = []; + for (let i = 0; i < len; i++) { + const raw = spring({ + frame: frame - i * stagger, + fps, + config: { damping: 14 }, + }); + // Değişmeyen karakter (ör. "6 yıl"daki "yıl") yerinde durur + const sabit = paddedFrom[i] === paddedTo[i]; + const t = sabit ? 0 : Math.max(0, Math.min(1, raw)); + columns.push( + + + {paddedFrom[i]} + {paddedTo[i]} + + , + ); + } + + const metin = ( + + {columns} + + ); + if (inline) return metin; + + return ( +
+ {metin} +
+ ); +} diff --git a/video/src/components/remocn/tracking-in.tsx b/video/src/components/remocn/tracking-in.tsx new file mode 100644 index 0000000..9215cd3 --- /dev/null +++ b/video/src/components/remocn/tracking-in.tsx @@ -0,0 +1,77 @@ +"use client"; + +import type { ReactNode } from "react"; +import { interpolate, spring, useCurrentFrame, useVideoConfig } from "remotion"; + +export interface TrackingInProps { + text: ReactNode; + fontFamily?: string; + background?: string; + endTracking?: number; + startTracking?: number; + startBlur?: number; + fontSize?: number; + color?: string; + fontWeight?: number; + speed?: number; + className?: string; +} + +export function TrackingIn({ + text, + startTracking = 0.5, + startBlur = 12, + fontSize = 96, + color = "#171717", + fontWeight = 700, + speed = 1, + className, + fontFamily = "sans-serif", + background = "transparent", + endTracking = -0.03, +}: TrackingInProps) { + const frame = useCurrentFrame() * speed; + const { fps } = useVideoConfig(); + + const t = spring({ + frame, + fps, + config: { damping: 18, stiffness: 90 }, + }); + + const letterSpacing = `${interpolate(t, [0, 1], [startTracking, endTracking])}em`; + const blurAmount = interpolate(t, [0, 1], [startBlur, 0]); + const opacity = interpolate(frame, [0, 15], [0, 1], { + extrapolateLeft: "clamp", + extrapolateRight: "clamp", + }); + + return ( +
+ + {text} + +
+ ); +} diff --git a/video/src/components/remocn/typewriter.tsx b/video/src/components/remocn/typewriter.tsx new file mode 100644 index 0000000..aa119a8 --- /dev/null +++ b/video/src/components/remocn/typewriter.tsx @@ -0,0 +1,72 @@ +"use client"; + +import { Caret } from "@/components/remocn/caret"; +import { useTypewriter } from "@/lib/remocn-ui"; + +export interface TypewriterProps { + text: string; + cursor?: boolean; + charsPerSecond?: number; + speed?: number; + fontSize?: number; + color?: string; + cursorColor?: string; + fontWeight?: number; + className?: string; +} + +export function Typewriter({ + text, + cursor = true, + charsPerSecond = 22, + speed = 1, + fontSize = 48, + color = "#171717", + cursorColor = "#171717", + fontWeight = 600, + className, +}: TypewriterProps) { + const tw = useTypewriter(text, { cps: charsPerSecond, speed }); + + return ( +
+ + {tw.text} + {cursor && ( + + )} + +
+ ); +} diff --git a/video/src/components/remocn/use-cursor-path.ts b/video/src/components/remocn/use-cursor-path.ts new file mode 100644 index 0000000..c52dd7c --- /dev/null +++ b/video/src/components/remocn/use-cursor-path.ts @@ -0,0 +1,133 @@ +"use client"; + +import { useCurrentFrame } from "remotion"; +import type { CursorStyle } from "@/components/remocn/cursor"; +import { clamp01, type EasingName, easings } from "@/lib/remocn-ui"; + +export interface CursorWaypoint { + at: number; + x: number; + y: number; + duration?: number; + click?: boolean; + press?: boolean; + easing?: EasingName; +} + +export const DEFAULT_DURATION = 24; + +export const CLICK_FRAMES = 16; + +export const PRESS_FRAMES = 8; + +export interface CursorPathOptions { + speed?: number; + defaultDuration?: number; +} + +function lerp(a: number, b: number, t: number): number { + return a + (b - a) * t; +} + +export function ripplePhase(framesSinceClick: number): { + rippleOpacity: number; + rippleScale: number; +} { + if (framesSinceClick < 0 || framesSinceClick >= CLICK_FRAMES) { + return { rippleOpacity: 0, rippleScale: 0 }; + } + const p = clamp01(framesSinceClick / CLICK_FRAMES); + return { + rippleOpacity: 0.5 * (1 - p), + rippleScale: 2.5 * easings.out(p), + }; +} + +export function clickPress(framesSinceClick: number): number { + if (framesSinceClick < 0 || framesSinceClick >= PRESS_FRAMES) return 1; + const half = PRESS_FRAMES / 2; + const p = + framesSinceClick < half + ? framesSinceClick / half + : 1 - (framesSinceClick - half) / half; + return 1 - clamp01(p); +} + +export function useCursorPath( + waypoints: CursorWaypoint[], + opts: CursorPathOptions = {}, +): CursorStyle { + const raw = useCurrentFrame(); + return cursorPathAt(waypoints, raw, opts); +} + +export function cursorPathAt( + waypoints: CursorWaypoint[], + raw: number, + opts: CursorPathOptions = {}, +): CursorStyle { + const { speed = 1, defaultDuration = DEFAULT_DURATION } = opts; + const effectiveFrame = raw * speed; + + if (waypoints.length === 0) { + return { x: 0, y: 0, scale: 1, rippleOpacity: 0, rippleScale: 0 }; + } + + const first = waypoints[0]; + + if (effectiveFrame <= first.at) { + return { + x: first.x, + y: first.y, + scale: 1, + rippleOpacity: 0, + rippleScale: 0, + pressScale: 1, + }; + } + + let toIndex = waypoints.length - 1; + for (let i = 1; i < waypoints.length; i++) { + if (waypoints[i].at > effectiveFrame) { + toIndex = i; + break; + } + } + const pastLast = effectiveFrame >= waypoints[waypoints.length - 1].at; + const to = pastLast ? waypoints[waypoints.length - 1] : waypoints[toIndex]; + const from = pastLast + ? waypoints[waypoints.length - 1] + : waypoints[toIndex - 1]; + + const dur = to.duration ?? defaultDuration; + const ease = easings[to.easing ?? "inOut"]; + const start = to.at - dur; + const t = + pastLast || dur <= 0 ? 1 : ease(clamp01((effectiveFrame - start) / dur)); + const x = lerp(from.x, to.x, t); + const y = lerp(from.y, to.y, t); + + let lastClickAt = -Infinity; + for (const wp of waypoints) { + if (wp.click && wp.at <= effectiveFrame && wp.at > lastClickAt) + lastClickAt = wp.at; + } + const sinceClick = + lastClickAt === -Infinity ? -1 : effectiveFrame - lastClickAt; + const ripple = ripplePhase(sinceClick); + const clickDip = clickPress(sinceClick); + + const holdWp = pastLast ? waypoints[waypoints.length - 1] : from; + const heldPress = holdWp.press ? 0 : 1; + + const pressScale = Math.min(clickDip, heldPress); + + return { + x, + y, + scale: 1, + rippleOpacity: ripple.rippleOpacity, + rippleScale: ripple.rippleScale, + pressScale, + }; +} diff --git a/video/src/fontlar-hazir.ts b/video/src/fontlar-hazir.ts new file mode 100644 index 0000000..eb9537b --- /dev/null +++ b/video/src/fontlar-hazir.ts @@ -0,0 +1,22 @@ +import { useEffect, useState } from "react"; +import { continueRender, delayRender } from "remotion"; + +/** + * Kinetik yerleşimler metni gerçek yazı tipiyle ölçer. Yazı tipleri + * yüklenmeden ölçülürse kelimeler kayar; bu kanca yazı tipleri hazır olana + * kadar render'ı bekletir ve hazır olunca ağacı yeniden çizdirir. + */ +export function useFontlarHazir() { + const [hazir, setHazir] = useState( + () => typeof document !== "undefined" && document.fonts.status === "loaded", + ); + const [handle] = useState(() => (hazir ? null : delayRender("yazı tipleri"))); + useEffect(() => { + if (hazir) return; + document.fonts.ready.then(() => { + setHazir(true); + if (handle !== null) continueRender(handle); + }); + }, [hazir, handle]); + return hazir; +} diff --git a/video/src/fontlar.ts b/video/src/fontlar.ts new file mode 100644 index 0000000..774ea9c --- /dev/null +++ b/video/src/fontlar.ts @@ -0,0 +1,38 @@ +import { loadFont as yerelFont } from "@remotion/fonts"; +import { loadFont as bricolageYukle } from "@remotion/google-fonts/BricolageGrotesque"; +import { loadFont as calSansYukle } from "@remotion/google-fonts/CalSans"; +import { staticFile } from "remotion"; + +// Sitenin dört yazı tipinden üçü (DESIGN.md §3): Cal Sans başlık ve iri sayı, +// Clarity City gövde/buton, Bricolage vurgu. Geist Mono arayüzde yok. +const cal = calSansYukle("normal", { + weights: ["400"], + subsets: ["latin", "latin-ext"], +}); +const bricolage = bricolageYukle("normal", { + weights: ["300", "400", "600", "700", "800"], + subsets: ["latin", "latin-ext"], +}); + +const CLARITY = "Clarity City"; +for (const [dosya, agirlik] of [ + ["Regular", "400"], + ["Medium", "500"], + ["SemiBold", "600"], + ["Bold", "700"], + ["ExtraBold", "800"], +] as const) { + yerelFont({ + family: CLARITY, + url: staticFile(`fonts/ClarityCity-${dosya}.woff2`), + weight: agirlik, + }); +} + +export const FONT = { + /** Cal Sans yalnız 400; site `font-bold` ile sentetik kalınlık kullanıyor, + * video da aynı görünsün diye başlıklarda fontWeight 700 verilir. */ + baslik: cal.fontFamily, + govde: CLARITY, + vurgu: bricolage.fontFamily, +} as const; diff --git a/video/src/gecisler/piksel-dalga.tsx b/video/src/gecisler/piksel-dalga.tsx new file mode 100644 index 0000000..f193495 --- /dev/null +++ b/video/src/gecisler/piksel-dalga.tsx @@ -0,0 +1,137 @@ +import type { + TransitionPresentation, + TransitionPresentationComponentProps, +} from "@remotion/transitions"; +import { AbsoluteFill, Easing, interpolate } from "remotion"; +import { H, LOGO_KARELER, PIKSEL, W } from "../marka"; +import { clamp01, hash } from "../yardimci"; + +/** + * Piksel dalgası: yeni sahne, bir noktadan (çoğunlukla imlecin tıkladığı + * yer) yayılan iri piksellerle açılır. Dalganın önünde logonun üç rengi + * (mavi, şeftali, turuncu) yanıp söner — hero haritasındaki ısınan + * piksellerin sahne ölçeğindeki hâli. Hücreler sitenin nokta oranını + * (%74, rx %20) taşır; dalga geçince birleşip kesintisiz yüzeye döner. + */ +export type PikselDalgaProps = { + origin?: { x: number; y: number }; + /** Hücre kenarı (px) */ + hucre?: number; + /** Dalga önünün kalınlığı (px) */ + bant?: number; + /** Dalga önündeki piksellerin renkleri */ + renkler?: string[]; + /** Çıkan sahne hafifçe geri çekilsin (derinlik) */ + geriCekil?: number; + tohum?: number; +}; + +const VARSAYILAN_RENKLER = LOGO_KARELER.map((k) => k.renk); + +const koseUzakligi = (o: { x: number; y: number }) => + Math.max( + Math.hypot(o.x, o.y), + Math.hypot(W - o.x, o.y), + Math.hypot(o.x, H - o.y), + Math.hypot(W - o.x, H - o.y), + ); + +/** + * Dalga önünün yarıçapı. Gelen sahne kendi öğelerini dalgayla eş zamanlı + * belirtmek isterse (ör. haritanın noktaları) aynı fonksiyonu kullanır. + */ +export const dalgaYaricapi = ( + p: number, + origin: { x: number; y: number } = { x: W / 2, y: H / 2 }, + bant = 420, +) => + interpolate(clamp01(p), [0, 1], [0, koseUzakligi(origin) + bant * 1.25], { + easing: Easing.bezier(0.45, 0.05, 0.4, 1), + }); + +const PikselDalgaSunum: React.FC< + TransitionPresentationComponentProps +> = ({ children, presentationProgress, presentationDirection, passedProps }) => { + const { + origin = { x: W / 2, y: H / 2 }, + hucre = 64, + bant = 420, + renkler = VARSAYILAN_RENKLER, + geriCekil = 0.05, + tohum = 3, + } = passedProps; + const p = presentationProgress; + + if (presentationDirection === "exiting") { + return ( + + {children} + + ); + } + + const sutun = Math.ceil(W / hucre); + const satir = Math.ceil(H / hucre); + const r = dalgaYaricapi(p, origin, bant); + + let maske = ""; + let renkli = ""; + for (let j = 0; j < satir; j++) { + for (let i = 0; i < sutun; i++) { + const cx = i * hucre + hucre / 2; + const cy = j * hucre + hucre / 2; + const d = Math.hypot(cx - origin.x, cy - origin.y) + (hash(i, j, tohum) - 0.5) * bant * 0.55; + const t = clamp01((r - d) / bant); + if (t <= 0) continue; + // Önde renkli piksel belirip söner… + if (t < 0.72) { + const c = Math.sin(Math.PI * (t / 0.72)); + const boy = hucre * PIKSEL.nokta * c; + const renk = renkler[Math.floor(hash(i, j, tohum + 9) * renkler.length)]; + renkli += ``; + } + // …arkasından yeni sahne piksel piksel açılır + const m = Easing.bezier(0.22, 1, 0.36, 1)(clamp01((t - 0.38) / 0.62)); + if (m > 0) { + const boy = hucre * (PIKSEL.nokta + 0.3 * m); + const rx = hucre * PIKSEL.rx * (1 - m); + maske += ``; + } + } + } + + const maskeUrl = `url("data:image/svg+xml;utf8,${encodeURIComponent( + `${maske}`, + )}")`; + + return ( + + + {children} + + + + + + ); +}; + +export function pikselDalga( + props: PikselDalgaProps = {}, +): TransitionPresentation { + return { component: PikselDalgaSunum, props }; +} diff --git a/video/src/index.ts b/video/src/index.ts new file mode 100644 index 0000000..f31c790 --- /dev/null +++ b/video/src/index.ts @@ -0,0 +1,4 @@ +import { registerRoot } from "remotion"; +import { RemotionRoot } from "./Root"; + +registerRoot(RemotionRoot); diff --git a/video/src/lib/remocn-ui/color.ts b/video/src/lib/remocn-ui/color.ts new file mode 100644 index 0000000..f92074d --- /dev/null +++ b/video/src/lib/remocn-ui/color.ts @@ -0,0 +1,87 @@ +import { + clampChroma, + converter, + formatRgb, + interpolate, + type Oklch, + parse, + type Rgb, +} from "culori"; + +const toRgb = converter("rgb"); +const toOklch = converter("oklch"); + +const BLACK: Rgb = { mode: "rgb", r: 0, g: 0, b: 0, alpha: 1 }; + +export function parseColor(c: string): Rgb { + const s = c.trim(); + + if (s.startsWith("var(")) { + if (process.env.NODE_ENV !== "production") { + console.warn( + `[remocn-ui] parseColor cannot resolve CSS variable "${s}" under Remotion's per-frame render. ` + + "Animated colors must be concrete oklch/hex/rgb values supplied via the theme." + + "Falling back to the JS default.", + ); + } + return { ...BLACK }; + } + + const rgb = toRgb(parse(s)); + if (!rgb) { + if (process.env.NODE_ENV !== "production") { + console.warn( + `[remocn-ui] parseColor could not parse "${s}"; using black.`, + ); + } + return { ...BLACK }; + } + + return { mode: "rgb", r: rgb.r, g: rgb.g, b: rgb.b, alpha: rgb.alpha ?? 1 }; +} + +export function oklchToRgb(l: number, c: number, h: number): Rgb { + const mapped = clampChroma({ mode: "oklch", l, c, h }, "oklch", "rgb"); + return toRgb(mapped); +} + +export function rgbToOklch(rgb: Rgb): Oklch { + const { l, c, h } = toOklch(rgb); + return { mode: "oklch", l, c, h: Number.isFinite(h) ? h : 0 }; +} + +function resolveColorString(s: string): string { + const trimmed = s.trim(); + if (trimmed.startsWith("var(")) { + if (process.env.NODE_ENV !== "production") { + console.warn( + `[remocn-ui] mixOklch cannot resolve CSS variable "${trimmed}" under Remotion's per-frame render. ` + + "Animated colors must be concrete oklch/hex/rgb values supplied via the theme." + + "Falling back to the JS default.", + ); + } + return "#000"; + } + if (!parse(trimmed)) { + if (process.env.NODE_ENV !== "production") { + console.warn( + `[remocn-ui] mixOklch could not parse "${trimmed}"; using black.`, + ); + } + return "#000"; + } + return trimmed; +} + +export function mixOklch(a: string, b: string, t: number): string { + const mixed = clampChroma( + interpolate([resolveColorString(a), resolveColorString(b)], "oklch")(t), + "oklch", + "rgb", + ); + return toCss(toRgb(mixed)); +} + +export function toCss(color: Rgb): string { + return formatRgb(color); +} diff --git a/video/src/lib/remocn-ui/index.ts b/video/src/lib/remocn-ui/index.ts new file mode 100644 index 0000000..ecaa3bd --- /dev/null +++ b/video/src/lib/remocn-ui/index.ts @@ -0,0 +1,27 @@ +export { + mixOklch, + oklchToRgb, + parseColor, + rgbToOklch, + toCss, +} from "./color"; +export type { EasingName, SpringName } from "./motion"; +export { easings, springs } from "./motion"; +export type { RemocnTheme, RemocnUIProviderProps } from "./theme"; +export { + defaultDarkTheme, + defaultLightTheme, + RemocnUIProvider, + useRemocnTheme, +} from "./theme"; +export type { TypewriterOptions, TypewriterState } from "./timeline"; +export { + clamp01, + framesFor, + revealCount, + revealedText, + useCurrentState, + useStateTransition, + useTypewriter, +} from "./timeline"; +export type { Step } from "./types"; diff --git a/video/src/lib/remocn-ui/motion.ts b/video/src/lib/remocn-ui/motion.ts new file mode 100644 index 0000000..e42e135 --- /dev/null +++ b/video/src/lib/remocn-ui/motion.ts @@ -0,0 +1,17 @@ +export const easings = { + linear: (t: number): number => t, + out: (t: number): number => 1 - (1 - t) ** 3, + in: (t: number): number => t * t * t, + inOut: (t: number): number => + t < 0.5 ? 4 * t * t * t : 1 - (-2 * t + 2) ** 3 / 2, +} as const; + +export type EasingName = keyof typeof easings; + +export const springs = { + snappy: { damping: 18, stiffness: 220, mass: 0.7 }, + soft: { damping: 14, stiffness: 120, mass: 0.9 }, + bouncy: { damping: 10, stiffness: 180, mass: 0.8 }, +} as const; + +export type SpringName = keyof typeof springs; diff --git a/video/src/lib/remocn-ui/theme.ts b/video/src/lib/remocn-ui/theme.ts new file mode 100644 index 0000000..40435f3 --- /dev/null +++ b/video/src/lib/remocn-ui/theme.ts @@ -0,0 +1,108 @@ +"use client"; + +import type { ReactNode } from "react"; +import { createContext, createElement, useContext } from "react"; + +export interface RemocnTheme { + background: string; + foreground: string; + card: string; + cardForeground: string; + popover: string; + popoverForeground: string; + primary: string; + primaryForeground: string; + secondary: string; + secondaryForeground: string; + muted: string; + mutedForeground: string; + accent: string; + accentForeground: string; + destructive: string; + destructiveForeground: string; + border: string; + input: string; + ring: string; + radius: number; +} + +export const defaultLightTheme: RemocnTheme = { + background: "oklch(1 0 0)", + foreground: "oklch(0.145 0 0)", + card: "oklch(1 0 0)", + cardForeground: "oklch(0.145 0 0)", + popover: "oklch(1 0 0)", + popoverForeground: "oklch(0.145 0 0)", + primary: "oklch(0.205 0 0)", + primaryForeground: "oklch(0.985 0 0)", + secondary: "oklch(0.97 0 0)", + secondaryForeground: "oklch(0.205 0 0)", + muted: "oklch(0.97 0 0)", + mutedForeground: "oklch(0.556 0 0)", + accent: "oklch(0.97 0 0)", + accentForeground: "oklch(0.205 0 0)", + destructive: "oklch(0.577 0.245 27.325)", + destructiveForeground: "oklch(0.985 0 0)", + border: "oklch(0.922 0 0)", + input: "oklch(0.922 0 0)", + ring: "oklch(0.708 0 0)", + radius: 10, +}; + +export const defaultDarkTheme: RemocnTheme = { + background: "oklch(0.145 0 0)", + foreground: "oklch(0.985 0 0)", + card: "oklch(0.205 0 0)", + cardForeground: "oklch(0.985 0 0)", + popover: "oklch(0.205 0 0)", + popoverForeground: "oklch(0.985 0 0)", + primary: "oklch(0.922 0 0)", + primaryForeground: "oklch(0.205 0 0)", + secondary: "oklch(0.269 0 0)", + secondaryForeground: "oklch(0.985 0 0)", + muted: "oklch(0.269 0 0)", + mutedForeground: "oklch(0.708 0 0)", + accent: "oklch(0.269 0 0)", + accentForeground: "oklch(0.985 0 0)", + destructive: "oklch(0.704 0.191 22.216)", + destructiveForeground: "oklch(0.985 0 0)", + border: "oklch(1 0 0 / 10%)", + input: "oklch(1 0 0 / 15%)", + ring: "oklch(0.556 0 0)", + radius: 10, +}; + +interface RemocnThemeContextValue { + theme?: Partial; + mode?: "light" | "dark"; +} + +const RemocnThemeContext = createContext({}); + +export interface RemocnUIProviderProps { + theme?: Partial; + mode?: "light" | "dark"; + children: ReactNode; +} + +export function RemocnUIProvider({ + theme, + mode, + children, +}: RemocnUIProviderProps) { + return createElement( + RemocnThemeContext.Provider, + { value: { theme, mode } }, + children, + ); +} + +export function useRemocnTheme( + override?: Partial, + modeOverride?: "light" | "dark", +): RemocnTheme { + const ctx = useContext(RemocnThemeContext); + const mode = modeOverride ?? ctx.mode ?? "light"; + const base = mode === "dark" ? defaultDarkTheme : defaultLightTheme; + return { ...base, ...ctx.theme, ...override }; +} diff --git a/video/src/lib/remocn-ui/timeline.ts b/video/src/lib/remocn-ui/timeline.ts new file mode 100644 index 0000000..f815976 --- /dev/null +++ b/video/src/lib/remocn-ui/timeline.ts @@ -0,0 +1,96 @@ +import { useCurrentFrame, useVideoConfig } from "remotion"; +import type { Step } from "./types"; + +export function framesFor( + d: number | { seconds: number }, + fps: number, +): number { + return typeof d === "number" ? d : Math.round(d.seconds * fps); +} + +export function revealCount( + localFrame: number, + fps: number, + len: number, + cps: number, +): number { + const over = (len / cps) * fps; + if (over <= 0) return len; + return Math.max(0, Math.min(len, Math.floor((localFrame / over) * len))); +} + +export function clamp01(t: number): number { + return Math.max(0, Math.min(1, t)); +} + +export function revealedText(full: string, count: number): string { + const c = Math.max(0, Math.min(full.length, Math.floor(count))); + return full.slice(0, c); +} + +export interface TypewriterOptions { + cps?: number; + speed?: number; + startFrame?: number; +} + +export interface TypewriterState { + text: string; + count: number; + done: boolean; + typing: boolean; +} + +export function useTypewriter( + full: string, + options: TypewriterOptions = {}, +): TypewriterState { + const { cps = 20, speed = 1, startFrame = 0 } = options; + const frame = useCurrentFrame(); + const { fps } = useVideoConfig(); + const local = frame * speed - startFrame; + const count = local <= 0 ? 0 : revealCount(local, fps, full.length, cps); + return { + text: revealedText(full, count), + count, + done: count >= full.length, + typing: count > 0 && count < full.length, + }; +} + +export function useCurrentState( + steps: Step[], + defaultState: S, + speed = 1, +): S { + const effectiveFrame = useCurrentFrame() * speed; + let current = defaultState; + let bestAt = -Infinity; + steps.forEach((step) => { + if (step.at <= effectiveFrame && step.at >= bestAt) { + bestAt = step.at; + current = step.state; + } + }); + return current; +} + +export function useStateTransition( + steps: Step[], + defaultState: S, + speed = 1, + defaultDuration = 8, +): { from: S; to: S; progress: number } { + const effectiveFrame = useCurrentFrame() * speed; + const started = steps + .map((step, index) => ({ step, index })) + .sort((a, b) => a.step.at - b.step.at || a.index - b.index) + .filter((e) => e.step.at <= effectiveFrame); + if (started.length === 0) + return { from: defaultState, to: defaultState, progress: 1 }; + const to = started[started.length - 1].step; + const from = started.length >= 2 ? started[started.length - 2].step : null; + const dur = to.duration ?? defaultDuration; + const progress = dur > 0 ? clamp01((effectiveFrame - to.at) / dur) : 1; + return { from: from ? from.state : defaultState, to: to.state, progress }; +} diff --git a/video/src/lib/remocn-ui/types.ts b/video/src/lib/remocn-ui/types.ts new file mode 100644 index 0000000..dea316e --- /dev/null +++ b/video/src/lib/remocn-ui/types.ts @@ -0,0 +1,5 @@ +export interface Step { + at: number; + state: S; + duration?: number; +} diff --git a/video/src/marka.ts b/video/src/marka.ts new file mode 100644 index 0000000..7c89865 --- /dev/null +++ b/video/src/marka.ts @@ -0,0 +1,67 @@ +/** + * Lansman videosunun görsel dili — docs/tasarim/DESIGN.md'nin video karşılığı. + * Renkler sitenin Tailwind v4 tonlarıyla birebir (oklch); logo renkleri + * public/kolay-tercih-mark.svg'den. Video 1080p olduğu için arayüz ölçüleri + * sitenin 2 katıdır (h-12 = 48 px → 96–104 px). + */ + +export const W = 1920; +export const H = 1080; +export const FPS = 30; + +export const R = { + // Bilgi mavisi (--primary) ve logo mavisi + primary: "oklch(0.623 0.188 259.8)", + mavi: "#3b82f6", + mavi400: "oklch(0.707 0.165 254.624)", + // Logo: şeftali + turuncu kare + seftali: "#fdc7a7", + turuncuLogo: "#ff5a00", + // Aksiyon turuncusu (orange-500) ve hover'ı + turuncu: "oklch(0.705 0.213 47.604)", + turuncu600: "oklch(0.646 0.222 41.116)", + turuncu50: "oklch(0.98 0.016 73.684)", + + slate50: "oklch(0.984 0.003 247.858)", + slate100: "oklch(0.968 0.007 247.896)", + slate200: "oklch(0.929 0.013 255.508)", + slate300: "oklch(0.869 0.022 252.894)", + slate400: "oklch(0.704 0.04 256.788)", + slate500: "oklch(0.554 0.046 257.417)", + slate600: "oklch(0.446 0.043 257.281)", + slate700: "oklch(0.372 0.044 257.287)", + slate800: "oklch(0.279 0.041 260.031)", + slate900: "oklch(0.208 0.042 265.755)", + slate950: "oklch(0.129 0.042 264.695)", + beyaz: "#ffffff", + + // Risk / dilim renkleri — her zaman metin etiketiyle birlikte + emerald500: "oklch(0.696 0.17 162.48)", + emerald600: "oklch(0.596 0.145 163.225)", + amber500: "oklch(0.769 0.188 70.08)", + amber600: "oklch(0.666 0.179 58.318)", + red500: "oklch(0.637 0.237 25.331)", + red600: "oklch(0.577 0.245 27.325)", + + // Gösterge kareleri (§4.11) + indigo500: "oklch(0.585 0.233 277.117)", + green600: "oklch(0.627 0.194 149.214)", +} as const; + +/** Piksel imzası: hero ızgarası (hücre 10, nokta 7.4, rx 2) oranları */ +export const PIKSEL = { + nokta: 0.74, + rx: 0.2, + // Hero doku paleti (turkey-pixel-map.tsx) + opakliklar: [0.3, 0.16, 0.24, 0.12, 0.27, 0.19], +} as const; + +export const opaklikFor = (x: number, y: number) => + PIKSEL.opakliklar[(x * 7 + y * 11) % PIKSEL.opakliklar.length]; + +/** Logo işareti (viewBox 180) */ +export const LOGO_KARELER = [ + { x: 27, y: 56, boy: 57, renk: "#3b82f6" }, + { x: 91, y: 29, boy: 56, renk: "#fdc7a7" }, + { x: 91, y: 95, boy: 56, renk: "#ff5a00" }, +] as const; diff --git a/video/src/sahneler/S1Gurultu.tsx b/video/src/sahneler/S1Gurultu.tsx new file mode 100644 index 0000000..a4d59a7 --- /dev/null +++ b/video/src/sahneler/S1Gurultu.tsx @@ -0,0 +1,183 @@ +import { AbsoluteFill, Sequence, useCurrentFrame } from "remotion"; +import { KineticCenterBuild } from "@/components/remocn/kinetic-center-build"; +import { TrackingIn } from "@/components/remocn/tracking-in"; +import { Vinyet } from "../bilesenler/Gren"; +import { Cikis } from "../bilesenler/Kinetik"; +import { FONT } from "../fontlar"; +import { H, PIKSEL, R, W } from "../marka"; +import { GURULTU_SAYILARI } from "../veri"; +import { aralik, clamp01, ease, hash, lerp } from "../yardimci"; + +/** + * 1 · Gürültü. Koyu zemin, derinlikten üstüne gelen gerçek taban sıraları + * (tercih dönemindeki tablo kalabalığı). Üç kinetik satır; sonunda bütün + * sayılar merkeze çöker ve geriye **tek bir turuncu piksel** kalır. Bir + * sonraki geçiş o pikselden yayılan dalgadır. + */ + +const ADET = 60; +const DERINLIK = 3200; +const YAKIN = 70; +const ODAK = 720; +const COKUS: [number, number] = [104, 122]; + +const tunel = Array.from({ length: ADET }, (_, i) => { + let x = (hash(i, 1) - 0.5) * 2800; + let y = (hash(i, 2) - 0.5) * 1600; + // Başlık alanının içinden geçmesin: merkeze yakın olanlar dışarı itilir + if (Math.abs(x) < 520 && Math.abs(y) < 260) { + x += Math.sign(x || 1) * 520; + y += Math.sign(y || 1) * 180; + } + const r = hash(i, 4); + return { + metin: GURULTU_SAYILARI[i % GURULTU_SAYILARI.length], + x, + y, + z0: hash(i, 3) * DERINLIK, + renk: r > 0.9 ? R.turuncu : r > 0.78 ? R.mavi400 : R.slate400, + }; +}); + +// Tünelde kat edilen yol: sabit hız, çöküşe doğru hızlanır +const yol = (f: number) => f * 24 + Math.max(0, f - 70) ** 2 * 0.9; + +export const S1Gurultu: React.FC = () => { + const f = useCurrentFrame(); + const cokus = aralik(f, COKUS[0], COKUS[1], ease.in); + const merkezPiksel = aralik(f, 116, 122, ease.geriTep); + + return ( + + {/* Derinlik tüneli */} + {tunel.map((t, i) => { + const z = YAKIN + ((((t.z0 - yol(f)) % DERINLIK) + DERINLIK) % DERINLIK); + const s = ODAK / z; + let X = W / 2 + t.x * s; + let Y = H / 2 + t.y * s; + let olcek = s; + // Çöküş: her sayı merkeze çekilip piksele küçülür + X = lerp(X, W / 2, cokus); + Y = lerp(Y, H / 2, cokus); + olcek = lerp(olcek, 0.02, cokus); + const uzak = aralik(z, DERINLIK, DERINLIK * 0.72); + const yakin = aralik(z, YAKIN, 220); + const op = uzak * yakin * 0.7 * (1 - aralik(f, COKUS[1] - 4, COKUS[1])); + const bulanik = Math.min(7, Math.abs(z - ODAK) / 420) + (1 - yakin) * 6; + if (op <= 0.01) return null; + return ( +
+ {t.metin} +
+ ); + })} + + {/* Başlığın arkasını sakinleştiren karartma */} + + + {/* Kinetik satırlar */} + + + + + + + + + + + + + + + {/* Geriye kalan tek piksel — dalga buradan doğar */} + {merkezPiksel > 0 && ( +
+ )} + + + ); +}; + +/** "Hangisi senin?" — belirir, sonra harf aralığı sıfırın altına çöküp piksele küçülür */ +const HangisiSenin: React.FC = () => { + const f = useCurrentFrame(); + const cok = aralik(f, 12, 26, ease.in); + return ( + + + Hangisi{" "} + + senin? + + + } + fontFamily={FONT.baslik} + fontSize={176} + color={R.beyaz} + startTracking={0.7} + endTracking={lerp(0.015, -0.2, cok)} + startBlur={12} + speed={1.4} + /> + + ); +}; diff --git a/video/src/sahneler/S2Harita.tsx b/video/src/sahneler/S2Harita.tsx new file mode 100644 index 0000000..34dfda4 --- /dev/null +++ b/video/src/sahneler/S2Harita.tsx @@ -0,0 +1,355 @@ +import { AbsoluteFill, Sequence, useCurrentFrame } from "remotion"; +import { KineticCenterBuild } from "@/components/remocn/kinetic-center-build"; +import { TrackingIn } from "@/components/remocn/tracking-in"; +import { Imlec, isi, isiIzi, type Yol } from "../bilesenler/Imlec"; +import { Cikis, Kutu } from "../bilesenler/Kinetik"; +import { LogoIsaret } from "../bilesenler/Logo"; +import { FONT } from "../fontlar"; +import { dalgaYaricapi } from "../gecisler/piksel-dalga"; +import { H, LOGO_KARELER, PIKSEL, R, W, opaklikFor } from "../marka"; +import { IZGARA_SATIR, IZGARA_SUTUN, SEHIRLER, TURKIYE_HUCRELER } from "../turkiye"; +import { IL_PROGRAM, TOPLAM_PROGRAM } from "../veri"; +import { aralik, clamp01, ease, hash, karis, lerp, olc, tr } from "../yardimci"; +import { GECIS, SAHNE, gecisBasi } from "../zaman"; + +/** + * 2 · Harita. Dalga geçerken hero'nun dot-matrix Türkiye'si piksel piksel + * belirir; harita derinlikte yatık durur, illerin program sayısı kadar + * piksel kuleleri yükselir. İmleç haritanın üstünden geçer, sitedeki gibi + * pikseller turuncuya ısınıp yavaş soğur. Sonra bütün pikseller logonun üç + * karesine toplanır; "KolayTercih" harf aralığı daralarak (tracking) yerine + * oturur. İmleç turuncu kareye tıklar → bir sonraki dalga oradan. + */ + +const HUCRE = 24; +const PERSPEKTIF = 2600; +const DALGA_BANT = 420; +const MORF: [number, number] = [110, 146]; +const LOGO_BOY = 260; +const LOGO_MERKEZ_Y = 470; + +// Kelime markanın logo svg'sindeki oranlarıyla: yazı 46.7/44 işaret boyu +// sağda başlar, punto işaret boyunun ~0.63'ü +const KELIME_BOY = 164; +const KELIME_OFSET = (46.7 / 44) * LOGO_BOY; + +/** Logonun son yerleşimi (işaret + kelime ortalı) */ +export const logoYerlesimi = () => { + const ww = + olc("Kolay", { family: FONT.vurgu, size: KELIME_BOY, weight: 300, tracking: -0.05 }) + + olc("Tercih", { family: FONT.vurgu, size: KELIME_BOY, weight: 600, tracking: -0.05 }); + const toplam = KELIME_OFSET + ww; + const sol = W / 2 - toplam / 2; + return { sol, ww, ust: LOGO_MERKEZ_Y - LOGO_BOY / 2 }; +}; + +/** İmlecin tıkladığı nokta: turuncu karenin merkezi */ +export const haritaTiklama = () => { + const { sol, ust } = logoYerlesimi(); + const k = LOGO_KARELER[2]; + return { + x: sol + ((k.x + k.boy / 2) / 180) * LOGO_BOY, + y: ust + ((k.y + k.boy / 2) / 180) * LOGO_BOY, + }; +}; + +const TIKLAMA_KARESI = gecisBasi(SAHNE.harita, GECIS.g2); + +// ——— Harita noktaları ve morf hedefleri (bir kez hesaplanır) ——— + +const bolgeOf = (x: number, y: number) => (x < 30 ? 0 : y < 12 ? 1 : 2); + +const noktalar = (() => { + const ham = TURKIYE_HUCRELER.map(({ x, y }) => ({ + gx: x, + gy: y, + mx: (x - IZGARA_SUTUN / 2 + 0.5) * HUCRE, + my: (y - IZGARA_SATIR / 2 + 0.5) * HUCRE, + op: 0.2 + opaklikFor(x, y) * 1.7, + bolge: bolgeOf(x, y), + })); + const sinir = [0, 1, 2].map((b) => { + const n = ham.filter((p) => p.bolge === b); + return { + n: n.length, + x0: Math.min(...n.map((p) => p.gx)), + x1: Math.max(...n.map((p) => p.gx)), + y0: Math.min(...n.map((p) => p.gy)), + y1: Math.max(...n.map((p) => p.gy)), + }; + }); + const mSol = W / 2 - LOGO_BOY / 2; + const mUst = LOGO_MERKEZ_Y - LOGO_BOY / 2; + return ham.map((p, i) => { + const s = sinir[p.bolge]; + const k = LOGO_KARELER[p.bolge]; + const u = (p.gx - s.x0) / Math.max(1, s.x1 - s.x0); + const v = (p.gy - s.y0) / Math.max(1, s.y1 - s.y0); + const kk = Math.ceil(Math.sqrt(s.n)); + const kenar = (k.boy / 180) * LOGO_BOY; + const hc = kenar / kk; + return { + ...p, + hedefX: mSol + (k.x / 180) * LOGO_BOY + (Math.min(kk - 1, Math.floor(u * kk)) + 0.5) * hc, + hedefY: mUst + (k.y / 180) * LOGO_BOY + (Math.min(kk - 1, Math.floor(v * kk)) + 0.5) * hc, + hedefBoy: hc * 1.08, + hedefRenk: k.renk, + // Soldan sağa süpürülen toplanma + biraz dağınıklık + gecikme: (p.gx / IZGARA_SUTUN) * 10 + hash(i, 5) * 6, + }; + }); +})(); + +const kuleler = SEHIRLER.filter((s) => IL_PROGRAM[s.name]).map((s, i) => ({ + ...s, + mx: (s.x - IZGARA_SUTUN / 2 + 0.5) * HUCRE, + my: (s.y - IZGARA_SATIR / 2 + 0.5) * HUCRE, + n: IL_PROGRAM[s.name], + yukseklik: 16 + 170 * Math.sqrt(IL_PROGRAM[s.name] / IL_PROGRAM["İstanbul"]), + i, +})); +const ETIKETLI = ["İstanbul", "Ankara", "İzmir"]; + +// ——— Kamera ——— + +type Kamera = { egim: number; donus: number; zoom: number; cx: number; cy: number }; + +const kameraAt = (f: number): Kamera => { + const t = aralik(f, 0, 130, ease.inOut); + return { + egim: (lerp(56, 44, t) * Math.PI) / 180, + donus: (lerp(-9, -3, t) * Math.PI) / 180, + zoom: lerp(0.94, 1.06, t), + cx: W / 2, + cy: lerp(560, 540, t), + }; +}; + +/** Harita uzayından ekrana: Z çevresinde dönüş, X çevresinde eğim, perspektif */ +const izdus = (mx: number, my: number, mz: number, k: Kamera) => { + const x1 = mx * Math.cos(k.donus) - my * Math.sin(k.donus); + const y1 = mx * Math.sin(k.donus) + my * Math.cos(k.donus); + const y2 = y1 * Math.cos(k.egim) - mz * Math.sin(k.egim); + const z2 = y1 * Math.sin(k.egim) + mz * Math.cos(k.egim); + const s = (PERSPEKTIF / (PERSPEKTIF - z2)) * k.zoom; + return { x: k.cx + x1 * s, y: k.cy + y2 * s, s }; +}; + +// ——— İmleç ——— + +const tik = () => haritaTiklama(); +const imlecYolu = (): Yol => { + const t = tik(); + return [ + { at: 44, x: 1860, y: 1010 }, + { at: 72, x: 1340, y: 700, duration: 28 }, + { at: 96, x: 920, y: 540, duration: 24 }, + { at: 120, x: 520, y: 620, duration: 24 }, + { at: 156, x: 1240, y: 880, duration: 36 }, + { at: TIKLAMA_KARESI - 4, x: t.x, y: t.y, duration: 34 }, + { at: TIKLAMA_KARESI, x: t.x, y: t.y, click: true, duration: 4 }, + ]; +}; +const IMLEC_GORUNUR: [number, number] = [42, SAHNE.harita]; + +export const S2Harita: React.FC = () => { + const f = useCurrentFrame(); + const kam = kameraAt(f); + const yol = imlecYolu(); + const izler = isiIzi(yol, f, IMLEC_GORUNUR); + const r = dalgaYaricapi(f / GECIS.g1, { x: W / 2, y: H / 2 }, DALGA_BANT); + const cos = Math.cos(kam.egim); + + const kuleCokus = 1 - aralik(f, MORF[0] - 10, MORF[0] + 6, ease.in); + const noktaSonus = 1 - aralik(f, MORF[1] + 2, MORF[1] + 10); + const logoBelir = aralik(f, MORF[1] - 4, MORF[1] + 6, ease.out); + + const { sol, ww } = logoYerlesimi(); + const kay = aralik(f, 150, 178, ease.inOut); + const logoSol = lerp(W / 2 - LOGO_BOY / 2, sol, kay); + + // Noktalar + const rects: React.ReactNode[] = []; + if (noktaSonus > 0) { + noktalar.forEach((p, i) => { + const e = ease.inOut(clamp01((f - MORF[0] - p.gecikme) / 22)); + const q = izdus(p.mx, p.my, 0, kam); + const d = Math.hypot(q.x - W / 2, q.y - H / 2); + const pop = ease.geriTep(clamp01((r - d - 0.36 * DALGA_BANT) / (0.42 * DALGA_BANT))); + if (pop <= 0) return; + const h = e < 1 ? isi(q.x, q.y, izler, 130) * (1 - e) : 0; + const boy0 = HUCRE * PIKSEL.nokta * q.s * pop; + const x = lerp(q.x, p.hedefX, e); + const y = lerp(q.y, p.hedefY, e); + const w = lerp(boy0, p.hedefBoy, e); + const hh = lerp(boy0 * cos, p.hedefBoy, e); + const renk = e > 0 ? karis(karis(R.primary, R.turuncu, h), p.hedefRenk, e) : karis(R.primary, R.turuncu, h); + const op = lerp(lerp(p.op, 0.95, h), 1, e) * noktaSonus; + rects.push( + , + ); + }); + } + + // Piksel kuleleri: il başına program sayısı kadar yükselen plakalar + const kuleRects: React.ReactNode[] = []; + const etiketler: React.ReactNode[] = []; + if (kuleCokus > 0) { + kuleler.forEach((k) => { + const buyu = aralik(f, 30 + k.i * 3, 70 + k.i * 3, ease.out) * kuleCokus; + const yuk = k.yukseklik * buyu; + const adim = HUCRE * 0.55; + const adet = Math.floor(yuk / adim); + for (let j = 0; j <= adet; j++) { + const q = izdus(k.mx, k.my, j * adim, kam); + const boy = HUCRE * PIKSEL.nokta * q.s; + const ust = j === adet; + kuleRects.push( + , + ); + } + if (ETIKETLI.includes(k.name)) { + const op = aralik(f, 62 + k.i * 5, 72 + k.i * 5) * (1 - aralik(f, 100, 110)); + if (op > 0) { + const q = izdus(k.mx, k.my, yuk, kam); + etiketler.push( +
+ {k.name} + · + {tr(k.n)} + program +
, + ); + } + } + }); + } + + return ( + + + + {rects} + {kuleRects} + + {etiketler} + + {/* Logo: morfun sonunda katı kareler, sonra sola kayar */} + {logoBelir > 0 && ( + + )} + + {/* Kelime marka: harf aralığı genişten daralarak yerine oturur */} + + + + Kolay + Tercih + + } + fontFamily={FONT.vurgu} + fontSize={KELIME_BOY} + fontWeight={300} + color="#0a0a0a" + startTracking={0.55} + endTracking={-0.05} + startBlur={14} + /> + + + + {/* Alt yazı: harita beliren veriyi söyler */} + + + + + + + + + {/* Slogan (hero h1) */} + + + + + + + + + ); +}; diff --git a/video/src/sahneler/S3Siralama.tsx b/video/src/sahneler/S3Siralama.tsx new file mode 100644 index 0000000..298b9ba --- /dev/null +++ b/video/src/sahneler/S3Siralama.tsx @@ -0,0 +1,155 @@ +import { Trophy } from "lucide-react"; +import { AbsoluteFill, Sequence, useCurrentFrame } from "remotion"; +import { TrackingIn } from "@/components/remocn/tracking-in"; +import { useTypewriter } from "@/lib/remocn-ui"; +import { Imlec, isiIzi, type Yol } from "../bilesenler/Imlec"; +import { Kutu } from "../bilesenler/Kinetik"; +import { Rozet } from "../bilesenler/Logo"; +import { PikselZemin } from "../bilesenler/PikselZemin"; +import { Cip, CtaButon, GirisHap } from "../bilesenler/UI"; +import { FONT } from "../fontlar"; +import { R, W } from "../marka"; +import { ORNEK_SIRA_METNI } from "../veri"; +import { aralik, ease, lerp, olc } from "../yardimci"; +import { GECIS, SAHNE, gecisBasi } from "../zaman"; + +/** + * 3 · Sıralamanı gir. Hero formunun kendisi (hero-form.tsx): puan türü + * çipleri, sıralama alanı, turuncu CTA. Sahne dalgayla açılırken form + * yatık bir düzlemden doğrulur (derinlik). İmleç alana tıklar, sıralama + * yazılır, imleç CTA'ya gider ve basar → sahne butonun içinden geçilerek + * terk edilir. + */ + +const CTA_METNI = "Yapay Zeka listemi kur"; +const FORM_Y = 610; +const FORM_H = 104; +const GIRIS_W = 860; +const ARA = 24; +const PUAN_TURLERI = ["Sayısal", "Eşit Ağırlık", "Sözel", "Dil", "TYT"]; + +const ctaGenislik = () => + 2 * 0.52 * FORM_H + + olc(CTA_METNI, { family: FONT.govde, size: FORM_H * 0.31, weight: 600 }) + + 16 + + FORM_H * 0.31; + +const formSol = () => W / 2 - (GIRIS_W + ARA + ctaGenislik()) / 2; + +export const siralamaTiklama = () => ({ + x: formSol() + GIRIS_W + ARA + ctaGenislik() / 2, + y: FORM_Y + FORM_H / 2, +}); + +const TIK = gecisBasi(SAHNE.siralama, GECIS.g3); +const YAZ_BAS = 34; + +export const S3Siralama: React.FC = () => { + const f = useCurrentFrame(); + const cta = siralamaTiklama(); + const sol = formSol(); + const girisX = sol + 150; + const yol: Yol = [ + { at: 2, x: 1620, y: 980 }, + { at: 28, x: girisX, y: cta.y + 6, duration: 26 }, + { at: 30, x: girisX, y: cta.y + 6, click: true, duration: 2 }, + { at: TIK - 10, x: cta.x - 40, y: cta.y + 4, duration: 30 }, + { at: TIK, x: cta.x - 40, y: cta.y + 4, click: true, duration: 10 }, + ]; + const izler = isiIzi(yol, f); + const yazi = useTypewriter(ORNEK_SIRA_METNI, { cps: 10, startFrame: YAZ_BAS }); + const odak = aralik(f, 30, 36); + const hover = aralik(f, TIK - 18, TIK - 10); + const bas = f >= TIK && f < TIK + 8 ? 1 - Math.abs(f - TIK - 4) / 4 : 0; + + // Form yatık düzlemden doğrulur + const dogrul = aralik(f, 0, 30, ease.out); + + return ( + + + + + + + Nasıl çalışır? · 1/3 + + + + + + + + {/* Puan türü çipleri: Sayısal seçili */} + + {PUAN_TURLERI.map((t, i) => ( +
+ {t} +
+ ))} +
+ +
+ } + /> + + {CTA_METNI} + +
+ + + + Veri: YÖK Atlas · 2026 yerleştirme sonuçları + + +
+
+ +
+ ); +}; diff --git a/video/src/sahneler/S4Havuz.tsx b/video/src/sahneler/S4Havuz.tsx new file mode 100644 index 0000000..cd81a7d --- /dev/null +++ b/video/src/sahneler/S4Havuz.tsx @@ -0,0 +1,707 @@ +import { Building2, Landmark, Scale } from "lucide-react"; +import { AbsoluteFill, Sequence, useCurrentFrame } from "remotion"; +import { FocusBlurResolve } from "@/components/remocn/focus-blur-resolve"; +import { KineticCenterBuild } from "@/components/remocn/kinetic-center-build"; +import { TrackingIn } from "@/components/remocn/tracking-in"; +import { Imlec, type Yol } from "../bilesenler/Imlec"; +import { Cikis, Kutu } from "../bilesenler/Kinetik"; +import { Rozet } from "../bilesenler/Logo"; +import { Cip, DILIM_RENK, DilimEtiketi, PikselTrend } from "../bilesenler/UI"; +import { FONT } from "../fontlar"; +import { PIKSEL, R, W, opaklikFor } from "../marka"; +import { TURKIYE_HUCRELER } from "../turkiye"; +import { DILIM_ETIKET, HUNI, ISKELET, LISTE, SORULAN, type Dilim } from "../veri"; +import { aralik, clamp01, ease, hash, karis, lerp, olc, tr } from "../yardimci"; +import { GECIS, SAHNE, gecisBasi } from "../zaman"; + +/** + * 4 · Havuz → 24'lük liste. + * + * A) Sihirbaz (alan → il → devlet/vakıf). Sağda aday havuzu: sayı her + * seçimde küçülür, altındaki piksel alanından o kadar piksel düşer. + * Son adımda kalan her piksel **bir gerçek programdır** (179). + * B) Kart derinliğe çekilir; 179 piksel havuz sınırının içine toplanır. + * Dışarıdaki gri pikseller sınıra çarpıp geri döner (yapay zekâ havuzun + * dışına çıkamaz). 24 piksel seçilir, dilim renklerini alır ve soldaki + * 24'lük şeride uçar; sağda liste yatık bir düzlemden doğrulur. İmleç + * bir satıra tıklar → sahne o satırın içinden terk edilir. + */ + +const TIK = gecisBasi(SAHNE.havuz, GECIS.g4); + +// ——— Sihirbaz kartı yerleşimi ——— +const KART = { x: 150, y: 170, w: 860, h: 740, ic: 64 }; +const ICERIK_X = KART.x + KART.ic; +const ICERIK_W = KART.w - KART.ic * 2; +const CIP_BOY = 72; + +const ALANLAR = [ + "Mühendislik & Teknoloji", + "Sağlık & Tıp", + "Fen & Temel Bilimler", + "Mimarlık & Tasarım", + "İktisat & İşletme", + "Eğitim & Öğretmenlik", + "Hukuk & Siyasal", + "Tarım & Doğa", +]; +const ILLER = ["İstanbul", "Ankara", "İzmir", "Bursa", "Antalya", "Eskişehir"]; +const IL_HUCRE: Record = { + İstanbul: [8, 4], + Ankara: [23, 9], + İzmir: [4, 16], +}; + +/** Çipleri kart genişliğinde satırlara dizer (gerçek yazı genişliğiyle) */ +const cipDiz = (metinler: string[], x0: number, y0: number, ikonlu = false) => { + const ara = 16; + let x = x0; + let y = y0; + return metinler.map((m) => { + const w = + CIP_BOY * 0.7 + + olc(m, { family: FONT.govde, size: CIP_BOY * 0.35, weight: 600 }) + + (ikonlu ? CIP_BOY * 0.35 + CIP_BOY * 0.15 : 0); + if (x + w > x0 + ICERIK_W) { + x = x0; + y += CIP_BOY + ara; + } + const k = { metin: m, x, y, w, cx: x + w / 2, cy: y + CIP_BOY / 2 }; + x += w + ara; + return k; + }); +}; + +// Adım pencereleri: [giriş, çıkış] +const ADIM: [number, number][] = [ + [-10, 88], + [86, 154], + [152, 214], +]; + +// Tıklama kareleri +const T_ALAN = 46; +const T_IL = [106, 120, 134]; +const T_TUR = 174; + +// ——— Havuz sayacı ve piksel alanı ——— +const SAYAC: { a: number; b: number; n: number }[] = [ + { a: 8, b: 34, n: HUNI[1].n }, + { a: 48, b: 70, n: HUNI[2].n }, + { a: 136, b: 158, n: HUNI[3].n }, + { a: 176, b: 198, n: HUNI[4].n }, +]; +const sayacAt = (f: number) => { + let n: number = HUNI[0].n; + let adim = 0; + for (const [i, s] of SAYAC.entries()) { + if (f >= s.a) { + n = lerp(n, s.n, aralik(f, s.a, s.b, ease.out)); + adim = i + 1; + } + } + return { n, adim }; +}; + +const ALAN = { x: 1100, y: 560, sutun: 30, satir: 14, hucre: 22 }; +const HAVUZ = HUNI[4].n; // 179 +const EN_COK = ALAN.sutun * ALAN.satir; // 420 +const yanan = (n: number) => + HAVUZ + (EN_COK - HAVUZ) * (Math.log10(n / HAVUZ) / Math.log10(HUNI[0].n / HAVUZ)); + +// Kümelenme (B): havuz sınırı içinde 17×11 +const KUME = { sutun: 17, hucre: 34, cx: 960, cy: 590 }; +const KUME_SATIR = Math.ceil(HAVUZ / KUME.sutun); +const KUME_X0 = KUME.cx - (KUME.sutun * KUME.hucre) / 2; +const KUME_Y0 = KUME.cy - (KUME_SATIR * KUME.hucre) / 2; +const SINIR = { + x: KUME_X0 - 30, + y: KUME_Y0 - 30, + w: KUME.sutun * KUME.hucre + 60, + h: KUME_SATIR * KUME.hucre + 60, +}; + +// Şerit (B4): seçilen 24 piksel +const SERIT = { x: 140, y: 700, hucre: 30 }; + +const pikseller = (() => { + const hucreler = Array.from({ length: EN_COK }, (_, i) => ({ + i, + gx: i % ALAN.sutun, + gy: Math.floor(i / ALAN.sutun), + h: hash(i % ALAN.sutun, Math.floor(i / ALAN.sutun), 41), + })); + const sirali = [...hucreler].sort((a, b) => a.h - b.h); + const rutbe = new Map(sirali.map((c, r) => [c.i, r])); + const havuzdakiler = hucreler.filter((c) => (rutbe.get(c.i) ?? 0) < HAVUZ); // alan sırasına göre + const havuzSira = new Map(havuzdakiler.map((c, p) => [c.i, p])); + // 24 seçim: havuzdan dağınık + const secimSirasi = [...havuzdakiler].sort((a, b) => hash(a.i, 3, 77) - hash(b.i, 3, 77)).slice(0, 24); + const dilimler: Dilim[] = ISKELET.flatMap((d) => Array(d.adet).fill(d.dilim)); + const secim = new Map(secimSirasi.map((c, k) => [c.i, { k, dilim: dilimler[k] }])); + return hucreler.map((c) => ({ + ...c, + rutbe: rutbe.get(c.i) ?? 0, + p: havuzSira.get(c.i), + secim: secim.get(c.i), + })); +})(); + +// Havuz dışındaki "hayalet" programlar: sınıra çarpıp geri döner +const HAYALETLER = [ + { bx: SINIR.x, by: SINIR.y + 90, nx: -1, ny: 0 }, + { bx: SINIR.x, by: SINIR.y + 300, nx: -1, ny: 0 }, + { bx: SINIR.x + SINIR.w, by: SINIR.y + 150, nx: 1, ny: 0 }, + { bx: SINIR.x + SINIR.w, by: SINIR.y + 340, nx: 1, ny: 0 }, + { bx: SINIR.x + 180, by: SINIR.y + SINIR.h, nx: 0, ny: 1 }, + { bx: SINIR.x + 420, by: SINIR.y, nx: 0, ny: -1 }, +]; + +// ——— Liste (B4) ——— +const LISTE_X = 950; +const LISTE_W = 860; +const SATIR_H = 84; +const BASLIK_H = 58; +const DAHA_H = 42; +const BOLUMLER = ISKELET.map((d) => ({ + ...d, + satirlar: LISTE.map((s, i) => ({ s, i })).filter(({ s }) => s.dilim === d.dilim), +})); +const listeUst = (f: number) => lerp(150, 12, aralik(f, 330, 392, ease.inOut)); +// Tıklanan satırın liste içindeki konumu +const HEDEF_SATIR = LISTE.indexOf(SORULAN); +const hedefOfset = (() => { + let y = 0; + for (const b of BOLUMLER) { + y += BASLIK_H; + for (const { i } of b.satirlar) { + if (i === HEDEF_SATIR) return y; + y += SATIR_H; + } + y += DAHA_H; + } + return y; +})(); + +export const havuzTiklama = () => ({ + x: LISTE_X + LISTE_W * 0.42, + y: listeUst(TIK) + hedefOfset + SATIR_H / 2, +}); + +export const S4Havuz: React.FC = () => { + const f = useCurrentFrame(); + + const alanCip = cipDiz(ALANLAR, ICERIK_X, 430); + const ilCip = cipDiz(ILLER, ICERIK_X, 744); + const turCip = cipDiz(["Devlet", "Vakıf", "Fark etmez"], ICERIK_X, 494, true); + const hedef = havuzTiklama(); + + const yol: Yol = [ + { at: 16, x: 1480, y: 1010 }, + { at: T_ALAN, x: alanCip[0].cx, y: alanCip[0].cy, duration: 26, click: true }, + { at: T_IL[0], x: ilCip[0].cx, y: ilCip[0].cy, duration: 30, click: true }, + { at: T_IL[1], x: ilCip[1].cx, y: ilCip[1].cy, duration: 12, click: true }, + { at: T_IL[2], x: ilCip[2].cx, y: ilCip[2].cy, duration: 12, click: true }, + { at: T_TUR, x: turCip[0].cx, y: turCip[0].cy, duration: 28, click: true }, + { at: 206, x: 1180, y: 1060, duration: 26 }, + { at: 350, x: 1880, y: 1040, duration: 4 }, + { at: 380, x: 1560, y: 760, duration: 28 }, + { at: TIK - 2, x: hedef.x, y: hedef.y, duration: 16 }, + { at: TIK, x: hedef.x, y: hedef.y, click: true, duration: 2 }, + ]; + const imlecGorunur = f < 230 ? ([12, 228] as [number, number]) : ([352, SAHNE.havuz] as [number, number]); + + const { n, adim } = sayacAt(f); + const yananF = yanan(n); + + // ——— Faz geçişleri ——— + const kartCikis = aralik(f, 198, 232, ease.in); + const panelCikis = aralik(f, 198, 214); + const kume = (p: number) => ease.inOut(clamp01((f - 204 - p * 0.1) / 26)); + const secimBas = 262; + const seritBas = 300; + const sinirOp = aralik(f, 222, 238) * (1 - aralik(f, 300, 316)); + + // ——— Pikseller ——— + const rects: React.ReactNode[] = []; + for (const c of pikseller) { + let x = ALAN.x + c.gx * ALAN.hucre + ALAN.hucre / 2; + let y = ALAN.y + c.gy * ALAN.hucre + ALAN.hucre / 2; + let boy = ALAN.hucre * PIKSEL.nokta; + let renk: string = R.primary; + let op = 0.25 + opaklikFor(c.gx, c.gy) * 1.9; + // Belirme (kart ile birlikte) + const belir = aralik(f, 4 + (c.gx + c.gy) * 0.35, 14 + (c.gx + c.gy) * 0.35, ease.out); + op *= belir; + // Havuzdan düşenler: sayaç indikçe sırası gelen piksel griye döner ve düşer + if (c.rutbe >= yananF) { + const dus = clamp01((c.rutbe + 1 - yananF) / 20); + if (dus >= 1) continue; + y += dus * dus * 150; + renk = karis(R.primary, R.slate300, clamp01(dus * 3)); + op *= 1 - dus; + } + if (c.p !== undefined) { + // B: kümeye toplanma + const e = kume(c.p); + const kx = KUME_X0 + (c.p % KUME.sutun) * KUME.hucre + KUME.hucre / 2; + const ky = KUME_Y0 + Math.floor(c.p / KUME.sutun) * KUME.hucre + KUME.hucre / 2; + x = lerp(x, kx, e); + y = lerp(y, ky, e); + boy = lerp(boy, KUME.hucre * PIKSEL.nokta, e); + op = lerp(op, 0.55 + opaklikFor(c.gx, c.gy), e); + if (c.secim) { + const s = aralik(f, secimBas + c.secim.k * 1.3, secimBas + 8 + c.secim.k * 1.3, ease.out); + renk = karis(renk, DILIM_RENK[c.secim.dilim].nokta, s); + op = lerp(op, 1, s); + // seçilirken kısa bir halka + const halka = Math.sin(Math.PI * s); + if (halka > 0.02) { + const hb = boy * (1 + 0.7 * halka); + rects.push( + , + ); + } + // şeride uçuş + const u = ease.inOut(clamp01((f - seritBas - c.secim.k * 0.9) / 26)); + x = lerp(x, SERIT.x + c.secim.k * SERIT.hucre + SERIT.hucre / 2, u); + y = lerp(y, SERIT.y + SERIT.hucre / 2, u); + boy = lerp(boy, SERIT.hucre * PIKSEL.nokta, u); + } else { + op *= 1 - 0.72 * aralik(f, secimBas, secimBas + 26); + op *= 1 - aralik(f, seritBas, seritBas + 14); + if (op <= 0.01) continue; + } + } + rects.push( + , + ); + } + + // Hayaletler + const hayaletler = HAYALETLER.map((g, i) => { + const u = (f - (240 + i * 5)) / 26; + if (u < 0 || f > 316) return null; + const bosluk = + u < 1 + ? lerp(170, 10, ease.in(u)) + : 10 + 46 * Math.abs(Math.sin((u - 1) * Math.PI * 1.2)) * Math.exp(-(u - 1) * 2.4); + const boy = KUME.hucre * PIKSEL.nokta; + const x = g.bx + g.nx * (bosluk + boy / 2); + const y = g.by + g.ny * (bosluk + boy / 2); + const op = aralik(u, 0, 0.3) * (1 - aralik(f, 300, 316)); + return ( + + ); + }); + // Çarpma anında sınır kısa süre turuncuya döner + const carpma = Math.max( + ...HAYALETLER.map((_, i) => { + const u = (f - (240 + i * 5)) / 26 - 1; + return u >= 0 && u < 0.4 ? 1 - u / 0.4 : 0; + }), + ); + + // Kartın adımları + const adimStil = (k: number): React.CSSProperties => { + const [a, b] = ADIM[k]; + const g = aralik(f, a, a + 10, ease.out); + const c = aralik(f, b - 8, b, ease.in); + return { + position: "absolute", + inset: 0, + opacity: g * (1 - c), + translate: `${(1 - g) * 90 - c * 90}px 0`, + filter: `blur(${(1 - g) * 6 + c * 6}px)`, + }; + }; + const secildi = (t: number) => aralik(f, t, t + 5); + const uzerinde = (t: number) => aralik(f, t - 7, t - 2) * (1 - aralik(f, t, t + 3)); + const aktifAdim = f < ADIM[1][0] + 4 ? 0 : f < ADIM[2][0] + 4 ? 1 : 2; + + const basliklar = ["Hangi alanlara ilgi duyuyorsun?", "Nerede okumak istersin?", "Üniversite tipi & öncelikler"]; + const aciklamalar = [ + "Sıralamanla ulaşabileceğin alanlar. En az bir tane seç.", + "En fazla 5 il seçebilirsin. İstersen boş bırak, fark etmez.", + "Bunlar listenin dengesini belirler.", + ]; + + return ( + + {/* ——— A: sihirbaz kartı (derinliğe çekilerek çıkar) ——— */} + +
+
+ {/* İlerleme */} +
+ {[0, 1, 2].map((k) => ( +
+ ))} + + {aktifAdim + 1} / 3 + +
+ {[0, 1, 2].map((k) => ( +
+
+ {basliklar[k]} +
+
+ {aciklamalar[k]} +
+ {k === 0 && + alanCip.map((c, i) => ( + + {c.metin} + + ))} + {k === 1 && ( + <> + + {ilCip.map((c, i) => ( + + {c.metin} + + ))} + + )} + {k === 2 && ( + <> +
+ Üniversite tipi +
+ {turCip.map((c, i) => { + const Ikon = [Landmark, Building2, Scale][i]; + const sec = i === 0 ? secildi(T_TUR) : 0; + return ( + } + style={{ position: "absolute", left: c.x, top: c.y }} + > + {c.metin} + + ); + })} +
+ Öncelikler +
+ {cipDiz(["Burslu", "Öğretim dili", "Evime yakın"], ICERIK_X, 672).map((c) => ( + + {c.metin} + + ))} + + )} +
+ ))} +
+
+ + + {/* ——— A: aday havuzu paneli ——— */} +
+ + Nasıl çalışır? · 2/3 + +
+ Aday havuzu +
+
+ + {tr(n)} + + program +
+ {HUNI.map((h, i) => { + const op = i === adim ? aralik(f, i === 0 ? 0 : SAYAC[i - 1].a, (i === 0 ? 0 : SAYAC[i - 1].a) + 8) : 0; + return ( +
+ {h.etiket} +
+ ); + })} +
+ + {/* ——— B: havuz sınırı ——— */} + {sinirOp > 0 && ( + <> +
+
+ Aday havuzu · 179 gerçek program +
+ + )} + + + {hayaletler} + {rects} + + + + + + + + + + + + + + + + {/* ——— B4: sol başlık + 24'lük şerit + dilimler ——— */} + {f >= 316 && } + + {/* ——— B4: liste ——— */} + {f >= 318 && } + + + + ); +}; + +/** İl adımındaki dot-matrix harita; seçilen iller turuncu yanar */ +const MiniHarita: React.FC<{ x: number; y: number; f: number }> = ({ x, y, f }) => { + const hucre = 10.6; + const boy = hucre * PIKSEL.nokta; + const secim = Object.entries(IL_HUCRE).map(([ad, [cx, cy]], i) => ({ ad, cx, cy, s: aralik(f, T_IL[i], T_IL[i] + 8, ease.geriTep) })); + return ( + + {TURKIYE_HUCRELER.map(({ x: gx, y: gy }) => { + let isi = 0; + for (const s of secim) { + const d = Math.hypot(gx - s.cx, gy - s.cy); + if (d <= 1.5) isi = Math.max(isi, s.s * (d < 0.5 ? 1 : 0.75)); + } + const b = boy * (1 + 0.25 * isi); + return ( + + ); + })} + + ); +}; + +const SolaYasli: React.FC<{ x: number; y: number; metin: React.ReactNode; genislik: number; bas: number; boy: number; family: string; renk?: string }> = ({ x, y, metin, genislik, bas, boy, family, renk = R.slate900 }) => ( + + + + + +); + +const ListeBasligi: React.FC<{ f: number }> = ({ f }) => { + const boy = 118; + const w1 = olc("Dengeli", { family: FONT.baslik, size: boy, weight: 700, tracking: 0.015 }); + const w2 = olc("24'lük", { family: FONT.vurgu, size: boy, weight: 700, italic: true, tracking: -0.05 }); + const w3 = olc("listen hazır.", { family: FONT.baslik, size: boy, weight: 700, tracking: 0.015 }); + return ( + <> + + Nasıl çalışır? · 3/3 + + + 24'lük} + /> + +
+ {ISKELET.map((d) => ( + + + {d.adet} + + ))} +
+
+ Örnek: SAY 45.000 · Mühendislik & Teknoloji · İstanbul, Ankara, İzmir · Devlet. + Satırlar 2026 YÖK Atlas kayıtlarıdır. +
+ + ); +}; + +const Liste: React.FC<{ f: number; hover: number }> = ({ f, hover }) => { + const duz = aralik(f, 330, 390, ease.inOut); + const ust = listeUst(f); + let y = 0; + let sira = 0; + const ogeler: React.ReactNode[] = []; + BOLUMLER.forEach((b, bi) => { + const by = y; + ogeler.push( +
+ + · {b.adet} tercih +
, + ); + y += BASLIK_H; + b.satirlar.forEach(({ s, i }) => { + sira++; + const hedef = i === HEDEF_SATIR; + const sy = y; + ogeler.push( +
+ + {LISTE_SIRASI[i]} + +
+
0.5 ? "underline" : "none", + textUnderlineOffset: 5, + whiteSpace: "nowrap", + }} + > + {s.program} +
+
+ {s.universite} · {s.il} +
+
+ +
+
{tr(s.sira[5])}
+
taban 2026
+
+
, + ); + y += SATIR_H; + }); + const kalan = b.adet - b.satirlar.length; + ogeler.push( +
+ +{kalan} {DILIM_ETIKET[b.dilim].toLocaleLowerCase("tr-TR")} tercih daha +
, + ); + y += DAHA_H; + }); + + return ( + +
+ {ogeler} +
+
+ ); +}; + +// Listede her satırın 24'lük listedeki sırası (hayal 1–5, dengeli 6–18, güvenli 19–24) +const LISTE_SIRASI: Record = (() => { + const out: Record = {}; + let bas = 1; + for (const b of BOLUMLER) { + b.satirlar.forEach(({ i }, k) => (out[i] = bas + k)); + bas += b.adet; + } + return out; +})(); + +/** Satır girişi: derinlikten öne, bulanıktan nete */ +const giris = (f: number, bas: number): React.CSSProperties => { + const g = aralik(f, bas, bas + 14, ease.out); + return { + opacity: g, + transform: `translateZ(${(1 - g) * -260}px) translateY(${(1 - g) * 24}px)`, + filter: `blur(${(1 - g) * 8}px)`, + }; +}; diff --git a/video/src/sahneler/S5Danisman.tsx b/video/src/sahneler/S5Danisman.tsx new file mode 100644 index 0000000..4e11a54 --- /dev/null +++ b/video/src/sahneler/S5Danisman.tsx @@ -0,0 +1,242 @@ +import { ArrowUp } from "lucide-react"; +import { AbsoluteFill, useCurrentFrame } from "remotion"; +import { useTypewriter } from "@/lib/remocn-ui"; +import { Imlec, type Yol } from "../bilesenler/Imlec"; +import { LogoIsaret } from "../bilesenler/Logo"; +import { PikselZemin } from "../bilesenler/PikselZemin"; +import { DilimEtiketi, GirisHap, PikselTrend } from "../bilesenler/UI"; +import { FONT } from "../fontlar"; +import { R } from "../marka"; +import { SORULAN, ORNEK_SIRA_METNI } from "../veri"; +import { aralik, ease, karis, lerp, olc, tr } from "../yardimci"; +import { GECIS, SAHNE, gecisBasi } from "../zaman"; + +/** + * 5 · Danışman. Tıklanan satır sohbetin konusu olur. Soru yazılır, gönder + * düğmesine basılır; yanıt beklenirken logonun üç karesi nabız atar + * (animasyonlu-mark.tsx "nabız"). Yanıt yalnızca gerçek taban geçmişini + * söyler ve altında 6 yılın piksel trendi belirir; son yılın turuncu pikseli + * bir sonraki dalganın çıkış noktasıdır. + */ + +const PANEL = { x: 330, y: 64, w: 1260, h: 952 }; +const SORU = "Bu tercih neden dengeli dilimde?"; +const YANIT = `2026'da taban sırası ${tr(SORULAN.sira[5])}, seninki ${ORNEK_SIRA_METNI}. Ama son 6 yılda taban ${tr(Math.min(...SORULAN.sira))} ile ${tr(Math.max(...SORULAN.sira))} arasında gidip geldi — bu kadar dalgalı olduğu için dengeli dilimde.`; + +const YAZ_BAS = 12; +const GONDER = 58; +const BEKLE: [number, number] = [64, 86]; +const TREND_BAS = 150; + +const GIRIS_Y = PANEL.y + PANEL.h - 132; +const GONDER_X = PANEL.x + PANEL.w - 64 - 42; +const GONDER_Y = GIRIS_Y + 52; + +// Yanıt balonu ve içindeki trend (satır sayısı gerçek yazı genişliğiyle) +const BALON = { x: PANEL.x + 56, y: PANEL.y + 330, w: 960, pad: 40, ust: 30, punto: 32, satir: 48 }; +const TREND_H = { hucre: 34, yukseklik: 90 }; +const satirSayisi = () => { + const bosluk = olc(" ", { family: FONT.govde, size: BALON.punto }); + let n = 1; + let x = 0; + for (const k of YANIT.split(" ")) { + const w = olc(k, { family: FONT.govde, size: BALON.punto }); + if (x > 0 && x + bosluk + w > BALON.w - BALON.pad * 2) { + n++; + x = w; + } else x += (x > 0 ? bosluk : 0) + w; + } + return n; +}; +const trendKonumu = () => ({ + x: BALON.x + BALON.pad, + y: BALON.y + BALON.ust + satirSayisi() * BALON.satir + 28, +}); +/** Trendin son (2026) pikseli: bir sonraki dalga buradan yayılır */ +export const danismanDalgaNoktasi = () => { + const t = trendKonumu(); + const son = SORULAN.sira[5]; + const min = Math.min(...SORULAN.sira); + const max = Math.max(...SORULAN.sira); + return { + x: t.x + 5 * TREND_H.hucre + TREND_H.hucre / 2, + y: t.y + ((son - min) / (max - min)) * TREND_H.yukseklik + (TREND_H.hucre * 0.74) / 2, + }; +}; + +export const S5Danisman: React.FC = () => { + const f = useCurrentFrame(); + const soru = useTypewriter(SORU, { cps: 24, startFrame: YAZ_BAS }); + const yanit = useTypewriter(YANIT, { cps: 70, startFrame: BEKLE[1] }); + const gonderildi = f >= GONDER; + + const yol: Yol = [ + { at: 8, x: 1700, y: 1050 }, + { at: GONDER - 4, x: GONDER_X, y: GONDER_Y, duration: 30 }, + { at: GONDER, x: GONDER_X, y: GONDER_Y, click: true, duration: 4 }, + { at: 100, x: 1740, y: 1010, duration: 30 }, + ]; + const bas = f >= GONDER && f < GONDER + 8 ? 1 - Math.abs(f - GONDER - 4) / 4 : 0; + const soruBalon = aralik(f, GONDER + 2, GONDER + 14, ease.geriTep); + const bekliyor = f >= BEKLE[0] && f < BEKLE[1] + 4; + const yanitBalon = aralik(f, BEKLE[1] - 4, BEKLE[1] + 8, ease.out); + const trend = trendKonumu(); + + return ( + + +
+ {/* Başlık */} +
+ { + const faz = ((f / 30) * 2 * Math.PI) / 1.8 - (i * 2 * Math.PI) / 3; + const nabiz = bekliyor ? 0.5 + 0.5 * Math.sin(faz) : 1; + return { olcek: lerp(0.78, 1, nabiz) }; + }} + /> +
+
Danışman
+
+ {SORULAN.program} · {SORULAN.universite} +
+
+
+
+ +
+
+ + {/* Soru balonu */} + {soruBalon > 0 && ( +
+ {SORU} +
+ )} + + {/* Bekleme: üç kare nabız */} + {bekliyor && ( +
+ {[0, 1, 2].map((i) => { + const s = 0.55 + 0.45 * Math.sin((f / 30) * 2 * Math.PI * 1.4 - i * 1.1); + return
; + })} +
+ )} + + {/* Yanıt balonu */} + {yanitBalon > 0 && ( +
+ {/* Yer tutucu: balon baştan tam boyda dursun, metin akarken zıplamasın */} +
+ {YANIT} + {yanit.text} +
+
+
+ )} +
+ + {/* Trend: 6 yılın taban sırası piksel piksel */} +
+ +
+
+
+ Taban sırası, 2021–2026 +
+
Kaynak: YÖK Atlas · yapay zekâ yorumu değil, gerçek geçmiş
+
+ + {/* Giriş */} +
+ +
+ +
+
+ + + + ); +}; + +export const DANISMAN_DALGA_BASI = gecisBasi(SAHNE.danisman, GECIS.g5); diff --git a/video/src/sahneler/S6Deger.tsx b/video/src/sahneler/S6Deger.tsx new file mode 100644 index 0000000..3edc7da --- /dev/null +++ b/video/src/sahneler/S6Deger.tsx @@ -0,0 +1,120 @@ +import { AbsoluteFill, Sequence, useCurrentFrame } from "remotion"; +import { FocusBlurResolve } from "@/components/remocn/focus-blur-resolve"; +import { SlotMachineRoll } from "@/components/remocn/slot-machine-roll"; +import { TrackingIn } from "@/components/remocn/tracking-in"; +import { Kutu } from "../bilesenler/Kinetik"; +import { Rozet } from "../bilesenler/Logo"; +import { FONT } from "../fontlar"; +import { R } from "../marka"; +import { aralik, ease, lerp, olc } from "../yardimci"; + +/** + * 6 · Değer. Solda "Tahmin değil, veri." ve dürüstlük notu; sağda sitenin + * gösterge kareleri (DESIGN.md §4.11): logodaki üç kare gibi iki sütun, + * sağdaki aşağı kaymış, boylar farklı. Kareler derinlikten gelip oturur, + * sayılar slot makinesi gibi yerine döner. + */ + +type Kare = { renk: string; sayi: [string, string]; etiket: string; x: number; y: number; w: number; h: number; bas: number }; + +const SUTUN_W = 400; +const SOL_X = 990; +const SAG_X = SOL_X + SUTUN_W + 36; +const UST = 96; + +// Renk sırası: en önemli turuncu, sonra mavi, indigo, yeşil (§4.11) +export const KARELER: Kare[] = [ + { renk: R.turuncu, sayi: ["00.000+", "21.000+"], etiket: "program tarandı", x: SOL_X, y: UST, w: SUTUN_W, h: 420, bas: 8 }, + { renk: R.primary, sayi: ["0 yıl", "6 yıl"], etiket: "taban sıralaması trendi", x: SAG_X, y: UST + 130, w: SUTUN_W, h: 330, bas: 15 }, + { renk: R.indigo500, sayi: ["%000", "%100"], etiket: "resmî YÖK Atlas verisi", x: SOL_X, y: UST + 460, w: SUTUN_W, h: 300, bas: 22 }, + { renk: R.green600, sayi: ["00", "24"], etiket: "tercihlik dengeli liste", x: SAG_X, y: UST + 500, w: SUTUN_W, h: 390, bas: 29 }, +]; + +/** Son karenin merkezi: kapanışa giden koyu dalga buradan */ +export const degerDalgaNoktasi = () => { + const k = KARELER[3]; + return { x: k.x + k.w / 2, y: k.y + k.h / 2 }; +}; + +export const S6Deger: React.FC = () => { + const f = useCurrentFrame(); + const boy = 132; + const w1 = olc("Tahmin değil,", { family: FONT.baslik, size: boy, weight: 700, tracking: 0.015 }); + const w2 = olc("veri.", { family: FONT.vurgu, size: boy, weight: 700, italic: true, tracking: -0.05 }); + const n1 = "Yerleşme garantisi vermiyoruz."; + const n2 = "Riski satır satır gösteriyoruz."; + const nw1 = olc(n1, { family: FONT.govde, size: 38, weight: 600 }); + const nw2 = olc(n2, { family: FONT.govde, size: 38, weight: 600 }); + + return ( + + + Neden KolayTercih? + + + + + + + + + veri.} + fontFamily={FONT.vurgu} + fontSize={boy} + color={R.primary} + startTracking={0.9} + endTracking={-0.05} + /> + + + + + + + + + + + + + + {/* Gösterge kareleri — derinlikten gelip oturur */} + + {KARELER.map((k, i) => { + const g = aralik(f, k.bas, k.bas + 22, ease.out); + const yuz = Math.sin((f + i * 17) / 22) * 6 * g; + return ( +
+ + + + {k.etiket} +
+ ); + })} +
+
+ ); +}; diff --git a/video/src/sahneler/S7Kapanis.tsx b/video/src/sahneler/S7Kapanis.tsx new file mode 100644 index 0000000..8ce5453 --- /dev/null +++ b/video/src/sahneler/S7Kapanis.tsx @@ -0,0 +1,205 @@ +import { AbsoluteFill, Sequence, useCurrentFrame } from "remotion"; +import { KineticCenterBuild } from "@/components/remocn/kinetic-center-build"; +import { TrackingIn } from "@/components/remocn/tracking-in"; +import { Vinyet } from "../bilesenler/Gren"; +import { Imlec, isi, isiIzi, type Yol } from "../bilesenler/Imlec"; +import { Kutu } from "../bilesenler/Kinetik"; +import { LogoIsaret } from "../bilesenler/Logo"; +import { CtaButon } from "../bilesenler/UI"; +import { FONT } from "../fontlar"; +import { dalgaYaricapi } from "../gecisler/piksel-dalga"; +import { H, LOGO_KARELER, PIKSEL, R, W } from "../marka"; +import { aralik, clamp01, ease, hash, karis, lerp, olc } from "../yardimci"; +import { GECIS } from "../zaman"; +import { degerDalgaNoktasi } from "./S6Deger"; + +/** + * 7 · Kapanış. Sitenin tek koyu yüzeyi olan CTA bandının dili: kenarlarda + * büyüklü küçüklü, hafif kaymış kareler (PixelMasonry). Logo kareleri + * "rota" hareketiyle yer değiştirip oturur, kelime marka harf aralığı + * daralarak gelir, slogan kinetik kurulur. İmleç CTA'ya gelirken yolundaki + * kareler turuncuya ısınır; tıklar. + */ + +const LOGO_BOY = 200; +const LOGO_Y = 330; +const KELIME_BOY = 126; +const KELIME_OFSET = (46.7 / 44) * LOGO_BOY; +const CTA_Y = 690; +const CTA_H = 112; +const TIK = 138; + +// PixelMasonry: 4×4 hücrelik makro hücrelere 2–4 hücrelik tek kare, kenar bandında +const MASONRY = (() => { + const hucre = 22; + const makro = hucre * 4; + const bant = Math.min(W, H) * 0.3; + const out: { x: number; y: number; boy: number; op: number; vurgu: string | null }[] = []; + for (let j = 0; j * makro < H; j++) { + for (let i = 0; i * makro < W; i++) { + const cx = i * makro + makro / 2; + const cy = j * makro + makro / 2; + const kenar = Math.min(cx, W - cx, cy, H - cy); + const yog = clamp01(1 - kenar / bant); + if (hash(i, j, 7) > yog * 0.95) continue; + const n = 2 + Math.floor(hash(i, j, 8) * 3); + const boy = n * hucre; + const bos = makro - boy; + const r = hash(i, j, 9); + out.push({ + x: i * makro + hash(i, j, 10) * bos + boy / 2, + y: j * makro + hash(i, j, 11) * bos + boy / 2, + boy: boy * 0.86, + op: 0.05 + hash(i, j, 12) * 0.08, + vurgu: r > 0.93 ? R.turuncu : r > 0.87 ? R.mavi : null, + }); + } + } + return out; +})(); + +export const S7Kapanis: React.FC = () => { + const f = useCurrentFrame(); + const kok = degerDalgaNoktasi(); + const r = dalgaYaricapi(f / GECIS.g6, kok, 440); + + const ww = + olc("Kolay", { family: FONT.vurgu, size: KELIME_BOY, weight: 300, tracking: -0.05 }) + + olc("Tercih", { family: FONT.vurgu, size: KELIME_BOY, weight: 600, tracking: -0.05 }); + const sol = W / 2 - (KELIME_OFSET + ww) / 2; + const ctaW = + 2 * 0.52 * CTA_H + olc("kolaytercih.com", { family: FONT.govde, size: CTA_H * 0.31, weight: 600 }) + 16 + CTA_H * 0.31; + const cta = { x: W / 2, y: CTA_Y + CTA_H / 2 }; + + const yol: Yol = [ + { at: 96, x: 1860, y: 1050 }, + { at: 120, x: 1500, y: 900, duration: 24 }, + { at: TIK - 2, x: cta.x + ctaW * 0.28, y: cta.y + 8, duration: 16 }, + { at: TIK, x: cta.x + ctaW * 0.28, y: cta.y + 8, click: true, duration: 2 }, + ]; + const izler = isiIzi(yol, f, [96, 999]); + + // Logo "rota": her kare sıradakinin yerine süzülür, bir tur sonra evine döner + const rota = (i: number) => { + const konum = (k: number) => { + const q = LOGO_KARELER[(i + k) % 3]; + const ev = LOGO_KARELER[i]; + return { dx: q.x + q.boy / 2 - (ev.x + ev.boy / 2), dy: q.y + q.boy / 2 - (ev.y + ev.boy / 2) }; + }; + const adim = [aralik(f, 14 + i * 3, 30 + i * 3, ease.inOut), aralik(f, 34 + i * 3, 50 + i * 3, ease.inOut), aralik(f, 54 + i * 3, 70 + i * 3, ease.inOut)]; + const a = konum(0); + const b = konum(1); + const c = konum(2); + let dx = lerp(a.dx, b.dx, adim[0]); + let dy = lerp(a.dy, b.dy, adim[0]); + dx = lerp(dx, c.dx, adim[1]); + dy = lerp(dy, c.dy, adim[1]); + dx = lerp(dx, 0, adim[2]); + dy = lerp(dy, 0, adim[2]); + const ucus = Math.max(...adim.map((t) => Math.sin(Math.PI * t))); + return { dx, dy, olcek: 1 - 0.16 * ucus, opaklik: 1 - 0.4 * ucus }; + }; + const kay = aralik(f, 66, 90, ease.inOut); + const logoSol = lerp(W / 2 - LOGO_BOY / 2, sol, kay); + const hover = aralik(f, TIK - 10, TIK - 4); + const bas = f >= TIK && f < TIK + 8 ? 1 - Math.abs(f - TIK - 4) / 4 : 0; + const son = aralik(f, 168, 180); + + return ( + + + {MASONRY.map((m, i) => { + const d = Math.hypot(m.x - kok.x, m.y - kok.y); + const pop = ease.geriTep(clamp01((r - d - 0.3 * 440) / (0.4 * 440))); + if (pop <= 0) return null; + const h = isi(m.x, m.y, izler, 150); + const boy = m.boy * pop; + const taban = m.vurgu ?? R.beyaz; + return ( + + ); + })} + + + + + + + + Kolay + Tercih + + } + fontFamily={FONT.vurgu} + fontSize={KELIME_BOY} + fontWeight={300} + color={R.beyaz} + startTracking={0.55} + endTracking={-0.05} + /> + + + + + + + +
+ + kolaytercih.com + +
+
+ Bağımsız bir karar destek aracıdır. ÖSYM ya da YÖK ile bağlantılı değildir; yerleşme garantisi vermez. +
+ + + + + ); +}; diff --git a/video/src/turkiye.ts b/video/src/turkiye.ts new file mode 100644 index 0000000..be87e5c --- /dev/null +++ b/video/src/turkiye.ts @@ -0,0 +1,51 @@ +/** + * Dot-matrix Türkiye silüeti — src/features/pazarlama/components/turkey-pixel-map.tsx + * ile aynı ızgara (64×26 hücre, gerçek sınır poligonlarından rasterize). + */ +export const TURKIYE_IZGARA = [ + "..######..............##########................................", + "..#######...........##############..............................", + "..#######.........#################................#####........", + ".########...###########################...........########......", + ".######.....###############################################.....", + ".###........###############################################.....", + ".##.......##################################################....", + ".###########################################################....", + ".#############################################################..", + "..#############################################################.", + "...############################################################.", + "...##########################################################...", + "...##########################################################...", + "...###########################################################..", + "..############################################################..", + "..############################################################..", + "...###########################################################..", + "....##########################################################..", + "....##########################################################..", + ".....#########################################################..", + ".....###################################################..##....", + ".....############################################...............", + "......##########..######################...###..................", + "...........#####....#########....#####..........................", + "............###.......#####......####...........................", + ".................................###............................",]; + +/** Hero'daki vurgu şehirleri (sütun, satır) */ +export const SEHIRLER = [ + { name: "İstanbul", x: 8, y: 4 }, + { name: "Ankara", x: 23, y: 9 }, + { name: "İzmir", x: 4, y: 16 }, + { name: "Antalya", x: 16, y: 22 }, + { name: "Kayseri", x: 32, y: 14 }, + { name: "Trabzon", x: 46, y: 5 }, + { name: "Diyarbakır", x: 47, y: 18 }, + { name: "Van", x: 58, y: 15 },]; + +export const IZGARA_SUTUN = TURKIYE_IZGARA[0].length; +export const IZGARA_SATIR = TURKIYE_IZGARA.length; + +/** Dolu hücreler (x, y) */ +export const TURKIYE_HUCRELER: { x: number; y: number }[] = TURKIYE_IZGARA.flatMap( + (satir, y) => + Array.from(satir).flatMap((c, x) => (c === "#" ? [{ x, y }] : [])), +); diff --git a/video/src/veri.ts b/video/src/veri.ts new file mode 100644 index 0000000..4154575 --- /dev/null +++ b/video/src/veri.ts @@ -0,0 +1,88 @@ +/** + * Videodaki örnek öğrenci ve liste — data/yokatlas.db'den (2026 kılavuzu) + * alınmış gerçek kayıtlar, uydurma satır yok. + * + * Örnek: SAY 45.000 · Mühendislik · İstanbul, Ankara, İzmir · Devlet. + * + * Havuz sayıları sadeleştirilmiş bir sorgudan (taban sırası sıralamanın + * 0,7–3 katı arasındaki SAY programları); ürünün gerçek havuz kuralı daha + * ayrıntılıdır. Sorgu: + * son_kilavuz_yili=2026 AND tur='SAYISAL' + * AND COALESCE(sira2026,sira2025) BETWEEN 31500 AND 135000 + * → 1.443 · +isim LIKE '%Mühendisliği%' → 704 + * · +il IN (İSTANBUL, ANKARA, İZMİR) → 484 · +unitur='DEVLET' → 179 + */ + +export const ORNEK_SIRA = 45000; +export const ORNEK_SIRA_METNI = "45.000"; + +/** 2026 kılavuzundaki toplam program (lisans + önlisans) */ +export const TOPLAM_PROGRAM = 21493; + +export const HUNI = [ + { n: TOPLAM_PROGRAM, etiket: "Tüm programlar" }, + { n: 1443, etiket: "Sıralamanla açılan · Sayısal" }, + { n: 704, etiket: "Mühendislik & Teknoloji" }, + { n: 484, etiket: "İstanbul · Ankara · İzmir" }, + { n: 179, etiket: "Devlet üniversiteleri" }, +] as const; + +export type Dilim = "hayal" | "dengeli" | "garanti"; + +export interface Satir { + program: string; + universite: string; + il: string; + dilim: Dilim; + /** Taban başarı sırası 2021 → 2026 */ + sira: number[]; +} + +// Görünen dilim adı "Güvenli"; iç anahtar "garanti" (src/lib/risk.ts DILIM_ETIKET) +export const DILIM_ETIKET: Record = { + hayal: "Hayal", + dengeli: "Dengeli", + garanti: "Güvenli", +}; + +export const LISTE: Satir[] = [ + { program: "Elektrik-Elektronik Mühendisliği", universite: "Dokuz Eylül Üniversitesi", il: "İzmir", dilim: "hayal", sira: [45295, 41759, 36137, 40164, 39190, 38626] }, + { program: "Elektrik-Elektronik Mühendisliği", universite: "Ankara Yıldırım Beyazıt Üniversitesi", il: "Ankara", dilim: "hayal", sira: [53586, 47520, 40031, 45027, 42086, 40221] }, + { program: "Elektrik-Elektronik Mühendisliği", universite: "İstanbul Üniversitesi-Cerrahpaşa", il: "İstanbul", dilim: "hayal", sira: [58073, 54911, 49623, 52063, 47099, 42633] }, + { program: "Endüstri Mühendisliği", universite: "İstanbul Üniversitesi-Cerrahpaşa", il: "İstanbul", dilim: "dengeli", sira: [51496, 46297, 43436, 46957, 46877, 45099] }, + { program: "Bilgisayar Mühendisliği", universite: "Dokuz Eylül Üniversitesi", il: "İzmir", dilim: "dengeli", sira: [26098, 15816, 14246, 23271, 36435, 52071] }, + { program: "Endüstri Mühendisliği", universite: "Dokuz Eylül Üniversitesi", il: "İzmir", dilim: "dengeli", sira: [58559, 52933, 49684, 54049, 54049, 53587] }, + { program: "Elektrik-Elektronik Mühendisliği", universite: "İzmir Katip Çelebi Üniversitesi", il: "İzmir", dilim: "dengeli", sira: [71760, 64426, 59156, 68341, 60857, 53699] }, + { program: "Bilgisayar Mühendisliği", universite: "Ankara Yıldırım Beyazıt Üniversitesi", il: "Ankara", dilim: "dengeli", sira: [37831, 27534, 21602, 30797, 42108, 55158] }, + { program: "Elektrik-Elektronik Mühendisliği", universite: "İstanbul Medeniyet Üniversitesi", il: "İstanbul", dilim: "garanti", sira: [76034, 74632, 70514, 74989, 67761, 59417] }, + { program: "Endüstri Mühendisliği", universite: "İstanbul Medeniyet Üniversitesi", il: "İstanbul", dilim: "garanti", sira: [79628, 73208, 67215, 70600, 68739, 65169] }, + { program: "Bilgisayar Mühendisliği", universite: "İstanbul Medeniyet Üniversitesi", il: "İstanbul", dilim: "garanti", sira: [50828, 43992, 38865, 48481, 56616, 66119] }, + { program: "Bilgisayar Mühendisliği", universite: "İzmir Katip Çelebi Üniversitesi", il: "İzmir", dilim: "garanti", sira: [55869, 41281, 36708, 47803, 56980, 71833] }, +]; + +/** Danışman sahnesinde sorulan satır: DEÜ Bilgisayar Mühendisliği */ +export const SORULAN = LISTE[4]; + +/** 24'lük iskelet hedefi (huni-semasi.tsx: hayal 5 · dengeli 13 · güvenli 6) */ +export const ISKELET: { dilim: Dilim; adet: number }[] = [ + { dilim: "hayal", adet: 5 }, + { dilim: "dengeli", adet: 13 }, + { dilim: "garanti", adet: 6 }, +]; + +/** Açılıştaki "gürültü" tüneli: listedeki gerçek taban sıraları */ +export const GURULTU_SAYILARI = [ + ...new Set(LISTE.flatMap((s) => s.sira)), +].map((n) => n.toLocaleString("tr-TR")); + +/** İl program sayıları (2026 kılavuzu) — harita kuleleri */ +export const IL_PROGRAM: Record = { + İstanbul: 6442, + Ankara: 1831, + İzmir: 793, + Antalya: 427, + Trabzon: 317, + Kayseri: 235, + Van: 123, + Diyarbakır: 111, +}; diff --git a/video/src/yardimci.ts b/video/src/yardimci.ts new file mode 100644 index 0000000..a50cda7 --- /dev/null +++ b/video/src/yardimci.ts @@ -0,0 +1,53 @@ +import { Easing } from "remotion"; + +export const clamp01 = (t: number) => Math.max(0, Math.min(1, t)); +export const lerp = (a: number, b: number, t: number) => a + (b - a) * t; + +/** Sitedeki pixel-decor.tsx ile aynı deterministik sözde-rastgele */ +export const hash = (x: number, y: number, seed = 0) => { + const n = Math.sin(x * 127.1 + y * 311.7 + seed * 74.7) * 43758.5453; + return n - Math.floor(n); +}; + +export const ease = { + out: Easing.bezier(0.22, 1, 0.36, 1), + inOut: Easing.bezier(0.65, 0, 0.35, 1), + in: Easing.bezier(0.64, 0, 0.78, 0), + // Sitenin yay hissi: bounce 0 (Apple damping 1) + yay: Easing.bezier(0.2, 0.8, 0.2, 1), + geriTep: Easing.bezier(0.34, 1.56, 0.64, 1), +}; + +/** f, [a, b] aralığında 0→1 ilerleme (kırpılmış, isteğe bağlı eğri) */ +export const aralik = ( + f: number, + a: number, + b: number, + egri: (t: number) => number = (t) => t, +) => egri(clamp01((f - a) / (b - a))); + +/** İki CSS rengi arasında oklab karışımı (oklch token'larla çalışır) */ +export const karis = (a: string, b: string, t: number) => { + const p = Math.round(clamp01(t) * 1000) / 10; + if (p <= 0) return a; + if (p >= 100) return b; + return `color-mix(in oklab, ${b} ${p}%, ${a})`; +}; + +/** Sayıyı Türkçe binlik ayraçla yazar: 45000 → "45.000" */ +export const tr = (n: number) => Math.round(n).toLocaleString("tr-TR"); + +/** Metin ölçümü: kinetik yerleşimler için gerçek yazı tipiyle genişlik */ +export const olc = ( + metin: string, + font: { family: string; size: number; weight?: number; italic?: boolean; tracking?: number }, +) => { + if (typeof document === "undefined") return metin.length * font.size * 0.55; + const ctx = document.createElement("canvas").getContext("2d"); + if (!ctx) return metin.length * font.size * 0.55; + ctx.font = `${font.italic ? "italic " : ""}${font.weight ?? 400} ${font.size}px "${font.family}"`; + return ( + ctx.measureText(metin).width + + (font.tracking ?? 0) * font.size * Array.from(metin).length + ); +}; diff --git a/video/src/zaman.ts b/video/src/zaman.ts new file mode 100644 index 0000000..52d4df0 --- /dev/null +++ b/video/src/zaman.ts @@ -0,0 +1,41 @@ +/** + * Zaman çizelgesi (30 fps). Sahneler TransitionSeries'te art arda; geçişler + * iki sahneyi üst üste bindirir, yani toplam süre = sahneler − geçişler. + * + * Storyboard omurgası: her geçiş ya bir **piksel** (dalga, tek piksele + * çöküş, havuzdan seçilen 24 piksel) ya da **imlecin tıkladığı nokta** + * (o noktanın içinden itme / o noktadan yayılan piksel dalgası) üstüne + * kurulu. Geçişin başladığı kare, imlecin tıkladığı karedir. + */ + +export const SAHNE = { + gurultu: 150, + harita: 250, + siralama: 126, + havuz: 420, + danisman: 200, + deger: 170, + kapanis: 180, +} as const; + +export const GECIS = { + /** gürültü → harita: tek piksel patlar, koyudan açığa piksel dalgası */ + g1: 30, + /** harita → sıralama: imleç logonun turuncu karesine tıklar, dalga oradan */ + g2: 26, + /** sıralama → havuz: CTA'ya tıklanır, sahne butonun içinden geçer */ + g3: 22, + /** havuz → danışman: listedeki satıra tıklanır, satırın içinden geçilir */ + g4: 22, + /** danışman → değer: gönder düğmesinden piksel dalgası */ + g5: 26, + /** değer → kapanış: son gösterge karesinden koyu piksel dalgası */ + g6: 28, +} as const; + +/** Bir sahnenin, kendisinden sonraki geçişin başladığı yerel karesi */ +export const gecisBasi = (sahne: number, gecis: number) => sahne - gecis; + +export const TOPLAM = + Object.values(SAHNE).reduce((a, b) => a + b, 0) - + Object.values(GECIS).reduce((a, b) => a + b, 0); diff --git a/video/tsconfig.json b/video/tsconfig.json new file mode 100644 index 0000000..0b576b9 --- /dev/null +++ b/video/tsconfig.json @@ -0,0 +1,18 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "ESNext", + "moduleResolution": "bundler", + "jsx": "react-jsx", + "strict": true, + "noEmit": true, + "lib": ["DOM", "DOM.Iterable", "ES2022"], + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "noUnusedLocals": true, + "baseUrl": ".", + "paths": { "@/*": ["./src/*"] } + }, + "include": ["src", "remotion.config.ts"] +}