From c9b66299d09321d548cbc16b6c824d7665e5e7b9 Mon Sep 17 00:00:00 2001 From: Etienne Lescot Date: Tue, 28 Jul 2026 17:50:13 +0200 Subject: [PATCH] chore(cleanup): move pure-math out of components/video-editor/videoPlayback/ into lib/zoomMath MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pure rename: the misnomer directory src/components/video-editor/videoPlayback/ contained 11 files of pure zoom/spring/focus math (zero React). Moved into a clearer home: src/lib/zoomMath/. Files moved (9 source + 2 co-located unit tests): cameraFullscreenUtils.ts cameraFullscreenUtils.test.ts constants.ts cursorFollowUtils.ts focusUtils.ts mathUtils.ts motionSmoothing.ts zoomRegionUtils.ts zoomRegionUtils.test.ts (does not exist; the 2 tests are co-located above) zoomSpring.ts zoomSpring.test.ts zoomTransform.ts Import sites updated (8 files, ~15 import specifiers): src/native/sceneDescription.test.ts src/lib/exporter/wgsl/evaluate.ts src/lib/exporter/frameRenderer.ts src/lib/cursor/pixiCursorRenderer.ts src/lib/cursor/cursorPathSmoothing.ts src/lib/ai-edition/timeline/zoom-preview.ts src/components/ai-edition/ZoomFocusOverlay.tsx src/components/ai-edition/PreviewCanvas.tsx Internal relative imports of ../types rewritten to @/components/video-editor/types (5 sites: cameraFullscreenUtils, constants, cursorFollowUtils, focusUtils, zoomRegionUtils; plus the moved test). types.ts itself stays in components/video-editor/ — it is still a real shared types module used by src/lib/ai-edition/, and the parent directory src/components/video-editor/ stays in place; only the misnamed videoPlayback/ subfolder moved. Doc references to the moved files (technical-documentation/architecture/cursor.md, crates/compositor/src/cursor.rs) updated to the new paths. Stale comments referencing files outside this move (VideoPlayback.tsx, videoPlayback/overlayUtils.ts, videoPlayback/videoEventHandlers.ts) are left alone — out of scope. No behavior change. Verified with: tsc --noEmit (clean), vitest --run (1144/1144 passing), biome check (0 new warnings vs baseline). --- crates/compositor/src/cursor.rs | 2 +- src/components/ai-edition/PreviewCanvas.tsx | 2 +- .../ai-edition/ZoomFocusOverlay.tsx | 2 +- src/lib/ai-edition/timeline/zoom-preview.ts | 4 +-- src/lib/cursor/cursorPathSmoothing.ts | 2 +- src/lib/cursor/pixiCursorRenderer.ts | 2 +- src/lib/exporter/frameRenderer.ts | 33 ++++++++----------- src/lib/exporter/wgsl/evaluate.ts | 30 +++++++---------- .../zoomMath}/cameraFullscreenUtils.test.ts | 2 +- .../zoomMath}/cameraFullscreenUtils.ts | 2 +- .../zoomMath}/constants.ts | 2 +- .../zoomMath}/cursorFollowUtils.ts | 2 +- .../zoomMath}/focusUtils.ts | 7 +++- .../zoomMath}/mathUtils.ts | 0 .../zoomMath}/motionSmoothing.ts | 0 .../zoomMath}/zoomRegionUtils.ts | 14 ++++++-- .../zoomMath}/zoomSpring.test.ts | 0 .../zoomMath}/zoomSpring.ts | 0 .../zoomMath}/zoomTransform.ts | 0 src/native/sceneDescription.test.ts | 2 +- .../architecture/cursor.md | 2 +- 21 files changed, 56 insertions(+), 54 deletions(-) rename src/{components/video-editor/videoPlayback => lib/zoomMath}/cameraFullscreenUtils.test.ts (98%) rename src/{components/video-editor/videoPlayback => lib/zoomMath}/cameraFullscreenUtils.ts (96%) rename src/{components/video-editor/videoPlayback => lib/zoomMath}/constants.ts (93%) rename src/{components/video-editor/videoPlayback => lib/zoomMath}/cursorFollowUtils.ts (97%) rename src/{components/video-editor/videoPlayback => lib/zoomMath}/focusUtils.ts (96%) rename src/{components/video-editor/videoPlayback => lib/zoomMath}/mathUtils.ts (100%) rename src/{components/video-editor/videoPlayback => lib/zoomMath}/motionSmoothing.ts (100%) rename src/{components/video-editor/videoPlayback => lib/zoomMath}/zoomRegionUtils.ts (97%) rename src/{components/video-editor/videoPlayback => lib/zoomMath}/zoomSpring.test.ts (100%) rename src/{components/video-editor/videoPlayback => lib/zoomMath}/zoomSpring.ts (100%) rename src/{components/video-editor/videoPlayback => lib/zoomMath}/zoomTransform.ts (100%) diff --git a/crates/compositor/src/cursor.rs b/crates/compositor/src/cursor.rs index 8d518c6e15..621309e672 100644 --- a/crates/compositor/src/cursor.rs +++ b/crates/compositor/src/cursor.rs @@ -5,7 +5,7 @@ use anyhow::{Context, Result}; // Paramètres de suivi auto — parité stricte avec -// `src/components/video-editor/videoPlayback/constants.ts` (AUTO_FOLLOW_PARAMS), partagés +// `src/lib/zoomMath/constants.ts` (AUTO_FOLLOW_PARAMS), partagés // là-bas entre preview et export pour que la caméra suive le curseur à l'identique. const AUTO_FOLLOW_MIN_FACTOR: f32 = 0.1; const AUTO_FOLLOW_MAX_FACTOR: f32 = 0.25; diff --git a/src/components/ai-edition/PreviewCanvas.tsx b/src/components/ai-edition/PreviewCanvas.tsx index 99d73ba8cc..63e7347d27 100644 --- a/src/components/ai-edition/PreviewCanvas.tsx +++ b/src/components/ai-edition/PreviewCanvas.tsx @@ -30,7 +30,6 @@ import { type WebcamMaskShape, type ZoomFocus, } from "@/components/video-editor/types"; -import { computeCameraFullscreenProgress } from "@/components/video-editor/videoPlayback/cameraFullscreenUtils"; import { useScopedT } from "@/contexts/I18nContext"; import { resolveAspectRatioValue } from "@/lib/ai-edition/document/outputFormat"; import type { @@ -52,6 +51,7 @@ import { } from "@/lib/compositeLayout"; import { classifyWallpaper, resolveImageWallpaperUrl } from "@/lib/wallpaper"; import { getCssClipPath } from "@/lib/webcamMaskShapes"; +import { computeCameraFullscreenProgress } from "@/lib/zoomMath/cameraFullscreenUtils"; import { clamp, clamp01 } from "@/utils/math"; import { AnnotationLayer } from "./AnnotationLayer"; import { NativeCompositorOverlay } from "./NativeCompositorOverlay"; diff --git a/src/components/ai-edition/ZoomFocusOverlay.tsx b/src/components/ai-edition/ZoomFocusOverlay.tsx index 0bfc0670d4..081f3be10b 100644 --- a/src/components/ai-edition/ZoomFocusOverlay.tsx +++ b/src/components/ai-edition/ZoomFocusOverlay.tsx @@ -10,8 +10,8 @@ import type { PointerEvent as ReactPointerEvent } from "react"; import { useCallback, useRef } from "react"; import { getZoomScale, type ZoomFocus } from "@/components/video-editor/types"; -import { getFocusBoundsForScale } from "@/components/video-editor/videoPlayback/focusUtils"; import type { AxcutZoomRegion } from "@/lib/ai-edition/schema"; +import { getFocusBoundsForScale } from "@/lib/zoomMath/focusUtils"; import { clamp01 } from "@/utils/math"; import styles from "./ZoomFocusOverlay.module.css"; diff --git a/src/lib/ai-edition/timeline/zoom-preview.ts b/src/lib/ai-edition/timeline/zoom-preview.ts index a73846f2ac..18b04daad2 100644 --- a/src/lib/ai-edition/timeline/zoom-preview.ts +++ b/src/lib/ai-edition/timeline/zoom-preview.ts @@ -15,9 +15,9 @@ import type { ZoomRegion as LegacyZoomRegion, } from "@/components/video-editor/types"; import { getZoomScale } from "@/components/video-editor/types"; -import { findDominantRegion } from "@/components/video-editor/videoPlayback/zoomRegionUtils"; -import { computeZoomTransform } from "@/components/video-editor/videoPlayback/zoomTransform"; import type { AxcutZoomRegion } from "@/lib/ai-edition/schema"; +import { findDominantRegion } from "@/lib/zoomMath/zoomRegionUtils"; +import { computeZoomTransform } from "@/lib/zoomMath/zoomTransform"; export interface ZoomPreviewTransform { scale: number; diff --git a/src/lib/cursor/cursorPathSmoothing.ts b/src/lib/cursor/cursorPathSmoothing.ts index c550fa623c..a7dd4a2ec6 100644 --- a/src/lib/cursor/cursorPathSmoothing.ts +++ b/src/lib/cursor/cursorPathSmoothing.ts @@ -1,4 +1,4 @@ -import { getCursorSpringConfig } from "@/components/video-editor/videoPlayback/motionSmoothing"; +import { getCursorSpringConfig } from "@/lib/zoomMath/motionSmoothing"; import type { CursorRecordingData, CursorRecordingSample } from "@/native/contracts"; import { clamp } from "@/utils/math"; diff --git a/src/lib/cursor/pixiCursorRenderer.ts b/src/lib/cursor/pixiCursorRenderer.ts index 1b4f567f98..25bd8ddc35 100644 --- a/src/lib/cursor/pixiCursorRenderer.ts +++ b/src/lib/cursor/pixiCursorRenderer.ts @@ -6,7 +6,7 @@ import { getCursorSpringConfig, resetSpringState, stepSpringValue, -} from "@/components/video-editor/videoPlayback/motionSmoothing"; +} from "@/lib/zoomMath/motionSmoothing"; import { clamp } from "@/utils/math"; import { UPLOADED_CURSOR_SAMPLE_SIZE, uploadedCursorAssets } from "./uploadedCursorAssets"; diff --git a/src/lib/exporter/frameRenderer.ts b/src/lib/exporter/frameRenderer.ts index 73aa82d1d2..6f42581ba8 100644 --- a/src/lib/exporter/frameRenderer.ts +++ b/src/lib/exporter/frameRenderer.ts @@ -24,26 +24,6 @@ import { isRotation3DIdentity, lerpRotation3D, } from "@/components/video-editor/types"; -import { computeCameraFullscreenProgress } from "@/components/video-editor/videoPlayback/cameraFullscreenUtils"; -import { - AUTO_FOLLOW_PARAMS, - DEFAULT_FOCUS, -} from "@/components/video-editor/videoPlayback/constants"; -import { advanceFollowFocus } from "@/components/video-editor/videoPlayback/cursorFollowUtils"; -import { clampFocusToScale } from "@/components/video-editor/videoPlayback/focusUtils"; -import { findDominantRegion } from "@/components/video-editor/videoPlayback/zoomRegionUtils"; -import { - createZoomSpringState, - resetZoomSpring, - stepZoomSpring, -} from "@/components/video-editor/videoPlayback/zoomSpring"; -import { - applyZoomTransform, - computeFocusFromTransform, - computeZoomTransform, - createMotionBlurState, - type MotionBlurState, -} from "@/components/video-editor/videoPlayback/zoomTransform"; import { computeCameraFullscreenRect, computeCompositeLayout, @@ -66,6 +46,19 @@ import { } from "@/lib/cursor/nativeCursor"; import { BackgroundLoadError, classifyWallpaper, resolveImageWallpaperUrl } from "@/lib/wallpaper"; import { drawCanvasClipPath } from "@/lib/webcamMaskShapes"; +import { computeCameraFullscreenProgress } from "@/lib/zoomMath/cameraFullscreenUtils"; +import { AUTO_FOLLOW_PARAMS, DEFAULT_FOCUS } from "@/lib/zoomMath/constants"; +import { advanceFollowFocus } from "@/lib/zoomMath/cursorFollowUtils"; +import { clampFocusToScale } from "@/lib/zoomMath/focusUtils"; +import { findDominantRegion } from "@/lib/zoomMath/zoomRegionUtils"; +import { createZoomSpringState, resetZoomSpring, stepZoomSpring } from "@/lib/zoomMath/zoomSpring"; +import { + applyZoomTransform, + computeFocusFromTransform, + computeZoomTransform, + createMotionBlurState, + type MotionBlurState, +} from "@/lib/zoomMath/zoomTransform"; import type { CursorRecordingData } from "@/native/contracts"; import { renderAnnotations } from "./annotationRenderer"; import { diff --git a/src/lib/exporter/wgsl/evaluate.ts b/src/lib/exporter/wgsl/evaluate.ts index 8c3e18a8c9..968da2de31 100644 --- a/src/lib/exporter/wgsl/evaluate.ts +++ b/src/lib/exporter/wgsl/evaluate.ts @@ -24,24 +24,6 @@ import type { ZoomRegion, } from "@/components/video-editor/types"; import { DEFAULT_ROTATION_3D, getZoomScale, lerpRotation3D } from "@/components/video-editor/types"; -import { computeCameraFullscreenProgress } from "@/components/video-editor/videoPlayback/cameraFullscreenUtils"; -import { - AUTO_FOLLOW_PARAMS, - DEFAULT_FOCUS, -} from "@/components/video-editor/videoPlayback/constants"; -import { advanceFollowFocus } from "@/components/video-editor/videoPlayback/cursorFollowUtils"; -import { clampFocusToScale } from "@/components/video-editor/videoPlayback/focusUtils"; -import { findDominantRegion } from "@/components/video-editor/videoPlayback/zoomRegionUtils"; -import { - createZoomSpringState, - resetZoomSpring, - stepZoomSpring, - type ZoomSpringState, -} from "@/components/video-editor/videoPlayback/zoomSpring"; -import { - computeFocusFromTransform, - computeZoomTransform, -} from "@/components/video-editor/videoPlayback/zoomTransform"; import { computeCameraFullscreenRect, computeCompositeLayout, @@ -52,6 +34,18 @@ import { type WebcamLayoutPreset, type WebcamSizePreset, } from "@/lib/compositeLayout"; +import { computeCameraFullscreenProgress } from "@/lib/zoomMath/cameraFullscreenUtils"; +import { AUTO_FOLLOW_PARAMS, DEFAULT_FOCUS } from "@/lib/zoomMath/constants"; +import { advanceFollowFocus } from "@/lib/zoomMath/cursorFollowUtils"; +import { clampFocusToScale } from "@/lib/zoomMath/focusUtils"; +import { findDominantRegion } from "@/lib/zoomMath/zoomRegionUtils"; +import { + createZoomSpringState, + resetZoomSpring, + stepZoomSpring, + type ZoomSpringState, +} from "@/lib/zoomMath/zoomSpring"; +import { computeFocusFromTransform, computeZoomTransform } from "@/lib/zoomMath/zoomTransform"; /** Everything about the document that does not depend on `t`. */ export interface EvaluateScene { diff --git a/src/components/video-editor/videoPlayback/cameraFullscreenUtils.test.ts b/src/lib/zoomMath/cameraFullscreenUtils.test.ts similarity index 98% rename from src/components/video-editor/videoPlayback/cameraFullscreenUtils.test.ts rename to src/lib/zoomMath/cameraFullscreenUtils.test.ts index 49ff853af7..d7f83ad0e5 100644 --- a/src/components/video-editor/videoPlayback/cameraFullscreenUtils.test.ts +++ b/src/lib/zoomMath/cameraFullscreenUtils.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from "vitest"; -import type { CameraFullscreenRegion } from "../types"; +import type { CameraFullscreenRegion } from "@/components/video-editor/types"; import { computeCameraFullscreenProgress } from "./cameraFullscreenUtils"; import { TRANSITION_WINDOW_MS } from "./constants"; diff --git a/src/components/video-editor/videoPlayback/cameraFullscreenUtils.ts b/src/lib/zoomMath/cameraFullscreenUtils.ts similarity index 96% rename from src/components/video-editor/videoPlayback/cameraFullscreenUtils.ts rename to src/lib/zoomMath/cameraFullscreenUtils.ts index bf7228d405..bec701edcb 100644 --- a/src/components/video-editor/videoPlayback/cameraFullscreenUtils.ts +++ b/src/lib/zoomMath/cameraFullscreenUtils.ts @@ -1,4 +1,4 @@ -import type { CameraFullscreenRegion } from "../types"; +import type { CameraFullscreenRegion } from "@/components/video-editor/types"; import { TRANSITION_WINDOW_MS } from "./constants"; import { easeOutScreenStudio } from "./mathUtils"; diff --git a/src/components/video-editor/videoPlayback/constants.ts b/src/lib/zoomMath/constants.ts similarity index 93% rename from src/components/video-editor/videoPlayback/constants.ts rename to src/lib/zoomMath/constants.ts index 84b273af4a..355b611ce9 100644 --- a/src/components/video-editor/videoPlayback/constants.ts +++ b/src/lib/zoomMath/constants.ts @@ -1,4 +1,4 @@ -import type { ZoomFocus } from "../types"; +import type { ZoomFocus } from "@/components/video-editor/types"; export const DEFAULT_FOCUS: ZoomFocus = { cx: 0.5, cy: 0.5 }; export const TRANSITION_WINDOW_MS = 1015.05; diff --git a/src/components/video-editor/videoPlayback/cursorFollowUtils.ts b/src/lib/zoomMath/cursorFollowUtils.ts similarity index 97% rename from src/components/video-editor/videoPlayback/cursorFollowUtils.ts rename to src/lib/zoomMath/cursorFollowUtils.ts index 12113970c4..3667867a93 100644 --- a/src/components/video-editor/videoPlayback/cursorFollowUtils.ts +++ b/src/lib/zoomMath/cursorFollowUtils.ts @@ -1,4 +1,4 @@ -import type { CursorTelemetryPoint, ZoomFocus } from "../types"; +import type { CursorTelemetryPoint, ZoomFocus } from "@/components/video-editor/types"; /** Binary-search the sorted telemetry and lerp the cursor position at the given playback time. */ export function interpolateCursorAt( diff --git a/src/components/video-editor/videoPlayback/focusUtils.ts b/src/lib/zoomMath/focusUtils.ts similarity index 96% rename from src/components/video-editor/videoPlayback/focusUtils.ts rename to src/lib/zoomMath/focusUtils.ts index a625df405e..d94dfe194c 100644 --- a/src/components/video-editor/videoPlayback/focusUtils.ts +++ b/src/lib/zoomMath/focusUtils.ts @@ -1,5 +1,10 @@ +import { + clampFocusToDepth, + ZOOM_DEPTH_SCALES, + type ZoomDepth, + type ZoomFocus, +} from "@/components/video-editor/types"; import { clamp } from "@/utils/math"; -import { clampFocusToDepth, ZOOM_DEPTH_SCALES, type ZoomDepth, type ZoomFocus } from "../types"; interface StageSize { width: number; diff --git a/src/components/video-editor/videoPlayback/mathUtils.ts b/src/lib/zoomMath/mathUtils.ts similarity index 100% rename from src/components/video-editor/videoPlayback/mathUtils.ts rename to src/lib/zoomMath/mathUtils.ts diff --git a/src/components/video-editor/videoPlayback/motionSmoothing.ts b/src/lib/zoomMath/motionSmoothing.ts similarity index 100% rename from src/components/video-editor/videoPlayback/motionSmoothing.ts rename to src/lib/zoomMath/motionSmoothing.ts diff --git a/src/components/video-editor/videoPlayback/zoomRegionUtils.ts b/src/lib/zoomMath/zoomRegionUtils.ts similarity index 97% rename from src/components/video-editor/videoPlayback/zoomRegionUtils.ts rename to src/lib/zoomMath/zoomRegionUtils.ts index f4b6efa1be..85a91a98a3 100644 --- a/src/components/video-editor/videoPlayback/zoomRegionUtils.ts +++ b/src/lib/zoomMath/zoomRegionUtils.ts @@ -1,6 +1,16 @@ +import type { + CursorTelemetryPoint, + Rotation3D, + ZoomFocus, + ZoomRegion, +} from "@/components/video-editor/types"; +import { + DEFAULT_ROTATION_3D, + getRotation3D, + getZoomScale, + lerpRotation3D, +} from "@/components/video-editor/types"; import { clamp01 } from "@/utils/math"; -import type { CursorTelemetryPoint, Rotation3D, ZoomFocus, ZoomRegion } from "../types"; -import { DEFAULT_ROTATION_3D, getRotation3D, getZoomScale, lerpRotation3D } from "../types"; import { TRANSITION_WINDOW_MS, ZOOM_IN_TRANSITION_WINDOW_MS } from "./constants"; import { interpolateCursorAt } from "./cursorFollowUtils"; import { clampFocusToScale } from "./focusUtils"; diff --git a/src/components/video-editor/videoPlayback/zoomSpring.test.ts b/src/lib/zoomMath/zoomSpring.test.ts similarity index 100% rename from src/components/video-editor/videoPlayback/zoomSpring.test.ts rename to src/lib/zoomMath/zoomSpring.test.ts diff --git a/src/components/video-editor/videoPlayback/zoomSpring.ts b/src/lib/zoomMath/zoomSpring.ts similarity index 100% rename from src/components/video-editor/videoPlayback/zoomSpring.ts rename to src/lib/zoomMath/zoomSpring.ts diff --git a/src/components/video-editor/videoPlayback/zoomTransform.ts b/src/lib/zoomMath/zoomTransform.ts similarity index 100% rename from src/components/video-editor/videoPlayback/zoomTransform.ts rename to src/lib/zoomMath/zoomTransform.ts diff --git a/src/native/sceneDescription.test.ts b/src/native/sceneDescription.test.ts index 0881e133d1..7262356e06 100644 --- a/src/native/sceneDescription.test.ts +++ b/src/native/sceneDescription.test.ts @@ -11,13 +11,13 @@ import { getZoomScale, ZOOM_DEPTH_SCALES, } from "@/components/video-editor/types"; -import { getFocusBoundsForScale } from "@/components/video-editor/videoPlayback/focusUtils"; import type { AxcutAsset, AxcutClip, AxcutDocument, AxcutZoomRegion, } from "@/lib/ai-edition/schema"; +import { getFocusBoundsForScale } from "@/lib/zoomMath/focusUtils"; import { buildSceneDescription } from "./sceneDescription"; // --- Fixture helpers -------------------------------------------------------- diff --git a/technical-documentation/architecture/cursor.md b/technical-documentation/architecture/cursor.md index 8312158417..dda5979057 100644 --- a/technical-documentation/architecture/cursor.md +++ b/technical-documentation/architecture/cursor.md @@ -27,7 +27,7 @@ The cursor settings pane is `CursorPane` in `src/components/ai-edition/RightPane ## Auto-follow -Cursor telemetry also drives camera focus for auto-follow zooms. `src/components/video-editor/videoPlayback/cursorFollowUtils.ts` interpolates the cursor at content time and applies distance-adaptive, frame-rate-independent smoothing. The zoom-region utilities use that focus for preview, while the export frame renderer uses the corresponding focus during export. The native compositor keeps a raw track for cursor placement and derives a separately smoothed follow track (`crates/compositor/src/cursor.rs:16-24,126-136`), preventing camera motion from changing the cursor's actual recorded position. +Cursor telemetry also drives camera focus for auto-follow zooms. `src/lib/zoomMath/cursorFollowUtils.ts` interpolates the cursor at content time and applies distance-adaptive, frame-rate-independent smoothing. The zoom-region utilities use that focus for preview, while the export frame renderer uses the corresponding focus during export. The native compositor keeps a raw track for cursor placement and derives a separately smoothed follow track (`crates/compositor/src/cursor.rs:16-24,126-136`), preventing camera motion from changing the cursor's actual recorded position. ## Bundled assets