← Learn · Build · 23 October 2026 · 8 min

Turn Anything into an Apple-Style 3D Website (I Did It with a Bowl of Ramen)

The full workflow: Tripo for the 3D models, Opus 5.5 for the code. Prompts, code snippets and the free credits link.

I made an Apple launch page for a bowl of ramen. "Ramen Pro Max". Scroll down and every ingredient gets its own product shot, with its own spec card ("A17 Noodle Engine", "18-hour tonkotsu"). Then they all rain into the bowl and it turns into the finished ramen. Then there's a flavor picker and a Buy button.

The short version: the website is code, the 3D is Tripo. Opus 5.5 can write an amazing Three.js site, but when it has to draw the food with code, you get flat discs and tubes. Tripo turns one line of text into a real textured 3D model. Put the two together and you can do this for anything: sneakers, your product, your college project, your startup.

Here's everything, step by step.

0. Get Tripo (free credits)

👉 Sign up with my link

🎁 500 bonus credits + 60% off your first month

  1. Click the link above (or the link in my bio), or
  2. Go to the official Tripo website, click your profile avatar, find the Redeem Code section and enter J0SG4G

Discount code: TRIPOCREW

⚠️ Complete both registration and purchase within 24 hours to get the offer.

1. The stack

Piece What I used
3D models Tripo Studio, Text to 3D
Code Claude Opus 5.5
3D in the browser three.js
Smooth scroll Lenis
Scroll animations GSAP + ScrollTrigger
Build tool Vite
Model compression gltf-transform
npm create vite@latest ramen-pro-max -- --template vanilla
cd ramen-pro-max
npm i three gsap lenis
npm i -g @gltf-transform/cli

2. Generate every piece as its own model in Tripo

The key idea: don't generate one model of the whole thing. Generate the finished product once (the hero), then every part separately. That's what lets the site pull it apart and put it back together.

In Tripo Studio: Model → Text to 3D, paste a prompt, hit Generate. Each one takes about 2 minutes.

I added this style line to the end of every ingredient prompt so they all match:

photorealistic food product render, isolated single object, centered, no background, no table, no plate unless stated, high detail PBR textures

The hero (the finished bowl):

a beautiful bowl of japanese tonkotsu ramen, black ceramic bowl with red rim, creamy broth, wavy noodles, two chashu pork slices, halved soft boiled egg with orange yolk, nori sheet standing up, narutomaki slices, green scallions, chopsticks resting on the rim, food product photography

The ingredients:

Part Prompt
Bowl an empty deep japanese ramen bowl, glossy black ceramic outside with red rim and subtle wave pattern, empty inside
Noodles a nest of wavy yellow ramen noodles lifted and folded, glossy, no bowl
Chashu two round slices of rolled japanese chashu pork belly, spiral fat layers, caramelized torched edges, slices fanned
Egg (ajitama) a soy marinated soft boiled ramen egg cut in half, jammy bright orange yolk, amber brown egg white, two halves side by side
Nori a single rectangular sheet of dark green roasted nori seaweed, slightly curved, glossy texture
Scallions a small pile of thinly sliced fresh green scallion rings
Chopsticks a pair of lacquered dark wooden japanese chopsticks lying parallel, slightly apart

Export each one as GLB and drop them in public/models/ramen/ as hero.glb, bowl.glb, noodles.glb and so on.

Doing your own product? Same recipe. One prompt for the finished thing, then one prompt per part (a sneaker = sole, upper, laces, insole, box).

3. Shrink the models for the web

Tripo models are big and detailed (mine were around 70 MB each). For a website you want around 1 MB. One command per model:

gltf-transform optimize hero.glb public/models/ramen/hero.glb \
  --compress meshopt --texture-compress webp --texture-size 1024 \
  --simplify-ratio 0.05 --simplify-error 0.002

Bump --texture-size to 2048 for the hero model if you want it extra crisp.

4. The prompt for Opus 5.5

This is the prompt to get the site built. Paste it with your models already in public/models/ramen/:

Build an Apple-style product launch website for a bowl of ramen called "Ramen Pro Max".
Stack: Vite, three.js, GSAP ScrollTrigger, Lenis smooth scroll. Dark background, Inter font, Apple product page vibe.

3D models (GLB, made in Tripo) are in public/models/ramen/: hero.glb (the finished bowl) plus one file per ingredient: bowl, noodles, chashu, egg, nori, scallions, chopsticks.
Load them with GLTFLoader + MeshoptDecoder. Normalise every model (centre it and scale it to a target size), because they come in at random scales.

Sections, all driven by scroll:
1. Hero: the finished bowl slowly rotating with steam, big title "Ramen Pro Max", tagline "Slurp. Redefined."
2. Statement: "Our most advanced bowl. Ever."
3. "Inside the bowl": a pinned section where each ingredient gets its own product shot, one at a time, centred, same visual size, slowly turning under a soft glow, with a spec card (name, a fake Apple-style spec like "A17 Noodle Engine", one detail line). At the end, every ingredient falls into the empty bowl and it crossfades into the finished hero bowl with a puff of steam.
4. Tech specs grid with count-up numbers (18 hr broth, 120 slurps/s, 98°C, 0.2 mm nori).
5. Flavors: four swatches (Tonkotsu, Shoyu, Miso, Spicy) that tint the glow behind the bowl.
6. Buy: price, monthly price, blue Buy button that triggers a steam burst and a toast "Order up".

Make it work in portrait (phone) too: objects centred, card at the bottom.
Add ?autoplay to scroll the whole page hands-free so I can screen-record it.

Then iterate. My first version showed the whole exploded stack at once and looked messy. What fixed it was telling Opus: one ingredient at a time, same size, centre stage, like a product film.

5. Code snippets that make it work

Normalise every Tripo model

Every GLB comes in at a different scale and offset. This wraps it so it's centred and exactly size units big:

import * as THREE from 'three';

export function normalise(object, size = 1, { anchor = 'center' } = {}) {
  object.updateMatrixWorld(true);
  const box = new THREE.Box3().setFromObject(object);
  const dim = box.getSize(new THREE.Vector3());
  const c = box.getCenter(new THREE.Vector3());
  const s = size / Math.max(dim.x, dim.y, dim.z, 1e-6);
  const pivot = new THREE.Group(), holder = new THREE.Group();
  holder.add(object);
  holder.scale.setScalar(s);
  holder.position.set(-c.x * s, anchor === 'bottom' ? -box.min.y * s : -c.y * s, -c.z * s);
  pivot.add(holder);
  return pivot;
}

Load with Meshopt (because we compressed them)

import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
import { MeshoptDecoder } from 'three/examples/jsm/libs/meshopt_decoder.module.js';

const loader = new GLTFLoader();
loader.setMeshoptDecoder(MeshoptDecoder);
const gltf = await loader.loadAsync('/models/ramen/egg.glb');
scene.add(normalise(gltf.scene, 1.8));

Fix "glassy" food

Some exported materials come out see-through or metallic. Food and ceramic should be solid and matte:

function solid(obj) {
  obj.traverse((o) => {
    if (!o.isMesh) return;
    [].concat(o.material).forEach((m) => {
      m.transparent = false; m.opacity = 1; m.depthWrite = true;
      m.metalness = Math.min(m.metalness ?? 0, 0.15);
      m.roughness = Math.max(m.roughness ?? 1, 0.6);
    });
  });
  return obj;
}

The "product film" scroll: one ingredient at a time

p is how far you've scrolled through the pinned section (0 to 1). Each ingredient slides up into the centre, holds, then slides out as the next one comes in:

const n = ingredients.length;
const f = THREE.MathUtils.clamp((p - 0.05) / 0.79, 0, 1) * n; // which ingredient we're on

ingredients.forEach((part, j) => {
  const e = f - j; // < 0: not yet, 0..1: on stage, > 1: gone
  const enter = THREE.MathUtils.smootherstep(e, -0.15, 0.22);
  const exit = j === n - 1 ? 0 : THREE.MathUtils.smootherstep(e, 0.78, 1.15);
  part.position.y = (1 - enter) * -2.6 + exit * 2.6;   // rise in, rise out
  part.scale.setScalar(part.fit * (0.85 + 0.15 * enter)); // same visual size for all
  part.rotation.y = time * 0.35;                        // slow turntable
  setOpacity(part, enter * (1 - exit));
});

Everything drops into the bowl

After the last ingredient, they hang in a ring over the empty bowl and fall in one after another. Then the empty bowl crossfades into the finished hero model:

const asm = THREE.MathUtils.smoothstep(p, 0.85, 0.98); // assembly progress
ingredients.forEach((part, j) => {
  const a = (j / n) * Math.PI * 2;
  const k = THREE.MathUtils.clamp(asm * 1.6 - (j / n) * 0.6, 0, 1); // staggered
  part.position.set(
    Math.cos(a) * 1.3 * (1 - k),
    THREE.MathUtils.lerp(1.05, 0.1, k * k), // gravity-ish ease
    Math.sin(a) * 0.6 * (1 - k)
  );
  part.scale.setScalar(part.fit * 0.45 * (1 - k * 0.7));
});
heroBowl.visible = asm > 0.7; // the finished Tripo bowl takes over

Steam (cheap and convincing)

A few hundred points with a soft round texture, each with a "life" from 0 to 1. Rise, drift, fade, respawn:

for (let i = 0; i < N; i++) {
  life[i] += dt * 0.25;
  if (life[i] > 1) life[i] = 0;
  const a = seed[i] * 6.283, r = 0.6 * (1 - life[i] * 0.3);
  pos[i * 3]     = Math.cos(a) * r + Math.sin(t * 0.8 + seed[i]) * 0.25 * life[i];
  pos[i * 3 + 1] = 0.4 + life[i] * 1.3;
  pos[i * 3 + 2] = Math.sin(a) * r;
}
steamGeometry.attributes.position.needsUpdate = true;

Fade each puff with sin(life * PI) in the shader so it appears and disappears smoothly.

6. Code vs Tripo (why you need both)

I also asked Opus to build the ramen out of pure code: cylinders, discs, torus rings. It works, it reads as ramen, but it looks like a low-poly game asset. Swap in the Tripo model and it suddenly looks like a product shot. That's the whole point:

  • Opus 5.5 is great at the experience: the scroll story, the animation timing, the layout, the copy.
  • Tripo is great at the object: real shape, real textures, in one line of text.

7. Do it with your own thing

  1. Pick an object (sneaker, headphones, your product, your mascot).
  2. Generate the finished object + each part in Tripo.
  3. Compress them with gltf-transform.
  4. Paste the prompt from step 4 into Opus 5.5, swapping "ramen" for your thing and the spec card jokes for yours.
  5. Iterate on the scroll story until every section has one clear shot.

Post it and tag me @avi_vashishta29, I want to see what you make.


Free Tripo credits: my invite link · code J0SG4G · discount TRIPOCREW · 500 bonus credits + 60% off your first month (register and purchase within 24 hours).