Another option if you don't want to create a pre-comp:
Make your mask and set the keyframes and apply this expression to the mask path property:
valueAtTime(time % key(numKeys).time)
This is basically an implementation of the loopOut function, but it works for all properties, including custom ones like mask shapes.
How it works: valueAtTime
returns the value of the property at a given time, so to loop the property we need a value that goes from 0 and rises until the playhead gets to the last keyframe and then the value loops back to 0.
The expression key(numKeys).time
returns the time of the last key (e.g. if there are 3 keys it will be key(3).time
). The %
operator is the modulus operator, which gives you the remainder when you divide the first term by the second. So if you find the remainder when dividing the current time (time
) by the time of the last keyframe it will return a value that starts at 0 and rises in synch with time
until the playhead reaches the last keyframe at which point the current time will divide exactly into the time of the last keyframe, so the remainder will go back to 0 then start rising in synch with the playhead, rinse, repeat.
A useful feature of this expression is that you can speed it up and down by multiplying time
by another factor, e.g. time * 2 % key(numKeys).time
would play back the animation in double speed.