html5

红包掉落

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>职场已读乱回</title>
    <style>
      :root {
        --dark-gray-start: #2d2f33;
        --dark-gray-end: #1a1a1a;
        --white-collar-blue-start: #6c8eb4;
        --white-collar-blue-end: #b4c7e7;
        --slacker-orange-start: #f4b183;
        --slacker-orange-end: #f8c471;
        --overachiever-red-start: #ff6666;
        --overachiever-red-end: #ff9999;
        --gold: #ffd700;
      }

      body {
        margin: 0;
        padding: 0;
        background: linear-gradient(
          var(--dark-gray-start),
          var(--dark-gray-end)
        );
        height: 100vh;
        overflow: hidden;
        user-select: none;
      }

      h1 {
        font-family: Arial, sans-serif;
        font-size: 48px;
        color: white;
        text-align: center;
        margin-top: 50px;
        position: relative;
        text-shadow: 0 0 10px var(--gold), 0 0 20px var(--gold),
          0 0 30px var(--gold);
        animation: glitch 1s infinite alternate;
        border: 5px solid white;
        padding: 10px;
        display: inline-block;
        left: 50%;
        transform: translateX(-50%);
        position: relative;
        box-shadow: 0 0 10px var(--gold);
      }

      @keyframes glitch {
        0% {
          transform: translateX(-50%) skewX(0deg);
          text-shadow: 0 0 10px var(--gold), 0 0 20px var(--gold),
            0 0 30px var(--gold);
        }
        20% {
          transform: translateX(-50%) skewX(10deg);
          text-shadow: -5px 0 var(--white-collar-blue-start), 5px 0 var(--overachiever-red-start);
        }
        40% {
          transform: translateX(-50%) skewX(-10deg);
          text-shadow: -5px 0 var(--slacker-orange-start), 5px 0 var(--white-collar-blue-start);
        }
        60% {
          transform: translateX(-50%) skewX(5deg);
          text-shadow: -5px 0 var(--overachiever-red-start), 5px 0 var(--slacker-orange-start);
        }
        80% {
          transform: translateX(-50%) skewX(-5deg);
          text-shadow: -5px 0 var(--white-collar-blue-start), 5px 0 var(--overachiever-red-start);
        }
        100% {
          transform: translateX(-50%) skewX(0deg);
          text-shadow: 0 0 10px var(--gold), 0 0 20px var(--gold),
            0 0 30px var(--gold);
        }
      }

      .message {
        position: absolute;
        top: -50px;
        padding: 10px;
        border-radius: 10px;
        font-size: 16px;
        display: flex;
        align-items: center;
        min-width: 100px;
        justify-content: center;
      }

      .message::before {
        content: '';
        display: inline-block;
        width: 20px;
        height: 20px;
        margin-right: 5px;
      }

      .white-collar {
        background: linear-gradient(
          var(--white-collar-blue-start),
          var(--white-collar-blue-end)
        );
      }

      .white-collar::before {
        background: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z" fill="white"/></svg>');
      }

      .slacker {
        background: linear-gradient(
          var(--slacker-orange-start),
          var(--slacker-orange-end)
        );
      }

      .slacker::before {
        background: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z" fill="white"/></svg>');
      }

      .overachiever {
        background: linear-gradient(
          var(--overachiever-red-start),
          var(--overachiever-red-end)
        );
      }

      .overachiever::before {
        background: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z" fill="white"/></svg>');
      }

      .catch-area {
        position: absolute;
        bottom: 20px;
        width: 200px;
        height: 50px;
        background: rgba(255, 255, 255, 0.2);
        backdrop-filter: blur(10px);
        border-radius: 10px;
        box-shadow: 0 0 10px rgba(255, 255, 255, 0.3);
      }

      .catch-area::after {
        content: '';
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        background: inherit;
        filter: blur(10px);
        opacity: 0.5;
        z-index: -1;
        animation: trail 0.5s infinite;
      }

      @keyframes trail {
        0% {
          transform: translateX(0);
          opacity: 0.5;
        }
        100% {
          transform: translateX(10px);
          opacity: 0;
        }
      }

      .particle-effect {
        position: fixed;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        pointer-events: none;
        display: none;
      }

      .particle {
        position: absolute;
        width: 5px;
        height: 5px;
        background: var(--gold);
        border-radius: 50%;
        animation: particle 1s ease-out forwards;
      }

      @keyframes particle {
        0% {
          transform: translate(0, 0);
          opacity: 1;
        }
        100% {
          transform: translate(var(--x), var(--y));
          opacity: 0;
        }
      }

      .prompt {
        position: fixed;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        background: rgba(0, 0, 0, 0.7);
        color: white;
        padding: 20px;
        border-radius: 10px;
        font-size: 24px;
        display: none;
      }
    </style>
  </head>

  <body>
    <h1>职场已读乱回</h1>
    <div class="catch-area" id="catchArea"></div>
    <div class="particle-effect" id="particleEffect"></div>
    <div class="prompt" id="prompt">功德+1</div>

    <script>
      const messages = [
        '嗯嗯,知道了。',
        '好的,安排一下。',
        '行,我看看。',
        '没问题,稍后处理。',
        '收到,马上跟进。',
        '了解,会处理的。',
        '好嘞,这就办。',
        '可以,我来弄。',
        '晓得,等我弄。',
        '明白,着手处理。'
      ]

      const messageTypes = ['white-collar', 'slacker', 'overachiever']
      const catchArea = document.getElementById('catchArea')
      const particleEffect = document.getElementById('particleEffect')
      const prompt = document.getElementById('prompt')
      const messageElements = []
      let score = 0
      let isPerformanceMode = window.innerWidth < 768

      document.addEventListener('mousemove', e => {
        const x = e.clientX - catchArea.offsetWidth / 2
        catchArea.style.left =
          Math.min(Math.max(x, 0), window.innerWidth - catchArea.offsetWidth) +
          'px'
      })

      document.addEventListener(
        'touchmove',
        e => {
          e.preventDefault()
          const touch = e.touches[0]
          const x = touch.clientX - catchArea.offsetWidth / 2
          catchArea.style.left =
            Math.min(
              Math.max(x, 0),
              window.innerWidth - catchArea.offsetWidth
            ) + 'px'
        },
        { passive: false }
      )

      document.addEventListener('keydown', e => {
        const speed = 20
        const currentLeft = parseInt(catchArea.style.left || 0)
        if (e.key === 'ArrowLeft') {
          catchArea.style.left = Math.max(0, currentLeft - speed) + 'px'
        } else if (e.key === 'ArrowRight') {
          catchArea.style.left =
            Math.min(
              window.innerWidth - catchArea.offsetWidth,
              currentLeft + speed
            ) + 'px'
        }
      })

      function createMessage() {
        const message = document.createElement('div')
        message.classList.add('message')
        const randomMessage =
          messages[Math.floor(Math.random() * messages.length)]
        const randomType =
          messageTypes[Math.floor(Math.random() * messageTypes.length)]
        message.classList.add(randomType)
        message.textContent = randomMessage
        message.style.left = Math.random() * (window.innerWidth - 100) + 'px'
        document.body.appendChild(message)
        messageElements.push(message)
      }

      function moveMessages() {
        messageElements.forEach((message, index) => {
          const rect = message.getBoundingClientRect()
          if (rect.bottom < window.innerHeight) {
            message.style.top = rect.top + 3 + 'px'
            if (isCollision(message, catchArea)) {
              catchMessage(message, index)
            }
          } else {
            removeMessage(message, index)
          }
        })
      }

      function isCollision(element1, element2) {
        const rect1 = element1.getBoundingClientRect()
        const rect2 = element2.getBoundingClientRect()
        return (
          rect1.left < rect2.right &&
          rect1.right > rect2.left &&
          rect1.bottom > rect2.top &&
          rect1.top < rect2.bottom
        )
      }

      function catchMessage(message, index) {
        playSound()
        showParticleEffect()
        showPrompt()
        removeMessage(message, index)
        score++
      }

      function playSound() {
        const audioContext = new (window.AudioContext ||
          window.webkitAudioContext)()
        const oscillator = audioContext.createOscillator()
        const gainNode = audioContext.createGain()
        oscillator.type = 'sine'
        oscillator.frequency.setValueAtTime(300, audioContext.currentTime)
        gainNode.gain.setValueAtTime(0.5, audioContext.currentTime)
        oscillator.connect(gainNode)
        gainNode.connect(audioContext.destination)
        oscillator.start()
        oscillator.stop(audioContext.currentTime + 0.2)
      }

      function showParticleEffect() {
        particleEffect.style.display = 'block'
        for (let i = 0; i < (isPerformanceMode ? 10 : 50); i++) {
          const particle = document.createElement('div')
          particle.classList.add('particle')
          const angle = Math.random() * 2 * Math.PI
          const distance = Math.random() * 200
          const x = Math.cos(angle) * distance
          const y = Math.sin(angle) * distance
          particle.style.setProperty('--x', `${x}px`)
          particle.style.setProperty('--y', `${y}px`)
          particle.style.left = window.innerWidth / 2 + 'px'
          particle.style.top = window.innerHeight / 2 + 'px'
          particleEffect.appendChild(particle)
          setTimeout(() => {
            particle.remove()
          }, 1000)
        }
        setTimeout(() => {
          particleEffect.style.display = 'none'
        }, 1000)
      }

      function showPrompt() {
        prompt.style.display = 'block'
        setTimeout(() => {
          prompt.style.display = 'none'
        }, 1000)
      }

      function removeMessage(message, index) {
        message.remove()
        messageElements.splice(index, 1)
      }

      function gameLoop() {
        if (Math.random() < 0.01) {
          createMessage()
        }
        moveMessages()
        requestAnimationFrame(gameLoop)
      }

      gameLoop()
    </script>
  </body>
</html>
上次更新: