Working on Primrose

Sean T. McBeth edited this page Jun 5, 2017 · 17 revisions

If you're hacking on the framework itself (rather than building a VR project that uses Primrose), there are a few steps you have to go through, but hopefully they are pretty straight forward.

There is a one-time setup of a few things that have to be installed:

From there, doing work on Primrose follows a few steps:

First-time Setup

Install Node.js

As the Node.js website explains:

Node.js® is a JavaScript runtime built on Chrome's V8 JavaScript engine... Node.js' package ecosystem, npm, is the largest ecosystem of open source libraries in the world

There are a lot of scripts that have to be run to take Primrose's source code and prepare it for running in the browser. We use Gulp as our task runner. Primrose code starts out as ECMAScript v6 (ES6) code, which is the current latest-and-greatest version of JavaScript, but ES6 isn't fully supported by all browsers yet. So, we have to convert it to ES5--which is nearly ubiquitous--using a tool called Babel. Those scripts then get bundled up into a single script file using Rollup. The build scripts also build the documentation site, which uses Pug for HTML templating and Stylus for style sheets.

You don't have to use Node.js for your projects that use Primrose--though you may want to consider it, as there are a plethora of libraries available in NPM (Node Package Manager) that you could use in your project. Primrose is a client-side framework only, meaning all of its code runs in your users' browsers. We just need it to be able to hack on Primrose.

The build scripts for Primrose run on both v6 and v7 of Node.js. If you have no projects requiring you to use v6, we recommend running v7 to have access to all the latest performance improvements.

Fork Primrose

Go to the Primrose GitHub repository while logged into your GitHub account and in the upper-right corner of the screen, click the Fork button. GitHub has additional documentation on how to do this.

Don't forget to follow Step #2: Create a local clone of your fork.

Install Dependencies

After you've cloned Primrose to your PC, use your command-line interface to CD into the Primrose directory. From there, run the command:

$ npm install

If you see the error message:

$ npm install
bash: npm: command not found

Then you need to return to the step to install Node.js.

If everything worked as expected, you should see a printout like:

$ npm install
| +-- rollup-plugin-replace@1.1.1
| | +-- magic-string@0.15.2
| | `-- minimatch@3.0.3
| `-- rollup-plugin-uglify@1.0.1
+-- pliny@3.3.5
+-- promise-polyfill@5.2.1
`-- three@0.84.0

Install Gulp

Finally, the Gulp command needs to be installed as a "global" package, which should look something like this:

$ npm install --global gulp-cli
  `-- yargs@3.32.0
    +-- cliui@3.2.0
    | `-- wrap-ansi@2.1.0
    `-- string-width@1.0.2
      +-- code-point-at@1.1.0
      `-- is-fullwidth-code-point@1.0.0
        `-- number-is-nan@1.0.1

Working on Primrose

Now that the development environment is setup, you can work on making changes to Primrose.

Run the DEV build script

Everything is setup to run off of the default Gulp script. All you have to do is type gulp in your CLI and you should see a printout running through all of the tasks necessary to build the full Primrose site from scratch:

$ gulp
[13:09:35] Using gulpfile ~\Documents\VR\test\Primrose\gulpfile.js
[13:09:35] Starting 'PrimroseWithDoc:umd:js:beautify'...
[13:09:35] Starting 'preloader:js:beautify'...
[13:09:35] Starting 'preloader:js:debug'...
[13:09:35] Starting 'Primrose:html:debug'...
[13:09:35] Starting 'Primrose:css:build:debug'...
Writing preloader.js
[13:09:36] Finished 'preloader:js:debug' after 320 ms
[13:09:36] Starting 'watch:preloader:js:debug:only'...
preloader:js:debug:only watching [ 'C:\\Users\\sean\\Documents\\VR\\test\\Primrose\\preloader\\**\\*' ]
[13:09:36] Finished 'watch:preloader:js:debug:only' after 12 ms
[13:09:36] Finished 'preloader:js:beautify' after 613 ms
[13:09:36] Finished 'Primrose:css:build:debug' after 1 s
[13:09:36] Starting 'watch:Primrose:css:build:debug'...
Primrose:css:build:debug watching [ '*.styl', 'doc/**/*.styl' ]
[13:09:36] Finished 'watch:Primrose:css:build:debug' after 29 ms
[13:09:36] Starting 'css'...
[13:09:36] Finished 'css' after 28 μs
[13:09:38] Finished 'PrimroseWithDoc:umd:js:beautify' after 2.62 s
[13:09:38] Starting 'format'...
[13:09:38] Finished 'format' after 4.23 μs
[13:09:38] Starting 'PrimroseWithDoc:umd:js:debug'...
[13:09:39] Finished 'Primrose:html:debug' after 3.33 s
[13:09:39] Starting 'watch:Primrose:html:debug'...
Primrose:html:debug watching [ '*.pug', 'doc/**/*.pug', 'templates/**/*.pug' ]
[13:09:39] Finished 'watch:Primrose:html:debug' after 143 ms
[13:09:39] Starting 'html'...
[13:09:39] Finished 'html' after 1.51 μs
Writing PrimroseWithDoc.js
[13:09:47] Finished 'PrimroseWithDoc:umd:js:debug' after 9.14 s
[13:09:47] Starting 'PrimroseWithDoc:umd:js:post:debug'...
[13:09:47] Finished 'PrimroseWithDoc:umd:js:post:debug' after 126 ms
[13:09:47] Starting 'watch:PrimroseWithDoc:umd:js:post:debug'...
PrimroseWithDoc:umd:js:post:debug watching [ 'C:\\Users\\sean\\Documents\\VR\\test\\Primrose\\src\\**\\*' ]
[13:09:47] Finished 'watch:PrimroseWithDoc:umd:js:post:debug' after 170 ms
[13:09:47] Starting 'js'...
[13:09:47] Finished 'js' after 1.51 μs
[13:09:47] Starting 'default'...
Mode is dev
Serving from directory ..
Listening on port 8080
starting insecure server
starting:  explorer http://localhost/Primrose/
[13:09:47] Finished 'default' after 10 ms

Some of the things happening here:

  • [13:09:35] Starting 'PrimroseWithDoc:umd:js:beautify'...: the JavaScript code gets ran through a process to make sure the formatting is consistent and readable.
  • [13:09:35] Starting 'preloader:js:debug'...: this task translates the code for the Preloader script from ES6 JavaScript into ES5, and bundles it into a single file.
  • [13:09:35] Starting 'Primrose:html:debug'...: this task translates the Pug templates into HTML files.
  • [13:09:35] Starting 'Primrose:css:build:debug'...: this task translates the Stylus templates into CSS files. Writing preloader.js
  • [13:09:36] Starting 'watch:preloader:js:debug:only'...: You'll see a number of these tasks that are previous tasks with the prefix "watch:" on the front of them. These tasks watch for changes in files related to those tasks, then trigger those tasks to run again.
  • [13:09:38] Starting 'PrimroseWithDoc:umd:js:debug'...: this task translates the code for the Primrose itself from ES6 JavaScript into ES5, and bundles it into a single file.
  • [13:09:47] Starting 'PrimroseWithDoc:umd:js:post:debug'...: this task strips the Pliny Documentation commands out of the bundled source.

[13:09:47] Starting 'default'... Mode is dev Serving from directory .. Listening on port 8080 starting insecure server starting: explorer http://localhost/Primrose/

This whole process may take up to a minute to run when you first start it. Subsequent changes don't have to run the full script, so it won't take a whole minute between changes to run the script. On the first run, once your browser opens, you're ready to start working.

NOTE: if you already have a webserver or other process running that is listening on port 8080, then you will see an error message:

      throw er; // Unhandled 'error' event

Error: listen EADDRINUSE :::8080
    at Object.exports._errnoException (util.js:1022:11)
    at exports._exceptionWithHostPort (util.js:1045:20)
    at Server._listen2 (net.js:1262:14)
    at listen (net.js:1298:10)
    at Server.listen (net.js:1376:9)
    at module.exports (C:\Users\sean\Documents\VR\Primrose\node_modules\notion-node\index.js:59:15)
    at Gulp.gulp.task (C:\Users\sean\Documents\VR\Primrose\gulpfile.js:125:53)
    at module.exports (C:\Users\sean\Documents\VR\Primrose\node_modules\orchestrator\lib\runTask.js:34:7)
    at Gulp.Orchestrator._runTask (C:\Users\sean\Documents\VR\Primrose\node_modules\orchestrator\index.js:273:3)
    at Gulp.Orchestrator._runStep (C:\Users\sean\Documents\VR\Primrose\node_modules\orchestrator\index.js:214:10)

The Gulp process will exit and you won't be able to run the DEV build. Your options are to shut down that other webserver that is listening on port 8080, modify the gulpfile.js to add a port option to the call to startServer, or run gulp debug, then gulp js separately and use your own webserver to view the files.

Making a change

Start by checking the Issues List for an issue that looks interesting to you. There are issues for first-timers-only, and there are easy issues for beginners. There are also Medium and Hard issues, but I'll assume you wouldn't be reading this document if you were ready to tackle those tasks. Choose the difficultly level that is appropriate for you: if you've never made a Git commit and/or Pull Request before, pick one of the first-timers-only tasks. Otherwise, leave those for others to practice on and go straight to easy.

Take, for example, Issue #115:

In order for the gaze cursor to work on mobile devices, the person implementing a script must set a configuration parameter named useGaze to the isMobile flag when setting up their BrowserEnvironment.

All that needs to be done is to change the BrowserEnvironment's DEFAULTS object at the end of the file. It current has useGaze set to false. It should be set to isMobile. Also, look for the line import isiOS from "../flags/isiOS"; and add a line below it to import the isMobile flag from the same flags directory.

As a first-timer-only issue, it lists out exactly which line in which file needs to be changed. Because this is a change to BrowserEnvironment, we can look at any of the demos. In particular, the "empty" demo is usually pretty good for testing changes, as is the "shadows" demo has a little more complexity to it. Always start a change by first looking at how the site currently behaves.

In this case, the issue refers to a change that would only be visible on mobile devices. There are a couple of ways to test this, but the easiest way is to just use your phone over your local wifi network. You'll first have to find out your PC's IP address.

On Windows, follow these instructions.

On macOS, follow these instructions.

On Linux, follow these instructions.

Once you have your IP Address, you can type it into the internet browser on your phone, followed by a forward-slash, followed by "Primrose"--e.g., and you should end up on the Primrose website, running off of your PC.

This issue has already been fulfilled, but if it hadn't, when we viewed the "empty" demo, then there would be no Gaze Cursor when looking at the ground. The Gaze Cursor is a circular marker in the middle of the view that follows where the user is looking, with a count-down timer that spins around the cursor whenever the user looks at an object before triggering that object's select event.

Now that you have verified the current behavior, you can make the change. In this case, it was to change the value of the useGaze field in the BrowserEnvironment.DEFAULTS from false to isMobile.

When you save the file, it will trigger the build script to run. It will start like this:

[watch:PrimroseWithDoc:umd:js:post:debug] File src\Primrose\BrowserEnvironment.js was changed, running task PrimroseWith
[14:09:40] Starting 'PrimroseWithDoc:umd:js:beautify'...
[14:09:40] Starting 'preloader:js:beautify'...
[14:09:41] Finished 'preloader:js:beautify' after 33 ms
[14:09:41] Finished 'PrimroseWithDoc:umd:js:beautify' after 114 ms
[14:09:41] Starting 'format'...
[14:09:41] Finished 'format' after 2.42 μs
[14:09:41] Starting 'PrimroseWithDoc:umd:js:debug'...

Depending on your system, the PrimroseWithDoc:umd:js:debug task could take anywhere from 3 to 10 seconds. You'll know it's complete when you see this:

Writing PrimroseWithDoc.js
[14:09:43] Finished 'PrimroseWithDoc:umd:js:debug' after 2.54 s
[14:09:43] Starting 'PrimroseWithDoc:umd:js:post:debug'...
[14:09:43] Finished 'PrimroseWithDoc:umd:js:post:debug' after 134 ms

At this point, we can reload the page and see if the desired result has taken place. In this case, we'd see that the Gaze Cursor is now active on our phone when we look at the ground plane.

Making a commit

If you're using GitHub Desktop, follow these instructions. Whatever your Git GUI might be, it should have similar instructions on their website.

If you're using the Git CLI, follow these instructions.

When you make a commit that is related to an Issue, don't forget to add the Issue name in the commit message some how. If you put "Issue #115" in your commit message somewhere (doesn't matter where), then GitHub will link your commit to the Issue ticket, making documentation of the change easier to follow.

Also, don't forget to add your name to, if you haven't already! We'd like to give you credit for the work you do, and that's where it goes. Just add your name and your GitHub handle at the end of the document. If you'd like to become a long-term contributor to Primrose, please email me at []( Primrose) and tell me a bit about your background and what you're hoping to learn from working on open source software. We can chat about how we can make Primrose fit those goals for you.

Making a Pull Request

Finally, follow these instructions to be able to send us a Pull Request. We'll review it and help you get it ready for merging into the mainline of the project. If there is anything missing or if there is anything that needs changed, you should be able to make the commits on your repository and they will be added to the pull request when you push them to GitHub.

We aren't super picky about branches. You can make a branch if it helps you keep your work organized, but it's not required by us.

And that's "all" there is to it!

It might seem like a lot now, but once you've done it a few times, you'll get the hang of it. Refer back to this document as many times as you need. Ask questions if you need, anywhere you feel comfortable. We're here to help you learn.

From here, you probably want to read Project Structure page to get familiar with how the Primrose project is laid out, then the Project Roadmap page to see the general direction in which everything is going.

You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.
Press h to open a hovercard with more details.