# How to Use the jumpToAction Method in OpenMAIC's Playback Engine

> Master the jumpToAction method in OpenMAIC's Playback Engine. Effortlessly move the playback cursor to any action index without replaying. Learn how to optimize your lecture playback now.

- Repository: [MAIC/OpenMAIC](https://github.com/THU-MAIC/OpenMAIC)
- Tags: how-to-guide
- Published: 2026-09-03

---

**The `jumpToAction` method allows you to move the playback cursor to a specific action index without replaying the entire lecture, provided the engine is not in live mode and the target lies within the reconstructable prefix of the action history.**

The OpenMAIC Playback Engine ([`lib/playback/engine.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/lib/playback/engine.ts)) drives lecture playback and navigation through recorded sequences of whiteboard actions. Unlike sequential playback that processes every frame, `jumpToAction` enables instant navigation by silently reconstructing the canvas state up to a specific target index. This article covers the prerequisites, internal mechanics, and practical integration patterns for programmatic navigation.

## Prerequisites for Calling jumpToAction

Before invoking `jumpToAction`, the engine validates two critical conditions in the `canJumpToAction` helper (lines 174–180 of [`lib/playback/engine.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/lib/playback/engine.ts)):

- **Not in live mode**: The engine must be processing recorded playback. Jumping is disabled during live discussions to prevent synchronization conflicts.
- **Within reconstructable prefix**: The target index must fall within the portion of the action list that can be safely replayed as whiteboard-only actions. The helper `canJumpWithinReconstructablePrefix` verifies that all actions before the target can be silently executed without side effects.

Always validate jumps using `engine.canJumpToAction(targetIndex)` before calling the main method to avoid runtime failures.

## How jumpToAction Works Internally

When `jumpToAction(targetIndex, options)` executes successfully (implementation spans lines 182–218), it performs the following operations in order:

1. **Invalidates the current generation** to cancel any pending timers or async operations from the previous playback position.
2. **Resets visual state** via `actionEngine.resetPlaybackVisualState()` to clear the canvas before reconstruction.
3. **Silently executes** all whiteboard actions from the start up to the target index without triggering animations or audio playback.
4. **Updates internal pointers** (`sceneIndex` and `actionIndex`) to reflect the new position in the timeline.
5. **Fires the `onProgress` callback** so UI components can synchronize their state with the new playback position.
6. **Handles autoplay logic**: If the `autoplay` option is `true` (default when the engine is already playing), playback continues immediately from the new position; otherwise, the engine pauses.

The method returns a `Promise<boolean>` indicating success or failure.

## Implementation Workflow

Standard integration follows a three-step pattern:

1. **Check feasibility**: Call `engine.canJumpToAction(targetIndex)` to verify the jump is legal.
2. **Execute jump**: Await `engine.jumpToAction(targetIndex, { autoplay?: boolean })`.
3. **Handle result**: Check the returned boolean to determine if navigation succeeded or if the generation changed during execution.

## Practical Code Examples

### Jumping with Autoplay from a UI Button

This example demonstrates a button that jumps to action 12 and immediately resumes playback:

```typescript
import { PlaybackEngine } from '@/lib/playback/engine';

function JumpButton({ engine }: { engine: PlaybackEngine }) {
  const goToAction = async (index: number) => {
    if (!engine.canJumpToAction(index)) {
      alert('Cannot jump to this point – live mode or unreconstructable prefix.');
      return;
    }
    const success = await engine.jumpToAction(index, { autoplay: true });
    if (!success) {
      console.error('Jump failed – generation may have changed.');
    }
  };

  return <button onClick={() => goToAction(12)}>Jump to Action 12</button>;
}

```

### Navigation Without Autoplay for Slide Selection

Use this pattern when users select a specific slide in a sidebar and want to pause for examination:

```typescript
function SlideNavigator({ engine }: { engine: PlaybackEngine }) {
  const onSelectSlide = async (actionIdx: number) => {
    // Pause playback after jumping so the user can explore the slide first
    const jumped = await engine.jumpToAction(actionIdx, { autoplay: false });
    if (jumped) {
      console.log(`Paused at action ${actionIdx}`);
    }
  };

  return (
    <ul>
      {[0, 5, 10].map(idx => (
        <li key={idx} onClick={() => onSelectSlide(idx)}>
          Slide {idx}
        </li>
      ))}
    </ul>
  );
}

```

### Unit Test Patterns

The test suite in [`tests/playback/action-navigation.test.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/tests/playback/action-navigation.test.ts) demonstrates edge case handling:

```typescript
// Valid jump within reconstructable prefix
expect(await engine.jumpToAction(saved!.actionIndex, { autoplay: false })).toBe(true);

// Out-of-range indices return false
expect(await engine.jumpToAction(-1)).toBe(false);      
expect(await engine.jumpToAction(99)).toBe(false);     

```

The UI component [`components/edit/PlaybackChromeRoot.tsx`](https://github.com/THU-MAIC/OpenMAIC/blob/main/components/edit/PlaybackChromeRoot.tsx) provides a production example of integrating `jumpToAction` for resume-point selection.

## Summary

- **Always validate first**: Use `canJumpToAction` to check live mode status and reconstructable prefix boundaries before attempting navigation.
- **Silent reconstruction**: The method rebuilds canvas state by executing whiteboard actions without visual or audio playback, making it efficient for large leaps in the timeline.
- **Generation safety**: The engine invalidates the current generation to prevent race conditions, returning `false` if the jump cannot complete atomically.
- **Flexible control**: The `autoplay` option lets you choose between pausing at the destination or continuing playback seamlessly.

## Frequently Asked Questions

### Can I use jumpToAction during a live lecture?

No. The `canJumpToAction` method explicitly returns `false` when the engine is in live mode (lines 174–180 of [`lib/playback/engine.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/lib/playback/engine.ts)). This restriction prevents synchronization conflicts between the instructor's live actions and client-side navigation. Jumping is only supported for recorded playback sessions.

### What happens if the target index is outside the reconstructable prefix?

The method returns `false` without modifying the playback state. The reconstructable prefix includes all actions that can be safely replayed as whiteboard-only operations without triggering side effects like audio playback or external API calls. Indices beyond this boundary are considered unsafe for silent reconstruction.

### Why does jumpToAction return a boolean instead of throwing exceptions?

The boolean return pattern follows the engine's design philosophy of graceful degradation. A `false` result typically indicates that the generation changed during the jump operation or the preconditions failed, allowing your UI to handle the failure case (such as showing a loading spinner or retry button) without crashing the component tree.

### How do I synchronize my UI components with the new playback position?

The engine automatically fires the `onProgress` callback after updating the internal `sceneIndex` and `actionIndex` pointers (lines 206–218). Connect your UI state management to this callback to ensure scrubber bars, slide thumbnails, and timeline indicators reflect the new position immediately after `jumpToAction` completes.