├── .gitignore ├── LICENSE ├── README.md ├── docs ├── make_site.js └── setup.sh ├── package.json ├── q5.js ├── q5.min.js ├── q5.p5acl.js └── tests.js /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | **/.DS_Store 3 | ./docs/assets/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # q5.js 2 | 3 | 4 | q5.js is a small and fast alternative (experimental) implementation of [p5.js](https://p5js.org), the client-side JS platform for creative expression on the web. q5.js is mostly code-compatible with p5.js, meaning you can simply swap out the library link in an existing sketch and expect it to work with minimal modification. It inherits most of its good stuff from p5.js, though it puts more emphasis on following aspects: 5 | 6 | - **lightweight**: 33KB minified (p5.min.js 1.1.9 is 800+KB). ([Smaller libraries have smaller carbon footprint!](https://observablehq.com/@mrchrisadams/carbon-footprint-of-sending-data-around)) 7 | - **fast**: It does so by being a thinner wrapper on Canvas/Web API, skipping parameter validation, and using faster algorithms wherever possible. 8 | 9 | Currently, q5.js supports almost all of p5.js's 2D drawing API's, most of its math functionality, and other utilities. It does not support 3D yet; 3D support will likely come as an extension to keep the main library lightweight. It excludes DOM and sound functionalities, though it is mostly compatible with p5.sound.js and p5.dom.js. 10 | 11 | To explore supported functionalities, check out these q5 renditions of the standard p5 examples on [this page](https://q5xjs.netlify.app). 12 | 13 | q5.js can also be used with the p5 online Web Editor (editor.p5js.org). [Example](https://editor.p5js.org/lingdong/sketches/xrT2VF08P). 14 | 15 | Here's a quick sampling of q5.js usage (in case you're not familiar with p5): 16 | 17 | ```js 18 | new Q5("global"); //initialize q5 19 | // alternatively use `const q=new Q5()` to contain all q5 functions inside a namespace. 20 | 21 | // the rest just looks like a regular p5.js sketch: 22 | 23 | function draw() { 24 | background(237, 34, 93); 25 | fill(0); 26 | 27 | if (mouseIsPressed) { 28 | ellipse(50, 50, 50, 50); 29 | } else { 30 | rect(25, 25, 50, 50); 31 | } 32 | }; 33 | 34 | ``` 35 | 36 | q5.js is currently experimental; Feel free to point out any issues. 37 | 38 | ## Download 39 | 40 | | ⬇︎
[    q5.js    
](https://cdn.jsdelivr.net/gh/LingDong-/q5xjs/q5.js)65KB | ⬇︎
[q5.min.js
](https://cdn.jsdelivr.net/gh/LingDong-/q5xjs/q5.min.js)33KB | 41 | |---|---| 42 | 43 | To use, put this line in your HTML: 44 | 45 | ```html 46 | 47 | ``` 48 | 49 | or via CDN: 50 | 51 | ```html 52 | 53 | ``` 54 | 55 | ## Table of Contents 56 | 57 | - [Download](#download) 58 | - [Motivation](#motivation) 59 | - [Key Differences with p5](#key-differences-with-p5) 60 | - [Extra Features](#extra-features) 61 | - [Using p5 Addons](#using-p5-addons) 62 | - [Benchmarks](#benchmarks) 63 | 64 | ## Motivation 65 | 66 | After having used many graphics libraries across many different languages, I have found that the Processing/p5.js/Openframeworks system has one huge advantage over others: 67 | 68 | It gets stuff drawn onto the screen quick and easy! 69 | 70 | This might sound silly, but it actually means a lot for people concerned with creative expression. The easier it is to try different things, the more possibilities you can try (before time and/or patience run out), and the greater the chance that you'll get something nice in the end. Therefore, although you can theoretically achieve the exact same result in any decent graphics system, the tool does matter in practice: You want more time to spend actually working on how your piece looks, instead of spending it on wondering why the computer doesn't work as you intend. 71 | 72 | 73 | [Where](https://www.cmu.edu/cfa/studio/index.html) I studied computational art, p5.js is taught as "the" framework for the web, and it's been a great introduction. However, due to some of the ways in which p5.js is implemented, I find myself using it less and less as I make more and more projects. Instead I reach directly for the JavaScript/Web API's (which are also well designed enough). I sometimes think of this as shedding the "baby" wheels on the bicycle. But then I miss the artist-centered logic of the p5 interface! I'm now thinking: is there a better way? 74 | 75 | To clarify: I think the official p5.js implementation is perfectly justified for its philosophy and suitability for its intended purpose, but my own needs are different enough that I think they justify another implementation instead of pull requests to the official one. 76 | 77 | 78 | In fact, it is not uncommon for successful software systems to have multiple implementations under one spec (think: compilers of C, implementations of SQL, and engines of JavaScript): The user can choose a backend that best suits their goals or needs. The distinction between the "spec" and the "implementation" is a good idea: when one is using p5.js (or Processing or OpenFrameworks), what one is really using is the same set of commands, the intuitive way of describing drawings, that empowers creative expression. The actual way these commands are implemented internally is incidental; it should be possible to swap internal implementations as necessary. 79 | 80 | 81 | q5.js aims to: 82 | 83 | - ✅ be mostly code-compatible with p5.js. 84 | - ✅ keep being very simple and lightweight. 85 | - ✅ be a very thin wrapper around Canvas/Web API: think of it as a collection of syntactic sugars. 86 | - ✅ be fast. 87 | 88 | q5.js does NOT not aim to: 89 | 90 | - ❌ replace p5.js. 91 | - ❌ be beginner friendly. 92 | - ❌ simulate completely identical behavior for current and future versions of p5.js. 93 | 94 | 95 | ## Key Differences with p5 96 | 97 | 98 | ### I. "Namespaced Mode" 🏷️ 99 | 100 | #### p5 101 | 102 | In **p5.js**, all p5 functions are in the global namespace, unless you use "instance" mode, like this: 103 | 104 | ```js 105 | 106 | let sketch = function(p) { 107 | p.setup = function() { 108 | p.createCanvas(100,100); 109 | }; 110 | p.draw = function(){ 111 | p.background(0); 112 | } 113 | }; 114 | 115 | let myp5 = new p5(sketch); 116 | 117 | ``` 118 | 119 | This does solve the problem of global namespace pollution, but there're still some inconveniences: 120 | 121 | - The extra wrapping of the `sketch` function makes code look complex. (Flat is better than nested!) 122 | - Variables inside `sketch` can no longer be accessed via browser console, which makes it less convenient for debugging. 123 | 124 | 125 | #### q5 126 | 127 | **q5** introduces "namespace" mode in place of global/instance mode: 128 | 129 | ```js 130 | let q5 = new Q5(); 131 | 132 | q5.setup = function(){ 133 | q5.createCanvas(100,100); 134 | } 135 | 136 | q5.draw = function(){ 137 | q5.background(0); 138 | } 139 | 140 | ``` 141 | 142 | You can call the namespace whatever you like. You can even get multiple instances of q5 running on the same page easily. 143 | 144 | ```js 145 | let q5 = new Q5(); 146 | let q6 = new Q5(); 147 | 148 | q5.setup = function(){ 149 | q5.background(255); 150 | } 151 | 152 | q6.setup = function(){ 153 | q6.background(0); 154 | } 155 | 156 | ``` 157 | 158 | Of course, you can still have the good old global namespacing via `Q5("global")`, making q5.js mostly code-compatible with existing p5 sketches: 159 | 160 | ```js 161 | 162 | new Q5("global"); 163 | 164 | function setup(){ 165 | background(0); 166 | } 167 | 168 | function draw(){ 169 | 170 | } 171 | 172 | ``` 173 | 174 | ### II. q5 Functions Anywhere 🌏 175 | 176 | #### p5 177 | 178 | In **p5.js**, most functions can only be used inside `setup()`, `draw()` etc. Otherwise, you might see something like this: 179 | 180 | ``` 181 | Did you just try to use p5.js's stroke() function? If so, you may want to move it 182 | into your sketch's setup() function. 183 | 184 | ``` 185 | 186 | #### q5 187 | 188 | **q5.js** functions can be used anywhere, it doesn't really matter! 189 | 190 | In fact, you can do away with the setup function all together. Just write your initialization routines at the top level. 191 | 192 | For example, you can now directly run examples on [p5js.org/reference](https://p5js.org/reference) without wrapping them in setup manually: 193 | 194 | ```js 195 | new Q5("global"); 196 | 197 | noStroke(); 198 | let c = color(0, 126, 255, 102); 199 | fill(c); 200 | rect(15, 15, 35, 70); 201 | 202 | ``` 203 | 204 | You can even roll out your own animation loop in place of `draw()`. Good for mixing with other libraries too. 205 | 206 | ```js 207 | 208 | new Q5("global"); 209 | 210 | fill(255,0,0); 211 | 212 | function myLoop(){ 213 | requestAnimationFrame(myLoop); 214 | rect(15, 15, 35, 70); 215 | } 216 | myLoop(); 217 | 218 | 219 | ``` 220 | 221 | Though of course the `setup()` and `draw()` functions are still there if you need them. 222 | 223 | 224 | ### III. HES 🐞 225 | 226 | #### p5 227 | 228 | **p5.js** has a nice feature called Friendly Error System (FES). It makes guesses about what you might have done wrong and put it to you via friendly language. 229 | 230 | #### q5 231 | 232 | **q5.js** does not help with your bad code. It WILL break and/or crash if you feed it the wrong stuff. 233 | 234 | ### IV. No Magic 🎩 235 | 236 | #### p5 237 | 238 | **p5.js** has some pretty smart features. For example, it can parse out a color from your strings like `color('hsl(160, 100%, 50%)')` or `color("lightblue")`. Functions behave sightly differently when under different "modes" (e.g. `hue`), and some have secret default settings. (e.g. `arc` and `text`) 239 | 240 | #### q5 241 | 242 | **q5.js** is pretty dumb. It will only do things when you communicate the command to it in the simplest way, and executes them in the most unimaginative way. This means that functions mainly just take numeric inputs (except `text()` of course), and any behavior needs to be explicitly triggered. You can expect q5 to have almost no overhead between digesting your parameters and putting them into use. 243 | 244 | 245 | ## Extra Features 246 | 247 | q5.js provides following features that are not in p5.js: 248 | 249 | - `randomExponential()` in addition to `randomGaussian()`: a random distribution that resembles exponential decay. 250 | - `curveAlpha()`: manipulate the `α` parameter of Catmull-Rom curves. 251 | - `relRotationX`, `relRotationY` and `relRotationZ`: Similar to `rotationX/Y/Z`, but are relative to the orientation of the mobile device. 252 | 253 | 254 | ## Using p5 Addons 255 | 256 | q5.js is mostly compatible with p5 addons. The only issue is that the addons usually expect a global object called `p5` for them to append methods to (among a couple other things), which `q5` naturally does not provide. 257 | 258 | As a solution, q5 provides a special file called `q5.p5acl.js` (p5 addon compatibility layer) which you can link to in your HTML before any p5 addons. For example: 259 | 260 | ```html 261 | 262 | 263 | 264 | 265 | 266 | 267 | ``` 268 | 269 | After which you'll be able to access functionalities from p5 addons under a global `addons` object, for example: 270 | 271 | ```js 272 | let sfx = addons.loadSound("music.mp3"); 273 | ``` 274 | 275 | 276 | ## Benchmarks 277 | 278 | q5.js has significant speed advantage in imaging operations because it uses hardware accelerated Canvas API directly whenever possible, instead of going over pixel by pixel. Most other functionalities have very marginal speed improvements (or none at all when parameter validation overhead is negligible). The operations with important performance differences are listed below. 279 | 280 | The following benchmarks are generated with Google Chrome 84, on an old-ish Macbook Pro 2015 (with lots of apps and tabs running); Performance varies depending on software and hardware. 281 | 282 | p5.js version used is **1.1.9**. 283 | 284 | 285 | | Operation on 1024x1024 image | p5.js | q5.js | 286 | |---|---|---| 287 | | tinting | 20FPS | 35FPS | 288 | | blurring(11px) | 0FPS | 40FPS * | 289 | | thresholding | 10FPS | 40FPS * | 290 | | grayscaling | 10FPS | 50FPS * | 291 | | inverting | 10FPS | 50FPS * | 292 | | opaque | 20FPS | 60FPS | 293 | | erode/dilate | 5FPS | 9FPS | 294 | 295 | 296 | | Misc | p5.js | q5.js | 297 | |---|---|---| 298 | | Generating 10,000 `randomGaussian()` sample | 10FPS | 20FPS| 299 | | Calling `noiseSeed()` 1,000 times | 10FPS | 60FPS | 300 | | Generate 10,000 (random) colors with `color(r,g,b)` | 5FPS | 60FPS | 301 | | Rotate a `Vector` 1,000,000 times | 13FPS | 60FPS | 302 | 303 | \* Only for browsers that support CanvasRenderingContext2D.filter ([75% of all](https://caniuse.com/#feat=mdn-api_canvasrenderingcontext2d_filter) as of Aug 2020, including Chrome, Firefox and Edge). For those that don't, performance is similar to p5.js, as identical implementations are usually used as fallbacks. 304 | 305 | Speed is a goal for q5.js, and we would very much like to see the above list grow. If you know how to make something faster, advice/pull requests are very welcome. 306 | 307 | -------------------------------------------------------------------------------- /docs/make_site.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | 3 | let snippets = fs.readFileSync("tests.js").toString().split("/*~~~").filter(x=>x.trim().length).map(x=>({link:x.split("~~~*/")[0].trim(),code:x.split("~~~*/")[1].trim()})) 4 | 5 | for (var i = 0; i < snippets.length; i++){ 6 | let romnum = ["I","II","III","IV","V","VI","VII","VIII","IX","X"]; 7 | 8 | for (var i = 0; i < snippets.length; i++){ 9 | let isUniq = true; 10 | let rank = 0; 11 | for (var j = 0; j < snippets.length; j++){ 12 | if (snippets[i].link == snippets[j].link){ 13 | if (i > j){ 14 | rank ++; 15 | isUniq = false; 16 | }else if (i < j){ 17 | isUniq = false; 18 | } 19 | } 20 | } 21 | let name = snippets[i].link.split("#/")[1].replace("p5/","").replace("p5.",""); 22 | let id = name.replace(/[^A-z0-9]/g,"_"); 23 | if (!isUniq){ 24 | name += " "+romnum[rank]+""; 25 | id += "__"+rank; 26 | } 27 | snippets[i].id = id; 28 | snippets[i].name = name; 29 | } 30 | } 31 | snippets = Object.fromEntries(snippets.map(x=>[x.id,x])/*.sort()*/); 32 | let keywords = Object.keys(snippets).map(x=>snippets[x].name.replace('/','.').split(" ")[0]).sort((a,b)=>(b.length-a.length)); 33 | 34 | function openEg(id){ 35 | function decorateP5(code){ 36 | if (!~code.search(/function +setup *\( *\)/)){ 37 | if (!~code.search(/function/)){ 38 | code = "function setup(){\n"+code+"\n};" 39 | }else{ 40 | code = "function setup(){};\n"+code; 41 | } 42 | } 43 | code = code.replace(/setup\( *\) *{/,"setup(){\npixelDensity(1);") 44 | code = `\nlet _a = new p5();\n`+code+`;\n_a._start();` 45 | return code; 46 | } 47 | function decorateQ5(code){ 48 | return `new Q5("global");\n\n${code.replace(/p5\.([A-Z])/g,"$1")}` 49 | } 50 | let cq5 = decorateQ5(snippets[id].code); 51 | 52 | let ifrl = document.getElementById("ifrl"); 53 | let ifrr = document.getElementById("ifrr"); 54 | 55 | 56 | let html = ` 236 | ` 237 | 238 | fs.writeFileSync("index.html",html); -------------------------------------------------------------------------------- /docs/setup.sh: -------------------------------------------------------------------------------- 1 | # setup q5.js docs site 2 | 3 | # download p5 example assets 4 | curl https://p5js.org/offline-reference/p5-reference.zip > p5-reference.zip; 5 | unzip p5-reference.zip; 6 | mv p5-reference/assets assets 7 | rm -rf p5-reference 8 | rm p5-reference.zip 9 | 10 | # copy files over 11 | cp ../q5.js q5.js 12 | cp ../q5.min.js q5.min.js 13 | cp ../tests.js tests.js 14 | cp ../README.md README.md 15 | 16 | # build site 17 | node make_site.js -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "q5xjs", 3 | "version": "0.0.3", 4 | "description": "A small and fast alternative (experimental) implementation of p5.js", 5 | "repository": { 6 | "type": "git", 7 | "url": "git+https://github.com/LingDong-/q5xjs.git" 8 | }, 9 | "main": "q5.min.js" 10 | } 11 | -------------------------------------------------------------------------------- /q5.js: -------------------------------------------------------------------------------- 1 | if(typeof exports === "object" && typeof module !== "undefined") module.exports = Q5; 2 | 3 | function Q5(scope){ 4 | "use strict"; 5 | return new graphics(scope); 6 | function graphics(scope){let $ = (scope == "global" ? window : this); 7 | $.canvas = document.createElement("canvas"); 8 | let ctx = $.canvas.getContext("2d"); 9 | 10 | $.width = 100; 11 | $.height = 100; 12 | $.canvas.width = $.width; 13 | $.canvas.height = $.height; 14 | 15 | if (scope != "offscreen"){ 16 | if (document.body){ 17 | document.body.appendChild($.canvas); 18 | }else{ 19 | window.addEventListener("load",function(){ 20 | document.body.appendChild($.canvas); 21 | }) 22 | } 23 | } 24 | 25 | defaultStyle(); 26 | 27 | //================================================================ 28 | // CONSTANTS 29 | //================================================================ 30 | $.MAGIC = 0x9A0CE55 31 | 32 | $.RGB = 0; 33 | $.HSV = 1; 34 | $.HSB = 1; 35 | 36 | $.CHORD = 0; 37 | $.PIE = 1; 38 | $.OPEN = 2; 39 | 40 | $.RADIUS = 1; 41 | $.CORNER = 2; 42 | $.CORNERS = 3; 43 | 44 | $.ROUND = "round"; 45 | $.SQUARE = "butt"; 46 | $.PROJECT = "square"; 47 | $.MITER = "miter"; 48 | $.BEVEL = "bevel"; 49 | 50 | $.CLOSE = 1; 51 | 52 | $.BLEND = 'source-over'; 53 | $.REMOVE = 'destination-out'; 54 | $.ADD = 'lighter'; 55 | $.DARKEST = 'darken'; 56 | $.LIGHTEST = 'lighten'; 57 | $.DIFFERENCE = 'difference'; 58 | $.SUBTRACT = 'subtract'; 59 | $.EXCLUSION = 'exclusion'; 60 | $.MULTIPLY = 'multiply'; 61 | $.SCREEN = 'screen'; 62 | $.REPLACE = 'copy'; 63 | $.OVERLAY = 'overlay'; 64 | $.HARD_LIGHT = 'hard-light'; 65 | $.SOFT_LIGHT = 'soft-light'; 66 | $.DODGE = 'color-dodge'; 67 | $.BURN = 'color-burn'; 68 | 69 | $.NORMAL = "normal"; 70 | $.ITALIC = "italic"; 71 | $.BOLD = "bold"; 72 | $.BOLDITALIC = "italic bold"; 73 | 74 | $.CENTER = "center"; 75 | $.LEFT = "left"; 76 | $.RIGHT = "right"; 77 | $.TOP = "top"; 78 | $.BOTTOM = "bottom"; 79 | $.BASELINE = "alphabetic"; 80 | 81 | $.LANDSCAPE = "landscape"; 82 | $.PORTRAIT = "portrait"; 83 | 84 | $.ALT = 18; 85 | $.BACKSPACE = 8; 86 | $.CONTROL = 17; 87 | $.DELETE = 46; 88 | $.DOWN_ARROW = 40; 89 | $.ENTER = 13; 90 | $.ESCAPE = 27; 91 | $.LEFT_ARROW = 37; 92 | $.OPTION = 18; 93 | $.RETURN = 13; 94 | $.RIGHT_ARROW = 39; 95 | $.SHIFT = 16; 96 | $.TAB = 9; 97 | $.UP_ARROW = 38; 98 | 99 | $.HALF_PI = Math.PI/2; 100 | $.PI = Math.PI; 101 | $.QUARTER_PI = Math.PI/4; 102 | $.TAU = Math.PI*2; 103 | $.TWO_PI = Math.PI*2; 104 | 105 | $.THRESHOLD = 1; 106 | $.GRAY = 2; 107 | $.OPAQUE = 3; 108 | $.INVERT = 4; 109 | $.POSTERIZE = 5; 110 | $.DILATE = 6; 111 | $.ERODE = 7; 112 | $.BLUR = 8; 113 | 114 | $.ARROW = 'default'; 115 | $.CROSS = 'crosshair'; 116 | $.HAND = 'pointer'; 117 | $.MOVE = 'move'; 118 | $.TEXT = 'text'; 119 | 120 | $.VIDEO = {video:true,audio:false}; 121 | $.AUDIO = {video:false,audio:true}; 122 | 123 | $.SHR3 = 1; 124 | $.LCG = 2; 125 | 126 | //================================================================ 127 | // HINTS 128 | //================================================================ 129 | 130 | $.HARDWARE_FILTERS = true; 131 | $.hint = function(prop,val){ 132 | $[prop]=val; 133 | } 134 | 135 | //================================================================ 136 | // PUBLIC PROPERTIES 137 | //================================================================ 138 | $.frameCount = 0; 139 | $.mouseX = 0; 140 | $.mouseY = 0; 141 | $.pmouseX = 0; 142 | $.pmouseY = 0; 143 | $.mouseButton = null; 144 | $.keyIsPressed = false; 145 | $.mouseIsPressed = false; 146 | $.key = null; 147 | $.keyCode = null; 148 | $.pixels = null; 149 | $.accelerationX = 0; 150 | $.accelerationY = 0; 151 | $.accelerationZ = 0; 152 | $.rotationX = 0; 153 | $.rotationY = 0; 154 | $.rotationZ = 0; 155 | $.relRotationX = 0; 156 | $.relRotationY = 0; 157 | $.relRotationZ = 0; 158 | 159 | $.pAccelerationX = 0; 160 | $.pAccelerationY = 0; 161 | $.pAccelerationZ = 0; 162 | $.pRotationX = 0; 163 | $.pRotationY = 0; 164 | $.pRotationZ = 0; 165 | $.pRelRotationX = 0; 166 | $.pRelRotationY = 0; 167 | $.pRelRotationZ = 0; 168 | 169 | $.touches = []; 170 | 171 | $._styleCache = [ 172 | { 173 | colorMode: $.RGB, 174 | noStroke: false, 175 | noFill: false, 176 | ellipseMode: $.CENTER, 177 | rectMode: $.CORNER, 178 | curveDetail: 20, 179 | curveAlpha: 0.0, 180 | textFont: "sans-serif", 181 | textSize: 12, 182 | textLeading: 12, 183 | textStyle: "normal" 184 | } 185 | ] 186 | $._style = $._styleCache[$._styleCache.length-1] 187 | 188 | $._noLoop = false; 189 | 190 | $._pixelDensity = 1; 191 | 192 | $._frameRate = null; 193 | 194 | $._tint = null; 195 | 196 | //================================================================ 197 | // PRIVATE VARS 198 | //================================================================ 199 | let looper = null; 200 | let firstVertex = true; 201 | let curveBuff = []; 202 | let imgData = null; 203 | let preloadCnt = 0; 204 | let keysHeld = {}; 205 | let millisStart = 0; 206 | let tmpCtx = null; 207 | let tmpCt2 = null; 208 | let tmpBuf = null; 209 | 210 | //================================================================ 211 | // ALIAS PROPERTIES 212 | //================================================================ 213 | 214 | 215 | Object.defineProperty($, "deviceOrientation", { 216 | get: function () {return Math.abs(window.orientation)==90?$.LANDSCAPE:$.PORTRAIT}, 217 | }); 218 | 219 | Object.defineProperty($, "windowWidth", { 220 | get: function () {return window.innerWidth}, 221 | }); 222 | 223 | Object.defineProperty($, "windowHeight", { 224 | get: function () {return window.innerHeight}, 225 | }); 226 | 227 | Object.defineProperty($, "drawingContext", { 228 | get: function () {return ctx}, 229 | }); 230 | 231 | //================================================================ 232 | // CANVAS 233 | //================================================================ 234 | 235 | $.createCanvas = function(width, height){ 236 | $.width = width; 237 | $.height = height; 238 | $.canvas.width = width; 239 | $.canvas.height = height; 240 | defaultStyle(); 241 | return $.canvas; 242 | } 243 | 244 | $.resizeCanvas = function(width, height){ 245 | $.width = width; 246 | $.height = height; 247 | $.canvas.width = width; 248 | $.canvas.height = height; 249 | } 250 | 251 | $.createGraphics = $.createImage = function(width, height){ 252 | let g = new graphics("offscreen"); 253 | g.createCanvas(width,height); 254 | g.noLoop(); 255 | return g; 256 | } 257 | 258 | $.pixelDensity = function(n){ 259 | if (n == undefined){ 260 | return $._pixelDensity; 261 | } 262 | $._pixelDensity = n; 263 | 264 | $.canvas.width = Math.ceil($.width*n); 265 | $.canvas.height = Math.ceil($.height*n); 266 | $.canvas.style.width = $.width+"px"; 267 | $.canvas.style.height = $.height+"px"; 268 | 269 | ctx.scale($._pixelDensity,$._pixelDensity); 270 | defaultStyle(); 271 | return $._pixelDensity; 272 | } 273 | 274 | //================================================================ 275 | // MATH 276 | //================================================================ 277 | 278 | $.map = function(value,istart,istop,ostart,ostop,clamp) { 279 | let val = ostart + (ostop - ostart) * ((value - istart)*1.0 / (istop - istart)); 280 | if (!clamp){ 281 | return val; 282 | } 283 | if (ostart < ostop){ 284 | return Math.min(Math.max(val,ostart),ostop); 285 | }else{ 286 | return Math.min(Math.max(val,ostop),ostart); 287 | } 288 | } 289 | $.lerp = function(a,b,t){ 290 | return a*(1-t) + b*t; 291 | } 292 | $.constrain = function(x,lo,hi){ 293 | return Math.min(Math.max(x,lo),hi); 294 | } 295 | $.dist = function() { 296 | if (arguments.length == 4){ 297 | return Math.hypot(arguments[0]-arguments[2],arguments[1]-arguments[3]); 298 | }else{ 299 | return Math.hypot(arguments[0]-arguments[3],arguments[1]-arguments[4],arguments[2]-arguments[5]); 300 | } 301 | } 302 | $.norm = function(value,start,stop){ 303 | return $.map(value,start,stop,0,1); 304 | } 305 | $.sq = function(x){ 306 | return x*x; 307 | } 308 | $.fract = function(x){ 309 | return x-Math.floor(x); 310 | } 311 | $.degrees = function(x){ 312 | return x*180/Math.PI; 313 | } 314 | $.radians = function(x){ 315 | return x*Math.PI/180; 316 | } 317 | $.abs = Math.abs; 318 | $.ceil = Math.ceil; 319 | $.exp = Math.exp; 320 | $.floor = Math.floor; 321 | $.log = Math.log; 322 | $.mag = Math.hypot; 323 | $.max = Math.max; 324 | $.min = Math.min; 325 | $.round = Math.round; 326 | $.sqrt = Math.sqrt; 327 | $.sin = Math.sin; 328 | $.cos = Math.cos; 329 | $.tan = Math.tan; 330 | $.asin = Math.asin; 331 | $.acos = Math.acos; 332 | $.atan = Math.atan; 333 | $.atan2 = Math.atan2; 334 | 335 | //================================================================ 336 | // VECTOR 337 | //================================================================ 338 | $.Vector = function(_x,_y,_z){let v = this; 339 | v.x = _x || 0; 340 | v.y = _y || 0; 341 | v.z = _z || 0; 342 | let cacheNorm = null; 343 | let cacheNormSq = null; 344 | v.set = function(_x,_y,_z){ 345 | v.x = _x || 0; 346 | v.y = _y || 0; 347 | v.z = _z || 0; 348 | } 349 | v.copy = function(){ 350 | return new $.Vector(v.x,v.y,v.z); 351 | } 352 | function arg2v(x,y,z){ 353 | if (x.x != undefined){ 354 | return x; 355 | } 356 | if (y != undefined){ 357 | return {x,y,z:z||0} 358 | } 359 | return {x:x,y:x,z:x}; 360 | } 361 | function calcNorm(){ 362 | if (cacheNormSq == null){ 363 | cacheNormSq = v.x*v.x+v.y*v.y+v.z*v.z; 364 | cacheNorm = Math.sqrt(cacheNormSq); 365 | } 366 | } 367 | function deprecNorm(){ 368 | cacheNormSq = null; 369 | cacheNorm = null; 370 | } 371 | v.add = function(){let u = arg2v.apply(null,arguments); v.x += u.x;v.y += u.y;v.z += u.z; deprecNorm(); return v} 372 | v.rem = function(){let u = arg2v.apply(null,arguments); v.x %= u.x;v.y %= u.y;v.z %= u.z; deprecNorm(); return v} 373 | v.sub = function(){let u = arg2v.apply(null,arguments); v.x -= u.x;v.y -= u.y;v.z -= u.z; deprecNorm(); return v} 374 | v.mult =function(){let u = arg2v.apply(null,arguments); v.x *= u.x;v.y *= u.y;v.z *= u.z; deprecNorm(); return v} 375 | v.div = function(){let u = arg2v.apply(null,arguments); v.x /= u.x;v.y /= u.y;v.z /= u.z; deprecNorm(); return v} 376 | v.mag = function(){calcNorm();return cacheNorm} 377 | v.magSq=function(){calcNorm();return cacheNormSq} 378 | v.dot= function(){let u = arg2v.apply(null,arguments); return v.x*u.x+v.y*u.y+v.z*u.z} 379 | v.dist= function(){let u = arg2v.apply(null,arguments); let x = v.x-u.x; let y = v.y-u.y; let z = v.z-u.z; return Math.sqrt(x*x+y*y+z*z)} 380 | v.cross=function(){ 381 | let u = arg2v.apply(null,arguments); 382 | let x = v.y*u.z - v.z*u.y; 383 | let y = v.z*u.x - v.x*u.z; 384 | let z = v.x*u.y - v.y*u.x; 385 | v.x = x; v.y = y; v.z = z; 386 | deprecNorm(); 387 | return v; 388 | } 389 | v.normalize = function(){ 390 | calcNorm(); 391 | let n = cacheNorm; 392 | v.x /= n; v.y /= n; v.z /= n; 393 | cacheNorm = 1; 394 | cacheNormSq = 1; 395 | return v; 396 | } 397 | v.limit = function(m){ 398 | calcNorm(); 399 | let n = cacheNorm; 400 | if (n > m){ 401 | let t = m/n; 402 | v.x *= t; v.y *= t; v.z *= t; 403 | cacheNorm = m; 404 | cacheNormSq = m*m; 405 | } 406 | return v; 407 | } 408 | v.setMag = function(m){ 409 | calcNorm(); 410 | let n = cacheNorm; 411 | let t = m/n; 412 | v.x *= t; v.y *= t; v.z *= t; 413 | cacheNorm = m; 414 | cacheNormSq = m*m; 415 | return v; 416 | } 417 | v.heading = function(){ 418 | return Math.atan2(v.y,v.x); 419 | } 420 | v.rotate = function(ang){ 421 | let costh = Math.cos(ang); 422 | let sinth = Math.sin(ang); 423 | let vx = (v.x * costh - v.y * sinth); 424 | let vy = (v.x * sinth + v.y * costh); 425 | v.x = vx; 426 | v.y = vy; 427 | return v; 428 | } 429 | v.angleBetween = function(){ 430 | let u = arg2v.apply(null,arguments); 431 | const costh = v.dot(u) / (v.mag() * u.mag()); 432 | let ang; 433 | ang = Math.acos(Math.min(1, Math.max(-1, costh))); 434 | ang = ang * Math.sign(v.cross(u).z || 1); 435 | return ang; 436 | } 437 | v.lerp = function(u,t){ 438 | v.x = v.x * (1-t) + u.x * t; 439 | v.y = v.y * (1-t) + u.y * t; 440 | v.z = v.z * (1-t) + u.z * t; 441 | deprecNorm(); 442 | return v; 443 | } 444 | v.reflect = function(n) { 445 | n.normalize(); 446 | return v.sub(n.mult(2 * v.dot(n))); 447 | } 448 | v.array = function(){ 449 | return [v.x,v.y,v.z]; 450 | } 451 | v.equals = function(u,epsilon){ 452 | if (epsilon == undefined){ 453 | epsilon = Number.EPSILON; 454 | if (epsilon == undefined){ 455 | epsilon = 0; 456 | } 457 | } 458 | return Math.abs(u.x-v.x) 360) hh = 0; 582 | hh /= 60; 583 | i = ~~hh; 584 | ff = hh-i; 585 | p = v * (1.0 - s); 586 | q = v * (1.0 - (s*ff)); 587 | t = v * (1.0 - (s*(1.0-ff))); 588 | switch (i){ 589 | case 0: 590 | r = v; g = t; b = p; 591 | break; 592 | case 1: 593 | r = q; g = v; b = p; 594 | break; 595 | case 2: 596 | r = p; g = v; b = t; 597 | break; 598 | case 3: 599 | r = p; g = q; b = v; 600 | break; 601 | case 4: 602 | r = t; g = p; b = v; 603 | break; 604 | default: 605 | r = v; g = p; b = q; 606 | break; 607 | } 608 | return [r*255,g*255,b*255]; 609 | } 610 | 611 | function rgb2hsv(r,g,b){ 612 | //https://stackoverflow.com/questions/3018313/algorithm-to-convert-rgb-to-hsv-and-hsv-to-rgb-in-range-0-255-for-both 613 | let rgbMin, rgbMax ; 614 | let h, s, v ; 615 | rgbMin = r < g ? (r < b ? r : b) : (g < b ? g : b); 616 | rgbMax = r > g ? (r > b ? r : b) : (g > b ? g : b); 617 | v = rgbMax * 100/255; 618 | if (v == 0){ 619 | h = 0; 620 | s = 0; 621 | return [h,s,v]; 622 | } 623 | s = 100 * (rgbMax - rgbMin) / rgbMax; 624 | if (s == 0){ 625 | h = 0; 626 | return [h,s,v]; 627 | } 628 | if (rgbMax == r) 629 | h = 0 + 60 * (g - b) / (rgbMax - rgbMin); 630 | else if (rgbMax == g) 631 | h = 120 + 60 * (b - r) / (rgbMax - rgbMin); 632 | else 633 | h = 240 + 60 * (r - g) / (rgbMax - rgbMin); 634 | return [h,s,v]; 635 | } 636 | 637 | $.Color = function(r,g,b,a){let that = this; 638 | that.MAGIC = 0xC010A; 639 | that._r = r; 640 | that._g = g; 641 | that._b = b; 642 | that._a = a; 643 | that._h = 0; 644 | that._s = 0; 645 | that._v = 0; 646 | that._hsvInferred = false; 647 | that.setRed = function(x){ 648 | that._r = x; 649 | that._hsvInferred = false; 650 | } 651 | that.setGreen = function(x){ 652 | that._g = x; 653 | that._hsvInferred = false; 654 | } 655 | that.setBlue = function(x){ 656 | that._b = x; 657 | that._hsvInferred = false; 658 | } 659 | that.setAlpha = function(x){ 660 | that._a = x/255; 661 | that._hsvInferred = false; 662 | } 663 | that._inferHSV = function(){ 664 | if (!that._hsvInferred){ 665 | [that._h, that._s, that._v] = rgb2hsv(that._r, that._g, that._b); 666 | that._hsvInferred = true; 667 | } 668 | } 669 | that.toString = function(){ 670 | return `rgba(${Math.round(that._r)},${Math.round(that._g)},${Math.round(that._b)},${(~~(that._a*1000))/1000})` 671 | } 672 | } 673 | 674 | $.colorMode = function(mode){ 675 | $._style.colorMode = mode; 676 | } 677 | 678 | $.color = function() { 679 | if (arguments.length == 1 && arguments[0].MAGIC == 0xC010A){ 680 | return arguments[0]; 681 | } 682 | if ($._style.colorMode == $.RGB){ 683 | if (arguments.length == 1){ 684 | return new $.Color(arguments[0],arguments[0],arguments[0],1); 685 | }else if (arguments.length == 2){ 686 | return new $.Color(arguments[0],arguments[0],arguments[0],arguments[1]/255); 687 | }else if (arguments.length == 3){ 688 | return new $.Color(arguments[0],arguments[1],arguments[2],1); 689 | }else if (arguments.length == 4){ 690 | return new $.Color(arguments[0],arguments[1],arguments[2],arguments[3]/255); 691 | } 692 | }else{ 693 | if (arguments.length == 1){ 694 | return new $.Color(...hsv2rgb(0,0,arguments[0]/100),1); 695 | }else if (arguments.length == 2){ 696 | return new $.Color(...hsv2rgb(0,0,arguments[0]/100),arguments[1]/255); 697 | }else if (arguments.length == 3){ 698 | return new $.Color(...hsv2rgb(arguments[0],arguments[1]/100,arguments[2]/100),1); 699 | }else if (arguments.length == 4){ 700 | return new $.Color(...hsv2rgb(arguments[0],arguments[1]/100,arguments[2]/100),arguments[3]); 701 | } 702 | } 703 | return null; 704 | } 705 | 706 | $.red = function(c ) { 707 | return c._r; 708 | } 709 | $.green = function(c ) { 710 | return c._g; 711 | } 712 | $.blue = function(c ) { 713 | return c._b; 714 | } 715 | $.alpha = function(c ) { 716 | return c._a*255; 717 | } 718 | $.hue = function(c ) { 719 | c._inferHSV(); 720 | return c._h; 721 | } 722 | $.saturation = function(c ) { 723 | c._inferHSV(); 724 | return c._s; 725 | } 726 | $.brightness = function(c ) { 727 | c._inferHSV(); 728 | return c._v; 729 | } 730 | $.lightness = function(c){ 731 | return (0.2126 * c._r + 0.7152 * c._g + 0.0722 * c._b)*100/255; 732 | } 733 | 734 | function lerpHue(h0,h1,t){ 735 | var methods = [ 736 | [Math.abs(h1-h0), $.map(t,0,1,h0,h1)], 737 | [Math.abs(h1+360-h0), $.map(t,0,1,h0,h1+360)], 738 | [Math.abs(h1-360-h0), $.map(t,0,1,h0,h1-360)] 739 | ] 740 | methods.sort((x,y)=>(x[0]-y[0])) 741 | return (methods[0][1]+720)%360; 742 | } 743 | 744 | $.lerpColor = function(a , b , t ){ 745 | if ($._style.colorMode == $.RGB){ 746 | return new $.Color( 747 | $.constrain($.lerp(a._r,b._r,t),0,255), 748 | $.constrain($.lerp(a._g,b._g,t),0,255), 749 | $.constrain($.lerp(a._b,b._b,t),0,255), 750 | $.constrain($.lerp(a._a,b._a,t),0,1), 751 | ) 752 | }else{ 753 | a._inferHSV(); 754 | b._inferHSV(); 755 | return new $.Color( 756 | $.constrain(lerpHue(a._h,b._h,t),0,360), 757 | $.constrain($.lerp(a._s,b._s,t),0,100), 758 | $.constrain($.lerp(a._v,b._v,t),0,100), 759 | $.constrain($.lerp(a._a,b._a,t),0,1), 760 | ) 761 | } 762 | } 763 | 764 | //================================================================ 765 | // DRAWING SETTING 766 | //================================================================ 767 | 768 | function defaultStyle(){ 769 | ctx.fillStyle = "white"; 770 | ctx.strokeStyle = "black"; 771 | ctx.lineCap = "round"; 772 | ctx.lineJoin = "miter"; 773 | } 774 | 775 | $.strokeWeight = function(n){ 776 | $._style_noStroke = false; 777 | ctx.lineWidth = n; 778 | } 779 | $.stroke = function(){ 780 | $._style.noStroke = false; 781 | if (typeof arguments[0] == "string"){ 782 | ctx.strokeStyle = arguments[0]; 783 | return; 784 | } 785 | let col = $.color.apply(null,arguments); 786 | if (col._a <= 0){ 787 | $._style.noStroke = true; 788 | return; 789 | } 790 | ctx.strokeStyle = col; 791 | } 792 | $.noStroke = function(){ 793 | $._style.noStroke = true; 794 | } 795 | $.fill = function(){ 796 | $._style.noFill = false; 797 | if (typeof arguments[0] == "string"){ 798 | ctx.fillStyle = arguments[0]; 799 | return; 800 | } 801 | let col = $.color.apply(null,arguments); 802 | if (col._a <= 0){ 803 | $._style.noFill = true; 804 | return; 805 | } 806 | ctx.fillStyle = col; 807 | } 808 | $.noFill = function(){ 809 | $._style.noFill = true; 810 | } 811 | $.blendMode = function(x){ 812 | ctx.globalCompositeOperation = x; 813 | } 814 | $.strokeCap = function(x){ctx.lineCap = x;} 815 | $.strokeJoin = function(x){ctx.lineJoin = x;} 816 | $.ellipseMode = function(x){$._style.ellipseMode = x;} 817 | $.rectMode = function(x){$._style.rectMode = x;} 818 | $.curveDetail = function(x){$._style.curveDetail = x;} 819 | $.curveAlpha = function(x){$._style.curveAlpha = x;} 820 | $.curveTightness = function(x){ 821 | console.warn("curveTightness() sets the 'alpha' parameter of Catmull-Rom curve, and is NOT identical to p5.js counterpart. As this might change in the future, please call curveAlpha() directly."); 822 | $._style.curveAlpha = x; 823 | } 824 | 825 | //================================================================ 826 | // DRAWING 827 | //================================================================ 828 | 829 | $.clear = function(){ 830 | ctx.clearRect(0,0,$.width,$.height); 831 | } 832 | 833 | $.background = function(){ 834 | if (arguments[0] && arguments[0].MAGIC == $.MAGIC){ 835 | return $.image(arguments[0],0,0,$.width,$.height); 836 | } 837 | ctx.save(); 838 | ctx.resetTransform(); 839 | ctx.scale($._pixelDensity,$._pixelDensity); 840 | if (typeof arguments[0] == "string"){ 841 | ctx.fillStyle = arguments[0]; 842 | }else{ 843 | ctx.fillStyle=$.color(...Array.from(arguments)); 844 | } 845 | ctx.fillRect(0,0,$.width,$.height); 846 | ctx.restore(); 847 | } 848 | 849 | $.line = function(x0, y0, x1, y1){ 850 | if (!$._style.noStroke){ 851 | ctx.beginPath(); 852 | ctx.moveTo(x0,y0); 853 | ctx.lineTo(x1,y1); 854 | ctx.stroke(); 855 | } 856 | } 857 | 858 | function norm2PI(x){ 859 | if (0 <= x && x < Math.PI*2){ 860 | return x; 861 | } 862 | while (x < 0){ 863 | x += Math.PI*2; 864 | } 865 | while (x >= Math.PI){ 866 | x -= Math.PI*2; 867 | } 868 | return x; 869 | } 870 | 871 | function arcImpl(x, y, w, h, start, stop, mode, detail){ 872 | if ($._style.noFill && $._style.noStroke){ 873 | return; 874 | } 875 | let lo = norm2PI(start); 876 | let hi = norm2PI(stop); 877 | ctx.beginPath(); 878 | for (let i = 0; i < detail+1; i++){ 879 | let t = i/detail; 880 | let a = $.lerp(lo,hi,t); 881 | let dx = Math.cos(a)*w/2; 882 | let dy = Math.sin(a)*h/2; 883 | ctx[i?"lineTo":"moveTo"](x+dx,y+dy); 884 | } 885 | if (mode == $.CHORD){ 886 | ctx.closePath(); 887 | }else if (mode == $.PIE){ 888 | ctx.lineTo(x,y); 889 | ctx.closePath(); 890 | } 891 | if (!$._style.noFill)ctx.fill(); 892 | if (!$._style.noStroke)ctx.stroke(); 893 | } 894 | $.arc = function(x, y, w, h, start, stop, mode, detail){ 895 | if (start == stop){ 896 | return $.ellipse(x,y,w,h); 897 | } 898 | if (detail == undefined){ 899 | detail = 25; 900 | } 901 | if (mode == undefined){ 902 | mode = $.PIE; 903 | } 904 | if ($._style.ellipseMode == $.CENTER){ 905 | arcImpl(x,y,w,h,start,stop,mode,detail); 906 | }else if ($._style.ellipseMode == $.RADIUS){ 907 | arcImpl(x,y,w*2,h*2,start,stop,mode,detail); 908 | }else if ($._style.ellipseMode == $.CORNER){ 909 | arcImpl(x+w/2,y+h/2,w,h,start,stop,mode,detail); 910 | }else if ($._style.ellipseMode == $.CORNERS){ 911 | arcImpl((x+w)/2,(y+h)/2,(w-x),(h-y),start,stop,mode,detail); 912 | } 913 | } 914 | 915 | function ellipseImpl(x,y,w,h){ 916 | if ($._style.noFill && $._style.noStroke){ 917 | return; 918 | } 919 | ctx.beginPath(); 920 | ctx.ellipse(x, y, w/2, h/2, 0, 0, Math.PI*2); 921 | if (!$._style.noFill)ctx.fill(); 922 | if (!$._style.noStroke)ctx.stroke(); 923 | } 924 | $.ellipse = function(x, y, w, h){ 925 | if (h == undefined){ 926 | h = w; 927 | } 928 | if ($._style.ellipseMode == $.CENTER){ 929 | ellipseImpl(x,y,w,h); 930 | }else if ($._style.ellipseMode == $.RADIUS){ 931 | ellipseImpl(x,y,w*2,h*2); 932 | }else if ($._style.ellipseMode == $.CORNER){ 933 | ellipseImpl(x+w/2,y+h/2,w,h); 934 | }else if ($._style.ellipseMode == $.CORNERS){ 935 | ellipseImpl((x+w)/2,(y+h)/2,(w-x),(h-y)); 936 | } 937 | } 938 | $.circle = function(x,y,r){ 939 | return $.ellipse(x,y,r,r); 940 | } 941 | $.point = function(x,y){ 942 | if (x.x){ 943 | y = x.y; 944 | x = x.x; 945 | } 946 | ctx.beginPath(); 947 | ctx.ellipse(x, y, 0.4, 0.4, 0, 0, Math.PI*2); 948 | ctx.stroke(); 949 | } 950 | function rectImpl(x,y,w,h){ 951 | if (!$._style.noFill){ 952 | ctx.fillRect(x,y,w,h); 953 | } 954 | if (!$._style.noStroke){ 955 | ctx.strokeRect(x,y,w,h); 956 | } 957 | } 958 | function roundedRectImpl(x,y,w,h,tl,tr,br,bl){ 959 | if ($._style.noFill && $._style.noStroke){ 960 | return; 961 | } 962 | if (tl == undefined){ 963 | return rectImpl(x,y,w,h); 964 | } 965 | if (tr == undefined){ 966 | return roundedRectImpl(x,y,w,h,tl,tl,tl,tl); 967 | } 968 | const hh = Math.min(Math.abs(h), Math.abs(w)) / 2; 969 | tl = Math.min(hh,tl); 970 | tr = Math.min(hh,tr); 971 | bl = Math.min(hh,bl); 972 | br = Math.min(hh,br); 973 | ctx.beginPath(); 974 | ctx.moveTo(x + tl, y); 975 | ctx.arcTo(x + w, y, x + w, y + h, tr); 976 | ctx.arcTo(x + w, y + h, x, y + h, br); 977 | ctx.arcTo(x, y + h, x, y, bl); 978 | ctx.arcTo(x, y, x + w, y, tl); 979 | ctx.closePath(); 980 | if (!$._style.noFill)ctx.fill(); 981 | if (!$._style.noStroke)ctx.stroke(); 982 | } 983 | 984 | $.rect = function(x,y,w,h, tl,tr,br,bl){ 985 | if ($._style.rectMode == $.CENTER){ 986 | roundedRectImpl(x-w/2,y-h/2,w,h, tl,tr,br,bl); 987 | }else if ($._style.rectMode == $.RADIUS){ 988 | roundedRectImpl(x-w,y-h,w*2,h*2, tl,tr,br,bl); 989 | }else if ($._style.rectMode == $.CORNER){ 990 | roundedRectImpl(x,y,w,h, tl,tr,br,bl); 991 | }else if ($._style.rectMode == $.CORNERS){ 992 | roundedRectImpl(x,y,w-x,h-y, tl,tr,br,bl); 993 | } 994 | } 995 | $.square = function(x,y,s,tl,tr,br,bl){ 996 | return $.rect(x,y,s,s,tl,tr,br,bl); 997 | } 998 | 999 | function clearBuff(){ 1000 | curveBuff = []; 1001 | } 1002 | 1003 | $.beginShape = function(){ 1004 | clearBuff(); 1005 | ctx.beginPath(); 1006 | firstVertex = true; 1007 | } 1008 | $.beginContour = function(){ 1009 | ctx.closePath(); 1010 | clearBuff(); 1011 | firstVertex = true; 1012 | } 1013 | $.endContour = function(){ 1014 | clearBuff(); 1015 | firstVertex = true; 1016 | } 1017 | $.vertex = function(x,y){ 1018 | clearBuff(); 1019 | if (firstVertex){ 1020 | ctx.moveTo(x,y); 1021 | }else{ 1022 | ctx.lineTo(x,y); 1023 | } 1024 | firstVertex = false; 1025 | } 1026 | $.bezierVertex = function(cp1x, cp1y, cp2x, cp2y, x, y){ 1027 | clearBuff(); 1028 | ctx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y); 1029 | } 1030 | $.quadraticVertex = function(cp1x, cp1y, x, y){ 1031 | clearBuff(); 1032 | ctx.quadraticCurveTo(cp1x, cp1y, x, y); 1033 | } 1034 | $.bezier = function(x1, y1, x2, y2, x3, y3, x4, y4){ 1035 | $.beginShape(); 1036 | $.vertex(x1,y1); 1037 | $.bezierVertex(x2,y2,x3,y3,x4,y4); 1038 | $.endShape(); 1039 | } 1040 | $.triangle = function(x1, y1, x2, y2, x3, y3){ 1041 | $.beginShape(); 1042 | $.vertex(x1,y1); 1043 | $.vertex(x2,y2); 1044 | $.vertex(x3,y3); 1045 | $.endShape($.CLOSE); 1046 | } 1047 | $.quad = function(x1, y1, x2, y2, x3, y3, x4, y4){ 1048 | $.beginShape(); 1049 | $.vertex(x1,y1); 1050 | $.vertex(x2,y2); 1051 | $.vertex(x3,y3); 1052 | $.vertex(x4,y4); 1053 | $.endShape($.CLOSE); 1054 | } 1055 | $.endShape = function(close){ 1056 | clearBuff(); 1057 | if (close){ 1058 | ctx.closePath(); 1059 | } 1060 | if (!$._style.noFill)ctx.fill(); 1061 | if (!$._style.noStroke)ctx.stroke(); 1062 | if ($._style.noFill && $._style.noStroke){ // eh. 1063 | ctx.save(); 1064 | ctx.fillStyle="none"; 1065 | ctx.fill(); 1066 | ctx.restore(); 1067 | } 1068 | } 1069 | function catmullRomSpline(p0x,p0y,p1x,p1y,p2x,p2y,p3x,p3y, numPts, alpha){ 1070 | //https://en.wikipedia.org/wiki/Centripetal_Catmull–Rom_spline 1071 | function catmullromSplineGetT(t, p0x, p0y, p1x, p1y, alpha){ 1072 | let a = Math.pow((p1x-p0x), 2.0) + Math.pow((p1y-p0y), 2.0); 1073 | let b = Math.pow(a, alpha * 0.5); 1074 | return (b + t); 1075 | } 1076 | let pts = []; 1077 | 1078 | let t0 = 0.0; 1079 | let t1 = catmullromSplineGetT(t0, p0x, p0y, p1x, p1y, alpha); 1080 | let t2 = catmullromSplineGetT(t1, p1x, p1y, p2x, p2y, alpha); 1081 | let t3 = catmullromSplineGetT(t2, p2x, p2y, p3x, p3y, alpha); 1082 | 1083 | for (let i=0; i0){ 1095 | s[j] = 1; 1096 | s[j+1] = 0; 1097 | }else{ 1098 | s[j] = 0; 1099 | s[j+1]=1; 1100 | } 1101 | } 1102 | } 1103 | let a1x = p0x*s[0]+p1x*s[1]; 1104 | let a1y = p0y*s[0]+p1y*s[1]; 1105 | let a2x = p1x*s[2]+p2x*s[3]; 1106 | let a2y = p1y*s[2]+p2y*s[3]; 1107 | let a3x = p2x*s[4]+p3x*s[5]; 1108 | let a3y = p2y*s[4]+p3y*s[5]; 1109 | let b1x = a1x*s[6]+a2x*s[7]; 1110 | let b1y = a1y*s[6]+a2y*s[7]; 1111 | let b2x = a2x*s[8]+a3x*s[9]; 1112 | let b2y = a2y*s[8]+a3y*s[9]; 1113 | let cx = b1x*s[2]+b2x*s[3]; 1114 | let cy = b1y*s[2]+b2y*s[3]; 1115 | pts.push([cx,cy]); 1116 | } 1117 | return pts; 1118 | } 1119 | 1120 | $.curveVertex = function(x,y){ 1121 | curveBuff.push([x,y]); 1122 | if (curveBuff.length < 4){ 1123 | return; 1124 | } 1125 | let p0 = curveBuff[curveBuff.length-4]; 1126 | let p1 = curveBuff[curveBuff.length-3]; 1127 | let p2 = curveBuff[curveBuff.length-2]; 1128 | let p3 = curveBuff[curveBuff.length-1]; 1129 | let pts = catmullRomSpline(...p0,...p1,...p2,...p3,$._style.curveDetail, 1130 | $._style.curveAlpha, 1131 | ); 1132 | for (let i = 0; i < pts.length; i++){ 1133 | if (firstVertex){ 1134 | ctx.moveTo(...pts[i]); 1135 | }else{ 1136 | ctx.lineTo(...pts[i]); 1137 | } 1138 | firstVertex = false; 1139 | } 1140 | } 1141 | $.curve = function(x1, y1, x2, y2, x3, y3, x4, y4){ 1142 | $.beginShape(); 1143 | $.curveVertex(x1,y1); 1144 | $.curveVertex(x2,y2); 1145 | $.curveVertex(x3,y3); 1146 | $.curveVertex(x4,y4); 1147 | $.endShape(); 1148 | } 1149 | 1150 | //================================================================ 1151 | // DRAWING MATRIX 1152 | //================================================================ 1153 | $.translate = function(x,y){ 1154 | ctx.translate(x,y); 1155 | } 1156 | $.rotate = function(r){ 1157 | ctx.rotate(r); 1158 | } 1159 | $.scale = function(x,y){ 1160 | if (y == undefined){ 1161 | y = x; 1162 | } 1163 | ctx.scale(x,y); 1164 | } 1165 | $.applyMatrix = function(a,b,c,d,e,f){ 1166 | ctx.transform(a,b,c,d,e,f); 1167 | } 1168 | $.shearX = function(ang){ 1169 | ctx.transform(1, 0, Math.tan(ang), 1, 0, 0); 1170 | } 1171 | $.shearY = function(ang){ 1172 | ctx.transform(1, Math.tan(ang), 0, 1, 0, 0); 1173 | } 1174 | 1175 | $.resetMatrix = function(){ 1176 | ctx.resetTransform(); 1177 | ctx.scale($._pixelDensity,$._pixelDensity); 1178 | } 1179 | 1180 | $.pushMatrix = $.push = function(){ 1181 | $._styleCache.push({...$._style}); 1182 | $._style = $._styleCache[$._styleCache.length-1]; 1183 | ctx.save(); 1184 | } 1185 | $.popMatrix = $.pop = function(){ 1186 | if ($._styleCache.length-1) { 1187 | $._styleCache.pop(); 1188 | $._style = $._styleCache[$._styleCache.length-1]; 1189 | ctx.restore(); 1190 | } 1191 | } 1192 | 1193 | //================================================================ 1194 | // IMAGING 1195 | //================================================================ 1196 | $.image = function(img, dx, dy, dWidth, dHeight, sx, sy, sWidth, sHeight){ 1197 | let drawable = img.MAGIC == $.MAGIC ? img.canvas : img; 1198 | function reset(){ 1199 | if (img.MAGIC != $.MAGIC || !$._tint){ 1200 | return; 1201 | } 1202 | let c = img.canvas.getContext('2d'); 1203 | c.save(); 1204 | c.resetTransform(); 1205 | c.clearRect(0,0,c.canvas.width,c.canvas.height); 1206 | c.drawImage(tmpCt2.canvas,0,0); 1207 | c.restore(); 1208 | } 1209 | if (img.MAGIC == $.MAGIC && $._tint != null){ 1210 | makeTmpCt2(img.canvas.width,img.canvas.height); 1211 | tmpCt2.drawImage(img.canvas,0,0); 1212 | img.tinted($._tint); 1213 | } 1214 | if (!dWidth){ 1215 | if (img.MAGIC == $.MAGIC || img.width){ 1216 | ctx.drawImage(drawable,dx,dy,img.width,img.height); 1217 | }else{ 1218 | ctx.drawImage(drawable,dx,dy,img.videoWidth,img.videoHeight); 1219 | } 1220 | reset(); 1221 | return; 1222 | } 1223 | if (!sx){ 1224 | ctx.drawImage(drawable,dx,dy,dWidth,dHeight); 1225 | reset(); 1226 | return; 1227 | } 1228 | if (!sWidth){ 1229 | sWidth = drawable.width; 1230 | } 1231 | if (!sHeight){ 1232 | sHeight = drawable.height; 1233 | } 1234 | ctx.drawImage(drawable,sx,sy,sWidth,sHeight,dx,dy,dWidth,dHeight); 1235 | reset(); 1236 | } 1237 | 1238 | $.loadPixels = function(){ 1239 | imgData = ctx.getImageData(0,0,$.canvas.width,$.canvas.height); 1240 | $.pixels = imgData.data; 1241 | } 1242 | $.updatePixels = function(){ 1243 | if (imgData != null){ 1244 | ctx.putImageData(imgData,0,0); 1245 | } 1246 | } 1247 | 1248 | $.loadImage = function(url,callback){ 1249 | preloadCnt++; 1250 | let g = $.createGraphics(100,100); 1251 | let c = g.canvas.getContext('2d'); 1252 | let img = new Image(); 1253 | img.src = url; 1254 | img.crossOrigin = "Anonymous"; 1255 | img.onload = function(){ 1256 | c.canvas.width = img.width; 1257 | c.canvas.height = img.height; 1258 | g.width = img.width; 1259 | g.height = img.height; 1260 | c.drawImage(img,0,0); 1261 | preloadCnt--; 1262 | if (callback){ 1263 | callback(g); 1264 | } 1265 | } 1266 | return g; 1267 | } 1268 | 1269 | let filterImpl = {}; 1270 | filterImpl[$.THRESHOLD] = function(data,thresh){ 1271 | if (thresh==undefined){ 1272 | thresh = 127.5; 1273 | }else{ 1274 | thresh *= 255; 1275 | } 1276 | for (let i = 0; i < data.length; i += 4) { 1277 | const gray = 0.2126 * data[i] + 0.7152 * data[i+1] + 0.0722 * data[i+2]; 1278 | data[i] = data[i + 1] = data[i + 2] = (gray>=thresh)?255:0; 1279 | } 1280 | } 1281 | filterImpl[$.GRAY] = function(data){ 1282 | for (let i = 0; i < data.length; i += 4) { 1283 | const gray = (0.2126 * data[i] + 0.7152 * data[i+1] + 0.0722 * data[i+2]); 1284 | data[i] = data[i + 1] = data[i + 2] = gray; 1285 | } 1286 | } 1287 | filterImpl[$.OPAQUE] = function(data){ 1288 | for (let i = 0; i < data.length; i += 4) { 1289 | data[i+3] = 255; 1290 | } 1291 | } 1292 | filterImpl[$.INVERT] = function(data){ 1293 | for (let i = 0; i < data.length; i += 4) { 1294 | data[i] = 255-data[i]; 1295 | data[i+1] = 255-data[i+1]; 1296 | data[i+2] = 255-data[i+2]; 1297 | } 1298 | } 1299 | filterImpl[$.POSTERIZE] = function(data,lvl){ 1300 | let lvl1 = lvl - 1; 1301 | for (let i = 0; i < data.length; i += 4) { 1302 | data[i ] = ((data[i] * lvl) >> 8) * 255 / lvl1; 1303 | data[i+1] = ((data[i+1] * lvl) >> 8) * 255 / lvl1; 1304 | data[i+2] = ((data[i+2] * lvl) >> 8) * 255 / lvl1; 1305 | } 1306 | } 1307 | 1308 | filterImpl[$.DILATE] = function(data){ 1309 | makeTmpBuf(); 1310 | tmpBuf.set(data); 1311 | let [w,h] = [ctx.canvas.width, ctx.canvas.height]; 1312 | for (let i = 0; i < h; i++){ 1313 | for (let j = 0; j < w; j++){ 1314 | let l = 4*Math.max(j-1,0); 1315 | let r = 4*Math.min(j+1,w-1); 1316 | let t = 4*Math.max(i-1,0)*w; 1317 | let b = 4*Math.min(i+1,h-1)*w; 1318 | let oi = 4*i*w; 1319 | let oj = 4*j; 1320 | for (let k = 0; k < 4; k++){ 1321 | let kt = k+t; 1322 | let kb = k+b; 1323 | let ko = k+oi; 1324 | data[oi+oj+k] = Math.max( 1325 | /*tmpBuf[kt+l],*/tmpBuf[kt+oj],/*tmpBuf[kt+r],*/ 1326 | tmpBuf[ko+l],tmpBuf[ko+oj],tmpBuf[ko+r], 1327 | /*tmpBuf[kb+l],*/tmpBuf[kb+oj],/*tmpBuf[kb+r],*/ 1328 | ); 1329 | } 1330 | } 1331 | } 1332 | } 1333 | filterImpl[$.ERODE] = function(data){ 1334 | makeTmpBuf(); 1335 | tmpBuf.set(data); 1336 | let [w,h] = [ctx.canvas.width, ctx.canvas.height]; 1337 | for (let i = 0; i < h; i++){ 1338 | for (let j = 0; j < w; j++){ 1339 | let l = 4*Math.max(j-1,0); 1340 | let r = 4*Math.min(j+1,w-1); 1341 | let t = 4*Math.max(i-1,0)*w; 1342 | let b = 4*Math.min(i+1,h-1)*w; 1343 | let oi = 4*i*w; 1344 | let oj = 4*j; 1345 | for (let k = 0; k < 4; k++){ 1346 | let kt = k+t; 1347 | let kb = k+b; 1348 | let ko = k+oi; 1349 | data[oi+oj+k] = Math.min( 1350 | /*tmpBuf[kt+l],*/tmpBuf[kt+oj],/*tmpBuf[kt+r],*/ 1351 | tmpBuf[ko+l],tmpBuf[ko+oj],tmpBuf[ko+r], 1352 | /*tmpBuf[kb+l],*/tmpBuf[kb+oj],/*tmpBuf[kb+r],*/ 1353 | ); 1354 | } 1355 | } 1356 | } 1357 | } 1358 | 1359 | 1360 | filterImpl[$.BLUR] = function(data,rad){ 1361 | rad = rad || 1; 1362 | rad = Math.floor(rad*$._pixelDensity); 1363 | makeTmpBuf(); 1364 | tmpBuf.set(data); 1365 | 1366 | let ksize = rad*2+1; 1367 | 1368 | function gauss1d(ksize){ 1369 | let im = new Float32Array(ksize); 1370 | let sigma = 0.3*rad+0.8; 1371 | let ss2 = sigma*sigma*2; 1372 | for (let i = 0; i < ksize; i++){ 1373 | let x = (i-ksize/2); 1374 | let z = Math.exp(-(x*x)/(ss2))/(2.5066282746*sigma); 1375 | im[i]=z; 1376 | } 1377 | return im; 1378 | } 1379 | 1380 | let kern = gauss1d(ksize); 1381 | let [w,h] = [ctx.canvas.width, ctx.canvas.height]; 1382 | for (let i = 0; i < h; i++){ 1383 | for (let j = 0; j < w; j++){ 1384 | let s0=0,s1=0,s2=0,s3=0; 1385 | for (let k = 0; k < ksize; k++){ 1386 | let jk = Math.min(Math.max(j-rad+k,0),w-1); 1387 | let idx = 4*(i*w+jk); 1388 | s0 += tmpBuf[idx ]*kern[k]; 1389 | s1 += tmpBuf[idx+1]*kern[k]; 1390 | s2 += tmpBuf[idx+2]*kern[k]; 1391 | s3 += tmpBuf[idx+3]*kern[k]; 1392 | } 1393 | let idx = 4*(i*w+j); 1394 | data[idx ] = s0; 1395 | data[idx+1] = s1; 1396 | data[idx+2] = s2; 1397 | data[idx+3] = s3; 1398 | } 1399 | } 1400 | tmpBuf.set(data); 1401 | for (let i = 0; i < h; i++){ 1402 | for (let j = 0; j < w; j++){ 1403 | let s0=0,s1=0,s2=0,s3=0; 1404 | for (let k = 0; k < ksize; k++){ 1405 | let ik = Math.min(Math.max(i-rad+k,0),h-1); 1406 | let idx = 4*(ik*w+j); 1407 | s0 += tmpBuf[idx ]*kern[k]; 1408 | s1 += tmpBuf[idx+1]*kern[k]; 1409 | s2 += tmpBuf[idx+2]*kern[k]; 1410 | s3 += tmpBuf[idx+3]*kern[k]; 1411 | } 1412 | let idx = 4*(i*w+j); 1413 | data[idx ] = s0; 1414 | data[idx+1] = s1; 1415 | data[idx+2] = s2; 1416 | data[idx+3] = s3; 1417 | } 1418 | } 1419 | } 1420 | 1421 | function makeTmpCtx(w,h){ 1422 | if (tmpCtx == null ){ 1423 | tmpCtx = document.createElement("canvas").getContext('2d'); 1424 | // document.body.appendChild(tmpCtx.canvas) 1425 | } 1426 | if (w == undefined){ 1427 | w = ctx.canvas.width; 1428 | h = ctx.canvas.height; 1429 | } 1430 | if (tmpCtx.canvas.width != w || tmpCtx.canvas.height != h){ 1431 | tmpCtx.canvas.width = w; 1432 | tmpCtx.canvas.height = h; 1433 | } 1434 | } 1435 | function makeTmpCt2(w,h){ 1436 | if (tmpCt2 == null ){ 1437 | tmpCt2 = document.createElement("canvas").getContext('2d'); 1438 | // document.body.appendChild(tmpCt2.canvas) 1439 | } 1440 | if (w == undefined){ 1441 | w = ctx.canvas.width; 1442 | h = ctx.canvas.height; 1443 | } 1444 | if (tmpCt2.canvas.width != w || tmpCt2.canvas.height != h){ 1445 | tmpCt2.canvas.width = w; 1446 | tmpCt2.canvas.height = h; 1447 | } 1448 | } 1449 | 1450 | function makeTmpBuf(){ 1451 | let l = ctx.canvas.width*ctx.canvas.height*4; 1452 | if (tmpBuf == null || l != tmpBuf.length){ 1453 | tmpBuf = new Uint8ClampedArray(l); 1454 | } 1455 | } 1456 | 1457 | function nativeFilter(filtstr){ 1458 | tmpCtx.clearRect(0,0,tmpCtx.canvas.width,tmpCtx.canvas.height); 1459 | tmpCtx.filter = filtstr; 1460 | tmpCtx.drawImage(ctx.canvas,0,0); 1461 | ctx.save(); 1462 | ctx.resetTransform(); 1463 | ctx.clearRect(0,0,ctx.canvas.width,ctx.canvas.height); 1464 | ctx.drawImage(tmpCtx.canvas,0,0); 1465 | ctx.restore(); 1466 | } 1467 | 1468 | $.filter = function(typ,x){ 1469 | let support = $.HARDWARE_FILTERS && (ctx.filter != undefined); 1470 | if (support){ 1471 | makeTmpCtx(); 1472 | if (typ == $.THRESHOLD){ 1473 | if (x == undefined){ 1474 | x = 0.5; 1475 | } 1476 | x = Math.max(x,0.00001); 1477 | let b = Math.floor((0.5/x)*100); 1478 | nativeFilter(`saturate(0%) brightness(${b}%) contrast(1000000%)`); 1479 | }else if (typ == $.GRAY){ 1480 | nativeFilter(`saturate(0%)`); 1481 | }else if (typ == $.OPAQUE){ 1482 | tmpCtx.fillStyle = "black"; 1483 | tmpCtx.fillRect(0,0,tmpCtx.canvas.width,tmpCtx.canvas.height); 1484 | tmpCtx.drawImage(ctx.canvas,0,0); 1485 | ctx.save(); 1486 | ctx.resetTransform(); 1487 | ctx.drawImage(tmpCtx.canvas,0,0); 1488 | ctx.restore(); 1489 | }else if (typ == $.INVERT){ 1490 | nativeFilter(`invert(100%)`); 1491 | }else if (typ == $.BLUR){ 1492 | nativeFilter(`blur(${Math.ceil(x*$._pixelDensity/1)||1}px)`); 1493 | }else{ 1494 | let imgData = ctx.getImageData(0,0,ctx.canvas.width,ctx.canvas.height); 1495 | filterImpl[typ](imgData.data,x); 1496 | ctx.putImageData(imgData,0,0); 1497 | } 1498 | }else{ 1499 | let imgData = ctx.getImageData(0,0,ctx.canvas.width,ctx.canvas.height); 1500 | filterImpl[typ](imgData.data,x); 1501 | ctx.putImageData(imgData,0,0); 1502 | } 1503 | } 1504 | 1505 | $.resize = function(w,h){ 1506 | makeTmpCtx(); 1507 | tmpCtx.drawImage(ctx.canvas,0,0); 1508 | $.width = w; 1509 | $.height = h; 1510 | ctx.canvas.width = w*$._pixelDensity; 1511 | ctx.canvas.height = h*$._pixelDensity; 1512 | ctx.save(); 1513 | ctx.resetTransform(); 1514 | ctx.clearRect(0,0,ctx.canvas.width,ctx.canvas.height); 1515 | ctx.drawImage(tmpCtx.canvas,0,0,ctx.canvas.width,ctx.canvas.height); 1516 | ctx.restore(); 1517 | } 1518 | 1519 | $.get = function(x,y,w,h){ 1520 | if (x != undefined && w == undefined){ 1521 | let c = ctx.getImageData(x,y,1,1).data; 1522 | return new $.Color(c[0],c[1],c[2],c[3]/255); 1523 | } 1524 | x = x || 0; 1525 | y = y || 0; 1526 | w = w || $.width; 1527 | h = h || $.height; 1528 | let g = $.createGraphics(w,h); 1529 | g.pixelDensity($._pixelDensity); 1530 | let imgData = ctx.getImageData( 1531 | x*$._pixelDensity,y*$._pixelDensity, 1532 | w*$._pixelDensity,h*$._pixelDensity); 1533 | g.canvas.getContext('2d').putImageData(imgData,0,0); 1534 | return g; 1535 | } 1536 | 1537 | $.set = function(x,y,c){ 1538 | if (c.MAGIC == $.MAGIC){ 1539 | let old = $._tint; 1540 | $._tint = null; 1541 | $.image(c,x,y); 1542 | $._tint = old; 1543 | return; 1544 | } 1545 | let idx = 4*((y*$._pixelDensity*ctx.canvas.width)+(x*$._pixelDensity)); 1546 | $.pixels[idx ] = c._r; 1547 | $.pixels[idx+1] = c._g; 1548 | $.pixels[idx+2] = c._b; 1549 | $.pixels[idx+3] = c._a*255; 1550 | } 1551 | 1552 | $.tinted = function(){ 1553 | let col = $.color(...Array.from(arguments)); 1554 | let alpha = col._a; 1555 | col._a = 1; 1556 | makeTmpCtx(); 1557 | tmpCtx.clearRect(0,0,tmpCtx.canvas.width,tmpCtx.canvas.height); 1558 | tmpCtx.fillStyle = col; 1559 | tmpCtx.fillRect(0,0,tmpCtx.canvas.width,tmpCtx.canvas.height); 1560 | tmpCtx.globalCompositeOperation = "multiply"; 1561 | tmpCtx.drawImage(ctx.canvas,0,0); 1562 | tmpCtx.globalCompositeOperation = "source-over"; 1563 | 1564 | ctx.save(); 1565 | ctx.resetTransform(); 1566 | let old = ctx.globalCompositeOperation; 1567 | ctx.globalCompositeOperation = "source-in"; 1568 | ctx.drawImage(tmpCtx.canvas,0,0); 1569 | ctx.globalCompositeOperation = old; 1570 | ctx.restore(); 1571 | 1572 | tmpCtx.globalAlpha = alpha; 1573 | tmpCtx.clearRect(0,0,tmpCtx.canvas.width,tmpCtx.canvas.height); 1574 | tmpCtx.drawImage(ctx.canvas,0,0); 1575 | tmpCtx.globalAlpha = 1; 1576 | 1577 | ctx.save(); 1578 | ctx.resetTransform(); 1579 | ctx.clearRect(0,0,ctx.canvas.width,ctx.canvas.height); 1580 | ctx.drawImage(tmpCtx.canvas,0,0); 1581 | ctx.restore(); 1582 | } 1583 | 1584 | $.tint = function(){ 1585 | $._tint = $.color(...Array.from(arguments)); 1586 | } 1587 | 1588 | $.noTint = function(){ 1589 | $._tint = null; 1590 | } 1591 | 1592 | $.mask = function(img){ 1593 | ctx.save(); 1594 | ctx.resetTransform(); 1595 | let old = ctx.globalCompositeOperation; 1596 | ctx.globalCompositeOperation = "destination-in"; 1597 | ctx.drawImage(img.canvas,0,0); 1598 | ctx.globalCompositeOperation = old; 1599 | ctx.restore(); 1600 | } 1601 | 1602 | $.clearTemporaryBuffers = function(){ 1603 | tmpCtx = null; 1604 | tmpCt2 = null; 1605 | tmpBuf = null; 1606 | } 1607 | 1608 | $.save = function(name,ext){ 1609 | name = name || "untitled"; 1610 | ext = ext || "png"; 1611 | var down = document.createElement('a') 1612 | down.innerHTML = "[Download]" 1613 | down.addEventListener('click', function() { 1614 | this.href = ctx.canvas.toDataURL(); 1615 | this.download = name + "." + ext; 1616 | }, false); 1617 | document.body.appendChild(down); 1618 | down.click() 1619 | document.body.removeChild(down); 1620 | } 1621 | $.saveCanvas = function(a,b,c){ 1622 | if (a.MAGIC == $.MAGIC){ 1623 | if (c){ 1624 | a.save(b,c); 1625 | } 1626 | let s = b.split(".") 1627 | return a.save(s.slice(0,-1).join("."),s[s.length-1]); 1628 | } 1629 | if (b){ 1630 | return $.save(a,b); 1631 | } 1632 | let s = a.split(".") 1633 | return $.save(s.slice(0,-1).join("."),s[s.length-1]); 1634 | } 1635 | 1636 | //================================================================ 1637 | // TYPOGRAPHY 1638 | //================================================================ 1639 | 1640 | $.loadFont = function(url,callback){ 1641 | let sp = url.split("/"); 1642 | let name = sp[sp.length-1].split(".")[0].replace(" ",""); 1643 | let cssStr = `@font-face { 1644 | font-family: '${name}'; 1645 | src: url('${url}'); 1646 | }`; 1647 | const style = document.createElement('style'); 1648 | style.textContent = cssStr; 1649 | document.head.append(style); 1650 | return name; 1651 | } 1652 | $.textFont = function(x){ 1653 | $._style.textFont = x; 1654 | } 1655 | $.textSize = function(x){ 1656 | $._style.textSize = x; 1657 | $._style.textLeading = x; 1658 | } 1659 | $.textLeading = function(x){ 1660 | $._style.textLeading = x; 1661 | } 1662 | $.textStyle = function(x){ 1663 | $._style.textStyle = x; 1664 | } 1665 | $.textAlign = function(horiz,vert){ 1666 | ctx.textAlign = horiz; 1667 | if (vert){ 1668 | ctx.textBaseline = (vert == $.CENTER) ? "middle" : vert; 1669 | } 1670 | } 1671 | $.text = function(str,x,y,w){ 1672 | if (!str){ 1673 | return; 1674 | } 1675 | str = str.toString(); 1676 | if ($._style.noFill && $._style.noStroke){ 1677 | return; 1678 | } 1679 | ctx.font = `${$._style.textStyle} ${$._style.textSize}px ${$._style.textFont}`; 1680 | let lines = str.split("\n"); 1681 | for (let i = 0; i < lines.length; i++){ 1682 | if (!$._style.noFill){ctx.fillText(lines[i],x,y,w)} 1683 | if (!$._style.noStroke){ctx.strokeText(lines[i],x,y,w)} 1684 | y += $._style.textLeading; 1685 | } 1686 | } 1687 | $.textWidth = function(str){ 1688 | ctx.font = `${$._style.textStyle} ${$._style.textSize}px ${$._style.textFont}`; 1689 | return ctx.measureText(str).width; 1690 | } 1691 | $.textAscent = function(str){ 1692 | ctx.font = `${$._style.textStyle} ${$._style.textSize}px ${$._style.textFont}`; 1693 | return ctx.measureText(str).actualBoundingBoxAscent; 1694 | } 1695 | $.textDescent = function(str){ 1696 | ctx.font = `${$._style.textStyle} ${$._style.textSize}px ${$._style.textFont}`; 1697 | return ctx.measureText(str).actualBoundingBoxDescent; 1698 | } 1699 | 1700 | 1701 | //================================================================ 1702 | // RANDOM 1703 | //================================================================ 1704 | 1705 | //https://github.com/processing/p5.js/blob/1.1.9/src/math/noise.js 1706 | var PERLIN_YWRAPB = 4; var PERLIN_YWRAP = 1<=1.0) { xi++; xf--; } 1746 | if (yf>=1.0) { yi++; yf--; } 1747 | if (zf>=1.0) { zi++; zf--; } 1748 | } 1749 | return r; 1750 | }; 1751 | 1752 | $.noiseDetail = function(lod, falloff) { 1753 | if (lod>0) { perlin_octaves=lod; } 1754 | if (falloff>0) { perlin_amp_falloff=falloff; } 1755 | }; 1756 | const Lcg = function(){ 1757 | const m = 4294967296; 1758 | const a = 1664525; 1759 | const c = 1013904223; 1760 | let seed, z; 1761 | return { 1762 | setSeed(val) { 1763 | z = seed = (val == null ? Math.random() * m : val) >>> 0; 1764 | }, 1765 | getSeed() { 1766 | return seed; 1767 | }, 1768 | rand() { 1769 | z = (a * z + c) % m; 1770 | return z / m; 1771 | } 1772 | }; 1773 | }; 1774 | const Shr3 = function(){ 1775 | let jsr, seed; 1776 | let m = 4294967295; 1777 | return { 1778 | setSeed(val){ 1779 | jsr = seed = (val == null ? Math.random() * m : val) >>> 0; 1780 | }, 1781 | getSeed() { 1782 | return seed; 1783 | }, 1784 | rand() { 1785 | jsr^=(jsr<<17); 1786 | jsr^=(jsr>>13); 1787 | jsr^=(jsr<<5); 1788 | return (jsr>>>0)/m; 1789 | } 1790 | } 1791 | } 1792 | let rng1 = Shr3(); 1793 | rng1.setSeed(); 1794 | 1795 | $.noiseSeed = function(seed) { 1796 | let jsr = (seed == undefined) ? (Math.random()*4294967295) : seed; 1797 | if (!p_perlin){ 1798 | p_perlin = new Float32Array(PERLIN_SIZE + 1); 1799 | } 1800 | for (var i = 0; i < PERLIN_SIZE + 1; i++) { 1801 | jsr^=(jsr<<17); 1802 | jsr^=(jsr>>13); 1803 | jsr^=(jsr<<5); 1804 | p_perlin[i] = (jsr>>>0)/4294967295; 1805 | } 1806 | }; 1807 | $.randomSeed = function(seed){ 1808 | rng1.setSeed(seed); 1809 | } 1810 | $.random = function(a,b){ 1811 | if (a == undefined){ 1812 | return rng1.rand(); 1813 | } 1814 | if (typeof a == 'number'){ 1815 | if (b != undefined){ 1816 | return rng1.rand()*(b-a)+a; 1817 | }else{ 1818 | return rng1.rand()*a; 1819 | } 1820 | }else{ 1821 | return a[~~(a.length*rng1.rand())]; 1822 | } 1823 | } 1824 | $.randomGenerator = function(method){ 1825 | if (method == $.LCG){ 1826 | rng1 = Lcg(); 1827 | }else if (method == $.SHR3){ 1828 | rng1 = Shr3(); 1829 | } 1830 | rng1.setSeed(); 1831 | } 1832 | 1833 | var ziggurat = new function() { 1834 | //http://ziggurat.glitch.me/ 1835 | var iz; 1836 | var jz; 1837 | var kn = new Array(128); 1838 | var ke = new Array(256); 1839 | var hz; 1840 | var wn = new Array(128); 1841 | var fn = new Array(128); 1842 | var we = new Array(256); 1843 | var fe = new Array(256); 1844 | var SHR3 = function() { 1845 | return rng1.rand()*4294967296-2147483648; 1846 | }; 1847 | var UNI = function() { 1848 | return 0.5 + (SHR3()<<0) * 0.2328306e-9; 1849 | }; 1850 | 1851 | var RNOR = function() { 1852 | hz = SHR3(); 1853 | iz = hz & 127; 1854 | return Math.abs(hz) < kn[iz] ? hz * wn[iz] : nfix(); 1855 | }; 1856 | var REXP = function() { 1857 | jz = SHR3()>>>0; 1858 | iz = jz & 255; 1859 | return jz < kn[iz] ? jz * we[iz] : efix(); 1860 | }; 1861 | var nfix = function() { 1862 | var r = 3.44262; 1863 | var x, y; 1864 | var u1, u2; 1865 | for (;;) { 1866 | x = hz * wn[iz]; 1867 | if (iz == 0) { 1868 | do { 1869 | u1 = UNI(); 1870 | u2 = UNI(); 1871 | x = -Math.log(u1) * 0.2904764; 1872 | y = -Math.log(u2); 1873 | } while (y + y < x * x); 1874 | return (hz > 0) ? (r + x) : (- r - x); 1875 | } 1876 | 1877 | if (fn[iz] + UNI() * (fn[iz - 1] - fn[iz]) < Math.exp(-0.5 * x * x)) { 1878 | return x; 1879 | } 1880 | hz = SHR3(); 1881 | iz = hz & 127; 1882 | if (Math.abs(hz) < kn[iz]) { 1883 | return hz * wn[iz]; 1884 | } 1885 | } 1886 | 1887 | }; 1888 | var efix = function() { 1889 | var x; 1890 | for (;;) { 1891 | if (iz == 0) { 1892 | return 7.69711 - Math.log(UNI()); 1893 | } 1894 | x = jz * we[iz]; 1895 | if (fe[iz] + UNI() * (fe[iz - 1] - fe[iz]) < Math.exp(-x)) { 1896 | return x; 1897 | } 1898 | jz = SHR3(); 1899 | iz = jz & 255; 1900 | if (jz < ke[iz]) { 1901 | return jz * we[iz]; 1902 | } 1903 | } 1904 | }; 1905 | 1906 | var zigset = function() { 1907 | var m1 = 2147483648; 1908 | var m2 = 4294967296; 1909 | var dn = 3.442619855899; 1910 | var tn = dn; 1911 | var vn = 9.91256303526217e-3; 1912 | var q; 1913 | var de = 7.697117470131487; 1914 | var te = de; 1915 | var ve = 3.949659822581572e-3; 1916 | var i; 1917 | 1918 | /* Tables for RNOR */ 1919 | q = vn / Math.exp(-0.5 * dn * dn); 1920 | kn[0] = Math.floor((dn / q) * m1); 1921 | kn[1] = 0; 1922 | wn[0] = q / m1; 1923 | wn[127] = dn / m1; 1924 | fn[0] = 1; 1925 | fn[127] = Math.exp(-0.5 * dn * dn); 1926 | for (i = 126; i >= 1; i--) { 1927 | dn = Math.sqrt(-2 * Math.log(vn / dn + Math.exp(-0.5 * dn * dn))); 1928 | kn[i + 1] = Math.floor((dn / tn) * m1); 1929 | tn = dn; 1930 | fn[i] = Math.exp(-0.5 * dn * dn); 1931 | wn[i] = dn / m1; 1932 | } 1933 | /*Tables for REXP */ 1934 | q = ve / Math.exp(-de); 1935 | ke[0] = Math.floor((de / q) * m2); 1936 | ke[1] = 0; 1937 | we[0] = q / m2; 1938 | we[255] = de / m2; 1939 | fe[0] = 1; 1940 | fe[255] = Math.exp(-de); 1941 | for (i = 254; i >= 1; i--) { 1942 | de = -Math.log(ve / de + Math.exp(-de)); 1943 | ke[i + 1] = Math.floor((de / te) * m2); 1944 | te = de; 1945 | fe[i] = Math.exp(-de); 1946 | we[i] = de / m2; 1947 | } 1948 | }; 1949 | this.SHR3 = SHR3; 1950 | this.UNI = UNI; 1951 | this.RNOR = RNOR; 1952 | this.REXP = REXP; 1953 | this.zigset = zigset; 1954 | } 1955 | ziggurat.hasInit = false; 1956 | 1957 | $.randomGaussian = function(mean,std){ 1958 | if (!ziggurat.hasInit){ 1959 | ziggurat.zigset(); 1960 | ziggurat.hasInit = true; 1961 | } 1962 | return ziggurat.RNOR()*std+mean; 1963 | } 1964 | 1965 | $.randomExponential = function(){ 1966 | if (!ziggurat.hasInit){ 1967 | ziggurat.zigset(); 1968 | ziggurat.hasInit = true; 1969 | } 1970 | return ziggurat.REXP(); 1971 | } 1972 | 1973 | 1974 | //================================================================ 1975 | // ENVIRONMENT 1976 | //================================================================ 1977 | 1978 | $.print = console.log; 1979 | $.cursor = function(name,x,y){ 1980 | let pfx = ""; 1981 | if (name.includes(".")){ 1982 | name = `url("${name}")`; 1983 | pfx = ", auto"; 1984 | } 1985 | if (x != undefined){ 1986 | name += " "+x+" "+y; 1987 | } 1988 | $.canvas.style.cursor = name+pfx; 1989 | } 1990 | $.noCursor = function(){ 1991 | $.canvas.style.cursor = "none"; 1992 | } 1993 | 1994 | //================================================================ 1995 | // DOM 1996 | //================================================================ 1997 | 1998 | $.createCapture = function(x){ 1999 | var vid = document.createElement("video"); 2000 | vid.playsinline="playsinline"; 2001 | vid.autoplay="autoplay"; 2002 | navigator.mediaDevices.getUserMedia(x).then(function(stream){ 2003 | vid.srcObject = stream; 2004 | }) 2005 | vid.style.position="absolute"; 2006 | vid.style.opacity=0.00001; 2007 | vid.style.zIndex =-1000; 2008 | document.body.appendChild(vid); 2009 | return vid; 2010 | } 2011 | 2012 | 2013 | //================================================================ 2014 | // EVENTS 2015 | //================================================================ 2016 | 2017 | 2018 | let eventNames = [ 2019 | "setup","draw","preload", 2020 | "mouseMoved","mousePressed","mouseReleased","mouseDragged","mouseClicked", 2021 | "keyPressed","keyReleased","keyTyped", 2022 | "touchStarted","touchEnded", 2023 | ]; 2024 | for (let k of eventNames){ 2025 | let intern = "_"+k+"Fn"; 2026 | $[intern] = function(){}; 2027 | $[intern].isPlaceHolder = true; 2028 | if ($[k]){ 2029 | $[intern] = $[k]; 2030 | }else{ 2031 | Object.defineProperty($, k, { 2032 | set: function (fun) {$[intern] = fun;}, 2033 | }); 2034 | } 2035 | } 2036 | 2037 | function _draw(){ 2038 | if (!$._noLoop){ 2039 | if ($._frameRate == null){ 2040 | looper = requestAnimationFrame(_draw); 2041 | }else{ 2042 | looper = setTimeout(_draw,1000/$._frameRate); 2043 | } 2044 | } 2045 | clearBuff(); 2046 | firstVertex = true; 2047 | $.push(); 2048 | $._drawFn(); 2049 | $.pop(); 2050 | ++$.frameCount; 2051 | } 2052 | 2053 | $.noLoop = function(){ 2054 | $._noLoop = true; 2055 | looper = null; 2056 | } 2057 | $.loop = function(){ 2058 | $._noLoop = false; 2059 | if (looper == null){ 2060 | _draw(); 2061 | } 2062 | } 2063 | $.redraw = function(){ 2064 | _draw(); 2065 | } 2066 | $.frameRate = function(fps){ 2067 | $._frameRate = fps; 2068 | } 2069 | 2070 | setTimeout(function(){ 2071 | $._preloadFn(); 2072 | millisStart = window.performance.now(); 2073 | _start(); 2074 | function _start(){ 2075 | if (preloadCnt > 0){ 2076 | return setTimeout(_start,10); 2077 | } 2078 | // ctx.save(); 2079 | $._setupFn(); 2080 | // ctx.restore(); 2081 | _draw(); 2082 | 2083 | }; 2084 | },1); 2085 | 2086 | $.canvas.onmousemove = function(event){ 2087 | 2088 | $.pmouseX = $.mouseX; 2089 | $.pmouseY = $.mouseY; 2090 | $.mouseX = event.offsetX; 2091 | $.mouseY = event.offsetY; 2092 | 2093 | if ($.mouseIsPressed){ 2094 | $._mouseDraggedFn(event); 2095 | }else{ 2096 | $._mouseMovedFn(event); 2097 | } 2098 | } 2099 | $.canvas.onmousedown = function(event){ 2100 | $.pmouseX = $.mouseX; 2101 | $.pmouseY = $.mouseY; 2102 | $.mouseX = event.offsetX; 2103 | $.mouseY = event.offsetY; 2104 | $.mouseIsPressed = true; 2105 | $.mouseButton = [$.LEFT,$.CENTER,$.RIGHT][event.button]; 2106 | $._mousePressedFn(event); 2107 | } 2108 | $.canvas.onmouseup = function(event){ 2109 | $.pmouseX = $.mouseX; 2110 | $.pmouseY = $.mouseY; 2111 | $.mouseX = event.offsetX; 2112 | $.mouseY = event.offsetY; 2113 | $.mouseIsPressed = false; 2114 | $._mouseReleasedFn(event); 2115 | } 2116 | $.canvas.onclick = function(event){ 2117 | $.pmouseX = $.mouseX; 2118 | $.pmouseY = $.mouseY; 2119 | $.mouseX = event.offsetX; 2120 | $.mouseY = event.offsetY; 2121 | $.mouseIsPressed = true; 2122 | $._mouseClickedFn(event); 2123 | $.mouseIsPressed = false; 2124 | } 2125 | window.addEventListener("keydown",function(event){ 2126 | $.keyIsPressed = true; 2127 | $.key = event.key; 2128 | $.keyCode = event.keyCode; 2129 | keysHeld[$.keyCode] = true; 2130 | $._keyPressedFn(event); 2131 | if (event.key.length == 1){ 2132 | $._keyTypedFn(event); 2133 | } 2134 | }) 2135 | window.addEventListener("keyup",function(event){ 2136 | $.keyIsPressed = false; 2137 | $.key = event.key; 2138 | $.keyCode = event.keyCode; 2139 | keysHeld[$.keyCode] = false; 2140 | $._keyReleasedFn(event); 2141 | }) 2142 | $.keyIsDown = function(x){ 2143 | return !!keysHeld[x]; 2144 | } 2145 | 2146 | 2147 | function getTouchInfo(touch) { 2148 | const rect = $.canvas.getBoundingClientRect(); 2149 | const sx = $.canvas.scrollWidth / $.width || 1; 2150 | const sy = $.canvas.scrollHeight / $.height || 1; 2151 | return { 2152 | x: (touch.clientX - rect.left) / sx, 2153 | y: (touch.clientY - rect.top) / sy, 2154 | id: touch.identifier 2155 | }; 2156 | } 2157 | function isTouchUnaware(){ 2158 | return $._touchStarted.isPlaceHolder 2159 | && $._touchMoved.isPlaceHolder 2160 | && $._touchEnded.isPlaceHolder 2161 | } 2162 | $.canvas.ontouchstart = function(event){ 2163 | $.touches = event.touches.map(getTouchInfo); 2164 | if (isTouchUnaware()){ 2165 | $.pmouseX = $.mouseX; 2166 | $.pmouseY = $.mouseY; 2167 | $.mouseX = $.touches[0].x; 2168 | $.mouseY = $.touches[0].y; 2169 | $.mouseIsPressed = true; 2170 | $.mouseButton = $.LEFT; 2171 | if (!$._mousePressedFn(event)){ 2172 | event.preventDefault(); 2173 | } 2174 | } 2175 | if (!$._touchStartedFn(event)){ 2176 | event.preventDefault(); 2177 | } 2178 | 2179 | } 2180 | $.canvas.ontouchmove = function(event){ 2181 | $.touches = event.touches.map(getTouchInfo); 2182 | if (isTouchUnaware()){ 2183 | $.pmouseX = $.mouseX; 2184 | $.pmouseY = $.mouseY; 2185 | $.mouseX = $.touches[0].x; 2186 | $.mouseY = $.touches[0].y; 2187 | $.mouseIsPressed = true; 2188 | $.mouseButton = $.LEFT; 2189 | if (!$._mouseDraggedFn(event)){ 2190 | event.preventDefault(); 2191 | } 2192 | } 2193 | if (!$._touchMovedFn(event)){ 2194 | event.preventDefault(); 2195 | } 2196 | 2197 | } 2198 | $.canvas.ontouchend = $.canvas.ontouchcancel = function(event){ 2199 | $.touches = event.touches.map(getTouchInfo); 2200 | if (isTouchUnaware()){ 2201 | $.pmouseX = $.mouseX; 2202 | $.pmouseY = $.mouseY; 2203 | $.mouseX = $.touches[0].x; 2204 | $.mouseY = $.touches[0].y; 2205 | $.mouseIsPressed = false; 2206 | if (!$._mouseReleasedFn(event)){ 2207 | event.preventDefault(); 2208 | } 2209 | } 2210 | if (!$._touchEndedFn(event)){ 2211 | event.preventDefault(); 2212 | } 2213 | } 2214 | 2215 | $.hasSensorPermission = ((!window.DeviceOrientationEvent) && (!window.DeviceMotionEvent)) || !(DeviceOrientationEvent.requestPermission || DeviceMotionEvent.requestPermission); 2216 | $.requestSensorPermissions = function(){ 2217 | if (DeviceOrientationEvent.requestPermission){ 2218 | DeviceOrientationEvent.requestPermission() 2219 | .then(response => { 2220 | if (response == 'granted') { 2221 | if (DeviceMotionEvent.requestPermission){ 2222 | DeviceMotionEvent.requestPermission() 2223 | .then(response => { 2224 | if (response == 'granted') { 2225 | $.hasSensorPermission = true; 2226 | } 2227 | }) 2228 | .catch(alert) 2229 | } 2230 | } 2231 | }) 2232 | .catch(alert) 2233 | } 2234 | } 2235 | 2236 | //================================================================ 2237 | // SENSORS 2238 | //================================================================ 2239 | 2240 | // 3d transformation helpers 2241 | let ROTX = a=> [1,0,0,0, 0,Math.cos(a),-Math.sin(a),0, 0,Math.sin(a),Math.cos(a),0, 0,0,0,1] 2242 | let ROTY = a=> [Math.cos(a),0,Math.sin(a),0, 0,1,0,0, -Math.sin(a),0,Math.cos(a),0, 0,0,0,1] 2243 | let MULT = (A,B)=> [(A)[0]*(B)[0]+(A)[1]*(B)[4]+(A)[2]*(B)[8]+(A)[3]*(B)[12],(A)[0]*(B)[1]+(A)[1]*(B)[5]+(A)[2]*(B)[9]+(A)[3]*(B)[13],(A)[0]*(B)[2]+(A)[1]*(B)[6]+(A)[2]*(B)[10]+(A)[3]*(B)[14],(A)[0]*(B)[3]+(A)[1]*(B)[7]+(A)[2]*(B)[11]+(A)[3]*(B)[15],(A)[4]*(B)[0]+(A)[5]*(B)[4]+(A)[6]*(B)[8]+(A)[7]*(B)[12],(A)[4]*(B)[1]+(A)[5]*(B)[5]+(A)[6]*(B)[9]+(A)[7]*(B)[13],(A)[4]*(B)[2]+(A)[5]*(B)[6]+(A)[6]*(B)[10]+(A)[7]*(B)[14],(A)[4]*(B)[3]+(A)[5]*(B)[7]+(A)[6]*(B)[11]+(A)[7]*(B)[15],(A)[8]*(B)[0]+(A)[9]*(B)[4]+(A)[10]*(B)[8]+(A)[11]*(B)[12],(A)[8]*(B)[1]+(A)[9]*(B)[5]+(A)[10]*(B)[9]+(A)[11]*(B)[13],(A)[8]*(B)[2]+(A)[9]*(B)[6]+(A)[10]*(B)[10]+(A)[11]*(B)[14],(A)[8]*(B)[3]+(A)[9]*(B)[7]+(A)[10]*(B)[11]+(A)[11]*(B)[15],(A)[12]*(B)[0]+(A)[13]*(B)[4]+(A)[14]*(B)[8]+(A)[15]*(B)[12],(A)[12]*(B)[1]+(A)[13]*(B)[5]+(A)[14]*(B)[9]+(A)[15]*(B)[13],(A)[12]*(B)[2]+(A)[13]*(B)[6]+(A)[14]*(B)[10]+(A)[15]*(B)[14],(A)[12]*(B)[3]+(A)[13]*(B)[7]+(A)[14]*(B)[11]+(A)[15]*(B)[15]] 2244 | let TRFM = (A,v)=> [((A)[0]*(v)[0]+(A)[1]*(v)[1]+(A)[2]*(v)[2]+(A)[3])/((A)[12]*(v)[0]+(A)[13]*(v)[1]+(A)[14]*(v)[2]+(A)[15]),((A)[4]*(v)[0]+(A)[5]*(v)[1]+(A)[6]*(v)[2]+(A)[7])/((A)[12]*(v)[0]+(A)[13]*(v)[1]+(A)[14]*(v)[2]+(A)[15]),((A)[8]*(v)[0]+(A)[9]*(v)[1]+(A)[10]*(v)[2]+(A)[11])/((A)[12]*(v)[0]+(A)[13]*(v)[1]+(A)[14]*(v)[2]+(A)[15])] 2245 | 2246 | window.ondeviceorientation = function(event){ 2247 | $.pRotationX = $.rotationX; 2248 | $.pRotationY = $.rotationY; 2249 | $.pRotationZ = $.rotationZ; 2250 | $.pRelRotationX = $.relRotationX; 2251 | $.pRelRotationY = $.relRotationY; 2252 | $.pRelRotationZ = $.relRotationZ; 2253 | 2254 | $.rotationX = event.beta * (Math.PI / 180.0); 2255 | $.rotationY = event.gamma * (Math.PI / 180.0); 2256 | $.rotationZ = event.alpha * (Math.PI / 180.0); 2257 | $.relRotationX = [-$.rotationY,-$.rotationX,$.rotationY][~~(window.orientation/90)+1]; 2258 | $.relRotationY = [-$.rotationX, $.rotationY,$.rotationX][~~(window.orientation/90)+1]; 2259 | $.relRotationZ = $.rotationZ; 2260 | } 2261 | window.ondevicemotion = function(event) { 2262 | $.pAccelerationX = $.accelerationX 2263 | $.pAccelerationY = $.accelerationY 2264 | $.pAccelerationZ = $.accelerationZ 2265 | if (!event.acceleration){ // devices that don't support plain acceleration 2266 | // compute gravitational acceleration's component on X Y Z axes based on gyroscope 2267 | // g = ~ 9.80665 2268 | let grav = TRFM(MULT( 2269 | ROTY($.rotationY), 2270 | ROTX($.rotationX) 2271 | ),[0,0,-9.80665]); 2272 | $.accelerationX = (event.accelerationIncludingGravity.x+grav[0]); 2273 | $.accelerationY = (event.accelerationIncludingGravity.y+grav[1]); 2274 | $.accelerationZ = (event.accelerationIncludingGravity.z-grav[2]); 2275 | } 2276 | } 2277 | 2278 | //================================================================ 2279 | // TIME 2280 | //================================================================ 2281 | 2282 | $.year = function(){ 2283 | return new Date().getFullYear(); 2284 | } 2285 | $.day = function(){ 2286 | return new Date().getDay(); 2287 | } 2288 | $.hour = function(){ 2289 | return new Date().getHours(); 2290 | } 2291 | $.minute = function(){ 2292 | return new Date().getMinutes(); 2293 | } 2294 | $.second = function(){ 2295 | return new Date().getSeconds(); 2296 | } 2297 | $.millis = function(){ 2298 | return window.performance.now() - millisStart; 2299 | } 2300 | 2301 | } 2302 | 2303 | } 2304 | -------------------------------------------------------------------------------- /q5.min.js: -------------------------------------------------------------------------------- 1 | if(typeof exports==="object"&&typeof module!=="undefined")module.exports=Q5;function Q5(e){"use strict";return new function e(t){let n="global"==t?window:this;n.canvas=document.createElement("canvas");let o=n.canvas.getContext("2d");n.width=100;n.height=100;n.canvas.width=n.width;n.canvas.height=n.height;"offscreen"!=t&&(document.body?document.body.appendChild(n.canvas):window.addEventListener("load",function(){document.body.appendChild(n.canvas)}));y();n.MAGIC=161533525;n.RGB=0;n.HSV=1;n.HSB=1;n.CHORD=0;n.PIE=1;n.OPEN=2;n.RADIUS=1;n.CORNER=2;n.CORNERS=3;n.ROUND="round";n.SQUARE="butt";n.PROJECT="square";n.MITER="miter";n.BEVEL="bevel";n.CLOSE=1;n.BLEND="source-over";n.REMOVE="destination-out";n.ADD="lighter";n.DARKEST="darken";n.LIGHTEST="lighten";n.DIFFERENCE="difference";n.SUBTRACT="subtract";n.EXCLUSION="exclusion";n.MULTIPLY="multiply";n.SCREEN="screen";n.REPLACE="copy";n.OVERLAY="overlay";n.HARD_LIGHT="hard-light";n.SOFT_LIGHT="soft-light";n.DODGE="color-dodge";n.BURN="color-burn";n.NORMAL="normal";n.ITALIC="italic";n.BOLD="bold";n.BOLDITALIC="italic bold";n.CENTER="center";n.LEFT="left";n.RIGHT="right";n.TOP="top";n.BOTTOM="bottom";n.BASELINE="alphabetic";n.LANDSCAPE="landscape";n.PORTRAIT="portrait";n.ALT=18;n.BACKSPACE=8;n.CONTROL=17;n.DELETE=46;n.DOWN_ARROW=40;n.ENTER=13;n.ESCAPE=27;n.LEFT_ARROW=37;n.OPTION=18;n.RETURN=13;n.RIGHT_ARROW=39;n.SHIFT=16;n.TAB=9;n.UP_ARROW=38;n.HALF_PI=Math.PI/2;n.PI=Math.PI;n.QUARTER_PI=Math.PI/4;n.TAU=2*Math.PI;n.TWO_PI=2*Math.PI;n.THRESHOLD=1;n.GRAY=2;n.OPAQUE=3;n.INVERT=4;n.POSTERIZE=5;n.DILATE=6;n.ERODE=7;n.BLUR=8;n.ARROW="default";n.CROSS="crosshair";n.HAND="pointer";n.MOVE="move";n.TEXT="text";n.VIDEO={video:!0,audio:!1};n.AUDIO={video:!1,audio:!0};n.SHR3=1;n.LCG=2;n.HARDWARE_FILTERS=!0;n.hint=function(e,t){n[e]=t};n.frameCount=0;n.mouseX=0;n.mouseY=0;n.pmouseX=0;n.pmouseY=0;n.mouseButton=null;n.keyIsPressed=!1;n.mouseIsPressed=!1;n.key=null;n.keyCode=null;n.pixels=null;n.accelerationX=0;n.accelerationY=0;n.accelerationZ=0;n.rotationX=0;n.rotationY=0;n.rotationZ=0;n.relRotationX=0;n.relRotationY=0;n.relRotationZ=0;n.pAccelerationX=0;n.pAccelerationY=0;n.pAccelerationZ=0;n.pRotationX=0;n.pRotationY=0;n.pRotationZ=0;n.pRelRotationX=0;n.pRelRotationY=0;n.pRelRotationZ=0;n.touches=[];n._styleCache=[{colorMode:n.RGB,noStroke:!1,noFill:!1,ellipseMode:n.CENTER,rectMode:n.CORNER,curveDetail:20,curveAlpha:0,textFont:"sans-serif",textSize:12,textLeading:12,textStyle:"normal"}];n._style=n._styleCache[n._styleCache.length-1];n._noLoop=!1;n._pixelDensity=1;n._frameRate=null;n._tint=null;let a=null;let r=!0;let i=[];let l=null;let s=0;let u={};let c=0;let h=null;let f=null;let d=null;Object.defineProperty(n,"deviceOrientation",{get:function(){return 90==Math.abs(window.orientation)?n.LANDSCAPE:n.PORTRAIT}});Object.defineProperty(n,"windowWidth",{get:function(){return window.innerWidth}});Object.defineProperty(n,"windowHeight",{get:function(){return window.innerHeight}});Object.defineProperty(n,"drawingContext",{get:function(){return o}});n.createCanvas=function(e,t){return n.width=e,n.height=t,n.canvas.width=e,n.canvas.height=t,y(),n.canvas};n.resizeCanvas=function(e,t){n.width=e,n.height=t,n.canvas.width=e,n.canvas.height=t};n.createGraphics=n.createImage=function(t,n){let o=new e("offscreen");return o.createCanvas(t,n),o.noLoop(),o};n.pixelDensity=function(e){return null==e?n._pixelDensity:(n._pixelDensity=e,n.canvas.width=Math.ceil(n.width*e),n.canvas.height=Math.ceil(n.height*e),n.canvas.style.width=n.width+"px",n.canvas.style.height=n.height+"px",o.scale(n._pixelDensity,n._pixelDensity),y(),n._pixelDensity)};n.map=function(e,t,n,o,a,r){let i=o+1*(e-t)/(n-t)*(a-o);return r?oe){let n=e/t;a.x*=n,a.y*=n,a.z*=n,r=e,i=e*e}return a},a.setMag=function(e){s();let t=r,n=e/t;return a.x*=n,a.y*=n,a.z*=n,r=e,i=e*e,a},a.heading=function(){return Math.atan2(a.y,a.x)},a.rotate=function(e){let t=Math.cos(e),n=Math.sin(e),o=a.x*t-a.y*n,r=a.x*n+a.y*t;return a.x=o,a.y=r,a},a.angleBetween=function(){let e=l.apply(null,arguments);const t=a.dot(e)/(a.mag()*e.mag());let n;return n=Math.acos(Math.min(1,Math.max(-1,t))),n*=Math.sign(a.cross(e).z||1)},a.lerp=function(e,t){return a.x=a.x*(1-t)+e.x*t,a.y=a.y*(1-t)+e.y*t,a.z=a.z*(1-t)+e.z*t,u(),a},a.reflect=function(e){return e.normalize(),a.sub(e.mult(2*a.dot(e)))},a.array=function(){return[a.x,a.y,a.z]},a.equals=function(e,t){return null==t&&null==(t=Number.EPSILON)&&(t=0),Math.abs(e.x-a.x)360&&(i=0),u=n*(1-t),c=n*(1-t*(s=(i/=60)-(l=~~i))),h=n*(1-t*(1-s)),l){case 0:o=n,a=h,r=u;break;case 1:o=c,a=n,r=u;break;case 2:o=u,a=n,r=h;break;case 3:o=u,a=c,r=n;break;case 4:o=h,a=u,r=n;break;default:o=n,a=u,r=c}return[255*o,255*a,255*r]}n.Color=function(e,t,n,o){let a=this;a.MAGIC=786698,a._r=e,a._g=t,a._b=n,a._a=o,a._h=0,a._s=0,a._v=0,a._hsvInferred=!1,a.setRed=function(e){a._r=e,a._hsvInferred=!1},a.setGreen=function(e){a._g=e,a._hsvInferred=!1},a.setBlue=function(e){a._b=e,a._hsvInferred=!1},a.setAlpha=function(e){a._a=e/255,a._hsvInferred=!1},a._inferHSV=function(){a._hsvInferred||([a._h,a._s,a._v]=function(e,t,n){let o,a,r,i,l;if(o=et?e>n?e:n:t>n?t:n)/255))return[r=0,i=0,l];if(0==(i=100*(a-o)/a))return[r=0,i,l];r=a==e?0+60*(t-n)/(a-o):a==t?120+60*(n-e)/(a-o):240+60*(e-t)/(a-o);return[r,i,l]}(a._r,a._g,a._b),a._hsvInferred=!0)},a.toString=function(){return`rgba(${Math.round(a._r)},${Math.round(a._g)},${Math.round(a._b)},${~~(1e3*a._a)/1e3})`}};n.colorMode=function(e){n._style.colorMode=e};n.color=function(){if(1==arguments.length&&786698==arguments[0].MAGIC)return arguments[0];if(n._style.colorMode==n.RGB){if(1==arguments.length)return new n.Color(arguments[0],arguments[0],arguments[0],1);if(2==arguments.length)return new n.Color(arguments[0],arguments[0],arguments[0],arguments[1]/255);if(3==arguments.length)return new n.Color(arguments[0],arguments[1],arguments[2],1);if(4==arguments.length)return new n.Color(arguments[0],arguments[1],arguments[2],arguments[3]/255)}else{if(1==arguments.length)return new n.Color(...p(0,0,arguments[0]/100),1);if(2==arguments.length)return new n.Color(...p(0,0,arguments[0]/100),arguments[1]/255);if(3==arguments.length)return new n.Color(...p(arguments[0],arguments[1]/100,arguments[2]/100),1);if(4==arguments.length)return new n.Color(...p(arguments[0],arguments[1]/100,arguments[2]/100),arguments[3])}return null};n.red=function(e){return e._r};n.green=function(e){return e._g};n.blue=function(e){return e._b};n.alpha=function(e){return 255*e._a};n.hue=function(e){return e._inferHSV(),e._h};n.saturation=function(e){return e._inferHSV(),e._s};n.brightness=function(e){return e._inferHSV(),e._v};n.lightness=function(e){return 100*(.2126*e._r+.7152*e._g+.0722*e._b)/255};n.lerpColor=function(e,t,o){return n._style.colorMode==n.RGB?new n.Color(n.constrain(n.lerp(e._r,t._r,o),0,255),n.constrain(n.lerp(e._g,t._g,o),0,255),n.constrain(n.lerp(e._b,t._b,o),0,255),n.constrain(n.lerp(e._a,t._a,o),0,1)):(e._inferHSV(),t._inferHSV(),new n.Color(n.constrain(function(e,t,o){var a=[[Math.abs(t-e),n.map(o,0,1,e,t)],[Math.abs(t+360-e),n.map(o,0,1,e,t+360)],[Math.abs(t-360-e),n.map(o,0,1,e,t-360)]];return a.sort((e,t)=>e[0]-t[0]),(a[0][1]+720)%360}(e._h,t._h,o),0,360),n.constrain(n.lerp(e._s,t._s,o),0,100),n.constrain(n.lerp(e._v,t._v,o),0,100),n.constrain(n.lerp(e._a,t._a,o),0,1)))};function y(){o.fillStyle="white",o.strokeStyle="black",o.lineCap="round",o.lineJoin="miter"}n.strokeWeight=function(e){n._style_noStroke=!1,o.lineWidth=e};n.stroke=function(){if(n._style.noStroke=!1,"string"==typeof arguments[0])return void(o.strokeStyle=arguments[0]);let e=n.color.apply(null,arguments);e._a<=0?n._style.noStroke=!0:o.strokeStyle=e};n.noStroke=function(){n._style.noStroke=!0};n.fill=function(){if(n._style.noFill=!1,"string"==typeof arguments[0])return void(o.fillStyle=arguments[0]);let e=n.color.apply(null,arguments);e._a<=0?n._style.noFill=!0:o.fillStyle=e};n.noFill=function(){n._style.noFill=!0};n.blendMode=function(e){o.globalCompositeOperation=e};n.strokeCap=function(e){o.lineCap=e};n.strokeJoin=function(e){o.lineJoin=e};n.ellipseMode=function(e){n._style.ellipseMode=e};n.rectMode=function(e){n._style.rectMode=e};n.curveDetail=function(e){n._style.curveDetail=e};n.curveAlpha=function(e){n._style.curveAlpha=e};n.curveTightness=function(e){console.warn("curveTightness() sets the 'alpha' parameter of Catmull-Rom curve, and is NOT identical to p5.js counterpart. As this might change in the future, please call curveAlpha() directly."),n._style.curveAlpha=e};n.clear=function(){o.clearRect(0,0,n.width,n.height)};n.background=function(){if(arguments[0]&&arguments[0].MAGIC==n.MAGIC)return n.image(arguments[0],0,0,n.width,n.height);o.save(),o.resetTransform(),o.scale(n._pixelDensity,n._pixelDensity),"string"==typeof arguments[0]?o.fillStyle=arguments[0]:o.fillStyle=n.color(...Array.from(arguments)),o.fillRect(0,0,n.width,n.height),o.restore()};n.line=function(e,t,a,r){n._style.noStroke||(o.beginPath(),o.moveTo(e,t),o.lineTo(a,r),o.stroke())};function m(e){if(0<=e&&e<2*Math.PI)return e;for(;e<0;)e+=2*Math.PI;for(;e>=Math.PI;)e-=2*Math.PI;return e}function g(e,t,a,r,i,l,s,u){if(n._style.noFill&&n._style.noStroke)return;let c=m(i),h=m(l);o.beginPath();for(let i=0;i0?(y[e]=1,y[e+1]=0):(y[e]=0,y[e+1]=1));let m=e*y[0]+n*y[1],g=t*y[0]+o*y[1],v=n*y[2]+a*y[3],_=o*y[2]+r*y[3],M=a*y[4]+i*y[5],x=r*y[4]+l*y[5],w=m*y[6]+v*y[7],R=g*y[6]+_*y[7],I=v*y[8]+M*y[9],C=_*y[8]+x*y[9],E=w*y[2]+I*y[3],S=R*y[2]+C*y[3];h.push([E,S])}return h}(...a,...l,...s,...u,n._style.curveDetail,n._style.curveAlpha);for(let e=0;e=t?255:0}};x[n.GRAY]=function(e){for(let t=0;t>8)/n,e[o+1]=255*(e[o+1]*t>>8)/n,e[o+2]=255*(e[o+2]*t>>8)/n};x[n.DILATE]=function(e){R(),d.set(e);let[t,n]=[o.canvas.width,o.canvas.height];for(let o=0;o=1&&(u++,f--),(d*=2)>=1&&(c++,d--),(p*=2)>=1&&(h++,p--)}return y};n.noiseDetail=function(e,t){e>0&&(C=e),t>0&&(E=t)};const D=function(){let e,t,n=4294967295;return{setSeed(o){e=t=(null==o?Math.random()*n:o)>>>0},getSeed:()=>t,rand:()=>(e^=e<<17,e^=e>>13,((e^=e<<5)>>>0)/n)}};let T=D();T.setSeed();n.noiseSeed=function(e){let t=null==e?4294967295*Math.random():e;A||(A=new Float32Array(4096));for(var n=0;n<4096;n++)t^=t<<17,t^=t>>13,t^=t<<5,A[n]=(t>>>0)/4294967295};n.randomSeed=function(e){T.setSeed(e)};n.random=function(e,t){return null==e?T.rand():"number"==typeof e?null!=t?T.rand()*(t-e)+e:T.rand()*e:e[~~(e.length*T.rand())]};n.randomGenerator=function(e){e==n.LCG?T=function(){const e=4294967296;let t,n;return{setSeed(o){n=t=(null==o?Math.random()*e:o)>>>0},getSeed:()=>t,rand:()=>(n=(1664525*n+1013904223)%e)/e}}():e==n.SHR3&&(T=D()),T.setSeed()};var P=new function(){var e,t,n,o=new Array(128),a=new Array(256),r=new Array(128),i=new Array(128),l=new Array(256),s=new Array(256),u=function(){return 4294967296*T.rand()-2147483648},c=function(){return.5+2.328306e-10*(u()<<0)},h=function(){for(var t,a,l,s,h=3.44262;;){if(t=n*r[e],0==e){do{l=c(),s=c(),t=.2904764*-Math.log(l),a=-Math.log(s)}while(a+a0?h+t:-h-t}if(i[e]+c()*(i[e-1]-i[e])>>0)=1;t--)c=Math.sqrt(-2*Math.log(f/c+Math.exp(-.5*c*c))),o[t+1]=Math.floor(c/h*n),h=c,i[t]=Math.exp(-.5*c*c),r[t]=c/n;for(e=y/Math.exp(-d),a[0]=Math.floor(d/e*u),a[1]=0,l[0]=e/u,l[255]=d/u,s[0]=1,s[255]=Math.exp(-d),t=254;t>=1;t--)d=-Math.log(y/d+Math.exp(-d)),a[t+1]=Math.floor(d/p*u),p=d,s[t]=Math.exp(-d),l[t]=d/u}};P.hasInit=!1;n.randomGaussian=function(e,t){return P.hasInit||(P.zigset(),P.hasInit=!0),P.RNOR()*t+e};n.randomExponential=function(){return P.hasInit||(P.zigset(),P.hasInit=!0),P.REXP()};n.print=console.log;n.cursor=function(e,t,o){let a="";e.includes(".")&&(e=`url("${e}")`,a=", auto"),null!=t&&(e+=" "+t+" "+o),n.canvas.style.cursor=e+a};n.noCursor=function(){n.canvas.style.cursor="none"};n.createCapture=function(e){var t=document.createElement("video");return t.playsinline="playsinline",t.autoplay="autoplay",navigator.mediaDevices.getUserMedia(e).then(function(e){t.srcObject=e}),t.style.position="absolute",t.style.opacity=1e-5,t.style.zIndex=-1e3,document.body.appendChild(t),t};let b=["setup","draw","preload","mouseMoved","mousePressed","mouseReleased","mouseDragged","mouseClicked","keyPressed","keyReleased","keyTyped","touchStarted","touchEnded"];for(let e of b){let t="_"+e+"Fn";n[t]=function(){},n[t].isPlaceHolder=!0,n[e]?n[t]=n[e]:Object.defineProperty(n,e,{set:function(e){n[t]=e}})}function z(){n._noLoop||(a=null==n._frameRate?requestAnimationFrame(z):setTimeout(z,1e3/n._frameRate)),M(),r=!0,n.push(),n._drawFn(),n.pop(),++n.frameCount}n.noLoop=function(){n._noLoop=!0,a=null};n.loop=function(){n._noLoop=!1,null==a&&z()};n.redraw=function(){z()};n.frameRate=function(e){n._frameRate=e};setTimeout(function(){n._preloadFn(),c=window.performance.now(),function e(){if(s>0)return setTimeout(e,10);n._setupFn();z()}()},1);n.canvas.onmousemove=function(e){n.pmouseX=n.mouseX,n.pmouseY=n.mouseY,n.mouseX=e.offsetX,n.mouseY=e.offsetY,n.mouseIsPressed?n._mouseDraggedFn(e):n._mouseMovedFn(e)};n.canvas.onmousedown=function(e){n.pmouseX=n.mouseX,n.pmouseY=n.mouseY,n.mouseX=e.offsetX,n.mouseY=e.offsetY,n.mouseIsPressed=!0,n.mouseButton=[n.LEFT,n.CENTER,n.RIGHT][e.button],n._mousePressedFn(e)};n.canvas.onmouseup=function(e){n.pmouseX=n.mouseX,n.pmouseY=n.mouseY,n.mouseX=e.offsetX,n.mouseY=e.offsetY,n.mouseIsPressed=!1,n._mouseReleasedFn(e)};n.canvas.onclick=function(e){n.pmouseX=n.mouseX,n.pmouseY=n.mouseY,n.mouseX=e.offsetX,n.mouseY=e.offsetY,n.mouseIsPressed=!0,n._mouseClickedFn(e),n.mouseIsPressed=!1};window.addEventListener("keydown",function(e){n.keyIsPressed=!0,n.key=e.key,n.keyCode=e.keyCode,u[n.keyCode]=!0,n._keyPressedFn(e),1==e.key.length&&n._keyTypedFn(e)});window.addEventListener("keyup",function(e){n.keyIsPressed=!1,n.key=e.key,n.keyCode=e.keyCode,u[n.keyCode]=!1,n._keyReleasedFn(e)});n.keyIsDown=function(e){return!!u[e]};function O(e){const t=n.canvas.getBoundingClientRect(),o=n.canvas.scrollWidth/n.width||1,a=n.canvas.scrollHeight/n.height||1;return{x:(e.clientX-t.left)/o,y:(e.clientY-t.top)/a,id:e.identifier}}function k(){return n._touchStarted.isPlaceHolder&&n._touchMoved.isPlaceHolder&&n._touchEnded.isPlaceHolder}n.canvas.ontouchstart=function(e){n.touches=e.touches.map(O),k()&&(n.pmouseX=n.mouseX,n.pmouseY=n.mouseY,n.mouseX=n.touches[0].x,n.mouseY=n.touches[0].y,n.mouseIsPressed=!0,n.mouseButton=n.LEFT,n._mousePressedFn(e)||e.preventDefault()),n._touchStartedFn(e)||e.preventDefault()};n.canvas.ontouchmove=function(e){n.touches=e.touches.map(O),k()&&(n.pmouseX=n.mouseX,n.pmouseY=n.mouseY,n.mouseX=n.touches[0].x,n.mouseY=n.touches[0].y,n.mouseIsPressed=!0,n.mouseButton=n.LEFT,n._mouseDraggedFn(e)||e.preventDefault()),n._touchMovedFn(e)||e.preventDefault()};n.canvas.ontouchend=n.canvas.ontouchcancel=function(e){n.touches=e.touches.map(O),k()&&(n.pmouseX=n.mouseX,n.pmouseY=n.mouseY,n.mouseX=n.touches[0].x,n.mouseY=n.touches[0].y,n.mouseIsPressed=!1,n._mouseReleasedFn(e)||e.preventDefault()),n._touchEndedFn(e)||e.preventDefault()};n.hasSensorPermission=!window.DeviceOrientationEvent&&!window.DeviceMotionEvent||!(DeviceOrientationEvent.requestPermission||DeviceMotionEvent.requestPermission);n.requestSensorPermissions=function(){DeviceOrientationEvent.requestPermission&&DeviceOrientationEvent.requestPermission().then(e=>{"granted"==e&&DeviceMotionEvent.requestPermission&&DeviceMotionEvent.requestPermission().then(e=>{"granted"==e&&(n.hasSensorPermission=!0)}).catch(alert)}).catch(alert)};window.ondeviceorientation=function(e){n.pRotationX=n.rotationX,n.pRotationY=n.rotationY,n.pRotationZ=n.rotationZ,n.pRelRotationX=n.relRotationX,n.pRelRotationY=n.relRotationY,n.pRelRotationZ=n.relRotationZ,n.rotationX=e.beta*(Math.PI/180),n.rotationY=e.gamma*(Math.PI/180),n.rotationZ=e.alpha*(Math.PI/180),n.relRotationX=[-n.rotationY,-n.rotationX,n.rotationY][1+~~(window.orientation/90)],n.relRotationY=[-n.rotationX,n.rotationY,n.rotationX][1+~~(window.orientation/90)],n.relRotationZ=n.rotationZ};window.ondevicemotion=function(e){if(n.pAccelerationX=n.accelerationX,n.pAccelerationY=n.accelerationY,n.pAccelerationZ=n.accelerationZ,!e.acceleration){let t=((e,t)=>[(e[0]*t[0]+e[1]*t[1]+e[2]*t[2]+e[3])/(e[12]*t[0]+e[13]*t[1]+e[14]*t[2]+e[15]),(e[4]*t[0]+e[5]*t[1]+e[6]*t[2]+e[7])/(e[12]*t[0]+e[13]*t[1]+e[14]*t[2]+e[15]),(e[8]*t[0]+e[9]*t[1]+e[10]*t[2]+e[11])/(e[12]*t[0]+e[13]*t[1]+e[14]*t[2]+e[15])])(((e,t)=>[e[0]*t[0]+e[1]*t[4]+e[2]*t[8]+e[3]*t[12],e[0]*t[1]+e[1]*t[5]+e[2]*t[9]+e[3]*t[13],e[0]*t[2]+e[1]*t[6]+e[2]*t[10]+e[3]*t[14],e[0]*t[3]+e[1]*t[7]+e[2]*t[11]+e[3]*t[15],e[4]*t[0]+e[5]*t[4]+e[6]*t[8]+e[7]*t[12],e[4]*t[1]+e[5]*t[5]+e[6]*t[9]+e[7]*t[13],e[4]*t[2]+e[5]*t[6]+e[6]*t[10]+e[7]*t[14],e[4]*t[3]+e[5]*t[7]+e[6]*t[11]+e[7]*t[15],e[8]*t[0]+e[9]*t[4]+e[10]*t[8]+e[11]*t[12],e[8]*t[1]+e[9]*t[5]+e[10]*t[9]+e[11]*t[13],e[8]*t[2]+e[9]*t[6]+e[10]*t[10]+e[11]*t[14],e[8]*t[3]+e[9]*t[7]+e[10]*t[11]+e[11]*t[15],e[12]*t[0]+e[13]*t[4]+e[14]*t[8]+e[15]*t[12],e[12]*t[1]+e[13]*t[5]+e[14]*t[9]+e[15]*t[13],e[12]*t[2]+e[13]*t[6]+e[14]*t[10]+e[15]*t[14],e[12]*t[3]+e[13]*t[7]+e[14]*t[11]+e[15]*t[15]])((e=>[Math.cos(e),0,Math.sin(e),0,0,1,0,0,-Math.sin(e),0,Math.cos(e),0,0,0,0,1])(n.rotationY),(e=>[1,0,0,0,0,Math.cos(e),-Math.sin(e),0,0,Math.sin(e),Math.cos(e),0,0,0,0,1])(n.rotationX)),[0,0,-9.80665]);n.accelerationX=e.accelerationIncludingGravity.x+t[0],n.accelerationY=e.accelerationIncludingGravity.y+t[1],n.accelerationZ=e.accelerationIncludingGravity.z-t[2]}};n.year=function(){return(new Date).getFullYear()};n.day=function(){return(new Date).getDay()};n.hour=function(){return(new Date).getHours()};n.minute=function(){return(new Date).getMinutes()};n.second=function(){return(new Date).getSeconds()};n.millis=function(){return window.performance.now()-c}}(e)} 2 | -------------------------------------------------------------------------------- /q5.p5acl.js: -------------------------------------------------------------------------------- 1 | // p5 addon compatibility layer (p5acl) 2 | window.addons = {Element:function(a){this.elt=a},_elements:[],Color:Function} 3 | window.p5 = window.addons; 4 | window.p5.prototype=window.addons; 5 | window.p5.prototype.registerMethod=function(){} 6 | window.p5.prototype.registerPreloadMethod=function(){} 7 | window.p5._validateParameters=function(){return true} -------------------------------------------------------------------------------- /tests.js: -------------------------------------------------------------------------------- 1 | /*~~~ https://p5js.org/reference/#/p5/alpha ~~~*/ 2 | 3 | noStroke(); 4 | let c = color(0, 126, 255, 102); 5 | fill(c); 6 | rect(15, 15, 35, 70); 7 | let value = alpha(c); // Sets 'value' to 102 8 | fill(value); 9 | rect(50, 15, 35, 70); 10 | 11 | /*~~~ https://p5js.org/reference/#/p5/blue ~~~*/ 12 | 13 | let c = color(175, 100, 220); 14 | fill(c); 15 | rect(15, 20, 35, 60); // Draw left rectangle 16 | let blueValue = blue(c); 17 | fill(0, 0, blueValue); 18 | rect(50, 20, 35, 60); // Draw right rectangle 19 | 20 | /*~~~ https://p5js.org/reference/#/p5/brightness ~~~*/ 21 | 22 | noStroke(); 23 | colorMode(HSB); 24 | let c = color(0, 50, 100); 25 | fill(c); 26 | rect(15, 20, 35, 60); 27 | let value = brightness(c); 28 | fill(value); 29 | rect(50, 20, 35, 60); 30 | 31 | 32 | /*~~~ https://p5js.org/reference/#/p5/color ~~~*/ 33 | 34 | let c = color(255, 204, 0); 35 | fill(c); 36 | noStroke(); 37 | rect(30, 20, 55, 55); 38 | 39 | /*~~~ https://p5js.org/reference/#/p5/color ~~~*/ 40 | 41 | let c = color(255, 204, 0); 42 | fill(c); 43 | noStroke(); 44 | ellipse(25, 25, 80, 80); // Draw left circle 45 | // Using only one value generates a grayscale value. 46 | c = color(65); 47 | fill(c); 48 | ellipse(75, 75, 80, 80); 49 | 50 | /*~~~ https://p5js.org/reference/#/p5/color ~~~*/ 51 | 52 | noStroke(); 53 | let c = color(50, 55, 100); 54 | fill(c); 55 | rect(0, 10, 45, 80); // Draw left rect 56 | colorMode(HSB); 57 | c = color(50*3.6, 55, 100); 58 | fill(c); 59 | rect(55, 10, 45, 80); 60 | 61 | /*~~~ https://p5js.org/reference/#/p5/green ~~~*/ 62 | 63 | let c = color(20, 75, 200); // Define color 'c' 64 | fill(c); // Use color variable 'c' as fill color 65 | rect(15, 20, 35, 60); // Draw left rectangle 66 | 67 | let greenValue = green(c); // Get green in 'c' 68 | print(greenValue); // Print "75.0" 69 | fill(0, greenValue, 0); // Use 'greenValue' in new fill 70 | rect(50, 20, 35, 60); // Draw right rectangle 71 | 72 | 73 | /*~~~ https://p5js.org/reference/#/p5/hue ~~~*/ 74 | 75 | noStroke(); 76 | colorMode(HSB); 77 | let c = color(0, 50, 100); 78 | fill(c); 79 | rect(15, 20, 35, 60); 80 | let value = hue(c); // Sets 'value' to "0" 81 | fill(value); 82 | rect(50, 20, 35, 60); 83 | 84 | /*~~~ https://p5js.org/reference/#/p5/lerpColor ~~~*/ 85 | 86 | colorMode(RGB); 87 | stroke(255); 88 | background(51); 89 | let from = color(218, 165, 32); 90 | let to = color(72, 61, 139); 91 | colorMode(RGB); // Try changing to HSB. 92 | let interA = lerpColor(from, to, 0.33); 93 | let interB = lerpColor(from, to, 0.66); 94 | fill(from); 95 | rect(10, 20, 20, 60); 96 | fill(interA); 97 | rect(30, 20, 20, 60); 98 | fill(interB); 99 | rect(50, 20, 20, 60); 100 | fill(to); 101 | rect(70, 20, 20, 60); 102 | 103 | 104 | /*~~~ https://p5js.org/reference/#/p5/red ~~~*/ 105 | 106 | let c = color(255, 204, 0); // Define color 'c' 107 | fill(c); // Use color variable 'c' as fill color 108 | rect(15, 20, 35, 60); // Draw left rectangle 109 | 110 | let redValue = red(c); // Get red in 'c' 111 | print(redValue); // Print "255.0" 112 | fill(redValue, 0, 0); // Use 'redValue' in new fill 113 | rect(50, 20, 35, 60); // Draw right rectangle 114 | 115 | /*~~~ https://p5js.org/reference/#/p5/saturation ~~~*/ 116 | 117 | noStroke(); 118 | colorMode(HSB); 119 | let c = color(0, 50, 100); 120 | fill(c); 121 | rect(15, 20, 35, 60); 122 | let value = saturation(c); // Sets 'value' to 50 123 | fill(value); 124 | rect(50, 20, 35, 60); 125 | 126 | /*~~~ https://p5js.org/reference/#/p5.Color/setRed ~~~*/ 127 | 128 | let backgroundColor; 129 | 130 | function setup() { 131 | backgroundColor = color(100, 50, 150); 132 | } 133 | 134 | function draw() { 135 | backgroundColor.setRed(128 + 128 * sin(millis() / 1000)); 136 | background(backgroundColor); 137 | } 138 | 139 | /*~~~ https://p5js.org/reference/#/p5.Color/setGreen ~~~*/ 140 | 141 | let backgroundColor = color(100, 50, 150); 142 | function draw() { 143 | backgroundColor.setGreen(128 + 128 * sin(millis() / 1000)); 144 | background(backgroundColor); 145 | } 146 | 147 | /*~~~ https://p5js.org/reference/#/p5.Color/setBlue ~~~*/ 148 | 149 | let backgroundColor = color(100, 50, 150); 150 | function draw() { 151 | backgroundColor.setBlue(128 + 128 * sin(millis() / 1000)); 152 | background(backgroundColor); 153 | } 154 | 155 | /*~~~ https://p5js.org/reference/#/p5.Color/setAlpha ~~~*/ 156 | 157 | function draw() { 158 | clear(); 159 | background(200); 160 | squareColor = color(100, 50, 100); 161 | squareColor.setAlpha(128 + 128 * sin(millis() / 1000)); 162 | fill(squareColor); 163 | rect(13, 13, width - 26, height - 26); 164 | } 165 | 166 | /*~~~ https://p5js.org/reference/#/p5/background ~~~*/ 167 | 168 | background(51); 169 | 170 | /*~~~ https://p5js.org/reference/#/p5/clear ~~~*/ 171 | 172 | // Clear the screen on mouse press. 173 | function draw() { 174 | ellipse(mouseX, mouseY, 20, 20); 175 | } 176 | function mousePressed() { 177 | clear(); 178 | background(128); 179 | } 180 | 181 | /*~~~ https://p5js.org/reference/#/p5/colorMode ~~~*/ 182 | 183 | noStroke(); 184 | colorMode(RGB); 185 | for (let i = 0; i < 100; i++) { 186 | for (let j = 0; j < 100; j++) { 187 | stroke(i*2.5, j*2.5, 0); 188 | point(i, j); 189 | } 190 | } 191 | 192 | /*~~~ https://p5js.org/reference/#/p5/colorMode ~~~*/ 193 | 194 | noStroke(); 195 | colorMode(HSB); 196 | for (let i = 0; i < 100; i++) { 197 | for (let j = 0; j < 100; j++) { 198 | stroke(i*3.6, j, 100); 199 | point(i, j); 200 | } 201 | } 202 | 203 | /*~~~ https://p5js.org/reference/#/p5/fill ~~~*/ 204 | 205 | // R, G & B integer values 206 | fill(255, 204, 0); 207 | rect(20, 20, 60, 60); 208 | 209 | 210 | /*~~~ https://p5js.org/reference/#/p5/noFill ~~~*/ 211 | 212 | rect(15, 10, 55, 55); 213 | noFill(); 214 | rect(20, 20, 60, 60); 215 | 216 | /*~~~ https://p5js.org/reference/#/p5/noStroke ~~~*/ 217 | 218 | noStroke(); 219 | rect(20, 20, 60, 60); 220 | 221 | /*~~~ https://p5js.org/reference/#/p5/stroke ~~~*/ 222 | 223 | // Grayscale integer value 224 | strokeWeight(4); 225 | stroke(51); 226 | rect(20, 20, 60, 60); 227 | 228 | /*~~~ https://p5js.org/reference/#/p5/stroke ~~~*/ 229 | 230 | // R, G & B integer values 231 | stroke(255, 204, 0); 232 | strokeWeight(4); 233 | rect(20, 20, 60, 60); 234 | 235 | /*~~~ https://p5js.org/reference/#/p5/arc ~~~*/ 236 | 237 | arc(50, 50, 80, 80, 0, PI + QUARTER_PI, OPEN); 238 | 239 | /*~~~ https://p5js.org/reference/#/p5/arc ~~~*/ 240 | 241 | arc(50, 50, 80, 80, 0, PI + QUARTER_PI, CHORD); 242 | 243 | /*~~~ https://p5js.org/reference/#/p5/arc ~~~*/ 244 | 245 | arc(50, 50, 80, 80, 0, PI + QUARTER_PI, PIE); 246 | 247 | /*~~~ https://p5js.org/reference/#/p5/ellipse ~~~*/ 248 | 249 | ellipse(56, 46, 55, 55); 250 | 251 | /*~~~ https://p5js.org/reference/#/p5/circle ~~~*/ 252 | 253 | // Draw a circle at location (30, 30) with a diameter of 20. 254 | circle(30, 30, 20); 255 | 256 | /*~~~ https://p5js.org/reference/#/p5/line ~~~*/ 257 | 258 | 259 | line(30, 20, 85, 75); 260 | 261 | /*~~~ https://p5js.org/reference/#/p5/line ~~~*/ 262 | 263 | line(30, 20, 85, 20); 264 | stroke(126); 265 | line(85, 20, 85, 75); 266 | stroke(255); 267 | line(85, 75, 30, 75); 268 | 269 | /*~~~ https://p5js.org/reference/#/p5/point ~~~*/ 270 | 271 | 272 | point(30, 20); 273 | point(85, 20); 274 | point(85, 75); 275 | point(30, 75); 276 | 277 | /*~~~ https://p5js.org/reference/#/p5/point ~~~*/ 278 | 279 | point(30, 20); 280 | point(85, 20); 281 | stroke('purple'); // Change the color 282 | strokeWeight(10); // Make the points 10 pixels in size 283 | point(85, 75); 284 | point(30, 75); 285 | 286 | /*~~~ https://p5js.org/reference/#/p5/point ~~~*/ 287 | 288 | let a = createVector(10, 10); 289 | point(a); 290 | let b = createVector(10, 20); 291 | point(b); 292 | point(createVector(20, 10)); 293 | point(createVector(20, 20)); 294 | 295 | /*~~~ https://p5js.org/reference/#/p5/quad ~~~*/ 296 | 297 | quad(38, 31, 86, 20, 69, 63, 30, 76); 298 | 299 | /*~~~ https://p5js.org/reference/#/p5/rect ~~~*/ 300 | 301 | // Draw a rectangle at location (30, 20) with a width and height of 55. 302 | rect(30, 20, 55, 55); 303 | 304 | /*~~~ https://p5js.org/reference/#/p5/rect ~~~*/ 305 | 306 | // Draw a rectangle with rounded corners, each having a radius of 20. 307 | rect(30, 20, 55, 55, 20); 308 | 309 | /*~~~ https://p5js.org/reference/#/p5/rect ~~~*/ 310 | 311 | // Draw a rectangle with rounded corners having the following radii: 312 | // top-left = 20, top-right = 15, bottom-right = 10, bottom-left = 5. 313 | rect(30, 20, 55, 55, 20, 15, 10, 5); 314 | 315 | /*~~~ https://p5js.org/reference/#/p5/square ~~~*/ 316 | 317 | // Draw a square at location (30, 20) with a side size of 55. 318 | square(30, 20, 55); 319 | 320 | /*~~~ https://p5js.org/reference/#/p5/square ~~~*/ 321 | 322 | // Draw a square with rounded corners, each having a radius of 20. 323 | square(30, 20, 55, 20); 324 | 325 | /*~~~ https://p5js.org/reference/#/p5/square ~~~*/ 326 | 327 | // Draw a square with rounded corners having the following radii: 328 | // top-left = 20, top-right = 15, bottom-right = 10, bottom-left = 5. 329 | square(30, 20, 55, 20, 15, 10, 5); 330 | 331 | 332 | /*~~~ https://p5js.org/reference/#/p5/triangle ~~~*/ 333 | 334 | triangle(30, 75, 58, 20, 86, 75); 335 | 336 | /*~~~ https://p5js.org/reference/#/p5/ellipseMode ~~~*/ 337 | 338 | // Example showing RADIUS and CENTER ellipsemode with 2 overlaying ellipses 339 | ellipseMode(RADIUS); 340 | fill(255); 341 | ellipse(50, 50, 30, 30); // Outer white ellipse 342 | ellipseMode(CENTER); 343 | fill(100); 344 | ellipse(50, 50, 30, 30); // Inner gray ellipse 345 | 346 | /*~~~ https://p5js.org/reference/#/p5/ellipseMode ~~~*/ 347 | 348 | // Example showing CORNER and CORNERS ellipseMode with 2 overlaying ellipses 349 | ellipseMode(CORNER); 350 | fill(255); 351 | ellipse(25, 25, 50, 50); // Outer white ellipse 352 | ellipseMode(CORNERS); 353 | fill(100); 354 | ellipse(25, 25, 50, 50); // Inner gray ellipse 355 | 356 | /*~~~ https://p5js.org/reference/#/p5/rectMode ~~~*/ 357 | 358 | 359 | rectMode(CORNER); 360 | fill(255); 361 | rect(25, 25, 50, 50); // Draw white rectangle using CORNER mode 362 | 363 | rectMode(CORNERS); 364 | fill(100); 365 | rect(25, 25, 50, 50); // Draw gray rectanle using CORNERS mode 366 | 367 | /*~~~ https://p5js.org/reference/#/p5/rectMode ~~~*/ 368 | 369 | rectMode(RADIUS); 370 | fill(255); 371 | rect(50, 50, 30, 30); // Draw white rectangle using RADIUS mode 372 | 373 | rectMode(CENTER); 374 | fill(100); 375 | rect(50, 50, 30, 30); // Draw gray rectangle using CENTER mode 376 | 377 | 378 | /*~~~ https://p5js.org/reference/#/p5/strokeCap ~~~*/ 379 | 380 | // Example of different strokeCaps 381 | strokeWeight(12.0); 382 | strokeCap(ROUND); 383 | line(20, 30, 80, 30); 384 | strokeCap(SQUARE); 385 | line(20, 50, 80, 50); 386 | strokeCap(PROJECT); 387 | line(20, 70, 80, 70); 388 | 389 | /*~~~ https://p5js.org/reference/#/p5/strokeJoin ~~~*/ 390 | 391 | // Example of MITER type of joints 392 | noFill(); 393 | strokeWeight(10.0); 394 | strokeJoin(MITER); 395 | beginShape(); 396 | vertex(35, 20); 397 | vertex(65, 50); 398 | vertex(35, 80); 399 | endShape(); 400 | 401 | 402 | /*~~~ https://p5js.org/reference/#/p5/strokeJoin ~~~*/ 403 | 404 | // Example of BEVEL type of joints 405 | noFill(); 406 | strokeWeight(10.0); 407 | strokeJoin(BEVEL); 408 | beginShape(); 409 | vertex(35, 20); 410 | vertex(65, 50); 411 | vertex(35, 80); 412 | endShape(); 413 | 414 | /*~~~ https://p5js.org/reference/#/p5/strokeJoin ~~~*/ 415 | 416 | // Example of ROUND type of joints 417 | noFill(); 418 | strokeWeight(10.0); 419 | strokeJoin(ROUND); 420 | beginShape(); 421 | vertex(35, 20); 422 | vertex(65, 50); 423 | vertex(35, 80); 424 | endShape(); 425 | 426 | 427 | /*~~~ https://p5js.org/reference/#/p5/strokeWeight ~~~*/ 428 | 429 | // Example of different stroke weights 430 | strokeWeight(1); // Default 431 | line(20, 20, 80, 20); 432 | strokeWeight(4); // Thicker 433 | line(20, 40, 80, 40); 434 | strokeWeight(10); // Beastly 435 | line(20, 70, 80, 70); 436 | 437 | /*~~~ https://p5js.org/reference/#/p5/bezier ~~~*/ 438 | 439 | noFill(); 440 | stroke(255, 102, 0); 441 | line(85, 20, 10, 10); 442 | line(90, 90, 15, 80); 443 | stroke(0, 0, 0); 444 | bezier(85, 20, 10, 10, 90, 90, 15, 80); 445 | 446 | /*~~~ https://p5js.org/reference/#/p5/bezierPoint ~~~*/ 447 | 448 | noFill(); 449 | let x1 = 85, 450 | x2 = 10, 451 | x3 = 90, 452 | x4 = 15; 453 | let y1 = 20, 454 | y2 = 10, 455 | y3 = 90, 456 | y4 = 80; 457 | bezier(x1, y1, x2, y2, x3, y3, x4, y4); 458 | fill(255); 459 | let steps = 10; 460 | for (let i = 0; i <= steps; i++) { 461 | let t = i / steps; 462 | let x = bezierPoint(x1, x2, x3, x4, t); 463 | let y = bezierPoint(y1, y2, y3, y4, t); 464 | circle(x, y, 5); 465 | } 466 | 467 | 468 | /*~~~ https://p5js.org/reference/#/p5/bezierTangent ~~~*/ 469 | 470 | noFill(); 471 | bezier(85, 20, 10, 10, 90, 90, 15, 80); 472 | let steps = 6; 473 | fill(255); 474 | for (let i = 0; i <= steps; i++) { 475 | let t = i / steps; 476 | // Get the location of the point 477 | let x = bezierPoint(85, 10, 90, 15, t); 478 | let y = bezierPoint(20, 10, 90, 80, t); 479 | // Get the tangent points 480 | let tx = bezierTangent(85, 10, 90, 15, t); 481 | let ty = bezierTangent(20, 10, 90, 80, t); 482 | // Calculate an angle from the tangent points 483 | let a = atan2(ty, tx); 484 | a += PI; 485 | stroke(255, 102, 0); 486 | line(x, y, cos(a) * 30 + x, sin(a) * 30 + y); 487 | // The following line of code makes a line 488 | // inverse of the above line 489 | //line(x, y, cos(a)*-30 + x, sin(a)*-30 + y); 490 | stroke(0); 491 | ellipse(x, y, 5, 5); 492 | } 493 | 494 | 495 | /*~~~ https://p5js.org/reference/#/p5/bezierTangent ~~~*/ 496 | 497 | noFill(); 498 | bezier(85, 20, 10, 10, 90, 90, 15, 80); 499 | stroke(255, 102, 0); 500 | let steps = 16; 501 | for (let i = 0; i <= steps; i++) { 502 | let t = i / steps; 503 | let x = bezierPoint(85, 10, 90, 15, t); 504 | let y = bezierPoint(20, 10, 90, 80, t); 505 | let tx = bezierTangent(85, 10, 90, 15, t); 506 | let ty = bezierTangent(20, 10, 90, 80, t); 507 | let a = atan2(ty, tx); 508 | a -= HALF_PI; 509 | line(x, y, cos(a) * 8 + x, sin(a) * 8 + y); 510 | } 511 | 512 | /*~~~ https://p5js.org/reference/#/p5/curve ~~~*/ 513 | 514 | noFill(); 515 | stroke(255, 102, 0); 516 | curve(5, 26, 5, 26, 73, 24, 73, 61); 517 | stroke(0); 518 | curve(5, 26, 73, 24, 73, 61, 15, 65); 519 | stroke(255, 102, 0); 520 | curve(73, 24, 73, 61, 15, 65, 15, 65); 521 | 522 | 523 | /*~~~ https://p5js.org/reference/#/p5/curve ~~~*/ 524 | 525 | // Define the curve points as JavaScript objects 526 | let p1 = { x: 5, y: 26 }; 527 | let p2 = { x: 73, y: 24 }; 528 | let p3 = { x: 73, y: 61 }; 529 | let p4 = { x: 15, y: 65 }; 530 | noFill(); 531 | stroke(255, 102, 0); 532 | curve(p1.x, p1.y, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y); 533 | stroke(0); 534 | curve(p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y); 535 | stroke(255, 102, 0); 536 | curve(p2.x, p2.y, p3.x, p3.y, p4.x, p4.y, p4.x, p4.y); 537 | 538 | 539 | /*~~~ https://p5js.org/reference/#/p5/curve ~~~*/ 540 | 541 | noFill(); 542 | stroke(255, 102, 0); 543 | curve(5, 26, 0, 5, 26, 0, 73, 24, 0, 73, 61, 0); 544 | stroke(0); 545 | curve(5, 26, 0, 73, 24, 0, 73, 61, 0, 15, 65, 0); 546 | stroke(255, 102, 0); 547 | curve(73, 24, 0, 73, 61, 0, 15, 65, 0, 15, 65, 0); 548 | 549 | 550 | /*~~~ https://p5js.org/reference/#/p5/curveTightness ~~~*/ 551 | 552 | // Move the mouse left and right to see the curve change 553 | function setup() { 554 | createCanvas(100, 100); 555 | noFill(); 556 | } 557 | 558 | function draw() { 559 | background(204); 560 | let t = map(mouseX, 0, width, -5, 5); 561 | curveTightness(t); 562 | beginShape(); 563 | curveVertex(10, 26); 564 | curveVertex(10, 26); 565 | curveVertex(83, 24); 566 | curveVertex(83, 61); 567 | curveVertex(25, 65); 568 | curveVertex(25, 65); 569 | endShape(); 570 | } 571 | 572 | /*~~~ https://p5js.org/reference/#/p5/curvePoint ~~~*/ 573 | 574 | 575 | noFill(); 576 | curve(5, 26, 5, 26, 73, 24, 73, 61); 577 | curve(5, 26, 73, 24, 73, 61, 15, 65); 578 | fill(255); 579 | ellipseMode(CENTER); 580 | let steps = 6; 581 | for (let i = 0; i <= steps; i++) { 582 | let t = i / steps; 583 | let x = curvePoint(5, 5, 73, 73, t); 584 | let y = curvePoint(26, 26, 24, 61, t); 585 | ellipse(x, y, 5, 5); 586 | x = curvePoint(5, 73, 73, 15, t); 587 | y = curvePoint(26, 24, 61, 65, t); 588 | ellipse(x, y, 5, 5); 589 | } 590 | 591 | 592 | /*~~~ https://p5js.org/reference/#/p5/curveTangent ~~~*/ 593 | 594 | noFill(); 595 | curve(5, 26, 73, 24, 73, 61, 15, 65); 596 | let steps = 6; 597 | for (let i = 0; i <= steps; i++) { 598 | let t = i / steps; 599 | let x = curvePoint(5, 73, 73, 15, t); 600 | let y = curvePoint(26, 24, 61, 65, t); 601 | //ellipse(x, y, 5, 5); 602 | let tx = curveTangent(5, 73, 73, 15, t); 603 | let ty = curveTangent(26, 24, 61, 65, t); 604 | let a = atan2(ty, tx); 605 | a -= PI / 2.0; 606 | line(x, y, cos(a) * 8 + x, sin(a) * 8 + y); 607 | } 608 | 609 | /*~~~ https://p5js.org/reference/#/p5/beginContour ~~~*/ 610 | 611 | translate(50, 50); 612 | stroke(255, 0, 0); 613 | beginShape(); 614 | // Exterior part of shape, clockwise winding 615 | vertex(-40, -40); 616 | vertex(40, -40); 617 | vertex(40, 40); 618 | vertex(-40, 40); 619 | // Interior part of shape, counter-clockwise winding 620 | beginContour(); 621 | vertex(-20, -20); 622 | vertex(-20, 20); 623 | vertex(20, 20); 624 | vertex(20, -20); 625 | endContour(); 626 | endShape(CLOSE); 627 | 628 | /*~~~ https://p5js.org/reference/#/p5/beginShape ~~~*/ 629 | 630 | beginShape(); 631 | vertex(20, 20); 632 | vertex(40, 20); 633 | vertex(40, 40); 634 | vertex(60, 40); 635 | vertex(60, 60); 636 | vertex(20, 60); 637 | endShape(CLOSE); 638 | 639 | /*~~~ https://p5js.org/reference/#/p5/bezierVertex ~~~*/ 640 | 641 | noFill(); 642 | beginShape(); 643 | vertex(30, 20); 644 | bezierVertex(80, 0, 80, 75, 30, 75); 645 | endShape(); 646 | 647 | /*~~~ https://p5js.org/reference/#/p5/bezierVertex ~~~*/ 648 | 649 | beginShape(); 650 | vertex(30, 20); 651 | bezierVertex(80, 0, 80, 75, 30, 75); 652 | bezierVertex(50, 80, 60, 25, 30, 20); 653 | endShape(); 654 | 655 | /*~~~ https://p5js.org/reference/#/p5/curveVertex ~~~*/ 656 | 657 | 658 | strokeWeight(5); 659 | point(84, 91); 660 | point(68, 19); 661 | point(21, 17); 662 | point(32, 91); 663 | strokeWeight(1); 664 | 665 | noFill(); 666 | beginShape(); 667 | curveVertex(84, 91); 668 | curveVertex(84, 91); 669 | curveVertex(68, 19); 670 | curveVertex(21, 17); 671 | curveVertex(32, 91); 672 | curveVertex(32, 91); 673 | endShape(); 674 | 675 | 676 | /*~~~ https://p5js.org/reference/#/p5/endShape ~~~*/ 677 | 678 | 679 | noFill(); 680 | 681 | beginShape(); 682 | vertex(20, 20); 683 | vertex(45, 20); 684 | vertex(45, 80); 685 | endShape(CLOSE); 686 | 687 | beginShape(); 688 | vertex(50, 20); 689 | vertex(75, 20); 690 | vertex(75, 80); 691 | endShape(); 692 | 693 | /*~~~ https://p5js.org/reference/#/p5/quadraticVertex ~~~*/ 694 | 695 | 696 | strokeWeight(5); 697 | point(20, 20); 698 | point(80, 20); 699 | point(50, 50); 700 | 701 | noFill(); 702 | strokeWeight(1); 703 | beginShape(); 704 | vertex(20, 20); 705 | quadraticVertex(80, 20, 50, 50); 706 | endShape(); 707 | 708 | 709 | /*~~~ https://p5js.org/reference/#/p5/quadraticVertex ~~~*/ 710 | 711 | strokeWeight(5); 712 | point(20, 20); 713 | point(80, 20); 714 | point(50, 50); 715 | 716 | point(20, 80); 717 | point(80, 80); 718 | point(80, 60); 719 | 720 | noFill(); 721 | strokeWeight(1); 722 | beginShape(); 723 | vertex(20, 20); 724 | quadraticVertex(80, 20, 50, 50); 725 | quadraticVertex(20, 80, 80, 80); 726 | vertex(80, 60); 727 | endShape(); 728 | 729 | /*~~~ https://p5js.org/reference/#/p5/vertex ~~~*/ 730 | 731 | createCanvas(100, 100); 732 | background(240, 240, 240); 733 | fill(237, 34, 93); 734 | noStroke(); 735 | translate(50,50); 736 | beginShape(); 737 | vertex(-10, 10); 738 | vertex(0, 35); 739 | vertex(10, 10); 740 | vertex(35, 0); 741 | vertex(10, -8); 742 | vertex(0, -35); 743 | vertex(-10, -8); 744 | vertex(-35, 0); 745 | endShape(); 746 | 747 | /*~~~ https://p5js.org/reference/#/p5/cursor ~~~*/ 748 | 749 | // Move the mouse across the quadrants 750 | // to see the cursor change 751 | function draw() { 752 | line(width / 2, 0, width / 2, height); 753 | line(0, height / 2, width, height / 2); 754 | if (mouseX < 50 && mouseY < 50) { 755 | cursor(CROSS); 756 | } else if (mouseX > 50 && mouseY < 50) { 757 | cursor('progress'); 758 | } else if (mouseX > 50 && mouseY > 50) { 759 | cursor('https://avatars0.githubusercontent.com/u/1617169?s=16'); 760 | } else { 761 | cursor('grab'); 762 | } 763 | } 764 | 765 | /*~~~ https://p5js.org/reference/#/p5/noCursor ~~~*/ 766 | 767 | function setup() { 768 | noCursor(); 769 | } 770 | 771 | function draw() { 772 | background(200); 773 | ellipse(mouseX, mouseY, 10, 10); 774 | } 775 | 776 | /*~~~ https://p5js.org/reference/#/p5/preload ~~~*/ 777 | 778 | let img; 779 | let c; 780 | function preload() { 781 | // preload() runs once 782 | img = loadImage('assets/laDefense.jpg'); 783 | } 784 | 785 | function setup() { 786 | // setup() waits until preload() is done 787 | img.loadPixels(); 788 | // get color of middle pixel 789 | c = img.get(img.width / 2, img.height / 2); 790 | } 791 | 792 | function draw() { 793 | background(c); 794 | image(img, 25, 25, 50, 50); 795 | } 796 | 797 | /*~~~ https://p5js.org/reference/#/p5/setup ~~~*/ 798 | 799 | let a = 0; 800 | 801 | function setup() { 802 | background(0); 803 | noStroke(); 804 | fill(102); 805 | } 806 | 807 | function draw() { 808 | rect(a++ % width, 10, 2, 80); 809 | } 810 | 811 | /*~~~ https://p5js.org/reference/#/p5/draw ~~~*/ 812 | 813 | let yPos = 0; 814 | function setup() { 815 | // setup() runs once 816 | frameRate(30); 817 | } 818 | function draw() { 819 | // draw() loops forever, until stopped 820 | background(204); 821 | yPos = yPos - 1; 822 | if (yPos < 0) { 823 | yPos = height; 824 | } 825 | line(0, yPos, width, yPos); 826 | } 827 | 828 | /*~~~ https://p5js.org/reference/#/p5/noLoop ~~~*/ 829 | 830 | function setup() { 831 | createCanvas(100, 100); 832 | background(200); 833 | noLoop(); 834 | } 835 | 836 | function draw() { 837 | line(10, 10, 90, 90); 838 | } 839 | 840 | /*~~~ https://p5js.org/reference/#/p5/noLoop ~~~*/ 841 | 842 | 843 | let x = 0; 844 | function setup() { 845 | createCanvas(100, 100); 846 | } 847 | 848 | function draw() { 849 | background(204); 850 | x = x + 0.1; 851 | if (x > width) { 852 | x = 0; 853 | } 854 | line(x, 0, x, height); 855 | } 856 | 857 | function mousePressed() { 858 | noLoop(); 859 | } 860 | 861 | function mouseReleased() { 862 | loop(); 863 | } 864 | 865 | 866 | /*~~~ https://p5js.org/reference/#/p5/loop ~~~*/ 867 | 868 | let x = 0; 869 | function setup() { 870 | createCanvas(100, 100); 871 | noLoop(); 872 | } 873 | 874 | function draw() { 875 | background(204); 876 | x = x + 0.1; 877 | if (x > width) { 878 | x = 0; 879 | } 880 | line(x, 0, x, height); 881 | } 882 | 883 | function mousePressed() { 884 | loop(); 885 | } 886 | 887 | function mouseReleased() { 888 | noLoop(); 889 | } 890 | 891 | /*~~~ https://p5js.org/reference/#/p5/push ~~~*/ 892 | 893 | ellipse(0, 50, 33, 33); // Left circle 894 | 895 | push(); // Start a new drawing state 896 | strokeWeight(10); 897 | fill(204, 153, 0); 898 | translate(50, 0); 899 | ellipse(0, 50, 33, 33); // Middle circle 900 | pop(); // Restore original state 901 | 902 | ellipse(100, 50, 33, 33); // Right circle 903 | 904 | 905 | /*~~~ https://p5js.org/reference/#/p5/push ~~~*/ 906 | 907 | ellipse(0, 50, 33, 33); // Left circle 908 | 909 | push(); // Start a new drawing state 910 | strokeWeight(10); 911 | fill(204, 153, 0); 912 | ellipse(33, 50, 33, 33); // Left-middle circle 913 | 914 | push(); // Start another new drawing state 915 | stroke(0, 102, 153); 916 | ellipse(66, 50, 33, 33); // Right-middle circle 917 | pop(); // Restore previous state 918 | 919 | pop(); // Restore original state 920 | 921 | ellipse(100, 50, 33, 33); // Right circle 922 | 923 | /*~~~ https://p5js.org/reference/#/p5/redraw ~~~*/ 924 | 925 | let x = 0; 926 | 927 | function setup() { 928 | createCanvas(100, 100); 929 | noLoop(); 930 | } 931 | 932 | function draw() { 933 | background(204); 934 | line(x, 0, x, height); 935 | } 936 | 937 | function mousePressed() { 938 | x += 1; 939 | redraw(); 940 | } 941 | 942 | /*~~~ https://p5js.org/reference/#/p5/createCanvas ~~~*/ 943 | 944 | function setup() { 945 | createCanvas(100, 50); 946 | background(153); 947 | line(0, 0, width, height); 948 | } 949 | 950 | /*~~~ https://p5js.org/reference/#/p5/createGraphics ~~~*/ 951 | 952 | let pg; 953 | function setup() { 954 | createCanvas(100, 100); 955 | pg = createGraphics(100, 100); 956 | } 957 | 958 | function draw() { 959 | background(200); 960 | pg.background(100); 961 | pg.noStroke(); 962 | pg.ellipse(pg.width / 2, pg.height / 2, 50, 50); 963 | image(pg, 50, 50); 964 | image(pg, 0, 0, 50, 50); 965 | } 966 | 967 | /*~~~ https://p5js.org/reference/#/p5/blendMode ~~~*/ 968 | 969 | blendMode(LIGHTEST); 970 | strokeWeight(30); 971 | stroke(80, 150, 255); 972 | line(25, 25, 75, 75); 973 | stroke(255, 50, 50); 974 | line(75, 25, 25, 75); 975 | 976 | /*~~~ https://p5js.org/reference/#/p5/blendMode ~~~*/ 977 | 978 | blendMode(MULTIPLY); 979 | strokeWeight(30); 980 | stroke(80, 150, 255); 981 | line(25, 25, 75, 75); 982 | stroke(255, 50, 50); 983 | line(75, 25, 25, 75); 984 | 985 | 986 | /*~~~ https://p5js.org/reference/#/p5/drawingContext ~~~*/ 987 | 988 | function setup() { 989 | drawingContext.shadowOffsetX = 5; 990 | drawingContext.shadowOffsetY = -5; 991 | drawingContext.shadowBlur = 10; 992 | drawingContext.shadowColor = 'black'; 993 | background(200); 994 | ellipse(width / 2, height / 2, 50, 50); 995 | } 996 | 997 | /*~~~ https://p5js.org/reference/#/p5/applyMatrix ~~~*/ 998 | 999 | function setup() { 1000 | frameRate(10); 1001 | rectMode(CENTER); 1002 | } 1003 | 1004 | function draw() { 1005 | let step = frameCount % 20; 1006 | background(200); 1007 | // Equivalent to translate(x, y); 1008 | applyMatrix(1, 0, 0, 1, 40 + step, 50); 1009 | rect(0, 0, 50, 50); 1010 | } 1011 | 1012 | /*~~~ https://p5js.org/reference/#/p5/applyMatrix ~~~*/ 1013 | 1014 | function setup() { 1015 | frameRate(10); 1016 | rectMode(CENTER); 1017 | } 1018 | 1019 | function draw() { 1020 | let step = frameCount % 20; 1021 | background(200); 1022 | translate(50, 50); 1023 | // Equivalent to scale(x, y); 1024 | applyMatrix(1 / step, 0, 0, 1 / step, 0, 0); 1025 | rect(0, 0, 50, 50); 1026 | } 1027 | 1028 | /*~~~ https://p5js.org/reference/#/p5/applyMatrix ~~~*/ 1029 | 1030 | function setup() { 1031 | frameRate(10); 1032 | rectMode(CENTER); 1033 | } 1034 | 1035 | function draw() { 1036 | let step = frameCount % 20; 1037 | let angle = map(step, 0, 20, 0, TWO_PI); 1038 | let cos_a = cos(angle); 1039 | let sin_a = sin(angle); 1040 | background(200); 1041 | translate(50, 50); 1042 | // Equivalent to rotate(angle); 1043 | applyMatrix(cos_a, sin_a, -sin_a, cos_a, 0, 0); 1044 | rect(0, 0, 50, 50); 1045 | } 1046 | 1047 | /*~~~ https://p5js.org/reference/#/p5/applyMatrix ~~~*/ 1048 | 1049 | 1050 | function setup() { 1051 | frameRate(10); 1052 | rectMode(CENTER); 1053 | } 1054 | 1055 | function draw() { 1056 | let step = frameCount % 20; 1057 | let angle = map(step, 0, 20, -PI / 4, PI / 4); 1058 | background(200); 1059 | translate(50, 50); 1060 | // equivalent to shearX(angle); 1061 | let shear_factor = 1 / tan(PI / 2 - angle); 1062 | applyMatrix(1, 0, shear_factor, 1, 0, 0); 1063 | rect(0, 0, 50, 50); 1064 | } 1065 | 1066 | 1067 | /*~~~ https://p5js.org/reference/#/p5/resetMatrix ~~~*/ 1068 | 1069 | translate(50, 50); 1070 | applyMatrix(0.5, 0.5, -0.5, 0.5, 0, 0); 1071 | rect(0, 0, 20, 20); 1072 | // Note that the translate is also reset. 1073 | resetMatrix(); 1074 | rect(0, 0, 20, 20); 1075 | 1076 | /*~~~ https://p5js.org/reference/#/p5/rotate ~~~*/ 1077 | 1078 | translate(width / 2, height / 2); 1079 | rotate(PI / 3.0); 1080 | rect(-26, -26, 52, 52); 1081 | 1082 | /*~~~ https://p5js.org/reference/#/p5/scale ~~~*/ 1083 | 1084 | rect(30, 20, 50, 50); 1085 | scale(0.5); 1086 | rect(30, 20, 50, 50); 1087 | 1088 | /*~~~ https://p5js.org/reference/#/p5/shearX ~~~*/ 1089 | 1090 | translate(width / 4, height / 4); 1091 | shearX(PI / 4.0); 1092 | rect(0, 0, 30, 30); 1093 | 1094 | /*~~~ https://p5js.org/reference/#/p5/shearY ~~~*/ 1095 | 1096 | translate(width / 4, height / 4); 1097 | shearY(PI / 4.0); 1098 | rect(0, 0, 30, 30); 1099 | 1100 | /*~~~ https://p5js.org/reference/#/p5/translate ~~~*/ 1101 | 1102 | translate(30, 20); 1103 | rect(0, 0, 55, 55); 1104 | 1105 | /*~~~ https://p5js.org/reference/#/p5/translate ~~~*/ 1106 | 1107 | rect(0, 0, 55, 55); // Draw rect at original 0,0 1108 | translate(30, 20); 1109 | rect(0, 0, 55, 55); // Draw rect at new 0,0 1110 | translate(14, 14); 1111 | rect(0, 0, 55, 55); // Draw rect at new 0,0 1112 | 1113 | /*~~~ https://p5js.org/reference/#/p5/translate ~~~*/ 1114 | 1115 | function draw() { 1116 | background(200); 1117 | rectMode(CENTER); 1118 | translate(width / 2, height / 2); 1119 | translate(p5.Vector.fromAngle(millis() / 1000, 40)); 1120 | rect(0, 0, 20, 20); 1121 | } 1122 | 1123 | /*~~~ https://p5js.org/reference/#/p5/keyIsPressed ~~~*/ 1124 | 1125 | function draw() { 1126 | if (keyIsPressed === true) { 1127 | fill(0); 1128 | } else { 1129 | fill(255); 1130 | } 1131 | rect(25, 25, 50, 50); 1132 | } 1133 | 1134 | /*~~~ https://p5js.org/reference/#/p5/key ~~~*/ 1135 | 1136 | 1137 | // Click any key to display it! 1138 | // (Not Guaranteed to be Case Sensitive) 1139 | function setup() { 1140 | fill(245, 123, 158); 1141 | textSize(50); 1142 | } 1143 | 1144 | function draw() { 1145 | background(200); 1146 | text(key, 33, 65); // Display last key pressed. 1147 | } 1148 | 1149 | /*~~~ https://p5js.org/reference/#/p5/keyCode ~~~*/ 1150 | 1151 | let fillVal = 126; 1152 | function draw() { 1153 | fill(fillVal); 1154 | rect(25, 25, 50, 50); 1155 | } 1156 | 1157 | function keyPressed() { 1158 | if (keyCode === UP_ARROW) { 1159 | fillVal = 255; 1160 | } else if (keyCode === DOWN_ARROW) { 1161 | fillVal = 0; 1162 | } 1163 | return false; // prevent default 1164 | } 1165 | 1166 | /*~~~ https://p5js.org/reference/#/p5/keyCode ~~~*/ 1167 | 1168 | function draw() {} 1169 | function keyPressed() { 1170 | background('yellow'); 1171 | noStroke(); 1172 | fill(0); 1173 | text(`${key} ${keyCode}`, 10, 40); 1174 | print(key, ' ', keyCode); 1175 | return false; // prevent default 1176 | } 1177 | 1178 | /*~~~ https://p5js.org/reference/#/p5/keyPressed ~~~*/ 1179 | 1180 | let value = 0; 1181 | function draw() { 1182 | fill(value); 1183 | rect(25, 25, 50, 50); 1184 | } 1185 | function keyPressed() { 1186 | if (value === 0) { 1187 | value = 255; 1188 | } else { 1189 | value = 0; 1190 | } 1191 | } 1192 | 1193 | /*~~~ https://p5js.org/reference/#/p5/keyPressed ~~~*/ 1194 | 1195 | let value = 0; 1196 | function draw() { 1197 | fill(value); 1198 | rect(25, 25, 50, 50); 1199 | } 1200 | function keyPressed() { 1201 | if (keyCode === LEFT_ARROW) { 1202 | value = 255; 1203 | } else if (keyCode === RIGHT_ARROW) { 1204 | value = 0; 1205 | } 1206 | } 1207 | 1208 | /*~~~ https://p5js.org/reference/#/p5/keyReleased ~~~*/ 1209 | 1210 | let value = 0; 1211 | function draw() { 1212 | fill(value); 1213 | rect(25, 25, 50, 50); 1214 | } 1215 | function keyReleased() { 1216 | if (value === 0) { 1217 | value = 255; 1218 | } else { 1219 | value = 0; 1220 | } 1221 | return false; // prevent any default behavior 1222 | } 1223 | 1224 | /*~~~ https://p5js.org/reference/#/p5/keyIsDown ~~~*/ 1225 | 1226 | let x = 50; 1227 | let y = 50; 1228 | 1229 | function setup() { 1230 | createCanvas(100, 100); 1231 | fill(255, 0, 0); 1232 | } 1233 | 1234 | function draw() { 1235 | if (keyIsDown(LEFT_ARROW)) { 1236 | x -= 5; 1237 | } 1238 | 1239 | if (keyIsDown(RIGHT_ARROW)) { 1240 | x += 5; 1241 | } 1242 | 1243 | if (keyIsDown(UP_ARROW)) { 1244 | y -= 5; 1245 | } 1246 | 1247 | if (keyIsDown(DOWN_ARROW)) { 1248 | y += 5; 1249 | } 1250 | 1251 | clear(); 1252 | ellipse(x, y, 50, 50); 1253 | } 1254 | 1255 | 1256 | /*~~~ https://p5js.org/reference/#/p5/keyIsDown ~~~*/ 1257 | 1258 | let diameter = 50; 1259 | 1260 | function setup() { 1261 | createCanvas(100, 100); 1262 | } 1263 | 1264 | function draw() { 1265 | // 107 and 187 are keyCodes for "+" 1266 | if (keyIsDown(107) || keyIsDown(187)) { 1267 | diameter += 1; 1268 | } 1269 | 1270 | // 109 and 189 are keyCodes for "-" 1271 | if (keyIsDown(109) || keyIsDown(189)) { 1272 | diameter -= 1; 1273 | } 1274 | 1275 | clear(); 1276 | fill(255, 0, 0); 1277 | ellipse(50, 50, diameter, diameter); 1278 | } 1279 | 1280 | /*~~~ https://p5js.org/reference/#/p5/mouseX ~~~*/ 1281 | 1282 | // Move the mouse across the canvas 1283 | function draw() { 1284 | background(244, 248, 252); 1285 | line(mouseX, 0, mouseX, 100); 1286 | } 1287 | 1288 | /*~~~ https://p5js.org/reference/#/p5/mouseY ~~~*/ 1289 | 1290 | // Move the mouse across the canvas 1291 | function draw() { 1292 | background(244, 248, 252); 1293 | line(0, mouseY, 100, mouseY); 1294 | } 1295 | 1296 | 1297 | /*~~~ https://p5js.org/reference/#/p5/pmouseX ~~~*/ 1298 | 1299 | // Move the mouse across the canvas to leave a trail 1300 | function setup() { 1301 | 1302 | } 1303 | 1304 | function draw() { 1305 | background(244, 248, 252); 1306 | line(mouseX, mouseY, pmouseX, pmouseY); 1307 | print(window.pmouseX + ' -> ' + window.mouseX); 1308 | } 1309 | 1310 | 1311 | /*~~~ https://p5js.org/reference/#/p5/pmouseY ~~~*/ 1312 | 1313 | function draw() { 1314 | background(237, 34, 93); 1315 | fill(0); 1316 | //draw a square only if the mouse is not moving 1317 | if (mouseY === pmouseY && mouseX === pmouseX) { 1318 | rect(20, 20, 60, 60); 1319 | } 1320 | 1321 | print(pmouseY + ' -> ' + mouseY); 1322 | } 1323 | 1324 | /*~~~ https://p5js.org/reference/#/p5/mouseButton ~~~*/ 1325 | 1326 | function draw() { 1327 | background(237, 34, 93); 1328 | fill(0); 1329 | 1330 | if (mouseIsPressed) { 1331 | if (mouseButton === LEFT) { 1332 | ellipse(50, 50, 50, 50); 1333 | } 1334 | if (mouseButton === RIGHT) { 1335 | rect(25, 25, 50, 50); 1336 | } 1337 | if (mouseButton === CENTER) { 1338 | triangle(23, 75, 50, 20, 78, 75); 1339 | } 1340 | } 1341 | 1342 | print(mouseButton); 1343 | } 1344 | 1345 | /*~~~ https://p5js.org/reference/#/p5/mouseIsPressed ~~~*/ 1346 | 1347 | function draw() { 1348 | background(237, 34, 93); 1349 | fill(0); 1350 | 1351 | if (mouseIsPressed) { 1352 | ellipse(50, 50, 50, 50); 1353 | } else { 1354 | rect(25, 25, 50, 50); 1355 | } 1356 | 1357 | print(mouseIsPressed); 1358 | } 1359 | 1360 | /*~~~ https://p5js.org/reference/#/p5/mouseMoved ~~~*/ 1361 | 1362 | // Move the mouse across the page 1363 | // to change its value 1364 | 1365 | let value = 0; 1366 | function draw() { 1367 | fill(value); 1368 | rect(25, 25, 50, 50); 1369 | } 1370 | function mouseMoved() { 1371 | value = value + 5; 1372 | if (value > 255) { 1373 | value = 0; 1374 | } 1375 | } 1376 | 1377 | /*~~~ https://p5js.org/reference/#/p5/mouseDragged ~~~*/ 1378 | 1379 | // Drag the mouse across the page 1380 | // to change its value 1381 | 1382 | let value = 0; 1383 | function draw() { 1384 | fill(value); 1385 | rect(25, 25, 50, 50); 1386 | } 1387 | function mouseDragged() { 1388 | value = value + 5; 1389 | if (value > 255) { 1390 | value = 0; 1391 | } 1392 | } 1393 | 1394 | /*~~~ https://p5js.org/reference/#/p5/mousePressed ~~~*/ 1395 | 1396 | // Click within the image to change 1397 | // the value of the rectangle 1398 | 1399 | let value = 0; 1400 | function draw() { 1401 | fill(value); 1402 | rect(25, 25, 50, 50); 1403 | } 1404 | function mousePressed() { 1405 | if (value === 0) { 1406 | value = 255; 1407 | } else { 1408 | value = 0; 1409 | } 1410 | } 1411 | 1412 | 1413 | /*~~~ https://p5js.org/reference/#/p5/mouseReleased ~~~*/ 1414 | 1415 | // Click within the image to change 1416 | // the value of the rectangle 1417 | // after the mouse has been clicked 1418 | 1419 | let value = 0; 1420 | function draw() { 1421 | fill(value); 1422 | rect(25, 25, 50, 50); 1423 | } 1424 | function mouseReleased() { 1425 | if (value === 0) { 1426 | value = 255; 1427 | } else { 1428 | value = 0; 1429 | } 1430 | } 1431 | 1432 | /*~~~ https://p5js.org/reference/#/p5/mouseClicked ~~~*/ 1433 | 1434 | // Click within the image to change 1435 | // the value of the rectangle 1436 | // after the mouse has been clicked 1437 | 1438 | let value = 0; 1439 | function draw() { 1440 | fill(value); 1441 | rect(25, 25, 50, 50); 1442 | } 1443 | 1444 | function mouseClicked() { 1445 | if (value === 0) { 1446 | value = 255; 1447 | } else { 1448 | value = 0; 1449 | } 1450 | } 1451 | 1452 | /*~~~ https://p5js.org/reference/#/p5/touches ~~~*/ 1453 | 1454 | // On a touchscreen device, touch 1455 | // the canvas using one or more fingers 1456 | // at the same time 1457 | function draw() { 1458 | clear(); 1459 | let display = touches.length + ' touches'; 1460 | text(display, 5, 10); 1461 | } 1462 | 1463 | 1464 | /*~~~ https://p5js.org/reference/#/p5/touchStarted ~~~*/ 1465 | 1466 | // Touch within the image to change 1467 | // the value of the rectangle 1468 | 1469 | let value = 0; 1470 | function draw() { 1471 | fill(value); 1472 | rect(25, 25, 50, 50); 1473 | } 1474 | function touchStarted() { 1475 | if (value === 0) { 1476 | value = 255; 1477 | } else { 1478 | value = 0; 1479 | } 1480 | } 1481 | 1482 | /*~~~ https://p5js.org/reference/#/p5/touchMoved ~~~*/ 1483 | 1484 | // Move your finger across the page 1485 | // to change its value 1486 | 1487 | let value = 0; 1488 | function draw() { 1489 | fill(value); 1490 | rect(25, 25, 50, 50); 1491 | } 1492 | function touchMoved() { 1493 | value = value + 5; 1494 | if (value > 255) { 1495 | value = 0; 1496 | } 1497 | } 1498 | 1499 | /*~~~ https://p5js.org/reference/#/p5/touchEnded ~~~*/ 1500 | 1501 | // Release touch within the image to 1502 | // change the value of the rectangle 1503 | 1504 | let value = 0; 1505 | function draw() { 1506 | fill(value); 1507 | rect(25, 25, 50, 50); 1508 | } 1509 | function touchEnded() { 1510 | if (value === 0) { 1511 | value = 255; 1512 | } else { 1513 | value = 0; 1514 | } 1515 | } 1516 | 1517 | /*~~~ https://p5js.org/reference/#/p5/createImage ~~~*/ 1518 | 1519 | let img = createImage(66, 66); 1520 | img.loadPixels(); 1521 | for (let i = 0; i < img.width; i++) { 1522 | for (let j = 0; j < img.height; j++) { 1523 | img.set(i, j, color(0, 90, 102)); 1524 | } 1525 | } 1526 | img.updatePixels(); 1527 | image(img, 17, 17); 1528 | 1529 | /*~~~ https://p5js.org/reference/#/p5/createImage ~~~*/ 1530 | 1531 | let img = createImage(66, 66); 1532 | img.loadPixels(); 1533 | for (let i = 0; i < img.width; i++) { 1534 | for (let j = 0; j < img.height; j++) { 1535 | img.set(i, j, color(0, 90, 102, (i % img.width) * 2)); 1536 | } 1537 | } 1538 | img.updatePixels(); 1539 | image(img, 17, 17); 1540 | image(img, 34, 34); 1541 | 1542 | 1543 | /*~~~ https://p5js.org/reference/#/p5/createImage ~~~*/ 1544 | 1545 | let pink = color(255, 102, 204); 1546 | let img = createImage(66, 66); 1547 | img.loadPixels(); 1548 | let d = pixelDensity(); 1549 | let halfImage = 4 * (img.width * d) * (img.height / 2 * d); 1550 | for (let i = 0; i < halfImage; i += 4) { 1551 | img.pixels[i] = red(pink); 1552 | img.pixels[i + 1] = green(pink); 1553 | img.pixels[i + 2] = blue(pink); 1554 | img.pixels[i + 3] = alpha(pink); 1555 | } 1556 | img.updatePixels(); 1557 | image(img, 17, 17); 1558 | 1559 | /*~~~ https://p5js.org/reference/#/p5.Image ~~~*/ 1560 | 1561 | function setup() { 1562 | let img = createImage(100, 100); // same as new p5.Image(100, 100); 1563 | img.loadPixels(); 1564 | createCanvas(100, 100); 1565 | background(0); 1566 | 1567 | // helper for writing color to array 1568 | function writeColor(image, x, y, red, green, blue, alpha) { 1569 | let index = (x + y * width) * 4; 1570 | image.pixels[index] = red; 1571 | image.pixels[index + 1] = green; 1572 | image.pixels[index + 2] = blue; 1573 | image.pixels[index + 3] = alpha; 1574 | } 1575 | 1576 | let x, y; 1577 | // fill with random colors 1578 | for (y = 0; y < img.height; y++) { 1579 | for (x = 0; x < img.width; x++) { 1580 | let red = random(255); 1581 | let green = random(255); 1582 | let blue = random(255); 1583 | let alpha = 255; 1584 | writeColor(img, x, y, red, green, blue, alpha); 1585 | } 1586 | } 1587 | 1588 | // draw a red line 1589 | y = 0; 1590 | for (x = 0; x < img.width; x++) { 1591 | writeColor(img, x, y, 255, 0, 0, 255); 1592 | } 1593 | 1594 | // draw a green line 1595 | y = img.height - 1; 1596 | for (x = 0; x < img.width; x++) { 1597 | writeColor(img, x, y, 0, 255, 0, 255); 1598 | } 1599 | 1600 | img.updatePixels(); 1601 | image(img, 0, 0); 1602 | } 1603 | 1604 | /*~~~ https://p5js.org/reference/#/p5.Image/loadPixels ~~~*/ 1605 | 1606 | let myImage; 1607 | let halfImage; 1608 | 1609 | function preload() { 1610 | myImage = loadImage('assets/rockies.jpg'); 1611 | } 1612 | 1613 | function setup() { 1614 | myImage.loadPixels(); 1615 | halfImage = 4 * myImage.width * myImage.height / 2; 1616 | for (let i = 0; i < halfImage; i++) { 1617 | myImage.pixels[i + halfImage] = myImage.pixels[i]; 1618 | } 1619 | myImage.updatePixels(); 1620 | } 1621 | 1622 | function draw() { 1623 | image(myImage, 0, 0, width, height); 1624 | } 1625 | 1626 | /*~~~ https://p5js.org/reference/#/p5.Image/get ~~~*/ 1627 | 1628 | let myImage; 1629 | let c; 1630 | 1631 | function preload() { 1632 | myImage = loadImage('assets/rockies.jpg'); 1633 | } 1634 | 1635 | function setup() { 1636 | background(myImage); 1637 | noStroke(); 1638 | c = myImage.get(60, 90); 1639 | fill(c); 1640 | rect(25, 25, 50, 50); 1641 | } 1642 | 1643 | //get() returns color here 1644 | 1645 | /*~~~ https://p5js.org/reference/#/p5.Image/resize ~~~*/ 1646 | 1647 | let img; 1648 | 1649 | function preload() { 1650 | img = loadImage('assets/rockies.jpg'); 1651 | } 1652 | 1653 | function draw() { 1654 | image(img, 0, 0); 1655 | } 1656 | 1657 | function mousePressed() { 1658 | img.resize(50, 100); 1659 | } 1660 | 1661 | /*~~~ https://p5js.org/reference/#/p5.Image/mask ~~~*/ 1662 | 1663 | let photo, maskImage; 1664 | function preload() { 1665 | photo = loadImage('assets/rockies.jpg'); 1666 | maskImage = loadImage('assets/mask2.png'); 1667 | } 1668 | 1669 | function setup() { 1670 | createCanvas(100, 100); 1671 | photo.mask(maskImage); 1672 | image(photo, 0, 0); 1673 | } 1674 | 1675 | /*~~~ https://p5js.org/reference/#/p5.Image/filter ~~~*/ 1676 | 1677 | let photo1; 1678 | let photo2; 1679 | 1680 | function preload() { 1681 | photo1 = loadImage('assets/rockies.jpg'); 1682 | photo2 = loadImage('assets/rockies.jpg'); 1683 | } 1684 | 1685 | function setup() { 1686 | photo2.filter(GRAY); 1687 | image(photo1, 0, 0); 1688 | image(photo2, width / 2, 0); 1689 | } 1690 | 1691 | /*~~~ https://p5js.org/reference/#/p5.Image/save ~~~*/ 1692 | 1693 | let photo; 1694 | 1695 | function preload() { 1696 | photo = loadImage('assets/rockies.jpg'); 1697 | } 1698 | 1699 | function draw() { 1700 | image(photo, 0, 0); 1701 | } 1702 | 1703 | function keyTyped() { 1704 | if (key === 's') { 1705 | photo.save('photo', 'png'); 1706 | } 1707 | } 1708 | 1709 | /*~~~ https://p5js.org/reference/#/p5/pixels ~~~*/ 1710 | 1711 | let pink = color(255, 102, 204); 1712 | loadPixels(); 1713 | let d = pixelDensity(); 1714 | let halfImage = 4 * (width * d) * (height / 2 * d); 1715 | for (let i = 0; i < halfImage; i += 4) { 1716 | pixels[i] = red(pink); 1717 | pixels[i + 1] = green(pink); 1718 | pixels[i + 2] = blue(pink); 1719 | pixels[i + 3] = alpha(pink); 1720 | } 1721 | updatePixels(); 1722 | 1723 | /*~~~ https://p5js.org/reference/#/p5/filter ~~~*/ 1724 | 1725 | let img; 1726 | function preload() { 1727 | img = loadImage('assets/bricks.jpg'); 1728 | } 1729 | function setup() { 1730 | image(img, 0, 0); 1731 | filter(THRESHOLD); 1732 | } 1733 | 1734 | /*~~~ https://p5js.org/reference/#/p5/filter ~~~*/ 1735 | 1736 | let img; 1737 | function preload() { 1738 | img = loadImage('assets/bricks.jpg'); 1739 | } 1740 | function setup() { 1741 | image(img, 0, 0); 1742 | filter(GRAY); 1743 | } 1744 | 1745 | /*~~~ https://p5js.org/reference/#/p5/filter ~~~*/ 1746 | 1747 | let img; 1748 | function preload() { 1749 | img = loadImage('assets/bricks.jpg'); 1750 | } 1751 | function setup() { 1752 | image(img, 0, 0); 1753 | filter(OPAQUE); 1754 | } 1755 | 1756 | /*~~~ https://p5js.org/reference/#/p5/filter ~~~*/ 1757 | 1758 | let img; 1759 | function preload() { 1760 | img = loadImage('assets/bricks.jpg'); 1761 | } 1762 | function setup() { 1763 | image(img, 0, 0); 1764 | filter(INVERT); 1765 | } 1766 | 1767 | /*~~~ https://p5js.org/reference/#/p5/filter ~~~*/ 1768 | 1769 | let img; 1770 | function preload() { 1771 | img = loadImage('assets/bricks.jpg'); 1772 | } 1773 | function setup() { 1774 | image(img, 0, 0); 1775 | filter(POSTERIZE, 3); 1776 | } 1777 | 1778 | /*~~~ https://p5js.org/reference/#/p5/filter ~~~*/ 1779 | 1780 | let img; 1781 | function preload() { 1782 | img = loadImage('assets/bricks.jpg'); 1783 | } 1784 | function setup() { 1785 | image(img, 0, 0); 1786 | filter(DILATE); 1787 | } 1788 | 1789 | /*~~~ https://p5js.org/reference/#/p5/filter ~~~*/ 1790 | 1791 | let img; 1792 | function preload() { 1793 | img = loadImage('assets/bricks.jpg'); 1794 | } 1795 | function setup() { 1796 | image(img, 0, 0); 1797 | filter(BLUR, 3); 1798 | } 1799 | 1800 | /*~~~ https://p5js.org/reference/#/p5/filter ~~~*/ 1801 | 1802 | let img; 1803 | function preload() { 1804 | img = loadImage('assets/bricks.jpg'); 1805 | } 1806 | function setup() { 1807 | image(img, 0, 0); 1808 | filter(ERODE); 1809 | } 1810 | 1811 | /*~~~ https://p5js.org/reference/#/p5/filter ~~~*/ 1812 | 1813 | let img; 1814 | function preload() { 1815 | img = loadImage('assets/rockies.jpg'); 1816 | } 1817 | function setup() { 1818 | image(img, 0, 0); 1819 | let c = get(); 1820 | image(c, width / 2, 0); 1821 | } 1822 | 1823 | /*~~~ https://p5js.org/reference/#/p5/get ~~~*/ 1824 | 1825 | let img; 1826 | function preload() { 1827 | img = loadImage('assets/rockies.jpg'); 1828 | } 1829 | function setup() { 1830 | image(img, 0, 0); 1831 | let c = get(); 1832 | image(c, width / 2, 0); 1833 | } 1834 | 1835 | /*~~~ https://p5js.org/reference/#/p5/get ~~~*/ 1836 | 1837 | let img; 1838 | function preload() { 1839 | img = loadImage('assets/rockies.jpg'); 1840 | } 1841 | function setup() { 1842 | image(img, 0, 0); 1843 | let c = get(50, 90); 1844 | fill(c); 1845 | noStroke(); 1846 | rect(25, 25, 50, 50); 1847 | } 1848 | 1849 | /*~~~ https://p5js.org/reference/#/p5/loadPixels ~~~*/ 1850 | 1851 | let img; 1852 | function preload() { 1853 | img = loadImage('assets/rockies.jpg'); 1854 | } 1855 | 1856 | function setup() { 1857 | image(img, 0, 0, width, height); 1858 | let d = pixelDensity(); 1859 | let halfImage = 4 * (width * d) * (height * d / 2); 1860 | loadPixels(); 1861 | for (let i = 0; i < halfImage; i++) { 1862 | pixels[i + halfImage] = pixels[i]; 1863 | } 1864 | updatePixels(); 1865 | } 1866 | 1867 | /*~~~ https://p5js.org/reference/#/p5/set ~~~*/ 1868 | 1869 | loadPixels(); 1870 | let black = color(0); 1871 | set(30, 20, black); 1872 | set(85, 20, black); 1873 | set(85, 75, black); 1874 | set(30, 75, black); 1875 | updatePixels(); 1876 | 1877 | 1878 | /*~~~ https://p5js.org/reference/#/p5/set ~~~*/ 1879 | 1880 | loadPixels(); 1881 | for (let i = 30; i < width - 15; i++) { 1882 | for (let j = 20; j < height - 25; j++) { 1883 | let c = color(204 - j, 153 - i, 0); 1884 | set(i, j, c); 1885 | } 1886 | } 1887 | updatePixels(); 1888 | 1889 | /*~~~ https://p5js.org/reference/#/p5/set ~~~*/ 1890 | 1891 | let img; 1892 | function preload() { 1893 | img = loadImage('assets/rockies.jpg'); 1894 | } 1895 | 1896 | function setup() { 1897 | tint(255,0,0,100); 1898 | set(0, 0, img); 1899 | updatePixels(); 1900 | line(0, 0, width, height); 1901 | line(0, height, width, 0); 1902 | } 1903 | 1904 | 1905 | /*~~~ https://p5js.org/reference/#/p5/createVector ~~~*/ 1906 | 1907 | let v1; 1908 | function setup() { 1909 | createCanvas(100, 100); 1910 | stroke(255, 0, 255); 1911 | v1 = createVector(width / 2, height / 2); 1912 | } 1913 | 1914 | function draw() { 1915 | background(255); 1916 | line(v1.x, v1.y, mouseX, mouseY); 1917 | } 1918 | 1919 | /*~~~ https://p5js.org/reference/#/p5.Vector ~~~*/ 1920 | 1921 | let v1 = createVector(40, 50); 1922 | let v2 = createVector(40, 50); 1923 | 1924 | ellipse(v1.x, v1.y, 50, 50); 1925 | ellipse(v2.x, v2.y, 50, 50); 1926 | v1.add(v2); 1927 | ellipse(v1.x, v1.y, 50, 50); 1928 | 1929 | /*~~~ https://p5js.org/reference/#/p5.Vector/toString ~~~*/ 1930 | 1931 | function draw() { 1932 | background(240); 1933 | 1934 | let v0 = createVector(0, 0); 1935 | let v1 = createVector(mouseX, mouseY); 1936 | drawArrow(v0, v1, color(0)); 1937 | 1938 | noStroke(); 1939 | fill(0); 1940 | text(v1.toString(), 10, 25, 90, 75); 1941 | } 1942 | 1943 | // draw an arrow for a vector at a given base position 1944 | function drawArrow(base, vec, myColor) { 1945 | push(); 1946 | stroke(myColor); 1947 | strokeWeight(3); 1948 | fill(myColor); 1949 | translate(base.x, base.y); 1950 | line(0, 0, vec.x, vec.y); 1951 | rotate(vec.heading()); 1952 | let arrowSize = 7; 1953 | translate(vec.mag() - arrowSize, 0); 1954 | triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0); 1955 | pop(); 1956 | } 1957 | 1958 | /*~~~ https://p5js.org/reference/#/p5.Vector/set ~~~*/ 1959 | 1960 | let v0, v1; 1961 | function setup() { 1962 | createCanvas(100, 100); 1963 | 1964 | v0 = createVector(0, 0); 1965 | v1 = createVector(50, 50); 1966 | } 1967 | 1968 | function draw() { 1969 | background(240); 1970 | 1971 | drawArrow(v0, v1, 'black'); 1972 | v1.set(v1.x + random(-1, 1), v1.y + random(-1, 1)); 1973 | 1974 | noStroke(); 1975 | fill(0); 1976 | text('x: ' + round(v1.x) + ' y: ' + round(v1.y), 20, 90); 1977 | } 1978 | 1979 | // draw an arrow for a vector at a given base position 1980 | function drawArrow(base, vec, myColor) { 1981 | push(); 1982 | stroke(myColor); 1983 | strokeWeight(3); 1984 | fill(myColor); 1985 | translate(base.x, base.y); 1986 | line(0, 0, vec.x, vec.y); 1987 | rotate(vec.heading()); 1988 | let arrowSize = 7; 1989 | translate(vec.mag() - arrowSize, 0); 1990 | triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0); 1991 | pop(); 1992 | } 1993 | 1994 | /*~~~ https://p5js.org/reference/#/p5.Vector/add ~~~*/ 1995 | 1996 | // red vector + blue vector = purple vector 1997 | function draw() { 1998 | background(240); 1999 | 2000 | let v0 = createVector(0, 0); 2001 | let v1 = createVector(mouseX, mouseY); 2002 | drawArrow(v0, v1, 'red'); 2003 | 2004 | let v2 = createVector(-30, 20); 2005 | drawArrow(v1, v2, 'blue'); 2006 | 2007 | let v3 = p5.Vector.add(v1, v2); 2008 | drawArrow(v0, v3, 'purple'); 2009 | } 2010 | 2011 | // draw an arrow for a vector at a given base position 2012 | function drawArrow(base, vec, myColor) { 2013 | push(); 2014 | stroke(myColor); 2015 | strokeWeight(3); 2016 | fill(myColor); 2017 | translate(base.x, base.y); 2018 | line(0, 0, vec.x, vec.y); 2019 | rotate(vec.heading()); 2020 | let arrowSize = 7; 2021 | translate(vec.mag() - arrowSize, 0); 2022 | triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0); 2023 | pop(); 2024 | } 2025 | 2026 | 2027 | /*~~~ https://p5js.org/reference/#/p5.Vector/sub ~~~*/ 2028 | 2029 | // red vector - blue vector = purple vector 2030 | function draw() { 2031 | background(240); 2032 | 2033 | let v0 = createVector(0, 0); 2034 | let v1 = createVector(70, 50); 2035 | drawArrow(v0, v1, 'red'); 2036 | 2037 | let v2 = createVector(mouseX, mouseY); 2038 | drawArrow(v0, v2, 'blue'); 2039 | 2040 | let v3 = p5.Vector.sub(v1, v2); 2041 | drawArrow(v2, v3, 'purple'); 2042 | } 2043 | 2044 | // draw an arrow for a vector at a given base position 2045 | function drawArrow(base, vec, myColor) { 2046 | push(); 2047 | stroke(myColor); 2048 | strokeWeight(3); 2049 | fill(myColor); 2050 | translate(base.x, base.y); 2051 | line(0, 0, vec.x, vec.y); 2052 | rotate(vec.heading()); 2053 | let arrowSize = 7; 2054 | translate(vec.mag() - arrowSize, 0); 2055 | triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0); 2056 | pop(); 2057 | } 2058 | 2059 | /*~~~ https://p5js.org/reference/#/p5.Vector/mult ~~~*/ 2060 | 2061 | function draw() { 2062 | background(240); 2063 | 2064 | let v0 = createVector(50, 50); 2065 | let v1 = createVector(25, -25); 2066 | drawArrow(v0, v1, 'red'); 2067 | 2068 | let num = map(mouseX, 0, width, -2, 2, true); 2069 | let v2 = p5.Vector.mult(v1, num); 2070 | drawArrow(v0, v2, 'blue'); 2071 | 2072 | noStroke(); 2073 | fill(0); 2074 | text('multiplied by ' + num.toFixed(2), 5, 90); 2075 | } 2076 | 2077 | // draw an arrow for a vector at a given base position 2078 | function drawArrow(base, vec, myColor) { 2079 | push(); 2080 | stroke(myColor); 2081 | strokeWeight(3); 2082 | fill(myColor); 2083 | translate(base.x, base.y); 2084 | line(0, 0, vec.x, vec.y); 2085 | rotate(vec.heading()); 2086 | let arrowSize = 7; 2087 | translate(vec.mag() - arrowSize, 0); 2088 | triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0); 2089 | pop(); 2090 | } 2091 | 2092 | /*~~~ https://p5js.org/reference/#/p5.Vector/div ~~~*/ 2093 | 2094 | function draw() { 2095 | background(240); 2096 | 2097 | let v0 = createVector(0, 100); 2098 | let v1 = createVector(50, -50); 2099 | drawArrow(v0, v1, 'red'); 2100 | 2101 | let num = map(mouseX, 0, width, 10, 0.5, true); 2102 | let v2 = p5.Vector.div(v1, num); 2103 | drawArrow(v0, v2, 'blue'); 2104 | 2105 | noStroke(); 2106 | fill(0); 2107 | text('divided by ' + num.toFixed(2), 10, 90); 2108 | } 2109 | 2110 | // draw an arrow for a vector at a given base position 2111 | function drawArrow(base, vec, myColor) { 2112 | push(); 2113 | stroke(myColor); 2114 | strokeWeight(3); 2115 | fill(myColor); 2116 | translate(base.x, base.y); 2117 | line(0, 0, vec.x, vec.y); 2118 | rotate(vec.heading()); 2119 | let arrowSize = 7; 2120 | translate(vec.mag() - arrowSize, 0); 2121 | triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0); 2122 | pop(); 2123 | } 2124 | 2125 | /*~~~ https://p5js.org/reference/#/p5.Vector/mag ~~~*/ 2126 | 2127 | function draw() { 2128 | background(240); 2129 | 2130 | let v0 = createVector(0, 0); 2131 | let v1 = createVector(mouseX, mouseY); 2132 | drawArrow(v0, v1, 'black'); 2133 | 2134 | noStroke(); 2135 | fill(0); 2136 | text('vector length: \n' + v1.mag().toFixed(2), 10, 70); 2137 | } 2138 | 2139 | // draw an arrow for a vector at a given base position 2140 | function drawArrow(base, vec, myColor) { 2141 | push(); 2142 | stroke(myColor); 2143 | strokeWeight(3); 2144 | fill(myColor); 2145 | translate(base.x, base.y); 2146 | line(0, 0, vec.x, vec.y); 2147 | rotate(vec.heading()); 2148 | let arrowSize = 7; 2149 | translate(vec.mag() - arrowSize, 0); 2150 | triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0); 2151 | pop(); 2152 | } 2153 | 2154 | 2155 | /*~~~ https://p5js.org/reference/#/p5.Vector/magSq ~~~*/ 2156 | 2157 | function draw() { 2158 | background(240); 2159 | 2160 | let v0 = createVector(0, 0); 2161 | let v1 = createVector(mouseX, mouseY); 2162 | drawArrow(v0, v1, 'black'); 2163 | 2164 | noStroke(); 2165 | fill(0); 2166 | text('vector length squared: \n' + v1.magSq().toFixed(2), 10, 45); 2167 | } 2168 | 2169 | // draw an arrow for a vector at a given base position 2170 | function drawArrow(base, vec, myColor) { 2171 | push(); 2172 | stroke(myColor); 2173 | strokeWeight(3); 2174 | fill(myColor); 2175 | translate(base.x, base.y); 2176 | line(0, 0, vec.x, vec.y); 2177 | rotate(vec.heading()); 2178 | let arrowSize = 7; 2179 | translate(vec.mag() - arrowSize, 0); 2180 | triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0); 2181 | pop(); 2182 | } 2183 | 2184 | /*~~~ https://p5js.org/reference/#/p5.Vector/dist ~~~*/ 2185 | 2186 | function draw() { 2187 | background(240); 2188 | 2189 | let v0 = createVector(0, 0); 2190 | 2191 | let v1 = createVector(70, 50); 2192 | drawArrow(v0, v1, 'red'); 2193 | 2194 | let v2 = createVector(mouseX, mouseY); 2195 | drawArrow(v0, v2, 'blue'); 2196 | 2197 | noStroke(); 2198 | fill(0); 2199 | text('distance between vectors: \n' + v2.dist(v1).toFixed(2), 5, 50); 2200 | } 2201 | 2202 | // draw an arrow for a vector at a given base position 2203 | function drawArrow(base, vec, myColor) { 2204 | push(); 2205 | stroke(myColor); 2206 | strokeWeight(3); 2207 | fill(myColor); 2208 | translate(base.x, base.y); 2209 | line(0, 0, vec.x, vec.y); 2210 | rotate(vec.heading()); 2211 | let arrowSize = 7; 2212 | translate(vec.mag() - arrowSize, 0); 2213 | triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0); 2214 | pop(); 2215 | } 2216 | 2217 | /*~~~ https://p5js.org/reference/#/p5.Vector/normalize ~~~*/ 2218 | 2219 | function draw() { 2220 | background(240); 2221 | 2222 | let v0 = createVector(50, 50); 2223 | let v1 = createVector(mouseX - 50, mouseY - 50); 2224 | 2225 | drawArrow(v0, v1, 'red'); 2226 | v1.normalize(); 2227 | drawArrow(v0, v1.mult(35), 'blue'); 2228 | 2229 | noFill(); 2230 | ellipse(50, 50, 35 * 2); 2231 | } 2232 | 2233 | // draw an arrow for a vector at a given base position 2234 | function drawArrow(base, vec, myColor) { 2235 | push(); 2236 | stroke(myColor); 2237 | strokeWeight(3); 2238 | fill(myColor); 2239 | translate(base.x, base.y); 2240 | line(0, 0, vec.x, vec.y); 2241 | rotate(vec.heading()); 2242 | let arrowSize = 7; 2243 | translate(vec.mag() - arrowSize, 0); 2244 | triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0); 2245 | pop(); 2246 | } 2247 | 2248 | /*~~~ https://p5js.org/reference/#/p5.Vector/limit ~~~*/ 2249 | 2250 | function draw() { 2251 | background(240); 2252 | 2253 | let v0 = createVector(50, 50); 2254 | let v1 = createVector(mouseX - 50, mouseY - 50); 2255 | 2256 | drawArrow(v0, v1, 'red'); 2257 | drawArrow(v0, v1.limit(35), 'blue'); 2258 | 2259 | noFill(); 2260 | ellipse(50, 50, 35 * 2); 2261 | } 2262 | 2263 | // draw an arrow for a vector at a given base position 2264 | function drawArrow(base, vec, myColor) { 2265 | push(); 2266 | stroke(myColor); 2267 | strokeWeight(3); 2268 | fill(myColor); 2269 | translate(base.x, base.y); 2270 | line(0, 0, vec.x, vec.y); 2271 | rotate(vec.heading()); 2272 | let arrowSize = 7; 2273 | translate(vec.mag() - arrowSize, 0); 2274 | triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0); 2275 | pop(); 2276 | } 2277 | 2278 | /*~~~ https://p5js.org/reference/#/p5.Vector/setMag ~~~*/ 2279 | 2280 | 2281 | function draw() { 2282 | background(240); 2283 | 2284 | let v0 = createVector(0, 0); 2285 | let v1 = createVector(50, 50); 2286 | 2287 | drawArrow(v0, v1, 'red'); 2288 | 2289 | let length = map(mouseX, 0, width, 0, 141, true); 2290 | v1.setMag(length); 2291 | drawArrow(v0, v1, 'blue'); 2292 | 2293 | noStroke(); 2294 | fill(0); 2295 | text('magnitude set to: \n' + length.toFixed(2), 10, 70); 2296 | } 2297 | 2298 | // draw an arrow for a vector at a given base position 2299 | function drawArrow(base, vec, myColor) { 2300 | push(); 2301 | stroke(myColor); 2302 | strokeWeight(3); 2303 | fill(myColor); 2304 | translate(base.x, base.y); 2305 | line(0, 0, vec.x, vec.y); 2306 | rotate(vec.heading()); 2307 | let arrowSize = 7; 2308 | translate(vec.mag() - arrowSize, 0); 2309 | triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0); 2310 | pop(); 2311 | } 2312 | 2313 | /*~~~ https://p5js.org/reference/#/p5.Vector/heading ~~~*/ 2314 | 2315 | function draw() { 2316 | background(240); 2317 | 2318 | let v0 = createVector(50, 50); 2319 | let v1 = createVector(mouseX - 50, mouseY - 50); 2320 | 2321 | drawArrow(v0, v1, 'black'); 2322 | 2323 | let myHeading = v1.heading(); 2324 | noStroke(); 2325 | fill(0); 2326 | text( 2327 | 'vector heading: \n' + 2328 | myHeading.toFixed(2) + 2329 | ' radians or \n' + 2330 | degrees(myHeading).toFixed(2) + 2331 | ' degrees', 2332 | 10, 2333 | 50, 2334 | ); 2335 | } 2336 | 2337 | // draw an arrow for a vector at a given base position 2338 | function drawArrow(base, vec, myColor) { 2339 | push(); 2340 | stroke(myColor); 2341 | strokeWeight(3); 2342 | fill(myColor); 2343 | translate(base.x, base.y); 2344 | line(0, 0, vec.x, vec.y); 2345 | rotate(vec.heading()); 2346 | let arrowSize = 7; 2347 | translate(vec.mag() - arrowSize, 0); 2348 | triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0); 2349 | pop(); 2350 | } 2351 | 2352 | /*~~~ https://p5js.org/reference/#/p5.Vector/rotate ~~~*/ 2353 | 2354 | let angle = 0; 2355 | function draw() { 2356 | background(240); 2357 | 2358 | let v0 = createVector(50, 50); 2359 | let v1 = createVector(50, 0); 2360 | 2361 | drawArrow(v0, v1.rotate(angle), 'black'); 2362 | angle += 0.01; 2363 | } 2364 | 2365 | // draw an arrow for a vector at a given base position 2366 | function drawArrow(base, vec, myColor) { 2367 | push(); 2368 | stroke(myColor); 2369 | strokeWeight(3); 2370 | fill(myColor); 2371 | translate(base.x, base.y); 2372 | line(0, 0, vec.x, vec.y); 2373 | rotate(vec.heading()); 2374 | let arrowSize = 7; 2375 | translate(vec.mag() - arrowSize, 0); 2376 | triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0); 2377 | pop(); 2378 | } 2379 | 2380 | 2381 | /*~~~ https://p5js.org/reference/#/p5.Vector/angleBetween ~~~*/ 2382 | 2383 | function draw() { 2384 | background(240); 2385 | let v0 = createVector(50, 50); 2386 | 2387 | let v1 = createVector(50, 0); 2388 | drawArrow(v0, v1, 'red'); 2389 | 2390 | let v2 = createVector(mouseX - 50, mouseY - 50); 2391 | drawArrow(v0, v2, 'blue'); 2392 | 2393 | let angleBetween = v1.angleBetween(v2); 2394 | noStroke(); 2395 | fill(0); 2396 | text( 2397 | 'angle between: \n' + 2398 | angleBetween.toFixed(2) + 2399 | '\n radians or \n' + 2400 | degrees(angleBetween).toFixed(2) + 2401 | ' degrees', 2402 | 10, 2403 | 50, 2404 | ); 2405 | } 2406 | 2407 | // draw an arrow for a vector at a given base position 2408 | function drawArrow(base, vec, myColor) { 2409 | push(); 2410 | stroke(myColor); 2411 | strokeWeight(3); 2412 | fill(myColor); 2413 | translate(base.x, base.y); 2414 | line(0, 0, vec.x, vec.y); 2415 | rotate(vec.heading()); 2416 | let arrowSize = 7; 2417 | translate(vec.mag() - arrowSize, 0); 2418 | triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0); 2419 | pop(); 2420 | } 2421 | 2422 | 2423 | /*~~~ https://p5js.org/reference/#/p5.Vector/lerp ~~~*/ 2424 | 2425 | let step = 0.01; 2426 | let amount = 0; 2427 | 2428 | function draw() { 2429 | background(240); 2430 | let v0 = createVector(0, 0); 2431 | 2432 | let v1 = createVector(mouseX, mouseY); 2433 | drawArrow(v0, v1, 'red'); 2434 | 2435 | let v2 = createVector(90, 90); 2436 | drawArrow(v0, v2, 'blue'); 2437 | 2438 | if (amount > 1 || amount < 0) { 2439 | step *= -1; 2440 | } 2441 | amount += step; 2442 | let v3 = p5.Vector.lerp(v1, v2, amount); 2443 | 2444 | drawArrow(v0, v3, 'purple'); 2445 | } 2446 | 2447 | // draw an arrow for a vector at a given base position 2448 | function drawArrow(base, vec, myColor) { 2449 | push(); 2450 | stroke(myColor); 2451 | strokeWeight(3); 2452 | fill(myColor); 2453 | translate(base.x, base.y); 2454 | line(0, 0, vec.x, vec.y); 2455 | rotate(vec.heading()); 2456 | let arrowSize = 7; 2457 | translate(vec.mag() - arrowSize, 0); 2458 | triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0); 2459 | pop(); 2460 | } 2461 | 2462 | 2463 | /*~~~ https://p5js.org/reference/#/p5.Vector/reflect ~~~*/ 2464 | 2465 | function draw() { 2466 | background(240); 2467 | 2468 | let v0 = createVector(0, 0); 2469 | let v1 = createVector(mouseX, mouseY); 2470 | drawArrow(v0, v1, 'red'); 2471 | 2472 | let n = createVector(0, -30); 2473 | drawArrow(v1, n, 'blue'); 2474 | 2475 | let r = v1.copy(); 2476 | r.reflect(n); 2477 | drawArrow(v1, r, 'purple'); 2478 | } 2479 | 2480 | // draw an arrow for a vector at a given base position 2481 | function drawArrow(base, vec, myColor) { 2482 | push(); 2483 | stroke(myColor); 2484 | strokeWeight(3); 2485 | fill(myColor); 2486 | translate(base.x, base.y); 2487 | line(0, 0, vec.x, vec.y); 2488 | rotate(vec.heading()); 2489 | let arrowSize = 7; 2490 | translate(vec.mag() - arrowSize, 0); 2491 | triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0); 2492 | pop(); 2493 | } 2494 | 2495 | /*~~~ https://p5js.org/reference/#/p5.Vector/fromAngle ~~~*/ 2496 | 2497 | function draw() { 2498 | background(200); 2499 | 2500 | // Create a variable, proportional to the mouseX, 2501 | // varying from 0-360, to represent an angle in degrees. 2502 | let myDegrees = map(mouseX, 0, width, 0, 360); 2503 | 2504 | // Display that variable in an onscreen text. 2505 | // (Note the nfc() function to truncate additional decimal places, 2506 | // and the "\xB0" character for the degree symbol.) 2507 | let readout = 'angle = ' + myDegrees.toFixed(1) + '\xB0'; 2508 | noStroke(); 2509 | fill(0); 2510 | text(readout, 5, 15); 2511 | 2512 | // Create a p5.Vector using the fromAngle function, 2513 | // and extract its x and y components. 2514 | let v = p5.Vector.fromAngle(radians(myDegrees), 30); 2515 | let vx = v.x; 2516 | let vy = v.y; 2517 | 2518 | push(); 2519 | translate(width / 2, height / 2); 2520 | noFill(); 2521 | stroke(150); 2522 | line(0, 0, 30, 0); 2523 | stroke(0); 2524 | line(0, 0, vx, vy); 2525 | pop(); 2526 | } 2527 | 2528 | /*~~~ https://p5js.org/reference/#/p5.Vector/random2D ~~~*/ 2529 | 2530 | function setup() { 2531 | frameRate(1); 2532 | } 2533 | 2534 | function draw() { 2535 | background(240); 2536 | 2537 | let v0 = createVector(50, 50); 2538 | let v1 = p5.Vector.random2D(); 2539 | drawArrow(v0, v1.mult(50), 'black'); 2540 | } 2541 | 2542 | // draw an arrow for a vector at a given base position 2543 | function drawArrow(base, vec, myColor) { 2544 | push(); 2545 | stroke(myColor); 2546 | strokeWeight(3); 2547 | fill(myColor); 2548 | translate(base.x, base.y); 2549 | line(0, 0, vec.x, vec.y); 2550 | rotate(vec.heading()); 2551 | let arrowSize = 7; 2552 | translate(vec.mag() - arrowSize, 0); 2553 | triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0); 2554 | pop(); 2555 | } 2556 | 2557 | /*~~~ https://p5js.org/reference/#/p5/textAlign ~~~*/ 2558 | 2559 | fill(0); 2560 | noStroke(); 2561 | textSize(16); 2562 | textAlign(RIGHT); 2563 | text('ABCD', 50, 30); 2564 | textAlign(CENTER); 2565 | text('EFGH', 50, 50); 2566 | textAlign(LEFT); 2567 | text('IJKL', 50, 70); 2568 | 2569 | /*~~~ https://p5js.org/reference/#/p5/textAlign ~~~*/ 2570 | 2571 | fill(0); 2572 | 2573 | textSize(16); 2574 | strokeWeight(0.5); 2575 | 2576 | line(0, 12, width, 12); 2577 | textAlign(CENTER, TOP); 2578 | text('TOP', width/2, 12); 2579 | 2580 | line(0, 37, width, 37); 2581 | textAlign(CENTER, CENTER); 2582 | text('CENTER', width/2, 37); 2583 | 2584 | line(0, 62, width, 62); 2585 | textAlign(CENTER, BASELINE); 2586 | text('BASELINE', width/2, 62); 2587 | 2588 | line(0, 87, width, 87); 2589 | textAlign(CENTER, BOTTOM); 2590 | text('BOTTOM', width/2, 87); 2591 | 2592 | 2593 | /*~~~ https://p5js.org/reference/#/p5/textLeading ~~~*/ 2594 | 2595 | fill(0); 2596 | noStroke(); 2597 | let lines = 'L1\nL2\nL3'; // "\n" is a "new line" character 2598 | textSize(12); 2599 | 2600 | textLeading(10); 2601 | text(lines, 10, 25); 2602 | 2603 | textLeading(20); 2604 | text(lines, 40, 25); 2605 | 2606 | textLeading(30); 2607 | text(lines, 70, 25); 2608 | 2609 | /*~~~ https://p5js.org/reference/#/p5/textSize ~~~*/ 2610 | 2611 | fill(0); 2612 | noStroke(); 2613 | textSize(12); 2614 | text('Font Size 12', 10, 30); 2615 | textSize(14); 2616 | text('Font Size 14', 10, 60); 2617 | textSize(16); 2618 | text('Font Size 16', 10, 90); 2619 | 2620 | /*~~~ https://p5js.org/reference/#/p5/textStyle ~~~*/ 2621 | 2622 | fill(0); 2623 | noStroke(); 2624 | textSize(12); 2625 | textStyle(NORMAL); 2626 | text('Font Style Normal', 10, 15); 2627 | textStyle(ITALIC); 2628 | text('Font Style Italic', 10, 40); 2629 | textStyle(BOLD); 2630 | text('Font Style Bold', 10, 65); 2631 | textStyle(BOLDITALIC); 2632 | text('Font Style Bold Italic', 10, 90); 2633 | 2634 | /*~~~ https://p5js.org/reference/#/p5/textWidth ~~~*/ 2635 | 2636 | textSize(28); 2637 | fill(0); 2638 | let aChar = 'P'; 2639 | let cWidth = textWidth(aChar); 2640 | text(aChar, 0, 40); 2641 | line(cWidth, 0, cWidth, 50); 2642 | 2643 | let aString = 'p5.js'; 2644 | let sWidth = textWidth(aString); 2645 | text(aString, 0, 85); 2646 | line(sWidth, 50, sWidth, 100); 2647 | 2648 | /*~~~ https://p5js.org/reference/#/p5/textAscent ~~~*/ 2649 | 2650 | fill(0); 2651 | let base = height * 0.75; 2652 | let scalar = 0.8; // Different for each font 2653 | 2654 | textSize(32); // Set initial text size 2655 | let asc = textAscent() * scalar; // Calc ascent 2656 | line(0, base - asc, width, base - asc); 2657 | text('dp', 0, base); // Draw text on baseline 2658 | 2659 | textSize(64); // Increase text size 2660 | asc = textAscent() * scalar; // Recalc ascent 2661 | line(40, base - asc, width, base - asc); 2662 | text('dp', 40, base); // Draw text on baseline 2663 | 2664 | /*~~~ https://p5js.org/reference/#/p5/textDescent ~~~*/ 2665 | 2666 | fill(0); 2667 | let base = height * 0.75; 2668 | let scalar = 0.8; // Different for each font 2669 | 2670 | textSize(32); // Set initial text size 2671 | let desc = textDescent() * scalar; // Calc ascent 2672 | line(0, base + desc, width, base + desc); 2673 | text('dp', 0, base); // Draw text on baseline 2674 | 2675 | textSize(64); // Increase text size 2676 | desc = textDescent() * scalar; // Recalc ascent 2677 | line(40, base + desc, width, base + desc); 2678 | text('dp', 40, base); // Draw text on baseline 2679 | 2680 | /*~~~ https://p5js.org/reference/#/p5/randomSeed ~~~*/ 2681 | 2682 | randomSeed(99); 2683 | for (let i = 0; i < 100; i++) { 2684 | let r = random(0, 255); 2685 | stroke(r); 2686 | line(i, 0, i, 100); 2687 | } 2688 | 2689 | /*~~~ https://p5js.org/reference/#/p5/random ~~~*/ 2690 | 2691 | for (let i = 0; i < 100; i++) { 2692 | let r = random(50); 2693 | stroke(r * 5); 2694 | line(50, i, 50 + r, i); 2695 | } 2696 | 2697 | /*~~~ https://p5js.org/reference/#/p5/random ~~~*/ 2698 | 2699 | for (let i = 0; i < 100; i++) { 2700 | let r = random(-50, 50); 2701 | line(50, i, 50 + r, i); 2702 | } 2703 | 2704 | /*~~~ https://p5js.org/reference/#/p5/random ~~~*/ 2705 | 2706 | // Get a random element from an array using the random(Array) syntax 2707 | let words = ['apple', 'bear', 'cat', 'dog']; 2708 | let word = random(words); // select random word 2709 | noStroke(); 2710 | fill(0); 2711 | text(word, 10, 50); // draw the word 2712 | 2713 | /*~~~ https://p5js.org/reference/#/p5/randomGaussian ~~~*/ 2714 | 2715 | for (let y = 0; y < 100; y++) { 2716 | let x = randomGaussian(50, 15); 2717 | line(50, y, x, y); 2718 | } 2719 | 2720 | /*~~~ https://p5js.org/reference/#/p5/randomGaussian ~~~*/ 2721 | 2722 | let distribution = new Array(360); 2723 | function setup() { 2724 | createCanvas(100, 100); 2725 | for (let i = 0; i < distribution.length; i++) { 2726 | distribution[i] = floor(randomGaussian(0, 15)); 2727 | } 2728 | } 2729 | function draw() { 2730 | background(204); 2731 | translate(width / 2, width / 2); 2732 | for (let i = 0; i < distribution.length; i++) { 2733 | rotate(TWO_PI / distribution.length); 2734 | stroke(0); 2735 | let dist = abs(distribution[i]); 2736 | line(0, 0, dist, 0); 2737 | } 2738 | } 2739 | 2740 | /*~~~ https://p5js.org/reference/#/p5/noise ~~~*/ 2741 | 2742 | let xoff = 0.0; 2743 | 2744 | function draw() { 2745 | background(204); 2746 | xoff = xoff + 0.01; 2747 | let n = noise(xoff) * width; 2748 | line(n, 0, n, height); 2749 | } 2750 | 2751 | /*~~~ https://p5js.org/reference/#/p5/noise ~~~*/ 2752 | 2753 | let noiseScale=0.02; 2754 | 2755 | function draw() { 2756 | background(0); 2757 | for (let x=0; x < width; x++) { 2758 | let noiseVal = noise((mouseX+x)*noiseScale, mouseY*noiseScale); 2759 | stroke(noiseVal*255); 2760 | line(x, mouseY+noiseVal*80, x, height); 2761 | } 2762 | } 2763 | 2764 | /*~~~ https://p5js.org/reference/#/p5/noiseDetail ~~~*/ 2765 | 2766 | let noiseVal; 2767 | let noiseScale = 0.02; 2768 | function setup() { 2769 | createCanvas(100, 100); 2770 | } 2771 | function draw() { 2772 | background(0); 2773 | for (let y = 0; y < height; y++) { 2774 | for (let x = 0; x < width / 2; x++) { 2775 | noiseDetail(2, 0.2); 2776 | noiseVal = noise((mouseX + x) * noiseScale, (mouseY + y) * noiseScale); 2777 | stroke(noiseVal * 255); 2778 | point(x, y); 2779 | noiseDetail(8, 0.65); 2780 | noiseVal = noise( 2781 | (mouseX + x + width / 2) * noiseScale, 2782 | (mouseY + y) * noiseScale 2783 | ); 2784 | stroke(noiseVal * 255); 2785 | point(x + width / 2, y); 2786 | } 2787 | } 2788 | } 2789 | 2790 | /*~~~ https://p5js.org/reference/#/p5/noiseSeed ~~~*/ 2791 | 2792 | 2793 | let xoff = 0.0; 2794 | 2795 | function setup() { 2796 | noiseSeed(99); 2797 | stroke(0, 10); 2798 | } 2799 | 2800 | function draw() { 2801 | xoff = xoff + .01; 2802 | let n = noise(xoff) * width; 2803 | line(n, 0, n, height); 2804 | } --------------------------------------------------------------------------------