diff --git a/ado2-marketing-intelligence---lala-cabin/.gitignore b/ado2-marketing-intelligence---lala-cabin/.gitignore
deleted file mode 100755
index a547bf3..0000000
--- a/ado2-marketing-intelligence---lala-cabin/.gitignore
+++ /dev/null
@@ -1,24 +0,0 @@
-# Logs
-logs
-*.log
-npm-debug.log*
-yarn-debug.log*
-yarn-error.log*
-pnpm-debug.log*
-lerna-debug.log*
-
-node_modules
-dist
-dist-ssr
-*.local
-
-# Editor directories and files
-.vscode/*
-!.vscode/extensions.json
-.idea
-.DS_Store
-*.suo
-*.ntvs*
-*.njsproj
-*.sln
-*.sw?
diff --git a/ado2-marketing-intelligence---lala-cabin/App.tsx b/ado2-marketing-intelligence---lala-cabin/App.tsx
deleted file mode 100755
index f7ca3fb..0000000
--- a/ado2-marketing-intelligence---lala-cabin/App.tsx
+++ /dev/null
@@ -1,233 +0,0 @@
-import React, { useMemo } from 'react';
-import { ArrowLeft, Sparkles, MapPin, Target, Zap, LayoutGrid, Users, Crown, TrendingUp } from 'lucide-react';
-import { LALA_CABIN_DATA } from './constants';
-import { GeometricChart } from './components/GeometricChart';
-import { KeywordBubble } from './components/KeywordBubble';
-import { BrandData, USP } from './types';
-
-// Logic to calculate scores based on ICP (Ideal Customer Profile) signals
-const calculateDynamicScores = (data: BrandData): USP[] => {
- // 1. Extract Demand Signals from Targets (Needs + Triggers)
- const marketSignals = data.targets.flatMap(t => [...t.needs, ...t.triggers]).map(s => s.replace(/\s+/g, ''));
-
- // High value keywords that represent the "Core Value" of this specific property type
- const coreKeywords = ['프라이빗', '감성', '독채', '캐빈', '조명', '불멍', 'Private', 'Mood'];
-
- return data.usps.map(usp => {
- let calculatedScore = 65; // Base score
- const contentStr = (usp.label + usp.subLabel + usp.description).replace(/\s+/g, '');
-
- // 2. Cross-reference USP with Market Signals
- marketSignals.forEach(signal => {
- if (contentStr.includes(signal)) calculatedScore += 4;
- });
-
- // 3. Boost based on Core Keywords (Weighted Importance)
- coreKeywords.forEach(keyword => {
- if (contentStr.includes(keyword)) calculatedScore += 6;
- });
-
- // 4. Special Boost based on specific Marketing Pillars (checking English SubLabels)
- if (usp.subLabel === 'CONCEPT') calculatedScore += 10;
- if (usp.subLabel === 'PRIVACY') calculatedScore += 8;
- if (usp.subLabel === 'NIGHT MOOD') calculatedScore += 8;
- if (usp.subLabel === 'PHOTO SPOT') calculatedScore += 5;
-
- return {
- ...usp,
- score: Math.min(Math.round(calculatedScore), 99) // Cap at 99
- };
- });
-};
-
-export default function App() {
- const rawData = LALA_CABIN_DATA;
-
- // Calculate scores on mount (or when data changes)
- const scoredUSPs = useMemo(() => calculateDynamicScores(rawData), [rawData]);
-
- // Find the top selling point
- const topUSP = useMemo(() => [...scoredUSPs].sort((a, b) => b.score - a.score)[0], [scoredUSPs]);
-
- return (
-
- {/* Top Navigation */}
-
-
- {/* Main Header */}
-
-
-
브랜드 인텔리전스
-
- AI 데이터 분석을 통해 도출된 라라캐빈의 핵심 전략입니다.
-
-
-
- {/* Grid Container */}
-
-
- {/* LEFT COLUMN: Identity & Text Analysis */}
-
-
- {/* Main Identity Card */}
-
-
-
-
- 브랜드 정체성
-
-
-
-
{rawData.name}
-
-
-
-
{rawData.address}
-
{rawData.subAddress}
-
-
-
-
-
-
입지 특성 분석
-
{rawData.locationAnalysis}
-
-
-
컨셉 확장성
-
{rawData.conceptAnalysis}
-
-
-
-
- {/* Positioning & Strategy Card */}
-
-
- 시장 포지셔닝
-
-
-
-
- 카테고리 정의
- {rawData.positioning.category}
-
-
- 핵심 가치 (Core Value)
- {rawData.positioning.coreValue}
-
-
-
-
- {/* Target Audience Card */}
-
-
- 타겟 페르소나
-
-
- {rawData.targets.map((target, idx) => (
-
-
-
{target.segment}
-
{target.age}
-
-
-
- {target.needs.map((need, i) => (
- {need}
- ))}
-
-
- Trigger: {target.triggers.join(', ')}
-
-
-
- ))}
-
-
-
-
-
- {/* RIGHT COLUMN: Visuals & Keywords */}
-
-
- {/* Chart Card */}
-
-
-
-
주요 셀링 포인트 (USP)
-
-
- AI Data Analysis
-
-
-
-
-
-
-
- {/* Core Competitiveness Highlight */}
- {topUSP && (
-
-
-
-
-
-
- Core Competitiveness
-
-
-
-
{topUSP.label}
-
{topUSP.subLabel}
-
- {/* Score removed */}
-
-
-
- )}
-
-
- {scoredUSPs.filter(u => u.label !== topUSP.label).slice(0, 4).map((usp, idx) => (
-
-
-
{usp.subLabel}
- {/* Score removed */}
-
-
{usp.label}
-
{usp.description}
-
- ))}
-
-
-
- {/* Keywords Card */}
-
-
추천 타겟 키워드
-
- {rawData.keywords.map((keyword, idx) => (
-
- ))}
-
-
-
-
-
-
- {/* Floating Action Button (Sticky Bottom) */}
-
-
-
-
- );
-}
\ No newline at end of file
diff --git a/ado2-marketing-intelligence---lala-cabin/README.md b/ado2-marketing-intelligence---lala-cabin/README.md
deleted file mode 100755
index d767aa2..0000000
--- a/ado2-marketing-intelligence---lala-cabin/README.md
+++ /dev/null
@@ -1,20 +0,0 @@
-
-

-
-
-# Run and deploy your AI Studio app
-
-This contains everything you need to run your app locally.
-
-View your app in AI Studio: https://ai.studio/apps/drive/198bB4uG9EOOi0btQWINncwYJz7xEjWS3
-
-## Run Locally
-
-**Prerequisites:** Node.js
-
-
-1. Install dependencies:
- `npm install`
-2. Set the `GEMINI_API_KEY` in [.env.local](.env.local) to your Gemini API key
-3. Run the app:
- `npm run dev`
diff --git a/ado2-marketing-intelligence---lala-cabin/components/GeometricChart.tsx b/ado2-marketing-intelligence---lala-cabin/components/GeometricChart.tsx
deleted file mode 100755
index 4c66635..0000000
--- a/ado2-marketing-intelligence---lala-cabin/components/GeometricChart.tsx
+++ /dev/null
@@ -1,159 +0,0 @@
-import React from 'react';
-import { USP } from '../types';
-
-interface GeometricChartProps {
- data: USP[];
-}
-
-export const GeometricChart: React.FC = ({ data }) => {
- // Increased canvas size to prevent labels (especially on the right side like 'Privacy') from being cut off
- const size = 500;
- const center = size / 2;
- const radius = 110; // Slightly increased radius for better visibility
- const sides = data.length;
-
- // Mint Color #94FBE0
- const accentColor = "#94FBE0";
-
- // Calculate polygon points
- const getPoints = (r: number) => {
- return data.map((_, i) => {
- const angle = (Math.PI * 2 * i) / sides - Math.PI / 2;
- const x = center + r * Math.cos(angle);
- const y = center + r * Math.sin(angle);
- return `${x},${y}`;
- }).join(' ');
- };
-
- // Calculate data points based on score
- const getDataPoints = () => {
- return data.map((item, i) => {
- const normalizedScore = item.score / 100;
- const r = radius * normalizedScore;
- const angle = (Math.PI * 2 * i) / sides - Math.PI / 2;
- const x = center + r * Math.cos(angle);
- const y = center + r * Math.sin(angle);
- return `${x},${y}`;
- }).join(' ');
- };
-
- // Calculate label positions (pushed out slightly further)
- const labelRadius = radius + 55; // Increased padding for labels
- const labels = data.map((item, i) => {
- const angle = (Math.PI * 2 * i) / sides - Math.PI / 2;
- const x = center + labelRadius * Math.cos(angle);
- const y = center + labelRadius * Math.sin(angle);
-
- // Adjust text anchor based on position
- let anchor: 'start' | 'middle' | 'end' = 'middle';
- if (x < center - 20) anchor = 'end';
- if (x > center + 20) anchor = 'start';
-
- return { x, y, text: item.label, sub: item.subLabel, anchor, score: item.score };
- });
-
- return (
-
-
-
- );
-};
\ No newline at end of file
diff --git a/ado2-marketing-intelligence---lala-cabin/components/KeywordBubble.tsx b/ado2-marketing-intelligence---lala-cabin/components/KeywordBubble.tsx
deleted file mode 100755
index 3ac29fc..0000000
--- a/ado2-marketing-intelligence---lala-cabin/components/KeywordBubble.tsx
+++ /dev/null
@@ -1,13 +0,0 @@
-import React from 'react';
-
-interface KeywordBubbleProps {
- text: string;
-}
-
-export const KeywordBubble: React.FC = ({ text }) => {
- return (
-
- # {text}
-
- );
-};
\ No newline at end of file
diff --git a/ado2-marketing-intelligence---lala-cabin/constants.ts b/ado2-marketing-intelligence---lala-cabin/constants.ts
deleted file mode 100755
index 6cacae7..0000000
--- a/ado2-marketing-intelligence---lala-cabin/constants.ts
+++ /dev/null
@@ -1,49 +0,0 @@
-import { BrandData } from './types';
-
-export const LALA_CABIN_DATA: BrandData = {
- name: "라라캐빈 펜션",
- address: "경기 가평군 조종면 와곡길 176",
- subAddress: "[별관] 경기 가평군 조종면 운악리 175-6",
- summary: "서울·경기 북부 근교 1~2시간대 숏브레이크 권역에 위치한 캐빈 감성 스테이. 조종면의 한적함과 프라이빗한 독채 구조를 강점으로 내세우며, '숲속 캐빈 무드'와 '야간 조명 감성'이 핵심입니다.",
- locationAnalysis: "조종면은 청평/가평읍 대비 '한적함·프라이빗' 이미지가 강해 커플 및 소규모 힐링 고객에게 유리하며, 운악산 권역의 자연형 스테이 포지셔닝에 적합합니다.",
- conceptAnalysis: "'라라캐빈'은 오두막(Cabin) 연상을 강하게 주며, 감성 목조/숲속/프라이빗 스테이로 스토리텔링 확장성이 큽니다. 별관의 동 분리 구조는 '세컨드 하우스' 느낌을 강화합니다.",
- usps: [
- { label: "입지 환경", subLabel: "LOCATION", score: 85, description: "서울근교 한적한 조종면 자연권 숲속 드라이브" },
- { label: "브랜드 컨셉", subLabel: "CONCEPT", score: 95, description: "숙소 자체가 여행 목적이 되는 캐빈 감성" },
- { label: "프라이버시", subLabel: "PRIVACY", score: 90, description: "우리만 쓰는 느낌의 별관 분리동 독립 동선" },
- { label: "야간 무드", subLabel: "NIGHT MOOD", score: 92, description: "어두울수록 예쁜 스테이 장면과 불멍" },
- { label: "힐링 요소", subLabel: "HEALING", score: 88, description: "창밖 자연로딩, 숲뷰 산책 리셋" },
- { label: "포토 스팟", subLabel: "PHOTO SPOT", score: 94, description: "찍는 곳마다 커버샷 무드, 인스타 각" },
- { label: "숏브레이크", subLabel: "SHORT GETAWAY", score: 80, description: "1박2일 가볍게 떠나는 주말 리셋 여행" }
- ],
- keywords: [
- "가평 독채 펜션", "숲속 오두막", "감성 숙소", "불멍 스테이",
- "서울근교 드라이브", "프라이빗 힐링", "커플 여행", "운악산 펜션",
- "반려견 동반", "비오는날 감성"
- ],
- targets: [
- {
- segment: "서울·경기 커플",
- age: "25~39세",
- needs: ["사진", "분위기", "프라이빗"],
- triggers: ["숲속 캐빈 무드", "비 오는 날 감성", "밤 조명"]
- },
- {
- segment: "소규모 우정여행",
- age: "20~34세",
- needs: ["예쁜 공간", "수다", "바베큐"],
- triggers: ["인스타 각", "감성 포토존", "테이블 셋업"]
- },
- {
- segment: "힐링 부부",
- age: "30~50세",
- needs: ["조용한 휴식", "숙면", "따뜻함"],
- triggers: ["조용한 숲뷰", "따뜻한 캐빈", "기념일"]
- }
- ],
- positioning: {
- category: "서울근교 숲속 캐빈 감성 스테이",
- coreValue: "프라이빗한 휴식 + 사진이 되는 공간 + 밤 무드",
- strategy: "시설 나열보다 '장면(Scenes)' 중심의 마케팅 전개"
- }
-};
\ No newline at end of file
diff --git a/ado2-marketing-intelligence---lala-cabin/index.html b/ado2-marketing-intelligence---lala-cabin/index.html
deleted file mode 100755
index f7651b2..0000000
--- a/ado2-marketing-intelligence---lala-cabin/index.html
+++ /dev/null
@@ -1,56 +0,0 @@
-
-
-
-
-
- ADO2 Brand Analysis
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/ado2-marketing-intelligence---lala-cabin/index.tsx b/ado2-marketing-intelligence---lala-cabin/index.tsx
deleted file mode 100755
index 6ca5361..0000000
--- a/ado2-marketing-intelligence---lala-cabin/index.tsx
+++ /dev/null
@@ -1,15 +0,0 @@
-import React from 'react';
-import ReactDOM from 'react-dom/client';
-import App from './App';
-
-const rootElement = document.getElementById('root');
-if (!rootElement) {
- throw new Error("Could not find root element to mount to");
-}
-
-const root = ReactDOM.createRoot(rootElement);
-root.render(
-
-
-
-);
\ No newline at end of file
diff --git a/ado2-marketing-intelligence---lala-cabin/metadata.json b/ado2-marketing-intelligence---lala-cabin/metadata.json
deleted file mode 100755
index 1bfb315..0000000
--- a/ado2-marketing-intelligence---lala-cabin/metadata.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "name": "ADO2 Marketing Intelligence - Lala Cabin",
- "description": "AI-powered marketing analysis dashboard for Lala Cabin Pension visualizing brand identity, target demographics, and key selling points.",
- "requestFramePermissions": []
-}
\ No newline at end of file
diff --git a/ado2-marketing-intelligence---lala-cabin/package.json b/ado2-marketing-intelligence---lala-cabin/package.json
deleted file mode 100755
index 1803756..0000000
--- a/ado2-marketing-intelligence---lala-cabin/package.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "name": "ado2-marketing-intelligence---lala-cabin",
- "private": true,
- "version": "0.0.0",
- "type": "module",
- "scripts": {
- "dev": "vite",
- "build": "vite build",
- "preview": "vite preview"
- },
- "dependencies": {
- "react-dom": "^19.2.3",
- "react": "^19.2.3",
- "lucide-react": "^0.563.0"
- },
- "devDependencies": {
- "@types/node": "^22.14.0",
- "@vitejs/plugin-react": "^5.0.0",
- "typescript": "~5.8.2",
- "vite": "^6.2.0"
- }
-}
diff --git a/ado2-marketing-intelligence---lala-cabin/tsconfig.json b/ado2-marketing-intelligence---lala-cabin/tsconfig.json
deleted file mode 100755
index 2c6eed5..0000000
--- a/ado2-marketing-intelligence---lala-cabin/tsconfig.json
+++ /dev/null
@@ -1,29 +0,0 @@
-{
- "compilerOptions": {
- "target": "ES2022",
- "experimentalDecorators": true,
- "useDefineForClassFields": false,
- "module": "ESNext",
- "lib": [
- "ES2022",
- "DOM",
- "DOM.Iterable"
- ],
- "skipLibCheck": true,
- "types": [
- "node"
- ],
- "moduleResolution": "bundler",
- "isolatedModules": true,
- "moduleDetection": "force",
- "allowJs": true,
- "jsx": "react-jsx",
- "paths": {
- "@/*": [
- "./*"
- ]
- },
- "allowImportingTsExtensions": true,
- "noEmit": true
- }
-}
\ No newline at end of file
diff --git a/ado2-marketing-intelligence---lala-cabin/types.ts b/ado2-marketing-intelligence---lala-cabin/types.ts
deleted file mode 100755
index 9ea0640..0000000
--- a/ado2-marketing-intelligence---lala-cabin/types.ts
+++ /dev/null
@@ -1,30 +0,0 @@
-export interface USP {
- label: string;
- subLabel: string;
- score: number; // 0-100
- description: string;
-}
-
-export interface TargetPersona {
- segment: string;
- age: string;
- needs: string[];
- triggers: string[];
-}
-
-export interface BrandData {
- name: string;
- address: string;
- subAddress: string;
- summary: string;
- locationAnalysis: string;
- conceptAnalysis: string;
- usps: USP[];
- keywords: string[];
- targets: TargetPersona[];
- positioning: {
- category: string;
- coreValue: string;
- strategy: string;
- };
-}
\ No newline at end of file
diff --git a/ado2-marketing-intelligence---lala-cabin/vite.config.ts b/ado2-marketing-intelligence---lala-cabin/vite.config.ts
deleted file mode 100755
index ee5fb8d..0000000
--- a/ado2-marketing-intelligence---lala-cabin/vite.config.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-import path from 'path';
-import { defineConfig, loadEnv } from 'vite';
-import react from '@vitejs/plugin-react';
-
-export default defineConfig(({ mode }) => {
- const env = loadEnv(mode, '.', '');
- return {
- server: {
- port: 3000,
- host: '0.0.0.0',
- },
- plugins: [react()],
- define: {
- 'process.env.API_KEY': JSON.stringify(env.GEMINI_API_KEY),
- 'process.env.GEMINI_API_KEY': JSON.stringify(env.GEMINI_API_KEY)
- },
- resolve: {
- alias: {
- '@': path.resolve(__dirname, '.'),
- }
- }
- };
-});
diff --git a/index.css b/index.css
index c28b10d..3f51efb 100644
--- a/index.css
+++ b/index.css
@@ -7914,7 +7914,7 @@
}
.genre-btn-placeholder {
- /* Empty space for grid alignment */
+ visibility: hidden;
}
/* Language Selector */
@@ -11905,6 +11905,27 @@
text-align: center;
}
+/* Schedule conflict notice */
+.upload-progress-schedule-notice {
+ display: flex;
+ align-items: flex-start;
+ gap: 0.5rem;
+ width: 100%;
+ background: rgba(251, 191, 36, 0.1);
+ border: 1px solid rgba(251, 191, 36, 0.35);
+ border-radius: 8px;
+ padding: 0.75rem 1rem;
+ color: #92400e;
+ font-size: 0.8125rem;
+ line-height: 1.5;
+}
+
+.upload-progress-schedule-notice svg {
+ flex-shrink: 0;
+ margin-top: 1px;
+ stroke: #d97706;
+}
+
/* YouTube Link */
.upload-progress-youtube-link {
display: inline-flex;
@@ -11978,37 +11999,6 @@
text-align: center;
}
-/* =====================================================
- Test Data Button (for development/testing)
- ===================================================== */
-.test-data-button {
- position: fixed;
- bottom: 24px;
- right: 24px;
- padding: 12px 20px;
- background-color: rgba(174, 114, 249, 0.9);
- color: #FFFFFF;
- border: 1px solid rgba(174, 114, 249, 0.5);
- border-radius: 8px;
- font-size: 14px;
- font-weight: 600;
- cursor: pointer;
- z-index: 9999;
- transition: all 0.2s ease;
- box-shadow: 0 4px 12px rgba(174, 114, 249, 0.3);
-}
-
-.test-data-button:hover {
- background-color: rgba(174, 114, 249, 1);
- transform: translateY(-2px);
- box-shadow: 0 6px 16px rgba(174, 114, 249, 0.4);
-}
-
-.test-data-button:disabled {
- opacity: 0.6;
- cursor: not-allowed;
- transform: none;
-}
/* Calendar panel scrollbar */
.calendar-panel-scroll::-webkit-scrollbar {
@@ -12583,3 +12573,1150 @@
opacity: 0.35;
cursor: not-allowed;
}
+
+/* ============================================
+ Hero 로그인 버튼 (랜딩 전용)
+ ============================================ */
+.hero-login-btn {
+ display: flex;
+ height: 52px;
+ padding: 0 2.5rem;
+ justify-content: center;
+ align-items: center;
+ gap: 10px;
+ min-width: 200px;
+ border-radius: 999px;
+ background-color: #AE72F9;
+ color: #ffffff;
+ font-weight: 600;
+ font-size: 16px;
+ letter-spacing: -0.006em;
+ box-shadow: 0px 4px 24px 0px rgba(174, 114, 249, 0.4);
+ transition: all var(--transition-normal);
+ border: none;
+ cursor: pointer;
+ margin-top: 2rem;
+ animation: button-glow 1.5s ease-in-out infinite;
+}
+
+.hero-login-btn:hover {
+ background-color: #9a5ef0;
+ animation: none;
+ box-shadow: 0px 4px 32px 0px rgba(174, 114, 249, 0.6);
+}
+
+.hero-login-btn:active {
+ transform: scale(0.98);
+}
+
+/* ============================================
+ UrlInputContent 숏폼 버튼
+ ============================================ */
+.url-input-shortform-btn {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 8px;
+ width: 100%;
+ height: 48px;
+ padding: 0 1.5rem;
+ margin-top: 12px;
+ border-radius: 999px;
+ border: 1px solid rgba(94, 235, 195, 0.4);
+ background: rgba(94, 235, 195, 0.06);
+ color: #5EEBC3;
+ font-size: 14px;
+ font-weight: 500;
+ cursor: pointer;
+ transition: all var(--transition-normal);
+ letter-spacing: -0.006em;
+}
+
+.url-input-shortform-btn:hover {
+ border-color: rgba(94, 235, 195, 0.7);
+ background: rgba(94, 235, 195, 0.12);
+ color: #7ff0d0;
+}
+
+.url-input-shortform-btn:active {
+ transform: scale(0.98);
+}
+
+/* ============================================
+ ShortformContent — 멀티스텝 위자드
+ ============================================ */
+
+/* 뒤로가기 버튼 (GenerationFlow 공통) */
+.shortform-back-btn {
+ display: flex;
+ align-items: center;
+ gap: 4px;
+ background-color: #462E64;
+ color: #CFABFB;
+ font-size: 0.875rem;
+ font-weight: 600;
+ padding: 0 1.25rem 0 0.5rem;
+ height: 36px;
+ border: 1px solid #694596;
+ border-radius: 999px;
+ cursor: pointer;
+ white-space: nowrap;
+ transition: background-color 0.2s;
+ line-height: 1.19;
+ letter-spacing: -0.006em;
+}
+
+.shortform-back-btn:hover {
+ background-color: #5a3a80;
+}
+
+/* 페이지 래퍼 */
+.sf-page {
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+ background-color: #0c1a1b;
+ overflow: hidden;
+ position: relative;
+}
+
+.sf-page-center {
+ align-items: center;
+ justify-content: center;
+}
+
+/* 스티키 헤더 */
+.sf-sticky-header {
+ flex-shrink: 0;
+ display: flex;
+ align-items: center;
+ gap: 1rem;
+ padding: 12px 1.25rem;
+ border-bottom: 1px solid rgba(255,255,255,0.06);
+ background: #0c1a1b;
+ z-index: 10;
+}
+
+/* 스크롤 영역 */
+.sf-scroll-area {
+ flex: 1;
+ overflow-y: auto;
+ overflow-x: hidden;
+ padding: 5rem 1.25rem 6rem;
+}
+
+.sf-scroll-area::-webkit-scrollbar { width: 4px; }
+.sf-scroll-area::-webkit-scrollbar-track { background: transparent; }
+.sf-scroll-area::-webkit-scrollbar-thumb { background: #2a4a4d; border-radius: 2px; }
+
+/* ---- 히어로 영역 (Step 1만) ---- */
+.sf-hero {
+ max-width: 560px;
+ margin: 0 auto 2rem;
+ padding-top: 0;
+}
+
+.sf-hero-title {
+ font-size: clamp(1.25rem, 4vw, 1.75rem);
+ font-weight: 800;
+ color: #E5F1F2;
+ line-height: 1.3;
+ margin: 0 0 0.75rem;
+ letter-spacing: -0.02em;
+}
+
+.sf-hero-accent {
+ color: #AE72F9;
+}
+
+.sf-hero-desc {
+ font-size: 0.9rem;
+ color: rgba(229, 241, 242, 0.55);
+ line-height: 1.6;
+ margin: 0;
+}
+
+/* ---- 스텝 인디케이터 바 ---- */
+.sf-step-bar {
+ max-width: 560px;
+ margin: 0 auto 2rem;
+ display: flex;
+ align-items: flex-start;
+ gap: 0;
+ position: relative;
+}
+
+.sf-step-bar::before {
+ content: '';
+ position: absolute;
+ top: 14px;
+ left: 14px;
+ right: 14px;
+ height: 1px;
+ background: rgba(255,255,255,0.1);
+}
+
+.sf-step-item {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 6px;
+ position: relative;
+ z-index: 1;
+}
+
+.sf-step-circle {
+ width: 28px;
+ height: 28px;
+ border-radius: 50%;
+ border: 1.5px solid rgba(255,255,255,0.15);
+ background: #0c1a1b;
+ color: rgba(229,241,242,0.3);
+ font-size: 0.8rem;
+ font-weight: 700;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ transition: all 0.25s;
+}
+
+.sf-step-item.active .sf-step-circle {
+ border-color: #AE72F9;
+ background: rgba(174,114,249,0.15);
+ color: #CFABFB;
+}
+
+.sf-step-item.done .sf-step-circle {
+ border-color: #5EEBC3;
+ background: rgba(94,235,195,0.15);
+ color: #5EEBC3;
+}
+
+.sf-step-label {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 1px;
+}
+
+.sf-step-name {
+ font-size: 0.7rem;
+ font-weight: 600;
+ color: rgba(229,241,242,0.35);
+ letter-spacing: -0.01em;
+ white-space: nowrap;
+}
+
+.sf-step-item.active .sf-step-name { color: #CFABFB; }
+.sf-step-item.done .sf-step-name { color: #5EEBC3; }
+
+.sf-step-sub {
+ font-size: 0.625rem;
+ color: rgba(229,241,242,0.2);
+ white-space: nowrap;
+}
+
+.sf-step-item.active .sf-step-sub { color: rgba(207,171,251,0.6); }
+.sf-step-item.done .sf-step-sub { color: rgba(94,235,195,0.5); }
+
+/* ---- 카드 컨테이너 ---- */
+.sf-card {
+ max-width: 560px;
+ margin: 0 auto;
+ background: rgba(255,255,255,0.03);
+ border: 1px solid rgba(255,255,255,0.07);
+ border-radius: 16px;
+ padding: 1.5rem;
+ display: flex;
+ flex-direction: column;
+ gap: 1.25rem;
+}
+
+.sf-card-title {
+ font-size: 1.125rem;
+ font-weight: 700;
+ color: #E5F1F2;
+ margin: 0;
+ letter-spacing: -0.02em;
+}
+
+.sf-card-desc {
+ font-size: 0.8375rem;
+ color: rgba(229,241,242,0.5);
+ margin: -0.5rem 0 0;
+ line-height: 1.55;
+}
+
+/* ---- 드래그앤드롭 업로드 영역 ---- */
+.sf-drop-zone {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ gap: 8px;
+ min-height: 130px;
+ border: 1.5px dashed rgba(94,235,195,0.3);
+ border-radius: 14px;
+ background: rgba(94,235,195,0.03);
+ cursor: pointer;
+ transition: all 0.2s;
+ padding: 1.5rem;
+}
+
+.sf-drop-zone:hover {
+ border-color: rgba(94,235,195,0.6);
+ background: rgba(94,235,195,0.07);
+}
+
+.sf-drop-icon { color: rgba(94,235,195,0.5); }
+.sf-drop-zone:hover .sf-drop-icon { color: #5EEBC3; }
+
+.sf-drop-text {
+ font-size: 0.9rem;
+ font-weight: 600;
+ color: rgba(229,241,242,0.65);
+ margin: 0;
+}
+
+.sf-drop-hint {
+ font-size: 0.775rem;
+ color: rgba(229,241,242,0.3);
+ margin: 0;
+}
+
+/* ---- 사진 그리드 ---- */
+.sf-photo-grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fill, minmax(90px, 1fr));
+ gap: 8px;
+}
+
+.sf-photo-item {
+ position: relative;
+ border-radius: 10px;
+ overflow: hidden;
+ aspect-ratio: 1;
+ background: rgba(0,0,0,0.3);
+}
+
+.sf-photo-item img {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ display: block;
+}
+
+.sf-photo-num {
+ position: absolute;
+ top: 5px;
+ left: 6px;
+ font-size: 0.7rem;
+ font-weight: 700;
+ color: #fff;
+ background: rgba(0,0,0,0.55);
+ border-radius: 4px;
+ padding: 1px 5px;
+ line-height: 1.4;
+}
+
+.sf-photo-remove {
+ position: absolute;
+ top: 4px;
+ right: 4px;
+ width: 22px;
+ height: 22px;
+ border-radius: 50%;
+ background: rgba(0,0,0,0.6);
+ color: #fff;
+ border: none;
+ font-size: 15px;
+ line-height: 1;
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ transition: background 0.2s;
+}
+
+.sf-photo-remove:hover { background: rgba(220,50,50,0.85); }
+
+/* ---- 하단 푸터 ---- */
+.sf-footer {
+ flex-shrink: 0;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 12px;
+ padding: 14px 1.25rem;
+ border-top: 1px solid rgba(255,255,255,0.07);
+ background: #0c1a1b;
+}
+
+.sf-footer-two {
+ justify-content: flex-end;
+}
+
+.sf-footer-info {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+}
+
+.sf-footer-count {
+ font-size: 0.9375rem;
+ font-weight: 700;
+ color: #E5F1F2;
+}
+
+.sf-footer-status {
+ font-size: 0.8125rem;
+ color: rgba(229,241,242,0.4);
+}
+
+.sf-footer-status.ok {
+ color: #5EEBC3;
+}
+
+/* ---- 버튼 ---- */
+.sf-btn-next {
+ height: 44px;
+ padding: 0 1.5rem;
+ border-radius: 999px;
+ border: none;
+ background: #AE72F9;
+ color: #fff;
+ font-size: 0.9375rem;
+ font-weight: 700;
+ cursor: pointer;
+ letter-spacing: -0.01em;
+ transition: background 0.2s, opacity 0.2s;
+ font-family: inherit;
+ white-space: nowrap;
+}
+
+.sf-btn-next:hover:not(:disabled) { background: #9a5ef0; }
+.sf-btn-next:disabled { opacity: 0.3; cursor: not-allowed; }
+
+.sf-btn-prev {
+ height: 44px;
+ padding: 0 1.25rem;
+ border-radius: 999px;
+ border: 1px solid rgba(255,255,255,0.18);
+ background: transparent;
+ color: rgba(229,241,242,0.7);
+ font-size: 0.875rem;
+ font-weight: 500;
+ cursor: pointer;
+ transition: all 0.2s;
+ font-family: inherit;
+ white-space: nowrap;
+}
+
+.sf-btn-prev:hover {
+ border-color: rgba(255,255,255,0.35);
+ color: #E5F1F2;
+}
+
+.sf-btn-generate {
+ height: 44px;
+ padding: 0 1.75rem;
+ border-radius: 999px;
+ border: none;
+ background: linear-gradient(135deg, #AE72F9 0%, #5EEBC3 100%);
+ color: #fff;
+ font-size: 0.9375rem;
+ font-weight: 700;
+ cursor: pointer;
+ letter-spacing: -0.01em;
+ transition: opacity 0.2s;
+ font-family: inherit;
+ white-space: nowrap;
+}
+
+.sf-btn-generate:hover:not(:disabled) { opacity: 0.88; }
+.sf-btn-generate:disabled { opacity: 0.3; cursor: not-allowed; }
+
+/* ---- 폼 필드 ---- */
+.sf-field {
+ display: flex;
+ flex-direction: column;
+ gap: 6px;
+}
+
+.sf-label {
+ font-size: 0.8375rem;
+ font-weight: 600;
+ color: rgba(229,241,242,0.75);
+ letter-spacing: -0.006em;
+}
+
+.sf-required { color: #AE72F9; margin-left: 2px; }
+.sf-optional { color: rgba(229,241,242,0.35); font-weight: 400; font-size: 0.8rem; margin-left: 4px; }
+
+.sf-input {
+ width: 100%;
+ height: 46px;
+ padding: 0 14px;
+ border-radius: 10px;
+ border: 1px solid rgba(255,255,255,0.1);
+ background: rgba(255,255,255,0.05);
+ color: #E5F1F2;
+ font-size: 0.9375rem;
+ transition: border-color 0.2s, background 0.2s;
+ box-sizing: border-box;
+ outline: none;
+ font-family: inherit;
+}
+
+.sf-input:focus {
+ border-color: rgba(174,114,249,0.55);
+ background: rgba(255,255,255,0.07);
+}
+
+.sf-input::placeholder { color: rgba(229,241,242,0.25); }
+
+.sf-textarea {
+ width: 100%;
+ padding: 12px 14px;
+ border-radius: 10px;
+ border: 1px solid rgba(255,255,255,0.1);
+ background: rgba(255,255,255,0.05);
+ color: #E5F1F2;
+ font-size: 0.9375rem;
+ line-height: 1.5;
+ transition: border-color 0.2s, background 0.2s;
+ box-sizing: border-box;
+ outline: none;
+ font-family: inherit;
+ resize: vertical;
+ min-height: 80px;
+}
+
+.sf-textarea:focus {
+ border-color: rgba(174,114,249,0.55);
+ background: rgba(255,255,255,0.07);
+}
+
+.sf-textarea::placeholder { color: rgba(229,241,242,0.25); }
+
+.sf-field-hint {
+ font-size: 0.775rem;
+ color: rgba(229,241,242,0.35);
+ line-height: 1.5;
+ margin: 0;
+}
+
+/* ---- Kind 카드 선택 ---- */
+.sf-kind-grid {
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+}
+
+.sf-kind-card {
+ display: flex;
+ flex-direction: column;
+ align-items: flex-start;
+ gap: 3px;
+ padding: 12px 14px;
+ border-radius: 12px;
+ border: 1.5px solid rgba(255,255,255,0.1);
+ background: rgba(255,255,255,0.03);
+ cursor: pointer;
+ transition: all 0.2s;
+ text-align: left;
+ font-family: inherit;
+}
+
+.sf-kind-card:hover:not(.active) {
+ border-color: rgba(255,255,255,0.22);
+ background: rgba(255,255,255,0.06);
+}
+
+.sf-kind-card.active {
+ border-color: #AE72F9;
+ background: rgba(174,114,249,0.12);
+}
+
+.sf-kind-label {
+ font-size: 0.9rem;
+ font-weight: 700;
+ color: rgba(229,241,242,0.6);
+}
+
+.sf-kind-card.active .sf-kind-label { color: #CFABFB; }
+
+.sf-kind-desc {
+ font-size: 0.775rem;
+ color: rgba(229,241,242,0.35);
+ line-height: 1.4;
+}
+
+.sf-kind-card.active .sf-kind-desc { color: rgba(207,171,251,0.6); }
+
+/* ---- 자막 생성 헤더 행 ---- */
+.sf-subtitle-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 8px;
+}
+
+.sf-subtitle-btn {
+ height: 32px;
+ padding: 0 1rem;
+ border-radius: 999px;
+ border: 1px solid rgba(94,235,195,0.35);
+ background: rgba(94,235,195,0.07);
+ color: rgba(94,235,195,0.7);
+ font-size: 0.8125rem;
+ font-weight: 600;
+ cursor: pointer;
+ transition: all 0.2s;
+ font-family: inherit;
+ white-space: nowrap;
+}
+
+.sf-subtitle-btn:hover:not(:disabled) {
+ border-color: rgba(94,235,195,0.65);
+ color: #5EEBC3;
+}
+
+.sf-subtitle-btn:disabled {
+ opacity: 0.35;
+ cursor: not-allowed;
+}
+
+/* ---- 자막 미리보기 결과 ---- */
+.sf-field-error {
+ font-size: 0.8rem;
+ color: #ff7070;
+ margin: 2px 0 0;
+}
+
+.sf-preview-spec {
+ display: flex;
+ flex-direction: column;
+ gap: 2px;
+ margin-top: 10px;
+ border: 1px solid transparent;
+ border-radius: 12px;
+ overflow: hidden;
+}
+
+.sf-preview-block {
+ padding: 12px 14px;
+ border-bottom: 1px solid rgba(255,255,255,0.05);
+ display: flex;
+ flex-direction: column;
+ gap: 6px;
+}
+
+.sf-preview-block:last-child {
+ border-bottom: none;
+}
+
+.sf-preview-tag {
+ font-size: 0.7rem;
+ font-weight: 700;
+ letter-spacing: 0.04em;
+ text-transform: uppercase;
+ color: rgba(94,235,195,0.7);
+ background: rgba(94,235,195,0.08);
+ border-radius: 4px;
+ padding: 2px 7px;
+ align-self: flex-start;
+}
+
+.sf-preview-main {
+ font-size: 1rem;
+ font-weight: 700;
+ color: #E5F1F2;
+ margin: 0;
+ line-height: 1.4;
+}
+
+.sf-preview-sub {
+ font-size: 0.875rem;
+ color: rgba(229,241,242,0.65);
+ margin: 0;
+ line-height: 1.5;
+}
+
+.sf-preview-badges {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 6px;
+}
+
+.sf-preview-badge {
+ font-size: 0.8rem;
+ font-weight: 600;
+ color: #CFABFB;
+ background: rgba(174,114,249,0.12);
+ border: 1px solid rgba(174,114,249,0.3);
+ border-radius: 999px;
+ padding: 3px 10px;
+}
+
+.sf-preview-caption {
+ background: rgba(255,255,255,0.02);
+}
+
+.sf-preview-input {
+ width: 100%;
+ background: rgba(255,255,255,0.04);
+ border: 1px solid rgba(255,255,255,0.08);
+ border-radius: 6px;
+ color: rgba(229,241,242,0.75);
+ font-size: 0.875rem;
+ font-family: inherit;
+ padding: 6px 10px;
+ box-sizing: border-box;
+ outline: none;
+ transition: border-color 0.15s, background 0.15s;
+}
+
+.sf-preview-input:focus {
+ border-color: rgba(94,235,195,0.4);
+ background: rgba(255,255,255,0.07);
+ color: #E5F1F2;
+}
+
+.sf-preview-input-bold {
+ font-size: 1rem;
+ font-weight: 700;
+ color: #E5F1F2;
+}
+
+.sf-preview-badge-inputs {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 6px;
+}
+
+.sf-preview-badge-input {
+ background: rgba(174,114,249,0.1);
+ border: 1px solid rgba(174,114,249,0.25);
+ border-radius: 999px;
+ color: #CFABFB;
+ font-size: 0.8rem;
+ font-weight: 600;
+ font-family: inherit;
+ padding: 4px 12px;
+ outline: none;
+ min-width: 60px;
+ width: auto;
+ max-width: 100%;
+ transition: border-color 0.15s;
+}
+
+.sf-preview-badge-input:focus {
+ border-color: rgba(174,114,249,0.6);
+ background: rgba(174,114,249,0.18);
+}
+
+.sf-preview-textarea {
+ width: 100%;
+ background: rgba(255,255,255,0.04);
+ border: 1px solid rgba(255,255,255,0.08);
+ border-radius: 6px;
+ color: rgba(229,241,242,0.7);
+ font-size: 0.8375rem;
+ font-family: inherit;
+ padding: 8px 10px;
+ box-sizing: border-box;
+ outline: none;
+ resize: vertical;
+ line-height: 1.5;
+ transition: border-color 0.15s, background 0.15s;
+}
+
+.sf-preview-textarea:focus {
+ border-color: rgba(94,235,195,0.4);
+ background: rgba(255,255,255,0.07);
+ color: #E5F1F2;
+}
+
+/* ---- 생성 중 화면 ---- */
+.sf-generating {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 1.75rem;
+ padding: 3rem 2rem 4rem;
+ width: 100%;
+ max-width: 560px;
+ margin: 0 auto;
+}
+
+/* 스피너 + 아이콘 오버레이 */
+.sf-gen-orb-ring {
+ position: relative;
+ width: 120px;
+ height: 120px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.sf-gen-spinner-lg {
+ position: absolute;
+ inset: 0;
+ border-radius: 50%;
+ border: 3px solid rgba(174,114,249,0.15);
+ border-top-color: #AE72F9;
+ border-right-color: rgba(94,235,195,0.5);
+ animation: sf-spin 1.1s linear infinite;
+}
+
+@keyframes sf-spin {
+ to { transform: rotate(360deg); }
+}
+
+.sf-gen-icon {
+ color: rgba(207,171,251,0.7);
+}
+
+.sf-gen-title {
+ font-size: 1.5rem;
+ font-weight: 800;
+ color: #E5F1F2;
+ margin: 0;
+ letter-spacing: -0.02em;
+ text-align: center;
+}
+
+.sf-gen-msg {
+ font-size: 0.9375rem;
+ font-weight: 500;
+ color: rgba(229,241,242,0.6);
+ margin: -0.75rem 0 0;
+ letter-spacing: -0.01em;
+ text-align: center;
+ min-height: 1.4em;
+}
+
+.sf-gen-sub {
+ font-size: 0.8125rem;
+ color: rgba(229,241,242,0.35);
+ margin: -0.75rem 0 0;
+ text-align: center;
+}
+
+/* 진행 단계 표시 */
+.sf-gen-steps {
+ display: flex;
+ flex-direction: column;
+ gap: 12px;
+ width: 100%;
+ max-width: 280px;
+ padding: 1.25rem 1.5rem;
+ border: 1px solid rgba(255,255,255,0.07);
+ border-radius: 14px;
+ background: rgba(255,255,255,0.03);
+}
+
+.sf-gen-step {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ font-size: 0.875rem;
+ color: rgba(229,241,242,0.3);
+ transition: color 0.3s;
+}
+
+.sf-gen-step.done {
+ color: rgba(94,235,195,0.7);
+}
+
+.sf-gen-step.active {
+ color: #E5F1F2;
+ font-weight: 600;
+}
+
+.sf-gen-step-dot {
+ width: 8px;
+ height: 8px;
+ border-radius: 50%;
+ background: currentColor;
+ flex-shrink: 0;
+ transition: background 0.3s;
+}
+
+.sf-gen-step.active .sf-gen-step-dot {
+ background: #AE72F9;
+ box-shadow: 0 0 6px rgba(174,114,249,0.6);
+ animation: sf-dot-pulse 1s ease-in-out infinite;
+}
+
+.sf-gen-step.done .sf-gen-step-dot {
+ background: #5EEBC3;
+}
+
+@keyframes sf-dot-pulse {
+ 0%, 100% { opacity: 1; }
+ 50% { opacity: 0.4; }
+}
+
+/* ---- 완성 화면 ---- */
+.sf-result {
+ max-width: 400px;
+ margin: 0 auto;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 1.25rem;
+ padding: 1rem 0 2rem;
+}
+
+.sf-result-label {
+ font-size: 1.125rem;
+ font-weight: 700;
+ color: #5EEBC3;
+ margin: 0;
+}
+
+.sf-result-video-wrap {
+ width: 100%;
+ max-width: 320px;
+ aspect-ratio: 9 / 16;
+ border-radius: 16px;
+ overflow: hidden;
+ background: #000;
+ position: relative;
+}
+
+.sf-result-video {
+ position: absolute;
+ inset: 0;
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ border-radius: 16px;
+}
+
+.sf-result-actions {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 10px;
+ width: 100%;
+ justify-content: center;
+}
+
+.sf-download-btn {
+ height: 48px;
+ padding: 0 2rem;
+ border-radius: 999px;
+ border: none;
+ background: #AE72F9;
+ color: #fff;
+ font-size: 0.9375rem;
+ font-weight: 600;
+ font-family: inherit;
+ cursor: pointer;
+ transition: background 0.2s, opacity 0.2s;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.sf-download-btn:hover:not(:disabled) { background: #9a5ef0; }
+.sf-download-btn:disabled { opacity: 0.5; cursor: not-allowed; }
+
+/* ---- 에러 토스트 ---- */
+.sf-error-toast {
+ position: fixed;
+ bottom: 80px;
+ left: 50%;
+ transform: translateX(-50%);
+ background: rgba(200,50,50,0.9);
+ color: #fff;
+ font-size: 0.875rem;
+ font-weight: 500;
+ padding: 10px 20px;
+ border-radius: 999px;
+ z-index: 100;
+ white-space: nowrap;
+ max-width: 90vw;
+ text-align: center;
+}
+
+/* ---- 데스크톱: sf-* 요소 확대 ---- */
+@media (min-width: 768px) {
+ .sf-scroll-area {
+ padding: 5rem 2.5rem 6rem;
+ }
+
+ .sf-hero,
+ .sf-step-bar,
+ .sf-card {
+ max-width: 760px;
+ }
+
+ .sf-hero-title {
+ font-size: 2.25rem;
+ margin-bottom: 1rem;
+ }
+
+ .sf-hero-desc {
+ font-size: 1rem;
+ }
+
+ .sf-card {
+ padding: 2rem 2.5rem;
+ gap: 1.5rem;
+ border-radius: 20px;
+ }
+
+ .sf-card-title {
+ font-size: 1.375rem;
+ }
+
+ .sf-card-desc {
+ font-size: 0.9rem;
+ margin-top: -0.75rem;
+ }
+
+ .sf-drop-zone {
+ min-height: 180px;
+ padding: 2.5rem;
+ }
+
+ .sf-drop-text {
+ font-size: 1rem;
+ }
+
+ .sf-drop-hint {
+ font-size: 0.875rem;
+ }
+
+ .sf-photo-grid {
+ grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
+ gap: 12px;
+ }
+
+ .sf-step-circle {
+ width: 34px;
+ height: 34px;
+ font-size: 0.875rem;
+ }
+
+ .sf-step-bar::before {
+ top: 17px;
+ }
+
+ .sf-step-name {
+ font-size: 0.8rem;
+ }
+
+ .sf-step-sub {
+ font-size: 0.7rem;
+ }
+
+ .sf-kind-grid {
+ flex-direction: row;
+ gap: 10px;
+ }
+
+ .sf-kind-card {
+ flex: 1;
+ padding: 16px 18px;
+ }
+
+ .sf-kind-label {
+ font-size: 1rem;
+ }
+
+ .sf-kind-desc {
+ font-size: 0.825rem;
+ }
+
+ .sf-input {
+ height: 52px;
+ font-size: 1rem;
+ padding: 0 16px;
+ }
+
+ .sf-textarea {
+ padding: 14px 16px;
+ font-size: 1rem;
+ min-height: 96px;
+ }
+
+ .sf-label {
+ font-size: 0.9rem;
+ }
+
+ .sf-field-hint {
+ font-size: 0.825rem;
+ }
+
+ .sf-btn-next,
+ .sf-btn-generate {
+ height: 50px;
+ padding: 0 2rem;
+ font-size: 1rem;
+ }
+
+ .sf-btn-prev {
+ height: 50px;
+ padding: 0 1.5rem;
+ font-size: 0.9375rem;
+ }
+
+ .sf-footer {
+ padding: 16px 2.5rem;
+ }
+
+ .sf-footer-count {
+ font-size: 1.0625rem;
+ }
+
+ .sf-footer-status {
+ font-size: 0.875rem;
+ }
+
+ .sf-gen-title {
+ font-size: 1.875rem;
+ }
+
+ .sf-gen-msg {
+ font-size: 1rem;
+ }
+
+ .sf-gen-sub {
+ font-size: 0.875rem;
+ }
+
+ .sf-gen-orb-ring {
+ width: 160px;
+ height: 160px;
+ }
+
+ .sf-gen-icon svg {
+ width: 48px;
+ height: 48px;
+ }
+
+ .sf-gen-steps {
+ max-width: 320px;
+ font-size: 0.9375rem;
+ }
+
+ .sf-result {
+ max-width: 500px;
+ }
+
+ .sf-result-label {
+ font-size: 1.375rem;
+ }
+
+ .sf-download-btn {
+ height: 52px;
+ line-height: 52px;
+ font-size: 1rem;
+ padding: 0 2.5rem;
+ }
+}
diff --git a/package-lock.json b/package-lock.json
index b35197e..ed853d0 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -16,6 +16,8 @@
},
"devDependencies": {
"@types/node": "^22.14.0",
+ "@types/react": "^19.2.17",
+ "@types/react-dom": "^19.2.3",
"@vitejs/plugin-react": "^5.0.0",
"typescript": "~5.8.2",
"vite": "^6.2.0"
@@ -52,6 +54,7 @@
"integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/code-frame": "^7.27.1",
"@babel/generator": "^7.28.5",
@@ -1288,10 +1291,32 @@
"integrity": "sha512-1N9SBnWYOJTrNZCdh/yJE+t910Y128BoyY+zBLWhL3r0TYzlTmFdXrPwHL9DyFZmlEXNQQolTZh3KHV31QDhyA==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"undici-types": "~6.21.0"
}
},
+ "node_modules/@types/react": {
+ "version": "19.2.17",
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.17.tgz",
+ "integrity": "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==",
+ "devOptional": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "csstype": "^3.2.2"
+ }
+ },
+ "node_modules/@types/react-dom": {
+ "version": "19.2.3",
+ "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz",
+ "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==",
+ "dev": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "^19.2.0"
+ }
+ },
"node_modules/@types/use-sync-external-store": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz",
@@ -1349,6 +1374,7 @@
}
],
"license": "MIT",
+ "peer": true,
"dependencies": {
"baseline-browser-mapping": "^2.9.0",
"caniuse-lite": "^1.0.30001759",
@@ -1400,6 +1426,13 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/csstype": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
+ "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
+ "devOptional": true,
+ "license": "MIT"
+ },
"node_modules/d3-array": {
"version": "3.2.4",
"resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz",
@@ -1691,6 +1724,7 @@
}
],
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/runtime": "^7.28.4"
},
@@ -1811,6 +1845,7 @@
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"dev": true,
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">=12"
},
@@ -1852,6 +1887,7 @@
"resolved": "https://registry.npmjs.org/react/-/react-19.2.3.tgz",
"integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==",
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">=0.10.0"
}
@@ -1861,6 +1897,7 @@
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.3.tgz",
"integrity": "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"scheduler": "^0.27.0"
},
@@ -1907,6 +1944,7 @@
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz",
"integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@types/use-sync-external-store": "^0.0.6",
"use-sync-external-store": "^1.4.0"
@@ -1969,7 +2007,8 @@
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz",
"integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==",
- "license": "MIT"
+ "license": "MIT",
+ "peer": true
},
"node_modules/redux-thunk": {
"version": "3.1.0",
@@ -2083,6 +2122,7 @@
"integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
"devOptional": true,
"license": "Apache-2.0",
+ "peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@@ -2166,6 +2206,7 @@
"integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"esbuild": "^0.25.0",
"fdir": "^6.4.4",
diff --git a/package.json b/package.json
index bdf154e..b049997 100755
--- a/package.json
+++ b/package.json
@@ -17,6 +17,8 @@
},
"devDependencies": {
"@types/node": "^22.14.0",
+ "@types/react": "^19.2.17",
+ "@types/react-dom": "^19.2.3",
"@vitejs/plugin-react": "^5.0.0",
"typescript": "~5.8.2",
"vite": "^6.2.0"
diff --git a/remotion/package-lock.json b/remotion/package-lock.json
new file mode 100644
index 0000000..aaa7a82
--- /dev/null
+++ b/remotion/package-lock.json
@@ -0,0 +1,2907 @@
+{
+ "name": "@ado2/higgsfield-remotion",
+ "version": "0.1.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "@ado2/higgsfield-remotion",
+ "version": "0.1.0",
+ "dependencies": {
+ "@remotion/cli": "4.0.468",
+ "@remotion/google-fonts": "4.0.468",
+ "react": "19.2.0",
+ "react-dom": "19.2.0",
+ "remotion": "4.0.468"
+ },
+ "devDependencies": {
+ "@types/react": "19.2.0",
+ "typescript": "5.7.3"
+ }
+ },
+ "node_modules/@babel/helper-string-parser": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz",
+ "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-identifier": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz",
+ "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/parser": {
+ "version": "7.24.1",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.1.tgz",
+ "integrity": "sha512-Zo9c7N3xdOIQrNip7Lc9wvRPzlRtovHVE4lkz8WEDr7uYh/GMQhSiIgFxGIArRHYdJE5kxtZjAf8rT0xhdLCzg==",
+ "license": "MIT",
+ "bin": {
+ "parser": "bin/babel-parser.js"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@babel/types": {
+ "version": "7.24.0",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz",
+ "integrity": "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-string-parser": "^7.23.4",
+ "@babel/helper-validator-identifier": "^7.22.20",
+ "to-fast-properties": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@emnapi/core": {
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz",
+ "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@emnapi/wasi-threads": "1.2.1",
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@emnapi/runtime": {
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz",
+ "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@emnapi/wasi-threads": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz",
+ "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@esbuild/aix-ppc64": {
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.0.tgz",
+ "integrity": "sha512-lhRUCeuOyJQURhTxl4WkpFTjIsbDayJHih5kZC1giwE+MhIzAb7mEsQMqMf18rHLsrb5qI1tafG20mLxEWcWlA==",
+ "cpu": [
+ "ppc64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "aix"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-arm": {
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.0.tgz",
+ "integrity": "sha512-wqh0ByljabXLKHeWXYLqoJ5jKC4XBaw6Hk08OfMrCRd2nP2ZQ5eleDZC41XHyCNgktBGYMbqnrJKq/K/lzPMSQ==",
+ "cpu": [
+ "arm"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-arm64": {
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.0.tgz",
+ "integrity": "sha512-+WzIXQOSaGs33tLEgYPYe/yQHf0WTU0X42Jca3y8NWMbUVhp7rUnw+vAsRC/QiDrdD31IszMrZy+qwPOPjd+rw==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-x64": {
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.0.tgz",
+ "integrity": "sha512-+VJggoaKhk2VNNqVL7f6S189UzShHC/mR9EE8rDdSkdpN0KflSwWY/gWjDrNxxisg8Fp1ZCD9jLMo4m0OUfeUA==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/darwin-arm64": {
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.0.tgz",
+ "integrity": "sha512-0T+A9WZm+bZ84nZBtk1ckYsOvyA3x7e2Acj1KdVfV4/2tdG4fzUp91YHx+GArWLtwqp77pBXVCPn2We7Letr0Q==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/darwin-x64": {
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.0.tgz",
+ "integrity": "sha512-fyzLm/DLDl/84OCfp2f/XQ4flmORsjU7VKt8HLjvIXChJoFFOIL6pLJPH4Yhd1n1gGFF9mPwtlN5Wf82DZs+LQ==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/freebsd-arm64": {
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.0.tgz",
+ "integrity": "sha512-l9GeW5UZBT9k9brBYI+0WDffcRxgHQD8ShN2Ur4xWq/NFzUKm3k5lsH4PdaRgb2w7mI9u61nr2gI2mLI27Nh3Q==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/freebsd-x64": {
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.0.tgz",
+ "integrity": "sha512-BXoQai/A0wPO6Es3yFJ7APCiKGc1tdAEOgeTNy3SsB491S3aHn4S4r3e976eUnPdU+NbdtmBuLncYir2tMU9Nw==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-arm": {
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.0.tgz",
+ "integrity": "sha512-CjaaREJagqJp7iTaNQjjidaNbCKYcd4IDkzbwwxtSvjI7NZm79qiHc8HqciMddQ6CKvJT6aBd8lO9kN/ZudLlw==",
+ "cpu": [
+ "arm"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-arm64": {
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.0.tgz",
+ "integrity": "sha512-RVyzfb3FWsGA55n6WY0MEIEPURL1FcbhFE6BffZEMEekfCzCIMtB5yyDcFnVbTnwk+CLAgTujmV/Lgvih56W+A==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-ia32": {
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.0.tgz",
+ "integrity": "sha512-KBnSTt1kxl9x70q+ydterVdl+Cn0H18ngRMRCEQfrbqdUuntQQ0LoMZv47uB97NljZFzY6HcfqEZ2SAyIUTQBQ==",
+ "cpu": [
+ "ia32"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-loong64": {
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.0.tgz",
+ "integrity": "sha512-zpSlUce1mnxzgBADvxKXX5sl8aYQHo2ezvMNI8I0lbblJtp8V4odlm3Yzlj7gPyt3T8ReksE6bK+pT3WD+aJRg==",
+ "cpu": [
+ "loong64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-mips64el": {
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.0.tgz",
+ "integrity": "sha512-2jIfP6mmjkdmeTlsX/9vmdmhBmKADrWqN7zcdtHIeNSCH1SqIoNI63cYsjQR8J+wGa4Y5izRcSHSm8K3QWmk3w==",
+ "cpu": [
+ "mips64el"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-ppc64": {
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.0.tgz",
+ "integrity": "sha512-bc0FE9wWeC0WBm49IQMPSPILRocGTQt3j5KPCA8os6VprfuJ7KD+5PzESSrJ6GmPIPJK965ZJHTUlSA6GNYEhg==",
+ "cpu": [
+ "ppc64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-riscv64": {
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.0.tgz",
+ "integrity": "sha512-SQPZOwoTTT/HXFXQJG/vBX8sOFagGqvZyXcgLA3NhIqcBv1BJU1d46c0rGcrij2B56Z2rNiSLaZOYW5cUk7yLQ==",
+ "cpu": [
+ "riscv64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-s390x": {
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.0.tgz",
+ "integrity": "sha512-SCfR0HN8CEEjnYnySJTd2cw0k9OHB/YFzt5zgJEwa+wL/T/raGWYMBqwDNAC6dqFKmJYZoQBRfHjgwLHGSrn3Q==",
+ "cpu": [
+ "s390x"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-x64": {
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.0.tgz",
+ "integrity": "sha512-us0dSb9iFxIi8srnpl931Nvs65it/Jd2a2K3qs7fz2WfGPHqzfzZTfec7oxZJRNPXPnNYZtanmRc4AL/JwVzHQ==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/netbsd-arm64": {
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.0.tgz",
+ "integrity": "sha512-CR/RYotgtCKwtftMwJlUU7xCVNg3lMYZ0RzTmAHSfLCXw3NtZtNpswLEj/Kkf6kEL3Gw+BpOekRX0BYCtklhUw==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/netbsd-x64": {
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.0.tgz",
+ "integrity": "sha512-nU1yhmYutL+fQ71Kxnhg8uEOdC0pwEW9entHykTgEbna2pw2dkbFSMeqjjyHZoCmt8SBkOSvV+yNmm94aUrrqw==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openbsd-arm64": {
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.0.tgz",
+ "integrity": "sha512-cXb5vApOsRsxsEl4mcZ1XY3D4DzcoMxR/nnc4IyqYs0rTI8ZKmW6kyyg+11Z8yvgMfAEldKzP7AdP64HnSC/6g==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openbsd-x64": {
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.0.tgz",
+ "integrity": "sha512-8wZM2qqtv9UP3mzy7HiGYNH/zjTA355mpeuA+859TyR+e+Tc08IHYpLJuMsfpDJwoLo1ikIJI8jC3GFjnRClzA==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openharmony-arm64": {
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.0.tgz",
+ "integrity": "sha512-FLGfyizszcef5C3YtoyQDACyg95+dndv79i2EekILBofh5wpCa1KuBqOWKrEHZg3zrL3t5ouE5jgr94vA+Wb2w==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openharmony"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/sunos-x64": {
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.0.tgz",
+ "integrity": "sha512-1ZgjUoEdHZZl/YlV76TSCz9Hqj9h9YmMGAgAPYd+q4SicWNX3G5GCyx9uhQWSLcbvPW8Ni7lj4gDa1T40akdlw==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "sunos"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-arm64": {
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.0.tgz",
+ "integrity": "sha512-Q9StnDmQ/enxnpxCCLSg0oo4+34B9TdXpuyPeTedN/6+iXBJ4J+zwfQI28u/Jl40nOYAxGoNi7mFP40RUtkmUA==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-ia32": {
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.0.tgz",
+ "integrity": "sha512-zF3ag/gfiCe6U2iczcRzSYJKH1DCI+ByzSENHlM2FcDbEeo5Zd2C86Aq0tKUYAJJ1obRP84ymxIAksZUcdztHA==",
+ "cpu": [
+ "ia32"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-x64": {
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.0.tgz",
+ "integrity": "sha512-pEl1bO9mfAmIC+tW5btTmrKaujg3zGtUmWNdCw/xs70FBjwAL3o9OEKNHvNmnyylD6ubxUERiEhdsL0xBQ9efw==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@jridgewell/gen-mapping": {
+ "version": "0.3.13",
+ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
+ "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/sourcemap-codec": "^1.5.0",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ }
+ },
+ "node_modules/@jridgewell/resolve-uri": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
+ "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/source-map": {
+ "version": "0.3.11",
+ "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz",
+ "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==",
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/gen-mapping": "^0.3.5",
+ "@jridgewell/trace-mapping": "^0.3.25"
+ }
+ },
+ "node_modules/@jridgewell/sourcemap-codec": {
+ "version": "1.5.5",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
+ "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
+ "license": "MIT"
+ },
+ "node_modules/@jridgewell/trace-mapping": {
+ "version": "0.3.31",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
+ "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/resolve-uri": "^3.1.0",
+ "@jridgewell/sourcemap-codec": "^1.4.14"
+ }
+ },
+ "node_modules/@mediabunny/aac-encoder": {
+ "version": "1.45.0",
+ "resolved": "https://registry.npmjs.org/@mediabunny/aac-encoder/-/aac-encoder-1.45.0.tgz",
+ "integrity": "sha512-vLQw8cY7Me6pvTTMkMhOiH9UCuINzfTOETCeDxbGNeNfDqc/7QlxloUH1Ylp/Zz2ek0O8kc6YdygV2vWAPakrA==",
+ "license": "MPL-2.0",
+ "funding": {
+ "type": "individual",
+ "url": "https://github.com/sponsors/Vanilagy"
+ },
+ "peerDependencies": {
+ "mediabunny": "^1.0.0"
+ }
+ },
+ "node_modules/@mediabunny/flac-encoder": {
+ "version": "1.45.0",
+ "resolved": "https://registry.npmjs.org/@mediabunny/flac-encoder/-/flac-encoder-1.45.0.tgz",
+ "integrity": "sha512-LfKbAMZVkxRS7PpEIVnWOY/l0KcHv+rjO7pYY3O0TPCZvbHWfrnQjn8JPacPIfuq6Yv7r4f8lhcl7yHSynoRkQ==",
+ "license": "MPL-2.0",
+ "funding": {
+ "type": "individual",
+ "url": "https://github.com/sponsors/Vanilagy"
+ },
+ "peerDependencies": {
+ "mediabunny": "^1.0.0"
+ }
+ },
+ "node_modules/@mediabunny/mp3-encoder": {
+ "version": "1.45.0",
+ "resolved": "https://registry.npmjs.org/@mediabunny/mp3-encoder/-/mp3-encoder-1.45.0.tgz",
+ "integrity": "sha512-Bobi6AaQYEc7TWmPJ8Q0/hcUtBN7pLUC2qjoC7oZR4FcGqGztby6k7A1SWlmswoMOEIhYsOrgDaemrSDAC0QVQ==",
+ "license": "MPL-2.0",
+ "funding": {
+ "type": "individual",
+ "url": "https://github.com/sponsors/Vanilagy"
+ },
+ "peerDependencies": {
+ "mediabunny": "^1.0.0"
+ }
+ },
+ "node_modules/@module-federation/error-codes": {
+ "version": "0.22.0",
+ "resolved": "https://registry.npmjs.org/@module-federation/error-codes/-/error-codes-0.22.0.tgz",
+ "integrity": "sha512-xF9SjnEy7vTdx+xekjPCV5cIHOGCkdn3pIxo9vU7gEZMIw0SvAEdsy6Uh17xaCpm8V0FWvR0SZoK9Ik6jGOaug==",
+ "license": "MIT"
+ },
+ "node_modules/@module-federation/runtime": {
+ "version": "0.22.0",
+ "resolved": "https://registry.npmjs.org/@module-federation/runtime/-/runtime-0.22.0.tgz",
+ "integrity": "sha512-38g5iPju2tPC3KHMPxRKmy4k4onNp6ypFPS1eKGsNLUkXgHsPMBFqAjDw96iEcjri91BrahG4XcdyKi97xZzlA==",
+ "license": "MIT",
+ "dependencies": {
+ "@module-federation/error-codes": "0.22.0",
+ "@module-federation/runtime-core": "0.22.0",
+ "@module-federation/sdk": "0.22.0"
+ }
+ },
+ "node_modules/@module-federation/runtime-core": {
+ "version": "0.22.0",
+ "resolved": "https://registry.npmjs.org/@module-federation/runtime-core/-/runtime-core-0.22.0.tgz",
+ "integrity": "sha512-GR1TcD6/s7zqItfhC87zAp30PqzvceoeDGYTgF3Vx2TXvsfDrhP6Qw9T4vudDQL3uJRne6t7CzdT29YyVxlgIA==",
+ "license": "MIT",
+ "dependencies": {
+ "@module-federation/error-codes": "0.22.0",
+ "@module-federation/sdk": "0.22.0"
+ }
+ },
+ "node_modules/@module-federation/runtime-tools": {
+ "version": "0.22.0",
+ "resolved": "https://registry.npmjs.org/@module-federation/runtime-tools/-/runtime-tools-0.22.0.tgz",
+ "integrity": "sha512-4ScUJ/aUfEernb+4PbLdhM/c60VHl698Gn1gY21m9vyC1Ucn69fPCA1y2EwcCB7IItseRMoNhdcWQnzt/OPCNA==",
+ "license": "MIT",
+ "dependencies": {
+ "@module-federation/runtime": "0.22.0",
+ "@module-federation/webpack-bundler-runtime": "0.22.0"
+ }
+ },
+ "node_modules/@module-federation/sdk": {
+ "version": "0.22.0",
+ "resolved": "https://registry.npmjs.org/@module-federation/sdk/-/sdk-0.22.0.tgz",
+ "integrity": "sha512-x4aFNBKn2KVQRuNVC5A7SnrSCSqyfIWmm1DvubjbO9iKFe7ith5niw8dqSFBekYBg2Fwy+eMg4sEFNVvCAdo6g==",
+ "license": "MIT"
+ },
+ "node_modules/@module-federation/webpack-bundler-runtime": {
+ "version": "0.22.0",
+ "resolved": "https://registry.npmjs.org/@module-federation/webpack-bundler-runtime/-/webpack-bundler-runtime-0.22.0.tgz",
+ "integrity": "sha512-aM8gCqXu+/4wBmJtVeMeeMN5guw3chf+2i6HajKtQv7SJfxV/f4IyNQJUeUQu9HfiAZHjqtMV5Lvq/Lvh8LdyA==",
+ "license": "MIT",
+ "dependencies": {
+ "@module-federation/runtime": "0.22.0",
+ "@module-federation/sdk": "0.22.0"
+ }
+ },
+ "node_modules/@napi-rs/wasm-runtime": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.0.7.tgz",
+ "integrity": "sha512-SeDnOO0Tk7Okiq6DbXmmBODgOAb9dp9gjlphokTUxmt8U3liIP1ZsozBahH69j/RJv+Rfs6IwUKHTgQYJ/HBAw==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@emnapi/core": "^1.5.0",
+ "@emnapi/runtime": "^1.5.0",
+ "@tybys/wasm-util": "^0.10.1"
+ }
+ },
+ "node_modules/@remotion/bundler": {
+ "version": "4.0.468",
+ "resolved": "https://registry.npmjs.org/@remotion/bundler/-/bundler-4.0.468.tgz",
+ "integrity": "sha512-jsCzE4KmDLnV+hz4UOWjOJnhzH90LNrnqIrSpwg+Wu5fZip9tPA414qZNKuF+M3Z4riBC4UOJVt5/BQ41Uk0wg==",
+ "license": "SEE LICENSE IN LICENSE.md",
+ "dependencies": {
+ "@remotion/media-parser": "4.0.468",
+ "@remotion/studio": "4.0.468",
+ "@remotion/studio-shared": "4.0.468",
+ "@remotion/timeline-utils": "4.0.468",
+ "@rspack/core": "1.7.6",
+ "@rspack/plugin-react-refresh": "1.6.1",
+ "css-loader": "7.1.4",
+ "esbuild": "0.28.0",
+ "react-refresh": "0.18.0",
+ "remotion": "4.0.468",
+ "style-loader": "4.0.0",
+ "webpack": "5.105.0"
+ },
+ "peerDependencies": {
+ "react": ">=16.8.0",
+ "react-dom": ">=16.8.0"
+ }
+ },
+ "node_modules/@remotion/cli": {
+ "version": "4.0.468",
+ "resolved": "https://registry.npmjs.org/@remotion/cli/-/cli-4.0.468.tgz",
+ "integrity": "sha512-wHc9cjDYJDiP5hfFHal1xuDnkb5Wku6162tCQ9V5bNf5BKC1zEN6DA+S5sN/yWMhYgUxyaO12nLmz9h50PrkDA==",
+ "license": "SEE LICENSE IN LICENSE.md",
+ "dependencies": {
+ "@remotion/bundler": "4.0.468",
+ "@remotion/media-utils": "4.0.468",
+ "@remotion/player": "4.0.468",
+ "@remotion/renderer": "4.0.468",
+ "@remotion/studio": "4.0.468",
+ "@remotion/studio-server": "4.0.468",
+ "@remotion/studio-shared": "4.0.468",
+ "dotenv": "17.3.1",
+ "minimist": "1.2.6",
+ "prompts": "2.4.2",
+ "remotion": "4.0.468"
+ },
+ "bin": {
+ "remotion": "remotion-cli.js",
+ "remotionb": "remotionb-cli.js",
+ "remotiond": "remotiond-cli.js"
+ },
+ "peerDependencies": {
+ "react": ">=16.8.0",
+ "react-dom": ">=16.8.0"
+ }
+ },
+ "node_modules/@remotion/compositor-darwin-arm64": {
+ "version": "4.0.468",
+ "resolved": "https://registry.npmjs.org/@remotion/compositor-darwin-arm64/-/compositor-darwin-arm64-4.0.468.tgz",
+ "integrity": "sha512-wB1m1bSvqU+CGg4qxZt8XGZf+4eDFot58IMy6Z7b2+qHpvE/qdtm2CENvlSuDu/zVO6b10wWbaWGKz0jf2YM0Q==",
+ "cpu": [
+ "arm64"
+ ],
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@remotion/compositor-darwin-x64": {
+ "version": "4.0.468",
+ "resolved": "https://registry.npmjs.org/@remotion/compositor-darwin-x64/-/compositor-darwin-x64-4.0.468.tgz",
+ "integrity": "sha512-WdJS1T7zbxHRraK9F6SIpWbfU3UprSeLnmoHtkMhW35o0zfaq3scfprmm1eTHSynlttz2nRwEvNPrNvhbJrBtg==",
+ "cpu": [
+ "x64"
+ ],
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@remotion/compositor-linux-arm64-gnu": {
+ "version": "4.0.468",
+ "resolved": "https://registry.npmjs.org/@remotion/compositor-linux-arm64-gnu/-/compositor-linux-arm64-gnu-4.0.468.tgz",
+ "integrity": "sha512-HEXjGlcL1b/7EfZkJOSs+XQt5mJ88f6SJB/uIHzde3hpYwZvqmtls9zC8wzM6VncIYNQOu8gDxfbVzAZ+Hfv3Q==",
+ "cpu": [
+ "arm64"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@remotion/compositor-linux-arm64-musl": {
+ "version": "4.0.468",
+ "resolved": "https://registry.npmjs.org/@remotion/compositor-linux-arm64-musl/-/compositor-linux-arm64-musl-4.0.468.tgz",
+ "integrity": "sha512-8Qf14zSsvbAKfWdcrdxhPP4pm0A6qsc72vzWjDIH1XmYAKHg49eOHolQTr6bzNyekMLgJ3eKC66W4UFYny0gfg==",
+ "cpu": [
+ "arm64"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@remotion/compositor-linux-x64-gnu": {
+ "version": "4.0.468",
+ "resolved": "https://registry.npmjs.org/@remotion/compositor-linux-x64-gnu/-/compositor-linux-x64-gnu-4.0.468.tgz",
+ "integrity": "sha512-PqbgcutSTR3Od3WTkOlMBIgW4sFeylnWYK8Pdcfs81TePD2xFDXEKY45HBYpi58EzSt6zp2qdQAW8b3NrIhEiw==",
+ "cpu": [
+ "x64"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@remotion/compositor-linux-x64-musl": {
+ "version": "4.0.468",
+ "resolved": "https://registry.npmjs.org/@remotion/compositor-linux-x64-musl/-/compositor-linux-x64-musl-4.0.468.tgz",
+ "integrity": "sha512-EtMjnQvaYOvNDGvYqEQdcfznN0sKCf7fT9lA1admcTYJ7h/jxFydj8aTTpvgmA3VG4TN1IL70RSLVu3Esx1Ylg==",
+ "cpu": [
+ "x64"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@remotion/compositor-win32-x64-msvc": {
+ "version": "4.0.468",
+ "resolved": "https://registry.npmjs.org/@remotion/compositor-win32-x64-msvc/-/compositor-win32-x64-msvc-4.0.468.tgz",
+ "integrity": "sha512-h6fpDu9e1Wfpg5jpYABYwbh1y3uqhkOS3FYfnUCvKNBp+ZpNkla8TfsQsQVoMECtxxOwLHLYesY5BzvUtOZ/5Q==",
+ "cpu": [
+ "x64"
+ ],
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@remotion/google-fonts": {
+ "version": "4.0.468",
+ "resolved": "https://registry.npmjs.org/@remotion/google-fonts/-/google-fonts-4.0.468.tgz",
+ "integrity": "sha512-Dl59gKL+GiVaozSfNt+b4b6iYyR5T1GtlMOF5Yxn/JLyRSw1hUYFreon+m0qZ8n5mZ+iipqlKeNjfYKGWtbtww==",
+ "license": "SEE LICENSE IN LICENSE.md",
+ "dependencies": {
+ "remotion": "4.0.468"
+ }
+ },
+ "node_modules/@remotion/licensing": {
+ "version": "4.0.468",
+ "resolved": "https://registry.npmjs.org/@remotion/licensing/-/licensing-4.0.468.tgz",
+ "integrity": "sha512-l0iIn8YVdKiOBYDN1bnbtguMReq/Q7QozxtHr+mKIHr66zeCjhpwFvHklmN/LXMFGWh2OxfNJ6fgXKWS1Iuy3A==",
+ "license": "MIT"
+ },
+ "node_modules/@remotion/media-parser": {
+ "version": "4.0.468",
+ "resolved": "https://registry.npmjs.org/@remotion/media-parser/-/media-parser-4.0.468.tgz",
+ "integrity": "sha512-lh6IGOmVnCsV6oytuGbgr9PB/AkWnWRwBr8tsq7gpjBqhR3oLe3fFd+p7jJreMrF+l4y55bcrf52qT3yxBD9fw==",
+ "license": "Remotion License https://remotion.dev/license"
+ },
+ "node_modules/@remotion/media-utils": {
+ "version": "4.0.468",
+ "resolved": "https://registry.npmjs.org/@remotion/media-utils/-/media-utils-4.0.468.tgz",
+ "integrity": "sha512-at4/faHpezfYuv3WikG1ePQY3pBnjWTgFv2++IRJ4z5+ZneoSM1mtFS9lIJO9maCPRLxJRqHWOI0+rnNrNHADA==",
+ "license": "MIT",
+ "dependencies": {
+ "mediabunny": "1.45.0",
+ "remotion": "4.0.468"
+ },
+ "peerDependencies": {
+ "react": ">=16.8.0",
+ "react-dom": ">=16.8.0"
+ }
+ },
+ "node_modules/@remotion/player": {
+ "version": "4.0.468",
+ "resolved": "https://registry.npmjs.org/@remotion/player/-/player-4.0.468.tgz",
+ "integrity": "sha512-M0kdFnAZvstMctK2ypoTkFOahI61kUE9HnQAh5/9dPb+FlOwCDLRDnM2LBkltZsJxgqgH1nDe1iNPsry0QCjmw==",
+ "license": "SEE LICENSE IN LICENSE.md",
+ "dependencies": {
+ "remotion": "4.0.468"
+ },
+ "peerDependencies": {
+ "react": ">=16.8.0",
+ "react-dom": ">=16.8.0"
+ }
+ },
+ "node_modules/@remotion/renderer": {
+ "version": "4.0.468",
+ "resolved": "https://registry.npmjs.org/@remotion/renderer/-/renderer-4.0.468.tgz",
+ "integrity": "sha512-n8fLD9o5W0N4FEz9V7OBmHjiG/Qo36cwH/MaUsEdATCfKIUGlMjrBvyFuKGobl5GHdt3xCyzYQoar3vFiwll8Q==",
+ "license": "SEE LICENSE IN LICENSE.md",
+ "dependencies": {
+ "@remotion/licensing": "4.0.468",
+ "@remotion/streaming": "4.0.468",
+ "execa": "5.1.1",
+ "remotion": "4.0.468",
+ "source-map": "0.8.0-beta.0",
+ "ws": "8.20.1"
+ },
+ "optionalDependencies": {
+ "@remotion/compositor-darwin-arm64": "4.0.468",
+ "@remotion/compositor-darwin-x64": "4.0.468",
+ "@remotion/compositor-linux-arm64-gnu": "4.0.468",
+ "@remotion/compositor-linux-arm64-musl": "4.0.468",
+ "@remotion/compositor-linux-x64-gnu": "4.0.468",
+ "@remotion/compositor-linux-x64-musl": "4.0.468",
+ "@remotion/compositor-win32-x64-msvc": "4.0.468"
+ },
+ "peerDependencies": {
+ "react": ">=16.8.0",
+ "react-dom": ">=16.8.0"
+ }
+ },
+ "node_modules/@remotion/streaming": {
+ "version": "4.0.468",
+ "resolved": "https://registry.npmjs.org/@remotion/streaming/-/streaming-4.0.468.tgz",
+ "integrity": "sha512-Ts0pq7Lh+ztSvJp5oOTHOc2oKuQ3LtXGfWhQKiJXm81Xz5Qjz3KbPhQ/Z94/GzbZDRrs+zdzwRyqS6pTFnoLdg==",
+ "license": "MIT"
+ },
+ "node_modules/@remotion/studio": {
+ "version": "4.0.468",
+ "resolved": "https://registry.npmjs.org/@remotion/studio/-/studio-4.0.468.tgz",
+ "integrity": "sha512-Wzy/EtI4GLbkExet253KTrwOunJb3ciGFf+/bd0FBOt3plmaPxuJe4iJ4IvMwwA0/xR1U9HkgXg/gPZxzVHsSQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/trace-mapping": "0.3.31",
+ "@remotion/media-utils": "4.0.468",
+ "@remotion/player": "4.0.468",
+ "@remotion/renderer": "4.0.468",
+ "@remotion/studio-shared": "4.0.468",
+ "@remotion/timeline-utils": "4.0.468",
+ "@remotion/web-renderer": "4.0.468",
+ "@remotion/zod-types": "4.0.468",
+ "mediabunny": "1.45.0",
+ "memfs": "3.4.3",
+ "open": "8.4.2",
+ "remotion": "4.0.468",
+ "semver": "7.5.3",
+ "zod": "4.3.6"
+ },
+ "peerDependencies": {
+ "react": ">=16.8.0",
+ "react-dom": ">=16.8.0"
+ }
+ },
+ "node_modules/@remotion/studio-server": {
+ "version": "4.0.468",
+ "resolved": "https://registry.npmjs.org/@remotion/studio-server/-/studio-server-4.0.468.tgz",
+ "integrity": "sha512-xg5BlBUSnb/t1wa84fPwfgOe5WkS25fr6JVEUt9SBRZW3bbtcrGgCfykSFvIqx/nlG6S9Rw9XZuQnO6GOKR2oQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "7.24.1",
+ "@babel/types": "7.24.0",
+ "@remotion/bundler": "4.0.468",
+ "@remotion/renderer": "4.0.468",
+ "@remotion/studio-shared": "4.0.468",
+ "memfs": "3.4.3",
+ "open": "8.4.2",
+ "prettier": "3.8.1",
+ "recast": "0.23.11",
+ "remotion": "4.0.468",
+ "semver": "7.5.3"
+ }
+ },
+ "node_modules/@remotion/studio-shared": {
+ "version": "4.0.468",
+ "resolved": "https://registry.npmjs.org/@remotion/studio-shared/-/studio-shared-4.0.468.tgz",
+ "integrity": "sha512-PNfOIpQ+tSzOuEbedU+SueyvSXemp2i5IesHwlJgN+70jcbOCt29d5/1MDlJbgcydBe9fMnsrYrosP3ln5kAxA==",
+ "license": "MIT",
+ "dependencies": {
+ "remotion": "4.0.468"
+ }
+ },
+ "node_modules/@remotion/timeline-utils": {
+ "version": "4.0.468",
+ "resolved": "https://registry.npmjs.org/@remotion/timeline-utils/-/timeline-utils-4.0.468.tgz",
+ "integrity": "sha512-B99PXVVDILfUurh8QesJAfwZOy56H2oHs6dxf8HUnUN8xMSNKJx62C0zELiYb56KBTT1ryTGxWY64lTaUIuEcw==",
+ "license": "MIT",
+ "dependencies": {
+ "mediabunny": "1.45.0"
+ }
+ },
+ "node_modules/@remotion/web-renderer": {
+ "version": "4.0.468",
+ "resolved": "https://registry.npmjs.org/@remotion/web-renderer/-/web-renderer-4.0.468.tgz",
+ "integrity": "sha512-Ucxw9F7IkqHQdol9qu6UqpQKr29JjeyLrTDPSzDp0ec55MCO7oDvlktYkdc8IGmMQfh0FD8b603phUSXax4XnQ==",
+ "license": "UNLICENSED",
+ "dependencies": {
+ "@mediabunny/aac-encoder": "1.45.0",
+ "@mediabunny/flac-encoder": "1.45.0",
+ "@mediabunny/mp3-encoder": "1.45.0",
+ "@remotion/licensing": "4.0.468",
+ "mediabunny": "1.45.0",
+ "remotion": "4.0.468"
+ },
+ "peerDependencies": {
+ "react": ">=18.0.0",
+ "react-dom": ">=18.0.0"
+ }
+ },
+ "node_modules/@remotion/zod-types": {
+ "version": "4.0.468",
+ "resolved": "https://registry.npmjs.org/@remotion/zod-types/-/zod-types-4.0.468.tgz",
+ "integrity": "sha512-W6KejABTdCFZW0P0uVO7Ol7QMD8n/ewaKhyo5AzKx+0CfIelgQREWDXINBzJxZM5XnJXdn9Q0ffDWsBCnQFAaw==",
+ "license": "MIT",
+ "dependencies": {
+ "remotion": "4.0.468"
+ },
+ "peerDependencies": {
+ "zod": "4.3.6"
+ }
+ },
+ "node_modules/@rspack/binding": {
+ "version": "1.7.6",
+ "resolved": "https://registry.npmjs.org/@rspack/binding/-/binding-1.7.6.tgz",
+ "integrity": "sha512-/NrEcfo8Gx22hLGysanrV6gHMuqZSxToSci/3M4kzEQtF5cPjfOv5pqeLK/+B6cr56ul/OmE96cCdWcXeVnFjQ==",
+ "license": "MIT",
+ "optionalDependencies": {
+ "@rspack/binding-darwin-arm64": "1.7.6",
+ "@rspack/binding-darwin-x64": "1.7.6",
+ "@rspack/binding-linux-arm64-gnu": "1.7.6",
+ "@rspack/binding-linux-arm64-musl": "1.7.6",
+ "@rspack/binding-linux-x64-gnu": "1.7.6",
+ "@rspack/binding-linux-x64-musl": "1.7.6",
+ "@rspack/binding-wasm32-wasi": "1.7.6",
+ "@rspack/binding-win32-arm64-msvc": "1.7.6",
+ "@rspack/binding-win32-ia32-msvc": "1.7.6",
+ "@rspack/binding-win32-x64-msvc": "1.7.6"
+ }
+ },
+ "node_modules/@rspack/binding-darwin-arm64": {
+ "version": "1.7.6",
+ "resolved": "https://registry.npmjs.org/@rspack/binding-darwin-arm64/-/binding-darwin-arm64-1.7.6.tgz",
+ "integrity": "sha512-NZ9AWtB1COLUX1tA9HQQvWpTy07NSFfKBU8A6ylWd5KH8AePZztpNgLLAVPTuNO4CZXYpwcoclf8jG/luJcQdQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@rspack/binding-darwin-x64": {
+ "version": "1.7.6",
+ "resolved": "https://registry.npmjs.org/@rspack/binding-darwin-x64/-/binding-darwin-x64-1.7.6.tgz",
+ "integrity": "sha512-J2g6xk8ZS7uc024dNTGTHxoFzFovAZIRixUG7PiciLKTMP78svbSSWrmW6N8oAsAkzYfJWwQpVgWfFNRHvYxSw==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@rspack/binding-linux-arm64-gnu": {
+ "version": "1.7.6",
+ "resolved": "https://registry.npmjs.org/@rspack/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.7.6.tgz",
+ "integrity": "sha512-eQfcsaxhFrv5FmtaA7+O1F9/2yFDNIoPZzV/ZvqvFz5bBXVc4FAm/1fVpBg8Po/kX1h0chBc7Xkpry3cabFW8w==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rspack/binding-linux-arm64-musl": {
+ "version": "1.7.6",
+ "resolved": "https://registry.npmjs.org/@rspack/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.7.6.tgz",
+ "integrity": "sha512-DfQXKiyPIl7i1yECHy4eAkSmlUzzsSAbOjgMuKn7pudsWf483jg0UUYutNgXSlBjc/QSUp7906Cg8oty9OfwPA==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rspack/binding-linux-x64-gnu": {
+ "version": "1.7.6",
+ "resolved": "https://registry.npmjs.org/@rspack/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.7.6.tgz",
+ "integrity": "sha512-NdA+2X3lk2GGrMMnTGyYTzM3pn+zNjaqXqlgKmFBXvjfZqzSsKq3pdD1KHZCd5QHN+Fwvoszj0JFsquEVhE1og==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rspack/binding-linux-x64-musl": {
+ "version": "1.7.6",
+ "resolved": "https://registry.npmjs.org/@rspack/binding-linux-x64-musl/-/binding-linux-x64-musl-1.7.6.tgz",
+ "integrity": "sha512-rEy6MHKob02t/77YNgr6dREyJ0e0tv1X6Xsg8Z5E7rPXead06zefUbfazj4RELYySWnM38ovZyJAkPx/gOn3VA==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rspack/binding-wasm32-wasi": {
+ "version": "1.7.6",
+ "resolved": "https://registry.npmjs.org/@rspack/binding-wasm32-wasi/-/binding-wasm32-wasi-1.7.6.tgz",
+ "integrity": "sha512-YupOrz0daSG+YBbCIgpDgzfMM38YpChv+afZpaxx5Ml7xPeAZIIdgWmLHnQ2rts73N2M1NspAiBwV00Xx0N4Vg==",
+ "cpu": [
+ "wasm32"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@napi-rs/wasm-runtime": "1.0.7"
+ }
+ },
+ "node_modules/@rspack/binding-win32-arm64-msvc": {
+ "version": "1.7.6",
+ "resolved": "https://registry.npmjs.org/@rspack/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.7.6.tgz",
+ "integrity": "sha512-INj7aVXjBvlZ84kEhSK4kJ484ub0i+BzgnjDWOWM1K+eFYDZjLdAsQSS3fGGXwVc3qKbPIssFfnftATDMTEJHQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rspack/binding-win32-ia32-msvc": {
+ "version": "1.7.6",
+ "resolved": "https://registry.npmjs.org/@rspack/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-1.7.6.tgz",
+ "integrity": "sha512-lXGvC+z67UMcw58In12h8zCa9IyYRmuptUBMItQJzu+M278aMuD1nETyGLL7e4+OZ2lvrnnBIcjXN1hfw2yRzw==",
+ "cpu": [
+ "ia32"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rspack/binding-win32-x64-msvc": {
+ "version": "1.7.6",
+ "resolved": "https://registry.npmjs.org/@rspack/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.7.6.tgz",
+ "integrity": "sha512-zeUxEc0ZaPpmaYlCeWcjSJUPuRRySiSHN23oJ2Xyw0jsQ01Qm4OScPdr0RhEOFuK/UE+ANyRtDo4zJsY52Hadw==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rspack/core": {
+ "version": "1.7.6",
+ "resolved": "https://registry.npmjs.org/@rspack/core/-/core-1.7.6.tgz",
+ "integrity": "sha512-Iax6UhrfZqJajA778c1d5DBFbSIqPOSrI34kpNIiNpWd8Jq7mFIa+Z60SQb5ZQDZuUxcCZikjz5BxinFjTkg7Q==",
+ "license": "MIT",
+ "dependencies": {
+ "@module-federation/runtime-tools": "0.22.0",
+ "@rspack/binding": "1.7.6",
+ "@rspack/lite-tapable": "1.1.0"
+ },
+ "engines": {
+ "node": ">=18.12.0"
+ },
+ "peerDependencies": {
+ "@swc/helpers": ">=0.5.1"
+ },
+ "peerDependenciesMeta": {
+ "@swc/helpers": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rspack/lite-tapable": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@rspack/lite-tapable/-/lite-tapable-1.1.0.tgz",
+ "integrity": "sha512-E2B0JhYFmVAwdDiG14+DW0Di4Ze4Jg10Pc4/lILUrd5DRCaklduz2OvJ5HYQ6G+hd+WTzqQb3QnDNfK4yvAFYw==",
+ "license": "MIT"
+ },
+ "node_modules/@rspack/plugin-react-refresh": {
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/@rspack/plugin-react-refresh/-/plugin-react-refresh-1.6.1.tgz",
+ "integrity": "sha512-eqqW5645VG3CzGzFgNg5HqNdHVXY+567PGjtDhhrM8t67caxmsSzRmT5qfoEIfBcGgFkH9vEg7kzXwmCYQdQDw==",
+ "license": "MIT",
+ "dependencies": {
+ "error-stack-parser": "^2.1.4",
+ "html-entities": "^2.6.0"
+ },
+ "peerDependencies": {
+ "react-refresh": ">=0.10.0 <1.0.0",
+ "webpack-hot-middleware": "2.x"
+ },
+ "peerDependenciesMeta": {
+ "webpack-hot-middleware": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@tybys/wasm-util": {
+ "version": "0.10.2",
+ "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz",
+ "integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@types/dom-mediacapture-transform": {
+ "version": "0.1.11",
+ "resolved": "https://registry.npmjs.org/@types/dom-mediacapture-transform/-/dom-mediacapture-transform-0.1.11.tgz",
+ "integrity": "sha512-Y2p+nGf1bF2XMttBnsVPHUWzRRZzqUoJAKmiP10b5umnO6DDrWI0BrGDJy1pOHoOULVmGSfFNkQrAlC5dcj6nQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/dom-webcodecs": "*"
+ }
+ },
+ "node_modules/@types/dom-webcodecs": {
+ "version": "0.1.13",
+ "resolved": "https://registry.npmjs.org/@types/dom-webcodecs/-/dom-webcodecs-0.1.13.tgz",
+ "integrity": "sha512-O5hkiFIcjjszPIYyUSyvScyvrBoV3NOEEZx/pMlsu44TKzWNkLVBBxnxJz42in5n3QIolYOcBYFCPZZ0h8SkwQ==",
+ "license": "MIT"
+ },
+ "node_modules/@types/eslint": {
+ "version": "9.6.1",
+ "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz",
+ "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree": "*",
+ "@types/json-schema": "*"
+ }
+ },
+ "node_modules/@types/eslint-scope": {
+ "version": "3.7.7",
+ "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz",
+ "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/eslint": "*",
+ "@types/estree": "*"
+ }
+ },
+ "node_modules/@types/estree": {
+ "version": "1.0.9",
+ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz",
+ "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==",
+ "license": "MIT"
+ },
+ "node_modules/@types/json-schema": {
+ "version": "7.0.15",
+ "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
+ "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
+ "license": "MIT"
+ },
+ "node_modules/@types/node": {
+ "version": "25.9.1",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.1.tgz",
+ "integrity": "sha512-xfrlY7UD5rMJk3ZVJP8BNzS28J36YJg+xp+LPXV1TdWxr8uMH5A860QNxYDGQe/ylDSgjxE52Q9VnO7p75tJxg==",
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": ">=7.24.0 <7.24.7"
+ }
+ },
+ "node_modules/@types/react": {
+ "version": "19.2.0",
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.0.tgz",
+ "integrity": "sha512-1LOH8xovvsKsCBq1wnT4ntDUdCJKmnEakhsuoUSy6ExlHCkGP2hqnatagYTgFk6oeL0VU31u7SNjunPN+GchtA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "csstype": "^3.0.2"
+ }
+ },
+ "node_modules/@webassemblyjs/ast": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz",
+ "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@webassemblyjs/helper-numbers": "1.13.2",
+ "@webassemblyjs/helper-wasm-bytecode": "1.13.2"
+ }
+ },
+ "node_modules/@webassemblyjs/floating-point-hex-parser": {
+ "version": "1.13.2",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz",
+ "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==",
+ "license": "MIT"
+ },
+ "node_modules/@webassemblyjs/helper-api-error": {
+ "version": "1.13.2",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz",
+ "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==",
+ "license": "MIT"
+ },
+ "node_modules/@webassemblyjs/helper-buffer": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz",
+ "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==",
+ "license": "MIT"
+ },
+ "node_modules/@webassemblyjs/helper-numbers": {
+ "version": "1.13.2",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz",
+ "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==",
+ "license": "MIT",
+ "dependencies": {
+ "@webassemblyjs/floating-point-hex-parser": "1.13.2",
+ "@webassemblyjs/helper-api-error": "1.13.2",
+ "@xtuc/long": "4.2.2"
+ }
+ },
+ "node_modules/@webassemblyjs/helper-wasm-bytecode": {
+ "version": "1.13.2",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz",
+ "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==",
+ "license": "MIT"
+ },
+ "node_modules/@webassemblyjs/helper-wasm-section": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz",
+ "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==",
+ "license": "MIT",
+ "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"
+ }
+ },
+ "node_modules/@webassemblyjs/ieee754": {
+ "version": "1.13.2",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz",
+ "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==",
+ "license": "MIT",
+ "dependencies": {
+ "@xtuc/ieee754": "^1.2.0"
+ }
+ },
+ "node_modules/@webassemblyjs/leb128": {
+ "version": "1.13.2",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz",
+ "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@xtuc/long": "4.2.2"
+ }
+ },
+ "node_modules/@webassemblyjs/utf8": {
+ "version": "1.13.2",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz",
+ "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==",
+ "license": "MIT"
+ },
+ "node_modules/@webassemblyjs/wasm-edit": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz",
+ "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==",
+ "license": "MIT",
+ "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"
+ }
+ },
+ "node_modules/@webassemblyjs/wasm-gen": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz",
+ "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==",
+ "license": "MIT",
+ "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"
+ }
+ },
+ "node_modules/@webassemblyjs/wasm-opt": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz",
+ "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==",
+ "license": "MIT",
+ "dependencies": {
+ "@webassemblyjs/ast": "1.14.1",
+ "@webassemblyjs/helper-buffer": "1.14.1",
+ "@webassemblyjs/wasm-gen": "1.14.1",
+ "@webassemblyjs/wasm-parser": "1.14.1"
+ }
+ },
+ "node_modules/@webassemblyjs/wasm-parser": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz",
+ "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==",
+ "license": "MIT",
+ "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"
+ }
+ },
+ "node_modules/@webassemblyjs/wast-printer": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz",
+ "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==",
+ "license": "MIT",
+ "dependencies": {
+ "@webassemblyjs/ast": "1.14.1",
+ "@xtuc/long": "4.2.2"
+ }
+ },
+ "node_modules/@xtuc/ieee754": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz",
+ "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==",
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/@xtuc/long": {
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz",
+ "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==",
+ "license": "Apache-2.0"
+ },
+ "node_modules/acorn": {
+ "version": "8.16.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz",
+ "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==",
+ "license": "MIT",
+ "bin": {
+ "acorn": "bin/acorn"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/acorn-import-phases": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz",
+ "integrity": "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=10.13.0"
+ },
+ "peerDependencies": {
+ "acorn": "^8.14.0"
+ }
+ },
+ "node_modules/ajv": {
+ "version": "8.20.0",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz",
+ "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==",
+ "license": "MIT",
+ "dependencies": {
+ "fast-deep-equal": "^3.1.3",
+ "fast-uri": "^3.0.1",
+ "json-schema-traverse": "^1.0.0",
+ "require-from-string": "^2.0.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/ajv-formats": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz",
+ "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==",
+ "license": "MIT",
+ "dependencies": {
+ "ajv": "^8.0.0"
+ },
+ "peerDependencies": {
+ "ajv": "^8.0.0"
+ },
+ "peerDependenciesMeta": {
+ "ajv": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/ajv-keywords": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz",
+ "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==",
+ "license": "MIT",
+ "dependencies": {
+ "fast-deep-equal": "^3.1.3"
+ },
+ "peerDependencies": {
+ "ajv": "^8.8.2"
+ }
+ },
+ "node_modules/ast-types": {
+ "version": "0.16.1",
+ "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.16.1.tgz",
+ "integrity": "sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==",
+ "license": "MIT",
+ "dependencies": {
+ "tslib": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/baseline-browser-mapping": {
+ "version": "2.10.32",
+ "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.32.tgz",
+ "integrity": "sha512-wbPvpyjJPC0zdfdKXxqEL3Ea+bOMD/87X4lftiJkkaBiuG6ALQy1SLmEd7BSmVCuwCQsBrCamgBoLyfFDD1EPg==",
+ "license": "Apache-2.0",
+ "bin": {
+ "baseline-browser-mapping": "dist/cli.cjs"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/browserslist": {
+ "version": "4.28.2",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz",
+ "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==",
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "baseline-browser-mapping": "^2.10.12",
+ "caniuse-lite": "^1.0.30001782",
+ "electron-to-chromium": "^1.5.328",
+ "node-releases": "^2.0.36",
+ "update-browserslist-db": "^1.2.3"
+ },
+ "bin": {
+ "browserslist": "cli.js"
+ },
+ "engines": {
+ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
+ }
+ },
+ "node_modules/buffer-from": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
+ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
+ "license": "MIT"
+ },
+ "node_modules/caniuse-lite": {
+ "version": "1.0.30001793",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001793.tgz",
+ "integrity": "sha512-iwSsYWaCOoh26cV8NwNRViHlrfUvYsHDfRVcbtmw0Kg6PJIZZXwMkj1442FYLBGkeUf1juAsU3DTfxW579mrPA==",
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "CC-BY-4.0"
+ },
+ "node_modules/chrome-trace-event": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz",
+ "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.0"
+ }
+ },
+ "node_modules/commander": {
+ "version": "2.20.3",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
+ "license": "MIT"
+ },
+ "node_modules/cross-spawn": {
+ "version": "7.0.6",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
+ "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
+ "license": "MIT",
+ "dependencies": {
+ "path-key": "^3.1.0",
+ "shebang-command": "^2.0.0",
+ "which": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/css-loader": {
+ "version": "7.1.4",
+ "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-7.1.4.tgz",
+ "integrity": "sha512-vv3J9tlOl04WjiMvHQI/9tmIrCxVrj6PFbHemBB1iihpeRbi/I4h033eoFIhwxBBqLhI0KYFS7yvynBFhIZfTw==",
+ "license": "MIT",
+ "dependencies": {
+ "icss-utils": "^5.1.0",
+ "postcss": "^8.4.40",
+ "postcss-modules-extract-imports": "^3.1.0",
+ "postcss-modules-local-by-default": "^4.0.5",
+ "postcss-modules-scope": "^3.2.0",
+ "postcss-modules-values": "^4.0.0",
+ "postcss-value-parser": "^4.2.0",
+ "semver": "^7.6.3"
+ },
+ "engines": {
+ "node": ">= 18.12.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/webpack"
+ },
+ "peerDependencies": {
+ "@rspack/core": "0.x || ^1.0.0 || ^2.0.0-0",
+ "webpack": "^5.27.0"
+ },
+ "peerDependenciesMeta": {
+ "@rspack/core": {
+ "optional": true
+ },
+ "webpack": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/css-loader/node_modules/semver": {
+ "version": "7.8.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz",
+ "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==",
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/cssesc": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
+ "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
+ "license": "MIT",
+ "bin": {
+ "cssesc": "bin/cssesc"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/csstype": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
+ "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/define-lazy-prop": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz",
+ "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/dotenv": {
+ "version": "17.3.1",
+ "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.3.1.tgz",
+ "integrity": "sha512-IO8C/dzEb6O3F9/twg6ZLXz164a2fhTnEWb95H23Dm4OuN+92NmEAlTrupP9VW6Jm3sO26tQlqyvyi4CsnY9GA==",
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://dotenvx.com"
+ }
+ },
+ "node_modules/electron-to-chromium": {
+ "version": "1.5.363",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.363.tgz",
+ "integrity": "sha512-VjUKPyWzGnT1fujlkEGC/BvN70Hh70KXtAqcmniXviYlJC/ivcT+BWGPyxWVbJZLfvtKR6dqg1L7T7pgAMBtWA==",
+ "license": "ISC"
+ },
+ "node_modules/enhanced-resolve": {
+ "version": "5.22.0",
+ "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.22.0.tgz",
+ "integrity": "sha512-xYcDWrpELkFzz9SpZ3PlI6Eu6eD93Yf0WLDRxikGhWJ3MAir2SNZTIVCVZqZ/NUyx8AdMc2gT9C0gPiw18kG+A==",
+ "license": "MIT",
+ "dependencies": {
+ "graceful-fs": "^4.2.4",
+ "tapable": "^2.3.3"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/error-stack-parser": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz",
+ "integrity": "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==",
+ "license": "MIT",
+ "dependencies": {
+ "stackframe": "^1.3.4"
+ }
+ },
+ "node_modules/es-module-lexer": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.1.0.tgz",
+ "integrity": "sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==",
+ "license": "MIT"
+ },
+ "node_modules/esbuild": {
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.0.tgz",
+ "integrity": "sha512-sNR9MHpXSUV/XB4zmsFKN+QgVG82Cc7+/aaxJ8Adi8hyOac+EXptIp45QBPaVyX3N70664wRbTcLTOemCAnyqw==",
+ "hasInstallScript": true,
+ "license": "MIT",
+ "bin": {
+ "esbuild": "bin/esbuild"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "optionalDependencies": {
+ "@esbuild/aix-ppc64": "0.28.0",
+ "@esbuild/android-arm": "0.28.0",
+ "@esbuild/android-arm64": "0.28.0",
+ "@esbuild/android-x64": "0.28.0",
+ "@esbuild/darwin-arm64": "0.28.0",
+ "@esbuild/darwin-x64": "0.28.0",
+ "@esbuild/freebsd-arm64": "0.28.0",
+ "@esbuild/freebsd-x64": "0.28.0",
+ "@esbuild/linux-arm": "0.28.0",
+ "@esbuild/linux-arm64": "0.28.0",
+ "@esbuild/linux-ia32": "0.28.0",
+ "@esbuild/linux-loong64": "0.28.0",
+ "@esbuild/linux-mips64el": "0.28.0",
+ "@esbuild/linux-ppc64": "0.28.0",
+ "@esbuild/linux-riscv64": "0.28.0",
+ "@esbuild/linux-s390x": "0.28.0",
+ "@esbuild/linux-x64": "0.28.0",
+ "@esbuild/netbsd-arm64": "0.28.0",
+ "@esbuild/netbsd-x64": "0.28.0",
+ "@esbuild/openbsd-arm64": "0.28.0",
+ "@esbuild/openbsd-x64": "0.28.0",
+ "@esbuild/openharmony-arm64": "0.28.0",
+ "@esbuild/sunos-x64": "0.28.0",
+ "@esbuild/win32-arm64": "0.28.0",
+ "@esbuild/win32-ia32": "0.28.0",
+ "@esbuild/win32-x64": "0.28.0"
+ }
+ },
+ "node_modules/escalade": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
+ "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/eslint-scope": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
+ "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "esrecurse": "^4.3.0",
+ "estraverse": "^4.1.1"
+ },
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
+ "node_modules/esprima": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
+ "license": "BSD-2-Clause",
+ "bin": {
+ "esparse": "bin/esparse.js",
+ "esvalidate": "bin/esvalidate.js"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/esrecurse": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
+ "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "estraverse": "^5.2.0"
+ },
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/esrecurse/node_modules/estraverse": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+ "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/estraverse": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
+ "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/events": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
+ "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.8.x"
+ }
+ },
+ "node_modules/execa": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz",
+ "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==",
+ "license": "MIT",
+ "dependencies": {
+ "cross-spawn": "^7.0.3",
+ "get-stream": "^6.0.0",
+ "human-signals": "^2.1.0",
+ "is-stream": "^2.0.0",
+ "merge-stream": "^2.0.0",
+ "npm-run-path": "^4.0.1",
+ "onetime": "^5.1.2",
+ "signal-exit": "^3.0.3",
+ "strip-final-newline": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sindresorhus/execa?sponsor=1"
+ }
+ },
+ "node_modules/fast-deep-equal": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
+ "license": "MIT"
+ },
+ "node_modules/fast-uri": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.2.tgz",
+ "integrity": "sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/fastify"
+ },
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/fastify"
+ }
+ ],
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/fs-monkey": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.3.tgz",
+ "integrity": "sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q==",
+ "license": "Unlicense"
+ },
+ "node_modules/get-stream": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz",
+ "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/glob-to-regexp": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz",
+ "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==",
+ "license": "BSD-2-Clause"
+ },
+ "node_modules/graceful-fs": {
+ "version": "4.2.11",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
+ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
+ "license": "ISC"
+ },
+ "node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/html-entities": {
+ "version": "2.6.0",
+ "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.6.0.tgz",
+ "integrity": "sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/mdevils"
+ },
+ {
+ "type": "patreon",
+ "url": "https://patreon.com/mdevils"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/human-signals": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
+ "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==",
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=10.17.0"
+ }
+ },
+ "node_modules/icss-utils": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz",
+ "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==",
+ "license": "ISC",
+ "engines": {
+ "node": "^10 || ^12 || >= 14"
+ },
+ "peerDependencies": {
+ "postcss": "^8.1.0"
+ }
+ },
+ "node_modules/is-docker": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz",
+ "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==",
+ "license": "MIT",
+ "bin": {
+ "is-docker": "cli.js"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/is-stream": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
+ "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/is-wsl": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz",
+ "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==",
+ "license": "MIT",
+ "dependencies": {
+ "is-docker": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/isexe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
+ "license": "ISC"
+ },
+ "node_modules/jest-worker": {
+ "version": "27.5.1",
+ "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz",
+ "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*",
+ "merge-stream": "^2.0.0",
+ "supports-color": "^8.0.0"
+ },
+ "engines": {
+ "node": ">= 10.13.0"
+ }
+ },
+ "node_modules/json-parse-even-better-errors": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
+ "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
+ "license": "MIT"
+ },
+ "node_modules/json-schema-traverse": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+ "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+ "license": "MIT"
+ },
+ "node_modules/kleur": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz",
+ "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/loader-runner": {
+ "version": "4.3.2",
+ "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.2.tgz",
+ "integrity": "sha512-DFEqQ3ihfS9blba08cLfYf1NRAIEm+dDjic073DRDc3/JspI/8wYmtDsHwd3+4hwvdxSK7PGaElfTmm0awWJ4w==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.11.5"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/webpack"
+ }
+ },
+ "node_modules/lodash.sortby": {
+ "version": "4.7.0",
+ "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz",
+ "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==",
+ "license": "MIT"
+ },
+ "node_modules/lru-cache": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+ "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+ "license": "ISC",
+ "dependencies": {
+ "yallist": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/mediabunny": {
+ "version": "1.45.0",
+ "resolved": "https://registry.npmjs.org/mediabunny/-/mediabunny-1.45.0.tgz",
+ "integrity": "sha512-oK3sMMYbucoF6LUX62L/2M9d+p9ve6KDQgL87kNfhsB0/XmTe9iRLUcgQgg9Gpgvi8Sb96zYfOUL6i17y0bdNg==",
+ "license": "MPL-2.0",
+ "workspaces": [
+ ".",
+ "packages/*"
+ ],
+ "dependencies": {
+ "@types/dom-mediacapture-transform": "^0.1.11",
+ "@types/dom-webcodecs": "0.1.13"
+ },
+ "funding": {
+ "type": "individual",
+ "url": "https://github.com/sponsors/Vanilagy"
+ }
+ },
+ "node_modules/memfs": {
+ "version": "3.4.3",
+ "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.4.3.tgz",
+ "integrity": "sha512-eivjfi7Ahr6eQTn44nvTnR60e4a1Fs1Via2kCR5lHo/kyNoiMWaXCNJ/GpSd0ilXas2JSOl9B5FTIhflXu0hlg==",
+ "license": "Unlicense",
+ "dependencies": {
+ "fs-monkey": "1.0.3"
+ },
+ "engines": {
+ "node": ">= 4.0.0"
+ }
+ },
+ "node_modules/merge-stream": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
+ "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
+ "license": "MIT"
+ },
+ "node_modules/mime-db": {
+ "version": "1.52.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+ "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mime-types": {
+ "version": "2.1.35",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+ "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+ "license": "MIT",
+ "dependencies": {
+ "mime-db": "1.52.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mimic-fn": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
+ "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/minimist": {
+ "version": "1.2.6",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
+ "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==",
+ "license": "MIT"
+ },
+ "node_modules/nanoid": {
+ "version": "3.3.12",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz",
+ "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "bin": {
+ "nanoid": "bin/nanoid.cjs"
+ },
+ "engines": {
+ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+ }
+ },
+ "node_modules/neo-async": {
+ "version": "2.6.2",
+ "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
+ "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
+ "license": "MIT"
+ },
+ "node_modules/node-releases": {
+ "version": "2.0.46",
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.46.tgz",
+ "integrity": "sha512-GYVXHE2KnrzAfsAjl4uP++evGFCrAU1jta4ubEjIG7YWt/64Gqv66a30yKwWczVjA6j3bM4nBwH7Pk1JmDHaxQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/npm-run-path": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
+ "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==",
+ "license": "MIT",
+ "dependencies": {
+ "path-key": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/onetime": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
+ "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
+ "license": "MIT",
+ "dependencies": {
+ "mimic-fn": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/open": {
+ "version": "8.4.2",
+ "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz",
+ "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==",
+ "license": "MIT",
+ "dependencies": {
+ "define-lazy-prop": "^2.0.0",
+ "is-docker": "^2.1.1",
+ "is-wsl": "^2.2.0"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/path-key": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/picocolors": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
+ "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
+ "license": "ISC"
+ },
+ "node_modules/postcss": {
+ "version": "8.5.15",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz",
+ "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==",
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/postcss"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "nanoid": "^3.3.12",
+ "picocolors": "^1.1.1",
+ "source-map-js": "^1.2.1"
+ },
+ "engines": {
+ "node": "^10 || ^12 || >=14"
+ }
+ },
+ "node_modules/postcss-modules-extract-imports": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz",
+ "integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==",
+ "license": "ISC",
+ "engines": {
+ "node": "^10 || ^12 || >= 14"
+ },
+ "peerDependencies": {
+ "postcss": "^8.1.0"
+ }
+ },
+ "node_modules/postcss-modules-local-by-default": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.2.0.tgz",
+ "integrity": "sha512-5kcJm/zk+GJDSfw+V/42fJ5fhjL5YbFDl8nVdXkJPLLW+Vf9mTD5Xe0wqIaDnLuL2U6cDNpTr+UQ+v2HWIBhzw==",
+ "license": "MIT",
+ "dependencies": {
+ "icss-utils": "^5.0.0",
+ "postcss-selector-parser": "^7.0.0",
+ "postcss-value-parser": "^4.1.0"
+ },
+ "engines": {
+ "node": "^10 || ^12 || >= 14"
+ },
+ "peerDependencies": {
+ "postcss": "^8.1.0"
+ }
+ },
+ "node_modules/postcss-modules-scope": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.1.tgz",
+ "integrity": "sha512-m9jZstCVaqGjTAuny8MdgE88scJnCiQSlSrOWcTQgM2t32UBe+MUmFSO5t7VMSfAf/FJKImAxBav8ooCHJXCJA==",
+ "license": "ISC",
+ "dependencies": {
+ "postcss-selector-parser": "^7.0.0"
+ },
+ "engines": {
+ "node": "^10 || ^12 || >= 14"
+ },
+ "peerDependencies": {
+ "postcss": "^8.1.0"
+ }
+ },
+ "node_modules/postcss-modules-values": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz",
+ "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==",
+ "license": "ISC",
+ "dependencies": {
+ "icss-utils": "^5.0.0"
+ },
+ "engines": {
+ "node": "^10 || ^12 || >= 14"
+ },
+ "peerDependencies": {
+ "postcss": "^8.1.0"
+ }
+ },
+ "node_modules/postcss-selector-parser": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz",
+ "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==",
+ "license": "MIT",
+ "dependencies": {
+ "cssesc": "^3.0.0",
+ "util-deprecate": "^1.0.2"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/postcss-value-parser": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
+ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
+ "license": "MIT"
+ },
+ "node_modules/prettier": {
+ "version": "3.8.1",
+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz",
+ "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==",
+ "license": "MIT",
+ "bin": {
+ "prettier": "bin/prettier.cjs"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/prettier/prettier?sponsor=1"
+ }
+ },
+ "node_modules/prompts": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz",
+ "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==",
+ "license": "MIT",
+ "dependencies": {
+ "kleur": "^3.0.3",
+ "sisteransi": "^1.0.5"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/punycode": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
+ "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/react": {
+ "version": "19.2.0",
+ "resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz",
+ "integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/react-dom": {
+ "version": "19.2.0",
+ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz",
+ "integrity": "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==",
+ "license": "MIT",
+ "dependencies": {
+ "scheduler": "^0.27.0"
+ },
+ "peerDependencies": {
+ "react": "^19.2.0"
+ }
+ },
+ "node_modules/react-refresh": {
+ "version": "0.18.0",
+ "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.18.0.tgz",
+ "integrity": "sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/recast": {
+ "version": "0.23.11",
+ "resolved": "https://registry.npmjs.org/recast/-/recast-0.23.11.tgz",
+ "integrity": "sha512-YTUo+Flmw4ZXiWfQKGcwwc11KnoRAYgzAE2E7mXKCjSviTKShtxBsN6YUUBB2gtaBzKzeKunxhUwNHQuRryhWA==",
+ "license": "MIT",
+ "dependencies": {
+ "ast-types": "^0.16.1",
+ "esprima": "~4.0.0",
+ "source-map": "~0.6.1",
+ "tiny-invariant": "^1.3.3",
+ "tslib": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "node_modules/recast/node_modules/source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/remotion": {
+ "version": "4.0.468",
+ "resolved": "https://registry.npmjs.org/remotion/-/remotion-4.0.468.tgz",
+ "integrity": "sha512-TPfoy8XZgKDgZDRseAiLpWfLUdix3+d6pL7eh9myPBW2ajdb6tAPzTd9BBKMp/9j+Ajpc5DZVqKuGQPHmBkGQA==",
+ "license": "SEE LICENSE IN LICENSE.md",
+ "peerDependencies": {
+ "react": ">=16.8.0",
+ "react-dom": ">=16.8.0"
+ }
+ },
+ "node_modules/require-from-string": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
+ "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/scheduler": {
+ "version": "0.27.0",
+ "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz",
+ "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==",
+ "license": "MIT"
+ },
+ "node_modules/schema-utils": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz",
+ "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/json-schema": "^7.0.9",
+ "ajv": "^8.9.0",
+ "ajv-formats": "^2.1.1",
+ "ajv-keywords": "^5.1.0"
+ },
+ "engines": {
+ "node": ">= 10.13.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/webpack"
+ }
+ },
+ "node_modules/semver": {
+ "version": "7.5.3",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz",
+ "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==",
+ "license": "ISC",
+ "dependencies": {
+ "lru-cache": "^6.0.0"
+ },
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/shebang-command": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+ "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+ "license": "MIT",
+ "dependencies": {
+ "shebang-regex": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/shebang-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/signal-exit": {
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
+ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
+ "license": "ISC"
+ },
+ "node_modules/sisteransi": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
+ "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==",
+ "license": "MIT"
+ },
+ "node_modules/source-map": {
+ "version": "0.8.0-beta.0",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz",
+ "integrity": "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==",
+ "deprecated": "The work that was done in this beta branch won't be included in future versions",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "whatwg-url": "^7.0.0"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/source-map-js": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
+ "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/source-map-support": {
+ "version": "0.5.21",
+ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
+ "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
+ "license": "MIT",
+ "dependencies": {
+ "buffer-from": "^1.0.0",
+ "source-map": "^0.6.0"
+ }
+ },
+ "node_modules/source-map-support/node_modules/source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/stackframe": {
+ "version": "1.3.4",
+ "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz",
+ "integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==",
+ "license": "MIT"
+ },
+ "node_modules/strip-final-newline": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz",
+ "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/style-loader": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-4.0.0.tgz",
+ "integrity": "sha512-1V4WqhhZZgjVAVJyt7TdDPZoPBPNHbekX4fWnCJL1yQukhCeZhJySUL+gL9y6sNdN95uEOS83Y55SqHcP7MzLA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 18.12.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/webpack"
+ },
+ "peerDependencies": {
+ "webpack": "^5.27.0"
+ }
+ },
+ "node_modules/supports-color": {
+ "version": "8.1.1",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
+ "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
+ "license": "MIT",
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/supports-color?sponsor=1"
+ }
+ },
+ "node_modules/tapable": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz",
+ "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/webpack"
+ }
+ },
+ "node_modules/terser": {
+ "version": "5.48.0",
+ "resolved": "https://registry.npmjs.org/terser/-/terser-5.48.0.tgz",
+ "integrity": "sha512-J/9An6vs9Us6wKRriSFXBWdRZapREHqFzdNUKk0pmu804EMR6dr6winwo7e5JDxN4xahxQsuysyYFwlwj4XN/Q==",
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "@jridgewell/source-map": "^0.3.3",
+ "acorn": "^8.15.0",
+ "commander": "^2.20.0",
+ "source-map-support": "~0.5.20"
+ },
+ "bin": {
+ "terser": "bin/terser"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/terser-webpack-plugin": {
+ "version": "5.6.1",
+ "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.6.1.tgz",
+ "integrity": "sha512-201R5j+sJpK8nFWwKVyNfZot8FaJbLZDq5evriVzbV1wDtSXDjRUDRfJzHpAaxFDMEhsZL1QkeqM61wgsS3KaQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/trace-mapping": "^0.3.25",
+ "jest-worker": "^27.4.5",
+ "schema-utils": "^4.3.0",
+ "terser": "^5.31.1"
+ },
+ "engines": {
+ "node": ">= 10.13.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/webpack"
+ },
+ "peerDependencies": {
+ "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
+ }
+ }
+ },
+ "node_modules/tiny-invariant": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz",
+ "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==",
+ "license": "MIT"
+ },
+ "node_modules/to-fast-properties": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
+ "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/tr46": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz",
+ "integrity": "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==",
+ "license": "MIT",
+ "dependencies": {
+ "punycode": "^2.1.0"
+ }
+ },
+ "node_modules/tslib": {
+ "version": "2.8.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
+ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
+ "license": "0BSD"
+ },
+ "node_modules/typescript": {
+ "version": "5.7.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz",
+ "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=14.17"
+ }
+ },
+ "node_modules/undici-types": {
+ "version": "7.24.6",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.24.6.tgz",
+ "integrity": "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==",
+ "license": "MIT"
+ },
+ "node_modules/update-browserslist-db": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz",
+ "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==",
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "escalade": "^3.2.0",
+ "picocolors": "^1.1.1"
+ },
+ "bin": {
+ "update-browserslist-db": "cli.js"
+ },
+ "peerDependencies": {
+ "browserslist": ">= 4.21.0"
+ }
+ },
+ "node_modules/util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
+ "license": "MIT"
+ },
+ "node_modules/watchpack": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.5.1.tgz",
+ "integrity": "sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==",
+ "license": "MIT",
+ "dependencies": {
+ "glob-to-regexp": "^0.4.1",
+ "graceful-fs": "^4.1.2"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/webidl-conversions": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz",
+ "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==",
+ "license": "BSD-2-Clause"
+ },
+ "node_modules/webpack": {
+ "version": "5.105.0",
+ "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.105.0.tgz",
+ "integrity": "sha512-gX/dMkRQc7QOMzgTe6KsYFM7DxeIONQSui1s0n/0xht36HvrgbxtM1xBlgx596NbpHuQU8P7QpKwrZYwUX48nw==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/eslint-scope": "^3.7.7",
+ "@types/estree": "^1.0.8",
+ "@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.15.0",
+ "acorn-import-phases": "^1.0.3",
+ "browserslist": "^4.28.1",
+ "chrome-trace-event": "^1.0.2",
+ "enhanced-resolve": "^5.19.0",
+ "es-module-lexer": "^2.0.0",
+ "eslint-scope": "5.1.1",
+ "events": "^3.2.0",
+ "glob-to-regexp": "^0.4.1",
+ "graceful-fs": "^4.2.11",
+ "json-parse-even-better-errors": "^2.3.1",
+ "loader-runner": "^4.3.1",
+ "mime-types": "^2.1.27",
+ "neo-async": "^2.6.2",
+ "schema-utils": "^4.3.3",
+ "tapable": "^2.3.0",
+ "terser-webpack-plugin": "^5.3.16",
+ "watchpack": "^2.5.1",
+ "webpack-sources": "^3.3.3"
+ },
+ "bin": {
+ "webpack": "bin/webpack.js"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/webpack"
+ },
+ "peerDependenciesMeta": {
+ "webpack-cli": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/webpack-sources": {
+ "version": "3.5.0",
+ "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.5.0.tgz",
+ "integrity": "sha512-HPuy+uuoTCaaoEoI1LQ3JN9+vrPBvEesnnX1jADHy728cHSMlq4wUc4afYqahq2B1mhQVZxCXOkNTnXltr+2vQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/whatwg-url": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz",
+ "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==",
+ "license": "MIT",
+ "dependencies": {
+ "lodash.sortby": "^4.7.0",
+ "tr46": "^1.0.1",
+ "webidl-conversions": "^4.0.2"
+ }
+ },
+ "node_modules/which": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+ "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+ "license": "ISC",
+ "dependencies": {
+ "isexe": "^2.0.0"
+ },
+ "bin": {
+ "node-which": "bin/node-which"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/ws": {
+ "version": "8.20.1",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.1.tgz",
+ "integrity": "sha512-It4dO0K5v//JtTXuPkfEOaI3uUN87iYPnqo/ZzqCoG3g8uhA66QUMs/SrM0YK7/NAu+r4LMh/9dq2A7k+rHs+w==",
+ "license": "MIT",
+ "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
+ }
+ }
+ },
+ "node_modules/yallist": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
+ "license": "ISC"
+ },
+ "node_modules/zod": {
+ "version": "4.3.6",
+ "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz",
+ "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/colinhacks"
+ }
+ }
+ }
+}
diff --git a/remotion/package.json b/remotion/package.json
new file mode 100644
index 0000000..ecacb19
--- /dev/null
+++ b/remotion/package.json
@@ -0,0 +1,22 @@
+{
+ "name": "@ado2/higgsfield-remotion",
+ "version": "0.1.0",
+ "private": true,
+ "description": "ADO2 Higgsfield Shorts — Remotion 자막·타이틀 오버레이 합성",
+ "scripts": {
+ "studio": "remotion studio",
+ "render": "remotion render MumumShort out/mumum-poc2-final.mp4",
+ "upgrade": "remotion upgrade"
+ },
+ "dependencies": {
+ "@remotion/cli": "4.0.468",
+ "@remotion/google-fonts": "4.0.468",
+ "remotion": "4.0.468",
+ "react": "19.2.0",
+ "react-dom": "19.2.0"
+ },
+ "devDependencies": {
+ "@types/react": "19.2.0",
+ "typescript": "5.7.3"
+ }
+}
diff --git a/remotion/public/mumum_marketing_v1.mp4 b/remotion/public/mumum_marketing_v1.mp4
new file mode 100644
index 0000000..04c27f7
Binary files /dev/null and b/remotion/public/mumum_marketing_v1.mp4 differ
diff --git a/remotion/remotion.config.ts b/remotion/remotion.config.ts
new file mode 100644
index 0000000..a0087e8
--- /dev/null
+++ b/remotion/remotion.config.ts
@@ -0,0 +1,6 @@
+import { Config } from "@remotion/cli/config";
+
+Config.setVideoImageFormat("jpeg");
+Config.setOverwriteOutput(true);
+// H.264 + AAC, 모바일 9:16 Shorts/Reels 호환
+Config.setCodec("h264");
diff --git a/remotion/src/MumumShort.tsx b/remotion/src/MumumShort.tsx
new file mode 100644
index 0000000..c9484bc
--- /dev/null
+++ b/remotion/src/MumumShort.tsx
@@ -0,0 +1,58 @@
+import React from "react";
+import { AbsoluteFill, OffthreadVideo, Sequence, staticFile } from "remotion";
+import { ShortProps } from "./data/types";
+import { HookTitle } from "./components/HookTitle";
+import { BrandLines } from "./components/BrandLines";
+import { SellingBadge } from "./components/SellingBadge";
+import { EndCard } from "./components/EndCard";
+
+// Higgsfield 완성본을 배경으로 깔고(오디오 포함), 자막/타이틀만 오버레이.
+// 모든 콘텐츠는 props로 주입 (펜션/제품마다 교체).
+export const MumumShort: React.FC = ({
+ videoSrc,
+ hook,
+ sellingPoint,
+ brandLines,
+ endCard,
+}) => {
+ return (
+
+
+
+ {/* 상단 후킹 타이틀 */}
+
+
+
+
+ {/* 셀링포인트: 3개 독립 박스 */}
+
+
+ {/* 브랜드 감성 2줄 (상단 중앙) */}
+
+
+ {/* 엔드카드 + AI 디스클로저 */}
+
+
+ );
+};
diff --git a/remotion/src/Root.tsx b/remotion/src/Root.tsx
new file mode 100644
index 0000000..85499b5
--- /dev/null
+++ b/remotion/src/Root.tsx
@@ -0,0 +1,25 @@
+import React from "react";
+import { Composition } from "remotion";
+import { MumumShort } from "./MumumShort";
+import { defaultProps } from "./data/mumum";
+
+export const RemotionRoot: React.FC = () => {
+ return (
+ ({
+ durationInFrames: props.durationInFrames,
+ fps: props.fps,
+ width: props.width,
+ height: props.height,
+ })}
+ />
+ );
+};
diff --git a/remotion/src/components/BrandLines.tsx b/remotion/src/components/BrandLines.tsx
new file mode 100644
index 0000000..9712e17
--- /dev/null
+++ b/remotion/src/components/BrandLines.tsx
@@ -0,0 +1,63 @@
+import React from "react";
+import { useCurrentFrame, interpolate, AbsoluteFill } from "remotion";
+import { serifFont } from "../fonts";
+
+// 브랜드 감성 2줄: 우상단 통일 위치에 한 덩어리로 쌓아 노출.
+// 첫 줄 먼저, 둘째 줄 살짝 뒤따라 등장 → 같은 자리에서 읽힘.
+export const BrandLines: React.FC<{
+ lines: string[];
+ fromFrame: number;
+ toFrame: number;
+}> = ({ lines, fromFrame, toFrame }) => {
+ const frame = useCurrentFrame();
+ const LINE_STAGGER = 18; // 줄 간 등장 간격(frame)
+
+ return (
+
+ {lines.map((line, i) => {
+ const start = fromFrame + i * LINE_STAGGER;
+ // interpolate는 배열이 단조증가해야 한다.
+ // 영상이 짧아 toFrame 이 start+24 이하로 내려오면 범위가 뒤집혀 크래시 발생.
+ const fadeIn = start + 12;
+ const fadeOut = Math.max(fadeIn + 1, toFrame - 12);
+ const end = Math.max(fadeOut + 1, toFrame);
+ const opacity = interpolate(
+ frame,
+ [start, fadeIn, fadeOut, end],
+ [0, 1, 1, 0],
+ { extrapolateLeft: "clamp", extrapolateRight: "clamp" },
+ );
+ const rise = interpolate(frame, [start, start + 16], [16, 0], {
+ extrapolateLeft: "clamp",
+ extrapolateRight: "clamp",
+ });
+ return (
+
+ {line}
+
+ );
+ })}
+
+ );
+};
diff --git a/remotion/src/components/EndCard.tsx b/remotion/src/components/EndCard.tsx
new file mode 100644
index 0000000..f61cd92
--- /dev/null
+++ b/remotion/src/components/EndCard.tsx
@@ -0,0 +1,91 @@
+import React from "react";
+import {
+ useCurrentFrame,
+ useVideoConfig,
+ interpolate,
+ spring,
+ AbsoluteFill,
+} from "remotion";
+import { serifFont } from "../fonts";
+
+// 엔드카드: 브랜드 + 위치 + AI 디스클로저 (가드레일 필수)
+export const EndCard: React.FC<{
+ brand: string;
+ location: string;
+ disclosure: string;
+ fromFrame: number;
+}> = ({ brand, location, disclosure, fromFrame }) => {
+ const frame = useCurrentFrame();
+ const { fps } = useVideoConfig();
+
+ const appear = interpolate(frame, [fromFrame, fromFrame + 12], [0, 1], {
+ extrapolateLeft: "clamp",
+ extrapolateRight: "clamp",
+ });
+ const brandSpring = spring({
+ frame: frame - fromFrame,
+ fps,
+ config: { damping: 200, mass: 0.5 },
+ });
+ const brandScale = interpolate(brandSpring, [0, 1], [0.92, 1]);
+
+ return (
+
+
+
+ {brand}
+
+
+ {location}
+
+
+
+ {disclosure}
+
+
+ );
+};
diff --git a/remotion/src/components/HookTitle.tsx b/remotion/src/components/HookTitle.tsx
new file mode 100644
index 0000000..8eba087
--- /dev/null
+++ b/remotion/src/components/HookTitle.tsx
@@ -0,0 +1,93 @@
+import React from "react";
+import {
+ useCurrentFrame,
+ useVideoConfig,
+ interpolate,
+ spring,
+ AbsoluteFill,
+} from "remotion";
+import { hookFont } from "../fonts";
+
+export const HookTitle: React.FC<{
+ eyebrow: string;
+ title: string;
+ fromFrame: number;
+ toFrame: number;
+}> = ({ eyebrow, title, fromFrame, toFrame }) => {
+ const frame = useCurrentFrame();
+ const { fps } = useVideoConfig();
+
+ // 스프링 슬라이드-다운 등장
+ const enter = spring({
+ frame: frame - fromFrame,
+ fps,
+ config: { damping: 200, mass: 0.6 },
+ });
+ const translateY = interpolate(enter, [0, 1], [-60, 0]);
+ // 퇴장 페이드
+ const fadeIn = fromFrame + 8;
+ const fadeOut = Math.max(fadeIn + 1, toFrame - 12);
+ const end = Math.max(fadeOut + 1, toFrame);
+ const opacity = interpolate(
+ frame,
+ [fromFrame, fadeIn, fadeOut, end],
+ [0, 1, 1, 0],
+ { extrapolateLeft: "clamp", extrapolateRight: "clamp" },
+ );
+
+ return (
+
+ {/* 상단 가독성 그라데이션 */}
+
+
+
+ {eyebrow}
+
+
+ {title}
+
+
+
+ );
+};
diff --git a/remotion/src/components/SellingBadge.tsx b/remotion/src/components/SellingBadge.tsx
new file mode 100644
index 0000000..9b99046
--- /dev/null
+++ b/remotion/src/components/SellingBadge.tsx
@@ -0,0 +1,72 @@
+import React from "react";
+import {
+ useCurrentFrame,
+ useVideoConfig,
+ interpolate,
+ spring,
+ AbsoluteFill,
+} from "remotion";
+import { serifFont } from "../fonts";
+
+// 셀링포인트: 3개 독립 pill 박스를 세로로 쌓고 순차 등장.
+// 컬러 지양 → 반투명 다크 pill + 흰색 텍스트. 앞 구간 단독 노출(시선 집중).
+export const SellingBadge: React.FC<{
+ items: string[];
+ fromFrame: number;
+ toFrame: number;
+}> = ({ items, fromFrame, toFrame }) => {
+ const frame = useCurrentFrame();
+ const { fps } = useVideoConfig();
+ const STAGGER = 9; // 박스 간 등장 간격(frame)
+
+ return (
+
+ {items.map((item, i) => {
+ const start = fromFrame + i * STAGGER;
+ const enter = spring({
+ frame: frame - start,
+ fps,
+ config: { damping: 200, mass: 0.5 },
+ });
+ const rise = interpolate(enter, [0, 1], [22, 0]);
+ const fadeIn = start + 8;
+ const fadeOut = Math.max(fadeIn + 1, toFrame - 10);
+ const end = Math.max(fadeOut + 1, toFrame);
+ const appear = interpolate(
+ frame,
+ [start, fadeIn, fadeOut, end],
+ [0, 1, 1, 0],
+ { extrapolateLeft: "clamp", extrapolateRight: "clamp" },
+ );
+ return (
+
+ {item}
+
+ );
+ })}
+
+ );
+};
diff --git a/remotion/src/components/Subtitle.tsx b/remotion/src/components/Subtitle.tsx
new file mode 100644
index 0000000..aa09d86
--- /dev/null
+++ b/remotion/src/components/Subtitle.tsx
@@ -0,0 +1,53 @@
+import React from "react";
+import {
+ useCurrentFrame,
+ interpolate,
+ AbsoluteFill,
+} from "remotion";
+import { serifFont } from "../fonts";
+
+// 브랜드 자막: 페이드 + 미세 상승 (Profile A 모션 프리셋)
+export const Subtitle: React.FC<{
+ text: string;
+ fromFrame: number;
+ toFrame: number;
+}> = ({ text, fromFrame, toFrame }) => {
+ const frame = useCurrentFrame();
+
+ const opacity = interpolate(
+ frame,
+ [fromFrame, fromFrame + 10, toFrame - 10, toFrame],
+ [0, 1, 1, 0],
+ { extrapolateLeft: "clamp", extrapolateRight: "clamp" },
+ );
+ const rise = interpolate(frame, [fromFrame, fromFrame + 18], [18, 0], {
+ extrapolateLeft: "clamp",
+ extrapolateRight: "clamp",
+ });
+
+ return (
+
+
+ {text}
+
+
+ );
+};
diff --git a/remotion/src/data/mumum.ts b/remotion/src/data/mumum.ts
new file mode 100644
index 0000000..ad44444
--- /dev/null
+++ b/remotion/src/data/mumum.ts
@@ -0,0 +1,35 @@
+// Default props = the verified 머뭄 PoC #2 layout.
+// The Python render bridge overrides these per-job via --props.
+import { ShortProps } from "./types";
+
+export const defaultProps: ShortProps = {
+ videoSrc: "mumum_marketing_v1.mp4",
+ fps: 30,
+ width: 720,
+ height: 1280,
+ durationInFrames: 241, // ≈ 8.04s
+
+ hook: {
+ eyebrow: "아무도 모르는 군산",
+ title: "골목 안, 단 한 채의 독채 스테이 머뭄",
+ fromFrame: 0,
+ toFrame: 78,
+ },
+ sellingPoint: {
+ items: ["프라이빗 독채펜션", "넓은 정원", "핵심 관광지 가까이"],
+ fromFrame: 80,
+ toFrame: 138,
+ },
+ brandLines: {
+ lines: ["머무는 시간이", "다르게 흐르는 곳"],
+ fromFrame: 138,
+ toFrame: 196,
+ },
+ endCard: {
+ brand: "Stay, 머뭄",
+ location: "전북 군산시 절골길 18",
+ disclosure: "실제 사진 기반, AI 카메라 효과를 적용한 영상입니다.",
+ fromFrame: 192,
+ toFrame: 241,
+ },
+};
diff --git a/remotion/src/data/types.ts b/remotion/src/data/types.ts
new file mode 100644
index 0000000..bcc7c26
--- /dev/null
+++ b/remotion/src/data/types.ts
@@ -0,0 +1,19 @@
+// Props contract — shared by Remotion composition and the Python render bridge.
+// Mirrors server/app/schemas.py VideoSpec (+ video config + timings).
+export type ShortProps = {
+ videoSrc: string; // file in public/ (staticFile name)
+ fps: number;
+ width: number;
+ height: number;
+ durationInFrames: number;
+ hook: { eyebrow: string; title: string; fromFrame: number; toFrame: number };
+ sellingPoint: { items: string[]; fromFrame: number; toFrame: number };
+ brandLines: { lines: string[]; fromFrame: number; toFrame: number };
+ endCard: {
+ brand: string;
+ location: string;
+ disclosure: string;
+ fromFrame: number;
+ toFrame: number;
+ };
+};
diff --git a/remotion/src/fonts.ts b/remotion/src/fonts.ts
new file mode 100644
index 0000000..383b303
--- /dev/null
+++ b/remotion/src/fonts.ts
@@ -0,0 +1,21 @@
+// 한글 폰트 로딩 (@remotion/google-fonts, korean subset)
+// Hook = Black Han Sans (굵고 강렬한 바이럴 헤드라인)
+// Body/Brand = Nanum Myeongjo (우아한 명조 — 머뭄의 정적 브랜드 톤)
+//
+// 주의: korean subset 자체가 unicode-range 파일이 많아 요청 수가 많다.
+// weights 를 최소화(NanumMyeongjo는 400/700만 실제 존재)해 요청 수를 줄임.
+// latin 서브셋 제거 — 콘텐츠가 한국어 전용이므로 불필요.
+import { loadFont as loadHook } from "@remotion/google-fonts/BlackHanSans";
+import { loadFont as loadSerif } from "@remotion/google-fonts/NanumMyeongjo";
+
+export const hookFont = loadHook("normal", {
+ weights: ["400"],
+ subsets: ["korean"],
+ ignoreTooManyRequestsWarning: true,
+}).fontFamily;
+
+export const serifFont = loadSerif("normal", {
+ weights: ["400", "700"], // 800은 NanumMyeongjo에 없음 → 제거
+ subsets: ["korean"],
+ ignoreTooManyRequestsWarning: true,
+}).fontFamily;
diff --git a/remotion/src/index.ts b/remotion/src/index.ts
new file mode 100644
index 0000000..f31c790
--- /dev/null
+++ b/remotion/src/index.ts
@@ -0,0 +1,4 @@
+import { registerRoot } from "remotion";
+import { RemotionRoot } from "./Root";
+
+registerRoot(RemotionRoot);
diff --git a/remotion/tsconfig.json b/remotion/tsconfig.json
new file mode 100644
index 0000000..fea0181
--- /dev/null
+++ b/remotion/tsconfig.json
@@ -0,0 +1,15 @@
+{
+ "compilerOptions": {
+ "target": "ES2020",
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
+ "module": "ESNext",
+ "moduleResolution": "Bundler",
+ "jsx": "react-jsx",
+ "strict": true,
+ "esModuleInterop": true,
+ "skipLibCheck": true,
+ "forceConsistentCasingInFileNames": true,
+ "noEmit": true
+ },
+ "include": ["src"]
+}
diff --git a/src/App.tsx b/src/App.tsx
index 2a5ad82..6b8d7f5 100755
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -358,32 +358,6 @@ const App: React.FC = () => {
}
};
- // 테스트 데이터로 브랜드 분석 페이지 이동
- const handleTestData = (data: CrawlingResponse) => {
- const tagged = { ...data, _isTestData: true };
- setAnalysisData(tagged);
- localStorage.setItem(ANALYSIS_DATA_KEY, JSON.stringify(tagged));
- setViewMode('analysis');
- };
-
- // 언어 변경 시 테스트 데이터 다시 로드
- useEffect(() => {
- const saved = localStorage.getItem(ANALYSIS_DATA_KEY);
- if (!saved) return;
- try {
- const parsed = JSON.parse(saved);
- if (!parsed._isTestData) return;
- const jsonFile = i18n.language === 'en' ? '/example_analysis_en.json' : '/example_analysis.json';
- fetch(jsonFile)
- .then(res => res.json())
- .then((data: CrawlingResponse) => {
- const tagged = { ...data, _isTestData: true };
- setAnalysisData(tagged);
- localStorage.setItem(ANALYSIS_DATA_KEY, JSON.stringify(tagged));
- })
- .catch(err => console.error('Failed to reload test data:', err));
- } catch { /* ignore */ }
- }, [i18n.language]);
const handleToLogin = async () => {
// 이미 로그인된 상태면 바로 generation_flow로 이동
@@ -504,12 +478,8 @@ const App: React.FC = () => {
scrollToSection(1)}
- error={error}
scrollProgress={scrollProgress}
/>
diff --git a/src/components/SearchInputForm.tsx b/src/components/SearchInputForm.tsx
index e616416..f488572 100644
--- a/src/components/SearchInputForm.tsx
+++ b/src/components/SearchInputForm.tsx
@@ -24,6 +24,7 @@ interface SearchInputFormProps {
onManualInput?: (businessName: string, address: string) => void;
/** 직접입력 버튼 클릭 시 기본 동작(모달 열기)을 대체합니다. 제공 시 모달을 직접 관리해야 합니다. */
onManualButtonClick?: () => void;
+ onShortform?: () => void;
error?: string | null;
}
@@ -32,6 +33,7 @@ const SearchInputForm: React.FC = ({
onAutocomplete,
onManualInput,
onManualButtonClick,
+ onShortform,
error: externalError,
}) => {
const { t } = useTranslation();
@@ -68,6 +70,7 @@ const SearchInputForm: React.FC = ({
const searchTypeOptions = [
{ value: 'url' as SearchType, label: 'URL' },
{ value: 'name' as SearchType, label: t('landing.hero.searchTypeBusinessName') },
+ { value: 'manual' as SearchType, label: t('landing.hero.searchTypeManual') },
];
const getPlaceholder = () =>
@@ -196,8 +199,12 @@ const SearchInputForm: React.FC = ({
type="button"
className={`hero-dropdown-item ${searchType === option.value ? 'active' : ''}`}
onClick={() => {
- setSearchType(option.value);
setIsDropdownOpen(false);
+ if (option.value === 'manual') {
+ handleManualButtonClick();
+ } else {
+ setSearchType(option.value);
+ }
}}
>
{option.label}
@@ -321,9 +328,19 @@ const SearchInputForm: React.FC = ({
{t('landing.hero.analyzeButton')}
-
+ {onShortform && (
+
+ )}
{/* onManualButtonClick 미제공 시 모달을 내부에서 관리 */}
{!onManualButtonClick && isManualModalOpen && (
diff --git a/src/components/SocialPostingModal.tsx b/src/components/SocialPostingModal.tsx
index 486f377..5321306 100644
--- a/src/components/SocialPostingModal.tsx
+++ b/src/components/SocialPostingModal.tsx
@@ -157,6 +157,7 @@ const SocialPostingModal: React.FC = ({
const [uploadVideoTitle, setUploadVideoTitle] = useState('');
const [uploadChannelName, setUploadChannelName] = useState('');
const [uploadIsScheduled, setUploadIsScheduled] = useState(false);
+ const [uploadScheduledAt, setUploadScheduledAt] = useState(null);
// 드롭다운 외부 클릭 시 닫기
useEffect(() => {
@@ -373,6 +374,7 @@ const SocialPostingModal: React.FC = ({
// 예약 업로드: 폴링 없이 바로 완료 처리
setUploadStatus('completed');
setUploadProgress(100);
+ setUploadScheduledAt(uploadResponse.scheduled_at ?? null);
onClose();
resetForm();
} else {
@@ -432,6 +434,7 @@ const SocialPostingModal: React.FC = ({
setUploadVideoTitle('');
setUploadChannelName('');
setUploadIsScheduled(false);
+ setUploadScheduledAt(null);
};
const handleClose = () => {
@@ -461,6 +464,7 @@ const SocialPostingModal: React.FC = ({
youtubeUrl={uploadYoutubeUrl}
errorMessage={uploadErrorMessage}
isScheduled={uploadIsScheduled}
+ scheduledAt={uploadScheduledAt}
onGoToCalendar={onGoToCalendar}
/>
);
diff --git a/src/components/Tutorial/tutorialSteps.ts b/src/components/Tutorial/tutorialSteps.ts
index 0633fd7..40299b3 100644
--- a/src/components/Tutorial/tutorialSteps.ts
+++ b/src/components/Tutorial/tutorialSteps.ts
@@ -45,44 +45,7 @@ export const TUTORIAL_PAGE_GROUPS: string[][] = [
export const tutorialSteps: TutorialStepDef[] = [
{
key: TUTORIAL_KEYS.LANDING,
- hints: [
- {
- targetSelector: '.hero-dropdown-trigger',
- titleKey: 'tutorial.landing.dropdown.title',
- descriptionKey: 'tutorial.landing.dropdown.desc',
- position: 'top',
- clickToAdvance: false,
- noSpotlight: true,
- variant: 'bubble',
- },
- {
- targetSelector: '.hero-input-wrapper',
- titleKey: 'tutorial.landing.field.title',
- descriptionKey: 'tutorial.landing.field.desc',
- position: 'top',
- clickToAdvance: false,
- noSpotlight: true,
- variant: 'bubble',
- },
- {
- targetSelector: '.hero-manual-button',
- titleKey: 'tutorial.landing.manual.title',
- descriptionKey: 'tutorial.landing.manual.desc',
- position: 'bottom',
- clickToAdvance: false,
- noSpotlight: true,
- variant: 'bubble',
- },
- {
- targetSelector: '.hero-button',
- titleKey: 'tutorial.landing.button.title',
- descriptionKey: 'tutorial.landing.button.desc',
- position: 'bottom',
- clickToAdvance: true,
- noSpotlight: true,
- variant: 'bubble',
- },
- ],
+ hints: [],
},
{
key: TUTORIAL_KEYS.ASSET,
diff --git a/src/components/UploadProgressModal.tsx b/src/components/UploadProgressModal.tsx
index 8572619..8aec55a 100644
--- a/src/components/UploadProgressModal.tsx
+++ b/src/components/UploadProgressModal.tsx
@@ -14,6 +14,7 @@ interface UploadProgressModalProps {
youtubeUrl?: string;
errorMessage?: string;
isScheduled?: boolean;
+ scheduledAt?: string | null;
onGoToCalendar?: () => void;
}
@@ -27,6 +28,7 @@ const UploadProgressModal: React.FC = ({
youtubeUrl,
errorMessage,
isScheduled = false,
+ scheduledAt,
onGoToCalendar,
}) => {
const { t } = useTranslation();
@@ -148,6 +150,28 @@ const UploadProgressModal: React.FC = ({
{t('upload.viewOnYoutube')}
)}
+
+ {/* Scheduled conflict notice */}
+ {status === 'completed' && isScheduled && scheduledAt && (
+
+
+
+ {t('upload.scheduleConflict', {
+ time: new Date(scheduledAt).toLocaleString('ko-KR', {
+ year: 'numeric',
+ month: 'long',
+ day: 'numeric',
+ hour: '2-digit',
+ minute: '2-digit',
+ }),
+ })}
+
+
+ )}
{/* Footer */}
diff --git a/src/locales/en.json b/src/locales/en.json
index a6393c5..35f4434 100644
--- a/src/locales/en.json
+++ b/src/locales/en.json
@@ -154,7 +154,8 @@
"confirm": "OK",
"close": "Close",
"doNotClose": "Upload is in progress. Do not close this window.",
- "goToCalendar": "View in Calendar"
+ "goToCalendar": "View in Calendar",
+ "scheduleConflict": "Schedule adjusted to {{time}} due to a conflict."
},
"landing": {
"hero": {
diff --git a/src/locales/ko.json b/src/locales/ko.json
index 26a79ed..9ce0d77 100644
--- a/src/locales/ko.json
+++ b/src/locales/ko.json
@@ -154,7 +154,8 @@
"confirm": "확인",
"close": "닫기",
"doNotClose": "업로드가 진행 중입니다. 창을 닫지 마세요.",
- "goToCalendar": "캘린더에서 확인"
+ "goToCalendar": "캘린더에서 확인",
+ "scheduleConflict": "예약 시간이 충돌하여 {{time}}으로 조정되었습니다."
},
"landing": {
"hero": {
diff --git a/src/pages/Dashboard/GenerationFlow.tsx b/src/pages/Dashboard/GenerationFlow.tsx
index 2c5dc23..b38f447 100755
--- a/src/pages/Dashboard/GenerationFlow.tsx
+++ b/src/pages/Dashboard/GenerationFlow.tsx
@@ -2,6 +2,7 @@
import React, { useCallback, useEffect, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
import Sidebar from '../../components/Sidebar';
+import ShortformContent from './ShortformContent';
import AssetManagementContent from './AssetManagementContent';
import SoundStudioContent from './SoundStudioContent';
import CompletionContent from './CompletionContent';
@@ -54,6 +55,7 @@ interface GenerationFlowProps {
initialImageList?: string[];
businessInfo?: BusinessInfo;
initialAnalysisData?: CrawlingResponse | null;
+ initialShortform?: boolean;
}
// 위저드 단계:
@@ -69,7 +71,8 @@ const GenerationFlow: React.FC = ({
initialActiveItem = '대시보드',
initialImageList = [],
businessInfo,
- initialAnalysisData
+ initialAnalysisData,
+ initialShortform = false,
}) => {
const { t, i18n } = useTranslation();
// localStorage에서 저장된 상태 복원
@@ -94,6 +97,9 @@ const GenerationFlow: React.FC = ({
// 초기 위저드 단계 결정
const getInitialWizardStep = (): number => {
+ // 숏폼 진입 플래그가 있으면 숏폼 화면(-3)으로 바로
+ if (initialShortform) return -3;
+
if (savedWizardStep !== null) {
const step = parseInt(savedWizardStep, 10);
// 분석 데이터가 있는데 URL 입력(-2) 또는 로딩(-1) 단계로 저장된 경우:
@@ -289,37 +295,6 @@ const GenerationFlow: React.FC = ({
};
// 테스트용 랜덤 m_id 생성 (99 ~ 300)
- const generateRandomMId = (): number => {
- return Math.floor(Math.random() * (300 - 99 + 1)) + 99;
- };
-
- // 테스트 데이터로 브랜드 분석 페이지 이동
- const handleTestData = (data: CrawlingResponse) => {
- const tagged = { ...data, m_id: generateRandomMId(), _isTestData: true };
- setAnalysisData(tagged);
- localStorage.setItem(ANALYSIS_DATA_KEY, JSON.stringify(tagged));
- goToWizardStep(0); // 브랜드 분석 결과로
- };
-
- // 언어 변경 시 테스트 데이터 다시 로드
- useEffect(() => {
- const saved = localStorage.getItem(ANALYSIS_DATA_KEY);
- if (!saved) return;
- try {
- const parsed = JSON.parse(saved);
- if (!parsed._isTestData) return;
- const jsonFile = i18n.language === 'en' ? '/example_analysis_en.json' : '/example_analysis.json';
- fetch(jsonFile)
- .then(res => res.json())
- .then((data: CrawlingResponse) => {
- // 언어 변경 시에는 기존 m_id 유지
- const tagged = { ...data, m_id: parsed.m_id || generateRandomMId(), _isTestData: true };
- setAnalysisData(tagged);
- localStorage.setItem(ANALYSIS_DATA_KEY, JSON.stringify(tagged));
- })
- .catch(err => console.error('Failed to reload test data:', err));
- } catch { /* ignore */ }
- }, [i18n.language]);
// URL 분석 시작
const handleStartAnalysis = async (url: string) => {
@@ -432,6 +407,13 @@ const GenerationFlow: React.FC = ({
// 새 프로젝트 만들기 - 단계별 컨텐츠 렌더링
const renderWizardContent = () => {
switch (wizardStep) {
+ case -3:
+ // 숏폼 생성 단계
+ return (
+
+ );
case -2:
// URL 입력 단계
return (
@@ -439,7 +421,7 @@ const GenerationFlow: React.FC = ({
onAnalyze={handleStartAnalysis}
onAutocomplete={handleAutocomplete}
onManualInput={handleManualInput}
- onTestData={handleTestData}
+onShortform={() => goToWizardStep(-3)}
error={analysisError}
/>
);
@@ -551,8 +533,8 @@ const GenerationFlow: React.FC = ({
case '내 정보':
return ;
case '새 프로젝트 만들기':
- // 브랜드 분석(0)과 로딩(-1)은 전체 화면으로 표시
- if (wizardStep === 0 || wizardStep === -1) {
+ // 브랜드 분석(0), 로딩(-1), 숏폼(-3)은 전체 화면으로 표시
+ if (wizardStep === 0 || wizardStep === -1 || wizardStep === -3) {
return renderWizardContent();
}
return (
diff --git a/src/pages/Dashboard/ShortformContent.tsx b/src/pages/Dashboard/ShortformContent.tsx
new file mode 100644
index 0000000..6d1a39f
--- /dev/null
+++ b/src/pages/Dashboard/ShortformContent.tsx
@@ -0,0 +1,478 @@
+import React, { useRef, useState } from 'react';
+import { uploadImages, generateShortform, waitForShortformComplete, previewShortform } from '../../utils/api';
+import { ShortformStatusResponse, VideoSpec } from '../../types/api';
+
+type Kind = 'place' | 'product' | 'message';
+type Step = 1 | 2 | 3 | 4;
+
+interface ShortformContentProps {
+ onComplete?: () => void;
+}
+
+const KIND_OPTIONS: { value: Kind; label: string; desc: string }[] = [
+ { value: 'place', label: '장소', desc: '펜션·카페·식당·매장 등 공간' },
+ { value: 'product', label: '물건', desc: '제품, 음식 등 시각적인 아이템' },
+ { value: 'message', label: '메시지', desc: '축하·안부·홍보 등' },
+];
+
+const STEP_META = [
+ { label: '사진 업로드', sub: '4~5장' },
+ { label: '정보 입력', sub: '몇 가지만 답하기' },
+ { label: '영상 생성', sub: 'AI 카메라 + 자막' },
+ { label: '완성', sub: '다운로드' },
+];
+
+const MIN_PHOTOS = 4;
+const MIN_PHOTOS_LABEL = `${MIN_PHOTOS}장`;
+
+const ShortformContent: React.FC = ({ onComplete }) => {
+ const fileInputRef = useRef(null);
+ const dropRef = useRef(null);
+
+ // 단계
+ const [step, setStep] = useState(1);
+
+ // Step 1 — 사진
+ const [files, setFiles] = useState([]);
+ const [previews, setPreviews] = useState([]);
+
+ // Step 2 — 폼
+ const [kind, setKind] = useState('place');
+ const [bizName, setBizName] = useState('');
+ const [selling, setSelling] = useState('');
+ const [addr, setAddr] = useState('');
+ const [price, setPrice] = useState('');
+
+ // Step 3/4 — 생성 상태
+ const [statusMsg, setStatusMsg] = useState('');
+ const [result, setResult] = useState(null);
+ const [errorMsg, setErrorMsg] = useState('');
+
+ // 자막 미리보기
+ const [preview, setPreview] = useState(null);
+ const [previewLoading, setPreviewLoading] = useState(false);
+ const [previewError, setPreviewError] = useState('');
+
+ // --- 사진 관리 ---
+ const addFiles = (newFiles: File[]) => {
+ const images = newFiles.filter(f => f.type.startsWith('image/'));
+ if (!images.length) return;
+ const newUrls = images.map(f => URL.createObjectURL(f));
+ setFiles(prev => [...prev, ...images]);
+ setPreviews(prev => [...prev, ...newUrls]);
+ };
+
+ const removeFile = (index: number) => {
+ URL.revokeObjectURL(previews[index]);
+ setFiles(prev => prev.filter((_, i) => i !== index));
+ setPreviews(prev => prev.filter((_, i) => i !== index));
+ };
+
+ const handleDragOver = (e: React.DragEvent) => { e.preventDefault(); };
+ const handleDrop = (e: React.DragEvent) => {
+ e.preventDefault();
+ addFiles(Array.from(e.dataTransfer.files));
+ };
+
+ // --- 미리보기 필드 수정 ---
+ const patchPreview = (updater: (prev: NonNullable) => NonNullable) => {
+ setPreview(prev => prev ? updater(prev) : prev);
+ };
+
+ // --- 자막 미리보기 ---
+ const handlePreview = async () => {
+ if (!selling.trim()) return;
+ setPreviewLoading(true);
+ setPreviewError('');
+ try {
+ const spec = await previewShortform({
+ kind,
+ biz_name: bizName.trim(),
+ selling: selling.trim(),
+ addr: addr.trim() || undefined,
+ price: price.trim() || undefined,
+ });
+ setPreview(spec);
+ } catch (err) {
+ setPreviewError(err instanceof Error ? err.message : '미리보기 생성에 실패했습니다.');
+ } finally {
+ setPreviewLoading(false);
+ }
+ };
+
+ // --- 다운로드 ---
+ const [isDownloading, setIsDownloading] = useState(false);
+ const handleDownload = async (url: string) => {
+ if (isDownloading) return;
+ setIsDownloading(true);
+ try {
+ const resp = await fetch(url);
+ const blob = await resp.blob();
+ const blobUrl = URL.createObjectURL(blob);
+ const link = document.createElement('a');
+ link.href = blobUrl;
+ link.download = `${bizName || 'shortform'}.mp4`;
+ document.body.appendChild(link);
+ link.click();
+ document.body.removeChild(link);
+ URL.revokeObjectURL(blobUrl);
+ } catch {
+ const link = document.createElement('a');
+ link.href = url;
+ link.download = `${bizName || 'shortform'}.mp4`;
+ link.target = '_blank';
+ document.body.appendChild(link);
+ link.click();
+ document.body.removeChild(link);
+ } finally {
+ setIsDownloading(false);
+ }
+ };
+
+ // --- 생성 실행 ---
+ const handleGenerate = async () => {
+ setStep(3);
+ setErrorMsg('');
+ setResult(null);
+ try {
+ setStatusMsg('사진 업로드 중...');
+ const uploadResp = await uploadImages([], files);
+
+ setStatusMsg('영상 생성 요청 중...');
+ await generateShortform({
+ task_id: uploadResp.task_id,
+ kind,
+ biz_name: bizName.trim(),
+ addr: addr.trim() || undefined,
+ price: price.trim() || undefined,
+ selling: selling.trim(),
+ spec: preview ?? undefined,
+ dry_run: true,
+ });
+
+ setStatusMsg('AI 카메라 무브·자막 렌더링 중...');
+ const statusResp = await waitForShortformComplete(uploadResp.task_id, s => {
+ setStatusMsg(s === 'processing' ? 'AI 카메라 무브·자막 렌더링 중...' : s);
+ });
+
+ setResult(statusResp);
+ setStep(4);
+ onComplete?.();
+ } catch (err) {
+ setErrorMsg(err instanceof Error ? err.message : '생성 중 오류가 발생했습니다.');
+ setStep(2);
+ }
+ };
+
+ const step1Valid = files.length >= MIN_PHOTOS;
+ const step2Valid = bizName.trim() && selling.trim();
+
+ // ===================== 렌더 =====================
+
+ // 스텝 인디케이터
+ const StepBar = () => (
+
+ {STEP_META.map((s, i) => {
+ const n = (i + 1) as Step;
+ const done = step > n;
+ const active = step === n;
+ return (
+
+
+
+ {s.label}
+ {s.sub}
+
+
+ );
+ })}
+
+ );
+
+ // ---- Step 1: 사진 업로드 ----
+ if (step === 1) return (
+
+
+
+
사진 몇 장과 한마디면, 8초 홍보 영상이 됩니다
+
복잡한 분석 없이 — 사진을 올리고 몇 가지만 답하면, AI 카메라 무브와 자막을 입힌 세로형 숏폼이 완성됩니다.
+
+
+
+
+
+
사진 업로드
+
홍보할 장소나 물건 사진 4~5장. 전경 1장·디테일 2~3장을 섞으면 영상의 서사가 살아납니다.
+
+
fileInputRef.current?.click()}
+ onDragOver={handleDragOver}
+ onDrop={handleDrop}
+ >
+
+
여기로 사진을 끌어다 놓거나 클릭
+
JPG·PNG·{MIN_PHOTOS_LABEL} 이상
+
+
{ addFiles(Array.from(e.target.files || [])); e.target.value = ''; }} />
+
+ {previews.length > 0 && (
+
+ {previews.map((url, i) => (
+
+
{i + 1}
+

+
+
+ ))}
+
+ )}
+
+
+
+
+
+ {files.length}장
+ {step1Valid
+ ? 업로드됨·준비 완료
+ : {MIN_PHOTOS - files.length}장 더 추가해주세요}
+
+
+
+
+ );
+
+ // ---- Step 2: 정보 입력 ----
+ if (step === 2) return (
+
+
+
+
+
+
몇 가지만 알려주세요
+
사장님·마케터가 가장 잘 아는 정보로 카피를 만듭니다.
+
+ {/* Kind */}
+
+
+
+ {KIND_OPTIONS.map(opt => (
+
+ ))}
+
+
+
+ {/* 업체명 */}
+
+
+ setBizName(e.target.value)}
+ maxLength={50}
+ />
+
+
+ {/* 셀링포인트 */}
+
+
+ {/* 자막 미리보기 */}
+
+
+
+
+
+
위 한 가지를 적은 뒤 누르면, AI가 인트로·셀링포인트·감성 스토리·CTA 4가지를 만들어줍니다.
+ {previewError &&
{previewError}
}
+ {preview && (
+
+
+ 인트로
+ patchPreview(p => ({ ...p, hook: { ...p.hook, eyebrow: e.target.value } }))} />
+ patchPreview(p => ({ ...p, hook: { ...p.hook, title: e.target.value } }))} />
+
+
+
셀링포인트
+
+ {preview.selling_point.items.slice(0, 3).map((item, i) => (
+ patchPreview(p => {
+ const items = [...p.selling_point.items];
+ items[i] = e.target.value;
+ return { ...p, selling_point: { items } };
+ })} />
+ ))}
+
+
+
+ 감성 스토리
+ {preview.brand_lines.slice(0, 2).map((line, i) => (
+ patchPreview(p => {
+ const brand_lines = [...p.brand_lines];
+ brand_lines[i] = e.target.value;
+ return { ...p, brand_lines };
+ })} />
+ ))}
+
+
+ CTA
+ patchPreview(p => ({ ...p, end_card: { ...p.end_card, brand: e.target.value } }))} />
+ patchPreview(p => ({ ...p, end_card: { ...p.end_card, location: e.target.value } }))} />
+
+
+ )}
+
+
+ {/* 주소 */}
+
+
+
setAddr(e.target.value)}
+ maxLength={100}
+ />
+
영상 엔드카드·해시태그에 활용됩니다.
+
+
+ {/* 가격 */}
+
+
+ setPrice(e.target.value)}
+ maxLength={50}
+ />
+
+
+
+
+
+
+
+
+
+ {errorMsg && (
+ {errorMsg}
+ )}
+
+ );
+
+ // ---- Step 3: 생성 중 ----
+ if (step === 3) return (
+
+
+
+
+
+
AI가 영상을 만들고 있어요
+
{statusMsg || 'AI 카메라 무브·자막 렌더링 중...'}
+
보통 1~3분 정도 소요됩니다. 잠시만 기다려주세요.
+
+
+ 사진 업로드
+
+
+ 영상 생성 요청
+
+
+ AI 렌더링
+
+
+
+
+
+ );
+
+ // ---- Step 4: 완성 ----
+ return (
+
+
+
+
+
✓ 영상이 완성됐습니다!
+ {result?.result_url && (
+
+
+
+ )}
+
+ {result?.result_url && (
+
+ )}
+
+
+
+
+
+ );
+};
+
+export default ShortformContent;
diff --git a/src/pages/Dashboard/UrlInputContent.tsx b/src/pages/Dashboard/UrlInputContent.tsx
index c84f547..ec99695 100644
--- a/src/pages/Dashboard/UrlInputContent.tsx
+++ b/src/pages/Dashboard/UrlInputContent.tsx
@@ -1,39 +1,16 @@
-import React, { useState } from 'react';
-import { useTranslation } from 'react-i18next';
+import React from 'react';
import { AutocompleteRequest } from '../../utils/api';
-import { CrawlingResponse } from '../../types/api';
import SearchInputForm, { SearchType } from '../../components/SearchInputForm';
-// 환경변수에서 테스트 모드 확인
-const isTestPage = import.meta.env.VITE_IS_TESTPAGE === 'true';
-
interface UrlInputContentProps {
onAnalyze: (value: string, type?: SearchType) => void;
onAutocomplete?: (data: AutocompleteRequest) => void;
onManualInput?: (businessName: string, address: string) => void;
- onTestData?: (data: CrawlingResponse) => void;
+ onShortform?: () => void;
error: string | null;
}
-const UrlInputContent: React.FC = ({ onAnalyze, onAutocomplete, onManualInput, onTestData, error }) => {
- const { t, i18n } = useTranslation();
- const [isLoadingTest, setIsLoadingTest] = useState(false);
-
- const handleTestData = async () => {
- if (!onTestData) return;
- setIsLoadingTest(true);
- try {
- const jsonFile = i18n.language === 'en' ? '/example_analysis_en.json' : '/example_analysis.json';
- const response = await fetch(jsonFile);
- const data: CrawlingResponse = await response.json();
- onTestData(data);
- } catch (err) {
- console.error('테스트 데이터 로드 실패:', err);
- } finally {
- setIsLoadingTest(false);
- }
- };
-
+const UrlInputContent: React.FC = ({ onAnalyze, onAutocomplete, onManualInput, onShortform, error }) => {
return (
@@ -46,20 +23,10 @@ const UrlInputContent: React.FC = ({ onAnalyze, onAutocomp
onAnalyze={onAnalyze}
onAutocomplete={onAutocomplete}
onManualInput={onManualInput}
+ onShortform={onShortform}
error={error}
/>
-
- {/* 테스트 버튼 (VITE_IS_TESTPAGE=true일 때만 표시) */}
- {isTestPage && onTestData && (
-
- )}
);
};
diff --git a/src/pages/Landing/HeroSection.tsx b/src/pages/Landing/HeroSection.tsx
index e2c9556..c7a1a2c 100755
--- a/src/pages/Landing/HeroSection.tsx
+++ b/src/pages/Landing/HeroSection.tsx
@@ -1,18 +1,4 @@
-
-import React, { useState, useEffect, useRef } from 'react';
-import { useTranslation } from 'react-i18next';
-import { AutocompleteRequest, isLoggedIn } from '../../utils/api';
-import { CrawlingResponse } from '../../types/api';
-import { useTutorial } from '../../components/Tutorial/useTutorial';
-import { TUTORIAL_KEYS } from '../../components/Tutorial/tutorialSteps';
-import TutorialOverlay from '../../components/Tutorial/TutorialOverlay';
-import BusinessNameInputModal from '../../components/BusinessNameInputModal';
-import LoginPromptModal from '../../components/LoginPromptModal';
-import SearchInputForm from '../../components/SearchInputForm';
-import { SearchType } from '../../components/SearchInputForm';
-
-// 환경변수에서 테스트 모드 확인
-const isTestPage = import.meta.env.VITE_IS_TESTPAGE === 'true';
+import React, { useEffect, useRef } from 'react';
// Orb configuration with movement zones to prevent overlap
interface OrbConfig {
@@ -37,50 +23,14 @@ const orbConfigs: OrbConfig[] = [
];
interface HeroSectionProps {
- onAnalyze?: (value: string, type?: SearchType) => void;
- onAutocomplete?: (data: AutocompleteRequest) => void;
- onManualInput?: (businessName: string, address: string) => void;
- onTestData?: (data: CrawlingResponse) => void;
+ onLogin?: () => void;
onNext?: () => void;
- error?: string | null;
scrollProgress?: number;
}
-const HeroSection: React.FC = ({ onAnalyze, onAutocomplete, onManualInput, onTestData, onNext, error: externalError, scrollProgress = 0 }) => {
- const { t, i18n } = useTranslation();
- const [isManualModalOpen, setIsManualModalOpen] = useState(false);
- const [isLoginPromptOpen, setIsLoginPromptOpen] = useState(false);
- const [testError, setTestError] = useState('');
- const [isLoadingTest, setIsLoadingTest] = useState(false);
+const HeroSection: React.FC = ({ onLogin, onNext, scrollProgress = 0 }) => {
const orbRefs = useRef<(HTMLDivElement | null)[]>([]);
const animationRefs = useRef([]);
- const tutorial = useTutorial();
-
- // 첫 방문 시 랜딩 튜토리얼 시작
- useEffect(() => {
- if (!tutorial.hasSeen(TUTORIAL_KEYS.LANDING)) {
- const timer = setTimeout(() => {
- tutorial.startTutorial(TUTORIAL_KEYS.LANDING);
- }, 800);
- return () => clearTimeout(timer);
- }
- }, []);
-
- // 테스트 데이터 로드 핸들러
- const handleTestData = async () => {
- if (!onTestData) return;
- setIsLoadingTest(true);
- try {
- const jsonFile = i18n.language === 'en' ? '/example_analysis_en.json' : '/example_analysis.json';
- const response = await fetch(jsonFile);
- const data: CrawlingResponse = await response.json();
- onTestData(data);
- } catch {
- setTestError(t('landing.hero.testDataLoadFailed'));
- } finally {
- setIsLoadingTest(false);
- }
- };
// Orb 랜덤 이동 애니메이션
useEffect(() => {
@@ -168,63 +118,20 @@ const HeroSection: React.FC = ({ onAnalyze, onAutocomplete, on
className="hero-logo"
/>
- {
- if (isLoggedIn()) {
- setIsManualModalOpen(true);
- } else {
- setIsLoginPromptOpen(true);
- }
- }}
- error={externalError || testError || null}
- />
+
{/* Footer Indicator */}
-
- {/* 테스트 버튼 */}
- {isTestPage && onTestData && (
-
- )}
-
- {tutorial.isActive && !isManualModalOpen && (
-
- )}
-
- {isManualModalOpen && (
- setIsManualModalOpen(false)}
- onSubmit={(businessName, address) => {
- if (tutorial.isActive) tutorial.nextHint();
- setIsManualModalOpen(false);
- onManualInput?.(businessName, address);
- }}
- />
- )}
-
- {isLoginPromptOpen && (
- setIsLoginPromptOpen(false)} />
- )}
);
};
diff --git a/src/types/api.ts b/src/types/api.ts
index c3373e6..0f37e3b 100644
--- a/src/types/api.ts
+++ b/src/types/api.ts
@@ -207,6 +207,58 @@ export interface ImageUploadResponse {
}>;
}
+// 숏폼 생성 요청
+export interface ShortformGenerateRequest {
+ task_id: string;
+ kind: string;
+ biz_name: string;
+ addr?: string;
+ price?: string;
+ selling: string;
+ spec?: VideoSpec;
+ dry_run?: boolean;
+}
+
+// 숏폼 생성 응답
+export interface ShortformGenerateResponse {
+ task_id: string;
+ video_id: number;
+ status: string;
+}
+
+// 숏폼 상태 조회 응답
+export interface ShortformStatusResponse {
+ task_id: string;
+ status: 'processing' | 'completed' | 'failed';
+ result_url: string | null;
+}
+
+// 숏폼 미리보기 요청
+export interface ShortformPreviewRequest {
+ kind: string;
+ biz_name: string;
+ selling: string;
+ addr?: string;
+ price?: string;
+}
+
+// 숏폼 미리보기 응답 (VideoSpec)
+export interface VideoSpec {
+ hook: {
+ eyebrow: string;
+ title: string;
+ };
+ selling_point: {
+ items: string[];
+ };
+ brand_lines: string[];
+ end_card: {
+ brand: string;
+ location: string;
+ };
+ caption: string;
+}
+
// 언어 매핑
export const LANGUAGE_MAP: Record = {
'한국어': 'Korean',
@@ -412,9 +464,11 @@ export interface SocialUploadRequest {
// 소셜 업로드 응답
export interface SocialUploadResponse {
success: boolean;
- upload_id: string;
- status: 'pending' | 'uploading' | 'completed' | 'failed';
+ upload_id: number;
+ platform: string;
+ status: string;
message: string;
+ scheduled_at?: string | null; // 예약 업로드 충돌 시 실제 예약 시간 반환
}
// 소셜 업로드 상태 조회 응답
diff --git a/src/utils/api.ts b/src/utils/api.ts
index 76ec24f..57cc6ec 100644
--- a/src/utils/api.ts
+++ b/src/utils/api.ts
@@ -34,6 +34,11 @@ import {
CommentsResponse,
CommentItem,
LikeToggleResponse,
+ ShortformGenerateRequest,
+ ShortformGenerateResponse,
+ ShortformStatusResponse,
+ ShortformPreviewRequest,
+ VideoSpec,
} from '../types/api';
export const API_URL = import.meta.env.VITE_API_URL || 'http://40.82.133.44';
@@ -557,6 +562,85 @@ export async function waitForVideoComplete(
return poll();
}
+// ============================================
+// 숏폼 생성 API
+// ============================================
+
+// 숏폼 생성 요청 (POST /shortform/generate, 202 Accepted)
+export async function generateShortform(req: ShortformGenerateRequest): Promise {
+ const response = await authenticatedFetch(`${API_URL}/shortform/generate`, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify(req),
+ });
+
+ if (!response.ok) {
+ throw new Error(`HTTP error! status: ${response.status}`);
+ }
+
+ return response.json();
+}
+
+// 숏폼 상태 조회 (GET /shortform/status/{task_id})
+export async function getShortformStatus(taskId: string): Promise {
+ const response = await authenticatedFetch(`${API_URL}/shortform/status/${taskId}`, {
+ method: 'GET',
+ });
+
+ if (!response.ok) {
+ throw new Error(`HTTP error! status: ${response.status}`);
+ }
+
+ return response.json();
+}
+
+// 숏폼 완료까지 폴링 (10분 타임아웃, 3초 간격)
+const SHORTFORM_POLL_TIMEOUT = 10 * 60 * 1000;
+const SHORTFORM_POLL_INTERVAL = 3000;
+
+export async function waitForShortformComplete(
+ taskId: string,
+ onStatusChange?: (status: string) => void
+): Promise {
+ const startTime = Date.now();
+
+ const poll = async (): Promise => {
+ if (Date.now() - startTime > SHORTFORM_POLL_TIMEOUT) {
+ throw new Error('TIMEOUT');
+ }
+
+ const statusResponse = await getShortformStatus(taskId);
+ onStatusChange?.(statusResponse.status);
+
+ if (statusResponse.status === 'completed') {
+ return statusResponse;
+ } else if (statusResponse.status === 'failed') {
+ throw new Error('Shortform generation failed');
+ }
+
+ await new Promise(resolve => setTimeout(resolve, SHORTFORM_POLL_INTERVAL));
+ return poll();
+ };
+
+ return poll();
+}
+
+// 숏폼 자막 미리보기 (POST /shortform/preview)
+export async function previewShortform(req: ShortformPreviewRequest): Promise {
+ const response = await authenticatedFetch(`${API_URL}/shortform/preview`, {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify(req),
+ });
+ if (!response.ok) {
+ const err = await response.json().catch(() => ({}));
+ throw new Error((err as { detail?: string }).detail || '미리보기 생성에 실패했습니다.');
+ }
+ return response.json();
+}
+
// ============================================
// 카카오 인증 API
// ============================================