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

react-zdog

v1.2.2

Published

React-fiber renderer for zdog

Downloads

441,104

Readme

npm install zdog react-zdog
# or
yarn add zdog react-zdog

npm npm

react-zdog is a declarative abstraction of zdog, a cute pseudo 3d-engine. Doing zdog in React allows you to break up your scene graph into declarative, re-usable components with clean, reactive semantics. Try a live demo here.

How it looks like

import ReactDOM from "react-dom";
import React from "react";
import { Illustration, Shape } from "react-zdog";

ReactDOM.render(
  <Illustration zoom={8}>
    <Shape stroke={20} color="lightblue" rotate={{ x: Math.PI }} />
  </Illustration>,
  document.getElementById("root")
);

Illustration

The Illustration object is your portal into zdog. It forwards unreserved properties to the internal Zdog.Illustration instance. The component auto adjusts to re-size changes and fills out the wrapping relative/absolute parent.

<Illustration element="svg" /> // Can be either 'svg' or 'canvas'
  • element: Sets the graphics rendering DOM Element. Can be either 'svg' or 'canvas'. Default is "svg"
  • frameloop: Determins the render loop behavior, Can be either 'always' or 'demand'. default is 'always'.
  • pointerEvents: enables pointer events on zdog elements if set to true. Default is False.
  • style: styles for main renderer dom elemeent container.
  • onDragStart: callback on illustration's on drag start event listener
  • onDragMove: callback on illustration's on drag move event listener
  • onDragEnd: callback on illustration's on drag end event listener

And all the other props you will pass will be attached to illustration object. So any other properties or methods that you wanna set on illustration can be passed as prop as it is.

Hooks

All hooks can only be used inside the Illustration element because they rely on context updates!

useRender(callback, dependencies=[])

If you're running effects that need to get updated every frame, useRender gives you access to the render-loop.

import { useRender } from "react-zdog";

function Spin({ children }) {
  const ref = useRef(undefined);
  useRender((t) => (ref.current.rotate.y += 0.01));
  return <Anchor ref={ref}>{children}</Anchor>;
}

useZdog()

Gives you access to the underlying state-model.

import { useZdog } from 'react-zdog'

function MyComponent() {
  const {
    illu,             // The parent Zdog.Illustration object
    scene,            // The Zdog.Anchor object that's being used as the default scene
    size,             // Current canvas size
  } = useZdog()

useInvalidate()

Gives you access to function that updates the one scene frame on each call. It is useful only if you're setting frameloop props on Illustration component as demand

function MyComponent() {
  const invalidate = useInvalidate()
  const boxRef = useRef()
  const rotate = () => {
    boxRef.current.rotate.x += 0.03;
    boxRef.current.rotate.y += 0.03; //this will update underlying javascript object
    invalidate() //But you need to call invalidate to render the changes on screen
  }

  return (
    <Box
      ref={boxRef}
      {/* ...other props */}
    />
  )}

Pointer Events

React-zdog supports the Click, Pointer Move, Pointer Enter and Pointer Leave events on Zdog elemets. To use pointer events just enable the pointer events by setting pointerEvents prop to true on Illustration component.

<Illustration pointerEvents={true} />

and use onClick, onPointerMove, onPointerEnter and OnPointerLeave on any zdog element.

const onClick = (e, ele) => {
  //runs when user clicks on box
};

const onPointerMove = (e, ele) => {
  //runs when user moves pointer over box
};

const onPointerEnter = (e, ele) => {
  //runs when user's pointer enters the box
};

const onPointerLeave = (e, ele) => {
  //runs when user's pointer leaves the box
};

return (
  <Box
    onClick={onClick}
    onPointerMove={onPointerMove}
    onPointerEnter={onPointerEnter}
    onPointerLeave={onPointerLeave}
  />
);

Examples

import React, { useRef, useEffect } from 'react';
import { Illustration, useRender, useInvalidate, Box } from 'react-zdog';

// RotatingCube Component
const RotatingCube = () => {
const boxRef = useRef();

// Use the useRender hook to continuously update the rotation
useRender(() => {
if (boxRef.current) {
boxRef.current.rotate.x += 0.03;
boxRef.current.rotate.y += 0.03;
}
});

    return (
      <Box
        ref={boxRef}
        width={50}
        height={50}
        depth={50}
        color="#E44"
        leftFace="#4E4"
        rightFace="#44E"
        topFace="#EE4"
        bottomFace="#4EE"
      />
    );

};

// App Component
const App = () => {
return (
<Illustration zoom={4}>
<RotatingCube />
</Illustration>
);
};

export default App;
import React, { useRef, useState } from 'react';
import { Illustration, useRender, Box } from 'react-zdog';

// InteractiveCube Component
const InteractiveCube = () => {
const [isClicked, setIsClicked] = useState(false);

const colorsBeforeClick = {
  main: "#E44",
  left: "#4E4",
  right: "#44E",
  top: "#EE4",
  bottom: "#4EE"
};

const colorsAfterClick = {
  main: "#FF5733",
  left: "#33FF57",
  right: "#3357FF",
  top: "#FF33A1",
  bottom: "#A133FF"
};

const currentColors = isClicked ? colorsAfterClick : colorsBeforeClick;

const handleBoxClick = () => {
  setIsClicked(!isClicked);
};


return (
  <Box
    width={50}
    height={50}
    depth={50}
    color={currentColors.main}
    leftFace={currentColors.left}
    rightFace={currentColors.right}
    topFace={currentColors.top}
    bottomFace={currentColors.bottom}
    onClick={handleBoxClick}
  />
);
};

// App Component
const App = () => {
return (
  <Illustration pointerEvents={true} zoom={4}>
    <InteractiveCube />
  </Illustration>
);
};

export default App;
import React, { useRef, useEffect } from "react";
import { Illustration, useInvalidate, Box } from "react-zdog";

// RotatingCube Component
const RotatingCube = () => {
  const boxRef = useRef();
  const invalidate = useInvalidate();

  useEffect(() => {
    const animate = () => {
      if (boxRef.current) {
        boxRef.current.rotate.x += 0.03;
        boxRef.current.rotate.y += 0.03;
        invalidate(); // Manually trigger a render
      }
    };

    const intervalId = setInterval(animate, 1000); // only renders the scene graph one a second instead of 60 times per second

    return () => intervalId && clearInterval(intervalId);
  }, [invalidate]);

  return (
    <Box
      ref={boxRef}
      width={50}
      height={50}
      depth={50}
      color="#E44"
      leftFace="#4E4"
      rightFace="#44E"
      topFace="#EE4"
      bottomFace="#4EE"
    />
  );
};

// App Component
const App = () => {
  return (
    <Illustration zoom={4} frameloop="demand">
      <RotatingCube />
    </Illustration>
  );
};

export default App;

Roadmap

  • Create more Examples
  • add More events support

Contributing

Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.