Utilities for reading structure/repos.json and operating on
OpenPhysics repositories. These scripts are intended for local use and for AI agents working in
the monorepo checkout.
jqghfor GitHub sync commands- Node.js +
npm install(in the repo root) for the screenshot and thumbnail scripts — installs Playwright and sharp
| Script | Purpose |
|---|---|
parse-repos.sh |
Core parser/CLI for repos.json |
list-repos.sh |
Human-friendly listing wrapper |
check-repos-catalog.sh |
Validate repos.json against structure/repos.schema.json + fleet invariants |
clone-fleet.sh |
Clone/update every catalog repo into the workspace as a sibling |
fleet |
Run a git command across every local checkout (fleet push, fleet status -s, …) |
fleet-exec.sh |
Run a command across many repos and open one PR each |
../doc/fleet-git.md |
Cheat sheet: everyday git across local checkouts (pull/push/status all) |
sync-github-metadata.sh |
Push description + website to GitHub |
sync-github-settings.sh |
Check/apply GitHub repo settings baseline (security + feature flags) |
../doc/github-repo-settings.md |
Documented GitHub settings baseline for sims |
create-sim.sh |
Bootstrap a new sim from SceneryStackTemplate (rename + N screens; --onboard / --pr / --shared-model) |
sync-claude-settings.sh |
Roll the scenerystack Claude Code plugin out to sim repos' .claude/settings.json |
lib/repos.sh |
Bash helper functions for other scripts |
check-repo-compliance.sh |
README/CI/structure compliance (bootstrap, i18n, memory-leak suite, KeyboardHelp, githooks, …) |
check-skills.sh |
Validate the skills/ collection and its README index (Baton self-check) |
check-node-version.sh |
Assert fleet Node major agrees across workflows; with sibling checkouts, also engines.node / @types/node |
sync-dependabot.sh |
Copy Dependabot configs from config/ to catalog npm/pip repos (see structure/repos.json) |
generate-pages-index.sh |
Build docs/index.html simulation landing page |
make-thumbnails.mjs |
Downscale screenshots/*.png to docs/assets/*.webp with sharp |
generate-screenshots.sh |
Capture each sim's screen to <sim>/assets/screenshot.png |
screenshot.mjs |
Playwright driver behind generate-screenshots.sh |
../.github/workflows/refresh-screenshots.yml |
Weekly/manual Pages thumbnail refresh → PR |
Primary entry point for agents. Reads structure/repos.json and adds computed fields:
githubHomepage— normalized Pages URL (https://openphysics.github.io/{name})localPath— sibling directory in the workspace checkoutlocalExists— whether that directory is present locally
# All repository names
scripts/parse-repos.sh names
# Simulation repos only
scripts/parse-repos.sh names --simulation
# Full JSON with computed fields
scripts/parse-repos.sh list --format json --simulation
# One repo
scripts/parse-repos.sh get DopplerEffect
# Local checkout paths for sims that exist on disk
scripts/parse-repos.sh paths --simulation --require-local
# Run a command per repo (env: REPO_NAME, REPO_DISPLAY_NAME, REPO_LINEAGE, REPO_HOMEPAGE, REPO_PATH, ...)
scripts/parse-repos.sh for-each --simulation -- \
echo "$REPO_NAME ($REPO_LINEAGE) -> $REPO_HOMEPAGE"
# Catalog summary
scripts/parse-repos.sh summaryFilters:
--type simulation|template|config|hardware-interface|tool--status active|template|draft|wip|archived--lineage original|phet|naap--simulation/--no-simulation
Populate the workspace from the catalog: clone every selected repo as a sibling directory
beside Baton. repos.json is the single source of truth — there are no submodules, so a
repo appears here the moment it is added to the catalog. Re-runnable and safe: repos already
on disk are skipped unless --update is given (which git pull --ff-onlys them).
The thin OpenPhysics superproject's
bootstrap.sh clones Baton and then calls this; run it directly once you already have
Baton.
# Clone whatever is missing into the workspace
scripts/clone-fleet.sh
# Only the simulations, and fast-forward any already present
scripts/clone-fleet.sh --simulation --update
# Preview the plan, change nothing (HTTPS instead of SSH)
scripts/clone-fleet.sh --dry-run --httpsReuses the same catalog filters as parse-repos.sh (--simulation, --type, --status,
--lineage, --only NAME, --skip NAME). Clones over SSH by default; --https for
token/anonymous use.
Run any git command across every catalog repo already checked out locally:
# put on PATH once (if ~/.local/bin is already there)
ln -sfn ~/OpenPhysics/Baton/scripts/fleet ~/.local/bin/fleet
fleet push
fleet pull --ff-only
fleet status -s
fleet --simulation log -1 --onelineSame catalog filters as parse-repos.sh. Full cheat sheet: doc/fleet-git.md.
Fan a change out across the org: clone each selected repo, run a command in it, and
— with --apply — push a branch and open one PR per repo. Dry-run by default (prints
a diffstat per repo and opens nothing). Reuses the same catalog filters as parse-repos.sh.
# Preview bumping a dependency across every simulation (no PRs):
scripts/fleet-exec.sh --simulation -- npm pkg set dependencies.scenerystack=^3.1.0
# Apply a Biome autofix across all sims and open one PR each:
scripts/fleet-exec.sh --simulation --apply --install \
--branch chore/biome-fix --title "chore: biome autofix" -- npm run fixKey options: --apply (push + open PRs), --install (npm install before the command,
needed for lint/build codemods), --branch, --title, --label, --skip NAME, --keep.
Pushing and opening PRs needs a token with write access to the target repos — your local
gh auth, or an org PAT / GitHub App token as GH_TOKEN. The default GITHUB_TOKEN only
reaches the repo running a workflow, so the fleet-exec.yml
dispatch wrapper reads a FLEET_PAT secret for apply=true.
Updates GitHub Description and Website from repos.json:
scripts/sync-github-metadata.sh --dry-run
scripts/sync-github-metadata.sh
scripts/sync-github-metadata.sh --repo SceneryStackTemplateNote: GitHub does not expose API toggles for Deployments / Packages in the About sidebar. Descriptions longer than 350 characters are truncated with a warning (GitHub’s API limit).
Check or apply the canonical GitHub repository settings baseline
(config/github-repo-baseline.json): wiki/Projects off,
Dependabot alerts + security updates, secret scanning + push protection, private vulnerability
reporting, and Pages build_type=workflow. Full write-up:
../doc/github-repo-settings.md.
scripts/sync-github-settings.sh --check # sims + template; exit 1 on drift
scripts/sync-github-settings.sh --apply --repo MyNewSim # fix one repo
scripts/sync-github-settings.sh --apply --all # every catalog repo
scripts/sync-github-settings.sh --apply --dry-run # show planned fixesUse this after creating a new sim (GitHub defaults diverge from the fleet) instead of inspecting a mature sim by hand.
Roll the scenerystack Claude Code plugin out to the
SceneryStack repos by merging the canonical keys from
config/claude-settings.json into each repo's
.claude/settings.json. It only adds/updates extraKnownMarketplaces.openphysics and
enabledPlugins["scenerystack@openphysics"] — existing keys in a repo's settings are preserved.
Targets every catalog repo whose framework is SceneryStack. Writes files only; commit/push (or
fan out as PRs via fleet-exec.sh) is left to you.
scripts/sync-claude-settings.sh --dry-run # show what would change, write nothing
scripts/sync-claude-settings.sh # merge into each sibling repo
scripts/sync-claude-settings.sh DopplerEffect # limit to named repo(s)Run by baton-selfcheck.yml on every PR or main push that
touches skills/, .claude-plugin/, scripts/, or Baton's own .github/workflows/.github/actions,
and runnable locally:
scripts/check-skills.sh # every skills/<name>/SKILL.md is well-formed and indexed in skills/README.md
scripts/check-node-version.sh # all setup-node workflows declare the same Node versionEnd-to-end checklist (create repo → repos.json → screenshot → WebP → regenerate
docs/index.html): ../doc/add-simulation.md.
Captures a screenshot of every SceneryStack simulation into <sim>/assets/screenshot.png.
It serves each sim's built dist/ and renders the requested screen with the sim's own
ScreenshotGenerator (the same code path as the in-app camera button), so the result is a
clean PNG at the sim's nominal layout — not a raw viewport grab. Multi-screen sims are forced
onto a single screen with ?screens=N, so the capture is that screen's play area rather than
the home-screen selector.
# One-time setup: install Playwright (declared in this repo's package.json)
npm install
# If Chromium is not already cached: npx playwright install chromium
# Capture every sim's first screen (reuses dist/ if already built)
npm run screenshots
# or directly:
scripts/generate-screenshots.sh
# Force a rebuild first, capture a specific screen, or limit to some sims
scripts/generate-screenshots.sh --build
scripts/generate-screenshots.sh --screen 2 Resonance OscillationsAndChaosOptions: --build (force npm run build), --screen N (default 1),
--width/--height (default 1154×753, matching existing assets). Trailing positional
arguments limit the run to the named sims.
screenshot.mjs is the underlying Playwright driver and can be run on a single dist directory:
node scripts/screenshot.mjs --dist ../DopplerEffect/dist --out /tmp/shot.png --screen 1It discovers a usable Chromium automatically (Playwright's bundled build, the newest cached
build, or a system Chromium); override with PLAYWRIGHT_CHROMIUM_EXECUTABLE.
Source from other scripts:
source "$(dirname "$0")/lib/repos.sh"
repos_simulation_names | while read -r sim; do
echo "$sim"
doneOr call the CLI directly:
scripts/parse-repos.sh names --simulationScripts assume the orchestration Baton repo lives beside member repos:
OpenPhysics/
Baton/ ← this repo
DopplerEffect/
SceneryStackTemplate/
...
If your checkout differs, set OPENPHYSICS_WORKSPACE or pass --catalog /path/to/repos.json.