Caroumesh is a React component to display your 3D models in a Carousel-like fashion inside your application, using three.js and react-three-fiber.
To install Caroumesh execute the following command in your React project:
# With npm
npm install caroumesh
# With yarn
yarn add caroumesh
Import the Caroumesh component and use it within your React components.
import { Caroumesh } from 'caroumesh';
...
<Caroumesh scenes={['assets/StarDestroyer.gltf', 'assets/TieFighter.gltf']} />
...
You can also view and play around with Caroumesh using this Storybook:
The Caroumesh component is the main and only component of this library.
<Caroumesh />
It accepts the following props:
Prop | Description | Type | Default value |
---|---|---|---|
scenes |
Scenes of the carousel | SceneObject [] |
❗️ Required |
dimensions |
Fixed dimensions of the component | Dimensions |
Takes all available space |
shadows |
Render shadows | boolean |
false |
controls |
Use orbits controls | boolean |
false |
lights |
Control lights behavior | LightsOptions |
undefined |
effects |
Add post-processing effects | EffectsOptions |
undefined |
radius |
Control how far apart scenes are from one another | number |
10 |
animationTime |
Time to transition to new scene, in ms | number |
1000 |
stats |
Show statistics of Caroumesh performance | boolean |
undefined |
styles |
Set of styles to customize | Styles |
undefined |
className |
Custom classname | string |
undefined |
You can add a scene by only specifying its path using a string.
<Caroumesh scenes={['assets/StarDestroyer.gltf', 'assets/TieFighter.gltf']} />
Otherwise, you might want to modify the scene first. You can import it by passing it as a SceneObject
. You can use both types in the same array.
<Caroumesh
scenes={[
{
src: 'assets/StarDestroyer.gltf',
scale: 0.5,
position: new Vector3(0.5, 0.25, -0.5),
},
'assets/TieFighter.gltf',
]}
/>
The SceneObject
accepts the following props:
{
/** Source path to scene file */
src: string;
/** Cast and receive shadows */
shadows?: boolean;
/** Control intensity of lights in scene */
lightIntensity?: number;
/** Rotation speed of scene: set to `0` to disable rotation */
rotationSpeed?: number;
} & {
position?: Vector3;
up?: Vector3;
scale?: number | Vector3;
rotation?: Euler;
matrix?: Matrix4;
quaternion?: Quaternion;
}
⚠️ Adding too many scenes might affect performance. You can use thestats
prop to analyze impact on the component's FPS (cf #stats)
Generally, 3D scenes and meshes are can be quite heavy, so to reduce load as much as possible it is recommended you compress your models into glb files with draco compression. You can run the following command to compress each gltf/glb file you have.
yarn scene:optimize model.gltf
ℹ️ This creates a new gltf file at the same location as the input file using the Draco compression library
If you want more customization over the arguments, use yarn scene
(see gltf-pipeline CLI documentation
to learn more about the arguments you can use). For example:
yarn scene -i model.gltf -b
By default, the component will take all available space of the parent's space.
You can manually set the dimensions using the dimensions
prop.
<Caroumesh
...
dimensions={[750, 500]}
...
/>
By default, shadows
are disabled. When enabled, built-in lights will emit shadows on scenes that cast and receive them.
<Caroumesh
...
shadows
...
/>
You can enable enhanced controls over the scenes using the controls
prop.
<Caroumesh
...
controls
...
/>
You can use the following key-binds on your mouse and keyboard to control the scene:
Key-bind | Action |
---|---|
Mouse Left (Hold) | Rotate |
Shift or Ctrl + Mouse Left (Hold) | Pan |
Scroll wheel | Zoom |
Space | Reset view |
The view resets every time you switch to a new scene.
The component comes by default with a three point light setup.
You can modify this setup by changing the props of the lights using the
lights: { keyLight, fillLight, backLight }
prop.
You can also display the lights' gizmos (visual helpers to see what area is affected by a light)
using the lights: { helpers }
prop.
If you want to setup your own light setup you can use the lights: { customLights }
prop.
<Caroumesh
...
lights={{
customLights: <spotLight position={new Vector3(4, 2, 4)} />
}}
...
/>
This prop accepts react-three-fiber light components. These are all the possible light components you can use:
<ambientLight />
<directionalLight />
<hemisphereLight />
<pointLight />
<rectAreaLight />
<spotLight />
You can add postprocessing effects
to your Caroumesh rendering, based on the @react-three/postprocessing library.
The list of effects components are listed here.
⚠️ Effects can have a great impact on performance. Use with caution!
import { Bloom } from '@react-three/postprocessing';
...
<Caroumesh
...
effects={{
children: [<Bloom key="bloom" intensity={0.1} />],
...
}}
...
/>
The radius
prop controls the radius of the carousel-circle upon which the scenes are placed,
thus the distance between the scenes. By default, the radius is set to 10.
<Caroumesh
...
radius={6}
...
/>
You can change the time to transition between the different scenes using the animationTime
prop.
The value is set in milliseconds (ms), and by default it is set to 1000ms.
<Caroumesh
...
animationTime={500}
...
/>
"If it works on my computer, then it's all good!"
While developing, you can use the stats
prop to evaluate performance
and check how adding models or lights may affect your FPS.
<Caroumesh
...
stats
...
/>
⚠️ It's suggested to enable this prop only when developing, for debugging purposes, and disable it when deploying to production.ℹ️ The FPS of the component depends on the workstation it is being run on. So performance will vary between different computers. Also, FPS might be lower when running on a phone.
In general, good performance would be an average of ~60 FPS, when switching scenes and also when holding idle on scenes.
If you have more than 60 FPS, then you probably have a "better than average" workstation, so don't be fooled into overloaded the scenes with high-poly meshes, lots of lights, and effects. You might be able to run it, but maybe not the average user.
If you have anything less than 50-60 FPS, then you might (click me👇)
- have scenes that are very heavy (lots of polygons or lights usually)
- Optimizing your scenes might help
- Use a 3D editing software (such as Blender 🧡) to simplify mesh and remove any components that could be heavy on the load (lights for example)
- have added too many scenes into the Caroumesh
- same suggestions as previous bullet points
- Remove any scene you deem optional
- Remove any scene that could be heavy
- have added effects which have a big impact on performance
- you can remove them if they're not strictly necessary
- reducing
- are re-rendering the Caroumesh several times
- the props you are passing could be changing
- memoize props passed to Caroumesh with
React.useMemo
- fix the parent components of Caroumesh from updating too much
- are using a browser with locked FPS
- not sure if you can change this, you should look it up
- Caroumesh is buggy or is built poorly 😳
- create an issue about your use case
- create a pull request to fix this darn thing
- if you are certain that all the above are not the reason of poor performance, and FPS is so
low, Caroumesh is barely useable, then you probably own a "potato computer" 🥔
- getting a better computer 🤷
The styles
prop is a set of predefined styling options that you can use to
customize the look of Caroumesh. You can directly control the following CSS properties:
{
colorTheme?: CSSProperties['color'];
backgroundColor?: CSSProperties['color'];
hasBorder?: boolean;
borderColor?: CSSProperties['borderColor'];
isBorderRounded?: boolean;
}
<Caroumesh
...
styles={{
hasBorder: true,
isBorderRounded: true,
}}
...
/>
This className
prop allows you to add a custom classname to the Caroumesh component,
so that you can style your component however you want.
<Caroumesh
...
className="my-custom-classname"
...
/>
The next releases may present the following features:
- Display visual indicator of position of current scene and the surrounding ones.
- Display textual information for each model (title and description)
For any feature requests, create an issue or feel free to create a pull request and contribute to the project!
- Fork the repository
- Setup it up by running
yarn
- Create a new branch
- Push your changes
- Create a pull request
- Wait for a review
Any feedback is welcome through issues as well. 🙏
Thanks to the amazing teams and contributors of three.js and react-three-fiber, for building such awesome stuff!
But also, Thank You for using Caroumesh
! ❤️