pixi-wheels
Building blocks

Anticipation

Anticipation baits the player with one section and lands on another. It is planned from the result, so it is deterministic, testable and always lands where the server said. One rule holds for every style: the wheel comes to rest exactly once, on the result. It never stops on the bait and moves on, and it never rolls back.

wheel.setResult({ value: 2 }, {
  anticipation: {
    bait: 'x50',              // section id, or { index }
    style: 'auto',            // 'creep' | 'stutter' | 'stall' | 'auto'
    rest: 0.22,               // where the pointer rests: this far into the target from the shared line ('keep' to leave it)
    creepSpeed: 40,           // deg/s at which the crawl begins
    hesitateSpeed: 2,         // stutter: the near-stall speed, deg/s
    dwellMs: 600,             // stutter: how long the near-stall lasts
    pushMs: 700,              // stutter: the slip over the line
    approachDeg: 45,          // stall: crawl length before the rest (default the target's arc, at most 45)
    maxDistanceDeg: 150,      // how far the bait may be from the landing
    protectSkip: false,
  },
});

.landing({ anticipation: { bait: 'x50' } }) on the builder baits every spin. bait alone is enough; the defaults are the beat.

The beat#

  • The approach is a crawl. The wheel comes down to creepSpeed and dies against friction over its last stretch, so the pointer takes its time reaching the line between the result and the bait.
  • It never stops early. creep crawls through the bait and barely crosses the line. stutter all but stalls a hair short of the line, still moving at hesitateSpeed, then slips over. stall enters the result and crawls toward the bait’s line as if it will cross, and dies just short of it.
  • It rests by the line. A tease puts the landing angle just inside the target, rest of its arc from the shared divider: 0.22 after crossing it, 0.15 when it died short. rest: 'keep' lets the landing mode place it; settle: 'center' glides to the middle afterwards. A target with its own offset, an angle / position target, or mode: 'exact' is never moved.

The crawls pass the divider under the pointer, so pointer:tick fires for them too, at crawl speed.

Geometry#

A clockwise wheel sweeps decreasing local angles under the pointer, so it meets the section after the landing (in layout order) first. In the spin direction:

  • bait before landing (the pointer passes the bait, then reaches the landing): creep or stutter.
  • bait after landing (the pointer reaches the landing first): stall.

'auto' picks by distance. A bait farther than maxDistanceDeg on both sides is dropped with a warning (bait-too-far); an explicit style with the wrong geometry warns (bait-order) and is dropped too. The wheel lands plainly either way.

Events#

EventWhen
anticipation:startThe stop was planned with a tease. Carries bait and style.
anticipation:baitThe crawl begins: the pointer enters the bait (creep, stutter) or the result (stall).
anticipation:endThe tease resolved, just before spin:landing.

Protected skip#

With protectSkip: true (or .skip({ protectAnticipation: true })) the first press fast-forwards to the start of the crawl and lets the tease play; the second press lands. skip:requested carries protectedByAnticipation so audio can tell the two apart.