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

# Vanilla JavaScript

> Use Helios with vanilla JavaScript for maximum control and flexibility

Helios works perfectly with vanilla JavaScript, giving you complete control without framework overhead.

## Quick start

<Steps>
  <Step title="Install Helios">
    ```bash theme={null}
    npm install @helios-project/core
    ```
  </Step>

  <Step title="Create your first animation">
    ```ts main.ts theme={null}
    import { Helios } from '@helios-project/core';
    import './style.css';

    // Initialize Helios engine
    const helios = new Helios({
        duration: 5,
        fps: 30,
        autoSyncAnimations: true
    });

    // Expose for the Player and debugging
    (window as any).helios = helios;

    // Enable external control (e.g. from Renderer)
    helios.bindToDocumentTimeline();
    ```
  </Step>

  <Step title="Add animation logic">
    ```ts theme={null}
    // Subscribe to frame updates
    helios.subscribe((state) => {
        const { currentFrame } = state;
        const progress = currentFrame / (helios.duration * helios.fps);

        // Update DOM elements
        const box = document.getElementById('box');
        if (box) {
            box.style.transform = `translateX(${progress * 500}px) rotate(${currentFrame * 2}deg)`;
            box.style.opacity = String(Math.min(1, currentFrame / 30));
        }
    });
    ```
  </Step>
</Steps>

## Animation approaches

<Tabs>
  <Tab title="DOM animations">
    Directly manipulate DOM elements in the subscribe callback:

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

    const helios = new Helios({ duration: 5, fps: 30 });
    helios.bindToDocumentTimeline();

    const box = document.createElement('div');
    box.style.width = '100px';
    box.style.height = '100px';
    box.style.backgroundColor = 'red';
    document.body.appendChild(box);

    helios.subscribe((state) => {
        const progress = state.currentFrame / (state.duration * state.fps);
        
        // Animate position
        const x = progress * 500;
        box.style.transform = `translateX(${x}px)`;
        
        // Animate opacity
        box.style.opacity = String(Math.min(1, state.currentFrame / 30));
    });

    (window as any).helios = helios;
    ```
  </Tab>

  <Tab title="Canvas animations">
    Draw frame-by-frame animations on a canvas:

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

    const helios = new Helios({
        fps: 30,
        duration: 5,
        autoSyncAnimations: true
    });

    // Create Canvas element
    const canvas = document.createElement('canvas');
    canvas.width = 1920;
    canvas.height = 1080;
    canvas.style.width = '100%';
    canvas.style.height = '100%';
    document.body.appendChild(canvas);

    const ctx = canvas.getContext('2d')!;

    // Animate using subscribe
    helios.subscribe((state) => {
        // Clear
        ctx.fillStyle = '#f0f0f0';
        ctx.fillRect(0, 0, canvas.width, canvas.height);

        const progress = state.currentFrame / (state.duration * state.fps);

        // Draw box
        const x = (progress * (canvas.width - 200)) + 100;
        const y = canvas.height / 2;

        ctx.fillStyle = 'red';
        ctx.beginPath();
        ctx.rect(x - 50, y - 50, 100, 100);
        ctx.fill();
    });

    // Enable external control
    helios.bindToDocumentTimeline();

    // Expose for debugging
    (window as any).helios = helios;
    ```
  </Tab>
</Tabs>

## Animation helpers

Use Helios utility functions for common animation patterns:

```ts theme={null}
import { Helios, interpolate, spring } from '@helios-project/core';

const helios = new Helios({
    fps: 30,
    duration: 5,
    autoSyncAnimations: true
});

const helperBox = document.createElement('div');
helperBox.className = 'box';
helperBox.style.backgroundColor = 'hotpink';
helperBox.style.position = 'absolute';
helperBox.style.top = '250px';
helperBox.style.left = '50px';
helperBox.style.width = '100px';
helperBox.style.height = '100px';
document.body.appendChild(helperBox);

helios.subscribe((state) => {
    const { currentFrame } = state;

    // Interpolate x position: 0 -> 200 over frames 0-60
    const x = interpolate(currentFrame, [0, 60], [0, 200], { extrapolateRight: 'clamp' });

    // Spring scale: 0 -> 1 starting at frame 0
    const scale = spring({ 
        frame: currentFrame, 
        fps: 30, 
        from: 0, 
        to: 1, 
        config: { stiffness: 100 } 
    });

    helperBox.style.transform = `translateX(${x}px) scale(${scale})`;
});

helios.bindToDocumentTimeline();
(window as any).helios = helios;
```

## Manual sequencing

Implement sequences with conditional logic:

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

const helios = new Helios({
    fps: 30,
    duration: 5,
    autoSyncAnimations: true
});

const app = document.getElementById('app')!;

// Create sequence boxes
function createBox(color: string, text: string) {
    const box = document.createElement('div');
    box.className = 'box';
    box.style.backgroundColor = color;
    box.textContent = text;
    box.style.position = 'absolute';
    box.style.display = 'none';
    box.style.width = '100px';
    box.style.height = '100px';
    return box;
}

const seq1 = createBox('red', 'Seq 1');
app.appendChild(seq1);

const seq2 = createBox('blue', 'Seq 2');
app.appendChild(seq2);

const seq3 = createBox('green', 'Seq 3');
app.appendChild(seq3);

// Subscribe to updates
helios.subscribe((state) => {
    const { currentFrame } = state;

    // Sequence 1: 0 - 30
    if (currentFrame >= 0 && currentFrame < 30) {
        seq1.style.display = 'flex';
    } else {
        seq1.style.display = 'none';
    }

    // Sequence 2: 30 - 60
    if (currentFrame >= 30 && currentFrame < 60) {
        seq2.style.display = 'flex';
    } else {
        seq2.style.display = 'none';
    }

    // Sequence 3: 60 - 90
    if (currentFrame >= 60 && currentFrame < 90) {
        seq3.style.display = 'flex';
    } else {
        seq3.style.display = 'none';
    }
});

helios.bindToDocumentTimeline();
(window as any).helios = helios;
```

## Advanced patterns

### Multiple animations

Orchestrate multiple elements:

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

const helios = new Helios({ duration: 5, fps: 30 });

const elements = [
    { el: document.getElementById('box1')!, delay: 0, color: 'red' },
    { el: document.getElementById('box2')!, delay: 15, color: 'blue' },
    { el: document.getElementById('box3')!, delay: 30, color: 'green' }
];

helios.subscribe((state) => {
    elements.forEach(({ el, delay }) => {
        const localFrame = Math.max(0, state.currentFrame - delay);
        const x = interpolate(localFrame, [0, 60], [0, 400], { extrapolateRight: 'clamp' });
        el.style.transform = `translateX(${x}px)`;
    });
});

helios.bindToDocumentTimeline();
```

### State machines

Implement complex animation states:

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

enum AnimationState {
    INTRO = 'intro',
    MAIN = 'main',
    OUTRO = 'outro'
}

const helios = new Helios({ duration: 5, fps: 30 });
let currentState: AnimationState = AnimationState.INTRO;

helios.subscribe((state) => {
    const { currentFrame } = state;

    // Determine state
    if (currentFrame < 30) {
        currentState = AnimationState.INTRO;
    } else if (currentFrame < 120) {
        currentState = AnimationState.MAIN;
    } else {
        currentState = AnimationState.OUTRO;
    }

    // Execute state-specific logic
    switch (currentState) {
        case AnimationState.INTRO:
            // Intro animations
            break;
        case AnimationState.MAIN:
            // Main animations
            break;
        case AnimationState.OUTRO:
            // Outro animations
            break;
    }
});

helios.bindToDocumentTimeline();
```

## Best practices

<AccordionGroup>
  <Accordion title="Cache DOM queries">
    Query DOM elements once, not in every frame:

    ```ts theme={null}
    // Good: Query once
    const box = document.getElementById('box');
    helios.subscribe((state) => {
        if (box) {
            box.style.transform = `translateX(${state.currentFrame * 5}px)`;
        }
    });

    // Avoid: Query every frame
    helios.subscribe((state) => {
        const box = document.getElementById('box'); // ❌
        // ...
    });
    ```
  </Accordion>

  <Accordion title="Use requestAnimationFrame for smoothness">
    For interactive animations, combine with `requestAnimationFrame`:

    ```ts theme={null}
    let latestState = helios.getState();

    helios.subscribe((state) => {
        latestState = state;
    });

    function render() {
        // Use latestState for rendering
        const progress = latestState.currentFrame / (helios.duration * helios.fps);
        // Update DOM...
        requestAnimationFrame(render);
    }

    requestAnimationFrame(render);
    ```
  </Accordion>

  <Accordion title="Always bind to document timeline">
    Enable external control for rendering and playback:

    ```ts theme={null}
    const helios = new Helios({ duration: 5, fps: 30 });
    helios.bindToDocumentTimeline();
    (window as any).helios = helios;
    ```
  </Accordion>

  <Accordion title="Clean up when needed">
    Unsubscribe when removing animations:

    ```ts theme={null}
    const unsubscribe = helios.subscribe((state) => {
        // Animation logic
    });

    // Later, when cleaning up:
    unsubscribe();
    ```
  </Accordion>
</AccordionGroup>

## TypeScript support

Helios is built with TypeScript and provides full type safety:

```ts theme={null}
import type { Helios, HeliosState } from '@helios-project/core';

const helios: Helios = new Helios({
    duration: 5,
    fps: 30,
    autoSyncAnimations: true
});

helios.subscribe((state: HeliosState) => {
    const { currentFrame, duration, fps } = state;
    // Type-safe state access
});
```

## Next steps

<CardGroup cols={2}>
  <Card title="Animation helpers" icon="wand-magic-sparkles" href="/features/animation-helpers">
    Learn about interpolation, spring physics, and easing functions
  </Card>

  <Card title="Canvas rendering" icon="paintbrush" href="/guides/canvas">
    Create high-performance canvas animations
  </Card>

  <Card title="Sequences" icon="film" href="/guides/sequences">
    Build complex multi-scene animations
  </Card>

  <Card title="Export videos" icon="file-export" href="/guides/export">
    Render your animations to video files
  </Card>
</CardGroup>
