PhET Interactive Simulations creates free, open source educational simulations in science and math, which you can find at the PhET website. This document explains PhET’s libraries (SceneryStack, practices and patterns for developing interactive simulations in HTML5. This document is also available at https://github.com/phetsims/phet-info/blob/main/doc/phet-development-overview.md. For discussion and feedback, please visit the SceneryStack Discussions forum.
Checking out the HTML5 Code from GitHub
Main is Unstable: Accessing Rigorously-Tested Code
Original Java/Flash Source Code
Development Process and Checklist
Utilities and Instrumentation for Development and Testing
Embedding a Simulation in Your Website
- You will need to be able to use the command line. This is called Terminal on macOS and Command Prompt on Windows.
git
is necessary to check out PhET code from GitHub. You can download and install git from http://git-scm.com/downloads. On macOS, the preferred way of getting git is by installing Xcode command-line tools. The instructions for that are at https://git-scm.com/book/en/v2/Getting-Started-Installing-Git.node
andnpm
are necessary to install dependencies and run build code processes. Download & install node+npm from https://nodejs.org/en/- After installing, run
npm config set save false
andnpm config set package-lock false
so that package-lock.json files are not created.
- After installing, run
- Create a directory where you intend to check out the PhET source code:
mkdir phetsims
- For building the simulations, install the grunt command line utility:
npm install -g grunt-cli
(May requiresudo
if you don't have sufficient permissions). - An HTTP Server is necessary to launch the simulations during development (though not necessary for built simulations).
Some systems already have Apache, or you can install something like
npm install http-server -g
. (May requiresudo
if you don't have sufficient permissions). - Serve files from the
phetsims/
directory. Forhttp-server
this can be done like so:- Change into the phetsims directory
cd phetsims/
- Run the http server program (with caching turned off to help with iteration)
http-server -c-1
- Change into the phetsims directory
Method 1 (recommended): Get all PhET repos
- Change directory to phetsims:
cd phetsims
- Get phetsims/perennial:
git clone https://github.com/phetsims/perennial
- Change directory to perennial:
cd perennial
- Run npm install:
npm install
- Change directory back:
cd ..
- Run "clone-missing-repos.sh":
./perennial/bin/clone-missing-repos.sh
Method 2: Manually get specific PhET repos
- Change directory to phetsims:
cd phetsims
- Run the
git clone
commands listed in a simulation README.md file, such as https://github.com/phetsims/example-sim/blob/main/README.md
When running the first git clone
command, macOS may show a dialog that says: The “git” command requires the command
line developer tools. Would you like to install the tools now? In this case, press “Install”.
Install dev dependencies via npm install
in the following directories:
cd chipper
npm install
cd ../perennial-alias
npm install
cd ../perennial
npm install
cd ../${directory of the sim you are working on}
npm install
- Change directory to the build tools:
cd chipper/
- Run the TypeScript transpiler:
grunt transpile --live
which starts a process that will auto-transpile when files change. - For more details about TypeScript, please see PhET's TypeScript Quick Start Guide
- Open a browser to the path for one of the simulations: http://localhost:8080/example-sim/example-sim_en.html?brand=adapted-from-phet (port or path may depend on your HTTP server configuration) Now you can test modifying the simulation code and see the changes by refreshing the browser.
- You can also use this to test on remote devices after looking up your ip address. If developing on Chrome, note that it can be helpful to set "Disable cache (while DevTools is open)" (see the devtools settings).
- Change to the directory of the simulation you are working on, such as
cd example-sim/
- Run
grunt --brands=adapted-from-phet
- Open a browser to the path for one of the simulations: http://localhost:8080/example-sim/build/adapted-from-phet/example-sim_en_adapted-from-phet.html (port or path may depend on your HTTP server configuration)
- Questions should be directed to the SceneryStack Discussions forum.
After checking out the dependencies and installing grunt-cli in the preceding instructions, you can create your own simulation using the template.
- Check out the template sim, called ‘simula-rasa’ using this git clone command:
cd phetsims
git clone https://github.com/phetsims/simula-rasa.git
- Install the chipper dependencies:
cd chipper
npm install
- Install the perennial dependencies:
cd ../perennial
npm install
- Install the perennial-alias dependencies:
cd ../perennial-alias
npm install
- Use the perennial ‘grunt’ task to create a new sim, like so (still in the perennial directory):
grunt create-sim --repo=NAME --author=AUTHOR
For instance, if the simulation is going to be named Acceleration Lab and the author is Jane Doe, then you could put:grunt create-sim --repo=acceleration-lab --author="Jane Doe"
- In your simulation directory, run the transpiler watch process and specify your new repo as a target:
cd ../acceleration-lab
grunt output-js-project --live
- Test the created simulation in the browser and make sure it launches. It should be a blank simulation. Write to the SceneryStack Discussions forum if you run into problems.
The process described above is sufficient for iterating during development. When you are ready to build the source code (including images, sounds and other assets) into an optimized HTML file suitable for student or client usage, you can build the simulation using the chipper grunt build process.
- Open Git Bash (Windows) or Terminal (macOS) and type:
cd example-sim
npm install
npm prune
npm update
npm install grunt-cli -g
cd ../chipper
npm update
cd ../example-sim
grunt
- Open a browser to the path to test it: http://localhost:8080/example-sim/build/phet/example-sim_en_phet.html
- Pulling the latest changes
- Creating an issue
- Committing
- Submitting a pull request
Our simulations and dependencies are hosted publicly on GitHub: https://github.com/phetsims
We have 150+ repositories for the simulations and their dependencies, listed at: https://github.com/orgs/phetsims/repositories.
PhET Simulations are based on a Model/View separation pattern. This pattern and others used in PhET Simulations are described at https://github.com/phetsims/phet-info/blob/main/doc/phet-software-design-patterns.md
The tables below depict the most significant common code libraries used by PhET Simulations. The simulations provide their own model and view implementations often building with common code components. Salient relationships between repos are identified, but many repos are cross-cutting. For instance, nearly every repo uses tandem for PhET-iO support and axon for Observer/Listeners patterns. The LOC reports the total lines of code (includes comments and blank lines) to give a rough sense of the size. Please note the LOC is not directly correlated to complexity--for instance, scenery-phet has many lines of code, but is less complex because it is made up of many separate, modular components.
Repository | LOC | Description |
---|---|---|
joist | 10,000 | Simulation loading, homescreen + navigation bar, screen management. Uses some user interface components from sun. Uses scenery to render and process input. Runs the animation loop. |
sun | 13,000 | Graphical user interface components, such as buttons and checkboxes which could be useful in any application context. Built using scenery. |
scenery-phet | 25,000 | Simulation-specific components, such as probes, sensors, buckets, magnifying glasses, etc. Built using scenery. |
scenery | 86,000 | Foundational library for representing graphics (rendering to SVG, canvas or WebGL), handling input and generally abstraction for the browser and cross-platform support. Shapes are represented using kite. Observer and emitter patterns use axon. Support for alternative input and accessibility features. |
tambo | 6,000 | Sound effects and sonification. Uses axon for some observer/listeners support. |
brand | 100 | Provides support for the main supported brands "PhET" and "PhET-iO" and hooks for clients to develop their own branding. |
twixt | 2,000 | Support for tweening and animation. Can be used to animate user interface components or artwork in the view or model elements directly. |
Repository | LOC | Description |
---|---|---|
kite | 16,000 | Shapes and geometry. Mathematics implemented using dot |
dot | 21,000 | Mathematical objects such as Vector, Matrix, and corresponding numerical algorithms |
axon | 8,000 | Data structures for the observer pattern (Property) and listener pattern (Emitters). |
phet-core | 4,000 | Basic utility & support data structures and algorithms |
tandem | 5,000 | Simulation-side code to support PhET-iO instrumentation. |
Repository | LOC | Description |
---|---|---|
chipper | 10,000 | Tools for developing and building simulations. Uses code in perennial-alias for some tasks. |
perennial | 11,000 | Maintenance tools that won't change with different versions of chipper checked out (always runs in main). |
perennial-alias | 11,000 | Copy of perennial that can run on non-main SHAs. |
sherpa | - | All of our 3rd-party dependencies. Some such as font-awesome or lodash are used in every simulation and some such as numeric or three.js are sim-specific. |
Our example-sim repository README.md includes a list of git clone commands that will check out the example simulation and all of its dependencies: https://github.com/phetsims/example-sim
And to clone some of our in-development sims:
git clone git://github.com/phetsims/forces-and-motion-basics.git
git clone git://github.com/phetsims/build-an-atom.git
All repositories should be cloned into the same directory so that relative paths will work.
Here is a full list of all phetsims repositories. If the sim won’t launch due to a missing dependency, you may need to check out some more of these repos: https://github.com/phetsims?tab=repositories
Also note that this will check out the ‘main’ branch of all of our dependencies, which may create breaking changes intermittently if you remain up-to-date with them. If you run into any breaking changes, please notify us immediately. Also, we recommend developing your code on a public repo such as GitHub to enable us to test and update your simulations as common dependencies are changed.
The main branch of the PhET simulation and library repositories is constantly under development and not guaranteed to be stable. It is our intent that the main branch of simulations + libraries will build and run properly, but sometimes the code goes through intermediate states where errors can be introduced. On the other hand, our published simulations have been rigorously tested across 18+ platforms and are the most stable option. If you are adapting a PhET simulation, or would like to access simulation code that corresponds directly to one of our published versions, then you will need to check out specific SHA revisions in all of the appropriate repositories. Checking out these fixed, tested revisions is also important when working on a release-candidate branch of a simulation. Here are the instructions:
- First, identify the version for which you want to check out the source code, for example: https://phet.colorado.edu/sims/html/area-builder/latest/area-builder_en.html
- Navigate to a file named dependencies.json at the same path, for example: https://phet.colorado.edu/sims/html/area-builder/latest/dependencies.json
- Download the dependencies.json file to the root of the simulation directory.
- Open a command prompt and cd into the root of the simulation directory.
- Run
grunt checkout-shas
. This step will read from the dependencies.json file and check out all of the SHAs corresponding to the entries in the file. - To checkout the SHA for the simulation itself, first look up the SHA in the dependencies file, move the dependencies
file to some other location or delete it, and use
git checkout
to check it out the appropriate SHA. (Note future version ofgrunt checkout-shas
may handle this last step). - Inspect the simulation and its dependencies to make sure
grunt checkout-shas
had the intended effect of getting the right SHA for each repo.
Now you can use the published source code. To restore each branch to main, you can run grunt checkout-main
.
- Running
grunt checkout-shas
gives errors when the working copy is not committed. These grunt commands are currently only supported for clean git repos. Stashing may be a way around this problem. Also, if you want to use dependencies from a different version than in the SHAs, that will have to be done as an additional manual step. - When working in a branch,
grunt checkout-main
will check out the main branch and additional manual steps will be required to get back to the desired branch(es). For instance, this is an issue when working with the “adapted-from-phet” branch of brand.
Follow the directions at this link to get the source code for original Java and Flash version of the simulations: https://phet.colorado.edu/en/about/source-code
After checking it out (could take 30+ minutes), the source code for the simulations are located in (for example): svn-checkout/trunk/simulations-java/simulations/forces-and-motion-basics
PhET Simulations use around 3 open source 3rd-party dependencies for the deployed source code, and more for the build phase. They are all included with the source code checkouts in the sherpa repository. The libraries and licenses are described in this 3rd-party dependency licensing document.
New simulations should be published under GPLv3 and reusable library dependencies should be published as MIT.
To improve the readability and maintainability of PhET Simulation code, we have identified several style recommendations for writing code and documentation:
-
The PhET Code Review Checklist is available at https://github.com/phetsims/phet-info/blob/main/checklists/code-review-checklist.md provides additional steps to make sure a simulation is well written. This checklist is used for publication of any new PhET simulation to make sure they are consistent and maintainable. It enumerates steps including but not limited to coding style.
-
We use ESLint to lint our code. See https://github.com/phetsims/chipper/blob/main/eslint/README.md.
-
An IntelliJ IDEA formatting XML file to automatically format code. This is the ground truth for how PhET code should be formatted. Our example-sim also shows how to use our libraries idiomatically as well as a good example of code commenting + documentation.
We also tend to agree with most of the guidelines set out in idiomatic.js.
The simulation should be tested and run on the platforms linked below. In our experience to date, some optimization is often required to obtain acceptable performance on tablets such as the iPad.
System requirements: https://phet.colorado.edu/en/help-center/running-sims/general#q11-header
The current iteration of PhET's simulation codebase uses native Javascript modules, which were introduced in ECMAScript
- For PhET specifically, default exports are only used (as opposed to named exports). ES6 Modules are used to support modularization of the JavaScript code. Information about ES6 Modules can be found here. Examples of how it will be used by PhET can be seen in the Example Simulation (specifically the source files in the js directory).
Minimum width x height: 768x504 (1.52:1, inside Mobile Safari)
The simulation should scale isometrically such that all portions are visible at any resolution. An example of this type of scaling can be seen in the example simulation.
A minification and unification process is implemented in our repo https://github.com/phetsims/chipper. This can be used to create a single-file HTML that contains all images and audio, and is suitable for download for offline usage.
Here's an example of how to compile example-sim into a single HTML file. Other sims would be compiled similarly. This assumes that you have all of example-sim's dependencies checked out in your local working copy.
% cd example-sim
% npm install
% grunt build --brands=adapted-from-phet
% cd build/adapted-from-phet
% ls
dependencies.json
example-sim-128.png
example-sim-600.png
example-sim_all_adapted-from-phet_debug.html
example-sim_en_adapted-from-phet.html
xhtml/
It is a requirement that all PhET simulations can be downloaded and run off line in all identified browsers from the file:// URL. PhET’s chipper build process (described above) produces a single file that can be downloaded for offline use. Please make sure you are not using any APIs that prevent launching and running properly when offline using file:// URL., and test that offline operation works properly for your simulation.
Here is a link to some published sims, so that you can see a demonstration of how some things should look and behave: https://phet.colorado.edu/en/simulations/category/html
The steps to create a fully functional PhET simulation, given an existing Java/Flash version or development specification:
- The simulation and its code: a. must use the appropriate libraries in the correct fashion b. must be adequately commented c. must contain no dead code (i.e. commented out code that does nothing) d. must be maintainable e. reusable components should be polished and moved to the appropriate libraries f. should pass all jshint tests when running chipper, and should be compiled into a single file HTML file h. original vector artwork for anything appearing in the images/ directory should be checked into the assets/ directory. i. must run with ?ea (assertions) enabled without any assertion errors being triggered
- Simulation & User Interface Testing a. Testing on our supported platforms and identification of problems on different
browsers b. Performance must be sufficiently fast on all supported platforms. i. The simulation should start in <8
seconds on iPad3 ii. We strive for a steady 60fps on iPad3 when possible c. The simulation should be tested with
assertions enabled:
?ea
d. The simulation should be tested for touch areas:?showPointerAreas
- Code review a. The code will be reviewed by one or more PhET developers in order to identify possible bugs or maintenance problems b. Issues raised in the review will be addressed
- Release candidate testing a. Before publication, a release candidate branch is created so that the branch can be thoroughly tested and, if no significant bugs are found, published
- Publication a. The simulation is made available on the PhET website
- Maintenance a. the simulation is published and any bugs reported by students or teachers will be resolved
Many aspects of a simulation must be developed properly and working well in order for the simulation to behave properly across our many supported platforms. PhET has developed several utilities and instruments to make this development and testing easier. The most up-to-date documentation for the query parameters is available here: https://github.com/phetsims/chipper/blob/main/js/browser/initialize-globals.js
- Query parameter:
?screenIndex
. This query parameter may be used to specify the initial screen of the simulation. It can be paired with standalone above to launch just a specific screen of the simulation. For instance: http://localhost:8080/energy-skate-park-basics/energy-skate-park-basics_en.html?screenIndex=1&standalone launches Energy Skate Park: Basics using only the 2nd screen. - Phet Allocations: Object instance allocation tracking, so we can cut down on garbage collection. See https://github.com/phetsims/phet-core/blob/main/js/phetAllocation.js Sample usage: a. Run the sim and set up the scenario that you wish to profile b. In the JS console, type: window.alloc={} c. Wait until you have taken enough data d. Type x = window.alloc; delete window.alloc; Now you can inspect the x variable which contains the allocation information.
- Run with query parameter
?ea
to enable assertions in the code. The sim should run without any assertion errors. ( Assertions are predicates about what should be true at specific points in the code. They are used to identify programming errors.) - Query parameter:
?showPointerAreas
. This query parameter shows the areas for mouse and touch input events. On mobile devices (and sometimes for mouse) it is essential to increase the interaction region for a scenery node. Touch areas are shown in red and custom mouse areas are shown in blue. - makeRandomSlowness(). This method can be called after the simulation is started to simulate an intermittently slow system. This can be used to help replicate bugs that only happen intermittently or only on slow platforms. To call this method, launch the sim, show the developer console, and type the command as above.
- makeEverythingSlow(). This method can be called after the simulation is started to simulate a slow system. This can be used to help replicate bugs that only happen intermittently or only on slow platforms. To call this method, launch the sim, show the developer console, and type the command as above.
- Query parameter:
?profiler
. Launching a sim with ?profiler will print out the time to create each screen, and will show a histogram which updates every 60 frames depicting how long the frames are taking (in ms). Note: just showing the average FPS or ms/frame is not sufficient, since we need to see when garbage collections happen, which are typically a spike in a single frame. Hence, the data is shown as a histogram. After the first 30ms slots, there is a ++= showing the times of longer frames (in ms) - Usage of Unit Tests: After making changes in one of the repos with unit tests (see if tests/qunit exists), run the unit tests afterwards (tests/qunit/unit-tests.html) to see if anything is broken. We highly recommend checking "Hide passed tests", and wait until all tests are complete (it may pause at 0 tests complete at the start).
- Adding Unit Tests: If you want to add a test, add it to one of the tests/qunit/js/* files that have a QUnit module( ' ...' ) declaration, and read the QUnit tutorials to understand how it works. You can add new files with more tests by creating the file and referencing it in tests/qunit/js/unit-tests.js (whose purpose is to load those files).
- Namespaces for Unit Tests and Playground: Each unit-tests.html makes certain namespaces global (e.g. Scenery's makes window.scenery/kite/dot/axon/core for Scenery/Kite/Dot/Axon/phet-core respectively).
- Playground: If it exists, it will be a tests/playground.html, and allows testing code in the console. To make code available in the console, check the 'main' file used by the playground and add a reference there. For instance, Scenery's playground.html loads 'scenery/js/main.js', and saves it to window.scenery.
- Run
grunt lint
on the command line to check for lint errors. All code should be free of lint errors. (lint is a tool that analyzes source code to flag programming errors, bugs, stylistic errors, and suspicious constructs. PhET uses the eslint variant of lint.) - Install PhET's git hooks to run basic checks as part of the git lifecycle. Run this from the root of your checkout. First it clears any pre-existing commit hooks, then installs the new hooks.
perennial-alias/bin/for-each.sh perennial-alias/data/active-repos "rm .git/hooks/pre-commit; git init --template=../phet-info/git-template-dir"
Getting to optimal performance on all supported platforms can be tricky--this section enumerates possible optimizations strategies:
- Consider using WebGL.
- Reduce allocations (including but not limited to closures) during animation.
- Eliminate closures and move values to properties and prototypes, see phetsims/scenery#664.
- Consider replacing color strings with color constants, see phetsims/sun#312.
When the problem described in a GitHub issue is solved, a description of the solution should be made in the issue and the issue should be reassigned to the original reporter of the GitHub issue for verification and closing. Commits that address the GitHub issue should also reference the issue in the commit message, so the change set can be easily reviewed.
Here are some example issues that show creation of an issue, solving it with a commit message that references the issue, an explanation of the solution and reassignment to the reporter for verification and closing: phetsims/color-vision#15 phetsims/fraction-matcher#56 phetsims/color-vision#37
To embed a simulation in your website, use an iframe like so:
<iframe src="https://phet.colorado.edu/sims/html/forces-and-motion-basics/latest/forces-and-motion-basics_en.html" width="834" height="504"></iframe>The aspect ratio 834x504 is used for new simulations, because it matches the aspect ratio available on popular devices.
To see a full embedding example in context, view the source for this page: https://phet-dev.colorado.edu/html/acid-base-solutions/1.1.0/acid-base-solutions_en-iframe.html