webchalk-animate - v0.31.0
    Preparing search index...

    Interface PresetEffectDefinition<TClipContext, TConfig>

    Object representing an entry in a PresetEffectBank. It contains

    • a function for composing an animation effect
    • two properties that can be used to specify clip configuration settings
      • one property contains default configuration settings
      • the other property contains immutable configuration settings
    • a property that sets how often the effect frame generator builder should be run
    interface PresetEffectDefinition<
        TClipContext extends unknown = unknown,
        TConfig extends unknown = unknown,
    > {
        defaultConfig?: Exclude<Partial<TConfig> & object, undefined> extends Function
            ? Partial<TConfig> & object & Function
            : Partial<TConfig> & object | undefined;
        howOftenBuildGenerators?: "on-first-play-only" | "on-every-play";
        immutableConfig?: Exclude<Partial<TConfig> & object, undefined> extends Function
            ? Partial<TConfig> & object & Function
            : Partial<TConfig> & object | undefined;
        buildFrameGenerators(
            this: TClipContext & Readonly<
                Pick<
                    AnimClip<
                        Readonly<
                            StripDuplicateMethodAutocompletion<
                                {
                                    defaultConfig?: Partial<unknown> & object;
                                    howOftenBuildGenerators?: "on-first-play-only" | "on-every-play";
                                    immutableConfig?: Partial<unknown> & object;
                                    buildFrameGenerators(
                                        this: Readonly<Pick<AnimClip<Readonly<StripDuplicateMethodAutocompletion<{ defaultConfig?: (Partial<unknown> & object) | undefined; immutableConfig?: (Partial<unknown> & object) | undefined; howOftenBuildGenerators?: "on-first-play-only" | "on-every-play" | undefined; buildFrameGenerators(this: Readonly<Pick<AnimClip<Readonly<StripDuplicateMethodAutocompletion<any>>, AnimClipConfig>, "computeTween">>, ...effectOptions: unknown[]): EffectFrameGeneratorSet; }>>, AnimClipConfig>, "computeTween">>,
                                        ...effectOptions: unknown[],
                                    ): EffectFrameGeneratorSet;
                                },
                            >,
                        >,
                        AnimClipConfig,
                    >,
                    "computeTween",
                >,
            >,
            ...effectOptions: unknown[],
        ): EffectFrameGeneratorSet;
    }

    Type Parameters

    • TClipContext extends unknown = unknown
    • TConfig extends unknown = unknown
    Index

    Clip Configuration

    defaultConfig?: Exclude<Partial<TConfig> & object, undefined> extends Function
        ? Partial<TConfig> & object & Function
        : Partial<TConfig> & object | undefined

    Object containing default configuration options that are appropriate for the effect. These options can be overwritten while calling the clip factory function. This makes it convenient to rely on some preset behaviors that make sense without having to set them in a clip factory function.

    When defining preset effects, the configuration options that you are allowed to set here may be limited by the AnimClip value for AnimClip.categoryImmutableConfig (which you cannot modify). For example, for exit animation clips, ExitClip.categoryImmutableConfig sets a value for commitsStyles, so you cannot set a value for commitsStyles in defaultConfig for any entries in the exit effects bank.

    const clipFactories = webchalk.createAnimationClipFactories({
    additionalEntranceEffectBank: {
    // Element fades in, starting from 0 opacity.
    fadeIn: {
    buildFrameGenerators() {
    return {
    keyframesGenerator_play: () => {
    return [ {opacity: '0'}, {} ];
    },
    } as const;
    },
    },

    fadeIn_default: {
    buildFrameGenerators() {
    return {keyframesGenerator_play: () => {
    return [ {opacity: '0'}, {} ];
    },
    } as const;
    },
    defaultConfig: {
    duration: 2000,
    },
    },
    }
    });

    // select element from DOM
    const element = document.querySelector('.some-element');

    const ent1 = clipFactories.Entrance(element, 'fadeIn', [], {});
    // ↑ duration will be set to whatever the default duration is for all
    // EntranceClip objects

    const ent2 = clipFactories.Entrance(element, 'fadeIn_default', [], {});
    // ↑ duration will be set to 2000 because that is what was specified in
    // the 'fadeIn_default' effect definition

    const ent3 = clipFactories.Entrance(element, 'fadeIn_default', [], {duration: 1000});
    // ↑ duration will be set to 1000 because configuration settings set in the
    // clip factory function call will overwrite any default settings
    immutableConfig?: Exclude<Partial<TConfig> & object, undefined> extends Function
        ? Partial<TConfig> & object & Function
        : Partial<TConfig> & object | undefined

    Object containing immutable configuration options for the effect that are appropriate for the effect. These options cannot be overwritten while calling the clip factory function). This makes it possible to set in stone some expected behaviors of clips that use certain effects.

    When creating custom effects, the configuration options that you are allowed to set here may be limited by the AnimClip value for AnimClip.categoryImmutableConfig (which you cannot modify). For example, for exit animation clips, ExitClip.categoryImmutableConfig sets a value for commitsStyles, so you cannot set a value for commitsStyles in immutableConfig for any entries in the exit effects bank.

    const clipFactories = webchalk.createAnimationClipFactories({
    additionalEntranceEffectBank: {
    appear: {
    buildFrameGenerators() {
    return {
    keyframesGenerator_play: () => {
    return [];
    },
    };
    },
    },

    appear_immutable: {
    buildFrameGenerators() {
    return {
    keyframesGenerator_play: () => {
    return [];
    },
    };
    },
    immutableConfig: {
    duration: 0,
    easing: 'linear',
    composite: 'replace',
    },
    },
    }
    });

    // select element from DOM
    const element = document.querySelector('.some-element');

    const ent1 = clipFactories.Entrance(element, 'appear', [], {duration: 1000});
    // ↑ no issues

    const ent2 = clipFactories.Entrance(element, 'appear_immutable', [], {endDelay: 1000});
    // ↑ no issues (there is no immutable setting on endDelay for 'appear_immutable')

    const ent3 = clipFactories.Entrance(element, 'appear_immutable', [], {duration: 1000});
    // ↑ TypeScript compiler error will be thrown because duration is not allowed to be set
    // when using the 'appear_immutable' effect. When running the code, this duration will
    // simply be ignored in favor of the immutable duration setting.

    Effect Definition

    howOftenBuildGenerators?: "on-first-play-only" | "on-every-play"

    String that determines how frequently buildFrameGenerators will be run. SUGGESTION: Read the documentation for buildFrameGenerators first.

    • if on-first-play-only, buildFrameGenerators will run the first time play() is called and never again. The first-made EffectFrameGeneratorSet object's functions and the closure created during the first call to buildFrameGenerators will be used for the clip's entire lifetime.
      • This should be set to on-first-play-only when code in the closure of buildFrameGenerators only needs to (or perhaps must only) run once for the returned generators to be correct.
    • if on-every-play, buildFrameGenerators will run every time the clip is about to play forward rather than just the first time, thus creating a new closure and returning a new EffectFrameGeneratorSet each time.
    'on-first-play-only'
    
    // global variable that will be used in the fadeOut_exclusive effect.
    let usedFadeOutEx = false;

    const clipFactories = webchalk.createAnimationClipFactories({
    additionalExitEffectBank: {
    // A preset effect you wrote for fading an element out.
    // Here, it makes no difference what howOftenBuildGenerators is set to.
    //
    // - If set to 'on-first-play-only', then buildFrameGenerators() will run only once
    // (on the first play()). Thus, keyframesGenerator_play() is defined
    // only once and is set to return [{}, {opacity: 0}].
    //
    // - If set to 'on-every-play', then EVERY time the clip
    // plays, buildFrameGenerators() plays. Thus, keyframesGenerator_play()
    // will keep being redefined and set to be a function that
    // returns [{}, {opacity: 0}]. It made no difference because
    // the body of keyframesGenerator_play() remains the same.
    //
    // Thus, it makes no difference what howOftenBuildGenerators is set to.
    // For the sake of optimization, you decide to set it to 'on-first-play-only'
    // (which is the default value anyway, but it adds more clarity).
    fadeOut: {
    buildFrameGenerators() {
    return {
    keyframesGenerator_play: () => {
    return [{}, {opacity: 0}];
    },
    };
    },

    howOftenBuildGenerators: 'on-first-play-only',
    },

    // A preset animation effect you made that can only be used by one animation clip
    // (Why you would ever do something this is unclear, but the reason does not matter.)
    // Here, howOftenBuildGenerators must be set to 'on-first-play-only'.
    //
    // - If set to 'on-first-play-only', then the global variable usedFadeOutEx is
    // checked for truthiness and then set to true on the first (and only) running of
    // buildFrameGenerators(). On subsequent calls to play(), buildFrameGenerators() does not re-run, so
    // the if-condition is not run again. However, any OTHER clip that uses the fadeOut_exclusive
    // effect will fail on their first play() because they need to run buildFrameGenerators() for
    // the first time and will throw the error (because usedFadeOutEx is already set to true).
    // This is the desired behavior.
    //
    // - If set to 'on-every-play', then buildFrameGenerators() will run on every play(). Thus,
    // playing the same clip twice will always cause an error because it will run into
    // the if-conditional again after usedFadeOutEx is already set to true, which is
    // NOT the desired behavior.
    //
    // The difference is that 'on-first-play-only' causes the if-conditional to run
    // only once, while 'on-every-play' causes it to be encountered a second time.
    fadeOut_exclusive: {
    buildFrameGenerators() {
    if (usedFadeOutEx) {
    throw new Error(`Only one clip is allowed to use the 'fadeOut_exclusive' effect.`);
    }
    usedFadeOutEx = true;

    return {
    keyframesGenerator_play: () => {
    return [ {}, {opacity: 0} ];
    },
    };
    },

    howOftenBuildGenerators: 'on-first-play-only',
    },

    // A preset animation effect you made for flying out to the left side of the screen.
    // Here, it makes no difference what howOftenBuildGenerators is set to.
    //
    // - If set to 'on-first-play-only', then buildFrameGenerators() will run only once. Thus,
    // keyframesGenerator_play() is defined only once, and the closure containing
    // computeTranslationStr() will also only be made once. On every play(),
    // keyframesGenerator_play() uses computeTranslationStr() to compute
    // the translation, so the translation will always be recomputed.
    // This is the desired behavior.
    //
    // - If set to 'on-every-play', then every time play() is called to play the clip,
    // buildFrameGenerators() is called again, creating a new closure containing a function
    // called computeTranslationStr() and returning a new keyframesGenerator_play()
    // that uses computeTranslationStr() to compute the translation. It makes no
    // difference since the bodies of computeTranslationStr() and
    // keyframesGenerator_play() remain the same, so this is functionally the
    // same as the previous paragraph.
    // This is the desired behavior.
    //
    // Thus, it makes no difference what howOftenBuildGenerators is set to.
    // For the sake of optimization, you decide to set it to 'on-first-play-only'.
    flyOutLeft1: {
    buildFrameGenerators() {
    const computeTranslationStr = () => {
    // compute distance between right side of element and left side of viewport
    const orthogonalDistance = -(this.domElem.getBoundingClientRect().right);
    // create translation string
    const translationString = `${orthogonalDistance}px 0px`;
    return translationString;
    }

    return {
    keyframesGenerator_play: () => {
    return [
    {translate: computeTranslationStr()}
    ];
    },
    // keyframesGenerator_rewind could have been omitted, but for ease of
    // visual understanding, they are kept for the flyOut effects
    keyframesGenerator_rewind: () => {
    return [
    {translate: computeTranslationStr()},
    {translate: `0 0`}
    ];
    }
    };
    },

    immutableConfig: {
    composite: 'accumulate',
    },

    howOftenBuildGenerators: 'on-first-play-only',
    },

    // A preset animation effect for flying out either left or right (random).
    // Here, howOftenBuildGenerators must be set to 'on-every-play'.
    //
    // - If set to 'on-first-play-only', then leftOrRight is defined only once. Thus,
    // once the clip plays for the first time, leftOrRight will be permanently set
    // to 'go left' or 'go right' within the closure created by buildFrameGenerators(),
    // so the element's direction will not be randomized each time.
    // This is NOT the desired effect.
    //
    // - If set to 'on-every-play', then every time play() is called to play the clip,
    // buildFrameGenerators() is called again. The variable leftOrRight is thus recomputed, so
    // the result of computeTranslationStr() will be randomly left or right every time
    // the clip is played.
    // This is the desired behavior.
    //
    // The difference is that 'on-every-play' causes the effect to use a fresh
    // leftOrRight on each play, while 'on-first-play-only' does not.
    flyOutRandom: {
    buildFrameGenerators() {
    // 50% change of going left or right
    const leftOrRight = Math.random() < 0.5 ? 'go left' : 'go right';

    const computeTranslationStr = () => {
    // compute distance between right side of element and left side of viewport
    const distGoingLeft = -(this.domElem.getBoundingClientRect().right);
    // compute distance between left side of element and right side of viewport
    const distGoingRight = window.innerWidth - this.domElem.getBoundingClientRect().left;
    // choose distance based on leftOrRight
    const orthogonalDistance = leftOrRight === 'go left' ? distGoingLeft : distGoingRight;
    // create translation string
    const translationString = `${orthogonalDistance}px 0px`;
    return translationString;
    }

    return {
    keyframesGenerator_play: () => {
    return [
    {translate: computeTranslationStr()}
    ];
    },
    keyframesGenerator_rewind: () => {
    return [
    {translate: computeTranslationStr()},
    {translate: `0 0`}
    ];
    }
    };
    },

    immutableConfig: {
    composite: 'accumulate',
    },

    howOftenBuildGenerators: 'on-every-play',
    },
    }
    });
    • Function that runs when the clip is played. Returns a EffectFrameGeneratorSet object, which contains callback functions that will produce the effects for both playing and rewinding the animation.

      Parameters

      • this: TClipContext & Readonly<
            Pick<
                AnimClip<
                    Readonly<
                        StripDuplicateMethodAutocompletion<
                            {
                                defaultConfig?: Partial<unknown> & object;
                                howOftenBuildGenerators?: "on-first-play-only" | "on-every-play";
                                immutableConfig?: Partial<unknown> & object;
                                buildFrameGenerators(
                                    this: Readonly<Pick<AnimClip<Readonly<StripDuplicateMethodAutocompletion<{ defaultConfig?: (Partial<unknown> & object) | undefined; immutableConfig?: (Partial<unknown> & object) | undefined; howOftenBuildGenerators?: "on-first-play-only" | "on-every-play" | undefined; buildFrameGenerators(this: Readonly<Pick<AnimClip<Readonly<StripDuplicateMethodAutocompletion<any>>, AnimClipConfig>, "computeTween">>, ...effectOptions: unknown[]): EffectFrameGeneratorSet; }>>, AnimClipConfig>, "computeTween">>,
                                    ...effectOptions: unknown[],
                                ): EffectFrameGeneratorSet;
                            },
                        >,
                    >,
                    AnimClipConfig,
                >,
                "computeTween",
            >,
        >

        A subset of properties of the AnimClip storing the effect at runtime

      • ...effectOptions: unknown[]

        An array containing parameters used to set the behavior for the specific animation effect when calling the clip factory function.

      Returns EffectFrameGeneratorSet

      An object containing 4 possible callback functions that return Keyframes and/or Mutator.

      Overview
      Whenever buildFrameGenerators runs (how often it runs depends on howOftenBuildGenerators), it returns a new EffectFrameGeneratorSet containing callback functions, which we can refer to as "effect generators". The clip will call these effect generators to generate the keyframes/mutators for the animation as soon as the animation needs to be executed. Naturally, the generators have access to the closure created by the call to buildFrameGenerators (in other words, its scope), which is useful for storing stateful data and helper functions that you can use within the generators.
      For the sake of code clarity, it is recommended that you keep a final return statement at the bottom of buildFrameGenerators (as opposed to several possible return statements scattered throughout).

      Special this
      For both convenience and utility, using this inside the scope of buildFrameGenerators gives access to a subset of useful properties and methods of the clip.

      Forward Keyframes Generator
      In a typical case, you will return a EffectFrameGeneratorSet containing the callback function EffectFrameGeneratorSet.keyframesGenerator_play. When the clip is played, the callback function will be called to produce the keyframes for the animation to play. When the clip is rewound, the same callback function will be called again to produce keyframes for the animation to play, but the direction will be reversed. This means that every time playback is initiated (playing or rewinding), a new set of keyframes is produced. When writing your keyframes, you must always define the full course of the effect. For example, from the forward keyframes generator, do not return [{}, {backgroundColor: 'blue'}, {backgroundColor: 'red', opacity: '0.5'}]. Instead, store the original styles—something like const initialStyles = this.getStyles(['backgroundColor', 'opacity']);, and return [{...initialStyles}, {backgroundColor: 'blue'}, {backgroundColor: 'red', opacity: 0.5}] (taking advantage of the fact that initialStyles will still be accessible even after the EffectFrameGeneratorSet is returned). This ensures that the initial styles can be restored when the clip is rewound. The helper method AnimClip.getStyles is a convenient way to get the current style properties of an element.

      Forward Mutator Generator
      You can also animate JavaScript values using EffectFrameGeneratorSet.mutatorGenerator_play. Like the keyframes generator, it is a callback function that will be called when the clip is played, and when the clip is rewound, it will be called again with its effect being reversed this time. The difference is that instead of returning a Keyframes, it will return a Mutator—a function that will be repeatedly called at the device's framerate. If some JavaScript value is changed within the mutator with respect to the clip's progress, then the result is the illusion of a smooth animation that couldn't be achieved using normal CSS-based animations (since CSS cannot animate JavaScript values). (Under the hood, requestAnimationFrame loops are being used.) See the documentation of EffectFrameGeneratorSet for details on how to use mutator generators.

      Backward Effect Generators
      In addition to the forward keyframes/mutator generators, you may also define EffectFrameGeneratorSet.keyframesGenerator_rewind and/or EffectFrameGeneratorSet.mutatorGenerator_rewind, giving you the ability to define more complex effects. When the clip is played, the full EffectFrameGeneratorSet will be produced. Only the forward keyframes/mutator generators will be called at first since they will be used for playing a clip (just as before). When the clip is eventually rewound, then the backward keyframes/mutator generators will be called and used for the animation (instead of reusing the forward generators). When the clip is eventually played again, the forward generators will be called to produce the effect again. Then when the clip is eventually rewound again, the backward generators will once again be called to produce the effect—so on and so forth.

      Generator Rebuild Frequency
      By default, buildFrameGenerators only runs the first time the clip is played, so the resulting generators will be reused for the lifetime of the clip. To allow buildFrameGenerators to rerun and remake the EffectFrameGeneratorSet, set PresetEffectDefinition.howOftenBuildGenerators to 'on-every-play'.

      Caution with composite
      Be mindful of how the value of AnimClipConfig.composite ('replace', 'add' or 'accumulate') may affect the effect when rewinding. This will less often be an issue for entrance and exit effects since changes resulting from effects in these categories are never committed (meaning composite-related bugs are less likely), but for motion and emphasis effects, you should be especially cognizant of potential logic errors.

      // EXAMPLES WHERE BACKWARD GENERATORS CAN BE OMITTED
      const clipFactories = webchalk.createAnimationClipFactories({
      additionalEmphasisEffectBank: {
      // -----------------------------------------------------------------
      // ----------------------------EXAMPLE 1----------------------------
      // -------------------------transparencyHalf------------------------
      // -----------------------------------------------------------------
      transparencyHalf: {
      buildFrameGenerators() {
      const initialOpacity = this.getStyles('opacity');

      // return EffectFrameGeneratorSet
      return {
      keyframesGenerator_play: () => {
      // return Keyframes (Keyframe[])
      return [{opacity: initialOpacity}, {opacity: 0.5}];
      },
      // Notice how the backward generator would be equivalent to running the forward generator
      // and reversing the effect of the keyframes. That means that the forward keyframes
      // generator is invertible, and the backward generator can be omitted.
      keyframesGenerator_rewind: () => {
      // return Keyframes (Keyframe[])
      return [{opacity: 0.5}, {opacity: initialOpacity}];
      },
      };
      },
      },

      // Exactly equivalent to transparencyHalf because the keyframe generator
      // is invertible
      transparencyHalf_shortcut: {
      buildFrameGenerators() {
      const initialOpacity = this.getStyles('opacity');

      // return EffectFrameGeneratorSet
      return {
      keyframesGenerator_play: () => {
      // return Keyframes (Keyframe[])
      return [{opacity: initialOpacity}, {opacity: 0.5}];
      },
      };
      },
      },
      },

      additionalEntranceEffectBank: {
      // -----------------------------------------------------------------
      // ----------------------------EXAMPLE 2----------------------------
      // ------------------------------shyIn------------------------------
      // -----------------------------------------------------------------
      // Element shyly enters, hesitantly fading and scaling in and out until it
      // reaches full opacity and scale
      shyIn: {
      buildFrameGenerators() {
      // return EffectFrameGeneratorSet
      return {
      keyframesGenerator_play: () => {
      // return Keyframes (PropertyIndexedKeyframes)
      return {
      opacity: [0, 0.5, 0.1, 0.7, 0, 1],
      scale: [0, 0.5, 0.1, 0.7, 0, 1],
      };
      },
      // Notice how the backward generator would be equivalent to running the forward generator
      // and reversing the effect of the keyframes. That means that the forward keyframes
      // generator is invertible.
      keyframesGenerator_rewind: () => {
      // return Keyframes (PropertyIndexedKeyframes)
      return {
      opacity: [1, 0, 0.7, 0.1, 0.5, 0],
      scale: [1, 0, 0.7, 0.1, 0.5, 0],
      };
      },
      };
      },
      },

      // Exactly equivalent to shyIn because the keyframes generator is invertible.
      shyIn_shortcut: {
      buildFrameGenerators() {
      // return EffectFrameGeneratorSet
      return {
      keyframesGenerator_play: () => {
      // return Keyframes (PropertyIndexedKeyframes)
      return {
      opacity: [0, 0.5, 0.1, 0.7, 0, 1],
      scale: [0, 0.5, 0.1, 0.7, 0, 1],
      };
      },
      };
      },
      },

      // -----------------------------------------------------------------
      // ----------------------------EXAMPLE 3----------------------------
      // -----------------------riseUp and sinkDown-----------------------
      // -----------------------------------------------------------------
      // Replicates PowerPoint's Rise Up animation.
      // Element flies in from the bottom of the screen and ends up
      // slightly too high, then settles down to its final position.
      riseUp: {
      buildFrameGenerators() {
      const belowViewportDist = () => {
      return window.innerHeight - this.domElem.getBoundingClientRect().top;
      };

      // return frame generator set
      return {
      keyframesGenerator_play: () => {
      // return Keyframes (Keyframe[])
      return [
      {
      opacity: 0,
      composite: 'replace'
      },
      {
      translate: `0 ${belowViewportDist()}px`,
      offset: 0,
      easing: useEasing('power2-out')
      },
      {
      translate: `0 -25px`,
      offset: 0.83333
      },
      {
      translate: `0 -25px`,
      offset: 0.86,
      easing: useEasing('power1-in')
      },
      {translate: `0 0`},
      ];
      },
      // It would be a pain to figure out what the backward keyframes should look like
      // for rewinding this effect. Fortunately, the forward generator is invertible,
      // (trust me—it is true) so keyframesGenerator_rewind() can be omitted.
      // ---------------------------------------------------------------------------------------
      // keyframesGenerator_rewind: () => {
      // // return Keyframes (Keyframe[])
      // return [] // ??????
      // },
      };
      },
      defaultConfig: {
      composite: 'accumulate',
      },
      immutableConfig: {},
      },
      },

      additionalExitEffectBank: {
      // Replicates PowerPoint's Sink Down animation, which is the opposite of Rise Up.
      // Element floats up slightly and then accelerates to the bottom of the screen.
      sinkDown: {
      buildFrameGenerators() {
      const belowViewportDist = () => {
      return window.innerHeight - this.domElem.getBoundingClientRect().top;
      };

      // return frame generator set
      return {
      // Most of the time, when you write your own preset entrance/exit effect, you will want
      // to write the corresponding exit/entrance effect. If you write flyIn, you'll probably
      // write flyOut; if you write slideOut, you'll probably write slideIn; if you write riseUp,
      // you'll probably write sinkDown. The beauty is that if riseUp and sinkDown are opposites,
      // then we know that playing riseUp should be the same as rewinding sinkDown. Therefore,
      // we can copy-paste the logic from riseUp's keyframesGenerator_play() and simply set
      // reverseKeyframesEffect to true. Once again, we have gotten
      // away with just figuring out what the forward keyframes look like without having
      // to figure out what the other set looks like.
      // ---------------------------------------------------------------------------------------
      reverseKeyframesEffect: true,
      keyframesGenerator_play: () => {
      // return Keyframes (Keyframe[])
      return [
      {
      opacity: 0,
      composite: 'replace'
      },
      {
      translate: `0 ${belowViewportDist()}px`,
      offset: 0,
      easing: useEasing('power2-out'),
      },
      {
      translate: `0 -25px`,
      offset: 0.83333
      },
      {
      translate: `0 -25px`,
      offset: 0.86,
      easing: useEasing('power1-in')
      },
      {translate: `0 0`},
      ];
      },

      // keyframesGenerator_rewind: () => {
      // // return Keyframes (Keyframe[])
      // return [] // ??????
      // },
      };
      },
      defaultConfig: {
      composite: 'accumulate',
      },
      immutableConfig: {},
      },

      // -----------------------------------------------------------------
      // ----------------------------EXAMPLE 4----------------------------
      // ----------------------------flyOutLeft---------------------------
      // -----------------------------------------------------------------
      // a preset animation effect for flying out to the left side of the screen
      // while displaying the percentage progress in the element's text content
      flyOutLeft: {
      buildFrameGenerators() {
      const computeTranslationStr = () => {
      const orthogonalDistance = -(this.domElem.getBoundingClientRect().right);
      const translationString = `${orthogonalDistance}px 0px`;
      return translationString;
      }

      // return EffectFrameGeneratorSet
      return {
      keyframesGenerator_play: () => {
      // return Keyframes (Keyframe[])
      return [
      {translate: computeTranslationStr()}
      ];
      },

      // Notice how the backward generator would be equivalent to running the forward generator
      // and reversing the effect of the keyframes (even though the composite value is
      // 'accumulate', it's still invertible because exit effects' changes are never committed).
      // That means that the forward keyframes generator is invertible.
      // --------------------------------------------------------------------------------------
      keyframesGenerator_rewind: () => {
      // return Keyframes (Keyframe[])
      return [
      {translate: computeTranslationStr()},
      {translate: `0 0`}
      ];
      },

      mutatorGenerator_play: () => {
      // return Mutator
      return () => {
      this.domElem.textContent = `${this.computeTween(0, 100)}%`;
      };
      },

      // Notice how the backward generator would be equivalent to running the forward generator
      // and reversing the effect of the mutator. That means that the mutator generator is
      // invertible. (Note that it may not always be the case that BOTH the keyframes
      // generators and the forward mutator generator are invertible).
      // --------------------------------------------------------------------------------------
      mutatorGenerator_rewind: () => {
      // return Mutator
      return () => {
      this.domElem.textContent = `${this.computeTween(100, 0)}%`;
      };
      },
      };
      },
      defaultConfig: {
      duration: 1000,
      easing: "ease-in",
      },
      immutableConfig: {
      // this means that the translation is added onto the element's position
      // instead of replacing it
      composite: 'accumulate',
      },
      },

      // Exactly equivalent to flyOutLeft
      flyOutLeft_shortcut: {
      buildFrameGenerators() {
      const computeTranslationStr = () => {
      const orthogonalDistance = -(this.domElem.getBoundingClientRect().right);
      const translationString = `${orthogonalDistance}px 0px`;
      return translationString;
      }

      // return EffectFrameGeneratorSet
      return {
      keyframesGenerator_play: () => {
      // return Keyframes (Keyframe[])
      return [
      {translate: computeTranslationStr()}
      ];
      },

      mutatorGenerator_play: () => {
      // return Mutator
      return () => {
      this.domElem.textContent = `${this.computeTween(0, 100)}%`;
      };
      },
      };
      },
      defaultConfig: {
      duration: 1000,
      easing: "ease-in",
      },
      immutableConfig: {
      composite: 'accumulate',
      },
      },
      },
      });
      // EXAMPLES WHERE BACKWARD GENERATORS CANNOT BE OMITTED
      const clipFactories = webchalk.createAnimationClipFactories({
      additionalMotionEffectBank: {
      // a preset animation effect for translating a certain number of pixels to the right
      translateRight: {
      buildFrameGenerators(numPixels: number) {
      // a helper function you wrote that will exist within a closure scoped to buildFrameGenerators()
      const createTranslationString = () => {
      if (numPixels <= 0) { throw RangeError(`Number of pixels must exceed 0.`) }
      const translationString = `${numPixels}px`;
      return translationString;
      }

      // return EffectFrameGeneratorSet
      return {
      keyframesGenerator_play: () => {
      // return Keyframes (Keyframe][])
      return [
      {translate: createTranslationString()} // Keyframe
      ];
      },
      // keyframesGenerator_rewind() must be specified because reversing the keyframes produced
      // by keyframesGenerator_play() would not have the intended effect (due to
      // {composite: 'accumulate'}, trying to simply use the reversal of
      // {translate: createTranslationString()} from keyframesGenerator_play() would actually
      // cause the target element to jump an additional numPixels pixels to the right
      // before sliding left, which is not the intended rewinding effect).
      keyframesGenerator_rewind: () => {
      // return Keyframes (Keyframe[])
      return [
      {translate: '-'+createTranslationString()}, // Keyframe
      ];
      }
      };
      },
      immutableConfig: {
      // this means that the translation is added onto the element's position
      // instead of replacing it
      composite: 'accumulate',
      },
      },

      // a preset animation effect for scrolling to a specific point on the page.
      scrollTo: {
      buildFrameGenerators(yPosition: number) {
      const initialPosition = this.domElem.scrollTop;

      // return EffectFrameGeneratorSet
      return {
      // The mutation is to use the scrollTo() method on the element.
      // Thanks to computeTween(), there will be a smooth scroll
      // from initialPosition to yPosition
      mutatorGenerator_play: () => {
      // return Mutator
      return () => {
      this.domElem.scrollTo({
      top: this.computeTween(initialPosition, yPosition),
      behavior: 'instant'
      });
      };
      },

      // The forward mutation loop is not invertible because reversing it requires
      // re-computing the element's scroll position at the time of rewinding
      // (which may have since changed for any number of reasons, including user
      // scrolling, size changes, etc.). So we must define mutatorGenerator_rewind()
      // to do exactly that.
      mutatorGenerator_rewind: () => {
      // return Mutator
      return () => {
      const currentPosition = this.domElem.scrollTop;
      this.domElem.scrollTo({
      top: this.computeTween(currentPosition, initialPosition),
      behavior: 'instant'
      });
      };
      }
      };
      },
      },
      }
      });
    arguments: any
    caller: Function
    length: number
    name: string

    Returns the name of the function. Function names are read-only and can not be changed.

    prototype: any
    • Determines whether the given value inherits from this function if this function was used as a constructor function.

      A constructor function can control which objects are recognized as its instances by 'instanceof' by overriding this method.

      Parameters

      • value: any

      Returns boolean

    • Calls the function, substituting the specified object for the this value of the function, and the specified array for the arguments of the function.

      Parameters

      • this: Function
      • thisArg: any

        The object to be used as the this object.

      • OptionalargArray: any

        A set of arguments to be passed to the function.

      Returns any

    • For a given function, creates a bound function that has the same body as the original function. The this object of the bound function is associated with the specified object, and has the specified initial parameters.

      Parameters

      • this: Function
      • thisArg: any

        An object to which the this keyword can refer inside the new function.

      • ...argArray: any[]

        A list of arguments to be passed to the new function.

      Returns any

    • Calls a method of an object, substituting another object for the current object.

      Parameters

      • this: Function
      • thisArg: any

        The object to be used as the current object.

      • ...argArray: any[]

        A list of arguments to be passed to the method.

      Returns any

    • Returns a string representation of a function.

      Returns string