I am working on a code tutorial from youtube and I have run into an issue where I have 13 icosohedronGeometry balls successfully rendered to my screen. However the 2d images the video has me displaying on the balls are not visible. I have no errors in my console. This project is Three.js and tailwindcss. NO TYPESCRIPT.
NOTE: This is my first thrre.js project and I am still very much a greenhorn in software development following the self taught route. Thank you for your patience, understanding, and help. You are greatly appreciated.
MAIN QUESTION How do I get the icon images from 'technologies' to render correctly onto the side of the ball?
The object seems to be to make it look similar to a golf ball with a company logo on it as you could find at any golf course or driving range.
I have been trying to resolve this for well over a week now and I am completely stumped.
The tutorial I am following on youtube is here: https://www.youtube.com/watch?v=0fYi8SGA20k&t=6190s
Below are my most relevant code files pertaining to the issue. I am happy to provide more if it is useful. Here is the Tech.jsx file containing the component which displays the Balls:
import { BallCanvas } from './canvas'
import { SectionWrapper } from '../hoc'
import { technologies } from '../constants/index'
const TechComponent = () => {
return (
<div className='flex flex-row flex-wrap justify-center gap-10'>
{technologies.map((technology) => (
<div className='w-28 h-28' key={technology.name}>
<BallCanvas icon={technology.icon} />
</div>
))}
</div>
)
}
const Tech = SectionWrapper(TechComponent, "about");
export default Tech;
Next is the Balls.jsx file that holds being imported into Tech.jsx:
import { Suspense } from 'react'
import { Canvas } from '@react-three/fiber'
import { Decal, Float, OrbitControls, Preload, useTexture } from '@react-three/drei'
import CanvasLoader from '../Loader'
import PropTypes from 'prop-types';
const Ball = (props) => {
const [decal] = useTexture([props.imgURL])
return (
<Float speed={1.75} rotationIntensity={1} floatIntensity={2}>
<ambientLight intensity={0.25}/>
{/* eslint-disable-next-line react/no-unknown-property */}
<directionalLight position={[0, 0, 0.05]} />
{/* eslint-disable-next-line react/no-unknown-property */}
<mesh castShadow receiveShadow>
{/* eslint-disable-next-line react/no-unknown-property */}
<icosahedronGeometry attach="geometry" args={[4, 3]} />
{/* eslint-disable-next-line react/no-unknown-property */}
<meshStandardMaterial color="#fff8eb" polygonOffset polygonOffsetFactor={-5} flatShading />
<Decal position={[0, 0, 1]} map={decal}/>
{/*decal not loading*/}
</mesh>
</Float>
)
}
const BallCanvas = ({ icon }) => {
return (
<Canvas
frameloop="demand"
shadows
camera={{ position: [20, 3, 5], fov:25}}
gl={{ preserveDrawingBuffer: true}}
>
<Suspense fallback={<CanvasLoader />}>
<OrbitControls
enableZoom={false}
/>
<Ball imgURL={icon}/>
</Suspense>
<Preload all />
</Canvas>
)
}
Ball.propTypes = {
imgURL: PropTypes.string.isRequired,
};
BallCanvas.propTypes = {
icon: PropTypes.string.isRequired,
};
export default BallCanvas;
Next a snippet from the index.js file that holds the navigation information to locate the icons that need to be displayed. This will be the imports and the 'technologies' const. Note that these files do all exist in my project and when I click on them they do display in the vscode window:
import {
mobile,
backend,
creator,
web,
javascript,
typescript,
html,
css,
reactjs,
redux,
tailwind,
nodejs,
mongodb,
git,
figma,
docker,
meta,
starbucks,
tesla,
shopify,
carrent,
jobit,
tripguide,
threejs,
} from "../assets";
const technologies = [
{
name: "HTML 5",
icon: html,
},
{
name: "CSS 3",
icon: css,
},
{
name: "JavaScript",
icon: javascript,
},
{
name: "TypeScript",
icon: typescript,
},
{
name: "React JS",
icon: reactjs,
},
{
name: "Redux Toolkit",
icon: redux,
},
{
name: "Tailwind CSS",
icon: tailwind,
},
{
name: "Node JS",
icon: nodejs,
},
{
name: "MongoDB",
icon: mongodb,
},
{
name: "Three JS",
icon: threejs,
},
{
name: "git",
icon: git,
},
{
name: "figma",
icon: figma,
},
{
name: "docker",
icon: docker,
},
];
Then we have my package.json and tailwind.config.js just for sanity.
First package.json:
{
"name": "portfolio-rob-2023",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"lint": "eslint src --ext js,jsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview"
},
"dependencies": {
"@emailjs/browser": "^3.11.0",
"@react-three/drei": "^9.66.6",
"@react-three/fiber": "^8.13.0",
"@types/three": "^0.152.0",
"framer-motion": "^10.12.8",
"maath": "^0.5.3",
"prop-types": "^15.8.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-parallax-tilt": "^1.7.140",
"react-router-dom": "^6.11.1",
"react-tilt": "^1.0.2",
"react-vertical-timeline-component": "^3.6.0",
"three": "^0.152.2"
},
"devDependencies": {
"@types/node": "^20.1.1",
"@types/react": "^18.0.28",
"@types/react-dom": "^18.0.11",
"@vitejs/plugin-react": "^4.0.0",
"autoprefixer": "^10.4.14",
"eslint": "^8.38.0",
"eslint-plugin-react": "^7.32.2",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.3.4",
"postcss": "^8.4.23",
"tailwindcss": "^3.3.2",
"vite": "^4.3.2"
}
}
And finally the tailwind.config.js here:
@type {import('tailwindcss').Config}
module.exports = {
content: [
"./src/**/*.{js,jsx}"
],
mode: "jit",
theme: {
extend: {
colors: {
primary: "#050816",
secondary: "#aaa6c3",
tertiary: "#151030",
"black-100": "#100d25",
"black-200": "#090325",
"white-100": "#f3f3f3",
},
boxShadow: {
card: "0px 35px 120px -15px #211e35",
},
screens: {
xs: "450px",
},
backgroundImage: {
"hero-pattern": "url('/src/assets/herobg.png')",
},
},
},
plugins: [],
};
` I have tried displaying the icons on plain balls but could only get them stretched around the entire surface of the 3d ball and there were multiple es linting problems of 'no-undefined'. It also involved completely deleting and re-writing the Ball.jsx file with more basic mesh. This was very much unsatisfactory however if I could just get the logos displayed on the side of any 3d ball at all that would be a huge win at this point. As mentioned before I need to be able to see the icons/logos on each ball.