npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@korkje/p5-react

v0.7.0

Published

Simple p5.js wrapper for React

Downloads

20

Readme

p5-react

npm NPM

Simple p5.js wrapper for React.

npm add @korkje/p5-react
import React from "react";
import P5React, { Sketch } from "@korkje/p5-react";

const sketch: Sketch = p => {
    p.setup = () => p.createCanvas(100, 100);
    p.draw = () => {
        p.background(0);
        p.ellipse(50, 50, 80, 80);
    };
};

export default () => <P5React sketch={sketch} />;

Usage

For most use cases, you will find that this works just like normal p5.js in instance mode. However, there are some extra features and differences worth mentioning.

Parent

The parent element of the canvas is passed to the sketch as the second argument. This can be useful, e.g. if you want the canvas to fill the parent element.

const sketch: Sketch = (p, parent) => {
    p.setup = () => p.createCanvas(
        parent.clientWidth,
        parent.clientHeight,
    );
    // ...
};

export default () => <P5React
    sketch={sketch}
    style={{ width: "100px", height: "100px" }}
/>;

The parent element is also set on the p5.js instance, if you prefer to use that.

const sketch: Sketch = p => {
    p.setup = () => p.createCanvas(
        p.parent.clientWidth,
        p.parent.clientHeight,
    );
    // ...
};

Cleanup

When the P5React component is unmounted, the p5.js instance is automatically removed. But you might also want to clean up other resources on unmount, e.g. timers set in the sketch. You can do this by returning a cleanup function.

const sketch: Sketch = p => {
    const handle = setInterval(() => {
        // ...
    }, 1000);

    return () => clearInterval(handle);
};

Props

P5React supports passing props into the sketch. For TypeScript users, props are defined as a type argument to the Sketch type, and they are made available on the p5.js instance as p.props.


const sketch: Sketch<{
    count: number;
    w: number;
    h: number;
}> = p => {
    p.setup = () => p.createCanvas(p.props.w, p.props.h);

    p.draw = () => {
        p.background(0);
        p.text(p.props.count, 50, 50);
    };
};

export default () => {
    const [count, setCount] = useState(0);

    return <>
        <P5React sketch={sketch} props={{ count, w: 100, h: 100 }} />
        <button onClick={() => setCount(ps => ps + 1)}>
            Increment
        </button>
    </>;
};

Effect

Similar to React's useEffect, you can use p.effect to run code when props change (and initially). The first argument is a function that takes in the new props object and an initial flag (which is true on the first run), and the second argument is an optional array of dependencies (keys of the props object).

const sketch: Sketch<{
    count: number;
    w: number;
    h: number;
}> = p => {
    p.setup = () => p.createCanvas(p.props.w, p.props.h);

    p.draw = () => {
        p.background(0);
        p.text(p.props.count, 50, 50);
    };

    p.effect(({ w, h }, initial) => {
        if (!initial) {
            p.resizeCanvas(w, h);
        }
    }, ["w", "h"]);
};

The second argument may also be a function that takes in the new props object and returns an array of dependencies, if you are so inclined.

const sketch: Sketch<{
    arr: number[];
}> = p => {
    p.setup = () => p.createCanvas(100, 100);

    p.effect(({ arr }) => {
        console.log(`Array length: ${arr.length}`);
    }, ({ arr }) => [arr.length]);
};

Note that on subsequent runs, p.props will only be updated after all effects have run. This means that in your effects, you can access both new and old props, if needed.

Dependencies

By default, props are updated when any of the prop values change according to shallow comparison, in fact Object.values is used to create a dependency array for the internal useEffect hook that updates props (and runs effects).

You may alter this behavior by supplying a deps array to the P5React component. This array will be passed to the internal useEffect hook instead of the prop values.

This could be useful if you e.g. are creating and passing object props, and only want to update when a specific property of the object changes, though I would consider memoizing the object in that case.

export default () => {
    const size = getSketchSize("my-sketch"); // { w: 100, h: 100 }

    return (
        <P5React
            sketch={sketch}
            props={{ size }}
            deps={[size.w, size.h]}
        />
    );
};

Using memoization, the deps array could be omitted.

export default () => {
    const size = useMemo(() => getSketchSize("my-sketch"), []);

    return <P5React sketch={sketch} props={{ size }} />;
};

Memoization

The P5React component isn't memoized, but it should be very inexpensive if used correctly. It contains two useEffect hooks, one for creating the p5.js instance and one for updating props. The first is only run when the sketch prop changes, and the second is only run when any of the props (or deps if supplied) change.

p5.sound

If you want to use p5.sound, be aware that it expects p5 to be globally available before it is imported. You can achieve this by doing something like this:

import p5 from "p5";
(window as any).p5 = p5;
await import("p5/lib/addons/p5.sound");