GithubHelp home page GithubHelp logo

lingdong- / q5xjs Goto Github PK

View Code? Open in Web Editor NEW
524.0 19.0 25.0 372 KB

A small and fast alternative (experimental) implementation of p5.js

Home Page: https://q5xjs.netlify.app/

License: The Unlicense

JavaScript 100.00%
p5js 2d js-library creative-coding

q5xjs's Introduction

q5.js

q5.js is a small and fast alternative (experimental) implementation of p5.js, 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:

  • lightweight: 33KB minified (p5.min.js 1.1.9 is 800+KB). (Smaller libraries have smaller carbon footprint!)
  • fast: It does so by being a thinner wrapper on Canvas/Web API, skipping parameter validation, and using faster algorithms wherever possible.

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.

To explore supported functionalities, check out these q5 renditions of the standard p5 examples on this page.

q5.js can also be used with the p5 online Web Editor (editor.p5js.org). Example.

Here's a quick sampling of q5.js usage (in case you're not familiar with p5):

new Q5("global"); //initialize q5
// alternatively use `const q=new Q5()` to contain all q5 functions inside a namespace.

// the rest just looks like a regular p5.js sketch:

function draw() {
  background(237, 34, 93);
  fill(0);

  if (mouseIsPressed) {
    ellipse(50, 50, 50, 50);
  } else {
    rect(25, 25, 50, 50);
  }
};

q5.js is currently experimental; Feel free to point out any issues.

Download

⬇︎
    q5.js    
65KB
⬇︎
q5.min.js
33KB

To use, put this line in your HTML:

<script src="q5.min.js"></script>

or via CDN:

<script src="https://cdn.jsdelivr.net/gh/LingDong-/q5xjs/q5.min.js"></script>

Table of Contents

Motivation

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:

It gets stuff drawn onto the screen quick and easy!

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.

Where 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?

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.

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.

q5.js aims to:

  • ✅ be mostly code-compatible with p5.js.
  • ✅ keep being very simple and lightweight.
  • ✅ be a very thin wrapper around Canvas/Web API: think of it as a collection of syntactic sugars.
  • ✅ be fast.

q5.js does NOT not aim to:

  • ❌ replace p5.js.
  • ❌ be beginner friendly.
  • ❌ simulate completely identical behavior for current and future versions of p5.js.

Key Differences with p5

I. "Namespaced Mode" 🏷️

p5

In p5.js, all p5 functions are in the global namespace, unless you use "instance" mode, like this:

let sketch = function(p) {
  p.setup = function() {
    p.createCanvas(100,100);
  };
  p.draw = function(){
    p.background(0);
  }
};

let myp5 = new p5(sketch);

This does solve the problem of global namespace pollution, but there're still some inconveniences:

  • The extra wrapping of the sketch function makes code look complex. (Flat is better than nested!)
  • Variables inside sketch can no longer be accessed via browser console, which makes it less convenient for debugging.

q5

q5 introduces "namespace" mode in place of global/instance mode:

let q5 = new Q5();

q5.setup = function(){
  q5.createCanvas(100,100);
}

q5.draw = function(){
  q5.background(0);
}

You can call the namespace whatever you like. You can even get multiple instances of q5 running on the same page easily.

let q5 = new Q5();
let q6 = new Q5();

q5.setup = function(){
  q5.background(255);
}

q6.setup = function(){
  q6.background(0);
}

Of course, you can still have the good old global namespacing via Q5("global"), making q5.js mostly code-compatible with existing p5 sketches:

new Q5("global");

function setup(){
  background(0);
}

function draw(){
  
}

II. q5 Functions Anywhere 🌏

p5

In p5.js, most functions can only be used inside setup(), draw() etc. Otherwise, you might see something like this:

Did you just try to use p5.js's stroke() function? If so, you may want to move it 
into your sketch's setup() function.

q5

q5.js functions can be used anywhere, it doesn't really matter!

In fact, you can do away with the setup function all together. Just write your initialization routines at the top level.

For example, you can now directly run examples on p5js.org/reference without wrapping them in setup manually:

new Q5("global");

noStroke();
let c = color(0, 126, 255, 102);
fill(c);
rect(15, 15, 35, 70);

You can even roll out your own animation loop in place of draw(). Good for mixing with other libraries too.

new Q5("global");

fill(255,0,0);

function myLoop(){
  requestAnimationFrame(myLoop);
  rect(15, 15, 35, 70);
}
myLoop();

Though of course the setup() and draw() functions are still there if you need them.

III. HES 🐞

p5

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.

q5

q5.js does not help with your bad code. It WILL break and/or crash if you feed it the wrong stuff.

IV. No Magic 🎩

p5

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)

q5

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.

Extra Features

q5.js provides following features that are not in p5.js:

  • randomExponential() in addition to randomGaussian(): a random distribution that resembles exponential decay.
  • curveAlpha(): manipulate the α parameter of Catmull-Rom curves.
  • relRotationX, relRotationY and relRotationZ: Similar to rotationX/Y/Z, but are relative to the orientation of the mobile device.

Using p5 Addons

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.

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:

<script src="q5.min.js"></script>
<script src="q5.p5acl.js"></script>

<!-- followed by p5 addons -->
<script src="p5.sound.js"></script>
<script src="p5.xyz.js"></script>

After which you'll be able to access functionalities from p5 addons under a global addons object, for example:

let sfx = addons.loadSound("music.mp3");

Benchmarks

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.

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.

p5.js version used is 1.1.9.

Operation on 1024x1024 image p5.js q5.js
tinting 20FPS 35FPS
blurring(11px) 0FPS 40FPS *
thresholding 10FPS 40FPS *
grayscaling 10FPS 50FPS *
inverting 10FPS 50FPS *
opaque 20FPS 60FPS
erode/dilate 5FPS 9FPS
Misc p5.js q5.js
Generating 10,000 randomGaussian() sample 10FPS 20FPS
Calling noiseSeed() 1,000 times 10FPS 60FPS
Generate 10,000 (random) colors with color(r,g,b) 5FPS 60FPS
Rotate a Vector 1,000,000 times 13FPS 60FPS

* Only for browsers that support CanvasRenderingContext2D.filter (75% of all 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.

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.

q5xjs's People

Contributors

0xflotus avatar endershadow8 avatar golanlevin avatar lingdong- avatar michaelpaulukonis avatar peilingjiang avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

q5xjs's Issues

Q5.Image() has problems with a Source Rectangle

Hey Ling,

Absolutely amazing project this is. I've been using Q5 in my own project because it's incredible. When creating a loading bar I ran into a strange issue that seemed related to Q5. Q5.Image() does not (properly) handle the source parameters in the way that P5 does.

The package configuration of my project contains Q5XJS ^0.0.5 and P5 ^1.4.0. I've reproduced this issue with the latest version of this repo too.

The image should load in from left to right. When using this code on Q5XJS it seems to stretch the image instead. I've provided code that you can run within the P5 Web Editor.

let img;
let start = Date.now(); 

function setup() {
  createCanvas(400, 400);
  img = loadImage('https://i.imgur.com/FjTgVcE.jpeg');
}

function draw() {
  background(220);
  
  let progress = (Date.now() - start) / 1000.0 % 1;
  
  let loadingbarPosition = {
     x: 0,
     y: 0 
  };

  let loadingbarSize = {
     width: 128,
     height: 128
  }

 if(img) image(   
    img, 
    loadingbarPosition.x, 
    loadingbarPosition.y,
    loadingbarSize.width  * progress, 
    loadingbarSize.height,
    0, // sx
    0, // sy
    img.width * progress, // sw
    img.height // sh
  );
}

Publish to npm?

Hi, are you considering publishing the package to npm? It would be easier for people to integrate it into projects then. Thanks!

`loadFont()` and `callback` not working properly.

loadFont() and its callback argument don't seem to work.
Loaded font is only available once the browser has cached the file, which normally happens when you open the sketch for the second time. This behaviour is even present when loadFont() is called within the preload() function.
Also the callback argument is not implemented.

Many issues fixed! Add me as a project maintainer :)

I solved issues #7 #9 #14 #17 #20 #21 and #22

Check out all the updates I made to q5xjs! I'd like to add all these changes to your q5xjs repo. Please add me as a project maintainer. :)

https://github.com/quinton-ashley/q5.js

  • registerMethod functionality for supporting p5.js addons such as p5play!
  • automatic global instance creation, can also be user instantiated as well with new Q5('global') like with the previous version of q5xjs
  • p5 instance mode support
  • add q5 canvas to a container element with new Q5('global', parentElem) or new Q5(parentElem)
  • angleMode functionality
  • loadSound function that returns a barebones sound object with play, pause, and setVolume methods
  • fixed pixelDensity bugs
  • fixed text function bug not displaying "0" (falsey value in JS)
  • fixed keyPressed repeating key presses
  • made instanceof checks work for q5.js objects of the Color, Vector, and Image classes
  • the push and pop functions now save and restore style properties like rectMode and strokeWeight
  • nf (number format) function, which is used in p5play
  • pow function alias to Math.pow
  • prevented text stroke from being drawn if the user did not specify a stroke (p5.js behavior)
  • fixed Vector.lerp implementation
  • fixed mouseX and mouseY not updating when the mouse is outside the canvas

Scaling issues with pixeldensity and background on Q5("global");

Hello!

This is related to a previously closed issue #6.

When using Q5("global") and pixelDensity(2), I still see the background unscaled.
See my code below and the output:

new Q5("global");


function setup() {
  createCanvas(700,700);
  pixelDensity(window.devicePixelRatio);
}

function draw() {
  background(100);

  fill(150,0,0);
  rect(350,350,100,100);
  
}
Captura de pantalla 2024-03-24 a las 20 10 30

Many thanks!

Targetting a specific canvas ?

Hello !

I was wondering if q5 was able to target a specific (already existing) canvas in a web page ?
This is a restriction in p5js that would be nice to be able to lift in q5 in my opinion.

random isn't random

Go to examples --> random III: q5 returns same value "apple", not random. p5 is random. same for the other random examples (I + II), they always render the same "not" random graphics.

I browsed through your code to see where this originated from, but didn't see anything, so I guess p5.random is missing.
(btw: make_site.js is a superb hack!).

Shape quality

Hey, thanks a lot for the lib, I'm testing it on a project and the js size decrease considerably.
So far the only problem that I've found is the quality of the shapes, they seem a bit more blurred and not as sharp as with p5

Any idea what can be causing this?
not sure if is related with pixelDensity, but I notice that this also doesn't work the same way as in p5

Thanks!

Bug in Vector.lerp() implementation

There seems to be a bug with the implementation of Vector.lerp() function

$.Vector.lerp= function(v,u,t){return new $.Vector(v.x * (1-t) + u.x * t,
                                                   v.y = v.y * (1-t) + u.y * t,
                                                   v.z = v.z * (1-t) + u.z * t);}

The function change the value of y and z coordinate of the first param vector, which don't seems to be intended (it should not modify any value of the first param vector)

Benchmarking

Hi, just want to reach out here about benchmarking the performance of this library against p5.js. I'm currently maintaining a benchmarking repo for p5.js here (it is extracted from the core repo a short while ago and partly rewritten) and would like to hear if you are interested in using it for benchmarking performance.

It is a slow work in progress and I only work on it when I have time left over but I have some plans for it. The setup uses benchmark.js + Karma and runs on headless Firefox and Chrome. To achieve consistency and comparability it is also run on a CI environment before the result is published at https://limzykenneth.github.io/p5-benchmark/

I originally work on it to have something I can benchmark my WebAssembly implementation of some p5.js functions so the ability to benchmark different libraries are already in consideration. If you are interested in being included, let me know so and also which areas/functions you want to be benchmarked against the main library. 😄

add support for use as an ESM module

All you would have to do is prepend export default to the main file and it would me much easier to use with npm managed projects. you could name it 'q5.esm.js' or something, but I would recommend pointing the package.json main filed to this version and it would work out of the box with node.

registerMethod implementation needed for p5play compatibility!

Hi I think this library is really great but I noticed there's no registerMethod implementation. Lots of p5 libraries rely on this feature, including mine, p5.play!

I think making q5 compatible with p5.play would be perfect because my library only needs the 2D p5 functions. p5js is bloated and I think my users would especially benefit from q5 on mobile.

Let me know if you're currently working on a registerMethod implementation. If not I will try doing it.

q5 + p5 sound

The q5 has been a very important tool in my processes. While p5 was a first step, q5 seems to lead me towards a better understanding of the processes and the possibility of being less and less dependent on a specific library. Thank you!

I'm trying to use the q5 together with the p5 sound and I followed everything that was indicated in the README: I included and linked the q5.p5acl.js in the correct sequence:

<script src="https://cdn.jsdelivr.net/gh/LingDong-/q5xjs/q5.min.js"></script>
<script src="./q5.p5acl.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/addons/p5.sound.min.js"></script>

I was able to load the audio file using let mySound = addons.loadSound('soundfile.mp3'), but I can't use the same principle as p5 to play the sound: mySound.play().

This is my entire code:

let q5 = new Q5()
let mySound = addons.loadSound("Damscray_DancingTiger.mp3");

q5.setup = () => {
  q5.createCanvas(100, 100)
  q5.background(0)
}

q5.canvas.addEventListener('click', () => {
  console.log('click')
  mySound.play()
})

And this is the error on the console:
InvalidStateError: Failed to construct 'AudioWorkletNode': AudioWorkletNode cannot be created: AudioWorklet does not have a valid AudioWorkletGlobalScope. Load a script via audioWorklet.addModule() first. at undefined:2:97382

Am I making a mistake or is some additional code needed?

q5.pop() does not restore fill properties

The following code will draw two ellipses every loop.
Expected: The first ellipse filled, the second no fill.
Got: Using q5 both ellipses will have no fill.
( With p5.js the expected behavior is shown )

It appears that q5.pop() doesn't restore a bunch of variables such as ._noFill, and ._noStroke.
The context's .fillStyle is restored properly, but is then unused;

code:

q5 = new Q5();
q5.setup = function () {
q5.createCanvas(q5.windowWidth, q5.windowHeight);
q5.fill('#000000');
};

q5.draw = function () {
q5.clear();
q5.ellipse(100, 100, 30, 30);
q5.push();
q5.noFill();
q5.ellipse(200, 100, 30, 30);
q5.pop();
};

It appears that q5.pop() doesn't restore a bunch of variables such as ._noFill, and ._noStroke.
The context's .fillStyle is restored properly, but is then unused;

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.