ecspresso
    Preparing search index...
    • Create a timer plugin for ECSpresso.

      The plugin installs one update system that ticks every slot of every timers component each frame. It does not touch entity lifecycle — react to justFinished (or use onComplete) and despawn yourself if needed.

      Type Parameters

      • Slots extends string = string
      • G extends string = "timers"

      Parameters

      Returns Plugin<
          WithComponents<EmptyConfig, TimerComponentTypes<Slots>>,
          EmptyConfig,
          "timer-update",
          G,
          never,
          never,
      >

      const ecs = ECSpresso.create()
      .withPlugin(createTimerPlugin())
      .withComponentTypes<{ spawner: true }>()
      .build();

      ecs.spawn({
      spawner: true,
      timers: { wave: createRepeatingTimer(5.0) },
      });

      ecs.addSystem('spawn-on-timer')
      .addQuery('spawners', { with: ['timers', 'spawner'] })
      .setProcess(({ queries, ecs }) => {
      for (const { components } of queries.spawners) {
      if (components.timers.wave?.justFinished) {
      ecs.spawn({ enemy: true });
      }
      }
      });

      Typed slot names — pass a string-union generic to lock the set of legal slot names. Spawn sites reject typos, autocomplete works on slot access, and slot is narrowed in onComplete callbacks. Defaults to string (any slot name) when omitted.

      const ecs = ECSpresso.create()
      .withPlugin(createTimerPlugin<'launch' | 'hangarCycle'>())
      .build();

      ecs.spawn({ timers: { launch: createTimer(2.0) } }); // ok
      ecs.spawn({ timers: { typo: createTimer(2.0) } }); // type error

      createTimer<'launch' | 'hangarCycle'>(1.0, {
      onComplete: ({ slot }) => {
      // slot is 'launch' | 'hangarCycle', not string
      },
      });

      Only one timer plugin can be installed per world. Feature plugins should re-export their slot union as a type so the app can assemble them: createTimerPlugin<FighterSlots | CarrierSlots>().