Skip to content

@web-engine-dev/events ​

Double-buffered event system with frame lifecycle for web-engine-dev. Provides a frame-synchronized event system where events written in one frame are available for reading in the next frame, ensuring deterministic behavior.

Features ​

  • Double Buffering: Events written this frame are read next frame
  • Frame Synchronization: Deterministic event ordering
  • Type-Safe Events: Generic event readers and writers
  • Memory Management: Automatic buffer clearing with configurable limits

Installation ​

bash
npm install @web-engine-dev/events
# or
pnpm add @web-engine-dev/events

Quick Start ​

typescript
import { createEventSystem, defineEvent } from '@web-engine-dev/events';

// Create the event system
const events = createEventSystem();

// Define event types
const COLLISION_EVENT = defineEvent('collision');
interface CollisionEvent {
  type: typeof COLLISION_EVENT;
  entityA: number;
  entityB: number;
}

// Write events
const writer = events.writer<CollisionEvent>(COLLISION_EVENT);
writer.send({ type: COLLISION_EVENT, entityA: 1, entityB: 2 });

// Advance frame (swap buffers)
events.update();

// Read events
const reader = events.reader<CollisionEvent>(COLLISION_EVENT);
for (const event of reader.read()) {
  console.log(`Collision: ${event.entityA} <-> ${event.entityB}`);
}

API Reference ​

EventSystem ​

MethodDescription
registerEvent()Pre-register an event type
reader<T>(type)Get a reader for event type
writer<T>(type)Get a writer for event type
update()Advance frame and swap buffers
currentFrame()Get current frame number
clear()Clear all events from all channels

EventReader ​

MethodDescription
read()Iterator of events from last frame
isEmpty()Check if any events available
length()Number of events available
clear()Mark events as consumed

EventWriter ​

MethodDescription
send(event)Emit a single event
sendBatch()Emit multiple events

Game Loop Integration ​

typescript
const events = createEventSystem();

function gameLoop() {
  // Start of frame - swap buffers
  events.update();

  // Systems can now read last frame's events
  const damageReader = events.reader<DamageEvent>(DAMAGE_EVENT);
  for (const event of damageReader.read()) {
    applyDamage(event.target, event.amount);
  }

  // Systems can write new events
  const damageWriter = events.writer<DamageEvent>(DAMAGE_EVENT);
  if (collision) {
    damageWriter.send({ type: DAMAGE_EVENT, target: entity, amount: 10 });
  }
}

Configuration ​

typescript
const events = createEventSystem({
  maxEventsPerType: 1000, // Prevent memory leaks
  retentionFrames: 2, // Number of frames to retain
});

Advanced Usage ​

Event Descriptors ​

For advanced use cases (validation, custom lifetime), use defineEventDescriptor.

typescript
import { defineEventDescriptor } from '@web-engine-dev/events';

const DamageEvent = defineEventDescriptor<{ amount: number }>('DamageEvent', {
  validate: (data) => data.amount > 0,
  lifetime: 1, // Persist for only 1 frame
});

Filtered Readers ​

Create readers that only see specific events.

typescript
const criticalEvents = events.filteredReader(LOG_EVENT, (e) => e.severity === 'critical');
for (const event of criticalEvents.read()) {
  // Only critical events
}

Priority Handlers ​

Register handlers that execute immediately when events are processed (during update()).

typescript
events.onEvent(COLLISION_EVENT, (event) => {
  // Handle immediately
}, 100); // Priority 100 (higher runs first)

Async Events ​

Send events that will be queued for the next frame asynchronously.

typescript
await writer.sendAsync(event);

Performance Tips ​

For maximum performance in tight loops, use forEach instead of read() iterator.

typescript
// Faster than for..of loop
reader.forEach((event) => {
  process(event);
});

Proprietary software. All rights reserved.