Skip to main content
Actions are the trigger layer for user-initiated operations in OpenCut. They provide a unified interface for keyboard shortcuts, UI interactions, and programmatic invocations.

Overview

The actions system separates “what to do” (the action) from “how to trigger it” (shortcuts, buttons, menu items). All action definitions live in a single source of truth: @/lib/actions/definitions.ts.

When to use actions

Use invokeAction() for user-triggered operations in components:
import { invokeAction } from '@/lib/actions';

// Good - uses action system with UX feedback
const handleSplit = () => invokeAction("split");

// Avoid - bypasses UX layer (toasts, validation feedback)
const handleSplit = () => editor.timeline.splitElements({ ... });
Direct editor.xxx() calls are for internal use (commands, tests, complex multi-step operations).

invokeAction()

Invokes an action by name, optionally passing arguments and trigger information.
action
TAction
required
The action name to invoke (e.g., "toggle-play", "split", "undo")
args
TActionArgsMap[A]
Arguments for actions that accept parameters. Only required for actions with args:
  • seek-forward / seek-backward: { seconds: number }
  • jump-forward / jump-backward: { seconds: number }
trigger
TInvocationTrigger
How the action was triggered. Values: "keypress" or "mouseclick". Used for analytics and conditional behavior.

Examples

import { invokeAction } from '@/lib/actions';

// Simple action without arguments
invokeAction("toggle-play");

// Action with arguments
invokeAction("seek-forward", { seconds: 5 });

// Action with trigger information
invokeAction("split", undefined, "keypress");

Action handlers

Actions are handled using the useActionHandler hook in React components. This connects action invocations to their implementations.
import { useActionHandler } from '@/hooks/actions/use-action-handler';
import { useEditor } from '@/hooks/use-editor';

function MyComponent() {
  const editor = useEditor();

  useActionHandler(
    "toggle-play",
    () => {
      editor.playback.toggle();
    },
    undefined, // isActive: when to bind this handler
  );
}

useActionHandler

Registers a handler for a specific action.
action
TAction
required
The action name to handle
handler
TActionFunc<A>
required
Function to execute when action is invoked. Receives action arguments and optional trigger.
isActive
boolean | MutableRefObject<boolean> | undefined
required
Controls when the handler is active:
  • undefined: Always active
  • boolean: Static active state
  • MutableRefObject<boolean>: Dynamic active state (useful for conditional handlers)

Available actions

All actions are defined in the ACTIONS constant in @/lib/actions/definitions.ts.

Playback

ActionDescriptionDefault ShortcutsArguments
toggle-playPlay/Pausespace, k-
stop-playbackStop playback--
seek-forwardSeek forward 1 secondl{ seconds?: number }
seek-backwardSeek backward 1 secondj{ seconds?: number }
ActionDescriptionDefault ShortcutsArguments
frame-step-forwardFrame step forwardright-
frame-step-backwardFrame step backwardleft-
jump-forwardJump forward 5 secondsshift+right{ seconds?: number }
jump-backwardJump backward 5 secondsshift+left{ seconds?: number }
goto-startGo to timeline starthome, enter-
goto-endGo to timeline endend-

Editing

ActionDescriptionDefault ShortcutsArguments
splitSplit elements at playheads-
split-leftSplit and remove leftq-
split-rightSplit and remove rightw-
delete-selectedDelete selected elementsbackspace, delete-
copy-selectedCopy selected elementsctrl+c-
paste-copiedPaste elements at playheadctrl+v-
toggle-snappingToggle snappingn-

Selection

ActionDescriptionDefault ShortcutsArguments
select-allSelect all elementsctrl+a-
duplicate-selectedDuplicate selected elementctrl+d-
toggle-elements-muted-selectedMute/unmute selected elements--
toggle-elements-visibility-selectedShow/hide selected elements--

History

ActionDescriptionDefault ShortcutsArguments
undoUndoctrl+z-
redoRedoctrl+shift+z, ctrl+y-

Timeline

ActionDescriptionDefault ShortcutsArguments
toggle-bookmarkToggle bookmark at playhead--

Action definition

Each action is defined with the following properties:
description
string
required
Human-readable description of what the action does
category
TActionCategory
required
Category for grouping actions. Values: "playback", "navigation", "editing", "selection", "history", "timeline", "controls"
defaultShortcuts
ShortcutKey[]
Array of default keyboard shortcuts for this action
args
Record<string, unknown>
Schema defining the arguments this action accepts

Adding new actions

To add a new action:
  1. Define the action in @/lib/actions/definitions.ts:
export const ACTIONS = {
  "my-action": {
    description: "What the action does",
    category: "editing",
    defaultShortcuts: ["ctrl+m"],
  },
  // ...
};
  1. Add the handler in @/hooks/use-editor-actions.ts (or your component):
useActionHandler(
  "my-action",
  () => {
    // Implementation
    editor.timeline.doSomething();
  },
  undefined,
);
  1. If the action takes arguments, add type definitions in @/lib/actions/types.ts:
export type TActionArgsMap = {
  "my-action": { value: number };
  // ...
};

Build docs developers (and LLMs) love