fix(renderer): apply single eased wheel spin

This commit is contained in:
tiennm99 committed 2026-07-07 00:11:32 +07:00
1 parent 8ab45eb5ea
commit 4632e87150
3 files changed
+59 -7

No files matched your search

+6 -7
View File
@@ -6,6 +6,7 @@ import {
getFinalWheelRotationDegrees,
getSliceCenterDegrees,
getSliceDegrees,
getWheelRotationDegrees,
rightPointerClipPath,
} from './wheel-layout.js';
import {getContrastingTextColor, getRadialLabelLayout} from './wheel-label-layout.js';
@@ -27,11 +28,6 @@ export const WheelComposition = (props) => {
const theme = getTheme(props.theme);
const spinFrames = Math.max(1, durationInFrames - Math.round((props.holdMs / 1000) * fps));
const holdStartFrame = spinFrames;
const progress = interpolate(frame, [0, spinFrames], [0, 1], {
easing: Easing.out(Easing.cubic),
extrapolateLeft: 'clamp',
extrapolateRight: 'clamp',
});
const settle = interpolate(frame, [holdStartFrame, durationInFrames - 1], [0, 1], {
easing: Easing.out(Easing.sin),
extrapolateLeft: 'clamp',
@@ -47,8 +43,11 @@ export const WheelComposition = (props) => {
const sliceDegrees = getSliceDegrees(props.options.length);
const finalRotation = getFinalWheelRotationDegrees(props.options.length, props.winnerIndex);
const startRotation = -24;
const rotation = interpolate(progress, [0, 1], [startRotation, finalRotation], {
easing: Easing.out(Easing.cubic),
const rotation = getWheelRotationDegrees({
finalRotationDegrees: finalRotation,
frame,
spinFrames,
startRotationDegrees: startRotation,
});
return (
+32
View File
@@ -35,3 +35,35 @@ export const getFinalWheelRotationDegrees = (optionCount, winnerIndex, fullTurns
* @returns {number}
*/
export const cssDegreesToPieRadians = (cssDegrees) => ((cssDegrees - 270) * Math.PI) / 180;
/**
* @param {number} value
* @param {number} min
* @param {number} max
* @returns {number}
*/
const clamp = (value, min, max) => Math.min(Math.max(value, min), max);
/**
* @param {number} frame
* @param {number} spinFrames
* @returns {number}
*/
export const getSpinProgress = (frame, spinFrames) => {
const safeSpinFrames = Math.max(1, spinFrames);
const progress = clamp(frame / safeSpinFrames, 0, 1);
return 1 - (1 - progress) ** 3;
};
/**
* @param {object} input
* @param {number} input.frame
* @param {number} input.spinFrames
* @param {number} input.startRotationDegrees
* @param {number} input.finalRotationDegrees
* @returns {number}
*/
export const getWheelRotationDegrees = ({frame, spinFrames, startRotationDegrees, finalRotationDegrees}) =>
startRotationDegrees +
(finalRotationDegrees - startRotationDegrees) * getSpinProgress(frame, spinFrames);
+21
View File
@@ -4,6 +4,8 @@ import {
getFinalWheelRotationDegrees,
getSliceCenterDegrees,
getSliceDegrees,
getSpinProgress,
getWheelRotationDegrees,
rightPointerClipPath,
} from '../src/remotion/wheel-layout.js';
@@ -43,6 +45,25 @@ describe('wheel layout', () => {
expect(getRenderedStartDegrees(270)).toBe(270);
});
test('eases spin progress once across the spin duration', () => {
expect(getSpinProgress(0, 100)).toBe(0);
expect(getSpinProgress(25, 100)).toBeCloseTo(0.578125);
expect(getSpinProgress(50, 100)).toBeCloseTo(0.875);
expect(getSpinProgress(100, 100)).toBe(1);
expect(getSpinProgress(125, 100)).toBe(1);
});
test('maps eased spin progress to wheel rotation', () => {
const rotation = getWheelRotationDegrees({
finalRotationDegrees: 696,
frame: 25,
spinFrames: 100,
startRotationDegrees: -24,
});
expect(rotation).toBeCloseTo(392.25);
});
test('defines a right-side pointer that points into the wheel', () => {
expect(rightPointerClipPath).toBe('polygon(0 50%, 100% 0, 100% 100%)');
});