Be sure you have these tools installed:
- Git
- Node.js v16+ (if using Linux or Mac, we recommend installing via nvm)
- Yarn v1.x (you need to install Node.js first)
Depending on your platform, here are some extra instructions:
If you're using an ARM-based Mac, node-canvas (one of our dependencies) also requires some additional packages to be installed. Install Homebrew if you don't already have it, then run this command:
brew install pkg-config cairo pango libpng jpeg giflib librsvg pixman
Here are some WSL-specific guides:
Once you've installed all prerequisites, clone this repo. Then open a terminal in your clone of it; for instance, if you cloned it via the terminal, run this command:
cd penrose/
The rest of this document assumes you are running commands from this directory, unless otherwise specified. Next install dependencies from npm:
yarn
Finally, enter the directory for our roger
tool, install it, and then come
back to this directory:
pushd packages/roger/
yarn install-global
popd
For VS Code users, we provide a VS Code workspace file called
penrose.code-workspace
which automatically configures many settings (and
recommends several extensions) that we strongly encourage using. From your
terminal, you can open VS Code to the workspace via this command:
code penrose.code-workspace
You should be automatically prompted to install the extensions we recommend, but if not, you can now find them listed in the Extensions tab.
Open a separate terminal (to the same directory), and run these commands:
cd packages/examples/src/
roger watch
You should see this output:
watching on port 9160
Then, back in your original terminal, run this command:
yarn start
Once it finishes building, you should see this near the end of the output:
@penrose/editor: > Local: http://localhost:3000/try/
@penrose/editor: > Network: use `--host` to expose
Click that link. The page may take some time to load, but once it does, you should see something like this:
Type in the drop-down boxes to search for any Penrose trio in
packages/examples/src/
; for example:
- Substance:
set-theory-domain/tree.sub
- Style:
set-theory-domain/venn.sty
- Domain:
set-theory-domain/setTheory.dsl
... and voilà! ✨ See the results in your browser:
Run this command to build all packages for production:
yarn build
Run this command to typecheck all packages:
yarn typecheck
We have a packages/examples/src/registry.json
file which lists several
diagrams from the packages/examples/src/
directory. All the "trios" listed in
this file are automatically run in GitHub Actions to produce the SVG files in
diagrams/
.
If you create a new diagram in packages/examples/src/
and you'd like to make
sure that future changes to Penrose don't inadvertently break your diagram, go
ahead add it to the registry! For instance, let's say you create this directory
under packages/examples/src/
:
packages/examples/src/foo-domain/
├── mydomain.dsl
├── bar.sty
└── baz.sub
The first step in adding this to the registry is to add the domain under
"domains"
:
"foo": {
"name": "My Domain",
"URI": "foo-domain/mydomain.dsl"
}
Next you can add the style under "styles"
referring to that domain:
"mystyle": {
"domain": "foo",
"name": "My Style",
"URI": "foo-domain/bar.sty"
}
And similarly the substance would go under "substances"
:
"mysubstance": {
"domain": "foo",
"name": "My Substance",
"URI": "foo-domain/baz.sub"
}
Then, if you find that these give a nice diagram using variation
CedarEagle308
, you can add the following under "trios"
:
{
"substance": "mysubstance",
"style": "mystyle",
"domain": "foo",
"variation": "CedarEagle308"
}
And you're almost done! If you were to commit and push this right now, CI would
fail because it would see that you added a new diagram to the registry without
adding its output SVG file to the diagrams/
directory. The last thing you need
to do is generate that output and check it into Git.
The easiest way to do this is to run automator
locally on the registry:
yarn build --filter=automator
pushd packages/automator/
yarn start batch registry.json ../../diagrams/ --src-prefix=../examples/src/
popd
This should regenerate everything in diagrams/
. Now just commit and push, and
you're on your way!
Note: some features relating to text are currently not deterministic across different operating systems, so diagrams using those features cannot be included in the registry. See these pull requests for examples of those limitations:
To delete all build artifacts (but no node_modules/
):
git clean -dfxe node_modules/
To delete node_modules/
(but not build artifacts) in all packages/
:
yarn lerna clean
To delete the node_modules/
at the repo root:
npx rimraf node_modules/
To do all of the above at once:
git clean -dfx
If roger
is not working as expected and you think it might be out of date, run
these commands to re-install it:
pushd packages/roger/
yarn unlink
yarn build
popd
To run all tests:
yarn test
To automatically re-run tests as you make changes to core
:
yarn turbo run test-watch
To add a project dependency to, e.g., browser-ui
(note, we don't use npm
):
pushd packages/browser-ui/
yarn add $DEPENDENCY_NAME
popd
To add a dev dependency:
pushd packages/$PACKAGE_NAME/
yarn add --dev $DEPENDENCY_NAME
popd
If you're using a package that involves the DOM, you probably want the react
version (e.g. react-graph-vis
instead of visjs
).
We use Turborepo to manage dependencies among our various scripts/tasks, and
we have a custom turboConfig.js
script which autogenerates Turborepo's
turbo.json
config file from metadata in all our package/*/package.json
files. Specifically, below the "scripts"
section we usually have a "turbo"
section defining metadata about each script. For instance, given this:
"scripts": {
"build": "mkdir dist/ && echo foo > dist/build.txt",
"test": "cat dist/*.txt"
}
we might define the metadata like this:
"turbo": {
"build": "out: [dist/*.txt]",
"test": "cache: false, deps: [build]"
}
When you update a script, be sure to update its accompanying metadata!
Note that turboConfig.js
defines a few global scripts which have implicit
dependencies that are automatically inherited by package-local scripts with the
same names:
build
means to produce executable artifacts (usually JavaScript files), and implicitly depends on thebuild
scripts of that package's dependenciesbuild-decls
means to produce TypeScript declaration files, and implicitly depends on thebuild-decls
scripts of that package's dependenciestypecheck
means to check for type errors in the package, and implicitly depends on thebuild-decls
script of that same package (with the intention being that for any given package you either write abuild-decls
script or atypecheck
script, but not both)
The "turbo"
metadata is written in YAML syntax, where the following keys
are allowed:
deps
corresponds to Turborepo'sdependsOn
key, except that it also inherits thedependsOn
from the existing global definition of the script if there is one (see above)out
corresponds to Turborepo'soutputs
key, except that it defaults to the empty array[]
instead of to["dist/**", "build/**"]
cache
corresponds to Turborepo'scache
key
See the Turborepo docs for more information.
To import a type or function from core
in another package like browser-ui
,
import the type into packages/core/src/index.ts
and export it from there
again, then import into your project.
If you'd like to make a change and contribute it back to the project, but you don't have write permissions to this repository, you'll need to create a fork. Click the Fork button in the top-right corner of this page.
You should already have a clone of this repo by following the instructions at the start of this document, so now you simply need to add your fork as another remote:
git remote add fork https://github.com/<your-github-account-name>/penrose.git
Check out our list of good first issues.
-
Before working on one of them, let us know that you are interested so we can give you more guidance! (Currently the issue descriptions are fairly brief.)
-
Create a separate branch in your forked repo to work on the issue:
git switch --create my-branch git push --set-upstream fork my-branch
If you need to merge new changes from upstream (i.e. the original Penrose repo):
git fetch origin main:main
git merge main
After running the above, manage any merge conflicts, commit to your branch, and then push to your fork:
git push
When your work is ready for review:
- Open a pull request (PR) by clicking on the Contribute button on the
homepage of your forked repo
(
https://github.com/<your-github-account-name>/penrose
). - Put
fix:
orfeat:
at the beginning of the PR title depending on if it's a fix or a feature. We follow conventional commit guidelines in our repo. - Document your changes in the PR's description (including specific paths for reproducing specific examples, and link(s) to any issue(s) you address).
- Some things will be checked automatically by our CI:
- Make sure the system passes the regression tests.
- Run Prettier via
yarn format
.
- If you have permission, request review from the relevant person. Otherwise, no worries: we'll take a look at your PR and assign it to a maintainer.
- When your PR is approved, a maintainer will merge it.
If you hit any snags in the process, run into bugs, or just have questions, please file an issue!