├── doc ├── images │ ├── axe-DevTools-location.png │ ├── axe-DevTools-results.png │ └── descriptionDesignFramework.png ├── supported-browsers.md ├── axe-devtools-guide.md ├── string-key-conventions.md ├── dynamic-string-layout-quickstart.md ├── typescript-quick-start.md ├── core-description-options.md ├── phet-dev-exercises.md ├── interactive-highlights-quickstart-guide.md ├── fluent-translation-glossary.md ├── vegas-description-quickstart-guide.md └── core-voicing-quickstart-guide.md ├── intern-info ├── job-postings.md ├── git_bash_tips.md └── web-dev-intern-setup.md ├── github-labels ├── package.json ├── printGithubAuthorization.js ├── labeling-scheme.md ├── delete-label.sh ├── new-label-all-repos.sh ├── change-label.sh ├── update-repos-list.js ├── github-labels ├── new-repo-add-labels.sh └── README.md ├── qa-team-info ├── Screenshots.md └── applicant-task.md ├── conferences └── README.md ├── contributors ├── CU PhET Institutional Contributor License Agreement.pdf └── CLA.md ├── sim-info ├── pixelzoom-sims.md ├── printReposPerDev.mjs ├── README.md ├── areAllReposInFile.js ├── getAllRepos.js └── generateMarkdownOutput.mjs ├── .gitignore ├── package.json ├── resources ├── screen-reader │ ├── voice-over.md │ └── nvda.md └── developer-resources.md ├── eslint.config.mjs ├── deployment-info └── README.md ├── typescript-conversion ├── playwright.config.js ├── rename-js-to-ts.sh ├── add-eslint-disable.sh ├── test │ └── snapshot-comparison-test.js ├── conversion-checklist.md └── .claude │ └── commands │ ├── migrate-method-types.md │ ├── migrate-constructor.md │ └── migrate-constructor-options.md ├── checklists ├── youtube-upload-checklist.md ├── external-library-checklist.md ├── prototype-checklist.md ├── updating-metadata.md ├── new-student-worker-checklist.md ├── S2015R-checklist.md ├── rename-repo-checklist.md ├── delete-repo-checklist.md ├── employee-leaving-checklist.md ├── postmortem-process.md ├── sim-republication-checklist.md ├── new-repo-checklist.md └── sim-checklist.md ├── .github ├── workflows │ └── sync.yml └── sync.yml ├── issue-info ├── unfuddle-ticket-search.md ├── github-issue-philosphy.md └── useful_searches.md ├── git-template-dir └── hooks │ └── pre-commit ├── README.md ├── ide ├── vscode │ └── setup.md ├── sublime-text │ ├── phet-plugin │ │ ├── README.md │ │ ├── Main.sublime-menu │ │ ├── phet.sublime-commands │ │ └── phet-find-results.tmLanguage │ └── eslint-and-sublime-text.md └── idea │ └── performance.md ├── LICENSE ├── github-dashboard ├── processCachedIssues.js └── issueReport.js ├── project-management ├── common-code-issue-template.md ├── reportEpicIssuesNotInSpreadsheet.js └── management-granularity-levels.md ├── policies ├── Confidentiality-of-user-information.md ├── team assignment.md └── availability.md ├── ai └── core-description │ ├── add-accessible-heading.md │ ├── add-checkbox-accessible-response.md │ ├── add-radio-accessible-response.md │ └── interact.md └── conduct └── communication-guidelines.md /doc/images/axe-DevTools-location.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phetsims/phet-info/HEAD/doc/images/axe-DevTools-location.png -------------------------------------------------------------------------------- /doc/images/axe-DevTools-results.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phetsims/phet-info/HEAD/doc/images/axe-DevTools-results.png -------------------------------------------------------------------------------- /intern-info/job-postings.md: -------------------------------------------------------------------------------- 1 | ## Resources 2 | 3 | Gender decoder for postings 4 | http://gender-decoder.katmatfield.com/ 5 | -------------------------------------------------------------------------------- /github-labels/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "axios": "~0.21.4", 4 | "fs": "~0.0.1-security" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /doc/images/descriptionDesignFramework.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phetsims/phet-info/HEAD/doc/images/descriptionDesignFramework.png -------------------------------------------------------------------------------- /qa-team-info/Screenshots.md: -------------------------------------------------------------------------------- 1 | The instructions are in the [QA Book](https://github.com/phetsims/QA/blob/main/doc/qa-book.md#screenshots). 2 | -------------------------------------------------------------------------------- /conferences/README.md: -------------------------------------------------------------------------------- 1 | This folder contains videos shown at our exhibit booth at conferences that we use to highlight sims in particular 2 | subject areas 3 | -------------------------------------------------------------------------------- /contributors/CU PhET Institutional Contributor License Agreement.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phetsims/phet-info/HEAD/contributors/CU PhET Institutional Contributor License Agreement.pdf -------------------------------------------------------------------------------- /sim-info/pixelzoom-sims.md: -------------------------------------------------------------------------------- 1 | ## Status of [@pixelzoom](https://github.com/pixelzoom) sims 2 | 3 | See https://docs.google.com/spreadsheets/d/123DgUkMRuEFG_hCsc47PQXw0v2pQZlwp5ZiCs7kznG8 | 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | build/ 3 | node_modules/ 4 | *.iml 5 | .DS_Store 6 | .DS_Store? 7 | *.sublime-project 8 | *.sublime-workspace 9 | .eslintcache 10 | github-labels/.repos 11 | github-labels/.response -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "phet-info", 3 | "version": "1.0.0", 4 | "license": "MIT", 5 | "repository": { 6 | "type": "git", 7 | "url": "https://github.com/phetsims/phet-info.git" 8 | }, 9 | "devDependencies": { 10 | "octokit": "^3.1.2" 11 | } 12 | } -------------------------------------------------------------------------------- /resources/screen-reader/voice-over.md: -------------------------------------------------------------------------------- 1 | ## Voice Over 2 | 3 | ### Gotchas 4 | 5 | - Make sure that "Quick nav" is off, press left and right arrow keys at the same time to toggle this. 6 | - Make sure that settings -> Navigation -> "synchronize keyboard focus and voiceover cursor" is checked. 7 | -------------------------------------------------------------------------------- /github-labels/printGithubAuthorization.js: -------------------------------------------------------------------------------- 1 | // Copyright 2020, University of Colorado Boulder 2 | // @author Michael Kauzmann (PhET Interactive Simulations) 3 | 4 | const buildLocal = require( '../../perennial/js/common/buildLocal' ); 5 | 6 | console.log( `${buildLocal.developerGithubUsername}:${buildLocal.developerGithubAccessToken}` ); -------------------------------------------------------------------------------- /eslint.config.mjs: -------------------------------------------------------------------------------- 1 | // Copyright 2024, University of Colorado Boulder 2 | 3 | /** 4 | * ESLint configuration for phet-info. 5 | * 6 | * @author Sam Reid (PhET Interactive Simulations) 7 | * @author Michael Kauzmann (PhET Interactive Simulations) 8 | */ 9 | 10 | import nodeEslintConfig from '../perennial-alias/js/eslint/config/node.eslint.config.mjs'; 11 | 12 | export default [ 13 | ...nodeEslintConfig 14 | ]; -------------------------------------------------------------------------------- /deployment-info/README.md: -------------------------------------------------------------------------------- 1 | # Maintenance release info 2 | 3 | Maintenance release instructions can be found 4 | in [automated-maintenance-process.md](https://github.com/phetsims/perennial/blob/main/doc/automated-maintenance-process.md) 5 | 6 | # Sim deployment info 7 | 8 | Sim deployment instructions can be found in [chipper-2.0.md](chipper-2.0.md) for main, 9 | and [chipper-1.0.md](chipper-1.0.md) for older pre-chipper-2.0 sims. 10 | -------------------------------------------------------------------------------- /typescript-conversion/playwright.config.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | // @ts-nocheck 3 | 4 | const { defineConfig } = require( '@playwright/test' ); 5 | 6 | module.exports = defineConfig( { 7 | testDir: './test', 8 | testMatch: '**/*test.js', 9 | timeout: 30000, 10 | fullyParallel: true, 11 | forbidOnly: !!process.env.CI, 12 | retries: process.env.CI ? 2 : 0, 13 | workers: 1, 14 | reporter: 'list', 15 | use: { 16 | headless: true, 17 | viewport: { width: 1280, height: 720 }, 18 | ignoreHTTPSErrors: true 19 | } 20 | } ); -------------------------------------------------------------------------------- /checklists/youtube-upload-checklist.md: -------------------------------------------------------------------------------- 1 | **Youtube Uploading Checklist** 2 | 3 | - [ ] Put in relevant keywords 4 | - [ ] Choose a quality keyframe (the image shown for the video) 5 | - [ ] Use a title and description that will make sense out of context, since YouTube videos can get shared broadly. 6 | - [ ] Link back to the PhET page somewhere in the description. 7 | - [ ] Put the video in a relevant playlist. 8 | - [ ] If this will be a series, consider a playlist to house the series. 9 | - The “about PhET” channel has quite a bit, but also a good place to put videos 10 | - [ ] Inform Kathy D. for the newsletter, and Ariel for twitter. 11 | -------------------------------------------------------------------------------- /.github/workflows/sync.yml: -------------------------------------------------------------------------------- 1 | name: Sync Files 2 | on: 3 | push: 4 | branches: 5 | - main 6 | workflow_dispatch: 7 | jobs: 8 | sync: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Checkout Repository 12 | uses: actions/checkout@main 13 | - name: Run GitHub File Sync 14 | uses: BetaHuhn/repo-file-sync-action@v1 15 | with: 16 | GH_PAT: ${{ secrets.BF_GH_PAT }} 17 | PR_LABELS: false 18 | # REVIEWERS: brettfiedler #reviewer cannot be author, leaving off for now 19 | COMMIT_BODY: 'Repo File Sync automated update' 20 | # DRY_RUN: true 21 | 22 | -------------------------------------------------------------------------------- /qa-team-info/applicant-task.md: -------------------------------------------------------------------------------- 1 | [Google Document](https://docs.google.com/document/d/1fRX_4ZD9D_vHsKM6b4u_7P5eZRE71A1akTfU91j3pBc/edit?usp=sharing) 2 | 3 | Instructions for Applicant: Perform a 30 minute test of Isotopes and Atomic Mass. Look out for any bugs that occur 4 | during interaction. Complete a bug report with relevant information for each bug. Good bug reports allow developers to 5 | easily reproduce an issue. 6 | 7 | Link to 8 | Simulation: https://phet-dev.colorado.edu/html/isotopes-and-atomic-mass/1.0.0-dev.5/isotopes-and-atomic-mass_en.html 9 | 10 | Send your bug report to phethelp@colorao.edu with “Student Tester Applicant: [Name]” in the subject line. 11 | -------------------------------------------------------------------------------- /doc/supported-browsers.md: -------------------------------------------------------------------------------- 1 | # Supported Browsers for PhET Simulations 2 | 3 | Below is a list of currently supported browsers for HTML5 PhET simulations 4 | 5 | - This document is regularly updated. **Last update: 10/14/2020** 6 | - *Although other browsers not on this list may work, IE11 and older are specifically NOT supported and will fail* 7 | 8 | ### 1. Mobile Safari 13 and newer 9 | 10 | ### 2. Desktop Safari 13 and newer 11 | 12 | ### 3. Chrome latest version 13 | 14 | ### 4. Firefox latest version 15 | 16 | ### 5. Edge latest version 17 | 18 | - **Note** although we officially support Edge, this browser is not regularly tested since it is derived from Chrome 19 | 20 | 21 | -------------------------------------------------------------------------------- /checklists/external-library-checklist.md: -------------------------------------------------------------------------------- 1 | This checklist should be used when evaluating a new external library for usage in one or more PhET simulations. 2 | 3 | PhET External Library Acceptance Checklist 4 | ========================================== 5 | 6 | - [ ] It should have a compatible license, such as MIT 7 | - [ ] It should not be too large! 8 | - [ ] Is it something that we could have easily written ourselves? If we could easily write it ourselves, then sometimes 9 | it is best to avoid the licensing encumbrances. 10 | - [ ] Does it use eval or new Function or Function(‘’,...)? These are prohibited by the Chrome web store and not a good 11 | sign. 12 | - [ ] Is it popular enough that it has a high probability of being maintained for a good healthy lifetime? 13 | 14 | 15 | -------------------------------------------------------------------------------- /typescript-conversion/rename-js-to-ts.sh: -------------------------------------------------------------------------------- 1 | 2 | #!/usr/bin/env zsh 3 | # 4 | # Recursively git-rename all *.js files under ./js to *.ts, 5 | # skipping anything whose path contains “overrides”. 6 | # Only files are renamed, not directories. 7 | # 8 | # Copy and run from the root of the repository. 9 | 10 | set -euo pipefail 11 | 12 | # Find all .js files under ./js, excluding any path with “overrides” 13 | find ./js -type f \( -iname '*.js' \) ! -iname '*overrides*' -print0 | 14 | while IFS= read -r -d '' file; do 15 | tsfile="${file%.*}.ts" 16 | 17 | # Skip if the target already exists 18 | if [[ -e "$tsfile" ]]; then 19 | echo "⚠️ Skipping '$file' → '$tsfile' (target exists)" 20 | continue 21 | fi 22 | 23 | echo "git mv \"$file\" \"$tsfile\"" 24 | git mv "$file" "$tsfile" 25 | done -------------------------------------------------------------------------------- /github-labels/labeling-scheme.md: -------------------------------------------------------------------------------- 1 | ### Standard Labels 2 | 3 | The standard label set is 4 | documented [in this json file](https://github.com/phetsims/phet-info/blob/main/github-labels/github-labels.json) 5 | 6 | ### General Scheme 7 | 8 | + labels follow the format `` 9 | + sim specific labels follow the format `` 10 | + just the word "sim" not the sim name 11 | + repo specific labels follow the format `` 12 | + example: `` 13 | + All label names are separated by dashes for multiple words 14 | + example `` 15 | 16 | ### Label Usage 17 | 18 | + For the Summer 2015 Redeploy `` color #5319e7 19 | + For bugs reported found testing the java/flash version `` #CD00CD 20 | -------------------------------------------------------------------------------- /issue-info/unfuddle-ticket-search.md: -------------------------------------------------------------------------------- 1 | # Searching Unfuddle for tickets related to a sim 2 | 3 | When performing ports, it is important to review open issues for the legacy sim. 4 | 5 | ## Steps: 6 | 7 | 1. Log in to Unfuddle at https://phet.unfuddle.com 8 | 2. Select the **Tickets** tab. 9 | 3. Click on **Report Options** at upper right. 10 | 4. At the bottom of the right-hand panel, click **New Report...**. 11 | 5. In the Criteria panel, use the combo boxes to set the first criterion to **"Component is {project}"**, where * 12 | *{project}** is the project name. Note that an Unfuddle project contains one or more sims, so project name may not be 13 | the same as the sim name. 14 | 6. In the Criteria panel, press **Add set...**, then set the second criterion to **"Status is not Closed"**. 15 | 7. Press the **Generate Report** button. 16 | -------------------------------------------------------------------------------- /contributors/CLA.md: -------------------------------------------------------------------------------- 1 | Any individual, party, or institution that wishes to contribute to the PhET project will need to provide a signed 2 | Contributor License Agreement (CLA) 3 | 4 | Signed Contributor License Agreements for contributors to the project can be found here: 5 | https://phet.unfuddle.com/a#/projects/9404/notebooks/17995/attachments 6 | 7 | As of March 5, 2021, individual License agreements are signed online at: 8 | https://powerforms.docusign.net/942abb00-7132-498e-94ce-e55344d32dd9?env=na2&acct=088d5d64-ef4d-40bb-acf2-480eabbf546d&accountId=088d5d64-ef4d-40bb-acf2-480eabbf546d 9 | 10 | #### File Naming Convention 11 | 12 | YearContributionsBegan_LastName_FirstName_Affiliation_githubUsername-CLA 13 | 14 | #### Original Word versions of the CLA 15 | 16 | https://github.com/phetsims/special-ops/tree/main/CLA-files 17 | 18 | 19 | -------------------------------------------------------------------------------- /checklists/prototype-checklist.md: -------------------------------------------------------------------------------- 1 | # Prototype Checklist 2 | 3 | This checklist includes a minimal list of tasks that should be completed before a prototype version is published. 4 | 5 | - [ ] Run with `stringTest=X` to verify that all strings are translatable. You should see nothing but 'X' strings in the 6 | running sim. This is important because prototypes are translatable. 7 | 8 | - [ ] Inspect `{REPO}-strings_en.json` and verify that all string keys conform 9 | to [PhET string key conventions](https://github.com/phetsims/phet-info/blob/main/doc/string-key-conventions.md). 10 | String keys are difficult to change after a sim has been published, and they appear in the PhET-iO API (and Studio) as 11 | the phetioIDs for StringProperties. 12 | 13 | - [ ] Verify that the About dialog shows appropriate credits. If a third party was involved, verify that they are 14 | included in credits. See `SimOptions.credits` for how to specify credits. 15 | -------------------------------------------------------------------------------- /git-template-dir/hooks/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #----------------------------------------------------------------------------------------------------------------------- 3 | # git pre-commit hooks for the PhET Codebase. These are installed on all repos. 4 | # 5 | # This script only launches another bash script, and new logic should NOT be added here. This way, changes can be made 6 | # without the need to reinstall git hooks across all repos. 7 | # 8 | # Please see https://github.com/phetsims/phet-info/blob/main/doc/phet-development-overview.md#utilities-and-instrumentation-for-development-and-testing 9 | # for installation instructions. 10 | #----------------------------------------------------------------------------------------------------------------------- 11 | 12 | PRE_COMMIT_SCRIPT="../perennial-alias/bin/hook-pre-commit.sh" 13 | 14 | # only run the file if it exists. This helps with backwards compatibility if on an older version of perennial-alias. 15 | if test -f "$PRE_COMMIT_SCRIPT"; then 16 | $PRE_COMMIT_SCRIPT 17 | fi 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | phet-info 2 | ========= 3 | 4 | Welcome! This is a collection of information shared by PhET team members for the purpose of using GitHub effectively and 5 | for other process-related topics. If you're new to PhET Sims and would like to learn more about how we develop our 6 | resources, we recommend these two to get started: 7 | 8 | + [Development Overview](https://github.com/phetsims/phet-info/blob/main/doc/phet-development-overview.md): General 9 | information on how to build and edit sims locally, as well as other content of interest. 10 | + [Onboarding Documentation](https://github.com/phetsims/phet-info/blob/main/doc/new-dev-onboarding.md): This one is for 11 | new developers at PhET, to help them in their journey. However, any developer might find useful information as well, 12 | such as environment set up, or roadmaps to gain familiarity with our codebase. 13 | 14 | To see a list of responsible developers based on each repo, 15 | see [here](https://github.com/phetsims/phet-info/blob/main/sim-info/responsible_dev.md). 16 | -------------------------------------------------------------------------------- /ide/vscode/setup.md: -------------------------------------------------------------------------------- 1 | # Set up of VSCode IDE for PhET Development 2 | 3 | ## Configuring ESLint 4 | 5 | UPDATE: As of Nov 2024, these instructions are out of date. We have upgraded to ESLint 9 which uses the flat config, 6 | and have not tested VSCode support for ESLint since then. 7 | 8 | 1. You should have installed the ESLint VSCode Extension from the marketplace. 9 | 2. Your settings.json for ESLint should contain the following (Replace `ABSOLUTE_USER_PATH` with your computer's 10 | absolute path): 11 | 12 | ``` 13 | { 14 | "eslint.nodePath": "ABSOLUTE_USER_PATH/phetsims/perennial-alias/node_modules", 15 | "eslint.options": { 16 | "cache": true, 17 | "ignorePath": "ABSOLUTE_USER_PATH/phetsims/chipper/eslint/.eslintignore", 18 | "resolvePluginsRelativeTo": "ABSOLUTE_USER_PATH/phetsims/chipper/", 19 | "rulePaths": [ "ABSOLUTE_USER_PATH/phetsims/chipper/eslint/rules" ], 20 | "extensions": [ ".js", ".ts" ] 21 | }, 22 | "eslint.workingDirectories": [ { "mode": "auto" } ] 23 | } 24 | ``` 25 | -------------------------------------------------------------------------------- /github-labels/delete-label.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # delete-label.sh 4 | # 5 | # This script removes the label from all repos 6 | 7 | if [[ $1 = '' ]] 8 | then 9 | echo "Usage: $0 label-name" 10 | exit 1 11 | else 12 | label=$1 13 | echo "$label" 14 | fi 15 | 16 | binDir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" 17 | creds=`../../perennial/bin/sage run ${binDir}/printGithubAuthorization.js` 18 | 19 | ../../perennial/bin/sage run ./update-repos-list.js 20 | 21 | echo 'For each repo, this script should print "204 No Content" to indicate success' 22 | 23 | for repo in `cat .repos` 24 | do 25 | repo=`echo ${repo}` 26 | url=https://api.github.com/repos/phetsims/${repo}/labels/${label} 27 | echo "Path: ${url}" 28 | echo "Result:" 29 | curl -isH 'User-Agent: "phet"' -u "$creds" -X DELETE ${url} | head -n 1 30 | done 31 | 32 | sed -n /${ppp}/'!p' github-labels > .tmp && mv .tmp github-labels 33 | sort github-labels -o github-labels 34 | git pull && git commit github-labels -m "Removed github label ${label}" && git push 35 | 36 | echo "Complete." 37 | 38 | -------------------------------------------------------------------------------- /sim-info/printReposPerDev.mjs: -------------------------------------------------------------------------------- 1 | // Copyright 2021, University of Colorado Boulder 2 | 3 | import fs from 'fs'; 4 | 5 | /** 6 | * List repos per developer 7 | * 8 | * Usage: 9 | * cd root 10 | * sage run phet-info/sim-info/printReposPerDev.mjs 11 | * 12 | * @author Sam Reid (PhET Interactive Simulations) 13 | */ 14 | const responsibleDevObject = JSON.parse( fs.readFileSync( './phet-info/sim-info/responsible_dev.json', 'utf8' ) ); 15 | const devs = []; 16 | const repos = Object.keys( responsibleDevObject ); 17 | repos.forEach( repoName => { 18 | responsibleDevObject[ repoName ].responsibleDevs.forEach( repoDev => { 19 | if ( !devs.includes( repoDev ) ) { 20 | devs.push( repoDev ); 21 | } 22 | } ); 23 | } ); 24 | devs.sort(); 25 | 26 | const devReport = dev => { 27 | const reposForDev = repos.filter( repo => responsibleDevObject[ repo ].responsibleDevs.includes( dev ) ); 28 | const repoNotes = reposForDev.map( repo => `* ${repo}` ).join( '\n' ); 29 | return '## ' + dev + '\n' + repoNotes; 30 | }; 31 | const report = devs.sort().map( devReport ).join( '\n\n' ); 32 | console.log( report ); -------------------------------------------------------------------------------- /typescript-conversion/add-eslint-disable.sh: -------------------------------------------------------------------------------- 1 | # Copy and run from the root of the repository. 2 | # 3 | #!/bin/bash 4 | 5 | # Find all .ts files under js/ directory 6 | find js -name "*.ts" -type f | while read -r file; do 7 | # Check if first line starts with "// Copyright" 8 | first_line=$(head -n 1 "$file") 9 | if [[ "$first_line" == "// Copyright"* ]]; then 10 | # Create temporary file with the modifications 11 | { 12 | # Write the first line (Copyright) 13 | echo "$first_line" 14 | # Add the two new lines 15 | echo "" 16 | echo "/* eslint-disable */" 17 | echo "// @ts-nocheck" 18 | # Write the rest of the file (starting from line 2) 19 | tail -n +2 "$file" 20 | } > "$file.tmp" 21 | 22 | # Replace the original file with the modified one 23 | mv "$file.tmp" "$file" 24 | echo "Modified: $file" 25 | else 26 | echo "Skipped: $file (first line doesn't start with '// Copyright')" 27 | fi 28 | done 29 | 30 | echo "Done processing all .ts files" -------------------------------------------------------------------------------- /resources/screen-reader/nvda.md: -------------------------------------------------------------------------------- 1 | ## NVDA 2 | 3 | ### Basics 4 | 5 | In general, use the "NVDA" key (defaults to `Insert`) to control NVDA with the keyboard. 6 | 7 | Here is a list of keyboard shortcuts to get you started: https://webaim.org/resources/shortcuts/nvda 8 | 9 | An important shortcut to note is the ability to cycle between speech mode "on", speech mode "off", and speech mode " 10 | beeps" 11 | `Insert + s` 12 | 13 | ### Setup 14 | 15 | @zepumph prefers to use the screen reader via the "speech viewer." To turn on speech viewer: 16 | 17 | `Insert + n -> tools -> speech viewer` 18 | 19 | It can also be set to "show speech viewer on startup" 20 | 21 | Here is a list of settings that will silence a screen reader when "speech mode" is off: 22 | 23 | * Turn off these settings: 24 | 25 | * Preferences -> Settings -> General -> "Play sounds when starting or exiting nvda" 26 | * Preferences -> Settings -> Keyboard -> "Play sound for spelling errors while typing" 27 | * Preferences -> settings -> Browse Mode -> "Audio indication of focus and browse modes" 28 | * Preferences -> settings -> Keyboard -> "Beep if typing lower case when caps lock is on" 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 University of Colorado Boulder 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /github-labels/new-label-all-repos.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # new-label-all-repos.sh 4 | # 5 | # This file adds a new label to all repos 6 | 7 | if [[ $1 = '' ]] || [[ $2 = '' ]] 8 | then 9 | echo "Usage: $0 label-name color" 10 | exit 1 11 | else 12 | name=$1 13 | color=$2 14 | label={\"name\":\"$1\",\"color\":\"$2\"} 15 | echo "$label" 16 | fi 17 | 18 | binDir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" 19 | creds=`../../perennial/bin/sage run ${binDir}/printGithubAuthorization.js` 20 | 21 | ../../perennial/bin/sage run ./update-repos-list.js 22 | 23 | echo 'For each repo, this script should print "201 Created" to indicate success"' 24 | 25 | for repo in `cat .repos` 26 | do 27 | repo=`echo ${repo}` 28 | url=https://api.github.com/repos/phetsims/$repo/labels 29 | echo "Adding label to: ${repo}" 30 | echo "Result:" 31 | curl -isH 'User-Agent: "phet"' -u "$creds" -d "$label" -X POST "$url" | head -n 1 32 | echo "" 33 | done 34 | 35 | echo ${name},${color} >> github-labels 36 | sort github-labels -o github-labels 37 | git pull && git commit github-labels -m "Added github label from ${label}" && git push 38 | 39 | echo "Complete." 40 | -------------------------------------------------------------------------------- /checklists/updating-metadata.md: -------------------------------------------------------------------------------- 1 | Updating metadata 2 | ============= 3 | 4 | If you make a change to any of the following, the single sim (or all sims) will need updates: 5 | 6 | - Preloads (build.json) 7 | - Dependencies (build.json or sim-specific phetLibs in package.json) 8 | - Package.json changes that affect what files should be generated (unit tests/colors/a11y/etc.) 9 | 10 | For anything that could potentially change checked-in top-level sim HTML or config files, the following should be done: 11 | 12 | - [ ] `perennial/bin/for-each.sh active-repos npm prune` 13 | - [ ] `perennial/bin/for-each.sh active-repos npm update` 14 | - [ ] `perennial/bin/for-each.sh active-repos grunt update` (or run `grunt update` in affected repos) 15 | - [ ] If possible, run local aqua 16 | testing (`/aqua/fuzz-lightyear/?ea&audio=disabled&testDuration=10000&testConcurrentBuilds=4&brand=phet&fuzz`) 17 | to make sure nothing broke horribly. 18 | - [ ] `git add` the relevant files, `git commit` (referencing the issue for the change) and `git push`. 19 | 20 | Note that for package.json changes that add flags, an automated process on bayes should update the perennial/data/ files 21 | automatically. 22 | -------------------------------------------------------------------------------- /github-dashboard/processCachedIssues.js: -------------------------------------------------------------------------------- 1 | // Copyright 2023, University of Colorado Boulder 2 | 3 | /** 4 | * Read the open issues cached to disk, and output the number of issues assigned to each user. 5 | * 6 | * @author Sam Reid (PhET Interactive Simulations) 7 | * @author Agustín Vallejo (PhET Interactive Simulations) 8 | */ 9 | 10 | const fs = require( 'fs' ); 11 | 12 | const repos = fs.readFileSync( './repos', 'utf8' ).split( '\n' ); 13 | const users = fs.readFileSync( './users', 'utf8' ).split( '\n' ); 14 | 15 | // Fetch the open issues assigned to users in the organization, organized by repository 16 | ( () => { 17 | 18 | users.forEach( user => { 19 | 20 | let sum = 0; 21 | // console.log( user); 22 | const map = {}; 23 | repos.forEach( repo => { 24 | 25 | const issues = JSON.parse( fs.readFileSync( `./repodir/${repo}`, 'utf8' ) ); 26 | const userIssues = issues.filter( issue => { 27 | return issue.assignees.filter( assignee => { 28 | return assignee.login === user; 29 | } ).length > 0; 30 | } ); 31 | 32 | if ( userIssues.length > 0 ) { 33 | map[ repo ] = userIssues.length; 34 | } 35 | 36 | sum += userIssues.length; 37 | 38 | } ); 39 | console.log( user, sum, JSON.stringify( map, null, 2 ) ); 40 | } ); 41 | } )(); -------------------------------------------------------------------------------- /intern-info/git_bash_tips.md: -------------------------------------------------------------------------------- 1 | More in here later, but for the moment.. 2 | 3 | Unix info tutorial http://www.ee.surrey.ac.uk/Teaching/Unix/ 4 | 5 | For windows users: 6 | when you install git bash in "Adjusting your PATH environment" choose "use GIt from the Windows Command Prompt" this 7 | should allow you to use Git from Git Bash 8 | 9 | make a .bashrc file in the top level directory (the directory in which your phetsims folder lives) something like c: 10 | \users\username To create the .bashrc file make it in notepad and do **Save as** ".bashrc" (you must use the quotes or 11 | notepad will append a .txt extension) 12 | Open git-bash and it will create a .bash_profile 13 | 14 | use the `$PATH` command to find the correct directory to insert the file assuming the folder for your files is " 15 | phetsims" the .bashrc file should look something like `PATH=${PATH}:${HOME}/phetsims/perennial/bin` 16 | this will allow chipper scripts (such as 'pull-all.sh') to be run from anywhere in git-bash 17 | 18 | For full capabilities need to install node.js in the chipper directory run `npm update` 19 | run `npm install -g grunt-cli` 20 | 21 | To get Git Bash to open in a certain directory right click on the icon in the start menu, and then right click on "Git 22 | Bash" and click "Properties" a dialog window will appear that allows you to change the "Start in" field 23 | -------------------------------------------------------------------------------- /typescript-conversion/test/snapshot-comparison-test.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | // @ts-nocheck 3 | const { test, expect } = require( '@playwright/test' ); 4 | 5 | test( 'snapshot comparison hash check', async ( { page } ) => { 6 | // Set up console listener before navigating 7 | const consolePromise = new Promise( ( resolve ) => { 8 | page.on( 'console', msg => { 9 | const text = msg.text(); 10 | // Look for the specific console log pattern 11 | if ( text.includes( 'Creating td for sim "states-of-matter"' ) && text.includes( 'hash=' ) ) { 12 | // Extract the short hash from the console log 13 | const hashMatch = text.match( /hash=([a-f0-9]+),/ ); 14 | if ( hashMatch ) { 15 | resolve( hashMatch[ 1 ] ); 16 | } 17 | } 18 | } ); 19 | } ); 20 | 21 | // Navigate to the snapshot comparison page 22 | await page.goto( 'http://localhost/aqua/html/snapshot-comparison.html?repos=states-of-matter&logHash' ); 23 | 24 | // Wait up to 5 seconds for the console log 25 | const hash = await Promise.race( [ 26 | consolePromise, 27 | new Promise( ( _, reject ) => setTimeout( () => reject( new Error( 'Timeout waiting for hash' ) ), 5000 ) ) 28 | ] ); 29 | 30 | // Check if the hash matches the expected values 31 | const validHashes = [ '210c3b' ]; 32 | expect( validHashes ).toContain( hash ); 33 | } ); -------------------------------------------------------------------------------- /.github/sync.yml: -------------------------------------------------------------------------------- 1 | scenerystack/community: 2 | - source: doc/phet-development-overview.md 3 | dest: docs/info-sync/simulation-development-overview.md 4 | - source: doc/phet-dev-exercises.md 5 | dest: docs/info-sync/scenerystack-exercises.md 6 | - source: deployment-info/chipper-2.0.md 7 | dest: docs/info-sync/chipper-deploy.md 8 | - source: doc/accessible-preferences-quickstart-guide.md 9 | dest: docs/info-sync/accessible-preferences-quickstart-guide.md 10 | - source: doc/alternative-input-quickstart-guide.md 11 | dest: docs/info-sync/alternative-input-quickstart-guide.md 12 | - source: doc/coding-conventions.md 13 | dest: docs/info-sync/coding-conventions.md 14 | - source: doc/dynamic-string-layout-quickstart.md 15 | dest: docs/info-sync/dynamic-string-layout-quickstart.md 16 | - source: doc/interactive-description-technical-guide.md 17 | dest: docs/info-sync/interactive-description-technical-guide.md 18 | - source: doc/interactive-highlights-quickstart-guide.md 19 | dest: docs/info-sync/interactive-highlights-quickstart-guide.md 20 | - source: doc/phet-software-design-patterns.md 21 | dest: docs/info-sync/phet-software-design-patterns.md 22 | - source: doc/coding-conventions.md 23 | dest: docs/info-sync/coding-conventions.md 24 | - source: doc/typescript-quick-start.md 25 | dest: docs/info-sync/typescript-quick-start.md 26 | -------------------------------------------------------------------------------- /checklists/new-student-worker-checklist.md: -------------------------------------------------------------------------------- 1 | # New Student Worker Checklist 2 | 3 | ## Admin 4 | 5 | - [ ] Complete Payroll forms (Personal data and Emergency contact), email to 6 | oliver.nix@colorado.edu [New Student Employee] (https://docs.google.com/document/d/1At37GOZ83luHGKOOQzjnJH2gu1E-sb-91OsdAmjYIIs/edit) 7 | - [ ] Enter/update W4 and Direct 8 | Deposit [New Student Employee] (https://docs.google.com/document/d/1At37GOZ83luHGKOOQzjnJH2gu1E-sb-91OsdAmjYIIs/edit) 9 | - [ ] Add contact info 10 | to [PhET Planning doc](https://docs.google.com/document/d/1hONYWo1R8gf24gaAd-5B1xmD_UrwbOG6BfB01WvrfiQ/edit) 11 | - [ ] Keys/card access if needed 12 | - [ ] Peripherals/computer if needed 13 | - [ ] Notify group, introduce (status meeting) 14 | 15 | ## Accounts 16 | 17 | - [ ] PhET gmail account (name.phet@gmail recommended) 18 | - [ ] Add to google group 19 | - [ ] Add to student employment calendar 20 | - [ ] Create github account 21 | - [ ] Github picture 22 | - [ ] Add to appropriate github team 23 | - [ ] Access to appropriate repos 24 | - [ ] Unfuddle account 25 | - [ ] Subscribe to phet@lists.colorado.edu 26 | - [(Instructions)](http://www.colorado.edu/oit/tutorial/email-list-manager-subscribe-list) 27 | - [ ] [Register](https://phet.colorado.edu/en/register?dest=%2F) for PhET website account 28 | - [ ] Grant admin access on website 29 | - [ ] Input job title (for About>People page) 30 | -------------------------------------------------------------------------------- /sim-info/README.md: -------------------------------------------------------------------------------- 1 | Sim Info 2 | ========= 3 | 4 | ## Responsible Lists 5 | 6 | [responsible_dev.json](./responsible_dev.json) is the central location for all responsible actors for a repo. Every repo 7 | should have a responsibleDev, someone in charge of maintaining the code/files inside that repo. This file should be 8 | maintained manually. 9 | 10 | [responsible_dev.md](./responsible_dev.md) is a generated markdown file of the json data. 11 | see [./generateMarkdownOutput.mjs](./generateMarkdownOutput.mjs) 12 | 13 | ------------------ 14 | 15 | To print out a list, by developer, of all repos a dev is responsible for: 16 | 17 | ```bash 18 | cd phet-info/../ 19 | sage run phet-info/sim-info/printReposPerDev.mjs 20 | ``` 21 | 22 | ---------------------- 23 | 24 | 25 | To test to make sure the list is in sync with github: 26 | 27 | 1. Make sure that you have appropriate credentials in your build local 28 | 2. Have perennial and phet-info checked out 29 | 3. Run: 30 | 31 | ```bash 32 | cd phet-info/../ 33 | node phet-info/sim-info/areAllReposInFile.js 34 | ``` 35 | 36 | With output that looks like: 37 | 38 | ``` 39 | must add faraday to responsible dev list 40 | must add seasons to responsible dev list 41 | must add skiffle to responsible dev list 42 | must add geometric-optics to responsible dev list 43 | must remove installer-builder from responsible dev list as it is not on github 44 | must remove phet-overview from responsible dev list as it is not on github 45 | ``` -------------------------------------------------------------------------------- /checklists/S2015R-checklist.md: -------------------------------------------------------------------------------- 1 | Checklist for S2015R milestone (GitHub issues labeled "Summer 2015 redeploy") 2 | 3 | **Developer** 4 | 5 | - [ ] Review outstanding issues, mark what will be addressed for redeploy (@ariel-phet and original developer). Then 6 | mark these issues with a milestone. 7 | - [ ] Look over the code review checklist, decide if code review should be 8 | redone, https://github.com/phetsims/phet-info/blob/main/checklists/code-review-checklist.md 9 | - [ ] Review and update licensing info (source code and images/audio) 10 | - [ ] Double check relevant entries in https://github.com/phetsims/sherpa/blob/main/third-party-licenses.md 11 | - [ ] Standardize the string keys, since they will be difficult to change later 12 | - [ ] Identify any strings in sims that should move to another repository, move them now 13 | - [ ] Publish RC version and test matrix 14 | - [ ] Address RC issues 15 | 16 | **QA** 17 | 18 | - [ ] stringTest=double 19 | - [ ] stringTest=long 20 | - [ ] stringTest=X (short strings) 21 | - [ ] stringTest=rtl (right-to-left) 22 | - [ ] stringTest=xss (should not redirect, OK to look bad, test on one desktop platform) 23 | - [ ] showPointerAreas (touchArea=red, mouseArea=blue) 24 | - [ ] Full screen test 25 | - [ ] Perform RC testing 26 | - [ ] Reference issues to RC test task 27 | 28 | **Design/Admin** 29 | 30 | - [ ] Rosetta test (Opening sim to trusted translators for beta) 31 | - [ ] Check teacher tips are up to date 32 | - [ ] Check sim primer is up to date 33 | -------------------------------------------------------------------------------- /github-labels/change-label.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # change-label.sh 4 | # 5 | # This script replaces the color and/or text of a github label for all repos 6 | 7 | if [[ $1 = '' ]] || [[ $2 = '' ]] || [[ $3 = '' ]] 8 | then 9 | echo "Usage: $0 old-label-name new-label-name new-color" 10 | exit 1 11 | else 12 | oldLabel=$1 13 | newLabel=$2 14 | newColor=$3 15 | new={\"new_name\":\"${newLabel}\",\"color\":\"${newColor}\"} 16 | fi 17 | 18 | binDir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" 19 | creds=`../../perennial/bin/sage run ${binDir}/printGithubAuthorization.js` 20 | ../../perennial/bin/sage run ./update-repos-list.js 21 | 22 | echo 'For each repo, this script should print "200 OK" to indicate success' 23 | echo 'If a 404 Not Found is printed, that repo is likely missing the standard label set.' 24 | echo 'If a 403 Forbidden is printed, that repo has probably been archived and this is correct. If you believe the repo should have been updated, check that your Github OAuth token is correct.' 25 | echo '' 26 | 27 | for repo in `cat .repos` 28 | do 29 | repo=`echo ${repo}` 30 | url=https://api.github.com/repos/phetsims/${repo}/labels/${oldLabel} 31 | echo "Path: ${url}" 32 | echo "Data: ${new}" 33 | echo "Result:" 34 | curl -isH 'User-Agent: "PhET"' -u "$creds" -d "$new" -X PATCH "$url" | head -n 1 35 | echo '' 36 | done 37 | 38 | sed s/${oldLabel}.*/${newLabel},${newColor}/ github-labels > .tmp && mv .tmp github-labels 39 | sort github-labels -o github-labels 40 | git pull && git commit github-labels -m "Changed github label from ${oldLabel} to ${new}" && git push 41 | 42 | echo "Complete." -------------------------------------------------------------------------------- /project-management/common-code-issue-template.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 9 | 10 | 11 | ## Expected Behavior 12 | 13 | 14 | 15 | 16 | ## Current Behavior 17 | 18 | 19 | 20 | 21 | ## Possible Solution 22 | 23 | 24 | 25 | 26 | ## Steps to Reproduce (for bugs) 27 | 28 | 29 | 30 | 31 | 1. 32 | 2. 33 | 3. 34 | 4. 35 | 36 | ## Context 37 | 38 | 39 | 40 | 41 | ## Your Environment (for bugs) 42 | 43 | 44 | 45 | * Version used: 46 | * Environment name and version (e.g. Chrome 39, node.js 5.4): 47 | * Operating System and version (desktop or mobile): 48 | * Link to your project: 49 | -------------------------------------------------------------------------------- /sim-info/areAllReposInFile.js: -------------------------------------------------------------------------------- 1 | // Copyright 2021, University of Colorado Boulder 2 | 3 | /** 4 | * Determine whether all PhET GitHub repos are represented in responsible_dev.json 5 | * 6 | * Usage: 7 | * cd root 8 | * sage run ./phet-info/sim-info/areAllReposInFile.js 9 | * 10 | * @author Michael Kauzmann (PhET Interactive Simulations) 11 | */ 12 | const getAllRepos = require( './getAllRepos' ); 13 | const fs = require( 'fs' ); 14 | 15 | ( async () => { 16 | 17 | // {Object.} - keys are repos 18 | const reposFromJSON = JSON.parse( fs.readFileSync( './phet-info/sim-info/responsible_dev.json', 'utf8' ) ); 19 | 20 | // {string[]} - repo names 21 | const reposInJSON = Object.keys( reposFromJSON ); 22 | 23 | // {string[]} - all repos on github 24 | const reposFromGithub = await getAllRepos(); 25 | 26 | let someDiscrepancy = false; 27 | 28 | for ( let i = 0; i < reposFromGithub.length; i++ ) { 29 | const repoInGithub = reposFromGithub[ i ]; 30 | if ( !reposFromJSON.hasOwnProperty( repoInGithub ) ) { 31 | console.log( `must add ${repoInGithub} to responsible dev list` ); 32 | someDiscrepancy = true; 33 | } 34 | } 35 | 36 | for ( let i = 0; i < reposInJSON.length; i++ ) { 37 | const repoInJSON = reposInJSON[ i ]; 38 | if ( !reposFromGithub.includes( repoInJSON ) ) { 39 | console.log( `must remove ${repoInJSON} from responsible dev list as it is not on github` ); 40 | someDiscrepancy = true; 41 | } 42 | } 43 | 44 | if ( !someDiscrepancy ) { 45 | console.log( 'No discrepancies found between responsible_dev.json and github.' ); 46 | } 47 | } )(); -------------------------------------------------------------------------------- /github-labels/update-repos-list.js: -------------------------------------------------------------------------------- 1 | // Copyright 2021, University of Colorado Boulder 2 | 3 | // update-repos-list.js 4 | // 5 | // This script creates a file in this directly called `.repos` that is 6 | // a newline separated list of all repos in the phetsims organization. 7 | // @author Matt Pennington (PhET Interactive Simulations) 8 | 9 | const axios = require( '../../perennial/node_modules/axios' ); 10 | const buildLocal = require( '../../perennial/js/common/buildLocal' ); 11 | const fs = require( 'fs' ); 12 | 13 | ( async () => { 14 | // temporarily store the old repos for troubleshooting if problems arise 15 | try { 16 | await fs.promises.rename( '.repos', '.repos.old' ); 17 | } 18 | catch( err ) { 19 | if ( err.code !== 'ENOENT' ) { 20 | console.error( err ); 21 | throw err; 22 | } 23 | } 24 | 25 | // Iterate over all repos in the organization 26 | let currentRepos; 27 | let repoNames = ''; 28 | let currentPage = 1; 29 | const pageSize = 100; 30 | do { 31 | currentRepos = ( await axios.get( `https://api.github.com/orgs/phetsims/repos?per_page=${pageSize}&page=${currentPage}&sort=full_name`, { 32 | auth: { 33 | username: buildLocal.developerGithubUsername, 34 | password: buildLocal.developerGithubAccessToken 35 | } 36 | } ) ).data; 37 | if ( currentRepos ) { 38 | const names = currentRepos.map( repo => repo.name.trim() ).filter( name => 39 | name !== 'community' 40 | ); 41 | repoNames += names.join( '\n' ) + '\n'; 42 | } 43 | currentPage++; 44 | } while ( currentRepos && currentRepos.length === pageSize ); 45 | 46 | // Save to disk 47 | await fs.promises.writeFile( '.repos', repoNames ); 48 | 49 | // Clean up 50 | await fs.promises.unlink( '.repos.old' ); 51 | } )(); -------------------------------------------------------------------------------- /sim-info/getAllRepos.js: -------------------------------------------------------------------------------- 1 | // Copyright 2021, University of Colorado Boulder 2 | 3 | /** 4 | * Get all repos in phetsims that are not archived, disabled, or forks. This probably won't work unless you have 5 | * admin privileges to read all repos. 6 | * 7 | * This is not intended to be run directly. It's used by areAllReposInFile.js. 8 | * 9 | * @author Michael Kauzmann (PhET Interactive Simulations) 10 | */ 11 | 12 | const buildLocal = require( '../../perennial/js/common/buildLocal' ); 13 | const https = require( 'https' ); 14 | 15 | const getSomeRepos = async pageNumber => { 16 | return new Promise( resolve => { 17 | 18 | const requestOptions = { 19 | host: 'api.github.com', 20 | path: `/orgs/phetsims/repos?per_page=100&page=${pageNumber}`, 21 | method: 'GET', 22 | auth: `${buildLocal.developerGithubUsername}:${buildLocal.developerGithubAccessToken}`, 23 | headers: { 24 | 'User-Agent': 'PhET' 25 | } 26 | }; 27 | 28 | const request = https.request( requestOptions, res => { 29 | 30 | let data = ''; 31 | res.on( 'data', d => { 32 | data += d.toString(); 33 | } ); 34 | 35 | res.on( 'end', () => { 36 | const repoData = JSON.parse( data.toString() ); 37 | resolve( repoData.filter( x => { 38 | return !x.archived && !x.disabled && !x.fork; // no repos that are archived, disabled, or actually just forks 39 | } ).map( x => x.name ) ); 40 | } ); 41 | } ); 42 | 43 | request.on( 'error', e => { throw e; } ); 44 | request.end(); 45 | } ); 46 | }; 47 | 48 | /** 49 | * @returns {Promise.} 50 | */ 51 | module.exports = async () => { 52 | let repos = []; 53 | 54 | for ( let i = 1; i < 5; i++ ) { 55 | repos = repos.concat( await getSomeRepos( i ) ); 56 | } 57 | return repos.sort(); 58 | }; -------------------------------------------------------------------------------- /ide/sublime-text/phet-plugin/README.md: -------------------------------------------------------------------------------- 1 | # PhET Sublime Package 2 | 3 | ## Usage 4 | 5 | This package can be used with sublime to add phet tasks to the command palette. To use these tools, you must know how to 6 | access the `command palette` (Command-shift-P on Mac, control-shift-P on Windows defaults). Open the command palette, 7 | then start typing something to auto-complete to a command name (starting with `phet` is useful). Once the command is 8 | highlighted, hit enter to run. 9 | 10 | You can open up the Sublime terminal (command/ctrl + \`) to see results from scripts that are run (things are written in 11 | Python) 12 | 13 | ## Commands 14 | 15 | ###PhET: Import 16 | 17 | This will attempt to import the text word that the cursor is over, either with an import or node.js require (depending 18 | on what type of file is detected), and then imports will be sorted. 19 | 20 | ###PhET: Sort Imports 21 | 22 | Sorts the import statements of the file. 23 | 24 | ### PhET: Document Function 25 | 26 | When over a function name in a class/other definition, it will stub out JSDoc comments in front with parameter/return 27 | value detection. 28 | 29 | ### PhET: Remove Unused Imports 30 | 31 | Searches each import to see if it's unused in the file (currently based on a substring search, so if it's commented it 32 | won't remove it currently). 33 | 34 | ### PhET: Clean 35 | 36 | Removes unused imports, and then sorts imports. 37 | 38 | ## Installing 39 | 40 | To add these to your copy of sublime, locate your Packages folder. `Preferences --> Browse Packages`. Then copy this 41 | folder the `phet-plugin` folder into the `Packages` directory. (On Windows the file path looks like: 42 | `C:\Users\{{USER}}\AppData\Roaming\Sublime Text 3\Packages\`, on Mac 43 | it's `~/Library/Application Support/Sublime Text 3/Packages/`). 44 | 45 | When these commands are added into the `Packages` folder in the Sublime installation directory, then they will also be 46 | added to the command palette, although a restart may be required. 47 | 48 | -------------------------------------------------------------------------------- /ide/sublime-text/eslint-and-sublime-text.md: -------------------------------------------------------------------------------- 1 | # Using eslint through the SublimeLinter plugin 2 | 3 | UPDATE: As of Nov 2024, these instructions are out of date. We have upgraded to ESLint 9 which uses the flat config, 4 | and have not tested Sublime support for ESLint since then. 5 | 6 | These steps were verified on Ubuntu 16.04 and Mac OS X 10.11 with Sublime Text 3, node 5.3.0 and eslint 2.9.0. Other 7 | setups and versions are also likely to work. 8 | 9 | - You should have node.js installed 10 | - You may already have the ST3 SublimeLinter package. If not, get it through Package Control in the usual way. 11 | - Install eslint system-wide: `sudo npm install -g eslint` 12 | - For Windows, enter in the git bash (MINGW64): `npm install -g eslint` 13 | - Make sure the eslint executable can be located by ST3 (in $PATH on OSX/Linux). 14 | - For Windows, make sure the directory of eslint.cmd is in your path: 15 | - Go to Control Panel > System and Security > System > Advanced system settings 16 | > Environment Variables > System variables > Path > Edit 17 | - Add a semicolon `;` at the end and your equivalent of `C:\Users\Andrea\AppData\Roaming\npm` 18 | - Install the eslint plugin (`SublimeLinter-eslint`) through Package control. 19 | - In ST3, open Preferences > Package Settings > SublimeLinter > Settings - User. Modify the arguments to include the 20 | PhET configuration and rules. For example (On Windows): 21 | 22 | ```json 23 | // SublimeLinter Settings - User 24 | { 25 | "linters": { 26 | "eslint": { 27 | "disable": false, 28 | "args": [ 29 | "--config", 30 | "${folder}\\chipper\\eslint\\.eslintrc.js", 31 | "--rulesdir", 32 | "${folder}\\chipper\\eslint\\rules\\" 33 | ], 34 | "executable": "${folder}\\chipper\\node_modules\\.bin\\eslint.cmd", 35 | "lint_mode": "background" 36 | } 37 | } 38 | } 39 | 40 | ``` 41 | 42 | Then, you can choose when you want it to run through Tools > SublimeLinter, (on load, save, perpetually in the 43 | background, etc.) Background mode is nice for real-time feedback. 44 | -------------------------------------------------------------------------------- /checklists/rename-repo-checklist.md: -------------------------------------------------------------------------------- 1 | # Rename Repo Checklist 2 | 3 | ## Steps for renaming a repo 4 | 5 | - [ ] Make sure all commits are pushed to that repo. 6 | - [ ] On Github.com, go to repo -> Settings -> Options -> "Repository name" and rename. 7 | - [ ] Rename in `perennial/data/active-repos` and any other perennial data files it occurs in, 8 | like `active-runnables`, `active-sims`, `phet-io`, etc. Push the change to perennial and then pull perennial-alias. 9 | - [ ] Clone the new repo by running `grunt sync`. 10 | - [ ] Update `package.json` accordingly. Including but not necessarily limited to: 11 | * `name` 12 | * `repository.url` 13 | * `phet.requirejsNamespace` 14 | - [ ] Change entry 15 | in [responsible_dev.json](https://github.com/phetsims/phet-info/blob/main/sim-info/responsible_dev.json). 16 | - [ ] If applicable, "Sync" on phettest. 17 | - [ ] Remove old repo directories in `chipper/dist/**/${oldRepo}` 18 | - [ ] Run `rm -rf {{OLD_REPO}}` from the phetsims directory 19 | - [ ] Notify Slack channel dev-public that the repo has been renamed. E.g. "I just renamed repository {{OLD_REPO}} to 20 | {{NEW_REPO}}. Please sync at your convenience, remove 21 | {{OLD_REPO}} references from `chipper/dist/` directories (such as `tsc/outdir/` and `eslint/cache/`), and restart your transpiler." 22 | 23 | ### If this is a simulation. . . 24 | 25 | - [ ] Rename many files: 26 | * `*en.json` string file 27 | * `main.js` file 28 | * Screens/Views/Models? 29 | * Namespace file 30 | - [ ] Make sure to update the title in the `*en.json` string file and update its usage in the main js file 31 | - [ ] Run `grunt modulify` 32 | - [ ] update usages of the Namespace file 33 | - [ ] Looks through all usages in the repo of the previous name to make sure issues links, comments and code are 34 | updated. This especially applies to imports for the namespace and strings. 35 | - [ ] Use `find` to search for files with the old repo name in generated files outside of the sim repo. For example, from your root directory: 36 | * `find . -name quantum-measurement* -print` 37 | - [ ] Search the entire codebase references to the old repo name. -------------------------------------------------------------------------------- /ide/sublime-text/phet-plugin/Main.sublime-menu: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "tools", 4 | "children": [ 5 | { 6 | "caption": "PhET", 7 | "children": [ 8 | { 9 | "caption": "Find", 10 | "children": [ 11 | { "caption": "Find", "command": "phet_find" }, 12 | { "caption": "Find Regex", "command": "phet_find_regex" }, 13 | { "caption": "Show Find", "command": "phet_show_find" }, 14 | { "caption": "Wipe Find", "command": "phet_wipe_find" }, 15 | { "caption": "Abort Find", "command": "phet_abort_find" } 16 | ] 17 | }, 18 | { 19 | "caption": "Code", 20 | "children": [ 21 | { "caption": "Import", "command": "phet_import" }, 22 | { "caption": "Sort Imports", "command": "phet_sort_imports" }, 23 | { "caption": "Document Function", "command": "phet_document_function" }, 24 | { "caption": "Remove Unused Imports", "command": "phet_remove_unused_imports" }, 25 | { "caption": "Clean", "command": "phet_clean" }, 26 | ] 27 | }, 28 | { 29 | "caption": "Navigation", 30 | "children": [ 31 | { "caption": "Open Phetmarks", "command": "phet_open_phetmarks" }, 32 | { "caption": "Open Issues", "command": "phet_open_issues" }, 33 | { "caption": "Open GitHub", "command": "phet_open_github" }, 34 | { "caption": "Open Sim", "command": "phet_open_sim" }, 35 | { "caption": "Open Built Sim", "command": "phet_open_built_sim" }, 36 | { "caption": "Go to repo", "command": "phet_go_to_repo" }, 37 | ] 38 | }, 39 | { "caption": "-" }, 40 | { "caption": "Grunt", "command": "phet_grunt" }, 41 | { "caption": "Update", "command": "phet_update" }, 42 | { "caption": "-" }, 43 | { "caption": "Lint", "command": "phet_lint" }, 44 | { "caption": "Lint Everything", "command": "phet_lint_everything" } 45 | ] 46 | } 47 | ] 48 | } 49 | ] 50 | -------------------------------------------------------------------------------- /ide/sublime-text/phet-plugin/phet.sublime-commands: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "caption": "PhET: Import", 4 | "command": "phet_import" 5 | }, 6 | { 7 | "caption": "PhET: Sort Imports", 8 | "command": "phet_sort_imports" 9 | }, 10 | { 11 | "caption": "PhET: Document Function", 12 | "command": "phet_document_function" 13 | }, 14 | { 15 | "caption": "PhET: Remove Unused Imports", 16 | "command": "phet_remove_unused_imports" 17 | }, 18 | { 19 | "caption": "PhET: Clean", 20 | "command": "phet_clean" 21 | }, 22 | 23 | { 24 | "caption": "PhET: Open Phetmarks", 25 | "command": "phet_open_phetmarks" 26 | }, 27 | { 28 | "caption": "PhET: Open Issues", 29 | "command": "phet_open_issues" 30 | }, 31 | { 32 | "caption": "PhET: Open GitHub", 33 | "command": "phet_open_github" 34 | }, 35 | { 36 | "caption": "PhET: Open Sim", 37 | "command": "phet_open_sim" 38 | }, 39 | { 40 | "caption": "PhET: Open Built Sim", 41 | "command": "phet_open_built_sim" 42 | }, 43 | { 44 | "caption": "PhET: Go to repo", 45 | "command": "phet_go_to_repo" 46 | }, 47 | 48 | { 49 | "caption": "PhET: Lint", 50 | "command": "phet_lint" 51 | }, 52 | { 53 | "caption": "PhET: Lint Everything", 54 | "command": "phet_lint_everything" 55 | }, 56 | { 57 | "caption": "PhET: Update", 58 | "command": "phet_update" 59 | }, 60 | { 61 | "caption": "PhET: Grunt", 62 | "command": "phet_grunt" 63 | }, 64 | 65 | { 66 | "caption": "PhET: Find", 67 | "command": "phet_find" 68 | }, 69 | { 70 | "caption": "PhET: Find Regex", 71 | "command": "phet_find_regex" 72 | }, 73 | { 74 | "caption": "PhET: Show Find", 75 | "command": "phet_show_find" 76 | }, 77 | { 78 | "caption": "PhET: Wipe Find", 79 | "command": "phet_wipe_find" 80 | }, 81 | { 82 | "caption": "PhET: Abort Find", 83 | "command": "phet_abort_find" 84 | }, 85 | 86 | { 87 | "caption": "PhET: Dev", 88 | "command": "phet_dev" 89 | } 90 | ] -------------------------------------------------------------------------------- /github-labels/github-labels: -------------------------------------------------------------------------------- 1 | a11y:wcag-a,34bfa3 2 | a11y:wcag-a,34bfa3 3 | a11y:wcag-a,34bfa3 4 | a11y:wcag-aa,2aa387 5 | beginner-friendly,FFB03D 6 | deprecated:meeting:developer,000000 7 | design:a11y,F488FA 8 | design:alt-input,a141ea 9 | design:artwork,d4c5f9 10 | design:description,ba60ff 11 | design:general,F6CCDA 12 | design:interviews,d4a0fb 13 | design:phet-io,1FFFFF 14 | design:polish,F6A4D5 15 | design:sound,601A35 16 | design:teaching-resources,F7B3DA 17 | design:voicing,841fd1 18 | dev:a11y,008080 19 | dev:alt-input,21f2eb 20 | dev:chip-away,2f4f4f 21 | dev:code-review,104E8B 22 | dev:description,59eff9 23 | dev:enhancement,0276FD 24 | dev:help-wanted,63D1F4 25 | dev:maintenance-release,1467ba 26 | dev:model,4876FF 27 | dev:phet-io,1FFFFF 28 | dev:sound,005C5F 29 | dev:typescript,0074c1 30 | dev:voicing,07f7db 31 | good-first-issue,7068FF 32 | help-wanted,FF709C 33 | meeting:a11y-team,000000 34 | meeting:design,000000 35 | meeting:phet-io,000000 36 | meeting:sonification,000000 37 | meeting:status,000000 38 | phet-io:breaking-api-change,B60205 39 | phet-io:collaboration,006B75 40 | phet-io:event-stream,bd5404 41 | phet-io:instance-proxies,FBCA04 42 | phet-io:migration,E59400 43 | phet-io:record-and-playback,0E8A16 44 | phet-io:save-and-load,BFDADC 45 | priority:1-top,FF007F 46 | priority:2-high,e11d21 47 | priority:3-medium,FFE600 48 | priority:4-low,c7def8 49 | priority:5-deferred,FFFAFA 50 | project:requires-kathy,0000FF 51 | project:sim-checklist,42426F 52 | status:blocks-publication,FF007F 53 | status:blocks-sim-publication,e11d21 54 | status:fixed-awaiting-deploy,006b75 55 | status:on-hold,F0FFF0 56 | status:ready-for-qa,00cc00 57 | status:ready-for-review,3E766D 58 | status:ready-to-cherry-pick,137556 59 | type:a11y-bug,FF0077 60 | type:automated-testing,FF00AA 61 | type:bug,FF00AA 62 | type:documentation,A17188 63 | type:duplicate,EEEED1 64 | type:emergent/choice,9C4A2A 65 | type:epic,4B0082 66 | type:i18n,B452CD 67 | type:legacy-bug,CD00CD 68 | type:licensing,4B0082 69 | type:misc,B87333 70 | type:multitouch,72587F 71 | type:open-source-ecosystem,71B1E1 72 | type:performance,8B1C62 73 | type:quarterly,735DA6 74 | type:question,EDCB62 75 | type:suggestion,ffd966 76 | type:user-feedback,EDE162 77 | type:wontfix,ffffff 78 | -------------------------------------------------------------------------------- /policies/Confidentiality-of-user-information.md: -------------------------------------------------------------------------------- 1 | # PhET Confidentiality Policy Regarding Access to PhET Website Account User Information 2 | 3 | ### User Information 4 | 5 | PhET takes the confidentiality of user information provided to the project extremely seriously. User information can be 6 | in the form of Personally Identifiable Information (PII) such as names, email addresses, physical addresses, and other 7 | information users might provide as part of registration for our website or communications with the project via email or 8 | other means. Both employees of PhET, and affiliates of the project (such as volunteer developers, or collaborators) may 9 | have access (knowingly or unknowingly) to user information. Such access includes but is not limited to an account with 10 | administrative privileges on our website, access to our social media accounts, access to our database, and access to 11 | official "phethelp@colorado.edu" email. 12 | 13 | ### Protecting User Information 14 | 15 | All employees and affiliates of the project, including volunteers, contractors, and collaborators with access to user 16 | personal information (PII) are expected to adhere to strict confidentiality requirements: 17 | 18 | - User information should never be shared with any unauthorized party 19 | - User information should never be made available in a public forum (such as github) 20 | - All reasonable precautions should be taken to prevent a breach of user information 21 | - In general, even for those with authorization, user information should only be accessed in cases requiring diagnostic, 22 | account service, correctional purposes, or as necessary to facilitate essential communication with a user 23 | - No user personal information should be shared with third-parties. Sharing/collaborating internally around user 24 | information should be conducted using PhET Files or PhET Research Sharepoint locations and the files must have the ' 25 | Block download' setting enabled (or accomplished using equivalent setting in Google Drive). 26 | 27 | ### Disciplinary Policy 28 | 29 | Failure to follow the confidentiality obligations outlined above will be considered grounds for termination for any 30 | employee or other party associated with the PhET project. 31 | -------------------------------------------------------------------------------- /ide/sublime-text/phet-plugin/phet-find-results.tmLanguage: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | name 5 | PhET Find Results 6 | 7 | 8 | 9 | patterns 10 | 11 | 12 | match 13 | ^([^ ]+) (\/[^ ]+):$ 14 | captures 15 | 16 | 1 17 | 18 | name 19 | constant.numeric.line-number.phet-find-results 20 | 21 | 2 22 | 23 | name 24 | entity.name.filename.phet-find-results 25 | 26 | 27 | 28 | 29 | match 30 | ^ (ERROR:) 31 | captures 32 | 33 | 1 34 | 35 | name 36 | constant.other.phet-find-results 37 | 38 | 39 | 40 | 41 | match 42 | ^ +([0-9]+) 43 | captures 44 | 45 | 1 46 | 47 | name 48 | constant.numeric.line-number.phet-find-results 49 | 50 | 51 | 52 | 53 | match 54 | ^ +([0-9]+): 55 | captures 56 | 57 | 1 58 | 59 | name 60 | constant.numeric.line-number.match.phet-find-results 61 | 62 | 63 | 64 | 65 | 66 | scopeName 67 | text.phet-find-results 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /ide/idea/performance.md: -------------------------------------------------------------------------------- 1 | # Optimize Performance for WebStorm and Intellij IDEA 2 | 3 | Jetbrains IDEs are quite "heavy" and have the habit of causing performance troubles on many computers. Here are some 4 | steps that can be taken to optimize the performance. 5 | 6 | * This guide proved helpful for @zepumph, and, though much is boiled into the below comments, it may be helpful for you! 7 | https://dev.to/adammcquiff/improve-the-performance-of-webstorm-and-other-jetbrains-ides-11bc 8 | * Disable any live templates that you aren't using. 9 | * Disable any plugins that you aren't using (most of the bundled ones aren't used by PhET developers). 10 | * Exclude any web browsers that you don't want support for opening HTML (in the top right corner while editing). 11 | * Add this line to `top menu > Help > Edit Custom Properties`: `editor.zero.latency.typing=true` 12 | * Make sure all library files are excluded, like `node_modules`. You may also want to exclude `sherpa/lib` and perhaps 13 | `babel`. @samreid has this pattern excluded: `Directories > Excluded files: build;node_modules;images;sounds` 14 | * Improving search performance: 15 | * Make sure that as many folders as possible are excluded (as is reasonable). See above. 16 | * Use a scope! In many cases, it is enough to just look in the `js/` folders of repos, so make a scope to look there. 17 | The pattern looks like `file:*/js//*`. 18 | * Optimizing VM options file: 19 | * Edit by opening `top menu > Help > Edit Custom VM Options` 20 | * zepumph's looks like: 21 | ``` 22 | -Xms1024m 23 | -Xmx2048m 24 | -XX:NewRatio=2 25 | -XX:ReservedCodeCacheSize=512m 26 | -XX:+UseConcMarkSweepGC 27 | -ea 28 | -Dsun.io.useCanonCaches=false 29 | -Djava.net.preferIPv4Stack=true 30 | -Djdk.http.auth.tunneling.disabledSchemes="" 31 | -XX:+HeapDumpOnOutOfMemoryError 32 | -XX:-OmitStackTraceInFastThrow 33 | ``` 34 | * the main memory related ones are explained 35 | in https://www.jetbrains.com/help/idea/tuning-the-ide.html#common-jvm-options 36 | * A complete documentation of JVM options can be found 37 | in https://docs.oracle.com/javase/8/docs/technotes/tools/windows/java.html 38 | 39 | ## Other Resources 40 | 41 | https://stackoverflow.com/questions/29388626/how-to-speed-up-webstorm contains all of the above tips and more, including 42 | specifics on which plugins to disable. 43 | -------------------------------------------------------------------------------- /checklists/delete-repo-checklist.md: -------------------------------------------------------------------------------- 1 | # Delete/Archive Repo Checklist 2 | 3 | ## Before using this checklist: 4 | 5 | Decide whether the repo is being (a) deleted (b) archived or (c) removed from active-repos. 6 | 7 | - A repo should be deleted if 8 | * it is clutter 9 | * it will never be used again 10 | * there is no valuable information in the GitHub issues 11 | * it is not referenced by any SHA in any published simulation 12 | - A repo should be archived if 13 | * we don't want to continue development on the repo, but it needs to stay for reference or because its SHAs are used. 14 | * We want a paper trail for issues/decisions/commits made in the repo. 15 | * you may also want to make it private, if it should not be used for reference by 3rd parties 16 | - A repo should be removed from active-repos if 17 | * We cannot maintain it at the moment, but we expect to bring it back into maintenance in the future. 18 | 19 | ## Do not remove repos that: 20 | 21 | - Are listed as dependencies of any published simulation. 22 | - Would prevent checking out old versions of sims (do not mess with the bisection). 23 | - Contain otherwise useful information that is linked to 24 | 25 | ## Deleting or Archiving Steps 26 | 27 | - [ ] Before deleting something, it should be approved for deletion at a dev meeting 28 | - [ ] If not confident about some of the above questions/advice, bring it to a dev meeting 29 | - [ ] Create a delete/archive repo github issue in special-ops. 30 | - [ ] Inform the dev team to delete their local copy (perhaps put a checklist of developers in the github issue) 31 | - [ ] If issues crop up they should be documented in the associated github issue for the dev responsible for deletion 32 | - [ ] The repo should be removed from active-repos, ideally a few minutes before archiving/deleting (so automated 33 | processes do not try to pull it) 34 | - [ ] In general, removing the repo should not break much, if empty rows in CT are a concern,restart CT 35 | - [ ] If archiving, update the repo's README.md file to indicate why it is archived 36 | - [ ] Remove from github labels tracker/tool in phet-info (see its README) 37 | - [ ] Remove from `responsible_dev.json`. 38 | 39 | We should explicitly state whether something needs to be done to delete the directory from aqua, build-server, and 40 | phettest, or whether these directories get automatically deleted, or just hang around forever with no consequences 41 | -------------------------------------------------------------------------------- /sim-info/generateMarkdownOutput.mjs: -------------------------------------------------------------------------------- 1 | // Copyright 2021, University of Colorado Boulder 2 | 3 | import fs from 'fs'; 4 | 5 | /** 6 | * List repos per developer 7 | * 8 | * Usage: 9 | * cd root 10 | * sage run phet-info/sim-info/generateMarkdownOutput.mjs 11 | * 12 | * @author Michael Kauzmann (PhET Interactive Simulations) 13 | */ 14 | const responsibleDevObject = JSON.parse( fs.readFileSync( './phet-info/sim-info/responsible_dev.json', 'utf8' ) ); 15 | 16 | const repos = Object.keys( responsibleDevObject ); 17 | let responsibleTableString = ` 18 | ## HTML5 Sim and Common Code Repos - Developer/Designer Responsibility List 19 | 20 | NOTE: This file is generated, do not edit directly. It is created from \`responsible_dev.json\`, see \`./generateMarkdownOutput.mjs\`. 21 | 22 | 23 | | Simulation | Developer | Designer | Features | 24 | | :---------- | :------------- | :------------- | :------------- | 25 | `; 26 | 27 | 28 | // look at the repo's package.json in phet.simFeatures and note selected features for the sim. 29 | const getFeatures = repo => { 30 | const features = []; 31 | try { 32 | const packageJSON = JSON.parse( fs.readFileSync( `./${repo}/package.json` ).toString() ); 33 | if ( packageJSON.phet && packageJSON.phet.simFeatures ) { 34 | if ( packageJSON.phet.simFeatures.supportsSound ) { 35 | features.push( 'Sound' ); 36 | } 37 | if ( packageJSON.phet.simFeatures.supportsInteractiveDescription ) { 38 | features.push( 'Interactive Description' ); 39 | } 40 | if ( packageJSON.phet.simFeatures.supportsVoicing ) { 41 | features.push( 'Voicing' ); 42 | } 43 | if ( packageJSON.phet.simFeatures.supportsInteractiveHighlights ) { 44 | features.push( 'Interactive Highlights' ); 45 | } 46 | } 47 | } 48 | catch( e ) { 49 | 50 | // some repos don't have package.json, and that's okay. 51 | } 52 | return features; 53 | }; 54 | 55 | repos.forEach( repoName => { 56 | const responsibleDeveloper = responsibleDevObject[ repoName ].responsibleDevs.join( ',' ); 57 | const responsibleDesigner = responsibleDevObject[ repoName ].responsibleDesigners.join( ',' ); 58 | const features = getFeatures( repoName ).join( '
' ); 59 | responsibleTableString += `| ${repoName} | ${responsibleDeveloper} | ${responsibleDesigner} | ${features} | \n`; 60 | } ); 61 | 62 | fs.writeFileSync( './phet-info/sim-info/responsible_dev.md', responsibleTableString ); -------------------------------------------------------------------------------- /issue-info/github-issue-philosphy.md: -------------------------------------------------------------------------------- 1 | GitHub Issue Philosophy 2 | ======================= 3 | 4 | We discovered we have different philosophies for GitHub issues. For example, some of us disagree on what being assigned 5 | to a GitHub issue entails. We hope having a shared philosophy for GitHub issues will help us prioritize them going 6 | forward. 7 | 8 | Contents 9 | -------- 10 | 11 | - [Assignment](#assignment) 12 | - [Definition](#definition) 13 | - [Assigners](#assigners) 14 | - [Assignees](#assignees) 15 | - [Removing Assignment](#removing-assignment) 16 | - [Labels](#labels) 17 | 18 | Assignment 19 | ---------- 20 | 21 | ### Definition 22 | 23 | Being assigned to an issue means you are actively working on an issue or have plans to work on the issue within the next 24 | week or so. 25 | 26 | ### Assigners 27 | 28 | Assign the developer(s) responsible for the repo in which you are creating the issue. 29 | See [the responsible developer document](https://github.com/phetsims/phet-info/blob/main/sim-info/responsible_dev.md) 30 | for who to assign. 31 | 32 | ### Assignees 33 | 34 | When you are assigned to an issue, it's your responsibility to add appropriate labels, and decide whether to work on it 35 | now or later. It is also your responsibility to ensure the title accurately describes the issue. 36 | 37 | If you will work on it now, keep your assignment. Post updates when you make progress or have useful information. 38 | 39 | If you will work on it later, provide as much context and useful information as you can for your future self or the 40 | developer who ends up working on the issue. Then remove your assignment. 41 | 42 | ### Removing Assignment 43 | 44 | If you can't work on an issue within the next week or so, it shouldn't be assigned to you. Provide as much context and 45 | useful information as you can for your future self or the developer who ends up working on the issue. Optionally add the 46 | issue to a backlog issue or meta issue where you track issues you might eventually want to work on. Finally, remove your 47 | assignment. 48 | 49 | Labels 50 | ------ 51 | 52 | - Only use a label if your issue meets the definition for that label. 53 | - If a label doesn't have a definition, and you want to use that label, please create a definition for that label. 54 | - If you need to create a new label, you can only do so if you provide a definition for the new label. 55 | 56 | To see labels and their definitions in a GitHub repository, go to: 57 | 58 | ``` 59 | https://github.com/phetsims//labels 60 | ``` 61 | -------------------------------------------------------------------------------- /project-management/reportEpicIssuesNotInSpreadsheet.js: -------------------------------------------------------------------------------- 1 | // Copyright 2021, University of Colorado Boulder 2 | 3 | /** 4 | * This script is used to compare epic labelled issues with those on the spreadsheet. 5 | * Usage: 6 | * 7 | * Step 1: get the list of hyperlinked issues in the PhET Project Overview Spreadsheet (PPOS) 8 | * - Go to the spreadsheet (https://docs.google.com/spreadsheets/d/133PIbF9fyA5QYVwCdEkGiMmt0vrQxq1qMCk_zzwkPEI/) 9 | * - Menu -> Tools -> Script Editor 10 | * - Go to "getAllLinks.gs" and press "run", it will likely require you to give permission to the script to access the spreadsheet 11 | * - Copy the output of the single "Info" console output: a list of URLs linked in the sim 12 | * 13 | * Step 2: run this script: 14 | * - Paste the list of URLs as the value below of "linksInSpreadsheet" 15 | * - Make sure you have the appropriate github credentials in your buildLocal.json file. 16 | * - Run this file with `sage run` on the command line, it will print out the github issues that are labelled with epic but 17 | * not in the spreadsheet. 18 | * 19 | * 20 | * @author Michael Kauzmann (PhET Interactive Simulations) 21 | */ 22 | 23 | const _ = require( '../../perennial/node_modules/lodash' ); 24 | const buildLocal = require( '../../perennial/js/common/buildLocal' ); 25 | const https = require( 'https' ); 26 | 27 | const linksInSpreadsheet = []; 28 | 29 | function compareIssues( fromSpreadSheet, fromGithub ) { 30 | console.log( _.difference( fromGithub, fromSpreadSheet ) ); 31 | } 32 | 33 | // NOTE: This only loads 100 epic issues. 34 | 35 | const requestOptions = { 36 | host: 'api.github.com', 37 | path: '/search/issues?q=is%3Aopen+is%3Aissue+user%3Aphetsims+label%3Atype%3Aepic&per_page=100&page=1', 38 | method: 'GET', 39 | auth: `${buildLocal.developerGithubUsername}:${buildLocal.developerGithubAccessToken}`, 40 | headers: { 41 | 'User-Agent': 'PhET' 42 | } 43 | }; 44 | 45 | const request = https.request( requestOptions, res => { 46 | 47 | let data = ''; 48 | res.on( 'data', d => { 49 | data += d.toString(); 50 | } ); 51 | 52 | res.on( 'end', () => { 53 | const issueData = JSON.parse( data.toString() ); 54 | if ( issueData.total_count > 100 ) { 55 | console.error( 'more issues than this is set up to track, talk to zepumph' ); 56 | } 57 | 58 | const issueURLs = issueData.items.map( issue => issue.html_url ); 59 | 60 | compareIssues( linksInSpreadsheet, issueURLs ); 61 | } ); 62 | } ); 63 | 64 | request.on( 'error', e => { 65 | throw e; 66 | } ); 67 | 68 | request.end(); -------------------------------------------------------------------------------- /checklists/employee-leaving-checklist.md: -------------------------------------------------------------------------------- 1 | # Employee/Affiliate Leaving Checklist 2 | 3 | ## Responsibilities of Departing Employee 4 | 5 | - [ ] Submit your letter of resignation to supervisor. 6 | - [ ] Ensure your address is up to date in myCUinfo. This ensures you will receive your W-2 in a timely manner. 7 | - [ ] Inform committees/team you are working on of your resignation. 8 | - [ ] Submit final my.leave timesheet as soon as possible (once your last day is finalized) 9 | 10 | ### Turn in all university property to Physics department or PhET: 11 | 12 | - [ ] Door Keys. If needed, can be mailed to: 13 | ``` 14 | Facilities Management Access Services 15 | University of Colorado Boulder 16 | UCB 53 17 | Boulder, CO 80309 18 | ``` 19 | - [ ] Buff OneCard 20 | - [ ] A-Card or US Bank Cards 21 | - [ ] Library materials 22 | - [ ] Departmental property such as computers, and related peripherals (monitors, keyboards) 23 | - [ ] Petty cash 24 | - [ ] Parking permits and gate cards 25 | 26 | ### Files and access: 27 | 28 | - [ ] Pass on any necessary external account administration/credential information. 29 | - [ ] Ensure PhET digital files are stored in 'PhET Files'. 30 | 31 | ## Internal (PhET) Administrative Responsibilities 32 | 33 | - [ ] Exit Interview if appropriate 34 | - [ ] Buff One card, Eco-Pass returned via campus mail to 159 UCB or in person at the Campus Card Office located at 35 | Center for Community (C4C), Room N180, 159 UCB 36 | - [ ] Send copy of final leave balance sheet to HR 565UCB 37 | - [ ] (if applicable) Cancel PSC cards (procurement/travel card) 38 | - [ ] Final payment submitted 39 | - [ ] Pay up to max of vacation at separation, VCT for resignation. Prorated leave accruals until last day worked and 40 | pay out vacation. 'CUES_HCM_LEAVE_ACCRUAL_SUM' - Leave Accrual Summary, departing employee signs, attached to VCT 41 | transaction. 42 | - [ ] Termination in HCM. Termination effective date in HCM is the following day after last day worked. 43 | 44 | ### Accounts 45 | 46 | - [ ] Remove from PhET google group 47 | - [ ] Remove from PhET Sharepoint Employee and Affiliate Group 48 | - [ ] Remove from [PhET Meetings 2.0 Outlook group](https://outlook.office.com/groups/home) 49 | - [ ] Remove GitHub access 50 | - [ ] Remove from Slack 51 | - [ ] Contact oithelp@colorado.edu for assistance with ensuring your employee’s IT access is disabled appropriately. 52 | - [ ] (if applicable) Remove unfuddle access 53 | - [ ] (if applicable) Cancel A-Card or US Bank Cards 54 | - [ ] Remove admin access on website 55 | - [ ] Remove from About>Team Page 56 | -------------------------------------------------------------------------------- /policies/team assignment.md: -------------------------------------------------------------------------------- 1 | Repo access should be managed by adding Teams, not individuals. 2 | 3 | _NOTE: 4 | The 'phet-dev' machine user is a member of APPS_DEV, BROWSER_SIDE_COMMON_CODE, PhET-iO, SERVER_CODE, SIMS_DEV, and 5 | WEBSITE_DEV teams. It is REQUIRED to add the Teams and Roles below to all new repos so that the 'phet-dev' machine user 6 | can properly clone/pull the repo for automated processes)._ 7 | 8 |

New sim repo

9 | 10 | | Team | Role | 11 | |-------------------|------------| 12 | | FULL_ACCESS_DEV | Admin | 13 | | Quality Assurance | Triage | 14 | | SIMS_DESIGN | PhET Write | 15 | | SIMS_DEV | PhET Write | 16 | | Development | Triage | 17 | | Design | Triage | 18 | 19 |

New PhET-iO repo

20 | 21 | | Team | Role | 22 | |-------------------|------------| 23 | | FULL_ACCESS_DEV | Admin | 24 | | Quality Assurance | Triage | 25 | | PhET-iO | PhET Write | 26 | | Development | Triage | 27 | | Design | Triage | 28 | 29 |

New browser-side common code repo

30 | 31 | | Team | Role | 32 | |--------------------------|------------| 33 | | FULL_ACCESS_DEV | Admin | 34 | | Quality Assurance | Triage | 35 | | BROWSER_SIDE_COMMON_CODE | PhET Write | 36 | | Development | Triage | 37 | | Design | Triage | 38 | 39 |

New server repo

40 | 41 | | Team | Role | 42 | |-------------------|------------| 43 | | FULL_ACCESS_DEV | Admin | 44 | | Quality Assurance | Triage | 45 | | SERVER_CODE | PhET Write | 46 | | Development | Triage | 47 | | Design | Triage | 48 | 49 |

New website repo

50 | 51 | | Team | Role | 52 | |-------------------|------------| 53 | | FULL_ACCESS_DEV | Admin | 54 | | Quality Assurance | Triage | 55 | | WEB_DESIGN | PhET Write | 56 | | WEBSITE_DEV | PhET Write | 57 | | Development | Triage | 58 | | Design | Triage | 59 | 60 |

New app repo

61 | 62 | | Team | Role | 63 | |-------------------|------------| 64 | | FULL_ACCESS_DEV | Admin | 65 | | Quality Assurance | Triage | 66 | | APPS_DESIGN | PhET Write | 67 | | APPS_DEV | PhET Write | 68 | | Development | Triage | 69 | | Design | Triage | 70 | 71 |

Existing Repositories

72 | 73 | For a list of repos assigned to each team, see https://github.com/orgs/phetsims/teams/development/teams 74 | -------------------------------------------------------------------------------- /issue-info/useful_searches.md: -------------------------------------------------------------------------------- 1 | ## Examples of Useful Github Issue Searches 2 | 3 | ##### Tips for issue searches 4 | 5 | - pressing ("g + d") and then ("g" + "i") brings you to the issues view 6 | - useful searches can be saved as a url 7 | - Ex., 8 | opened [developer meeting issues](https://github.com/issues?utf8=%E2%9C%93&q=is%3Aissue+label%3Ameeting%3Adeveloper+user%3Aphetsims+sort%3Acreated-asc+is%3Aopen+) 9 | 10 | #### All PhET repos, opened issues for assignee 11 | 12 | ##### In issues search bar 13 | 14 | - is:issue user:phetsims is:open assignee:username sort:created-desc 15 | - example is:issue user:phetsims is:open assignee:ariel-phet sort:created-desc 16 | - the sort here is in order created (newest first) 17 | 18 | #### All PhET repos, opened issues by label 19 | 20 | ##### In issues search bar 21 | 22 | - is:issue label:label-name user:phetsims sort:created-asc is:open 23 | - example is:issue label:developer-meeting user:phetsims sort:created-asc is:open 24 | - the sort here is in alphabetical order 25 | 26 | #### Useful searches 27 | 28 | - [marked for developer meeting](https://github.com/issues?utf8=%E2%9C%93&q=is%3Aissue+label%3Ameeting%3Adeveloper+user%3Aphetsims+sort%3Acreated-asc+is%3Aopen+) 29 | - [marked for status meeting](https://github.com/issues?utf8=%E2%9C%93&q=is%3Aissue+label%3Ameeting%3Astatus+user%3Aphetsims+sort%3Acreated-asc+is%3Aopen+) 30 | - [marked for phet-io meeting](https://github.com/issues?utf8=%E2%9C%93&q=is%3Aissue+label%3Ameeting%3Aphet-io+user%3Aphetsims+sort%3Acreated-asc+is%3Aopen+) 31 | - [open main-checklists](https://github.com/issues?utf8=%E2%9C%93&q=is%3Aissue+label%3Aproject%3Amain-checklist+user%3Aphetsims+sort%3Acreated-asc+is%3Aopen+) 32 | - [open high-priority issues](https://github.com/issues?utf8=%E2%9C%93&q=is%3Aissue+label%3Apriority%3A2-high+user%3Aphetsims+sort%3Acreated-asc+is%3Aopen+) 33 | - [open unassigned high-priority issues](https://github.com/issues?utf8=%E2%9C%93&q=is%3Aissue+user%3Aphetsims+no%3Aassignee+is%3Aopen+label%3Apriority%3A2-high) 34 | - [open phet-io issues](https://github.com/issues?utf8=%E2%9C%93&q=is%3Aissue+label%3Adev%3Aphet-io+user%3Aphetsims+sort%3Acreated-asc+is%3Aopen+) 35 | - [open a11y issues](https://github.com/issues?utf8=%E2%9C%93&q=is%3Aissue+label%3Adev%3Aa11y+user%3Aphetsims+sort%3Acreated-asc+is%3Aopen+) 36 | - [open high priority a11y issues](https://github.com/issues?utf8=%E2%9C%93&q=is%3Aissue+label%3Adev%3Aa11y+label%3Apriority%3A2-high+user%3Aphetsims+sort%3Acreated-asc+is%3Aopen+) 37 | - [open help-wanted issues](https://github.com/issues?utf8=%E2%9C%93&q=is%3Aissue+label%3Adev%3Ahelp-wanted+user%3Aphetsims+sort%3Acreated-asc+is%3Aopen+) 38 | -------------------------------------------------------------------------------- /checklists/postmortem-process.md: -------------------------------------------------------------------------------- 1 | # {SIM_TITLE} postmortem 2 | 3 | - [ ] **1. Schedule the meeting** 4 | - Invite the entire sim team to participate, and optionally anyone else who had a significant involvement. Have the 5 | meeting as soon as possible after the sim is released, so that experiences are still fresh in everyone's mind. Allow 6 | sufficient time for the meeting, 1.5-2 hours. 7 | 8 | - [ ] **2. Enlist a meeting moderator** 9 | - The moderator's job is to make sure the meeting runs efficiently, stays on point, and focuses on constructive (but not 10 | overly negative) criticism. The moderator can be someone not on the sim team, or in many cases the Development 11 | Coordinator. The moderator also documents the important points of the meeting. 12 | 13 | - [ ] **3. Create github postmortem issue and postmortem google doc** 14 | - Create a GitHub issue in the repository of the sim for which the postmortem is occurring. This checklist will should 15 | be copied into the issue. 16 | - Create a postmortem Google doc for the sim and set phethelp as the owner. This Google doc should live within the 17 | appropriate sim folder on Google drive. 18 | 19 | - [ ] **4. Two successes and two improvements** 20 | - Participants will bring a list of no more than 2 items that were done well during the project, and no more than 2 21 | items that could be improved upon. Limiting to 2 requires people to think critically about their experience. 22 | - Consider reflecting on processes, accessibility, novel design components/interactions, and surprises. 23 | 24 | - [ ] **5. Identifying the top five** 25 | - At the meeting, start by having each person present their items (successes, then improvements). Make a list of these 26 | items, and note duplicates. Based on popularity, identify the top 5 success items and the top 5 items that need 27 | improvement. 28 | 29 | * Discuss the 5 success items first. Identify specific things that can be applied to future sims. Celebrate, pat each 30 | other on the back. Then move on to the harder part. 31 | * Discuss the 5 improvement items. Try to avoid getting personal. Discuss what was learned, and identify specific things 32 | that can be done to prevent these problems in the future. If anything needs more investigation, assign to specific 33 | individuals. 34 | 35 | - [ ] **6. Action items** 36 | - Note important items in the postmortem GitHub issue, and create issues for any tasks the require action, such as 37 | updating documents, leftover TODOs, etc. 38 | - Action Item Questions: 39 | - Suggest updates to project process at next retrospective? 40 | - Modifications to sim checklist? 41 | - Messages to share at status? 42 | -------------------------------------------------------------------------------- /doc/axe-devtools-guide.md: -------------------------------------------------------------------------------- 1 | # axe DevTools Guide 2 | @author Jesse Greenberg 3 | 4 | Quick reference for using **axe DevTools** to find accessibility issues in a PhET simulation. 5 | 6 | axe DevTools is a free browser plugin that automatically scans for common accessibility problems. 7 | 8 | ## Installation 9 | 1. Install [axe DevTools](https://chromewebstore.google.com/detail/axe-devtools-web-accessib/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US) for Chrome or Firefox. 10 | 2. Open **DevTools** in the browser (`F12` or `Cmd+Opt+I` / `Ctrl+Shift+I`). 11 | 3. Select the **axe DevTools** tab. 12 | 13 | ⚠️ There is a bug in the tool where the icon can be invisible. You should be able to find it in the top tabs in your development tools. 14 | ![Tool Location](./images/axe-DevTools-location.png) 15 | 16 | ## Using axe DevTools 17 | 1. Navigate to the simulation in your browser. 18 | 2. Open **axe DevTools** in browser development tools. 19 | 3. Click **"Full Page Scan:"** to scan the current visible content. 20 | 4. Review issues in the results panel. 21 | 22 | ## Procedure for Testing PhET Simulations 23 | ⚠️ axe ignores invisible elements. It only reports on what’s visible when you run the scan. 24 | 25 | To get good coverage: 26 | - Run a scan on each **screen** in its **default startup state**. 27 | - Run scans in a few **common states** of the sim. 28 | - Scan **dialogs/pop-ups** with lots of UI elements. 29 | - Run a few scans with `?fuzz` to catch state-specific issues. 30 | 31 | Most issues are in **common code libraries**. 32 | - If you can identify the source, open an issue in the correct repo. 33 | - If not, file in `scenery` and assign to `@jessegreenberg` for triage. 34 | 35 | ## Scope of Testing 36 | - Run axe DevTools only against the **standalone simulation build**. Don’t test in Studio, wrappers, or other embed contexts because they add markup that hides true sim issues and produces noise we can’t act on. 37 | - Skip axe DevTools when the **Voicing feature** is enabled. Voicing manipulates the DOM in ways that we expect to be incompatible with axe DevTools, so the results are unreliable. 38 | 39 | ## Acceptable Problems 40 | Some axe issues are expected and **can be ignored** for now: 41 | - “Zooming and scaling must not be disabled” 42 | - Other known global issues (to be listed as we encounter them) 43 | 44 | ## Example Results 45 | Below is a sample results panel from *Molecules and Light 1.5.28*. 46 | 47 | ![Molecules and Light axe results](./images/axe-DevTools-results.png) 48 | 49 | **Critical issues flagged**: 50 | - Elements must only use supported ARIA attributes 51 | - `
  • ` elements must be contained in a `
      ` or `
        ` 52 | 53 | The **zooming/scaling** warning is acceptable. 54 | -------------------------------------------------------------------------------- /doc/string-key-conventions.md: -------------------------------------------------------------------------------- 1 | # Conventions for naming string keys 2 | 3 | This document described the naming conventions for string keys that appear in translated string files. It is important 4 | to get these right before publication because keys are difficult to change after a sim has been published, and they 5 | appear in the PhET-iO API (and Studio) as the phetioIDs for StringProperties. 6 | _If you're unsure about these conventions, ask another PhET developer._ 7 | 8 | Guidelines: 9 | 10 | (1) Strings keys should generally match their values. E.g.: 11 | 12 | ```json 13 | "gravityForce": { 14 | "value": "Gravity Force" 15 | }, 16 | "quadraticTerms": { 17 | "value": "Quadratic Terms" 18 | } 19 | ``` 20 | 21 | (2) String keys for screen names should have the general form `"screen.{{screenName}}"`. E.g.: 22 | 23 | ```json 24 | "screen.explore": { 25 | "value": "Explore" 26 | }, 27 | ``` 28 | 29 | (3) If a string key would be exceptionally long, use a key name that is an abbreviated form of the string value, or that 30 | captures the purpose/essence of the value. E.g.: 31 | 32 | ```js 33 | // key is abbreviated 34 | "iWentToTheStore": { 35 | "value": "I went to the store to get milk, eggs, butter, and sugar." 36 | }, 37 | 38 | // key is based on purpose 39 | "describeTheScreen": { 40 | "value": "The Play Area is a small room. The Control Panel has buttons, a checkbox, and radio buttons to change conditions in the room." 41 | } 42 | ``` 43 | 44 | (4) If string keys would collide, use your judgment to disambiguate them. E.g.: 45 | 46 | ```json 47 | "simplifyTitle": { 48 | "value": "Simplify!" 49 | }, 50 | "simplifyCheckbox": { 51 | "value": "simplify" 52 | } 53 | ``` 54 | 55 | (5) String patterns that contain placeholders should use keys that are unlikely to conflict with strings that might be 56 | needed in the future. For example, for value `"The price is {{dollars}}"` consider using key `"pricePattern"` 57 | or `"thePriceIsDollars"` 58 | instead of `"price"`, if you think there might be a future need for a `"Price"` string value. 59 | 60 | (6) It is acceptable to group related strings with a prefix, for example: 61 | 62 | ```json 63 | "material.brick": { 64 | "value": "Brick" 65 | }, 66 | "material.metal": { 67 | "value": "Metal" 68 | }, 69 | "material.plastic": { 70 | "value": "Plastic" 71 | }, 72 | "material.wood": { 73 | "value": "Wood" 74 | }, 75 | ``` 76 | 77 | Note that nested substructure is not yet fully supported for string keys. 78 | 79 | (7) For strings that begin with a number, the string key should also begin with a number. For example: 80 | 81 | ```json 82 | "3DHeight": { 83 | "value": "3D Height" 84 | }, 85 | ``` 86 | -------------------------------------------------------------------------------- /policies/availability.md: -------------------------------------------------------------------------------- 1 | ### Known time off (2+ days or more) 2 | 3 | 1. For time off known in advance that is more than a single day, such time off should be included in status reports in 4 | advance so the team can plan for absence. 5 | 2. This time off should also be marked as "Out of Office" or "Busy" on your [Colorado Exchange Calendar](https://outlook.office.com/calendar/view/week) as far in advance 6 | as possible. 7 | 3. For large amounts of time (bigger vacations), an email is also often helpful (for instance to let people know if you 8 | will be completely out of touch, if you want messages marked URGENT, etc). 9 | 10 | ### Known time off (1/2 day to full day) 11 | 12 | 1. For single day time off, best to also include in status reports. 13 | 2. This time off should also be marked as "Out of Office" or "Busy" on your [Colorado Exchange Calendar](https://outlook.office.com/calendar/view/week) as far in advance 14 | as possible. 15 | 3. An email does not necessarily need to be sent to the group, but decline the meeting invitation so others know you 16 | will not be attending. 17 | 18 | ### Unexpected time off (sick day for instance) 19 | 20 | 1. Sick days, since they usually happen unexpectedly, best to decline a meeting invitation if your presence is expected 21 | for something (like Thursday meetings). A slack message/status change is also reasonable communication 22 | 2. Sick time must also be marked on your my.leave calendar. 23 | 24 | ### Small unavailability (2'ish hours, long lunch, kid duties, errand, etc) 25 | 26 | 1. Best communicated by changing slack status 27 | 2. It is nice if this time is marked as "Out of Office" or "Busy" on your [Colorado Exchange Calendar](https://outlook.office.com/calendar/view/week) (so that others don't 28 | inadvertently schedule meetings with you) 29 | 3. Again if expected to be in a meeting or such, decline the meeting invitation so others know you will not be 30 | attending. 31 | 32 | ### Slack status hints/recommendations 33 | 34 | We are going to try to use slack status more to communicate availability, since most of us are on Slack these days. 35 | 36 | - `/away` toggles the green dot associated with username to turn off 37 | - `/active` toggles the green dot associated with your username to turn on 38 | - `/status [:your_new_status_emoji:] [your new status message]` allows you to set a custom status message 39 | - In the desktop apps, you’ll appear active whenever Slack is open and you're interacting with your computer. After 30 40 | minutes of inactivity, Slack will automatically change your status to away 41 | - The "Workspace Directory" allows you to see everyone's status in a single view 42 | 43 | ### CU Leave Policies 44 | 45 | Sick: https://www.colorado.edu/hr/leave#sick-89 46 | 47 | Vacation: https://www.colorado.edu/hr/leave#vacation_annual-89 48 | -------------------------------------------------------------------------------- /typescript-conversion/conversion-checklist.md: -------------------------------------------------------------------------------- 1 | For https://github.com/phetsims/chipper/issues/1616, we would like to convert the sim to TypeScript. 2 | 3 | - [ ] Identify what brands and feature sets are supported. Is it a phet-io sim? Does it have a stable API? 4 | - [ ] Publish dev version before. Use `grunt dev --brands={{brands}} --message="before TypeScript conversion, see {{issue number URL}}"` option in grunt build to connect to the conversion issue. 5 | - [ ] Create a branch 6 | - [ ] Create a harness that will test for snapshot-comparison regressions. Record the URL and SHAs. Set up to run in `npm test`: 7 | - [ ] Copy the test/ folder as well as playwright.config.js to the repo. Make sure to use the correct sim name in the test script. 8 | - [ ] Add this to the package.json 9 | ``` 10 | "devDependencies": { 11 | "grunt": , 12 | "@playwright/test": "^1.40.0" 13 | }, 14 | "scripts": { 15 | "test": "playwright test && grunt type-check && grunt lint" 16 | }, 17 | ``` 18 | - Continuation of test harness: 19 | - [ ] Do the necessary npm installations for playwright. 20 | - [ ] Run `npm test`, it will fail, but then get the correct testing hash and put it at the end of the testing script where it says `const validHashes = [ '12adf4' ];` 21 | - [ ] Run `npm test` a couple of times, to make sure the new hash is correct and consistent (no random layout changes from the sim) 22 | - [ ] Use [typescript-quick-start.md](https://github.com/phetsims/phet-info/blob/cdee426ece5ea24fff45d92194ce9638b8cf1bb0/doc/typescript-quick-start.md) to familiarize yourself with the typescript conversion process. 23 | - [ ] Rename all files as a batch and commit *just the renames*, see https://github.com/phetsims/balancing-act/issues/168#issuecomment-3146720372 (You can use `rename-js-to-ts.sh`) 24 | - [ ] Add `// @ts-nocheck` to the top of all files, and commit (You can use `add-eslint-disable.sh`) 25 | - [ ] **Convert to TypeScript** This is where all the work is done 26 | - [ ] Test in wrappers as appropriate: the PhET-iO State wrapper as you go if the sim supports PhET-iO. The a11y view, etc. 27 | - [ ] merge to main 28 | - [ ] delete branch 29 | - [ ] test on CT 30 | - [ ] Publish dev version after. Use `grunt dev --brands={{brands}} --message="after TypeScript conversion, see {{issue number URL}}"` 31 | - [ ] Compare between both versions to identify any regression due to the typescript conversion. 32 | - [ ] If needed, schedule a QA test for regressions 33 | - [ ] consult with the lead developer about any remaining work 34 | 35 | @jbphet approved me to start here. He said: You're of course welcome to work on those, but please regression test thoroughly as you do. They were both tricky sims. SOM has lots of optimizations for fast model calculations, and EFAC has its own 2D interaction model for stacking and such, and these things are a little complicated. Also, the behavior of the energy chunks is a bit touchy. 36 | -------------------------------------------------------------------------------- /typescript-conversion/.claude/commands/migrate-method-types.md: -------------------------------------------------------------------------------- 1 | --- 2 | allowed-tools: Read, Edit, MultiEdit 3 | argument-hint: 4 | description: Migrate TypeScript method signatures from JSDoc to TypeScript syntax 5 | --- 6 | 7 | Migrate all method signatures + constructor signatures in the file @$ARGUMENTS from JSDoc type annotations to TypeScript syntax following these rules: 8 | 9 | 1. Convert JSDoc method signatures to TypeScript: 10 | - Move type annotations from `@param {Type}` to TypeScript parameter types 11 | - Move `@returns {Type}` to TypeScript return type annotation 12 | - Move `@private`, `@public`, `@protected` to TypeScript modifiers 13 | 14 | 2. Preserve all documentation: 15 | - Keep method descriptions intact 16 | - Keep parameter descriptions (after the hyphen in `@param`) 17 | - Keep return value descriptions, if any 18 | 19 | 3. Clean up JSDoc: 20 | - Remove all `@param` tags if and if none have documentation (only type) 21 | - Remove `@returns` tags that have no documentation (only type) 22 | - Keep `@param name - description` format for documented parameters 23 | - Keep `@returns description` format for documented return values 24 | 25 | 4. Example transformation: 26 | ```typescript 27 | // Before: 28 | /** 29 | * Given an (initial) position, find a position with the targeted electric potential 30 | * @private 31 | * @param {Vector2} position 32 | * @param {number} electricPotential 33 | * @param {number} deltaDistance - a distance in meters 34 | * @returns {Vector2} finalPosition 35 | */ 36 | getNextPosition( position, electricPotential, deltaDistance ) { 37 | 38 | // After: 39 | /** 40 | * Given an (initial) position, find a position with the targeted electric potential 41 | * @param position 42 | * @param electricPotential 43 | * @param deltaDistance - a distance in meters 44 | */ 45 | private getNextPosition( position: Vector2, electricPotential: number, deltaDistance: number ): Vector2 { 46 | ``` 47 | 48 | 5. Apply to all methods in the file (static and instance methods) 49 | 6. DO NOT change any runtime behavior - only type annotations, comments, and imports 50 | 7. Think carefully to figure out the imports. See if the type is already imported, or if you need to import it. If you need to import it, carefully compute the import path based on the current file's location. 51 | 8. Visit the constructors as well, but JSDOC and signature ONLY. 52 | 9. Move `@override` jsdoc to the typescript keyword like `public override myMethod(...)` 53 | 10. `constructor` should be made public, i.e. `public constructor(...)` 54 | 11. If the resultant JSDoc is blank, like 55 | ``` 56 | /** 57 | */ 58 | ``` 59 | 60 | Then remove it entirely. 61 | 12. If the method has no return type, then `: void` must be explictly added to the method signature. 62 | 63 | 13. If the file has: 64 | ``` 65 | /* eslint-disable */ 66 | // @ts-nocheck 67 | ``` 68 | 69 | LEAVE IT INTACT. Do not change. Keep it. -------------------------------------------------------------------------------- /typescript-conversion/.claude/commands/migrate-constructor.md: -------------------------------------------------------------------------------- 1 | --- 2 | allowed-tools: Read, Edit, MultiEdit 3 | argument-hint: 4 | description: Migrate constructor from JavaScript style to TypeScript style 5 | --- 6 | 7 | Migrate all declarations in a constructor in the file @$ARGUMENTS from JavaScript style (no class attribute declarations) to TypeScript syntax (with class attribute declarations) following these rules: 8 | 9 | 1. Add type declarations for class attributes: 10 | - Documentation moves with the declaration. 11 | - Preserve or infer private/public/protected/readonly modifiers. 12 | - Preserve assignment in the constructor. 13 | 14 | 2. Preserve all documentation: 15 | - Keep method descriptions intact 16 | 17 | 3. Example transformation: 18 | ```typescript 19 | // Before: 20 | 21 | class MotionAtom { 22 | 23 | /** 24 | * @param initialAtomType - initial type, aka element, for this atom 25 | * @param initialXPosition - x position in the model, in picometers 26 | * @param initialYPosition - y position in the model, in picometers 27 | * @param tandem 28 | */ 29 | public constructor( initialAtomType: AtomType, initialXPosition: number, initialYPosition: number, tandem: Tandem ) { 30 | 31 | // @public (read-write) {EnumerationDeprecatedProperty.} - the type of atom being modeled, e.g. Argon, Neon, etc. 32 | this.atomTypeProperty = new EnumerationDeprecatedProperty( AtomType, initialAtomType, { 33 | tandem: tandem.createTandem( 'atomTypeProperty' ), 34 | phetioReadOnly: true 35 | } ); 36 | 37 | // After: 38 | class MotionAtom { 39 | 40 | // The type of atom being modeled, e.g. Argon, Neon, etc. 41 | public readonly atomTypeProperty: EnumerationDeprecatedProperty; 42 | 43 | /** 44 | * @param initialAtomType - initial type, aka element, for this atom 45 | * @param initialXPosition - x position in the model, in picometers 46 | * @param initialYPosition - y position in the model, in picometers 47 | * @param tandem 48 | */ 49 | public constructor( initialAtomType: AtomType, initialXPosition: number, initialYPosition: number, tandem: Tandem ) { 50 | 51 | this.atomTypeProperty = new EnumerationDeprecatedProperty( AtomType, initialAtomType, { 52 | tandem: tandem.createTandem( 'atomTypeProperty' ), 53 | phetioReadOnly: true 54 | } ); 55 | 56 | ``` 57 | 58 | 4. Apply to ALL attributes in ALL constructors in the file 59 | 5. DO NOT change any runtime behavior - only type annotations, comments, and imports. Work in 100% type space and code comments/documentation. 60 | 6. Think carefully to figure out the imports. See if the type is already imported, or if you need to import it. If you need to import it, carefully compute the import path based on the current file's location. 61 | 8. Think about the file to understand if a declaration should be readonly. If you are uncertain, err on the side of readonly. 62 | 9. Think about the file to understand if a declaration should be public, protected, or private. If you are uncertain, err on the side of private. 63 | 64 | 8. If the file has: 65 | ``` 66 | /* eslint-disable */ 67 | // @ts-nocheck 68 | ``` 69 | 70 | LEAVE IT INTACT. Do not change. Keep it. -------------------------------------------------------------------------------- /github-labels/new-repo-add-labels.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # new-repo-add-labels.sh 4 | # 5 | # This script adds all labels in github-labels to the specified repo 6 | 7 | if [[ -z "$1" ]] 8 | then 9 | echo "Usage: $0 organization/repo" 10 | exit 1 11 | fi 12 | echo $1 13 | 14 | binDir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" 15 | creds=`../../perennial/bin/sage run ${binDir}/printGithubAuthorization.js` 16 | 17 | ../../perennial/bin/sage run ./update-repos-list.js 18 | 19 | echo 'For each repo, this script should print "200 OK", "201 Created" or "204 No Content" to indicate success.' 20 | echo '"422 Unprocessable Entity" indicates an attempt to duplicate a label and can be ignored.' 21 | 22 | repo=$1 23 | url=https://api.github.com/repos/${repo}/labels 24 | 25 | 26 | #delete the "invalid" label 27 | echo "Path: ${url}/invalid" 28 | echo "Result (204 expected):" 29 | curl -isH 'User-Agent: "PhET"' -u "$creds" -X DELETE "$url/invalid" | head -n 1 30 | 31 | # Replace standard-issue labels with phet-specific labels if they exist 32 | replace='{ 33 | "name": "type:wontfix", 34 | "color": "ffffff" 35 | }' 36 | echo "Path: ${url}/wontfix" 37 | echo "Data: ${replace}" 38 | echo "Result (200 expected):" 39 | curl -isH 'User-Agent: "PhET"' -u "$creds" -d "$replace" -X PATCH "$url/wontfix" | head -n 1 40 | 41 | replace='{ 42 | "name": "type:question", 43 | "color": "EDCB62" 44 | }' 45 | echo "Path: ${url}/question" 46 | echo "Data: ${replace}" 47 | echo "Result (200 expected):" 48 | curl -isH 'User-Agent: "PhET"' -u "$creds" -d "$replace" -X PATCH "$url/question" | head -n 1 49 | 50 | replace='{ 51 | "name": "dev:help-wanted", 52 | "color": "63D1F4" 53 | }' 54 | echo "Path: ${url}/20wanted" 55 | echo "Data: ${replace}" 56 | echo "Result (200 expected):" 57 | curl -isH 'User-Agent: "PhET"' -u "$creds" -d "$replace" -X PATCH "$url/help%20wanted" | head -n 1 58 | 59 | replace='{ 60 | "name": "dev:enhancement", 61 | "color": "0276FD" 62 | }' 63 | echo "Path: ${url}/enhancement" 64 | echo "Data: ${replace}" 65 | echo "Result (200 expected):" 66 | curl -isH 'User-Agent: "PhET"' -u "$creds" -d "$replace" -X PATCH "$url/enhancement" | head -n 1 67 | 68 | replace='{ 69 | "name": "type:duplicate", 70 | "color": "EEEED1" 71 | }' 72 | echo "Path: ${url}/duplicate" 73 | echo "Data: ${replace}" 74 | echo "Result (200 expected):" 75 | curl -isH 'User-Agent: "PhET"' -u "$creds" -d "$replace" -X PATCH "$url/duplicate" | head -n 1 76 | 77 | replace='{ 78 | "name": "type:bug", 79 | "color": "FF00AA" 80 | }' 81 | echo "Path: ${url}/bug" 82 | echo "Data: ${replace}" 83 | echo "Result (200 expected):" 84 | curl -isH 'User-Agent: "PhET"' -u "$creds" -d "$replace" -X PATCH "$url/bug" | head -n 1 85 | 86 | #Add labels from file 87 | for label in `cat github-labels` 88 | do 89 | name=`echo ${label} | cut -f1 -d,` 90 | color=`echo ${label} | cut -f2 -d,` 91 | json="{\"name\":\"$name\",\"color\":\"$color\"}" 92 | echo "Path: ${url}" 93 | echo "Data: ${json}" 94 | echo "Result (201 expected):" 95 | curl -isH 'User-Agent: "PhET"' -u "$creds" -d "$json" -X POST "$url" | head -n 1 96 | done 97 | 98 | echo "Complete." 99 | 100 | 101 | -------------------------------------------------------------------------------- /github-labels/README.md: -------------------------------------------------------------------------------- 1 | # Updating Github Repo Labels 2 | 3 | #### NOTE: The `.phet/.credentials` file is no longer required. 4 | 5 | This file is not used anywhere else in the project and should be removed. We are now storing credentials in 6 | build-local.json. See Getting Started for details. 7 | 8 | ## Getting Started 9 | 10 | 1. Setup credentials 11 | 12 | - You must add the developerGithubAccessToken and developerGithubUsername properties to ~/.phet/build-local.json. See 13 | https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line#creating-a-token 14 | for creating a personal access token. Under "Select Scopes", the token should be given full "repo" access. 15 | 16 | 2. Install npm packages 17 | 18 | - The node scripts in this repo require running `npm install` in the phet-info/github-labels directory. 19 | 20 | 3. Github label code requires a checkout of `perennial/`. 21 | 22 | ## PhET Github Label operations 23 | 24 | ### To standardize the labels on a new repo 25 | 26 | 1. `cd phet-info/github-labels` 27 | 2. Run `./new-repo-add-labels.sh phetsims/{{new-repo-name}}` 28 | 29 | ### To add a new label to all the organization's repos 30 | 31 | 1. Choose a new label following the [labeling-scheme](labeling-scheme.md) 32 | 2. `cd phet-info/github-labels` 33 | 3. Run `./new-label-all-repos.sh {{new-label-name}} {{new-label-color}}`. `new-label-color` should be the hexcode with 34 | no # symbol, e.g. FF00AA. 35 | 36 | ### To change the text and/or color of a label 37 | 38 | 1. Update the desired label in [github-labels](github-labels), following the [labeling-scheme](labeling-scheme.md) 39 | 2. `cd phet-info/github-labels` 40 | 3. Run `./change-label.sh {{old-label-name}} {{new-label-name}} {{new-label-color}}`. `new-label-color` should be the 41 | hexcode with no # symbol, e.g. `FF00AA`. 42 | 43 | ### To remove a label from all repos 44 | 45 | 1. `cd phet-info/github-labels` 46 | 2. Run `./delete-label.sh {{label-name}}`. 47 | 48 | ### To remove a repo from github label management 49 | 50 | 1. If you have the file `.repos` (because you have used this tool before), delete the repo line from that file 51 | 52 | ## FAQ 53 | 54 | * ### Error statuses during label script execution 55 | 56 | * __200, 201, etc__ - Anything in the 200 range indicates success. 57 | * __400 Bad Request__ - This probably indicates a fatal error. Verify if the change did not happen as expected and 58 | contact the responsible dev if not (Matt Pennington as of 2020). 59 | * __401 Unauthorized__ - This indicates that your credentials are incorrect. Make sure your username and personal 60 | access token are entered in ~/.phet/build-local.json correctly and check the status of your PAT 61 | at https://github.com/settings/tokens. 62 | * __403 Forbidden__ - This indicates that the Github User that you used does not have admin access for that repo. Make 63 | sure your username and personal access token are entered in ~/.phet/build-local.json correctly and contact any PhET 64 | Github Admin for further assistance. 65 | * __422 Unprocessable Entity__ - This is probably __*not*__ an error and most likely indicates that the script 66 | attempted a duplicate action. Verify if the change did not happen as expected and contact the responsible dev if 67 | not (Matt Pennington as of 2020). 68 | -------------------------------------------------------------------------------- /typescript-conversion/.claude/commands/migrate-constructor-options.md: -------------------------------------------------------------------------------- 1 | --- 2 | allowed-tools: Read, Edit, MultiEdit 3 | argument-hint: 4 | description: Migrate constructor from JavaScript style to TypeScript style 5 | --- 6 | 7 | Migrate all options parameters in constructors in the file @$ARGUMENTS from JavaScript style (no types) to PhET's optionize TypeScript pattern (with types) following these rules: 8 | 9 | 1. Rename `options` to `providedOptions`. 10 | - Make sure to visit every occurrence of this variable in its scope. 11 | - Note that there may be multiple constructors or other methods with `options`, so take care. 12 | 13 | 2. Change `merge` to `optionize` 14 | 15 | 3. Example transformation: 16 | ```typescript 17 | 18 | // BEFORE: 19 | 20 | import merge from '../../../../phet-core/js/merge.js'; 21 | import Image from '../../../../scenery/js/nodes/Image.js'; 22 | import RectangularPushButton from '../../../../sun/js/buttons/RectangularPushButton.js'; 23 | import pencil_png from '../../../mipmaps/pencil_png.js'; 24 | import chargesAndFields from '../../chargesAndFields.js'; 25 | 26 | class PencilButton extends RectangularPushButton { 27 | 28 | /** 29 | * @param {Tandem} tandem 30 | * @param {Object} [options] 31 | */ 32 | constructor( tandem, options ) { 33 | options = merge( { 34 | iconWidth: 26, 35 | iconHeight: 20, 36 | tandem: tandem 37 | }, options ); 38 | 39 | 40 | // AFTER: 41 | 42 | import optionize from '../../../../phet-core/js/optionize.js'; 43 | import Image from '../../../../scenery/js/nodes/Image.js'; 44 | import RectangularPushButton, { RectangularPushButtonOptions } from '../../../../sun/js/buttons/RectangularPushButton.js'; 45 | import Tandem from '../../../../tandem/js/Tandem.js'; 46 | import pencil_png from '../../../mipmaps/pencil_png.js'; 47 | import chargesAndFields from '../../chargesAndFields.js'; 48 | 49 | type SelfOptions = { 50 | iconWidth?: number; 51 | iconHeight?: number; 52 | }; 53 | 54 | type PencilButtonOptions = SelfOptions & RectangularPushButtonOptions; 55 | 56 | export default class PencilButton extends RectangularPushButton { 57 | 58 | public constructor( tandem: Tandem, providedOptions?: PencilButtonOptions ) { 59 | 60 | const options = optionize()( { 61 | iconWidth: 26, 62 | iconHeight: 20, 63 | tandem: tandem 64 | }, providedOptions ); 65 | ``` 66 | 67 | 4. Apply to options parameters in ALL constructors in the file 68 | 5. DO NOT change any runtime behavior - only type annotations, comments, and imports. Work in 100% type space and code comments/documentation. 69 | 6. If there are no new options introduced for the constructor at hand, then use `type SelfOptions = EmptySelfOptions`. You can get EmptySelfOptions from `import optionize, { type EmptySelfOptions } from '../../phet-core/js/optionize.js';` 70 | 7. NOTE: The implementation of `optionize` is identical to `merge`, so you can be confident the behavior is the same. These changes are solely for type space. 71 | 8. If the parent doesn't export its own options type, you can jump to the grandparent class for its options type. 72 | 9. If `merge` is used elsewhere in the file, do not remove the import! 73 | 10. If the file has: 74 | ``` 75 | /* eslint-disable */ 76 | // @ts-nocheck 77 | ``` 78 | 79 | LEAVE IT INTACT. Do not change. Keep it. -------------------------------------------------------------------------------- /doc/dynamic-string-layout-quickstart.md: -------------------------------------------------------------------------------- 1 | # Dynamic Strings Layout Quickstart Guide 2 | 3 | ## Table of Contents 4 | 5 | - First Steps 6 | - PatternStringProperty 7 | - Dynamic Layout 8 | - Testing 9 | - Final steps 10 | 11 | ### First Steps 12 | 13 | String lookups should be changed to the `*StringProperty` suffix, e.g. `someSimStrings.something` to 14 | `someSimStrings.somethingStringProperty`. These are auto-generated`TReadOnlyProperty` instances that will 15 | dynamically update when the locale changes, and every single usage of string accesses of this form should be converted. 16 | 17 | Any code that relied on these being a `string` should be refactored to be dynamic, and to accept a 18 | `TReadOnlyProperty`. This should happen all the way to the displayed `Text` Nodes, which can take a 19 | `TReadOnlyProperty` as a constructor argument (or as a `stringProperty` option). 20 | 21 | Certain components may need to be set to `resizable: true`. If you see that components are not resizing as expected, 22 | this is a good place to start. 23 | 24 | You can define support for dynamic locale in the package.json. It is recommended to wait until all strings have been 25 | converted to use the `*stringProperty` from the strings file. If you know that you will not need to support dynamic 26 | locale for your publication, you can opt out in the package.json 27 | like: 28 | 29 | ```json 30 | { 31 | "simFeatures": { 32 | "supportsDynamicLocale": false 33 | } 34 | } 35 | ``` 36 | 37 | ### PatternStringProperty and DerivedStringProperty 38 | 39 | For situations where a pattern string is needed, generally use `PatternStringProperty`. This replaces the pattern where 40 | we use `StringUtils.fillIn()`. Refer to `PatternStringProperty.ts` 41 | for implementation documentation. There may be rare/specific situations where `PatternStringProperty` is not needed. 42 | Also know that these are likely good cases for DerivedStringProperty, which should be used for i18n derived, non-pattern 43 | strings. We prefer `DerivedStringProperty` to `DerivedProperty` for PhET-iO consistency. 44 | 45 | ### Dynamic Layout 46 | Sizable components found in both Scenery and Sun support dynamic strings in sims. Familiarize yourself with the 47 | [Scenery Layout Documentation](https://scenerystack.org/learn/scenery-layout/) to learn more about sizable components and how they can help you create a dynamic 48 | and robust layout architecture for your sim. It is recommended to use these components instead of listening to 49 | `BoundsProperty`. 50 | 51 | ### Testing 52 | Use the `stringTest=dynamic` query parameter to change all the strings in your sim at once. `DynamicStringTest` uses a 53 | keyboard event listener to adjust the length of strings with the arrow keys and space bar. For more specific usage info 54 | refer to [DynamicStringTest](https://github.com/phetsims/joist/blob/main/js/DynamicStringTest.ts) documentation. This 55 | tool will allow you to see if dynamic layout is working as anticipated, and that components are resizing as would be 56 | expected. Strings will only change if they have been implemented with a `TReadOnlyProperty` from the strings file. 57 | 58 | ### Final Steps 59 | 60 | To support dynamic locales in your sim update your `package.json` with: 61 | 62 | ```json 63 | { 64 | "simFeatures": { 65 | "supportsDynamicLocale": true 66 | } 67 | } 68 | ``` 69 | 70 | This will create a Typescript error if the old style of strings is used, forcing you to access i18n strings via 71 | the `*StringProperty` key. 72 | 73 | Also make sure to run `grunt update`. 74 | 75 | CM tracked some useful roadblocks that came up during Natural Selection conversion 76 | here: https://github.com/phetsims/natural-selection/issues/319 77 | -------------------------------------------------------------------------------- /ai/core-description/add-accessible-heading.md: -------------------------------------------------------------------------------- 1 | ### Goal 2 | Create a heading that screen readers can use to describe a logical section of the PDOM such as a description block, control group, or button set. 3 | 4 | ### 1. Add the heading string in the sim’s Fluent YAML 5 | 1. Open the sim’s `{sim}-strings_en.yaml`. 6 | 2. Add `accessibleHeading` (or a selector pattern) under the relevant `a11y` subgroup so that it sits next to the rest of the copy for that section. 7 | 3. Keep headings concise; they are announced each time the user enters the region. 8 | 9 | Examples 10 | `number-pairs/number-pairs-strings_en.yaml` 11 | ```yaml 12 | a11y: 13 | countingArea: 14 | accessibleHeading: Counting Area 15 | ``` 16 | `forces-and-motion-basics/forces-and-motion-basics-strings_en.yaml``` 17 | ```yaml 18 | a11y: 19 | motionScreen: 20 | playAreaControls: 21 | appliedForceControl: 22 | accessibleHeading: Applied Force Control 23 | ``` 24 | The perennial watcher regenerates `*Strings.ts` and `*Fluent.ts` automatically, so no manual build step is needed after saving the YAML. 25 | 26 | ### 2. Reference the new string from code 27 | 1. Import the sim’s Fluent module (e.g., `NumberPairsFluent`, `ForcesAndMotionBasicsFluent`). 28 | 2. Pass the associated `accessibleHeading` property to the `Node` (or control class) that represents the logical section. 29 | - If the heading text is static, use the generated `...accessibleHeadingStringProperty`. 30 | - If the heading varies (e.g., per challenge type), call `.accessibleHeading.createProperty( { ... } )` with the variants. 31 | 3. The heading typically lives on a `Node` with `tagName: 'div'` that wraps the child nodes the user will explore—yes, nesting a wrapper `Node` is the right approach if the widget itself cannot accept the heading option. 32 | 33 | Examples 34 | `number-pairs/js/common/view/description/CountingAreaDescriptionNode.ts` 35 | ```ts 36 | const options = optionize<...>()( { 37 | accessibleHeading: NumberPairsFluent.a11y.countingArea.accessibleHeadingStringProperty, 38 | children: [ countingAreaAccessibleListNode, numberLineDescription ] 39 | }, providedOptions ); 40 | ``` 41 | `number-pairs/js/game/view/AnswerButtonGroup.ts` (dynamic heading) 42 | ```ts 43 | accessibleHeading: NumberPairsFluent.a11y.gameScreen.answerButtonGroup.accessibleHeading.createProperty( { 44 | challengeType: challengeTypeProperty 45 | } ), 46 | ``` 47 | `forces-and-motion-basics/js/motion/view/MotionScreenView.ts` (wrapping Node) 48 | ```ts 49 | const appliedForcePlayAreaControlNode = new Node( { 50 | tagName: 'div', 51 | accessibleHeading: ForcesAndMotionBasicsFluent.a11y.motionScreen.playAreaControls.appliedForceControl.accessibleHeadingStringProperty, 52 | descriptionContent: ForcesAndMotionBasicsFluent.a11y.motionScreen.playAreaControls.appliedForceControl.descriptionStringProperty, 53 | children: [ appliedForceControl ] 54 | } ); 55 | ``` 56 | 57 | ### 3. Keep the PDOM structure coherent 58 | - Group related elements under the heading wrapper so the heading precedes the content in reading order. 59 | - When adding a wrapper Node, forward `tandem`, `visibleProperty`, and other important options so instrumentation still works. 60 | - If you already extend a class that exposes `AccessibleOptions`, set `accessibleHeading` directly on the subclass options object instead of introducing another wrapper. 61 | 62 | ### 4. Validate 63 | - Tab through the sim (or inspect the PDOM with browser dev tools) to confirm the heading now appears before the intended section. 64 | - Confirm that no duplicate headings exist for the same content and that any dynamic variants announce correctly. 65 | 66 | Following this pattern ensures new sections match existing implementations in `number-pairs` and `forces-and-motion-basics`, so screen reader users receive consistent structural cues throughout the sims. 67 | -------------------------------------------------------------------------------- /doc/typescript-quick-start.md: -------------------------------------------------------------------------------- 1 | ### TypeScript Quick Start 2 | 3 | These are the basic steps and summary for converting a repo to TypeScript, how to use it, and summary of some workflows, 4 | known problems, etc. 5 | 6 | ### Getting Started 7 | 8 | 1. Update your codebase to support typescript features with `cd perennial; grunt sync;` 9 | 2. Mark chipper/dist/ as excluded from your IDE. You can create that directory eagerly now, or wait until chipper/dist/ 10 | is created by a compilation step below. Compiled code will be written to chipper/dist/. 11 | 3. Update your IDE to use the code style file from `phet-info/ide/idea/phet-idea-codestyle.xml`. You may need to 12 | re-import the xml file so that your IDE picks up any changes related to TypeScript. Your IDE may not stay in sync 13 | with what is checked into phet-info. 14 | 4. Turn on TypeScript support in WebStorm: Preferences > Languages & Frameworks > TypeScript. Make sure you are using 15 | your system's absolute path for `perennial-alias/node_modules/typescript`, turn on "TypeScript language service" 16 | and "Show project errors". Turn off "Recompile on changes". 17 | 5. Sublime also has an officially-supported plugin. 18 | 19 | ### Porting from JavaScript 20 | 21 | 1. Create an issue in the repo you are converting to connect your commits to. If you are converting a sim, publish a dev 22 | version before making any changes and point the build to the issue using the `--message` option in `grunt dev`. Do 23 | the same after the conversion is complete to do any regression testing. 24 | 2. Rename the file from *.js to *.ts. This must be committed as a pure rename, without changing contents. If you change 25 | the content more than a small amount, git will think it is a delete and create, which will lose the history of the 26 | file. Use `git mv` to rename the file, or if you are using WebStorm, it will do this automatically for you. See https://github.com/phetsims/sun/issues/732#issuecomment-995330513 and https://github.com/phetsims/charges-and-fields/issues/208#issuecomment-3134618756 27 | 2. I have found it efficient to convert a single file (or a small batch of related files) at a time. Rename the file 28 | from *.js to *.ts, fix any errors, run `grunt type-check` and `grunt lint`, and run to test in the browser. As you 29 | get more skilled, you can convert more and more at once. 30 | 3. WebStorm provides helpful shortcuts. For constructor parameters, you can promote constructor JSDoc params to types 31 | via Option+Enter then "Annotate with Type from JSDoc". You can automatically promote variables to class attributes 32 | with Option+Enter then "Declare property [...]" 33 | 4. After all class attributes have been declared as class properties, you can mark each as `private readonly` then the 34 | compiler will tell you where that needs to be relaxed. 35 | 5. Try to minimize its use as much as possible, but use `// @ts-expect-error` to get past any insurmountable problems. 36 | We prefer that to `// @ts-ignore` so it will tell you if there is no problem. Please also add a message about why 37 | there is an error there. 38 | 39 | ### Caveats and Notes 40 | 41 | 1. Ambient type definitions are provided in perennial-alias/phet-types.d.ts and chipper/phet-types-module.d.ts 42 | 2. Conventions and patterns listed in https://github.com/phetsims/phet-info/blob/main/doc/typescript-conventions.md 43 | 3. For certain files, when changing JS=>TS, WebStorm will say it is a rename in the commit dialog, then show a “delete + 44 | create” in the history. This is not desirable. For those files, a workaround is to rename the file with no content 45 | changes, then change the contents in a separate commit. We no longer are using `@ts-nocheck` as part of this process 46 | because it wasn't worth the cost, and this doesn't prevent downstream errors by files that use your converting file 47 | as a dependency. This came from https://github.com/phetsims/sun/issues/732#issuecomment-995330513. 48 | -------------------------------------------------------------------------------- /github-dashboard/issueReport.js: -------------------------------------------------------------------------------- 1 | // Copyright 2023, University of Colorado Boulder 2 | 3 | /** 4 | * This script interacts with the GitHub API to fetch organization members, repositories, and open issues 5 | * for the 'phetsims' organization. For users and repos, they are output to console where they can be saved to file manually. 6 | * Issues are outputted to ./repodir. 7 | * Key functionalities: 8 | * * Get the list of organization members (getUsersFromGitHub) 9 | * * Get the list of repositories (getReposFromGitHub) 10 | * * Fetch open issues assigned to organization members, organized by repository (getAssignedIssuesByRepo) 11 | * Usage: Run the script with Node.js. Optionally, set downloadNewData to true to download updated user and repo data. 12 | * 13 | * @author Sam Reid (PhET Interactive Simulations) 14 | * @author Agustín Vallejo (PhET Interactive Simulations) 15 | */ 16 | 17 | const buildLocal = require( '../../perennial-alias/js/common/buildLocal' ); 18 | const { Octokit } = require( 'octokit' ); 19 | const octokit = new Octokit( { 20 | auth: buildLocal.phetDevGitHubAccessToken 21 | } ); 22 | const fs = require( 'fs' ); 23 | 24 | // List all users for the organization 25 | const getUsersFromGitHub = async () => { 26 | const result = await octokit.request( 'GET /orgs/phetsims/members', { 27 | org: 'phetsims', 28 | per_page: 100 29 | } ); 30 | 31 | // console.log( result.data.length ); 32 | const logins = result.data.map( member => member.login ); 33 | return logins; 34 | }; 35 | 36 | // Fetch the list of repositories in the organization 37 | const getReposFromGitHub = async () => { 38 | const fetchRepos = async page => { 39 | const result = await octokit.request( 'GET /orgs/phetsims/repos', { 40 | org: 'phetsims', 41 | per_page: 100, 42 | page: page 43 | } ); 44 | 45 | return result; 46 | }; 47 | 48 | let allRepos = []; 49 | let currentPage = 1; 50 | let fetchedRepos; 51 | 52 | do { 53 | fetchedRepos = await fetchRepos( currentPage ); 54 | allRepos = allRepos.concat( fetchedRepos.data ); 55 | currentPage += 1; 56 | } while ( fetchedRepos.data.length === 100 ); 57 | 58 | const repoNames = allRepos.map( repo => repo.name ); 59 | return repoNames; 60 | }; 61 | 62 | const repos = fs.readFileSync( './repos', 'utf8' ).split( '\n' ); 63 | // const users = fs.readFileSync( './users', 'utf8' ).split( '\n' ); 64 | 65 | // Fetch the open issues assigned to users in the organization, organized by repository 66 | const getAssignedIssuesByRepo = async () => { 67 | 68 | const fetchIssues = async ( repo, page ) => { 69 | const issues = await octokit.request( 'GET /search/issues', { 70 | q: `repo:phetsims/${repo} is:issue is:open`, 71 | per_page: 100, 72 | page: page 73 | } ); 74 | 75 | return issues; 76 | }; 77 | 78 | for ( const repo of repos ) { 79 | let repoIssues = []; 80 | let currentPage = 1; 81 | let fetchedIssues; 82 | 83 | do { 84 | fetchedIssues = await fetchIssues( repo, currentPage ); 85 | repoIssues = repoIssues.concat( fetchedIssues.data.items ); 86 | currentPage += 1; 87 | } while ( fetchedIssues.data.items.length === 100 ); 88 | try { 89 | fs.mkdirSync( './repodir' ); 90 | } 91 | catch( e ) { 92 | console.log( e ); 93 | } 94 | fs.writeFileSync( `./repodir/${repo}`, JSON.stringify( repoIssues, null, 2 ) ); 95 | 96 | // exit(); 97 | 98 | // Exit from the node process 99 | // process.exit( 0 ); 100 | } 101 | }; 102 | 103 | ( async () => { 104 | const downloadNewData = false; 105 | if ( downloadNewData ) { 106 | const users = await getUsersFromGitHub(); 107 | console.log( users ); 108 | 109 | const repos = await getReposFromGitHub(); 110 | console.log( repos.length, repos.join( '\n' ) ); 111 | } 112 | 113 | await getAssignedIssuesByRepo(); 114 | } )(); -------------------------------------------------------------------------------- /doc/core-description-options.md: -------------------------------------------------------------------------------- 1 | # Core Description Options 2 | 3 | This document was written in response to https://github.com/phetsims/phet-info/issues/243 so designers and developers 4 | could see all the options for specifying descriptive text in one place, with the exact option names. I do not know how 5 | to automatically keep this in sync with the code. 6 | 7 | * @author Sam Reid (PhET Interactive Simulations). 8 | 9 | ## SCENERY 10 | 11 | ### Node 12 | 13 | * accessibleName 14 | * accessibleHelpText 15 | * accessibleParagraph 16 | * accessibleHeading 17 | * accessibleRoleDescription 18 | 19 | ### Most buttons and simple components, including but not limited to AquaRadioButton | ComboBox | ButtonNode 20 | 21 | * accessibleContextResponse 22 | 23 | ## SUN 24 | 25 | ### ABSwitch 26 | 27 | * valueAAccessibleName (to be renamed to accessibleNameValueA soon) 28 | * valueBAccessibleName (to be renamed to accessibleNameValueB soon) 29 | 30 | ### AccordionBox 31 | 32 | * accessibleContextResponseExpanded 33 | * accessibleContextResponseCollapsed 34 | * accessibleHelpTextExpanded 35 | * accessibleHelpTextCollapsed 36 | 37 | ### AccessibleSlider 38 | * createAriaValueText (for object responses, to be renamed soon) 39 | * createContextResponseAlert (for context responses, to be renamed soon) 40 | * keyboardStep 41 | * shiftKeyboardStep 42 | * pageKeyboardStep 43 | 44 | ### AccessibleValueHandler 45 | 46 | * createAriaValueText 47 | * createContextResponseAlert 48 | 49 | ### AquaRadioButton 50 | 51 | * accessibleContextResponse 52 | 53 | ### ButtonNode 54 | 55 | * accessibleContextResponse 56 | 57 | ### Checkbox 58 | 59 | * accessibleContextResponseChecked 60 | * accessibleContextResponseUnchecked 61 | 62 | ### ComboBox 63 | 64 | * accessibleContextResponse 65 | 66 | ### Carousel 67 | 68 | * buttonAccessibleContextResponsePatternProperty - accessible context response for arrow buttons 69 | 70 | ### RectangularMomentaryButton | RoundMomentaryButton | RectangularToggleButton | RoundToggleButton | RectangularStickyToggleButton | RoundStickyToggleButton 71 | 72 | * accessibleContextResponseOn 73 | * accessibleContextResponseOn 74 | 75 | ### RectangularToggleButton | RoundToggleButton 76 | * accessibleNameOn 77 | * accessibleNameOff 78 | 79 | ### ToggleSwitch 80 | 81 | * accessibleContextResponseLeftValue 82 | * accessibleContextResponseRightValue 83 | 84 | ## SCENERY PHET 85 | 86 | ### PlayControlButton 87 | 88 | * startPlayingAccessibleName (to be renamed to accessibleNameStartPlaying soon) 89 | * endPlayingAccessibleName (to be renamed to accessibleNameEndPlaying soon) 90 | 91 | ### PlayPauseStepButtonGroup 92 | 93 | * playingHelpText (to be renamed to accessibleHelpTextPlaying soon) 94 | * pausedHelpText (to be renamed to accessibleHelpTextPaused soon) 95 | 96 | ### ZoomButtonGroup 97 | 98 | * accessibleNameZoomIn 99 | * accessibleHelpTextZoomIn 100 | * accessibleNameZoomOut 101 | * accessibleHelpTextZoomOut 102 | 103 | ## JOIST 104 | 105 | ### Screen 106 | 107 | * screenButtonsHelpText 108 | 109 | ### ScreenSummaryContent 110 | 111 | * playAreaContent 112 | * controlAreaContent 113 | * currentDetailsContent 114 | * interactionHintContent 115 | 116 | ### AccessibleListNode 117 | 118 | * leadingParagraphStringProperty 119 | * leadingParagraphVisibleProperty 120 | * listType ('ordered' or 'unordered') 121 | * punctuationStyle (`null`, 'comma', or 'semicolon') - prefer `null` unless you need punctuation to change with the number of items 122 | * Each item in the list can be a string or a string Property, with changing visibility. 123 | 124 | ## VEGAS 125 | 126 | ### ChallengeScreenNode 127 | * accessibleChallengePrompt - A leading prompt for the game challenge. 128 | * accessibleAnswerSummary - A summary of the revealed answer. 129 | 130 | ### InfiniteStatusBar 131 | * accessibleMessageStringProperty 132 | 133 | ### LevelSelectionScreenNode 134 | * accessibleIncludeOptionsDescription 135 | 136 | ### LevelSelectionButton 137 | * accessibleBriefLevelName -------------------------------------------------------------------------------- /conduct/communication-guidelines.md: -------------------------------------------------------------------------------- 1 | # This is a draft document for communication on GitHub and Slack channels 2 | 3 | This document is targeted towards public forums, but the principles should be applicable in general. 4 | 5 | ## Guiding principles 6 | 7 | ### Empathy 8 | 9 | Recognize that we all have different stresses at different times, and we all make mistakes. 10 | 11 | ### Respectful Candor 12 | 13 | We should be able to discuss topics in a candid manner, but maintain professionalism and respect. 14 | 15 | ### Specificity 16 | 17 | When providing critiques we should be specific and clear. 18 | 19 | ### Trust 20 | 21 | We are all working towards a common goal, and need to trust that we have the best intentions at heart. 22 | 23 | ## Strategies 24 | 25 | ### Outside reader 26 | 27 | These are public forums. A simple heuristic to apply is if an outside person were reading comments with no knowledge of 28 | the participants, would they view the exchange as respectful and collaborative? 29 | 30 | ### Tone is two-way 31 | 32 | To be refined but -- basically consider tone when writing comments, and also try not to infer a tone when reading them 33 | "Good faith" interpretation of what is written 34 | 35 | ### Offering solutions 36 | 37 | When pointing out issues/critiques, offering potential solutions adds a more collaborative nature to discussion. There 38 | will of course be times when another solution is not obvious. In such cases it is best to say something like "this 39 | approach seems problematic for these reasons...but I don't have a solution to offer currently". 40 | 41 | ### Be open to feedback 42 | 43 | We want to "gracefully accept constructive criticism" and ideally avoid feeling defensive. (Situations have arisen where 44 | people feel their expertise/ability is being questioned, need to have strategy to avoid this feeling, not a fully-formed 45 | thought yet, but seems to mainly be about trusting your team.) 46 | 47 | ## To be recognized 48 | 49 | ### Bandwidth of the medium 50 | 51 | intent/voice is harder to gauge in places github comments 52 | 53 | ### Impact vs Intent 54 | 55 | ## If communication seems problematic 56 | 57 | 1. Contact the other party directly, no need to "call them out" in the public forum 58 | 2. Assume the "offending party" did not intend poor communication, we are all on the same team 59 | 3. If you are the "offending party" listen to the criticism and be willing to adjust/edit language 60 | 4. Even if you feel wording was totally reasonable, respect that another party might appreciate a different phrasing ( 61 | e.g. a characteristic that is statistically rare might be reasonable to call "abnormal" but "uncommon" might be a 62 | better phrasing) 63 | 5. If talking directly is ineffective OR if you do not feel comfortable initiating the conversation in the first place, 64 | speak to a supervisor. 65 | 66 | Notes from dev discussion 07/11/2019 It’s not about efficiency. It’s about creating a supportive environment. 67 | 68 | Concern that it will take more time. How to balance. 69 | 70 | Add something into the document about tone - try to use a “nice” tone. 71 | 72 | Read things without inferring a tone. 73 | 74 | Impact vs intent - understanding that the impact of your comment can be different than the intent of your communication. 75 | 76 | Recognizing that everyone is working hard with good intentions, and that we are a learning organization, framing 77 | comments in offering improvements and opportunities to grow ... more than just being critical. 78 | 79 | We want to have an open environment, where everyone feels comfortable making suggestions, offering well-intentioned 80 | critiques, etc. So we don’t want team members not making their comments, because they are worried about how reactions. 81 | 82 | Lots of energy (emotional energy) can be used up when events arise … pick up the phone and don’t let things linger. 83 | 84 | How do people perceive comments on GitHub? That is "talking to a person", "documenting", or etc ... Perspective makes a 85 | difference on interpretation? 86 | 87 | Useful links to think about: 88 | Interplay with how to bring more diversity into open source communities? 89 | -------------------------------------------------------------------------------- /ai/core-description/add-checkbox-accessible-response.md: -------------------------------------------------------------------------------- 1 | ## Checkbox Accessible Context Responses 2 | 3 | PhET checkboxes announce a short “context response” immediately after a toggle so that screen reader and Voicing users know what changed. `Checkbox` defaults to the provided `accessibleContextResponseChecked`/`accessibleContextResponseUnchecked` (see `sun/js/Checkbox.ts`) and also reuses them for Voicing context responses, so getting these strings right benefits every modality. 4 | 5 | ### What the responses should say 6 | - Describe the state of the visualization **after** the toggle, not the action the user took. Keep the statement short, declarative, and scoped to what the checkbox controls (e.g., “Tick marks labeled.” instead of “You checked the tick marks checkbox.”). 7 | - Mention the specific objects that appear/disappear so the response stands on its own. Example strings in `number-pairs/number-pairs-strings_en.yaml:411`–`420` describe which annotations are shown on the number line (“Addends are { $leftAddend } and { $rightAddend }, labeled on number line.”) and what hides when unchecked (“Total jump not shown.”). 8 | - Use present tense and avoid redundant wording. `forces-and-motion-basics/forces-and-motion-basics-strings_en.yaml:235`–`248` shows the preferred pattern: “Applied force arrow shown.” / “Applied force arrow hidden.” 9 | - Provide only the context necessary to understand the change. If extra qualifiers are important (e.g., where something is added), include them succinctly (“Stopwatch added to Play Area.” in `forces-and-motion-basics-strings_en.yaml:243`). 10 | 11 | ### Where to put the strings 12 | 1. Add both responses to the sim’s `{sim}-strings_en.yaml` near the checkbox’s other a11y strings. Nest under the same logical section so `Fluent` keys match existing naming conventions. 13 | 2. When the response needs dynamic data, declare placeholders and document them in the YAML entry just like other Fluent strings (see `{ $leftAddend }` and `{ $rightAddend }` in `number-pairs-strings_en.yaml:411`). 14 | 3. The perennial string watcher will regenerate `{sim}Strings.ts` and `{sim}Fluent.ts` automatically after the YAML edit; no manual JSON edits are needed. 15 | 16 | ```yaml 17 | a11y: 18 | controls: 19 | addendsCheckbox: 20 | accessibleContextResponseChecked: Addends are { $leftAddend } and { $rightAddend }, labeled on number line. 21 | accessibleContextResponseUnchecked: Addends hidden. 22 | ``` 23 | 24 | ### Hooking the responses up in code 25 | 1. Import the generated Fluent string properties and pass them to the checkbox options: 26 | - `number-pairs/js/common/view/NumberLineCheckboxItems.ts:23`–`38` shows passing a `FluentValue` with placeholders to `accessibleContextResponseChecked` and the static unchecked property for the “Addends” checkbox. 27 | - `forces-and-motion-basics/js/motion/view/MotionControlPanel.ts:160`–`257` demonstrates the same pattern inside a `VerticalCheckboxGroup`, sometimes pairing a derived description property for the checked response (e.g., `this.sumOfForcesDescriptionProperty`) with a static unchecked string when the “visible” state depends on live data. 28 | 2. When the checked response needs live values, use a `DerivedProperty` or the Fluent helper’s `.createProperty` to supply the parameters (see `createAddendsCheckboxItem` in `NumberLineCheckboxItems.ts`). 29 | 3. Pass both responses wherever a `Checkbox` is instantiated—directly or via helpers like `VerticalCheckboxGroupItem.options`—so each toggle announces the new state. Omitting one leaves the last announcement cached, which confuses assistive technologies. 30 | 31 | ### Implementation checklist 32 | 1. Decide what the user needs to know when the checkbox turns on/off. Summarize the resulting visual/aural change in one clause per response. 33 | 2. Add the Fluent strings (checked + unchecked) to `{sim}-strings_en.yaml`, including placeholders for any dynamic values. 34 | 3. Reference the generated string properties from code and connect them through `Checkbox` options (or `VerticalCheckboxGroupItem.options`) for both states. 35 | 4. Test with a screen reader or Voicing to confirm that toggling the checkbox produces the expected announcement and that the wording matches the updated UI. 36 | -------------------------------------------------------------------------------- /ai/core-description/add-radio-accessible-response.md: -------------------------------------------------------------------------------- 1 | ## Radio Button Accessible Context Responses 2 | 3 | Radio buttons announce a single “context response” after selection changes so users know what the newly selected option does. `AquaRadioButton`/`RectangularRadioButton` expose this via `accessibleContextResponse` (see `sun/js/AquaRadioButton.ts:61`), and `AquaRadioButtonGroup`/`RectangularRadioButtonGroup` simply pass those responses through. The same string is reused for Voicing context output unless you supply an override, so the guidance below keeps both modalities in sync. 4 | 5 | ### What the responses should say 6 | - Describe the effect of the newly selected option, not the gesture (“Preset mode selected” is too vague). `beers-law-lab/js/beerslaw/view/LightModeRadioButtonGroup.ts:48` plays back “Light source wavelength set to …” so learners hear the updated wavelength plus its color range (string defined in `beers-law-lab/beers-law-lab-strings_en.json:489`). 7 | - Include the minimum context needed to distinguish choices. `membrane-transport/js/common/view/MembranePotentialPanel.ts:35` derives responses like “Sodium-selective Voltage-gated, open.” / “Voltage-gated channels closed.” from `membrane-transport/membrane-transport-strings_en.yaml:590`, so the announcement tells which channels changed when the membrane potential shifted. 8 | - Keep it short (one clause) and in present tense. Reserve extra detail for help text/paragraphs so the rapid feedback stays scannable. When qualitative names are helpful (e.g., “violet range” for wavelengths), append them after the quantitative value. 9 | 10 | ### Where to put the strings 11 | 1. Add the base message to `{sim}-strings_en.yaml` (or `.json` for legacy sims) under the relevant `a11y` section. For shared patterns, group them the way `beers-law-lab/beers-law-lab-strings_en.json:489` does in `a11y.sharedAccessibleContextResponses`. 12 | 2. If the statement needs live data, define placeholders/selector blocks in YAML or build a derived Property in code that stitches together existing localized strings. `MembranePotentialDescriber.createDescriptionStringProperty` (`membrane-transport/js/common/view/MembranePotentialDescriber.ts:12`) converts channel state changes into fluent strings instead of duplicating text inside each button. 13 | 3. Let perennial’s watcher regenerate `{sim}Strings.ts` and `{sim}Fluent.ts`; reference the generated string/Property rather than hard-coding text. 14 | 15 | ```yaml 16 | a11y: 17 | sharedAccessibleContextResponses: 18 | presetWavelengthSet: Light source wavelength set to { $wavelength } { $units }, { $colorName } range. 19 | ``` 20 | 21 | ### Hooking the responses up in code 22 | 1. **Per-button responses:** Pass the string Property directly in each item’s options. `beers-law-lab/js/beerslaw/view/DetectorModeRadioButtonGroup.ts:47` supplies two DerivedProperties—one describing transmittance with units, another describing absorbance—via the item’s `accessibleContextResponse`. The group handles layout; each button keeps its own announcement. 23 | 2. **Shared response for every button:** When the announcement logic depends on the selected value but not on which control triggered it (e.g., multiple widgets set the same property), provide a single Property through `radioButtonOptions.accessibleContextResponse`. `MembranePotentialPanel` shares `MembranePotentialDescriber.createDescriptionStringProperty( model )` with every membrane-potential button so whichever value you choose produces the same, fully contextual string. 24 | 3. **Don’t skip it:** If `accessibleContextResponse` is omitted, assistive tech will keep repeating whatever the last control said, which is misleading for mutually exclusive options. Always pair the response with a distinct accessible name and (if needed) help text. 25 | 26 | ### Implementation checklist 27 | 1. Decide what state change each radio option causes and summarize it in one clause (“Transmittance measured at 85 percent”). Capture any numeric values or qualitative tags users rely on. 28 | 2. Add the string/Fluent pattern to `{sim}-strings_en.yaml` (or `.json`) and wire it up through `{sim}Strings.ts`/`{sim}Fluent.ts`. Use placeholders or DerivedProperties when the value depends on live model data. 29 | 3. Reference the string Property via each item’s `accessibleContextResponse` (or via shared `radioButtonOptions`) when creating the `AquaRadioButtonGroup`/`RectangularRadioButtonGroup`. 30 | 4. Spot-check with a screen reader or Voicing: arrow through the group and confirm the announcement describes the selection’s effect and matches the updated visual state. 31 | -------------------------------------------------------------------------------- /resources/developer-resources.md: -------------------------------------------------------------------------------- 1 | # Developer Resources 2 | 3 | ## Overview 4 | 5 | This document contains miscellaneous resources, tips, and tricks that are available to PhET developers. 6 | 7 | ### Applets, extensions, and other Misc to assist in development 8 | 9 | ##### On Windows 10 | 11 | * Ditto clipboard manager - helpful for keeping complex copy paste operation history 12 | 13 | ##### Chrome 14 | 15 | * Lightshot (screenshot tool) 16 | * Tenon Check (accessibility auditing) 17 | 18 | ### Github 19 | 20 | Most of these can be found with simple google searches, but it is nice to have a list of resources that have been 21 | helpful to PhET devs while learning how to superuse Github 22 | 23 | * Mastering markdown: https://guides.github.com/features/mastering-markdown/ 24 | * Mastering search: https://help.github.com/en/articles/searching-code 25 | * Referencing issues in commit messages can be done in the following ways: 26 | * If referencing the same repo as the commit, just use a hash: "I did a commit, see #32" 27 | * You can also use the full URL to the github issue: "The things I did in this commit are good, 28 | see https://github.com/phetsims/chipper/issues/32" 29 | * You can use github shorthand too: "This commit fixes a lot of stuff, see phetsims/chipper#32" 30 | 31 | ### Debugging iOS devices 32 | 33 | ##### On Mac 34 | 35 | Mac users can use the Safari Web Inspector to debug a sim in mobile Safari. Once you device is connected to your Mac 36 | through USB, you should be able to see your device listed under the "Develop" menu item in the Safari menu bar. Make 37 | sure that "Show Develop in menu bar" is enabled in advanced Safari settings. For more detailed information, see 38 | https://webdesign.tutsplus.com/articles/quick-tip-using-web-inspector-to-debug-mobile-safari--webdesign-8787 39 | 40 | ##### On Windows 41 | 42 | There is nothing native in Windows that lets you debug mobile Apple platforms, but Weinre does a pretty good job. Weinre 43 | is a debugger for web pages, and is designed to work remotely so you can debug mobile devices. It does not support 44 | `debugger` breakpoints, but it allows you to inspect the DOM, print statements, and inspect the application with 45 | JavaScript. Please see https://people.apache.org/~pmuellr/weinre/docs/latest/Home.html for detailed information on how 46 | to install and run Weinre. The following is a quick list that may help get it up and running faster. 47 | 48 | 1) Weinre is deployed at https://npmjs.org/package/weinre, and you can install it with 49 | `sudo npm -g install weinre` 50 | 2) To run the debug server, run 51 | `weinre -httpPort [portNumber] -boundHost -all-` 52 | where [portNumber] is your desired http port number. `-boundHost -all-` is required for remote debugging and tells 53 | Weinre to allow all interfaces on the current machine rather than just localhost. 54 | 3) Navigate to http://localhost:[portNumber]/client/#anonymous once the Weinre server is running. This is the Weinre 55 | debugging interface. 56 | 4) Add this snippet somewhere in the top level sim HTML file. 57 | `` 58 | This will inject the Weinre target code into the simulation. 59 | 5) Launch the simulation from the mobile device. You should see the sim top level HTML file listed under "Targets" in 60 | the Weinre interface. 61 | 6) The interface has a similar look and feel to the Chrome dev tools. Have fun debugging! 62 | 63 | You can go to `http://localhost:[portNumber]/` once Weinre server is up and running for additional quick help and 64 | information. 65 | 66 | Please beware of the following "Gotchyas" that I have encountered while using Weinre 67 | 68 | * HTML Elements in the "Elements" inspector sometimes never appear, especially those that are added later with 69 | document.createElement(). 70 | * Sometimes elements in the tree navigation of the "Elements" inspector don't appear when you "open" a new level by 71 | clicking on the triangle next to a parent element. Opening/closing the level a few times sometimes makes the elements 72 | appear correctly. 73 | * When styles are removed from an element with the "Styles" panel on the right of the "Elements" inspector, sometimes 74 | they are removed for good if you click a checkbox, even if you try to add them back. Reloading is the only solution. 75 | 76 | #### Getting crash logs 77 | 78 | Crash logs are transferred to iTunes whenever the device is synced to another computer. Just plug in your device and 79 | launch iTunes to complete the sync. The location of the crash logs will depend on whether you are using Mac or Windows. 80 | 81 | ##### On Mac 82 | 83 | Logs are located at `~/Library/Logs/CrashReporter/MobileDevice/`. Open the folder with your device's name. Look for 84 | files starting with "Read It LaterPro". If you don't see any, try opening a file called "Retired". 85 | 86 | ##### On Windows. 87 | 88 | Logs are located at `~/AppData/Roaming/Apple Computer/Logs/CrashReporter\MobileDevice`. Open the folder with your 89 | device's name. 90 | 91 | ### Accessibility Resources 92 | 93 | * The [Accessibility Developer Guide](https://www.accessibility-developer-guide.com/) is fairly comprehensive. 94 | -------------------------------------------------------------------------------- /doc/phet-dev-exercises.md: -------------------------------------------------------------------------------- 1 | # 💪 PhET Dev Exercises 2 | 3 | Here you will find a list of coding exercises that are designed to provide insight into the fundamentals of PhET Sim 4 | Development. If you ever get stuck or have questions reach out to your mentor for guidance. Please start by creating an 5 | issue on [Example Sim](https://github.com/phetsims/example-sim) with the title *"Dev Exercises Solution: \"*. Use this issue to track your progress and solutions to every challenge. Additionally, you should 7 | create a new branch of example-sim while you work on the exercises. This branch should be named: *" 8 | dev-exercises-{{username}}"*. 9 | 10 | This is meant to be a fun learning experience, so do enjoy! 11 | 12 | ### 1. Add a second magnet to example sim 🧲 13 | 14 | Look at the way the first magnet was created in the simulation. How should you go about displaying a second one that 15 | shares the same logic? You will frequently find yourself instantiating multiple objects of the same class in PhET sims. 16 | Keeping the code organized, and minimizing repetition is something to consider. Remember to read 17 | through [The Model-View coding pattern](https://github.com/phetsims/phet-info/blob/main/doc/phet-software-design-patterns.md#model-view-controller-mvc) 18 | . 19 | 20 |
        HintLook into `MagnetsScreenView.js` to see how the magnet is added to the screen. There will be a model field for the magnet, so you'll have to work your way around that in `MagnetsModel.js`...
        21 | 22 | ### 2. Add a ball ⚽️ 23 | 24 | Create a Ball class in the model, then create the corresponding BallNode class in the view ( it should 25 | extend `ShadedSphereNode` ). Display the ball in the simulation and make the BallNode draggable. This time, you will 26 | have to create new files for the object, in both the model and the view directories. When developing sims, you will do 27 | this for almost every new class of an object there is on the screen. 28 | 29 |
        HintYou can make the contents of `Ball.js` (The model) very similar to `BarMagnet.js`. As for the Node, read through the constructor documentation of `ShadedSphereNode.js` to know what to add to the `super()` call.
        30 | 31 | ### 3. Add a checkbox that controls the Ball's visibility ☑️ 32 | 33 | Most PhET Simulations have checkboxes that control boolean aspects of the sim. Have you read 34 | about [phetmarks](https://github.com/phetsims/phet-info/blob/main/doc/new-dev-onboarding.md#phetmarks) yet? Use it to 35 | access the Sun example to see how checkboxes are implemented, remember you can use `Ctrl + Shift + H` to get details as 36 | to how components are used. 37 | 38 |
        HintLook into `MagnetsControlPanel` in example-sim, that's where you have to add the Checkbox. Also, checkboxes get a Property as their first parameter, so you should probably give it the `visibleProperty` of Ball.
        39 | 40 | ### 4. Add a HSlider to control the ball’s diameter 🎚 41 | 42 | Sliders are frequently used as a way for users to interact with the components, physics, or data on the screen. Once 43 | again, you should refer to Sun's implementation of Sliders as a starting point to control your ball's diameter. 44 | 45 |
        HintTry passing in the BallNode's radius or diameter properties to the slider, and don't forget to use `link` to ensure these changes are being communicated between the components.
        46 | 47 | ### 5. Options 🎨 48 | 49 | Add an option to the ball constructor to control its color. Read through 50 | the [Javascript Options](https://github.com/phetsims/phet-info/blob/main/doc/phet-software-design-patterns.md#options-and-config-javascript) 51 | design pattern, if you're using JS. Keep in mind that the Javascript options pattern is different 52 | than [the TypeScript options pattern](https://github.com/phetsims/phet-info/blob/main/doc/phet-software-design-patterns.md#options-typescript) 53 | . 54 | 55 |
        Hint You can look into `ShadedSphereNodeOptions` to know what options you can play with.
        56 | 57 | ### 6. Layout 🖼 58 | 59 | Proper layout is a big part of ensuring users have the best experience possible when interacting with PhET sims. 60 | Organize the checkbox and slider in their own control panel to the lower left of the screen. Look into the 61 | implementation of control panels in other PhET sims. You might find a variety of ways this is done and all of them are 62 | right! Be inspired to take from the examples you see, or implement your own approach. 63 | 64 |
        Hint In PhETmarks, Scenery/layout-documentation is the best place to learn about all the amazing tools that have been built for layout management. Start there to discover what tools you have at your disposal, and narrow down the approach you want to use.
        65 | 66 | ### 7. You did it! 🎉 67 | 68 | Great job you got through all the exercises! Give yourself a pat on the back, you just learned a lot. To get feedback on 69 | your solutions, make sure to assign the corresponding issue to your mentor for review. Once you've done that and both 70 | you and your mentor feel satisfied, close the issue and delete the branch. 71 | -------------------------------------------------------------------------------- /checklists/sim-republication-checklist.md: -------------------------------------------------------------------------------- 1 | # {{SIM_NAME}} {{VERSION}} Republication Checklist 2 | 3 | (see [Sim Checklist](https://github.com/phetsims/phet-info/blob/main/checklists/sim-checklist.md#design-pre-qa) for any items missing from this checklist that are a part of your sim update (e.g., PhET-iO)) 4 | 5 | ## Design 6 | 7 | ### Prep 8 | 9 | - [ ] Review all open issues 10 | - [ ] Revise design doc or create new doc for updated version. 11 | 12 | ### Scope 13 | 14 | - [ ] Kick-off meeting (Date: //) 15 | - [ ] Establish scope of this release (what new features are being added?) 16 | - [ ] Triage open issues and decide what to include or defer 17 | - Scope of additional features for this release (Basics Sounds, Core Description, Alternative Input, Pan and Zoom, Interactive Highlights, Dynamic Locale, PhET-iO/Studio are assumed as of Nov 2025) 18 | - [ ] Sound & Sonification 19 | - [ ] Interactive Description 20 | - [ ] Mobile description included 21 | - [ ] Voicing (specify Core or Full) 22 | - [ ] Regional Character Sets 23 | - [ ] Optional: paste all issues that will be included, or list features - these will be useful for release notes 24 | - [{{GITHUB PLACEHOLDER LINK}}](https://github.com/phetsims/phet-info) 25 | - {{NEW SIM FEATURE PLACEHOLDER, e.g., Stopwatch added.}} 26 | - [ ] Identify any common code components that do not yet have support for features, and elevate need to #planning Slack channel 27 | - [ ] Create feature-specific milestone deadlines for simulation sub-epics in Monday. Reviewed and updated on a regular basis. 28 | 29 | ### Design (Pre-QA) 30 | 31 | - [ ] Update (or create) design doc(s) to reflect sim updates and feature additions, as needed 32 | - **If applicable to your update:** 33 | - [ ] Core Description reviewed by external designer - [CORE REVIEW CHECKLIST](https://github.com/phetsims/phet-info/blob/main/checklists/core-description-review-checklist.md) 34 | - [ ] Verify [color contrast](https://docs.google.com/document/d/1rlVX9DHXclCtpcFV-5YAoA0uI0Ui_H1mzPJck7v8PcM/edit?tab=t.0) 35 | - [ ] Add to Essential Exceptions doc ([guidelines](https://docs.google.com/document/d/1NjLGmGr2Oi9A9D9SCH5WAgOhpA7ysmuvv0Jn_batPVU/edit?tab=t.0#heading=h.c063kqhkkg)) 36 | - [ ] Carefully review `?showPointerAreas` for mouse and touch areas 37 | - [ ] Check strings using `?stringTest=dynamic` for layout changes and readability 38 | - [ ] PhET-iO 39 | - [ ] Determine any custom PhET-iO needs 40 | - [ ] PhET-iO tree review complete 41 | - [ ] `phetioFeatured` elements identified/updated 42 | - [ ] Create/update examples.md 43 | - [ ] Lead designer final review before QA (Date: //) 44 | - [ ] (if applicable) Obtain external design team/partners approval 45 | 46 | ### Publication Prep 47 | 48 | - [ ] Update teacher tips (query parameters, new features, model simplification changes, etc.) 49 | - [ ] Update screenshots (including screen-specific screenshots) 50 | - [ ] Update release-notes.md with developer 51 | - [ ] Update responsible_dev.json, as appropriate 52 | - [ ] Verify updates to credits with team (Team, Contributors, QA, Graphic Arts, Sound Design, any Thanks - see [conventions](https://github.com/phetsims/joist/blob/main/js/CreditsNode.js)) 53 | 54 | ### Post Publication 55 | 56 | - [ ] Update Sim Page Info, including tagging any new inclusive features on website 57 | - [ ] Create a GitHub issue for @oliver-phet to alert translators if there have been significant string changes (manual process since Nov 2024) 58 | - [ ] Write newsletter announcement 59 | - [ ] Update website credits 60 | - [ ] Message #website-public to ask web devs to add the latest version to PhET Studio 61 | - [ ] Create 2-3 example presets ([guidelines](https://docs.google.com/document/d/1gZmobd5h1VBZxjwT6ZuDhFIRWWQvQUKD_VgUDZW5-io/edit?tab=t.0)) 62 | - [ ] If already in PhET Studio, recreate the example presets on latest ([instructions](https://docs.google.com/document/d/1gZmobd5h1VBZxjwT6ZuDhFIRWWQvQUKD_VgUDZW5-io/edit?tab=t.0#heading=h.tk5tep7h8l7a)) 63 | - [ ] Decide as a team if a postmortem is applicable, and schedule (Date: //) 64 | 65 | ## Developer Implementation 66 | 67 | - [ ] Feature-complete (Date: //) 68 | - [ ] Sim team sign-off (Date: //) 69 | - [ ] Update model.md, if needed. (Date: //) 70 | - [ ] Update implementation-notes.md, if needed. (Date: //) 71 | - [ ] Code review completed (Date: //) 72 | - [ ] Pre-publication items 73 | - [ ] Memory leak testing 74 | - [ ] Verify credits with lead (Team, Contributors, QA, Graphic Arts, Sound Design, any Thanks - 75 | see [conventions](https://github.com/phetsims/joist/blob/main/js/CreditsNode.js)) 76 | - [ ] Finalize release-notes.md with designer. 77 | - [ ] Add CT tests for public query parameters that need testing. See examples 78 | in [listContinuousTests.js](https://github.com/phetsims/perennial/blob/main/js/listContinuousTests.js) 79 | - [ ] Published (Date: //) 80 | 81 | ## QA 82 | 83 | - [ ] Dev testing issue created (Date: //) 84 | - [ ] Dev testing started (Date: //) 85 | - [ ] Dev testing completed (Date: //) 86 | - [ ] First RC published (Date: //) 87 | - [ ] Test matrices put 88 | in [Testing Matrices Folder](https://drive.google.com/drive/folders/0B6CMwxdP0NGYbW9fTGNCODdYVjQ) 89 | - [ ] RC testing completed (Date: //) 90 | -------------------------------------------------------------------------------- /doc/interactive-highlights-quickstart-guide.md: -------------------------------------------------------------------------------- 1 | # Interactive Highlights - Quickstart Guide 2 | 3 | @author Jesse Greenberg 4 | 5 | A quick guide for adding Interactive Highlights to your PhET Simulation. 6 | 7 | Interactive Highlights are highlights that surround interactive components on mouse and touch input. Interactive 8 | Highlights can benefit many users, and are particularly helpful for users with low vision who need a little extra visual 9 | boldness to identify the interactive components in the sim. 10 | 11 | When a sim supports Interactive Highlights, a toggle switch will be available in the Visual tab of the Preferences 12 | dialog to enable the feature. When enabled, moving a mouse or finger over an interactive component will display a visual 13 | highlight around that component. When the pointer leaves the component the highlight will disappear. 14 | 15 | You can use query parameter flag `interactiveHighlightsInitiallyEnabled` to have Interactive Highlights enabled when the 16 | sim loads. 17 | 18 | ## package.json 19 | 20 | By default, Interactive Highlights are enabled when the sim supports Interactive Description (or alternative input). To 21 | enable both Interactive Description and Interactive Highlights, have the following in the sim's package.json 22 | 23 | ```json 24 | { 25 | "phet": { 26 | "simFeatures": { 27 | "supportsInteractiveDescription": true 28 | } 29 | } 30 | } 31 | ``` 32 | 33 | If you want to enable or disable Interactive Highlights separately from `supportsInteractiveDescription`, you can do so 34 | with 35 | 36 | ```json 37 | { 38 | "phet": { 39 | "simFeatures": { 40 | "supportsInteractiveHighlights": false 41 | } 42 | } 43 | } 44 | ``` 45 | 46 | `supportsInteractiveHighlights` will always override the default from `supportsInteractiveDescription`. 47 | 48 | After modifying package.json, run `grunt update`. 49 | 50 | When Interactive Highlights are supported, there will be a toggle switch in the Visual tab of the Preferences dialog to 51 | enable the feature. 52 | 53 | ## InteractiveHighlighting.ts 54 | 55 | Common code components will now be highlighted when a pointer moves over them. But sim-specific interactive Nodes will 56 | need to be composed with `InteractiveHighlighting.ts` to get this feature. 57 | `InteractiveHighlighting` is a trait that adds listeners to a Node that activate highlights from pointer input. 58 | 59 | Here is an example of composing a Node with InteractiveHighlighting. 60 | 61 | ```js 62 | class MyDraggableNode extends InteractiveHighlighting( Node ) { 63 | public constructor() { 64 | super(); 65 | 66 | // Now presumably it adds its own input listeners to implement dragging. 67 | // ... 68 | } 69 | } 70 | ``` 71 | 72 | ## InteractiveHighlightingNode.ts 73 | 74 | If the trait pattern is inconvenient (or you prefer not to use traits in general) you can extend or instantiate an 75 | InteractiveHighlightingNode which will accomplish the same thing. 76 | 77 | ```js 78 | class MyCompositeNode extends Node { 79 | public constructor() { 80 | super(); 81 | 82 | // InteractiveHighlightingNode is a Node composed with InteractiveHighlighting so you don't have to create your 83 | // own sublcass for the trait pattern. 84 | const subcomponentNode = new InteractiveHighlightingNode(); 85 | 86 | // Now add your own listeners to subcomponentNode. 87 | } 88 | } 89 | ``` 90 | 91 | ## Custom Highlights 92 | 93 | By default, highlights are rectangular and surround the Node's bounds. But the highlight can be customized. By default, 94 | Interactive Highlights will use the same highlight as the focus highlight, so you can set both at once with this setter 95 | from `ParallelDOM.ts`. 96 | 97 | ```js 98 | myNode.focusHighlight = new HighlightPath( focusHighlightShape ); 99 | ``` 100 | 101 | If the Interactive Highlight needs to look different than the focus highlight, you can do that with an additional setter 102 | from `InteractiveHighlighting.ts`. 103 | 104 | ```js 105 | myNode.interactiveHighlight = new HighlightPath( interactiveHighlightShape ); 106 | ``` 107 | 108 | See InteractiveHighlighting.ts for more documentation. 109 | 110 | ## Disabling Interactive Highlights 111 | 112 | The highlights for Interactive Highlights are activated on mouse and touch input. If you need to prevent highlights from 113 | activating (for an icon or instance of a Node that is not interactive) you can set `pickable: false` on the Node. 114 | 115 | If you don't want to use `pickable`, you can also disable Interactive Highlights for a Node with setter/option in 116 | InteractiveHighlighting.ts 117 | 118 | ```js 119 | myNode.interactiveHighlightEnabled = false 120 | ``` 121 | 122 | ## Disposal 123 | 124 | InteractiveHighlighting adds listeners to the Node to activate it on mouse/touch input. Remember to dispose the Node 125 | composed with InteractiveHighlighting if you need to. 126 | 127 | ## Potential Pitfalls 128 | 129 | Try to use default highlights or `HighlightFromNode.ts` for custom highlights if possible. These will manage styling and 130 | repositioning for you. If you use a more custom highlight Node, it is your responsibility to reposition the highlight if 131 | the Node it surrounds resizes or moves. 132 | -------------------------------------------------------------------------------- /intern-info/web-dev-intern-setup.md: -------------------------------------------------------------------------------- 1 | Web Development Intern Setup 2 | = 3 | 4 | # TODO update this with latest information this is fairly out of date as of 2/22 5 | 6 | #### Initial machine setup: 7 | 8 | ###### Hardware Requirements 9 | 10 | * 30-40 GB free storage 11 | * 8GB+ RAM 12 | 13 | There are developers at PhET using Windows and MacOS, if you use a different host OS you may need to independently find 14 | solutions. 15 | 16 | ###### Create file directory: 17 | 18 | * Create a folder named /phet 19 | * Create subfolders /phet/git and /phet/svn 20 | 21 | ###### Setup SSH client: 22 | 23 | * Windows: Install putty from http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html 24 | 25 | #### Setup SVN: 26 | 27 | ###### Install SVN: 28 | 29 | * Windows: You will need access to the command line tools. 30 | * SlikSVN is known to be compatible https://sliksvn.com/download 31 | 32 | ###### Checkout the svn trunk: 33 | 34 | * You will need a good network connection and time as this repository is very large. 35 | * In the `/phet/svn` directory, run the following command 36 | * `svn checkout https://phet.unfuddle.com/svn/phet_svn/trunk trunk --username guest --password guest` 37 | 38 | #### Setup Git: 39 | 40 | ###### Sign up for a Github account. 41 | 42 | * Go to https://github.com/join. 43 | * Use the email address that you intend to use for PhET. 44 | * You will receive a lot of email, so choose your account accordingly. 45 | 46 | ###### Install Git: 47 | 48 | * Windows: Install the software found at http://www.git-scm.com/download/win 49 | * If you want git to remember your username and password (highly recommended), run this command: git config --global 50 | credential.helper store 51 | 52 | ###### Checkout the website repo from Github: 53 | 54 | In the phet/git directory, run this command: 55 | 56 | * `git clone https://github.com/phetsims/website.git` 57 | 58 | ###### Learn the common git commands: 59 | 60 | [Git Tutorial](http://git-scm.com/docs/gittutorial) 61 | 62 | #### Setup the VM: 63 | 64 | 1. Install VirtualBox: https://www.virtualbox.org/wiki/Downloads 65 | 1. Download the OVA files from bayes:/data/phet-vm. The .ova files are about 30GB. 66 | 2. Launch VirtualBox. Go to File > Import Appliance and select the .ova file. 67 | 4. Launch the VM: 68 | > Username: phet 69 | > Password: phet (or ph3t) 70 | 71 | ###### Setup SSH and sync the DB with phet-server 72 | 73 | *Requires access to phet-server* 74 | 75 | 1. Add this text to a new file ~/.ssh/config 76 | ``` 77 | host phet-server 78 | hostname phet-server.int.colorado.edu 79 | user [YOUR Identikey here] 80 | port 22 81 | identityfile ~/.ssh/id_rsa 82 | ``` 83 | 2. Create an RSA key Enter this command in the terminal: `ssh-keygen -t rsa` 84 | 85 | Press enter 4 times, leave the file path as default and the password blank. 86 | 3. Copy the contents of ~/.ssh/id_rsa.pub from the VM to ~/.ssh/authorized_keys on phet-server. 87 | 4. You should now be able to sync the local VM database and document root with phet-server by running ~/Desktop/sync.sh. 88 | 89 | ###### Common commands on the VM: 90 | 91 | * logs = displays the last 10 lines of the Tomcat logfile and appends it to the console in real time. 92 | * apps = cd to the tomcat7 directory 93 | * restart = restarts the varnish service (clears static cache) 94 | * /var/lib/tomcat7/webapps/restart.sh = Delete unpacked files from war and restart tomcat service 95 | * deploy = Rebuilds application from war. Needs to be run after apps/restart.sh 96 | 97 | #### Setup IntelliJ Idea 98 | 99 | ###### Initial Setup 100 | 101 | 1. Sign up for a jetbrains account at the link provided by PhET (Ask the PhET operations manager). 102 | 2. Download the IntelliJ Idea Ultimate edition https://www.jetbrains.com/idea/download/ 103 | 3. On initial launch, sign in with your Jetbrains username and password. 104 | 105 | ###### Project Setup: 106 | 107 | 1. Launch IntelliJ 108 | 2. Choose Open an existing project. 109 | 3. Navigate to phet/svn and click on the "trunk" folder. It should have an IntelliJ icon, not a normal folder icon. 110 | 3. Click OK 111 | 4. Setup Java SDK 112 | 1. Go to File > Project Structure > Project Settings:Project 113 | 5. Select the your locally installed Java SDK under "Project SDK" (Needs to be Java 1.7 not 1.8) 114 | 6. Click OK 115 | 5. Import Website 116 | 6. Go to Project Settings:Modules 117 | 7. Hit the + in the upper left corner and select "Import Module" 118 | 8. Open phet/git/website/ide/intellij/website.iml 119 | 9. Click OK 120 | 6. Setup the style template: 121 | 1. Download the template xml file from https://github.com/phetsims/phet-info/blob/main/ide/idea/phet-idea-codestyle.xml 122 | 2. Put the file in the local IntelliJ directory. Try $HOMEPATH$/.IntelliJIdea14/config/codestyles 123 | 3. Restart IntelliJ, go to File > Settings > Editor > Code Style > Java. 124 | 4. Click the "Manage" button next to "Scheme" and select "phet-idea-codestyle". 125 | 126 | #### Build-tools setup 127 | 128 | 1. Update lines 62-71 in phet/svn/trunk/build-tools/build-local.properties.template with the following: 129 | ``` 130 | # Local website development credentials 131 | local-server.username=phet 132 | local-server.password=phet 133 | 134 | # Local website Tomcat Manager credentials 135 | local-server.tomcatmanager.username=phet 136 | local-server.tomcatmanager.password=phet 137 | 138 | Local website IP address 139 | local-server.ip={IP of the "host-only" network adapter for the VM} 140 | ``` 141 | 3. Update the tomcatmanager credentials for the phet-server and phet-server-dev. These are provided by the PhET web 142 | developer. 143 | 4. Update git.root to be the absolute file path of the phet/git directory you created on your machine. 144 | 2. Update the ssh credentials for phet-server and phet-server-dev to be your IdentiKey username/password. 145 | 3. The file in the same directory as "build-local.properties" 146 | 147 | 148 | -------------------------------------------------------------------------------- /checklists/new-repo-checklist.md: -------------------------------------------------------------------------------- 1 | # New Repository Checklist 2 | 3 | These steps contain the following placeholders that you'll need to fill in: 4 | 5 | - `{{AUTHOR}}` - the name that will appear in `@author` code annotations, e.g. `Jane Doe` 6 | - `{{REPO}}` - the repository name, e.g. `gas-properties`. This should be composed of lower-case characters and dashes, 7 | and should have <=214 characters (see naming constraints 8 | in https://docs.npmjs.com/cli/v7/configuring-npm/package-json). 9 | - `{{TITLE}}` - the simulation's title, e.g. `Gas Properties` 10 | 11 | ## Steps to create a new simulation repo 12 | 13 | At https://github.com/phetsims: 14 | 15 | - [ ] At the top right, press the "+" button and select "New repository". 16 | - [ ] Set the "Owner" combo box to "phetsims". 17 | - [ ] In "Repository name" text field, enter the repository name. 18 | - [ ] In the "Description" text field, enter 19 | `"{{TITLE}}" is an educational simulation in HTML5, by PhET Interactive Simulations.` 20 | - [ ] Leave the "Choose visibility" combo box set to "Public". 21 | - [ ] Leave the "Add a README" toggle switch set to Off. 22 | - [ ] Leave the "Add .gitignore" combo box set to "No .gitignore". 23 | - [ ] Leave the "Add a license" combo box set to "No license". 24 | - [ ] Press the "Create Repository" button. 25 | 26 | Create your working copy of the sim repo: 27 | 28 | - [ ] `cd perennial` 29 | - [ ] Run `grunt create-sim --repo="{{REPO}}" --author="{{AUTHOR}}" --title="{{TITLE}}"` to create the file structure 30 | and skeleton code for the sim. 31 | 32 | In your working copy of the sim repo: 33 | 34 | - [ ] `git init` 35 | - [ ] `git add * .gitignore` 36 | - [ ] `git commit -m "Initial commit"` 37 | - [ ] `git remote add origin https://github.com/phetsims/{{REPO}}.git` 38 | - [ ] `git branch -M main` 39 | - [ ] `git push -u origin main` 40 | - [ ] `cp ../phet-info/git-template-dir/hooks/* .git/hooks/` 41 | 42 | At https://github.com/phetsims/{{REPO}}: 43 | 44 | - [ ] Go to _Settings => Collaborators and teams_. Press the "Add teams" button. 45 | See [team assignment.md](https://github.com/phetsims/phet-info/blob/main/policies/team%20assignment.md) for 46 | assignments by repo type. 47 | - [ ] Create a Sim Checklist issue using 48 | template [sim-checklist.md](https://github.com/phetsims/phet-info/blob/main/checklists/sim-checklist.md). Use " 49 | {{TITLE}} 1.0 main checklist" as the issue name. 50 | 51 | In your working copy of perennial repo: 52 | 53 | - [ ] Add the new repo to `perennial/data/active-repos`. Commit and push. Then pull perennial-alias so these two 54 | checkouts stay in sync. If needed immediately, run `cd perennial/ && grunt generate-data` and commit and push to 55 | update data lists. Otherwise it is done every night as part of daily grunt work. _Note that your sim won't run in 56 | phetmarks until this is done._ 57 | 58 | Other: 59 | 60 | - [ ] Navigate to https://bayes.colorado.edu/dev/phettest/ and click the "Refresh perennial, perennial-alias, and 61 | chipper" button. If you do not know the password, please ask another developer. 62 | - [ ] Apply GitHub labels. 63 | See [github-labels/README.md](https://github.com/phetsims/phet-info/blob/main/github-labels/README.md). 64 | - [ ] Apply branch protection rules 65 | using [protect-branches-for-repo.js](https://github.com/phetsims/perennial/blob/main/js/scripts/protect-branches-for-repo.js). 66 | Follow the instructions in the documentation at the top of the script. 67 | - [ ] If using IDEA/Webstorm (pre-2018), add the git source root for the repository. 68 | - [ ] Follow any remaining "Implementation" tasks in the Main Checklist issue that you created above. 69 | - [ ] If applicable, add any needed dependencies to `phetLibs` in package.json. If you change package.json, 70 | run `grunt update`. 71 | - [ ] Add the sim 72 | to [responsible_dev.json](https://github.com/phetsims/phet-info/blob/main/sim-info/responsible_dev.json). 73 | - [ ] If applicable, add corresponding dependencies from `phetLibs` in package.json to "references" in tsconfig.json. 74 | 75 | ## Steps to create a different type of repo 76 | 77 | At https://github.com/phetsims: 78 | 79 | - [ ] Press the "New" button. 80 | - [ ] Fill in the Description field. (Ask other developers if you need suggestions.) 81 | - [ ] Decide on visibility. (Ask other developers if you're not sure.) 82 | - [ ] Typically do not select options that would initialize the repo by creating files (README, .gitignore, LICENSE). 83 | 84 | In your working copy of the sim repo: 85 | 86 | - [ ] Create the file structure locally. It's best to start (currently) by copying from a similar repository (but 87 | without the `.git` directory). Make sure to keep `.gitignore`, etc. 88 | - [ ] `git init` 89 | - [ ] `git add * .gitignore` 90 | - [ ] `git commit -m "Initial commit"` 91 | - [ ] `git branch -M main` 92 | - [ ] `git remote add origin https://github.com/phetsims/{{REPO}}.git` 93 | - [ ] `git push -u origin main` 94 | - [ ] `cp ../phet-info/git-template-dir/hooks/* .git/hooks/` 95 | 96 | At https://github.com/phetsims/{{REPO}}: 97 | - [ ] Go to _Settings => Collaborators and teams_. Press the "Add teams" button. 98 | See [team assignment.md](https://github.com/phetsims/phet-info/blob/main/policies/team%20assignment.md) for assignments 99 | by repo type. 100 | 101 | In your working copy of perennial repo: 102 | 103 | - [ ] If applicable: Add the new repo to `perennial/data/active-repos`. Commit and push. Pull perennial-alias. If needed 104 | immediately, run `cd perennial/ && grunt generate-data` and commit and push to update data lists. Otherwise it is done 105 | every night as part of daily grunt work. 106 | - [ ] If applicable: Add to any other lists in `perennial/data/`. For example, `active-common-sim-repos` (likely if your 107 | repo ends in `-common`). 108 | 109 | If this repo is a common code dependency for all sims: 110 | 111 | - [ ] Add it to the list of `clone` commands 112 | in [phet-development-overview.md](https://github.com/phetsims/phet-info/blob/main/doc/phet-development-overview.md) 113 | - [ ] Update all sim published README files (because the "Quick Start" section has these git clone commands too). 114 | 115 | Other: 116 | 117 | - [ ] Apply GitHub labels. 118 | See [github-labels/README.md](https://github.com/phetsims/phet-info/blob/main/github-labels/README.md). 119 | - [ ] Apply branch protection rules. 120 | Use [this script to do so](https://github.com/phetsims/perennial/blob/main/js/scripts/protect-branches-for-repo.js). 121 | - [ ] If using IDEA/Webstorm (pre-2018), add the git source root for the repository. 122 | - [ ] Add the repo 123 | to [responsible_dev.json](https://github.com/phetsims/phet-info/blob/main/sim-info/responsible_dev.json). 124 | -------------------------------------------------------------------------------- /ai/core-description/interact.md: -------------------------------------------------------------------------------- 1 | # Interact CLI - Simplified Simulation Control 2 | 3 | The `interact` command provides a human-friendly interface to the keyboard daemon, eliminating curl/JSON complexity. 4 | 5 | ## Setup 6 | 7 | Add to `~/.zshrc` (adjust path for your system): 8 | ```bash 9 | alias interact='sage run ~/phet/root/chipper/js/grunt/tasks/interact.ts' 10 | ``` 11 | 12 | Reload: `source ~/.zshrc` 13 | 14 | If you don't have the alias, you can run the same command directly, e.g. 15 | `~/phet/root/perennial/bin/sage run ~/phet/root/chipper/js/grunt/tasks/interact.ts peek`. That's how we've been 16 | invoking it during this project when the alias wasn't available. 17 | 18 | ## Prerequisites 19 | 20 | Start the keyboard daemon in a separate terminal: 21 | ```bash 22 | cd your-sim-repo 23 | grunt interact-daemon --screens=2 24 | ``` 25 | 26 | This is a "blocking" process that runs until you stop it (Ctrl+C). 27 | 28 | NOTE: It may already be running from a prior session. Check `interact status` to see if it is active. 29 | 30 | ## Core Commands 31 | 32 | ### Observing State 33 | 34 | ```bash 35 | interact peek # Show PDOM (doesn't change focus) 36 | interact look # Show PDOM + focus order (WARNING: changes focus) 37 | interact getFocus # Show currently focused element 38 | interact status # Check daemon status 39 | ``` 40 | 41 | **Important:** `look` generates the focus order by tabbing through all elements, which may hide popups or dialogs if focus leaves them. Use `peek` for non-invasive PDOM inspection. 42 | 43 | ### Navigation 44 | 45 | ```bash 46 | interact tab 5 # Tab forward 5 times 47 | interact tab "Reset All" # Tab to element named "Reset All" (doesn't activate) 48 | interact shiftTab 1 # Shift+Tab once (tab backward) 49 | interact shiftTab 3 # Shift+Tab three times (tab backward) 50 | ``` 51 | 52 | The `tab "name"` command tabs until it finds the named element and stops without pressing any keys. 53 | 54 | **Note:** To tab backward, use `shiftTab`, not `press Shift+Tab`. The `press` command is for activating or controlling the currently focused element. 55 | 56 | ### Activation 57 | 58 | ```bash 59 | interact press Space # Press Space on focused element 60 | interact press Enter # Press Enter on focused element 61 | interact press ArrowDown # Press ArrowDown on focused element 62 | ``` 63 | 64 | Common pattern - tab to element, then activate: 65 | ```bash 66 | interact tab "Reset All" + press Space 67 | interact tab "Submit" + press Enter 68 | ``` 69 | 70 | ### Timing & Control 71 | 72 | ```bash 73 | interact wait 200 # Wait 200ms (useful after actions) 74 | interact reload # Reload simulation (recovery) 75 | ``` 76 | 77 | ### Navigation Between Sims 78 | 79 | ```bash 80 | interact navigate "http://localhost/number-pairs/number-pairs_en.html?brand=phet-io&ea&debugger&screens=5" 81 | ``` 82 | 83 | ## Command Sequences 84 | 85 | Chain commands with `+`: 86 | ```bash 87 | # Open keyboard help 88 | interact tab "Keyboard Shortcuts" + press Space + wait 200 + peek 89 | 90 | # Navigate to Lab screen and survey 91 | interact tab "Lab" + press Space + wait 300 + look 92 | 93 | # Multi-step interaction 94 | interact tab 5 + press ArrowDown + wait 100 + peek 95 | ``` 96 | 97 | ## Options 98 | 99 | ```bash 100 | --daemonPort=3001 # Daemon port (default: 3001) 101 | --daemonHost=localhost # Daemon host (default: localhost) 102 | --continueOnError # Continue on command failure 103 | --raw / --json # Output raw JSON (for LLMs) 104 | --debug # Show debug info 105 | ``` 106 | 107 | ## Output 108 | 109 | Default output is human-readable with: 110 | - Focus information (name, role, checked state, value) 111 | - ARIA live announcements (prefixed with 🔊) 112 | - PDOM tree (with `>>>` marking focused element) 113 | - Focus order (numbered list of tab stops) 114 | 115 | Use `--json` for machine-readable output suitable for LLM agents. 116 | 117 | ## Common Patterns 118 | 119 | ### Initial Orientation 120 | ```bash 121 | # Quick survey without disrupting focus 122 | interact peek 123 | 124 | # Full survey (if you don't mind focus changes) 125 | interact look 126 | ``` 127 | 128 | ### Opening and Reading Keyboard Help 129 | ```bash 130 | interact tab "Keyboard Shortcuts" + press Space + wait 200 + peek 131 | ``` 132 | 133 | ### Screen Switching 134 | ```bash 135 | interact tab "Lab" + press Space + wait 300 + tab "Keyboard Shortcuts" + press Space + peek 136 | ``` 137 | 138 | ### Group Navigation 139 | Many controls are composite widgets (radio groups, sliders, draggables). Tab to them, then use arrow keys: 140 | ```bash 141 | # Tab to radio group, then navigate within it 142 | interact tab "Current Direction" + press ArrowDown + peek 143 | ``` 144 | 145 | ### Error Recovery 146 | ```bash 147 | # If something goes wrong 148 | interact reload 149 | ``` 150 | 151 | ## Understanding Tab Behavior 152 | 153 | The `tab` command has two modes: 154 | 155 | 1. **Numeric**: `interact tab 5` - Tabs forward 5 times sequentially 156 | 2. **Named**: `interact tab "Reset All"` - Tabs until "Reset All" is focused, then stops (doesn't press) 157 | 158 | Named tabbing only works for **tab stops** (focusable elements). It won't find: 159 | - Plain text or headings 160 | - Radio button options (IMPORTANT: for radio buttons, tab to the selected item which is tab-focusable, then use arrow keys) 161 | - Items inside composite widgets 162 | 163 | Check `focusOrder` from `interact look` to see what's actually tab-focusable. 164 | 165 | ## Focus Order Side Effects 166 | 167 | When you run `interact look`, it generates the focus order by tabbing through the entire focus loop. This means: 168 | - Focus will move through all elements 169 | - Popups/dialogs may close if they require focus to stay visible 170 | - The simulation may briefly appear to "flash through" all interactive elements 171 | 172 | Use `interact peek` instead when you need to inspect the PDOM without these side effects. 173 | 174 | ## Design Philosophy 175 | 176 | **Composability**: Chain simple operations to build complex interactions 177 | **Clarity**: Clear command names that match keyboard concepts 178 | **Efficiency**: Minimal JSON overhead (~50-200 tokens per command) 179 | **Debuggability**: Same commands work manually and in scripts 180 | 181 | ## For LLM Agents 182 | 183 | The tool is optimized for AI usage: 184 | - Simple, parseable syntax 185 | - Structured JSON output with `--json` 186 | - All daemon features accessible 187 | - Composable command sequences 188 | - Minimal token overhead 189 | - Clear error messages 190 | 191 | Example LLM workflow: 192 | ```bash 193 | # Discover structure 194 | interact peek --json | parse_pdom 195 | 196 | # Open help to understand controls 197 | interact tab "Keyboard Shortcuts" --json 198 | 199 | # Interact based on discovered structure 200 | interact tab "Show Current Values" + press Space --json 201 | ``` 202 | -------------------------------------------------------------------------------- /doc/fluent-translation-glossary.md: -------------------------------------------------------------------------------- 1 | # Glossary of Terms for Accessible Description Translation 2 | 3 | This glossary of terms covers key terms and concepts translators may need to be aware of when making a translation of the *accessible descriptions* for a simulation or a project using **. 4 | 5 | ## About Accessible Descriptions 6 | - ***Accessible Descriptions*** 7 | - *Accessible descriptions* are the descriptions designed to be accessed through alternative methods, such as text-to-speech, specifically the *Interactive Description* and *Voicing* features. While there is overlap in content with the text visually displayed on the screen, more descriptions are needed to support a diverse range of needs, including non-visual access. Note: The number of PhET simulations that have accessible description that can be accessed through one or both of these description features is growing. 8 | 9 | - ***Speech Synthesis*** and ***Text-to-Speech*** 10 | - *Speech synthesis* is the artificial production of human speech. A computer system used for this purpose is called a speech synthesizer, and can be implemented in software or hardware products. A *text-to-speech (TTS) system* converts language strings (text) into speech. 11 | 12 | - ***Interactive Description*** 13 | - The *Interactive Description* feature provides a robust set of dynamic and contextually relevant descriptions that can be accessed using traditonal screen reader software (e.g. JAWS, NVDA and VoiceOver) while also using alternative input such as a keyboard. The interactive description feature is designed to meet the needs of learners who are comfortable using screen reader software, such as people who blind or have low vision (BLV). 14 | 15 | - ***Voicing*** 16 | - The *Voicing* feature provides a customizable described experience. This includes a robust set of dynamic and contextually relevant *voicing responses* that are delivered natively through a user's browser. No additional screen reader software is required making the *Voicing* feature accessible to a much broader audience--anyone who would like spoken descriptions in addition to other sound and visuals. 17 | 18 | - ***A11y View (Interactive Description)*** 19 | - The *A11y View* is a tool that displays all of the descriptions that are currently designed to be delivered through the *Interactive Description* feature--these descriptions can originate from multiple locations, including the sim repository, common code repositories, and the babel repository. The *A11y View* tool is very useful for first checking to see if parts of the sim have already been translated, and for testing translated description originating from *Fluent* files. At the time of writing (January 2025), the *A11y View* displays the accessible descriptions that are available in the *Interactive Description* feature only for PhET Simulations. Community effort may expand this tool. 20 | 21 | ## Description Terminology 22 | - ***Static State Descriptions*** 23 | - Descriptions strings that are constant--always accurate and true regardless of user interaction. These descriptions are the easiest to translate, and require no additional knowledge of *Fluent* syntax. Common static state descriptions are: 24 | - The first part of the screen summary, often refered to as the 'overview'. 25 | - Names of interactive controls. 26 | - Help text for interactive controls. 27 | 28 | - ***Dynamic State Descriptions*** 29 | - Descriptions strings that update silently in the background, staying in synch with the current state. *Dynamic state descriptions* will have embedded *parameters*. Translating *dynamic state descriptions* and their *parameters* will require knowledge of additional *Fluent* syntax. Common *dynamic state descriptions* are: 30 | - The second part of the screen summary, often referred to as the 'current details'. 31 | - Detailed descriptions of state of objects. 32 | - Names and help text can also be dynamic, but only when absolutely necessary. 33 | 34 | - ***Object Responses*** 35 | - Brief strings or phrases, often quantitative or qualitative values, that convey the current state of an object. Object responses or their parameters are often listed in the re-usable strings section of the *Fluent* file. Descriptions for common code interactions may live in other *Fluent* files in other respositories. Object response are often followed by context responses. Examples of when object responses can be heard are when: 36 | - A learner moves their keyboard focus to an interactve control, like a slider. 37 | - A learner presses arrow keys to change the value on a slider. 38 | 39 | - ***Context Responses*** 40 | - Brief strings or phrases that convey the current state of the surrounding context, beyond the object the user is actively manipulating. This allows for interpreting cause and effect relationships. Context responses often have embedded *parameters*. Context responses can be heard on their own or in addition to object responses. Examples of when context responses can be heard are when: 41 | - A learner checks or unchecks a checkbox. 42 | - A learner moves an object and the new position creates a change to the context. 43 | - A learner activates or toggles a control, causing ongoing changes to the context. 44 | 45 | - ***Parameters*** and ***Re-usable strings*** 46 | - Sub-strings--often used in more than one description--are strings that fill in the changing parts of *State* and *Responsive descriptions*. *Parameters* are designed to capture all meaningful states of a particular description and to minimize wording changes. Because *parameter* are often used in more than one description, they are often listed in the ***re-usable strings*** section at the top of the *Fluent* file. Translators may find the need to add to the re-usable strings section to handle language specific changes. Doing so, is optional, but can make translations more efficient. 47 | 48 | - ***Voicing Responses*** 49 | - *Voicing responses* are the *accessible descriptions* that are delivered through the *Voicing* feature. The *Voicing responses* often consist of the same strings used for *Interactive Description*, but they can differ. You might find a seperate section in the *Fluent* file with *accessible description* for the *Voicing* feature. 50 | 51 | - ***Description Design Framework*** 52 | - PhET created and uses the *Description Design Framework* [Smith and Moore, 2020](https://dl.acm.org/doi/abs/10.1145/3313831.3376460) to design *accessible descriptions*. To learn more, we encourage you to take our free online Coursera course, see [Description Design for Interactive Resources](https://www.coursera.org/learn/description-design-for-interactive-learning-resources). The description terminology above can be referenced in the comments of *Fluent* files. Familiarity with the types of descriptions may provide some helpful context for translation. All *accessible descriptions* are either *State Descriptions* designed to capture the ***current state*** when a user is not actively making changes, or *Responsive Descriptions* designed to describe ***relevant changes*** as they occur in response to user interaction or ongoing changes to the model. There is typically significant overlap between the *accessible descriptions* delivered via the *Interactive Description* and *Voicing features*. 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /checklists/sim-checklist.md: -------------------------------------------------------------------------------- 1 | # {{SIM_NAME}} 1.0 main checklist 2 | 3 | ## Design 4 | 5 | ### **Prep** 6 | 7 | - [ ] **Sim folder and design doc created** (Date: //) 8 | - [ ] Create sim folder in PhET Sim Design Folder on [Google Drive](() AND [Microsoft Sharepoint](https://o365coloradoedu.sharepoint.com/sites/PHYS-phet-pilot/PhET%20Files/Forms/AllItems.aspx?id=%2Fsites%2FPHYS%2Dphet%2Dpilot%2FPhET%20Files%2FPhET%20Files%2FPhET%20Sim%20Design&viewid=3aa550f4%2Df9ef%2D4871%2Dbcb3%2Da192486a9aaa) 9 | - [ ] In the SharePoint folder, add link to Google Drive folder 10 | - [ ] Create design doc in the sim folder on Google Drive 11 | 12 | ### Scope 13 | 14 | - [ ] **Review user feedback** 15 | - [ ] *If a 16 | Port:* [Google Form suggestions reviewed](https://docs.google.com/spreadsheets/d/1KkvutfIVwZLi5-jz_DVP3zC8jXkzF32-hzMI4ztB1uY/edit?resourcekey#gid=324007787&fvid=677625918) 17 | - Ask developer to move tickets from Unfuddle to GitHub (and create the new repo if not done) 18 | - [ ] *If a new 19 | sim:* [Google Form suggestions reviewed](https://docs.google.com/spreadsheets/d/1KkvutfIVwZLi5-jz_DVP3zC8jXkzF32-hzMI4ztB1uY/edit?resourcekey#gid=324007787&fvid=898967246) 20 | - [ ] Schedule kick-off meeting 21 | - Scope of additional features for this release (Basics Sounds, Core Description, Alternative Input, Pan and Zoom, Interactive Highlights, Dynamic Locale, PhET-iO/Studio are assumed as of Nov 2025) 22 | - [ ] Sound & Sonification 23 | - [ ] Interactive Description 24 | - [ ] Mobile description included 25 | - [ ] Voicing (specify Core or Full) 26 | - [ ] Regional Character Sets 27 | - [ ] *For Ports*: Paste all issues that will be included OR list features (useful for release notes): 28 | - [{{GITHUB PLACEHOLDER LINK}}](https://github.com/phetsims/phet-info) 29 | - {{NEW SIM FEATURE PLACEHOLDER, e.g., Stopwatch added.}} 30 | - [ ] Create feature-specific milestone deadlines for simulation sub-epics in Monday. Reviewed and updated on a regular basis. 31 | 32 | ### Design (Pre-QA) 33 | 34 | - [ ] Ensure design doc has sections for relevant features or create feature-specific design docs 35 | - [ ] Learning goals and standards identified 36 | - [ ] Design concept complete 37 | - [ ] Wireframes complete 38 | - [ ] Mockups complete 39 | - [ ] Mockups checked for [color contrast](https://docs.google.com/document/d/1rlVX9DHXclCtpcFV-5YAoA0uI0Ui_H1mzPJck7v8PcM/edit?tab=t.0) 40 | - [ ] [Essential Exceptions](https://docs.google.com/document/d/1buKmqjn9hiYrUpPjcEeAmgX0HDd-KO2G87aKBq5Gjjw/edit?usp=sharing) noted 41 | - [ ] Carefully review `?showPointerAreas` for mouse and touch areas 42 | - [ ] Check strings using `?stringTest=dynamic` for layout changes and readability 43 | - [ ] Core Description reviewed by external designer - [CORE REVIEW CHECKLIST](https://github.com/phetsims/phet-info/blob/main/checklists/core-description-review-checklist.md) 44 | - [ ] PhET-iO 45 | - [ ] Determine any custom PhET-iO needs 46 | - [ ] PhET-iO tree review complete 47 | - [ ] `phetioFeatured` elements identified 48 | - [ ] Create examples.md 49 | - [ ] [Interviews](https://drive.google.com/drive/folders/0B6CMwxdP0NGYVkYyOTZBVk8tdDA?resourcekey=0-rOMQFMdLt8biIpZ5iooCnQ) complete (Date: //) 50 | - [ ] Results reported to team 51 | - [ ] Notes pasted into design doc 52 | - [ ] Interview recordings backed up to Sharepoint 53 | - [ ] No more feature requests (Date: //) 54 | - [ ] Lead designer final review before QA (Date: //) 55 | - [ ] (if applicable) Obtain external design team/partners approval 56 | 57 | ### Publication Prep 58 | 59 | - [ ] *If a Port:* If the legacy sim or project name differs from HTML5, notify the website team at least on month prior to publication ([example](https://github.com/phetsims/models-of-the-hydrogen-atom/issues/161)) 60 | - [ ] Teacher Tips created, uploaded, and added to sim design folder on SharePoint 61 | - [ ] Verify credits with team (Team, Contributors, QA, Graphic Arts, Sound Design, any Thanks - see [conventions](https://github.com/phetsims/joist/blob/main/js/CreditsNode.js)) 62 | - [ ] Create Main screenshot and Auxiliary screenshots (up to 3 additional) for sim assets folder (read [this](https://github.com/phetsims/QA/blob/main/documentation/qa-book.md#screenshots)) 63 | - [ ] Create Screen-specific screenshots for metadata service ( 64 | see [naming convention](https://github.com/phetsims/website/issues/1322#issuecomment-1010320827)) 65 | - [ ] [Prepare and Update Sim Page Info](https://docs.google.com/document/d/1JtFR0paPJIU19ybn3SwkMO-ZvRCr2a_KRMPUe-OikAc/edit?tab=t.0#heading=h.94p3cgxenan4) (keywords, (filter) categories, description, learning goals, related sims, inclusive features) 66 | - [ ] **Make sim visible on website (Invisible -> Published)** 67 | - [ ] Clear "Metadata caches" on 68 | the [Basic Administration Caches](https://phet.colorado.edu/?wicket:bookmarkablePage=:edu.colorado.phet.website.admin.AdminCachesPage) 69 | page 70 | 71 | ### Post Publication 72 | 73 | - [ ] *If a Port:* Review legacy gold star activities. For appropriate activities, tag the HTML5 version and UNTAG the deprecated version. Contact Diana for support. 74 | - [ ] Draft newsletter entry 75 | - [ ] Ask web devs to add to PhET Studio (#website-public Slack channel) 76 | - [ ] Create 2-3 example PhET Studio presets ([guidelines](https://docs.google.com/document/d/1gZmobd5h1VBZxjwT6ZuDhFIRWWQvQUKD_VgUDZW5-io/edit?tab=t.0)) 77 | - [ ] Announce sim publication in #general Slack channel and celebrate! 78 | - [ ] Create a GitHub issue for Oliver `@oliver-phet` to alert translators that a new sim is available for translation for new sim publications OR if there have been significant string changes (manual process since Nov 2024) 79 | - Legends of Learning (LoL) Partnership Tasks 80 | - [ ] [Icons](https://docs.google.com/document/d/1GmLNE31gs8hQYGze3xwmN9k7B6gu7lQ7wJe2phqdH9Y/edit) for each 81 | screen created and uploaded to Drive 82 | - [ ] [Metadata](https://docs.google.com/spreadsheets/d/1umIAmhn89WN1nzcHKhYJcv-n3Oj6ps1wITc-CjWYytE/edit#gid=562591429) 83 | for each screen (description, vocab words, questions for before/after sim use) 84 | - [ ] [Deliver](https://docs.google.com/spreadsheets/d/1umIAmhn89WN1nzcHKhYJcv-n3Oj6ps1wITc-CjWYytE/edit#gid=0) 85 | - ~~Send Simulation Notification from the Admin page (to alert translators)~~ 86 | - [ ] Decide as a team if a postmortem is applicable, and schedule (Date: //) 87 | 88 | 89 | ## Developer Implementation 90 | 91 | - [ ] Repository created by 92 | following [new-repo-checklist.md](https://github.com/phetsims/phet-info/blob/main/checklists/new-repo-checklist.md) ( 93 | Date: //) 94 | - [ ] Development started (Date: //) 95 | - [ ] Sim is "feature complete" (Date: //) 96 | - [ ] QA team "first look" (Date: //) 97 | - [ ] Interviews may happen around here (see above) 98 | - [ ] Sim team sign-off (Date: //) 99 | - [ ] Code review completed (Date: //) 100 | - [ ] Sim dev test completed (Date: //) 101 | - [ ] Sim RC tests completed (Date: //) 102 | - [ ] Pre-publication items 103 | - [ ] Add CT tests for public query parameters that need testing. See examples 104 | in [listContinuousTests.js](https://github.com/phetsims/perennial/blob/main/js/listContinuousTests.js) 105 | - [ ] Published (Date: //) 106 | 107 | ## QA 108 | 109 | - [ ] *If a Port:* Legacy sim tested for bugs; issues reported in repo 110 | - [ ] Dev testing issue created (Date: //) 111 | - [ ] Dev testing started (Date: //) 112 | - [ ] Dev testing completed (Date: //) 113 | - [ ] First RC published (Date: //) 114 | - [ ] Test matrices put 115 | in [Testing Matrices Folder](https://drive.google.com/drive/folders/0B6CMwxdP0NGYbW9fTGNCODdYVjQ) 116 | - [ ] RC testing completed (Date: //) 117 | -------------------------------------------------------------------------------- /project-management/management-granularity-levels.md: -------------------------------------------------------------------------------- 1 | # Granularity Levels in Project Management Software 2 | 3 | As we explore project management software, it has become clear that there are different levels of interest in github 4 | issue integration as well as management usage with these softwares. This document's goal is to first and foremost 5 | identify and define the different levels of project management granularity in our organization, discuss the diferring 6 | opinions related to Github integration, as well as identify the relationship between github and a project management 7 | software at the different levels. 8 | 9 | ## Github Integration Main Arguments 10 | 11 | Below you will find the two main arguments that have arisen when talking about Github integration. Obviously there is 12 | much more nuance to these discussions that cannot be captured here, but the opinions are summarized to give context 13 | around processes that may develop as well as inform the levels of granularity identified later on in this document. 14 | 15 | ### Github Integration is Necessary 16 | 17 | Main Points: 18 | 19 | - Integration will reduce duplication for day-to-day workflows 20 | - It is difficult to separate github level issues from iteration specific goals 21 | - Integration will reduce space for errors 22 | - Integration will reduce project maintenance work 23 | 24 | Overall, proponents of this argument see difficulty in separating our day-to-day workflows in Github from planning work 25 | done in a project management tool. They also see increased value to members across departments who may not rely on 26 | Github as much as the development team. Many decisions are already made at the Github issue level. If the project 27 | management tool is not integrated with Github it may not reflect these decisions, and lead to erroneous planning down 28 | the line. It is most beneficial to know that all workflows are synced up so that we can truly visualize all the work 29 | being completed and how the progress of a task rolls up into its associated epic. 30 | 31 | ### Github Integration is Unnecessary 32 | 33 | Main Points: 34 | 35 | - Github issues are too granular for high level overviews 36 | - Proper integration takes time to set up and maintain 37 | - Hidden integration errors could lead to confusion and miscommunication 38 | - Planning workflows exist that would not rely on github issue integration for management 39 | 40 | It is important to note that it is not that proponents of this argument see no value in Github integration, rather they 41 | do not see it as a critical element of successful project management tool adoption. Proponents of this argument believe 42 | that high level project planning, focusing on epics, grant deliverables, etc. does not require the granular view of 43 | github issues. Most importantly they believe that the project would still receive a high amount of benefit from adopting 44 | project management tools focused solely on high level planning, and that issue level granularity is covered by our 45 | workflows in Github. There is also concern that integration could negatively tamper with our current Github workflows. 46 | Lag in one or both tools, as well as erroneous syncing could make our granular level issue management worse rather than 47 | better. Thorough research and testing would be required to ensure integration would not hamper already positive 48 | experiences. 49 | 50 | ## Levels of Granularity 51 | 52 | This document identifies four levels of granularity from an Epic level, to a Subtask level. This is not to indicate that 53 | there is no spectrum between all these levels, but rather to provide concrete points to assess our workflow needs along 54 | the spectrum. 55 | 56 | ### :weight_lifting: Epic Level 57 | 58 | Example: Epics, grant deliverables, releases 59 | 60 | #### Summary 61 | 62 | The Epic level is only focused on the due dates, and timeline for sim releases, publications, and other grant/client 63 | deliverables. It can be helpful to think of this level on a quarter-to-quarter, or even year-to-year basis. This level 64 | requires high input from administrative and management positions, but is only used as a reference for developers, 65 | designers, QA, etc. 66 | 67 | #### Github's Role 68 | 69 | Benefits could potentially come from task roll up, but other than that zero github input needed. Task roll up would only 70 | require a one-way sync. 71 | 72 | ### :woman_scientist: Phase Level 73 | 74 | Example: Iteration planning, epic milestones 75 | 76 | #### Summary 77 | 78 | The Phase level is focused on scheduling epics and epic milestones (design complete, development complete, etc.) inside 79 | of two week chunks. This level of planning requires prioritization of epics, when we plan to work on epics within our 80 | iteration schedule, as well as the amount of effort we can put in towards each epic. A high amount of input is needed 81 | from administrative and management positions, with a medium amount of input needed from others. This is mostly used as a 82 | reference for the majority of team members with iteration planning being the highest point of contribution. 83 | 84 | #### Github Role 85 | 86 | It is not uncommon for epic milestones to have associated github issues ( dev tests, initial screen development, etc.). 87 | Integration for these epic milestone issues would be necessary, however can be filtered by a label. These issues would 88 | require one way sync only. It is not expected that team members will comment or update cards from the management end, 89 | rather the Github issue would drive the progress in management tooling we choose. 90 | 91 | ### :microscope: Task Level 92 | 93 | Example: Iteration goals, iteration task tracking 94 | 95 | #### Summary 96 | 97 | The Task level is focused on the specific tasks and goals we wish to accomplish during an iteration. This level would 98 | help us track the status of an iteration, as well as add emergent work that was unexpected and may delay an iteration 99 | goal (and perhaps even an epic). Teams may reference this level daily to discuss work for the day during standups, as 100 | well as update task status, add new goals, move tasks into and out of the backlog. This level requires a medium amount 101 | of input from administrative and management positions, with a high amount of input needed from others. Team members 102 | consistently contribute and reference this level. 103 | 104 | #### Github's Role 105 | 106 | Currently PhET uses a mixture of issues and draft issues (cards) to organize this work. These issues must be integrated 107 | with a two-way sync. Team members are allowed to update issues both in github as well as in management tooling, reducing 108 | the need to jump back and forth between tools. Labels would need to be used to sync issues appropriately, as well as 109 | filter which issues are synced and which are not. 110 | 111 | ### :dna: Subtask Level 112 | 113 | Example: Issues, bugs, commits 114 | 115 | #### Summary 116 | 117 | The Subtask Level is focused on the incremental work that gets done on a day-to-day and sometimes hour-to-hour basis. 118 | This level includes tracking commits, designer feedback/comments, discussions, bug reports, and any issues that may be 119 | worked on at any time wether they are directly related to an epic or not. Team members may reference this level multiple 120 | times throughout a work day to track their own contributions, as well as the current work status of team members. This 121 | level requires very little input from administrative and management positions, with almost all input coming from the 122 | individual. This level is critical to an individual's workflow and in many cases is unique and specific to the 123 | individual. 124 | 125 | #### Github's Role 126 | 127 | This level requires the largest amount of integration with Github. All issues will be synced over. Team members can work 128 | seamlessly in either tool and expect efficiency and updates both ways. Labels may be used to organize issues on project 129 | boards, but will not be used to filter. Two-way sync is critical at this level, as is flexibility or a large cap on the 130 | amount of monthly syncs we are allowed. 131 | -------------------------------------------------------------------------------- /doc/vegas-description-quickstart-guide.md: -------------------------------------------------------------------------------- 1 | # Vegas Description - Quickstart Guide 2 | 3 | @author Jesse Greenberg 4 | 5 | A quick guide for adding Core Description to PhET game screens that use vegas components. 6 | 7 | This guide assumes you have already implemented the patterns in 8 | the [Core Description Quickstart Guide](https://github.com/phetsims/phet-info/blob/main/doc/core-description-quickstart-guide.md). 9 | You should be comfortable with `accessibleName`, `accessibleHelpText`, `accessibleParagraph`, `pdomOrder`, and the 10 | strings organization described there. The focus here is on vegas-specific structure, components, and focus management. 11 | 12 | ## Overall Process 13 | 14 | - Disable the default `ScreenView` accessible sections that are tailored to standard sims. 15 | - Build each game phase on the vegas screen node classes (`LevelSelectionScreenNode`, `ChallengeScreenNode`, 16 | `RewardScreenNode`) to get consistent structure and heading hierarchy. 17 | - Use `pdomOrder` within each vegas screen node to organize headings, controls, and descriptive content exactly as 18 | specified in the design document. 19 | - Prefer vegas UI components for default accessible names, help text, and context responses. 20 | - Manage focus transitions whenever content hides or changes. Some of this will be automatic in `visibleProperty` 21 | observers. 22 | - Verify context responses (alerts) for button actions and game outcomes, augmenting the vegas defaults with 23 | sim-specific behavior. 24 | 25 | ## Implementation Steps 26 | 27 | ### 1. Prepare the ScreenView 28 | 29 | `ScreenView` includes accessible sections that work for most sims but not for vegas games. Disable them so you can control 30 | the structure with vegas screen nodes. 31 | 32 | ```ts 33 | const gameScreenView = new ScreenView( { 34 | includeAccessibleSectionNodes: false 35 | } ); 36 | ``` 37 | 38 | From this point forward, one of the vegas screen node classes should own the accessible structure for each game phase. 39 | 40 | ### 2. Level Selection Screens 41 | 42 | Extend `LevelSelectionScreenNode`, or compose with it, for any UI where the player chooses a level or game mode. 43 | 44 | - The node supplies headings and sections for "Choose Your Level" and (optionally) "Game Options". 45 | - Set `accessibleIncludeOptionsDescription` if the screen includes game option controls. 46 | - Use `pdomOrder` on the provided section nodes to arrange content as specified by the design document. 47 | 48 | ```ts 49 | class MyLevelSelectionScreen extends LevelSelectionScreenNode { 50 | public constructor() { 51 | const levelButtons = new LevelSelectionButtonGroup(); 52 | super( simScreenNameProperty, levelButtons, { 53 | accessibleIncludeOptionsDescription: true 54 | } ); 55 | 56 | const infoButton = new GameInfoButton(); 57 | const timerToggleButton = new GameTimerToggleButton(); 58 | const resetAllButton = new ResetAllButton(); 59 | 60 | this.accessibleLevelsSectionNode.pdomOrder = [ levelButtons, infoButton ]; 61 | this.accessibleOptionsSectionNode.pdomOrder = [ timerToggleButton, resetAllButton ]; 62 | } 63 | } 64 | ``` 65 | 66 | ### 3. Challenge Screens 67 | 68 | Use `ChallengeScreenNode` for gameplay challenges. It provides headings and sections for the main challenge, answer 69 | controls, and status indicators. 70 | 71 | - Pass level/challenge counts so vegas can describe progress. 72 | - Populate each section via `pdomOrder`, keeping interactive elements grouped logically. 73 | - The game challenge content goes in the `accessibleChallengeSectionNode`. 74 | - Buttons and controls for submitting answers go in the `accessibleAnswerSectionNode`. 75 | - Status bars go in the `accessibleStatusSectionNode`. 76 | 77 | ```ts 78 | class MyChallengeScreen extends ChallengeScreenNode { 79 | public constructor() { 80 | super( { 81 | challengeNumberProperty: challengeNumberProperty, 82 | challengeCountProperty: challengeCountProperty, 83 | levelNumberProperty: levelNumberProperty 84 | } ); 85 | 86 | const interactionArea = new GameDiagram(); 87 | const numberControl = new NumberControl(); 88 | const checkAnswerButton = new CheckButton(); 89 | const tryAgainButton = new TryAgainButton(); 90 | const statusBar = new FiniteStatusBar(); 91 | 92 | this.accessibleChallengeSectionNode.pdomOrder = [ interactionArea, numberControl ]; 93 | this.accessibleAnswerSectionNode.pdomOrder = [ checkAnswerButton, tryAgainButton ]; 94 | this.accessibleStatusSectionNode.pdomOrder = [ statusBar ]; 95 | } 96 | } 97 | ``` 98 | 99 | If the design calls for an accessible prompt or answer summary, populate `accessibleChallengePrompt` or 100 | `accessibleAnswerSummary` (see options below). If your game challenge does not include one of these sections, you can 101 | make it invisible with the `visible` setter. 102 | 103 | ### 4. Reward Screens 104 | 105 | For end-of-level feedback, use `RewardScreenNode`. It exposes a single section for reward content. 106 | 107 | ```ts 108 | class MyRewardScreen extends RewardScreenNode { 109 | public constructor() { 110 | super(); 111 | 112 | const levelCompletedNode = new LevelCompletedNode(); 113 | this.accessibleRewardSectionNode.pdomOrder = [ levelCompletedNode ]; 114 | } 115 | } 116 | ``` 117 | 118 | ### 5. Prefer Vegas Components 119 | 120 | Vegas buttons and controls include default labels, accessible names, accessible help text, and context responses that 121 | match PhET game design language. Use them whenever the UI design aligns. 122 | 123 | - GameInfoButton, GameTimerToggleButton, TryAgainButton, etc. 124 | - Review [vegas/js/buttons/](https://github.com/phetsims/vegas/tree/main/js/buttons) for the full list. 125 | 126 | If you need to override defaults, supply string properties through the options, matching the naming conventions from the 127 | core guide. 128 | 129 | ### 6. Manage Focus Transitions 130 | 131 | Screen content in vegas games is dynamic. Ensure focus is never lost during a transition and always moves somewhere 132 | meaningful: 133 | 134 | - Set `visibleProperty` on `LevelSelectionScreenNode` and `ChallengeScreenNode` so those screens manage 135 | focus and default context responses for you when visibility changes. If you cannot use `visibleProperty`, call 136 | `handleShow()` directly after the screen appears. 137 | - When you swap in reward content, set `visibleProperty` on `LevelCompletedNode` 138 | or use `show()`/`hide()` on `RewardDialog` so focus lands correctly and the built-in responses fire. 139 | - If a button hides itself (e.g., `CheckButton`, `ShowAnswerButton`), move focus explicitly to the next logical 140 | control (TryAgainButton, NextButton, or ShowAnswerButton). The flow will be outlined in the game design document. 141 | - When the `GameInfoButton` opens a dialog, focus is moved inside the dialog automatically. Make sure closing the dialog 142 | returns focus to the element that launched it or to a follow-up control if the design specifies one. 143 | 144 | ### 7. Context Responses and Alerts 145 | 146 | Vegas provides standard context responses for common game states. Use them before creating custom strings: 147 | 148 | - Example keys: `VegasFluent.checkButton.accessibleContextResponseIncorrect`, 149 | `VegasFluent.checkButton.accessibleContextResponseCorrectPoints`. 150 | - For unique scenarios, implement additional alerts in your game logic with `addAccessibleContextResponse`. 151 | 152 | ### 8. Strings and Naming 153 | 154 | Continue to store accessibility strings under the `a11y` key in the sim's strings.json. See the core guide for details. 155 | 156 | ## Vegas Accessibility Options Reference 157 | 158 | Refer to vegas source code for information about each of these. 159 | 160 | The design document will call out when to use these options: 161 | 162 | - ChallengeScreenNode 163 | - accessibleChallengePrompt 164 | - accessibleAnswerSummary 165 | - InfiniteStatusBar 166 | - accessibleMessageStringProperty 167 | 168 | Additional options relating to vegas accessibility: 169 | 170 | - LevelSelectionScreenNode 171 | - accessibleIncludeOptionsDescription 172 | - LevelSelectionButton 173 | - accessibleBriefLevelName 174 | 175 | ## Reference Implementations 176 | 177 | - build-an-atom 178 | - vegas/js/demo/ (lightweight samples for vegas buttons) -------------------------------------------------------------------------------- /doc/core-voicing-quickstart-guide.md: -------------------------------------------------------------------------------- 1 | # Core Voicing - Quickstart Guide 2 | 3 | @author Jesse Greenberg 4 | 5 | A quick guide for adding Core Voicing to a PhET simulation. 6 | 7 | Voicing uses speech synthesis to make PhET simulations more accessible. Unlike Interactive Description, which primarily 8 | uses the Parallel DOM for screen reader support, Voicing provides a built-in solution that self-voices content. 9 | 10 | Core Voicing is a subset of the full Voicing feature. It focuses on four main elements: 11 | 12 | - Voicing names for interactive objects 13 | - Voicing hint responses 14 | - Screen summary content (overview, details, hints) 15 | - Reading blocks for prominent text 16 | 17 | These features are generally quicker to design and implement but still significantly improve accessibility. Because 18 | Voicing content often overlaps with Interactive Description, it is recommended to implementing both at once. 19 | 20 | This guide outlines the fundamentals of Core Voicing and shows how to integrate it into your simulation. Refer to the 21 | source code documentation for more advanced details. 22 | 23 | ## Overall Process 24 | 25 | The simulation design team typically provides Core Voicing content in a table, often alongside Interactive Description 26 | details. Developers then reference those tables to apply the appropriate Voicing options in the code. For sim-specific 27 | components, you will use scenery’s Voicing classes and mixins to ensure interactive objects speak their assigned 28 | content. 29 | 30 | ## package.json 31 | 32 | In package.json, set the following flag to enable Core Voicing: 33 | 34 | ```json 35 | { 36 | "phet": { 37 | "simFeatures": { 38 | "supportsVoicing": true 39 | } 40 | } 41 | } 42 | ``` 43 | 44 | After modifying package.json, run `grunt update` to apply changes. 45 | 46 | ## Testing 47 | 48 | Once Core Voicing is enabled in package.json, launch the simulation. In the Preferences dialog, go to the Audio tab 49 | and enable Voicing. A toolbar will then appear on the left with buttons that play screen summary content. 50 | 51 | Some components already support Voicing by default. Click them to hear their audio. For other UI elements, add Voicing 52 | using the appropriate options and setters. 53 | 54 | For debugging, use the ?logVoicingResponses query parameter to log spoken output in the console. 55 | 56 | ## Screen Summary 57 | 58 | Use `ScreenSummaryContent.ts` in joist to implement the screen summary. 59 | 60 | By default, this pulls the same content used by Interactive Description. If the Voicing content differs from Core 61 | Description, you can customize with options. 62 | 63 | For each screen, the design document provides text for the play area, control area, current details, and an interaction 64 | hint. Pass these to the `ScreenSummaryContent`, then include that content as an option in the `ScreenView` constructor. 65 | 66 | ```ts 67 | const screenView = new ScreenView( { 68 | screenSummaryContent: new ScreenSummaryContent( { 69 | playAreaContent: playAreaDescriptionStringProperty, 70 | controlAreaContent: controlAreaDescriptionStringProperty, 71 | currentDetailsContent: [ firstDescriptionStringProperty, secondDescriptionStringProperty ], 72 | 73 | // An example of how to set content that will be customized for Voicing. 74 | interactionHintContent: { 75 | descriptionContent: [ descriptionInteractionHintStringProperty ], 76 | voicingContent: [ voicingInteractionHintStringProperty ] 77 | } 78 | } ) 79 | } ); 80 | ``` 81 | 82 | ## Voicing.ts 83 | 84 | `Voicing.ts` is a trait defined in Scenery that you mix into any Scenery Node. 85 | 86 | ```ts 87 | const voicingRectangle = new ( Voicing( Rectangle ) )( 0, 0, 40, 40, { 88 | fill: 'green', 89 | 90 | // Voicing options 91 | voicingNameResponse: nameStringProperty, 92 | voicingHintResponse: hintStringProperty 93 | } ); 94 | ``` 95 | - `voicingNameResponse` is the name for the component and is spoken when the component is focused or activated. 96 | - `voicingHintResponse` is a brief hint and is spoken after the name when the component is focused. 97 | Together, these options satisfy almost all Core Voicing requirements. 98 | 99 | ## Default Content for common code 100 | 101 | Many components already determine their default Voicing content. 102 | 103 | - If a component has an `accessibleName`, it is used for `voicingNameResponse`. 104 | - If it has an `accessibleHelpText`, that is used for `voicingHintResponse`. 105 | 106 | As a result, Core Voicing often comes for free once Core Description is in place. However, you can 107 | always override these defaults by supplying your own `voicingNameResponse` and `voicingHintResponse` options. 108 | 109 | NOTE: PhET is in the process of implementing this behavior in common code components. If you find a component where 110 | these options do not work as expected, please create an issue in the component repository. 111 | 112 | ## Sim Specific Components 113 | 114 | For custom elements, compose your Node with Voicing. You can then specify `voicingNameResponse` and 115 | `voicingHintResponse`. If a component can be pressed or dragged, also set `voicingPressable: true` to announce its 116 | content during interaction. 117 | 118 | ```ts 119 | const voicingCircle = ( new Voicing( Circle )( 25, { 120 | voicingNameResponse: nameStringProperty, 121 | voicingHintResponse: hintStringProperty, 122 | voicingPressable: true 123 | } ) ); 124 | ``` 125 | 126 | ## Reading Blocks 127 | 128 | Reading Blocks highlight important text so it can be spoken when clicked or focused. This text is identified in the 129 | design document. 130 | 131 | In most cases, implement Reading Blocks with VoicingText or VoicingRichText: 132 | 133 | ```ts 134 | const voicingText = new VoicingText( myStringProperty ); 135 | const voicingRichText = new VoicingRichText( myStringProperty ); 136 | ``` 137 | 138 | By default, they also add their text to the PDOM for Interactive Description. Make sure they appear in the correct 139 | location in the `pdomOrder`. 140 | 141 | ## Interactive Highlights 142 | 143 | Interactive Highlights is already included through Voicing, so you don’t need to separately mix in 144 | `InteractiveHighlighting`. Any Node using Voicing will automatically gain Interactive Highlights features. For more 145 | details, see [the Interactive Highlights quickstart guide](https://github.com/phetsims/phet-info/blob/f9fcab965f857627b7a2da4d0bb90f95ea9edc1e/doc/interactive-highlights-quickstart-guide.md). 146 | 147 | ## Accessibility Strings 148 | 149 | Accessibility strings for Core Voicing follow the same guidelines as Core Description. For details, see 150 | the Core Description quickstart guide. 151 | 152 | - If a string is only used for Voicing, include the option name of its usage site (like `voicingNameResponse`) in the 153 | key. 154 | - If a string is only used for Voicing but not tied to a specific option, prefix the key with "voicing" to clarify its 155 | purpose. 156 | - If there is an equivalent string that appears in Interactive Description (`description`), prefix its key with 157 | `description` to show it is the Interactive Description version, and use the `voicing` prefix for the Voicing version. 158 | 159 | ```json 160 | { 161 | "a11y": { 162 | "screenA": { 163 | "screenSummary": { 164 | "playArea": { 165 | "voicing": { 166 | "value": "Voicing specific play area content..." 167 | }, 168 | "description": { 169 | "value": "Contains a light source and..." 170 | } 171 | } 172 | } 173 | } 174 | }, 175 | "visibilityCheckbox": { 176 | "accessibleNameResponse": { 177 | "value": "Units" 178 | }, 179 | "voicingNameResponse": { 180 | "value": "Units Visibility" 181 | }, 182 | "voicingHintResponse": { 183 | "value": "Toggle to hide units" 184 | } 185 | } 186 | } 187 | ``` 188 | 189 | ## Disposal 190 | 191 | Voicing adds listeners that enable speech from input events. When a Node using Voicing is no longer needed, call its 192 | `dispose()` method to avoid memory leaks. 193 | 194 | ## Additional Resources 195 | 196 | ### Alt Input 197 | 198 | Voicing is closely integrated with alternative input. Refer to the Alternative Input quickstart guide for that 199 | implementation: 200 | [Alternative Input Quickstart Guide](https://github.com/phetsims/phet-info/blob/main/doc/alternative-input-quickstart-guide.md). 201 | 202 | ### Core Description 203 | 204 | Core Voicing complements Core Description. If you already support Core Description, much of your 205 | voicing content will come “for free.” For details, 206 | see [Core Description Quickstart Guide](https://github.com/phetsims/phet-info/blob/main/doc/core-description-quick-start-guide.md). --------------------------------------------------------------------------------