Skip to content

`PhaseConfig`

One phase of an movement + its outgoing transitions. The atom of the rule-based rep counting path.

class PhaseConfig {
final String id;
final String name;
final PhaseType type;
final List<String> trackingPoints;
final PhaseDuration duration;
final List<PhaseTransition> transitions;
}

Example

A squat’s down phase, transitioning back to up:

const downPhase = PhaseConfig(
id: 'down',
name: 'Down',
type: PhaseType.transition,
trackingPoints: ['left_knee', 'right_knee'],
duration: PhaseDuration(min: 0, max: 5000),
transitions: [
PhaseTransition(
toPhase: 'up',
conditions: [
PhaseCondition(
trackingPoint: 'left_knee',
operator: ConditionOperator.gt,
value: 160,
),
PhaseCondition(
trackingPoint: 'right_knee',
operator: ConditionOperator.gt,
value: 160,
),
],
),
],
);

The phase enters when the previous phase’s transition fires. While the user is in this phase, the runtime evaluates every transition’s conditions per frame. When all conditions of ANY transition are satisfied (AND across conditions, OR across transitions), the machine moves to that transition’s toPhase.

Fields

id

Stable identifier, unique within the movement. Referenced from repDetection.phases, phaseAlternatives, formRules.appliesToPhase, and the Studio’s selected-phase state.

name

Display name for the Studio + consumer UIs.

type

  • PhaseType.transition, most phases. The user is expected to move through this phase as part of the cycle.
  • PhaseType.rep, marks the boundary phase (used by some rep detectors).
  • PhaseType.hold, the user is expected to PAUSE in this phase. Drives the hold rep-detection strategy.

trackingPoints

IDs of channels relevant to this phase. The Studio uses this as a UI hint (“which measurements affect this phase?”) and doesn’t affect runtime evaluation (the form service references rules directly).

duration

class PhaseDuration {
final int min; // milliseconds
final int max; // milliseconds
}
  • min, minimum hold time before any transition can fire. Useful for hold phases (“hold the plank for 5 seconds”).
  • max, force a transition when exceeded. Prevents the user from getting stuck in a phase if they pause mid-rep.

Defaults to (min: 0, max: 5000).

PhaseTransition

class PhaseTransition {
final String toPhase;
final List<PhaseCondition> conditions;
}

A transition fires when ALL conditions are satisfied. To express OR logic, add multiple transitions with disjoint condition sets, the phase machine picks the first one whose conditions match.

PhaseCondition

class PhaseCondition {
final String trackingPoint;
final ConditionOperator operator;
final dynamic value; // number or [min, max] for `between`
final int? holdTime; // optional ms
}

Operators

OperatorComparesvalue shape
gttracking value > thresholdnumber
lttracking value < thresholdnumber
eqtracking value ≈ threshold (±2°)number
betweentracking value ∈ [min, max][number, number]

holdTime

When set, the condition must remain satisfied for this many milliseconds before the transition fires. Use to prevent flicker on noisy frames or to require the user to actually pause at the position.

The phase state machine

PhaseStateMachine is the runtime that walks phaseConfigs. Initialised once per loaded movement, ticked once per frame:

machine.initialize(movementConfig);
for (final frame in frames) {
machine.update(trackingValues);
}
machine.currentPhaseId; // string
machine.completedReps; // int
machine.onPhaseChanged.listen(…); // PhaseChangeEvent stream
machine.onRepCompleted.listen(…); // RepCompletedEvent stream

MovementTracker owns the state machine, you don’t need to drive it yourself unless you’re writing a non-tracker consumer.

Studio authoring

In PoseFlow Studio, phases are the first thing a trainer adds. See the Studio phases page for the authoring workflow + the _PhaseTile UI (border highlights when a phase is the live-detected one + when a sequence is in progress through it).