react-p5-wrapper
    TypeScript icon, indicating that this package has built-in type declarations

    3.3.0 • Public • Published

    react-p5-wrapper

    A component to integrate P5.js sketches into React apps.

    Demo & Examples

    Live demo

    A live demo can be viewed at P5-wrapper.github.io/react.

    Examples

    The repository contains further examples.

    To try them out for yourself, run the following:

    git clone git@github.com:P5-wrapper/react.git
    cd react
    npm install
    npm start

    Then just open http://localhost:3001 in a browser.

    Installation

    NPM

      npm install react-p5-wrapper

    Yarn

      yarn add react-p5-wrapper

    Usage

    Javascript

    import React from "react";
    import { ReactP5Wrapper } from "react-p5-wrapper";
    
    function sketch(p5) {
      p5.setup = () => p5.createCanvas(600, 400, p5.WEBGL);
    
      p5.draw = () => {
        p5.background(250);
        p5.normalMaterial();
        p5.push();
        p5.rotateZ(p5.frameCount * 0.01);
        p5.rotateX(p5.frameCount * 0.01);
        p5.rotateY(p5.frameCount * 0.01);
        p5.plane(100);
        p5.pop();
      };
    }
    
    export function App() {
      return <ReactP5Wrapper sketch={sketch} />;
    }

    TypeScript

    TypeScript sketches can be declared in two different ways, below you will find two ways to declare a sketch, both examples do the exact same thing.

    In short though, the ReactP5Wrapper component requires you to pass a sketch prop. The sketch prop is typed as a (instance: P5Instance): void;. As long as the function declaration of your sketch is set to take in a single argument of type P5Instance, you are good to go!

    Option 1: Declaring a sketch using the P5Instance type

    import React from "react";
    import { ReactP5Wrapper, P5Instance } from "react-p5-wrapper";
    
    function sketch(p5: P5Instance) {
      p5.setup = () => p5.createCanvas(600, 400, p5.WEBGL);
    
      p5.draw = () => {
        p5.background(250);
        p5.normalMaterial();
        p5.push();
        p5.rotateZ(p5.frameCount * 0.01);
        p5.rotateX(p5.frameCount * 0.01);
        p5.rotateY(p5.frameCount * 0.01);
        p5.plane(100);
        p5.pop();
      };
    }
    
    export function App() {
      return <ReactP5Wrapper sketch={sketch} />;
    }

    Option 2: Declaring a sketch using the Sketch type

    Using the Sketch type has one nice benefit over using P5Instance and that is that the p5 argument passed to the sketch function is auto-typed as a P5Instance for you.

    Sidenote:

    In general it comes down to personal preference as to how you declare your sketches and there is nothing wrong with using the P5Instance manually in a regular function declaration.

    import React from "react";
    import { ReactP5Wrapper, Sketch } from "react-p5-wrapper";
    
    const sketch: Sketch = p5 => {
      p5.setup = () => p5.createCanvas(600, 400, p5.WEBGL);
    
      p5.draw = () => {
        p5.background(250);
        p5.normalMaterial();
        p5.push();
        p5.rotateZ(p5.frameCount * 0.01);
        p5.rotateX(p5.frameCount * 0.01);
        p5.rotateY(p5.frameCount * 0.01);
        p5.plane(100);
        p5.pop();
      };
    };
    
    export function App() {
      return <ReactP5Wrapper sketch={sketch} />;
    }

    TypeScript Generics

    We also support the use of Generics to add type definitions for your props. If used, the props will be properly typed when the props are passed to the updateWithProps method.

    To utilise generics you can use one of two methods. In both of the examples below, we create a custom internal type called MySketchProps which is a union type of SketchProps and a custom type which has a rotation key applied to it.

    Sidenote:

    We could also write the MySketchProps type as an interface to do exactly the same thing if that is to your personal preference:

    interface MySketchProps extends SketchProps {
      rotation: number;
    }

    This means, in these examples, that when the rotation prop that is provided as part of the props passed to the updateWithProps function, it will be correctly typed as a number.

    Usage with the P5Instance type
    import React, { useState, useEffect } from "react";
    import { ReactP5Wrapper, P5Instance, SketchProps } from "react-p5-wrapper";
    
    type MySketchProps = SketchProps & {
      rotation: number;
    };
    
    function sketch(p5: P5Instance<MySketchProps>) {
      let rotation = 0;
    
      p5.setup = () => p5.createCanvas(600, 400, p5.WEBGL);
    
      p5.updateWithProps = props => {
        if (props.rotation) {
          rotation = (props.rotation * Math.PI) / 180;
        }
      };
    
      p5.draw = () => {
        p5.background(100);
        p5.normalMaterial();
        p5.noStroke();
        p5.push();
        p5.rotateY(rotation);
        p5.box(100);
        p5.pop();
      };
    }
    
    export function App() {
      const [rotation, setRotation] = useState(0);
    
      useEffect(() => {
        const interval = setInterval(
          () => setRotation(rotation => rotation + 100),
          100
        );
    
        return () => {
          clearInterval(interval);
        };
      }, []);
    
      return <ReactP5Wrapper sketch={sketch} rotation={rotation} />;
    }
    Usage with the Sketch type
    import React, { useState, useEffect } from "react";
    import { ReactP5Wrapper, Sketch, SketchProps } from "react-p5-wrapper";
    
    type MySketchProps = SketchProps & {
      rotation: number;
    };
    
    const sketch: Sketch<MySketchProps> = p5 => {
      let rotation = 0;
    
      p5.setup = () => p5.createCanvas(600, 400, p5.WEBGL);
    
      p5.updateWithProps = props => {
        if (props.rotation) {
          rotation = (props.rotation * Math.PI) / 180;
        }
      };
    
      p5.draw = () => {
        p5.background(100);
        p5.normalMaterial();
        p5.noStroke();
        p5.push();
        p5.rotateY(rotation);
        p5.box(100);
        p5.pop();
      };
    };
    
    export function App() {
      const [rotation, setRotation] = useState(0);
    
      useEffect(() => {
        const interval = setInterval(
          () => setRotation(rotation => rotation + 100),
          100
        );
    
        return () => {
          clearInterval(interval);
        };
      }, []);
    
      return <ReactP5Wrapper sketch={sketch} rotation={rotation} />;
    }

    Using abstracted setup and draw functions

    import React from "react";
    import { ReactP5Wrapper } from "react-p5-wrapper";
    
    function setup(p5) {
      return () => {
        p5.createCanvas(600, 400, p5.WEBGL);
      };
    }
    
    function draw(p5) {
      return () => {
        p5.background(250);
        p5.normalMaterial();
        p5.push();
        p5.rotateZ(p5.frameCount * 0.01);
        p5.rotateX(p5.frameCount * 0.01);
        p5.rotateY(p5.frameCount * 0.01);
        p5.plane(100);
        p5.pop();
      };
    }
    
    function sketch(p5) {
      p5.setup = setup(p5);
      p5.draw = draw(p5);
    }
    
    export function App() {
      return <ReactP5Wrapper sketch={sketch} />;
    }

    Props

    The only required property of the ReactP5Wrapper component is the sketch prop. The sketch prop is a function that will be passed a p5 instance to use for rendering your sketches as shown in the usage section above.

    You can pass as many custom props as you want to the ReactP5Wrapper component and these will all be passed into the updateWithProps method if you have defined it within your sketch.

    Reacting to props

    In the below example you see the updateWithProps method being used. This is called when the component initially renders and when the props passed to the wrapper are changed, if it is set within your sketch. This way we can render our ReactP5Wrapper component and react to component prop changes directly within our sketches!

    import React, { useState, useEffect } from "react";
    import { ReactP5Wrapper } from "react-p5-wrapper";
    
    function sketch(p5) {
      let rotation = 0;
    
      p5.setup = () => p5.createCanvas(600, 400, p5.WEBGL);
    
      p5.updateWithProps = props => {
        if (props.rotation) {
          rotation = (props.rotation * Math.PI) / 180;
        }
      };
    
      p5.draw = () => {
        p5.background(100);
        p5.normalMaterial();
        p5.noStroke();
        p5.push();
        p5.rotateY(rotation);
        p5.box(100);
        p5.pop();
      };
    }
    
    export function App() {
      const [rotation, setRotation] = useState(0);
    
      useEffect(() => {
        const interval = setInterval(
          () => setRotation(rotation => rotation + 100),
          100
        );
    
        return () => {
          clearInterval(interval);
        };
      }, []);
    
      return <ReactP5Wrapper sketch={sketch} rotation={rotation} />;
    }

    Children

    To render a component on top of the sketch, simply add it as a child of the ReactP5Wrapper component.

    Development

    NOTE: The source code for the component is in the src directory.

    To build, watch and serve the examples which will also watch the component source, run:

      npm start

    Install

    npm i react-p5-wrapper

    DownloadsWeekly Downloads

    1,250

    Version

    3.3.0

    License

    MIT

    Unpacked Size

    16.9 kB

    Total Files

    8

    Last publish

    Collaborators

    • nerocor
    • jamesrweb