creates type interface ScrollyVideoInstance

This commit is contained in:
MinamiFunakoshiTR 2025-07-23 12:22:34 -04:00
parent df9c4ae29c
commit dabe1549a0
Failed to extract signature
2 changed files with 77 additions and 13 deletions

View file

@ -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);

View file

@ -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<void>;
paintCanvasFrame(frameNum: number): void;
transitionToTargetTime(options: TransitionOptions): void;
setTargetTimePercent(percentage: number, options?: TransitionOptions): void;
setScrollPercent(percentage: number): void;
destroy(): void;
autoplayScroll(): void;
updateDebugInfo(): void;
}