summaryrefslogtreecommitdiff
path: root/apps/web/src/lib/timeline
diff options
context:
space:
mode:
authorMaze Winther <mazewinther@gmail.com>2026-02-02 18:11:12 +0100
committerMaze Winther <mazewinther@gmail.com>2026-02-02 18:11:12 +0100
commitc3f0d640ef366fe4d94ff995ee8fe5ef282b9c1e (patch)
treeb1f6907de1250698f19b00791cf50f27ad69f48a /apps/web/src/lib/timeline
parent22ea6b89256328458bd8d67f6e5a53d9a3623a90 (diff)
downloadopencut-c3f0d640ef366fe4d94ff995ee8fe5ef282b9c1e.tar.gz
feat: exponential zoom
Diffstat (limited to 'apps/web/src/lib/timeline')
-rw-r--r--apps/web/src/lib/timeline/zoom-utils.ts33
1 files changed, 33 insertions, 0 deletions
diff --git a/apps/web/src/lib/timeline/zoom-utils.ts b/apps/web/src/lib/timeline/zoom-utils.ts
index 49f7fcb6..c4a64ed1 100644
--- a/apps/web/src/lib/timeline/zoom-utils.ts
+++ b/apps/web/src/lib/timeline/zoom-utils.ts
@@ -51,3 +51,36 @@ export function getZoomPercent({
}): number {
return (zoomLevel - minZoom) / (TIMELINE_CONSTANTS.ZOOM_MAX - minZoom);
}
+
+/**
+ * Convert linear slider position (0-1) to exponential zoom level.
+ * At low slider values, zoom changes are small. At high values, changes are large.
+ */
+export function sliderToZoom({
+ sliderPosition,
+ minZoom,
+ maxZoom = TIMELINE_CONSTANTS.ZOOM_MAX,
+}: {
+ sliderPosition: number;
+ minZoom: number;
+ maxZoom?: number;
+}): number {
+ const clampedPosition = Math.max(0, Math.min(1, sliderPosition));
+ return minZoom * (maxZoom / minZoom) ** clampedPosition;
+}
+
+/**
+ * Convert exponential zoom level to linear slider position (0-1).
+ */
+export function zoomToSlider({
+ zoomLevel,
+ minZoom,
+ maxZoom = TIMELINE_CONSTANTS.ZOOM_MAX,
+}: {
+ zoomLevel: number;
+ minZoom: number;
+ maxZoom?: number;
+}): number {
+ const clampedZoom = Math.max(minZoom, Math.min(maxZoom, zoomLevel));
+ return Math.log(clampedZoom / minZoom) / Math.log(maxZoom / minZoom);
+}