# Removing animation keyframes outside of a specified range

I have over 1000 animation files that I want to "crop" off keyframes outside of a specified range.

Keyframes all start at frame 1 instead of frame 0, as such I want to shift all keyframes by one frame such that the animations start at frame 0.

I have an int variable named "framelength" which stores the framenumber of the last good frame. I want to remove every keyframe after this value.

The most similar code I was able to find online was:

How to remove all only rotation keyframes from current action with Python? and Editing fcurve.keyframe points in FAST mode? Both were written by BatFINGER.

I tried using a combination of the two to achieve what I want, but am struggling with deleting only certain keyframes.

ob = context.object
ad = ob.animation_data
action = ad.action if ad else None
if action:
for fc in action.fcurves:
sel = list(bool(i > int(framelength)) for i in range(len(fc.keyframe_points)))
for i in range(len(fc.keyframe_points)):
if i>35:
fc.pop()


Above is my attempt at solving the problem.

• Here's another that may be useful, creates a new sliced action. To make the default start frame 0 change to _kfs[:,0] -= start_frame. For when use shift is set. blender.stackexchange.com/a/214899/15543 May 8 '21 at 10:21

## 1 Answer

I got it working thanks to batFINGER's comment.

My final code looked like this:

import numpy as np
def action_slice(action, start_frame, end_frame, shift=True):
copy = bpy.data.actions.new(action.name)
copy.id_root = action.id_root

for fcurve in action.fcurves:
kfs = np.empty(len(fcurve.keyframe_points) << 1)
fcurve.keyframe_points.foreach_get("co", kfs)
kfs = kfs.reshape((-1, 2))
_fc = copy.fcurves.new(
fcurve.data_path,
index = fcurve.array_index
)
_fc.keyframe_points.add(0)
_kfs = kfs[
np.logical_and(
kfs[:,0] >= start_frame,
kfs[:,0] <= end_frame
)
]
if shift:
_kfs[:,0] -= start_frame
_fc.keyframe_points.add(_kfs.shape[0])
_fc.keyframe_points.foreach_set("co", _kfs.ravel())
return copy

def object_do_slice(string, endframe):
ob = bpy.data.objects.get(string)#context.object
ad = ob.animation_data
action = ad.action if ad else None
if action:
ad.action = action_slice(action, 1, endframe, shift=True)

object_do_slice("Root",framelength+1)