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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@p5-wrapper/react

v5.0.4

Published

A wrapper component that allows you to utilise P5 sketches within React apps.

Downloads

43,768

Readme

@P5-wrapper/react

@P5-wrapper/react

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

Breaking changes in v5:

  1. Component rename

    • ReactP5WrapperP5Canvas
  2. Types

    • P5WrapperPropsP5CanvasProps
    • P5WrapperClassNameCanvasContainerClassName
  3. Peer dependencies

    • p5 >= 2.0.0
    • react >= 19.0.0
    • react-dom >= 19.0.0

If you are still using version 4, you can find the documentation here.

Installation

[npm|yarn|pnpm] [install|add] p5 @p5-wrapper/react

p5, react and react-dom are peer dependencies and must be installed in your project.

Install the p5 type definitions as a dev dependency:

[npm|yarn|pnpm] [install|add] -D @types/p5

For Next.js applications, use our Next.js dynamic implementation:

[npm|yarn|pnpm] [install|add] p5 @p5-wrapper/next @p5-wrapper/react

See the Next.js dynamic implementation docs for further details.

Demo & Examples

A live demo can be viewed at P5-wrapper.github.io/react. The repository also contains example sketches.

To run the examples locally:

git clone [email protected]:<your username>/react.git
cd react
pnpm install
pnpm preview

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

Usage

JavaScript

import * as React from "react";
import { P5Canvas } from "@p5-wrapper/react";

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 <P5Canvas sketch={sketch} />;
}

TypeScript

The sketch prop is a function that receives a p5 instance. You can type it using either the Sketch type or the P5CanvasInstance type:

import * as React from "react";
import { P5Canvas, Sketch } from "@p5-wrapper/react";

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 <P5Canvas sketch={sketch} />;
}

Sketch auto-types the p5 argument for you. If you prefer a regular function declaration, you can use P5CanvasInstance directly:

import { P5CanvasInstance } from "@p5-wrapper/react";

function sketch(p5: P5CanvasInstance) {
  /* ... */
}

Using abstracted setup and draw functions

If you prefer to split your sketch logic into separate functions:

import * as React from "react";
import { P5Canvas } from "@p5-wrapper/react";

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 <P5Canvas sketch={sketch} />;
}

Props

You can pass any custom props to P5Canvas. These are forwarded to the updateWithProps method if you define it in your sketch.

Reacting to props

updateWithProps is called on initial render and whenever the props change:

import { P5Canvas } from "@p5-wrapper/react";
import React, { useEffect, useState } from "react";

function sketch(p5) {
  let rotation = 0;

  p5.setup = () => p5.createCanvas(600, 400, p5.WEBGL);

  p5.updateWithProps = props => {
    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 <P5Canvas sketch={sketch} rotation={rotation} />;
}

Typed props with generics

Use generics so that props passed to updateWithProps are properly typed:

import { P5Canvas, Sketch, SketchProps } from "@p5-wrapper/react";
import React, { useEffect, useState } from "react";

type MySketchProps = SketchProps & {
  rotation: number;
};

const sketch: Sketch<MySketchProps> = p5 => {
  let rotation = 0;

  p5.setup = () => p5.createCanvas(600, 400, p5.WEBGL);

  p5.updateWithProps = props => {
    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 <P5Canvas sketch={sketch} rotation={rotation} />;
}

You can also write MySketchProps as an interface:

interface MySketchProps extends SketchProps {
  rotation: number;
}

And if you prefer P5CanvasInstance over Sketch, generics work the same way:

function sketch(p5: P5CanvasInstance<MySketchProps>) {
  /* ... */
}

Custom updaters

If you need to bridge React state updates from within the p5 lifecycle — for example, reading frameCount or other instance properties to drive React state — you can use the updater prop. It receives a callback that runs alongside updateWithProps on every props change, but lives in the React layer:

import { P5Canvas, Sketch, SketchProps, Updater } from "@p5-wrapper/react";
import React, { useCallback, useState } from "react";

type MySketchProps = SketchProps & { rotation: number };

const sketch: Sketch<MySketchProps> = p5 => {
  let rotation = 0;

  p5.setup = () => p5.createCanvas(600, 400, p5.WEBGL);

  p5.updateWithProps = props => {
    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);
  const [frameCount, setFrameCount] = useState(0);

  const updater = useCallback<Updater<MySketchProps>>((instance, props) => {
    setFrameCount(instance.frameCount);
  }, []);

  return <P5Canvas sketch={sketch} updater={updater} rotation={rotation} />;
}

The updater callback receives the p5 instance and the current sketch props. It is not passed to updateWithProps, so it does not leak React concerns into your sketch logic.

Children

To render a component on top of the sketch, add it as a child of P5Canvas and use the exported CanvasContainerClassName constant to style the overlay via CSS.

import { CanvasContainerClassName, P5Canvas } from "@p5-wrapper/react";
import styled, { createGlobalStyle } from "styled-components";

const GlobalWrapperStyles = createGlobalStyle`
  .${CanvasContainerClassName} {
    position: relative;
  }
`;

const StyledCentredText = styled.span`
  .${CanvasContainerClassName} & {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    color: white;
    font-size: 2rem;
    margin: 0;
    text-align: center;
  }
`;

export function App() {
  const [rotation, setRotation] = useState(0);

  useEffect(() => {
    const interval = setInterval(
      () => setRotation(rotation => rotation + 100),
      100
    );

    return () => {
      clearInterval(interval);
    };
  }, []);

  return (
    <Fragment>
      <GlobalWrapperStyles />
      <P5Canvas sketch={sketch} rotation={rotation}>
        <StyledCentredText>Hello world!</StyledCentredText>
      </P5Canvas>
    </Fragment>
  );
}

You can use any CSS-in-JS library or plain CSS — just target the wrapper class as your root selector.

Fallback UIs

If the sketch prop is undefined, you can provide a fallback UI:

import * as React from "react";
import { P5Canvas } from "@p5-wrapper/react";

function sketchOne(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();
  };
}

function sketchTwo(p5) {
  p5.setup = () => p5.createCanvas(600, 400, p5.WEBGL);
  p5.draw = () => {
    p5.background(500);
    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() {
  const [sketch, setSketch] = React.useState(undefined);
  const chooseNothing = () => setSketch(undefined);
  const chooseSketchOne = () => setSketch(sketchOne);
  const chooseSketchTwo = () => setSketch(sketchTwo);

  return (
    <>
      <ul>
        <li>
          <button onClick={chooseNothing}>Choose nothing</button>
        </li>
        <li>
          <button onClick={chooseSketchOne}>Choose sketch 1</button>
        </li>
        <li>
          <button onClick={chooseSketchTwo}>Choose sketch 2</button>
        </li>
      </ul>
      <P5Canvas fallback={<h1>No sketch selected yet.</h1>} sketch={sketch} />
    </>
  );
}

When no sketch is selected, the fallback UI is shown. Selecting a sketch replaces it with the canvas.

Error and Loading UIs

You can pass error and loading props to customise what is shown when something goes wrong or while the component is loading.

Error UIs

Pass a function to the error prop to handle errors thrown within the sketch or its children:

import * as React from "react";
import { P5Canvas, P5CanvasInstance } from "@p5-wrapper/react";

function ErrorChild() {
  throw new Error("oops");
}

function ErrorUI(error: unknown) {
  if (error instanceof Error) {
    return <p>An error occured: {error.message}</p>;
  }

  return <p>An unknown error occured: {String(error)}</p>;
}

function sketch(p5: P5CanvasInstance) {
  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 (
    <P5Canvas sketch={sketch} error={ErrorUI}>
      <ErrorChild />
    </P5Canvas>
  );
}

JS/TS allow you to throw any value, not just Error instances. Always check error instanceof Error before accessing .message.

Loading UIs

Pass a function to the loading prop to show a custom UI while the component is being lazy loaded:

import * as React from "react";
import { P5Canvas, P5CanvasInstance } from "@p5-wrapper/react";

function LoadingUI() {
  return <p>The sketch is being loaded.</p>;
}

function sketch(p5: P5CanvasInstance) {
  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 <P5Canvas sketch={sketch} loading={LoadingUI} />;
}

P5 plugins and constructors

Since P5 is used in instance mode, plugins are not loaded automatically. You need to set p5 on the window object before importing the plugin:

import * as p5 from "p5";
import { P5Canvas, Sketch } from "@p5-wrapper/react";
import React, { useEffect, useState } from "react";

(window as any).p5 = p5;

await import("p5/lib/addons/p5.sound");

const sketch: Sketch = p5 => {
  let song: p5.SoundFile;
  let button: p5.Element;

  p5.setup = () => {
    p5.createCanvas(600, 400, p5.WEBGL);
    p5.background(255, 0, 0);
    button = p5.createButton("Toggle audio");

    button.mousePressed(() => {
      if (!song) {
        const songPath = "/piano.mp3";
        song = p5.loadSound(
          songPath,
          () => {
            song.play();
          },
          () => {
            console.error(
              `Could not load the requested sound file ${songPath}`
            );
          }
        );
        return;
      }

      if (!song.isPlaying()) {
        song.play();
        return;
      }

      song.pause();
    });
  };

  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 default function App() {
  return <P5Canvas sketch={sketch} />;
}

Key points:

  • p5 must be set on window before importing the plugin.
  • Audio must be triggered by a user action (e.g. a button click) — browsers block autoplay.
  • Safari blocks audio from all tabs by default; users may need to change this in their browser settings.

Note: This example requires top level await, dynamic imports and the stream API (HTTPS only).

In instance mode, constructors are accessed via p5.constructor instead of the global p5 namespace:

| Constructor | Global mode | Instance mode | | ----------- | ----------- | ----------------------- | | Vector | p5.Vector | p5.constructor.Vector | | Envelope | p5.Envelope | p5.constructor.Envelope |

For example, to get a random 2D vector, call p5.constructor.Vector.random2D() instead of p5.Vector.random2D().

Development

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

To build, watch and serve the examples (which also watches the component source):

pnpm preview