React-zdog: A Declarative Abstraction of zdog for React
Introduction
React-zdog is a declarative abstraction of zdog, a pseudo 3D-engine. It allows you to break up your scene graph into declarative, reusable components with clean, reactive semantics. With react-zdog, you can create interactive 3D graphics in React, making it easy to integrate 3D elements into your React applications.
To get started with react-zdog, you’ll need to install the library using npm or yarn:
npm install zdog react-zdog
or
yarn add zdog react-zdog
Basic Usage
The basic usage of react-zdog involves creating an Illustration
component and adding Shape
components to it. Here’s an example:
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")
);
This code creates an Illustration
component with a zoom
property set to 8, and adds a Shape
component to it with a stroke
property set to 20, a color
property set to “lightblue”, and a rotate
property set to { x: Math.PI }
.
Illustration
The Illustration
component is the main entry point for react-zdog. It forwards unreserved properties to the internal Zdog.Illustration instance. You can customize the Illustration
component by passing props to it.
Here are some props you can pass to the Illustration
component:
element
: Sets the graphics rendering DOM Element. Can be either ‘svg’ or ‘canvas’. Default is “svg”frameloop
: Determines 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 element container.onDragStart
: Callback on illustration’s on drag start event listeneronDragMove
: Callback on illustration’s on drag move event listeneronDragEnd
: Callback on illustration’s on drag end event listener
Hooks
React-zdog provides several hooks that you can use to interact with the Illustration
component.
useRender(callback, dependencies=[])
The useRender
hook gives you access to the render loop. You can use it to update the scene graph or perform other tasks that need to be executed every frame.
Here’s an example:
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()
The useZdog
hook gives you access to the underlying state model of the Illustration
component.
Here’s an example:
import { useZdog } from "react-zdog";
function MyComponent() {
const { illu, scene, size } = useZdog();
// Use the illu, scene, and size variables to interact with the illustration
}
useInvalidate()
The useInvalidate
hook gives you access to a function that updates the scene graph on each call. You can use it to manually trigger a render.
Here’s an example:
import { useInvalidate } from "react-zdog";
function MyComponent() {
const invalidate = useInvalidate();
const boxRef = useRef();
const rotate = () => {
boxRef.current.rotate.x += 0.03;
boxRef.current.rotate.y += 0.03;
invalidate(); // Manually trigger a render
};
return (
<Box
ref={boxRef}
width={50}
height={50}
depth={50}
color="#E44"
leftFace="#4E4"
rightFace="#44E"
topFace="#EE4"
bottomFace="#4EE"
/>
);
}
Pointer Events
React-zdog supports pointer events on zdog elements. You can enable pointer events by setting the pointerEvents
prop to true
on the Illustration
component.
Here’s an example:
<Illustration pointerEvents={true} />
You can also use the onClick
, onPointerMove
, onPointerEnter
, and onPointerLeave
props to handle pointer events on individual zdog elements.
Here’s an example:
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
Here are some examples of using react-zdog:
Basic Example
This example shows how to create a rotating cube using react-zdog:
import React, { useRef, useEffect } from "react";
import { Illustration, useRender, Box } from "react-zdog";
const RotatingCube = () => {
const boxRef = useRef();
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"
/>
);
};
const App = () => {
return (
<Illustration zoom={4}>
<RotatingCube />
</Illustration>
);
};
Pointer Events Example
This example shows how to use pointer events with react-zdog:
import React, { useRef, useState } from "react";
import { Illustration, Box } from "react-zdog";
const InteractiveCube = () => {
const [isClicked, setIsClicked] = useState(false);
const handleBoxClick = () => {
setIsClicked(!isClicked);
};
return (
<Box
width={50}
height={50}
depth={50}
color={isClicked ? "#FF5733" : "#E44"}
leftFace={isClicked ? "#33FF57" : "#4E4"}
rightFace={isClicked ? "#3357FF" : "#44E"}
topFace={isClicked ? "#FF33A1" : "#EE4"}
bottomFace={isClicked ? "#A133FF" : "#4EE"}
onClick={handleBoxClick}
/>
);
};
const App = () => {
return (
<Illustration pointerEvents={true} zoom={4}>
<InteractiveCube />
</Illustration>
);
};
On Demand Rendering Example
This example shows how to use on demand rendering with react-zdog:
import React, { useRef, useEffect } from "react";
import { Illustration, useInvalidate, Box } from "react-zdog";
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"
/>
);
};
const App = () => {
return (
<Illustration zoom={4} frameloop="demand">
<RotatingCube />
</Illustration>
);
};
Conclusion
React-zdog is a powerful library that allows you to create declarative, reusable components with clean, reactive semantics for 3D graphics in React. By breaking up your scene graph into components, you can easily create interactive 3D graphics in React applications. With its simple API and powerful features, react-zdog makes it easy to integrate 3D elements into your React projects. Give it a try and start creating stunning 3D graphics in React today!