PhET-iO Wrappers for friction 1.5.0-dev.12
A PhET-iO wrapper embeds a PhET-iO simulation and leverages the PhET-iO API and feature set. The following wrappers demonstrate the PhET-iO API and features for this simulation, and can be used as examples to begin new wrapper development.
Wrapper | Description |
---|---|
Simulation | Shows the simulation without any data streams or iframes. |
Studio | Shows all of the instrumented instances in a simulation, with their corresponding IDs, types and a basic functionality for testing interacting with them. This also provides a "Generate HTML" feature which can be used to create a customized simulation or to generate a template/starting point for developing new wrappers. |
Events: colorized | Shows the PhET-iO Event Stream in the console, colorized and optimized for human readability. The console must be open to see this data. Chrome/Firefox/Safari only. |
Events: JSON | Shows the PhET-iO Event Stream in the console, formatted in JSON, suitable for machine parsing and analysis. The console must be open to see this data. |
Events: textarea | Shows the PhET-iO Event Stream in the wrapper frame instead of the console. |
Events: recording | The simulation is embedded in a full-size iframe and emits events to the console. Query parameters can be added to redirect the data stream to another location. |
Events: playback | Plays back a previously recorded session (make sure to use the same browser as was used for recording to rule out platform-specific issues). |
State | Shows a JSON object representing the simulation's state, and immediately sets the state to a copy of the simulation for testing the ability to set state to a simulation. Provides a "Launch" button to launch another copy of the simulation with the given state using Query Parameters. |
Mirror Inputs | Shows the Scenery input event stream in the console and mirrors the events to a copy of the simulation, to test for visual playback (like a recorded screen capture). |
Screenshot | Shows a "Screenshot" button that can be used to capture and display screenshots from a live simulation. |
Active | Shows a button that enables the user to toggle whether a simulation is active (running and taking user input) or inactive (paused and not accepting user input). |
API
Here is a basic example of a functional wrapper, demonstrating some PhET-iO features.
<!DOCTYPE HTML>
<!--
Copyright 2016-2018, University of Colorado Boulder
This PhET-iO file requires a license
USE WITHOUT A LICENSE AGREEMENT IS STRICTLY PROHIBITED.
For licensing, please contact phethelp@colorado.edu
Minimal template for developing a wrapper. Used as a template for devguide.
@author Sam Reid (PhET Interactive Simulations)
@author Michael Kauzmann (PhET Interactive Simulations)
-->
<html>
<head>
<title>PhET-iO Wrapper Harness</title>
</head>
<body>
<!-- Specify the simulation to run in the iframe. -->
<iframe id="sim" width="768" height="464"></iframe>
<!--Load PhET-iO scripts.-->
<script src="{{PHET_IO_LIB_ABSOLUTE_PATH}}"></script>
<script>
// Construct the sim iframe client that can be used to interface between the sim. The simIFrameClient can send messages
// and receive messages as changes occur in the sim.
var simIFrameClient = new phetio.SimIFrameClient( document.getElementById( 'sim' ) );
// Start the simulation with specific customizations, specified below.
simIFrameClient.launchSim( {
/**
* Choose details of how the sim is launched and fill in callbacks for events
*/
// Data stream customizations
// Choose whether the sim should emit json states and/or input events in addition to the instance-based messages.
// This can be overriden by query parameters in the wrapper.
emitStates: false,
emitInputEvents: false,
// NOTE: For development only
// This will launch the simulation with added error throwing to catch mistakes and problems easier.
debug: true,
// Callback for messages (events) from the sim's event stream
phetioEventsListener: function( message ) {
console.log( 'message emitted: ', JSON.parse( message ) );
},
// Add a listener when PhET-iO is ready, before the simulation has started initialization
onPhETiOInitialized: function() {
// add a listener called whenever an instance is created in the simulation, print out that created phetioID
simIFrameClient.invoke( 'phetio', 'addInstanceAddedListener', [
function( phetioID ) {
console.log( phetioID + ' has been created' );
} ] );
},
// Callback when the sim is initialized
onSimInitialized: function() {
console.log( 'sim initialized' );
// Invoke a method on a variable in the simulation. Open the "Studio" wrapper to see all of the variables
// and methods available in friction 1.5.0-dev.12
simIFrameClient.invoke( 'phetio', 'getState', [], function( state ) {
console.log( 'got the simulation state: ' + JSON.stringify( state, null, 2 ) );
} );
},
// Callback when the sim encounters an error
onError: function( error ) { throw error; }
} );
</script>
</body>
</html>
This file can be used as a template for beginning your own wrapper development. Alternatively, you can launch the Studio wrapper above and press the "Generate HTML" button to create a template like the one above with customizations provided by the Studio wrapper.
A good place to start is by downloading the example above (or one generated by Studio => "Generate HTML")
and launching it on your development machine. Try printing messages to the console from the phetioEventsListener
callback. Once that is working, you can start changing the commands sent across the SimIFrameClient
and
switch to a different simulation/version. All necessary globals like SimIFrameClient
,
are imported from the phet-io.js
import. To assure compatibility, please make
sure that the version and sim from that import match that of the sim you are loading.
To send one command to one simulation instance, use simIFrameClient.invoke() as shown in the example above. To invoke multiple commands, use simIFrameClient.invokeSequence(), shown in an example later in this page.
Wrapper development
When developing wrappers, there are a few tools that can make the process easier.
- Passing
debug: true
as an option toSimIFrameClient.launchSim()
will load the PhET-iO simulation with lower error tolerance. In this mode, problems are easier to catch and solve while developing the wrapper. - You can handle errors received from the simulation frame with the
onError
callback option inlaunchSim()
. - Another way to "handle" errors is to run the simulation with the
phetioThrowSimErrors
query parameter (using thequeryString
option passed tolaunchSim()
). This parameter will automatically throw any error triggered in the simulation frame, rather than packaging it and sending it back to the wrapper frame.
onError
callback may still be useful, but the debug
option and the phetioThrowSimErrors
query
parameter may cause unwanted problems in production code.
For a complete list of options that can be passed to SimIFrameClient.launchSim()
, as well as a list of
all valid query parameters both for the wrapper and simulation frames, see the Full
API
Documentation.
Further documentation
For more documentation detailing globals imported in the phet-io.js
library, phet-io and
simulation query parameters, and more, please see the Full API
Documentation.
Supporting Customization and Reset
If you are planning to customize a simulation with a Reset All button, then special action must be taken.
Resetting can remove certain customizations, restoring the sim to its original state. If you don't need
the Reset All button, then you can hide it using the API with NodeIO.setVisible()
. If the ResetAllButton
is made invisible,
invoking customizations on the simulation in the SimIFrameClient.onSimInitialized()
listener is enough.
Otherwise, you will need to add a listener to the Reset All button to apply the customizations on
the button fire
event. This can also be done successfully in
SimIFrameClient.onSimInitialized()
. Note that it is recommended that you
add SimIFrameClient
callbacks (like onSimInitialized
and onPhetioInitialized
)
from the launchSim options.
// Note that this example is for the Faraday's Law PhET-iO Simulation
// customizations to be added to the sim on startup. Here we want both coils and the field lines displayed.
var customizations = [
{
phetioID: 'faradaysLaw.faradaysLawScreen.model.magnetModel.showFieldLinesProperty',
method: 'setValue',
args: [ true ]
},
{
phetioID: 'faradaysLaw.faradaysLawScreen.model.showSecondCoilProperty',
method: 'setValue',
args: [true]
}
];
simIFrameClient.launchSim( {
onSimInitialized: function() {
simIFrameClient.invokeSequence(customizations);
// When the sim is reset, re-apply the initial customization.
simIFrameClient.invoke(
'faradaysLaw.faradaysLawScreen.view.controlPanel.resetAllButton',
'addListener',
[ function() {
simIFrameClient.invokeSequence( customizations );
} ] );
}
} );