nurjns

Feuerwerk Website

Jan 3rd, 2026
3,769
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
HTML 13.43 KB | None | 0 0
  1. <!DOCTYPE html>
  2. <html lang="de">
  3. <head>
  4.     <meta charset="UTF-8">
  5.     <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6.     <title>Feuerwerk Simulator</title>
  7.     <style>
  8.         body {
  9.             margin: 0;
  10.             overflow: hidden;
  11.             background: #020202;
  12.             font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
  13.             color: white;
  14.             user-select: none;
  15.         }
  16.  
  17.         canvas {
  18.             display: block;
  19.             cursor: crosshair;
  20.         }
  21.  
  22.         /* Container für alle Controls */
  23.         #ui-container {
  24.             position: absolute;
  25.             bottom: 30px;
  26.             left: 50%;
  27.             transform: translateX(-50%);
  28.             display: flex;
  29.             flex-direction: column;
  30.             align-items: center;
  31.             gap: 15px;
  32.             z-index: 10;
  33.             width: 90%;
  34.             max-width: 800px;
  35.             transition: opacity 0.5s; /* Für das Ausblenden im Fullscreen */
  36.         }
  37.  
  38.         /* Die Leiste für die Varianten */
  39.         #controls-variants {
  40.             background: rgba(20, 20, 20, 0.8);
  41.             backdrop-filter: blur(10px);
  42.             padding: 15px 25px;
  43.             border-radius: 50px;
  44.             display: flex;
  45.             flex-wrap: wrap;
  46.             justify-content: center;
  47.             gap: 10px;
  48.             box-shadow: 0 10px 30px rgba(0,0,0,0.5);
  49.             border: 1px solid rgba(255,255,255,0.1);
  50.         }
  51.  
  52.         /* Controls für Dauerfeuer und Fullscreen */
  53.         #controls-utility {
  54.             display: flex;
  55.             gap: 10px;
  56.         }
  57.  
  58.         .btn {
  59.             background: transparent;
  60.             border: 1px solid rgba(255, 255, 255, 0.3);
  61.             color: #ccc;
  62.             padding: 10px 18px;
  63.             border-radius: 25px;
  64.             cursor: pointer;
  65.             transition: all 0.3s ease;
  66.             font-size: 13px;
  67.             font-weight: 600;
  68.             text-transform: uppercase;
  69.             letter-spacing: 1px;
  70.             white-space: nowrap;
  71.         }
  72.  
  73.         .btn:hover {
  74.             background: rgba(255, 255, 255, 0.1);
  75.             color: white;
  76.             border-color: white;
  77.         }
  78.  
  79.         .btn.active {
  80.             background: white;
  81.             color: black;
  82.             border-color: white;
  83.             box-shadow: 0 0 15px rgba(255, 255, 255, 0.4);
  84.         }
  85.  
  86.         #auto-btn.auto-active {
  87.             background: #4CAF50; /* Grün */
  88.             color: white;
  89.             border-color: #4CAF50;
  90.             box-shadow: 0 0 20px rgba(76, 175, 80, 0.6);
  91.         }
  92.  
  93.         #fullscreen-btn {
  94.             background: #FF9800; /* Orange */
  95.             color: white;
  96.             border: 1px solid #FF9800;
  97.         }
  98.         #fullscreen-btn:hover {
  99.             background: #E68A00;
  100.         }
  101.  
  102.         #instructions {
  103.             position: absolute;
  104.             top: 20px;
  105.             width: 100%;
  106.             text-align: center;
  107.             pointer-events: none;
  108.             opacity: 0.7;
  109.             font-weight: 300;
  110.             text-shadow: 0 2px 5px black;
  111.             transition: opacity 1.5s ease-out; /* Für das Ausfaden */
  112.         }
  113.  
  114.         /* Spezifische Anweisung im Fullscreen Modus */
  115.         .fullscreen-active #instructions {
  116.             opacity: 1;
  117.         }
  118.        
  119.         /* Klasse für das Ausfaden */
  120.         .fade-out {
  121.             opacity: 0 !important;
  122.         }
  123.     </style>
  124. </head>
  125. <body id="body">
  126.  
  127.     <div id="instructions">Klicke zum Zünden oder aktiviere Dauerfeuer!</div>
  128.  
  129.     <div id="ui-container">
  130.         <div id="controls-utility">
  131.             <button id="auto-btn" class="btn" onclick="toggleAutoFire()">Dauerfeuer: AUS</button>
  132.             <button id="fullscreen-btn" class="btn" onclick="toggleFullscreen()">Full-Screen Modus</button>
  133.         </div>
  134.  
  135.         <div id="controls-variants">
  136.             <button class="btn active variant-btn" onclick="setMode('bunt', this)">Bunt</button>
  137.             <button class="btn variant-btn" onclick="setMode('gold', this)">Goldregen</button>
  138.             <button class="btn variant-btn" onclick="setMode('silber', this)">Silber-Blitz</button>
  139.             <button class="btn variant-btn" onclick="setMode('neon', this)">Neon</button>
  140.             <button class="btn variant-btn" onclick="setMode('palme', this)">Palme</button>
  141.             <button class="btn variant-btn" onclick="setMode('geist', this)">Geist</button>
  142.         </div>
  143.     </div>
  144.  
  145.     <canvas id="canvas"></canvas>
  146.  
  147.     <script>
  148.         // --- SETUP ---
  149.         const canvas = document.getElementById('canvas');
  150.         const ctx = canvas.getContext('2d');
  151.         const body = document.getElementById('body');
  152.         const instructions = document.getElementById('instructions');
  153.         let cw = window.innerWidth;
  154.         let ch = window.innerHeight;
  155.         let fadeOutTimer = null;
  156.  
  157.         canvas.width = cw;
  158.         canvas.height = ch;
  159.         window.addEventListener('resize', () => {
  160.             cw = window.innerWidth;
  161.             ch = window.innerHeight;
  162.             canvas.width = cw;
  163.             canvas.height = ch;
  164.         });
  165.  
  166.         // --- ERWEITERTE KONFIGURATION & NEUE PHYSIK ---
  167.         let currentMode = 'bunt';
  168.         let dauerfeuerAktiv = false;
  169.         let dauerfeuerTimer = null;
  170.         let isFullscreen = false;
  171.  
  172.         const modes = {
  173.             // [GEÄNDERT] Decay und Speed reduziert, um länger zu halten
  174.             bunt: {
  175.                 hueMin: 0, hueMax: 360, saturation: 100,
  176.                 friction: 0.94, gravity: 1.2,
  177.                 countMin: 80, countMax: 180, // Zufällige Größe
  178.                 decay: 0.008, speed: 5
  179.             },
  180.             // [GEÄNDERT] Gravity deutlich niedriger für langes Schweben
  181.             gold: {
  182.                 hueMin: 35, hueMax: 45, saturation: 100,
  183.                 friction: 0.97, gravity: 0.5, // Sehr niedrige Schwerkraft
  184.                 countMin: 120, countMax: 250,
  185.                 decay: 0.005, speed: 3.5 // Langsamere Ausbreitung
  186.             },
  187.             // [GEÄNDERT] Decay und Friction leicht reduziert
  188.             silber: {
  189.                 hueMin: 0, hueMax: 360, saturation: 0,
  190.                 friction: 0.95, gravity: 1.2,
  191.                 countMin: 60, countMax: 100,
  192.                 decay: 0.015, speed: 8, brightnessMin: 80
  193.             },
  194.             // [GEÄNDERT] Decay reduziert
  195.             neon: {
  196.                 hueMin: 180, hueMax: 320, saturation: 100,
  197.                 friction: 0.93, gravity: 1,
  198.                 countMin: 50, countMax: 120,
  199.                 decay: 0.015, speed: 10
  200.             },
  201.             // [GEÄNDERT] Decay reduziert, damit die "Blätter" länger sichtbar fallen
  202.             palme: {
  203.                 hueMin: 20, hueMax: 30, saturation: 90,
  204.                 friction: 0.99,
  205.                 gravity: 2.5,
  206.                 countMin: 100, countMax: 200,
  207.                 decay: 0.008, speed: 4
  208.             },
  209.             // [GEÄNDERT] Decay stark reduziert, um länger zu verweilen
  210.             geist: {
  211.                 hueMin: 200, hueMax: 260, saturation: 60,
  212.                 friction: 0.96, gravity: 0.5,
  213.                 countMin: 40, countMax: 90,
  214.                 decay: 0.01, speed: 3, brightnessMin: 30
  215.             }
  216.         };
  217.  
  218.         // --- KLASSEN ---
  219.  
  220.         // 1. Die Rakete
  221.         class Firework {
  222.             constructor(sx, sy, tx, ty) {
  223.                 this.x = sx; this.y = sy;
  224.                 this.sx = sx; this.sy = sy;
  225.                 this.tx = tx; this.ty = ty;
  226.                 this.distanceToTarget = calculateDistance(sx, sy, tx, ty);
  227.                 this.distanceTraveled = 0;
  228.                 this.coordinates = [];
  229.                 this.coordinateCount = 3;
  230.                 while(this.coordinateCount--) { this.coordinates.push([this.x, this.y]); }
  231.                 this.angle = Math.atan2(ty - sy, tx - sx);
  232.                 // [GEÄNDERT] Aufstiegsgeschwindigkeit leicht reduziert
  233.                 this.speed = 1.8;
  234.                 this.acceleration = 1.04;
  235.                 const mode = modes[currentMode];
  236.                 this.brightness = Math.random() * 40 + 60;
  237.                 this.hue = Math.floor(Math.random() * (mode.hueMax - mode.hueMin + 1)) + mode.hueMin;
  238.                 this.saturation = mode.saturation;
  239.             }
  240.  
  241.             update(index) {
  242.                 this.coordinates.pop();
  243.                 this.coordinates.unshift([this.x, this.y]);
  244.                 this.speed *= this.acceleration;
  245.                 const vx = Math.cos(this.angle) * this.speed;
  246.                 const vy = Math.sin(this.angle) * this.speed;
  247.                 this.distanceTraveled = calculateDistance(this.sx, this.sy, this.x + vx, this.y + vy);
  248.                
  249.                 if(this.distanceTraveled >= this.distanceToTarget) {
  250.                     createParticles(this.tx, this.ty, this.hue);
  251.                     fireworks.splice(index, 1);
  252.                 } else {
  253.                     this.x += vx;
  254.                     this.y += vy;
  255.                 }
  256.             }
  257.  
  258.             draw() {
  259.                 ctx.beginPath();
  260.                 ctx.moveTo(this.coordinates[this.coordinates.length - 1][0], this.coordinates[this.coordinates.length - 1][1]);
  261.                 ctx.lineTo(this.x, this.y);
  262.                 ctx.strokeStyle = `hsl(${this.hue}, ${this.saturation}%, ${this.brightness}%)`;
  263.                 ctx.stroke();
  264.             }
  265.         }
  266.  
  267.         // 2. Die Partikel
  268.         class Particle {
  269.             constructor(x, y, hue) {
  270.                 const mode = modes[currentMode];
  271.                 this.x = x; this.y = y;
  272.                 this.coordinates = [];
  273.                 this.coordinateCount = 6;
  274.                 while(this.coordinateCount--) { this.coordinates.push([this.x, this.y]); }
  275.                
  276.                 this.angle = Math.random() * Math.PI * 2;
  277.                 // [GEÄNDERT] Anfangsgeschwindigkeit leicht niedriger
  278.                 this.speed = Math.random() * mode.speed + 0.5;
  279.                 this.friction = mode.friction;
  280.                 this.gravity = mode.gravity;
  281.                 this.hue = Math.floor(Math.random() * (mode.hueMax - mode.hueMin + 1)) + mode.hueMin;
  282.                 this.saturation = mode.saturation;
  283.                
  284.                 let bMin = mode.brightnessMin !== undefined ? mode.brightnessMin : 50;
  285.                 this.brightness = Math.random() * (100 - bMin) + bMin;
  286.                
  287.                 this.alpha = 1;
  288.                 this.decay = Math.random() * mode.decay + mode.decay/2;
  289.             }
  290.  
  291.             update(index) {
  292.                 this.coordinates.pop();
  293.                 this.coordinates.unshift([this.x, this.y]);
  294.                 this.speed *= this.friction;
  295.                 this.x += Math.cos(this.angle) * this.speed;
  296.                 this.y += Math.sin(this.angle) * this.speed + this.gravity;
  297.                 this.alpha -= this.decay;
  298.                 if(this.alpha <= this.decay) { particles.splice(index, 1); }
  299.             }
  300.  
  301.             draw() {
  302.                 ctx.beginPath();
  303.                 ctx.moveTo(this.coordinates[this.coordinates.length - 1][0], this.coordinates[this.coordinates.length - 1][1]);
  304.                 ctx.lineTo(this.x, this.y);
  305.                 ctx.strokeStyle = `hsla(${this.hue}, ${this.saturation}%, ${this.brightness}%, ${this.alpha})`;
  306.                 ctx.stroke();
  307.             }
  308.         }
  309.  
  310.         // --- ENGINE LOGIK ---
  311.         const fireworks = [];
  312.         const particles = [];
  313.  
  314.         function calculateDistance(p1x, p1y, p2x, p2y) {
  315.             const xDistance = p1x - p2x;
  316.             const yDistance = p1y - p2y;
  317.             return Math.sqrt(Math.pow(xDistance, 2) + Math.pow(yDistance, 2));
  318.         }
  319.  
  320.         // [GEÄNDERT] Erzeugt eine zufällige Anzahl von Partikeln (klein bis groß)
  321.         function createParticles(x, y, hue) {
  322.             const mode = modes[currentMode];
  323.            
  324.             // Zufällige Partikelanzahl innerhalb des definierten Min/Max-Bereichs
  325.             const count = Math.floor(Math.random() * (mode.countMax - mode.countMin + 1)) + mode.countMin;
  326.            
  327.             for(let i = 0; i < count; i++) {
  328.                 particles.push(new Particle(x, y, hue));
  329.             }
  330.         }
  331.  
  332.         function loop() {
  333.             requestAnimationFrame(loop);
  334.             ctx.globalCompositeOperation = 'destination-out';
  335.             ctx.fillStyle = 'rgba(0, 0, 0, 0.5)';
  336.             ctx.fillRect(0, 0, cw, ch);
  337.             ctx.globalCompositeOperation = 'lighter';
  338.  
  339.             let i = fireworks.length;
  340.             while(i--) { fireworks[i].draw(); fireworks[i].update(i); }
  341.             let j = particles.length;
  342.             while(j--) { particles[j].draw(); particles[j].update(j); }
  343.         }
  344.  
  345.         // --- INTERAKTION & MODI (Full-Screen Fade-Out Logik beibehalten) ---
  346.        
  347.         window.setMode = function(modeName, btnElement) {
  348.             currentMode = modeName;
  349.             document.querySelectorAll('.variant-btn').forEach(btn => btn.classList.remove('active'));
  350.             btnElement.classList.add('active');
  351.         };
  352.  
  353.         window.toggleAutoFire = function() {
  354.             dauerfeuerAktiv = !dauerfeuerAktiv;
  355.             updateAutoFireUI();
  356.             if(dauerfeuerAktiv) {
  357.                 autoFireLoop();
  358.             } else {
  359.                 clearTimeout(dauerfeuerTimer);
  360.             }
  361.         };
  362.  
  363.         function updateAutoFireUI() {
  364.              const btn = document.getElementById('auto-btn');
  365.              if(dauerfeuerAktiv) {
  366.                 btn.textContent = "Dauerfeuer: AN";
  367.                 btn.classList.add('auto-active');
  368.             } else {
  369.                 btn.textContent = "Dauerfeuer: AUS";
  370.                 btn.classList.remove('auto-active');
  371.             }
  372.         }
  373.  
  374.         function autoFireLoop() {
  375.             if(!dauerfeuerAktiv) return;
  376.  
  377.             let targetX = Math.random() * cw;
  378.             let targetY = Math.random() * (ch * 0.6);
  379.             let startX = Math.random() * cw;
  380.  
  381.             fireworks.push(new Firework(startX, ch, targetX, targetY));
  382.  
  383.             let randomDelay = Math.random() * 900 + 300;
  384.             dauerfeuerTimer = setTimeout(autoFireLoop, randomDelay);
  385.         }
  386.  
  387.         // --- FULLSCREEN LOGIK (mit 3s Fade-Out) ---
  388.  
  389.         window.toggleFullscreen = function() {
  390.             if (!isFullscreen) {
  391.                 enterFullscreen();
  392.             } else {
  393.                 exitFullscreen();
  394.             }
  395.         };
  396.  
  397.         function enterFullscreen() {
  398.             isFullscreen = true;
  399.             document.getElementById('ui-container').style.opacity = '0';
  400.             body.classList.add('fullscreen-active');
  401.             instructions.textContent = "Klicke zum Beenden";
  402.             instructions.classList.remove('fade-out');
  403.            
  404.             // Timer starten, um den Text nach 3 Sekunden auszublenden
  405.             fadeOutTimer = setTimeout(() => {
  406.                 instructions.classList.add('fade-out');
  407.             }, 3000);
  408.            
  409.             if (!dauerfeuerAktiv) {
  410.                 toggleAutoFire();
  411.             }
  412.            
  413.             const elem = document.documentElement;
  414.             if (elem.requestFullscreen) {
  415.                 elem.requestFullscreen();
  416.             } else if (elem.webkitRequestFullscreen) {
  417.                 elem.webkitRequestFullscreen();
  418.             }
  419.            
  420.             canvas.removeEventListener('mousedown', handleManualClick);
  421.             canvas.addEventListener('mousedown', exitFullscreen, { once: true });
  422.         }
  423.  
  424.         function exitFullscreen() {
  425.             clearTimeout(fadeOutTimer);
  426.             instructions.classList.remove('fade-out');
  427.            
  428.             isFullscreen = false;
  429.             document.getElementById('ui-container').style.opacity = '1';
  430.             body.classList.remove('fullscreen-active');
  431.             document.getElementById('instructions').textContent = "Klicke zum Zünden oder aktiviere Dauerfeuer!";
  432.  
  433.             if (dauerfeuerAktiv) {
  434.                  toggleAutoFire();
  435.             }
  436.  
  437.             if (document.exitFullscreen) {
  438.                 document.exitFullscreen();
  439.             } else if (document.webkitExitFullscreen) {
  440.                 document.webkitExitFullscreen();
  441.             }
  442.            
  443.             canvas.removeEventListener('mousedown', exitFullscreen);
  444.             canvas.addEventListener('mousedown', handleManualClick);
  445.         }
  446.        
  447.         document.addEventListener('fullscreenchange', function() {
  448.             if (!document.fullscreenElement && isFullscreen) {
  449.                 exitFullscreen();
  450.             }
  451.         });
  452.         document.addEventListener('webkitfullscreenchange', function() {
  453.             if (!document.webkitFullscreenElement && isFullscreen) {
  454.                 exitFullscreen();
  455.             }
  456.         });
  457.  
  458.         function handleManualClick(e) {
  459.              e.preventDefault();
  460.              fireworks.push(new Firework(cw / 2, ch, e.clientX, e.clientY));
  461.         }
  462.  
  463.         canvas.addEventListener('mousedown', handleManualClick);
  464.  
  465.         loop();
  466.  
  467.     </script>
  468. </body>
  469. </html>
Advertisement