{
  "streamed": true,
  "usage": {
    "prompt_tokens": 108,
    "completion_tokens": 21129,
    "total_tokens": 21237,
    "cost": 0.63441,
    "is_byok": false,
    "prompt_tokens_details": {
      "cached_tokens": 0,
      "cache_write_tokens": 0,
      "audio_tokens": 0,
      "video_tokens": 0
    },
    "cost_details": {
      "upstream_inference_cost": 0.63441,
      "upstream_inference_prompt_cost": 0.00054,
      "upstream_inference_completions_cost": 0.63387
    },
    "completion_tokens_details": {
      "reasoning_tokens": 11912,
      "image_tokens": 0,
      "audio_tokens": 0
    }
  },
  "finishReason": "stop",
  "content": "```html\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"utf-8\" />\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <title>3D Burger Visualization</title>\n  <style>\n    html, body {\n      margin: 0;\n      width: 100%;\n      height: 100%;\n      overflow: hidden;\n      background: #111114;\n    }\n    canvas {\n      display: block;\n      width: 100%;\n      height: 100%;\n    }\n    body::after {\n      content: \"\";\n      position: fixed;\n      inset: 0;\n      pointer-events: none;\n      background:\n        radial-gradient(circle at 50% 44%, rgba(255,255,255,0.05), transparent 34%),\n        radial-gradient(circle at 50% 50%, transparent 52%, rgba(0,0,0,0.48) 100%);\n      mix-blend-mode: soft-light;\n    }\n  </style>\n</head>\n<body>\n<script src=\"https://cdn.jsdelivr.net/npm/three@0.128.0/build/three.min.js\"></script>\n<script src=\"https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/controls/OrbitControls.js\"></script>\n<script>\n(function () {\n  \"use strict\";\n\n  let rngSeed = 812547;\n  function rand() {\n    rngSeed |= 0;\n    rngSeed = (rngSeed + 0x6D2B79F5) | 0;\n    let t = Math.imul(rngSeed ^ (rngSeed >>> 15), 1 | rngSeed);\n    t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;\n    return ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n  }\n  function randRange(a, b) { return a + (b - a) * rand(); }\n  function lerp(a, b, t) { return a + (b - a) * t; }\n  function clamp(v, a, b) { return Math.max(a, Math.min(b, v)); }\n\n  const scene = new THREE.Scene();\n  scene.background = new THREE.Color(0x141418);\n  scene.fog = new THREE.Fog(0x141418, 7.5, 15);\n\n  const camera = new THREE.PerspectiveCamera(42, window.innerWidth / window.innerHeight, 0.05, 100);\n  camera.position.set(4.4, 2.75, 5.25);\n\n  const renderer = new THREE.WebGLRenderer({ antialias: true, powerPreference: \"high-performance\" });\n  renderer.setSize(window.innerWidth, window.innerHeight);\n  renderer.setPixelRatio(Math.min(window.devicePixelRatio || 1, 2));\n  renderer.outputEncoding = THREE.sRGBEncoding;\n  renderer.toneMapping = THREE.ACESFilmicToneMapping;\n  renderer.toneMappingExposure = 1.08;\n  renderer.shadowMap.enabled = true;\n  renderer.shadowMap.type = THREE.PCFSoftShadowMap;\n  document.body.appendChild(renderer.domElement);\n\n  const maxAniso = renderer.capabilities.getMaxAnisotropy();\n\n  const controls = new THREE.OrbitControls(camera, renderer.domElement);\n  controls.target.set(0, 1.15, 0);\n  controls.enableDamping = true;\n  controls.dampingFactor = 0.065;\n  controls.enablePan = false;\n  controls.minDistance = 3.5;\n  controls.maxDistance = 9.5;\n  controls.maxPolarAngle = Math.PI * 0.48;\n  controls.update();\n\n  const hemi = new THREE.HemisphereLight(0xfff4df, 0x171827, 0.72);\n  scene.add(hemi);\n\n  const key = new THREE.DirectionalLight(0xfff1d8, 1.45);\n  key.position.set(4.8, 6.4, 3.6);\n  key.castShadow = true;\n  key.shadow.mapSize.set(2048, 2048);\n  key.shadow.camera.left = -5.5;\n  key.shadow.camera.right = 5.5;\n  key.shadow.camera.top = 5.5;\n  key.shadow.camera.bottom = -5.5;\n  key.shadow.camera.near = 1;\n  key.shadow.camera.far = 14;\n  key.shadow.bias = -0.00018;\n  scene.add(key);\n\n  const rim = new THREE.DirectionalLight(0xbfd7ff, 0.45);\n  rim.position.set(-5, 3.8, -3.8);\n  scene.add(rim);\n\n  const warmFill = new THREE.PointLight(0xffbb72, 0.65, 8);\n  warmFill.position.set(-2.7, 2.1, 3.4);\n  scene.add(warmFill);\n\n  function textureFromCanvas(width, height, draw, repeatX, repeatY, srgb) {\n    const c = document.createElement(\"canvas\");\n    c.width = width;\n    c.height = height;\n    const ctx = c.getContext(\"2d\");\n    draw(ctx, width, height);\n    const tex = new THREE.CanvasTexture(c);\n    tex.wrapS = tex.wrapT = THREE.RepeatWrapping;\n    tex.repeat.set(repeatX || 1, repeatY || 1);\n    tex.anisotropy = maxAniso;\n    if (srgb !== false) tex.encoding = THREE.SRGBEncoding || THREE.sRGBEncoding;\n    tex.needsUpdate = true;\n    return tex;\n  }\n\n  function drawBun(ctx, w, h) {\n    const g = ctx.createLinearGradient(0, 0, w, h);\n    g.addColorStop(0, \"#f1b15a\");\n    g.addColorStop(0.42, \"#d88a35\");\n    g.addColorStop(0.78, \"#bd6b28\");\n    g.addColorStop(1, \"#f0b968\");\n    ctx.fillStyle = g;\n    ctx.fillRect(0, 0, w, h);\n\n    for (let i = 0; i < 11500; i++) {\n      const x = rand() * w, y = rand() * h;\n      const s = randRange(0.4, 2.4);\n      const light = rand() > 0.48;\n      ctx.fillStyle = light\n        ? `rgba(255,219,139,${randRange(0.015, 0.065)})`\n        : `rgba(97,45,16,${randRange(0.012, 0.072)})`;\n      ctx.fillRect(x, y, s, s);\n    }\n\n    for (let i = 0; i < 95; i++) {\n      ctx.beginPath();\n      ctx.ellipse(rand() * w, rand() * h, randRange(7, 31), randRange(4, 22), rand() * Math.PI, 0, Math.PI * 2);\n      ctx.fillStyle = rand() > 0.45 ? \"rgba(116,50,13,0.055)\" : \"rgba(255,202,107,0.055)\";\n      ctx.fill();\n    }\n  }\n\n  function drawBump(ctx, w, h) {\n    ctx.fillStyle = \"rgb(128,128,128)\";\n    ctx.fillRect(0, 0, w, h);\n    for (let i = 0; i < 14000; i++) {\n      const v = Math.floor(randRange(92, 172));\n      ctx.fillStyle = `rgba(${v},${v},${v},${randRange(0.08, 0.42)})`;\n      ctx.fillRect(rand() * w, rand() * h, randRange(0.5, 2.2), randRange(0.5, 2.2));\n    }\n  }\n\n  function drawPatty(ctx, w, h) {\n    ctx.fillStyle = \"#3a1d13\";\n    ctx.fillRect(0, 0, w, h);\n\n    for (let i = 0; i < 9000; i++) {\n      const x = rand() * w, y = rand() * h;\n      const r = rand();\n      let color;\n      if (r < 0.33) color = `rgba(17,10,7,${randRange(0.14, 0.46)})`;\n      else if (r < 0.72) color = `rgba(93,43,25,${randRange(0.08, 0.35)})`;\n      else color = `rgba(160,88,45,${randRange(0.035, 0.16)})`;\n      ctx.fillStyle = color;\n      ctx.fillRect(x, y, randRange(0.7, 3.8), randRange(0.7, 3.8));\n    }\n\n    for (let i = 0; i < 180; i++) {\n      ctx.beginPath();\n      ctx.ellipse(rand() * w, rand() * h, randRange(4, 18), randRange(2, 10), rand() * Math.PI, 0, Math.PI * 2);\n      ctx.fillStyle = rand() > 0.55 ? \"rgba(5,3,2,0.22)\" : \"rgba(122,55,28,0.12)\";\n      ctx.fill();\n    }\n  }\n\n  function drawLettuce(ctx, w, h) {\n    const g = ctx.createLinearGradient(0, 0, w, h);\n    g.addColorStop(0, \"#77c043\");\n    g.addColorStop(0.45, \"#2e972f\");\n    g.addColorStop(1, \"#165d23\");\n    ctx.fillStyle = g;\n    ctx.fillRect(0, 0, w, h);\n\n    for (let i = 0; i < 7000; i++) {\n      ctx.fillStyle = rand() > 0.55\n        ? `rgba(181,236,100,${randRange(0.025, 0.12)})`\n        : `rgba(8,65,20,${randRange(0.025, 0.15)})`;\n      ctx.fillRect(rand() * w, rand() * h, randRange(0.7, 3.2), randRange(0.7, 3.2));\n    }\n\n    ctx.lineCap = \"round\";\n    for (let i = 0; i < 45; i++) {\n      const y = rand() * h;\n      ctx.beginPath();\n      ctx.moveTo(0, y);\n      for (let x = 0; x <= w; x += 42) {\n        ctx.lineTo(x, y + Math.sin(x * 0.025 + i) * randRange(3, 13));\n      }\n      ctx.strokeStyle = rand() > 0.45 ? \"rgba(196,244,112,0.18)\" : \"rgba(10,72,18,0.16)\";\n      ctx.lineWidth = randRange(1.0, 3.2);\n      ctx.stroke();\n    }\n  }\n\n  function drawCheese(ctx, w, h) {\n    const g = ctx.createLinearGradient(0, 0, w, h);\n    g.addColorStop(0, \"#ffd15d\");\n    g.addColorStop(0.55, \"#ffad1e\");\n    g.addColorStop(1, \"#e98112\");\n    ctx.fillStyle = g;\n    ctx.fillRect(0, 0, w, h);\n    for (let i = 0; i < 5500; i++) {\n      ctx.fillStyle = rand() > 0.5\n        ? `rgba(255,237,143,${randRange(0.012, 0.05)})`\n        : `rgba(180,82,0,${randRange(0.01, 0.04)})`;\n      ctx.fillRect(rand() * w, rand() * h, randRange(0.7, 2.0), randRange(0.7, 2.0));\n    }\n  }\n\n  function drawPickle(ctx, w, h) {\n    const radial = ctx.createRadialGradient(w * 0.52, h * 0.46, 10, w * 0.5, h * 0.5, w * 0.55);\n    radial.addColorStop(0, \"#b6cf4a\");\n    radial.addColorStop(0.35, \"#7fae32\");\n    radial.addColorStop(0.74, \"#3f7b22\");\n    radial.addColorStop(1, \"#214817\");\n    ctx.fillStyle = radial;\n    ctx.fillRect(0, 0, w, h);\n\n    ctx.strokeStyle = \"rgba(210,230,95,0.35)\";\n    ctx.lineWidth = 6;\n    for (let r = 44; r < w * 0.48; r += 32) {\n      ctx.beginPath();\n      ctx.arc(w / 2, h / 2, r, 0, Math.PI * 2);\n      ctx.stroke();\n    }\n\n    for (let i = 0; i < 42; i++) {\n      ctx.beginPath();\n      ctx.ellipse(randRange(w * 0.25, w * 0.75), randRange(h * 0.25, h * 0.75), randRange(3, 8), randRange(2, 5), rand() * Math.PI, 0, Math.PI * 2);\n      ctx.fillStyle = \"rgba(231,238,126,0.43)\";\n      ctx.fill();\n    }\n  }\n\n  function drawShadow(ctx, w, h) {\n    const g = ctx.createRadialGradient(w / 2, h / 2, 0, w / 2, h / 2, w / 2);\n    g.addColorStop(0, \"rgba(0,0,0,0.43)\");\n    g.addColorStop(0.38, \"rgba(0,0,0,0.25)\");\n    g.addColorStop(0.72, \"rgba(0,0,0,0.07)\");\n    g.addColorStop(1, \"rgba(0,0,0,0)\");\n    ctx.fillStyle = g;\n    ctx.fillRect(0, 0, w, h);\n  }\n\n  const bunMap = textureFromCanvas(512, 512, drawBun, 2.1, 1.05, true);\n  const bunBump = textureFromCanvas(512, 512, drawBump, 2.1, 1.05, false);\n  const pattyMap = textureFromCanvas(512, 512, drawPatty, 2.4, 1.2, true);\n  const pattyBump = textureFromCanvas(512, 512, drawBump, 2.4, 1.2, false);\n  const lettuceMap = textureFromCanvas(512, 512, drawLettuce, 2.0, 1.0, true);\n  const lettuceBump = textureFromCanvas(512, 512, drawBump, 1.5, 1.0, false);\n  const cheeseMap = textureFromCanvas(384, 384, drawCheese, 1, 1, true);\n  const pickleTopMap = textureFromCanvas(256, 256, drawPickle, 1, 1, true);\n  const contactShadowMap = textureFromCanvas(512, 512, drawShadow, 1, 1, false);\n\n  const bunMat = new THREE.MeshPhysicalMaterial({\n    map: bunMap,\n    bumpMap: bunBump,\n    bumpScale: 0.027,\n    roughness: 0.72,\n    clearcoat: 0.12,\n    clearcoatRoughness: 0.85,\n    color: 0xffffff\n  });\n\n  const pattyMat = new THREE.MeshPhysicalMaterial({\n    map: pattyMap,\n    bumpMap: pattyBump,\n    bumpScale: 0.055,\n    roughness: 0.92,\n    clearcoat: 0.03,\n    color: 0xffffff\n  });\n\n  const lettuceMat = new THREE.MeshPhysicalMaterial({\n    map: lettuceMap,\n    bumpMap: lettuceBump,\n    bumpScale: 0.025,\n    roughness: 0.78,\n    clearcoat: 0.05,\n    color: 0xffffff,\n    side: THREE.DoubleSide\n  });\n\n  const cheeseMat = new THREE.MeshPhysicalMaterial({\n    map: cheeseMap,\n    color: 0xffffff,\n    roughness: 0.48,\n    clearcoat: 0.12,\n    clearcoatRoughness: 0.42,\n    side: THREE.DoubleSide\n  });\n\n  const sauceMat = new THREE.MeshPhysicalMaterial({\n    color: 0xe99d63,\n    roughness: 0.24,\n    metalness: 0,\n    clearcoat: 0.8,\n    clearcoatRoughness: 0.18\n  });\n\n  const pickleSideMat = new THREE.MeshPhysicalMaterial({\n    color: 0x477826,\n    roughness: 0.42,\n    clearcoat: 0.45,\n    clearcoatRoughness: 0.3\n  });\n\n  const pickleTopMat = new THREE.MeshPhysicalMaterial({\n    map: pickleTopMap,\n    color: 0xffffff,\n    roughness: 0.38,\n    clearcoat: 0.5,\n    clearcoatRoughness: 0.26\n  });\n\n  const onionMat = new THREE.MeshPhysicalMaterial({\n    color: 0xfff4d6,\n    roughness: 0.54,\n    clearcoat: 0.18,\n    clearcoatRoughness: 0.4\n  });\n\n  const seedMat = new THREE.MeshPhysicalMaterial({\n    color: 0xf5dfae,\n    roughness: 0.76,\n    clearcoat: 0.08,\n    clearcoatRoughness: 0.7\n  });\n\n  const charMat = new THREE.MeshStandardMaterial({\n    color: 0x090604,\n    roughness: 0.96\n  });\n\n  const burger = new THREE.Group();\n  scene.add(burger);\n\n  const floorMat = new THREE.MeshStandardMaterial({\n    color: 0x2a2522,\n    roughness: 0.82,\n    metalness: 0.02\n  });\n  const floor = new THREE.Mesh(new THREE.PlaneGeometry(20, 20), floorMat);\n  floor.rotation.x = -Math.PI / 2;\n  floor.position.y = -0.025;\n  floor.receiveShadow = true;\n  scene.add(floor);\n\n  const contactShadow = new THREE.Mesh(\n    new THREE.PlaneGeometry(5.8, 5.8),\n    new THREE.MeshBasicMaterial({\n      map: contactShadowMap,\n      transparent: true,\n      depthWrite: false\n    })\n  );\n  contactShadow.rotation.x = -Math.PI / 2;\n  contactShadow.position.y = -0.019;\n  scene.add(contactShadow);\n\n  function organicLathe(points, material, yOffset, wobble) {\n    const pts = points.map(p => new THREE.Vector2(p[0], p[1]));\n    const geo = new THREE.LatheGeometry(pts, 192);\n    const pos = geo.attributes.position;\n\n    for (let i = 0; i < pos.count; i++) {\n      const x = pos.getX(i), y = pos.getY(i), z = pos.getZ(i);\n      const r = Math.sqrt(x * x + z * z);\n      if (r > 0.04) {\n        const a = Math.atan2(z, x);\n        const n = Math.sin(5 * a + 0.4) * 0.55 +\n                  Math.sin(11 * a + 1.7) * 0.32 +\n                  Math.sin(23 * a + 2.9) * 0.13;\n        const f = 1 + n * wobble;\n        pos.setX(i, x * f);\n        pos.setZ(i, z * f);\n        pos.setY(i, y + wobble * 0.04 * Math.sin(8 * a + y * 7.0) * clamp(r / 2.2, 0, 1));\n      }\n    }\n\n    geo.computeVertexNormals();\n\n    const mesh = new THREE.Mesh(geo, material);\n    mesh.position.y = yOffset;\n    mesh.castShadow = true;\n    mesh.receiveShadow = true;\n    burger.add(mesh);\n    return mesh;\n  }\n\n  organicLathe([\n    [0.00, 0.00],\n    [1.65, 0.00],\n    [2.05, 0.035],\n    [2.22, 0.105],\n    [2.14, 0.205],\n    [1.75, 0.310],\n    [0.55, 0.370],\n    [0.00, 0.350]\n  ], bunMat, 0.00, 0.010);\n\n  organicLathe([\n    [0.00, 0.00],\n    [1.72, 0.00],\n    [2.06, 0.030],\n    [2.20, 0.095],\n    [2.18, 0.215],\n    [1.86, 0.305],\n    [0.72, 0.355],\n    [0.00, 0.330]\n  ], bunMat, 0.86, 0.012);\n\n  organicLathe([\n    [0.00, 0.020],\n    [1.35, 0.020],\n    [1.88, 0.040],\n    [2.16, 0.090],\n    [2.25, 0.180],\n    [2.12, 0.345],\n    [1.72, 0.540],\n    [1.05, 0.685],\n    [0.36, 0.745],\n    [0.00, 0.735]\n  ], bunMat, 1.68, 0.008);\n\n  function createPatty(y, radius, height) {\n    const geo = new THREE.CylinderGeometry(radius * 1.015, radius * 0.995, height, 180, 7, false);\n    const pos = geo.attributes.position;\n\n    for (let i = 0; i < pos.count; i++) {\n      const x = pos.getX(i), yy = pos.getY(i), z = pos.getZ(i);\n      const r = Math.sqrt(x * x + z * z);\n      const a = Math.atan2(z, x);\n      const radial = clamp(r / radius, 0, 1);\n      const edgeNoise =\n        Math.sin(7 * a + 0.5) * 0.026 +\n        Math.sin(15 * a + 2.1) * 0.020 +\n        Math.sin(31 * a + yy * 9.0) * 0.012;\n      const f = 1 + edgeNoise * (0.2 + 0.8 * radial);\n      const surfaceBump =\n        (Math.sin(10.7 * x + 6.1 * z) * 0.010 +\n         Math.sin(17.0 * a + yy * 8.5) * 0.012) * radial;\n\n      pos.setX(i, x * f);\n      pos.setZ(i, z * f);\n      if (Math.abs(yy) > height * 0.22 || radial > 0.82) {\n        pos.setY(i, yy + surfaceBump);\n      }\n    }\n\n    geo.computeVertexNormals();\n\n    const mesh = new THREE.Mesh(geo, pattyMat);\n    mesh.position.y = y;\n    mesh.castShadow = true;\n    mesh.receiveShadow = true;\n    burger.add(mesh);\n    return mesh;\n  }\n\n  createPatty(0.49, 2.04, 0.30);\n  createPatty(1.34, 2.02, 0.31);\n\n  const sphereCharGeo = new THREE.SphereGeometry(1, 8, 6);\n  const circleCharGeo = new THREE.CircleGeometry(1, 12);\n\n  function setRadialBasis(mesh, theta) {\n    const radial = new THREE.Vector3(Math.cos(theta), 0, Math.sin(theta)).normalize();\n    const tangent = new THREE.Vector3(-Math.sin(theta), 0, Math.cos(theta)).normalize();\n    const up = new THREE.Vector3(0, 1, 0);\n    const m = new THREE.Matrix4().makeBasis(tangent, up, radial);\n    mesh.setRotationFromMatrix(m);\n  }\n\n  function addCharMarks(y, radius, height) {\n    for (let i = 0; i < 48; i++) {\n      const theta = rand() * Math.PI * 2;\n      const mesh = new THREE.Mesh(sphereCharGeo, charMat);\n      setRadialBasis(mesh, theta);\n      mesh.position.set(Math.cos(theta) * radius * 1.015, y + randRange(-height * 0.42, height * 0.42), Math.sin(theta) * radius * 1.015);\n      mesh.scale.set(randRange(0.055, 0.15), randRange(0.018, 0.05), randRange(0.010, 0.022));\n      mesh.castShadow = true;\n      burger.add(mesh);\n    }\n\n    for (let i = 0; i < 22; i++) {\n      const r = Math.sqrt(rand()) * radius * 0.76;\n      const theta = rand() * Math.PI * 2;\n      const mesh = new THREE.Mesh(circleCharGeo, charMat);\n      mesh.position.set(Math.cos(theta) * r, y + height * 0.5 + 0.004, Math.sin(theta) * r);\n      mesh.rotation.x = -Math.PI / 2;\n      mesh.rotation.z = rand() * Math.PI;\n      mesh.scale.set(randRange(0.035, 0.12), randRange(0.025, 0.09), 1);\n      burger.add(mesh);\n    }\n  }\n  addCharMarks(0.49, 2.06, 0.30);\n  addCharMarks(1.34, 2.04, 0.31);\n\n  function wavySquareShape(half, amp) {\n    const shape = new THREE.Shape();\n    const pts = [];\n    const steps = 15;\n\n    for (let i = 0; i <= steps; i++) {\n      const t = i / steps;\n      pts.push(new THREE.Vector2(lerp(-half, half, t), -half + Math.sin(t * Math.PI * 3.0) * amp + randRange(-amp, amp) * 0.25));\n    }\n    for (let i = 1; i <= steps; i++) {\n      const t = i / steps;\n      pts.push(new THREE.Vector2(half + Math.sin(t * Math.PI * 2.7) * amp + randRange(-amp, amp) * 0.22, lerp(-half, half, t)));\n    }\n    for (let i = 1; i <= steps; i++) {\n      const t = i / steps;\n      pts.push(new THREE.Vector2(lerp(half, -half, t), half + Math.sin(t * Math.PI * 3.2 + 1.4) * amp + randRange(-amp, amp) * 0.25));\n    }\n    for (let i = 1; i < steps; i++) {\n      const t = i / steps;\n      pts.push(new THREE.Vector2(-half + Math.sin(t * Math.PI * 2.9 + 0.3) * amp + randRange(-amp, amp) * 0.22, lerp(half, -half, t)));\n    }\n\n    shape.moveTo(pts[0].x, pts[0].y);\n    for (let i = 1; i < pts.length; i++) shape.lineTo(pts[i].x, pts[i].y);\n    shape.closePath();\n    return shape;\n  }\n\n  function createCheeseSlice(y, yaw) {\n    const shape = wavySquareShape(1.53, 0.035);\n    const geo = new THREE.ExtrudeGeometry(shape, {\n      depth: 0.038,\n      bevelEnabled: true,\n      bevelSize: 0.018,\n      bevelThickness: 0.012,\n      bevelSegments: 2,\n      curveSegments: 3\n    });\n    geo.computeVertexNormals();\n\n    const mesh = new THREE.Mesh(geo, cheeseMat);\n    mesh.rotation.x = -Math.PI / 2;\n    mesh.rotation.z = yaw;\n    mesh.position.y = y;\n    mesh.castShadow = true;\n    mesh.receiveShadow = true;\n    burger.add(mesh);\n  }\n\n  createCheeseSlice(0.635, 0.72);\n\n  function createCheeseDrip(theta, yTop, radius, width, length) {\n    const shape = new THREE.Shape();\n    shape.moveTo(-width * 0.5, 0);\n    shape.bezierCurveTo(-width * 0.48, -length * 0.22, -width * 0.40, -length * 0.55, -width * 0.22, -length * 0.78);\n    shape.quadraticCurveTo(0, -length * 1.04, width * 0.22, -length * 0.78);\n    shape.bezierCurveTo(width * 0.42, -length * 0.50, width * 0.50, -length * 0.25, width * 0.5, 0);\n    shape.closePath();\n\n    const geo = new THREE.ShapeGeometry(shape, 18);\n    const mesh = new THREE.Mesh(geo, cheeseMat);\n    setRadialBasis(mesh, theta);\n    mesh.position.set(Math.cos(theta) * radius, yTop, Math.sin(theta) * radius);\n    mesh.castShadow = true;\n    burger.add(mesh);\n  }\n\n  createCheeseDrip(Math.PI * 0.41, 0.665, 1.82, 0.36, 0.36);\n  createCheeseDrip(Math.PI * 0.52, 0.665, 1.83, 0.30, 0.28);\n  createCheeseDrip(Math.PI * 0.31, 0.665, 1.78, 0.22, 0.22);\n\n  function createLettuceRing(y, innerR, outerR, phase) {\n    const seg = 192;\n    const rows = 4;\n    const vertices = [];\n    const uvs = [];\n    const indices = [];\n\n    for (let i = 0; i <= seg; i++) {\n      const theta = Math.PI * 2 * i / seg;\n      const wave =\n        1 +\n        0.070 * Math.sin(7 * theta + phase) +\n        0.045 * Math.sin(13 * theta + phase * 0.33) +\n        0.025 * Math.sin(23 * theta + phase * 1.7);\n\n      for (let j = 0; j <= rows; j++) {\n        const f = j / rows;\n        const r = lerp(innerR, outerR * wave, f);\n        const yy = y +\n          (0.045 * Math.sin(11 * theta + phase) + 0.030 * Math.sin(19 * theta + 0.8)) * f +\n          0.015 * Math.sin(5 * theta + f * 4.0) +\n          (f - 0.5) * 0.018;\n        vertices.push(Math.cos(theta) * r, yy, Math.sin(theta) * r);\n        uvs.push(i / seg * 2, f);\n      }\n    }\n\n    for (let i = 0; i < seg; i++) {\n      for (let j = 0; j < rows; j++) {\n        const a = i * (rows + 1) + j;\n        const b = (i + 1) * (rows + 1) + j;\n        const c = b + 1;\n        const d = a + 1;\n        indices.push(a, b, d, b, c, d);\n      }\n    }\n\n    const geo = new THREE.BufferGeometry();\n    geo.setAttribute(\"position\", new THREE.Float32BufferAttribute(vertices, 3));\n    geo.setAttribute(\"uv\", new THREE.Float32BufferAttribute(uvs, 2));\n    geo.setIndex(indices);\n    geo.computeVertexNormals();\n\n    const mesh = new THREE.Mesh(geo, lettuceMat);\n    mesh.castShadow = true;\n    mesh.receiveShadow = true;\n    burger.add(mesh);\n  }\n\n  createLettuceRing(0.775, 0.62, 2.30, 0.7);\n  createLettuceRing(1.605, 0.58, 2.34, 2.1);\n\n  function createSauceRing(y, innerR, outerR, phase) {\n    const seg = 160;\n    const rows = 2;\n    const vertices = [];\n    const uvs = [];\n    const indices = [];\n\n    for (let i = 0; i <= seg; i++) {\n      const theta = Math.PI * 2 * i / seg;\n      const wave = 1 + 0.04 * Math.sin(8 * theta + phase) + 0.025 * Math.sin(17 * theta + phase);\n      for (let j = 0; j <= rows; j++) {\n        const f = j / rows;\n        const r = lerp(innerR, outerR * wave, f);\n        vertices.push(Math.cos(theta) * r, y + 0.018 * Math.sin(10 * theta + phase) * f, Math.sin(theta) * r);\n        uvs.push(i / seg, f);\n      }\n    }\n\n    for (let i = 0; i < seg; i++) {\n      for (let j = 0; j < rows; j++) {\n        const a = i * (rows + 1) + j;\n        const b = (i + 1) * (rows + 1) + j;\n        indices.push(a, b, a + 1, b, b + 1, a + 1);\n      }\n    }\n\n    const geo = new THREE.BufferGeometry();\n    geo.setAttribute(\"position\", new THREE.Float32BufferAttribute(vertices, 3));\n    geo.setAttribute(\"uv\", new THREE.Float32BufferAttribute(uvs, 2));\n    geo.setIndex(indices);\n    geo.computeVertexNormals();\n\n    const mesh = new THREE.Mesh(geo, sauceMat);\n    mesh.castShadow = true;\n    mesh.receiveShadow = true;\n    burger.add(mesh);\n  }\n\n  createSauceRing(0.735, 1.35, 2.05, 1.1);\n  createSauceRing(1.555, 1.30, 2.04, 2.4);\n\n  const sauceBlobGeo = new THREE.SphereGeometry(1, 18, 12);\n  function addSauceBlobs(y, count, radius, phase) {\n    for (let i = 0; i < count; i++) {\n      const theta = Math.PI * 2 * (i / count) + randRange(-0.065, 0.065) + phase;\n      const mesh = new THREE.Mesh(sauceBlobGeo, sauceMat);\n      setRadialBasis(mesh, theta);\n      const r = radius + randRange(-0.10, 0.09);\n      mesh.position.set(Math.cos(theta) * r, y + randRange(-0.016, 0.018), Math.sin(theta) * r);\n      mesh.scale.set(randRange(0.10, 0.25), randRange(0.035, 0.075), randRange(0.07, 0.16));\n      mesh.castShadow = true;\n      burger.add(mesh);\n\n      if (rand() > 0.74) {\n        const drip = new THREE.Mesh(sauceBlobGeo, sauceMat);\n        setRadialBasis(drip, theta);\n        drip.position.set(Math.cos(theta) * (r + 0.015), y - randRange(0.06, 0.13), Math.sin(theta) * (r + 0.015));\n        drip.scale.set(randRange(0.045, 0.085), randRange(0.09, 0.20), randRange(0.035, 0.075));\n        drip.castShadow = true;\n        burger.add(drip);\n      }\n    }\n  }\n\n  addSauceBlobs(0.735, 26, 2.03, 0.1);\n  addSauceBlobs(1.555, 30, 2.05, 0.25);\n\n  function addPickle(x, z, y, scale, rot) {\n    const group = new THREE.Group();\n    group.position.set(x, y, z);\n    group.rotation.y = rot;\n\n    const side = new THREE.Mesh(new THREE.CylinderGeometry(0.23 * scale, 0.23 * scale, 0.047, 48, 1), pickleSideMat);\n    side.castShadow = true;\n    side.receiveShadow = true;\n    group.add(side);\n\n    const top = new THREE.Mesh(new THREE.CircleGeometry(0.225 * scale, 48), pickleTopMat);\n    top.rotation.x = -Math.PI / 2;\n    top.position.y = 0.025;\n    top.receiveShadow = true;\n    group.add(top);\n\n    burger.add(group);\n  }\n\n  addPickle(-0.92, 1.22, 0.825, 1.0, 0.4);\n  addPickle(0.14, 1.48, 0.825, 0.95, 1.7);\n  addPickle(1.05, 1.05, 0.825, 1.05, 2.5);\n  addPickle(-1.45, 0.42, 0.825, 0.9, 0.8);\n\n  const onionGeo = new THREE.BoxGeometry(1, 1, 1);\n  function sprinkleOnions(y, count, inner, outer) {\n    for (let i = 0; i < count; i++) {\n      const theta = rand() * Math.PI * 2;\n      const r = lerp(inner, outer, Math.pow(rand(), 0.62));\n      const mesh = new THREE.Mesh(onionGeo, onionMat);\n      mesh.position.set(Math.cos(theta) * r, y + randRange(-0.018, 0.018), Math.sin(theta) * r);\n      mesh.rotation.set(rand() * Math.PI, rand() * Math.PI, rand() * Math.PI);\n      mesh.scale.set(randRange(0.035, 0.085), randRange(0.014, 0.035), randRange(0.030, 0.075));\n      mesh.castShadow = true;\n      burger.add(mesh);\n    }\n  }\n  sprinkleOnions(0.815, 46, 0.75, 2.06);\n  sprinkleOnions(1.615, 58, 0.72, 2.07);\n\n  const seedGeo = new THREE.SphereGeometry(1, 14, 8);\n  const topBase = 1.68;\n  const domeR = 2.18;\n  function domeY(r) {\n    const rr = domeR * 0.96;\n    const t = clamp(1 - (r * r) / (rr * rr), 0, 1);\n    return topBase + 0.065 + 0.655 * Math.pow(t, 0.56);\n  }\n  function domeDYDR(r) {\n    const rr = domeR * 0.96;\n    const t = clamp(1 - (r * r) / (rr * rr), 0.001, 1);\n    return 0.655 * 0.56 * Math.pow(t, -0.44) * (-2 * r / (rr * rr));\n  }\n\n  for (let i = 0; i < 96; i++) {\n    const theta = rand() * Math.PI * 2;\n    const r = Math.sqrt(rand()) * 1.74;\n    const y = domeY(r);\n    const normal = new THREE.Vector3(\n      -domeDYDR(r) * Math.cos(theta),\n      1,\n      -domeDYDR(r) * Math.sin(theta)\n    ).normalize();\n\n    const seed = new THREE.Mesh(seedGeo, seedMat);\n    seed.position.set(Math.cos(theta) * r, y + 0.018, Math.sin(theta) * r);\n    seed.scale.set(randRange(0.038, 0.055), randRange(0.015, 0.023), randRange(0.085, 0.135));\n\n    const q = new THREE.Quaternion().setFromUnitVectors(new THREE.Vector3(0, 1, 0), normal);\n    const twist = new THREE.Quaternion().setFromAxisAngle(normal, rand() * Math.PI * 2);\n    seed.quaternion.copy(twist.multiply(q));\n\n    seed.castShadow = true;\n    seed.receiveShadow = true;\n    burger.add(seed);\n  }\n\n  const clock = new THREE.Clock();\n\n  function animate() {\n    requestAnimationFrame(animate);\n    const dt = clock.getDelta();\n    burger.rotation.y += dt * 0.18;\n    controls.update();\n    renderer.render(scene, camera);\n  }\n\n  function onResize() {\n    const w = window.innerWidth;\n    const h = window.innerHeight;\n    camera.aspect = w / h;\n    camera.updateProjectionMatrix();\n    renderer.setSize(w, h);\n    renderer.setPixelRatio(Math.min(window.devicePixelRatio || 1, 2));\n  }\n\n  window.addEventListener(\"resize\", onResize, { passive: true });\n  animate();\n})();\n</script>\n</body>\n</html>\n```"
}