Primitives / Time

ticks: a clock the Model drives

Both bundles own a running flag at an interval fixed where they are placed. When the parent's Model already decides whether the clock runs and how fast (a game's phase and score), a second flag would be a second owner of that fact. ticks is the entry for that case: intervalMs reads the interval from the Model, None while stopped, and onTick makes the parent's Message:

ts
import { Option } from 'effect'
import * as Subscription from 'foldkit/subscription'
import { ticks } from 'foldkit-primitives/time'

const subscriptions = Subscription.make<Game, GameMessage>()(() => ({
  clock: ticks({
    intervalMs: (game: Game) =>
      game.playing ? Option.some(Math.max(80, 150 - game.points)) : Option.none(),
    onTick: () => GameMessage.TickedClock(),
  }),
}))

A Model change that leaves the interval alone does nothing. A new interval applies from the next tick without restarting the clock, so a game that speeds up keeps its rhythm instead of ticking at once; None stops it, and Some again starts afresh, one interval before the first tick. Timer and Interval are built on it. An interval that answers zero, negative, or non-finite throws, which crashes the runtime naming the mistake.