Merge pull request #491 from AmitwalaH/feature/video-playback-fix

Fix video playback initialization and zoom sync
This commit is contained in:
Sid
2026-04-25 09:24:00 -07:00
committed by GitHub
2 changed files with 24 additions and 80 deletions
+20 -76
View File
@@ -184,6 +184,7 @@ const VideoPlayback = forwardRef<VideoPlaybackRef, VideoPlaybackProps>(
const [overlaySize, setOverlaySize] = useState({ width: 800, height: 600 });
const [overlayElement, setOverlayElement] = useState<HTMLDivElement | null>(null);
const overlayRef = useRef<HTMLDivElement | null>(null);
const focusIndicatorRef = useRef<HTMLDivElement | null>(null);
const [webcamLayout, setWebcamLayout] = useState<StyledRenderRect | null>(null);
const [webcamDimensions, setWebcamDimensions] = useState<Size | null>(null);
@@ -368,7 +369,10 @@ const VideoPlayback = forwardRef<VideoPlaybackRef, VideoPlaybackProps>(
if (!vid) return;
try {
allowPlaybackRef.current = true;
await vid.play();
await vid.play().catch((err) => {
console.log("PLAY ERROR:", err);
throw err;
});
} catch (error) {
allowPlaybackRef.current = false;
throw error;
@@ -541,84 +545,24 @@ const VideoPlayback = forwardRef<VideoPlaybackRef, VideoPlaybackProps>(
useEffect(() => {
if (!pixiReady || !videoReady) return;
const el = overlayRef.current;
if (!el) return;
const app = appRef.current;
const cameraContainer = cameraContainerRef.current;
const video = videoRef.current;
// Seed immediately so overlays never start at 800×600
setOverlaySize({ width: el.clientWidth, height: el.clientHeight });
if (!app || !cameraContainer || !video) return;
const tickerWasStarted = app.ticker?.started || false;
if (tickerWasStarted && app.ticker) {
app.ticker.stop();
}
const wasPlaying = !video.paused;
if (wasPlaying) {
video.pause();
}
animationStateRef.current = {
scale: 1,
focusX: DEFAULT_FOCUS.cx,
focusY: DEFAULT_FOCUS.cy,
progress: 0,
x: 0,
y: 0,
appliedScale: 1,
};
// Reset motion blur state for clean transitions
motionBlurStateRef.current = createMotionBlurState();
if (blurFilterRef.current) {
blurFilterRef.current.blur = 0;
}
requestAnimationFrame(() => {
const container = cameraContainerRef.current;
const videoStage = videoContainerRef.current;
const sprite = videoSpriteRef.current;
const currentApp = appRef.current;
if (!container || !videoStage || !sprite || !currentApp) {
return;
}
container.scale.set(1);
container.position.set(0, 0);
videoStage.scale.set(1);
videoStage.position.set(0, 0);
sprite.scale.set(1);
sprite.position.set(0, 0);
layoutVideoContent();
applyZoomTransform({
cameraContainer: container,
blurFilter: blurFilterRef.current,
stageSize: stageSizeRef.current,
baseMask: baseMaskRef.current,
zoomScale: 1,
focusX: DEFAULT_FOCUS.cx,
focusY: DEFAULT_FOCUS.cy,
motionIntensity: 0,
isPlaying: false,
motionBlurAmount: motionBlurAmountRef.current,
});
requestAnimationFrame(() => {
const finalApp = appRef.current;
if (wasPlaying && video) {
video.play().catch(() => {
// Ignore autoplay restoration failures.
});
}
if (tickerWasStarted && finalApp?.ticker) {
finalApp.ticker.start();
}
const observer = new ResizeObserver((entries) => {
if (!entries[0]) return;
const { width, height } = entries[0].contentRect;
setOverlaySize((prev) => {
if (prev.width === width && prev.height === height) return prev;
return { width, height };
});
});
}, [pixiReady, videoReady, layoutVideoContent]);
observer.observe(el);
return () => observer.disconnect();
}, [pixiReady, videoReady]);
useEffect(() => {
if (!pixiReady || !videoReady) return;
@@ -1287,7 +1231,7 @@ const VideoPlayback = forwardRef<VideoPlaybackRef, VideoPlaybackProps>(
<div
ref={setOverlayRefs}
className="absolute inset-0 select-none"
style={{ pointerEvents: "none", zIndex: 30 }}
style={{ pointerEvents: "auto", zIndex: 30 }}
onPointerDown={handleOverlayPointerDown}
onPointerMove={handleOverlayPointerMove}
onPointerUp={handleOverlayPointerUp}
+4 -4
View File
@@ -394,8 +394,8 @@ export class FrameRenderer {
this.compositeCtx
) {
// Calculate scale factor based on export vs preview dimensions
const previewWidth = this.config.previewWidth || 1920;
const previewHeight = this.config.previewHeight || 1080;
const previewWidth = this.config.previewWidth ?? this.config.width;
const previewHeight = this.config.previewHeight ?? this.config.height;
const scaleX = this.config.width / previewWidth;
const scaleY = this.config.height / previewHeight;
const scaleFactor = (scaleX + scaleY) / 2;
@@ -480,8 +480,8 @@ export class FrameRenderer {
this.videoContainer.y = screenRect.y;
// scale border radius by export/preview canvas ratio
const previewWidth = this.config.previewWidth || 1920;
const previewHeight = this.config.previewHeight || 1080;
const previewWidth = this.config.previewWidth ?? this.config.width;
const previewHeight = this.config.previewHeight ?? this.config.height;
const canvasScaleFactor = Math.min(width / previewWidth, height / previewHeight);
const scaledBorderRadius =
compositeLayout.screenBorderRadius != null