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.0, maximum-scale=1.0, user-scalable=no"/>
<title>合成大丑照</title>
<style>
*{margin:0;padding:0;box-sizing:border-box;font-family:system-ui, sans-serif;}
html,body{width:100%;height:100%;background:#111;color:#fff;overflow:hidden;user-select:none;touch-action:none;}
#gamePage{
  position:fixed;inset:0;
  display:flex;align-items:center;justify-content:center;
}
#canvas{
  display:block;
  width:100vw;
  height:100vh;
  background:#111;
}
.game-hint{
  position:fixed;
  top:12px;left:50%;
  transform:translateX(-50%);
  font-size:14px;color:#eee;
  text-align:center;
  pointer-events:none;
  z-index:5;
}
.tip-small{
  position:fixed;
  top:38px;left:50%;
  transform:translateX(-50%);
  font-size:12px;color:#aaa;
  pointer-events:none;
  z-index:5;
}
.mask{
  display:none;
  position:fixed;inset:0;
  background:
    radial-gradient(circle at 20% 30%, rgba(255,105,180,0.35), transparent 45%),
    radial-gradient(circle at 80% 20%, rgba(255,182,193,0.30), transparent 50%),
    radial-gradient(circle at 50% 80%, rgba(255,120,160,0.35), transparent 45%),
    linear-gradient(160deg, #ffb6d5, #ff7ab6, #ff5e87);
  flex-direction:column;
  align-items:center;
  justify-content:center;
  gap:24px;
  z-index:10;
  animation:bgGlow 2.4s ease-in-out infinite alternate;
}
@keyframes bgGlow{
  from{filter:brightness(1);}
  to{filter:brightness(1.12);}
}
.love-title{
  font-size:48px;
  font-weight:800;
  color:#fff;
  letter-spacing:4px;
  text-shadow:
    0 0 12px rgba(255,255,255,0.9),
    0 0 24px rgba(255,105,180,0.8),
    0 0 40px rgba(255,80,140,0.6);
  animation:lovePop 1.1s ease-out infinite alternate;
}
.love-sub{
  font-size:20px;
  color:#fff;
  letter-spacing:2px;
  text-shadow:0 0 10px rgba(255,255,255,0.7);
  animation:loveFade 1.8s ease-in-out infinite alternate;
}
@keyframes lovePop{
  from{transform:scale(1);}
  to{transform:scale(1.06);}
}
@keyframes loveFade{
  from{opacity:0.75;}
  to{opacity:1;}
}
.heart{
  position:absolute;
  color:rgba(255,255,255,0.55);
  animation:floatUp linear infinite;
  pointer-events:none;
}
@keyframes floatUp{
  from{transform:translateY(30px) scale(0.8); opacity:0;}
  20%{opacity:0.6;}
  to{transform:translateY(-110vh) scale(1.2); opacity:0;}
}
.restart-btn{
  padding:12px 28px;
  border:none;border-radius:999px;
  font-size:16px;cursor:pointer;
  background:#fff;color:#ff4d7a;
  font-weight:700;
  box-shadow:0 10px 30px rgba(255,105,180,0.45);
  z-index:20;
}
</style>
</head>
<body>
<div id="gamePage">
  <div class="game-hint">点击屏幕放照片|同级合成,异级碰撞堆叠</div>
  <div class="tip-small">合成到最后,给你一个惊喜</div>
  <canvas id="canvas"></canvas>

  <div class="mask" id="winMask">
    <div class="love-title">我爱你老婆</div>
    <div class="love-sub">永远在一起</div>
    <button class="restart-btn" onclick="location.reload()">再爱一次</button>
  </div>

  <div class="mask" id="loseMask" style="background:rgba(0,0,0,0.88);">
    <h1 style="color:#eee;">堆满溢出了</h1>
    <p style="color:#aaa;">别灰心,再来一次</p>
    <button class="restart-btn" onclick="location.reload()">重新开始</button>
  </div>
</div>

<script>
const IMG_URLS = [
  "https://i.ibb.co/jZHQLjsq/mmexport1792511228537.jpg",
  "https://i.ibb.co/bRRXyY0c/mmexport1792511226057.jpg",
  "https://i.ibb.co/27mZyGJ6/mmexport1792511222092.jpg",
  "https://i.ibb.co/sv2jJWDd/mmexport1792511220090.jpg",
  "https://i.ibb.co/XZYZQB7S/mmexport1792511218637.jpg",
  "https://i.ibb.co/tTDN1jfH/mmexport1792511217231.jpg",
  "https://i.ibb.co/pjpQ0HGG/mmexport1792504275774.jpg",
  "https://i.ibb.co/F4tXxQNN/8.jpg"
];

const TOTAL_LV = 8;
let levelImages = Array(TOTAL_LV).fill(null);

const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const winMask = document.getElementById('winMask');
const loseMask = document.getElementById('loseMask');

let W = 0, H = 0;
const GRAVITY = 0.32;
const RESTITUTION = 0.22;
const FRICTION = 0.995;
const GROUND_DAMP = 0.85;
const AIR_DRAG = 0.999;

function resize(){
  const dpr = window.devicePixelRatio || 1;
  W = window.innerWidth;
  H = window.innerHeight;
  canvas.width = W * dpr;
  canvas.height = H * dpr;
  canvas.style.width = W + "px";
  canvas.style.height = H + "px";
  ctx.setTransform(dpr,0,0,dpr,0,0);
}
window.addEventListener("resize", resize);
resize();

const RADIUS_MAP = [26, 34, 42, 50, 58, 66, 74, 84];
const FAIL_LINE_Y = 110;

let balls = [];
let nextLv = 1;
let gameOver = false;
let win = false;
let dropX = W / 2;
const dropY = 44;

IMG_URLS.forEach((url, idx) => {
  const img = new Image();
  img.src = url;
  img.onload = () => levelImages[idx] = img;
});

function getPos(clientX){
  const rect = canvas.getBoundingClientRect();
  return (clientX || 0) - rect.left;
}
function onMove(clientX){
  if(gameOver || win) return;
  dropX = Math.max(30, Math.min(W - 30, getPos(clientX)));
}
function onClick(clientX){
  if(gameOver || win) return;
  const x = Math.max(30, Math.min(W - 30, getPos(clientX)));
  spawnBall(x, dropY, nextLv);
  nextLv = Math.floor(Math.random() * 4) + 1;
}

canvas.addEventListener("mousemove", e => onMove(e.clientX));
canvas.addEventListener("click", e => onClick(e.clientX));
canvas.addEventListener("touchmove", e => {
  if(e.touches && e.touches[0]){
    onMove(e.touches[0].clientX);
    e.preventDefault();
  }
},{passive:false});
canvas.addEventListener("touchstart", e => {
  if(e.touches && e.touches[0]){
    onMove(e.touches[0].clientX);
    onClick(e.touches[0].clientX);
    e.preventDefault();
  }
},{passive:false});

class Ball{
  constructor(x, y, lv){
    this.x = x;
    this.y = y;
    this.lv = lv;
    this.r = RADIUS_MAP[lv - 1];
    this.vx = 0;
    this.vy = 0;
    this.bornTime = Date.now();
  }

  update(){
    this.vy += GRAVITY;
    this.vx *= AIR_DRAG;
    this.vy *= AIR_DRAG;
    this.x += this.vx;
    this.y += this.vy;

    if(this.x - this.r < 0){
      this.x = this.r;
      this.vx = -this.vx * RESTITUTION;
    }
    if(this.x + this.r > W){
      this.x = W - this.r;
      this.vx = -this.vx * RESTITUTION;
    }

    if(this.y + this.r > H){
      this.y = H - this.r;
      this.vy = -this.vy * RESTITUTION;
      this.vx *= GROUND_DAMP;
      if(Math.abs(this.vy) < 0.6) this.vy = 0;
    }
  }

  draw(){
    const img = levelImages[this.lv - 1];
    ctx.save();
    ctx.beginPath();
    ctx.arc(this.x, this.y, this.r, 0, Math.PI * 2);
    ctx.clip();
    if(img){
      ctx.drawImage(img, this.x - this.r, this.y - this.r, this.r * 2, this.r * 2);
    }else{
      ctx.fillStyle = "#ff6688";
      ctx.beginPath();
      ctx.arc(this.x, this.y, this.r, 0, Math.PI * 2);
      ctx.fill();
    }
    ctx.restore();
  }

  isNew(){
    return Date.now() - this.bornTime < 800;
  }
}

function spawnBall(x,y,lv){
  balls.push(new Ball(x,y,lv));
}

function checkMerge(){
  for(let i = 0; i < balls.length; i++){
    for(let j = i + 1; j < balls.length; j++){
      const a = balls[i];
      const