# Include p5.js in Observable notebook

**URL:** <https://discourse.processing.org/t/include-p5-js-in-observable-notebook/458>\
**Category:** p5.js\
**Created:** [May 28, 2018, 8:51am UTC](https://discourse.processing.org/t/include-p5-js-in-observable-notebook/458 "2018-05-28T08:51:50Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![mainul12](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/mainul12/32/209_2.png) [@mainul12](https://discourse.processing.org/u/mainul12)\
**Post date:** [May 28, 2018, 8:51am UTC](https://discourse.processing.org/t/include-p5-js-in-observable-notebook/458/1 "2018-05-28T08:51:50Z")

</div>

I have recently come across Observable notebooks and I would like to know how to include the p5.js library in the notebook. I have tried the following but it throws a syntax error.

> p5 = require(“[https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.6.1/p5.js](https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.6.1/p5.js)”)
> 
> function setup() {  
> createCanvas(800,300);  
> background(220,220,220);  
> }
> 
> function draw() {  
> // put drawing code here  
> }

---

<div class="post-metadata">

**Author:** ![WakeMeAtThree](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/wakemeatthree/32/38_2.png) [@WakeMeAtThree](https://discourse.processing.org/u/WakeMeAtThree)\
**Post date:** [May 28, 2018, 10:11am UTC](https://discourse.processing.org/t/include-p5-js-in-observable-notebook/458/2 "2018-05-28T10:11:58Z")

</div>

I looked through Observable and found two people making p5js notebooks:

- [Using p5.js](https://beta.observablehq.com/@jermspeaks/p5-test)
- [Meta Bubbles and P5](https://beta.observablehq.com/@erochongit/bubbles-and-p5)

I played around with their code and translated your [simple test into this](https://beta.observablehq.com/@wakemeatthree/untitled).

This Observable notebooks thing seems neat. I use jupyter notebooks regularly for python, and I’m glad there’s a javascript equivalent for this, need to read more on it later. Thanks for mentioning it.

---

<div class="post-metadata">

**Author:** ![mainul12](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/mainul12/32/209_2.png) [@mainul12](https://discourse.processing.org/u/mainul12)\
**Post date:** [May 28, 2018, 10:33am UTC](https://discourse.processing.org/t/include-p5-js-in-observable-notebook/458/3 "2018-05-28T10:33:14Z")

</div>

There is a processing kernel in Jupyter and one specifically for JavaScript, too. 😃

---

<div class="post-metadata">

**Author:** ![jeremydouglass](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/jeremydouglass/32/20_2.png) [@jeremydouglass](https://discourse.processing.org/u/jeremydouglass)\
**Post date:** [May 29, 2018, 7:58pm UTC](https://discourse.processing.org/t/include-p5-js-in-observable-notebook/458/4 "2018-05-29T19:58:12Z")

</div>

Here is a template for Observable p5.js notebooks:

- [p5.js sketch on Observable: Template](https://beta.observablehq.com/@jeremydouglass/p5-js-sketch-on-observable-template) (forkable template by me)

Also, Tom MacWright has created a helper function which you can import into a notebook to get started quickly, as well as a template with it already in-place:

- [p5 (twcw tutorial)](https://beta.observablehq.com/@tmcw/p5-basic-example)
- [p5 basic example](https://beta.observablehq.com/@tmcw/p5-basic-example) (forkable template)

These are instance mode sketches,and you need to prefix _everything_ – get ready write `sketch.foo` `sketch.bar` `sketch.baz` `sketch.etc`…

~~One thing I discovered while writing the first template is that the sketches work well, but you cannot currently include libraries like p5.dom and p5.sound in Observable notebooks. I have an [open question](https://talk.observablehq.com/t/importing-a-typescript-module/526/10) about that.~~

**Edit:** : Including p5.dom in Observable is quite possible – there is a trick to it, shared by twcw and now included in my template notebook (linked above).

---

<div class="post-metadata">

**Author:** ![GoToLoop](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/gotoloop/32/86_2.png) [@GoToLoop](https://discourse.processing.org/u/GoToLoop)\
**Post date:** [May 30, 2018, 1:14am UTC](https://discourse.processing.org/t/include-p5-js-in-observable-notebook/458/5 "2018-05-30T01:14:09Z")

</div>

> [@jeremydouglass](#):
>
> … but you cannot currently include libraries like “p5.dom” and “p5.sound”…

if you navigate thru’ [p5 CDN by jsDelivr - A free, fast, and reliable Open Source CDN](https://CDN.JsDelivr.net/npm/p5/), you’re gonna find those addon libraries here: 📚  
[p5 CDN by jsDelivr - A free, fast, and reliable Open Source CDN](https://CDN.JsDelivr.net/npm/p5/lib/addons/)

---

<div class="post-metadata">

**Author:** ![jeremydouglass](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/jeremydouglass/32/20_2.png) [@jeremydouglass](https://discourse.processing.org/u/jeremydouglass)\
**Post date:** [May 30, 2018, 2:18am UTC](https://discourse.processing.org/t/include-p5-js-in-observable-notebook/458/6 "2018-05-30T02:18:43Z")

</div>

Thank you @GoToLoop.

I actually know where they are via CDNs – the issue is that the Observable “require()” mechanism cannot correctly load the library.

~~I _believe_ this is because of the `(function (root, factory)` style immediately-invoked function expression (IIFE) wrapper… see the link to the discussion thread for more. Any suggestions welcome!~~

**Edit:** resolved below.

---

<div class="post-metadata">

**Author:** ![GoToLoop](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/gotoloop/32/86_2.png) [@GoToLoop](https://discourse.processing.org/u/GoToLoop)\
**Post date:** [May 30, 2018, 2:38am UTC](https://discourse.processing.org/t/include-p5-js-in-observable-notebook/458/7 "2018-05-30T02:38:32Z")

</div>

> [@jeremydouglass](#):
>
> I actually know where they are via CDNs…

That CDN points directly to the contents of the whole p5.js project in the NPM repo! 👆

More specifically, I was merely pointing out that both files “p5.dom.js” & “p5.sound.js” are bundled together inside the p5 NPM repo already! 🙄

> [@jeremydouglass](#):
>
> The issue is that the Observable’s **require()** mechanism cannot correctly load the library.

Maybe this GitHub issue got some clues to it. Dunno… 😕

> <https://github.com/processing/p5.js/issues/2920>
>
> \*\*TLDR:\*\* Apparent bug in \`p5.sound.min.js\` causing it to load the educational (…heavy) \`p5.js\` file instead of production \`p5.min.js\` with NPM.
> 
> \---
> If there's a trivial way to use the minified build with npm, please share, as I am new to define.js. This is a package request on behalf of those using webpack and npm. AFAIK, webpack is used for production builds and heavy documentation in source code is an anti-pattern in the npm world. The way p5 is set up currently with npm makes it difficult to use for production:
> 
> Using p5.js with webpack/ES6, we run \`npm install --save p5\` in our project which gives us the \`p5\` npm package, containing \`p5.js\`, \`p5.min.js\` and the associated add-ons. This line of code is used to import p5 into an ES6 app:
> \`\`\`
> import p5 from "p5"
> // make cool artsy stuff here in instance mode!
> \`\`\`
> The \`package.json\` refers to code in \`p5.js\`, which is 2.6MB. The minified build is around 380KB, so I looked into the source to see what was causing the bloat.
> \#### The main package file \`p5.js\` contains around 1MB of tutorial content such as:
> \`\`\`
> ...
> {
> "file": "lib/addons/p5.dom.js",
> "line": 2216,
> "description": "\<p\>Sets volume for this HTML5 media element. If no argument is given,\\nreturns the current volume.\</p\>\\n",
> "params": \[
> {
> "name": "val",
> "description": "\<p\>volume between 0.0 and 1.0\</p\>\\n",
> "type": "Number",
> "optional": true
> }
> \],
> "return": {
> "description": "current volume or p5.MediaElement",
> "type": "Number|p5.MediaElement"
> },
> "itemtype": "method",
> "name": "volume",
> "example": \[
> "\\n\<div\>\<code\>\\nvar ele;\\nfunction setup() {\\n // p5.MediaElement objects are usually created\\n // by calling the createAudio(), createVideo(),\\n // and createCapture() functions.\\n // In this example we create\\n // a new p5.MediaElement via createAudio().\\n ele = createAudio('assets/lucky\_dragons.mp3');\\n background(250);\\n textAlign(CENTER);\\n text('Click to Play!', width / 2, height / 2);\\n}\\nfunction mouseClicked() {\\n // Here we call the volume() function\\n // on the sound element to set its volume\\n // Volume must be between 0.0 and 1.0\\n ele.volume(0.2);\\n ele.play();\\n background(200);\\n text('You clicked Play!', width / 2, height / 2);\\n}\\n\</code\>\</div\>\\n\<div\>\<code\>\\nvar audio;\\nvar counter = 0;\\n\\nfunction loaded() {\\n audio.play();\\n}\\n\\nfunction setup() {\\n audio = createAudio('assets/lucky\_dragons.mp3', loaded);\\n textAlign(CENTER);\\n}\\n\\nfunction draw() {\\n if (counter === 0) {\\n background(0, 255, 0);\\n text('volume(0.9)', width / 2, height / 2);\\n } else if (counter === 1) {\\n background(255, 255, 0);\\n text('volume(0.5)', width / 2, height / 2);\\n } else if (counter === 2) {\\n background(255, 0, 0);\\n text('volume(0.1)', width / 2, height / 2);\\n }\\n}\\n\\nfunction mousePressed() {\\n counter++;\\n if (counter === 0) {\\n audio.volume(0.9);\\n } else if (counter === 1) {\\n audio.volume(0.5);\\n } else if (counter === 2) {\\n audio.volume(0.1);\\n } else {\\n counter = 0;\\n audio.volume(0.9);\\n }\\n}\\n\</code\>\\n\</div\>"
> \],
> "class": "p5.MediaElement",
> "module": "p5.dom",
> "submodule": "p5.dom"
> },
> ...
> \`\`\`
> \#### It contains a few hundred KB of repeated logs such as:
> \`\`\`
> ...
> {
> "message": "unknown tag: alt",
> "line": " src/color/creating\_reading.js:16"
> },
> {
> "message": "unknown tag: alt",
> "line": " src/color/creating\_reading.js:61"
> },
> {
> "message": "unknown tag: alt",
> "line": " src/color/creating\_reading.js:91"
> },
> {
> "message": "unknown tag: alt",
> "line": " src/color/creating\_reading.js:121"
> },
> {
> "message": "unknown tag: alt",
> "line": " src/color/creating\_reading.js:319"
> },
> {
> "message": "unknown tag: alt",
> "line": " src/color/creating\_reading.js:350"
> },
> {
> "message": "unknown tag: alt",
> "line": " src/color/creating\_reading.js:387"
> },
> {
> "message": "unknown tag: alt",
> "line": " src/color/creating\_reading.js:484"
> },
> {
> "message": "unknown tag: alt",
> "line": " src/color/creating\_reading.js:514"
> },
> {
> "message": "unknown tag: alt",
> "line": " src/color/creating\_reading.js:554"
> },
> {
> "message": "unknown tag: alt",
> "line": " src/color/p5.Color.js:52"
> },
> {
> "message": "unknown tag: alt",
> "line": " src/color/p5.Color.js:247"
> },
> {
> "message": "unknown tag: alt",
> "line": " src/color/p5.Color.js:274"
> },
> ...
> \`\`\`
> 
> \#### It contains a few hundred KB of documentation such as:
> 
> \`\`\`
> /\*\*
> \* Specular material for geometry with a given color. You can view all
> \* possible materials in this
> \* \<a href="https://p5js.org/examples/3d-materials.html"\>example\</a\>.
> \* @method specularMaterial
> \* @param {Number} v1 gray value, red or hue value
> \* (depending on the current color mode),
> \* @param {Number} \[v2\] green or saturation value
> \* @param {Number} \[v3\] blue or brightness value
> \* @param {Number} \[a\] opacity
> \* @chainable
> \* @example
> \* \<div\>
> \* \<code\>
> \* function setup() {
> \* createCanvas(100, 100, WEBGL);
> \* }
> \* function draw() {
> \* background(0);
> \* ambientLight(100);
> \* pointLight(250, 250, 250, 100, 100, 0);
> \* specularMaterial(250);
> \* sphere(50);
> \* }
> \* \</code\>
> \* \</div\>
> \*
> \* @alt
> \* diffused radiating light source from top right of canvas
> \*
> \*/
> \`\`\`
> IIUC, this stuff isn't required, and is slowing down the actual app, making it basically impossible for anyone in data-scarce countries to use. I'm still scratching my head as to why this is monolithic file is the main import in the npm package... the npm package should include this docu-code for learning purposes, but should probably allow people to import the minified version of the distribution:
> \`\`\`
> import p5 from "p5/lib/p5.min.js"
> \`\`\`
> Hold on, we can do that already! But what about \`p5.sound.min.js\`?:
> \`\`\`
> import p5 from "p5/lib/p5.min.js"
> import "p5/lib/addons/p5.sound.min.js" // this doesn't depend on the minified p5???
> \`\`\`
> I tried referring to the minified builds as seen above, but it appears that \`p5.sound.min.js\` actually depends on the \*\*non-minified\*\* p5.js file, making it basically unusable for production. The only solution I can think of is to fall back and manually insert the following script tags in my \`index.html\`:
> 
> \`\`\`
> 
> \<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.6.1/p5.min.js"\>\</script\>
> \<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.6.1/addons/p5.sound.min.js"\>\</script\>
> \`\`\`
> Unfortunately, doing so means that I can't easily benefit from the advantages that webpack provides, and it creates a discontinuity in my workflow.
> 
> \### Apparent fix:
> 
> 1. NPM package \`p5\` should export only the absolute necessary code for better end-user experience and development
> 2. \`p5.sound.min.js\` needs to require \`p5\`? Or can this be independent? In any case, should depend on the minified version for the same reasons.

---

<div class="post-metadata">

**Author:** ![jeremydouglass](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/jeremydouglass/32/20_2.png) [@jeremydouglass](https://discourse.processing.org/u/jeremydouglass)\
**Post date:** [May 30, 2018, 3:52am UTC](https://discourse.processing.org/t/include-p5-js-in-observable-notebook/458/8 "2018-05-30T03:52:47Z")

</div>

As it turns out, this is a working Observable method for running require on p5 and then adding p5.dom:

```
p5 = require('p5').then(async p5 => {
  await require('p5@0.6.1/lib/addons/p5.dom.js');
  return p5;
})
```
