> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/BintzGavin/helios/llms.txt
> Use this file to discover all available pages before exploring further.

# Sequencing

> Timeline sequencing utilities for orchestrating complex animations in Helios

Sequencing functions help you organize and coordinate multiple animations across your composition's timeline. These utilities make it easy to create complex choreography without manual frame calculations.

## sequence()

Calculates the local time and progress of a sequence relative to a start frame.

```typescript theme={null}
import { sequence } from '@helios-project/core';

const seq = sequence({
  frame: currentFrame,
  from: 30,
  durationInFrames: 60
});

if (seq.isActive) {
  const opacity = seq.progress;
}
```

### Parameters

<ParamField path="options" type="SequenceOptions" required>
  Sequence configuration object

  <Expandable title="properties">
    <ParamField path="frame" type="number" required>
      Current frame number from your composition
    </ParamField>

    <ParamField path="from" type="number" required>
      Starting frame for this sequence
    </ParamField>

    <ParamField path="durationInFrames" type="number">
      Duration in frames. If undefined, sequence is active indefinitely after start.
    </ParamField>
  </Expandable>
</ParamField>

### Returns

`SequenceResult` object with the following properties:

<ParamField path="localFrame" type="number">
  Frame number relative to the sequence start (frame - from)
</ParamField>

<ParamField path="relativeFrame" type="number">
  Alias for localFrame, for clarity
</ParamField>

<ParamField path="progress" type="number">
  Normalized progress from 0 to 1. Always 0 if no duration specified.
</ParamField>

<ParamField path="isActive" type="boolean">
  True if the current frame is within the sequence's time range
</ParamField>

### Examples

#### Basic sequence

```typescript theme={null}
import { sequence } from '@helios-project/core';

function SequencedElement({ frame }) {
  const seq = sequence({
    frame,
    from: 30,
    durationInFrames: 60
  });
  
  if (!seq.isActive) return null;
  
  return (
    <div style={{ opacity: seq.progress }}>
      Visible from frame 30-90
    </div>
  );
}
```

#### Using local frame

```typescript theme={null}
const seq = sequence({ frame, from: 30, durationInFrames: 90 });

if (seq.isActive) {
  // seq.localFrame goes from 0 to 89
  const x = interpolate(seq.localFrame, [0, 90], [0, 800]);
}
```

#### Infinite sequence

```typescript theme={null}
// Sequence starts at frame 60 and runs until end of composition
const seq = sequence({ frame, from: 60 });

if (seq.isActive) {
  // Active from frame 60 onward
}
```

## series()

Arranges items sequentially, automatically calculating start times based on each item's duration.

```typescript theme={null}
import { series } from '@helios-project/core';

const scenes = series([
  { id: 'intro', durationInFrames: 60 },
  { id: 'main', durationInFrames: 120 },
  { id: 'outro', durationInFrames: 60 }
]);

// scenes[0].from = 0
// scenes[1].from = 60
// scenes[2].from = 180
```

### Parameters

<ParamField path="items" type="T[]" required>
  Array of items with `durationInFrames` and optional `offset` properties
</ParamField>

<ParamField path="startFrame" type="number" default="0">
  Starting frame for the first item in the series
</ParamField>

### Returns

`Array<T & { from: number }>` - Original items with `from` property added

### Examples

#### Sequential scenes

```typescript theme={null}
import { series, sequence } from '@helios-project/core';

const scenes = series([
  { name: 'Intro', durationInFrames: 90 },
  { name: 'Main', durationInFrames: 180 },
  { name: 'Credits', durationInFrames: 60 }
]);

function VideoComposition({ frame }) {
  return (
    <>
      {scenes.map((scene) => {
        const seq = sequence({
          frame,
          from: scene.from,
          durationInFrames: scene.durationInFrames
        });
        
        if (!seq.isActive) return null;
        
        return <Scene key={scene.name} name={scene.name} progress={seq.progress} />;
      })}
    </>
  );
}
```

#### With offsets

```typescript theme={null}
const scenes = series([
  { id: 'a', durationInFrames: 60 },
  { id: 'b', durationInFrames: 60, offset: -10 }, // Starts 10 frames before 'a' ends
  { id: 'c', durationInFrames: 60, offset: 20 }   // Starts 20 frames after 'b' ends
]);

// scenes[0].from = 0
// scenes[1].from = 50  (60 - 10)
// scenes[2].from = 130 (50 + 60 + 20)
```

#### Custom start frame

```typescript theme={null}
const delayedScenes = series(
  [
    { durationInFrames: 60 },
    { durationInFrames: 90 }
  ],
  30 // Start at frame 30
);

// delayedScenes[0].from = 30
// delayedScenes[1].from = 90
```

## stagger()

Staggers items at a fixed interval, useful for animating lists and grids.

```typescript theme={null}
import { stagger } from '@helios-project/core';

const items = stagger(
  ['Apple', 'Banana', 'Cherry'],
  10  // 10 frames between each
);

// items[0].from = 0
// items[1].from = 10
// items[2].from = 20
```

### Parameters

<ParamField path="items" type="T[]" required>
  Array of items to stagger
</ParamField>

<ParamField path="interval" type="number" required>
  Number of frames between each item's start time
</ParamField>

<ParamField path="startFrame" type="number" default="0">
  Frame to start the first item at
</ParamField>

### Returns

`Array<T & { from: number }>` - Items with `from` property added

### Examples

#### Staggered list animation

```typescript theme={null}
import { stagger, interpolate } from '@helios-project/core';

function StaggeredList({ items, frame }) {
  const staggeredItems = stagger(items, 8); // 8 frames delay between each
  
  return (
    <div>
      {staggeredItems.map((item, i) => {
        const opacity = interpolate(
          frame,
          [item.from, item.from + 20],
          [0, 1],
          { extrapolateRight: 'clamp' }
        );
        
        const y = interpolate(
          frame,
          [item.from, item.from + 20],
          [20, 0],
          { extrapolateRight: 'clamp' }
        );
        
        return (
          <div key={i} style={{ opacity, transform: `translateY(${y}px)` }}>
            {item}
          </div>
        );
      })}
    </div>
  );
}
```

#### Grid stagger

```typescript theme={null}
const grid = [
  ['A', 'B', 'C'],
  ['D', 'E', 'F'],
  ['G', 'H', 'I']
];

const flatGrid = grid.flat();
const staggeredGrid = stagger(flatGrid, 5, 30); // Start at frame 30
```

## shift()

Shifts the start times of all items by a fixed offset.

```typescript theme={null}
import { series, shift } from '@helios-project/core';

const scenes = series([
  { durationInFrames: 60 },
  { durationInFrames: 90 }
]);

const delayedScenes = shift(scenes, 30); // Delay everything by 30 frames
```

### Parameters

<ParamField path="items" type="T[]" required>
  Array of items with a `from` property
</ParamField>

<ParamField path="offset" type="number" required>
  Number of frames to shift by (can be negative)
</ParamField>

### Returns

`T[]` - Items with updated `from` values

### Examples

#### Delaying a sequence

```typescript theme={null}
const scenes = series([
  { durationInFrames: 60 },
  { durationInFrames: 90 }
]);

const delayed = shift(scenes, 60); // Start 60 frames later
```

#### Creating variations

```typescript theme={null}
const baseSequence = stagger(['A', 'B', 'C'], 10);

const earlyVersion = shift(baseSequence, -20);
const lateVersion = shift(baseSequence, 40);
```

## Common patterns

### Chapter-based composition

```typescript theme={null}
import { series, sequence } from '@helios-project/core';

const chapters = series([
  { title: 'Opening', durationInFrames: 90 },
  { title: 'Presentation', durationInFrames: 240 },
  { title: 'Demonstration', durationInFrames: 180 },
  { title: 'Conclusion', durationInFrames: 90 }
]);

function VideoComposition({ frame }) {
  return (
    <>
      {chapters.map((chapter) => {
        const seq = sequence({
          frame,
          from: chapter.from,
          durationInFrames: chapter.durationInFrames
        });
        
        return seq.isActive ? (
          <Chapter key={chapter.title} {...chapter} progress={seq.progress} />
        ) : null;
      })}
    </>
  );
}
```

### Overlapping transitions

```typescript theme={null}
const scenes = series([
  { id: 'a', durationInFrames: 90 },
  { id: 'b', durationInFrames: 90, offset: -15 }, // 15 frame overlap
  { id: 'c', durationInFrames: 90, offset: -15 }
]);

function Scene({ scene, frame }) {
  const seq = sequence({
    frame,
    from: scene.from,
    durationInFrames: scene.durationInFrames
  });
  
  // Fade in during first 15 frames, fade out during last 15 frames
  let opacity = 1;
  if (seq.localFrame < 15) {
    opacity = seq.localFrame / 15;
  } else if (seq.localFrame > scene.durationInFrames - 15) {
    opacity = (scene.durationInFrames - seq.localFrame) / 15;
  }
  
  return <div style={{ opacity }}>Scene content</div>;
}
```

### Multi-track timeline

```typescript theme={null}
const videoTrack = series([
  { type: 'clip', source: 'intro.mp4', durationInFrames: 120 },
  { type: 'clip', source: 'main.mp4', durationInFrames: 300 }
]);

const overlayTrack = stagger(
  ['Title', 'Subtitle', 'Call to action'],
  60,
  30 // Start at frame 30
);

function Timeline({ frame }) {
  return (
    <>
      <VideoLayer clips={videoTrack} frame={frame} />
      <OverlayLayer items={overlayTrack} frame={frame} />
    </>
  );
}
```

### Combining with animation helpers

```typescript theme={null}
import { series, sequence, interpolate, spring, Easing } from '@helios-project/core';

const elements = stagger(
  ['First', 'Second', 'Third', 'Fourth'],
  12
);

function AnimatedElements({ frame }) {
  return elements.map((item, i) => {
    const startFrame = item.from;
    
    // Use spring for natural entrance
    const scale = spring({
      frame: frame - startFrame,
      fps: 30,
      from: 0,
      to: 1,
      config: { stiffness: 150, damping: 12 }
    });
    
    // Use interpolate with easing for position
    const x = interpolate(
      frame,
      [startFrame, startFrame + 24],
      [-100, 0],
      { easing: Easing.cubic.out, extrapolateRight: 'clamp' }
    );
    
    const opacity = frame >= startFrame ? 1 : 0;
    
    return (
      <div
        key={i}
        style={{
          opacity,
          transform: `translateX(${x}px) scale(${scale})`
        }}
      >
        {item}
      </div>
    );
  });
}
```
