SOURCE

console 命令行工具 X clear

                    
>
console
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no,viewport-fit=cover">
<meta name="theme-color" content="#1b3a57">
<title>我的专属图片桌宠</title>
<style>
  * { margin: 0; padding: 0; box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
  html, body {
    width: 100%; height: 100%; overflow: hidden;
    background: radial-gradient(circle at 50% 38%, #1b3a57 0%, #0a1622 72%);
    touch-action: none; user-select: none; -webkit-user-select: none;
    font-family: -apple-system, "PingFang SC", "Microsoft YaHei", sans-serif;
  }
  
  /* 上传界面的样式 */
  #upload-ui {
    position: fixed; inset: 0; display: flex; flex-direction: column;
    align-items: center; justify-content: center; color: #fff;
    background: rgba(10, 22, 34, 0.9); z-index: 100;
    transition: opacity 0.3s;
  }
  #upload-ui.hide { opacity: 0; pointer-events: none; }
  #upload-ui h2 { font-size: 22px; margin-bottom: 20px; color: #8FE3FF; }
  .upload-btn {
    padding: 14px 30px; font-size: 16px; font-weight: bold; color: #05101a;
    background: linear-gradient(135deg, #8FE3FF, #2AA0DC);
    border: none; border-radius: 30px; box-shadow: 0 8px 20px rgba(42, 160, 220, 0.4);
    cursor: pointer; transition: transform 0.1s; margin-bottom: 20px;
  }
  .upload-btn:active { transform: scale(0.95); }
  #file-input { display: none; }
  .tips { font-size: 13px; color: #9cb8cc; text-align: center; line-height: 1.6; }
  
  /* 桌宠容器样式 */
  #pet-container {
    position: absolute; left: 50%; top: 50%;
    transform: translate(-50%, -50%);
    display: none; /* 默认隐藏,上传后显示 */
    cursor: grab;
    touch-action: none;
    filter: drop-shadow(0 10px 15px rgba(0,0,0,0.5)); /* 给图片加点立体阴影 */
  }
  #pet-container:active { cursor: grabbing; }
  #pet-img {
    width: 280px; /* 手机上默认大小,可调整 */
    max-width: 80vw;
    pointer-events: none;
  }

  /* 气泡样式 */
  #bubble {
    position: absolute; left: 50%; top: -30px;
    transform: translate(-50%, -100%) scale(0.7);
    background: #fff; color: #333;
    padding: 10px 18px; border-radius: 20px;
    font-size: 16px; font-weight: bold;
    white-space: nowrap; opacity: 0; pointer-events: none;
    transition: transform 0.2s cubic-bezier(0.3, 1.6, 0.6, 1), opacity 0.2s;
    box-shadow: 0 5px 15px rgba(0,0,0,0.3);
  }
  #bubble.show { opacity: 1; transform: translate(-50%, -100%) scale(1); }
  #bubble::after {
    content: ""; position: absolute; left: 50%; bottom: -8px;
    transform: translateX(-50%);
    border: 9px solid transparent; border-top-color: #fff; border-bottom: 0;
  }
</style>
</head>
<body>

<!-- 上传界面 -->
<div id="upload-ui">
  <h2>召唤你的专属桌宠</h2>
  <button class="upload-btn" id="upload-btn">选择图片</button>
  <input type="file" id="file-input" accept="image/*">
  <p class="tips">建议选择背景透明的 PNG 图片<br>(如果图片有白底,可以在下一步选去除)</p>
</div>

<!-- 桌宠展示区 -->
<div id="pet-container">
  <div id="bubble">你看,又急</div>
  <img id="pet-img" src="" alt="pet">
</div>

<script>
(function(){
  const uploadUI = document.getElementById('upload-ui');
  const uploadBtn = document.getElementById('upload-btn');
  const fileInput = document.getElementById('file-input');
  const petContainer = document.getElementById('pet-container');
  const petImg = document.getElementById('pet-img');
  const bubble = document.getElementById('bubble');

  const LINES = [
    '你看,又急',
    '别戳啦!',
    '今天也要好好工作哦~',
    '要摸摸尾巴吗?',
    '哼,才不是特意来陪你的'
  ];

  // 拖拽状态
  let isDragging = false;
  let startX = 0, startY = 0;
  let initialX = 0, initialY = 0;
  let moveThreshold = 5; // 移动超过5像素算拖拽,否则算点击
  let hasMoved = false;

  // 初始位置居中 (绝对定位,但通过 left/top 改变)
  let currentX = window.innerWidth / 2;
  let currentY = window.innerHeight / 2;
  let isCentered = true;

  uploadBtn.addEventListener('click', () => fileInput.click());

  // 处理上传的图片
  fileInput.addEventListener('change', (e) => {
    const file = e.target.files[0];
    if (!file) return;

    const reader = new FileReader();
    reader.onload = (event) => {
      const img = new Image();
      img.onload = () => {
        // 处理图片(去白底)
        removeWhiteBackground(img);
        
        // 切换界面
        uploadUI.classList.add('hide');
        petContainer.style.display = 'block';
        
        // 居中显示
        currentX = window.innerWidth / 2;
        currentY = window.innerHeight / 2;
        petContainer.style.left = currentX + 'px';
        petContainer.style.top = currentY + 'px';
        petContainer.style.transform = 'translate(-50%, -50%)';
      };
      img.src = event.target.result;
    };
    reader.readAsDataURL(file);
  });

  // 核心魔法:去除纯白背景
  function removeWhiteBackground(img) {
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');
    canvas.width = img.width;
    canvas.height = img.height;
    ctx.drawImage(img, 0, 0);
    
    const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
    const data = imageData.data;
    
    // 遍历所有像素
    for (let i = 0; i < data.length; i += 4) {
      const r = data[i];
      const g = data[i + 1];
      const b = data[i + 2];
      // 如果RGB值都很高(接近纯白),则把透明度设为0
      if (r > 240 && g > 240 && b > 240) {
        data[i + 3] = 0; 
      }
    }
    ctx.putImageData(imageData, 0, 0);
    petImg.src = canvas.toDataURL('image/png');
  }

  // --- 互动逻辑 ---

  function say(text) {
    bubble.textContent = text;
    bubble.classList.add('show');
    clearTimeout(window.sayTimer);
    window.sayTimer = setTimeout(() => bubble.classList.remove('show'), 2000);
  }

  // 按下
  function dragStart(e) {
    if (e.target === uploadBtn) return;
    isDragging = true;
    hasMoved = false;
    
    const clientX = e.touches ? e.touches[0].clientX : e.clientX;
    const clientY = e.touches ? e.touches[0].clientY : e.clientY;
    
    startX = clientX;
    startY = clientY;
    
    const rect = petContainer.getBoundingClientRect();
    // 记录鼠标按下时,点击位置相对于图片中心的偏移量
    initialX = startX - (rect.left + rect.width / 2);
    initialY = startY - (rect.top + rect.height / 2);

    petContainer.style.transform = 'translate(-50%, -50%) scale(1.05)'; // 抓取时稍微放大
    
    document.addEventListener('mousemove', dragMove, { passive: false });
    document.addEventListener('mouseup', dragEnd);
    document.addEventListener('touchmove', dragMove, { passive: false });
    document.addEventListener('touchend', dragEnd);
  }

  // 移动
  function dragMove(e) {
    if (!isDragging) return;
    if (e.cancelable) e.preventDefault();
    
    const clientX = e.touches ? e.touches[0].clientX : e.clientX;
    const clientY = e.touches ? e.touches[0].clientY : e.clientY;
    
    // 计算是否移动了足够的距离(为了防止长按轻微的抖动被判定为拖拽)
    const dx = clientX - startX;
    const dy = clientY - startY;
    if (Math.abs(dx) > moveThreshold || Math.abs(dy) > moveThreshold) {
      hasMoved = true;
    }

    if (hasMoved) {
      currentX = clientX - initialX;
      currentY = clientY - initialY;
      petContainer.style.left = currentX + 'px';
      petContainer.style.top = currentY + 'px';
      bubble.classList.remove('show'); // 拖拽时隐藏气泡
    }
  }

  // 松开
  function dragEnd() {
    if (!isDragging) return;
    isDragging = false;
    
    petContainer.style.transform = 'translate(-50%, -50%) scale(1)';
    
    // 如果没有移动,说明是点击,触发对话
    if (!hasMoved) {
      const line = LINES[Math.floor(Math.random() * LINES.length)];
      say(line);
      // 点击跳动动画
      petContainer.animate([
        { transform: 'translate(-50%, -50%) scale(1)' },
        { transform: 'translate(-50%, -55%) scale(1.1)' },
        { transform: 'translate(-50%, -50%) scale(1)' }
      ], { duration: 300, easing: 'ease-out' });
    }

    document.removeEventListener('mousemove', dragMove);
    document.removeEventListener('mouseup', dragEnd);
    document.removeEventListener('touchmove', dragMove);
    document.removeEventListener('touchend', dragEnd);
  }

  petContainer.addEventListener('mousedown', dragStart);
  petContainer.addEventListener('touchstart', dragStart, { passive: false });

})();
</script>
</body>
</html>