Skip to content

FiniteStatusBar and InfiniteStatusBar ​

FiniteStatusBar and InfiniteStatusBar (both from scenerystack/vegas) are the two standard game-screen status bars: a Rectangle bar, floated against the top of the screen, that keeps a score display (and other UI) aligned to its left and right edges as the browser window resizes. Both extend scenery-phet's StatusBar base class, which handles the resize-following geometry; each subclass only decides what content goes in the bar.

  • FiniteStatusBar is for games with a fixed number of challenges per level — it shows "Level N", an optional "Challenge N of M", a score display, an optional elapsed-time display, and a "Start Over" button.
  • InfiniteStatusBar is for open-ended games with no fixed challenge count — it shows a back button, an arbitrary messageNode (typically a Text), and a score display, with no level/challenge/timer/start-over concepts at all.
ts
import { FiniteStatusBar, InfiniteStatusBar } from 'scenerystack/vegas';
import { NumberProperty } from 'scenerystack/axon';
import { Text } from 'scenerystack/scenery';

A minimal example ​

ts
const scoreProperty = new NumberProperty( 0 );
const levelNumberProperty = new NumberProperty( 1 );

// Finite: fixed challenges per level.
const finiteStatusBar = new FiniteStatusBar( this.layoutBounds, this.visibleBoundsProperty, scoreProperty, {
  levelNumberProperty: levelNumberProperty,
  challengeNumberProperty: new NumberProperty( 1 ),
  numberOfChallengesProperty: new NumberProperty( 10 )
} );

// Infinite: open-ended, no challenge count.
const infiniteStatusBar = new InfiniteStatusBar(
  this.layoutBounds,
  this.visibleBoundsProperty,
  new Text( 'Explore freely' ),
  scoreProperty,
  { backButtonListener: () => this.showLevelSelectionScreen() }
);

Constructors ​

ts
new FiniteStatusBar(
  layoutBounds: Bounds2,
  visibleBoundsProperty: TReadOnlyProperty<Bounds2>,
  scoreProperty: ReadOnlyProperty<number>,
  providedOptions?: FiniteStatusBarOptions
)

new InfiniteStatusBar(
  layoutBounds: Bounds2,
  visibleBoundsProperty: TReadOnlyProperty<Bounds2>,
  messageNode: Node,
  scoreProperty: ReadOnlyProperty<number>,
  providedOptions?: InfiniteStatusBarOptions
)

Both take the ScreenView's layoutBounds and visibleBoundsProperty first, so the bar can stretch to match the browser's actual visible width even when it differs from layoutBounds.

Options ​

OptionClassDefaultEffect
levelNumberPropertyFiniteStatusBarnullIf set (and levelNumberVisible), shows a "Level N" label
challengeNumberProperty / numberOfChallengesPropertyFiniteStatusBarnull / nullMust both be set or both be null (asserted); shows "Challenge N of M"
elapsedTimeProperty / timerEnabledPropertyFiniteStatusBarnull / nullIf both set, shows an ElapsedTimeNode, visible only while timerEnabledProperty is true
createScoreDisplaybothScoreDisplayLabeledNumber (FiniteStatusBar) / ScoreDisplayNumberAndStar (InfiniteStatusBar)Factory building the score-display Node — swap in any member of the ScoreDisplay family
startOverButtonText / startOverButtonOptionsFiniteStatusBarlocalized "Start Over" string / {}Text and extra options for the "Start Over" TextPushButton
backButtonListenerInfiniteStatusBarno-opCalled when the back button (a BackButton) is pressed
messageNode (constructor parameter)InfiniteStatusBar—Arbitrary Node shown next to the back button, e.g. a Text describing the current activity
font / textFillFiniteStatusBarStatusBar.DEFAULT_FONT / StatusBar.DEFAULT_TEXT_FILLApplied to the level/challenge/score/timer text
barFill / barStroke (inherited StatusBarOptions)both'lightGray' / nullThe bar rectangle's own paint
floatToTop (inherited StatusBarOptions)bothfalsetrue floats the bar to the top of the browser's visible bounds instead of layoutBounds' top

Methods ​

Both classes are otherwise thin: all layout happens in the constructor via a Multilink/link on positioningBoundsProperty (from StatusBar) plus the content's own bounds. The only public member beyond inherited Node API is:

MemberDescription
dispose()Disposes internally-created Text/score-display/timer/button children and their string-Property links, then calls StatusBar.dispose()

Picking between the two is about challenge structure, not visual polish

The deciding factor is whether "Challenge N of M" is meaningful for your game. If challenges are counted and finite, use FiniteStatusBar (which also gives you "Start Over" and an optional timer). If play is open-ended — no fixed challenge count to report — use InfiniteStatusBar, and pass whatever messageNode best describes the current state instead.