@@ -74,15 +74,19 @@ export const renderFramesAt = (input: RenderInput): RenderOutput => {
7474
7575 // Use and cache prepared points for current interpolation.
7676 let preparedStartPoints : Point [ ] | undefined =
77- renderCache [ startKeyframe . id ] . preparedStartPoints ;
78- let preparedEndPoints : Point [ ] | undefined = renderCache [ endKeyframe . id ] . preparedEndPoints ;
77+ renderCache [ startKeyframe . id ] ? .preparedStartPoints ;
78+ let preparedEndPoints : Point [ ] | undefined = renderCache [ endKeyframe . id ] ? .preparedEndPoints ;
7979 if ( ! preparedStartPoints || ! preparedEndPoints ) {
8080 [ preparedStartPoints , preparedEndPoints ] = prepare (
8181 startKeyframe . initialPoints ,
8282 endKeyframe . initialPoints ,
8383 { rawAngles : false , divideRatio : 1 } ,
8484 ) ;
85+
86+ renderCache [ startKeyframe . id ] = renderCache [ startKeyframe . id ] || { } ;
8587 renderCache [ startKeyframe . id ] . preparedStartPoints = preparedStartPoints ;
88+
89+ renderCache [ endKeyframe . id ] = renderCache [ endKeyframe . id ] || { } ;
8690 renderCache [ endKeyframe . id ] . preparedEndPoints = preparedEndPoints ;
8791 }
8892
@@ -91,12 +95,15 @@ export const renderFramesAt = (input: RenderInput): RenderOutput => {
9195 ( input . timestamp - startKeyframe . timestamp ) /
9296 ( endKeyframe . timestamp - startKeyframe . timestamp ) ;
9397
98+ // Keep progress withing expected range (ex. division by 0).
99+ const clampedProgress = Math . max ( 0 , Math . min ( 1 , progress ) ) ;
100+
94101 // Apply timing function of end frame.
95- const adjustedProgress = endKeyframe . timingFunction ( progress ) ;
102+ const adjustedProgress = endKeyframe . timingFunction ( clampedProgress ) ;
96103
97104 return {
98105 renderCache,
99- lastFrameId : startKeyframe . id ,
106+ lastFrameId : clampedProgress === 1 ? endKeyframe . id : startKeyframe . id ,
100107 points : interpolateBetween ( adjustedProgress , preparedStartPoints , preparedEndPoints ) ,
101108 } ;
102109} ;
@@ -115,6 +122,22 @@ export const transitionFrames = <T extends Keyframe>(
115122
116123 // Add current state as initial frame.
117124 const currentState = renderFramesAt ( input ) ;
125+ if ( currentState . lastFrameId === null ) {
126+ // If there is currently no shape being rendered, use a point in the
127+ // center of the next frame as the initial point.
128+ const firstShape = input . shapeGenerator ( input . newFrames [ 0 ] ) ;
129+ let firstShapeCenterPoint : Point = {
130+ x : 0 ,
131+ y : 0 ,
132+ handleIn : { angle : 0 , length : 0 } ,
133+ handleOut : { angle : 0 , length : 0 } ,
134+ } ;
135+ for ( const point of firstShape ) {
136+ firstShapeCenterPoint . x += point . x / firstShape . length ;
137+ firstShapeCenterPoint . y += point . y / firstShape . length ;
138+ }
139+ currentState . points = [ firstShapeCenterPoint , firstShapeCenterPoint , firstShapeCenterPoint ] ;
140+ }
118141 newInternalFrames . push ( {
119142 id : genId ( ) ,
120143 initialPoints : currentState . points ,
0 commit comments