> ## 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.

# Transitions

> Simple transition and crossfade utilities for smooth scene changes in Helios

Helios provides lightweight transition utilities for creating smooth fades, crossfades, and custom transitions between scenes or states.

## transition()

Calculates transition progress over a specified duration with optional easing.

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

const progress = transition(frame, 30, 60); // 0 to 1 from frame 30 to 90
```

### Parameters

<ParamField path="frame" type="number" required>
  Current frame number
</ParamField>

<ParamField path="start" type="number" required>
  Frame to start the transition
</ParamField>

<ParamField path="duration" type="number" required>
  Duration of the transition in frames
</ParamField>

<ParamField path="options" type="TransitionOptions">
  Optional transition configuration

  <Expandable title="properties">
    <ParamField path="easing" type="(t: number) => number">
      Easing function to apply. Use functions from the `Easing` object.
    </ParamField>
  </Expandable>
</ParamField>

### Returns

`number` - Progress value:

* `0` before start frame
* `0` to `1` during transition
* `1` after transition completes

### Examples

#### Basic fade in

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

function FadeIn({ frame }) {
  const opacity = transition(frame, 0, 30); // Fade in over 30 frames
  
  return (
    <div style={{ opacity }}>
      Content fades in
    </div>
  );
}
```

#### With easing

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

function SmoothFadeIn({ frame }) {
  const opacity = transition(frame, 0, 60, {
    easing: Easing.cubic.out
  });
  
  return <div style={{ opacity }}>Smooth fade</div>;
}
```

#### Delayed transition

```typescript theme={null}
// Start transition at frame 120, duration 45 frames
const opacity = transition(frame, 120, 45);
```

#### Scale transition

```typescript theme={null}
function ScaleIn({ frame }) {
  const progress = transition(frame, 30, 60, {
    easing: Easing.back.out // Slight overshoot
  });
  
  const scale = 0.5 + (progress * 0.5); // Scale from 0.5 to 1
  
  return (
    <div style={{ transform: `scale(${scale})` }}>
      Content
    </div>
  );
}
```

## crossfade()

Calculates opacity values for crossfading between two elements.

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

const { in: opacityIn, out: opacityOut } = crossfade(frame, 60, 30);
```

### Parameters

<ParamField path="frame" type="number" required>
  Current frame number
</ParamField>

<ParamField path="start" type="number" required>
  Frame to start the crossfade
</ParamField>

<ParamField path="duration" type="number" required>
  Duration of the crossfade in frames
</ParamField>

<ParamField path="options" type="TransitionOptions">
  Optional transition configuration

  <Expandable title="properties">
    <ParamField path="easing" type="(t: number) => number">
      Easing function to apply to the crossfade
    </ParamField>
  </Expandable>
</ParamField>

### Returns

`CrossfadeResult` object with:

<ParamField path="in" type="number">
  Opacity for the incoming element (0 to 1)
</ParamField>

<ParamField path="out" type="number">
  Opacity for the outgoing element (1 to 0)
</ParamField>

### Examples

#### Basic crossfade between scenes

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

function SceneTransition({ frame }) {
  const fade = crossfade(frame, 90, 30); // 30-frame crossfade at frame 90
  
  return (
    <>
      <div style={{ opacity: fade.out }}>
        Scene A
      </div>
      <div style={{ opacity: fade.in }}>
        Scene B
      </div>
    </>
  );
}
```

#### Smooth crossfade with easing

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

function SmoothTransition({ frame }) {
  const fade = crossfade(frame, 60, 45, {
    easing: Easing.sine.inOut
  });
  
  return (
    <>
      <SceneA opacity={fade.out} />
      <SceneB opacity={fade.in} />
    </>
  );
}
```

#### Multiple overlapping scenes

```typescript theme={null}
function MultiSceneComposition({ frame }) {
  const fade1 = crossfade(frame, 90, 30);
  const fade2 = crossfade(frame, 180, 30);
  const fade3 = crossfade(frame, 270, 30);
  
  return (
    <>
      <Scene1 opacity={fade1.out} />
      <Scene2 opacity={Math.min(fade1.in, fade2.out)} />
      <Scene3 opacity={Math.min(fade2.in, fade3.out)} />
      <Scene4 opacity={fade3.in} />
    </>
  );
}
```

## Common patterns

### Scene manager with transitions

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

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

const TRANSITION_DURATION = 20;

function VideoComposition({ frame }) {
  return (
    <>
      {scenes.map((scene, i) => {
        const nextScene = scenes[i + 1];
        let opacity = 1;
        
        // Fade in at start
        if (frame < scene.from + TRANSITION_DURATION) {
          const fade = crossfade(
            frame,
            scene.from,
            TRANSITION_DURATION
          );
          opacity = fade.in;
        }
        
        // Fade out before next scene
        if (nextScene && frame > nextScene.from - TRANSITION_DURATION) {
          const fade = crossfade(
            frame,
            nextScene.from - TRANSITION_DURATION,
            TRANSITION_DURATION
          );
          opacity = fade.out;
        }
        
        return (
          <Scene key={scene.id} id={scene.id} opacity={opacity} />
        );
      })}
    </>
  );
}
```

### Custom transition effects

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

function SlideTransition({ frame, children }) {
  const progress = transition(frame, 0, 60, {
    easing: Easing.cubic.out
  });
  
  const x = (1 - progress) * 100; // Slide from right
  const opacity = progress;
  
  return (
    <div style={{
      transform: `translateX(${x}%)`,
      opacity
    }}>
      {children}
    </div>
  );
}

function ZoomTransition({ frame, children }) {
  const progress = transition(frame, 30, 45, {
    easing: Easing.back.out
  });
  
  const scale = 0.3 + (progress * 0.7); // Scale from 0.3 to 1
  const opacity = progress;
  
  return (
    <div style={{
      transform: `scale(${scale})`,
      opacity
    }}>
      {children}
    </div>
  );
}
```

### Transition with blur

```typescript theme={null}
function BlurTransition({ frame }) {
  const fade = crossfade(frame, 90, 30);
  
  // Blur increases during transition
  const blurOut = (1 - fade.out) * 10;
  const blurIn = (1 - fade.in) * 10;
  
  return (
    <>
      <div style={{
        opacity: fade.out,
        filter: `blur(${blurOut}px)`
      }}>
        Previous scene
      </div>
      <div style={{
        opacity: fade.in,
        filter: `blur(${blurIn}px)`
      }}>
        Next scene
      </div>
    </>
  );
}
```

### Wipe transition

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

function WipeTransition({ frame, direction = 'left' }) {
  const progress = transition(frame, 60, 40);
  
  const clipPath = direction === 'left'
    ? `inset(0 ${(1 - progress) * 100}% 0 0)`
    : `inset(0 0 0 ${(1 - progress) * 100}%)`;
  
  return (
    <>
      <div>Background</div>
      <div style={{ clipPath }}>
        Foreground (wipes in)
      </div>
    </>
  );
}
```

### State-based transitions

```typescript theme={null}
function StateMachine({ frame }) {
  const states = [
    { name: 'idle', from: 0 },
    { name: 'loading', from: 60 },
    { name: 'ready', from: 120 },
    { name: 'complete', from: 180 }
  ];
  
  const currentStateIndex = states.findIndex((s, i) => {
    const next = states[i + 1];
    return frame >= s.from && (!next || frame < next.from);
  });
  
  const currentState = states[currentStateIndex];
  const nextState = states[currentStateIndex + 1];
  
  let transitionProgress = 0;
  if (nextState) {
    const transitionStart = nextState.from - 20;
    if (frame >= transitionStart) {
      transitionProgress = transition(frame, transitionStart, 20);
    }
  }
  
  return (
    <StateRenderer
      state={currentState.name}
      nextState={nextState?.name}
      transitionProgress={transitionProgress}
    />
  );
}
```

### Combining with spring physics

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

function HybridTransition({ frame }) {
  // Use transition for opacity
  const opacity = transition(frame, 0, 30, {
    easing: Easing.cubic.out
  });
  
  // Use spring for scale (more natural bounce)
  const scale = spring({
    frame,
    fps: 30,
    from: 0,
    to: 1,
    config: { stiffness: 150, damping: 12 }
  });
  
  return (
    <div style={{
      opacity,
      transform: `scale(${scale})`
    }}>
      Content
    </div>
  );
}
```
