I'm working on a code tutorial from youtube but I'm running into an issue where I have 13 icosahedral geometry spheres successfully rendered to my screen. However, the video makes the 2D image I display on the ball invisible. There are no errors in my console. This project is Three.js and tailwindcss. There is no typescript.
NOTE: This is my first thrre.js project and I am still new to software development following the self-taught route. Thank you for your patience, understanding and help. Thank you very much.
main problem How can I get the icon image from "tech" to render correctly to the side of the ball?
The intention seems to be to make it look similar to a golf ball with the company logo on it, like you would find on any golf course or driving range.
I've been trying to solve this problem for over a week now and I'm completely stumped.
The tutorial I followed on YouTube is here: https://www.youtube.com/watch?v=0fYi8SGA20k&t=6190s
The following are the code files most relevant to this issue. I'd be happy to provide more if useful. Here is the Tech.jsx file that contains the component that displays the ball:
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;
The next step is to import the Balls.jsx file 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 is a snippet from the index.js file that contains navigation information to locate the icon that needs to be displayed. This will be the import and "technical" constant. Note that these files do all exist in my project and when I click on them they show up 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 to keep things sane.
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" } }
Finally tailwind.config.js:
@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've tried showing the icons on a normal ball, but that only allowed them to stretch over the entire surface of the 3d ball, and there were multiple "no-undefined" es linting issues. It also involves completely removing the Ball.jsx file and rewriting it with a more basic grid. This is very unsatisfactory, but if I could display a logo on the side of any 3D ball it would be a huge win at this point. As mentioned before, I need to be able to see the icon/logo on each ball.
Update your Balls.jsx file, here’s what I did: