From dabe1549a0208c53d8515c9ad81c08db45435e8e Mon Sep 17 00:00:00 2001 From: MinamiFunakoshiTR Date: Wed, 23 Jul 2025 12:22:34 -0400 Subject: [PATCH] creates type interface ScrollyVideoInstance --- .../ScrollyVideo/demo/AdvancedUsecases.svelte | 26 ++++++-- .../ScrollyVideo/ts/ScrollyVideo.ts | 64 +++++++++++++++++-- 2 files changed, 77 insertions(+), 13 deletions(-) diff --git a/src/components/ScrollyVideo/demo/AdvancedUsecases.svelte b/src/components/ScrollyVideo/demo/AdvancedUsecases.svelte index 2f090285..8b2fb551 100644 --- a/src/components/ScrollyVideo/demo/AdvancedUsecases.svelte +++ b/src/components/ScrollyVideo/demo/AdvancedUsecases.svelte @@ -3,9 +3,10 @@ import ScrollerBase from '../../ScrollerBase/ScrollerBase.svelte'; import Tennis from '../videos/tennis.mp4'; import { onDestroy } from 'svelte'; + import type { ScrollyVideoInstance } from '../ts/ScrollyVideo'; let progress = $state(0); - let scrollyVideo = $state(); + let scrollyVideo: ScrollyVideoInstance | undefined = $state(undefined); let now; let then = 0; let time = 0; @@ -13,15 +14,22 @@ let loopCutoff = 0.35; // value between 0-1 to loop the video by let totalTime = 9 * 1000; // milliseconds - let animationId; + let animationId = $state(0); // clamps n value between low and high - function constrain(n, low, high) { + function constrain(n: number, low: number, high: number) { return Math.max(Math.min(n, high), low); } // maps n value between two ranges - function map(n, start1, stop1, start2, stop2, withinBounds = true) { + function map( + n: number, + start1: number, + stop1: number, + start2: number, + stop2: number, + withinBounds = true + ) { const newval = ((n - start1) / (stop1 - start1)) * (stop2 - start2) + start2; if (!withinBounds) { @@ -42,17 +50,21 @@ time += elapsed; currentProgress = map(time, 0, totalTime, 0, 1); - scrollyVideo.setVideoPercentage(currentProgress, { jump: true }); + scrollyVideo?.setVideoPercentage(currentProgress, { + jump: true, + }); if (currentProgress > loopCutoff) { currentProgress = 0; time = 0; - scrollyVideo.setVideoPercentage(0, { jump: true }); + scrollyVideo?.setVideoPercentage(0, { jump: true }); } then = now; } else { - scrollyVideo.setVideoPercentage(progress, { jump: true }); + scrollyVideo?.setVideoPercentage(progress, { + jump: true, + }); } animationId = requestAnimationFrame(renderVideo); diff --git a/src/components/ScrollyVideo/ts/ScrollyVideo.ts b/src/components/ScrollyVideo/ts/ScrollyVideo.ts index c952214f..920a1365 100644 --- a/src/components/ScrollyVideo/ts/ScrollyVideo.ts +++ b/src/components/ScrollyVideo/ts/ScrollyVideo.ts @@ -18,6 +18,11 @@ interface ScrollyVideoArgs { onChange?: (percentage?: number) => void; debug?: boolean; autoplay?: boolean; + setVideoPercentage?: ( + percentage: number, + options?: TransitionOptions + ) => void; + resize?: () => void; } interface TransitionOptions { @@ -197,8 +202,8 @@ class ScrollyVideo { transitionSpeed = 8, frameThreshold = 0.1, useWebCodecs = true, - onReady = () => {}, - onChange = (_percentage?: number) => {}, + onReady = () => { }, + onChange = (_percentage?: number) => { }, debug = false, autoplay = false, }: ScrollyVideoArgs) { @@ -464,7 +469,7 @@ class ScrollyVideo { setVideoPercentage( percentage: number, options: TransitionOptions = { jump: false, transitionSpeed: 8 } - ): void { + ) { // Early termination if the video percentage is already at the percentage that is intended. if (this.videoPercentage === percentage) return; @@ -736,7 +741,7 @@ class ScrollyVideo { const hasPassedThreshold = isForwardTransition ? this.currentTime >= this.targetTime - : this.currentTime <= this.targetTime; + : this.currentTime <= this.targetTime; if (this.componentState.isAutoPlaying) { this.componentState.autoplayProgress = parseFloat( @@ -775,7 +780,7 @@ class ScrollyVideo { isForwardTransition ? startCurrentTime + easedProgress * Math.abs(distance) * transitionSpeed - : startCurrentTime - + : startCurrentTime - easedProgress * Math.abs(distance) * transitionSpeed; if (this.canvas) { @@ -864,7 +869,7 @@ class ScrollyVideo { const targetDuration = this.frames?.length && this.frameRate ? this.frames.length / this.frameRate - : this.video?.duration || 0; + : this.video?.duration || 0; // The time we want to transition to this.targetTime = Math.max(Math.min(percentage, 1), 0) * targetDuration; @@ -967,3 +972,50 @@ class ScrollyVideo { } } export default ScrollyVideo; + +// Complete ScrollyVideo instance interface +export interface ScrollyVideoInstance { + // Properties + container: HTMLElement | null; + scrollyVideoContainer: Element | string | undefined; + src: string; + transitionSpeed: number; + frameThreshold: number; + useWebCodecs: boolean; + objectFit: string; + sticky: boolean; + trackScroll: boolean; + onReady: () => void; + onChange: (percentage?: number) => void; + debug: boolean; + autoplay: boolean; + video: HTMLVideoElement | undefined; + videoPercentage: number; + isSafari: boolean; + currentTime: number; + targetTime: number; + canvas: HTMLCanvasElement | null; + context: CanvasRenderingContext2D | null; + frames: ImageBitmap[] | null; + frameRate: number; + targetScrollPosition: number | null; + currentFrame: number; + usingWebCodecs: boolean; + totalTime: number; + transitioningRaf: number | null; + componentState: ScrollyVideoState; + + // Methods + updateScrollPercentage: ((jump: boolean) => void) | undefined; + resize: (() => void) | undefined; + setVideoPercentage(percentage: number, options?: TransitionOptions): void; + setCoverStyle(el: HTMLElement | HTMLCanvasElement | undefined): void; + decodeVideo(): Promise; + paintCanvasFrame(frameNum: number): void; + transitionToTargetTime(options: TransitionOptions): void; + setTargetTimePercent(percentage: number, options?: TransitionOptions): void; + setScrollPercent(percentage: number): void; + destroy(): void; + autoplayScroll(): void; + updateDebugInfo(): void; +}