Changes
This commit is contained in:
@@ -61,41 +61,29 @@ export const useOfflineVideoExport = () => {
|
||||
|
||||
setState(prev => ({ ...prev, stage: 'rendering', progress: 5 }));
|
||||
|
||||
// Load intro video
|
||||
// Load intro video - always use webm
|
||||
console.log('📹 Loading intro video...');
|
||||
const introVideo = document.createElement('video');
|
||||
introVideo.muted = true;
|
||||
introVideo.playsInline = true;
|
||||
introVideo.preload = 'auto';
|
||||
introVideo.src = '/intro.webm';
|
||||
|
||||
// Try webm first, fallback to mp4
|
||||
let introLoaded = false;
|
||||
let introDuration = 0;
|
||||
|
||||
try {
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
introVideo.onloadedmetadata = () => {
|
||||
introDuration = introVideo.duration;
|
||||
console.log(`✅ Intro video loaded: ${introDuration.toFixed(2)}s`);
|
||||
introLoaded = true;
|
||||
resolve();
|
||||
};
|
||||
introVideo.onerror = () => {
|
||||
console.warn('⚠️ Could not load intro.webm, trying intro.mp4');
|
||||
introVideo.src = '/intro.mp4';
|
||||
};
|
||||
introVideo.src = '/intro.webm';
|
||||
|
||||
// Timeout after 5 seconds
|
||||
setTimeout(() => {
|
||||
if (!introLoaded) {
|
||||
console.warn('⚠️ Intro video loading timed out');
|
||||
resolve();
|
||||
}
|
||||
}, 5000);
|
||||
});
|
||||
} catch (introError) {
|
||||
console.warn('⚠️ Could not load intro video:', introError);
|
||||
}
|
||||
// Wait for video to be fully loaded
|
||||
await new Promise<void>((resolve) => {
|
||||
introVideo.onloadeddata = () => {
|
||||
introDuration = introVideo.duration;
|
||||
console.log(`✅ Intro video loaded: ${introDuration.toFixed(2)}s, ${introVideo.videoWidth}x${introVideo.videoHeight}`);
|
||||
resolve();
|
||||
};
|
||||
introVideo.onerror = (e) => {
|
||||
console.error('❌ Failed to load intro video:', e);
|
||||
resolve();
|
||||
};
|
||||
introVideo.load();
|
||||
});
|
||||
|
||||
setState(prev => ({ ...prev, progress: 10 }));
|
||||
|
||||
@@ -215,7 +203,7 @@ export const useOfflineVideoExport = () => {
|
||||
recorder.start(1000); // 1 second chunks
|
||||
|
||||
// Calculate total frames including intro
|
||||
const introFrames = introLoaded ? Math.ceil(introDuration * fps) : 0;
|
||||
const introFrames = introDuration > 0 ? Math.ceil(introDuration * fps) : 0;
|
||||
const mainFrames = Math.ceil(duration * fps);
|
||||
const fadeFrames = Math.ceil(fps * 0.5); // 0.5 second fade
|
||||
const totalFrames = introFrames + mainFrames;
|
||||
@@ -223,22 +211,31 @@ export const useOfflineVideoExport = () => {
|
||||
|
||||
console.log(`🎬 Total frames: ${totalFrames} (intro: ${introFrames}, main: ${mainFrames}, fade: ${fadeFrames})`);
|
||||
|
||||
// Render intro frames first (if loaded)
|
||||
if (introLoaded && introFrames > 0) {
|
||||
// Render intro frames first
|
||||
if (introFrames > 0) {
|
||||
console.log('📹 Rendering intro frames...');
|
||||
introVideo.currentTime = 0;
|
||||
await introVideo.play();
|
||||
|
||||
for (let frameIndex = 0; frameIndex < introFrames; frameIndex++) {
|
||||
if (cancelledRef.current) {
|
||||
introVideo.pause();
|
||||
recorder.stop();
|
||||
setState({ isExporting: false, progress: 0, error: 'Cancelled', stage: 'idle', fps: 0 });
|
||||
return null;
|
||||
}
|
||||
|
||||
// Seek to correct time
|
||||
introVideo.currentTime = frameIndex / fps;
|
||||
// Seek to correct time and wait for frame
|
||||
const targetTime = frameIndex / fps;
|
||||
introVideo.currentTime = targetTime;
|
||||
|
||||
// Wait for the seek to complete
|
||||
await new Promise<void>((resolve) => {
|
||||
const onSeeked = () => {
|
||||
introVideo.removeEventListener('seeked', onSeeked);
|
||||
resolve();
|
||||
};
|
||||
introVideo.addEventListener('seeked', onSeeked);
|
||||
// Fallback timeout
|
||||
setTimeout(resolve, 50);
|
||||
});
|
||||
|
||||
// Draw intro video frame scaled to canvas
|
||||
ctx.fillStyle = '#0a0f0a';
|
||||
@@ -268,7 +265,6 @@ export const useOfflineVideoExport = () => {
|
||||
await new Promise(resolve => setTimeout(resolve, 1000 / fps));
|
||||
}
|
||||
|
||||
introVideo.pause();
|
||||
console.log('✅ Intro frames complete');
|
||||
}
|
||||
|
||||
@@ -338,7 +334,7 @@ export const useOfflineVideoExport = () => {
|
||||
}
|
||||
|
||||
// Apply fade-in effect from intro (first fadeFrames of main content)
|
||||
if (introLoaded && frameIndex < fadeFrames) {
|
||||
if (introDuration > 0 && frameIndex < fadeFrames) {
|
||||
const fadeProgress = frameIndex / fadeFrames;
|
||||
// Draw a semi-transparent black overlay that fades out
|
||||
ctx.fillStyle = `rgba(10, 15, 10, ${1 - fadeProgress})`;
|
||||
|
||||
Reference in New Issue
Block a user