arcane-engine 0.26.1

Arcane game engine — agent-native 2D engine with embedded TypeScript runtime
# Screen Transitions

Visual effects for scene or level changes. Use these instead of hand-rolling fade overlays with manual timers and fullscreen rectangles.

**Always call `updateScreenTransition(dt)` and `drawScreenTransition()` in your frame loop** — they're no-ops when no transition is active.

## Five Built-in Patterns

- `"fade"` — alpha fade to/from a solid color
- `"wipe"` — horizontal sweep from left to right
- `"circleIris"` — expanding/contracting circle from center
- `"diamond"` — diamond-shaped iris
- `"pixelate"` — increasing pixel size that obscures the image

## Basic Usage

```typescript
import {
  startScreenTransition, updateScreenTransition,
  drawScreenTransition, isScreenTransitionActive,
} from "@arcane/runtime/rendering";

// Trigger transition — callback runs at midpoint (when screen is fully covered)
startScreenTransition("circleIris", 0.6, { color: { r: 0, g: 0, b: 0 } },
  () => { currentScene = "gameplay"; },  // runs at midpoint — swap state here
  () => { console.log("done"); },         // runs when transition finishes
);

// In onFrame (always call, no-op if inactive):
updateScreenTransition(dt);
drawScreenTransition();
```

## Level Transition Pattern

```typescript
function goToNextLevel() {
  startScreenTransition("fade", 0.8, { color: { r: 0, g: 0, b: 0 } },
    () => {
      // This runs when the screen is fully black — swap the level here
      state = generateLevel(state.level + 1);
    },
  );
}

// In game logic — trigger on portal contact:
if (touchingPortal) {
  goToNextLevel();
}
```

## Avoiding Stale Closures

The midpoint callback fires asynchronously — state may change between when you start the transition and when the callback runs (especially under hot-reload). Capture values at call time:

```typescript
// BAD — state.level may have changed by the time midpoint fires
startScreenTransition("fade", 0.5, {}, () => {
  state = loadLevel(state.level + 1);  // stale reference
});

// GOOD — capture the value upfront
const nextLevel = state.level + 1;
startScreenTransition("fade", 0.5, {}, () => {
  state = loadLevel(nextLevel);
});
```

## With Scene Manager

Transitions integrate with the scene manager automatically:

```typescript
import { replaceScene } from "@arcane/runtime/scenes";

replaceScene("gameplay", {
  transition: { type: "diamond", duration: 0.5, color: { r: 0, g: 0, b: 0 } },
});
```