Skip to content

Phase sequences

By default, a rep is “the user traversed every phase in declared order.” For most movements that’s fine. For some (alternating lunges, skater hops, multi-path movements), you want explicit control. That’s what phase sequences are for.

Auto-cycle (default)

When you don’t pin any sequences, the runtime uses repDetection.phases (your declared phase order) as the cycle. Reps count when the user has traversed every phase in that order and re-entered the first.

For a 2-phase squat (Down → Up), the rep counts on every full Down→Up→Down→Up cycle.

Pinning sequences

Open the Phases panel → expand the Sequences section (collapsed by default for the simple case).

  • Pin sequence: captures the current phase order as a named sequence (sequence #1, sequence #2, …).
  • Add sequence: drop a new empty sequence + add phases to it one at a time via the per-phase dropdown.

A pinned sequence is just an ordered list of phase ids. The runtime accepts a rep on ANY one of the authored sequences.

Example, alternating lunge

The movement: stand → drop left leg into a lunge → stand → drop right leg into a lunge → stand.

Phases (4):

  1. Standing
  2. Left lunge (left knee bent, right knee straight)
  3. Right lunge (left knee straight, right knee bent)

That’s only 3 phases. Standing is shared between cycles. The trainer can author either:

  • Auto-cycle with phases [Standing, Left lunge, Right lunge] , a rep counts after both sides happen. Works but the rep tick comes only on the second side.

  • Two pinned sequences:

    • [Standing, Left lunge, Standing], one rep for the left side.
    • [Standing, Right lunge, Standing], one rep for the right side.

    Now the rep counter ticks ONCE per leg. More natural for the user.

The looping-sequence case

Many sequences return to their start phase (squat: Up → Down → Up, predator jack: Stand → Clap → Stand). PoseFlow’s phase state machine handles these correctly, the rep-completion check runs against [...history, transition.toPhase] (the virtual post-transition history) so the closing phase is part of the match. History only resets AFTER a rep completes, not on every re-entry of the first phase.

This means you can author [Up, Down, Up] and the rep ticks on the closing Up entry, not on the next Up after that.

Sequence progress stepper

Below the Sequences section, the Sequence progress stepper shows where you are in each authored sequence in real time:

1. ● Up → ● Down → ● Up
passed ACTIVE pending
2. ● Stand → ● Squat → ● Plank → ● Squat → ● Stand
passed ACTIVE pending pending pending
  • ✓ tick + green tint = phase already passed in this rep.
  • Filled green = the live-detected phase (the active step).
  • Outline = upcoming phase.
  • Arrow connectors turn green between passed steps.

If you’ve authored 3 sequences, the stepper shows 3 rows. Each row has a sequence number on the left.

Use this while testing to verify the user is actually traversing the sequence you authored, if step 3 never lights up, your phase transitions aren’t firing.

What pinned sequences produce

When you save, sequences become entries in the .pose file’s repDetection.phaseAlternatives:

"repDetection": {
"strategy": "sequence",
"countOn": "sequenceComplete",
"phases": ["Stand", "Left lunge", "Right lunge"],
"phaseAlternatives": [
["Stand", "Left lunge", "Stand"],
["Stand", "Right lunge", "Stand"]
]
}

The runtime PhaseStateMachine checks the virtual history against every entry of phaseAlternatives on every transition. First match wins.

When NOT to pin

For simple 2-phase movements (squat, push-up), auto-cycle is clearer + less to maintain. Only pin when:

  • The movement has multiple valid paths (alternating, skater).
  • The natural cycle returns to a non-first phase.
  • You want different feedback per path.