Guest User

Untitled

a guest
Aug 3rd, 2026
299
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
HTML 12.63 KB | None | 0 0
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <title>Döner Kebab Simulation</title>
  7. <style>
  8.     body, html {
  9.         margin: 0;
  10.         padding: 0;
  11.         overflow: hidden;
  12.         background: #000;
  13.     }
  14.     canvas {
  15.         display: block;
  16.         width: 100%;
  17.         height: 100%;
  18.         background: linear-gradient(to bottom, #1a1a1a, #2b2b2b, #1a1a1a);
  19.     }
  20. </style>
  21. </head>
  22. <body>
  23. <canvas id="canvas"></canvas>
  24. <script>
  25. (function(){
  26.     const canvas = document.getElementById('canvas');
  27.     const ctx = canvas.getContext('2d');
  28.     let W, H;
  29.     let centerX, radius, topY, bottomY;
  30.     let alpha = 0; // rotation angle in radians
  31.  
  32.     // Texture generation
  33.     const texSize = 128;
  34.     const textureCanvas = document.createElement('canvas');
  35.     textureCanvas.width = texSize;
  36.     textureCanvas.height = texSize;
  37.     const texCtx = textureCanvas.getContext('2d');
  38.     const texImage = texCtx.createImageData(texSize, texSize);
  39.     const texData = texImage.data;
  40.  
  41.     // Generates a seamless, blotchy meat texture
  42.     function generateTexture() {
  43.         const size = texSize;
  44.         // Simple deterministic pseudo-random
  45.         function noise(px, py) {
  46.             const u = px / size;
  47.             const v = py / size;
  48.             // sum of sines for smooth periodic pattern
  49.             let n = 0.5 + 0.5*Math.sin(u * 2 * Math.PI * 2 + v * 2 * Math.PI * 3) * 0.6;
  50.             n += 0.4 * Math.cos(u * 2 * Math.PI * 3 - v * 2 * Math.PI * 5);
  51.             n += 0.3 * Math.sin(u * 2 * Math.PI * 5 + v * 2 * Math.PI * 1);
  52.             n += 0.2 * Math.cos(u * 2 * Math.PI * 1 + v * 2 * Math.PI * 7);
  53.             // Add blotches using a second frequency
  54.             const blotch = 0.5 + 0.5 * Math.sin(u * 2 * Math.PI * 10) * Math.sin(v * 2 * Math.PI * 8);
  55.             n = (n + blotch) / 2;
  56.             return n;
  57.         }
  58.  
  59.         for (let y = 0; y < size; y++) {
  60.            for (let x = 0; x < size; x++) {
  61.                const n = noise(x, y);
  62.                // Base meat color: brownish
  63.                let r = 120 + 40 * n;
  64.                let g = 55 + 20 * n;
  65.                let b = 20 + 15 * n;
  66.                // Add darker charry spots
  67.                const spot = Math.sin(x * 0.05 + y * 0.07) * 0.5 + noise(x*2, y*2);
  68.                if (spot > 0.65) {
  69.                     r *= 0.8; g *= 0.8; b *= 0.8;
  70.                 }
  71.                 // Add lighter fat streaks
  72.                 if (Math.sin(x * 0.1 + y * 0.02) > 0.8) {
  73.                     r += 30; g += 20; b += 10;
  74.                 }
  75.                 const idx = (y * size + x) * 4;
  76.                 texData[idx] = Math.min(255, Math.max(0, r));
  77.                 texData[idx+1] = Math.min(255, Math.max(0, g));
  78.                 texData[idx+2] = Math.min(255, Math.max(0, b));
  79.                 texData[idx+3] = 255;
  80.             }
  81.         }
  82.         texCtx.putImageData(texImage, 0, 0);
  83.     }
  84.  
  85.     generateTexture();
  86.  
  87.     // Offscreen canvas for kebab
  88.     let kebabCanvas;
  89.  
  90.     function resize() {
  91.         W = window.innerWidth;
  92.         H = window.innerHeight;
  93.         canvas.width = W;
  94.         canvas.height = H;
  95.         // Adjust positions based on window
  96.         centerX = W * 0.42;
  97.         radius = Math.min(W, H) * 0.16;
  98.         topY = H * 0.12;
  99.         bottomY = H * 0.83;
  100.         // Prepare offscreen canvas for kebab
  101.         const w = Math.ceil(2 * radius) + 2;
  102.         const h = Math.ceil(bottomY - topY) + 2;
  103.         kebabCanvas = document.createElement('canvas');
  104.         kebabCanvas.width = w;
  105.         kebabCanvas.height = h;
  106.     }
  107.     resize();
  108.     window.addEventListener('resize', resize);
  109.  
  110.     // Utility to wrap a number in [0,1)
  111.     function wrap01(x) {
  112.         return x - Math.floor(x);
  113.     }
  114.  
  115.     // Draw the kebab using image data mapping
  116.     function drawKebab(time) {
  117.         if (!kebabCanvas) return;
  118.         const w = kebabCanvas.width;
  119.         const h = kebabCanvas.height;
  120.         const offCenterX = Math.ceil(radius);
  121.         const offTop = topY;
  122.         const ctxKeb = kebabCanvas.getContext('2d');
  123.         const imgData = ctxKeb.createImageData(w, h);
  124.         const data = imgData.data;
  125.         const texData = texCtx.getImageData(0,0,texSize,texSize).data;
  126.         const r = radius;
  127.         const height = bottomY - topY;
  128.  
  129.         // Precompute lighting factor for angle: bright on right, dark on left
  130.         // We'll compute per pixel.
  131.         for (let y = 0; y < h; y++) {
  132.            const v = y / (h - 1); // 0 at top, 1 at bottom
  133.            // v coordinate for texture: we want vertical variation, but maybe not stretch? Use as is.
  134.            const texY = Math.min(texSize-1, Math.floor(v * (texSize-1)));
  135.            const yWorld = topY + y;
  136.            // Skip if outside? We'll compute everything and set alpha 0 if not on cylinder.
  137.            for (let x = 0; x < w; x++) {
  138.                const dx = x - offCenterX; // relative to center
  139.                const absDx = Math.abs(dx);
  140.                // Check if within cylinder radius
  141.                if (absDx <= r) {
  142.                    const phi = Math.asin(dx / r); // angle in [-π/2, π/2]
  143.                    // Texture u: (phi + alpha) / 2π
  144.                    let u = (phi + alpha) / (2 * Math.PI);
  145.                    u = wrap01(u);
  146.                    // Sample texture
  147.                    const texX = Math.min(texSize-1, Math.floor(u * (texSize-1)));
  148.                    const idx = (texY * texSize + texX) * 4;
  149.                    let R = texData[idx];
  150.                    let G = texData[idx+1];
  151.                    let B = texData[idx+2];
  152.                    // Lighting: right side (phi>0) lit, left dark.
  153.                     let light = 0.4 + 0.6 * (phi + Math.PI/2) / Math.PI; // 0 to 1
  154.                     // Add a slight vertical variation: hotter near middle
  155.                     const verticalLight = 0.85 + 0.15 * Math.sin(v * Math.PI);
  156.                     light *= verticalLight;
  157.                     // Add flicker from flames? Maybe based on time? We'll keep static.
  158.                     R = Math.min(255, Math.max(0, R * light));
  159.                     G = Math.min(255, Math.max(0, G * light));
  160.                     B = Math.min(255, Math.max(0, B * light));
  161.                     // Set pixel
  162.                     const dataIdx = (y * w + x) * 4;
  163.                     data[dataIdx] = R;
  164.                     data[dataIdx+1] = G;
  165.                     data[dataIdx+2] = B;
  166.                     data[dataIdx+3] = 255;
  167.                 } else {
  168.                     // Outside cylinder: transparent
  169.                     const dataIdx = (y * w + x) * 4;
  170.                     data[dataIdx+3] = 0;
  171.                 }
  172.             }
  173.         }
  174.         ctxKeb.putImageData(imgData, 0, 0);
  175.         // Draw the kebab canvas onto main canvas
  176.         ctx.drawImage(kebabCanvas, centerX - offCenterX, topY);
  177.     }
  178.  
  179.     // Draw the skewer stick (vertical metal rod)
  180.     function drawSkewer() {
  181.         ctx.save();
  182.         const stickWidth = Math.max(2, radius * 0.06);
  183.         // Metal gradient
  184.         const gradient = ctx.createLinearGradient(centerX - stickWidth/2, 0, centerX + stickWidth/2, 0);
  185.         gradient.addColorStop(0, '#888');
  186.         gradient.addColorStop(0.5, '#ddd');
  187.         gradient.addColorStop(1, '#555');
  188.         ctx.fillStyle = gradient;
  189.         ctx.fillRect(centerX - stickWidth/2, topY - 20, stickWidth, bottomY - topY + 40);
  190.         // Add top and bottom handles
  191.         ctx.fillStyle = '#999';
  192.         ctx.beginPath();
  193.         ctx.arc(centerX, topY - 20, stickWidth*1.2, 0, Math.PI*2);
  194.         ctx.fill();
  195.         ctx.fillStyle = '#aaa';
  196.         ctx.beginPath();
  197.         ctx.arc(centerX, bottomY + 20, stickWidth*1.2, 0, Math.PI*2);
  198.         ctx.fill();
  199.         ctx.restore();
  200.     }
  201.  
  202.     // Draw heating element with flickering gas flames
  203.     function drawHeatingElement(time) {
  204.         // Position: to the right of the kebab
  205.         const bx = centerX + radius + 35; // heating element x
  206.         const by = topY - 10;
  207.         const bh = bottomY - topY + 20;
  208.  
  209.         // Metal backing: dark red glowing grill
  210.         const metalGrad = ctx.createLinearGradient(bx - 10, 0, bx + 10, 0);
  211.         metalGrad.addColorStop(0, '#300');
  212.         metalGrad.addColorStop(0.5, '#500');
  213.         metalGrad.addColorStop(1, '#200');
  214.         ctx.fillStyle = metalGrad;
  215.         ctx.fillRect(bx - 5, by, 15, bh);
  216.  
  217.         // Gas flames: multiple small burners
  218.         const flameCount = 8;
  219.         const flameSpacing = bh / (flameCount + 1);
  220.         for (let i = 0; i < flameCount; i++) {
  221.            const fy = by + (i+1) * flameSpacing;
  222.            // Flicker using time and index
  223.            const flicker = 0.6 + 0.4 * Math.sin(time * 0.005 + i * 1.7);
  224.            const flameHeight = 30 * flicker + 15;
  225.            // Flame shape: drawn as an ellipse with gradient
  226.            const grad = ctx.createRadialGradient(bx + 7, fy - 5, 0, bx + 7, fy, flameHeight*0.8);
  227.            grad.addColorStop(0, '#ffdd00');
  228.            grad.addColorStop(0.3, '#ff8800');
  229.            grad.addColorStop(0.6, '#ff4400');
  230.            grad.addColorStop(1, 'rgba(50,0,0,0)');
  231.            ctx.fillStyle = grad;
  232.            ctx.beginPath();
  233.            ctx.ellipse(bx + 7, fy - flameHeight/2, flameHeight*0.5, flameHeight*0.9, 0, 0, Math.PI*2);
  234.            ctx.fill();
  235.  
  236.            // Inner blue flame
  237.            const grad2 = ctx.createRadialGradient(bx + 7, fy, 0, bx + 7, fy, flameHeight*0.4);
  238.            grad2.addColorStop(0, 'rgba(0,200,255,0.8)');
  239.            grad2.addColorStop(0.5, 'rgba(0,100,200,0.4)');
  240.            grad2.addColorStop(1, 'rgba(0,0,100,0)');
  241.            ctx.fillStyle = grad2;
  242.            ctx.beginPath();
  243.            ctx.ellipse(bx + 7, fy - flameHeight*0.3, flameHeight*0.2, flameHeight*0.6, 0, 0, Math.PI*2);
  244.            ctx.fill();
  245.        }
  246.  
  247.        // Ambient glow on the right side
  248.        const glow = ctx.createRadialGradient(bx + 7, by + bh/2, 0, bx + 7, by + bh/2, radius*3);
  249.        glow.addColorStop(0, 'rgba(255,80,0,0.35)');
  250.        glow.addColorStop(1, 'rgba(255,80,0,0)');
  251.        ctx.fillStyle = glow;
  252.        ctx.fillRect(0,0,W,H);
  253.    }
  254.  
  255.    // Draw some dripping fat and smoke
  256.    function drawExtras(time) {
  257.        // Fat drips from kebab bottom
  258.        const dripCount = 3;
  259.        for (let i=0; i<dripCount; i++) {
  260.            const x = centerX + radius * 0.5 * Math.sin(time*0.001 + i*2);
  261.            const y = bottomY - 10 + Math.sin(time*0.01 + i) * 5;
  262.            const size = 2 + Math.sin(time*0.02+i)*1;
  263.            ctx.fillStyle = 'rgba(255,220,150,0.6)';
  264.            ctx.beginPath();
  265.            ctx.ellipse(x, y, size, size*1.5, 0, 0, Math.PI*2);
  266.            ctx.fill();
  267.        }
  268.  
  269.        // Smoke particles
  270.        ctx.fillStyle = 'rgba(128,128,128,0.15)';
  271.        for (let i=0; i<10; i++) {
  272.            const x = centerX + radius * (Math.sin(time*0.0007 + i) * 0.8);
  273.            const y = topY + Math.random() * (bottomY - topY);
  274.            const size = 10 + 5 * Math.sin(time*0.003 + i);
  275.            ctx.beginPath();
  276.            ctx.arc(x, y, size, 0, Math.PI*2);
  277.            ctx.fill();
  278.        }
  279.    }
  280.  
  281.    // Draw background tile wall
  282.    function drawBackground() {
  283.        // Dark gradient already set in style? We'll override with canvas
  284.        const grad = ctx.createLinearGradient(0,0,0,H);
  285.        grad.addColorStop(0, '#1a1a1a');
  286.        grad.addColorStop(0.5, '#222222');
  287.        grad.addColorStop(1, '#1a1a1a');
  288.        ctx.fillStyle = grad;
  289.        ctx.fillRect(0,0,W,H);
  290.        // Subtle tiles
  291.        ctx.strokeStyle = 'rgba(255,255,255,0.05)';
  292.        ctx.lineWidth = 1;
  293.        const tileSize = 80;
  294.        for (let y=0; y<H; y+=tileSize) {
  295.            for (let x=0; x<W; x+=tileSize) {
  296.                ctx.strokeRect(x, y, tileSize, tileSize);
  297.            }
  298.        }
  299.        // Light from flame on the right wall
  300.        ctx.fillStyle = 'rgba(255,120,0,0.05)';
  301.        ctx.fillRect(0,0,W,H);
  302.    }
  303.    // Main animation loop
  304.    function animate(time) {
  305.        // Update rotation speed
  306.        alpha += 0.018; // radians per frame
  307.        // Clear and draw background
  308.        drawBackground();
  309.        // Draw heating element (behind kebab)
  310.        drawHeatingElement(time);
  311.        // Draw kebab
  312.        drawKebab(time);
  313.        // Draw skewer (should be on top of kebab? Actually skewer goes through, visible where meat ends)
  314.        // We draw after kebab so it's visible
  315.        drawSkewer();
  316.  
  317.        // Extras like drips and smoke
  318.        drawExtras(time);
  319.  
  320.        requestAnimationFrame(animate);
  321.    }
  322.  
  323.    requestAnimationFrame(animate);
  324. })();
  325. </script>
  326. </body>
  327. </html>
  328.  
Advertisement
Add Comment
Please, Sign In to add comment