Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/components/error-boundary.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { Component, type ReactNode, type ErrorInfo } from 'react';
import { Button } from '@/components/ui/button';
import { AlertTriangle, RefreshCw } from 'lucide-react';
import { createLogger } from '@/shared/logging/logger';

const logger = createLogger('ErrorBoundary');

interface Props {
children: ReactNode;
Expand All @@ -27,7 +30,7 @@ export class ErrorBoundary extends Component<Props, State> {
componentDidCatch(error: Error, errorInfo: ErrorInfo): void {
// Log to console in development
if (import.meta.env.DEV) {
console.error('ErrorBoundary caught:', error, errorInfo);
logger.error('ErrorBoundary caught:', error, errorInfo);
}

this.props.onError?.(error, errorInfo);
Expand Down
5 changes: 4 additions & 1 deletion src/domain/timeline/transitions/registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
* - A TransitionRenderer (calculation logic for CSS styles and canvas export)
*/

import { createLogger } from '@/shared/logging/logger';
import type {
TransitionDefinition,
TransitionCategory,
Expand All @@ -18,6 +19,8 @@ import type {
} from '@/types/transition';
import type { TransitionStyleCalculation } from './engine';

const logger = createLogger('TransitionRegistry');

/**
* Renderer interface for CSS/DOM-based transitions (preview + Composition).
* Each registered transition must provide this.
Expand Down Expand Up @@ -83,7 +86,7 @@ export class TransitionRegistry {
*/
register(id: string, definition: TransitionDefinition, renderer: TransitionRenderer): void {
if (this.entries.has(id)) {
console.warn(`Transition "${id}" is being overwritten`);
logger.warn(`Transition "${id}" is being overwritten`);
}
this.entries.set(id, { definition, renderer });
}
Expand Down
7 changes: 5 additions & 2 deletions src/features/composition-runtime/components/item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ import {
} from '@/features/composition-runtime/deps/timeline';
import { isGifUrl, isWebpUrl } from '@/utils/media-utils';
import { useMediaLibraryStore } from '@/features/composition-runtime/deps/stores';
import { createLogger } from '@/shared/logging/logger';

const logger = createLogger('CompositionItem');

/** Mask information passed from composition to items */
export interface MaskInfo {
Expand Down Expand Up @@ -115,7 +118,7 @@ export const Item = React.memo<ItemProps>(({ item, muted = false, masks = [], re
const hasCorruptedMetadata = sourceDuration === 0 && effectiveSourceSegment === 0 && trimBefore > MAX_REASONABLE_FRAMES;

if (hasCorruptedMetadata || isInvalidSeek) {
console.error('[Composition Item] Invalid source position detected:', {
logger.error('Invalid source position detected:', {
itemId: item.id,
sourceStart: item.sourceStart,
trimBefore,
Expand Down Expand Up @@ -149,7 +152,7 @@ export const Item = React.memo<ItemProps>(({ item, muted = false, masks = [], re
1,
sourceToTimelineFrames(effectiveDuration, playbackRate, sourceFps, timelineFps)
);
console.warn('[Composition Item] Clip duration exceeds source duration (graceful clamp):', {
logger.warn('Clip duration exceeds source duration (graceful clamp):', {
itemId: item.id,
sourceFramesNeeded,
sourceDuration,
Expand Down
11 changes: 6 additions & 5 deletions src/features/composition-runtime/components/video-content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
} from './video-audio-context';

const videoLog = createLogger('NativePreviewVideo');
const contentLog = createLogger('VideoContent');
videoLog.setLevel(2); // WARN — suppress noisy per-frame debug logs

// Feature detection for requestVideoFrameCallback (avoids per-frame React sync)
Expand Down Expand Up @@ -156,7 +157,7 @@ const NativePreviewVideo: React.FC<{
useEffect(() => {
// Guard: poolClipId and src are required
if (!poolClipId || !src) {
console.error('[NativePreviewVideo] Missing poolClipId or src');
videoLog.error('Missing poolClipId or src');
return;
}

Expand All @@ -177,13 +178,13 @@ const NativePreviewVideo: React.FC<{
if (cancelled || isVideoPoolAbortError(error)) {
return;
}
console.warn(`[NativePreviewVideo] Failed to preload ${src}:`, error);
videoLog.warn(`Failed to preload ${src}:`, error);
});

// Acquire element for this clip
const element = pool.acquireForClip(poolClipId, src);
if (!element) {
console.error(`[NativePreviewVideo] Failed to acquire element for ${poolClipId}`);
videoLog.error(`Failed to acquire element for ${poolClipId}`);
return;
}

Expand Down Expand Up @@ -336,7 +337,7 @@ const NativePreviewVideo: React.FC<{
stallTimerId = window.setTimeout(() => {
stallTimerId = null;
if (elementRef.current === element && element.readyState === 0) {
console.warn(`[NativePreviewVideo] Video stalled at readyState 0 for ${shortId}, retrying load`);
videoLog.warn(`Video stalled at readyState 0 for ${shortId}, retrying load`);
try {
element.load();
} catch {
Expand Down Expand Up @@ -776,7 +777,7 @@ export const VideoContent: React.FC<{

// Handle media errors (e.g., invalid blob URL after HMR or cache cleanup)
const handleError = useCallback((error: Error) => {
console.warn(`[VideoContent] Media error for item ${item.id}:`, error.message);
contentLog.warn(`Media error for item ${item.id}:`, error.message);
setHasError(true);
}, [item.id]);

Expand Down
9 changes: 6 additions & 3 deletions src/features/editor/components/media-sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ import type { VisualEffect, GpuEffect } from '@/types/effects';
import { EFFECT_PRESETS } from '@/types/effects';
import { getGpuCategoriesWithEffects, getGpuEffectDefaultParams } from '@/infrastructure/gpu/effects';
import { useEffectPreviews } from '@/features/editor/deps/effects-contract';
import { createLogger } from '@/shared/logging/logger';

const logger = createLogger('MediaSidebar');

export const MediaSidebar = memo(function MediaSidebar() {
// Use granular selectors - Zustand v5 best practice
Expand Down Expand Up @@ -102,7 +105,7 @@ export const MediaSidebar = memo(function MediaSidebar() {
}

if (!targetTrack) {
console.warn('No available track for text item');
logger.warn('No available track for text item');
return;
}

Expand Down Expand Up @@ -174,7 +177,7 @@ export const MediaSidebar = memo(function MediaSidebar() {
}

if (!targetTrack) {
console.warn('No available track for shape item');
logger.warn('No available track for shape item');
return;
}

Expand Down Expand Up @@ -248,7 +251,7 @@ export const MediaSidebar = memo(function MediaSidebar() {
}

if (!targetTrack) {
console.warn('No available track for adjustment layer');
logger.warn('No available track for adjustment layer');
return;
}

Expand Down
5 changes: 4 additions & 1 deletion src/features/editor/components/unsaved-changes-dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ import {
} from '@/components/ui/alert-dialog';
import { Button } from '@/components/ui/button';
import { Save, Trash2 } from 'lucide-react';
import { createLogger } from '@/shared/logging/logger';

const logger = createLogger('UnsavedChangesDialog');

interface UnsavedChangesDialogProps {
open: boolean;
Expand All @@ -36,7 +39,7 @@ export function UnsavedChangesDialog({
onOpenChange(false);
navigate({ to: '/projects' });
} catch (error) {
console.error('Failed to save project:', error);
logger.error('Failed to save project:', error);
// Keep dialog open on error
} finally {
setIsSaving(false);
Expand Down
7 changes: 4 additions & 3 deletions src/features/editor/hooks/use-auto-save.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,14 @@ export function useAutoSave({ isDirty, onSave, enabled = true }: UseAutoSaveOpti
async () => {
if (isSavingRef.current) return;
isSavingRef.current = true;
logger.debug(`Auto-saving (interval: ${autoSaveInterval}m)...`);
const event = logger.startEvent('save');
event.set('interval_min', autoSaveInterval);

try {
await onSave();
logger.debug('Auto-save completed');
event.success();
} catch (error) {
logger.error('Auto-save failed:', error);
event.failure(error);
toast.error('Auto-save failed');
} finally {
isSavingRef.current = false;
Expand Down
Loading
Loading