phetsims / balancing-act

"Balancing Act" is an educational simulation in HTML5, by PhET Interactive Simulations.
http://phet.colorado.edu/en/simulation/balancing-act
GNU General Public License v3.0
1 stars 8 forks source link

Show mass identity/name in the phet-io message #99

Open samreid opened 4 years ago

samreid commented 4 years ago

For https://github.com/phetsims/balancing-act/issues/96

@kathy-phet said:

One piece of information I don't see is that the bricks and the mystery objects look the same in the messages - so you don't know what was added where, because all you have is their mass. I suppose this is OK because everything here has a unique mass, but I think it would be clearer if the mass objects had an additional parameter to them - not just "mass" and "distance" but also maybe "name", where "name" was "Brick 5kg" and "Mystery A" etc. What do you think? Does this make sense for the objects?

samreid commented 4 years ago

Great idea! I mocked this up for the first screen and it read like so:

      "data": {
        "phetioID": "balancingAct.introScreen.model.smallTrashCan",
        "mass": 10,
        "distance": 0.5,
        "fullState": [
          {
            "name": "balancingAct.introScreen.model.fireExtinguisher1",
            "mass": 5,
            "distance": 1.25
          },
          {
            "name": "balancingAct.introScreen.model.smallTrashCan",
            "mass": 10,
            "distance": 0.5
          }
        ]
      }

However, I realized to get this working for the creator pattern on the 2nd screen, we would likely need to introduce PhetioGroup for the elements to set their names. That will be a good long term plan but I don't know if I have enough time to implement that by tomorrow.

Here's the patch:

```diff Index: js/common/model/Mass.js IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- js/common/model/Mass.js (revision bdb38565d338d01cc13b664945c92a2b62d6b7cd) +++ js/common/model/Mass.js (date 1579544812001) @@ -20,7 +20,7 @@ // TODO: JSDoc is missing in many places, see https://github.com/phetsims/balancing-act/issues/96 // TODO: Convert to ES6, see https://github.com/phetsims/balancing-act/issues/96 - function Mass( massValue, initialPosition, isMystery ) { + function Mass( massValue, initialPosition, isMystery, tandem ) { const self = this; // Property that indicates whether this mass is currently user controlled, i.e. being moved around by the user. @@ -60,6 +60,10 @@ // that indicates where their center of mass is when placed on a balance. // This is the horizontal offset from the center of the shape or image. self.centerOfMassXOffset = 0; + + // TODO: Should this be an instrumented PhetioObject, or an empty intermediate node? See https://github.com/phetsims/balancing-act/issues/99 + // @public (read-only) {Tandem} + this.tandem = tandem; } balancingAct.register( 'Mass', Mass ); Index: js/intro/model/BAIntroModel.js IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- js/intro/model/BAIntroModel.js (revision bdb38565d338d01cc13b664945c92a2b62d6b7cd) +++ js/intro/model/BAIntroModel.js (date 1579544422856) @@ -26,9 +26,9 @@ BalanceModel.call( this, tandem ); // Add the initial masses and save their initial positions. - this.addMass( new FireExtinguisher( new Vector2( 2.7, 0 ), false ) ); - this.addMass( new FireExtinguisher( new Vector2( 3.2, 0 ), false ) ); - this.addMass( new SmallTrashCan( new Vector2( 3.7, 0 ), false ) ); + this.addMass( new FireExtinguisher( new Vector2( 2.7, 0 ), false, tandem.createTandem( 'fireExtinguisher1' ) ) ); + this.addMass( new FireExtinguisher( new Vector2( 3.2, 0 ), false, tandem.createTandem( 'fireExtinguisher2' ) ) ); + this.addMass( new SmallTrashCan( new Vector2( 3.7, 0 ), false, tandem.createTandem( 'smallTrashCan' ) ) ); } balancingAct.register( 'BAIntroModel', BAIntroModel ); Index: js/common/model/masses/SmallTrashCan.js IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- js/common/model/masses/SmallTrashCan.js (revision bdb38565d338d01cc13b664945c92a2b62d6b7cd) +++ js/common/model/masses/SmallTrashCan.js (date 1579544422862) @@ -18,10 +18,11 @@ /** * @param initialPosition * @param isMystery + * @param {Tandem} tandem * @constructor */ - function SmallTrashCan( initialPosition, isMystery ) { - ImageMass.call( this, MASS, trashCanImage, HEIGHT, initialPosition, isMystery ); + function SmallTrashCan( initialPosition, isMystery, tandem ) { + ImageMass.call( this, MASS, trashCanImage, HEIGHT, initialPosition, isMystery, tandem ); } balancingAct.register( 'SmallTrashCan', SmallTrashCan ); Index: js/balancing-act-main.js IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- js/balancing-act-main.js (revision bdb38565d338d01cc13b664945c92a2b62d6b7cd) +++ js/balancing-act-main.js (date 1579544757240) @@ -8,7 +8,7 @@ // modules const BAIntroScreen = require( 'BALANCING_ACT/intro/BAIntroScreen' ); - const BalanceGameScreen = require( 'BALANCING_ACT/game/BalanceGameScreen' ); + // const BalanceGameScreen = require( 'BALANCING_ACT/game/BalanceGameScreen' ); const BalanceLabScreen = require( 'BALANCING_ACT/balancelab/BalanceLabScreen' ); const Sim = require( 'JOIST/Sim' ); const SimLauncher = require( 'JOIST/SimLauncher' ); @@ -35,7 +35,7 @@ new Sim( balancingActTitleString, [ new BAIntroScreen( tandem.createTandem( 'introScreen' ) ), new BalanceLabScreen( tandem.createTandem( 'balanceLabScreen' ) ), - new BalanceGameScreen( tandem.createTandem( 'gameScreen' ) ) + // new BalanceGameScreen( tandem.createTandem( 'gameScreen' ) ) ], simOptions ).start(); } ); } ); \ No newline at end of file Index: js/common/model/masses/FireExtinguisher.js IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- js/common/model/masses/FireExtinguisher.js (revision bdb38565d338d01cc13b664945c92a2b62d6b7cd) +++ js/common/model/masses/FireExtinguisher.js (date 1579543813116) @@ -18,10 +18,11 @@ /** * @param initialPosition * @param isMystery + * @param {Tandem} tandem * @constructor */ - function FireExtinguisher( initialPosition, isMystery ) { - ImageMass.call( this, MASS, fireExtinguisherImage, HEIGHT, initialPosition, isMystery ); + function FireExtinguisher( initialPosition, isMystery, tandem ) { + ImageMass.call( this, MASS, fireExtinguisherImage, HEIGHT, initialPosition, isMystery, tandem ); this.centerOfMassXOffset = 0.03; // Empirically determined. } Index: js/common/model/ImageMass.js IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- js/common/model/ImageMass.js (revision bdb38565d338d01cc13b664945c92a2b62d6b7cd) +++ js/common/model/ImageMass.js (date 1579543869648) @@ -26,10 +26,11 @@ * @param height * @param initialPosition * @param isMystery + * @param {Tandem} tandem * @constructor */ - function ImageMass( mass, image, height, initialPosition, isMystery ) { - Mass.call( this, mass, initialPosition, isMystery ); + function ImageMass( mass, image, height, initialPosition, isMystery, tandem ) { + Mass.call( this, mass, initialPosition, isMystery, tandem ); // Property that contains the current image. this.imageProperty = new Property( image ); Index: js/common/model/Plank.js IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- js/common/model/Plank.js (revision bdb38565d338d01cc13b664945c92a2b62d6b7cd) +++ js/common/model/Plank.js (date 1579544336417) @@ -22,6 +22,7 @@ const ObservableArray = require( 'AXON/ObservableArray' ); const Property = require( 'AXON/Property' ); const Shape = require( 'KITE/Shape' ); + const StringIO = require( 'TANDEM/types/StringIO' ); const Vector2 = require( 'DOT/Vector2' ); // constants @@ -73,8 +74,9 @@ this.massDroppedOnPlankEmitter = new Emitter( { tandem: tandem.createTandem( 'massDroppedOnPlankEmitter' ), parameters: [ + { name: 'phetioID', phetioType: StringIO }, { name: 'mass', phetioType: NumberIO }, - { name: 'position', phetioType: NumberIO }, + { name: 'distance', phetioType: NumberIO }, { name: 'fullState', phetioType: ObjectIO } ] } ); @@ -82,8 +84,9 @@ this.massRemovedFromPlankEmitter = new Emitter( { tandem: tandem.createTandem( 'massRemovedFromPlankEmitter' ), parameters: [ + { name: 'phetioID', phetioType: StringIO }, { name: 'mass', phetioType: NumberIO }, - { name: 'position', phetioType: NumberIO }, + { name: 'distance', phetioType: NumberIO }, { name: 'fullState', phetioType: ObjectIO } ] } ); @@ -202,20 +205,14 @@ }; this.massDistancePairs.push( result ); - const fullState = this.massDistancePairs.map( massDistancePair => { - return { - mass: massDistancePair.mass.massValue, - distance: massDistancePair.distance - }; - } ); - this.massDroppedOnPlankEmitter.emit( mass.massValue, result.distance, fullState ); + this.massDroppedOnPlankEmitter.emit( mass.tandem.phetioID, mass.massValue, result.distance, this.getPhetioState() ); // Add the force vector for this mass. this.forceVectors.push( new MassForceVector( mass ) ); // Add an observer that will remove this mass when the user picks it up. const self = this; - var userControlledObserver = function( userControlled ) { + const userControlledObserver = function( userControlled ) { if ( userControlled ) { // The user has picked up this mass, so it is no longer // on the surface. @@ -234,6 +231,20 @@ return massAdded; }, + /** + * @returns {Object} + * @private + */ + getPhetioState() { + return this.massDistancePairs.map( massDistancePair => { + return { + name: massDistancePair.mass.tandem.phetioID, + mass: massDistancePair.mass.massValue, + distance: massDistancePair.distance + }; + } ) + }, + // Add a mass to the specified location on the plank. addMassToSurfaceAt: function( mass, distanceFromCenter ) { if ( Math.abs( distanceFromCenter ) > PLANK_LENGTH / 2 ) { @@ -283,14 +294,7 @@ const distance = this.massDistancePairs[ i ].distance; this.massDistancePairs.splice( i, 1 ); - - const fullState = this.massDistancePairs.map( massDistancePair => { - return { - mass: massDistancePair.mass.massValue, - distance: massDistancePair.distance - }; - } ); - this.massRemovedFromPlankEmitter.emit( mass.massValue, distance, fullState ); + this.massRemovedFromPlankEmitter.emit( mass.tandem.phetioID, mass.massValue, distance, this.getPhetioState() ); break; } ```
kathy-phet commented 4 years ago

@samreid - Tomorrow will definitely not include data collection, so I don't think this is a "by tomorrow" sort of question. Logging is a week away - at a minimum - and could be more depending on how the testing of the logging goes this week.

chrisklus commented 4 years ago

I tried out @samreid's suggestion of implementing PhetioGroups for the brick stacks and mystery masses.

It looks nice in the data stream:

"data": {
  "phetioID": "balancingAct.balanceLabScreen.model.mysteryMassGroup.mysteryMass_0",
  "mass": 15,
  "distance": -0.5,
  "fullState": [
    {
      "name": "balancingAct.balanceLabScreen.model.brickStackGroup.brickStack_0",
      "mass": 5,
      "distance": 0.5
    },
    {
      "name": "balancingAct.balanceLabScreen.model.mysteryMassGroup.mysteryMass_0",
      "mass": 15,
      "distance": -0.5
    }
  ]
}

However, it was difficult and not pretty to get this working. Most of the trouble I ran into was because I was trying to make the conversion for just these two types (many more "mass" types are used in the sim). I think it will be a project to implement this generally for the whole sim.

Working patch (including @samreid's changes from above):

```diff Index: balancing-act/js/intro/model/BAIntroModel.js IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- balancing-act/js/intro/model/BAIntroModel.js (revision bdb38565d338d01cc13b664945c92a2b62d6b7cd) +++ balancing-act/js/intro/model/BAIntroModel.js (date 1579570484000) @@ -26,9 +26,9 @@ BalanceModel.call( this, tandem ); // Add the initial masses and save their initial positions. - this.addMass( new FireExtinguisher( new Vector2( 2.7, 0 ), false ) ); - this.addMass( new FireExtinguisher( new Vector2( 3.2, 0 ), false ) ); - this.addMass( new SmallTrashCan( new Vector2( 3.7, 0 ), false ) ); + this.addMass( new FireExtinguisher( new Vector2( 2.7, 0 ), false, { tandem: tandem.createTandem( 'fireExtinguisher1' ) } ) ); + this.addMass( new FireExtinguisher( new Vector2( 3.2, 0 ), false, { tandem: tandem.createTandem( 'fireExtinguisher2' ) } ) ); + this.addMass( new SmallTrashCan( new Vector2( 3.7, 0 ), false, { tandem: tandem.createTandem( 'smallTrashCan' ) } ) ); } balancingAct.register( 'BAIntroModel', BAIntroModel ); Index: balancing-act/js/balancelab/view/BrickStackCreatorNode.js IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- balancing-act/js/balancelab/view/BrickStackCreatorNode.js (revision bdb38565d338d01cc13b664945c92a2b62d6b7cd) +++ balancing-act/js/balancelab/view/BrickStackCreatorNode.js (date 1579569958000) @@ -21,6 +21,7 @@ const ModelViewTransform2 = require( 'PHETCOMMON/view/ModelViewTransform2' ); const Property = require( 'AXON/Property' ); const Shape = require( 'KITE/Shape' ); + const Tandem = require( 'TANDEM/Tandem' ); const Vector2 = require( 'DOT/Vector2' ); // Model-view transform for scaling the node used in the toolbox. This @@ -47,7 +48,7 @@ } ); const selectionNode = new BrickStackNode( - new BrickStack( numBricks, Vector2.ZERO, false ), + new BrickStack( numBricks, Vector2.ZERO, { tandem: Tandem.OPT_OUT } ), SCALING_MVT, false, new Property( false ), @@ -70,11 +71,7 @@ return inherit( MassCreatorNode, BrickStackCreatorNode, { addElementToModel: function( position ) { - const brickStack = new BrickStack( this.numBricks, position ); - brickStack.userControlledProperty.set( true ); - brickStack.animationDestination = position; - this.model.addMass( brickStack ); - return brickStack; + return this.model.brickStackGroup.createNextMember( this.numBricks, position ); } } ); } ); \ No newline at end of file Index: balancing-act/js/common/model/masses/BrickStack.js IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- balancing-act/js/common/model/masses/BrickStack.js (revision bdb38565d338d01cc13b664945c92a2b62d6b7cd) +++ balancing-act/js/common/model/masses/BrickStack.js (date 1579570886000) @@ -25,9 +25,10 @@ /** * @param {number} numBricks * @param {Vector2} initialPosition + * @param {Object} options * @constructor */ - function BrickStack( numBricks, initialPosition ) { + function BrickStack( numBricks, initialPosition, options ) { if ( numBricks <= 0 ) { throw new Error( 'Must have at least one brick in stack' ); } @@ -44,7 +45,7 @@ this.shape = brickStackShape; - Mass.call( this, numBricks * BRICK_MASS, initialPosition ); + Mass.call( this, numBricks * BRICK_MASS, initialPosition, false, options ); } balancingAct.register( 'BrickStack', BrickStack ); Index: balancing-act/js/common/model/masses/LabeledImageMass.js IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- balancing-act/js/common/model/masses/LabeledImageMass.js (revision bdb38565d338d01cc13b664945c92a2b62d6b7cd) +++ balancing-act/js/common/model/masses/LabeledImageMass.js (date 1579569958000) @@ -21,7 +21,7 @@ * @constructor */ function LabeledImageMass( initialPosition, config ) { - ImageMass.call( this, config.massValue, config.image, config.height, initialPosition, config.isMystery ); + ImageMass.call( this, config.massValue, config.image, config.height, initialPosition, config.isMystery, config ); this.labelText = config.labelText; } Index: balancing-act/js/balancelab/view/MysteryMassCreatorNode.js IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- balancing-act/js/balancelab/view/MysteryMassCreatorNode.js (revision bdb38565d338d01cc13b664945c92a2b62d6b7cd) +++ balancing-act/js/balancelab/view/MysteryMassCreatorNode.js (date 1579570529000) @@ -19,6 +19,7 @@ const MysteryMassNode = require( 'BALANCING_ACT/common/view/MysteryMassNode' ); const Property = require( 'AXON/Property' ); const Vector2 = require( 'DOT/Vector2' ); + const Tandem = require( 'TANDEM/Tandem' ); // Model-view transform for scaling the node used in the toolbox. This // may scale the node differently than what is used in the model so that @@ -26,12 +27,18 @@ const SCALING_MVT = ModelViewTransform2.createOffsetScaleMapping( Vector2.ZERO, 150 ); function MysteryMassCreatorNode( mysteryMassID, model, modelViewTransform, options ) { - ImageMassCreatorNode.call( this, model, modelViewTransform, new MysteryMass( Vector2.ZERO, mysteryMassID ), false, options ); + ImageMassCreatorNode.call( this, model, modelViewTransform, new MysteryMass( Vector2.ZERO, mysteryMassID, { tandem: Tandem.OPT_OUT } ), false, options ); + this.mysteryMassId = mysteryMassID; this.setSelectionNode( new MysteryMassNode( this.prototypeImageMass, SCALING_MVT, false, new Property( false ), false, model.columnStateProperty ) ); this.positioningOffset = new Vector2( 0, -modelViewTransform.modelToViewDeltaY( this.prototypeImageMass.heightProperty.get() / 2 ) ); } balancingAct.register( 'MysteryMassCreatorNode', MysteryMassCreatorNode ); - return inherit( ImageMassCreatorNode, MysteryMassCreatorNode ); + return inherit( ImageMassCreatorNode, MysteryMassCreatorNode, { + + addElementToModel: function( position ) { + return this.model.mysteryMassGroup.createNextMember( position, this.mysteryMassId ); + } + } ); } ); \ No newline at end of file Index: balancing-act/js/phet-io/balancing-act-phet-io-elements-baseline.js IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- balancing-act/js/phet-io/balancing-act-phet-io-elements-baseline.js (revision bdb38565d338d01cc13b664945c92a2b62d6b7cd) +++ balancing-act/js/phet-io/balancing-act-phet-io-elements-baseline.js (date 1579570543000) @@ -14,6 +14,32 @@ "phetioStudioControl": true, "phetioTypeName": "PropertyIO" }, + "balancingAct.balanceLabScreen.model.brickStackGroup": { + "phetioDocumentation": "", + "phetioDynamicElement": false, + "phetioEventType": "MODEL", + "phetioFeatured": false, + "phetioHighFrequency": false, + "phetioIsArchetype": false, + "phetioPlayback": false, + "phetioReadOnly": false, + "phetioState": false, + "phetioStudioControl": true, + "phetioTypeName": "PhetioGroupIO" + }, + "balancingAct.balanceLabScreen.model.brickStackGroup.archetype": { + "phetioDocumentation": "", + "phetioDynamicElement": false, + "phetioEventType": "MODEL", + "phetioFeatured": false, + "phetioHighFrequency": false, + "phetioIsArchetype": true, + "phetioPlayback": false, + "phetioReadOnly": false, + "phetioState": true, + "phetioStudioControl": true, + "phetioTypeName": "ReferenceIO" + }, "balancingAct.balanceLabScreen.model.columnStateProperty": { "phetioDocumentation": "", "phetioDynamicElement": false, @@ -27,8 +53,8 @@ "phetioStudioControl": true, "phetioTypeName": "PropertyIO" }, - "balancingAct.balanceLabScreen.model.plank.massDroppedOnPlankEmitter": { - "phetioDocumentation": "A function that executes. The arguments are:
  1. mass: NumberIO

  2. position: NumberIO

  3. fullState: ObjectIO
", + "balancingAct.balanceLabScreen.model.mysteryMassGroup": { + "phetioDocumentation": "", "phetioDynamicElement": false, "phetioEventType": "MODEL", "phetioFeatured": false, @@ -38,36 +64,36 @@ "phetioReadOnly": false, "phetioState": false, "phetioStudioControl": true, - "phetioTypeName": "EmitterIO" + "phetioTypeName": "PhetioGroupIO" }, - "balancingAct.balanceLabScreen.model.plank.massRemovedFromPlankEmitter": { - "phetioDocumentation": "A function that executes. The arguments are:
  1. mass: NumberIO

  2. position: NumberIO

  3. fullState: ObjectIO
", + "balancingAct.balanceLabScreen.model.mysteryMassGroup.archetype": { + "phetioDocumentation": "", "phetioDynamicElement": false, "phetioEventType": "MODEL", "phetioFeatured": false, "phetioHighFrequency": false, - "phetioIsArchetype": false, + "phetioIsArchetype": true, "phetioPlayback": false, "phetioReadOnly": false, - "phetioState": false, + "phetioState": true, "phetioStudioControl": true, - "phetioTypeName": "EmitterIO" + "phetioTypeName": "ReferenceIO" }, - "balancingAct.balanceLabScreen.model.plank.tiltAngleProperty": { - "phetioDocumentation": "Angle of the plank with respect to the ground. A value of 0 indicates a level plank, positive is tilted left, negative to the right.", + "balancingAct.balanceLabScreen.model.plank.massDroppedOnPlankEmitter": { + "phetioDocumentation": "A function that executes. The arguments are:
  1. phetioID: StringIO

  2. mass: NumberIO

  3. distance: NumberIO

  4. fullState: ObjectIO
", "phetioDynamicElement": false, "phetioEventType": "MODEL", "phetioFeatured": false, - "phetioHighFrequency": true, + "phetioHighFrequency": false, "phetioIsArchetype": false, "phetioPlayback": false, - "phetioReadOnly": true, - "phetioState": true, + "phetioReadOnly": false, + "phetioState": false, "phetioStudioControl": true, - "phetioTypeName": "NumberPropertyIO" + "phetioTypeName": "EmitterIO" }, - "balancingAct.balanceLabScreen.view.columnControlPanel": { - "phetioDocumentation": "", + "balancingAct.balanceLabScreen.model.plank.massRemovedFromPlankEmitter": { + "phetioDocumentation": "A function that executes. The arguments are:
  1. phetioID: StringIO

  2. mass: NumberIO

  3. distance: NumberIO

  4. fullState: ObjectIO
", "phetioDynamicElement": false, "phetioEventType": "MODEL", "phetioFeatured": false, @@ -77,22 +103,22 @@ "phetioReadOnly": false, "phetioState": false, "phetioStudioControl": true, - "phetioTypeName": "NodeIO" + "phetioTypeName": "EmitterIO" }, - "balancingAct.balanceLabScreen.view.columnControlPanel.abSwitch": { - "phetioDocumentation": "", + "balancingAct.balanceLabScreen.model.plank.tiltAngleProperty": { + "phetioDocumentation": "Angle of the plank with respect to the ground. A value of 0 indicates a level plank, positive is tilted left, negative to the right.", "phetioDynamicElement": false, "phetioEventType": "MODEL", "phetioFeatured": false, - "phetioHighFrequency": false, + "phetioHighFrequency": true, "phetioIsArchetype": false, "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": false, + "phetioReadOnly": true, + "phetioState": true, "phetioStudioControl": true, - "phetioTypeName": "NodeIO" + "phetioTypeName": "NumberPropertyIO" }, - "balancingAct.balanceLabScreen.view.columnControlPanel.abSwitch.aInputListener": { + "balancingAct.balanceLabScreen.view.columnControlPanel": { "phetioDocumentation": "", "phetioDynamicElement": false, "phetioEventType": "MODEL", @@ -103,9 +129,9 @@ "phetioReadOnly": false, "phetioState": false, "phetioStudioControl": true, - "phetioTypeName": "ButtonListenerIO" + "phetioTypeName": "NodeIO" }, - "balancingAct.balanceLabScreen.view.columnControlPanel.abSwitch.bInputListener": { + "balancingAct.balanceLabScreen.view.columnControlPanel.abSwitch": { "phetioDocumentation": "", "phetioDynamicElement": false, "phetioEventType": "MODEL", @@ -116,7 +142,7 @@ "phetioReadOnly": false, "phetioState": false, "phetioStudioControl": true, - "phetioTypeName": "ButtonListenerIO" + "phetioTypeName": "NodeIO" }, "balancingAct.balanceLabScreen.view.columnControlPanel.abSwitch.onOffSwitch": { "phetioDocumentation": "", @@ -585,123 +611,6 @@ "phetioState": true, "phetioStudioControl": true, "phetioTypeName": "PropertyIO" - }, - "balancingAct.balanceLabScreen.view.massCarousel.brickStackCreatorNode3": { - "phetioDocumentation": "", - "phetioDynamicElement": false, - "phetioEventType": "MODEL", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": false, - "phetioStudioControl": true, - "phetioTypeName": "NodeIO" - }, - "balancingAct.balanceLabScreen.view.massCarousel.brickStackCreatorNode3.dragHandler": { - "phetioDocumentation": "", - "phetioDynamicElement": false, - "phetioEventType": "USER", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": true, - "phetioState": false, - "phetioStudioControl": true, - "phetioTypeName": "ObjectIO" - }, - "balancingAct.balanceLabScreen.view.massCarousel.brickStackCreatorNode3.dragHandler.dragAction": { - "phetioDocumentation": "A function that executes. The arguments are:
  1. point: Vector2IO. the position of the drag in view coordinates
", - "phetioDynamicElement": false, - "phetioEventType": "MODEL", - "phetioFeatured": false, - "phetioHighFrequency": true, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": true, - "phetioState": false, - "phetioStudioControl": true, - "phetioTypeName": "ActionIO" - }, - "balancingAct.balanceLabScreen.view.massCarousel.brickStackCreatorNode3.dragHandler.dragEndAction": { - "phetioDocumentation": "A function that executes. The arguments are:
  1. point: Vector2IO. the position of the drag end in view coordinates
", - "phetioDynamicElement": false, - "phetioEventType": "MODEL", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": true, - "phetioState": false, - "phetioStudioControl": true, - "phetioTypeName": "ActionIO" - }, - "balancingAct.balanceLabScreen.view.massCarousel.brickStackCreatorNode3.dragHandler.dragStartAction": { - "phetioDocumentation": "A function that executes. The arguments are:
  1. point: Vector2IO. the position of the drag start in view coordinates
", - "phetioDynamicElement": false, - "phetioEventType": "MODEL", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": true, - "phetioState": false, - "phetioStudioControl": true, - "phetioTypeName": "ActionIO" - }, - "balancingAct.balanceLabScreen.view.massCarousel.brickStackCreatorNode3.dragHandler.isDraggingProperty": { - "phetioDocumentation": "Indicates whether the object is dragging", - "phetioDynamicElement": false, - "phetioEventType": "MODEL", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": true, - "phetioState": false, - "phetioStudioControl": true, - "phetioTypeName": "PropertyIO" - }, - "balancingAct.balanceLabScreen.view.massCarousel.brickStackCreatorNode3.opacityProperty": { - "phetioDocumentation": "Opacity of the parent NodeIO, between 0 (invisible) and 1 (fully visible)", - "phetioDynamicElement": false, - "phetioEventType": "MODEL", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": true, - "phetioStudioControl": true, - "phetioTypeName": "NumberPropertyIO" - }, - "balancingAct.balanceLabScreen.view.massCarousel.brickStackCreatorNode3.pickableProperty": { - "phetioDocumentation": "Sets whether the node will be pickable (and hence interactive), see the NodeIO documentation for more details", - "phetioDynamicElement": false, - "phetioEventType": "MODEL", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": true, - "phetioStudioControl": true, - "phetioTypeName": "PropertyIO>" - }, - "balancingAct.balanceLabScreen.view.massCarousel.brickStackCreatorNode3.visibleProperty": { - "phetioDocumentation": "Controls whether the Node will be visible (and interactive), see the NodeIO documentation for more details.", - "phetioDynamicElement": false, - "phetioEventType": "MODEL", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": true, - "phetioStudioControl": true, - "phetioTypeName": "PropertyIO" }, "balancingAct.balanceLabScreen.view.massCarousel.brickStackCreatorNode4": { "phetioDocumentation": "", @@ -2900,474 +2809,6 @@ "phetioStudioControl": true, "phetioTypeName": "PropertyIO" }, - "balancingAct.gameScreen.activeProperty": { - "phetioDocumentation": "Indicates whether the screen is currently displayed in the simulation. For single-screen simulations, there is only one screen and it is always active.", - "phetioDynamicElement": false, - "phetioEventType": "MODEL", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": true, - "phetioState": true, - "phetioStudioControl": true, - "phetioTypeName": "PropertyIO" - }, - "balancingAct.gameScreen.model.plank.massDroppedOnPlankEmitter": { - "phetioDocumentation": "A function that executes. The arguments are:
  1. mass: NumberIO

  2. position: NumberIO

  3. fullState: ObjectIO
", - "phetioDynamicElement": false, - "phetioEventType": "MODEL", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": false, - "phetioStudioControl": true, - "phetioTypeName": "EmitterIO" - }, - "balancingAct.gameScreen.model.plank.massRemovedFromPlankEmitter": { - "phetioDocumentation": "A function that executes. The arguments are:
  1. mass: NumberIO

  2. position: NumberIO

  3. fullState: ObjectIO
", - "phetioDynamicElement": false, - "phetioEventType": "MODEL", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": false, - "phetioStudioControl": true, - "phetioTypeName": "EmitterIO" - }, - "balancingAct.gameScreen.model.plank.tiltAngleProperty": { - "phetioDocumentation": "Angle of the plank with respect to the ground. A value of 0 indicates a level plank, positive is tilted left, negative to the right.", - "phetioDynamicElement": false, - "phetioEventType": "MODEL", - "phetioFeatured": false, - "phetioHighFrequency": true, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": true, - "phetioState": true, - "phetioStudioControl": true, - "phetioTypeName": "NumberPropertyIO" - }, - "balancingAct.gameScreen.view.positionPanel": { - "phetioDocumentation": "", - "phetioDynamicElement": false, - "phetioEventType": "MODEL", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": false, - "phetioStudioControl": true, - "phetioTypeName": "NodeIO" - }, - "balancingAct.gameScreen.view.positionPanel.opacityProperty": { - "phetioDocumentation": "Opacity of the parent NodeIO, between 0 (invisible) and 1 (fully visible)", - "phetioDynamicElement": false, - "phetioEventType": "MODEL", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": true, - "phetioStudioControl": true, - "phetioTypeName": "NumberPropertyIO" - }, - "balancingAct.gameScreen.view.positionPanel.pickableProperty": { - "phetioDocumentation": "Sets whether the node will be pickable (and hence interactive), see the NodeIO documentation for more details", - "phetioDynamicElement": false, - "phetioEventType": "MODEL", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": true, - "phetioStudioControl": true, - "phetioTypeName": "PropertyIO>" - }, - "balancingAct.gameScreen.view.positionPanel.positionRadioButtonGroup": { - "phetioDocumentation": "", - "phetioDynamicElement": false, - "phetioEventType": "MODEL", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": false, - "phetioStudioControl": true, - "phetioTypeName": "NodeIO" - }, - "balancingAct.gameScreen.view.positionPanel.positionRadioButtonGroup.marksRadioButton": { - "phetioDocumentation": "", - "phetioDynamicElement": false, - "phetioEventType": "MODEL", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": false, - "phetioStudioControl": true, - "phetioTypeName": "NodeIO" - }, - "balancingAct.gameScreen.view.positionPanel.positionRadioButtonGroup.marksRadioButton.enabledProperty": { - "phetioDocumentation": "Determines whether the AquaRadioButton is enabled (pressable) or disabled (grayed-out)", - "phetioDynamicElement": false, - "phetioEventType": "MODEL", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": true, - "phetioStudioControl": true, - "phetioTypeName": "PropertyIO" - }, - "balancingAct.gameScreen.view.positionPanel.positionRadioButtonGroup.marksRadioButton.fireListener.firedEmitter": { - "phetioDocumentation": "A function that executes. The arguments are:
  1. event: NullableIO
", - "phetioDynamicElement": false, - "phetioEventType": "USER", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": false, - "phetioStudioControl": true, - "phetioTypeName": "EmitterIO>" - }, - "balancingAct.gameScreen.view.positionPanel.positionRadioButtonGroup.marksRadioButton.fireListener.pressAction": { - "phetioDocumentation": "Executes whenever a press occurs. The first argument when executing can be used to convey info about the SceneryEvent. The arguments are:
  1. event: SceneryEventIO
", - "phetioDynamicElement": false, - "phetioEventType": "USER", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": false, - "phetioStudioControl": true, - "phetioTypeName": "ActionIO" - }, - "balancingAct.gameScreen.view.positionPanel.positionRadioButtonGroup.marksRadioButton.fireListener.releaseAction": { - "phetioDocumentation": "Executes whenever a release occurs. The arguments are:
  1. event: NullableIO
", - "phetioDynamicElement": false, - "phetioEventType": "USER", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": false, - "phetioStudioControl": true, - "phetioTypeName": "ActionIO>" - }, - "balancingAct.gameScreen.view.positionPanel.positionRadioButtonGroup.marksRadioButton.opacityProperty": { - "phetioDocumentation": "Opacity of the parent NodeIO, between 0 (invisible) and 1 (fully visible)", - "phetioDynamicElement": false, - "phetioEventType": "MODEL", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": true, - "phetioStudioControl": true, - "phetioTypeName": "NumberPropertyIO" - }, - "balancingAct.gameScreen.view.positionPanel.positionRadioButtonGroup.marksRadioButton.pickableProperty": { - "phetioDocumentation": "Sets whether the node will be pickable (and hence interactive), see the NodeIO documentation for more details", - "phetioDynamicElement": false, - "phetioEventType": "MODEL", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": true, - "phetioStudioControl": true, - "phetioTypeName": "PropertyIO>" - }, - "balancingAct.gameScreen.view.positionPanel.positionRadioButtonGroup.marksRadioButton.visibleProperty": { - "phetioDocumentation": "Controls whether the Node will be visible (and interactive), see the NodeIO documentation for more details.", - "phetioDynamicElement": false, - "phetioEventType": "MODEL", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": true, - "phetioStudioControl": true, - "phetioTypeName": "PropertyIO" - }, - "balancingAct.gameScreen.view.positionPanel.positionRadioButtonGroup.noneRadioButton": { - "phetioDocumentation": "", - "phetioDynamicElement": false, - "phetioEventType": "MODEL", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": false, - "phetioStudioControl": true, - "phetioTypeName": "NodeIO" - }, - "balancingAct.gameScreen.view.positionPanel.positionRadioButtonGroup.noneRadioButton.enabledProperty": { - "phetioDocumentation": "Determines whether the AquaRadioButton is enabled (pressable) or disabled (grayed-out)", - "phetioDynamicElement": false, - "phetioEventType": "MODEL", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": true, - "phetioStudioControl": true, - "phetioTypeName": "PropertyIO" - }, - "balancingAct.gameScreen.view.positionPanel.positionRadioButtonGroup.noneRadioButton.fireListener.firedEmitter": { - "phetioDocumentation": "A function that executes. The arguments are:
  1. event: NullableIO
", - "phetioDynamicElement": false, - "phetioEventType": "USER", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": false, - "phetioStudioControl": true, - "phetioTypeName": "EmitterIO>" - }, - "balancingAct.gameScreen.view.positionPanel.positionRadioButtonGroup.noneRadioButton.fireListener.pressAction": { - "phetioDocumentation": "Executes whenever a press occurs. The first argument when executing can be used to convey info about the SceneryEvent. The arguments are:
  1. event: SceneryEventIO
", - "phetioDynamicElement": false, - "phetioEventType": "USER", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": false, - "phetioStudioControl": true, - "phetioTypeName": "ActionIO" - }, - "balancingAct.gameScreen.view.positionPanel.positionRadioButtonGroup.noneRadioButton.fireListener.releaseAction": { - "phetioDocumentation": "Executes whenever a release occurs. The arguments are:
  1. event: NullableIO
", - "phetioDynamicElement": false, - "phetioEventType": "USER", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": false, - "phetioStudioControl": true, - "phetioTypeName": "ActionIO>" - }, - "balancingAct.gameScreen.view.positionPanel.positionRadioButtonGroup.noneRadioButton.opacityProperty": { - "phetioDocumentation": "Opacity of the parent NodeIO, between 0 (invisible) and 1 (fully visible)", - "phetioDynamicElement": false, - "phetioEventType": "MODEL", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": true, - "phetioStudioControl": true, - "phetioTypeName": "NumberPropertyIO" - }, - "balancingAct.gameScreen.view.positionPanel.positionRadioButtonGroup.noneRadioButton.pickableProperty": { - "phetioDocumentation": "Sets whether the node will be pickable (and hence interactive), see the NodeIO documentation for more details", - "phetioDynamicElement": false, - "phetioEventType": "MODEL", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": true, - "phetioStudioControl": true, - "phetioTypeName": "PropertyIO>" - }, - "balancingAct.gameScreen.view.positionPanel.positionRadioButtonGroup.noneRadioButton.visibleProperty": { - "phetioDocumentation": "Controls whether the Node will be visible (and interactive), see the NodeIO documentation for more details.", - "phetioDynamicElement": false, - "phetioEventType": "MODEL", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": true, - "phetioStudioControl": true, - "phetioTypeName": "PropertyIO" - }, - "balancingAct.gameScreen.view.positionPanel.positionRadioButtonGroup.opacityProperty": { - "phetioDocumentation": "Opacity of the parent NodeIO, between 0 (invisible) and 1 (fully visible)", - "phetioDynamicElement": false, - "phetioEventType": "MODEL", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": true, - "phetioStudioControl": true, - "phetioTypeName": "NumberPropertyIO" - }, - "balancingAct.gameScreen.view.positionPanel.positionRadioButtonGroup.pickableProperty": { - "phetioDocumentation": "Sets whether the node will be pickable (and hence interactive), see the NodeIO documentation for more details", - "phetioDynamicElement": false, - "phetioEventType": "MODEL", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": true, - "phetioStudioControl": true, - "phetioTypeName": "PropertyIO>" - }, - "balancingAct.gameScreen.view.positionPanel.positionRadioButtonGroup.rulerRadioButton": { - "phetioDocumentation": "", - "phetioDynamicElement": false, - "phetioEventType": "MODEL", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": false, - "phetioStudioControl": true, - "phetioTypeName": "NodeIO" - }, - "balancingAct.gameScreen.view.positionPanel.positionRadioButtonGroup.rulerRadioButton.enabledProperty": { - "phetioDocumentation": "Determines whether the AquaRadioButton is enabled (pressable) or disabled (grayed-out)", - "phetioDynamicElement": false, - "phetioEventType": "MODEL", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": true, - "phetioStudioControl": true, - "phetioTypeName": "PropertyIO" - }, - "balancingAct.gameScreen.view.positionPanel.positionRadioButtonGroup.rulerRadioButton.fireListener.firedEmitter": { - "phetioDocumentation": "A function that executes. The arguments are:
  1. event: NullableIO
", - "phetioDynamicElement": false, - "phetioEventType": "USER", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": false, - "phetioStudioControl": true, - "phetioTypeName": "EmitterIO>" - }, - "balancingAct.gameScreen.view.positionPanel.positionRadioButtonGroup.rulerRadioButton.fireListener.pressAction": { - "phetioDocumentation": "Executes whenever a press occurs. The first argument when executing can be used to convey info about the SceneryEvent. The arguments are:
  1. event: SceneryEventIO
", - "phetioDynamicElement": false, - "phetioEventType": "USER", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": false, - "phetioStudioControl": true, - "phetioTypeName": "ActionIO" - }, - "balancingAct.gameScreen.view.positionPanel.positionRadioButtonGroup.rulerRadioButton.fireListener.releaseAction": { - "phetioDocumentation": "Executes whenever a release occurs. The arguments are:
  1. event: NullableIO
", - "phetioDynamicElement": false, - "phetioEventType": "USER", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": false, - "phetioStudioControl": true, - "phetioTypeName": "ActionIO>" - }, - "balancingAct.gameScreen.view.positionPanel.positionRadioButtonGroup.rulerRadioButton.opacityProperty": { - "phetioDocumentation": "Opacity of the parent NodeIO, between 0 (invisible) and 1 (fully visible)", - "phetioDynamicElement": false, - "phetioEventType": "MODEL", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": true, - "phetioStudioControl": true, - "phetioTypeName": "NumberPropertyIO" - }, - "balancingAct.gameScreen.view.positionPanel.positionRadioButtonGroup.rulerRadioButton.pickableProperty": { - "phetioDocumentation": "Sets whether the node will be pickable (and hence interactive), see the NodeIO documentation for more details", - "phetioDynamicElement": false, - "phetioEventType": "MODEL", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": true, - "phetioStudioControl": true, - "phetioTypeName": "PropertyIO>" - }, - "balancingAct.gameScreen.view.positionPanel.positionRadioButtonGroup.rulerRadioButton.visibleProperty": { - "phetioDocumentation": "Controls whether the Node will be visible (and interactive), see the NodeIO documentation for more details.", - "phetioDynamicElement": false, - "phetioEventType": "MODEL", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": true, - "phetioStudioControl": true, - "phetioTypeName": "PropertyIO" - }, - "balancingAct.gameScreen.view.positionPanel.positionRadioButtonGroup.visibleProperty": { - "phetioDocumentation": "Controls whether the Node will be visible (and interactive), see the NodeIO documentation for more details.", - "phetioDynamicElement": false, - "phetioEventType": "MODEL", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": true, - "phetioStudioControl": true, - "phetioTypeName": "PropertyIO" - }, - "balancingAct.gameScreen.view.positionPanel.visibleProperty": { - "phetioDocumentation": "Controls whether the Node will be visible (and interactive), see the NodeIO documentation for more details.", - "phetioDynamicElement": false, - "phetioEventType": "MODEL", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": true, - "phetioStudioControl": true, - "phetioTypeName": "PropertyIO" - }, "balancingAct.general.activeProperty": { "phetioDocumentation": "Determines whether the entire simulation is running and processing user input. Setting this property to false pauses the simulation, and prevents user interaction.", "phetioDynamicElement": false, @@ -3914,227 +3355,6 @@ "phetioStudioControl": true, "phetioTypeName": "PropertyIO" }, - "balancingAct.general.navigationBar.gameScreenButton": { - "phetioDocumentation": "Button in the navigation bar that selects the 'gameScreen' screen", - "phetioDynamicElement": false, - "phetioEventType": "MODEL", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": false, - "phetioStudioControl": true, - "phetioTypeName": "NodeIO" - }, - "balancingAct.general.navigationBar.gameScreenButton.enabledProperty": { - "phetioDocumentation": "When disabled, the button is grayed out and cannot be pressed", - "phetioDynamicElement": false, - "phetioEventType": "MODEL", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": true, - "phetioStudioControl": true, - "phetioTypeName": "PropertyIO" - }, - "balancingAct.general.navigationBar.gameScreenButton.firedEmitter": { - "phetioDocumentation": "Emits when the button is fired No arguments.", - "phetioDynamicElement": false, - "phetioEventType": "USER", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": false, - "phetioStudioControl": true, - "phetioTypeName": "EmitterIO<>" - }, - "balancingAct.general.navigationBar.gameScreenButton.icon": { - "phetioDocumentation": "", - "phetioDynamicElement": false, - "phetioEventType": "MODEL", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": false, - "phetioStudioControl": true, - "phetioTypeName": "NodeIO" - }, - "balancingAct.general.navigationBar.gameScreenButton.icon.opacityProperty": { - "phetioDocumentation": "Opacity of the parent NodeIO, between 0 (invisible) and 1 (fully visible)", - "phetioDynamicElement": false, - "phetioEventType": "MODEL", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": true, - "phetioStudioControl": true, - "phetioTypeName": "NumberPropertyIO" - }, - "balancingAct.general.navigationBar.gameScreenButton.icon.pickableProperty": { - "phetioDocumentation": "Sets whether the node will be pickable (and hence interactive), see the NodeIO documentation for more details", - "phetioDynamicElement": false, - "phetioEventType": "MODEL", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": true, - "phetioStudioControl": true, - "phetioTypeName": "PropertyIO>" - }, - "balancingAct.general.navigationBar.gameScreenButton.icon.visibleProperty": { - "phetioDocumentation": "Controls whether the Node will be visible (and interactive), see the NodeIO documentation for more details.", - "phetioDynamicElement": false, - "phetioEventType": "MODEL", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": true, - "phetioStudioControl": true, - "phetioTypeName": "PropertyIO" - }, - "balancingAct.general.navigationBar.gameScreenButton.opacityProperty": { - "phetioDocumentation": "Opacity of the parent NodeIO, between 0 (invisible) and 1 (fully visible)", - "phetioDynamicElement": false, - "phetioEventType": "MODEL", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": true, - "phetioStudioControl": true, - "phetioTypeName": "NumberPropertyIO" - }, - "balancingAct.general.navigationBar.gameScreenButton.pickableProperty": { - "phetioDocumentation": "Sets whether the node will be pickable (and hence interactive), see the NodeIO documentation for more details", - "phetioDynamicElement": false, - "phetioEventType": "MODEL", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": true, - "phetioStudioControl": true, - "phetioTypeName": "PropertyIO>" - }, - "balancingAct.general.navigationBar.gameScreenButton.pressListener.pressAction": { - "phetioDocumentation": "Executes whenever a press occurs. The first argument when executing can be used to convey info about the SceneryEvent. The arguments are:
  1. event: SceneryEventIO
", - "phetioDynamicElement": false, - "phetioEventType": "USER", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": false, - "phetioStudioControl": true, - "phetioTypeName": "ActionIO" - }, - "balancingAct.general.navigationBar.gameScreenButton.pressListener.releaseAction": { - "phetioDocumentation": "Executes whenever a release occurs. The arguments are:
  1. event: NullableIO
", - "phetioDynamicElement": false, - "phetioEventType": "USER", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": false, - "phetioStudioControl": true, - "phetioTypeName": "ActionIO>" - }, - "balancingAct.general.navigationBar.gameScreenButton.text": { - "phetioDocumentation": "", - "phetioDynamicElement": false, - "phetioEventType": "MODEL", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": false, - "phetioStudioControl": true, - "phetioTypeName": "TextIO" - }, - "balancingAct.general.navigationBar.gameScreenButton.text.opacityProperty": { - "phetioDocumentation": "Opacity of the parent NodeIO, between 0 (invisible) and 1 (fully visible)", - "phetioDynamicElement": false, - "phetioEventType": "MODEL", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": true, - "phetioStudioControl": true, - "phetioTypeName": "NumberPropertyIO" - }, - "balancingAct.general.navigationBar.gameScreenButton.text.pickableProperty": { - "phetioDocumentation": "Sets whether the node will be pickable (and hence interactive), see the NodeIO documentation for more details", - "phetioDynamicElement": false, - "phetioEventType": "MODEL", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": true, - "phetioStudioControl": true, - "phetioTypeName": "PropertyIO>" - }, - "balancingAct.general.navigationBar.gameScreenButton.text.textProperty": { - "phetioDocumentation": "Property for the displayed text", - "phetioDynamicElement": false, - "phetioEventType": "MODEL", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": true, - "phetioStudioControl": true, - "phetioTypeName": "PropertyIO" - }, - "balancingAct.general.navigationBar.gameScreenButton.text.visibleProperty": { - "phetioDocumentation": "Controls whether the Node will be visible (and interactive), see the NodeIO documentation for more details.", - "phetioDynamicElement": false, - "phetioEventType": "MODEL", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": true, - "phetioStudioControl": true, - "phetioTypeName": "PropertyIO" - }, - "balancingAct.general.navigationBar.gameScreenButton.visibleProperty": { - "phetioDocumentation": "Controls whether the Node will be visible (and interactive), see the NodeIO documentation for more details.", - "phetioDynamicElement": false, - "phetioEventType": "MODEL", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": true, - "phetioStudioControl": true, - "phetioTypeName": "PropertyIO" - }, "balancingAct.general.navigationBar.homeButton": { "phetioDocumentation": "", "phetioDynamicElement": false, @@ -5591,318 +4811,6 @@ "phetioStudioControl": true, "phetioTypeName": "PropertyIO" }, - "balancingAct.homeScreen.view.gameScreenLargeButton": { - "phetioDocumentation": "A pressable button in the simulation, in the home screen", - "phetioDynamicElement": false, - "phetioEventType": "USER", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": false, - "phetioStudioControl": true, - "phetioTypeName": "NodeIO" - }, - "balancingAct.homeScreen.view.gameScreenLargeButton.inputListener.firedEmitter": { - "phetioDocumentation": "A function that executes. The arguments are:
  1. event: NullableIO
", - "phetioDynamicElement": false, - "phetioEventType": "USER", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": false, - "phetioStudioControl": true, - "phetioTypeName": "EmitterIO>" - }, - "balancingAct.homeScreen.view.gameScreenLargeButton.inputListener.pressAction": { - "phetioDocumentation": "Executes whenever a press occurs. The first argument when executing can be used to convey info about the SceneryEvent. The arguments are:
  1. event: SceneryEventIO
", - "phetioDynamicElement": false, - "phetioEventType": "USER", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": false, - "phetioStudioControl": true, - "phetioTypeName": "ActionIO" - }, - "balancingAct.homeScreen.view.gameScreenLargeButton.inputListener.releaseAction": { - "phetioDocumentation": "Executes whenever a release occurs. The arguments are:
  1. event: NullableIO
", - "phetioDynamicElement": false, - "phetioEventType": "USER", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": false, - "phetioStudioControl": true, - "phetioTypeName": "ActionIO>" - }, - "balancingAct.homeScreen.view.gameScreenLargeButton.opacityProperty": { - "phetioDocumentation": "Opacity of the parent NodeIO, between 0 (invisible) and 1 (fully visible)", - "phetioDynamicElement": false, - "phetioEventType": "MODEL", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": true, - "phetioStudioControl": true, - "phetioTypeName": "NumberPropertyIO" - }, - "balancingAct.homeScreen.view.gameScreenLargeButton.pickableProperty": { - "phetioDocumentation": "Sets whether the node will be pickable (and hence interactive), see the NodeIO documentation for more details", - "phetioDynamicElement": false, - "phetioEventType": "MODEL", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": true, - "phetioStudioControl": true, - "phetioTypeName": "PropertyIO>" - }, - "balancingAct.homeScreen.view.gameScreenLargeButton.text": { - "phetioDocumentation": "", - "phetioDynamicElement": false, - "phetioEventType": "MODEL", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": false, - "phetioStudioControl": true, - "phetioTypeName": "TextIO" - }, - "balancingAct.homeScreen.view.gameScreenLargeButton.text.opacityProperty": { - "phetioDocumentation": "Opacity of the parent NodeIO, between 0 (invisible) and 1 (fully visible)", - "phetioDynamicElement": false, - "phetioEventType": "MODEL", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": true, - "phetioStudioControl": true, - "phetioTypeName": "NumberPropertyIO" - }, - "balancingAct.homeScreen.view.gameScreenLargeButton.text.pickableProperty": { - "phetioDocumentation": "Sets whether the node will be pickable (and hence interactive), see the NodeIO documentation for more details", - "phetioDynamicElement": false, - "phetioEventType": "MODEL", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": true, - "phetioStudioControl": true, - "phetioTypeName": "PropertyIO>" - }, - "balancingAct.homeScreen.view.gameScreenLargeButton.text.textProperty": { - "phetioDocumentation": "Property for the displayed text", - "phetioDynamicElement": false, - "phetioEventType": "MODEL", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": true, - "phetioStudioControl": true, - "phetioTypeName": "PropertyIO" - }, - "balancingAct.homeScreen.view.gameScreenLargeButton.text.visibleProperty": { - "phetioDocumentation": "Controls whether the Node will be visible (and interactive), see the NodeIO documentation for more details.", - "phetioDynamicElement": false, - "phetioEventType": "MODEL", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": true, - "phetioStudioControl": true, - "phetioTypeName": "PropertyIO" - }, - "balancingAct.homeScreen.view.gameScreenLargeButton.visibleProperty": { - "phetioDocumentation": "Controls whether the Node will be visible (and interactive), see the NodeIO documentation for more details.", - "phetioDynamicElement": false, - "phetioEventType": "MODEL", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": true, - "phetioStudioControl": true, - "phetioTypeName": "PropertyIO" - }, - "balancingAct.homeScreen.view.gameScreenSmallButton": { - "phetioDocumentation": "A pressable button in the simulation, in the home screen", - "phetioDynamicElement": false, - "phetioEventType": "USER", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": false, - "phetioStudioControl": true, - "phetioTypeName": "NodeIO" - }, - "balancingAct.homeScreen.view.gameScreenSmallButton.inputListener.firedEmitter": { - "phetioDocumentation": "A function that executes. The arguments are:
  1. event: NullableIO
", - "phetioDynamicElement": false, - "phetioEventType": "USER", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": false, - "phetioStudioControl": true, - "phetioTypeName": "EmitterIO>" - }, - "balancingAct.homeScreen.view.gameScreenSmallButton.inputListener.pressAction": { - "phetioDocumentation": "Executes whenever a press occurs. The first argument when executing can be used to convey info about the SceneryEvent. The arguments are:
  1. event: SceneryEventIO
", - "phetioDynamicElement": false, - "phetioEventType": "USER", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": false, - "phetioStudioControl": true, - "phetioTypeName": "ActionIO" - }, - "balancingAct.homeScreen.view.gameScreenSmallButton.inputListener.releaseAction": { - "phetioDocumentation": "Executes whenever a release occurs. The arguments are:
  1. event: NullableIO
", - "phetioDynamicElement": false, - "phetioEventType": "USER", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": false, - "phetioStudioControl": true, - "phetioTypeName": "ActionIO>" - }, - "balancingAct.homeScreen.view.gameScreenSmallButton.opacityProperty": { - "phetioDocumentation": "Opacity of the parent NodeIO, between 0 (invisible) and 1 (fully visible)", - "phetioDynamicElement": false, - "phetioEventType": "MODEL", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": true, - "phetioStudioControl": true, - "phetioTypeName": "NumberPropertyIO" - }, - "balancingAct.homeScreen.view.gameScreenSmallButton.pickableProperty": { - "phetioDocumentation": "Sets whether the node will be pickable (and hence interactive), see the NodeIO documentation for more details", - "phetioDynamicElement": false, - "phetioEventType": "MODEL", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": true, - "phetioStudioControl": true, - "phetioTypeName": "PropertyIO>" - }, - "balancingAct.homeScreen.view.gameScreenSmallButton.text": { - "phetioDocumentation": "", - "phetioDynamicElement": false, - "phetioEventType": "MODEL", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": false, - "phetioStudioControl": true, - "phetioTypeName": "TextIO" - }, - "balancingAct.homeScreen.view.gameScreenSmallButton.text.opacityProperty": { - "phetioDocumentation": "Opacity of the parent NodeIO, between 0 (invisible) and 1 (fully visible)", - "phetioDynamicElement": false, - "phetioEventType": "MODEL", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": true, - "phetioStudioControl": true, - "phetioTypeName": "NumberPropertyIO" - }, - "balancingAct.homeScreen.view.gameScreenSmallButton.text.pickableProperty": { - "phetioDocumentation": "Sets whether the node will be pickable (and hence interactive), see the NodeIO documentation for more details", - "phetioDynamicElement": false, - "phetioEventType": "MODEL", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": true, - "phetioStudioControl": true, - "phetioTypeName": "PropertyIO>" - }, - "balancingAct.homeScreen.view.gameScreenSmallButton.text.textProperty": { - "phetioDocumentation": "Property for the displayed text", - "phetioDynamicElement": false, - "phetioEventType": "MODEL", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": true, - "phetioStudioControl": true, - "phetioTypeName": "PropertyIO" - }, - "balancingAct.homeScreen.view.gameScreenSmallButton.text.visibleProperty": { - "phetioDocumentation": "Controls whether the Node will be visible (and interactive), see the NodeIO documentation for more details.", - "phetioDynamicElement": false, - "phetioEventType": "MODEL", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": true, - "phetioStudioControl": true, - "phetioTypeName": "PropertyIO" - }, - "balancingAct.homeScreen.view.gameScreenSmallButton.visibleProperty": { - "phetioDocumentation": "Controls whether the Node will be visible (and interactive), see the NodeIO documentation for more details.", - "phetioDynamicElement": false, - "phetioEventType": "MODEL", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": true, - "phetioStudioControl": true, - "phetioTypeName": "PropertyIO" - }, "balancingAct.homeScreen.view.introScreenLargeButton": { "phetioDocumentation": "A pressable button in the simulation, in the home screen", "phetioDynamicElement": false, @@ -6345,8 +5253,34 @@ "phetioStudioControl": true, "phetioTypeName": "PropertyIO" }, + "balancingAct.introScreen.model.fireExtinguisher1": { + "phetioDocumentation": "", + "phetioDynamicElement": false, + "phetioEventType": "MODEL", + "phetioFeatured": false, + "phetioHighFrequency": false, + "phetioIsArchetype": false, + "phetioPlayback": false, + "phetioReadOnly": false, + "phetioState": true, + "phetioStudioControl": true, + "phetioTypeName": "ReferenceIO" + }, + "balancingAct.introScreen.model.fireExtinguisher2": { + "phetioDocumentation": "", + "phetioDynamicElement": false, + "phetioEventType": "MODEL", + "phetioFeatured": false, + "phetioHighFrequency": false, + "phetioIsArchetype": false, + "phetioPlayback": false, + "phetioReadOnly": false, + "phetioState": true, + "phetioStudioControl": true, + "phetioTypeName": "ReferenceIO" + }, "balancingAct.introScreen.model.plank.massDroppedOnPlankEmitter": { - "phetioDocumentation": "A function that executes. The arguments are:
  1. mass: NumberIO

  2. position: NumberIO

  3. fullState: ObjectIO
", + "phetioDocumentation": "A function that executes. The arguments are:
  1. phetioID: StringIO

  2. mass: NumberIO

  3. distance: NumberIO

  4. fullState: ObjectIO
", "phetioDynamicElement": false, "phetioEventType": "MODEL", "phetioFeatured": false, @@ -6356,10 +5290,10 @@ "phetioReadOnly": false, "phetioState": false, "phetioStudioControl": true, - "phetioTypeName": "EmitterIO" + "phetioTypeName": "EmitterIO" }, "balancingAct.introScreen.model.plank.massRemovedFromPlankEmitter": { - "phetioDocumentation": "A function that executes. The arguments are:
  1. mass: NumberIO

  2. position: NumberIO

  3. fullState: ObjectIO
", + "phetioDocumentation": "A function that executes. The arguments are:
  1. phetioID: StringIO

  2. mass: NumberIO

  3. distance: NumberIO

  4. fullState: ObjectIO
", "phetioDynamicElement": false, "phetioEventType": "MODEL", "phetioFeatured": false, @@ -6369,7 +5303,7 @@ "phetioReadOnly": false, "phetioState": false, "phetioStudioControl": true, - "phetioTypeName": "EmitterIO" + "phetioTypeName": "EmitterIO" }, "balancingAct.introScreen.model.plank.tiltAngleProperty": { "phetioDocumentation": "Angle of the plank with respect to the ground. A value of 0 indicates a level plank, positive is tilted left, negative to the right.", @@ -6384,7 +5318,7 @@ "phetioStudioControl": true, "phetioTypeName": "NumberPropertyIO" }, - "balancingAct.introScreen.view.columnControlPanel": { + "balancingAct.introScreen.model.smallTrashCan": { "phetioDocumentation": "", "phetioDynamicElement": false, "phetioEventType": "MODEL", @@ -6393,11 +5327,11 @@ "phetioIsArchetype": false, "phetioPlayback": false, "phetioReadOnly": false, - "phetioState": false, + "phetioState": true, "phetioStudioControl": true, - "phetioTypeName": "NodeIO" + "phetioTypeName": "ReferenceIO" }, - "balancingAct.introScreen.view.columnControlPanel.abSwitch": { + "balancingAct.introScreen.view.columnControlPanel": { "phetioDocumentation": "", "phetioDynamicElement": false, "phetioEventType": "MODEL", @@ -6410,20 +5344,7 @@ "phetioStudioControl": true, "phetioTypeName": "NodeIO" }, - "balancingAct.introScreen.view.columnControlPanel.abSwitch.aInputListener": { - "phetioDocumentation": "", - "phetioDynamicElement": false, - "phetioEventType": "MODEL", - "phetioFeatured": false, - "phetioHighFrequency": false, - "phetioIsArchetype": false, - "phetioPlayback": false, - "phetioReadOnly": false, - "phetioState": false, - "phetioStudioControl": true, - "phetioTypeName": "ButtonListenerIO" - }, - "balancingAct.introScreen.view.columnControlPanel.abSwitch.bInputListener": { + "balancingAct.introScreen.view.columnControlPanel.abSwitch": { "phetioDocumentation": "", "phetioDynamicElement": false, "phetioEventType": "MODEL", @@ -6434,7 +5355,7 @@ "phetioReadOnly": false, "phetioState": false, "phetioStudioControl": true, - "phetioTypeName": "ButtonListenerIO" + "phetioTypeName": "NodeIO" }, "balancingAct.introScreen.view.columnControlPanel.abSwitch.onOffSwitch": { "phetioDocumentation": "", Index: balancing-act/js/balancing-act-main.js IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- balancing-act/js/balancing-act-main.js (revision bdb38565d338d01cc13b664945c92a2b62d6b7cd) +++ balancing-act/js/balancing-act-main.js (date 1579558147000) @@ -8,7 +8,7 @@ // modules const BAIntroScreen = require( 'BALANCING_ACT/intro/BAIntroScreen' ); - const BalanceGameScreen = require( 'BALANCING_ACT/game/BalanceGameScreen' ); + // const BalanceGameScreen = require( 'BALANCING_ACT/game/BalanceGameScreen' ); const BalanceLabScreen = require( 'BALANCING_ACT/balancelab/BalanceLabScreen' ); const Sim = require( 'JOIST/Sim' ); const SimLauncher = require( 'JOIST/SimLauncher' ); @@ -34,8 +34,8 @@ // Create and start the sim new Sim( balancingActTitleString, [ new BAIntroScreen( tandem.createTandem( 'introScreen' ) ), - new BalanceLabScreen( tandem.createTandem( 'balanceLabScreen' ) ), - new BalanceGameScreen( tandem.createTandem( 'gameScreen' ) ) + new BalanceLabScreen( tandem.createTandem( 'balanceLabScreen' ) ) //, + // new BalanceGameScreen( tandem.createTandem( 'gameScreen' ) ) ], simOptions ).start(); } ); } ); \ No newline at end of file Index: balancing-act/js/phet-io/balancing-act-phet-io-types.js IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- balancing-act/js/phet-io/balancing-act-phet-io-types.js (revision bdb38565d338d01cc13b664945c92a2b62d6b7cd) +++ balancing-act/js/phet-io/balancing-act-phet-io-types.js (date 1579570543000) @@ -85,32 +85,6 @@ "supertype": "ObjectIO", "typeName": "ActionIO>" }, - "ActionIO": { - "documentation": "Executes when an event occurs.", - "events": [ - "emitted" - ], - "methodOrder": [], - "methods": { - "execute": { - "documentation": "Executes the function the Action is wrapping.", - "invocableForReadOnlyElements": false, - "parameterTypes": [ - "NumberIO", - "NumberIO", - "ObjectIO" - ], - "returnType": "VoidIO" - } - }, - "parameterTypes": [ - "NumberIO", - "NumberIO", - "ObjectIO" - ], - "supertype": "ObjectIO", - "typeName": "ActionIO" - }, "ActionIO": { "documentation": "Executes when an event occurs.", "events": [ @@ -205,6 +179,34 @@ "supertype": "ObjectIO", "typeName": "ActionIO" }, + "ActionIO": { + "documentation": "Executes when an event occurs.", + "events": [ + "emitted" + ], + "methodOrder": [], + "methods": { + "execute": { + "documentation": "Executes the function the Action is wrapping.", + "invocableForReadOnlyElements": false, + "parameterTypes": [ + "StringIO", + "NumberIO", + "NumberIO", + "ObjectIO" + ], + "returnType": "VoidIO" + } + }, + "parameterTypes": [ + "StringIO", + "NumberIO", + "NumberIO", + "ObjectIO" + ], + "supertype": "ObjectIO", + "typeName": "ActionIO" + }, "ActionIO": { "documentation": "Executes when an event occurs.", "events": [ @@ -267,20 +269,6 @@ "supertype": "ObjectIO", "typeName": "BooleanIO" }, - "ButtonListenerIO": { - "documentation": "Button listener", - "events": [ - "up", - "over", - "down", - "out", - "fire" - ], - "methodOrder": [], - "methods": {}, - "supertype": "ObjectIO", - "typeName": "ButtonListenerIO" - }, "DerivedPropertyIO": { "documentation": "Like PropertyIO, but not settable. Instead it is derived from other DerivedPropertyIO or PropertyIO instances", "events": [ @@ -365,7 +353,7 @@ "supertype": "ActionIO>", "typeName": "EmitterIO>" }, - "EmitterIO": { + "EmitterIO": { "documentation": "Emits when an event occurs and calls added listeners.", "events": [ "emitted" @@ -375,7 +363,7 @@ "addListener": { "documentation": "Adds a listener which will be called when the emitter emits.", "parameterTypes": [ - "FunctionIO(NumberIO,NumberIO,ObjectIO)=>VoidIO" + "FunctionIO(StringIO,NumberIO,NumberIO,ObjectIO)=>VoidIO" ], "returnType": "VoidIO" }, @@ -383,6 +371,7 @@ "documentation": "Emits a single event to all listeners.", "invocableForReadOnlyElements": false, "parameterTypes": [ + "StringIO", "NumberIO", "NumberIO", "ObjectIO" @@ -391,12 +380,13 @@ } }, "parameterTypes": [ + "StringIO", "NumberIO", "NumberIO", "ObjectIO" ], - "supertype": "ActionIO", - "typeName": "EmitterIO" + "supertype": "ActionIO", + "typeName": "EmitterIO" }, "EnumerationIO(DOUBLE_COLUMNS|SINGLE_COLUMN|NO_COLUMNS)": { "documentation": "Possible values: DOUBLE_COLUMNS,SINGLE_COLUMN,NO_COLUMNS.", @@ -539,20 +529,6 @@ "supertype": "ObjectIO", "typeName": "FunctionIO(NumberIO,NullableIO)=>VoidIO" }, - "FunctionIO(NumberIO,NumberIO,ObjectIO)=>VoidIO": { - "documentation": "Wrapper for the built-in JS function type.
Arguments: NumberIO, NumberIO, ObjectIO
Return Type: VoidIO", - "events": [], - "methodOrder": [], - "methods": {}, - "parameterTypes": [ - "NumberIO", - "NumberIO", - "ObjectIO", - "VoidIO" - ], - "supertype": "ObjectIO", - "typeName": "FunctionIO(NumberIO,NumberIO,ObjectIO)=>VoidIO" - }, "FunctionIO(ObjectIO)=>VoidIO": { "documentation": "Wrapper for the built-in JS function type.
Arguments: ObjectIO
Return Type: VoidIO", "events": [], @@ -578,6 +554,21 @@ "supertype": "ObjectIO", "typeName": "FunctionIO(StringIO,NullableIO)=>VoidIO" }, + "FunctionIO(StringIO,NumberIO,NumberIO,ObjectIO)=>VoidIO": { + "documentation": "Wrapper for the built-in JS function type.
Arguments: StringIO, NumberIO, NumberIO, ObjectIO
Return Type: VoidIO", + "events": [], + "methodOrder": [], + "methods": {}, + "parameterTypes": [ + "StringIO", + "NumberIO", + "NumberIO", + "ObjectIO", + "VoidIO" + ], + "supertype": "ObjectIO", + "typeName": "FunctionIO(StringIO,NumberIO,NumberIO,ObjectIO)=>VoidIO" + }, "FunctionIO(StringIO,ObjectIO,ObjectIO)=>VoidIO": { "documentation": "Wrapper for the built-in JS function type.
Arguments: StringIO, ObjectIO, ObjectIO
Return Type: VoidIO", "events": [], @@ -1037,6 +1028,17 @@ "supertype": "ObjectIO", "typeName": "PhetioEngineIO" }, + "PhetioGroupIO": { + "documentation": "An array that sends notifications when its values have changed.", + "events": [], + "methodOrder": [], + "methods": {}, + "parameterTypes": [ + "ReferenceIO" + ], + "supertype": "ObjectIO", + "typeName": "PhetioGroupIO" + }, "PropertyIO": { "documentation": "Observable values that send out notifications when the value changes. This differs from the traditional listener pattern in that added listeners also receive a callback with the current value when the listeners are registered. This is a widely-used pattern in PhET-iO simulations.", "events": [ @@ -1345,6 +1347,14 @@ "supertype": "ObjectIO", "typeName": "PropertyIO" }, + "ReferenceIO": { + "documentation": "Uses reference identity for toStateObject/fromStateObject", + "events": [], + "methodOrder": [], + "methods": {}, + "supertype": "ObjectIO", + "typeName": "ReferenceIO" + }, "ResetAllButtonIO": { "documentation": "Button that performs an action while it is being pressed, and stops the action when released", "events": [ Index: balancing-act/js/balancelab/model/BalanceLabModel.js IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- balancing-act/js/balancelab/model/BalanceLabModel.js (revision bdb38565d338d01cc13b664945c92a2b62d6b7cd) +++ balancing-act/js/balancelab/model/BalanceLabModel.js (date 1579570607000) @@ -13,7 +13,13 @@ // modules const BalanceModel = require( 'BALANCING_ACT/common/model/BalanceModel' ); const balancingAct = require( 'BALANCING_ACT/balancingAct' ); + const BrickStack = require( 'BALANCING_ACT/common/model/masses/BrickStack' ); const inherit = require( 'PHET_CORE/inherit' ); + const MysteryMass = require( 'BALANCING_ACT/common/model/masses/MysteryMass' ); + const PhetioGroup = require( 'TANDEM/PhetioGroup' ); + const PhetioGroupIO = require( 'TANDEM/PhetioGroupIO' ); + const ReferenceIO = require( 'TANDEM/types/ReferenceIO' ); + const Vector2 = require( 'DOT/Vector2' ); /** * @param {Tandem} tandem @@ -21,6 +27,36 @@ */ function BalanceLabModel( tandem ) { BalanceModel.call( this, tandem ); + + this.brickStackGroup = new PhetioGroup( ( tandem, numberOfBricks, position ) => { + const brickStack = new BrickStack( numberOfBricks, position, { + tandem: tandem, + phetioDynamicElement: true + } ); + brickStack.userControlledProperty.set( true ); + brickStack.animationDestination = position; + this.addMass( brickStack ); + return brickStack; + }, + [ 1, Vector2.ZERO ], { + tandem: tandem.createTandem( 'brickStackGroup' ), + phetioType: PhetioGroupIO( ReferenceIO ) + } ); + + this.mysteryMassGroup = new PhetioGroup( ( tandem, position, mysteryMassId ) => { + const mysteryMassModelElement = new MysteryMass( position, mysteryMassId, { + tandem: tandem, + phetioDynamicElement: true + } ); + mysteryMassModelElement.animationDestination = mysteryMassModelElement.positionProperty.get(); + mysteryMassModelElement.userControlledProperty.set( true ); + this.addMass( mysteryMassModelElement ); + return mysteryMassModelElement; + }, + [ Vector2.ZERO, 0 ], { + tandem: tandem.createTandem( 'mysteryMassGroup' ), + phetioType: PhetioGroupIO( ReferenceIO ) + } ); } balancingAct.register( 'BalanceLabModel', BalanceLabModel ); Index: balancing-act/js/common/model/masses/FireExtinguisher.js IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- balancing-act/js/common/model/masses/FireExtinguisher.js (revision bdb38565d338d01cc13b664945c92a2b62d6b7cd) +++ balancing-act/js/common/model/masses/FireExtinguisher.js (date 1579570803000) @@ -18,10 +18,11 @@ /** * @param initialPosition * @param isMystery + * @param {Object} options * @constructor */ - function FireExtinguisher( initialPosition, isMystery ) { - ImageMass.call( this, MASS, fireExtinguisherImage, HEIGHT, initialPosition, isMystery ); + function FireExtinguisher( initialPosition, isMystery, options ) { + ImageMass.call( this, MASS, fireExtinguisherImage, HEIGHT, initialPosition, isMystery, options ); this.centerOfMassXOffset = 0.03; // Empirically determined. } Index: balancing-act/js/common/model/masses/MysteryMass.js IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- balancing-act/js/common/model/masses/MysteryMass.js (revision bdb38565d338d01cc13b664945c92a2b62d6b7cd) +++ balancing-act/js/common/model/masses/MysteryMass.js (date 1579570079000) @@ -13,6 +13,7 @@ const BAQueryParameters = require( 'BALANCING_ACT/common/BAQueryParameters' ); const inherit = require( 'PHET_CORE/inherit' ); const LabeledImageMass = require( 'BALANCING_ACT/common/model/masses/LabeledImageMass' ); + const merge = require( 'PHET_CORE/merge' ); // images const mysteryObject1Image = require( 'image!BALANCING_ACT/mystery-object-01.png' ); @@ -99,8 +100,10 @@ } ]; - function MysteryMass( initialPosition, mysteryMassId ) { - LabeledImageMass.call( this, initialPosition, MYSTERY_MASS_CONFIGURATIONS[ mysteryMassId ] ); + function MysteryMass( initialPosition, mysteryMassId, options ) { + const config = merge( options, MYSTERY_MASS_CONFIGURATIONS[ mysteryMassId ] ); + + LabeledImageMass.call( this, initialPosition, config ); this.mysteryMassId = mysteryMassId; } Index: balancing-act/js/common/view/MassCarousel.js IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- balancing-act/js/common/view/MassCarousel.js (revision bdb38565d338d01cc13b664945c92a2b62d6b7cd) +++ balancing-act/js/common/view/MassCarousel.js (date 1579564833000) @@ -78,7 +78,7 @@ ); // Create the 1st kit node for creating people. - const peopleKit1 = new Node( + const peopleKit1 = BAQueryParameters.stanford ? new Node() : new Node( { children: [ new HBox( @@ -93,7 +93,7 @@ } ); // Create the 2nd kit node for creating people. - const peopleKit2 = new Node( + const peopleKit2 = BAQueryParameters.stanford ? new Node() : new Node( { children: [ new HBox( Index: balancing-act/js/common/model/masses/SmallTrashCan.js IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- balancing-act/js/common/model/masses/SmallTrashCan.js (revision bdb38565d338d01cc13b664945c92a2b62d6b7cd) +++ balancing-act/js/common/model/masses/SmallTrashCan.js (date 1579570803000) @@ -18,10 +18,11 @@ /** * @param initialPosition * @param isMystery + * @param {Object} options * @constructor */ - function SmallTrashCan( initialPosition, isMystery ) { - ImageMass.call( this, MASS, trashCanImage, HEIGHT, initialPosition, isMystery ); + function SmallTrashCan( initialPosition, isMystery, options ) { + ImageMass.call( this, MASS, trashCanImage, HEIGHT, initialPosition, isMystery, options ); } balancingAct.register( 'SmallTrashCan', SmallTrashCan ); Index: balancing-act/js/common/model/Plank.js IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- balancing-act/js/common/model/Plank.js (revision bdb38565d338d01cc13b664945c92a2b62d6b7cd) +++ balancing-act/js/common/model/Plank.js (date 1579570855000) @@ -22,6 +22,7 @@ const ObservableArray = require( 'AXON/ObservableArray' ); const Property = require( 'AXON/Property' ); const Shape = require( 'KITE/Shape' ); + const StringIO = require( 'TANDEM/types/StringIO' ); const Vector2 = require( 'DOT/Vector2' ); // constants @@ -73,8 +74,9 @@ this.massDroppedOnPlankEmitter = new Emitter( { tandem: tandem.createTandem( 'massDroppedOnPlankEmitter' ), parameters: [ + { name: 'phetioID', phetioType: StringIO }, { name: 'mass', phetioType: NumberIO }, - { name: 'position', phetioType: NumberIO }, + { name: 'distance', phetioType: NumberIO }, { name: 'fullState', phetioType: ObjectIO } ] } ); @@ -82,8 +84,9 @@ this.massRemovedFromPlankEmitter = new Emitter( { tandem: tandem.createTandem( 'massRemovedFromPlankEmitter' ), parameters: [ + { name: 'phetioID', phetioType: StringIO }, { name: 'mass', phetioType: NumberIO }, - { name: 'position', phetioType: NumberIO }, + { name: 'distance', phetioType: NumberIO }, { name: 'fullState', phetioType: ObjectIO } ] } ); @@ -202,20 +205,14 @@ }; this.massDistancePairs.push( result ); - const fullState = this.massDistancePairs.map( massDistancePair => { - return { - mass: massDistancePair.mass.massValue, - distance: massDistancePair.distance - }; - } ); - this.massDroppedOnPlankEmitter.emit( mass.massValue, result.distance, fullState ); + this.massDroppedOnPlankEmitter.emit( mass.tandem.phetioID, mass.massValue, result.distance, this.getPhetioState() ); // Add the force vector for this mass. this.forceVectors.push( new MassForceVector( mass ) ); // Add an observer that will remove this mass when the user picks it up. const self = this; - var userControlledObserver = function( userControlled ) { + const userControlledObserver = function( userControlled ) { if ( userControlled ) { // The user has picked up this mass, so it is no longer // on the surface. @@ -234,6 +231,20 @@ return massAdded; }, + /** + * @returns {Object} + * @private + */ + getPhetioState() { + return this.massDistancePairs.map( massDistancePair => { + return { + name: massDistancePair.mass.tandem.phetioID, + mass: massDistancePair.mass.massValue, + distance: massDistancePair.distance + }; + } ); + }, + // Add a mass to the specified location on the plank. addMassToSurfaceAt: function( mass, distanceFromCenter ) { if ( Math.abs( distanceFromCenter ) > PLANK_LENGTH / 2 ) { @@ -283,14 +294,7 @@ const distance = this.massDistancePairs[ i ].distance; this.massDistancePairs.splice( i, 1 ); - - const fullState = this.massDistancePairs.map( massDistancePair => { - return { - mass: massDistancePair.mass.massValue, - distance: massDistancePair.distance - }; - } ); - this.massRemovedFromPlankEmitter.emit( mass.massValue, distance, fullState ); + this.massRemovedFromPlankEmitter.emit( mass.tandem.phetioID, mass.massValue, distance, this.getPhetioState() ); break; } Index: balancing-act/js/common/model/ImageMass.js IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- balancing-act/js/common/model/ImageMass.js (revision bdb38565d338d01cc13b664945c92a2b62d6b7cd) +++ balancing-act/js/common/model/ImageMass.js (date 1579570803000) @@ -26,10 +26,11 @@ * @param height * @param initialPosition * @param isMystery + * @param {Object} options * @constructor */ - function ImageMass( mass, image, height, initialPosition, isMystery ) { - Mass.call( this, mass, initialPosition, isMystery ); + function ImageMass( mass, image, height, initialPosition, isMystery, options ) { + Mass.call( this, mass, initialPosition, isMystery, options ); // Property that contains the current image. this.imageProperty = new Property( image ); Index: balancing-act/js/common/model/Mass.js IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- balancing-act/js/common/model/Mass.js (revision bdb38565d338d01cc13b664945c92a2b62d6b7cd) +++ balancing-act/js/common/model/Mass.js (date 1579570211000) @@ -11,7 +11,11 @@ // modules const balancingAct = require( 'BALANCING_ACT/balancingAct' ); const inherit = require( 'PHET_CORE/inherit' ); + const merge = require( 'PHET_CORE/merge' ); + const ReferenceIO = require( 'TANDEM/types/ReferenceIO' ); + const PhetioObject = require( 'TANDEM/PhetioObject' ); const Property = require( 'AXON/Property' ); + const Tandem = require( 'TANDEM/Tandem' ); const Vector2 = require( 'DOT/Vector2' ); // constants @@ -20,9 +24,14 @@ // TODO: JSDoc is missing in many places, see https://github.com/phetsims/balancing-act/issues/96 // TODO: Convert to ES6, see https://github.com/phetsims/balancing-act/issues/96 - function Mass( massValue, initialPosition, isMystery ) { + function Mass( massValue, initialPosition, isMystery, options ) { const self = this; + options = merge( { + tandem: Tandem.REQUIRED, + phetioType: ReferenceIO + }, options ); + // Property that indicates whether this mass is currently user controlled, i.e. being moved around by the user. this.userControlledProperty = new Property( false ); @@ -60,11 +69,16 @@ // that indicates where their center of mass is when placed on a balance. // This is the horizontal offset from the center of the shape or image. self.centerOfMassXOffset = 0; + + // TODO: Should this be an instrumented PhetioObject, or an empty intermediate node? See https://github.com/phetsims/balancing-act/issues/99 + // @public (read-only) {Tandem} + // this.tandem = tandem; + PhetioObject.call( this, options ); } balancingAct.register( 'Mass', Mass ); - return inherit( Object, Mass, { + return inherit( PhetioObject, Mass, { reset: function() { this.userControlledProperty.reset(); Index: chipper/js/grunt/phet-io/generatePhetioAPIFiles.js IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- chipper/js/grunt/phet-io/generatePhetioAPIFiles.js (revision 1996fd10e24f58498b7e66983d2403adfd34a245) +++ chipper/js/grunt/phet-io/generatePhetioAPIFiles.js (date 1579568098000) @@ -72,7 +72,7 @@ page.on( 'pageerror', msg => reject( msg ) ); try { - await page.goto( `${localTestingURL}${repo}/${repo}_en.html?brand=phet-io&phetioStandalone&phetioPrintPhetioFiles` ); + await page.goto( `${localTestingURL}${repo}/${repo}_en.html?brand=phet-io&phetioStandalone&phetioPrintPhetioFiles&stanford` ); } catch( e ) { reject( e ); ```
samreid commented 4 years ago

@chrisklus your changes look great. I made a few improvements in this patch.

```diff Index: js/common/model/masses/BrickStack.js IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- js/common/model/masses/BrickStack.js (revision 527096485d7212335d1b1a58d0163514150ffe97) +++ js/common/model/masses/BrickStack.js (date 1580181676286) @@ -25,9 +25,10 @@ /** * @param {number} numBricks * @param {Vector2} initialPosition + * @param {Object} options * @constructor */ - function BrickStack( numBricks, initialPosition ) { + function BrickStack( numBricks, initialPosition, options ) { if ( numBricks <= 0 ) { throw new Error( 'Must have at least one brick in stack' ); } @@ -44,7 +45,7 @@ this.shape = brickStackShape; - Mass.call( this, numBricks * BRICK_MASS, initialPosition ); + Mass.call( this, numBricks * BRICK_MASS, initialPosition, false, options ); } balancingAct.register( 'BrickStack', BrickStack ); Index: js/common/model/masses/SmallTrashCan.js IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- js/common/model/masses/SmallTrashCan.js (revision 527096485d7212335d1b1a58d0163514150ffe97) +++ js/common/model/masses/SmallTrashCan.js (date 1580181676299) @@ -18,10 +18,11 @@ /** * @param initialPosition * @param isMystery + * @param {Object} options * @constructor */ - function SmallTrashCan( initialPosition, isMystery ) { - ImageMass.call( this, MASS, trashCanImage, HEIGHT, initialPosition, isMystery ); + function SmallTrashCan( initialPosition, isMystery, options ) { + ImageMass.call( this, MASS, trashCanImage, HEIGHT, initialPosition, isMystery, options ); } balancingAct.register( 'SmallTrashCan', SmallTrashCan ); Index: js/common/model/masses/LabeledImageMass.js IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- js/common/model/masses/LabeledImageMass.js (revision 527096485d7212335d1b1a58d0163514150ffe97) +++ js/common/model/masses/LabeledImageMass.js (date 1580181676291) @@ -21,7 +21,7 @@ * @constructor */ function LabeledImageMass( initialPosition, config ) { - ImageMass.call( this, config.massValue, config.image, config.height, initialPosition, config.isMystery ); + ImageMass.call( this, config.massValue, config.image, config.height, initialPosition, config.isMystery, config ); this.labelText = config.labelText; } Index: js/common/model/ImageMass.js IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- js/common/model/ImageMass.js (revision 527096485d7212335d1b1a58d0163514150ffe97) +++ js/common/model/ImageMass.js (date 1580181676303) @@ -26,10 +26,11 @@ * @param height * @param initialPosition * @param isMystery + * @param {Object} options * @constructor */ - function ImageMass( mass, image, height, initialPosition, isMystery ) { - Mass.call( this, mass, initialPosition, isMystery ); + function ImageMass( mass, image, height, initialPosition, isMystery, options ) { + Mass.call( this, mass, initialPosition, isMystery, options ); // Property that contains the current image. this.imageProperty = new Property( image ); Index: js/common/model/Plank.js IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- js/common/model/Plank.js (revision 527096485d7212335d1b1a58d0163514150ffe97) +++ js/common/model/Plank.js (date 1580181676313) @@ -22,6 +22,7 @@ const ObservableArray = require( 'AXON/ObservableArray' ); const Property = require( 'AXON/Property' ); const Shape = require( 'KITE/Shape' ); + const StringIO = require( 'TANDEM/types/StringIO' ); const Vector2 = require( 'DOT/Vector2' ); // constants @@ -73,8 +74,9 @@ this.massDroppedOnPlankEmitter = new Emitter( { tandem: tandem.createTandem( 'massDroppedOnPlankEmitter' ), parameters: [ + { name: 'phetioID', phetioType: StringIO }, { name: 'mass', phetioType: NumberIO }, - { name: 'position', phetioType: NumberIO }, + { name: 'distance', phetioType: NumberIO }, { name: 'fullState', phetioType: ObjectIO } ] } ); @@ -82,8 +84,9 @@ this.massRemovedFromPlankEmitter = new Emitter( { tandem: tandem.createTandem( 'massRemovedFromPlankEmitter' ), parameters: [ + { name: 'phetioID', phetioType: StringIO }, { name: 'mass', phetioType: NumberIO }, - { name: 'position', phetioType: NumberIO }, + { name: 'distance', phetioType: NumberIO }, { name: 'fullState', phetioType: ObjectIO } ] } ); @@ -202,20 +205,14 @@ }; this.massDistancePairs.push( result ); - const fullState = this.massDistancePairs.map( massDistancePair => { - return { - mass: massDistancePair.mass.massValue, - distance: massDistancePair.distance - }; - } ); - this.massDroppedOnPlankEmitter.emit( mass.massValue, result.distance, fullState ); + this.massDroppedOnPlankEmitter.emit( mass.tandem.phetioID, mass.massValue, result.distance, this.getPhetioState() ); // Add the force vector for this mass. this.forceVectors.push( new MassForceVector( mass ) ); // Add an observer that will remove this mass when the user picks it up. const self = this; - var userControlledObserver = function( userControlled ) { + const userControlledObserver = function( userControlled ) { if ( userControlled ) { // The user has picked up this mass, so it is no longer // on the surface. @@ -234,6 +231,20 @@ return massAdded; }, + /** + * @returns {Object} + * @private + */ + getPhetioState() { + return this.massDistancePairs.map( massDistancePair => { + return { + name: massDistancePair.mass.tandem.phetioID, + mass: massDistancePair.mass.massValue, + distance: massDistancePair.distance + }; + } ); + }, + // Add a mass to the specified location on the plank. addMassToSurfaceAt: function( mass, distanceFromCenter ) { if ( Math.abs( distanceFromCenter ) > PLANK_LENGTH / 2 ) { @@ -283,14 +294,7 @@ const distance = this.massDistancePairs[ i ].distance; this.massDistancePairs.splice( i, 1 ); - - const fullState = this.massDistancePairs.map( massDistancePair => { - return { - mass: massDistancePair.mass.massValue, - distance: massDistancePair.distance - }; - } ); - this.massRemovedFromPlankEmitter.emit( mass.massValue, distance, fullState ); + this.massRemovedFromPlankEmitter.emit( mass.tandem.phetioID, mass.massValue, distance, this.getPhetioState() ); break; } Index: js/common/model/masses/MysteryMass.js IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- js/common/model/masses/MysteryMass.js (revision 527096485d7212335d1b1a58d0163514150ffe97) +++ js/common/model/masses/MysteryMass.js (date 1580181676294) @@ -13,6 +13,7 @@ const BAQueryParameters = require( 'BALANCING_ACT/common/BAQueryParameters' ); const inherit = require( 'PHET_CORE/inherit' ); const LabeledImageMass = require( 'BALANCING_ACT/common/model/masses/LabeledImageMass' ); + const merge = require( 'PHET_CORE/merge' ); // images const mysteryObject1Image = require( 'image!BALANCING_ACT/mystery-object-01.png' ); @@ -99,8 +100,10 @@ } ]; - function MysteryMass( initialPosition, mysteryMassId ) { - LabeledImageMass.call( this, initialPosition, MYSTERY_MASS_CONFIGURATIONS[ mysteryMassId ] ); + function MysteryMass( initialPosition, mysteryMassId, options ) { + const config = merge( options, MYSTERY_MASS_CONFIGURATIONS[ mysteryMassId ] ); + + LabeledImageMass.call( this, initialPosition, config ); this.mysteryMassId = mysteryMassId; } Index: js/common/model/Mass.js IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- js/common/model/Mass.js (revision 527096485d7212335d1b1a58d0163514150ffe97) +++ js/common/model/Mass.js (date 1580181676307) @@ -11,7 +11,11 @@ // modules const balancingAct = require( 'BALANCING_ACT/balancingAct' ); const inherit = require( 'PHET_CORE/inherit' ); + const merge = require( 'PHET_CORE/merge' ); + const ReferenceIO = require( 'TANDEM/types/ReferenceIO' ); + const PhetioObject = require( 'TANDEM/PhetioObject' ); const Property = require( 'AXON/Property' ); + const Tandem = require( 'TANDEM/Tandem' ); const Vector2 = require( 'DOT/Vector2' ); // constants @@ -20,9 +24,14 @@ // TODO: JSDoc is missing in many places, see https://github.com/phetsims/balancing-act/issues/96 // TODO: Convert to ES6, see https://github.com/phetsims/balancing-act/issues/96 - function Mass( massValue, initialPosition, isMystery ) { + function Mass( massValue, initialPosition, isMystery, options ) { const self = this; + options = merge( { + tandem: Tandem.REQUIRED, + phetioType: ReferenceIO + }, options ); + // Property that indicates whether this mass is currently user controlled, i.e. being moved around by the user. this.userControlledProperty = new Property( false ); @@ -60,11 +69,16 @@ // that indicates where their center of mass is when placed on a balance. // This is the horizontal offset from the center of the shape or image. self.centerOfMassXOffset = 0; + + // TODO: Should this be an instrumented PhetioObject, or an empty intermediate node? See https://github.com/phetsims/balancing-act/issues/99 + // @public (read-only) {Tandem} + // this.tandem = tandem; + PhetioObject.call( this, options ); } balancingAct.register( 'Mass', Mass ); - return inherit( Object, Mass, { + return inherit( PhetioObject, Mass, { reset: function() { this.userControlledProperty.reset(); Index: js/intro/model/BAIntroModel.js IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- js/intro/model/BAIntroModel.js (revision 527096485d7212335d1b1a58d0163514150ffe97) +++ js/intro/model/BAIntroModel.js (date 1580181676330) @@ -26,9 +26,9 @@ BalanceModel.call( this, tandem ); // Add the initial masses and save their initial positions. - this.addMass( new FireExtinguisher( new Vector2( 2.7, 0 ), false ) ); - this.addMass( new FireExtinguisher( new Vector2( 3.2, 0 ), false ) ); - this.addMass( new SmallTrashCan( new Vector2( 3.7, 0 ), false ) ); + this.addMass( new FireExtinguisher( new Vector2( 2.7, 0 ), false, { tandem: tandem.createTandem( 'fireExtinguisher1' ) } ) ); + this.addMass( new FireExtinguisher( new Vector2( 3.2, 0 ), false, { tandem: tandem.createTandem( 'fireExtinguisher2' ) } ) ); + this.addMass( new SmallTrashCan( new Vector2( 3.7, 0 ), false, { tandem: tandem.createTandem( 'smallTrashCan' ) } ) ); } balancingAct.register( 'BAIntroModel', BAIntroModel ); Index: js/balancelab/view/ImageMassCreatorNode.js IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- js/balancelab/view/ImageMassCreatorNode.js (revision 527096485d7212335d1b1a58d0163514150ffe97) +++ js/balancelab/view/ImageMassCreatorNode.js (date 1580184102878) @@ -39,6 +39,10 @@ return inherit( MassCreatorNode, ImageMassCreatorNode, { + /** + * @param position + * @returns {*} + */ addElementToModel: function( position ) { const imageMassModelElement = this.createImageMassInstance(); imageMassModelElement.positionProperty.set( position.copy() ); Index: js/balancelab/view/MysteryMassCreatorNode.js IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- js/balancelab/view/MysteryMassCreatorNode.js (revision 527096485d7212335d1b1a58d0163514150ffe97) +++ js/balancelab/view/MysteryMassCreatorNode.js (date 1580184102881) @@ -19,6 +19,7 @@ const MysteryMassNode = require( 'BALANCING_ACT/common/view/MysteryMassNode' ); const Property = require( 'AXON/Property' ); const Vector2 = require( 'DOT/Vector2' ); + const Tandem = require( 'TANDEM/Tandem' ); // Model-view transform for scaling the node used in the toolbox. This // may scale the node differently than what is used in the model so that @@ -26,12 +27,25 @@ const SCALING_MVT = ModelViewTransform2.createOffsetScaleMapping( Vector2.ZERO, 150 ); function MysteryMassCreatorNode( mysteryMassID, model, modelViewTransform, options ) { - ImageMassCreatorNode.call( this, model, modelViewTransform, new MysteryMass( Vector2.ZERO, mysteryMassID ), false, options ); + ImageMassCreatorNode.call( this, model, modelViewTransform, new MysteryMass( Vector2.ZERO, mysteryMassID, { tandem: Tandem.OPT_OUT } ), false, options ); + this.mysteryMassId = mysteryMassID; this.setSelectionNode( new MysteryMassNode( this.prototypeImageMass, SCALING_MVT, false, new Property( false ), false, model.columnStateProperty ) ); this.positioningOffset = new Vector2( 0, -modelViewTransform.modelToViewDeltaY( this.prototypeImageMass.heightProperty.get() / 2 ) ); } balancingAct.register( 'MysteryMassCreatorNode', MysteryMassCreatorNode ); - return inherit( ImageMassCreatorNode, MysteryMassCreatorNode ); + return inherit( ImageMassCreatorNode, MysteryMassCreatorNode, { + + /** + * @param position + * @returns {PhetioObject} + * @override + */ + addElementToModel: function( position ) { + const mass = this.model.mysteryMassGroup.createNextMember( position, this.mysteryMassId ); + this.model.addMass( mass ); + return mass; + } + } ); } ); \ No newline at end of file Index: js/balancelab/view/BrickStackCreatorNode.js IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- js/balancelab/view/BrickStackCreatorNode.js (revision 527096485d7212335d1b1a58d0163514150ffe97) +++ js/balancelab/view/BrickStackCreatorNode.js (date 1580184102884) @@ -21,6 +21,7 @@ const ModelViewTransform2 = require( 'PHETCOMMON/view/ModelViewTransform2' ); const Property = require( 'AXON/Property' ); const Shape = require( 'KITE/Shape' ); + const Tandem = require( 'TANDEM/Tandem' ); const Vector2 = require( 'DOT/Vector2' ); // Model-view transform for scaling the node used in the toolbox. This @@ -47,7 +48,7 @@ } ); const selectionNode = new BrickStackNode( - new BrickStack( numBricks, Vector2.ZERO, false ), + new BrickStack( numBricks, Vector2.ZERO, { tandem: Tandem.OPT_OUT } ), SCALING_MVT, false, new Property( false ), @@ -70,11 +71,9 @@ return inherit( MassCreatorNode, BrickStackCreatorNode, { addElementToModel: function( position ) { - const brickStack = new BrickStack( this.numBricks, position ); - brickStack.userControlledProperty.set( true ); - brickStack.animationDestination = position; - this.model.addMass( brickStack ); - return brickStack; + const mass = this.model.brickStackGroup.createNextMember( this.numBricks, position ); + this.model.addMass( mass ); + return mass; } } ); } ); \ No newline at end of file Index: js/common/model/masses/FireExtinguisher.js IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- js/common/model/masses/FireExtinguisher.js (revision 527096485d7212335d1b1a58d0163514150ffe97) +++ js/common/model/masses/FireExtinguisher.js (date 1580181676288) @@ -18,10 +18,11 @@ /** * @param initialPosition * @param isMystery + * @param {Object} options * @constructor */ - function FireExtinguisher( initialPosition, isMystery ) { - ImageMass.call( this, MASS, fireExtinguisherImage, HEIGHT, initialPosition, isMystery ); + function FireExtinguisher( initialPosition, isMystery, options ) { + ImageMass.call( this, MASS, fireExtinguisherImage, HEIGHT, initialPosition, isMystery, options ); this.centerOfMassXOffset = 0.03; // Empirically determined. } Index: js/balancelab/model/BalanceLabModel.js IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- js/balancelab/model/BalanceLabModel.js (revision 527096485d7212335d1b1a58d0163514150ffe97) +++ js/balancelab/model/BalanceLabModel.js (date 1580184017604) @@ -13,7 +13,13 @@ // modules const BalanceModel = require( 'BALANCING_ACT/common/model/BalanceModel' ); const balancingAct = require( 'BALANCING_ACT/balancingAct' ); + const BrickStack = require( 'BALANCING_ACT/common/model/masses/BrickStack' ); const inherit = require( 'PHET_CORE/inherit' ); + const MysteryMass = require( 'BALANCING_ACT/common/model/masses/MysteryMass' ); + const PhetioGroup = require( 'TANDEM/PhetioGroup' ); + const PhetioGroupIO = require( 'TANDEM/PhetioGroupIO' ); + const ReferenceIO = require( 'TANDEM/types/ReferenceIO' ); + const Vector2 = require( 'DOT/Vector2' ); /** * @param {Tandem} tandem @@ -21,6 +27,36 @@ */ function BalanceLabModel( tandem ) { BalanceModel.call( this, tandem ); + + this.brickStackGroup = new PhetioGroup( ( tandem, numberOfBricks, position ) => { + const brickStack = new BrickStack( numberOfBricks, position, { + tandem: tandem, + phetioDynamicElement: true + } ); + brickStack.userControlledProperty.set( true ); + brickStack.animationDestination = position; + // this.addMass( brickStack ); + return brickStack; + }, + [ 1, Vector2.ZERO ], { + tandem: tandem.createTandem( 'brickStackGroup' ), + phetioType: PhetioGroupIO( ReferenceIO ) + } ); + + this.mysteryMassGroup = new PhetioGroup( ( tandem, position, mysteryMassId ) => { + const mysteryMassModelElement = new MysteryMass( position, mysteryMassId, { + tandem: tandem, + phetioDynamicElement: true + } ); + mysteryMassModelElement.animationDestination = mysteryMassModelElement.positionProperty.get(); + mysteryMassModelElement.userControlledProperty.set( true ); + // this.addMass( mysteryMassModelElement ); + return mysteryMassModelElement; + }, + [ Vector2.ZERO, 0 ], { + tandem: tandem.createTandem( 'mysteryMassGroup' ), + phetioType: PhetioGroupIO( ReferenceIO ) + } ); } balancingAct.register( 'BalanceLabModel', BalanceLabModel ); ```

I think this is the right direction to move in, and I'm ready to commit, but I wanted to hear from @kathy-phet whether this initial version should have object IDs.

samreid commented 4 years ago

We reviewed the current status with @kathy-phet, and we discussed the following 3 options:

We decided to go with the (b) because it helps disambiguate which mass the user is using. In the future we will probably pursue (c) but we will need to take time to make sure it's well designed.

chrisklus commented 4 years ago

When this sim gets fully instrumented we'll proceed with (c) from https://github.com/phetsims/balancing-act/issues/99#issuecomment-579870712, but are going to close for now since this is a limited instrumentation.

samreid commented 4 years ago

There are still TODOs marked for this issue, discovered during https://github.com/phetsims/chipper/issues/946

samreid commented 4 years ago

Unassigning until we return focus to this sim.

marlitas commented 11 months ago

Im marking this as deferred since phet-io brand will not be part of the upcoming publication.