Visión general: Landing 3D
README.md
A one-page landing site for a juice brand, built with Next.js 15. A 3D wheel of juice cans turns with the mouse wheel, the arrow keys or the arrow buttons, and the whole page takes on the colours of the flavour in front.
Features
- 3D can carousel: four juice cans on a wheel, built with React Three Fiber and Three.js.
- Theme per flavour: background, glow and buttons change colour with the selected juice.
- Floating fruits: fruit images that follow the selected flavour.
- Ice cubes and leaves: decorative elements around the scene.
- Water ripple: the background ripples under the pointer.
- Responsive: a separate layout for phones.
- Two languages: English and Arabic, with a right-to-left layout for Arabic.
The flavours are Lemon Ginger, Blueberry Açai, Mango Burst and Raspberry Rosé.
The sign-in form and the cart panel are demo UI. The form checks its fields, but there is no back-end, so nothing is sent anywhere.
Requirements
Pick one:
- Docker, nothing else.
- Node.js 22 or newer and Yarn 4. Yarn comes with Node through Corepack: run
corepack enableonce if theyarncommand is missing. The exact Yarn version is pinned inpackage.json.
The site reads no environment variables, so there is no .env file to create. Every file it loads ships in this folder, including the 3D models and the lighting, so it needs no outside service to run.
Path A: run it with Docker
From this folder:
docker build -t juicy .
docker run -p 3030:3030 juicyOpen http://localhost:3030. Press Ctrl+C in the terminal to stop it.
Path B: run it without Docker
From this folder:
yarn install
yarn devOpen http://localhost:3030. The development server reloads the page when you change a file.
For the production build:
yarn build
yarn startIt is served on http://localhost:3030 too.
A port is already in use?
Another program is using port 3030. Stop it, or use another port:
- With Docker, change the left number only:
docker run -p 3041:3030 juicy, then open http://localhost:3041. - Without Docker:
yarn dev -p 3041(oryarn start -p 3041), then open http://localhost:3041.
Languages
English is at /en (the default) and Arabic at /ar. Opening / sends the visitor to the language their browser prefers. The menu has a language switcher.
In Arabic the text and the layout run right to left. The 3D scene (wheel, fruits, ice) keeps its own orientation.
Make it yours
| What | Where |
|---|---|
| Text, in both languages | messages/en.json and messages/ar.json. Keep the same keys in both files. |
| Page title and description (SEO) | the metadata keys in the same two files |
| Flavours (the 3D cans) | src/features/carousel/constants/juiceCans.ts, models in public/assets/3d/can/ |
| Colours of each flavour | src/features/product-showcase/constants/themes.ts. While the page runs, useBodyBackground (src/features/landing/hooks/) paints the page background in the active flavour's mainBgColor. The body background in src/app/globals.css (#82AF38, the first flavour) only covers the moment before the page loads, so change it together with the first flavour. |
| Lighting on the cans | public/assets/hdri/forest_slope_1k.hdr, set in src/features/carousel/constants/environment.ts. It is Poly Haven's Forest Slope HDRI (CC0). |
| Fruit images | public/assets/images/fruit/, listed in src/features/floating-fruits/constants/fruitImages.ts |
| Ice cubes, leaves, water drop | public/assets/images/ice/, public/assets/images/leaf/, public/assets/images/drop.png |
| Cart sample items | src/features/navigation/constants/sampleCartItems.ts, images in public/assets/images/can/ |
| Bottle sizes | src/features/product-showcase/constants/sizes.ts. The one marked selected is chosen when the page opens. |
| Contact links | src/features/product-showcase/constants/contactLinks.ts |
| Menu items | src/features/navigation/constants/navItems.ts, labels under nav.items in the message files |
| Fonts | src/app/[locale]/layout.tsx loads them: Thunder (the big wordmark, files in src/app/fonts/) and Cairo (Arabic text). The Latin body font is set in src/app/globals.css. |
| Favicon | src/app/favicon.ico |
The wheel holds four cans, one per quarter turn (src/features/carousel/constants/positionConfigs.ts). To replace a flavour, rename its id in src/types/juice.ts, then update its entry in juiceCans.ts, themes.ts, fruitImages.ts, sampleCartItems.ts (if it is in the cart), and under juices and cart.items in both message files. yarn typecheck lists any code file you missed.
Scripts
| Command | What it does |
|---|---|
yarn dev | Development server on port 3030 |
yarn build | Production build |
yarn start | Serve the production build on port 3030 |
yarn lint | ESLint |
yarn typecheck | TypeScript check (tsc --noEmit) |
Dependencies are pinned to exact versions, and yarn.lock is included, so yarn install gives you the same versions this was tested with.
Project structure
messages/ # en.json, ar.json
public/assets/ # 3D can models and images
src/
├── app/[locale]/ # layout (html lang and dir, fonts, metadata) and the page
├── components/ # shared UI: backgrounds, spinner, LocaleSwitcher, ui/Input, ui/ThemedButton
├── features/
│ ├── carousel/ # 3D juice wheel
│ ├── floating-fruits/ # animated fruit images
│ ├── ice-cubes/ # ice cube and leaf decorations
│ ├── landing/ # page state hook and the water-ripple stage
│ ├── navigation/ # nav bar, cart and account dropdowns, sign-in form
│ └── product-showcase/ # product text, sizes, themes, contact menu
├── hooks/ # shared hooks (useMobile, useInView, ...)
├── i18n/ # routing, request config, navigation helpers
├── middleware.ts # language detection and redirects
└── types/ # shared typesTech stack
Next.js 15 (App Router), React 19, TypeScript, Tailwind CSS 4, React Three Fiber with Three.js and Drei, GSAP, next-intl, React Hook Form with Zod, react-water-wave.
Licence
The licence terms are in LICENSE.md, at the top of your downloaded folder.
More templates
More templates are at Aniq UI.