---
# System prepended metadata

title: Copy-Pasting Keyframes in Action Editor

---

# Copy-Pasting Keyframes in Action Editor

This is a draft for a design for copy-pasting keyframes in the Action editor. The main goal is to add the necessary changes for working with slotted Actions.

> [!Note]
> 
> Bug report:
> : [#129690: Anim: pasting keyframes in Action editor sends them to the wrong slot](https://projects.blender.org/blender/blender/issues/129690)
>
> PR that adds the suggested approach to the tech docs:
> : [#103: Anim: document slot-aware copy-paste of keyframes in Action editor](https://projects.blender.org/blender/blender-developer-docs/pulls/103)

## The Problem

These two don't mix very well:

1. Single interaction, just Ctrl+C / Ctrl+V. Just one option to flip poses.
2. Long list of intended behaviours, depending on what was copied and what is selected when pasting.

This list of behaviours can be roughly be broken down into the following categories:

1. Dumb copy-paste of keys **to the same channels**. This can be from one frame to another, between Actions, between blend files, etc. But each key goes to an F-Curve with the same data path and array index as where it was copied from.
2. Copy-paste of keys **between channels**. For example, using rotation keys to scale F-Curves, as reference for further animation.


## Current Use Cases

What I (Sybren) was able to figure out of the current code, these use cases are supported:

- 1 → 1: just copy.
- 1 → N: just copy when the data path matches.
- N → 1: for things like copying location XYZ, and pasting to one channel. This should pick up either the X, Y, or Z component, depending on what is being pasted to.
- N → N: for copying entire poses (so exact matches), or copying location XYZ to scale XYZ (so only matching on array index).

### Matching Rules

When pasting, the copied F-Curves are matched to the target F-Curves, using increasingly accepting rule sets. If a rule set matches at least one curve, the following rule sets are ignored.

1. Match exactly by the F-Curve's data path (like `pose.bones["name"].location`) + array index. The name can be flipped when animating bones and flipping is requested.
2. Match by the animated property name, so only when ending in `location` when the copied data path was `pose.bones["name"].location`. Plus the array index.
3. Match by array index only.

### Exceptions

Depending on how many curves were copied from, and how many curves were copied to, there are exceptions to the above:

Copied from one curve
: array index is ignored

Pasting to one curve
: data path is ignored

## Pasting Process

Blender follows this pseudo-code when pasting:

```python=
for target_fcurve in selected_fcurves:
    # Find a matching F-Curve to paste onto the target:
    source_fcurve = find_match(copy_buffer, target_fcurve)
    
    # If we found one, copy it to the target F-Curve
    if source_fcurve:
        copy(source_fcurve, target_fcurve)
```

This means that slots are completely ignored, and that thus all slots receive the copied data (if they have matching F-Curves, which is likely when animating two similarly rigged characters).

## Adding Slotted Actions support

Needs good list of use cases.

### Detectable Things

These two may interfere with each other, we should pick one:

1. One or more Slot channels is selected in the channel list.
2. The active Object's assigned slot (in the Action editor header).

Probably 1. is better, as 2. only works for objects (so wouldn't be able to paste object curves to material slot).

**Big question:** how does this interact with the matching rules that are already in Blender?

## Ponderings & Direction

It's probably the best to **create multiple paste operators**. Those can then be shown as a choice in a popup (like the Ctrl+P for parenting) or a pie menu, or people can directly bind them to the hotkeys they want.

Paste to Same Channels:
: Would go **to the same channels** as the copied keys were on. This ignores the selection of the F-Curves. This can thus also be used to start animating something, by pasting into an empty Action.

Paste to Selected Channels:
: This is the behaviour that's now in Blender, which **takes the channel selection into account** to determine what you want to paste to. This means the F-Curves must already exist and thus be animated to receive pasted data.

### Visibility & Existence

Pasting should only happen to *visible* F-Curves.

Pasting should only happen to *valid* F-Curves. When pasting from one rig to another, this should skip animation of bones that do not exist in the target rig.

### Selected F-Curves

Selection is a bit borken. Selecting a group does _not_ select the F-Curves in it, so it's hard to select all F-Curves in a range. You have to expand all the groups before range-selecting.


## New Behaviour

![2025-01-20-1650-copy paste keyframes behaviour](https://hackmd.io/_uploads/r1D_fl2v1e.jpg)


# Animation Tools: Copy-Paste in Action Editor

This chapter describes how the copy-pasting of animation keys works in the Action editor.

<style>
  .copy {
    color:#3af;
  }
  .paste {
    color:#3fa;
  }
</style>

Since some parts of the behavior are determined by what was copied, and other parts depend on what is selected when pasting, colors are used to distinguish between those:

- <span class="copy">blue</span> indicates information at the time of copying, and
- <span class="paste">green</span> indicates information at the time of pasting.

Copy-Paste of animation keys in the Action editor works as follows:

1. <span class='copy'>Key selection</span> indicates what gets copied. For copying, the selection state of the channels (F-Curves, slots, etc.) is irrelevant.
2. Pressing Ctrl+C copies those keys, recording the F-Curves and Action slots they came from.
3. <span class='paste'>Channel selection (F-Curves, slots)</span> indicates what gets pasted, and where. For pasting, key selection is irrelevant.

Note that pasting should **never**:

- **Create new F-Curves**. Only already-existing curves should be pasted into.
- **Paste into invisible F-Curves**. Collapsed groups and other summary-like channels also count as "visible". But when "Only Show Selected" is enabled, the animation of non-selected objects/bones should not be touched.


## F-Curve Matching

The diagram below describes how target F-Curves (i.e. the ones being pasted into) are chosen, and how they are matched to the copied keyframes.

The following shorthand is used:

- `R`: RNA data path of the F-Curve (like `pose.bones["Root"].location`)
- `I`: Array Index of the F-Curve (like `1` for the Y-location).
- `N`: The identifier of the property the F-Curve animates (like `location`).

Combinations are concatenated, so `RI` means the combination of (RNA path, array index).

```mermaid
flowchart TD

  classDef copy stroke:#3af;
  classDef paste stroke:#3fa;
  classDef choice stroke:#a3f;

  num_fcurves_selected("How many F-Curves selected to paste into?"):::paste
  original_ri["RI of copied F-Curve(s)"]:::choice

  fcurves_copied("How many F-Curves copied?"):::copy
  slots_copied("Copied from how many slots?"):::copy

  ri_of_target("Selected F-Curve"):::choice
  degrade("Degrade (RI, NI, I)<br>matching copied to selected F-Curves"):::choice
  degrade_within_slot("Degrade (RI, NI, I)<br>but keep within slot<br>of the same name"):::choice

  num_fcurves_selected -->|None| original_ri
  num_fcurves_selected -->|Single| fcurves_copied
  num_fcurves_selected -->|Multiple| slots_copied

  fcurves_copied -->|Single| ri_of_target
  fcurves_copied -->|Multiple| degrade

  slots_copied -->|Single| degrade
  slots_copied -->|Multiple| degrade_within_slot

```

The "Degrade" behavior works as follows. The first rule that matches anything "wins", and in that case subsequent rules are not visited any more.

1. `RI`: Exact match on (RNA data path, array index). So if you copied from (`pose.bones["Root"].location, 1`) and that is among the selected F-Curves too, this rule matches.
2. `NI`: Match (property name, array index). So in the above example, it would also match if you have `pose.bones["Arm_L"].location` selected.
3. `I`: Match only the array index. So if you have Location X/Y/Z copied, and selected an "Y thing", it will paste the Y location keys there.


## Slot Matching

The diagram below describes how the target slot is chosen when pasting.

```mermaid
flowchart TD

  classDef copy stroke:#3af;
  classDef paste stroke:#3fa;
  classDef choice stroke:#a3f;

  any_fcurve_selected(Any F-curve selected?):::paste
  any_slot_selected(Any slot selected?):::paste
  copied_from_slots(Copied from slots?):::copy

  slot_of_target_fcurves["Use slot(s) of<br>selected F-curves"]:::choice
  all_selected_slots["Duplicate into<br>all selected slots"]:::choice
  match_by_name["Match slots by name<br>(fallback to active)"]:::choice

  any_fcurve_selected -->|One or more| slot_of_target_fcurves
  any_fcurve_selected -->|None| any_slot_selected

  any_slot_selected -->|One or more| copied_from_slots
  any_slot_selected -->|None| match_by_name

  copied_from_slots -->|One slot| all_selected_slots
  copied_from_slots -->|Multiple slots| match_by_name

```
