Skip to content

PhetioGroup

PhetioGroup (from scenerystack/tandem) manages a dynamically-growing/shrinking collection of same-shaped PhetioObjects — the PhET-iO-aware equivalent of const particles: Particle[] = [] for state you want save/restore, API validation, and Studio visibility on. Use it whenever a sim creates and destroys an unbounded, indexed set of instrumented elements at runtime — particles, balloons, graph points — rather than pushing/splicing a plain array yourself.

ts
import { PhetioGroup } from 'scenerystack/tandem';
import { Tandem } from 'scenerystack/tandem';

class Particle {
  public constructor( public readonly tandem: Tandem, public x: number ) {}
}

const particleGroup = new PhetioGroup(
  ( tandem, x: number ) => new Particle( tandem, x ), // createElement
  [ 0 ],                                              // defaultArguments, used to build the archetype
  { tandem: Tandem.REQUIRED.createTandem( 'particleGroup' ) }
);

const particle = particleGroup.createNextElement( 10 );
// ...later, when the particle should disappear:
particleGroup.disposeElement( particle );

The createElement function is called once up front (with defaultArguments) to build a hidden "archetype" — a template instance PhET-iO uses to know the group's element API and baseline metadata before any real elements exist — and again for every element you actually create via createNextElement. Elements are named <groupName>_0, <groupName>_1, … automatically, indexed from groupElementStartingIndex (default 1).

Methods

MethodEffect
createNextElement( ...args )Creates and adds an element at the next available index
disposeElement( element )Removes an element from the group and disposes it, updating countProperty
getArray() / getArrayCopy()Reference to (or a defensive copy of) the underlying elements array
clear( options? )Disposes every element currently in the group
forEach( action ) / map( f ) / filter( predicate ) / find( predicate )Array-like iteration helpers over the group's elements
includes( element ) / indexOf( element )Membership/position queries
getElement( index ) / getLastElement()Direct indexed access

Key state

MemberDescription
countPropertyRead-only, PhET-iO-instrumented NumberProperty tracking the current element count

PhetioGroup vs. PhetioCapsule

Both are "dynamic element container" subclasses of the shared PhetioDynamicElementContainer base, and both build an archetype the same way — the difference is cardinality. PhetioGroup manages many same-shaped elements at once (an indexed, growable array); PhetioCapsule manages at most one element that can be created, disposed, and recreated over the sim's lifetime (e.g. a lazily-created dialog). Reach for PhetioGroup when you're modeling "a collection," and PhetioCapsule when you're modeling "one optional/lazy thing."

PhetioGroup itself is not disposable

Calling .dispose() on the group container asserts — a PhetioGroup is meant to exist for the lifetime of the sim (or its owning screen), even as the elements inside it are created and disposed freely via createNextElement/disposeElement. If you need the container itself to go away, you're likely looking for a differently-scoped structure, not a disposed PhetioGroup.