Recent Post:
Categories:
August 16, 2024
313
Think you know it all?
Take quiz!code
const PricingDemo = () => {
const [value, setValue] = React.useState(3427);
return (
<ThreeDWraper title="PRICING" link="/blog/6f683bd5-e52e-40d9-8d9c-8f0629901bf9">
<div className="flex flex-col gap-4 w-full">
{/* On Click */}
<div className="flex flex-row flex-wrap gap-4">
<p>On Click</p>
{[200, 400, 2600, 3100, 2639, 1243, 5437, 3242].map((val) => (
<Button key={val} onClick={() => setValue(val)}>
{val}
</Button>
))}
</div>
{/* On Hover */}
<div className="hidden md:flex flex-row flex-wrap gap-4">
<p>On Hover</p>
{[200, 400, 2600, 3100, 2639, 1243, 5437, 3242].map((val) => (
<Button key={val} onMouseEnter={() => setValue(val)} onMouseLeave={() => setValue(3457)}>
{val}
</Button>
))}
</div>
</div>
</ThreeDWraper>
);
};
In this blog, I will walk you through how I created an interactive 3D Pricing Demo using Three.js, @react-three/fiber, and @react-three/drei. This project dynamically updates the 3D text rendered on a canvas based on user interactions such as button clicks and hover events.
We'll break down the setup, components, and rendering process step by step to help you create a similar 3D experience for your own projects.
To get started, install the necessary dependencies for the project:
code
npm install three @react-three/fiber @react-three/drei maath
We also rely on Three.js's powerful utilities for rendering and the maath library for easing animations.
1. Counter Component
The Counter component renders a series of 3D numbers that update based on the value passed to them. The numbers rotate on the y axis with smooth animation using maath for easing.
code
import { Text, useMask } from '@react-three/drei';
import * as THREE from 'three';
import { easing } from 'maath';
import { useRef } from 'react';
import { useFrame } from '@react-three/fiber';
const Counter = ({ index, value, speed = 0.1 }: { index: number; value: number; speed?: number }) => {
const ref = useRef<THREE.Group | null>(null);
const stencil = useMask(1);
useFrame((state, delta) => {
if (ref.current) {
easing.damp(ref.current.position, 'y', value * -2, speed, delta);
}
});
return (
<group position-x={index * 1.1} ref={ref}>
{[0, 1, 2, 3, 4, 5, 6, 7, 8, 9].map((number) => (
<Text key={number} position={[-2.2, number * 2, 2]} fontSize={2}>
{number}
<meshBasicMaterial {...stencil} />
</Text>
))}
</group>
);
};
Key Points:
useRef is used to store references to the group of numbers.
useFrame allows the numbers to move and rotate smoothly in sync with the animation frame, creating a dynamic effect.
The Price component manages the display of a number based on user interactions. It uses the Counter component to display each digit of the price in 3D.
code
const Price = ({ value, currency = '₹', ...props }: { value: number; currency?: string; [key: string]: any }) => {
return (
<group {...props}>
{[...`✨✨✨${value}`.slice(-4)].map((num, index) => (
<Counter index={index} value={num === '✨' ? -1 : parseInt(num)} key={index} speed={0.1 * (4 - index)} />
))}
<Text anchorY="bottom" position={[2 * 1.1, -0.25, 2]} fontSize={1}>
{currency}
</Text>
</group>
);
};
Here, the price is split into individual digits, and each digit is passed to a separate Counter component. The speed of the number’s animation decreases for each successive digit, creating a staggered animation effect.
The next step is to add buttons that allow the user to change the displayed price by clicking or hovering.
Clicking or hovering on a button changes the value, which is passed to the Price component, triggering a visual update.
The price reverts to a default value (3457) when the user moves the mouse away from the button.
Finally, we render the 3D scene using the Canvas component from @react-three/fiber:
code
<Canvas className="max-h-[calc(100%-60%)]">
<Price value={value} />
</Canvas>
This is encapsulated within a responsive layout that ensures the 3D canvas fits well within the page.
By combining Three.js, @react-three/fiber, and @react-three/drei, we’ve created an interactive 3D pricing demo that updates dynamically based on user interactions. This can be further extended to suit a wide range of interactive 3D applications, from product showcases to creative pricing displays.
I hope you found this tutorial helpful! Feel free to experiment with this concept and create your own 3D experiences.