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

# Pixi.js 2D rendering

> Create high-performance 2D graphics with Pixi.js and Helios

Pixi.js is a fast 2D rendering engine built on WebGL. Helios provides deterministic frame control for exporting Pixi.js animations to video.

## Basic setup

Pixi.js requires disabling its internal ticker and using Helios for frame updates.

```typescript theme={null}
import { Helios } from '@helios-project/core';
import { Application, Graphics } from 'pixi.js';

async function init() {
  // Initialize Pixi
  const app = new Application();
  await app.init({
    resizeTo: window,
    backgroundColor: 0x111111,
  });

  // Append canvas to DOM
  document.getElementById('app')!.appendChild(app.canvas);

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

  // Create a rotating rectangle
  const graphics = new Graphics();
  graphics.rect(0, 0, 100, 100).fill({ color: 0xff4444 });
  graphics.pivot.set(50, 50);
  graphics.position.set(app.screen.width / 2, app.screen.height / 2);

  app.stage.addChild(graphics);

  // Handle Resize
  window.addEventListener('resize', () => {
    graphics.position.set(app.screen.width / 2, app.screen.height / 2);
  });

  // Bind to document.timeline so the Renderer can drive us
  helios.bindToDocumentTimeline();

  // Sync with Helios
  helios.subscribe((state) => {
    const time = state.currentFrame / helios.fps;
    graphics.rotation = time * Math.PI; // Rotate 180 degrees per second
  });

  // Expose helios for the Renderer/Bridge
  (window as any).helios = helios;
}

init();
```

## React integration

For React applications, manage Pixi.js lifecycle in a `useEffect` hook.

```jsx theme={null}
import React, { useRef, useEffect } from 'react';
import { Helios } from '@helios-project/core';
import { Application, Graphics } from 'pixi.js';

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

helios.bindToDocumentTimeline();

if (typeof window !== 'undefined') {
  window.helios = helios;
}

export default function App() {
  const containerRef = useRef(null);

  useEffect(() => {
    let app = null;
    let unsubscribe = null;
    let mounted = true;

    const init = async () => {
      const pixiApp = new Application();

      await pixiApp.init({
        resizeTo: window,
        backgroundColor: 0x111111,
        antialias: true
      });

      if (!mounted) {
        pixiApp.destroy({ removeView: true, children: true });
        return;
      }

      app = pixiApp;

      if (containerRef.current) {
        containerRef.current.appendChild(app.canvas);
      }

      // Create a simple rotating rectangle
      const rect = new Graphics();
      rect.rect(-50, -50, 100, 100);
      rect.fill(0x61dafb);

      rect.x = app.screen.width / 2;
      rect.y = app.screen.height / 2;

      app.stage.addChild(rect);

      // Sync with Helios
      unsubscribe = helios.subscribe((state) => {
        const time = state.currentTime;
        // Rotate based on time
        rect.rotation = time * Math.PI;

        // Keep centered on resize
        rect.x = app.screen.width / 2;
        rect.y = app.screen.height / 2;
      });
    };

    init();

    return () => {
      mounted = false;
      if (unsubscribe) unsubscribe();
      if (app) {
        app.destroy({ removeView: true, children: true });
      }
    };
  }, []);

  return (
    <div ref={containerRef} style={{ width: '100%', height: '100%' }} />
  );
}
```

### Custom React hook

Create a reusable hook to sync with Helios frames:

```javascript theme={null}
import { useState, useEffect } from 'react';

export function useVideoFrame(helios) {
  const [frame, setFrame] = useState(helios.getState().currentFrame);

  useEffect(() => {
    const update = (state) => setFrame(state.currentFrame);
    return helios.subscribe(update);
  }, [helios]);

  return frame;
}
```

Usage:

```javascript theme={null}
import { useVideoFrame } from './hooks/useVideoFrame';

function MyComponent() {
  const frame = useVideoFrame(helios);
  
  // Use frame in your rendering logic
}
```

## Critical patterns

### Disable Pixi.js ticker

Pixi.js has an internal ticker for animations. Don't use it with Helios:

```typescript theme={null}
// DON'T DO THIS
app.ticker.add(() => {
  // This creates non-deterministic rendering
});

// DO THIS INSTEAD
helios.subscribe((state) => {
  const time = state.currentFrame / helios.fps;
  // Update your graphics based on Helios time
});
```

### Use Helios time for animations

Calculate all animations from `state.currentFrame` or `state.currentTime`:

```typescript theme={null}
helios.subscribe((state) => {
  const time = state.currentFrame / helios.fps;
  
  // Position animation
  sprite.x = Math.sin(time * 2) * 100 + app.screen.width / 2;
  
  // Rotation animation
  sprite.rotation = time * Math.PI;
  
  // Alpha animation
  sprite.alpha = (Math.sin(time) + 1) / 2;
});
```

### Async initialization

Pixi.js v8+ requires async initialization. Always await `app.init()`:

```typescript theme={null}
const app = new Application();
await app.init({
  resizeTo: window,
  backgroundColor: 0x111111,
});
```

## Performance considerations

### Sprite batching

Pixi.js automatically batches sprites with the same texture. Keep sprites using the same texture together:

```typescript theme={null}
// Good: sprites batched together
const texture = await Assets.load('sprite.png');
for (let i = 0; i < 1000; i++) {
  const sprite = new Sprite(texture);
  app.stage.addChild(sprite);
}

// Bad: forces multiple draw calls
for (let i = 0; i < 1000; i++) {
  const texture = await Assets.load('sprite.png');
  const sprite = new Sprite(texture);
  app.stage.addChild(sprite);
}
```

### Graphics objects

Reuse `Graphics` objects instead of recreating them each frame:

```typescript theme={null}
// Good: create once, update properties
const graphics = new Graphics();
app.stage.addChild(graphics);

helios.subscribe((state) => {
  const time = state.currentTime;
  graphics.rotation = time;
});

// Bad: recreates every frame
helios.subscribe((state) => {
  const graphics = new Graphics(); // Memory leak!
  graphics.rect(0, 0, 100, 100);
  app.stage.addChild(graphics);
});
```

### Texture management

Preload textures and dispose of them when done:

```typescript theme={null}
import { Assets } from 'pixi.js';

// Preload textures
const textures = await Assets.load([
  'sprite1.png',
  'sprite2.png',
  'background.png'
]);

// Use textures
const sprite = new Sprite(textures['sprite1.png']);

// Clean up when unmounting
useEffect(() => {
  return () => {
    Assets.unload('sprite1.png');
  };
}, []);
```

### Canvas resolution

Set resolution based on your export target:

```typescript theme={null}
const app = new Application();
await app.init({
  width: 1920,
  height: 1080,
  resolution: window.devicePixelRatio || 1,
  autoDensity: true,
});
```

Higher resolutions increase memory usage and render time.

### Filters and effects

Filters are GPU-intensive. Use sparingly:

```typescript theme={null}
import { BlurFilter } from 'pixi.js';

const blur = new BlurFilter();
sprite.filters = [blur];

// Limit filter updates
helios.subscribe((state) => {
  if (state.currentFrame % 5 === 0) {
    blur.blur = Math.sin(state.currentTime) * 10;
  }
});
```

## Package dependencies

```json theme={null}
{
  "dependencies": {
    "pixi.js": "^8.0.0",
    "@helios-project/core": "latest"
  },
  "devDependencies": {
    "@types/node": "^20.0.0",
    "typescript": "^5.0.0",
    "vite": "^5.0.0"
  }
}
```

## Common issues

### Canvas not appearing

Ensure you await Pixi.js initialization and append the canvas:

```typescript theme={null}
const app = new Application();
await app.init({ resizeTo: window });
document.getElementById('app')!.appendChild(app.canvas);
```

### Animation stuttering

Verify Helios is properly bound and you're not mixing ticker with Helios:

```typescript theme={null}
// Don't use both!
helios.bindToDocumentTimeline(); // Use this
// app.ticker.add(...); // Not this
```

### Memory leaks in React

Always destroy the Pixi.js app on unmount:

```javascript theme={null}
useEffect(() => {
  const init = async () => {
    const app = new Application();
    await app.init();
    // ... setup
  };
  
  init();
  
  return () => {
    app?.destroy({ removeView: true, children: true });
  };
}, []);
```

### Blurry graphics

Set `autoDensity` and match device pixel ratio:

```typescript theme={null}
await app.init({
  resolution: window.devicePixelRatio || 1,
  autoDensity: true,
});
```
